fullcalendar-timegrid.js 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  1. /*!
  2. FullCalendar v5.11.3
  3. Docs & License: https://fullcalendar.io/
  4. (c) 2022 Adam Shaw
  5. */
  6. import './main.css';
  7. import { hasBgRendering, Splitter, createFormatter, createElement, ViewContextType, RenderHook, BaseComponent, createRef, diffDays, buildNavLinkAttrs, WeekNumberRoot, getStickyHeaderDates, ViewRoot, SimpleScrollGrid, getStickyFooterScrollbar, NowTimer, NowIndicatorRoot, renderScrollShim, DateComponent, rangeContainsMarker, startOfDay, asRoughMs, createDuration, RefMap, PositionCache, MoreLinkRoot, setRef, SegHierarchy, groupIntersectingEntries, buildEntryKey, binarySearch, getEntrySpanEnd, StandardEvent, DayCellContent, Fragment, getSegMeta, memoize, sortEventSegs, DayCellRoot, buildIsoString, computeEarliestSegStart, buildEventRangeKey, BgEvent, renderFill, addDurations, multiplyDuration, wholeDivideDurations, intersectRanges, Slicer, formatIsoTimeString, DayHeader, DaySeriesModel, DayTableModel, createPlugin } from '@fullcalendar/common';
  8. import { __extends, __assign } from 'tslib';
  9. import { DayTable } from '@fullcalendar/daygrid';
  10. var AllDaySplitter = /** @class */ (function (_super) {
  11. __extends(AllDaySplitter, _super);
  12. function AllDaySplitter() {
  13. return _super !== null && _super.apply(this, arguments) || this;
  14. }
  15. AllDaySplitter.prototype.getKeyInfo = function () {
  16. return {
  17. allDay: {},
  18. timed: {},
  19. };
  20. };
  21. AllDaySplitter.prototype.getKeysForDateSpan = function (dateSpan) {
  22. if (dateSpan.allDay) {
  23. return ['allDay'];
  24. }
  25. return ['timed'];
  26. };
  27. AllDaySplitter.prototype.getKeysForEventDef = function (eventDef) {
  28. if (!eventDef.allDay) {
  29. return ['timed'];
  30. }
  31. if (hasBgRendering(eventDef)) {
  32. return ['timed', 'allDay'];
  33. }
  34. return ['allDay'];
  35. };
  36. return AllDaySplitter;
  37. }(Splitter));
  38. var DEFAULT_SLAT_LABEL_FORMAT = createFormatter({
  39. hour: 'numeric',
  40. minute: '2-digit',
  41. omitZeroMinute: true,
  42. meridiem: 'short',
  43. });
  44. function TimeColsAxisCell(props) {
  45. var classNames = [
  46. 'fc-timegrid-slot',
  47. 'fc-timegrid-slot-label',
  48. props.isLabeled ? 'fc-scrollgrid-shrink' : 'fc-timegrid-slot-minor',
  49. ];
  50. return (createElement(ViewContextType.Consumer, null, function (context) {
  51. if (!props.isLabeled) {
  52. return (createElement("td", { className: classNames.join(' '), "data-time": props.isoTimeStr }));
  53. }
  54. var dateEnv = context.dateEnv, options = context.options, viewApi = context.viewApi;
  55. var labelFormat = // TODO: fully pre-parse
  56. options.slotLabelFormat == null ? DEFAULT_SLAT_LABEL_FORMAT :
  57. Array.isArray(options.slotLabelFormat) ? createFormatter(options.slotLabelFormat[0]) :
  58. createFormatter(options.slotLabelFormat);
  59. var hookProps = {
  60. level: 0,
  61. time: props.time,
  62. date: dateEnv.toDate(props.date),
  63. view: viewApi,
  64. text: dateEnv.format(props.date, labelFormat),
  65. };
  66. return (createElement(RenderHook, { hookProps: hookProps, classNames: options.slotLabelClassNames, content: options.slotLabelContent, defaultContent: renderInnerContent, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-time": props.isoTimeStr },
  67. createElement("div", { className: "fc-timegrid-slot-label-frame fc-scrollgrid-shrink-frame" },
  68. createElement("div", { className: "fc-timegrid-slot-label-cushion fc-scrollgrid-shrink-cushion", ref: innerElRef }, innerContent)))); }));
  69. }));
  70. }
  71. function renderInnerContent(props) {
  72. return props.text;
  73. }
  74. var TimeBodyAxis = /** @class */ (function (_super) {
  75. __extends(TimeBodyAxis, _super);
  76. function TimeBodyAxis() {
  77. return _super !== null && _super.apply(this, arguments) || this;
  78. }
  79. TimeBodyAxis.prototype.render = function () {
  80. return this.props.slatMetas.map(function (slatMeta) { return (createElement("tr", { key: slatMeta.key },
  81. createElement(TimeColsAxisCell, __assign({}, slatMeta)))); });
  82. };
  83. return TimeBodyAxis;
  84. }(BaseComponent));
  85. var DEFAULT_WEEK_NUM_FORMAT = createFormatter({ week: 'short' });
  86. var AUTO_ALL_DAY_MAX_EVENT_ROWS = 5;
  87. var TimeColsView = /** @class */ (function (_super) {
  88. __extends(TimeColsView, _super);
  89. function TimeColsView() {
  90. var _this = _super !== null && _super.apply(this, arguments) || this;
  91. _this.allDaySplitter = new AllDaySplitter(); // for use by subclasses
  92. _this.headerElRef = createRef();
  93. _this.rootElRef = createRef();
  94. _this.scrollerElRef = createRef();
  95. _this.state = {
  96. slatCoords: null,
  97. };
  98. _this.handleScrollTopRequest = function (scrollTop) {
  99. var scrollerEl = _this.scrollerElRef.current;
  100. if (scrollerEl) { // TODO: not sure how this could ever be null. weirdness with the reducer
  101. scrollerEl.scrollTop = scrollTop;
  102. }
  103. };
  104. /* Header Render Methods
  105. ------------------------------------------------------------------------------------------------------------------*/
  106. _this.renderHeadAxis = function (rowKey, frameHeight) {
  107. if (frameHeight === void 0) { frameHeight = ''; }
  108. var options = _this.context.options;
  109. var dateProfile = _this.props.dateProfile;
  110. var range = dateProfile.renderRange;
  111. var dayCnt = diffDays(range.start, range.end);
  112. var navLinkAttrs = (dayCnt === 1) // only do in day views (to avoid doing in week views that dont need it)
  113. ? buildNavLinkAttrs(_this.context, range.start, 'week')
  114. : {};
  115. if (options.weekNumbers && rowKey === 'day') {
  116. return (createElement(WeekNumberRoot, { date: range.start, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("th", { ref: rootElRef, "aria-hidden": true, className: [
  117. 'fc-timegrid-axis',
  118. 'fc-scrollgrid-shrink',
  119. ].concat(classNames).join(' ') },
  120. createElement("div", { className: "fc-timegrid-axis-frame fc-scrollgrid-shrink-frame fc-timegrid-axis-frame-liquid", style: { height: frameHeight } },
  121. createElement("a", __assign({ ref: innerElRef, className: "fc-timegrid-axis-cushion fc-scrollgrid-shrink-cushion fc-scrollgrid-sync-inner" }, navLinkAttrs), innerContent)))); }));
  122. }
  123. return (createElement("th", { "aria-hidden": true, className: "fc-timegrid-axis" },
  124. createElement("div", { className: "fc-timegrid-axis-frame", style: { height: frameHeight } })));
  125. };
  126. /* Table Component Render Methods
  127. ------------------------------------------------------------------------------------------------------------------*/
  128. // only a one-way height sync. we don't send the axis inner-content height to the DayGrid,
  129. // but DayGrid still needs to have classNames on inner elements in order to measure.
  130. _this.renderTableRowAxis = function (rowHeight) {
  131. var _a = _this.context, options = _a.options, viewApi = _a.viewApi;
  132. var hookProps = {
  133. text: options.allDayText,
  134. view: viewApi,
  135. };
  136. return (
  137. // TODO: make reusable hook. used in list view too
  138. createElement(RenderHook, { hookProps: hookProps, classNames: options.allDayClassNames, content: options.allDayContent, defaultContent: renderAllDayInner, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, "aria-hidden": true, className: [
  139. 'fc-timegrid-axis',
  140. 'fc-scrollgrid-shrink',
  141. ].concat(classNames).join(' ') },
  142. createElement("div", { className: 'fc-timegrid-axis-frame fc-scrollgrid-shrink-frame' + (rowHeight == null ? ' fc-timegrid-axis-frame-liquid' : ''), style: { height: rowHeight } },
  143. createElement("span", { className: "fc-timegrid-axis-cushion fc-scrollgrid-shrink-cushion fc-scrollgrid-sync-inner", ref: innerElRef }, innerContent)))); }));
  144. };
  145. _this.handleSlatCoords = function (slatCoords) {
  146. _this.setState({ slatCoords: slatCoords });
  147. };
  148. return _this;
  149. }
  150. // rendering
  151. // ----------------------------------------------------------------------------------------------------
  152. TimeColsView.prototype.renderSimpleLayout = function (headerRowContent, allDayContent, timeContent) {
  153. var _a = this, context = _a.context, props = _a.props;
  154. var sections = [];
  155. var stickyHeaderDates = getStickyHeaderDates(context.options);
  156. if (headerRowContent) {
  157. sections.push({
  158. type: 'header',
  159. key: 'header',
  160. isSticky: stickyHeaderDates,
  161. chunk: {
  162. elRef: this.headerElRef,
  163. tableClassName: 'fc-col-header',
  164. rowContent: headerRowContent,
  165. },
  166. });
  167. }
  168. if (allDayContent) {
  169. sections.push({
  170. type: 'body',
  171. key: 'all-day',
  172. chunk: { content: allDayContent },
  173. });
  174. sections.push({
  175. type: 'body',
  176. key: 'all-day-divider',
  177. outerContent: ( // TODO: rename to cellContent so don't need to define <tr>?
  178. createElement("tr", { role: "presentation", className: "fc-scrollgrid-section" },
  179. createElement("td", { className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))),
  180. });
  181. }
  182. sections.push({
  183. type: 'body',
  184. key: 'body',
  185. liquid: true,
  186. expandRows: Boolean(context.options.expandRows),
  187. chunk: {
  188. scrollerElRef: this.scrollerElRef,
  189. content: timeContent,
  190. },
  191. });
  192. return (createElement(ViewRoot, { viewSpec: context.viewSpec, elRef: this.rootElRef }, function (rootElRef, classNames) { return (createElement("div", { className: ['fc-timegrid'].concat(classNames).join(' '), ref: rootElRef },
  193. createElement(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [{ width: 'shrink' }], sections: sections }))); }));
  194. };
  195. TimeColsView.prototype.renderHScrollLayout = function (headerRowContent, allDayContent, timeContent, colCnt, dayMinWidth, slatMetas, slatCoords) {
  196. var _this = this;
  197. var ScrollGrid = this.context.pluginHooks.scrollGridImpl;
  198. if (!ScrollGrid) {
  199. throw new Error('No ScrollGrid implementation');
  200. }
  201. var _a = this, context = _a.context, props = _a.props;
  202. var stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options);
  203. var stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options);
  204. var sections = [];
  205. if (headerRowContent) {
  206. sections.push({
  207. type: 'header',
  208. key: 'header',
  209. isSticky: stickyHeaderDates,
  210. syncRowHeights: true,
  211. chunks: [
  212. {
  213. key: 'axis',
  214. rowContent: function (arg) { return (createElement("tr", { role: "presentation" }, _this.renderHeadAxis('day', arg.rowSyncHeights[0]))); },
  215. },
  216. {
  217. key: 'cols',
  218. elRef: this.headerElRef,
  219. tableClassName: 'fc-col-header',
  220. rowContent: headerRowContent,
  221. },
  222. ],
  223. });
  224. }
  225. if (allDayContent) {
  226. sections.push({
  227. type: 'body',
  228. key: 'all-day',
  229. syncRowHeights: true,
  230. chunks: [
  231. {
  232. key: 'axis',
  233. rowContent: function (contentArg) { return (createElement("tr", { role: "presentation" }, _this.renderTableRowAxis(contentArg.rowSyncHeights[0]))); },
  234. },
  235. {
  236. key: 'cols',
  237. content: allDayContent,
  238. },
  239. ],
  240. });
  241. sections.push({
  242. key: 'all-day-divider',
  243. type: 'body',
  244. outerContent: ( // TODO: rename to cellContent so don't need to define <tr>?
  245. createElement("tr", { role: "presentation", className: "fc-scrollgrid-section" },
  246. createElement("td", { colSpan: 2, className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))),
  247. });
  248. }
  249. var isNowIndicator = context.options.nowIndicator;
  250. sections.push({
  251. type: 'body',
  252. key: 'body',
  253. liquid: true,
  254. expandRows: Boolean(context.options.expandRows),
  255. chunks: [
  256. {
  257. key: 'axis',
  258. content: function (arg) { return (
  259. // TODO: make this now-indicator arrow more DRY with TimeColsContent
  260. createElement("div", { className: "fc-timegrid-axis-chunk" },
  261. createElement("table", { "aria-hidden": true, style: { height: arg.expandRows ? arg.clientHeight : '' } },
  262. arg.tableColGroupNode,
  263. createElement("tbody", null,
  264. createElement(TimeBodyAxis, { slatMetas: slatMetas }))),
  265. createElement("div", { className: "fc-timegrid-now-indicator-container" },
  266. createElement(NowTimer, { unit: isNowIndicator ? 'minute' : 'day' /* hacky */ }, function (nowDate) {
  267. var nowIndicatorTop = isNowIndicator &&
  268. slatCoords &&
  269. slatCoords.safeComputeTop(nowDate); // might return void
  270. if (typeof nowIndicatorTop === 'number') {
  271. return (createElement(NowIndicatorRoot, { isAxis: true, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timegrid-now-indicator-arrow'].concat(classNames).join(' '), style: { top: nowIndicatorTop } }, innerContent)); }));
  272. }
  273. return null;
  274. })))); },
  275. },
  276. {
  277. key: 'cols',
  278. scrollerElRef: this.scrollerElRef,
  279. content: timeContent,
  280. },
  281. ],
  282. });
  283. if (stickyFooterScrollbar) {
  284. sections.push({
  285. key: 'footer',
  286. type: 'footer',
  287. isSticky: true,
  288. chunks: [
  289. {
  290. key: 'axis',
  291. content: renderScrollShim,
  292. },
  293. {
  294. key: 'cols',
  295. content: renderScrollShim,
  296. },
  297. ],
  298. });
  299. }
  300. return (createElement(ViewRoot, { viewSpec: context.viewSpec, elRef: this.rootElRef }, function (rootElRef, classNames) { return (createElement("div", { className: ['fc-timegrid'].concat(classNames).join(' '), ref: rootElRef },
  301. createElement(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: false, colGroups: [
  302. { width: 'shrink', cols: [{ width: 'shrink' }] },
  303. { cols: [{ span: colCnt, minWidth: dayMinWidth }] },
  304. ], sections: sections }))); }));
  305. };
  306. /* Dimensions
  307. ------------------------------------------------------------------------------------------------------------------*/
  308. TimeColsView.prototype.getAllDayMaxEventProps = function () {
  309. var _a = this.context.options, dayMaxEvents = _a.dayMaxEvents, dayMaxEventRows = _a.dayMaxEventRows;
  310. if (dayMaxEvents === true || dayMaxEventRows === true) { // is auto?
  311. dayMaxEvents = undefined;
  312. dayMaxEventRows = AUTO_ALL_DAY_MAX_EVENT_ROWS; // make sure "auto" goes to a real number
  313. }
  314. return { dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows };
  315. };
  316. return TimeColsView;
  317. }(DateComponent));
  318. function renderAllDayInner(hookProps) {
  319. return hookProps.text;
  320. }
  321. var TimeColsSlatsCoords = /** @class */ (function () {
  322. function TimeColsSlatsCoords(positions, dateProfile, slotDuration) {
  323. this.positions = positions;
  324. this.dateProfile = dateProfile;
  325. this.slotDuration = slotDuration;
  326. }
  327. TimeColsSlatsCoords.prototype.safeComputeTop = function (date) {
  328. var dateProfile = this.dateProfile;
  329. if (rangeContainsMarker(dateProfile.currentRange, date)) {
  330. var startOfDayDate = startOfDay(date);
  331. var timeMs = date.valueOf() - startOfDayDate.valueOf();
  332. if (timeMs >= asRoughMs(dateProfile.slotMinTime) &&
  333. timeMs < asRoughMs(dateProfile.slotMaxTime)) {
  334. return this.computeTimeTop(createDuration(timeMs));
  335. }
  336. }
  337. return null;
  338. };
  339. // Computes the top coordinate, relative to the bounds of the grid, of the given date.
  340. // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.
  341. TimeColsSlatsCoords.prototype.computeDateTop = function (when, startOfDayDate) {
  342. if (!startOfDayDate) {
  343. startOfDayDate = startOfDay(when);
  344. }
  345. return this.computeTimeTop(createDuration(when.valueOf() - startOfDayDate.valueOf()));
  346. };
  347. // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).
  348. // This is a makeshify way to compute the time-top. Assumes all slatMetas dates are uniform.
  349. // Eventually allow computation with arbirary slat dates.
  350. TimeColsSlatsCoords.prototype.computeTimeTop = function (duration) {
  351. var _a = this, positions = _a.positions, dateProfile = _a.dateProfile;
  352. var len = positions.els.length;
  353. // floating-point value of # of slots covered
  354. var slatCoverage = (duration.milliseconds - asRoughMs(dateProfile.slotMinTime)) / asRoughMs(this.slotDuration);
  355. var slatIndex;
  356. var slatRemainder;
  357. // compute a floating-point number for how many slats should be progressed through.
  358. // from 0 to number of slats (inclusive)
  359. // constrained because slotMinTime/slotMaxTime might be customized.
  360. slatCoverage = Math.max(0, slatCoverage);
  361. slatCoverage = Math.min(len, slatCoverage);
  362. // an integer index of the furthest whole slat
  363. // from 0 to number slats (*exclusive*, so len-1)
  364. slatIndex = Math.floor(slatCoverage);
  365. slatIndex = Math.min(slatIndex, len - 1);
  366. // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition.
  367. // could be 1.0 if slatCoverage is covering *all* the slots
  368. slatRemainder = slatCoverage - slatIndex;
  369. return positions.tops[slatIndex] +
  370. positions.getHeight(slatIndex) * slatRemainder;
  371. };
  372. return TimeColsSlatsCoords;
  373. }());
  374. var TimeColsSlatsBody = /** @class */ (function (_super) {
  375. __extends(TimeColsSlatsBody, _super);
  376. function TimeColsSlatsBody() {
  377. return _super !== null && _super.apply(this, arguments) || this;
  378. }
  379. TimeColsSlatsBody.prototype.render = function () {
  380. var _a = this, props = _a.props, context = _a.context;
  381. var options = context.options;
  382. var slatElRefs = props.slatElRefs;
  383. return (createElement("tbody", null, props.slatMetas.map(function (slatMeta, i) {
  384. var hookProps = {
  385. time: slatMeta.time,
  386. date: context.dateEnv.toDate(slatMeta.date),
  387. view: context.viewApi,
  388. };
  389. var classNames = [
  390. 'fc-timegrid-slot',
  391. 'fc-timegrid-slot-lane',
  392. slatMeta.isLabeled ? '' : 'fc-timegrid-slot-minor',
  393. ];
  394. return (createElement("tr", { key: slatMeta.key, ref: slatElRefs.createRef(slatMeta.key) },
  395. props.axis && (createElement(TimeColsAxisCell, __assign({}, slatMeta))),
  396. createElement(RenderHook, { hookProps: hookProps, classNames: options.slotLaneClassNames, content: options.slotLaneContent, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-time": slatMeta.isoTimeStr }, innerContent)); })));
  397. })));
  398. };
  399. return TimeColsSlatsBody;
  400. }(BaseComponent));
  401. /*
  402. for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL.
  403. */
  404. var TimeColsSlats = /** @class */ (function (_super) {
  405. __extends(TimeColsSlats, _super);
  406. function TimeColsSlats() {
  407. var _this = _super !== null && _super.apply(this, arguments) || this;
  408. _this.rootElRef = createRef();
  409. _this.slatElRefs = new RefMap();
  410. return _this;
  411. }
  412. TimeColsSlats.prototype.render = function () {
  413. var _a = this, props = _a.props, context = _a.context;
  414. return (createElement("div", { ref: this.rootElRef, className: "fc-timegrid-slots" },
  415. createElement("table", { "aria-hidden": true, className: context.theme.getClass('table'), style: {
  416. minWidth: props.tableMinWidth,
  417. width: props.clientWidth,
  418. height: props.minHeight,
  419. } },
  420. props.tableColGroupNode /* relies on there only being a single <col> for the axis */,
  421. createElement(TimeColsSlatsBody, { slatElRefs: this.slatElRefs, axis: props.axis, slatMetas: props.slatMetas }))));
  422. };
  423. TimeColsSlats.prototype.componentDidMount = function () {
  424. this.updateSizing();
  425. };
  426. TimeColsSlats.prototype.componentDidUpdate = function () {
  427. this.updateSizing();
  428. };
  429. TimeColsSlats.prototype.componentWillUnmount = function () {
  430. if (this.props.onCoords) {
  431. this.props.onCoords(null);
  432. }
  433. };
  434. TimeColsSlats.prototype.updateSizing = function () {
  435. var _a = this, context = _a.context, props = _a.props;
  436. if (props.onCoords &&
  437. props.clientWidth !== null // means sizing has stabilized
  438. ) {
  439. var rootEl = this.rootElRef.current;
  440. if (rootEl.offsetHeight) { // not hidden by css
  441. props.onCoords(new TimeColsSlatsCoords(new PositionCache(this.rootElRef.current, collectSlatEls(this.slatElRefs.currentMap, props.slatMetas), false, true), this.props.dateProfile, context.options.slotDuration));
  442. }
  443. }
  444. };
  445. return TimeColsSlats;
  446. }(BaseComponent));
  447. function collectSlatEls(elMap, slatMetas) {
  448. return slatMetas.map(function (slatMeta) { return elMap[slatMeta.key]; });
  449. }
  450. function splitSegsByCol(segs, colCnt) {
  451. var segsByCol = [];
  452. var i;
  453. for (i = 0; i < colCnt; i += 1) {
  454. segsByCol.push([]);
  455. }
  456. if (segs) {
  457. for (i = 0; i < segs.length; i += 1) {
  458. segsByCol[segs[i].col].push(segs[i]);
  459. }
  460. }
  461. return segsByCol;
  462. }
  463. function splitInteractionByCol(ui, colCnt) {
  464. var byRow = [];
  465. if (!ui) {
  466. for (var i = 0; i < colCnt; i += 1) {
  467. byRow[i] = null;
  468. }
  469. }
  470. else {
  471. for (var i = 0; i < colCnt; i += 1) {
  472. byRow[i] = {
  473. affectedInstances: ui.affectedInstances,
  474. isEvent: ui.isEvent,
  475. segs: [],
  476. };
  477. }
  478. for (var _i = 0, _a = ui.segs; _i < _a.length; _i++) {
  479. var seg = _a[_i];
  480. byRow[seg.col].segs.push(seg);
  481. }
  482. }
  483. return byRow;
  484. }
  485. var TimeColMoreLink = /** @class */ (function (_super) {
  486. __extends(TimeColMoreLink, _super);
  487. function TimeColMoreLink() {
  488. var _this = _super !== null && _super.apply(this, arguments) || this;
  489. _this.rootElRef = createRef();
  490. return _this;
  491. }
  492. TimeColMoreLink.prototype.render = function () {
  493. var _this = this;
  494. var props = this.props;
  495. return (createElement(MoreLinkRoot, { allDayDate: null, moreCnt: props.hiddenSegs.length, allSegs: props.hiddenSegs, hiddenSegs: props.hiddenSegs, alignmentElRef: this.rootElRef, defaultContent: renderMoreLinkInner, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, todayRange: props.todayRange, popoverContent: function () { return renderPlainFgSegs(props.hiddenSegs, props); } }, function (rootElRef, classNames, innerElRef, innerContent, handleClick, title, isExpanded, popoverId) { return (createElement("a", { ref: function (el) {
  496. setRef(rootElRef, el);
  497. setRef(_this.rootElRef, el);
  498. }, className: ['fc-timegrid-more-link'].concat(classNames).join(' '), style: { top: props.top, bottom: props.bottom }, onClick: handleClick, title: title, "aria-expanded": isExpanded, "aria-controls": popoverId },
  499. createElement("div", { ref: innerElRef, className: "fc-timegrid-more-link-inner fc-sticky" }, innerContent))); }));
  500. };
  501. return TimeColMoreLink;
  502. }(BaseComponent));
  503. function renderMoreLinkInner(props) {
  504. return props.shortText;
  505. }
  506. // segInputs assumed sorted
  507. function buildPositioning(segInputs, strictOrder, maxStackCnt) {
  508. var hierarchy = new SegHierarchy();
  509. if (strictOrder != null) {
  510. hierarchy.strictOrder = strictOrder;
  511. }
  512. if (maxStackCnt != null) {
  513. hierarchy.maxStackCnt = maxStackCnt;
  514. }
  515. var hiddenEntries = hierarchy.addSegs(segInputs);
  516. var hiddenGroups = groupIntersectingEntries(hiddenEntries);
  517. var web = buildWeb(hierarchy);
  518. web = stretchWeb(web, 1); // all levelCoords/thickness will have 0.0-1.0
  519. var segRects = webToRects(web);
  520. return { segRects: segRects, hiddenGroups: hiddenGroups };
  521. }
  522. function buildWeb(hierarchy) {
  523. var entriesByLevel = hierarchy.entriesByLevel;
  524. var buildNode = cacheable(function (level, lateral) { return level + ':' + lateral; }, function (level, lateral) {
  525. var siblingRange = findNextLevelSegs(hierarchy, level, lateral);
  526. var nextLevelRes = buildNodes(siblingRange, buildNode);
  527. var entry = entriesByLevel[level][lateral];
  528. return [
  529. __assign(__assign({}, entry), { nextLevelNodes: nextLevelRes[0] }),
  530. entry.thickness + nextLevelRes[1], // the pressure builds
  531. ];
  532. });
  533. return buildNodes(entriesByLevel.length
  534. ? { level: 0, lateralStart: 0, lateralEnd: entriesByLevel[0].length }
  535. : null, buildNode)[0];
  536. }
  537. function buildNodes(siblingRange, buildNode) {
  538. if (!siblingRange) {
  539. return [[], 0];
  540. }
  541. var level = siblingRange.level, lateralStart = siblingRange.lateralStart, lateralEnd = siblingRange.lateralEnd;
  542. var lateral = lateralStart;
  543. var pairs = [];
  544. while (lateral < lateralEnd) {
  545. pairs.push(buildNode(level, lateral));
  546. lateral += 1;
  547. }
  548. pairs.sort(cmpDescPressures);
  549. return [
  550. pairs.map(extractNode),
  551. pairs[0][1], // first item's pressure
  552. ];
  553. }
  554. function cmpDescPressures(a, b) {
  555. return b[1] - a[1];
  556. }
  557. function extractNode(a) {
  558. return a[0];
  559. }
  560. function findNextLevelSegs(hierarchy, subjectLevel, subjectLateral) {
  561. var levelCoords = hierarchy.levelCoords, entriesByLevel = hierarchy.entriesByLevel;
  562. var subjectEntry = entriesByLevel[subjectLevel][subjectLateral];
  563. var afterSubject = levelCoords[subjectLevel] + subjectEntry.thickness;
  564. var levelCnt = levelCoords.length;
  565. var level = subjectLevel;
  566. // skip past levels that are too high up
  567. for (; level < levelCnt && levelCoords[level] < afterSubject; level += 1)
  568. ; // do nothing
  569. for (; level < levelCnt; level += 1) {
  570. var entries = entriesByLevel[level];
  571. var entry = void 0;
  572. var searchIndex = binarySearch(entries, subjectEntry.span.start, getEntrySpanEnd);
  573. var lateralStart = searchIndex[0] + searchIndex[1]; // if exact match (which doesn't collide), go to next one
  574. var lateralEnd = lateralStart;
  575. while ( // loop through entries that horizontally intersect
  576. (entry = entries[lateralEnd]) && // but not past the whole seg list
  577. entry.span.start < subjectEntry.span.end) {
  578. lateralEnd += 1;
  579. }
  580. if (lateralStart < lateralEnd) {
  581. return { level: level, lateralStart: lateralStart, lateralEnd: lateralEnd };
  582. }
  583. }
  584. return null;
  585. }
  586. function stretchWeb(topLevelNodes, totalThickness) {
  587. var stretchNode = cacheable(function (node, startCoord, prevThickness) { return buildEntryKey(node); }, function (node, startCoord, prevThickness) {
  588. var nextLevelNodes = node.nextLevelNodes, thickness = node.thickness;
  589. var allThickness = thickness + prevThickness;
  590. var thicknessFraction = thickness / allThickness;
  591. var endCoord;
  592. var newChildren = [];
  593. if (!nextLevelNodes.length) {
  594. endCoord = totalThickness;
  595. }
  596. else {
  597. for (var _i = 0, nextLevelNodes_1 = nextLevelNodes; _i < nextLevelNodes_1.length; _i++) {
  598. var childNode = nextLevelNodes_1[_i];
  599. if (endCoord === undefined) {
  600. var res = stretchNode(childNode, startCoord, allThickness);
  601. endCoord = res[0];
  602. newChildren.push(res[1]);
  603. }
  604. else {
  605. var res = stretchNode(childNode, endCoord, 0);
  606. newChildren.push(res[1]);
  607. }
  608. }
  609. }
  610. var newThickness = (endCoord - startCoord) * thicknessFraction;
  611. return [endCoord - newThickness, __assign(__assign({}, node), { thickness: newThickness, nextLevelNodes: newChildren })];
  612. });
  613. return topLevelNodes.map(function (node) { return stretchNode(node, 0, 0)[1]; });
  614. }
  615. // not sorted in any particular order
  616. function webToRects(topLevelNodes) {
  617. var rects = [];
  618. var processNode = cacheable(function (node, levelCoord, stackDepth) { return buildEntryKey(node); }, function (node, levelCoord, stackDepth) {
  619. var rect = __assign(__assign({}, node), { levelCoord: levelCoord,
  620. stackDepth: stackDepth, stackForward: 0 });
  621. rects.push(rect);
  622. return (rect.stackForward = processNodes(node.nextLevelNodes, levelCoord + node.thickness, stackDepth + 1) + 1);
  623. });
  624. function processNodes(nodes, levelCoord, stackDepth) {
  625. var stackForward = 0;
  626. for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
  627. var node = nodes_1[_i];
  628. stackForward = Math.max(processNode(node, levelCoord, stackDepth), stackForward);
  629. }
  630. return stackForward;
  631. }
  632. processNodes(topLevelNodes, 0, 0);
  633. return rects; // TODO: sort rects by levelCoord to be consistent with toRects?
  634. }
  635. // TODO: move to general util
  636. function cacheable(keyFunc, workFunc) {
  637. var cache = {};
  638. return function () {
  639. var args = [];
  640. for (var _i = 0; _i < arguments.length; _i++) {
  641. args[_i] = arguments[_i];
  642. }
  643. var key = keyFunc.apply(void 0, args);
  644. return (key in cache)
  645. ? cache[key]
  646. : (cache[key] = workFunc.apply(void 0, args));
  647. };
  648. }
  649. function computeSegVCoords(segs, colDate, slatCoords, eventMinHeight) {
  650. if (slatCoords === void 0) { slatCoords = null; }
  651. if (eventMinHeight === void 0) { eventMinHeight = 0; }
  652. var vcoords = [];
  653. if (slatCoords) {
  654. for (var i = 0; i < segs.length; i += 1) {
  655. var seg = segs[i];
  656. var spanStart = slatCoords.computeDateTop(seg.start, colDate);
  657. var spanEnd = Math.max(spanStart + (eventMinHeight || 0), // :(
  658. slatCoords.computeDateTop(seg.end, colDate));
  659. vcoords.push({
  660. start: Math.round(spanStart),
  661. end: Math.round(spanEnd), //
  662. });
  663. }
  664. }
  665. return vcoords;
  666. }
  667. function computeFgSegPlacements(segs, segVCoords, // might not have for every seg
  668. eventOrderStrict, eventMaxStack) {
  669. var segInputs = [];
  670. var dumbSegs = []; // segs without coords
  671. for (var i = 0; i < segs.length; i += 1) {
  672. var vcoords = segVCoords[i];
  673. if (vcoords) {
  674. segInputs.push({
  675. index: i,
  676. thickness: 1,
  677. span: vcoords,
  678. });
  679. }
  680. else {
  681. dumbSegs.push(segs[i]);
  682. }
  683. }
  684. var _a = buildPositioning(segInputs, eventOrderStrict, eventMaxStack), segRects = _a.segRects, hiddenGroups = _a.hiddenGroups;
  685. var segPlacements = [];
  686. for (var _i = 0, segRects_1 = segRects; _i < segRects_1.length; _i++) {
  687. var segRect = segRects_1[_i];
  688. segPlacements.push({
  689. seg: segs[segRect.index],
  690. rect: segRect,
  691. });
  692. }
  693. for (var _b = 0, dumbSegs_1 = dumbSegs; _b < dumbSegs_1.length; _b++) {
  694. var dumbSeg = dumbSegs_1[_b];
  695. segPlacements.push({ seg: dumbSeg, rect: null });
  696. }
  697. return { segPlacements: segPlacements, hiddenGroups: hiddenGroups };
  698. }
  699. var DEFAULT_TIME_FORMAT = createFormatter({
  700. hour: 'numeric',
  701. minute: '2-digit',
  702. meridiem: false,
  703. });
  704. var TimeColEvent = /** @class */ (function (_super) {
  705. __extends(TimeColEvent, _super);
  706. function TimeColEvent() {
  707. return _super !== null && _super.apply(this, arguments) || this;
  708. }
  709. TimeColEvent.prototype.render = function () {
  710. var classNames = [
  711. 'fc-timegrid-event',
  712. 'fc-v-event',
  713. ];
  714. if (this.props.isShort) {
  715. classNames.push('fc-timegrid-event-short');
  716. }
  717. return (createElement(StandardEvent, __assign({}, this.props, { defaultTimeFormat: DEFAULT_TIME_FORMAT, extraClassNames: classNames })));
  718. };
  719. return TimeColEvent;
  720. }(BaseComponent));
  721. var TimeColMisc = /** @class */ (function (_super) {
  722. __extends(TimeColMisc, _super);
  723. function TimeColMisc() {
  724. return _super !== null && _super.apply(this, arguments) || this;
  725. }
  726. TimeColMisc.prototype.render = function () {
  727. var props = this.props;
  728. return (createElement(DayCellContent, { date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraHookProps: props.extraHookProps }, function (innerElRef, innerContent) { return (innerContent &&
  729. createElement("div", { className: "fc-timegrid-col-misc", ref: innerElRef }, innerContent)); }));
  730. };
  731. return TimeColMisc;
  732. }(BaseComponent));
  733. var TimeCol = /** @class */ (function (_super) {
  734. __extends(TimeCol, _super);
  735. function TimeCol() {
  736. var _this = _super !== null && _super.apply(this, arguments) || this;
  737. _this.sortEventSegs = memoize(sortEventSegs);
  738. return _this;
  739. }
  740. // TODO: memoize event-placement?
  741. TimeCol.prototype.render = function () {
  742. var _this = this;
  743. var _a = this, props = _a.props, context = _a.context;
  744. var isSelectMirror = context.options.selectMirror;
  745. var mirrorSegs = (props.eventDrag && props.eventDrag.segs) ||
  746. (props.eventResize && props.eventResize.segs) ||
  747. (isSelectMirror && props.dateSelectionSegs) ||
  748. [];
  749. var interactionAffectedInstances = // TODO: messy way to compute this
  750. (props.eventDrag && props.eventDrag.affectedInstances) ||
  751. (props.eventResize && props.eventResize.affectedInstances) ||
  752. {};
  753. var sortedFgSegs = this.sortEventSegs(props.fgEventSegs, context.options.eventOrder);
  754. return (createElement(DayCellRoot, { elRef: props.elRef, date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraHookProps: props.extraHookProps }, function (rootElRef, classNames, dataAttrs) { return (createElement("td", __assign({ ref: rootElRef, role: "gridcell", className: ['fc-timegrid-col'].concat(classNames, props.extraClassNames || []).join(' ') }, dataAttrs, props.extraDataAttrs),
  755. createElement("div", { className: "fc-timegrid-col-frame" },
  756. createElement("div", { className: "fc-timegrid-col-bg" },
  757. _this.renderFillSegs(props.businessHourSegs, 'non-business'),
  758. _this.renderFillSegs(props.bgEventSegs, 'bg-event'),
  759. _this.renderFillSegs(props.dateSelectionSegs, 'highlight')),
  760. createElement("div", { className: "fc-timegrid-col-events" }, _this.renderFgSegs(sortedFgSegs, interactionAffectedInstances, false, false, false)),
  761. createElement("div", { className: "fc-timegrid-col-events" }, _this.renderFgSegs(mirrorSegs, {}, Boolean(props.eventDrag), Boolean(props.eventResize), Boolean(isSelectMirror))),
  762. createElement("div", { className: "fc-timegrid-now-indicator-container" }, _this.renderNowIndicator(props.nowIndicatorSegs)),
  763. createElement(TimeColMisc, { date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraHookProps: props.extraHookProps })))); }));
  764. };
  765. TimeCol.prototype.renderFgSegs = function (sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting) {
  766. var props = this.props;
  767. if (props.forPrint) {
  768. return renderPlainFgSegs(sortedFgSegs, props);
  769. }
  770. return this.renderPositionedFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting);
  771. };
  772. TimeCol.prototype.renderPositionedFgSegs = function (segs, // if not mirror, needs to be sorted
  773. segIsInvisible, isDragging, isResizing, isDateSelecting) {
  774. var _this = this;
  775. var _a = this.context.options, eventMaxStack = _a.eventMaxStack, eventShortHeight = _a.eventShortHeight, eventOrderStrict = _a.eventOrderStrict, eventMinHeight = _a.eventMinHeight;
  776. var _b = this.props, date = _b.date, slatCoords = _b.slatCoords, eventSelection = _b.eventSelection, todayRange = _b.todayRange, nowDate = _b.nowDate;
  777. var isMirror = isDragging || isResizing || isDateSelecting;
  778. var segVCoords = computeSegVCoords(segs, date, slatCoords, eventMinHeight);
  779. var _c = computeFgSegPlacements(segs, segVCoords, eventOrderStrict, eventMaxStack), segPlacements = _c.segPlacements, hiddenGroups = _c.hiddenGroups;
  780. return (createElement(Fragment, null,
  781. this.renderHiddenGroups(hiddenGroups, segs),
  782. segPlacements.map(function (segPlacement) {
  783. var seg = segPlacement.seg, rect = segPlacement.rect;
  784. var instanceId = seg.eventRange.instance.instanceId;
  785. var isVisible = isMirror || Boolean(!segIsInvisible[instanceId] && rect);
  786. var vStyle = computeSegVStyle(rect && rect.span);
  787. var hStyle = (!isMirror && rect) ? _this.computeSegHStyle(rect) : { left: 0, right: 0 };
  788. var isInset = Boolean(rect) && rect.stackForward > 0;
  789. var isShort = Boolean(rect) && (rect.span.end - rect.span.start) < eventShortHeight; // look at other places for this problem
  790. return (createElement("div", { className: 'fc-timegrid-event-harness' +
  791. (isInset ? ' fc-timegrid-event-harness-inset' : ''), key: instanceId, style: __assign(__assign({ visibility: isVisible ? '' : 'hidden' }, vStyle), hStyle) },
  792. createElement(TimeColEvent, __assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, isShort: isShort }, getSegMeta(seg, todayRange, nowDate)))));
  793. })));
  794. };
  795. // will already have eventMinHeight applied because segInputs already had it
  796. TimeCol.prototype.renderHiddenGroups = function (hiddenGroups, segs) {
  797. var _a = this.props, extraDateSpan = _a.extraDateSpan, dateProfile = _a.dateProfile, todayRange = _a.todayRange, nowDate = _a.nowDate, eventSelection = _a.eventSelection, eventDrag = _a.eventDrag, eventResize = _a.eventResize;
  798. return (createElement(Fragment, null, hiddenGroups.map(function (hiddenGroup) {
  799. var positionCss = computeSegVStyle(hiddenGroup.span);
  800. var hiddenSegs = compileSegsFromEntries(hiddenGroup.entries, segs);
  801. return (createElement(TimeColMoreLink, { key: buildIsoString(computeEarliestSegStart(hiddenSegs)), hiddenSegs: hiddenSegs, top: positionCss.top, bottom: positionCss.bottom, extraDateSpan: extraDateSpan, dateProfile: dateProfile, todayRange: todayRange, nowDate: nowDate, eventSelection: eventSelection, eventDrag: eventDrag, eventResize: eventResize }));
  802. })));
  803. };
  804. TimeCol.prototype.renderFillSegs = function (segs, fillType) {
  805. var _a = this, props = _a.props, context = _a.context;
  806. var segVCoords = computeSegVCoords(segs, props.date, props.slatCoords, context.options.eventMinHeight); // don't assume all populated
  807. var children = segVCoords.map(function (vcoords, i) {
  808. var seg = segs[i];
  809. return (createElement("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-timegrid-bg-harness", style: computeSegVStyle(vcoords) }, fillType === 'bg-event' ?
  810. createElement(BgEvent, __assign({ seg: seg }, getSegMeta(seg, props.todayRange, props.nowDate))) :
  811. renderFill(fillType)));
  812. });
  813. return createElement(Fragment, null, children);
  814. };
  815. TimeCol.prototype.renderNowIndicator = function (segs) {
  816. var _a = this.props, slatCoords = _a.slatCoords, date = _a.date;
  817. if (!slatCoords) {
  818. return null;
  819. }
  820. return segs.map(function (seg, i) { return (createElement(NowIndicatorRoot, { isAxis: false, date: date,
  821. // key doesn't matter. will only ever be one
  822. key: i }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timegrid-now-indicator-line'].concat(classNames).join(' '), style: { top: slatCoords.computeDateTop(seg.start, date) } }, innerContent)); })); });
  823. };
  824. TimeCol.prototype.computeSegHStyle = function (segHCoords) {
  825. var _a = this.context, isRtl = _a.isRtl, options = _a.options;
  826. var shouldOverlap = options.slotEventOverlap;
  827. var nearCoord = segHCoords.levelCoord; // the left side if LTR. the right side if RTL. floating-point
  828. var farCoord = segHCoords.levelCoord + segHCoords.thickness; // the right side if LTR. the left side if RTL. floating-point
  829. var left; // amount of space from left edge, a fraction of the total width
  830. var right; // amount of space from right edge, a fraction of the total width
  831. if (shouldOverlap) {
  832. // double the width, but don't go beyond the maximum forward coordinate (1.0)
  833. farCoord = Math.min(1, nearCoord + (farCoord - nearCoord) * 2);
  834. }
  835. if (isRtl) {
  836. left = 1 - farCoord;
  837. right = nearCoord;
  838. }
  839. else {
  840. left = nearCoord;
  841. right = 1 - farCoord;
  842. }
  843. var props = {
  844. zIndex: segHCoords.stackDepth + 1,
  845. left: left * 100 + '%',
  846. right: right * 100 + '%',
  847. };
  848. if (shouldOverlap && !segHCoords.stackForward) {
  849. // add padding to the edge so that forward stacked events don't cover the resizer's icon
  850. props[isRtl ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width
  851. }
  852. return props;
  853. };
  854. return TimeCol;
  855. }(BaseComponent));
  856. function renderPlainFgSegs(sortedFgSegs, _a) {
  857. var todayRange = _a.todayRange, nowDate = _a.nowDate, eventSelection = _a.eventSelection, eventDrag = _a.eventDrag, eventResize = _a.eventResize;
  858. var hiddenInstances = (eventDrag ? eventDrag.affectedInstances : null) ||
  859. (eventResize ? eventResize.affectedInstances : null) ||
  860. {};
  861. return (createElement(Fragment, null, sortedFgSegs.map(function (seg) {
  862. var instanceId = seg.eventRange.instance.instanceId;
  863. return (createElement("div", { key: instanceId, style: { visibility: hiddenInstances[instanceId] ? 'hidden' : '' } },
  864. createElement(TimeColEvent, __assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === eventSelection, isShort: false }, getSegMeta(seg, todayRange, nowDate)))));
  865. })));
  866. }
  867. function computeSegVStyle(segVCoords) {
  868. if (!segVCoords) {
  869. return { top: '', bottom: '' };
  870. }
  871. return {
  872. top: segVCoords.start,
  873. bottom: -segVCoords.end,
  874. };
  875. }
  876. function compileSegsFromEntries(segEntries, allSegs) {
  877. return segEntries.map(function (segEntry) { return allSegs[segEntry.index]; });
  878. }
  879. var TimeColsContent = /** @class */ (function (_super) {
  880. __extends(TimeColsContent, _super);
  881. function TimeColsContent() {
  882. var _this = _super !== null && _super.apply(this, arguments) || this;
  883. _this.splitFgEventSegs = memoize(splitSegsByCol);
  884. _this.splitBgEventSegs = memoize(splitSegsByCol);
  885. _this.splitBusinessHourSegs = memoize(splitSegsByCol);
  886. _this.splitNowIndicatorSegs = memoize(splitSegsByCol);
  887. _this.splitDateSelectionSegs = memoize(splitSegsByCol);
  888. _this.splitEventDrag = memoize(splitInteractionByCol);
  889. _this.splitEventResize = memoize(splitInteractionByCol);
  890. _this.rootElRef = createRef();
  891. _this.cellElRefs = new RefMap();
  892. return _this;
  893. }
  894. TimeColsContent.prototype.render = function () {
  895. var _this = this;
  896. var _a = this, props = _a.props, context = _a.context;
  897. var nowIndicatorTop = context.options.nowIndicator &&
  898. props.slatCoords &&
  899. props.slatCoords.safeComputeTop(props.nowDate); // might return void
  900. var colCnt = props.cells.length;
  901. var fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, colCnt);
  902. var bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, colCnt);
  903. var businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, colCnt);
  904. var nowIndicatorSegsByRow = this.splitNowIndicatorSegs(props.nowIndicatorSegs, colCnt);
  905. var dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, colCnt);
  906. var eventDragByRow = this.splitEventDrag(props.eventDrag, colCnt);
  907. var eventResizeByRow = this.splitEventResize(props.eventResize, colCnt);
  908. return (createElement("div", { className: "fc-timegrid-cols", ref: this.rootElRef },
  909. createElement("table", { role: "presentation", style: {
  910. minWidth: props.tableMinWidth,
  911. width: props.clientWidth,
  912. } },
  913. props.tableColGroupNode,
  914. createElement("tbody", { role: "presentation" },
  915. createElement("tr", { role: "row" },
  916. props.axis && (createElement("td", { "aria-hidden": true, className: "fc-timegrid-col fc-timegrid-axis" },
  917. createElement("div", { className: "fc-timegrid-col-frame" },
  918. createElement("div", { className: "fc-timegrid-now-indicator-container" }, typeof nowIndicatorTop === 'number' && (createElement(NowIndicatorRoot, { isAxis: true, date: props.nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timegrid-now-indicator-arrow'].concat(classNames).join(' '), style: { top: nowIndicatorTop } }, innerContent)); })))))),
  919. props.cells.map(function (cell, i) { return (createElement(TimeCol, { key: cell.key, elRef: _this.cellElRefs.createRef(cell.key), dateProfile: props.dateProfile, date: cell.date, nowDate: props.nowDate, todayRange: props.todayRange, extraHookProps: cell.extraHookProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, fgEventSegs: fgEventSegsByRow[i], bgEventSegs: bgEventSegsByRow[i], businessHourSegs: businessHourSegsByRow[i], nowIndicatorSegs: nowIndicatorSegsByRow[i], dateSelectionSegs: dateSelectionSegsByRow[i], eventDrag: eventDragByRow[i], eventResize: eventResizeByRow[i], slatCoords: props.slatCoords, eventSelection: props.eventSelection, forPrint: props.forPrint })); }))))));
  920. };
  921. TimeColsContent.prototype.componentDidMount = function () {
  922. this.updateCoords();
  923. };
  924. TimeColsContent.prototype.componentDidUpdate = function () {
  925. this.updateCoords();
  926. };
  927. TimeColsContent.prototype.updateCoords = function () {
  928. var props = this.props;
  929. if (props.onColCoords &&
  930. props.clientWidth !== null // means sizing has stabilized
  931. ) {
  932. props.onColCoords(new PositionCache(this.rootElRef.current, collectCellEls(this.cellElRefs.currentMap, props.cells), true, // horizontal
  933. false));
  934. }
  935. };
  936. return TimeColsContent;
  937. }(BaseComponent));
  938. function collectCellEls(elMap, cells) {
  939. return cells.map(function (cell) { return elMap[cell.key]; });
  940. }
  941. /* A component that renders one or more columns of vertical time slots
  942. ----------------------------------------------------------------------------------------------------------------------*/
  943. var TimeCols = /** @class */ (function (_super) {
  944. __extends(TimeCols, _super);
  945. function TimeCols() {
  946. var _this = _super !== null && _super.apply(this, arguments) || this;
  947. _this.processSlotOptions = memoize(processSlotOptions);
  948. _this.state = {
  949. slatCoords: null,
  950. };
  951. _this.handleRootEl = function (el) {
  952. if (el) {
  953. _this.context.registerInteractiveComponent(_this, {
  954. el: el,
  955. isHitComboAllowed: _this.props.isHitComboAllowed,
  956. });
  957. }
  958. else {
  959. _this.context.unregisterInteractiveComponent(_this);
  960. }
  961. };
  962. _this.handleScrollRequest = function (request) {
  963. var onScrollTopRequest = _this.props.onScrollTopRequest;
  964. var slatCoords = _this.state.slatCoords;
  965. if (onScrollTopRequest && slatCoords) {
  966. if (request.time) {
  967. var top_1 = slatCoords.computeTimeTop(request.time);
  968. top_1 = Math.ceil(top_1); // zoom can give weird floating-point values. rather scroll a little bit further
  969. if (top_1) {
  970. top_1 += 1; // to overcome top border that slots beyond the first have. looks better
  971. }
  972. onScrollTopRequest(top_1);
  973. }
  974. return true;
  975. }
  976. return false;
  977. };
  978. _this.handleColCoords = function (colCoords) {
  979. _this.colCoords = colCoords;
  980. };
  981. _this.handleSlatCoords = function (slatCoords) {
  982. _this.setState({ slatCoords: slatCoords });
  983. if (_this.props.onSlatCoords) {
  984. _this.props.onSlatCoords(slatCoords);
  985. }
  986. };
  987. return _this;
  988. }
  989. TimeCols.prototype.render = function () {
  990. var _a = this, props = _a.props, state = _a.state;
  991. return (createElement("div", { className: "fc-timegrid-body", ref: this.handleRootEl, style: {
  992. // these props are important to give this wrapper correct dimensions for interactions
  993. // TODO: if we set it here, can we avoid giving to inner tables?
  994. width: props.clientWidth,
  995. minWidth: props.tableMinWidth,
  996. } },
  997. createElement(TimeColsSlats, { axis: props.axis, dateProfile: props.dateProfile, slatMetas: props.slatMetas, clientWidth: props.clientWidth, minHeight: props.expandRows ? props.clientHeight : '', tableMinWidth: props.tableMinWidth, tableColGroupNode: props.axis ? props.tableColGroupNode : null /* axis depends on the colgroup's shrinking */, onCoords: this.handleSlatCoords }),
  998. createElement(TimeColsContent, { cells: props.cells, axis: props.axis, dateProfile: props.dateProfile, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange, nowDate: props.nowDate, nowIndicatorSegs: props.nowIndicatorSegs, clientWidth: props.clientWidth, tableMinWidth: props.tableMinWidth, tableColGroupNode: props.tableColGroupNode, slatCoords: state.slatCoords, onColCoords: this.handleColCoords, forPrint: props.forPrint })));
  999. };
  1000. TimeCols.prototype.componentDidMount = function () {
  1001. this.scrollResponder = this.context.createScrollResponder(this.handleScrollRequest);
  1002. };
  1003. TimeCols.prototype.componentDidUpdate = function (prevProps) {
  1004. this.scrollResponder.update(prevProps.dateProfile !== this.props.dateProfile);
  1005. };
  1006. TimeCols.prototype.componentWillUnmount = function () {
  1007. this.scrollResponder.detach();
  1008. };
  1009. TimeCols.prototype.queryHit = function (positionLeft, positionTop) {
  1010. var _a = this.context, dateEnv = _a.dateEnv, options = _a.options;
  1011. var colCoords = this.colCoords;
  1012. var dateProfile = this.props.dateProfile;
  1013. var slatCoords = this.state.slatCoords;
  1014. var _b = this.processSlotOptions(this.props.slotDuration, options.snapDuration), snapDuration = _b.snapDuration, snapsPerSlot = _b.snapsPerSlot;
  1015. var colIndex = colCoords.leftToIndex(positionLeft);
  1016. var slatIndex = slatCoords.positions.topToIndex(positionTop);
  1017. if (colIndex != null && slatIndex != null) {
  1018. var cell = this.props.cells[colIndex];
  1019. var slatTop = slatCoords.positions.tops[slatIndex];
  1020. var slatHeight = slatCoords.positions.getHeight(slatIndex);
  1021. var partial = (positionTop - slatTop) / slatHeight; // floating point number between 0 and 1
  1022. var localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat
  1023. var snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
  1024. var dayDate = this.props.cells[colIndex].date;
  1025. var time = addDurations(dateProfile.slotMinTime, multiplyDuration(snapDuration, snapIndex));
  1026. var start = dateEnv.add(dayDate, time);
  1027. var end = dateEnv.add(start, snapDuration);
  1028. return {
  1029. dateProfile: dateProfile,
  1030. dateSpan: __assign({ range: { start: start, end: end }, allDay: false }, cell.extraDateSpan),
  1031. dayEl: colCoords.els[colIndex],
  1032. rect: {
  1033. left: colCoords.lefts[colIndex],
  1034. right: colCoords.rights[colIndex],
  1035. top: slatTop,
  1036. bottom: slatTop + slatHeight,
  1037. },
  1038. layer: 0,
  1039. };
  1040. }
  1041. return null;
  1042. };
  1043. return TimeCols;
  1044. }(DateComponent));
  1045. function processSlotOptions(slotDuration, snapDurationOverride) {
  1046. var snapDuration = snapDurationOverride || slotDuration;
  1047. var snapsPerSlot = wholeDivideDurations(slotDuration, snapDuration);
  1048. if (snapsPerSlot === null) {
  1049. snapDuration = slotDuration;
  1050. snapsPerSlot = 1;
  1051. // TODO: say warning?
  1052. }
  1053. return { snapDuration: snapDuration, snapsPerSlot: snapsPerSlot };
  1054. }
  1055. var DayTimeColsSlicer = /** @class */ (function (_super) {
  1056. __extends(DayTimeColsSlicer, _super);
  1057. function DayTimeColsSlicer() {
  1058. return _super !== null && _super.apply(this, arguments) || this;
  1059. }
  1060. DayTimeColsSlicer.prototype.sliceRange = function (range, dayRanges) {
  1061. var segs = [];
  1062. for (var col = 0; col < dayRanges.length; col += 1) {
  1063. var segRange = intersectRanges(range, dayRanges[col]);
  1064. if (segRange) {
  1065. segs.push({
  1066. start: segRange.start,
  1067. end: segRange.end,
  1068. isStart: segRange.start.valueOf() === range.start.valueOf(),
  1069. isEnd: segRange.end.valueOf() === range.end.valueOf(),
  1070. col: col,
  1071. });
  1072. }
  1073. }
  1074. return segs;
  1075. };
  1076. return DayTimeColsSlicer;
  1077. }(Slicer));
  1078. var DayTimeCols = /** @class */ (function (_super) {
  1079. __extends(DayTimeCols, _super);
  1080. function DayTimeCols() {
  1081. var _this = _super !== null && _super.apply(this, arguments) || this;
  1082. _this.buildDayRanges = memoize(buildDayRanges);
  1083. _this.slicer = new DayTimeColsSlicer();
  1084. _this.timeColsRef = createRef();
  1085. return _this;
  1086. }
  1087. DayTimeCols.prototype.render = function () {
  1088. var _this = this;
  1089. var _a = this, props = _a.props, context = _a.context;
  1090. var dateProfile = props.dateProfile, dayTableModel = props.dayTableModel;
  1091. var isNowIndicator = context.options.nowIndicator;
  1092. var dayRanges = this.buildDayRanges(dayTableModel, dateProfile, context.dateEnv);
  1093. // give it the first row of cells
  1094. // TODO: would move this further down hierarchy, but sliceNowDate needs it
  1095. return (createElement(NowTimer, { unit: isNowIndicator ? 'minute' : 'day' }, function (nowDate, todayRange) { return (createElement(TimeCols, __assign({ ref: _this.timeColsRef }, _this.slicer.sliceProps(props, dateProfile, null, context, dayRanges), { forPrint: props.forPrint, axis: props.axis, dateProfile: dateProfile, slatMetas: props.slatMetas, slotDuration: props.slotDuration, cells: dayTableModel.cells[0], tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, clientWidth: props.clientWidth, clientHeight: props.clientHeight, expandRows: props.expandRows, nowDate: nowDate, nowIndicatorSegs: isNowIndicator && _this.slicer.sliceNowDate(nowDate, context, dayRanges), todayRange: todayRange, onScrollTopRequest: props.onScrollTopRequest, onSlatCoords: props.onSlatCoords }))); }));
  1096. };
  1097. return DayTimeCols;
  1098. }(DateComponent));
  1099. function buildDayRanges(dayTableModel, dateProfile, dateEnv) {
  1100. var ranges = [];
  1101. for (var _i = 0, _a = dayTableModel.headerDates; _i < _a.length; _i++) {
  1102. var date = _a[_i];
  1103. ranges.push({
  1104. start: dateEnv.add(date, dateProfile.slotMinTime),
  1105. end: dateEnv.add(date, dateProfile.slotMaxTime),
  1106. });
  1107. }
  1108. return ranges;
  1109. }
  1110. // potential nice values for the slot-duration and interval-duration
  1111. // from largest to smallest
  1112. var STOCK_SUB_DURATIONS = [
  1113. { hours: 1 },
  1114. { minutes: 30 },
  1115. { minutes: 15 },
  1116. { seconds: 30 },
  1117. { seconds: 15 },
  1118. ];
  1119. function buildSlatMetas(slotMinTime, slotMaxTime, explicitLabelInterval, slotDuration, dateEnv) {
  1120. var dayStart = new Date(0);
  1121. var slatTime = slotMinTime;
  1122. var slatIterator = createDuration(0);
  1123. var labelInterval = explicitLabelInterval || computeLabelInterval(slotDuration);
  1124. var metas = [];
  1125. while (asRoughMs(slatTime) < asRoughMs(slotMaxTime)) {
  1126. var date = dateEnv.add(dayStart, slatTime);
  1127. var isLabeled = wholeDivideDurations(slatIterator, labelInterval) !== null;
  1128. metas.push({
  1129. date: date,
  1130. time: slatTime,
  1131. key: date.toISOString(),
  1132. isoTimeStr: formatIsoTimeString(date),
  1133. isLabeled: isLabeled,
  1134. });
  1135. slatTime = addDurations(slatTime, slotDuration);
  1136. slatIterator = addDurations(slatIterator, slotDuration);
  1137. }
  1138. return metas;
  1139. }
  1140. // Computes an automatic value for slotLabelInterval
  1141. function computeLabelInterval(slotDuration) {
  1142. var i;
  1143. var labelInterval;
  1144. var slotsPerLabel;
  1145. // find the smallest stock label interval that results in more than one slots-per-label
  1146. for (i = STOCK_SUB_DURATIONS.length - 1; i >= 0; i -= 1) {
  1147. labelInterval = createDuration(STOCK_SUB_DURATIONS[i]);
  1148. slotsPerLabel = wholeDivideDurations(labelInterval, slotDuration);
  1149. if (slotsPerLabel !== null && slotsPerLabel > 1) {
  1150. return labelInterval;
  1151. }
  1152. }
  1153. return slotDuration; // fall back
  1154. }
  1155. var DayTimeColsView = /** @class */ (function (_super) {
  1156. __extends(DayTimeColsView, _super);
  1157. function DayTimeColsView() {
  1158. var _this = _super !== null && _super.apply(this, arguments) || this;
  1159. _this.buildTimeColsModel = memoize(buildTimeColsModel);
  1160. _this.buildSlatMetas = memoize(buildSlatMetas);
  1161. return _this;
  1162. }
  1163. DayTimeColsView.prototype.render = function () {
  1164. var _this = this;
  1165. var _a = this.context, options = _a.options, dateEnv = _a.dateEnv, dateProfileGenerator = _a.dateProfileGenerator;
  1166. var props = this.props;
  1167. var dateProfile = props.dateProfile;
  1168. var dayTableModel = this.buildTimeColsModel(dateProfile, dateProfileGenerator);
  1169. var splitProps = this.allDaySplitter.splitProps(props);
  1170. var slatMetas = this.buildSlatMetas(dateProfile.slotMinTime, dateProfile.slotMaxTime, options.slotLabelInterval, options.slotDuration, dateEnv);
  1171. var dayMinWidth = options.dayMinWidth;
  1172. var hasAttachedAxis = !dayMinWidth;
  1173. var hasDetachedAxis = dayMinWidth;
  1174. var headerContent = options.dayHeaders && (createElement(DayHeader, { dates: dayTableModel.headerDates, dateProfile: dateProfile, datesRepDistinctDays: true, renderIntro: hasAttachedAxis ? this.renderHeadAxis : null }));
  1175. var allDayContent = (options.allDaySlot !== false) && (function (contentArg) { return (createElement(DayTable, __assign({}, splitProps.allDay, { dateProfile: dateProfile, dayTableModel: dayTableModel, nextDayThreshold: options.nextDayThreshold, tableMinWidth: contentArg.tableMinWidth, colGroupNode: contentArg.tableColGroupNode, renderRowIntro: hasAttachedAxis ? _this.renderTableRowAxis : null, showWeekNumbers: false, expandRows: false, headerAlignElRef: _this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }, _this.getAllDayMaxEventProps()))); });
  1176. var timeGridContent = function (contentArg) { return (createElement(DayTimeCols, __assign({}, splitProps.timed, { dayTableModel: dayTableModel, dateProfile: dateProfile, axis: hasAttachedAxis, slotDuration: options.slotDuration, slatMetas: slatMetas, forPrint: props.forPrint, tableColGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, onSlatCoords: _this.handleSlatCoords, expandRows: contentArg.expandRows, onScrollTopRequest: _this.handleScrollTopRequest }))); };
  1177. return hasDetachedAxis
  1178. ? this.renderHScrollLayout(headerContent, allDayContent, timeGridContent, dayTableModel.colCnt, dayMinWidth, slatMetas, this.state.slatCoords)
  1179. : this.renderSimpleLayout(headerContent, allDayContent, timeGridContent);
  1180. };
  1181. return DayTimeColsView;
  1182. }(TimeColsView));
  1183. function buildTimeColsModel(dateProfile, dateProfileGenerator) {
  1184. var daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
  1185. return new DayTableModel(daySeries, false);
  1186. }
  1187. var OPTION_REFINERS = {
  1188. allDaySlot: Boolean,
  1189. };
  1190. var main = createPlugin({
  1191. initialView: 'timeGridWeek',
  1192. optionRefiners: OPTION_REFINERS,
  1193. views: {
  1194. timeGrid: {
  1195. component: DayTimeColsView,
  1196. usesMinMaxTime: true,
  1197. allDaySlot: true,
  1198. slotDuration: '00:30:00',
  1199. slotEventOverlap: true, // a bad name. confused with overlap/constraint system
  1200. },
  1201. timeGridDay: {
  1202. type: 'timeGrid',
  1203. duration: { days: 1 },
  1204. },
  1205. timeGridWeek: {
  1206. type: 'timeGrid',
  1207. duration: { weeks: 1 },
  1208. },
  1209. },
  1210. });
  1211. export default main;
  1212. export { DayTimeCols, DayTimeColsSlicer, DayTimeColsView, TimeCols, TimeColsSlatsCoords, TimeColsView, buildDayRanges, buildSlatMetas, buildTimeColsModel };
  1213. //# sourceMappingURL=main.js.map