Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • komasolver
  • main
  • renovate/django-5.x
  • renovate/django-debug-toolbar-5.x
  • renovate/django_csp-4.x
  • renovate/djangorestframework-3.x
  • renovate/tzdata-2025.x
  • renovate/uwsgi-2.x
8 results

Target

Select target project
  • konstantin/akplanning
  • matedealer/akplanning
  • kif/akplanning
  • mirco/akplanning
  • lordofthevoid/akplanning
  • voidptr/akplanning
  • xayomer/akplanning-fork
  • mollux/akplanning
  • neumantm/akplanning
  • mmarx/akplanning
  • nerf/akplanning
  • felix_bonn/akplanning
  • sebastian.uschmann/akplanning
13 results
Select Git revision
  • 520-akowner
  • 520-fix-event-wizard-datepicker
  • 520-fix-scheduling
  • 520-improve-scheduling
  • 520-improve-scheduling-2
  • 520-improve-submission
  • 520-improve-trackmanager
  • 520-improve-wall
  • 520-message-resolved
  • 520-status
  • 520-upgrades
  • add_express_interest_to_ak_overview
  • admin-production-color
  • bugfixes
  • csp
  • featire-ical-export
  • feature-ak-requirement-lists
  • feature-akslide-export-better-filename
  • feature-akslides
  • feature-better-admin
  • feature-better-cv-list
  • feature-colors
  • feature-constraint-checking
  • feature-constraint-checking-wip
  • feature-dashboard-history-button
  • feature-event-status
  • feature-event-wizard
  • feature-export-flag
  • feature-improve-admin
  • feature-improve-filters
  • feature-improved-user-creation-workflow
  • feature-interest-view
  • feature-mails
  • feature-modular-status
  • feature-plan-autoreload
  • feature-present-default
  • feature-register-link
  • feature-remaining-constraint-validation
  • feature-room-import
  • feature-scheduler-improve
  • feature-scheduling-2.0
  • feature-special-attention
  • feature-time-input
  • feature-tracker
  • feature-wiki-wishes
  • feature-wish-slots
  • feature-wizard-buttons
  • features-availabilities
  • fix-ak-times-above-folg
  • fix-api
  • fix-constraint-violation-string
  • fix-cv-checking
  • fix-default-slot-length
  • fix-default-slot-localization
  • fix-doc-minor
  • fix-duration-display
  • fix-event-tz-pytz-update
  • fix-history-interest
  • fix-interest-view
  • fix-js
  • fix-pipeline
  • fix-plan-timezone-now
  • fix-room-add
  • fix-scheduling-drag
  • fix-slot-defaultlength
  • fix-timezone
  • fix-translation-scheduling
  • fix-virtual-room-admin
  • fix-wizard-csp
  • font-locally
  • improve-admin
  • improve-online
  • improve-slides
  • improve-submission-coupling
  • interest_restriction
  • main
  • master
  • meta-debug-toolbar
  • meta-export
  • meta-makemessages
  • meta-performance
  • meta-tests
  • meta-tests-gitlab-test
  • meta-upgrades
  • mollux-master-patch-02906
  • port-availabilites-fullcalendar
  • qs
  • remove-tags
  • renovate/configure
  • renovate/django-4.x
  • renovate/django-5.x
  • renovate/django-bootstrap-datepicker-plus-5.x
  • renovate/django-bootstrap5-23.x
  • renovate/django-bootstrap5-24.x
  • renovate/django-compressor-4.x
  • renovate/django-debug-toolbar-4.x
  • renovate/django-registration-redux-2.x
  • renovate/django-simple-history-3.x
  • renovate/django-split-settings-1.x
  • renovate/django-timezone-field-5.x
100 results
Show changes
Showing
with 28 additions and 8235 deletions
@charset "UTF-8";
/* TimeGridView all-day area
--------------------------------------------------------------------------------------------------*/
.fc-timeGrid-view .fc-day-grid {
position: relative;
z-index: 2;
/* so the "more.." popover will be over the time grid */
}
.fc-timeGrid-view .fc-day-grid .fc-row {
min-height: 3em;
/* all-day section will never get shorter than this */
}
.fc-timeGrid-view .fc-day-grid .fc-row .fc-content-skeleton {
padding-bottom: 1em;
/* give space underneath events for clicking/selecting days */
}
/* TimeGrid axis running down the side (for both the all-day area and the slot area)
--------------------------------------------------------------------------------------------------*/
.fc .fc-axis {
/* .fc to overcome default cell styles */
vertical-align: middle;
padding: 0 4px;
white-space: nowrap;
}
.fc-ltr .fc-axis {
text-align: right;
}
.fc-rtl .fc-axis {
text-align: left;
}
/* TimeGrid Structure
--------------------------------------------------------------------------------------------------*/
.fc-time-grid-container,
.fc-time-grid {
/* so slats/bg/content/etc positions get scoped within here */
position: relative;
z-index: 1;
}
.fc-time-grid {
min-height: 100%;
/* so if height setting is 'auto', .fc-bg stretches to fill height */
}
.fc-time-grid table {
/* don't put outer borders on slats/bg/content/etc */
border: 0 hidden transparent;
}
.fc-time-grid > .fc-bg {
z-index: 1;
}
.fc-time-grid .fc-slats,
.fc-time-grid > hr {
/* the <hr> TimeGridView injects when grid is shorter than scroller */
position: relative;
z-index: 2;
}
.fc-time-grid .fc-content-col {
position: relative;
/* because now-indicator lives directly inside */
}
.fc-time-grid .fc-content-skeleton {
position: absolute;
z-index: 3;
top: 0;
left: 0;
right: 0;
}
/* divs within a cell within the fc-content-skeleton */
.fc-time-grid .fc-business-container {
position: relative;
z-index: 1;
}
.fc-time-grid .fc-bgevent-container {
position: relative;
z-index: 2;
}
.fc-time-grid .fc-highlight-container {
position: relative;
z-index: 3;
}
.fc-time-grid .fc-event-container {
position: relative;
z-index: 4;
}
.fc-time-grid .fc-now-indicator-line {
z-index: 5;
}
.fc-time-grid .fc-mirror-container {
/* also is fc-event-container */
position: relative;
z-index: 6;
}
/* TimeGrid Slats (lines that run horizontally)
--------------------------------------------------------------------------------------------------*/
.fc-time-grid .fc-slats td {
height: 1.5em;
border-bottom: 0;
/* each cell is responsible for its top border */
}
.fc-time-grid .fc-slats .fc-minor td {
border-top-style: dotted;
}
/* TimeGrid Highlighting Slots
--------------------------------------------------------------------------------------------------*/
.fc-time-grid .fc-highlight-container {
/* a div within a cell within the fc-highlight-skeleton */
position: relative;
/* scopes the left/right of the fc-highlight to be in the column */
}
.fc-time-grid .fc-highlight {
position: absolute;
left: 0;
right: 0;
/* top and bottom will be in by JS */
}
/* TimeGrid Event Containment
--------------------------------------------------------------------------------------------------*/
.fc-ltr .fc-time-grid .fc-event-container {
/* space on the sides of events for LTR (default) */
margin: 0 2.5% 0 2px;
}
.fc-rtl .fc-time-grid .fc-event-container {
/* space on the sides of events for RTL */
margin: 0 2px 0 2.5%;
}
.fc-time-grid .fc-event,
.fc-time-grid .fc-bgevent {
position: absolute;
z-index: 1;
/* scope inner z-index's */
}
.fc-time-grid .fc-bgevent {
/* background events always span full width */
left: 0;
right: 0;
}
/* TimeGrid Event Styling
----------------------------------------------------------------------------------------------------
We use the full "fc-time-grid-event" class instead of using descendants because the event won't
be a descendant of the grid when it is being dragged.
*/
.fc-time-grid-event {
margin-bottom: 1px;
}
.fc-time-grid-event-inset {
-webkit-box-shadow: 0px 0px 0px 1px #fff;
box-shadow: 0px 0px 0px 1px #fff;
}
.fc-time-grid-event.fc-not-start {
/* events that are continuing from another day */
/* replace space made by the top border with padding */
border-top-width: 0;
padding-top: 1px;
/* remove top rounded corners */
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.fc-time-grid-event.fc-not-end {
/* replace space made by the top border with padding */
border-bottom-width: 0;
padding-bottom: 1px;
/* remove bottom rounded corners */
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.fc-time-grid-event .fc-content {
overflow: hidden;
max-height: 100%;
}
.fc-time-grid-event .fc-time,
.fc-time-grid-event .fc-title {
padding: 0 1px;
}
.fc-time-grid-event .fc-time {
font-size: 0.85em;
white-space: nowrap;
}
/* short mode, where time and title are on the same line */
.fc-time-grid-event.fc-short .fc-content {
/* don't wrap to second line (now that contents will be inline) */
white-space: nowrap;
}
.fc-time-grid-event.fc-short .fc-time,
.fc-time-grid-event.fc-short .fc-title {
/* put the time and title on the same line */
display: inline-block;
vertical-align: top;
}
.fc-time-grid-event.fc-short .fc-time span {
display: none;
/* don't display the full time text... */
}
.fc-time-grid-event.fc-short .fc-time:before {
content: attr(data-start);
/* ...instead, display only the start time */
}
.fc-time-grid-event.fc-short .fc-time:after {
content: " - ";
/* seperate with a dash, wrapped in nbsp's */
}
.fc-time-grid-event.fc-short .fc-title {
font-size: 0.85em;
/* make the title text the same size as the time */
padding: 0;
/* undo padding from above */
}
/* resizer (cursor device) */
.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer {
left: 0;
right: 0;
bottom: 0;
height: 8px;
overflow: hidden;
line-height: 8px;
font-size: 11px;
font-family: monospace;
text-align: center;
cursor: s-resize;
}
.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer:after {
content: "=";
}
/* resizer (touch device) */
.fc-time-grid-event.fc-selected .fc-resizer {
/* 10x10 dot */
border-radius: 5px;
border-width: 1px;
width: 8px;
height: 8px;
border-style: solid;
border-color: inherit;
background: #fff;
/* horizontally center */
left: 50%;
margin-left: -5px;
/* center on the bottom edge */
bottom: -5px;
}
/* Now Indicator
--------------------------------------------------------------------------------------------------*/
.fc-time-grid .fc-now-indicator-line {
border-top-width: 1px;
left: 0;
right: 0;
}
/* arrow on axis */
.fc-time-grid .fc-now-indicator-arrow {
margin-top: -5px;
/* vertically center on top coordinate */
}
.fc-ltr .fc-time-grid .fc-now-indicator-arrow {
left: 0;
/* triangle pointing right... */
border-width: 5px 0 5px 6px;
border-top-color: transparent;
border-bottom-color: transparent;
}
.fc-rtl .fc-time-grid .fc-now-indicator-arrow {
right: 0;
/* triangle pointing left... */
border-width: 5px 6px 5px 0;
border-top-color: transparent;
border-bottom-color: transparent;
}
// Generated by dts-bundle v0.7.3-fork.1
// Dependencies for this module:
// ../../../../../@fullcalendar/core
// ../../../../../@fullcalendar/daygrid
declare module '@fullcalendar/timegrid' {
import AbstractTimeGridView from '@fullcalendar/timegrid/AbstractTimeGridView';
import TimeGridView, {buildDayTable} from '@fullcalendar/timegrid/TimeGridView';
import {TimeGridSeg} from '@fullcalendar/timegrid/TimeGrid';
import {buildDayRanges, TimeGridSlicer} from '@fullcalendar/timegrid/SimpleTimeGrid';
export {TimeGridView, AbstractTimeGridView, buildDayTable, buildDayRanges, TimeGridSlicer, TimeGridSeg};
export {default as TimeGrid} from '@fullcalendar/timegrid/TimeGrid';
const _default: import("@fullcalendar/core").PluginDef;
export default _default;
}
declare module '@fullcalendar/timegrid/AbstractTimeGridView' {
import {
ComponentContext,
DateProfileGenerator,
Duration,
ScrollComponent,
View,
ViewSpec
} from '@fullcalendar/core';
import {DayGrid} from '@fullcalendar/daygrid';
import TimeGrid from '@fullcalendar/timegrid/TimeGrid';
import AllDaySplitter from '@fullcalendar/timegrid/AllDaySplitter';
export {TimeGridView as default, TimeGridView};
abstract class TimeGridView extends View {
timeGrid: TimeGrid;
dayGrid: DayGrid;
scroller: ScrollComponent;
axisWidth: any;
protected splitter: AllDaySplitter;
constructor(context: ComponentContext, viewSpec: ViewSpec, dateProfileGenerator: DateProfileGenerator, parentEl: HTMLElement);
destroy(): void;
renderSkeletonHtml(): string;
getNowIndicatorUnit(): string;
unrenderNowIndicator(): void;
updateSize(isResize: boolean, viewHeight: number, isAuto: boolean): void;
updateBaseSize(isResize: any, viewHeight: any, isAuto: any): void;
computeScrollerHeight(viewHeight: any): number;
computeDateScroll(duration: Duration): {
top: any;
};
queryDateScroll(): {
top: number;
};
applyDateScroll(scroll: any): void;
renderHeadIntroHtml: () => string;
axisStyleAttr(): string;
renderTimeGridBgIntroHtml: () => string;
renderTimeGridIntroHtml: () => string;
renderDayGridBgIntroHtml: () => string;
renderDayGridIntroHtml: () => string;
}
}
declare module '@fullcalendar/timegrid/TimeGridView' {
import {
ComponentContext,
DateProfile,
DateProfileGenerator,
DayHeader,
DayTable,
ViewProps,
ViewSpec
} from '@fullcalendar/core';
import {SimpleDayGrid} from '@fullcalendar/daygrid';
import SimpleTimeGrid from '@fullcalendar/timegrid/SimpleTimeGrid';
import AbstractTimeGridView from '@fullcalendar/timegrid/AbstractTimeGridView';
export {TimeGridView as default, TimeGridView};
class TimeGridView extends AbstractTimeGridView {
header: DayHeader;
simpleDayGrid: SimpleDayGrid;
simpleTimeGrid: SimpleTimeGrid;
constructor(_context: ComponentContext, viewSpec: ViewSpec, dateProfileGenerator: DateProfileGenerator, parentEl: HTMLElement);
destroy(): void;
render(props: ViewProps): void;
renderNowIndicator(date: any): void;
}
export function buildDayTable(dateProfile: DateProfile, dateProfileGenerator: DateProfileGenerator): DayTable;
}
declare module '@fullcalendar/timegrid/TimeGrid' {
import {
ComponentContext,
DateComponent,
DateFormatter,
DateMarker,
DateProfile,
Duration,
EventSegUiInteractionState,
PositionCache,
Seg
} from '@fullcalendar/core';
export interface RenderProps {
renderBgIntroHtml: () => string;
renderIntroHtml: () => string;
}
export interface TimeGridSeg extends Seg {
col: number;
start: DateMarker;
end: DateMarker;
}
export interface TimeGridCell {
date: DateMarker;
htmlAttrs?: string;
}
export interface TimeGridProps {
dateProfile: DateProfile;
cells: TimeGridCell[];
businessHourSegs: TimeGridSeg[];
bgEventSegs: TimeGridSeg[];
fgEventSegs: TimeGridSeg[];
dateSelectionSegs: TimeGridSeg[];
eventSelection: string;
eventDrag: EventSegUiInteractionState | null;
eventResize: EventSegUiInteractionState | null;
}
export { TimeGrid as default, TimeGrid };
class TimeGrid extends DateComponent<TimeGridProps> {
renderProps: RenderProps;
slotDuration: Duration;
snapDuration: Duration;
snapsPerSlot: any;
labelFormat: DateFormatter;
labelInterval: Duration;
colCnt: number;
colEls: HTMLElement[];
slatContainerEl: HTMLElement;
slatEls: HTMLElement[];
nowIndicatorEls: HTMLElement[];
colPositions: PositionCache;
slatPositions: PositionCache;
isSlatSizesDirty: boolean;
isColSizesDirty: boolean;
rootBgContainerEl: HTMLElement;
bottomRuleEl: HTMLElement;
contentSkeletonEl: HTMLElement;
colContainerEls: HTMLElement[];
fgContainerEls: HTMLElement[];
bgContainerEls: HTMLElement[];
mirrorContainerEls: HTMLElement[];
highlightContainerEls: HTMLElement[];
businessContainerEls: HTMLElement[];
constructor(context: ComponentContext, el: HTMLElement, renderProps: RenderProps);
processOptions(): void;
computeLabelInterval(slotDuration: any): any;
render(props: TimeGridProps): void;
destroy(): void;
updateSize(isResize: boolean): void;
_renderSlats(dateProfile: DateProfile): void;
renderSlatRowHtml(dateProfile: DateProfile): string;
_renderColumns(cells: TimeGridCell[], dateProfile: DateProfile): void;
_unrenderColumns(): void;
renderContentSkeleton(): void;
unrenderContentSkeleton(): void;
groupSegsByCol(segs: any): any[];
attachSegsByCol(segsByCol: any, containerEls: HTMLElement[]): void;
getNowIndicatorUnit(): string;
renderNowIndicator(segs: TimeGridSeg[], date: any): void;
unrenderNowIndicator(): void;
getTotalSlatHeight(): number;
computeDateTop(when: DateMarker, startOfDayDate?: DateMarker): any;
computeTimeTop(duration: Duration): any;
computeSegVerticals(segs: any): void;
assignSegVerticals(segs: any): void;
generateSegVerticalCss(seg: any): {
top: any;
bottom: number;
};
buildPositionCaches(): void;
buildColPositions(): void;
buildSlatPositions(): void;
positionToHit(positionLeft: any, positionTop: any): {
col: any;
dateSpan: {
range: {
start: Date;
end: Date;
};
allDay: boolean;
};
dayEl: HTMLElement;
relativeRect: {
left: any;
right: any;
top: any;
bottom: any;
};
};
_renderEventDrag(state: EventSegUiInteractionState): void;
_unrenderEventDrag(state: EventSegUiInteractionState): void;
_renderEventResize(state: EventSegUiInteractionState): void;
_unrenderEventResize(state: EventSegUiInteractionState): void;
_renderDateSelection(segs: Seg[]): void;
_unrenderDateSelection(segs: Seg[]): void;
}
}
declare module '@fullcalendar/timegrid/SimpleTimeGrid' {
import {
ComponentContext,
DateComponent,
DateEnv,
DateMarker,
DateProfile,
DateRange,
DateSpan,
DayTable,
EventInteractionState,
EventStore,
EventUiHash,
Hit,
Slicer
} from '@fullcalendar/core';
import TimeGrid, {TimeGridSeg} from '@fullcalendar/timegrid/TimeGrid';
export interface SimpleTimeGridProps {
dateProfile: DateProfile | null;
dayTable: DayTable;
businessHours: EventStore;
eventStore: EventStore;
eventUiBases: EventUiHash;
dateSelection: DateSpan | null;
eventSelection: string;
eventDrag: EventInteractionState | null;
eventResize: EventInteractionState | null;
}
export { SimpleTimeGrid as default, SimpleTimeGrid };
class SimpleTimeGrid extends DateComponent<SimpleTimeGridProps> {
timeGrid: TimeGrid;
constructor(context: ComponentContext, timeGrid: TimeGrid);
destroy(): void;
render(props: SimpleTimeGridProps): void;
renderNowIndicator(date: DateMarker): void;
buildPositionCaches(): void;
queryHit(positionLeft: number, positionTop: number): Hit;
}
export function buildDayRanges(dayTable: DayTable, dateProfile: DateProfile, dateEnv: DateEnv): DateRange[];
export class TimeGridSlicer extends Slicer<TimeGridSeg, [DateRange[]]> {
sliceRange(range: DateRange, dayRanges: DateRange[]): TimeGridSeg[];
}
}
declare module '@fullcalendar/timegrid/AllDaySplitter' {
import {DateSpan, EventDef, Splitter} from '@fullcalendar/core';
export { AllDaySplitter as default, AllDaySplitter };
class AllDaySplitter extends Splitter {
getKeyInfo(): {
allDay: {};
timed: {};
};
getKeysForDateSpan(dateSpan: DateSpan): string[];
getKeysForEventDef(eventDef: EventDef): string[];
}
}
/*!
FullCalendar Time Grid Plugin v4.3.0
Docs & License: https://fullcalendar.io/
(c) 2019 Adam Shaw
*/
import {
addDurations,
applyStyle,
asRoughMs,
buildGotoAnchorHtml,
buildSegCompareObj,
compareByFieldSpecs,
compensateScroll,
createDuration,
createElement,
createFormatter,
createPlugin,
cssToStr,
DateComponent,
DayHeader,
DaySeries,
DayTable,
diffDays,
FgEventRenderer,
FillRenderer,
findElements,
formatIsoTimeString,
getAllDayHtml,
hasBgRendering,
htmlEscape,
htmlToElement,
intersectRanges,
isMultiDayRange,
matchCellWidths,
memoize,
memoizeRendering,
multiplyDuration,
PositionCache,
removeElement,
ScrollComponent,
Slicer,
Splitter,
startOfDay,
subtractInnerElHeight,
uncompensateScroll,
View,
wholeDivideDurations
} from '@fullcalendar/core';
import {DayBgRow, DayGrid, SimpleDayGrid} from '@fullcalendar/daygrid';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* 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, timeGrid.context) || this;
_this.timeGrid = timeGrid;
_this.fullTimeFormat = createFormatter({
hour: 'numeric',
minute: '2-digit',
separator: _this.context.options.defaultRangeSeparator
});
return _this;
}
// 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 view = this.context.view;
var eventRange = seg.eventRange;
var eventDef = eventRange.def;
var eventUi = eventRange.ui;
var allDay = eventDef.allDay;
var isDraggable = view.computeEventDraggable(eventDef, eventUi);
var isResizableFromStart = seg.isStart && view.computeEventStartResizable(eventDef, eventUi);
var isResizableFromEnd = seg.isEnd && view.computeEventEndResizable(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.view.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.timeGrid.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, timeGrid.context) || 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(context, el, renderProps) {
var _this = _super.call(this, context, el) || this;
_this.isSlatSizesDirty = false;
_this.isColSizesDirty = false;
_this.renderSlats = memoizeRendering(_this._renderSlats);
var eventRenderer = _this.eventRenderer = new TimeGridEventRenderer(_this);
var fillRenderer = _this.fillRenderer = new TimeGridFillRenderer(_this);
_this.mirrorRenderer = new TimeGridMirrorRenderer(_this);
var renderColumns = _this.renderColumns = memoizeRendering(_this._renderColumns, _this._unrenderColumns);
_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]);
_this.processOptions();
el.innerHTML =
'<div class="fc-bg"></div>' +
'<div class="fc-slats"></div>' +
'<hr class="fc-divider ' + _this.theme.getClass('widgetHeader') + '" style="display:none" />';
_this.rootBgContainerEl = el.querySelector('.fc-bg');
_this.slatContainerEl = el.querySelector('.fc-slats');
_this.bottomRuleEl = el.querySelector('.fc-divider');
_this.renderProps = renderProps;
return _this;
}
/* Options
------------------------------------------------------------------------------------------------------------------*/
// Parses various options into properties of this object
TimeGrid.prototype.processOptions = function () {
var slotDuration = this.opt('slotDuration');
var snapDuration = this.opt('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 = this.opt('slotLabelFormat');
if (Array.isArray(input)) {
input = input[input.length - 1];
}
this.labelFormat = createFormatter(input || {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short'
});
input = this.opt('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) {
var cells = props.cells;
this.colCnt = cells.length;
this.renderSlats(props.dateProfile);
this.renderColumns(props.cells, props.dateProfile);
this.renderBusinessHours(props.businessHourSegs);
this.renderDateSelection(props.dateSelectionSegs);
this.renderFgEvents(props.fgEventSegs);
this.renderBgEvents(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();
};
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._renderSlats = function (dateProfile) {
var theme = this.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, 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, theme = _a.theme, dateEnv = _a.dateEnv, view = _a.view;
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++) {
this.publiclyTrigger('dayRender', [
{
date: dateEnv.toDate(cells[col].date),
el: this.colEls[col],
view: view
}
]);
}
if (this.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 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 (this.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 (this.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 eventMinHeight = this.opt('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 _a = this, dateEnv = _a.dateEnv, 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(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
else {
this.fillRenderer.renderSegs('highlight', state.segs);
}
}
};
TimeGrid.prototype._unrenderEventDrag = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.mirrorRenderer.unrender(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
this.fillRenderer.unrender('highlight');
}
};
/* Event Resize Visualization
------------------------------------------------------------------------------------------------------------------*/
TimeGrid.prototype._renderEventResize = function (state) {
if (state) {
this.eventRenderer.hideByHash(state.affectedInstances);
this.mirrorRenderer.renderSegs(state.segs, { isResizing: true, sourceSeg: state.sourceSeg });
}
};
TimeGrid.prototype._unrenderEventResize = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.mirrorRenderer.unrender(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.opt('selectMirror')) {
this.mirrorRenderer.renderSegs(segs, { isSelecting: true });
}
else {
this.fillRenderer.renderSegs('highlight', segs);
}
}
};
TimeGrid.prototype._unrenderDateSelection = function (segs) {
this.mirrorRenderer.unrender(segs, { isSelecting: true });
this.fillRenderer.unrender('highlight');
};
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 TimeGridView = /** @class */ (function (_super) {
__extends(TimeGridView, _super);
function TimeGridView(context, viewSpec, dateProfileGenerator, parentEl) {
var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this;
_this.splitter = new AllDaySplitter();
/* Header Render Methods
------------------------------------------------------------------------------------------------------------------*/
// Generates the HTML that will go before the day-of week header cells
_this.renderHeadIntroHtml = function () {
var _a = _this, theme = _a.theme, dateEnv = _a.dateEnv;
var range = _this.props.dateProfile.renderRange;
var dayCnt = diffDays(range.start, range.end);
var weekText;
if (_this.opt('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
_this, { 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.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 theme = _this.theme;
return '' +
'<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '>' +
'<span>' + // needed for matchCellWidths
getAllDayHtml(_this) +
'</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>';
};
_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(_this.context, timeGridEl, {
renderBgIntroHtml: _this.renderTimeGridBgIntroHtml,
renderIntroHtml: _this.renderTimeGridIntroHtml
});
if (_this.opt('allDaySlot')) { // should we display the "all-day" area?
_this.dayGrid = new DayGrid(// the all-day subcomponent of this view
_this.context, _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;
}
return _this;
}
TimeGridView.prototype.destroy = function () {
_super.prototype.destroy.call(this);
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.
TimeGridView.prototype.renderSkeletonHtml = function () {
var theme = this.theme;
return '' +
'<table class="' + theme.getClass('tableGrid') + '">' +
(this.opt('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') + '">' +
(this.opt('allDaySlot') ?
'<div class="fc-day-grid"></div>' +
'<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" />' :
'') +
'</td>' +
'</tr>' +
'</tbody>' +
'</table>';
};
/* Now Indicator
------------------------------------------------------------------------------------------------------------------*/
TimeGridView.prototype.getNowIndicatorUnit = function () {
return this.timeGrid.getNowIndicatorUnit();
};
// subclasses should implement
// renderNowIndicator(date: DateMarker) {
// }
TimeGridView.prototype.unrenderNowIndicator = function () {
this.timeGrid.unrenderNowIndicator();
};
/* Dimensions
------------------------------------------------------------------------------------------------------------------*/
TimeGridView.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
TimeGridView.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.opt('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
TimeGridView.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
TimeGridView.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 };
};
TimeGridView.prototype.queryDateScroll = function () {
return { top: this.scroller.getScrollTop() };
};
TimeGridView.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
TimeGridView.prototype.axisStyleAttr = function () {
if (this.axisWidth != null) {
return 'style="width:' + this.axisWidth + 'px"';
}
return '';
};
return TimeGridView;
}(View));
TimeGridView.prototype.usesMinMaxTime = true; // indicates that minTime/maxTime affects rendering
var SimpleTimeGrid = /** @class */ (function (_super) {
__extends(SimpleTimeGrid, _super);
function SimpleTimeGrid(context, timeGrid) {
var _this = _super.call(this, context, timeGrid.el) || this;
_this.buildDayRanges = memoize(buildDayRanges);
_this.slicer = new TimeGridSlicer();
_this.timeGrid = timeGrid;
context.calendar.registerInteractiveComponent(_this, {
el: _this.timeGrid.el
});
return _this;
}
SimpleTimeGrid.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.calendar.unregisterInteractiveComponent(this);
};
SimpleTimeGrid.prototype.render = function (props) {
var dateProfile = props.dateProfile, dayTable = props.dayTable;
var dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, this.dateEnv);
this.timeGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, null, this.timeGrid, dayRanges), { dateProfile: dateProfile, cells: dayTable.cells[0] }));
};
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$1 = /** @class */ (function (_super) {
__extends(TimeGridView, _super);
function TimeGridView(_context, viewSpec, dateProfileGenerator, parentEl) {
var _this = _super.call(this, _context, viewSpec, dateProfileGenerator, parentEl) || this;
_this.buildDayTable = memoize(buildDayTable);
if (_this.opt('columnHeader')) {
_this.header = new DayHeader(_this.context, _this.el.querySelector('.fc-head-container'));
}
_this.simpleTimeGrid = new SimpleTimeGrid(_this.context, _this.timeGrid);
if (_this.dayGrid) {
_this.simpleDayGrid = new SimpleDayGrid(_this.context, _this.dayGrid);
}
return _this;
}
TimeGridView.prototype.destroy = function () {
_super.prototype.destroy.call(this);
if (this.header) {
this.header.destroy();
}
this.simpleTimeGrid.destroy();
if (this.simpleDayGrid) {
this.simpleDayGrid.destroy();
}
};
TimeGridView.prototype.render = function (props) {
_super.prototype.render.call(this, props); // for flags for updateSize
var dateProfile = this.props.dateProfile;
var dayTable = this.buildDayTable(dateProfile, this.dateProfileGenerator);
var splitProps = this.splitter.splitProps(props);
if (this.header) {
this.header.receiveProps({
dateProfile: dateProfile,
dates: dayTable.headerDates,
datesRepDistinctDays: true,
renderIntroHtml: this.renderHeadIntroHtml
});
}
this.simpleTimeGrid.receiveProps(__assign({}, splitProps['timed'], { dateProfile: dateProfile,
dayTable: dayTable }));
if (this.simpleDayGrid) {
this.simpleDayGrid.receiveProps(__assign({}, splitProps['allDay'], { dateProfile: dateProfile,
dayTable: dayTable, nextDayThreshold: this.nextDayThreshold, isRigid: false }));
}
};
TimeGridView.prototype.renderNowIndicator = function (date) {
this.simpleTimeGrid.renderNowIndicator(date);
};
return TimeGridView;
}(TimeGridView));
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$1,
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 { TimeGridView as AbstractTimeGridView, TimeGrid, TimeGridSlicer, TimeGridView$1 as TimeGridView, buildDayRanges, buildDayTable };
/*!
FullCalendar Time Grid Plugin v4.3.0
Docs & License: https://fullcalendar.io/
(c) 2019 Adam Shaw
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core'), require('@fullcalendar/daygrid')) :
typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core', '@fullcalendar/daygrid'], factory) :
(global = global || self, factory(global.FullCalendarTimeGrid = {}, global.FullCalendar, global.FullCalendarDayGrid));
}(this, function (exports, core, daygrid) { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* 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, timeGrid.context) || this;
_this.timeGrid = timeGrid;
_this.fullTimeFormat = core.createFormatter({
hour: 'numeric',
minute: '2-digit',
separator: _this.context.options.defaultRangeSeparator
});
return _this;
}
// 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) {
core.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 view = this.context.view;
var eventRange = seg.eventRange;
var eventDef = eventRange.def;
var eventUi = eventRange.ui;
var allDay = eventDef.allDay;
var isDraggable = view.computeEventDraggable(eventDef, eventUi);
var isResizableFromStart = seg.isStart && view.computeEventStartResizable(eventDef, eventUi);
var isResizableFromEnd = seg.isEnd && view.computeEventEndResizable(eventDef, eventUi);
var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo);
var skinCss = core.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 (core.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="' + core.htmlEscape(eventDef.url) + '"' :
'') +
(skinCss ?
' style="' + skinCss + '"' :
'') +
'>' +
'<div class="fc-content">' +
(timeText ?
'<div class="fc-time"' +
' data-start="' + core.htmlEscape(startTimeText) + '"' +
' data-full="' + core.htmlEscape(fullTimeText) + '"' +
'>' +
'<span>' + core.htmlEscape(timeText) + '</span>' +
'</div>' :
'') +
(eventDef.title ?
'<div class="fc-title">' +
core.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.view.eventOrderSpecs);
objs.sort(function (obj0, obj1) {
return core.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];
core.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.timeGrid.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;
}(core.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 = core.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, timeGrid.context) || 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;
}(core.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(context, el, renderProps) {
var _this = _super.call(this, context, el) || this;
_this.isSlatSizesDirty = false;
_this.isColSizesDirty = false;
_this.renderSlats = core.memoizeRendering(_this._renderSlats);
var eventRenderer = _this.eventRenderer = new TimeGridEventRenderer(_this);
var fillRenderer = _this.fillRenderer = new TimeGridFillRenderer(_this);
_this.mirrorRenderer = new TimeGridMirrorRenderer(_this);
var renderColumns = _this.renderColumns = core.memoizeRendering(_this._renderColumns, _this._unrenderColumns);
_this.renderBusinessHours = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'), [renderColumns]);
_this.renderDateSelection = core.memoizeRendering(_this._renderDateSelection, _this._unrenderDateSelection, [renderColumns]);
_this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderColumns]);
_this.renderBgEvents = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'), [renderColumns]);
_this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]);
_this.renderEventDrag = core.memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag, [renderColumns]);
_this.renderEventResize = core.memoizeRendering(_this._renderEventResize, _this._unrenderEventResize, [renderColumns]);
_this.processOptions();
el.innerHTML =
'<div class="fc-bg"></div>' +
'<div class="fc-slats"></div>' +
'<hr class="fc-divider ' + _this.theme.getClass('widgetHeader') + '" style="display:none" />';
_this.rootBgContainerEl = el.querySelector('.fc-bg');
_this.slatContainerEl = el.querySelector('.fc-slats');
_this.bottomRuleEl = el.querySelector('.fc-divider');
_this.renderProps = renderProps;
return _this;
}
/* Options
------------------------------------------------------------------------------------------------------------------*/
// Parses various options into properties of this object
TimeGrid.prototype.processOptions = function () {
var slotDuration = this.opt('slotDuration');
var snapDuration = this.opt('snapDuration');
var snapsPerSlot;
var input;
slotDuration = core.createDuration(slotDuration);
snapDuration = snapDuration ? core.createDuration(snapDuration) : slotDuration;
snapsPerSlot = core.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 = this.opt('slotLabelFormat');
if (Array.isArray(input)) {
input = input[input.length - 1];
}
this.labelFormat = core.createFormatter(input || {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short'
});
input = this.opt('slotLabelInterval');
this.labelInterval = input ?
core.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 = core.createDuration(AGENDA_STOCK_SUB_DURATIONS[i]);
slotsPerLabel = core.wholeDivideDurations(labelInterval, slotDuration);
if (slotsPerLabel !== null && slotsPerLabel > 1) {
return labelInterval;
}
}
return slotDuration; // fall back
};
/* Rendering
------------------------------------------------------------------------------------------------------------------*/
TimeGrid.prototype.render = function (props) {
var cells = props.cells;
this.colCnt = cells.length;
this.renderSlats(props.dateProfile);
this.renderColumns(props.cells, props.dateProfile);
this.renderBusinessHours(props.businessHourSegs);
this.renderDateSelection(props.dateSelectionSegs);
this.renderFgEvents(props.fgEventSegs);
this.renderBgEvents(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();
};
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._renderSlats = function (dateProfile) {
var theme = this.theme;
this.slatContainerEl.innerHTML =
'<table class="' + theme.getClass('tableGrid') + '">' +
this.renderSlatRowHtml(dateProfile) +
'</table>';
this.slatEls = core.findElements(this.slatContainerEl, 'tr');
this.slatPositions = new core.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, dateEnv = _a.dateEnv, theme = _a.theme, isRtl = _a.isRtl;
var html = '';
var dayStart = core.startOfDay(dateProfile.renderRange.start);
var slotTime = dateProfile.minTime;
var slotIterator = core.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 (core.asRoughMs(slotTime) < core.asRoughMs(dateProfile.maxTime)) {
slotDate = dateEnv.add(dayStart, slotTime);
isLabeled = core.wholeDivideDurations(slotIterator, this.labelInterval) !== null;
axisHtml =
'<td class="fc-axis fc-time ' + theme.getClass('widgetContent') + '">' +
(isLabeled ?
'<span>' + // for matchCellWidths
core.htmlEscape(dateEnv.format(slotDate, this.labelFormat)) +
'</span>' :
'') +
'</td>';
html +=
'<tr data-time="' + core.formatIsoTimeString(slotDate) + '"' +
(isLabeled ? '' : ' class="fc-minor"') +
'>' +
(!isRtl ? axisHtml : '') +
'<td class="' + theme.getClass('widgetContent') + '"></td>' +
(isRtl ? axisHtml : '') +
'</tr>';
slotTime = core.addDurations(slotTime, this.slotDuration);
slotIterator = core.addDurations(slotIterator, this.slotDuration);
}
return html;
};
TimeGrid.prototype._renderColumns = function (cells, dateProfile) {
var _a = this, theme = _a.theme, dateEnv = _a.dateEnv, view = _a.view;
var bgRow = new daygrid.DayBgRow(this.context);
this.rootBgContainerEl.innerHTML =
'<table class="' + theme.getClass('tableGrid') + '">' +
bgRow.renderHtml({
cells: cells,
dateProfile: dateProfile,
renderIntroHtml: this.renderProps.renderBgIntroHtml
}) +
'</table>';
this.colEls = core.findElements(this.el, '.fc-day, .fc-disabled-day');
for (var col = 0; col < this.colCnt; col++) {
this.publiclyTrigger('dayRender', [
{
date: dateEnv.toDate(cells[col].date),
el: this.colEls[col],
view: view
}
]);
}
if (this.isRtl) {
this.colEls.reverse();
}
this.colPositions = new core.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 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 (this.isRtl) {
parts.reverse();
}
skeletonEl = this.contentSkeletonEl = core.htmlToElement('<div class="fc-content-skeleton">' +
'<table>' +
'<tr>' + parts.join('') + '</tr>' +
'</table>' +
'</div>');
this.colContainerEls = core.findElements(skeletonEl, '.fc-content-col');
this.mirrorContainerEls = core.findElements(skeletonEl, '.fc-mirror-container');
this.fgContainerEls = core.findElements(skeletonEl, '.fc-event-container:not(.fc-mirror-container)');
this.bgContainerEls = core.findElements(skeletonEl, '.fc-bgevent-container');
this.highlightContainerEls = core.findElements(skeletonEl, '.fc-highlight-container');
this.businessContainerEls = core.findElements(skeletonEl, '.fc-business-container');
if (this.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 () {
core.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 = core.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 = core.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(core.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 = core.startOfDay(when);
}
return this.computeTimeTop(core.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 - core.asRoughMs(dateProfile.minTime)) / core.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 eventMinHeight = this.opt('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];
core.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 _a = this, dateEnv = _a.dateEnv, 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 = core.addDurations(this.props.dateProfile.minTime, core.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(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
else {
this.fillRenderer.renderSegs('highlight', state.segs);
}
}
};
TimeGrid.prototype._unrenderEventDrag = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.mirrorRenderer.unrender(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
this.fillRenderer.unrender('highlight');
}
};
/* Event Resize Visualization
------------------------------------------------------------------------------------------------------------------*/
TimeGrid.prototype._renderEventResize = function (state) {
if (state) {
this.eventRenderer.hideByHash(state.affectedInstances);
this.mirrorRenderer.renderSegs(state.segs, { isResizing: true, sourceSeg: state.sourceSeg });
}
};
TimeGrid.prototype._unrenderEventResize = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.mirrorRenderer.unrender(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.opt('selectMirror')) {
this.mirrorRenderer.renderSegs(segs, { isSelecting: true });
}
else {
this.fillRenderer.renderSegs('highlight', segs);
}
}
};
TimeGrid.prototype._unrenderDateSelection = function (segs) {
this.mirrorRenderer.unrender(segs, { isSelecting: true });
this.fillRenderer.unrender('highlight');
};
return TimeGrid;
}(core.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 (core.hasBgRendering(eventDef)) {
return ['timed', 'allDay'];
}
else {
return ['allDay'];
}
};
return AllDaySplitter;
}(core.Splitter));
var TIMEGRID_ALL_DAY_EVENT_LIMIT = 5;
var WEEK_HEADER_FORMAT = core.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 TimeGridView = /** @class */ (function (_super) {
__extends(TimeGridView, _super);
function TimeGridView(context, viewSpec, dateProfileGenerator, parentEl) {
var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this;
_this.splitter = new AllDaySplitter();
/* Header Render Methods
------------------------------------------------------------------------------------------------------------------*/
// Generates the HTML that will go before the day-of week header cells
_this.renderHeadIntroHtml = function () {
var _a = _this, theme = _a.theme, dateEnv = _a.dateEnv;
var range = _this.props.dateProfile.renderRange;
var dayCnt = core.diffDays(range.start, range.end);
var weekText;
if (_this.opt('weekNumbers')) {
weekText = dateEnv.format(range.start, WEEK_HEADER_FORMAT);
return '' +
'<th class="fc-axis fc-week-number ' + theme.getClass('widgetHeader') + '" ' + _this.axisStyleAttr() + '>' +
core.buildGotoAnchorHtml(// aside from link, important for matchCellWidths
_this, { date: range.start, type: 'week', forceOff: dayCnt > 1 }, core.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.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 theme = _this.theme;
return '' +
'<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '>' +
'<span>' + // needed for matchCellWidths
core.getAllDayHtml(_this) +
'</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>';
};
_this.el.classList.add('fc-timeGrid-view');
_this.el.innerHTML = _this.renderSkeletonHtml();
_this.scroller = new core.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 = core.createElement('div', { className: 'fc-time-grid' });
timeGridWrapEl.appendChild(timeGridEl);
_this.timeGrid = new TimeGrid(_this.context, timeGridEl, {
renderBgIntroHtml: _this.renderTimeGridBgIntroHtml,
renderIntroHtml: _this.renderTimeGridIntroHtml
});
if (_this.opt('allDaySlot')) { // should we display the "all-day" area?
_this.dayGrid = new daygrid.DayGrid(// the all-day subcomponent of this view
_this.context, _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;
}
return _this;
}
TimeGridView.prototype.destroy = function () {
_super.prototype.destroy.call(this);
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.
TimeGridView.prototype.renderSkeletonHtml = function () {
var theme = this.theme;
return '' +
'<table class="' + theme.getClass('tableGrid') + '">' +
(this.opt('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') + '">' +
(this.opt('allDaySlot') ?
'<div class="fc-day-grid"></div>' +
'<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" />' :
'') +
'</td>' +
'</tr>' +
'</tbody>' +
'</table>';
};
/* Now Indicator
------------------------------------------------------------------------------------------------------------------*/
TimeGridView.prototype.getNowIndicatorUnit = function () {
return this.timeGrid.getNowIndicatorUnit();
};
// subclasses should implement
// renderNowIndicator(date: DateMarker) {
// }
TimeGridView.prototype.unrenderNowIndicator = function () {
this.timeGrid.unrenderNowIndicator();
};
/* Dimensions
------------------------------------------------------------------------------------------------------------------*/
TimeGridView.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
TimeGridView.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) {
var _this = this;
var eventLimit;
var scrollerHeight;
var scrollbarWidths;
// make all axis cells line up
this.axisWidth = core.matchCellWidths(core.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 = core.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(core.uncompensateScroll);
// limit number of events in the all-day area
if (this.dayGrid) {
this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed
eventLimit = this.opt('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) {
core.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
TimeGridView.prototype.computeScrollerHeight = function (viewHeight) {
return viewHeight -
core.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
TimeGridView.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 };
};
TimeGridView.prototype.queryDateScroll = function () {
return { top: this.scroller.getScrollTop() };
};
TimeGridView.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
TimeGridView.prototype.axisStyleAttr = function () {
if (this.axisWidth != null) {
return 'style="width:' + this.axisWidth + 'px"';
}
return '';
};
return TimeGridView;
}(core.View));
TimeGridView.prototype.usesMinMaxTime = true; // indicates that minTime/maxTime affects rendering
var SimpleTimeGrid = /** @class */ (function (_super) {
__extends(SimpleTimeGrid, _super);
function SimpleTimeGrid(context, timeGrid) {
var _this = _super.call(this, context, timeGrid.el) || this;
_this.buildDayRanges = core.memoize(buildDayRanges);
_this.slicer = new TimeGridSlicer();
_this.timeGrid = timeGrid;
context.calendar.registerInteractiveComponent(_this, {
el: _this.timeGrid.el
});
return _this;
}
SimpleTimeGrid.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.calendar.unregisterInteractiveComponent(this);
};
SimpleTimeGrid.prototype.render = function (props) {
var dateProfile = props.dateProfile, dayTable = props.dayTable;
var dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, this.dateEnv);
this.timeGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, null, this.timeGrid, dayRanges), { dateProfile: dateProfile, cells: dayTable.cells[0] }));
};
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;
}(core.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 = core.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;
}(core.Slicer));
var TimeGridView$1 = /** @class */ (function (_super) {
__extends(TimeGridView, _super);
function TimeGridView(_context, viewSpec, dateProfileGenerator, parentEl) {
var _this = _super.call(this, _context, viewSpec, dateProfileGenerator, parentEl) || this;
_this.buildDayTable = core.memoize(buildDayTable);
if (_this.opt('columnHeader')) {
_this.header = new core.DayHeader(_this.context, _this.el.querySelector('.fc-head-container'));
}
_this.simpleTimeGrid = new SimpleTimeGrid(_this.context, _this.timeGrid);
if (_this.dayGrid) {
_this.simpleDayGrid = new daygrid.SimpleDayGrid(_this.context, _this.dayGrid);
}
return _this;
}
TimeGridView.prototype.destroy = function () {
_super.prototype.destroy.call(this);
if (this.header) {
this.header.destroy();
}
this.simpleTimeGrid.destroy();
if (this.simpleDayGrid) {
this.simpleDayGrid.destroy();
}
};
TimeGridView.prototype.render = function (props) {
_super.prototype.render.call(this, props); // for flags for updateSize
var dateProfile = this.props.dateProfile;
var dayTable = this.buildDayTable(dateProfile, this.dateProfileGenerator);
var splitProps = this.splitter.splitProps(props);
if (this.header) {
this.header.receiveProps({
dateProfile: dateProfile,
dates: dayTable.headerDates,
datesRepDistinctDays: true,
renderIntroHtml: this.renderHeadIntroHtml
});
}
this.simpleTimeGrid.receiveProps(__assign({}, splitProps['timed'], { dateProfile: dateProfile,
dayTable: dayTable }));
if (this.simpleDayGrid) {
this.simpleDayGrid.receiveProps(__assign({}, splitProps['allDay'], { dateProfile: dateProfile,
dayTable: dayTable, nextDayThreshold: this.nextDayThreshold, isRigid: false }));
}
};
TimeGridView.prototype.renderNowIndicator = function (date) {
this.simpleTimeGrid.renderNowIndicator(date);
};
return TimeGridView;
}(TimeGridView));
function buildDayTable(dateProfile, dateProfileGenerator) {
var daySeries = new core.DaySeries(dateProfile.renderRange, dateProfileGenerator);
return new core.DayTable(daySeries, false);
}
var main = core.createPlugin({
defaultView: 'timeGridWeek',
views: {
timeGrid: {
class: TimeGridView$1,
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 }
}
}
});
exports.AbstractTimeGridView = TimeGridView;
exports.TimeGrid = TimeGrid;
exports.TimeGridSlicer = TimeGridSlicer;
exports.TimeGridView = TimeGridView$1;
exports.buildDayRanges = buildDayRanges;
exports.buildDayTable = buildDayTable;
exports.default = main;
Object.defineProperty(exports, '__esModule', { value: true });
}));
@charset "UTF-8";.fc-timeGrid-view .fc-day-grid{position:relative;z-index:2}.fc-timeGrid-view .fc-day-grid .fc-row{min-height:3em}.fc-timeGrid-view .fc-day-grid .fc-row .fc-content-skeleton{padding-bottom:1em}.fc .fc-axis{vertical-align:middle;padding:0 4px;white-space:nowrap}.fc-ltr .fc-axis{text-align:right}.fc-rtl .fc-axis{text-align:left}.fc-time-grid,.fc-time-grid-container{position:relative;z-index:1}.fc-time-grid{min-height:100%}.fc-time-grid table{border:0 hidden transparent}.fc-time-grid>.fc-bg{z-index:1}.fc-time-grid .fc-slats,.fc-time-grid>hr{position:relative;z-index:2}.fc-time-grid .fc-content-col{position:relative}.fc-time-grid .fc-content-skeleton{position:absolute;z-index:3;top:0;left:0;right:0}.fc-time-grid .fc-business-container{position:relative;z-index:1}.fc-time-grid .fc-bgevent-container{position:relative;z-index:2}.fc-time-grid .fc-highlight-container{z-index:3;position:relative}.fc-time-grid .fc-event-container{position:relative;z-index:4}.fc-time-grid .fc-now-indicator-line{z-index:5}.fc-time-grid .fc-mirror-container{position:relative;z-index:6}.fc-time-grid .fc-slats td{height:1.5em;border-bottom:0}.fc-time-grid .fc-slats .fc-minor td{border-top-style:dotted}.fc-time-grid .fc-highlight{position:absolute;left:0;right:0}.fc-ltr .fc-time-grid .fc-event-container{margin:0 2.5% 0 2px}.fc-rtl .fc-time-grid .fc-event-container{margin:0 2px 0 2.5%}.fc-time-grid .fc-bgevent,.fc-time-grid .fc-event{position:absolute;z-index:1}.fc-time-grid .fc-bgevent{left:0;right:0}.fc-time-grid-event{margin-bottom:1px}.fc-time-grid-event-inset{-webkit-box-shadow:0 0 0 1px #fff;box-shadow:0 0 0 1px #fff}.fc-time-grid-event.fc-not-start{border-top-width:0;padding-top:1px;border-top-left-radius:0;border-top-right-radius:0}.fc-time-grid-event.fc-not-end{border-bottom-width:0;padding-bottom:1px;border-bottom-left-radius:0;border-bottom-right-radius:0}.fc-time-grid-event .fc-content{overflow:hidden;max-height:100%}.fc-time-grid-event .fc-time,.fc-time-grid-event .fc-title{padding:0 1px}.fc-time-grid-event .fc-time{font-size:.85em;white-space:nowrap}.fc-time-grid-event.fc-short .fc-content{white-space:nowrap}.fc-time-grid-event.fc-short .fc-time,.fc-time-grid-event.fc-short .fc-title{display:inline-block;vertical-align:top}.fc-time-grid-event.fc-short .fc-time span{display:none}.fc-time-grid-event.fc-short .fc-time:before{content:attr(data-start)}.fc-time-grid-event.fc-short .fc-time:after{content:" - "}.fc-time-grid-event.fc-short .fc-title{font-size:.85em;padding:0}.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer{left:0;right:0;bottom:0;height:8px;overflow:hidden;line-height:8px;font-size:11px;font-family:monospace;text-align:center;cursor:s-resize}.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer:after{content:"="}.fc-time-grid-event.fc-selected .fc-resizer{border-radius:5px;border-width:1px;width:8px;height:8px;border-style:solid;border-color:inherit;background:#fff;left:50%;margin-left:-5px;bottom:-5px}.fc-time-grid .fc-now-indicator-line{border-top-width:1px;left:0;right:0}.fc-time-grid .fc-now-indicator-arrow{margin-top:-5px}.fc-ltr .fc-time-grid .fc-now-indicator-arrow{left:0;border-width:5px 0 5px 6px;border-top-color:transparent;border-bottom-color:transparent}.fc-rtl .fc-time-grid .fc-now-indicator-arrow{right:0;border-width:5px 6px 5px 0;border-top-color:transparent;border-bottom-color:transparent}
\ No newline at end of file
/*!
FullCalendar Time Grid Plugin v4.3.0
Docs & License: https://fullcalendar.io/
(c) 2019 Adam Shaw
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@fullcalendar/core"),require("@fullcalendar/daygrid")):"function"==typeof define&&define.amd?define(["exports","@fullcalendar/core","@fullcalendar/daygrid"],t):t((e=e||self).FullCalendarTimeGrid={},e.FullCalendar,e.FullCalendarDayGrid)}(this,function(e,t,r){"use strict";var i=function(e,t){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)};function n(e,t){function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}var o=function(){return(o=Object.assign||function(e){for(var t,r=1,i=arguments.length;r<i;r++)for(var n in t=arguments[r])Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e}).apply(this,arguments)},s=function(e){function r(r){var i=e.call(this,r.context)||this;return i.timeGrid=r,i.fullTimeFormat=t.createFormatter({hour:"numeric",minute:"2-digit",separator:i.context.options.defaultRangeSeparator}),i}return n(r,e),r.prototype.attachSegs=function(e,t){for(var r=this.timeGrid.groupSegsByCol(e),i=0;i<r.length;i++)r[i]=this.sortEventSegs(r[i]);this.segsByCol=r,this.timeGrid.attachSegsByCol(r,this.timeGrid.fgContainerEls)},r.prototype.detachSegs=function(e){e.forEach(function(e){t.removeElement(e.el)}),this.segsByCol=null},r.prototype.computeSegSizes=function(e){var t=this.timeGrid,r=this.segsByCol,i=t.colCnt;if(t.computeSegVerticals(e),r)for(var n=0;n<i;n++)this.computeSegHorizontals(r[n])},r.prototype.assignSegSizes=function(e){var t=this.timeGrid,r=this.segsByCol,i=t.colCnt;if(t.assignSegVerticals(e),r)for(var n=0;n<i;n++)this.assignSegCss(r[n])},r.prototype.computeEventTimeFormat=function(){return{hour:"numeric",minute:"2-digit",meridiem:!1}},r.prototype.computeDisplayEventEnd=function(){return!0},r.prototype.renderSegHtml=function(e,r){var i,n,o,s=this.context.view,a=e.eventRange,l=a.def,d=a.ui,c=l.allDay,h=s.computeEventDraggable(l,d),u=e.isStart&&s.computeEventStartResizable(l,d),p=e.isEnd&&s.computeEventEndResizable(l,d),f=this.getSegClasses(e,h,u||p,r),g=t.cssToStr(this.getSkinCss(d));if(f.unshift("fc-time-grid-event"),t.isMultiDayRange(a.range)){if(e.isStart||e.isEnd){var m=e.start,y=e.end;i=this._getTimeText(m,y,c),n=this._getTimeText(m,y,c,this.fullTimeFormat),o=this._getTimeText(m,y,c,null,!1)}}else i=this.getTimeText(a),n=this.getTimeText(a,this.fullTimeFormat),o=this.getTimeText(a,null,!1);return'<a class="'+f.join(" ")+'"'+(l.url?' href="'+t.htmlEscape(l.url)+'"':"")+(g?' style="'+g+'"':"")+'><div class="fc-content">'+(i?'<div class="fc-time" data-start="'+t.htmlEscape(o)+'" data-full="'+t.htmlEscape(n)+'"><span>'+t.htmlEscape(i)+"</span></div>":"")+(l.title?'<div class="fc-title">'+t.htmlEscape(l.title)+"</div>":"")+"</div>"+(p?'<div class="fc-resizer fc-end-resizer"></div>':"")+"</a>"},r.prototype.computeSegHorizontals=function(e){var t,r,i;if(function(e){var t,r,i,n,o;for(t=0;t<e.length;t++)for(r=e[t],i=0;i<r.length;i++)for((n=r[i]).forwardSegs=[],o=t+1;o<e.length;o++)l(n,e[o],n.forwardSegs)}(t=function(e){var t,r,i,n=[];for(t=0;t<e.length;t++){for(r=e[t],i=0;i<n.length&&l(r,n[i]).length;i++);r.level=i,(n[i]||(n[i]=[])).push(r)}return n}(e)),r=t[0]){for(i=0;i<r.length;i++)a(r[i]);for(i=0;i<r.length;i++)this.computeSegForwardBack(r[i],0,0)}},r.prototype.computeSegForwardBack=function(e,t,r){var i,n=e.forwardSegs;if(void 0===e.forwardCoord)for(n.length?(this.sortForwardSegs(n),this.computeSegForwardBack(n[0],t+1,r),e.forwardCoord=n[0].backwardCoord):e.forwardCoord=1,e.backwardCoord=e.forwardCoord-(e.forwardCoord-r)/(t+1),i=0;i<n.length;i++)this.computeSegForwardBack(n[i],0,e.forwardCoord)},r.prototype.sortForwardSegs=function(e){var r=e.map(d),i=[{field:"forwardPressure",order:-1},{field:"backwardCoord",order:1}].concat(this.context.view.eventOrderSpecs);return r.sort(function(e,r){return t.compareByFieldSpecs(e,r,i)}),r.map(function(e){return e._seg})},r.prototype.assignSegCss=function(e){for(var r=0,i=e;r<i.length;r++){var n=i[r];t.applyStyle(n.el,this.generateSegCss(n)),n.level>0&&n.el.classList.add("fc-time-grid-event-inset"),n.eventRange.def.title&&n.bottom-n.top<30&&n.el.classList.add("fc-short")}},r.prototype.generateSegCss=function(e){var t,r,i=this.context.options.slotEventOverlap,n=e.backwardCoord,o=e.forwardCoord,s=this.timeGrid.generateSegVerticalCss(e),a=this.timeGrid.isRtl;return i&&(o=Math.min(1,n+2*(o-n))),a?(t=1-o,r=n):(t=n,r=1-o),s.zIndex=e.level+1,s.left=100*t+"%",s.right=100*r+"%",i&&e.forwardPressure&&(s[a?"marginLeft":"marginRight"]=20),s},r}(t.FgEventRenderer);function a(e){var t,r,i=e.forwardSegs,n=0;if(void 0===e.forwardPressure){for(t=0;t<i.length;t++)a(r=i[t]),n=Math.max(n,1+r.forwardPressure);e.forwardPressure=n}}function l(e,t,r){void 0===r&&(r=[]);for(var i=0;i<t.length;i++)n=e,o=t[i],n.bottom>o.top&&n.top<o.bottom&&r.push(t[i]);var n,o;return r}function d(e){var r=t.buildSegCompareObj(e);return r.forwardPressure=e.forwardPressure,r.backwardCoord=e.backwardCoord,r}var c=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return n(t,e),t.prototype.attachSegs=function(e,t){this.segsByCol=this.timeGrid.groupSegsByCol(e),this.timeGrid.attachSegsByCol(this.segsByCol,this.timeGrid.mirrorContainerEls),this.sourceSeg=t.sourceSeg},t.prototype.generateSegCss=function(t){var r=e.prototype.generateSegCss.call(this,t),i=this.sourceSeg;if(i&&i.col===t.col){var n=e.prototype.generateSegCss.call(this,i);r.left=n.left,r.right=n.right,r.marginLeft=n.marginLeft,r.marginRight=n.marginRight}return r},t}(s),h=function(e){function t(t){var r=e.call(this,t.context)||this;return r.timeGrid=t,r}return n(t,e),t.prototype.attachSegs=function(e,t){var r,i=this.timeGrid;return"bgEvent"===e?r=i.bgContainerEls:"businessHours"===e?r=i.businessContainerEls:"highlight"===e&&(r=i.highlightContainerEls),i.attachSegsByCol(i.groupSegsByCol(t),r),t.map(function(e){return e.el})},t.prototype.computeSegSizes=function(e){this.timeGrid.computeSegVerticals(e)},t.prototype.assignSegSizes=function(e){this.timeGrid.assignSegVerticals(e)},t}(t.FillRenderer),u=[{hours:1},{minutes:30},{minutes:15},{seconds:30},{seconds:15}],p=function(e){function i(r,i,n){var o=e.call(this,r,i)||this;o.isSlatSizesDirty=!1,o.isColSizesDirty=!1,o.renderSlats=t.memoizeRendering(o._renderSlats);var a=o.eventRenderer=new s(o),l=o.fillRenderer=new h(o);o.mirrorRenderer=new c(o);var d=o.renderColumns=t.memoizeRendering(o._renderColumns,o._unrenderColumns);return o.renderBusinessHours=t.memoizeRendering(l.renderSegs.bind(l,"businessHours"),l.unrender.bind(l,"businessHours"),[d]),o.renderDateSelection=t.memoizeRendering(o._renderDateSelection,o._unrenderDateSelection,[d]),o.renderFgEvents=t.memoizeRendering(a.renderSegs.bind(a),a.unrender.bind(a),[d]),o.renderBgEvents=t.memoizeRendering(l.renderSegs.bind(l,"bgEvent"),l.unrender.bind(l,"bgEvent"),[d]),o.renderEventSelection=t.memoizeRendering(a.selectByInstanceId.bind(a),a.unselectByInstanceId.bind(a),[o.renderFgEvents]),o.renderEventDrag=t.memoizeRendering(o._renderEventDrag,o._unrenderEventDrag,[d]),o.renderEventResize=t.memoizeRendering(o._renderEventResize,o._unrenderEventResize,[d]),o.processOptions(),i.innerHTML='<div class="fc-bg"></div><div class="fc-slats"></div><hr class="fc-divider '+o.theme.getClass("widgetHeader")+'" style="display:none" />',o.rootBgContainerEl=i.querySelector(".fc-bg"),o.slatContainerEl=i.querySelector(".fc-slats"),o.bottomRuleEl=i.querySelector(".fc-divider"),o.renderProps=n,o}return n(i,e),i.prototype.processOptions=function(){var e,r,i=this.opt("slotDuration"),n=this.opt("snapDuration");i=t.createDuration(i),n=n?t.createDuration(n):i,null===(e=t.wholeDivideDurations(i,n))&&(n=i,e=1),this.slotDuration=i,this.snapDuration=n,this.snapsPerSlot=e,r=this.opt("slotLabelFormat"),Array.isArray(r)&&(r=r[r.length-1]),this.labelFormat=t.createFormatter(r||{hour:"numeric",minute:"2-digit",omitZeroMinute:!0,meridiem:"short"}),r=this.opt("slotLabelInterval"),this.labelInterval=r?t.createDuration(r):this.computeLabelInterval(i)},i.prototype.computeLabelInterval=function(e){var r,i,n;for(r=u.length-1;r>=0;r--)if(i=t.createDuration(u[r]),null!==(n=t.wholeDivideDurations(i,e))&&n>1)return i;return e},i.prototype.render=function(e){var t=e.cells;this.colCnt=t.length,this.renderSlats(e.dateProfile),this.renderColumns(e.cells,e.dateProfile),this.renderBusinessHours(e.businessHourSegs),this.renderDateSelection(e.dateSelectionSegs),this.renderFgEvents(e.fgEventSegs),this.renderBgEvents(e.bgEventSegs),this.renderEventSelection(e.eventSelection),this.renderEventDrag(e.eventDrag),this.renderEventResize(e.eventResize)},i.prototype.destroy=function(){e.prototype.destroy.call(this),this.renderSlats.unrender(),this.renderColumns.unrender()},i.prototype.updateSize=function(e){var t=this.fillRenderer,r=this.eventRenderer,i=this.mirrorRenderer;(e||this.isSlatSizesDirty)&&(this.buildSlatPositions(),this.isSlatSizesDirty=!1),(e||this.isColSizesDirty)&&(this.buildColPositions(),this.isColSizesDirty=!1),t.computeSizes(e),r.computeSizes(e),i.computeSizes(e),t.assignSizes(e),r.assignSizes(e),i.assignSizes(e)},i.prototype._renderSlats=function(e){var r=this.theme;this.slatContainerEl.innerHTML='<table class="'+r.getClass("tableGrid")+'">'+this.renderSlatRowHtml(e)+"</table>",this.slatEls=t.findElements(this.slatContainerEl,"tr"),this.slatPositions=new t.PositionCache(this.el,this.slatEls,!1,!0),this.isSlatSizesDirty=!0},i.prototype.renderSlatRowHtml=function(e){for(var r,i,n,o=this.dateEnv,s=this.theme,a=this.isRtl,l="",d=t.startOfDay(e.renderRange.start),c=e.minTime,h=t.createDuration(0);t.asRoughMs(c)<t.asRoughMs(e.maxTime);)r=o.add(d,c),i=null!==t.wholeDivideDurations(h,this.labelInterval),n='<td class="fc-axis fc-time '+s.getClass("widgetContent")+'">'+(i?"<span>"+t.htmlEscape(o.format(r,this.labelFormat))+"</span>":"")+"</td>",l+='<tr data-time="'+t.formatIsoTimeString(r)+'"'+(i?"":' class="fc-minor"')+">"+(a?"":n)+'<td class="'+s.getClass("widgetContent")+'"></td>'+(a?n:"")+"</tr>",c=t.addDurations(c,this.slotDuration),h=t.addDurations(h,this.slotDuration);return l},i.prototype._renderColumns=function(e,i){var n=this.theme,o=this.dateEnv,s=this.view,a=new r.DayBgRow(this.context);this.rootBgContainerEl.innerHTML='<table class="'+n.getClass("tableGrid")+'">'+a.renderHtml({cells:e,dateProfile:i,renderIntroHtml:this.renderProps.renderBgIntroHtml})+"</table>",this.colEls=t.findElements(this.el,".fc-day, .fc-disabled-day");for(var l=0;l<this.colCnt;l++)this.publiclyTrigger("dayRender",[{date:o.toDate(e[l].date),el:this.colEls[l],view:s}]);this.isRtl&&this.colEls.reverse(),this.colPositions=new t.PositionCache(this.el,this.colEls,!0,!1),this.renderContentSkeleton(),this.isColSizesDirty=!0},i.prototype._unrenderColumns=function(){this.unrenderContentSkeleton()},i.prototype.renderContentSkeleton=function(){var e,r=[];r.push(this.renderProps.renderIntroHtml());for(var i=0;i<this.colCnt;i++)r.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>');this.isRtl&&r.reverse(),e=this.contentSkeletonEl=t.htmlToElement('<div class="fc-content-skeleton"><table><tr>'+r.join("")+"</tr></table></div>"),this.colContainerEls=t.findElements(e,".fc-content-col"),this.mirrorContainerEls=t.findElements(e,".fc-mirror-container"),this.fgContainerEls=t.findElements(e,".fc-event-container:not(.fc-mirror-container)"),this.bgContainerEls=t.findElements(e,".fc-bgevent-container"),this.highlightContainerEls=t.findElements(e,".fc-highlight-container"),this.businessContainerEls=t.findElements(e,".fc-business-container"),this.isRtl&&(this.colContainerEls.reverse(),this.mirrorContainerEls.reverse(),this.fgContainerEls.reverse(),this.bgContainerEls.reverse(),this.highlightContainerEls.reverse(),this.businessContainerEls.reverse()),this.el.appendChild(e)},i.prototype.unrenderContentSkeleton=function(){t.removeElement(this.contentSkeletonEl)},i.prototype.groupSegsByCol=function(e){var t,r=[];for(t=0;t<this.colCnt;t++)r.push([]);for(t=0;t<e.length;t++)r[e[t].col].push(e[t]);return r},i.prototype.attachSegsByCol=function(e,t){var r,i,n;for(r=0;r<this.colCnt;r++)for(i=e[r],n=0;n<i.length;n++)t[r].appendChild(i[n].el)},i.prototype.getNowIndicatorUnit=function(){return"minute"},i.prototype.renderNowIndicator=function(e,r){if(this.colContainerEls){var i,n=this.computeDateTop(r),o=[];for(i=0;i<e.length;i++){var s=t.createElement("div",{className:"fc-now-indicator fc-now-indicator-line"});s.style.top=n+"px",this.colContainerEls[e[i].col].appendChild(s),o.push(s)}if(e.length>0){var a=t.createElement("div",{className:"fc-now-indicator fc-now-indicator-arrow"});a.style.top=n+"px",this.contentSkeletonEl.appendChild(a),o.push(a)}this.nowIndicatorEls=o}},i.prototype.unrenderNowIndicator=function(){this.nowIndicatorEls&&(this.nowIndicatorEls.forEach(t.removeElement),this.nowIndicatorEls=null)},i.prototype.getTotalSlatHeight=function(){return this.slatContainerEl.getBoundingClientRect().height},i.prototype.computeDateTop=function(e,r){return r||(r=t.startOfDay(e)),this.computeTimeTop(t.createDuration(e.valueOf()-r.valueOf()))},i.prototype.computeTimeTop=function(e){var r,i,n=this.slatEls.length,o=this.props.dateProfile,s=(e.milliseconds-t.asRoughMs(o.minTime))/t.asRoughMs(this.slotDuration);return s=Math.max(0,s),s=Math.min(n,s),r=Math.floor(s),i=s-(r=Math.min(r,n-1)),this.slatPositions.tops[r]+this.slatPositions.getHeight(r)*i},i.prototype.computeSegVerticals=function(e){var t,r,i,n=this.opt("timeGridEventMinHeight");for(t=0;t<e.length;t++)r=e[t],i=this.props.cells[r.col].date,r.top=this.computeDateTop(r.start,i),r.bottom=Math.max(r.top+n,this.computeDateTop(r.end,i))},i.prototype.assignSegVerticals=function(e){var r,i;for(r=0;r<e.length;r++)i=e[r],t.applyStyle(i.el,this.generateSegVerticalCss(i))},i.prototype.generateSegVerticalCss=function(e){return{top:e.top,bottom:-e.bottom}},i.prototype.buildPositionCaches=function(){this.buildColPositions(),this.buildSlatPositions()},i.prototype.buildColPositions=function(){this.colPositions.build()},i.prototype.buildSlatPositions=function(){this.slatPositions.build()},i.prototype.positionToHit=function(e,r){var i=this.dateEnv,n=this.snapsPerSlot,o=this.slatPositions,s=this.colPositions,a=s.leftToIndex(e),l=o.topToIndex(r);if(null!=a&&null!=l){var d=o.tops[l],c=o.getHeight(l),h=(r-d)/c,u=l*n+Math.floor(h*n),p=this.props.cells[a].date,f=t.addDurations(this.props.dateProfile.minTime,t.multiplyDuration(this.snapDuration,u)),g=i.add(p,f);return{col:a,dateSpan:{range:{start:g,end:i.add(g,this.snapDuration)},allDay:!1},dayEl:this.colEls[a],relativeRect:{left:s.lefts[a],right:s.rights[a],top:d,bottom:d+c}}}},i.prototype._renderEventDrag=function(e){e&&(this.eventRenderer.hideByHash(e.affectedInstances),e.isEvent?this.mirrorRenderer.renderSegs(e.segs,{isDragging:!0,sourceSeg:e.sourceSeg}):this.fillRenderer.renderSegs("highlight",e.segs))},i.prototype._unrenderEventDrag=function(e){e&&(this.eventRenderer.showByHash(e.affectedInstances),this.mirrorRenderer.unrender(e.segs,{isDragging:!0,sourceSeg:e.sourceSeg}),this.fillRenderer.unrender("highlight"))},i.prototype._renderEventResize=function(e){e&&(this.eventRenderer.hideByHash(e.affectedInstances),this.mirrorRenderer.renderSegs(e.segs,{isResizing:!0,sourceSeg:e.sourceSeg}))},i.prototype._unrenderEventResize=function(e){e&&(this.eventRenderer.showByHash(e.affectedInstances),this.mirrorRenderer.unrender(e.segs,{isResizing:!0,sourceSeg:e.sourceSeg}))},i.prototype._renderDateSelection=function(e){e&&(this.opt("selectMirror")?this.mirrorRenderer.renderSegs(e,{isSelecting:!0}):this.fillRenderer.renderSegs("highlight",e))},i.prototype._unrenderDateSelection=function(e){this.mirrorRenderer.unrender(e,{isSelecting:!0}),this.fillRenderer.unrender("highlight")},i}(t.DateComponent),f=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return n(r,e),r.prototype.getKeyInfo=function(){return{allDay:{},timed:{}}},r.prototype.getKeysForDateSpan=function(e){return e.allDay?["allDay"]:["timed"]},r.prototype.getKeysForEventDef=function(e){return e.allDay?t.hasBgRendering(e)?["timed","allDay"]:["allDay"]:["timed"]},r}(t.Splitter),g=t.createFormatter({week:"short"}),m=function(e){function i(i,n,o,s){var a=e.call(this,i,n,o,s)||this;a.splitter=new f,a.renderHeadIntroHtml=function(){var e,r=a,i=r.theme,n=r.dateEnv,o=a.props.dateProfile.renderRange,s=t.diffDays(o.start,o.end);return a.opt("weekNumbers")?(e=n.format(o.start,g),'<th class="fc-axis fc-week-number '+i.getClass("widgetHeader")+'" '+a.axisStyleAttr()+">"+t.buildGotoAnchorHtml(a,{date:o.start,type:"week",forceOff:s>1},t.htmlEscape(e))+"</th>"):'<th class="fc-axis '+i.getClass("widgetHeader")+'" '+a.axisStyleAttr()+"></th>"},a.renderTimeGridBgIntroHtml=function(){return'<td class="fc-axis '+a.theme.getClass("widgetContent")+'" '+a.axisStyleAttr()+"></td>"},a.renderTimeGridIntroHtml=function(){return'<td class="fc-axis" '+a.axisStyleAttr()+"></td>"},a.renderDayGridBgIntroHtml=function(){return'<td class="fc-axis '+a.theme.getClass("widgetContent")+'" '+a.axisStyleAttr()+"><span>"+t.getAllDayHtml(a)+"</span></td>"},a.renderDayGridIntroHtml=function(){return'<td class="fc-axis" '+a.axisStyleAttr()+"></td>"},a.el.classList.add("fc-timeGrid-view"),a.el.innerHTML=a.renderSkeletonHtml(),a.scroller=new t.ScrollComponent("hidden","auto");var l=a.scroller.el;a.el.querySelector(".fc-body > tr > td").appendChild(l),l.classList.add("fc-time-grid-container");var d=t.createElement("div",{className:"fc-time-grid"});if(l.appendChild(d),a.timeGrid=new p(a.context,d,{renderBgIntroHtml:a.renderTimeGridBgIntroHtml,renderIntroHtml:a.renderTimeGridIntroHtml}),a.opt("allDaySlot")){a.dayGrid=new r.DayGrid(a.context,a.el.querySelector(".fc-day-grid"),{renderNumberIntroHtml:a.renderDayGridIntroHtml,renderBgIntroHtml:a.renderDayGridBgIntroHtml,renderIntroHtml:a.renderDayGridIntroHtml,colWeekNumbersVisible:!1,cellWeekNumbersVisible:!1});var c=a.el.querySelector(".fc-divider");a.dayGrid.bottomCoordPadding=c.getBoundingClientRect().height}return a}return n(i,e),i.prototype.destroy=function(){e.prototype.destroy.call(this),this.timeGrid.destroy(),this.dayGrid&&this.dayGrid.destroy(),this.scroller.destroy()},i.prototype.renderSkeletonHtml=function(){var e=this.theme;return'<table class="'+e.getClass("tableGrid")+'">'+(this.opt("columnHeader")?'<thead class="fc-head"><tr><td class="fc-head-container '+e.getClass("widgetHeader")+'">&nbsp;</td></tr></thead>':"")+'<tbody class="fc-body"><tr><td class="'+e.getClass("widgetContent")+'">'+(this.opt("allDaySlot")?'<div class="fc-day-grid"></div><hr class="fc-divider '+e.getClass("widgetHeader")+'" />':"")+"</td></tr></tbody></table>"},i.prototype.getNowIndicatorUnit=function(){return this.timeGrid.getNowIndicatorUnit()},i.prototype.unrenderNowIndicator=function(){this.timeGrid.unrenderNowIndicator()},i.prototype.updateSize=function(t,r,i){e.prototype.updateSize.call(this,t,r,i),this.timeGrid.updateSize(t),this.dayGrid&&this.dayGrid.updateSize(t)},i.prototype.updateBaseSize=function(e,r,i){var n,o,s,a=this;if(this.axisWidth=t.matchCellWidths(t.findElements(this.el,".fc-axis")),this.timeGrid.colEls){var l=t.findElements(this.el,".fc-row").filter(function(e){return!a.scroller.el.contains(e)});this.timeGrid.bottomRuleEl.style.display="none",this.scroller.clear(),l.forEach(t.uncompensateScroll),this.dayGrid&&(this.dayGrid.removeSegPopover(),(n=this.opt("eventLimit"))&&"number"!=typeof n&&(n=5),n&&this.dayGrid.limitRows(n)),i||(o=this.computeScrollerHeight(r),this.scroller.setHeight(o),((s=this.scroller.getScrollbarWidths()).left||s.right)&&(l.forEach(function(e){t.compensateScroll(e,s)}),o=this.computeScrollerHeight(r),this.scroller.setHeight(o)),this.scroller.lockOverflow(s),this.timeGrid.getTotalSlatHeight()<o&&(this.timeGrid.bottomRuleEl.style.display=""))}else i||(o=this.computeScrollerHeight(r),this.scroller.setHeight(o))},i.prototype.computeScrollerHeight=function(e){return e-t.subtractInnerElHeight(this.el,this.scroller.el)},i.prototype.computeDateScroll=function(e){var t=this.timeGrid.computeTimeTop(e);return(t=Math.ceil(t))&&t++,{top:t}},i.prototype.queryDateScroll=function(){return{top:this.scroller.getScrollTop()}},i.prototype.applyDateScroll=function(e){void 0!==e.top&&this.scroller.setScrollTop(e.top)},i.prototype.axisStyleAttr=function(){return null!=this.axisWidth?'style="width:'+this.axisWidth+'px"':""},i}(t.View);m.prototype.usesMinMaxTime=!0;var y=function(e){function r(r,i){var n=e.call(this,r,i.el)||this;return n.buildDayRanges=t.memoize(v),n.slicer=new S,n.timeGrid=i,r.calendar.registerInteractiveComponent(n,{el:n.timeGrid.el}),n}return n(r,e),r.prototype.destroy=function(){e.prototype.destroy.call(this),this.calendar.unregisterInteractiveComponent(this)},r.prototype.render=function(e){var t=e.dateProfile,r=e.dayTable,i=this.dayRanges=this.buildDayRanges(r,t,this.dateEnv);this.timeGrid.receiveProps(o({},this.slicer.sliceProps(e,t,null,this.timeGrid,i),{dateProfile:t,cells:r.cells[0]}))},r.prototype.renderNowIndicator=function(e){this.timeGrid.renderNowIndicator(this.slicer.sliceNowDate(e,this.timeGrid,this.dayRanges),e)},r.prototype.buildPositionCaches=function(){this.timeGrid.buildPositionCaches()},r.prototype.queryHit=function(e,t){var r=this.timeGrid.positionToHit(e,t);if(r)return{component:this.timeGrid,dateSpan:r.dateSpan,dayEl:r.dayEl,rect:{left:r.relativeRect.left,right:r.relativeRect.right,top:r.relativeRect.top,bottom:r.relativeRect.bottom},layer:0}},r}(t.DateComponent);function v(e,t,r){for(var i=[],n=0,o=e.headerDates;n<o.length;n++){var s=o[n];i.push({start:r.add(s,t.minTime),end:r.add(s,t.maxTime)})}return i}var S=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return n(r,e),r.prototype.sliceRange=function(e,r){for(var i=[],n=0;n<r.length;n++){var o=t.intersectRanges(e,r[n]);o&&i.push({start:o.start,end:o.end,isStart:o.start.valueOf()===e.start.valueOf(),isEnd:o.end.valueOf()===e.end.valueOf(),col:n})}return i},r}(t.Slicer),C=function(e){function i(i,n,o,s){var a=e.call(this,i,n,o,s)||this;return a.buildDayTable=t.memoize(E),a.opt("columnHeader")&&(a.header=new t.DayHeader(a.context,a.el.querySelector(".fc-head-container"))),a.simpleTimeGrid=new y(a.context,a.timeGrid),a.dayGrid&&(a.simpleDayGrid=new r.SimpleDayGrid(a.context,a.dayGrid)),a}return n(i,e),i.prototype.destroy=function(){e.prototype.destroy.call(this),this.header&&this.header.destroy(),this.simpleTimeGrid.destroy(),this.simpleDayGrid&&this.simpleDayGrid.destroy()},i.prototype.render=function(t){e.prototype.render.call(this,t);var r=this.props.dateProfile,i=this.buildDayTable(r,this.dateProfileGenerator),n=this.splitter.splitProps(t);this.header&&this.header.receiveProps({dateProfile:r,dates:i.headerDates,datesRepDistinctDays:!0,renderIntroHtml:this.renderHeadIntroHtml}),this.simpleTimeGrid.receiveProps(o({},n.timed,{dateProfile:r,dayTable:i})),this.simpleDayGrid&&this.simpleDayGrid.receiveProps(o({},n.allDay,{dateProfile:r,dayTable:i,nextDayThreshold:this.nextDayThreshold,isRigid:!1}))},i.prototype.renderNowIndicator=function(e){this.simpleTimeGrid.renderNowIndicator(e)},i}(m);function E(e,r){var i=new t.DaySeries(e.renderRange,r);return new t.DayTable(i,!1)}var b=t.createPlugin({defaultView:"timeGridWeek",views:{timeGrid:{class:C,allDaySlot:!0,slotDuration:"00:30:00",slotEventOverlap:!0},timeGridDay:{type:"timeGrid",duration:{days:1}},timeGridWeek:{type:"timeGrid",duration:{weeks:1}}}});e.AbstractTimeGridView=m,e.TimeGrid=p,e.TimeGridSlicer=S,e.TimeGridView=C,e.buildDayRanges=v,e.buildDayTable=E,e.default=b,Object.defineProperty(e,"__esModule",{value:!0})});
\ No newline at end of file
{
"name": "@fullcalendar/timegrid",
"version": "4.3.0",
"title": "FullCalendar Time Grid Plugin",
"description": "Display your events on a grid of time slots",
"keywords": [
"calendar",
"event",
"full-sized"
],
"homepage": "https://fullcalendar.io/",
"docs": "https://fullcalendar.io/docs/timegrid-view",
"bugs": "https://fullcalendar.io/reporting-bugs",
"repository": {
"type": "git",
"url": "https://github.com/fullcalendar/fullcalendar.git",
"homepage": "https://github.com/fullcalendar/fullcalendar"
},
"license": "MIT",
"author": {
"name": "Adam Shaw",
"email": "arshaw@arshaw.com",
"url": "http://arshaw.com/"
},
"copyright": "2019 Adam Shaw",
"dependencies": {
"@fullcalendar/daygrid": "~4.3.0"
},
"peerDependencies": {
"@fullcalendar/core": "~4.3.0"
},
"main": "main.js",
"module": "main.esm.js",
"unpkg": "main.min.js",
"types": "main.d.ts"
}
For complete licensing information, visit:
http://fullcalendar.io/scheduler/license
FullCalendar Scheduler is tri-licensed, meaning you must choose
one of three licenses to use. Here is a summary of those licenses:
- Commercial License
(a paid license, meant for commercial use)
http://fullcalendar.io/scheduler/license-details
- Creative Commons Non-Commercial No-Derivatives
(meant for trial and non-commercial use)
https://creativecommons.org/licenses/by-nc-nd/4.0/
- GPLv3 License
(meant for open-source projects)
http://www.gnu.org/licenses/gpl-3.0.en.html
# FullCalendar Timeline Plugin
Display events on a horizontal time axis (without resources)
[View the docs &raquo;](https://fullcalendar.io/docs/timeline-view-no-resources)
This package was created from the [FullCalendar monorepo &raquo;](https://github.com/fullcalendar/fullcalendar-scheduler)
/* Scroller
--------------------------------------------------------------------------------------------------*/
.fc-scroller-clip {
overflow: hidden;
/* for clipping scrollbars */
position: relative;
/* so things like scrollfollowers can attach to this */
}
/* supresses rendering of native scrollbars */
/* on .fc-scroller */
.fc-no-scrollbars {
background: rgba(255, 255, 255, 0);
/* hack for dynamic DOM nodes (in Chrome OSX at least) */
}
.fc-no-scrollbars::-webkit-scrollbar {
width: 0;
height: 0;
}
.fc-scroller-canvas {
position: relative;
/* origin for bg */
box-sizing: border-box;
/* so that padding (for gutter) will be part of height */
min-height: 100%;
}
.fc-scroller-canvas > .fc-bg {
z-index: 1;
/* make default? */
}
.fc-scroller-canvas > .fc-content {
z-index: 2;
/* make default? */
position: relative;
/* origin for inner content */
border-style: solid;
border-width: 0;
}
.fc-scroller-canvas.fc-gutter-left > .fc-content {
border-left-width: 1px;
margin-left: -1px;
}
.fc-scroller-canvas.fc-gutter-right > .fc-content {
border-right-width: 1px;
margin-right: -1px;
}
.fc-scroller-canvas.fc-gutter-top > .fc-content {
border-top-width: 1px;
margin-top: -1px;
}
/* content is responsible for bottom border */
/* View Structure
--------------------------------------------------------------------------------------------------*/
.fc-rtl .fc-timeline {
direction: rtl;
}
.fc-scrolled .fc-head .fc-scroller {
z-index: 2;
/* so drop shadow will go above body panes */
}
.fc-timeline.fc-scrolled .fc-head .fc-scroller {
box-shadow: 0 3px 4px rgba(0, 0, 0, 0.075);
}
.fc-timeline .fc-body .fc-scroller {
z-index: 1;
}
/*
on most tables that expand to the edges, kill the outer border,
because the container elements take care of it.
example tables:
.fc-scroller-canvas .fc-content table
.fc-scroller-canvas .fc-bg .fc-slats table
*/
.fc-timeline .fc-scroller-canvas > div > table,
.fc-timeline .fc-scroller-canvas > div > div > table {
border-style: hidden;
}
/*
for resource rows (in both the spreadsheet and timeline areas),
undo previous rule in order to always show last border.
*/
.fc-timeline .fc-scroller-canvas > .fc-content > .fc-rows > table {
border-bottom-style: none;
}
/* Table Cell Common
--------------------------------------------------------------------------------------------------*/
.fc-timeline th,
.fc-timeline td {
white-space: nowrap;
}
.fc-timeline .fc-cell-content {
overflow: hidden;
}
.fc-timeline .fc-cell-text {
display: inline-block;
padding-left: 4px;
padding-right: 4px;
}
/*
Cells at the start of a week
TODO: figure out better styling
.fc-ltr .fc-timeline .fc-em-cell div {
border-left: 3px solid #eee;
height: 100%;
}
.fc-rtl .fc-timeline .fc-em-cell {
border-right-width: 3px;
}
*/
/* head */
.fc-timeline th {
vertical-align: middle;
}
.fc-timeline .fc-head .fc-cell-content {
padding-top: 3px;
padding-bottom: 3px;
}
.fc-timeline .fc-head .fc-time-area .fc-cell-content {
overflow: visible;
}
/* Time Area
--------------------------------------------------------------------------------------------------*/
.fc-time-area col {
min-width: 2.2em;
/* detected by JS */
}
/* head */
.fc-ltr .fc-time-area .fc-chrono th {
text-align: left;
}
.fc-rtl .fc-time-area .fc-chrono th {
text-align: right;
}
/* body slats (vertical lines) */
.fc-time-area .fc-slats {
/* fc-bg is responsible for a lot of this now! */
position: absolute;
z-index: 1;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.fc-time-area .fc-slats table {
height: 100%;
}
.fc-time-area .fc-slats .fc-minor {
border-style: dotted;
}
.fc-time-area .fc-slats td {
border-width: 0 1px;
/* need to do this. sometimes -1 margin wouldn't hide the dotted */
}
.fc-ltr .fc-time-area .fc-slats td {
border-right-width: 0;
}
.fc-rtl .fc-time-area .fc-slats td {
border-left-width: 0;
}
/* body content containers
can be within rows or directly within the pane's content
*/
.fc-time-area .fc-bgevent-container,
.fc-time-area .fc-highlight-container {
position: absolute;
z-index: 2;
/* only for directly within pane. not for row. overridden later */
top: 0;
bottom: 0;
width: 0;
}
.fc-ltr .fc-time-area .fc-mirror-container,
.fc-ltr .fc-time-area .fc-bgevent-container,
.fc-ltr .fc-time-area .fc-highlight-container {
left: 0;
}
.fc-rtl .fc-time-area .fc-mirror-container,
.fc-rtl .fc-time-area .fc-bgevent-container,
.fc-rtl .fc-time-area .fc-highlight-container {
right: 0;
}
.fc-time-area .fc-bgevent,
.fc-time-area .fc-highlight {
position: absolute;
top: 0;
bottom: 0;
}
/* Now Indicator
--------------------------------------------------------------------------------------------------*/
.fc-timeline .fc-now-indicator {
/* both the arrow and the line */
z-index: 3;
/* one above scroller's fc-content */
top: 0;
}
.fc-time-area .fc-now-indicator-arrow {
margin: 0 -6px;
/* 5, then one more to counteract scroller's negative margins */
/* triangle pointing down... */
border-width: 6px 5px 0 5px;
border-left-color: transparent;
border-right-color: transparent;
}
.fc-time-area .fc-now-indicator-line {
margin: 0 -1px;
/* counteract scroller's negative margins */
bottom: 0;
border-left-width: 1px;
}
/* Event Container
--------------------------------------------------------------------------------------------------*/
.fc-time-area .fc-event-container {
position: relative;
z-index: 2;
/* above bgevent and highlight */
width: 0;
/* for event positioning. will end up on correct side based on dir */
}
.fc-time-area .fc-mirror-container {
/* also an fc-event-container */
position: absolute;
z-index: 3;
top: 0;
}
.fc-time-area .fc-event-container {
padding-bottom: 8px;
top: -1px;
}
.fc-time-area tr:first-child .fc-event-container {
top: 0;
}
.fc-no-overlap .fc-time-area .fc-event-container {
padding-bottom: 0;
top: 0;
}
/* Time Grid Events
--------------------------------------------------------------------------------------------------*/
.fc-timeline-event {
position: absolute;
display: flex;
border-radius: 0;
padding: 2px 1px;
margin-bottom: 1px;
}
.fc-no-overlap .fc-timeline-event {
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 0;
}
.fc-ltr .fc-timeline-event {
flex-direction: row;
margin-right: 1px;
}
.fc-rtl .fc-timeline-event {
margin-left: 1px;
}
.fc-timeline-event .fc-time-wrap {
flex-shrink: 0;
min-width: 0;
}
.fc-timeline-event .fc-title-wrap {
flex-grow: 1;
min-width: 0;
}
.fc-timeline-event .fc-time,
.fc-timeline-event .fc-title {
display: inline-block;
vertical-align: top;
max-width: 100%;
padding: 0 2px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
}
.fc-timeline-event .fc-time {
font-weight: bold;
}
.fc-timeline-event.fc-not-start:before,
.fc-timeline-event.fc-not-end:after {
content: "";
align-self: center;
width: 0;
height: 0;
margin: 0 1px;
border: 5px solid #000;
border-top-color: transparent;
border-bottom-color: transparent;
opacity: 0.5;
}
.fc-ltr .fc-timeline-event.fc-not-start:before,
.fc-rtl .fc-timeline-event.fc-not-end:after {
border-left: 0;
}
.fc-ltr .fc-timeline-event.fc-not-end:after,
.fc-rtl .fc-timeline-event.fc-not-start:before {
border-right: 0;
}
// Generated by dts-bundle v0.7.3-fork.1
// Dependencies for this module:
// ../../../../../@fullcalendar/core
declare module '@fullcalendar/timeline' {
import TimelineView from '@fullcalendar/timeline/TimelineView';
export { TimelineView };
export { default as TimelineLane } from '@fullcalendar/timeline/TimelineLane';
export { default as ScrollJoiner } from '@fullcalendar/timeline/util/ScrollJoiner';
export { default as StickyScroller } from '@fullcalendar/timeline/util/StickyScroller';
export { default as TimeAxis } from '@fullcalendar/timeline/TimeAxis';
export { default as HeaderBodyLayout } from '@fullcalendar/timeline/HeaderBodyLayout';
const _default: import("@fullcalendar/core").PluginDef;
export default _default;
}
declare module '@fullcalendar/timeline/TimelineView' {
import {
ComponentContext,
DateProfile,
DateProfileGenerator,
Duration,
Hit,
View,
ViewProps,
ViewSpec
} from '@fullcalendar/core';
import TimeAxis from '@fullcalendar/timeline/TimeAxis';
import TimelineLane from '@fullcalendar/timeline/TimelineLane';
export {TimelineView as default, TimelineView};
class TimelineView extends View {
timeAxis: TimeAxis;
lane: TimelineLane;
constructor(context: ComponentContext, viewSpec: ViewSpec, dateProfileGenerator: DateProfileGenerator, parentEl: HTMLElement);
destroy(): void;
renderSkeletonHtml(): string;
render(props: ViewProps): void;
updateSize(isResize: any, totalHeight: any, isAuto: any): void;
getNowIndicatorUnit(dateProfile: DateProfile): string;
renderNowIndicator(date: any): void;
unrenderNowIndicator(): void;
computeDateScroll(duration: Duration): {
left: number;
};
applyScroll(scroll: any, isResize: any): void;
applyDateScroll(scroll: any): void;
queryScroll(): {
top: number;
left: number;
};
buildPositionCaches(): void;
queryHit(positionLeft: number, positionTop: number, elWidth: number, elHeight: number): Hit;
}
}
declare module '@fullcalendar/timeline/TimelineLane' {
import {
ComponentContext,
DateComponent,
DateMarker,
DateProfile,
DateSpan,
Duration,
EventInteractionState,
EventSegUiInteractionState,
EventStore,
EventUiHash,
Seg
} from '@fullcalendar/core';
import TimeAxis from '@fullcalendar/timeline/TimeAxis';
export interface TimelineLaneSeg extends Seg {
start: DateMarker;
end: DateMarker;
}
export interface TimelineLaneProps {
dateProfile: DateProfile;
nextDayThreshold: Duration;
businessHours: EventStore | null;
eventStore: EventStore | null;
eventUiBases: EventUiHash;
dateSelection: DateSpan | null;
eventSelection: string;
eventDrag: EventInteractionState | null;
eventResize: EventInteractionState | null;
}
export { TimelineLane as default, TimelineLane };
class TimelineLane extends DateComponent<TimelineLaneProps> {
timeAxis: TimeAxis;
constructor(context: ComponentContext, fgContainerEl: HTMLElement, bgContainerEl: HTMLElement, timeAxis: TimeAxis);
render(props: TimelineLaneProps): void;
destroy(): void;
_renderEventDrag(state: EventSegUiInteractionState): void;
_unrenderEventDrag(state: EventSegUiInteractionState): void;
_renderEventResize(state: EventSegUiInteractionState): void;
_unrenderEventResize(state: EventSegUiInteractionState): void;
updateSize(isResize: boolean): void;
}
}
declare module '@fullcalendar/timeline/util/ScrollJoiner' {
import ClippedScroller from '@fullcalendar/timeline/util/ClippedScroller';
export { ScrollJoiner as default, ScrollJoiner };
class ScrollJoiner {
axis: any;
scrollers: ClippedScroller[];
masterScroller: ClippedScroller;
constructor(axis: any, scrollers: ClippedScroller[]);
initScroller(scroller: ClippedScroller): void;
assignMasterScroller(scroller: any): void;
unassignMasterScroller(): void;
update(): void;
}
}
declare module '@fullcalendar/timeline/util/StickyScroller' {
import {Point, Rect} from '@fullcalendar/core';
import EnhancedScroller from '@fullcalendar/timeline/util/EnhancedScroller';
interface ElementGeom {
parentBound: Rect;
naturalBound: Rect | null;
elWidth: number;
elHeight: number;
computedTextAlign: string;
intendedTextAlign: string;
}
export { StickyScroller as default, StickyScroller };
class StickyScroller {
scroller: EnhancedScroller;
usingRelative: boolean | null;
constructor(scroller: EnhancedScroller, isRtl: boolean, isVertical: boolean);
destroy(): void;
updateSize: () => void;
queryElGeoms(els: HTMLElement[]): ElementGeom[];
computeElDestinations(elGeoms: ElementGeom[], viewportWidth: number): Point[];
}
export {};
}
declare module '@fullcalendar/timeline/TimeAxis' {
import {Component, ComponentContext, DateMarker, DateProfile, Duration} from '@fullcalendar/core';
import HeaderBodyLayout from '@fullcalendar/timeline/HeaderBodyLayout';
import TimelineHeader from '@fullcalendar/timeline/TimelineHeader';
import TimelineSlats from '@fullcalendar/timeline/TimelineSlats';
import {TimelineDateProfile} from '@fullcalendar/timeline/timeline-date-profile';
import TimelineNowIndicator from '@fullcalendar/timeline/TimelineNowIndicator';
import StickyScroller from '@fullcalendar/timeline/util/StickyScroller';
export interface TimeAxisProps {
dateProfile: DateProfile;
}
export { TimeAxis as default, TimeAxis };
class TimeAxis extends Component<TimeAxisProps> {
layout: HeaderBodyLayout;
header: TimelineHeader;
slats: TimelineSlats;
nowIndicator: TimelineNowIndicator;
headStickyScroller: StickyScroller;
bodyStickyScroller: StickyScroller;
tDateProfile: TimelineDateProfile;
constructor(context: ComponentContext, headerContainerEl: any, bodyContainerEl: any);
destroy(): void;
render(props: TimeAxisProps): void;
getNowIndicatorUnit(dateProfile: DateProfile): string;
renderNowIndicator(date: any): void;
unrenderNowIndicator(): void;
updateSize(isResize: any, totalHeight: any, isAuto: any): void;
updateStickyScrollers(): void;
computeSlotWidth(): any;
computeDefaultSlotWidth(tDateProfile: any): number;
applySlotWidth(slotWidth: number | string): void;
computeDateSnapCoverage(date: DateMarker): number;
dateToCoord(date: any): any;
rangeToCoords(range: any): {
right: any;
left: any;
};
computeDateScroll(duration: Duration): {
left: number;
};
queryDateScroll(): {
left: number;
};
applyDateScroll(scroll: any): void;
}
}
declare module '@fullcalendar/timeline/HeaderBodyLayout' {
import ClippedScroller from '@fullcalendar/timeline/util/ClippedScroller';
import ScrollJoiner from '@fullcalendar/timeline/util/ScrollJoiner';
export { HeaderBodyLayout as default, HeaderBodyLayout };
class HeaderBodyLayout {
headerScroller: ClippedScroller;
bodyScroller: ClippedScroller;
scrollJoiner: ScrollJoiner;
constructor(headerContainerEl: any, bodyContainerEl: any, verticalScroll: any);
destroy(): void;
setHeight(totalHeight: any, isAuto: any): void;
queryHeadHeight(): number;
}
}
declare module '@fullcalendar/timeline/util/ClippedScroller' {
import {ScrollbarWidths} from '@fullcalendar/core';
import EnhancedScroller from '@fullcalendar/timeline/util/EnhancedScroller';
export { ClippedScroller as default, ClippedScroller };
class ClippedScroller {
el: HTMLElement;
enhancedScroll: EnhancedScroller;
isHScrollbarsClipped: boolean;
isVScrollbarsClipped: boolean;
constructor(overflowX: string, overflowY: string, parentEl: HTMLElement);
destroy(): void;
updateSize(): void;
setHeight(height: number | string): void;
getScrollbarWidths(): ScrollbarWidths;
}
}
declare module '@fullcalendar/timeline/util/EnhancedScroller' {
import {EmitterInterface, ScrollComponent} from '@fullcalendar/core';
import ScrollerCanvas from '@fullcalendar/timeline/util/ScrollerCanvas';
export { EnhancedScroller as default, EnhancedScroller };
class EnhancedScroller extends ScrollComponent {
on: EmitterInterface['on'];
one: EmitterInterface['one'];
off: EmitterInterface['off'];
trigger: EmitterInterface['trigger'];
triggerWith: EmitterInterface['triggerWith'];
hasHandlers: EmitterInterface['hasHandlers'];
canvas: ScrollerCanvas;
isScrolling: boolean;
isTouching: boolean;
isMoving: boolean;
isTouchScrollEnabled: boolean;
preventTouchScrollHandler: any;
requestMovingEnd: any;
constructor(overflowX: string, overflowY: string);
destroy(): void;
disableTouchScroll(): void;
enableTouchScroll(): void;
bindPreventTouchScroll(): void;
unbindPreventTouchScroll(): void;
bindHandlers(): void;
unbindHandlers(): void;
reportScroll: () => void;
reportScrollStart: () => void;
reportMovingEnd(): void;
reportScrollEnd(): void;
reportTouchStart: () => void;
reportTouchEnd: () => void;
getScrollLeft(): number;
setScrollLeft(val: any): void;
getScrollFromLeft(): number;
}
}
declare module '@fullcalendar/timeline/TimelineHeader' {
import {Component, ComponentContext, DateProfile} from '@fullcalendar/core';
import {TimelineDateProfile} from '@fullcalendar/timeline/timeline-date-profile';
export interface TimelineHeaderProps {
dateProfile: DateProfile;
tDateProfile: TimelineDateProfile;
}
export {TimelineHeader as default, TimelineHeader};
class TimelineHeader extends Component<TimelineHeaderProps> {
tableEl: HTMLElement;
slatColEls: HTMLElement[];
innerEls: HTMLElement[];
constructor(context: ComponentContext, parentEl: HTMLElement);
destroy(): void;
render(props: TimelineHeaderProps): void;
renderDates(tDateProfile: TimelineDateProfile): void;
}
}
declare module '@fullcalendar/timeline/TimelineSlats' {
import {Component, ComponentContext, DateProfile, PositionCache} from '@fullcalendar/core';
import {TimelineDateProfile} from '@fullcalendar/timeline/timeline-date-profile';
export interface TimelineSlatsProps {
dateProfile: DateProfile;
tDateProfile: TimelineDateProfile;
}
export {TimelineSlats as default, TimelineSlats};
class TimelineSlats extends Component<TimelineSlatsProps> {
el: HTMLElement;
slatColEls: HTMLElement[];
slatEls: HTMLElement[];
outerCoordCache: PositionCache;
innerCoordCache: PositionCache;
constructor(context: ComponentContext, parentEl: HTMLElement);
destroy(): void;
render(props: TimelineSlatsProps): void;
renderDates(tDateProfile: TimelineDateProfile): void;
slatCellHtml(date: any, isEm: any, tDateProfile: TimelineDateProfile): string;
updateSize(): void;
positionToHit(leftPosition: any): {
dateSpan: {
range: {
start: Date;
end: Date;
};
allDay: boolean;
};
dayEl: HTMLElement;
left: any;
right: any;
};
}
}
declare module '@fullcalendar/timeline/timeline-date-profile' {
import {DateEnv, DateMarker, DateProfile, DateRange, Duration, View} from '@fullcalendar/core';
export interface TimelineDateProfile {
labelInterval: Duration;
slotDuration: Duration;
headerFormats: any;
isTimeScale: boolean;
largeUnit: string;
emphasizeWeeks: boolean;
snapDuration: Duration;
snapsPerSlot: number;
normalizedRange: DateRange;
timeWindowMs: number;
slotDates: DateMarker[];
isWeekStarts: boolean[];
snapDiffToIndex: number[];
snapIndexToDiff: number[];
snapCnt: number;
slotCnt: number;
cellRows: TimelineHeaderCell[][];
}
export interface TimelineHeaderCell {
text: string;
spanHtml: string;
date: DateMarker;
colspan: number;
isWeekStart: boolean;
}
export function buildTimelineDateProfile(dateProfile: DateProfile, view: View): TimelineDateProfile;
export function normalizeDate(date: DateMarker, tDateProfile: TimelineDateProfile, dateEnv: DateEnv): DateMarker;
export function normalizeRange(range: DateRange, tDateProfile: TimelineDateProfile, dateEnv: DateEnv): DateRange;
export function isValidDate(date: DateMarker, tDateProfile: TimelineDateProfile, dateProfile: DateProfile, view: View): boolean;
}
declare module '@fullcalendar/timeline/TimelineNowIndicator' {
export { TimelineNowIndicator as default, TimelineNowIndicator };
class TimelineNowIndicator {
headParent: HTMLElement;
bodyParent: HTMLElement;
arrowEl: HTMLElement;
lineEl: HTMLElement;
constructor(headParent: HTMLElement, bodyParent: HTMLElement);
render(coord: number, isRtl: boolean): void;
unrender(): void;
}
}
declare module '@fullcalendar/timeline/util/ScrollerCanvas' {
export { ScrollerCanvas as default, ScrollerCanvas };
class ScrollerCanvas {
el: HTMLElement;
contentEl: HTMLElement;
bgEl: HTMLElement;
gutters: any;
width: any;
minWidth: any;
constructor();
setGutters(gutters: any): void;
setWidth(width: any): void;
setMinWidth(minWidth: any): void;
clearWidth(): void;
updateSize(): void;
}
}
/*!
FullCalendar Timeline Plugin v4.3.0
Docs & License: https://fullcalendar.io/scheduler
(c) 2019 Adam Shaw
*/
import {
addDays,
addMs,
applyStyle,
applyStyleProp,
asRoughMinutes,
asRoughMs,
asRoughSeconds,
buildGotoAnchorHtml,
Component,
computeEdges,
computeHeightAndMargins,
computeVisibleDayRange,
config,
createDuration,
createElement,
createFormatter,
createPlugin,
cssToStr,
DateComponent,
debounce,
diffWholeDays,
EmitterMixin,
FgEventRenderer,
FillRenderer,
findChildren,
findElements,
forceClassName,
getDayClasses,
greatestDurationDenominator,
htmlEscape,
htmlToElement,
intersectRanges,
isInt,
isSingleDay,
memoizeRendering,
multiplyDuration,
padStart,
PositionCache,
preventDefault,
rangeContainsMarker,
removeElement,
ScrollComponent,
Slicer,
startOfDay,
translateRect,
View,
wholeDivideDurations
} from '@fullcalendar/core';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* 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);
};
/*
A rectangular area of content that lives within a Scroller.
Can have "gutters", areas of dead spacing around the perimeter.
Also very useful for forcing a width, which a Scroller cannot do alone.
Has a content area that lives above a background area.
*/
var ScrollerCanvas = /** @class */ (function () {
function ScrollerCanvas() {
this.gutters = {};
this.el = htmlToElement("<div class=\"fc-scroller-canvas\"> <div class=\"fc-content\"></div> <div class=\"fc-bg\"></div> </div>");
this.contentEl = this.el.querySelector('.fc-content');
this.bgEl = this.el.querySelector('.fc-bg');
}
/*
If falsy, resets all the gutters to 0
*/
ScrollerCanvas.prototype.setGutters = function (gutters) {
if (!gutters) {
this.gutters = {};
}
else {
__assign(this.gutters, gutters);
}
this.updateSize();
};
ScrollerCanvas.prototype.setWidth = function (width) {
this.width = width;
this.updateSize();
};
ScrollerCanvas.prototype.setMinWidth = function (minWidth) {
this.minWidth = minWidth;
this.updateSize();
};
ScrollerCanvas.prototype.clearWidth = function () {
this.width = null;
this.minWidth = null;
this.updateSize();
};
ScrollerCanvas.prototype.updateSize = function () {
var _a = this, gutters = _a.gutters, el = _a.el;
// is border-box (width includes padding)
forceClassName(el, 'fc-gutter-left', gutters.left);
forceClassName(el, 'fc-gutter-right', gutters.right);
forceClassName(el, 'fc-gutter-top', gutters.top);
forceClassName(el, 'fc-gutter-bottom', gutters.bottom);
applyStyle(el, {
paddingLeft: gutters.left || '',
paddingRight: gutters.right || '',
paddingTop: gutters.top || '',
paddingBottom: gutters.bottom || '',
width: (this.width != null) ?
this.width + (gutters.left || 0) + (gutters.right || 0) :
'',
minWidth: (this.minWidth != null) ?
this.minWidth + (gutters.left || 0) + (gutters.right || 0) :
''
});
applyStyle(this.bgEl, {
left: gutters.left || '',
right: gutters.right || '',
top: gutters.top || '',
bottom: gutters.bottom || ''
});
};
return ScrollerCanvas;
}());
var EnhancedScroller = /** @class */ (function (_super) {
__extends(EnhancedScroller, _super);
function EnhancedScroller(overflowX, overflowY) {
var _this = _super.call(this, overflowX, overflowY) || this;
// Scroll Events
// ----------------------------------------------------------------------------------------------
_this.reportScroll = function () {
if (!_this.isScrolling) {
_this.reportScrollStart();
}
_this.trigger('scroll');
_this.isMoving = true;
_this.requestMovingEnd();
};
_this.reportScrollStart = function () {
if (!_this.isScrolling) {
_this.isScrolling = true;
_this.trigger('scrollStart', _this.isTouching); // created in constructor
}
};
// Touch Events
// ----------------------------------------------------------------------------------------------
// will fire *before* the scroll event is fired
_this.reportTouchStart = function () {
_this.isTouching = true;
};
_this.reportTouchEnd = function () {
if (_this.isTouching) {
_this.isTouching = false;
// if touch scrolling was re-enabled during a recent touch scroll
// then unbind the handlers that are preventing it from happening.
if (_this.isTouchScrollEnabled) {
_this.unbindPreventTouchScroll(); // won't do anything if not bound
}
// if the user ended their touch, and the scroll area wasn't moving,
// we consider this to be the end of the scroll.
if (!_this.isMoving) {
_this.reportScrollEnd(); // won't fire if already ended
}
}
};
_this.isScrolling = false;
_this.isTouching = false;
_this.isMoving = false;
_this.isTouchScrollEnabled = true;
_this.requestMovingEnd = debounce(_this.reportMovingEnd, 500);
_this.canvas = new ScrollerCanvas();
_this.el.appendChild(_this.canvas.el);
_this.applyOverflow();
_this.bindHandlers();
return _this;
}
EnhancedScroller.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.unbindHandlers();
};
// Touch scroll prevention
// ----------------------------------------------------------------------------------------------
EnhancedScroller.prototype.disableTouchScroll = function () {
this.isTouchScrollEnabled = false;
this.bindPreventTouchScroll(); // will be unbound in enableTouchScroll or reportTouchEnd
};
EnhancedScroller.prototype.enableTouchScroll = function () {
this.isTouchScrollEnabled = true;
// only immediately unbind if a touch event is NOT in progress.
// otherwise, it will be handled by reportTouchEnd.
if (!this.isTouching) {
this.unbindPreventTouchScroll();
}
};
EnhancedScroller.prototype.bindPreventTouchScroll = function () {
if (!this.preventTouchScrollHandler) {
this.el.addEventListener('touchmove', (this.preventTouchScrollHandler = preventDefault));
}
};
EnhancedScroller.prototype.unbindPreventTouchScroll = function () {
if (this.preventTouchScrollHandler) {
this.el.removeEventListener('touchmove', this.preventTouchScrollHandler);
this.preventTouchScrollHandler = null;
}
};
// Handlers
// ----------------------------------------------------------------------------------------------
EnhancedScroller.prototype.bindHandlers = function () {
this.el.addEventListener('scroll', this.reportScroll);
this.el.addEventListener('touchstart', this.reportTouchStart, { passive: true });
this.el.addEventListener('touchend', this.reportTouchEnd);
};
EnhancedScroller.prototype.unbindHandlers = function () {
this.el.removeEventListener('scroll', this.reportScroll);
this.el.removeEventListener('touchstart', this.reportTouchStart, { passive: true });
this.el.removeEventListener('touchend', this.reportTouchEnd);
};
EnhancedScroller.prototype.reportMovingEnd = function () {
this.isMoving = false;
// only end the scroll if not currently touching.
// if touching, the scrolling will end later, on touchend.
if (!this.isTouching) {
this.reportScrollEnd();
}
};
EnhancedScroller.prototype.reportScrollEnd = function () {
if (this.isScrolling) {
this.trigger('scrollEnd');
this.isScrolling = false;
}
};
// Horizontal Scroll Normalization
// ----------------------------------------------------------------------------------------------
// http://stackoverflow.com/questions/24276619/better-way-to-get-the-viewport-of-a-scrollable-div-in-rtl-mode/24394376#24394376
// TODO: move all this to util functions
/*
If RTL, and scrolled to the left, returns NEGATIVE value (like Firefox)
*/
EnhancedScroller.prototype.getScrollLeft = function () {
var el = this.el;
var direction = window.getComputedStyle(el).direction;
var val = el.scrollLeft;
if (direction === 'rtl') {
switch (getRtlScrollSystem()) {
case 'positive':
val = (val + el.clientWidth) - el.scrollWidth;
break;
case 'reverse':
val = -val;
break;
}
}
return val;
};
/*
Accepts a NEGATIVE value for when scrolled in RTL
*/
EnhancedScroller.prototype.setScrollLeft = function (val) {
var el = this.el;
var direction = window.getComputedStyle(el).direction;
if (direction === 'rtl') {
switch (getRtlScrollSystem()) {
case 'positive':
val = (val - el.clientWidth) + el.scrollWidth;
break;
case 'reverse':
val = -val;
break;
}
}
el.scrollLeft = val;
};
/*
Always returns the number of pixels scrolled from the leftmost position (even if RTL).
Always positive.
*/
EnhancedScroller.prototype.getScrollFromLeft = function () {
var el = this.el;
var direction = window.getComputedStyle(el).direction;
var val = el.scrollLeft;
if (direction === 'rtl') {
switch (getRtlScrollSystem()) {
case 'negative':
val = (val - el.clientWidth) + el.scrollWidth;
break;
case 'reverse':
val = (-val - el.clientWidth) + el.scrollWidth;
break;
}
}
return val;
};
return EnhancedScroller;
}(ScrollComponent));
EmitterMixin.mixInto(EnhancedScroller);
// Horizontal Scroll System Detection
// ----------------------------------------------------------------------------------------------
var _rtlScrollSystem;
function getRtlScrollSystem() {
return _rtlScrollSystem || (_rtlScrollSystem = detectRtlScrollSystem());
}
function detectRtlScrollSystem() {
var el = htmlToElement("<div style=\" position: absolute; top: -1000px; width: 1px; height: 1px; overflow: scroll; direction: rtl; font-size: 100px; \">A</div>");
document.body.appendChild(el);
var system;
if (el.scrollLeft > 0) {
system = 'positive';
}
else {
el.scrollLeft = 1;
if (el.scrollLeft > 0) {
system = 'reverse';
}
else {
system = 'negative';
}
}
removeElement(el);
return system;
}
/*
A Scroller, but with a wrapping div that allows "clipping" away of native scrollbars,
giving the appearance that there are no scrollbars.
*/
var ClippedScroller = /** @class */ (function () {
/*
Received overflows can be set to 'clipped', meaning scrollbars shouldn't be visible
to the user, but the area should still scroll.
*/
function ClippedScroller(overflowX, overflowY, parentEl) {
this.isHScrollbarsClipped = false;
this.isVScrollbarsClipped = false;
if (overflowX === 'clipped-scroll') {
overflowX = 'scroll';
this.isHScrollbarsClipped = true;
}
if (overflowY === 'clipped-scroll') {
overflowY = 'scroll';
this.isVScrollbarsClipped = true;
}
this.enhancedScroll = new EnhancedScroller(overflowX, overflowY);
parentEl.appendChild(this.el = createElement('div', {
className: 'fc-scroller-clip'
}));
this.el.appendChild(this.enhancedScroll.el);
}
ClippedScroller.prototype.destroy = function () {
removeElement(this.el);
};
ClippedScroller.prototype.updateSize = function () {
var enhancedScroll = this.enhancedScroll;
var scrollEl = enhancedScroll.el;
var edges = computeEdges(scrollEl);
var cssProps = { marginLeft: 0, marginRight: 0, marginTop: 0, marginBottom: 0 };
// give the inner scrolling div negative margins so that its scrollbars
// are nudged outside of the bounding box of the wrapper, which is overflow:hidden
if (this.isVScrollbarsClipped) {
cssProps.marginLeft = -edges.scrollbarLeft;
cssProps.marginRight = -edges.scrollbarRight;
}
if (this.isHScrollbarsClipped) {
cssProps.marginBottom = -edges.scrollbarBottom;
}
applyStyle(scrollEl, cssProps);
// if we are attempting to hide the scrollbars offscreen, OSX/iOS will still
// display the floating scrollbars. attach a className to force-hide them.
if ((this.isHScrollbarsClipped || (enhancedScroll.overflowX === 'hidden')) && // should never show?
(this.isVScrollbarsClipped || (enhancedScroll.overflowY === 'hidden')) && // should never show?
!( // doesn't have any scrollbar mass
edges.scrollbarLeft ||
edges.scrollbarRight ||
edges.scrollbarBottom)) {
scrollEl.classList.add('fc-no-scrollbars');
}
else {
scrollEl.classList.remove('fc-no-scrollbars');
}
};
ClippedScroller.prototype.setHeight = function (height) {
this.enhancedScroll.setHeight(height);
};
/*
Accounts for 'clipped' scrollbars
*/
ClippedScroller.prototype.getScrollbarWidths = function () {
var widths = this.enhancedScroll.getScrollbarWidths();
if (this.isVScrollbarsClipped) {
widths.left = 0;
widths.right = 0;
}
if (this.isHScrollbarsClipped) {
widths.bottom = 0;
}
return widths;
};
return ClippedScroller;
}());
var ScrollJoiner = /** @class */ (function () {
function ScrollJoiner(axis, scrollers) {
this.axis = axis;
this.scrollers = scrollers;
for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
var scroller = _a[_i];
this.initScroller(scroller);
}
}
ScrollJoiner.prototype.initScroller = function (scroller) {
var _this = this;
var enhancedScroll = scroller.enhancedScroll;
// when the user scrolls via mousewheel, we know for sure the target
// scroller should be the master. capture the various x-browser events that fire.
var onScroll = function () {
_this.assignMasterScroller(scroller);
};
'wheel mousewheel DomMouseScroll MozMousePixelScroll'.split(' ').forEach(function (evName) {
enhancedScroll.el.addEventListener(evName, onScroll);
});
enhancedScroll
.on('scrollStart', function () {
if (!_this.masterScroller) {
_this.assignMasterScroller(scroller);
}
})
.on('scroll', function () {
if (scroller === _this.masterScroller) {
for (var _i = 0, _a = _this.scrollers; _i < _a.length; _i++) {
var otherScroller = _a[_i];
if (otherScroller !== scroller) {
switch (_this.axis) {
case 'horizontal':
otherScroller.enhancedScroll.el.scrollLeft = enhancedScroll.el.scrollLeft;
break;
case 'vertical':
otherScroller.enhancedScroll.setScrollTop(enhancedScroll.getScrollTop());
break;
}
}
}
}
})
.on('scrollEnd', function () {
if (scroller === _this.masterScroller) {
_this.unassignMasterScroller();
}
});
};
ScrollJoiner.prototype.assignMasterScroller = function (scroller) {
this.unassignMasterScroller();
this.masterScroller = scroller;
for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
var otherScroller = _a[_i];
if (otherScroller !== scroller) {
otherScroller.enhancedScroll.disableTouchScroll();
}
}
};
ScrollJoiner.prototype.unassignMasterScroller = function () {
if (this.masterScroller) {
for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
var otherScroller = _a[_i];
otherScroller.enhancedScroll.enableTouchScroll();
}
this.masterScroller = null;
}
};
ScrollJoiner.prototype.update = function () {
var allWidths = this.scrollers.map(function (scroller) { return scroller.getScrollbarWidths(); });
var maxLeft = 0;
var maxRight = 0;
var maxTop = 0;
var maxBottom = 0;
var widths;
var i;
for (var _i = 0, allWidths_1 = allWidths; _i < allWidths_1.length; _i++) {
widths = allWidths_1[_i];
maxLeft = Math.max(maxLeft, widths.left);
maxRight = Math.max(maxRight, widths.right);
maxTop = Math.max(maxTop, widths.top);
maxBottom = Math.max(maxBottom, widths.bottom);
}
for (i = 0; i < this.scrollers.length; i++) {
var scroller = this.scrollers[i];
widths = allWidths[i];
scroller.enhancedScroll.canvas.setGutters(this.axis === 'horizontal' ?
{
left: maxLeft - widths.left,
right: maxRight - widths.right
} :
{
top: maxTop - widths.top,
bottom: maxBottom - widths.bottom
});
}
};
return ScrollJoiner;
}());
var HeaderBodyLayout = /** @class */ (function () {
/*
verticalScroll = 'auto' | 'clipped-scroll'
*/
function HeaderBodyLayout(headerContainerEl, bodyContainerEl, verticalScroll) {
this.headerScroller = new ClippedScroller('clipped-scroll', 'hidden', headerContainerEl);
this.bodyScroller = new ClippedScroller('auto', verticalScroll, bodyContainerEl);
this.scrollJoiner = new ScrollJoiner('horizontal', [
this.headerScroller,
this.bodyScroller
]);
}
HeaderBodyLayout.prototype.destroy = function () {
this.headerScroller.destroy();
this.bodyScroller.destroy();
};
HeaderBodyLayout.prototype.setHeight = function (totalHeight, isAuto) {
var bodyHeight;
if (isAuto) {
bodyHeight = 'auto';
}
else {
bodyHeight = totalHeight - this.queryHeadHeight();
}
this.bodyScroller.setHeight(bodyHeight);
this.headerScroller.updateSize(); // adjusts gutters and classNames
this.bodyScroller.updateSize(); // adjusts gutters and classNames
this.scrollJoiner.update();
};
HeaderBodyLayout.prototype.queryHeadHeight = function () {
return this.headerScroller.enhancedScroll.canvas.contentEl.getBoundingClientRect().height;
};
return HeaderBodyLayout;
}());
var TimelineHeader = /** @class */ (function (_super) {
__extends(TimelineHeader, _super);
function TimelineHeader(context, parentEl) {
var _this = _super.call(this, context) || this;
parentEl.appendChild(_this.tableEl = createElement('table', {
className: _this.theme.getClass('tableGrid')
}));
return _this;
}
TimelineHeader.prototype.destroy = function () {
removeElement(this.tableEl);
_super.prototype.destroy.call(this);
};
TimelineHeader.prototype.render = function (props) {
this.renderDates(props.tDateProfile);
};
TimelineHeader.prototype.renderDates = function (tDateProfile) {
var _a = this, dateEnv = _a.dateEnv, theme = _a.theme;
var cellRows = tDateProfile.cellRows;
var lastRow = cellRows[cellRows.length - 1];
var isChrono = asRoughMs(tDateProfile.labelInterval) > asRoughMs(tDateProfile.slotDuration);
var oneDay = isSingleDay(tDateProfile.slotDuration);
var html = '<colgroup>';
// needs to be a col for each body slat. header cells will have colspans
for (var i = tDateProfile.slotCnt - 1; i >= 0; i--) {
html += '<col/>';
}
html += '</colgroup>';
html += '<tbody>';
for (var _i = 0, cellRows_1 = cellRows; _i < cellRows_1.length; _i++) {
var rowCells = cellRows_1[_i];
var isLast = rowCells === lastRow;
html += '<tr' + (isChrono && isLast ? ' class="fc-chrono"' : '') + '>';
for (var _b = 0, rowCells_1 = rowCells; _b < rowCells_1.length; _b++) {
var cell = rowCells_1[_b];
var headerCellClassNames = [theme.getClass('widgetHeader')];
if (cell.isWeekStart) {
headerCellClassNames.push('fc-em-cell');
}
if (oneDay) {
headerCellClassNames = headerCellClassNames.concat(getDayClasses(cell.date, this.props.dateProfile, this.context, true) // adds "today" class and other day-based classes
);
}
html +=
'<th class="' + headerCellClassNames.join(' ') + '"' +
' data-date="' + dateEnv.formatIso(cell.date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }) + '"' +
(cell.colspan > 1 ? ' colspan="' + cell.colspan + '"' : '') +
'>' +
'<div class="fc-cell-content">' +
cell.spanHtml +
'</div>' +
'</th>';
}
html += '</tr>';
}
html += '</tbody>';
this.tableEl.innerHTML = html; // TODO: does this work cross-browser?
this.slatColEls = findElements(this.tableEl, 'col');
this.innerEls = findElements(this.tableEl.querySelector('tr:last-child'), // compound selector won't work because of query-root problem
'th .fc-cell-text');
findElements(this.tableEl.querySelectorAll('tr:not(:last-child)'), // compound selector won't work because of query-root problem
'th .fc-cell-text').forEach(function (innerEl) {
innerEl.classList.add('fc-sticky');
});
};
return TimelineHeader;
}(Component));
var TimelineSlats = /** @class */ (function (_super) {
__extends(TimelineSlats, _super);
function TimelineSlats(context, parentEl) {
var _this = _super.call(this, context) || this;
parentEl.appendChild(_this.el = createElement('div', { className: 'fc-slats' }));
return _this;
}
TimelineSlats.prototype.destroy = function () {
removeElement(this.el);
_super.prototype.destroy.call(this);
};
TimelineSlats.prototype.render = function (props) {
this.renderDates(props.tDateProfile);
};
TimelineSlats.prototype.renderDates = function (tDateProfile) {
var _a = this, theme = _a.theme, view = _a.view, dateEnv = _a.dateEnv;
var slotDates = tDateProfile.slotDates, isWeekStarts = tDateProfile.isWeekStarts;
var html = '<table class="' + theme.getClass('tableGrid') + '">' +
'<colgroup>';
for (var i = 0; i < slotDates.length; i++) {
html += '<col/>';
}
html += '</colgroup>';
html += '<tbody><tr>';
for (var i = 0; i < slotDates.length; i++) {
html += this.slatCellHtml(slotDates[i], isWeekStarts[i], tDateProfile);
}
html += '</tr></tbody></table>';
this.el.innerHTML = html;
this.slatColEls = findElements(this.el, 'col');
this.slatEls = findElements(this.el, 'td');
for (var i = 0; i < slotDates.length; i++) {
view.publiclyTrigger('dayRender', [
{
date: dateEnv.toDate(slotDates[i]),
el: this.slatEls[i],
view: view
}
]);
}
this.outerCoordCache = new PositionCache(this.el, this.slatEls, true, // isHorizontal
false // isVertical
);
// for the inner divs within the slats
// used for event rendering and scrollTime, to disregard slat border
this.innerCoordCache = new PositionCache(this.el, findChildren(this.slatEls, 'div'), true, // isHorizontal
false // isVertical
);
};
TimelineSlats.prototype.slatCellHtml = function (date, isEm, tDateProfile) {
var _a = this, theme = _a.theme, dateEnv = _a.dateEnv;
var classes;
if (tDateProfile.isTimeScale) {
classes = [];
classes.push(isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval)) ?
'fc-major' :
'fc-minor');
}
else {
classes = getDayClasses(date, this.props.dateProfile, this.context);
classes.push('fc-day');
}
classes.unshift(theme.getClass('widgetContent'));
if (isEm) {
classes.push('fc-em-cell');
}
return '<td class="' + classes.join(' ') + '"' +
' data-date="' + dateEnv.formatIso(date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }) + '"' +
'><div></div></td>';
};
TimelineSlats.prototype.updateSize = function () {
this.outerCoordCache.build();
this.innerCoordCache.build();
};
TimelineSlats.prototype.positionToHit = function (leftPosition) {
var outerCoordCache = this.outerCoordCache;
var tDateProfile = this.props.tDateProfile;
var slatIndex = outerCoordCache.leftToIndex(leftPosition);
if (slatIndex != null) {
// somewhat similar to what TimeGrid does. consolidate?
var slatWidth = outerCoordCache.getWidth(slatIndex);
var partial = this.isRtl ?
(outerCoordCache.rights[slatIndex] - leftPosition) / slatWidth :
(leftPosition - outerCoordCache.lefts[slatIndex]) / slatWidth;
var localSnapIndex = Math.floor(partial * tDateProfile.snapsPerSlot);
var start = this.dateEnv.add(tDateProfile.slotDates[slatIndex], multiplyDuration(tDateProfile.snapDuration, localSnapIndex));
var end = this.dateEnv.add(start, tDateProfile.snapDuration);
return {
dateSpan: {
range: { start: start, end: end },
allDay: !this.props.tDateProfile.isTimeScale
},
dayEl: this.slatColEls[slatIndex],
left: outerCoordCache.lefts[slatIndex],
right: outerCoordCache.rights[slatIndex]
};
}
return null;
};
return TimelineSlats;
}(Component));
var MIN_AUTO_LABELS = 18; // more than `12` months but less that `24` hours
var MAX_AUTO_SLOTS_PER_LABEL = 6; // allows 6 10-min slots in an hour
var MAX_AUTO_CELLS = 200; // allows 4-days to have a :30 slot duration
config.MAX_TIMELINE_SLOTS = 1000;
// potential nice values for slot-duration and interval-duration
var STOCK_SUB_DURATIONS = [
{ years: 1 },
{ months: 1 },
{ days: 1 },
{ hours: 1 },
{ minutes: 30 },
{ minutes: 15 },
{ minutes: 10 },
{ minutes: 5 },
{ minutes: 1 },
{ seconds: 30 },
{ seconds: 15 },
{ seconds: 10 },
{ seconds: 5 },
{ seconds: 1 },
{ milliseconds: 500 },
{ milliseconds: 100 },
{ milliseconds: 10 },
{ milliseconds: 1 }
];
function buildTimelineDateProfile(dateProfile, view) {
var dateEnv = view.dateEnv;
var tDateProfile = {
labelInterval: queryDurationOption(view, 'slotLabelInterval'),
slotDuration: queryDurationOption(view, 'slotDuration')
};
validateLabelAndSlot(tDateProfile, dateProfile, dateEnv); // validate after computed grid duration
ensureLabelInterval(tDateProfile, dateProfile, dateEnv);
ensureSlotDuration(tDateProfile, dateProfile, dateEnv);
var input = view.opt('slotLabelFormat');
var rawFormats = Array.isArray(input) ?
input
: (input != null) ?
[input]
:
computeHeaderFormats(tDateProfile, dateProfile, dateEnv, view);
tDateProfile.headerFormats = rawFormats.map(function (rawFormat) {
return createFormatter(rawFormat);
});
tDateProfile.isTimeScale = Boolean(tDateProfile.slotDuration.milliseconds);
var largeUnit = null;
if (!tDateProfile.isTimeScale) {
var slotUnit = greatestDurationDenominator(tDateProfile.slotDuration).unit;
if (/year|month|week/.test(slotUnit)) {
largeUnit = slotUnit;
}
}
tDateProfile.largeUnit = largeUnit;
tDateProfile.emphasizeWeeks =
isSingleDay(tDateProfile.slotDuration) &&
currentRangeAs('weeks', dateProfile, dateEnv) >= 2 &&
!view.opt('businessHours');
/*
console.log('label interval =', timelineView.labelInterval.humanize())
console.log('slot duration =', timelineView.slotDuration.humanize())
console.log('header formats =', timelineView.headerFormats)
console.log('isTimeScale', timelineView.isTimeScale)
console.log('largeUnit', timelineView.largeUnit)
*/
var rawSnapDuration = view.opt('snapDuration');
var snapDuration;
var snapsPerSlot;
if (rawSnapDuration) {
snapDuration = createDuration(rawSnapDuration);
snapsPerSlot = wholeDivideDurations(tDateProfile.slotDuration, snapDuration);
// ^ TODO: warning if not whole?
}
if (snapsPerSlot == null) {
snapDuration = tDateProfile.slotDuration;
snapsPerSlot = 1;
}
tDateProfile.snapDuration = snapDuration;
tDateProfile.snapsPerSlot = snapsPerSlot;
// more...
var timeWindowMs = asRoughMs(dateProfile.maxTime) - asRoughMs(dateProfile.minTime);
// TODO: why not use normalizeRange!?
var normalizedStart = normalizeDate(dateProfile.renderRange.start, tDateProfile, dateEnv);
var normalizedEnd = normalizeDate(dateProfile.renderRange.end, tDateProfile, dateEnv);
// apply minTime/maxTime
// TODO: View should be responsible.
if (tDateProfile.isTimeScale) {
normalizedStart = dateEnv.add(normalizedStart, dateProfile.minTime);
normalizedEnd = dateEnv.add(addDays(normalizedEnd, -1), dateProfile.maxTime);
}
tDateProfile.timeWindowMs = timeWindowMs;
tDateProfile.normalizedRange = { start: normalizedStart, end: normalizedEnd };
var slotDates = [];
var date = normalizedStart;
while (date < normalizedEnd) {
if (isValidDate(date, tDateProfile, dateProfile, view)) {
slotDates.push(date);
}
date = dateEnv.add(date, tDateProfile.slotDuration);
}
tDateProfile.slotDates = slotDates;
// more...
var snapIndex = -1;
var snapDiff = 0; // index of the diff :(
var snapDiffToIndex = [];
var snapIndexToDiff = [];
date = normalizedStart;
while (date < normalizedEnd) {
if (isValidDate(date, tDateProfile, dateProfile, view)) {
snapIndex++;
snapDiffToIndex.push(snapIndex);
snapIndexToDiff.push(snapDiff);
}
else {
snapDiffToIndex.push(snapIndex + 0.5);
}
date = dateEnv.add(date, tDateProfile.snapDuration);
snapDiff++;
}
tDateProfile.snapDiffToIndex = snapDiffToIndex;
tDateProfile.snapIndexToDiff = snapIndexToDiff;
tDateProfile.snapCnt = snapIndex + 1; // is always one behind
tDateProfile.slotCnt = tDateProfile.snapCnt / tDateProfile.snapsPerSlot;
// more...
tDateProfile.isWeekStarts = buildIsWeekStarts(tDateProfile, dateEnv);
tDateProfile.cellRows = buildCellRows(tDateProfile, dateEnv, view);
return tDateProfile;
}
/*
snaps to appropriate unit
*/
function normalizeDate(date, tDateProfile, dateEnv) {
var normalDate = date;
if (!tDateProfile.isTimeScale) {
normalDate = startOfDay(normalDate);
if (tDateProfile.largeUnit) {
normalDate = dateEnv.startOf(normalDate, tDateProfile.largeUnit);
}
}
return normalDate;
}
/*
snaps to appropriate unit
*/
function normalizeRange(range, tDateProfile, dateEnv) {
if (!tDateProfile.isTimeScale) {
range = computeVisibleDayRange(range);
if (tDateProfile.largeUnit) {
var dayRange = range; // preserve original result
range = {
start: dateEnv.startOf(range.start, tDateProfile.largeUnit),
end: dateEnv.startOf(range.end, tDateProfile.largeUnit)
};
// if date is partially through the interval, or is in the same interval as the start,
// make the exclusive end be the *next* interval
if (range.end.valueOf() !== dayRange.end.valueOf() || range.end <= range.start) {
range = {
start: range.start,
end: dateEnv.add(range.end, tDateProfile.slotDuration)
};
}
}
}
return range;
}
function isValidDate(date, tDateProfile, dateProfile, view) {
if (view.dateProfileGenerator.isHiddenDay(date)) {
return false;
}
else if (tDateProfile.isTimeScale) {
// determine if the time is within minTime/maxTime, which may have wacky values
var day = startOfDay(date);
var timeMs = date.valueOf() - day.valueOf();
var ms = timeMs - asRoughMs(dateProfile.minTime); // milliseconds since minTime
ms = ((ms % 86400000) + 86400000) % 86400000; // make negative values wrap to 24hr clock
return ms < tDateProfile.timeWindowMs; // before the maxTime?
}
else {
return true;
}
}
function queryDurationOption(view, name) {
var input = view.opt(name);
if (input != null) {
return createDuration(input);
}
}
function validateLabelAndSlot(tDateProfile, dateProfile, dateEnv) {
var currentRange = dateProfile.currentRange;
// make sure labelInterval doesn't exceed the max number of cells
if (tDateProfile.labelInterval) {
var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.labelInterval);
if (labelCnt > config.MAX_TIMELINE_SLOTS) {
console.warn('slotLabelInterval results in too many cells');
tDateProfile.labelInterval = null;
}
}
// make sure slotDuration doesn't exceed the maximum number of cells
if (tDateProfile.slotDuration) {
var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.slotDuration);
if (slotCnt > config.MAX_TIMELINE_SLOTS) {
console.warn('slotDuration results in too many cells');
tDateProfile.slotDuration = null;
}
}
// make sure labelInterval is a multiple of slotDuration
if (tDateProfile.labelInterval && tDateProfile.slotDuration) {
var slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
if (slotsPerLabel === null || slotsPerLabel < 1) {
console.warn('slotLabelInterval must be a multiple of slotDuration');
tDateProfile.slotDuration = null;
}
}
}
function ensureLabelInterval(tDateProfile, dateProfile, dateEnv) {
var currentRange = dateProfile.currentRange;
var labelInterval = tDateProfile.labelInterval;
if (!labelInterval) {
// compute based off the slot duration
// find the largest label interval with an acceptable slots-per-label
var input = void 0;
if (tDateProfile.slotDuration) {
for (var _i = 0, STOCK_SUB_DURATIONS_1 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_1.length; _i++) {
input = STOCK_SUB_DURATIONS_1[_i];
var tryLabelInterval = createDuration(input);
var slotsPerLabel = wholeDivideDurations(tryLabelInterval, tDateProfile.slotDuration);
if (slotsPerLabel !== null && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
labelInterval = tryLabelInterval;
break;
}
}
// use the slot duration as a last resort
if (!labelInterval) {
labelInterval = tDateProfile.slotDuration;
}
// compute based off the view's duration
// find the largest label interval that yields the minimum number of labels
}
else {
for (var _a = 0, STOCK_SUB_DURATIONS_2 = STOCK_SUB_DURATIONS; _a < STOCK_SUB_DURATIONS_2.length; _a++) {
input = STOCK_SUB_DURATIONS_2[_a];
labelInterval = createDuration(input);
var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, labelInterval);
if (labelCnt >= MIN_AUTO_LABELS) {
break;
}
}
}
tDateProfile.labelInterval = labelInterval;
}
return labelInterval;
}
function ensureSlotDuration(tDateProfile, dateProfile, dateEnv) {
var currentRange = dateProfile.currentRange;
var slotDuration = tDateProfile.slotDuration;
if (!slotDuration) {
var labelInterval = ensureLabelInterval(tDateProfile, dateProfile, dateEnv); // will compute if necessary
// compute based off the label interval
// find the largest slot duration that is different from labelInterval, but still acceptable
for (var _i = 0, STOCK_SUB_DURATIONS_3 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_3.length; _i++) {
var input = STOCK_SUB_DURATIONS_3[_i];
var trySlotDuration = createDuration(input);
var slotsPerLabel = wholeDivideDurations(labelInterval, trySlotDuration);
if (slotsPerLabel !== null && slotsPerLabel > 1 && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
slotDuration = trySlotDuration;
break;
}
}
// only allow the value if it won't exceed the view's # of slots limit
if (slotDuration) {
var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, slotDuration);
if (slotCnt > MAX_AUTO_CELLS) {
slotDuration = null;
}
}
// use the label interval as a last resort
if (!slotDuration) {
slotDuration = labelInterval;
}
tDateProfile.slotDuration = slotDuration;
}
return slotDuration;
}
function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, view) {
var format1;
var format2;
var labelInterval = tDateProfile.labelInterval;
var unit = greatestDurationDenominator(labelInterval).unit;
var weekNumbersVisible = view.opt('weekNumbers');
var format0 = (format1 = (format2 = null));
// NOTE: weekNumber computation function wont work
if ((unit === 'week') && !weekNumbersVisible) {
unit = 'day';
}
switch (unit) {
case 'year':
format0 = { year: 'numeric' }; // '2015'
break;
case 'month':
if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
format0 = { year: 'numeric' }; // '2015'
}
format1 = { month: 'short' }; // 'Jan'
break;
case 'week':
if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
format0 = { year: 'numeric' }; // '2015'
}
format1 = { week: 'narrow' }; // 'Wk4'
break;
case 'day':
if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
format0 = { year: 'numeric', month: 'long' }; // 'January 2014'
}
else if (currentRangeAs('months', dateProfile, dateEnv) > 1) {
format0 = { month: 'long' }; // 'January'
}
if (weekNumbersVisible) {
format1 = { week: 'short' }; // 'Wk 4'
}
format2 = { weekday: 'narrow', day: 'numeric' }; // 'Su 9'
break;
case 'hour':
if (weekNumbersVisible) {
format0 = { week: 'short' }; // 'Wk 4'
}
if (currentRangeAs('days', dateProfile, dateEnv) > 1) {
format1 = { weekday: 'short', day: 'numeric', month: 'numeric', omitCommas: true }; // Sat 4/7
}
format2 = {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short'
};
break;
case 'minute':
// sufficiently large number of different minute cells?
if ((asRoughMinutes(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
format0 = {
hour: 'numeric',
meridiem: 'short'
};
format1 = function (params) {
return ':' + padStart(params.date.minute, 2); // ':30'
};
}
else {
format0 = {
hour: 'numeric',
minute: 'numeric',
meridiem: 'short'
};
}
break;
case 'second':
// sufficiently large number of different second cells?
if ((asRoughSeconds(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
format0 = { hour: 'numeric', minute: '2-digit', meridiem: 'lowercase' }; // '8:30 PM'
format1 = function (params) {
return ':' + padStart(params.date.second, 2); // ':30'
};
}
else {
format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM'
}
break;
case 'millisecond':
format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM'
format1 = function (params) {
return '.' + padStart(params.millisecond, 3);
};
break;
}
return [].concat(format0 || [], format1 || [], format2 || []);
}
// Compute the number of the give units in the "current" range.
// Won't go more precise than days.
// Will return `0` if there's not a clean whole interval.
function currentRangeAs(unit, dateProfile, dateEnv) {
var range = dateProfile.currentRange;
var res = null;
if (unit === 'years') {
res = dateEnv.diffWholeYears(range.start, range.end);
}
else if (unit === 'months') {
res = dateEnv.diffWholeMonths(range.start, range.end);
}
else if (unit === 'weeks') {
res = dateEnv.diffWholeMonths(range.start, range.end);
}
else if (unit === 'days') {
res = diffWholeDays(range.start, range.end);
}
return res || 0;
}
function buildIsWeekStarts(tDateProfile, dateEnv) {
var slotDates = tDateProfile.slotDates, emphasizeWeeks = tDateProfile.emphasizeWeeks;
var prevWeekNumber = null;
var isWeekStarts = [];
for (var _i = 0, slotDates_1 = slotDates; _i < slotDates_1.length; _i++) {
var slotDate = slotDates_1[_i];
var weekNumber = dateEnv.computeWeekNumber(slotDate);
var isWeekStart = emphasizeWeeks && (prevWeekNumber !== null) && (prevWeekNumber !== weekNumber);
prevWeekNumber = weekNumber;
isWeekStarts.push(isWeekStart);
}
return isWeekStarts;
}
function buildCellRows(tDateProfile, dateEnv, view) {
var slotDates = tDateProfile.slotDates;
var formats = tDateProfile.headerFormats;
var cellRows = formats.map(function (format) { return []; }); // indexed by row,col
// specifically for navclicks
var rowUnits = formats.map(function (format) {
return format.getLargestUnit ? format.getLargestUnit() : null;
});
// builds cellRows and slotCells
for (var i = 0; i < slotDates.length; i++) {
var date = slotDates[i];
var isWeekStart = tDateProfile.isWeekStarts[i];
for (var row = 0; row < formats.length; row++) {
var format = formats[row];
var rowCells = cellRows[row];
var leadingCell = rowCells[rowCells.length - 1];
var isSuperRow = (formats.length > 1) && (row < (formats.length - 1)); // more than one row and not the last
var newCell = null;
if (isSuperRow) {
var text = dateEnv.format(date, format);
if (!leadingCell || (leadingCell.text !== text)) {
newCell = buildCellObject(date, text, rowUnits[row], view);
}
else {
leadingCell.colspan += 1;
}
}
else {
if (!leadingCell ||
isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval))) {
var text = dateEnv.format(date, format);
newCell = buildCellObject(date, text, rowUnits[row], view);
}
else {
leadingCell.colspan += 1;
}
}
if (newCell) {
newCell.weekStart = isWeekStart;
rowCells.push(newCell);
}
}
}
return cellRows;
}
function buildCellObject(date, text, rowUnit, view) {
var spanHtml = buildGotoAnchorHtml(view, {
date: date,
type: rowUnit,
forceOff: !rowUnit
}, {
'class': 'fc-cell-text'
}, htmlEscape(text));
return { text: text, spanHtml: spanHtml, date: date, colspan: 1, isWeekStart: false };
}
var TimelineNowIndicator = /** @class */ (function () {
function TimelineNowIndicator(headParent, bodyParent) {
this.headParent = headParent;
this.bodyParent = bodyParent;
}
TimelineNowIndicator.prototype.render = function (coord, isRtl) {
var styleProps = isRtl ? { right: -coord } : { left: coord };
this.headParent.appendChild(this.arrowEl = createElement('div', {
className: 'fc-now-indicator fc-now-indicator-arrow',
style: styleProps
}));
this.bodyParent.appendChild(this.lineEl = createElement('div', {
className: 'fc-now-indicator fc-now-indicator-line',
style: styleProps
}));
};
TimelineNowIndicator.prototype.unrender = function () {
if (this.arrowEl) {
removeElement(this.arrowEl);
}
if (this.lineEl) {
removeElement(this.lineEl);
}
};
return TimelineNowIndicator;
}());
var STICKY_PROP_VAL = computeStickyPropVal(); // if null, means not supported at all
var IS_MS_EDGE = /Edge/.test(navigator.userAgent);
var IS_SAFARI = STICKY_PROP_VAL === '-webkit-sticky'; // good b/c doesn't confuse chrome
var STICKY_CLASSNAME = 'fc-sticky';
/*
useful beyond the native position:sticky for these reasons:
- support in IE11
- nice centering support
*/
var StickyScroller = /** @class */ (function () {
function StickyScroller(scroller, isRtl, isVertical) {
var _this = this;
this.usingRelative = null;
/*
known bug: called twice on init. problem when mixing with ScrollJoiner
*/
this.updateSize = function () {
var els = Array.prototype.slice.call(_this.scroller.canvas.el.querySelectorAll('.' + STICKY_CLASSNAME));
var elGeoms = _this.queryElGeoms(els);
var viewportWidth = _this.scroller.el.clientWidth;
if (_this.usingRelative) {
var elDestinations = _this.computeElDestinations(elGeoms, viewportWidth); // read before prepPositioning
assignRelativePositions(els, elGeoms, elDestinations);
}
else {
assignStickyPositions(els, elGeoms, viewportWidth);
}
};
this.scroller = scroller;
this.usingRelative =
!STICKY_PROP_VAL || // IE11
(IS_MS_EDGE && isRtl) || // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/18883305/
((IS_MS_EDGE || IS_SAFARI) && isVertical); // because doesn't work with rowspan in tables, our only vertial use
if (this.usingRelative) {
scroller.on('scrollEnd', this.updateSize);
}
}
StickyScroller.prototype.destroy = function () {
this.scroller.off('scrollEnd', this.updateSize);
};
StickyScroller.prototype.queryElGeoms = function (els) {
var canvasOrigin = this.scroller.canvas.el.getBoundingClientRect();
var elGeoms = [];
for (var _i = 0, els_1 = els; _i < els_1.length; _i++) {
var el = els_1[_i];
var parentBound = translateRect(el.parentNode.getBoundingClientRect(), -canvasOrigin.left, -canvasOrigin.top);
var elRect = el.getBoundingClientRect();
var computedStyles = window.getComputedStyle(el);
var computedTextAlign = window.getComputedStyle(el.parentNode).textAlign; // ask the parent
var intendedTextAlign = computedTextAlign;
var naturalBound = null;
if (computedStyles.position !== 'sticky') {
naturalBound = translateRect(elRect, -canvasOrigin.left - (parseFloat(computedStyles.left) || 0), // could be 'auto'
-canvasOrigin.top - (parseFloat(computedStyles.top) || 0));
}
if (el.hasAttribute('data-sticky-center')) {
intendedTextAlign = 'center';
}
elGeoms.push({
parentBound: parentBound,
naturalBound: naturalBound,
elWidth: elRect.width,
elHeight: elRect.height,
computedTextAlign: computedTextAlign,
intendedTextAlign: intendedTextAlign
});
}
return elGeoms;
};
StickyScroller.prototype.computeElDestinations = function (elGeoms, viewportWidth) {
var viewportLeft = this.scroller.getScrollFromLeft();
var viewportTop = this.scroller.getScrollTop();
var viewportRight = viewportLeft + viewportWidth;
return elGeoms.map(function (elGeom) {
var elWidth = elGeom.elWidth, elHeight = elGeom.elHeight, parentBound = elGeom.parentBound, naturalBound = elGeom.naturalBound;
var destLeft; // relative to canvas topleft
var destTop; // "
switch (elGeom.intendedTextAlign) {
case 'left':
destLeft = viewportLeft;
break;
case 'right':
destLeft = viewportRight - elWidth;
break;
case 'center':
destLeft = (viewportLeft + viewportRight) / 2 - elWidth / 2;
break;
}
destLeft = Math.min(destLeft, parentBound.right - elWidth);
destLeft = Math.max(destLeft, parentBound.left);
destTop = viewportTop;
destTop = Math.min(destTop, parentBound.bottom - elHeight);
destTop = Math.max(destTop, naturalBound.top); // better to use natural top for upper bound
return { left: destLeft, top: destTop };
});
};
return StickyScroller;
}());
function assignRelativePositions(els, elGeoms, elDestinations) {
els.forEach(function (el, i) {
var naturalBound = elGeoms[i].naturalBound;
applyStyle(el, {
position: 'relative',
left: elDestinations[i].left - naturalBound.left,
top: elDestinations[i].top - naturalBound.top
});
});
}
function assignStickyPositions(els, elGeoms, viewportWidth) {
els.forEach(function (el, i) {
var stickyLeft = 0;
if (elGeoms[i].intendedTextAlign === 'center') {
stickyLeft = (viewportWidth - elGeoms[i].elWidth) / 2;
// needs to be forced to left?
if (elGeoms[i].computedTextAlign === 'center') {
el.setAttribute('data-sticky-center', '') // remember for next queryElGeoms
;
el.parentNode.style.textAlign = 'left';
}
}
applyStyle(el, {
position: STICKY_PROP_VAL,
left: stickyLeft,
right: 0,
top: 0
});
});
}
function computeStickyPropVal() {
var el = htmlToElement('<div style="position:-webkit-sticky;position:sticky"></div>');
var val = el.style.position;
if (val.indexOf('sticky') !== -1) {
return val;
}
else {
return null;
}
}
var TimeAxis = /** @class */ (function (_super) {
__extends(TimeAxis, _super);
function TimeAxis(context, headerContainerEl, bodyContainerEl) {
var _this = _super.call(this, context) || this;
var layout = _this.layout = new HeaderBodyLayout(headerContainerEl, bodyContainerEl, 'auto');
var headerEnhancedScroller = layout.headerScroller.enhancedScroll;
var bodyEnhancedScroller = layout.bodyScroller.enhancedScroll;
// needs to go after layout, which has ScrollJoiner
_this.headStickyScroller = new StickyScroller(headerEnhancedScroller, _this.isRtl, false); // isVertical=false
_this.bodyStickyScroller = new StickyScroller(bodyEnhancedScroller, _this.isRtl, false); // isVertical=false
_this.header = new TimelineHeader(context, headerEnhancedScroller.canvas.contentEl);
_this.slats = new TimelineSlats(context, bodyEnhancedScroller.canvas.bgEl);
_this.nowIndicator = new TimelineNowIndicator(headerEnhancedScroller.canvas.el, bodyEnhancedScroller.canvas.el);
return _this;
}
TimeAxis.prototype.destroy = function () {
this.layout.destroy();
this.header.destroy();
this.slats.destroy();
this.nowIndicator.unrender();
this.headStickyScroller.destroy();
this.bodyStickyScroller.destroy();
_super.prototype.destroy.call(this);
};
TimeAxis.prototype.render = function (props) {
var tDateProfile = this.tDateProfile =
buildTimelineDateProfile(props.dateProfile, this.view); // TODO: cache
this.header.receiveProps({
dateProfile: props.dateProfile,
tDateProfile: tDateProfile
});
this.slats.receiveProps({
dateProfile: props.dateProfile,
tDateProfile: tDateProfile
});
};
// Now Indicator
// ------------------------------------------------------------------------------------------
TimeAxis.prototype.getNowIndicatorUnit = function (dateProfile) {
// yuck
var tDateProfile = this.tDateProfile =
buildTimelineDateProfile(dateProfile, this.view); // TODO: cache
if (tDateProfile.isTimeScale) {
return greatestDurationDenominator(tDateProfile.slotDuration).unit;
}
};
// will only execute if isTimeScale
TimeAxis.prototype.renderNowIndicator = function (date) {
if (rangeContainsMarker(this.tDateProfile.normalizedRange, date)) {
this.nowIndicator.render(this.dateToCoord(date), this.isRtl);
}
};
// will only execute if isTimeScale
TimeAxis.prototype.unrenderNowIndicator = function () {
this.nowIndicator.unrender();
};
// Sizing
// ------------------------------------------------------------------------------------------
TimeAxis.prototype.updateSize = function (isResize, totalHeight, isAuto) {
this.applySlotWidth(this.computeSlotWidth());
// adjusts gutters. do after slot widths set
this.layout.setHeight(totalHeight, isAuto);
// pretty much just queries coords. do last
this.slats.updateSize();
};
TimeAxis.prototype.updateStickyScrollers = function () {
this.headStickyScroller.updateSize();
this.bodyStickyScroller.updateSize();
};
TimeAxis.prototype.computeSlotWidth = function () {
var slotWidth = this.opt('slotWidth') || '';
if (slotWidth === '') {
slotWidth = this.computeDefaultSlotWidth(this.tDateProfile);
}
return slotWidth;
};
TimeAxis.prototype.computeDefaultSlotWidth = function (tDateProfile) {
var maxInnerWidth = 0; // TODO: harness core's `matchCellWidths` for this
this.header.innerEls.forEach(function (innerEl, i) {
maxInnerWidth = Math.max(maxInnerWidth, innerEl.getBoundingClientRect().width);
});
var headingCellWidth = Math.ceil(maxInnerWidth) + 1; // assume no padding, and one pixel border
// in TimelineView.defaults we ensured that labelInterval is an interval of slotDuration
// TODO: rename labelDuration?
var slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
var slotWidth = Math.ceil(headingCellWidth / slotsPerLabel);
var minWidth = window.getComputedStyle(this.header.slatColEls[0]).minWidth;
if (minWidth) {
minWidth = parseInt(minWidth, 10);
if (minWidth) {
slotWidth = Math.max(slotWidth, minWidth);
}
}
return slotWidth;
};
TimeAxis.prototype.applySlotWidth = function (slotWidth) {
var _a = this, layout = _a.layout, tDateProfile = _a.tDateProfile;
var containerWidth = '';
var containerMinWidth = '';
var nonLastSlotWidth = '';
if (slotWidth !== '') {
slotWidth = Math.round(slotWidth);
containerWidth = slotWidth * tDateProfile.slotDates.length;
containerMinWidth = '';
nonLastSlotWidth = slotWidth;
var availableWidth = layout.bodyScroller.enhancedScroll.getClientWidth();
if (availableWidth > containerWidth) {
containerMinWidth = availableWidth;
containerWidth = '';
nonLastSlotWidth = Math.floor(availableWidth / tDateProfile.slotDates.length);
}
}
layout.headerScroller.enhancedScroll.canvas.setWidth(containerWidth);
layout.headerScroller.enhancedScroll.canvas.setMinWidth(containerMinWidth);
layout.bodyScroller.enhancedScroll.canvas.setWidth(containerWidth);
layout.bodyScroller.enhancedScroll.canvas.setMinWidth(containerMinWidth);
if (nonLastSlotWidth !== '') {
this.header.slatColEls.slice(0, -1).concat(this.slats.slatColEls.slice(0, -1)).forEach(function (el) {
el.style.width = nonLastSlotWidth + 'px';
});
}
};
// returned value is between 0 and the number of snaps
TimeAxis.prototype.computeDateSnapCoverage = function (date) {
var _a = this, dateEnv = _a.dateEnv, tDateProfile = _a.tDateProfile;
var snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
if (snapDiff < 0) {
return 0;
}
else if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
return tDateProfile.snapCnt;
}
else {
var snapDiffInt = Math.floor(snapDiff);
var snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
if (isInt(snapCoverage)) { // not an in-between value
snapCoverage += snapDiff - snapDiffInt; // add the remainder
}
else {
// a fractional value, meaning the date is not visible
// always round up in this case. works for start AND end dates in a range.
snapCoverage = Math.ceil(snapCoverage);
}
return snapCoverage;
}
};
// for LTR, results range from 0 to width of area
// for RTL, results range from negative width of area to 0
TimeAxis.prototype.dateToCoord = function (date) {
var tDateProfile = this.tDateProfile;
var snapCoverage = this.computeDateSnapCoverage(date);
var slotCoverage = snapCoverage / tDateProfile.snapsPerSlot;
var slotIndex = Math.floor(slotCoverage);
slotIndex = Math.min(slotIndex, tDateProfile.slotCnt - 1);
var partial = slotCoverage - slotIndex;
var _a = this.slats, innerCoordCache = _a.innerCoordCache, outerCoordCache = _a.outerCoordCache;
if (this.isRtl) {
return (outerCoordCache.rights[slotIndex] -
(innerCoordCache.getWidth(slotIndex) * partial)) - outerCoordCache.originClientRect.width;
}
else {
return (outerCoordCache.lefts[slotIndex] +
(innerCoordCache.getWidth(slotIndex) * partial));
}
};
TimeAxis.prototype.rangeToCoords = function (range) {
if (this.isRtl) {
return { right: this.dateToCoord(range.start), left: this.dateToCoord(range.end) };
}
else {
return { left: this.dateToCoord(range.start), right: this.dateToCoord(range.end) };
}
};
// Scrolling
// ------------------------------------------------------------------------------------------
TimeAxis.prototype.computeDateScroll = function (duration) {
var dateEnv = this.dateEnv;
var dateProfile = this.props.dateProfile;
var left = 0;
if (dateProfile) {
left = this.dateToCoord(dateEnv.add(startOfDay(dateProfile.activeRange.start), // startOfDay needed?
duration));
// hack to overcome the left borders of non-first slat
if (!this.isRtl && left) {
left += 1;
}
}
return { left: left };
};
TimeAxis.prototype.queryDateScroll = function () {
var enhancedScroll = this.layout.bodyScroller.enhancedScroll;
return {
left: enhancedScroll.getScrollLeft()
};
};
TimeAxis.prototype.applyDateScroll = function (scroll) {
// TODO: lame we have to update both. use the scrolljoiner instead maybe
this.layout.bodyScroller.enhancedScroll.setScrollLeft(scroll.left || 0);
this.layout.headerScroller.enhancedScroll.setScrollLeft(scroll.left || 0);
};
return TimeAxis;
}(Component));
var TimelineLaneEventRenderer = /** @class */ (function (_super) {
__extends(TimelineLaneEventRenderer, _super);
function TimelineLaneEventRenderer(context, masterContainerEl, timeAxis) {
var _this = _super.call(this, context) || this;
_this.masterContainerEl = masterContainerEl;
_this.timeAxis = timeAxis;
return _this;
}
TimelineLaneEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) {
var view = this.context.view;
var eventRange = seg.eventRange;
var eventDef = eventRange.def;
var eventUi = eventRange.ui;
var isDraggable = view.computeEventDraggable(eventDef, eventUi);
var isResizableFromStart = seg.isStart && view.computeEventStartResizable(eventDef, eventUi);
var isResizableFromEnd = seg.isEnd && view.computeEventEndResizable(eventDef, eventUi);
var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo);
classes.unshift('fc-timeline-event', 'fc-h-event');
var timeText = this.getTimeText(eventRange);
return '<a class="' + classes.join(' ') + '" style="' + cssToStr(this.getSkinCss(eventUi)) + '"' +
(eventDef.url ?
' href="' + htmlEscape(eventDef.url) + '"' :
'') +
'>' +
(timeText ?
'<span class="fc-time-wrap">' +
'<span class="fc-time">' +
htmlEscape(timeText) +
'</span>' +
'</span>'
:
'') +
'<span class="fc-title-wrap">' +
'<span class="fc-title fc-sticky">' +
(eventDef.title ? htmlEscape(eventDef.title) : '&nbsp;') +
'</span>' +
'</span>' +
(isResizableFromStart ?
'<div class="fc-resizer fc-start-resizer"></div>' :
'') +
(isResizableFromEnd ?
'<div class="fc-resizer fc-end-resizer"></div>' :
'') +
'</a>';
};
TimelineLaneEventRenderer.prototype.computeDisplayEventTime = function () {
return !this.timeAxis.tDateProfile.isTimeScale; // because times should be obvious via axis
};
TimelineLaneEventRenderer.prototype.computeDisplayEventEnd = function () {
return false;
};
// Computes a default event time formatting string if `timeFormat` is not explicitly defined
TimelineLaneEventRenderer.prototype.computeEventTimeFormat = function () {
return {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'narrow'
};
};
TimelineLaneEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) {
if (!this.el && this.masterContainerEl) {
this.el = createElement('div', { className: 'fc-event-container' });
if (mirrorInfo) {
this.el.classList.add('fc-mirror-container');
}
this.masterContainerEl.appendChild(this.el);
}
if (this.el) {
for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
var seg = segs_1[_i];
this.el.appendChild(seg.el);
}
}
};
TimelineLaneEventRenderer.prototype.detachSegs = function (segs) {
for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
var seg = segs_2[_i];
removeElement(seg.el);
}
};
// computes AND assigns (assigns the left/right at least). bad
TimelineLaneEventRenderer.prototype.computeSegSizes = function (segs) {
var timeAxis = this.timeAxis;
for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) {
var seg = segs_3[_i];
var coords = timeAxis.rangeToCoords(seg); // works because Seg has start/end
applyStyle(seg.el, {
left: (seg.left = coords.left),
right: -(seg.right = coords.right)
});
}
};
TimelineLaneEventRenderer.prototype.assignSegSizes = function (segs) {
if (!this.el) {
return;
}
// compute seg verticals
for (var _i = 0, segs_4 = segs; _i < segs_4.length; _i++) {
var seg = segs_4[_i];
seg.height = computeHeightAndMargins(seg.el);
}
this.buildSegLevels(segs); // populates above/below props for computeOffsetForSegs
var totalHeight = computeOffsetForSegs(segs); // also assigns seg.top
applyStyleProp(this.el, 'height', totalHeight);
// assign seg verticals
for (var _a = 0, segs_5 = segs; _a < segs_5.length; _a++) {
var seg = segs_5[_a];
applyStyleProp(seg.el, 'top', seg.top);
}
};
TimelineLaneEventRenderer.prototype.buildSegLevels = function (segs) {
var segLevels = [];
segs = this.sortEventSegs(segs);
for (var _i = 0, segs_6 = segs; _i < segs_6.length; _i++) {
var unplacedSeg = segs_6[_i];
unplacedSeg.above = [];
// determine the first level with no collisions
var level = 0; // level index
while (level < segLevels.length) {
var isLevelCollision = false;
// determine collisions
for (var _a = 0, _b = segLevels[level]; _a < _b.length; _a++) {
var placedSeg = _b[_a];
if (timeRowSegsCollide(unplacedSeg, placedSeg)) {
unplacedSeg.above.push(placedSeg);
isLevelCollision = true;
}
}
if (isLevelCollision) {
level += 1;
}
else {
break;
}
}
// insert into the first non-colliding level. create if necessary
(segLevels[level] || (segLevels[level] = []))
.push(unplacedSeg);
// record possible colliding segments below (TODO: automated test for this)
level += 1;
while (level < segLevels.length) {
for (var _c = 0, _d = segLevels[level]; _c < _d.length; _c++) {
var belowSeg = _d[_c];
if (timeRowSegsCollide(unplacedSeg, belowSeg)) {
belowSeg.above.push(unplacedSeg);
}
}
level += 1;
}
}
return segLevels;
};
return TimelineLaneEventRenderer;
}(FgEventRenderer));
function computeOffsetForSegs(segs) {
var max = 0;
for (var _i = 0, segs_7 = segs; _i < segs_7.length; _i++) {
var seg = segs_7[_i];
max = Math.max(max, computeOffsetForSeg(seg));
}
return max;
}
function computeOffsetForSeg(seg) {
if ((seg.top == null)) {
seg.top = computeOffsetForSegs(seg.above);
}
return seg.top + seg.height;
}
function timeRowSegsCollide(seg0, seg1) {
return (seg0.left < seg1.right) && (seg0.right > seg1.left);
}
var TimelineLaneFillRenderer = /** @class */ (function (_super) {
__extends(TimelineLaneFillRenderer, _super);
function TimelineLaneFillRenderer(context, masterContainerEl, timeAxis) {
var _this = _super.call(this, context) || this;
_this.masterContainerEl = masterContainerEl;
_this.timeAxis = timeAxis;
return _this;
}
TimelineLaneFillRenderer.prototype.attachSegs = function (type, segs) {
if (segs.length) {
var className = void 0;
if (type === 'businessHours') {
className = 'bgevent';
}
else {
className = type.toLowerCase();
}
// making a new container each time is OKAY
// all types of segs (background or business hours or whatever) are rendered in one pass
var containerEl = createElement('div', { className: 'fc-' + className + '-container' });
this.masterContainerEl.appendChild(containerEl);
for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
var seg = segs_1[_i];
containerEl.appendChild(seg.el);
}
return [containerEl]; // return value
}
};
TimelineLaneFillRenderer.prototype.computeSegSizes = function (segs) {
var timeAxis = this.timeAxis;
for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
var seg = segs_2[_i];
var coords = timeAxis.rangeToCoords(seg);
seg.left = coords.left;
seg.right = coords.right;
}
};
TimelineLaneFillRenderer.prototype.assignSegSizes = function (segs) {
for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) {
var seg = segs_3[_i];
applyStyle(seg.el, {
left: seg.left,
right: -seg.right
});
}
};
return TimelineLaneFillRenderer;
}(FillRenderer));
var TimelineLane = /** @class */ (function (_super) {
__extends(TimelineLane, _super);
function TimelineLane(context, fgContainerEl, bgContainerEl, timeAxis) {
var _this = _super.call(this, context, bgContainerEl) // should el be bgContainerEl???
|| this;
_this.slicer = new TimelineLaneSlicer();
_this.renderEventDrag = memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag);
_this.renderEventResize = memoizeRendering(_this._renderEventResize, _this._unrenderEventResize);
var fillRenderer = _this.fillRenderer = new TimelineLaneFillRenderer(context, bgContainerEl, timeAxis);
var eventRenderer = _this.eventRenderer = new TimelineLaneEventRenderer(context, fgContainerEl, timeAxis);
_this.mirrorRenderer = new TimelineLaneEventRenderer(context, fgContainerEl, timeAxis);
_this.renderBusinessHours = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'));
_this.renderDateSelection = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'highlight'), fillRenderer.unrender.bind(fillRenderer, 'highlight'));
_this.renderBgEvents = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'));
_this.renderFgEvents = memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer));
_this.renderEventSelection = memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]);
_this.timeAxis = timeAxis;
return _this;
}
TimelineLane.prototype.render = function (props) {
var slicedProps = this.slicer.sliceProps(props, props.dateProfile, this.timeAxis.tDateProfile.isTimeScale ? null : props.nextDayThreshold, this, this.timeAxis);
this.renderBusinessHours(slicedProps.businessHourSegs);
this.renderDateSelection(slicedProps.dateSelectionSegs);
this.renderBgEvents(slicedProps.bgEventSegs);
this.renderFgEvents(slicedProps.fgEventSegs);
this.renderEventSelection(slicedProps.eventSelection);
this.renderEventDrag(slicedProps.eventDrag);
this.renderEventResize(slicedProps.eventResize);
};
TimelineLane.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.renderBusinessHours.unrender();
this.renderDateSelection.unrender();
this.renderBgEvents.unrender();
this.renderFgEvents.unrender();
this.renderEventSelection.unrender();
this.renderEventDrag.unrender();
this.renderEventResize.unrender();
};
TimelineLane.prototype._renderEventDrag = function (state) {
if (state) {
this.eventRenderer.hideByHash(state.affectedInstances);
this.mirrorRenderer.renderSegs(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype._unrenderEventDrag = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.mirrorRenderer.unrender(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype._renderEventResize = function (state) {
if (state) {
// HACK. eventRenderer and fillRenderer both use these segs. would compete over seg.el
var segsForHighlight = state.segs.map(function (seg) {
return __assign({}, seg);
});
this.eventRenderer.hideByHash(state.affectedInstances);
this.fillRenderer.renderSegs('highlight', segsForHighlight);
this.mirrorRenderer.renderSegs(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype._unrenderEventResize = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.fillRenderer.unrender('highlight');
this.mirrorRenderer.unrender(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype.updateSize = function (isResize) {
var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer;
fillRenderer.computeSizes(isResize);
eventRenderer.computeSizes(isResize);
mirrorRenderer.computeSizes(isResize);
fillRenderer.assignSizes(isResize);
eventRenderer.assignSizes(isResize);
mirrorRenderer.assignSizes(isResize);
};
return TimelineLane;
}(DateComponent));
var TimelineLaneSlicer = /** @class */ (function (_super) {
__extends(TimelineLaneSlicer, _super);
function TimelineLaneSlicer() {
return _super !== null && _super.apply(this, arguments) || this;
}
TimelineLaneSlicer.prototype.sliceRange = function (origRange, timeAxis) {
var tDateProfile = timeAxis.tDateProfile;
var dateProfile = timeAxis.props.dateProfile;
var normalRange = normalizeRange(origRange, tDateProfile, timeAxis.dateEnv);
var segs = [];
// protect against when the span is entirely in an invalid date region
if (timeAxis.computeDateSnapCoverage(normalRange.start) < timeAxis.computeDateSnapCoverage(normalRange.end)) {
// intersect the footprint's range with the grid's range
var slicedRange = intersectRanges(normalRange, tDateProfile.normalizedRange);
if (slicedRange) {
segs.push({
start: slicedRange.start,
end: slicedRange.end,
isStart: slicedRange.start.valueOf() === normalRange.start.valueOf() && isValidDate(slicedRange.start, tDateProfile, dateProfile, timeAxis.view),
isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf() && isValidDate(addMs(slicedRange.end, -1), tDateProfile, dateProfile, timeAxis.view)
});
}
}
return segs;
};
return TimelineLaneSlicer;
}(Slicer));
var TimelineView = /** @class */ (function (_super) {
__extends(TimelineView, _super);
function TimelineView(context, viewSpec, dateProfileGenerator, parentEl) {
var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this;
_this.el.classList.add('fc-timeline');
if (_this.opt('eventOverlap') === false) {
_this.el.classList.add('fc-no-overlap');
}
_this.el.innerHTML = _this.renderSkeletonHtml();
_this.timeAxis = new TimeAxis(_this.context, _this.el.querySelector('thead .fc-time-area'), _this.el.querySelector('tbody .fc-time-area'));
_this.lane = new TimelineLane(_this.context, _this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.contentEl, _this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.bgEl, _this.timeAxis);
context.calendar.registerInteractiveComponent(_this, {
el: _this.timeAxis.slats.el
});
return _this;
}
TimelineView.prototype.destroy = function () {
this.timeAxis.destroy();
this.lane.destroy();
_super.prototype.destroy.call(this);
this.calendar.unregisterInteractiveComponent(this);
};
TimelineView.prototype.renderSkeletonHtml = function () {
var theme = this.theme;
return "<table class=\"" + theme.getClass('tableGrid') + "\"> <thead class=\"fc-head\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetHeader') + "\"></td> </tr> </thead> <tbody class=\"fc-body\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetContent') + "\"></td> </tr> </tbody> </table>";
};
TimelineView.prototype.render = function (props) {
_super.prototype.render.call(this, props); // flags for updateSize, addScroll
this.timeAxis.receiveProps({
dateProfile: props.dateProfile
});
this.lane.receiveProps(__assign({}, props, { nextDayThreshold: this.nextDayThreshold }));
};
TimelineView.prototype.updateSize = function (isResize, totalHeight, isAuto) {
this.timeAxis.updateSize(isResize, totalHeight, isAuto);
this.lane.updateSize(isResize);
};
// Now Indicator
// ------------------------------------------------------------------------------------------
TimelineView.prototype.getNowIndicatorUnit = function (dateProfile) {
return this.timeAxis.getNowIndicatorUnit(dateProfile);
};
TimelineView.prototype.renderNowIndicator = function (date) {
this.timeAxis.renderNowIndicator(date);
};
TimelineView.prototype.unrenderNowIndicator = function () {
this.timeAxis.unrenderNowIndicator();
};
// Scroll System
// ------------------------------------------------------------------------------------------
TimelineView.prototype.computeDateScroll = function (duration) {
return this.timeAxis.computeDateScroll(duration);
};
TimelineView.prototype.applyScroll = function (scroll, isResize) {
_super.prototype.applyScroll.call(this, scroll, isResize); // will call applyDateScroll
// avoid updating stickyscroll too often
// TODO: repeat code as ResourceTimelineView::updateSize
var calendar = this.calendar;
if (isResize || calendar.isViewUpdated || calendar.isDatesUpdated || calendar.isEventsUpdated) {
this.timeAxis.updateStickyScrollers();
}
};
TimelineView.prototype.applyDateScroll = function (scroll) {
this.timeAxis.applyDateScroll(scroll);
};
TimelineView.prototype.queryScroll = function () {
var enhancedScroll = this.timeAxis.layout.bodyScroller.enhancedScroll;
return {
top: enhancedScroll.getScrollTop(),
left: enhancedScroll.getScrollLeft()
};
};
// Hit System
// ------------------------------------------------------------------------------------------
TimelineView.prototype.buildPositionCaches = function () {
this.timeAxis.slats.updateSize();
};
TimelineView.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) {
var slatHit = this.timeAxis.slats.positionToHit(positionLeft);
if (slatHit) {
return {
component: this,
dateSpan: slatHit.dateSpan,
rect: {
left: slatHit.left,
right: slatHit.right,
top: 0,
bottom: elHeight
},
dayEl: slatHit.dayEl,
layer: 0
};
}
};
return TimelineView;
}(View));
var main = createPlugin({
defaultView: 'timelineDay',
views: {
timeline: {
class: TimelineView,
eventResizableFromStart: true // how is this consumed for TimelineView tho?
},
timelineDay: {
type: 'timeline',
duration: { days: 1 }
},
timelineWeek: {
type: 'timeline',
duration: { weeks: 1 }
},
timelineMonth: {
type: 'timeline',
duration: { months: 1 }
},
timelineYear: {
type: 'timeline',
duration: { years: 1 }
}
}
});
export default main;
export { HeaderBodyLayout, ScrollJoiner, StickyScroller, TimeAxis, TimelineLane, TimelineView };
/*!
FullCalendar Timeline Plugin v4.3.0
Docs & License: https://fullcalendar.io/scheduler
(c) 2019 Adam Shaw
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core')) :
typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) :
(global = global || self, factory(global.FullCalendarTimeline = {}, global.FullCalendar));
}(this, function (exports, core) { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* 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);
};
/*
A rectangular area of content that lives within a Scroller.
Can have "gutters", areas of dead spacing around the perimeter.
Also very useful for forcing a width, which a Scroller cannot do alone.
Has a content area that lives above a background area.
*/
var ScrollerCanvas = /** @class */ (function () {
function ScrollerCanvas() {
this.gutters = {};
this.el = core.htmlToElement("<div class=\"fc-scroller-canvas\"> <div class=\"fc-content\"></div> <div class=\"fc-bg\"></div> </div>");
this.contentEl = this.el.querySelector('.fc-content');
this.bgEl = this.el.querySelector('.fc-bg');
}
/*
If falsy, resets all the gutters to 0
*/
ScrollerCanvas.prototype.setGutters = function (gutters) {
if (!gutters) {
this.gutters = {};
}
else {
__assign(this.gutters, gutters);
}
this.updateSize();
};
ScrollerCanvas.prototype.setWidth = function (width) {
this.width = width;
this.updateSize();
};
ScrollerCanvas.prototype.setMinWidth = function (minWidth) {
this.minWidth = minWidth;
this.updateSize();
};
ScrollerCanvas.prototype.clearWidth = function () {
this.width = null;
this.minWidth = null;
this.updateSize();
};
ScrollerCanvas.prototype.updateSize = function () {
var _a = this, gutters = _a.gutters, el = _a.el;
// is border-box (width includes padding)
core.forceClassName(el, 'fc-gutter-left', gutters.left);
core.forceClassName(el, 'fc-gutter-right', gutters.right);
core.forceClassName(el, 'fc-gutter-top', gutters.top);
core.forceClassName(el, 'fc-gutter-bottom', gutters.bottom);
core.applyStyle(el, {
paddingLeft: gutters.left || '',
paddingRight: gutters.right || '',
paddingTop: gutters.top || '',
paddingBottom: gutters.bottom || '',
width: (this.width != null) ?
this.width + (gutters.left || 0) + (gutters.right || 0) :
'',
minWidth: (this.minWidth != null) ?
this.minWidth + (gutters.left || 0) + (gutters.right || 0) :
''
});
core.applyStyle(this.bgEl, {
left: gutters.left || '',
right: gutters.right || '',
top: gutters.top || '',
bottom: gutters.bottom || ''
});
};
return ScrollerCanvas;
}());
var EnhancedScroller = /** @class */ (function (_super) {
__extends(EnhancedScroller, _super);
function EnhancedScroller(overflowX, overflowY) {
var _this = _super.call(this, overflowX, overflowY) || this;
// Scroll Events
// ----------------------------------------------------------------------------------------------
_this.reportScroll = function () {
if (!_this.isScrolling) {
_this.reportScrollStart();
}
_this.trigger('scroll');
_this.isMoving = true;
_this.requestMovingEnd();
};
_this.reportScrollStart = function () {
if (!_this.isScrolling) {
_this.isScrolling = true;
_this.trigger('scrollStart', _this.isTouching); // created in constructor
}
};
// Touch Events
// ----------------------------------------------------------------------------------------------
// will fire *before* the scroll event is fired
_this.reportTouchStart = function () {
_this.isTouching = true;
};
_this.reportTouchEnd = function () {
if (_this.isTouching) {
_this.isTouching = false;
// if touch scrolling was re-enabled during a recent touch scroll
// then unbind the handlers that are preventing it from happening.
if (_this.isTouchScrollEnabled) {
_this.unbindPreventTouchScroll(); // won't do anything if not bound
}
// if the user ended their touch, and the scroll area wasn't moving,
// we consider this to be the end of the scroll.
if (!_this.isMoving) {
_this.reportScrollEnd(); // won't fire if already ended
}
}
};
_this.isScrolling = false;
_this.isTouching = false;
_this.isMoving = false;
_this.isTouchScrollEnabled = true;
_this.requestMovingEnd = core.debounce(_this.reportMovingEnd, 500);
_this.canvas = new ScrollerCanvas();
_this.el.appendChild(_this.canvas.el);
_this.applyOverflow();
_this.bindHandlers();
return _this;
}
EnhancedScroller.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.unbindHandlers();
};
// Touch scroll prevention
// ----------------------------------------------------------------------------------------------
EnhancedScroller.prototype.disableTouchScroll = function () {
this.isTouchScrollEnabled = false;
this.bindPreventTouchScroll(); // will be unbound in enableTouchScroll or reportTouchEnd
};
EnhancedScroller.prototype.enableTouchScroll = function () {
this.isTouchScrollEnabled = true;
// only immediately unbind if a touch event is NOT in progress.
// otherwise, it will be handled by reportTouchEnd.
if (!this.isTouching) {
this.unbindPreventTouchScroll();
}
};
EnhancedScroller.prototype.bindPreventTouchScroll = function () {
if (!this.preventTouchScrollHandler) {
this.el.addEventListener('touchmove', (this.preventTouchScrollHandler = core.preventDefault));
}
};
EnhancedScroller.prototype.unbindPreventTouchScroll = function () {
if (this.preventTouchScrollHandler) {
this.el.removeEventListener('touchmove', this.preventTouchScrollHandler);
this.preventTouchScrollHandler = null;
}
};
// Handlers
// ----------------------------------------------------------------------------------------------
EnhancedScroller.prototype.bindHandlers = function () {
this.el.addEventListener('scroll', this.reportScroll);
this.el.addEventListener('touchstart', this.reportTouchStart, { passive: true });
this.el.addEventListener('touchend', this.reportTouchEnd);
};
EnhancedScroller.prototype.unbindHandlers = function () {
this.el.removeEventListener('scroll', this.reportScroll);
this.el.removeEventListener('touchstart', this.reportTouchStart, { passive: true });
this.el.removeEventListener('touchend', this.reportTouchEnd);
};
EnhancedScroller.prototype.reportMovingEnd = function () {
this.isMoving = false;
// only end the scroll if not currently touching.
// if touching, the scrolling will end later, on touchend.
if (!this.isTouching) {
this.reportScrollEnd();
}
};
EnhancedScroller.prototype.reportScrollEnd = function () {
if (this.isScrolling) {
this.trigger('scrollEnd');
this.isScrolling = false;
}
};
// Horizontal Scroll Normalization
// ----------------------------------------------------------------------------------------------
// http://stackoverflow.com/questions/24276619/better-way-to-get-the-viewport-of-a-scrollable-div-in-rtl-mode/24394376#24394376
// TODO: move all this to util functions
/*
If RTL, and scrolled to the left, returns NEGATIVE value (like Firefox)
*/
EnhancedScroller.prototype.getScrollLeft = function () {
var el = this.el;
var direction = window.getComputedStyle(el).direction;
var val = el.scrollLeft;
if (direction === 'rtl') {
switch (getRtlScrollSystem()) {
case 'positive':
val = (val + el.clientWidth) - el.scrollWidth;
break;
case 'reverse':
val = -val;
break;
}
}
return val;
};
/*
Accepts a NEGATIVE value for when scrolled in RTL
*/
EnhancedScroller.prototype.setScrollLeft = function (val) {
var el = this.el;
var direction = window.getComputedStyle(el).direction;
if (direction === 'rtl') {
switch (getRtlScrollSystem()) {
case 'positive':
val = (val - el.clientWidth) + el.scrollWidth;
break;
case 'reverse':
val = -val;
break;
}
}
el.scrollLeft = val;
};
/*
Always returns the number of pixels scrolled from the leftmost position (even if RTL).
Always positive.
*/
EnhancedScroller.prototype.getScrollFromLeft = function () {
var el = this.el;
var direction = window.getComputedStyle(el).direction;
var val = el.scrollLeft;
if (direction === 'rtl') {
switch (getRtlScrollSystem()) {
case 'negative':
val = (val - el.clientWidth) + el.scrollWidth;
break;
case 'reverse':
val = (-val - el.clientWidth) + el.scrollWidth;
break;
}
}
return val;
};
return EnhancedScroller;
}(core.ScrollComponent));
core.EmitterMixin.mixInto(EnhancedScroller);
// Horizontal Scroll System Detection
// ----------------------------------------------------------------------------------------------
var _rtlScrollSystem;
function getRtlScrollSystem() {
return _rtlScrollSystem || (_rtlScrollSystem = detectRtlScrollSystem());
}
function detectRtlScrollSystem() {
var el = core.htmlToElement("<div style=\" position: absolute; top: -1000px; width: 1px; height: 1px; overflow: scroll; direction: rtl; font-size: 100px; \">A</div>");
document.body.appendChild(el);
var system;
if (el.scrollLeft > 0) {
system = 'positive';
}
else {
el.scrollLeft = 1;
if (el.scrollLeft > 0) {
system = 'reverse';
}
else {
system = 'negative';
}
}
core.removeElement(el);
return system;
}
/*
A Scroller, but with a wrapping div that allows "clipping" away of native scrollbars,
giving the appearance that there are no scrollbars.
*/
var ClippedScroller = /** @class */ (function () {
/*
Received overflows can be set to 'clipped', meaning scrollbars shouldn't be visible
to the user, but the area should still scroll.
*/
function ClippedScroller(overflowX, overflowY, parentEl) {
this.isHScrollbarsClipped = false;
this.isVScrollbarsClipped = false;
if (overflowX === 'clipped-scroll') {
overflowX = 'scroll';
this.isHScrollbarsClipped = true;
}
if (overflowY === 'clipped-scroll') {
overflowY = 'scroll';
this.isVScrollbarsClipped = true;
}
this.enhancedScroll = new EnhancedScroller(overflowX, overflowY);
parentEl.appendChild(this.el = core.createElement('div', {
className: 'fc-scroller-clip'
}));
this.el.appendChild(this.enhancedScroll.el);
}
ClippedScroller.prototype.destroy = function () {
core.removeElement(this.el);
};
ClippedScroller.prototype.updateSize = function () {
var enhancedScroll = this.enhancedScroll;
var scrollEl = enhancedScroll.el;
var edges = core.computeEdges(scrollEl);
var cssProps = { marginLeft: 0, marginRight: 0, marginTop: 0, marginBottom: 0 };
// give the inner scrolling div negative margins so that its scrollbars
// are nudged outside of the bounding box of the wrapper, which is overflow:hidden
if (this.isVScrollbarsClipped) {
cssProps.marginLeft = -edges.scrollbarLeft;
cssProps.marginRight = -edges.scrollbarRight;
}
if (this.isHScrollbarsClipped) {
cssProps.marginBottom = -edges.scrollbarBottom;
}
core.applyStyle(scrollEl, cssProps);
// if we are attempting to hide the scrollbars offscreen, OSX/iOS will still
// display the floating scrollbars. attach a className to force-hide them.
if ((this.isHScrollbarsClipped || (enhancedScroll.overflowX === 'hidden')) && // should never show?
(this.isVScrollbarsClipped || (enhancedScroll.overflowY === 'hidden')) && // should never show?
!( // doesn't have any scrollbar mass
edges.scrollbarLeft ||
edges.scrollbarRight ||
edges.scrollbarBottom)) {
scrollEl.classList.add('fc-no-scrollbars');
}
else {
scrollEl.classList.remove('fc-no-scrollbars');
}
};
ClippedScroller.prototype.setHeight = function (height) {
this.enhancedScroll.setHeight(height);
};
/*
Accounts for 'clipped' scrollbars
*/
ClippedScroller.prototype.getScrollbarWidths = function () {
var widths = this.enhancedScroll.getScrollbarWidths();
if (this.isVScrollbarsClipped) {
widths.left = 0;
widths.right = 0;
}
if (this.isHScrollbarsClipped) {
widths.bottom = 0;
}
return widths;
};
return ClippedScroller;
}());
var ScrollJoiner = /** @class */ (function () {
function ScrollJoiner(axis, scrollers) {
this.axis = axis;
this.scrollers = scrollers;
for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
var scroller = _a[_i];
this.initScroller(scroller);
}
}
ScrollJoiner.prototype.initScroller = function (scroller) {
var _this = this;
var enhancedScroll = scroller.enhancedScroll;
// when the user scrolls via mousewheel, we know for sure the target
// scroller should be the master. capture the various x-browser events that fire.
var onScroll = function () {
_this.assignMasterScroller(scroller);
};
'wheel mousewheel DomMouseScroll MozMousePixelScroll'.split(' ').forEach(function (evName) {
enhancedScroll.el.addEventListener(evName, onScroll);
});
enhancedScroll
.on('scrollStart', function () {
if (!_this.masterScroller) {
_this.assignMasterScroller(scroller);
}
})
.on('scroll', function () {
if (scroller === _this.masterScroller) {
for (var _i = 0, _a = _this.scrollers; _i < _a.length; _i++) {
var otherScroller = _a[_i];
if (otherScroller !== scroller) {
switch (_this.axis) {
case 'horizontal':
otherScroller.enhancedScroll.el.scrollLeft = enhancedScroll.el.scrollLeft;
break;
case 'vertical':
otherScroller.enhancedScroll.setScrollTop(enhancedScroll.getScrollTop());
break;
}
}
}
}
})
.on('scrollEnd', function () {
if (scroller === _this.masterScroller) {
_this.unassignMasterScroller();
}
});
};
ScrollJoiner.prototype.assignMasterScroller = function (scroller) {
this.unassignMasterScroller();
this.masterScroller = scroller;
for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
var otherScroller = _a[_i];
if (otherScroller !== scroller) {
otherScroller.enhancedScroll.disableTouchScroll();
}
}
};
ScrollJoiner.prototype.unassignMasterScroller = function () {
if (this.masterScroller) {
for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
var otherScroller = _a[_i];
otherScroller.enhancedScroll.enableTouchScroll();
}
this.masterScroller = null;
}
};
ScrollJoiner.prototype.update = function () {
var allWidths = this.scrollers.map(function (scroller) { return scroller.getScrollbarWidths(); });
var maxLeft = 0;
var maxRight = 0;
var maxTop = 0;
var maxBottom = 0;
var widths;
var i;
for (var _i = 0, allWidths_1 = allWidths; _i < allWidths_1.length; _i++) {
widths = allWidths_1[_i];
maxLeft = Math.max(maxLeft, widths.left);
maxRight = Math.max(maxRight, widths.right);
maxTop = Math.max(maxTop, widths.top);
maxBottom = Math.max(maxBottom, widths.bottom);
}
for (i = 0; i < this.scrollers.length; i++) {
var scroller = this.scrollers[i];
widths = allWidths[i];
scroller.enhancedScroll.canvas.setGutters(this.axis === 'horizontal' ?
{
left: maxLeft - widths.left,
right: maxRight - widths.right
} :
{
top: maxTop - widths.top,
bottom: maxBottom - widths.bottom
});
}
};
return ScrollJoiner;
}());
var HeaderBodyLayout = /** @class */ (function () {
/*
verticalScroll = 'auto' | 'clipped-scroll'
*/
function HeaderBodyLayout(headerContainerEl, bodyContainerEl, verticalScroll) {
this.headerScroller = new ClippedScroller('clipped-scroll', 'hidden', headerContainerEl);
this.bodyScroller = new ClippedScroller('auto', verticalScroll, bodyContainerEl);
this.scrollJoiner = new ScrollJoiner('horizontal', [
this.headerScroller,
this.bodyScroller
]);
}
HeaderBodyLayout.prototype.destroy = function () {
this.headerScroller.destroy();
this.bodyScroller.destroy();
};
HeaderBodyLayout.prototype.setHeight = function (totalHeight, isAuto) {
var bodyHeight;
if (isAuto) {
bodyHeight = 'auto';
}
else {
bodyHeight = totalHeight - this.queryHeadHeight();
}
this.bodyScroller.setHeight(bodyHeight);
this.headerScroller.updateSize(); // adjusts gutters and classNames
this.bodyScroller.updateSize(); // adjusts gutters and classNames
this.scrollJoiner.update();
};
HeaderBodyLayout.prototype.queryHeadHeight = function () {
return this.headerScroller.enhancedScroll.canvas.contentEl.getBoundingClientRect().height;
};
return HeaderBodyLayout;
}());
var TimelineHeader = /** @class */ (function (_super) {
__extends(TimelineHeader, _super);
function TimelineHeader(context, parentEl) {
var _this = _super.call(this, context) || this;
parentEl.appendChild(_this.tableEl = core.createElement('table', {
className: _this.theme.getClass('tableGrid')
}));
return _this;
}
TimelineHeader.prototype.destroy = function () {
core.removeElement(this.tableEl);
_super.prototype.destroy.call(this);
};
TimelineHeader.prototype.render = function (props) {
this.renderDates(props.tDateProfile);
};
TimelineHeader.prototype.renderDates = function (tDateProfile) {
var _a = this, dateEnv = _a.dateEnv, theme = _a.theme;
var cellRows = tDateProfile.cellRows;
var lastRow = cellRows[cellRows.length - 1];
var isChrono = core.asRoughMs(tDateProfile.labelInterval) > core.asRoughMs(tDateProfile.slotDuration);
var oneDay = core.isSingleDay(tDateProfile.slotDuration);
var html = '<colgroup>';
// needs to be a col for each body slat. header cells will have colspans
for (var i = tDateProfile.slotCnt - 1; i >= 0; i--) {
html += '<col/>';
}
html += '</colgroup>';
html += '<tbody>';
for (var _i = 0, cellRows_1 = cellRows; _i < cellRows_1.length; _i++) {
var rowCells = cellRows_1[_i];
var isLast = rowCells === lastRow;
html += '<tr' + (isChrono && isLast ? ' class="fc-chrono"' : '') + '>';
for (var _b = 0, rowCells_1 = rowCells; _b < rowCells_1.length; _b++) {
var cell = rowCells_1[_b];
var headerCellClassNames = [theme.getClass('widgetHeader')];
if (cell.isWeekStart) {
headerCellClassNames.push('fc-em-cell');
}
if (oneDay) {
headerCellClassNames = headerCellClassNames.concat(core.getDayClasses(cell.date, this.props.dateProfile, this.context, true) // adds "today" class and other day-based classes
);
}
html +=
'<th class="' + headerCellClassNames.join(' ') + '"' +
' data-date="' + dateEnv.formatIso(cell.date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }) + '"' +
(cell.colspan > 1 ? ' colspan="' + cell.colspan + '"' : '') +
'>' +
'<div class="fc-cell-content">' +
cell.spanHtml +
'</div>' +
'</th>';
}
html += '</tr>';
}
html += '</tbody>';
this.tableEl.innerHTML = html; // TODO: does this work cross-browser?
this.slatColEls = core.findElements(this.tableEl, 'col');
this.innerEls = core.findElements(this.tableEl.querySelector('tr:last-child'), // compound selector won't work because of query-root problem
'th .fc-cell-text');
core.findElements(this.tableEl.querySelectorAll('tr:not(:last-child)'), // compound selector won't work because of query-root problem
'th .fc-cell-text').forEach(function (innerEl) {
innerEl.classList.add('fc-sticky');
});
};
return TimelineHeader;
}(core.Component));
var TimelineSlats = /** @class */ (function (_super) {
__extends(TimelineSlats, _super);
function TimelineSlats(context, parentEl) {
var _this = _super.call(this, context) || this;
parentEl.appendChild(_this.el = core.createElement('div', { className: 'fc-slats' }));
return _this;
}
TimelineSlats.prototype.destroy = function () {
core.removeElement(this.el);
_super.prototype.destroy.call(this);
};
TimelineSlats.prototype.render = function (props) {
this.renderDates(props.tDateProfile);
};
TimelineSlats.prototype.renderDates = function (tDateProfile) {
var _a = this, theme = _a.theme, view = _a.view, dateEnv = _a.dateEnv;
var slotDates = tDateProfile.slotDates, isWeekStarts = tDateProfile.isWeekStarts;
var html = '<table class="' + theme.getClass('tableGrid') + '">' +
'<colgroup>';
for (var i = 0; i < slotDates.length; i++) {
html += '<col/>';
}
html += '</colgroup>';
html += '<tbody><tr>';
for (var i = 0; i < slotDates.length; i++) {
html += this.slatCellHtml(slotDates[i], isWeekStarts[i], tDateProfile);
}
html += '</tr></tbody></table>';
this.el.innerHTML = html;
this.slatColEls = core.findElements(this.el, 'col');
this.slatEls = core.findElements(this.el, 'td');
for (var i = 0; i < slotDates.length; i++) {
view.publiclyTrigger('dayRender', [
{
date: dateEnv.toDate(slotDates[i]),
el: this.slatEls[i],
view: view
}
]);
}
this.outerCoordCache = new core.PositionCache(this.el, this.slatEls, true, // isHorizontal
false // isVertical
);
// for the inner divs within the slats
// used for event rendering and scrollTime, to disregard slat border
this.innerCoordCache = new core.PositionCache(this.el, core.findChildren(this.slatEls, 'div'), true, // isHorizontal
false // isVertical
);
};
TimelineSlats.prototype.slatCellHtml = function (date, isEm, tDateProfile) {
var _a = this, theme = _a.theme, dateEnv = _a.dateEnv;
var classes;
if (tDateProfile.isTimeScale) {
classes = [];
classes.push(core.isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval)) ?
'fc-major' :
'fc-minor');
}
else {
classes = core.getDayClasses(date, this.props.dateProfile, this.context);
classes.push('fc-day');
}
classes.unshift(theme.getClass('widgetContent'));
if (isEm) {
classes.push('fc-em-cell');
}
return '<td class="' + classes.join(' ') + '"' +
' data-date="' + dateEnv.formatIso(date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }) + '"' +
'><div></div></td>';
};
TimelineSlats.prototype.updateSize = function () {
this.outerCoordCache.build();
this.innerCoordCache.build();
};
TimelineSlats.prototype.positionToHit = function (leftPosition) {
var outerCoordCache = this.outerCoordCache;
var tDateProfile = this.props.tDateProfile;
var slatIndex = outerCoordCache.leftToIndex(leftPosition);
if (slatIndex != null) {
// somewhat similar to what TimeGrid does. consolidate?
var slatWidth = outerCoordCache.getWidth(slatIndex);
var partial = this.isRtl ?
(outerCoordCache.rights[slatIndex] - leftPosition) / slatWidth :
(leftPosition - outerCoordCache.lefts[slatIndex]) / slatWidth;
var localSnapIndex = Math.floor(partial * tDateProfile.snapsPerSlot);
var start = this.dateEnv.add(tDateProfile.slotDates[slatIndex], core.multiplyDuration(tDateProfile.snapDuration, localSnapIndex));
var end = this.dateEnv.add(start, tDateProfile.snapDuration);
return {
dateSpan: {
range: { start: start, end: end },
allDay: !this.props.tDateProfile.isTimeScale
},
dayEl: this.slatColEls[slatIndex],
left: outerCoordCache.lefts[slatIndex],
right: outerCoordCache.rights[slatIndex]
};
}
return null;
};
return TimelineSlats;
}(core.Component));
var MIN_AUTO_LABELS = 18; // more than `12` months but less that `24` hours
var MAX_AUTO_SLOTS_PER_LABEL = 6; // allows 6 10-min slots in an hour
var MAX_AUTO_CELLS = 200; // allows 4-days to have a :30 slot duration
core.config.MAX_TIMELINE_SLOTS = 1000;
// potential nice values for slot-duration and interval-duration
var STOCK_SUB_DURATIONS = [
{ years: 1 },
{ months: 1 },
{ days: 1 },
{ hours: 1 },
{ minutes: 30 },
{ minutes: 15 },
{ minutes: 10 },
{ minutes: 5 },
{ minutes: 1 },
{ seconds: 30 },
{ seconds: 15 },
{ seconds: 10 },
{ seconds: 5 },
{ seconds: 1 },
{ milliseconds: 500 },
{ milliseconds: 100 },
{ milliseconds: 10 },
{ milliseconds: 1 }
];
function buildTimelineDateProfile(dateProfile, view) {
var dateEnv = view.dateEnv;
var tDateProfile = {
labelInterval: queryDurationOption(view, 'slotLabelInterval'),
slotDuration: queryDurationOption(view, 'slotDuration')
};
validateLabelAndSlot(tDateProfile, dateProfile, dateEnv); // validate after computed grid duration
ensureLabelInterval(tDateProfile, dateProfile, dateEnv);
ensureSlotDuration(tDateProfile, dateProfile, dateEnv);
var input = view.opt('slotLabelFormat');
var rawFormats = Array.isArray(input) ?
input
: (input != null) ?
[input]
:
computeHeaderFormats(tDateProfile, dateProfile, dateEnv, view);
tDateProfile.headerFormats = rawFormats.map(function (rawFormat) {
return core.createFormatter(rawFormat);
});
tDateProfile.isTimeScale = Boolean(tDateProfile.slotDuration.milliseconds);
var largeUnit = null;
if (!tDateProfile.isTimeScale) {
var slotUnit = core.greatestDurationDenominator(tDateProfile.slotDuration).unit;
if (/year|month|week/.test(slotUnit)) {
largeUnit = slotUnit;
}
}
tDateProfile.largeUnit = largeUnit;
tDateProfile.emphasizeWeeks =
core.isSingleDay(tDateProfile.slotDuration) &&
currentRangeAs('weeks', dateProfile, dateEnv) >= 2 &&
!view.opt('businessHours');
/*
console.log('label interval =', timelineView.labelInterval.humanize())
console.log('slot duration =', timelineView.slotDuration.humanize())
console.log('header formats =', timelineView.headerFormats)
console.log('isTimeScale', timelineView.isTimeScale)
console.log('largeUnit', timelineView.largeUnit)
*/
var rawSnapDuration = view.opt('snapDuration');
var snapDuration;
var snapsPerSlot;
if (rawSnapDuration) {
snapDuration = core.createDuration(rawSnapDuration);
snapsPerSlot = core.wholeDivideDurations(tDateProfile.slotDuration, snapDuration);
// ^ TODO: warning if not whole?
}
if (snapsPerSlot == null) {
snapDuration = tDateProfile.slotDuration;
snapsPerSlot = 1;
}
tDateProfile.snapDuration = snapDuration;
tDateProfile.snapsPerSlot = snapsPerSlot;
// more...
var timeWindowMs = core.asRoughMs(dateProfile.maxTime) - core.asRoughMs(dateProfile.minTime);
// TODO: why not use normalizeRange!?
var normalizedStart = normalizeDate(dateProfile.renderRange.start, tDateProfile, dateEnv);
var normalizedEnd = normalizeDate(dateProfile.renderRange.end, tDateProfile, dateEnv);
// apply minTime/maxTime
// TODO: View should be responsible.
if (tDateProfile.isTimeScale) {
normalizedStart = dateEnv.add(normalizedStart, dateProfile.minTime);
normalizedEnd = dateEnv.add(core.addDays(normalizedEnd, -1), dateProfile.maxTime);
}
tDateProfile.timeWindowMs = timeWindowMs;
tDateProfile.normalizedRange = { start: normalizedStart, end: normalizedEnd };
var slotDates = [];
var date = normalizedStart;
while (date < normalizedEnd) {
if (isValidDate(date, tDateProfile, dateProfile, view)) {
slotDates.push(date);
}
date = dateEnv.add(date, tDateProfile.slotDuration);
}
tDateProfile.slotDates = slotDates;
// more...
var snapIndex = -1;
var snapDiff = 0; // index of the diff :(
var snapDiffToIndex = [];
var snapIndexToDiff = [];
date = normalizedStart;
while (date < normalizedEnd) {
if (isValidDate(date, tDateProfile, dateProfile, view)) {
snapIndex++;
snapDiffToIndex.push(snapIndex);
snapIndexToDiff.push(snapDiff);
}
else {
snapDiffToIndex.push(snapIndex + 0.5);
}
date = dateEnv.add(date, tDateProfile.snapDuration);
snapDiff++;
}
tDateProfile.snapDiffToIndex = snapDiffToIndex;
tDateProfile.snapIndexToDiff = snapIndexToDiff;
tDateProfile.snapCnt = snapIndex + 1; // is always one behind
tDateProfile.slotCnt = tDateProfile.snapCnt / tDateProfile.snapsPerSlot;
// more...
tDateProfile.isWeekStarts = buildIsWeekStarts(tDateProfile, dateEnv);
tDateProfile.cellRows = buildCellRows(tDateProfile, dateEnv, view);
return tDateProfile;
}
/*
snaps to appropriate unit
*/
function normalizeDate(date, tDateProfile, dateEnv) {
var normalDate = date;
if (!tDateProfile.isTimeScale) {
normalDate = core.startOfDay(normalDate);
if (tDateProfile.largeUnit) {
normalDate = dateEnv.startOf(normalDate, tDateProfile.largeUnit);
}
}
return normalDate;
}
/*
snaps to appropriate unit
*/
function normalizeRange(range, tDateProfile, dateEnv) {
if (!tDateProfile.isTimeScale) {
range = core.computeVisibleDayRange(range);
if (tDateProfile.largeUnit) {
var dayRange = range; // preserve original result
range = {
start: dateEnv.startOf(range.start, tDateProfile.largeUnit),
end: dateEnv.startOf(range.end, tDateProfile.largeUnit)
};
// if date is partially through the interval, or is in the same interval as the start,
// make the exclusive end be the *next* interval
if (range.end.valueOf() !== dayRange.end.valueOf() || range.end <= range.start) {
range = {
start: range.start,
end: dateEnv.add(range.end, tDateProfile.slotDuration)
};
}
}
}
return range;
}
function isValidDate(date, tDateProfile, dateProfile, view) {
if (view.dateProfileGenerator.isHiddenDay(date)) {
return false;
}
else if (tDateProfile.isTimeScale) {
// determine if the time is within minTime/maxTime, which may have wacky values
var day = core.startOfDay(date);
var timeMs = date.valueOf() - day.valueOf();
var ms = timeMs - core.asRoughMs(dateProfile.minTime); // milliseconds since minTime
ms = ((ms % 86400000) + 86400000) % 86400000; // make negative values wrap to 24hr clock
return ms < tDateProfile.timeWindowMs; // before the maxTime?
}
else {
return true;
}
}
function queryDurationOption(view, name) {
var input = view.opt(name);
if (input != null) {
return core.createDuration(input);
}
}
function validateLabelAndSlot(tDateProfile, dateProfile, dateEnv) {
var currentRange = dateProfile.currentRange;
// make sure labelInterval doesn't exceed the max number of cells
if (tDateProfile.labelInterval) {
var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.labelInterval);
if (labelCnt > core.config.MAX_TIMELINE_SLOTS) {
console.warn('slotLabelInterval results in too many cells');
tDateProfile.labelInterval = null;
}
}
// make sure slotDuration doesn't exceed the maximum number of cells
if (tDateProfile.slotDuration) {
var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.slotDuration);
if (slotCnt > core.config.MAX_TIMELINE_SLOTS) {
console.warn('slotDuration results in too many cells');
tDateProfile.slotDuration = null;
}
}
// make sure labelInterval is a multiple of slotDuration
if (tDateProfile.labelInterval && tDateProfile.slotDuration) {
var slotsPerLabel = core.wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
if (slotsPerLabel === null || slotsPerLabel < 1) {
console.warn('slotLabelInterval must be a multiple of slotDuration');
tDateProfile.slotDuration = null;
}
}
}
function ensureLabelInterval(tDateProfile, dateProfile, dateEnv) {
var currentRange = dateProfile.currentRange;
var labelInterval = tDateProfile.labelInterval;
if (!labelInterval) {
// compute based off the slot duration
// find the largest label interval with an acceptable slots-per-label
var input = void 0;
if (tDateProfile.slotDuration) {
for (var _i = 0, STOCK_SUB_DURATIONS_1 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_1.length; _i++) {
input = STOCK_SUB_DURATIONS_1[_i];
var tryLabelInterval = core.createDuration(input);
var slotsPerLabel = core.wholeDivideDurations(tryLabelInterval, tDateProfile.slotDuration);
if (slotsPerLabel !== null && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
labelInterval = tryLabelInterval;
break;
}
}
// use the slot duration as a last resort
if (!labelInterval) {
labelInterval = tDateProfile.slotDuration;
}
// compute based off the view's duration
// find the largest label interval that yields the minimum number of labels
}
else {
for (var _a = 0, STOCK_SUB_DURATIONS_2 = STOCK_SUB_DURATIONS; _a < STOCK_SUB_DURATIONS_2.length; _a++) {
input = STOCK_SUB_DURATIONS_2[_a];
labelInterval = core.createDuration(input);
var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, labelInterval);
if (labelCnt >= MIN_AUTO_LABELS) {
break;
}
}
}
tDateProfile.labelInterval = labelInterval;
}
return labelInterval;
}
function ensureSlotDuration(tDateProfile, dateProfile, dateEnv) {
var currentRange = dateProfile.currentRange;
var slotDuration = tDateProfile.slotDuration;
if (!slotDuration) {
var labelInterval = ensureLabelInterval(tDateProfile, dateProfile, dateEnv); // will compute if necessary
// compute based off the label interval
// find the largest slot duration that is different from labelInterval, but still acceptable
for (var _i = 0, STOCK_SUB_DURATIONS_3 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_3.length; _i++) {
var input = STOCK_SUB_DURATIONS_3[_i];
var trySlotDuration = core.createDuration(input);
var slotsPerLabel = core.wholeDivideDurations(labelInterval, trySlotDuration);
if (slotsPerLabel !== null && slotsPerLabel > 1 && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
slotDuration = trySlotDuration;
break;
}
}
// only allow the value if it won't exceed the view's # of slots limit
if (slotDuration) {
var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, slotDuration);
if (slotCnt > MAX_AUTO_CELLS) {
slotDuration = null;
}
}
// use the label interval as a last resort
if (!slotDuration) {
slotDuration = labelInterval;
}
tDateProfile.slotDuration = slotDuration;
}
return slotDuration;
}
function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, view) {
var format1;
var format2;
var labelInterval = tDateProfile.labelInterval;
var unit = core.greatestDurationDenominator(labelInterval).unit;
var weekNumbersVisible = view.opt('weekNumbers');
var format0 = (format1 = (format2 = null));
// NOTE: weekNumber computation function wont work
if ((unit === 'week') && !weekNumbersVisible) {
unit = 'day';
}
switch (unit) {
case 'year':
format0 = { year: 'numeric' }; // '2015'
break;
case 'month':
if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
format0 = { year: 'numeric' }; // '2015'
}
format1 = { month: 'short' }; // 'Jan'
break;
case 'week':
if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
format0 = { year: 'numeric' }; // '2015'
}
format1 = { week: 'narrow' }; // 'Wk4'
break;
case 'day':
if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
format0 = { year: 'numeric', month: 'long' }; // 'January 2014'
}
else if (currentRangeAs('months', dateProfile, dateEnv) > 1) {
format0 = { month: 'long' }; // 'January'
}
if (weekNumbersVisible) {
format1 = { week: 'short' }; // 'Wk 4'
}
format2 = { weekday: 'narrow', day: 'numeric' }; // 'Su 9'
break;
case 'hour':
if (weekNumbersVisible) {
format0 = { week: 'short' }; // 'Wk 4'
}
if (currentRangeAs('days', dateProfile, dateEnv) > 1) {
format1 = { weekday: 'short', day: 'numeric', month: 'numeric', omitCommas: true }; // Sat 4/7
}
format2 = {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short'
};
break;
case 'minute':
// sufficiently large number of different minute cells?
if ((core.asRoughMinutes(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
format0 = {
hour: 'numeric',
meridiem: 'short'
};
format1 = function (params) {
return ':' + core.padStart(params.date.minute, 2); // ':30'
};
}
else {
format0 = {
hour: 'numeric',
minute: 'numeric',
meridiem: 'short'
};
}
break;
case 'second':
// sufficiently large number of different second cells?
if ((core.asRoughSeconds(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
format0 = { hour: 'numeric', minute: '2-digit', meridiem: 'lowercase' }; // '8:30 PM'
format1 = function (params) {
return ':' + core.padStart(params.date.second, 2); // ':30'
};
}
else {
format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM'
}
break;
case 'millisecond':
format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM'
format1 = function (params) {
return '.' + core.padStart(params.millisecond, 3);
};
break;
}
return [].concat(format0 || [], format1 || [], format2 || []);
}
// Compute the number of the give units in the "current" range.
// Won't go more precise than days.
// Will return `0` if there's not a clean whole interval.
function currentRangeAs(unit, dateProfile, dateEnv) {
var range = dateProfile.currentRange;
var res = null;
if (unit === 'years') {
res = dateEnv.diffWholeYears(range.start, range.end);
}
else if (unit === 'months') {
res = dateEnv.diffWholeMonths(range.start, range.end);
}
else if (unit === 'weeks') {
res = dateEnv.diffWholeMonths(range.start, range.end);
}
else if (unit === 'days') {
res = core.diffWholeDays(range.start, range.end);
}
return res || 0;
}
function buildIsWeekStarts(tDateProfile, dateEnv) {
var slotDates = tDateProfile.slotDates, emphasizeWeeks = tDateProfile.emphasizeWeeks;
var prevWeekNumber = null;
var isWeekStarts = [];
for (var _i = 0, slotDates_1 = slotDates; _i < slotDates_1.length; _i++) {
var slotDate = slotDates_1[_i];
var weekNumber = dateEnv.computeWeekNumber(slotDate);
var isWeekStart = emphasizeWeeks && (prevWeekNumber !== null) && (prevWeekNumber !== weekNumber);
prevWeekNumber = weekNumber;
isWeekStarts.push(isWeekStart);
}
return isWeekStarts;
}
function buildCellRows(tDateProfile, dateEnv, view) {
var slotDates = tDateProfile.slotDates;
var formats = tDateProfile.headerFormats;
var cellRows = formats.map(function (format) { return []; }); // indexed by row,col
// specifically for navclicks
var rowUnits = formats.map(function (format) {
return format.getLargestUnit ? format.getLargestUnit() : null;
});
// builds cellRows and slotCells
for (var i = 0; i < slotDates.length; i++) {
var date = slotDates[i];
var isWeekStart = tDateProfile.isWeekStarts[i];
for (var row = 0; row < formats.length; row++) {
var format = formats[row];
var rowCells = cellRows[row];
var leadingCell = rowCells[rowCells.length - 1];
var isSuperRow = (formats.length > 1) && (row < (formats.length - 1)); // more than one row and not the last
var newCell = null;
if (isSuperRow) {
var text = dateEnv.format(date, format);
if (!leadingCell || (leadingCell.text !== text)) {
newCell = buildCellObject(date, text, rowUnits[row], view);
}
else {
leadingCell.colspan += 1;
}
}
else {
if (!leadingCell ||
core.isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval))) {
var text = dateEnv.format(date, format);
newCell = buildCellObject(date, text, rowUnits[row], view);
}
else {
leadingCell.colspan += 1;
}
}
if (newCell) {
newCell.weekStart = isWeekStart;
rowCells.push(newCell);
}
}
}
return cellRows;
}
function buildCellObject(date, text, rowUnit, view) {
var spanHtml = core.buildGotoAnchorHtml(view, {
date: date,
type: rowUnit,
forceOff: !rowUnit
}, {
'class': 'fc-cell-text'
}, core.htmlEscape(text));
return { text: text, spanHtml: spanHtml, date: date, colspan: 1, isWeekStart: false };
}
var TimelineNowIndicator = /** @class */ (function () {
function TimelineNowIndicator(headParent, bodyParent) {
this.headParent = headParent;
this.bodyParent = bodyParent;
}
TimelineNowIndicator.prototype.render = function (coord, isRtl) {
var styleProps = isRtl ? { right: -coord } : { left: coord };
this.headParent.appendChild(this.arrowEl = core.createElement('div', {
className: 'fc-now-indicator fc-now-indicator-arrow',
style: styleProps
}));
this.bodyParent.appendChild(this.lineEl = core.createElement('div', {
className: 'fc-now-indicator fc-now-indicator-line',
style: styleProps
}));
};
TimelineNowIndicator.prototype.unrender = function () {
if (this.arrowEl) {
core.removeElement(this.arrowEl);
}
if (this.lineEl) {
core.removeElement(this.lineEl);
}
};
return TimelineNowIndicator;
}());
var STICKY_PROP_VAL = computeStickyPropVal(); // if null, means not supported at all
var IS_MS_EDGE = /Edge/.test(navigator.userAgent);
var IS_SAFARI = STICKY_PROP_VAL === '-webkit-sticky'; // good b/c doesn't confuse chrome
var STICKY_CLASSNAME = 'fc-sticky';
/*
useful beyond the native position:sticky for these reasons:
- support in IE11
- nice centering support
*/
var StickyScroller = /** @class */ (function () {
function StickyScroller(scroller, isRtl, isVertical) {
var _this = this;
this.usingRelative = null;
/*
known bug: called twice on init. problem when mixing with ScrollJoiner
*/
this.updateSize = function () {
var els = Array.prototype.slice.call(_this.scroller.canvas.el.querySelectorAll('.' + STICKY_CLASSNAME));
var elGeoms = _this.queryElGeoms(els);
var viewportWidth = _this.scroller.el.clientWidth;
if (_this.usingRelative) {
var elDestinations = _this.computeElDestinations(elGeoms, viewportWidth); // read before prepPositioning
assignRelativePositions(els, elGeoms, elDestinations);
}
else {
assignStickyPositions(els, elGeoms, viewportWidth);
}
};
this.scroller = scroller;
this.usingRelative =
!STICKY_PROP_VAL || // IE11
(IS_MS_EDGE && isRtl) || // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/18883305/
((IS_MS_EDGE || IS_SAFARI) && isVertical); // because doesn't work with rowspan in tables, our only vertial use
if (this.usingRelative) {
scroller.on('scrollEnd', this.updateSize);
}
}
StickyScroller.prototype.destroy = function () {
this.scroller.off('scrollEnd', this.updateSize);
};
StickyScroller.prototype.queryElGeoms = function (els) {
var canvasOrigin = this.scroller.canvas.el.getBoundingClientRect();
var elGeoms = [];
for (var _i = 0, els_1 = els; _i < els_1.length; _i++) {
var el = els_1[_i];
var parentBound = core.translateRect(el.parentNode.getBoundingClientRect(), -canvasOrigin.left, -canvasOrigin.top);
var elRect = el.getBoundingClientRect();
var computedStyles = window.getComputedStyle(el);
var computedTextAlign = window.getComputedStyle(el.parentNode).textAlign; // ask the parent
var intendedTextAlign = computedTextAlign;
var naturalBound = null;
if (computedStyles.position !== 'sticky') {
naturalBound = core.translateRect(elRect, -canvasOrigin.left - (parseFloat(computedStyles.left) || 0), // could be 'auto'
-canvasOrigin.top - (parseFloat(computedStyles.top) || 0));
}
if (el.hasAttribute('data-sticky-center')) {
intendedTextAlign = 'center';
}
elGeoms.push({
parentBound: parentBound,
naturalBound: naturalBound,
elWidth: elRect.width,
elHeight: elRect.height,
computedTextAlign: computedTextAlign,
intendedTextAlign: intendedTextAlign
});
}
return elGeoms;
};
StickyScroller.prototype.computeElDestinations = function (elGeoms, viewportWidth) {
var viewportLeft = this.scroller.getScrollFromLeft();
var viewportTop = this.scroller.getScrollTop();
var viewportRight = viewportLeft + viewportWidth;
return elGeoms.map(function (elGeom) {
var elWidth = elGeom.elWidth, elHeight = elGeom.elHeight, parentBound = elGeom.parentBound, naturalBound = elGeom.naturalBound;
var destLeft; // relative to canvas topleft
var destTop; // "
switch (elGeom.intendedTextAlign) {
case 'left':
destLeft = viewportLeft;
break;
case 'right':
destLeft = viewportRight - elWidth;
break;
case 'center':
destLeft = (viewportLeft + viewportRight) / 2 - elWidth / 2;
break;
}
destLeft = Math.min(destLeft, parentBound.right - elWidth);
destLeft = Math.max(destLeft, parentBound.left);
destTop = viewportTop;
destTop = Math.min(destTop, parentBound.bottom - elHeight);
destTop = Math.max(destTop, naturalBound.top); // better to use natural top for upper bound
return { left: destLeft, top: destTop };
});
};
return StickyScroller;
}());
function assignRelativePositions(els, elGeoms, elDestinations) {
els.forEach(function (el, i) {
var naturalBound = elGeoms[i].naturalBound;
core.applyStyle(el, {
position: 'relative',
left: elDestinations[i].left - naturalBound.left,
top: elDestinations[i].top - naturalBound.top
});
});
}
function assignStickyPositions(els, elGeoms, viewportWidth) {
els.forEach(function (el, i) {
var stickyLeft = 0;
if (elGeoms[i].intendedTextAlign === 'center') {
stickyLeft = (viewportWidth - elGeoms[i].elWidth) / 2;
// needs to be forced to left?
if (elGeoms[i].computedTextAlign === 'center') {
el.setAttribute('data-sticky-center', '') // remember for next queryElGeoms
;
el.parentNode.style.textAlign = 'left';
}
}
core.applyStyle(el, {
position: STICKY_PROP_VAL,
left: stickyLeft,
right: 0,
top: 0
});
});
}
function computeStickyPropVal() {
var el = core.htmlToElement('<div style="position:-webkit-sticky;position:sticky"></div>');
var val = el.style.position;
if (val.indexOf('sticky') !== -1) {
return val;
}
else {
return null;
}
}
var TimeAxis = /** @class */ (function (_super) {
__extends(TimeAxis, _super);
function TimeAxis(context, headerContainerEl, bodyContainerEl) {
var _this = _super.call(this, context) || this;
var layout = _this.layout = new HeaderBodyLayout(headerContainerEl, bodyContainerEl, 'auto');
var headerEnhancedScroller = layout.headerScroller.enhancedScroll;
var bodyEnhancedScroller = layout.bodyScroller.enhancedScroll;
// needs to go after layout, which has ScrollJoiner
_this.headStickyScroller = new StickyScroller(headerEnhancedScroller, _this.isRtl, false); // isVertical=false
_this.bodyStickyScroller = new StickyScroller(bodyEnhancedScroller, _this.isRtl, false); // isVertical=false
_this.header = new TimelineHeader(context, headerEnhancedScroller.canvas.contentEl);
_this.slats = new TimelineSlats(context, bodyEnhancedScroller.canvas.bgEl);
_this.nowIndicator = new TimelineNowIndicator(headerEnhancedScroller.canvas.el, bodyEnhancedScroller.canvas.el);
return _this;
}
TimeAxis.prototype.destroy = function () {
this.layout.destroy();
this.header.destroy();
this.slats.destroy();
this.nowIndicator.unrender();
this.headStickyScroller.destroy();
this.bodyStickyScroller.destroy();
_super.prototype.destroy.call(this);
};
TimeAxis.prototype.render = function (props) {
var tDateProfile = this.tDateProfile =
buildTimelineDateProfile(props.dateProfile, this.view); // TODO: cache
this.header.receiveProps({
dateProfile: props.dateProfile,
tDateProfile: tDateProfile
});
this.slats.receiveProps({
dateProfile: props.dateProfile,
tDateProfile: tDateProfile
});
};
// Now Indicator
// ------------------------------------------------------------------------------------------
TimeAxis.prototype.getNowIndicatorUnit = function (dateProfile) {
// yuck
var tDateProfile = this.tDateProfile =
buildTimelineDateProfile(dateProfile, this.view); // TODO: cache
if (tDateProfile.isTimeScale) {
return core.greatestDurationDenominator(tDateProfile.slotDuration).unit;
}
};
// will only execute if isTimeScale
TimeAxis.prototype.renderNowIndicator = function (date) {
if (core.rangeContainsMarker(this.tDateProfile.normalizedRange, date)) {
this.nowIndicator.render(this.dateToCoord(date), this.isRtl);
}
};
// will only execute if isTimeScale
TimeAxis.prototype.unrenderNowIndicator = function () {
this.nowIndicator.unrender();
};
// Sizing
// ------------------------------------------------------------------------------------------
TimeAxis.prototype.updateSize = function (isResize, totalHeight, isAuto) {
this.applySlotWidth(this.computeSlotWidth());
// adjusts gutters. do after slot widths set
this.layout.setHeight(totalHeight, isAuto);
// pretty much just queries coords. do last
this.slats.updateSize();
};
TimeAxis.prototype.updateStickyScrollers = function () {
this.headStickyScroller.updateSize();
this.bodyStickyScroller.updateSize();
};
TimeAxis.prototype.computeSlotWidth = function () {
var slotWidth = this.opt('slotWidth') || '';
if (slotWidth === '') {
slotWidth = this.computeDefaultSlotWidth(this.tDateProfile);
}
return slotWidth;
};
TimeAxis.prototype.computeDefaultSlotWidth = function (tDateProfile) {
var maxInnerWidth = 0; // TODO: harness core's `matchCellWidths` for this
this.header.innerEls.forEach(function (innerEl, i) {
maxInnerWidth = Math.max(maxInnerWidth, innerEl.getBoundingClientRect().width);
});
var headingCellWidth = Math.ceil(maxInnerWidth) + 1; // assume no padding, and one pixel border
// in TimelineView.defaults we ensured that labelInterval is an interval of slotDuration
// TODO: rename labelDuration?
var slotsPerLabel = core.wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
var slotWidth = Math.ceil(headingCellWidth / slotsPerLabel);
var minWidth = window.getComputedStyle(this.header.slatColEls[0]).minWidth;
if (minWidth) {
minWidth = parseInt(minWidth, 10);
if (minWidth) {
slotWidth = Math.max(slotWidth, minWidth);
}
}
return slotWidth;
};
TimeAxis.prototype.applySlotWidth = function (slotWidth) {
var _a = this, layout = _a.layout, tDateProfile = _a.tDateProfile;
var containerWidth = '';
var containerMinWidth = '';
var nonLastSlotWidth = '';
if (slotWidth !== '') {
slotWidth = Math.round(slotWidth);
containerWidth = slotWidth * tDateProfile.slotDates.length;
containerMinWidth = '';
nonLastSlotWidth = slotWidth;
var availableWidth = layout.bodyScroller.enhancedScroll.getClientWidth();
if (availableWidth > containerWidth) {
containerMinWidth = availableWidth;
containerWidth = '';
nonLastSlotWidth = Math.floor(availableWidth / tDateProfile.slotDates.length);
}
}
layout.headerScroller.enhancedScroll.canvas.setWidth(containerWidth);
layout.headerScroller.enhancedScroll.canvas.setMinWidth(containerMinWidth);
layout.bodyScroller.enhancedScroll.canvas.setWidth(containerWidth);
layout.bodyScroller.enhancedScroll.canvas.setMinWidth(containerMinWidth);
if (nonLastSlotWidth !== '') {
this.header.slatColEls.slice(0, -1).concat(this.slats.slatColEls.slice(0, -1)).forEach(function (el) {
el.style.width = nonLastSlotWidth + 'px';
});
}
};
// returned value is between 0 and the number of snaps
TimeAxis.prototype.computeDateSnapCoverage = function (date) {
var _a = this, dateEnv = _a.dateEnv, tDateProfile = _a.tDateProfile;
var snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
if (snapDiff < 0) {
return 0;
}
else if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
return tDateProfile.snapCnt;
}
else {
var snapDiffInt = Math.floor(snapDiff);
var snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
if (core.isInt(snapCoverage)) { // not an in-between value
snapCoverage += snapDiff - snapDiffInt; // add the remainder
}
else {
// a fractional value, meaning the date is not visible
// always round up in this case. works for start AND end dates in a range.
snapCoverage = Math.ceil(snapCoverage);
}
return snapCoverage;
}
};
// for LTR, results range from 0 to width of area
// for RTL, results range from negative width of area to 0
TimeAxis.prototype.dateToCoord = function (date) {
var tDateProfile = this.tDateProfile;
var snapCoverage = this.computeDateSnapCoverage(date);
var slotCoverage = snapCoverage / tDateProfile.snapsPerSlot;
var slotIndex = Math.floor(slotCoverage);
slotIndex = Math.min(slotIndex, tDateProfile.slotCnt - 1);
var partial = slotCoverage - slotIndex;
var _a = this.slats, innerCoordCache = _a.innerCoordCache, outerCoordCache = _a.outerCoordCache;
if (this.isRtl) {
return (outerCoordCache.rights[slotIndex] -
(innerCoordCache.getWidth(slotIndex) * partial)) - outerCoordCache.originClientRect.width;
}
else {
return (outerCoordCache.lefts[slotIndex] +
(innerCoordCache.getWidth(slotIndex) * partial));
}
};
TimeAxis.prototype.rangeToCoords = function (range) {
if (this.isRtl) {
return { right: this.dateToCoord(range.start), left: this.dateToCoord(range.end) };
}
else {
return { left: this.dateToCoord(range.start), right: this.dateToCoord(range.end) };
}
};
// Scrolling
// ------------------------------------------------------------------------------------------
TimeAxis.prototype.computeDateScroll = function (duration) {
var dateEnv = this.dateEnv;
var dateProfile = this.props.dateProfile;
var left = 0;
if (dateProfile) {
left = this.dateToCoord(dateEnv.add(core.startOfDay(dateProfile.activeRange.start), // startOfDay needed?
duration));
// hack to overcome the left borders of non-first slat
if (!this.isRtl && left) {
left += 1;
}
}
return { left: left };
};
TimeAxis.prototype.queryDateScroll = function () {
var enhancedScroll = this.layout.bodyScroller.enhancedScroll;
return {
left: enhancedScroll.getScrollLeft()
};
};
TimeAxis.prototype.applyDateScroll = function (scroll) {
// TODO: lame we have to update both. use the scrolljoiner instead maybe
this.layout.bodyScroller.enhancedScroll.setScrollLeft(scroll.left || 0);
this.layout.headerScroller.enhancedScroll.setScrollLeft(scroll.left || 0);
};
return TimeAxis;
}(core.Component));
var TimelineLaneEventRenderer = /** @class */ (function (_super) {
__extends(TimelineLaneEventRenderer, _super);
function TimelineLaneEventRenderer(context, masterContainerEl, timeAxis) {
var _this = _super.call(this, context) || this;
_this.masterContainerEl = masterContainerEl;
_this.timeAxis = timeAxis;
return _this;
}
TimelineLaneEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) {
var view = this.context.view;
var eventRange = seg.eventRange;
var eventDef = eventRange.def;
var eventUi = eventRange.ui;
var isDraggable = view.computeEventDraggable(eventDef, eventUi);
var isResizableFromStart = seg.isStart && view.computeEventStartResizable(eventDef, eventUi);
var isResizableFromEnd = seg.isEnd && view.computeEventEndResizable(eventDef, eventUi);
var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo);
classes.unshift('fc-timeline-event', 'fc-h-event');
var timeText = this.getTimeText(eventRange);
return '<a class="' + classes.join(' ') + '" style="' + core.cssToStr(this.getSkinCss(eventUi)) + '"' +
(eventDef.url ?
' href="' + core.htmlEscape(eventDef.url) + '"' :
'') +
'>' +
(timeText ?
'<span class="fc-time-wrap">' +
'<span class="fc-time">' +
core.htmlEscape(timeText) +
'</span>' +
'</span>'
:
'') +
'<span class="fc-title-wrap">' +
'<span class="fc-title fc-sticky">' +
(eventDef.title ? core.htmlEscape(eventDef.title) : '&nbsp;') +
'</span>' +
'</span>' +
(isResizableFromStart ?
'<div class="fc-resizer fc-start-resizer"></div>' :
'') +
(isResizableFromEnd ?
'<div class="fc-resizer fc-end-resizer"></div>' :
'') +
'</a>';
};
TimelineLaneEventRenderer.prototype.computeDisplayEventTime = function () {
return !this.timeAxis.tDateProfile.isTimeScale; // because times should be obvious via axis
};
TimelineLaneEventRenderer.prototype.computeDisplayEventEnd = function () {
return false;
};
// Computes a default event time formatting string if `timeFormat` is not explicitly defined
TimelineLaneEventRenderer.prototype.computeEventTimeFormat = function () {
return {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'narrow'
};
};
TimelineLaneEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) {
if (!this.el && this.masterContainerEl) {
this.el = core.createElement('div', { className: 'fc-event-container' });
if (mirrorInfo) {
this.el.classList.add('fc-mirror-container');
}
this.masterContainerEl.appendChild(this.el);
}
if (this.el) {
for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
var seg = segs_1[_i];
this.el.appendChild(seg.el);
}
}
};
TimelineLaneEventRenderer.prototype.detachSegs = function (segs) {
for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
var seg = segs_2[_i];
core.removeElement(seg.el);
}
};
// computes AND assigns (assigns the left/right at least). bad
TimelineLaneEventRenderer.prototype.computeSegSizes = function (segs) {
var timeAxis = this.timeAxis;
for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) {
var seg = segs_3[_i];
var coords = timeAxis.rangeToCoords(seg); // works because Seg has start/end
core.applyStyle(seg.el, {
left: (seg.left = coords.left),
right: -(seg.right = coords.right)
});
}
};
TimelineLaneEventRenderer.prototype.assignSegSizes = function (segs) {
if (!this.el) {
return;
}
// compute seg verticals
for (var _i = 0, segs_4 = segs; _i < segs_4.length; _i++) {
var seg = segs_4[_i];
seg.height = core.computeHeightAndMargins(seg.el);
}
this.buildSegLevels(segs); // populates above/below props for computeOffsetForSegs
var totalHeight = computeOffsetForSegs(segs); // also assigns seg.top
core.applyStyleProp(this.el, 'height', totalHeight);
// assign seg verticals
for (var _a = 0, segs_5 = segs; _a < segs_5.length; _a++) {
var seg = segs_5[_a];
core.applyStyleProp(seg.el, 'top', seg.top);
}
};
TimelineLaneEventRenderer.prototype.buildSegLevels = function (segs) {
var segLevels = [];
segs = this.sortEventSegs(segs);
for (var _i = 0, segs_6 = segs; _i < segs_6.length; _i++) {
var unplacedSeg = segs_6[_i];
unplacedSeg.above = [];
// determine the first level with no collisions
var level = 0; // level index
while (level < segLevels.length) {
var isLevelCollision = false;
// determine collisions
for (var _a = 0, _b = segLevels[level]; _a < _b.length; _a++) {
var placedSeg = _b[_a];
if (timeRowSegsCollide(unplacedSeg, placedSeg)) {
unplacedSeg.above.push(placedSeg);
isLevelCollision = true;
}
}
if (isLevelCollision) {
level += 1;
}
else {
break;
}
}
// insert into the first non-colliding level. create if necessary
(segLevels[level] || (segLevels[level] = []))
.push(unplacedSeg);
// record possible colliding segments below (TODO: automated test for this)
level += 1;
while (level < segLevels.length) {
for (var _c = 0, _d = segLevels[level]; _c < _d.length; _c++) {
var belowSeg = _d[_c];
if (timeRowSegsCollide(unplacedSeg, belowSeg)) {
belowSeg.above.push(unplacedSeg);
}
}
level += 1;
}
}
return segLevels;
};
return TimelineLaneEventRenderer;
}(core.FgEventRenderer));
function computeOffsetForSegs(segs) {
var max = 0;
for (var _i = 0, segs_7 = segs; _i < segs_7.length; _i++) {
var seg = segs_7[_i];
max = Math.max(max, computeOffsetForSeg(seg));
}
return max;
}
function computeOffsetForSeg(seg) {
if ((seg.top == null)) {
seg.top = computeOffsetForSegs(seg.above);
}
return seg.top + seg.height;
}
function timeRowSegsCollide(seg0, seg1) {
return (seg0.left < seg1.right) && (seg0.right > seg1.left);
}
var TimelineLaneFillRenderer = /** @class */ (function (_super) {
__extends(TimelineLaneFillRenderer, _super);
function TimelineLaneFillRenderer(context, masterContainerEl, timeAxis) {
var _this = _super.call(this, context) || this;
_this.masterContainerEl = masterContainerEl;
_this.timeAxis = timeAxis;
return _this;
}
TimelineLaneFillRenderer.prototype.attachSegs = function (type, segs) {
if (segs.length) {
var className = void 0;
if (type === 'businessHours') {
className = 'bgevent';
}
else {
className = type.toLowerCase();
}
// making a new container each time is OKAY
// all types of segs (background or business hours or whatever) are rendered in one pass
var containerEl = core.createElement('div', { className: 'fc-' + className + '-container' });
this.masterContainerEl.appendChild(containerEl);
for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
var seg = segs_1[_i];
containerEl.appendChild(seg.el);
}
return [containerEl]; // return value
}
};
TimelineLaneFillRenderer.prototype.computeSegSizes = function (segs) {
var timeAxis = this.timeAxis;
for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
var seg = segs_2[_i];
var coords = timeAxis.rangeToCoords(seg);
seg.left = coords.left;
seg.right = coords.right;
}
};
TimelineLaneFillRenderer.prototype.assignSegSizes = function (segs) {
for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) {
var seg = segs_3[_i];
core.applyStyle(seg.el, {
left: seg.left,
right: -seg.right
});
}
};
return TimelineLaneFillRenderer;
}(core.FillRenderer));
var TimelineLane = /** @class */ (function (_super) {
__extends(TimelineLane, _super);
function TimelineLane(context, fgContainerEl, bgContainerEl, timeAxis) {
var _this = _super.call(this, context, bgContainerEl) // should el be bgContainerEl???
|| this;
_this.slicer = new TimelineLaneSlicer();
_this.renderEventDrag = core.memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag);
_this.renderEventResize = core.memoizeRendering(_this._renderEventResize, _this._unrenderEventResize);
var fillRenderer = _this.fillRenderer = new TimelineLaneFillRenderer(context, bgContainerEl, timeAxis);
var eventRenderer = _this.eventRenderer = new TimelineLaneEventRenderer(context, fgContainerEl, timeAxis);
_this.mirrorRenderer = new TimelineLaneEventRenderer(context, fgContainerEl, timeAxis);
_this.renderBusinessHours = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'));
_this.renderDateSelection = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'highlight'), fillRenderer.unrender.bind(fillRenderer, 'highlight'));
_this.renderBgEvents = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'));
_this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer));
_this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]);
_this.timeAxis = timeAxis;
return _this;
}
TimelineLane.prototype.render = function (props) {
var slicedProps = this.slicer.sliceProps(props, props.dateProfile, this.timeAxis.tDateProfile.isTimeScale ? null : props.nextDayThreshold, this, this.timeAxis);
this.renderBusinessHours(slicedProps.businessHourSegs);
this.renderDateSelection(slicedProps.dateSelectionSegs);
this.renderBgEvents(slicedProps.bgEventSegs);
this.renderFgEvents(slicedProps.fgEventSegs);
this.renderEventSelection(slicedProps.eventSelection);
this.renderEventDrag(slicedProps.eventDrag);
this.renderEventResize(slicedProps.eventResize);
};
TimelineLane.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.renderBusinessHours.unrender();
this.renderDateSelection.unrender();
this.renderBgEvents.unrender();
this.renderFgEvents.unrender();
this.renderEventSelection.unrender();
this.renderEventDrag.unrender();
this.renderEventResize.unrender();
};
TimelineLane.prototype._renderEventDrag = function (state) {
if (state) {
this.eventRenderer.hideByHash(state.affectedInstances);
this.mirrorRenderer.renderSegs(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype._unrenderEventDrag = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.mirrorRenderer.unrender(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype._renderEventResize = function (state) {
if (state) {
// HACK. eventRenderer and fillRenderer both use these segs. would compete over seg.el
var segsForHighlight = state.segs.map(function (seg) {
return __assign({}, seg);
});
this.eventRenderer.hideByHash(state.affectedInstances);
this.fillRenderer.renderSegs('highlight', segsForHighlight);
this.mirrorRenderer.renderSegs(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype._unrenderEventResize = function (state) {
if (state) {
this.eventRenderer.showByHash(state.affectedInstances);
this.fillRenderer.unrender('highlight');
this.mirrorRenderer.unrender(state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
}
};
TimelineLane.prototype.updateSize = function (isResize) {
var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer;
fillRenderer.computeSizes(isResize);
eventRenderer.computeSizes(isResize);
mirrorRenderer.computeSizes(isResize);
fillRenderer.assignSizes(isResize);
eventRenderer.assignSizes(isResize);
mirrorRenderer.assignSizes(isResize);
};
return TimelineLane;
}(core.DateComponent));
var TimelineLaneSlicer = /** @class */ (function (_super) {
__extends(TimelineLaneSlicer, _super);
function TimelineLaneSlicer() {
return _super !== null && _super.apply(this, arguments) || this;
}
TimelineLaneSlicer.prototype.sliceRange = function (origRange, timeAxis) {
var tDateProfile = timeAxis.tDateProfile;
var dateProfile = timeAxis.props.dateProfile;
var normalRange = normalizeRange(origRange, tDateProfile, timeAxis.dateEnv);
var segs = [];
// protect against when the span is entirely in an invalid date region
if (timeAxis.computeDateSnapCoverage(normalRange.start) < timeAxis.computeDateSnapCoverage(normalRange.end)) {
// intersect the footprint's range with the grid's range
var slicedRange = core.intersectRanges(normalRange, tDateProfile.normalizedRange);
if (slicedRange) {
segs.push({
start: slicedRange.start,
end: slicedRange.end,
isStart: slicedRange.start.valueOf() === normalRange.start.valueOf() && isValidDate(slicedRange.start, tDateProfile, dateProfile, timeAxis.view),
isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf() && isValidDate(core.addMs(slicedRange.end, -1), tDateProfile, dateProfile, timeAxis.view)
});
}
}
return segs;
};
return TimelineLaneSlicer;
}(core.Slicer));
var TimelineView = /** @class */ (function (_super) {
__extends(TimelineView, _super);
function TimelineView(context, viewSpec, dateProfileGenerator, parentEl) {
var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this;
_this.el.classList.add('fc-timeline');
if (_this.opt('eventOverlap') === false) {
_this.el.classList.add('fc-no-overlap');
}
_this.el.innerHTML = _this.renderSkeletonHtml();
_this.timeAxis = new TimeAxis(_this.context, _this.el.querySelector('thead .fc-time-area'), _this.el.querySelector('tbody .fc-time-area'));
_this.lane = new TimelineLane(_this.context, _this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.contentEl, _this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.bgEl, _this.timeAxis);
context.calendar.registerInteractiveComponent(_this, {
el: _this.timeAxis.slats.el
});
return _this;
}
TimelineView.prototype.destroy = function () {
this.timeAxis.destroy();
this.lane.destroy();
_super.prototype.destroy.call(this);
this.calendar.unregisterInteractiveComponent(this);
};
TimelineView.prototype.renderSkeletonHtml = function () {
var theme = this.theme;
return "<table class=\"" + theme.getClass('tableGrid') + "\"> <thead class=\"fc-head\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetHeader') + "\"></td> </tr> </thead> <tbody class=\"fc-body\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetContent') + "\"></td> </tr> </tbody> </table>";
};
TimelineView.prototype.render = function (props) {
_super.prototype.render.call(this, props); // flags for updateSize, addScroll
this.timeAxis.receiveProps({
dateProfile: props.dateProfile
});
this.lane.receiveProps(__assign({}, props, { nextDayThreshold: this.nextDayThreshold }));
};
TimelineView.prototype.updateSize = function (isResize, totalHeight, isAuto) {
this.timeAxis.updateSize(isResize, totalHeight, isAuto);
this.lane.updateSize(isResize);
};
// Now Indicator
// ------------------------------------------------------------------------------------------
TimelineView.prototype.getNowIndicatorUnit = function (dateProfile) {
return this.timeAxis.getNowIndicatorUnit(dateProfile);
};
TimelineView.prototype.renderNowIndicator = function (date) {
this.timeAxis.renderNowIndicator(date);
};
TimelineView.prototype.unrenderNowIndicator = function () {
this.timeAxis.unrenderNowIndicator();
};
// Scroll System
// ------------------------------------------------------------------------------------------
TimelineView.prototype.computeDateScroll = function (duration) {
return this.timeAxis.computeDateScroll(duration);
};
TimelineView.prototype.applyScroll = function (scroll, isResize) {
_super.prototype.applyScroll.call(this, scroll, isResize); // will call applyDateScroll
// avoid updating stickyscroll too often
// TODO: repeat code as ResourceTimelineView::updateSize
var calendar = this.calendar;
if (isResize || calendar.isViewUpdated || calendar.isDatesUpdated || calendar.isEventsUpdated) {
this.timeAxis.updateStickyScrollers();
}
};
TimelineView.prototype.applyDateScroll = function (scroll) {
this.timeAxis.applyDateScroll(scroll);
};
TimelineView.prototype.queryScroll = function () {
var enhancedScroll = this.timeAxis.layout.bodyScroller.enhancedScroll;
return {
top: enhancedScroll.getScrollTop(),
left: enhancedScroll.getScrollLeft()
};
};
// Hit System
// ------------------------------------------------------------------------------------------
TimelineView.prototype.buildPositionCaches = function () {
this.timeAxis.slats.updateSize();
};
TimelineView.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) {
var slatHit = this.timeAxis.slats.positionToHit(positionLeft);
if (slatHit) {
return {
component: this,
dateSpan: slatHit.dateSpan,
rect: {
left: slatHit.left,
right: slatHit.right,
top: 0,
bottom: elHeight
},
dayEl: slatHit.dayEl,
layer: 0
};
}
};
return TimelineView;
}(core.View));
var main = core.createPlugin({
defaultView: 'timelineDay',
views: {
timeline: {
class: TimelineView,
eventResizableFromStart: true // how is this consumed for TimelineView tho?
},
timelineDay: {
type: 'timeline',
duration: { days: 1 }
},
timelineWeek: {
type: 'timeline',
duration: { weeks: 1 }
},
timelineMonth: {
type: 'timeline',
duration: { months: 1 }
},
timelineYear: {
type: 'timeline',
duration: { years: 1 }
}
}
});
exports.HeaderBodyLayout = HeaderBodyLayout;
exports.ScrollJoiner = ScrollJoiner;
exports.StickyScroller = StickyScroller;
exports.TimeAxis = TimeAxis;
exports.TimelineLane = TimelineLane;
exports.TimelineView = TimelineView;
exports.default = main;
Object.defineProperty(exports, '__esModule', { value: true });
}));
.fc-scroller-clip{overflow:hidden;position:relative}.fc-no-scrollbars{background:rgba(255,255,255,0)}.fc-no-scrollbars::-webkit-scrollbar{width:0;height:0}.fc-scroller-canvas{position:relative;box-sizing:border-box;min-height:100%}.fc-scroller-canvas>.fc-bg{z-index:1}.fc-scroller-canvas>.fc-content{z-index:2;position:relative;border-style:solid;border-width:0}.fc-scroller-canvas.fc-gutter-left>.fc-content{border-left-width:1px;margin-left:-1px}.fc-scroller-canvas.fc-gutter-right>.fc-content{border-right-width:1px;margin-right:-1px}.fc-scroller-canvas.fc-gutter-top>.fc-content{border-top-width:1px;margin-top:-1px}.fc-rtl .fc-timeline{direction:rtl}.fc-scrolled .fc-head .fc-scroller{z-index:2}.fc-timeline.fc-scrolled .fc-head .fc-scroller{box-shadow:0 3px 4px rgba(0,0,0,.075)}.fc-timeline .fc-body .fc-scroller{z-index:1}.fc-timeline .fc-scroller-canvas>div>div>table,.fc-timeline .fc-scroller-canvas>div>table{border-style:hidden}.fc-timeline .fc-scroller-canvas>.fc-content>.fc-rows>table{border-bottom-style:none}.fc-timeline td,.fc-timeline th{white-space:nowrap}.fc-timeline .fc-cell-content{overflow:hidden}.fc-timeline .fc-cell-text{display:inline-block;padding-left:4px;padding-right:4px}.fc-timeline th{vertical-align:middle}.fc-timeline .fc-head .fc-cell-content{padding-top:3px;padding-bottom:3px}.fc-timeline .fc-head .fc-time-area .fc-cell-content{overflow:visible}.fc-time-area col{min-width:2.2em}.fc-ltr .fc-time-area .fc-chrono th{text-align:left}.fc-rtl .fc-time-area .fc-chrono th{text-align:right}.fc-time-area .fc-slats{position:absolute;z-index:1;top:0;left:0;right:0;bottom:0}.fc-time-area .fc-slats table{height:100%}.fc-time-area .fc-slats .fc-minor{border-style:dotted}.fc-time-area .fc-slats td{border-width:0 1px}.fc-ltr .fc-time-area .fc-slats td{border-right-width:0}.fc-rtl .fc-time-area .fc-slats td{border-left-width:0}.fc-time-area .fc-bgevent-container,.fc-time-area .fc-highlight-container{position:absolute;z-index:2;top:0;bottom:0;width:0}.fc-ltr .fc-time-area .fc-bgevent-container,.fc-ltr .fc-time-area .fc-highlight-container,.fc-ltr .fc-time-area .fc-mirror-container{left:0}.fc-rtl .fc-time-area .fc-bgevent-container,.fc-rtl .fc-time-area .fc-highlight-container,.fc-rtl .fc-time-area .fc-mirror-container{right:0}.fc-time-area .fc-bgevent,.fc-time-area .fc-highlight{position:absolute;top:0;bottom:0}.fc-timeline .fc-now-indicator{z-index:3;top:0}.fc-time-area .fc-now-indicator-arrow{margin:0 -6px;border-width:6px 5px 0;border-left-color:transparent;border-right-color:transparent}.fc-time-area .fc-now-indicator-line{margin:0 -1px;bottom:0;border-left-width:1px}.fc-time-area .fc-event-container{position:relative;z-index:2;width:0}.fc-time-area .fc-mirror-container{position:absolute;z-index:3;top:0}.fc-time-area .fc-event-container{padding-bottom:8px;top:-1px}.fc-time-area tr:first-child .fc-event-container{top:0}.fc-no-overlap .fc-time-area .fc-event-container{padding-bottom:0;top:0}.fc-timeline-event{position:absolute;display:flex;border-radius:0;padding:2px 1px;margin-bottom:1px}.fc-no-overlap .fc-timeline-event{padding-top:5px;padding-bottom:5px;margin-bottom:0}.fc-ltr .fc-timeline-event{flex-direction:row;margin-right:1px}.fc-rtl .fc-timeline-event{margin-left:1px}.fc-timeline-event .fc-time-wrap{flex-shrink:0;min-width:0}.fc-timeline-event .fc-title-wrap{flex-grow:1;min-width:0}.fc-timeline-event .fc-time,.fc-timeline-event .fc-title{display:inline-block;vertical-align:top;max-width:100%;padding:0 2px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;overflow:hidden}.fc-timeline-event .fc-time{font-weight:700}.fc-timeline-event.fc-not-end:after,.fc-timeline-event.fc-not-start:before{content:"";align-self:center;width:0;height:0;margin:0 1px;border:5px solid #000;border-top-color:transparent;border-bottom-color:transparent;opacity:.5}.fc-ltr .fc-timeline-event.fc-not-start:before,.fc-rtl .fc-timeline-event.fc-not-end:after{border-left:0}.fc-ltr .fc-timeline-event.fc-not-end:after,.fc-rtl .fc-timeline-event.fc-not-start:before{border-right:0}
\ No newline at end of file
/*!
FullCalendar Timeline Plugin v4.3.0
Docs & License: https://fullcalendar.io/scheduler
(c) 2019 Adam Shaw
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@fullcalendar/core")):"function"==typeof define&&define.amd?define(["exports","@fullcalendar/core"],t):t((e=e||self).FullCalendarTimeline={},e.FullCalendar)}(this,function(e,t){"use strict";var r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)};function n(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var i,o=function(){return(o=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var i in t=arguments[r])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)},l=function(){function e(){this.gutters={},this.el=t.htmlToElement('<div class="fc-scroller-canvas"> <div class="fc-content"></div> <div class="fc-bg"></div> </div>'),this.contentEl=this.el.querySelector(".fc-content"),this.bgEl=this.el.querySelector(".fc-bg")}return e.prototype.setGutters=function(e){e?o(this.gutters,e):this.gutters={},this.updateSize()},e.prototype.setWidth=function(e){this.width=e,this.updateSize()},e.prototype.setMinWidth=function(e){this.minWidth=e,this.updateSize()},e.prototype.clearWidth=function(){this.width=null,this.minWidth=null,this.updateSize()},e.prototype.updateSize=function(){var e=this.gutters,r=this.el;t.forceClassName(r,"fc-gutter-left",e.left),t.forceClassName(r,"fc-gutter-right",e.right),t.forceClassName(r,"fc-gutter-top",e.top),t.forceClassName(r,"fc-gutter-bottom",e.bottom),t.applyStyle(r,{paddingLeft:e.left||"",paddingRight:e.right||"",paddingTop:e.top||"",paddingBottom:e.bottom||"",width:null!=this.width?this.width+(e.left||0)+(e.right||0):"",minWidth:null!=this.minWidth?this.minWidth+(e.left||0)+(e.right||0):""}),t.applyStyle(this.bgEl,{left:e.left||"",right:e.right||"",top:e.top||"",bottom:e.bottom||""})},e}(),s=function(e){function r(r,n){var i=e.call(this,r,n)||this;return i.reportScroll=function(){i.isScrolling||i.reportScrollStart(),i.trigger("scroll"),i.isMoving=!0,i.requestMovingEnd()},i.reportScrollStart=function(){i.isScrolling||(i.isScrolling=!0,i.trigger("scrollStart",i.isTouching))},i.reportTouchStart=function(){i.isTouching=!0},i.reportTouchEnd=function(){i.isTouching&&(i.isTouching=!1,i.isTouchScrollEnabled&&i.unbindPreventTouchScroll(),i.isMoving||i.reportScrollEnd())},i.isScrolling=!1,i.isTouching=!1,i.isMoving=!1,i.isTouchScrollEnabled=!0,i.requestMovingEnd=t.debounce(i.reportMovingEnd,500),i.canvas=new l,i.el.appendChild(i.canvas.el),i.applyOverflow(),i.bindHandlers(),i}return n(r,e),r.prototype.destroy=function(){e.prototype.destroy.call(this),this.unbindHandlers()},r.prototype.disableTouchScroll=function(){this.isTouchScrollEnabled=!1,this.bindPreventTouchScroll()},r.prototype.enableTouchScroll=function(){this.isTouchScrollEnabled=!0,this.isTouching||this.unbindPreventTouchScroll()},r.prototype.bindPreventTouchScroll=function(){this.preventTouchScrollHandler||this.el.addEventListener("touchmove",this.preventTouchScrollHandler=t.preventDefault)},r.prototype.unbindPreventTouchScroll=function(){this.preventTouchScrollHandler&&(this.el.removeEventListener("touchmove",this.preventTouchScrollHandler),this.preventTouchScrollHandler=null)},r.prototype.bindHandlers=function(){this.el.addEventListener("scroll",this.reportScroll),this.el.addEventListener("touchstart",this.reportTouchStart,{passive:!0}),this.el.addEventListener("touchend",this.reportTouchEnd)},r.prototype.unbindHandlers=function(){this.el.removeEventListener("scroll",this.reportScroll),this.el.removeEventListener("touchstart",this.reportTouchStart,{passive:!0}),this.el.removeEventListener("touchend",this.reportTouchEnd)},r.prototype.reportMovingEnd=function(){this.isMoving=!1,this.isTouching||this.reportScrollEnd()},r.prototype.reportScrollEnd=function(){this.isScrolling&&(this.trigger("scrollEnd"),this.isScrolling=!1)},r.prototype.getScrollLeft=function(){var e=this.el,t=window.getComputedStyle(e).direction,r=e.scrollLeft;if("rtl"===t)switch(a()){case"positive":r=r+e.clientWidth-e.scrollWidth;break;case"reverse":r=-r}return r},r.prototype.setScrollLeft=function(e){var t=this.el;if("rtl"===window.getComputedStyle(t).direction)switch(a()){case"positive":e=e-t.clientWidth+t.scrollWidth;break;case"reverse":e=-e}t.scrollLeft=e},r.prototype.getScrollFromLeft=function(){var e=this.el,t=window.getComputedStyle(e).direction,r=e.scrollLeft;if("rtl"===t)switch(a()){case"negative":r=r-e.clientWidth+e.scrollWidth;break;case"reverse":r=-r-e.clientWidth+e.scrollWidth}return r},r}(t.ScrollComponent);function a(){return i||(i=function(){var e,r=t.htmlToElement('<div style=" position: absolute; top: -1000px; width: 1px; height: 1px; overflow: scroll; direction: rtl; font-size: 100px; ">A</div>');document.body.appendChild(r),r.scrollLeft>0?e="positive":(r.scrollLeft=1,e=r.scrollLeft>0?"reverse":"negative");return t.removeElement(r),e}())}t.EmitterMixin.mixInto(s);var c=function(){function e(e,r,n){this.isHScrollbarsClipped=!1,this.isVScrollbarsClipped=!1,"clipped-scroll"===e&&(e="scroll",this.isHScrollbarsClipped=!0),"clipped-scroll"===r&&(r="scroll",this.isVScrollbarsClipped=!0),this.enhancedScroll=new s(e,r),n.appendChild(this.el=t.createElement("div",{className:"fc-scroller-clip"})),this.el.appendChild(this.enhancedScroll.el)}return e.prototype.destroy=function(){t.removeElement(this.el)},e.prototype.updateSize=function(){var e=this.enhancedScroll,r=e.el,n=t.computeEdges(r),i={marginLeft:0,marginRight:0,marginTop:0,marginBottom:0};this.isVScrollbarsClipped&&(i.marginLeft=-n.scrollbarLeft,i.marginRight=-n.scrollbarRight),this.isHScrollbarsClipped&&(i.marginBottom=-n.scrollbarBottom),t.applyStyle(r,i),!this.isHScrollbarsClipped&&"hidden"!==e.overflowX||!this.isVScrollbarsClipped&&"hidden"!==e.overflowY||n.scrollbarLeft||n.scrollbarRight||n.scrollbarBottom?r.classList.remove("fc-no-scrollbars"):r.classList.add("fc-no-scrollbars")},e.prototype.setHeight=function(e){this.enhancedScroll.setHeight(e)},e.prototype.getScrollbarWidths=function(){var e=this.enhancedScroll.getScrollbarWidths();return this.isVScrollbarsClipped&&(e.left=0,e.right=0),this.isHScrollbarsClipped&&(e.bottom=0),e},e}(),d=function(){function e(e,t){this.axis=e,this.scrollers=t;for(var r=0,n=this.scrollers;r<n.length;r++){var i=n[r];this.initScroller(i)}}return e.prototype.initScroller=function(e){var t=this,r=e.enhancedScroll,n=function(){t.assignMasterScroller(e)};"wheel mousewheel DomMouseScroll MozMousePixelScroll".split(" ").forEach(function(e){r.el.addEventListener(e,n)}),r.on("scrollStart",function(){t.masterScroller||t.assignMasterScroller(e)}).on("scroll",function(){if(e===t.masterScroller)for(var n=0,i=t.scrollers;n<i.length;n++){var o=i[n];if(o!==e)switch(t.axis){case"horizontal":o.enhancedScroll.el.scrollLeft=r.el.scrollLeft;break;case"vertical":o.enhancedScroll.setScrollTop(r.getScrollTop())}}}).on("scrollEnd",function(){e===t.masterScroller&&t.unassignMasterScroller()})},e.prototype.assignMasterScroller=function(e){this.unassignMasterScroller(),this.masterScroller=e;for(var t=0,r=this.scrollers;t<r.length;t++){var n=r[t];n!==e&&n.enhancedScroll.disableTouchScroll()}},e.prototype.unassignMasterScroller=function(){if(this.masterScroller){for(var e=0,t=this.scrollers;e<t.length;e++){t[e].enhancedScroll.enableTouchScroll()}this.masterScroller=null}},e.prototype.update=function(){for(var e,t,r=this.scrollers.map(function(e){return e.getScrollbarWidths()}),n=0,i=0,o=0,l=0,s=0,a=r;s<a.length;s++)e=a[s],n=Math.max(n,e.left),i=Math.max(i,e.right),o=Math.max(o,e.top),l=Math.max(l,e.bottom);for(t=0;t<this.scrollers.length;t++){var c=this.scrollers[t];e=r[t],c.enhancedScroll.canvas.setGutters("horizontal"===this.axis?{left:n-e.left,right:i-e.right}:{top:o-e.top,bottom:l-e.bottom})}},e}(),h=function(){function e(e,t,r){this.headerScroller=new c("clipped-scroll","hidden",e),this.bodyScroller=new c("auto",r,t),this.scrollJoiner=new d("horizontal",[this.headerScroller,this.bodyScroller])}return e.prototype.destroy=function(){this.headerScroller.destroy(),this.bodyScroller.destroy()},e.prototype.setHeight=function(e,t){var r;r=t?"auto":e-this.queryHeadHeight(),this.bodyScroller.setHeight(r),this.headerScroller.updateSize(),this.bodyScroller.updateSize(),this.scrollJoiner.update()},e.prototype.queryHeadHeight=function(){return this.headerScroller.enhancedScroll.canvas.contentEl.getBoundingClientRect().height},e}(),u=function(e){function r(r,n){var i=e.call(this,r)||this;return n.appendChild(i.tableEl=t.createElement("table",{className:i.theme.getClass("tableGrid")})),i}return n(r,e),r.prototype.destroy=function(){t.removeElement(this.tableEl),e.prototype.destroy.call(this)},r.prototype.render=function(e){this.renderDates(e.tDateProfile)},r.prototype.renderDates=function(e){for(var r=this.dateEnv,n=this.theme,i=e.cellRows,o=i[i.length-1],l=t.asRoughMs(e.labelInterval)>t.asRoughMs(e.slotDuration),s=t.isSingleDay(e.slotDuration),a="<colgroup>",c=e.slotCnt-1;c>=0;c--)a+="<col/>";a+="</colgroup>",a+="<tbody>";for(var d=0,h=i;d<h.length;d++){var u=h[d];a+="<tr"+(l&&u===o?' class="fc-chrono"':"")+">";for(var p=0,f=u;p<f.length;p++){var g=f[p],m=[n.getClass("widgetHeader")];g.isWeekStart&&m.push("fc-em-cell"),s&&(m=m.concat(t.getDayClasses(g.date,this.props.dateProfile,this.context,!0))),a+='<th class="'+m.join(" ")+'" data-date="'+r.formatIso(g.date,{omitTime:!e.isTimeScale,omitTimeZoneOffset:!0})+'"'+(g.colspan>1?' colspan="'+g.colspan+'"':"")+'><div class="fc-cell-content">'+g.spanHtml+"</div></th>"}a+="</tr>"}a+="</tbody>",this.tableEl.innerHTML=a,this.slatColEls=t.findElements(this.tableEl,"col"),this.innerEls=t.findElements(this.tableEl.querySelector("tr:last-child"),"th .fc-cell-text"),t.findElements(this.tableEl.querySelectorAll("tr:not(:last-child)"),"th .fc-cell-text").forEach(function(e){e.classList.add("fc-sticky")})},r}(t.Component),p=function(e){function r(r,n){var i=e.call(this,r)||this;return n.appendChild(i.el=t.createElement("div",{className:"fc-slats"})),i}return n(r,e),r.prototype.destroy=function(){t.removeElement(this.el),e.prototype.destroy.call(this)},r.prototype.render=function(e){this.renderDates(e.tDateProfile)},r.prototype.renderDates=function(e){for(var r=this.theme,n=this.view,i=this.dateEnv,o=e.slotDates,l=e.isWeekStarts,s='<table class="'+r.getClass("tableGrid")+'"><colgroup>',a=0;a<o.length;a++)s+="<col/>";s+="</colgroup>",s+="<tbody><tr>";for(a=0;a<o.length;a++)s+=this.slatCellHtml(o[a],l[a],e);s+="</tr></tbody></table>",this.el.innerHTML=s,this.slatColEls=t.findElements(this.el,"col"),this.slatEls=t.findElements(this.el,"td");for(a=0;a<o.length;a++)n.publiclyTrigger("dayRender",[{date:i.toDate(o[a]),el:this.slatEls[a],view:n}]);this.outerCoordCache=new t.PositionCache(this.el,this.slatEls,!0,!1),this.innerCoordCache=new t.PositionCache(this.el,t.findChildren(this.slatEls,"div"),!0,!1)},r.prototype.slatCellHtml=function(e,r,n){var i,o=this.theme,l=this.dateEnv;return n.isTimeScale?(i=[]).push(t.isInt(l.countDurationsBetween(n.normalizedRange.start,e,n.labelInterval))?"fc-major":"fc-minor"):(i=t.getDayClasses(e,this.props.dateProfile,this.context)).push("fc-day"),i.unshift(o.getClass("widgetContent")),r&&i.push("fc-em-cell"),'<td class="'+i.join(" ")+'" data-date="'+l.formatIso(e,{omitTime:!n.isTimeScale,omitTimeZoneOffset:!0})+'"><div></div></td>'},r.prototype.updateSize=function(){this.outerCoordCache.build(),this.innerCoordCache.build()},r.prototype.positionToHit=function(e){var r=this.outerCoordCache,n=this.props.tDateProfile,i=r.leftToIndex(e);if(null!=i){var o=r.getWidth(i),l=this.isRtl?(r.rights[i]-e)/o:(e-r.lefts[i])/o,s=Math.floor(l*n.snapsPerSlot),a=this.dateEnv.add(n.slotDates[i],t.multiplyDuration(n.snapDuration,s));return{dateSpan:{range:{start:a,end:this.dateEnv.add(a,n.snapDuration)},allDay:!this.props.tDateProfile.isTimeScale},dayEl:this.slatColEls[i],left:r.lefts[i],right:r.rights[i]}}return null},r}(t.Component),f=18,g=6,m=200;t.config.MAX_TIMELINE_SLOTS=1e3;var v=[{years:1},{months:1},{days:1},{hours:1},{minutes:30},{minutes:15},{minutes:10},{minutes:5},{minutes:1},{seconds:30},{seconds:15},{seconds:10},{seconds:5},{seconds:1},{milliseconds:500},{milliseconds:100},{milliseconds:10},{milliseconds:1}];function y(e,r){var n=r.dateEnv,i={labelInterval:E(r,"slotLabelInterval"),slotDuration:E(r,"slotDuration")};!function(e,r,n){var i=r.currentRange;if(e.labelInterval){var o=n.countDurationsBetween(i.start,i.end,e.labelInterval);o>t.config.MAX_TIMELINE_SLOTS&&(console.warn("slotLabelInterval results in too many cells"),e.labelInterval=null)}if(e.slotDuration){var l=n.countDurationsBetween(i.start,i.end,e.slotDuration);l>t.config.MAX_TIMELINE_SLOTS&&(console.warn("slotDuration results in too many cells"),e.slotDuration=null)}if(e.labelInterval&&e.slotDuration){var s=t.wholeDivideDurations(e.labelInterval,e.slotDuration);(null===s||s<1)&&(console.warn("slotLabelInterval must be a multiple of slotDuration"),e.slotDuration=null)}}(i,e,n),D(i,e,n),function(e,r,n){var i=r.currentRange,o=e.slotDuration;if(!o){for(var l=D(e,r,n),s=0,a=v;s<a.length;s++){var c=a[s],d=t.createDuration(c),h=t.wholeDivideDurations(l,d);if(null!==h&&h>1&&h<=g){o=d;break}}if(o){var u=n.countDurationsBetween(i.start,i.end,o);u>m&&(o=null)}o||(o=l),e.slotDuration=o}}(i,e,n);var o=r.opt("slotLabelFormat"),l=Array.isArray(o)?o:null!=o?[o]:function(e,r,n,i){var o,l,s=e.labelInterval,a=t.greatestDurationDenominator(s).unit,c=i.opt("weekNumbers"),d=o=l=null;"week"!==a||c||(a="day");switch(a){case"year":d={year:"numeric"};break;case"month":w("years",r,n)>1&&(d={year:"numeric"}),o={month:"short"};break;case"week":w("years",r,n)>1&&(d={year:"numeric"}),o={week:"narrow"};break;case"day":w("years",r,n)>1?d={year:"numeric",month:"long"}:w("months",r,n)>1&&(d={month:"long"}),c&&(o={week:"short"}),l={weekday:"narrow",day:"numeric"};break;case"hour":c&&(d={week:"short"}),w("days",r,n)>1&&(o={weekday:"short",day:"numeric",month:"numeric",omitCommas:!0}),l={hour:"numeric",minute:"2-digit",omitZeroMinute:!0,meridiem:"short"};break;case"minute":t.asRoughMinutes(s)/60>=g?(d={hour:"numeric",meridiem:"short"},o=function(e){return":"+t.padStart(e.date.minute,2)}):d={hour:"numeric",minute:"numeric",meridiem:"short"};break;case"second":t.asRoughSeconds(s)/60>=g?(d={hour:"numeric",minute:"2-digit",meridiem:"lowercase"},o=function(e){return":"+t.padStart(e.date.second,2)}):d={hour:"numeric",minute:"2-digit",second:"2-digit",meridiem:"lowercase"};break;case"millisecond":d={hour:"numeric",minute:"2-digit",second:"2-digit",meridiem:"lowercase"},o=function(e){return"."+t.padStart(e.millisecond,3)}}return[].concat(d||[],o||[],l||[])}(i,e,n,r);i.headerFormats=l.map(function(e){return t.createFormatter(e)}),i.isTimeScale=Boolean(i.slotDuration.milliseconds);var s=null;if(!i.isTimeScale){var a=t.greatestDurationDenominator(i.slotDuration).unit;/year|month|week/.test(a)&&(s=a)}i.largeUnit=s,i.emphasizeWeeks=t.isSingleDay(i.slotDuration)&&w("weeks",e,n)>=2&&!r.opt("businessHours");var c,d,h=r.opt("snapDuration");h&&(c=t.createDuration(h),d=t.wholeDivideDurations(i.slotDuration,c)),null==d&&(c=i.slotDuration,d=1),i.snapDuration=c,i.snapsPerSlot=d;var u=t.asRoughMs(e.maxTime)-t.asRoughMs(e.minTime),p=S(e.renderRange.start,i,n),f=S(e.renderRange.end,i,n);i.isTimeScale&&(p=n.add(p,e.minTime),f=n.add(t.addDays(f,-1),e.maxTime)),i.timeWindowMs=u,i.normalizedRange={start:p,end:f};for(var y=[],T=p;T<f;)b(T,i,e,r)&&y.push(T),T=n.add(T,i.slotDuration);i.slotDates=y;var R=-1,x=0,M=[],z=[];for(T=p;T<f;)b(T,i,e,r)?(R++,M.push(R),z.push(x)):M.push(R+.5),T=n.add(T,i.snapDuration),x++;return i.snapDiffToIndex=M,i.snapIndexToDiff=z,i.snapCnt=R+1,i.slotCnt=i.snapCnt/i.snapsPerSlot,i.isWeekStarts=function(e,t){for(var r=e.slotDates,n=e.emphasizeWeeks,i=null,o=[],l=0,s=r;l<s.length;l++){var a=s[l],c=t.computeWeekNumber(a),d=n&&null!==i&&i!==c;i=c,o.push(d)}return o}(i,n),i.cellRows=function(e,r,n){for(var i=e.slotDates,o=e.headerFormats,l=o.map(function(e){return[]}),s=o.map(function(e){return e.getLargestUnit?e.getLargestUnit():null}),a=0;a<i.length;a++)for(var c=i[a],d=e.isWeekStarts[a],h=0;h<o.length;h++){var u=o[h],p=l[h],f=p[p.length-1],g=o.length>1&&h<o.length-1,m=null;if(g){var v=r.format(c,u);f&&f.text===v?f.colspan+=1:m=C(c,v,s[h],n)}else if(!f||t.isInt(r.countDurationsBetween(e.normalizedRange.start,c,e.labelInterval))){var v=r.format(c,u);m=C(c,v,s[h],n)}else f.colspan+=1;m&&(m.weekStart=d,p.push(m))}return l}(i,n,r),i}function S(e,r,n){var i=e;return r.isTimeScale||(i=t.startOfDay(i),r.largeUnit&&(i=n.startOf(i,r.largeUnit))),i}function b(e,r,n,i){if(i.dateProfileGenerator.isHiddenDay(e))return!1;if(r.isTimeScale){var o=t.startOfDay(e),l=e.valueOf()-o.valueOf()-t.asRoughMs(n.minTime);return(l=(l%864e5+864e5)%864e5)<r.timeWindowMs}return!0}function E(e,r){var n=e.opt(r);if(null!=n)return t.createDuration(n)}function D(e,r,n){var i=r.currentRange,o=e.labelInterval;if(!o){var l=void 0;if(e.slotDuration){for(var s=0,a=v;s<a.length;s++){l=a[s];var c=t.createDuration(l),d=t.wholeDivideDurations(c,e.slotDuration);if(null!==d&&d<=g){o=c;break}}o||(o=e.slotDuration)}else for(var h=0,u=v;h<u.length;h++){if(l=u[h],o=t.createDuration(l),n.countDurationsBetween(i.start,i.end,o)>=f)break}e.labelInterval=o}return o}function w(e,r,n){var i=r.currentRange,o=null;return"years"===e?o=n.diffWholeYears(i.start,i.end):"months"===e?o=n.diffWholeMonths(i.start,i.end):"weeks"===e?o=n.diffWholeMonths(i.start,i.end):"days"===e&&(o=t.diffWholeDays(i.start,i.end)),o||0}function C(e,r,n,i){return{text:r,spanHtml:t.buildGotoAnchorHtml(i,{date:e,type:n,forceOff:!n},{class:"fc-cell-text"},t.htmlEscape(r)),date:e,colspan:1,isWeekStart:!1}}var T,R=function(){function e(e,t){this.headParent=e,this.bodyParent=t}return e.prototype.render=function(e,r){var n=r?{right:-e}:{left:e};this.headParent.appendChild(this.arrowEl=t.createElement("div",{className:"fc-now-indicator fc-now-indicator-arrow",style:n})),this.bodyParent.appendChild(this.lineEl=t.createElement("div",{className:"fc-now-indicator fc-now-indicator-line",style:n}))},e.prototype.unrender=function(){this.arrowEl&&t.removeElement(this.arrowEl),this.lineEl&&t.removeElement(this.lineEl)},e}(),x=-1!==(T=t.htmlToElement('<div style="position:-webkit-sticky;position:sticky"></div>').style.position).indexOf("sticky")?T:null,M=/Edge/.test(navigator.userAgent),z="-webkit-sticky"===x,k="fc-sticky",P=function(){function e(e,r,n){var i=this;this.usingRelative=null,this.updateSize=function(){var e=Array.prototype.slice.call(i.scroller.canvas.el.querySelectorAll("."+k)),r=i.queryElGeoms(e),n=i.scroller.el.clientWidth;i.usingRelative?function(e,r,n){e.forEach(function(e,i){var o=r[i].naturalBound;t.applyStyle(e,{position:"relative",left:n[i].left-o.left,top:n[i].top-o.top})})}(e,r,i.computeElDestinations(r,n)):function(e,r,n){e.forEach(function(e,i){var o=0;"center"===r[i].intendedTextAlign&&(o=(n-r[i].elWidth)/2,"center"===r[i].computedTextAlign&&(e.setAttribute("data-sticky-center",""),e.parentNode.style.textAlign="left")),t.applyStyle(e,{position:x,left:o,right:0,top:0})})}(e,r,n)},this.scroller=e,this.usingRelative=!x||M&&r||(M||z)&&n,this.usingRelative&&e.on("scrollEnd",this.updateSize)}return e.prototype.destroy=function(){this.scroller.off("scrollEnd",this.updateSize)},e.prototype.queryElGeoms=function(e){for(var r=this.scroller.canvas.el.getBoundingClientRect(),n=[],i=0,o=e;i<o.length;i++){var l=o[i],s=t.translateRect(l.parentNode.getBoundingClientRect(),-r.left,-r.top),a=l.getBoundingClientRect(),c=window.getComputedStyle(l),d=window.getComputedStyle(l.parentNode).textAlign,h=d,u=null;"sticky"!==c.position&&(u=t.translateRect(a,-r.left-(parseFloat(c.left)||0),-r.top-(parseFloat(c.top)||0))),l.hasAttribute("data-sticky-center")&&(h="center"),n.push({parentBound:s,naturalBound:u,elWidth:a.width,elHeight:a.height,computedTextAlign:d,intendedTextAlign:h})}return n},e.prototype.computeElDestinations=function(e,t){var r=this.scroller.getScrollFromLeft(),n=this.scroller.getScrollTop(),i=r+t;return e.map(function(e){var t,o,l=e.elWidth,s=e.elHeight,a=e.parentBound,c=e.naturalBound;switch(e.intendedTextAlign){case"left":t=r;break;case"right":t=i-l;break;case"center":t=(r+i)/2-l/2}return t=Math.min(t,a.right-l),t=Math.max(t,a.left),o=n,o=Math.min(o,a.bottom-s),{left:t,top:o=Math.max(o,c.top)}})},e}();var I=function(e){function r(t,r,n){var i=e.call(this,t)||this,o=i.layout=new h(r,n,"auto"),l=o.headerScroller.enhancedScroll,s=o.bodyScroller.enhancedScroll;return i.headStickyScroller=new P(l,i.isRtl,!1),i.bodyStickyScroller=new P(s,i.isRtl,!1),i.header=new u(t,l.canvas.contentEl),i.slats=new p(t,s.canvas.bgEl),i.nowIndicator=new R(l.canvas.el,s.canvas.el),i}return n(r,e),r.prototype.destroy=function(){this.layout.destroy(),this.header.destroy(),this.slats.destroy(),this.nowIndicator.unrender(),this.headStickyScroller.destroy(),this.bodyStickyScroller.destroy(),e.prototype.destroy.call(this)},r.prototype.render=function(e){var t=this.tDateProfile=y(e.dateProfile,this.view);this.header.receiveProps({dateProfile:e.dateProfile,tDateProfile:t}),this.slats.receiveProps({dateProfile:e.dateProfile,tDateProfile:t})},r.prototype.getNowIndicatorUnit=function(e){var r=this.tDateProfile=y(e,this.view);if(r.isTimeScale)return t.greatestDurationDenominator(r.slotDuration).unit},r.prototype.renderNowIndicator=function(e){t.rangeContainsMarker(this.tDateProfile.normalizedRange,e)&&this.nowIndicator.render(this.dateToCoord(e),this.isRtl)},r.prototype.unrenderNowIndicator=function(){this.nowIndicator.unrender()},r.prototype.updateSize=function(e,t,r){this.applySlotWidth(this.computeSlotWidth()),this.layout.setHeight(t,r),this.slats.updateSize()},r.prototype.updateStickyScrollers=function(){this.headStickyScroller.updateSize(),this.bodyStickyScroller.updateSize()},r.prototype.computeSlotWidth=function(){var e=this.opt("slotWidth")||"";return""===e&&(e=this.computeDefaultSlotWidth(this.tDateProfile)),e},r.prototype.computeDefaultSlotWidth=function(e){var r=0;this.header.innerEls.forEach(function(e,t){r=Math.max(r,e.getBoundingClientRect().width)});var n=Math.ceil(r)+1,i=t.wholeDivideDurations(e.labelInterval,e.slotDuration),o=Math.ceil(n/i),l=window.getComputedStyle(this.header.slatColEls[0]).minWidth;return l&&(l=parseInt(l,10))&&(o=Math.max(o,l)),o},r.prototype.applySlotWidth=function(e){var t=this.layout,r=this.tDateProfile,n="",i="",o="";if(""!==e){n=(e=Math.round(e))*r.slotDates.length,i="",o=e;var l=t.bodyScroller.enhancedScroll.getClientWidth();l>n&&(i=l,n="",o=Math.floor(l/r.slotDates.length))}t.headerScroller.enhancedScroll.canvas.setWidth(n),t.headerScroller.enhancedScroll.canvas.setMinWidth(i),t.bodyScroller.enhancedScroll.canvas.setWidth(n),t.bodyScroller.enhancedScroll.canvas.setMinWidth(i),""!==o&&this.header.slatColEls.slice(0,-1).concat(this.slats.slatColEls.slice(0,-1)).forEach(function(e){e.style.width=o+"px"})},r.prototype.computeDateSnapCoverage=function(e){var r=this.dateEnv,n=this.tDateProfile,i=r.countDurationsBetween(n.normalizedRange.start,e,n.snapDuration);if(i<0)return 0;if(i>=n.snapDiffToIndex.length)return n.snapCnt;var o=Math.floor(i),l=n.snapDiffToIndex[o];return t.isInt(l)?l+=i-o:l=Math.ceil(l),l},r.prototype.dateToCoord=function(e){var t=this.tDateProfile,r=this.computeDateSnapCoverage(e)/t.snapsPerSlot,n=Math.floor(r),i=r-(n=Math.min(n,t.slotCnt-1)),o=this.slats,l=o.innerCoordCache,s=o.outerCoordCache;return this.isRtl?s.rights[n]-l.getWidth(n)*i-s.originClientRect.width:s.lefts[n]+l.getWidth(n)*i},r.prototype.rangeToCoords=function(e){return this.isRtl?{right:this.dateToCoord(e.start),left:this.dateToCoord(e.end)}:{left:this.dateToCoord(e.start),right:this.dateToCoord(e.end)}},r.prototype.computeDateScroll=function(e){var r=this.dateEnv,n=this.props.dateProfile,i=0;return n&&(i=this.dateToCoord(r.add(t.startOfDay(n.activeRange.start),e)),!this.isRtl&&i&&(i+=1)),{left:i}},r.prototype.queryDateScroll=function(){return{left:this.layout.bodyScroller.enhancedScroll.getScrollLeft()}},r.prototype.applyDateScroll=function(e){this.layout.bodyScroller.enhancedScroll.setScrollLeft(e.left||0),this.layout.headerScroller.enhancedScroll.setScrollLeft(e.left||0)},r}(t.Component),H=function(e){function r(t,r,n){var i=e.call(this,t)||this;return i.masterContainerEl=r,i.timeAxis=n,i}return n(r,e),r.prototype.renderSegHtml=function(e,r){var n=this.context.view,i=e.eventRange,o=i.def,l=i.ui,s=n.computeEventDraggable(o,l),a=e.isStart&&n.computeEventStartResizable(o,l),c=e.isEnd&&n.computeEventEndResizable(o,l),d=this.getSegClasses(e,s,a||c,r);d.unshift("fc-timeline-event","fc-h-event");var h=this.getTimeText(i);return'<a class="'+d.join(" ")+'" style="'+t.cssToStr(this.getSkinCss(l))+'"'+(o.url?' href="'+t.htmlEscape(o.url)+'"':"")+">"+(h?'<span class="fc-time-wrap"><span class="fc-time">'+t.htmlEscape(h)+"</span></span>":"")+'<span class="fc-title-wrap"><span class="fc-title fc-sticky">'+(o.title?t.htmlEscape(o.title):"&nbsp;")+"</span></span>"+(a?'<div class="fc-resizer fc-start-resizer"></div>':"")+(c?'<div class="fc-resizer fc-end-resizer"></div>':"")+"</a>"},r.prototype.computeDisplayEventTime=function(){return!this.timeAxis.tDateProfile.isTimeScale},r.prototype.computeDisplayEventEnd=function(){return!1},r.prototype.computeEventTimeFormat=function(){return{hour:"numeric",minute:"2-digit",omitZeroMinute:!0,meridiem:"narrow"}},r.prototype.attachSegs=function(e,r){if(!this.el&&this.masterContainerEl&&(this.el=t.createElement("div",{className:"fc-event-container"}),r&&this.el.classList.add("fc-mirror-container"),this.masterContainerEl.appendChild(this.el)),this.el)for(var n=0,i=e;n<i.length;n++){var o=i[n];this.el.appendChild(o.el)}},r.prototype.detachSegs=function(e){for(var r=0,n=e;r<n.length;r++){var i=n[r];t.removeElement(i.el)}},r.prototype.computeSegSizes=function(e){for(var r=this.timeAxis,n=0,i=e;n<i.length;n++){var o=i[n],l=r.rangeToCoords(o);t.applyStyle(o.el,{left:o.left=l.left,right:-(o.right=l.right)})}},r.prototype.assignSegSizes=function(e){if(this.el){for(var r=0,n=e;r<n.length;r++){(s=n[r]).height=t.computeHeightAndMargins(s.el)}this.buildSegLevels(e);var i=L(e);t.applyStyleProp(this.el,"height",i);for(var o=0,l=e;o<l.length;o++){var s=l[o];t.applyStyleProp(s.el,"top",s.top)}}},r.prototype.buildSegLevels=function(e){for(var t=[],r=0,n=e=this.sortEventSegs(e);r<n.length;r++){var i=n[r];i.above=[];for(var o=0;o<t.length;){for(var l=!1,s=0,a=t[o];s<a.length;s++){var c=a[s];A(i,c)&&(i.above.push(c),l=!0)}if(!l)break;o+=1}for((t[o]||(t[o]=[])).push(i),o+=1;o<t.length;){for(var d=0,h=t[o];d<h.length;d++){var u=h[d];A(i,u)&&u.above.push(i)}o+=1}}return t},r}(t.FgEventRenderer);function L(e){for(var t=0,r=0,n=e;r<n.length;r++){var i=n[r];t=Math.max(t,W(i))}return t}function W(e){return null==e.top&&(e.top=L(e.above)),e.top+e.height}function A(e,t){return e.left<t.right&&e.right>t.left}var B=function(e){function r(t,r,n){var i=e.call(this,t)||this;return i.masterContainerEl=r,i.timeAxis=n,i}return n(r,e),r.prototype.attachSegs=function(e,r){if(r.length){var n=void 0;n="businessHours"===e?"bgevent":e.toLowerCase();var i=t.createElement("div",{className:"fc-"+n+"-container"});this.masterContainerEl.appendChild(i);for(var o=0,l=r;o<l.length;o++){var s=l[o];i.appendChild(s.el)}return[i]}},r.prototype.computeSegSizes=function(e){for(var t=this.timeAxis,r=0,n=e;r<n.length;r++){var i=n[r],o=t.rangeToCoords(i);i.left=o.left,i.right=o.right}},r.prototype.assignSegSizes=function(e){for(var r=0,n=e;r<n.length;r++){var i=n[r];t.applyStyle(i.el,{left:i.left,right:-i.right})}},r}(t.FillRenderer),O=function(e){function r(r,n,i,o){var l=e.call(this,r,i)||this;l.slicer=new N,l.renderEventDrag=t.memoizeRendering(l._renderEventDrag,l._unrenderEventDrag),l.renderEventResize=t.memoizeRendering(l._renderEventResize,l._unrenderEventResize);var s=l.fillRenderer=new B(r,i,o),a=l.eventRenderer=new H(r,n,o);return l.mirrorRenderer=new H(r,n,o),l.renderBusinessHours=t.memoizeRendering(s.renderSegs.bind(s,"businessHours"),s.unrender.bind(s,"businessHours")),l.renderDateSelection=t.memoizeRendering(s.renderSegs.bind(s,"highlight"),s.unrender.bind(s,"highlight")),l.renderBgEvents=t.memoizeRendering(s.renderSegs.bind(s,"bgEvent"),s.unrender.bind(s,"bgEvent")),l.renderFgEvents=t.memoizeRendering(a.renderSegs.bind(a),a.unrender.bind(a)),l.renderEventSelection=t.memoizeRendering(a.selectByInstanceId.bind(a),a.unselectByInstanceId.bind(a),[l.renderFgEvents]),l.timeAxis=o,l}return n(r,e),r.prototype.render=function(e){var t=this.slicer.sliceProps(e,e.dateProfile,this.timeAxis.tDateProfile.isTimeScale?null:e.nextDayThreshold,this,this.timeAxis);this.renderBusinessHours(t.businessHourSegs),this.renderDateSelection(t.dateSelectionSegs),this.renderBgEvents(t.bgEventSegs),this.renderFgEvents(t.fgEventSegs),this.renderEventSelection(t.eventSelection),this.renderEventDrag(t.eventDrag),this.renderEventResize(t.eventResize)},r.prototype.destroy=function(){e.prototype.destroy.call(this),this.renderBusinessHours.unrender(),this.renderDateSelection.unrender(),this.renderBgEvents.unrender(),this.renderFgEvents.unrender(),this.renderEventSelection.unrender(),this.renderEventDrag.unrender(),this.renderEventResize.unrender()},r.prototype._renderEventDrag=function(e){e&&(this.eventRenderer.hideByHash(e.affectedInstances),this.mirrorRenderer.renderSegs(e.segs,{isDragging:!0,sourceSeg:e.sourceSeg}))},r.prototype._unrenderEventDrag=function(e){e&&(this.eventRenderer.showByHash(e.affectedInstances),this.mirrorRenderer.unrender(e.segs,{isDragging:!0,sourceSeg:e.sourceSeg}))},r.prototype._renderEventResize=function(e){if(e){var t=e.segs.map(function(e){return o({},e)});this.eventRenderer.hideByHash(e.affectedInstances),this.fillRenderer.renderSegs("highlight",t),this.mirrorRenderer.renderSegs(e.segs,{isDragging:!0,sourceSeg:e.sourceSeg})}},r.prototype._unrenderEventResize=function(e){e&&(this.eventRenderer.showByHash(e.affectedInstances),this.fillRenderer.unrender("highlight"),this.mirrorRenderer.unrender(e.segs,{isDragging:!0,sourceSeg:e.sourceSeg}))},r.prototype.updateSize=function(e){var t=this.fillRenderer,r=this.eventRenderer,n=this.mirrorRenderer;t.computeSizes(e),r.computeSizes(e),n.computeSizes(e),t.assignSizes(e),r.assignSizes(e),n.assignSizes(e)},r}(t.DateComponent),N=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return n(r,e),r.prototype.sliceRange=function(e,r){var n=r.tDateProfile,i=r.props.dateProfile,o=function(e,r,n){if(!r.isTimeScale&&(e=t.computeVisibleDayRange(e),r.largeUnit)){var i=e;((e={start:n.startOf(e.start,r.largeUnit),end:n.startOf(e.end,r.largeUnit)}).end.valueOf()!==i.end.valueOf()||e.end<=e.start)&&(e={start:e.start,end:n.add(e.end,r.slotDuration)})}return e}(e,n,r.dateEnv),l=[];if(r.computeDateSnapCoverage(o.start)<r.computeDateSnapCoverage(o.end)){var s=t.intersectRanges(o,n.normalizedRange);s&&l.push({start:s.start,end:s.end,isStart:s.start.valueOf()===o.start.valueOf()&&b(s.start,n,i,r.view),isEnd:s.end.valueOf()===o.end.valueOf()&&b(t.addMs(s.end,-1),n,i,r.view)})}return l},r}(t.Slicer),_=function(e){function t(t,r,n,i){var o=e.call(this,t,r,n,i)||this;return o.el.classList.add("fc-timeline"),!1===o.opt("eventOverlap")&&o.el.classList.add("fc-no-overlap"),o.el.innerHTML=o.renderSkeletonHtml(),o.timeAxis=new I(o.context,o.el.querySelector("thead .fc-time-area"),o.el.querySelector("tbody .fc-time-area")),o.lane=new O(o.context,o.timeAxis.layout.bodyScroller.enhancedScroll.canvas.contentEl,o.timeAxis.layout.bodyScroller.enhancedScroll.canvas.bgEl,o.timeAxis),t.calendar.registerInteractiveComponent(o,{el:o.timeAxis.slats.el}),o}return n(t,e),t.prototype.destroy=function(){this.timeAxis.destroy(),this.lane.destroy(),e.prototype.destroy.call(this),this.calendar.unregisterInteractiveComponent(this)},t.prototype.renderSkeletonHtml=function(){var e=this.theme;return'<table class="'+e.getClass("tableGrid")+'"> <thead class="fc-head"> <tr> <td class="fc-time-area '+e.getClass("widgetHeader")+'"></td> </tr> </thead> <tbody class="fc-body"> <tr> <td class="fc-time-area '+e.getClass("widgetContent")+'"></td> </tr> </tbody> </table>'},t.prototype.render=function(t){e.prototype.render.call(this,t),this.timeAxis.receiveProps({dateProfile:t.dateProfile}),this.lane.receiveProps(o({},t,{nextDayThreshold:this.nextDayThreshold}))},t.prototype.updateSize=function(e,t,r){this.timeAxis.updateSize(e,t,r),this.lane.updateSize(e)},t.prototype.getNowIndicatorUnit=function(e){return this.timeAxis.getNowIndicatorUnit(e)},t.prototype.renderNowIndicator=function(e){this.timeAxis.renderNowIndicator(e)},t.prototype.unrenderNowIndicator=function(){this.timeAxis.unrenderNowIndicator()},t.prototype.computeDateScroll=function(e){return this.timeAxis.computeDateScroll(e)},t.prototype.applyScroll=function(t,r){e.prototype.applyScroll.call(this,t,r);var n=this.calendar;(r||n.isViewUpdated||n.isDatesUpdated||n.isEventsUpdated)&&this.timeAxis.updateStickyScrollers()},t.prototype.applyDateScroll=function(e){this.timeAxis.applyDateScroll(e)},t.prototype.queryScroll=function(){var e=this.timeAxis.layout.bodyScroller.enhancedScroll;return{top:e.getScrollTop(),left:e.getScrollLeft()}},t.prototype.buildPositionCaches=function(){this.timeAxis.slats.updateSize()},t.prototype.queryHit=function(e,t,r,n){var i=this.timeAxis.slats.positionToHit(e);if(i)return{component:this,dateSpan:i.dateSpan,rect:{left:i.left,right:i.right,top:0,bottom:n},dayEl:i.dayEl,layer:0}},t}(t.View),F=t.createPlugin({defaultView:"timelineDay",views:{timeline:{class:_,eventResizableFromStart:!0},timelineDay:{type:"timeline",duration:{days:1}},timelineWeek:{type:"timeline",duration:{weeks:1}},timelineMonth:{type:"timeline",duration:{months:1}},timelineYear:{type:"timeline",duration:{years:1}}}});e.HeaderBodyLayout=h,e.ScrollJoiner=d,e.StickyScroller=P,e.TimeAxis=I,e.TimelineLane=O,e.TimelineView=_,e.default=F,Object.defineProperty(e,"__esModule",{value:!0})});
\ No newline at end of file
{
"name": "@fullcalendar/timeline",
"version": "4.3.0",
"title": "FullCalendar Timeline Plugin",
"description": "Display events on a horizontal time axis (without resources)",
"keywords": [
"calendar",
"event",
"full-sized"
],
"homepage": "https://fullcalendar.io/scheduler",
"docs": "https://fullcalendar.io/docs/timeline-view-no-resources",
"bugs": "https://fullcalendar.io/reporting-bugs",
"repository": {
"type": "git",
"url": "https://github.com/fullcalendar/fullcalendar-scheduler.git",
"homepage": "https://github.com/fullcalendar/fullcalendar-scheduler"
},
"license": "SEE LICENSE IN LICENSE.md",
"author": {
"name": "Adam Shaw",
"email": "arshaw@arshaw.com",
"url": "http://arshaw.com/"
},
"copyright": "2019 Adam Shaw",
"peerDependencies": {
"@fullcalendar/core": "~4.3.0"
},
"main": "main.js",
"module": "main.esm.js",
"unpkg": "main.min.js",
"types": "main.d.ts"
}
......@@ -5,13 +5,14 @@
{% for slot in slots %}
{% if slot.start %}
{
'title': '{{ slot.ak.name }}',
'title': '{{ slot.ak.short_name }}',
'description': '{{ slot.ak.name }}',
'start': '{{ slot.start | timezone:event.timezone | date:"Y-m-d H:i:s" }}',
'end': '{{ slot.end | timezone:event.timezone | date:"Y-m-d H:i:s" }}',
'resourceId': '{{ slot.room.title }}',
'backgroundColor': '{{ slot|highlight_change_colors }}',
'borderColor': '{{ slot.ak.category.color }}',
'url': '{% url 'submit:ak_detail' event_slug=event.slug pk=slot.ak.pk %}'
'url': '{{ slot.ak.detail_url }}'
},
{% endif %}
{% endfor %}
......
......@@ -3,7 +3,7 @@
{
'id': '{{ room.title }}',
'title': '{{ room.title }}',
'parentId': '{{ room.building }}',
'parentId': '{{ room.location }}',
},
{% endfor %}
{% for building in buildings %}
......
{% load static %}
{% load tz %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% load tags_AKPlan %}
<link href='{% static 'AKPlan/vendor/fullcalendar/core/main.min.css' %}' rel='stylesheet'/>
<link href='{% static 'AKPlan/vendor/fullcalendar/daygrid/main.min.css' %}' rel='stylesheet'/>
<link href='{% static 'AKPlan/vendor/fullcalendar/timegrid/main.min.css' %}' rel='stylesheet'/>
<script src='{% static 'AKPlan/vendor/fullcalendar/core/main.min.js' %}'></script>
{% with 'AKPlan/vendor/fullcalendar/core/locales/'|add:LANGUAGE_CODE|add:'.js' as locale_file %}
<script src="{% static locale_file %}"></script>
{% endwith %}
<script src='{% static 'AKPlan/vendor/fullcalendar/daygrid/main.min.js' %}'></script>
<script src='{% static 'AKPlan/vendor/fullcalendar/timegrid/main.min.js' %}'></script>
<script src='{% static 'AKPlan/vendor/fullcalendar/bootstrap/main.min.js' %}'></script>
{% include "AKModel/load_fullcalendar.html" %}
<script>
{% get_current_language as LANGUAGE_CODE %}
document.addEventListener('DOMContentLoaded', function () {
var calendarEl = document.getElementById('akSlotCalendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ['timeGrid', 'bootstrap'],
// Adapt to timezone of the connected event
timeZone: '{{ ak.event.timezone }}',
defaultView: 'timeGrid',
initialView: 'timeGrid',
// Adapt to user selected locale
locale: '{{ LANGUAGE_CODE }}',
// No header, not buttons
header: {
left: '',
center: '',
right: ''
},
headerToolbar: false,
aspectRatio: 2.5,
themeSystem: 'bootstrap',
themeSystem: 'bootstrap5',
buttonIcons: {
prev: 'ignore fa-solid fa-angle-left',
next: 'ignore fa-solid fa-angle-right',
},
// Only show calendar view for the dates of the connected event
visibleRange: {
start: '{{ ak.event.start | timezone:ak.event.timezone | date:"Y-m-d H:i:s" }}',
end: '{{ ak.event.end | timezone:ak.event.timezone | date:"Y-m-d H:i:s"}}',
},
scrollTime: '08:00:00',
allDaySlot: false,
nowIndicator: true,
now: "{% timestamp_now event.timezone %}",
eventTextColor: '#fff',
eventColor: '#127ba3',
// Create entries for all scheduled slots
......@@ -53,7 +45,7 @@
'title': '{{ slot.room }}',
'start': '{{ slot.start | timezone:ak.event.timezone | date:"Y-m-d H:i:s" }}',
'end': '{{ slot.end | timezone:ak.event.timezone | date:"Y-m-d H:i:s" }}',
'url' : '{% url "plan:plan_room" event_slug=ak.event.slug pk=slot.room.pk %}'
'url' : '{% if slot.room %}{% url "plan:plan_room" event_slug=ak.event.slug pk=slot.room.pk %}{% else %}#{% endif %}'
},
{% endif %}
{% endfor %}
......@@ -64,10 +56,11 @@
start: '{{ a.start | timezone:ak.event.timezone | date:"Y-m-d H:i:s" }}',
end: '{{ a.end | timezone:ak.event.timezone | date:"Y-m-d H:i:s" }}',
backgroundColor: '#28B62C',
rendering: 'background'
display: 'background'
},
{% endfor %}
]
],
schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
});
calendar.render();
......
{% extends "base.html" %}
{% load fontawesome_5 %}
{% load fontawesome_6 %}
{% load i18n %}
{% load static %}
{% block imports %}
{% get_current_language as LANGUAGE_CODE %}
<link href='{% static 'AKPlan/vendor/fullcalendar/core/main.css' %}' rel='stylesheet'/>
{% block meta %}
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="{{ event.name }} - {% trans "Plan" %}" />
{% endblock %}
<script src='{% static 'AKPlan/vendor/fullcalendar/core/main.js' %}'></script>
{% with 'AKPlan/vendor/fullcalendar/core/locales/'|add:LANGUAGE_CODE|add:'.js' as locale_file %}
<script src="{% static locale_file %}"></script>
{% endwith %}
<script src='{% static 'AKPlan/vendor/fullcalendar/bootstrap/main.js' %}'></script>
{% block imports %}
{% include "AKModel/load_fullcalendar.html" %}
{% block fullcalendar %}{% endblock %}
{% endblock imports %}
......@@ -21,7 +18,7 @@
{% block footer_custom %}
{% if event.contact_email %}
<h4>
<a href="mailto:{{ event.contact_email }}">{% fa5_icon "envelope" "far" %} {% trans "Write to organizers of this event for questions and comments" %}</a>
<a href="mailto:{{ event.contact_email }}">{% fa6_icon "envelope" "far" %} {% trans "Write to organizers of this event for questions and comments" %}</a>
</h4>
{% endif %}
{% endblock %}