internal.cjs 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var internal_cjs = require('@fullcalendar/core/internal.cjs');
  4. var preact_cjs = require('@fullcalendar/core/preact.cjs');
  5. /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells.
  6. ----------------------------------------------------------------------------------------------------------------------*/
  7. // It is a manager for a Table subcomponent, which does most of the heavy lifting.
  8. // It is responsible for managing width/height.
  9. class TableView extends internal_cjs.DateComponent {
  10. constructor() {
  11. super(...arguments);
  12. this.headerElRef = preact_cjs.createRef();
  13. }
  14. renderSimpleLayout(headerRowContent, bodyContent) {
  15. let { props, context } = this;
  16. let sections = [];
  17. let stickyHeaderDates = internal_cjs.getStickyHeaderDates(context.options);
  18. if (headerRowContent) {
  19. sections.push({
  20. type: 'header',
  21. key: 'header',
  22. isSticky: stickyHeaderDates,
  23. chunk: {
  24. elRef: this.headerElRef,
  25. tableClassName: 'fc-col-header',
  26. rowContent: headerRowContent,
  27. },
  28. });
  29. }
  30. sections.push({
  31. type: 'body',
  32. key: 'body',
  33. liquid: true,
  34. chunk: { content: bodyContent },
  35. });
  36. return (preact_cjs.createElement(internal_cjs.ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
  37. preact_cjs.createElement(internal_cjs.SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections })));
  38. }
  39. renderHScrollLayout(headerRowContent, bodyContent, colCnt, dayMinWidth) {
  40. let ScrollGrid = this.context.pluginHooks.scrollGridImpl;
  41. if (!ScrollGrid) {
  42. throw new Error('No ScrollGrid implementation');
  43. }
  44. let { props, context } = this;
  45. let stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(context.options);
  46. let stickyFooterScrollbar = !props.forPrint && internal_cjs.getStickyFooterScrollbar(context.options);
  47. let sections = [];
  48. if (headerRowContent) {
  49. sections.push({
  50. type: 'header',
  51. key: 'header',
  52. isSticky: stickyHeaderDates,
  53. chunks: [{
  54. key: 'main',
  55. elRef: this.headerElRef,
  56. tableClassName: 'fc-col-header',
  57. rowContent: headerRowContent,
  58. }],
  59. });
  60. }
  61. sections.push({
  62. type: 'body',
  63. key: 'body',
  64. liquid: true,
  65. chunks: [{
  66. key: 'main',
  67. content: bodyContent,
  68. }],
  69. });
  70. if (stickyFooterScrollbar) {
  71. sections.push({
  72. type: 'footer',
  73. key: 'footer',
  74. isSticky: true,
  75. chunks: [{
  76. key: 'main',
  77. content: internal_cjs.renderScrollShim,
  78. }],
  79. });
  80. }
  81. return (preact_cjs.createElement(internal_cjs.ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
  82. preact_cjs.createElement(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections })));
  83. }
  84. }
  85. function splitSegsByRow(segs, rowCnt) {
  86. let byRow = [];
  87. for (let i = 0; i < rowCnt; i += 1) {
  88. byRow[i] = [];
  89. }
  90. for (let seg of segs) {
  91. byRow[seg.row].push(seg);
  92. }
  93. return byRow;
  94. }
  95. function splitSegsByFirstCol(segs, colCnt) {
  96. let byCol = [];
  97. for (let i = 0; i < colCnt; i += 1) {
  98. byCol[i] = [];
  99. }
  100. for (let seg of segs) {
  101. byCol[seg.firstCol].push(seg);
  102. }
  103. return byCol;
  104. }
  105. function splitInteractionByRow(ui, rowCnt) {
  106. let byRow = [];
  107. if (!ui) {
  108. for (let i = 0; i < rowCnt; i += 1) {
  109. byRow[i] = null;
  110. }
  111. }
  112. else {
  113. for (let i = 0; i < rowCnt; i += 1) {
  114. byRow[i] = {
  115. affectedInstances: ui.affectedInstances,
  116. isEvent: ui.isEvent,
  117. segs: [],
  118. };
  119. }
  120. for (let seg of ui.segs) {
  121. byRow[seg.row].segs.push(seg);
  122. }
  123. }
  124. return byRow;
  125. }
  126. const DEFAULT_TABLE_EVENT_TIME_FORMAT = internal_cjs.createFormatter({
  127. hour: 'numeric',
  128. minute: '2-digit',
  129. omitZeroMinute: true,
  130. meridiem: 'narrow',
  131. });
  132. function hasListItemDisplay(seg) {
  133. let { display } = seg.eventRange.ui;
  134. return display === 'list-item' || (display === 'auto' &&
  135. !seg.eventRange.def.allDay &&
  136. seg.firstCol === seg.lastCol && // can't be multi-day
  137. seg.isStart && // "
  138. seg.isEnd // "
  139. );
  140. }
  141. class TableBlockEvent extends internal_cjs.BaseComponent {
  142. render() {
  143. let { props } = this;
  144. return (preact_cjs.createElement(internal_cjs.StandardEvent, Object.assign({}, props, { elClasses: ['fc-daygrid-event', 'fc-daygrid-block-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.seg.eventRange.def.allDay })));
  145. }
  146. }
  147. class TableListItemEvent extends internal_cjs.BaseComponent {
  148. render() {
  149. let { props, context } = this;
  150. let { options } = context;
  151. let { seg } = props;
  152. let timeFormat = options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT;
  153. let timeText = internal_cjs.buildSegTimeText(seg, timeFormat, context, true, props.defaultDisplayEventEnd);
  154. return (preact_cjs.createElement(internal_cjs.EventContainer, Object.assign({}, props, { elTag: "a", elClasses: ['fc-daygrid-event', 'fc-daygrid-dot-event'], elAttrs: internal_cjs.getSegAnchorAttrs(props.seg, context), defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));
  155. }
  156. }
  157. function renderInnerContent(renderProps) {
  158. return (preact_cjs.createElement(preact_cjs.Fragment, null,
  159. preact_cjs.createElement("div", { className: "fc-daygrid-event-dot", style: { borderColor: renderProps.borderColor || renderProps.backgroundColor } }),
  160. renderProps.timeText && (preact_cjs.createElement("div", { className: "fc-event-time" }, renderProps.timeText)),
  161. preact_cjs.createElement("div", { className: "fc-event-title" }, renderProps.event.title || preact_cjs.createElement(preact_cjs.Fragment, null, "\u00A0"))));
  162. }
  163. class TableCellMoreLink extends internal_cjs.BaseComponent {
  164. constructor() {
  165. super(...arguments);
  166. this.compileSegs = internal_cjs.memoize(compileSegs);
  167. }
  168. render() {
  169. let { props } = this;
  170. let { allSegs, invisibleSegs } = this.compileSegs(props.singlePlacements);
  171. return (preact_cjs.createElement(internal_cjs.MoreLinkContainer, { elClasses: ['fc-daygrid-more-link'], dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, moreCnt: props.moreCnt, allSegs: allSegs, hiddenSegs: invisibleSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: () => {
  172. let isForcedInvisible = (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
  173. (props.eventResize ? props.eventResize.affectedInstances : null) ||
  174. {};
  175. return (preact_cjs.createElement(preact_cjs.Fragment, null, allSegs.map((seg) => {
  176. let instanceId = seg.eventRange.instance.instanceId;
  177. return (preact_cjs.createElement("div", { className: "fc-daygrid-event-harness", key: instanceId, style: {
  178. visibility: isForcedInvisible[instanceId] ? 'hidden' : '',
  179. } }, hasListItemDisplay(seg) ? (preact_cjs.createElement(TableListItemEvent, Object.assign({ seg: seg, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getSegMeta(seg, props.todayRange)))) : (preact_cjs.createElement(TableBlockEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getSegMeta(seg, props.todayRange))))));
  180. })));
  181. } }));
  182. }
  183. }
  184. function compileSegs(singlePlacements) {
  185. let allSegs = [];
  186. let invisibleSegs = [];
  187. for (let placement of singlePlacements) {
  188. allSegs.push(placement.seg);
  189. if (!placement.isVisible) {
  190. invisibleSegs.push(placement.seg);
  191. }
  192. }
  193. return { allSegs, invisibleSegs };
  194. }
  195. const DEFAULT_WEEK_NUM_FORMAT = internal_cjs.createFormatter({ week: 'narrow' });
  196. class TableCell extends internal_cjs.DateComponent {
  197. constructor() {
  198. super(...arguments);
  199. this.rootElRef = preact_cjs.createRef();
  200. this.state = {
  201. dayNumberId: internal_cjs.getUniqueDomId(),
  202. };
  203. this.handleRootEl = (el) => {
  204. internal_cjs.setRef(this.rootElRef, el);
  205. internal_cjs.setRef(this.props.elRef, el);
  206. };
  207. }
  208. render() {
  209. let { context, props, state, rootElRef } = this;
  210. let { options, dateEnv } = context;
  211. let { date, dateProfile } = props;
  212. // TODO: memoize this?
  213. const isMonthStart = props.showDayNumber &&
  214. shouldDisplayMonthStart(date, dateProfile.currentRange, dateEnv);
  215. return (preact_cjs.createElement(internal_cjs.DayCellContainer, { elTag: "td", elRef: this.handleRootEl, elClasses: [
  216. 'fc-daygrid-day',
  217. ...(props.extraClassNames || []),
  218. ], elAttrs: Object.assign(Object.assign(Object.assign({}, props.extraDataAttrs), (props.showDayNumber ? { 'aria-labelledby': state.dayNumberId } : {})), { role: 'gridcell' }), defaultGenerator: renderTopInner, date: date, dateProfile: dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart, extraRenderProps: props.extraRenderProps }, (InnerContent, renderProps) => (preact_cjs.createElement("div", { ref: props.innerElRef, className: "fc-daygrid-day-frame fc-scrollgrid-sync-inner", style: { minHeight: props.minHeight } },
  219. props.showWeekNumber && (preact_cjs.createElement(internal_cjs.WeekNumberContainer, { elTag: "a", elClasses: ['fc-daygrid-week-number'], elAttrs: internal_cjs.buildNavLinkAttrs(context, date, 'week'), date: date, defaultFormat: DEFAULT_WEEK_NUM_FORMAT })),
  220. !renderProps.isDisabled &&
  221. (props.showDayNumber || internal_cjs.hasCustomDayCellContent(options) || props.forceDayTop) ? (preact_cjs.createElement("div", { className: "fc-daygrid-day-top" },
  222. preact_cjs.createElement(InnerContent, { elTag: "a", elClasses: [
  223. 'fc-daygrid-day-number',
  224. isMonthStart && 'fc-daygrid-month-start',
  225. ], elAttrs: Object.assign(Object.assign({}, internal_cjs.buildNavLinkAttrs(context, date)), { id: state.dayNumberId }) }))) : props.showDayNumber ? (
  226. // for creating correct amount of space (see issue #7162)
  227. preact_cjs.createElement("div", { className: "fc-daygrid-day-top", style: { visibility: 'hidden' } },
  228. preact_cjs.createElement("a", { className: "fc-daygrid-day-number" }, "\u00A0"))) : undefined,
  229. preact_cjs.createElement("div", { className: "fc-daygrid-day-events", ref: props.fgContentElRef },
  230. props.fgContent,
  231. preact_cjs.createElement("div", { className: "fc-daygrid-day-bottom", style: { marginTop: props.moreMarginTop } },
  232. preact_cjs.createElement(TableCellMoreLink, { allDayDate: date, singlePlacements: props.singlePlacements, moreCnt: props.moreCnt, alignmentElRef: rootElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange }))),
  233. preact_cjs.createElement("div", { className: "fc-daygrid-day-bg" }, props.bgContent)))));
  234. }
  235. }
  236. function renderTopInner(props) {
  237. return props.dayNumberText || preact_cjs.createElement(preact_cjs.Fragment, null, "\u00A0");
  238. }
  239. function shouldDisplayMonthStart(date, currentRange, dateEnv) {
  240. const { start: currentStart, end: currentEnd } = currentRange;
  241. const currentEndIncl = internal_cjs.addMs(currentEnd, -1);
  242. const currentFirstYear = dateEnv.getYear(currentStart);
  243. const currentFirstMonth = dateEnv.getMonth(currentStart);
  244. const currentLastYear = dateEnv.getYear(currentEndIncl);
  245. const currentLastMonth = dateEnv.getMonth(currentEndIncl);
  246. // spans more than one month?
  247. return !(currentFirstYear === currentLastYear && currentFirstMonth === currentLastMonth) &&
  248. Boolean(
  249. // first date in current view?
  250. date.valueOf() === currentStart.valueOf() ||
  251. // a month-start that's within the current range?
  252. (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
  253. }
  254. function generateSegKey(seg) {
  255. return seg.eventRange.instance.instanceId + ':' + seg.firstCol;
  256. }
  257. function generateSegUid(seg) {
  258. return generateSegKey(seg) + ':' + seg.lastCol;
  259. }
  260. function computeFgSegPlacement(segs, // assumed already sorted
  261. dayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells) {
  262. let hierarchy = new DayGridSegHierarchy((segEntry) => {
  263. // TODO: more DRY with generateSegUid
  264. let segUid = segs[segEntry.index].eventRange.instance.instanceId +
  265. ':' + segEntry.span.start +
  266. ':' + (segEntry.span.end - 1);
  267. // if no thickness known, assume 1 (if 0, so small it always fits)
  268. return segHeights[segUid] || 1;
  269. });
  270. hierarchy.allowReslicing = true;
  271. hierarchy.strictOrder = strictOrder;
  272. if (dayMaxEvents === true || dayMaxEventRows === true) {
  273. hierarchy.maxCoord = maxContentHeight;
  274. hierarchy.hiddenConsumes = true;
  275. }
  276. else if (typeof dayMaxEvents === 'number') {
  277. hierarchy.maxStackCnt = dayMaxEvents;
  278. }
  279. else if (typeof dayMaxEventRows === 'number') {
  280. hierarchy.maxStackCnt = dayMaxEventRows;
  281. hierarchy.hiddenConsumes = true;
  282. }
  283. // create segInputs only for segs with known heights
  284. let segInputs = [];
  285. let unknownHeightSegs = [];
  286. for (let i = 0; i < segs.length; i += 1) {
  287. let seg = segs[i];
  288. let segUid = generateSegUid(seg);
  289. let eventHeight = segHeights[segUid];
  290. if (eventHeight != null) {
  291. segInputs.push({
  292. index: i,
  293. span: {
  294. start: seg.firstCol,
  295. end: seg.lastCol + 1,
  296. },
  297. });
  298. }
  299. else {
  300. unknownHeightSegs.push(seg);
  301. }
  302. }
  303. let hiddenEntries = hierarchy.addSegs(segInputs);
  304. let segRects = hierarchy.toRects();
  305. let { singleColPlacements, multiColPlacements, leftoverMargins } = placeRects(segRects, segs, cells);
  306. let moreCnts = [];
  307. let moreMarginTops = [];
  308. // add segs with unknown heights
  309. for (let seg of unknownHeightSegs) {
  310. multiColPlacements[seg.firstCol].push({
  311. seg,
  312. isVisible: false,
  313. isAbsolute: true,
  314. absoluteTop: 0,
  315. marginTop: 0,
  316. });
  317. for (let col = seg.firstCol; col <= seg.lastCol; col += 1) {
  318. singleColPlacements[col].push({
  319. seg: resliceSeg(seg, col, col + 1, cells),
  320. isVisible: false,
  321. isAbsolute: false,
  322. absoluteTop: 0,
  323. marginTop: 0,
  324. });
  325. }
  326. }
  327. // add the hidden entries
  328. for (let col = 0; col < cells.length; col += 1) {
  329. moreCnts.push(0);
  330. }
  331. for (let hiddenEntry of hiddenEntries) {
  332. let seg = segs[hiddenEntry.index];
  333. let hiddenSpan = hiddenEntry.span;
  334. multiColPlacements[hiddenSpan.start].push({
  335. seg: resliceSeg(seg, hiddenSpan.start, hiddenSpan.end, cells),
  336. isVisible: false,
  337. isAbsolute: true,
  338. absoluteTop: 0,
  339. marginTop: 0,
  340. });
  341. for (let col = hiddenSpan.start; col < hiddenSpan.end; col += 1) {
  342. moreCnts[col] += 1;
  343. singleColPlacements[col].push({
  344. seg: resliceSeg(seg, col, col + 1, cells),
  345. isVisible: false,
  346. isAbsolute: false,
  347. absoluteTop: 0,
  348. marginTop: 0,
  349. });
  350. }
  351. }
  352. // deal with leftover margins
  353. for (let col = 0; col < cells.length; col += 1) {
  354. moreMarginTops.push(leftoverMargins[col]);
  355. }
  356. return { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops };
  357. }
  358. // rects ordered by top coord, then left
  359. function placeRects(allRects, segs, cells) {
  360. let rectsByEachCol = groupRectsByEachCol(allRects, cells.length);
  361. let singleColPlacements = [];
  362. let multiColPlacements = [];
  363. let leftoverMargins = [];
  364. for (let col = 0; col < cells.length; col += 1) {
  365. let rects = rectsByEachCol[col];
  366. // compute all static segs in singlePlacements
  367. let singlePlacements = [];
  368. let currentHeight = 0;
  369. let currentMarginTop = 0;
  370. for (let rect of rects) {
  371. let seg = segs[rect.index];
  372. singlePlacements.push({
  373. seg: resliceSeg(seg, col, col + 1, cells),
  374. isVisible: true,
  375. isAbsolute: false,
  376. absoluteTop: rect.levelCoord,
  377. marginTop: rect.levelCoord - currentHeight,
  378. });
  379. currentHeight = rect.levelCoord + rect.thickness;
  380. }
  381. // compute mixed static/absolute segs in multiPlacements
  382. let multiPlacements = [];
  383. currentHeight = 0;
  384. currentMarginTop = 0;
  385. for (let rect of rects) {
  386. let seg = segs[rect.index];
  387. let isAbsolute = rect.span.end - rect.span.start > 1; // multi-column?
  388. let isFirstCol = rect.span.start === col;
  389. currentMarginTop += rect.levelCoord - currentHeight; // amount of space since bottom of previous seg
  390. currentHeight = rect.levelCoord + rect.thickness; // height will now be bottom of current seg
  391. if (isAbsolute) {
  392. currentMarginTop += rect.thickness;
  393. if (isFirstCol) {
  394. multiPlacements.push({
  395. seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
  396. isVisible: true,
  397. isAbsolute: true,
  398. absoluteTop: rect.levelCoord,
  399. marginTop: 0,
  400. });
  401. }
  402. }
  403. else if (isFirstCol) {
  404. multiPlacements.push({
  405. seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
  406. isVisible: true,
  407. isAbsolute: false,
  408. absoluteTop: rect.levelCoord,
  409. marginTop: currentMarginTop, // claim the margin
  410. });
  411. currentMarginTop = 0;
  412. }
  413. }
  414. singleColPlacements.push(singlePlacements);
  415. multiColPlacements.push(multiPlacements);
  416. leftoverMargins.push(currentMarginTop);
  417. }
  418. return { singleColPlacements, multiColPlacements, leftoverMargins };
  419. }
  420. function groupRectsByEachCol(rects, colCnt) {
  421. let rectsByEachCol = [];
  422. for (let col = 0; col < colCnt; col += 1) {
  423. rectsByEachCol.push([]);
  424. }
  425. for (let rect of rects) {
  426. for (let col = rect.span.start; col < rect.span.end; col += 1) {
  427. rectsByEachCol[col].push(rect);
  428. }
  429. }
  430. return rectsByEachCol;
  431. }
  432. function resliceSeg(seg, spanStart, spanEnd, cells) {
  433. if (seg.firstCol === spanStart && seg.lastCol === spanEnd - 1) {
  434. return seg;
  435. }
  436. let eventRange = seg.eventRange;
  437. let origRange = eventRange.range;
  438. let slicedRange = internal_cjs.intersectRanges(origRange, {
  439. start: cells[spanStart].date,
  440. end: internal_cjs.addDays(cells[spanEnd - 1].date, 1),
  441. });
  442. return Object.assign(Object.assign({}, seg), { firstCol: spanStart, lastCol: spanEnd - 1, eventRange: {
  443. def: eventRange.def,
  444. ui: Object.assign(Object.assign({}, eventRange.ui), { durationEditable: false }),
  445. instance: eventRange.instance,
  446. range: slicedRange,
  447. }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() });
  448. }
  449. class DayGridSegHierarchy extends internal_cjs.SegHierarchy {
  450. constructor() {
  451. super(...arguments);
  452. // config
  453. this.hiddenConsumes = false;
  454. // allows us to keep hidden entries in the hierarchy so they take up space
  455. this.forceHidden = {};
  456. }
  457. addSegs(segInputs) {
  458. const hiddenSegs = super.addSegs(segInputs);
  459. const { entriesByLevel } = this;
  460. const excludeHidden = (entry) => !this.forceHidden[internal_cjs.buildEntryKey(entry)];
  461. // remove the forced-hidden segs
  462. for (let level = 0; level < entriesByLevel.length; level += 1) {
  463. entriesByLevel[level] = entriesByLevel[level].filter(excludeHidden);
  464. }
  465. return hiddenSegs;
  466. }
  467. handleInvalidInsertion(insertion, entry, hiddenEntries) {
  468. const { entriesByLevel, forceHidden } = this;
  469. const { touchingEntry, touchingLevel, touchingLateral } = insertion;
  470. // the entry that the new insertion is touching must be hidden
  471. if (this.hiddenConsumes && touchingEntry) {
  472. const touchingEntryId = internal_cjs.buildEntryKey(touchingEntry);
  473. if (!forceHidden[touchingEntryId]) {
  474. if (this.allowReslicing) {
  475. // split up the touchingEntry, reinsert it
  476. const hiddenEntry = Object.assign(Object.assign({}, touchingEntry), { span: internal_cjs.intersectSpans(touchingEntry.span, entry.span) });
  477. // reinsert the area that turned into a "more" link (so no other entries try to
  478. // occupy the space) but mark it forced-hidden
  479. const hiddenEntryId = internal_cjs.buildEntryKey(hiddenEntry);
  480. forceHidden[hiddenEntryId] = true;
  481. entriesByLevel[touchingLevel][touchingLateral] = hiddenEntry;
  482. hiddenEntries.push(hiddenEntry);
  483. this.splitEntry(touchingEntry, entry, hiddenEntries);
  484. }
  485. else {
  486. forceHidden[touchingEntryId] = true;
  487. hiddenEntries.push(touchingEntry);
  488. }
  489. }
  490. }
  491. // will try to reslice...
  492. super.handleInvalidInsertion(insertion, entry, hiddenEntries);
  493. }
  494. }
  495. class TableRow extends internal_cjs.DateComponent {
  496. constructor() {
  497. super(...arguments);
  498. this.cellElRefs = new internal_cjs.RefMap(); // the <td>
  499. this.frameElRefs = new internal_cjs.RefMap(); // the fc-daygrid-day-frame
  500. this.fgElRefs = new internal_cjs.RefMap(); // the fc-daygrid-day-events
  501. this.segHarnessRefs = new internal_cjs.RefMap(); // indexed by "instanceId:firstCol"
  502. this.rootElRef = preact_cjs.createRef();
  503. this.state = {
  504. framePositions: null,
  505. maxContentHeight: null,
  506. segHeights: {},
  507. };
  508. this.handleResize = (isForced) => {
  509. if (isForced) {
  510. this.updateSizing(true); // isExternal=true
  511. }
  512. };
  513. }
  514. render() {
  515. let { props, state, context } = this;
  516. let { options } = context;
  517. let colCnt = props.cells.length;
  518. let businessHoursByCol = splitSegsByFirstCol(props.businessHourSegs, colCnt);
  519. let bgEventSegsByCol = splitSegsByFirstCol(props.bgEventSegs, colCnt);
  520. let highlightSegsByCol = splitSegsByFirstCol(this.getHighlightSegs(), colCnt);
  521. let mirrorSegsByCol = splitSegsByFirstCol(this.getMirrorSegs(), colCnt);
  522. let { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops } = computeFgSegPlacement(internal_cjs.sortEventSegs(props.fgEventSegs, options.eventOrder), props.dayMaxEvents, props.dayMaxEventRows, options.eventOrderStrict, state.segHeights, state.maxContentHeight, props.cells);
  523. let isForcedInvisible = // TODO: messy way to compute this
  524. (props.eventDrag && props.eventDrag.affectedInstances) ||
  525. (props.eventResize && props.eventResize.affectedInstances) ||
  526. {};
  527. return (preact_cjs.createElement("tr", { ref: this.rootElRef, role: "row" },
  528. props.renderIntro && props.renderIntro(),
  529. props.cells.map((cell, col) => {
  530. let normalFgNodes = this.renderFgSegs(col, props.forPrint ? singleColPlacements[col] : multiColPlacements[col], props.todayRange, isForcedInvisible);
  531. let mirrorFgNodes = this.renderFgSegs(col, buildMirrorPlacements(mirrorSegsByCol[col], multiColPlacements), props.todayRange, {}, Boolean(props.eventDrag), Boolean(props.eventResize), false);
  532. return (preact_cjs.createElement(TableCell, { key: cell.key, elRef: this.cellElRefs.createRef(cell.key), innerElRef: this.frameElRefs.createRef(cell.key) /* FF <td> problem, but okay to use for left/right. TODO: rename prop */, dateProfile: props.dateProfile, date: cell.date, showDayNumber: props.showDayNumbers, showWeekNumber: props.showWeekNumbers && col === 0, forceDayTop: props.showWeekNumbers /* even displaying weeknum for row, not necessarily day */, todayRange: props.todayRange, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, extraRenderProps: cell.extraRenderProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, moreCnt: moreCnts[col], moreMarginTop: moreMarginTops[col], singlePlacements: singleColPlacements[col], fgContentElRef: this.fgElRefs.createRef(cell.key), fgContent: ( // Fragment scopes the keys
  533. preact_cjs.createElement(preact_cjs.Fragment, null,
  534. preact_cjs.createElement(preact_cjs.Fragment, null, normalFgNodes),
  535. preact_cjs.createElement(preact_cjs.Fragment, null, mirrorFgNodes))), bgContent: ( // Fragment scopes the keys
  536. preact_cjs.createElement(preact_cjs.Fragment, null,
  537. this.renderFillSegs(highlightSegsByCol[col], 'highlight'),
  538. this.renderFillSegs(businessHoursByCol[col], 'non-business'),
  539. this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), minHeight: props.cellMinHeight }));
  540. })));
  541. }
  542. componentDidMount() {
  543. this.updateSizing(true);
  544. this.context.addResizeHandler(this.handleResize);
  545. }
  546. componentDidUpdate(prevProps, prevState) {
  547. let currentProps = this.props;
  548. this.updateSizing(!internal_cjs.isPropsEqual(prevProps, currentProps));
  549. }
  550. componentWillUnmount() {
  551. this.context.removeResizeHandler(this.handleResize);
  552. }
  553. getHighlightSegs() {
  554. let { props } = this;
  555. if (props.eventDrag && props.eventDrag.segs.length) { // messy check
  556. return props.eventDrag.segs;
  557. }
  558. if (props.eventResize && props.eventResize.segs.length) { // messy check
  559. return props.eventResize.segs;
  560. }
  561. return props.dateSelectionSegs;
  562. }
  563. getMirrorSegs() {
  564. let { props } = this;
  565. if (props.eventResize && props.eventResize.segs.length) { // messy check
  566. return props.eventResize.segs;
  567. }
  568. return [];
  569. }
  570. renderFgSegs(col, segPlacements, todayRange, isForcedInvisible, isDragging, isResizing, isDateSelecting) {
  571. let { context } = this;
  572. let { eventSelection } = this.props;
  573. let { framePositions } = this.state;
  574. let defaultDisplayEventEnd = this.props.cells.length === 1; // colCnt === 1
  575. let isMirror = isDragging || isResizing || isDateSelecting;
  576. let nodes = [];
  577. if (framePositions) {
  578. for (let placement of segPlacements) {
  579. let { seg } = placement;
  580. let { instanceId } = seg.eventRange.instance;
  581. let isVisible = placement.isVisible && !isForcedInvisible[instanceId];
  582. let isAbsolute = placement.isAbsolute;
  583. let left = '';
  584. let right = '';
  585. if (isAbsolute) {
  586. if (context.isRtl) {
  587. right = 0;
  588. left = framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol];
  589. }
  590. else {
  591. left = 0;
  592. right = framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol];
  593. }
  594. }
  595. /*
  596. known bug: events that are force to be list-item but span multiple days still take up space in later columns
  597. todo: in print view, for multi-day events, don't display title within non-start/end segs
  598. */
  599. nodes.push(preact_cjs.createElement("div", { className: 'fc-daygrid-event-harness' + (isAbsolute ? ' fc-daygrid-event-harness-abs' : ''), key: generateSegKey(seg), ref: isMirror ? null : this.segHarnessRefs.createRef(generateSegUid(seg)), style: {
  600. visibility: isVisible ? '' : 'hidden',
  601. marginTop: isAbsolute ? '' : placement.marginTop,
  602. top: isAbsolute ? placement.absoluteTop : '',
  603. left,
  604. right,
  605. } }, hasListItemDisplay(seg) ? (preact_cjs.createElement(TableListItemEvent, Object.assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getSegMeta(seg, todayRange)))) : (preact_cjs.createElement(TableBlockEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getSegMeta(seg, todayRange))))));
  606. }
  607. }
  608. return nodes;
  609. }
  610. renderFillSegs(segs, fillType) {
  611. let { isRtl } = this.context;
  612. let { todayRange } = this.props;
  613. let { framePositions } = this.state;
  614. let nodes = [];
  615. if (framePositions) {
  616. for (let seg of segs) {
  617. let leftRightCss = isRtl ? {
  618. right: 0,
  619. left: framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol],
  620. } : {
  621. left: 0,
  622. right: framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol],
  623. };
  624. nodes.push(preact_cjs.createElement("div", { key: internal_cjs.buildEventRangeKey(seg.eventRange), className: "fc-daygrid-bg-harness", style: leftRightCss }, fillType === 'bg-event' ?
  625. preact_cjs.createElement(internal_cjs.BgEvent, Object.assign({ seg: seg }, internal_cjs.getSegMeta(seg, todayRange))) :
  626. internal_cjs.renderFill(fillType)));
  627. }
  628. }
  629. return preact_cjs.createElement(preact_cjs.Fragment, {}, ...nodes);
  630. }
  631. updateSizing(isExternalSizingChange) {
  632. let { props, state, frameElRefs } = this;
  633. if (!props.forPrint &&
  634. props.clientWidth !== null // positioning ready?
  635. ) {
  636. if (isExternalSizingChange) {
  637. let frameEls = props.cells.map((cell) => frameElRefs.currentMap[cell.key]);
  638. if (frameEls.length) {
  639. let originEl = this.rootElRef.current;
  640. let newPositionCache = new internal_cjs.PositionCache(originEl, frameEls, true, // isHorizontal
  641. false);
  642. if (!state.framePositions || !state.framePositions.similarTo(newPositionCache)) {
  643. this.setState({
  644. framePositions: new internal_cjs.PositionCache(originEl, frameEls, true, // isHorizontal
  645. false),
  646. });
  647. }
  648. }
  649. }
  650. const oldSegHeights = this.state.segHeights;
  651. const newSegHeights = this.querySegHeights();
  652. const limitByContentHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
  653. this.safeSetState({
  654. // HACK to prevent oscillations of events being shown/hidden from max-event-rows
  655. // Essentially, once you compute an element's height, never null-out.
  656. // TODO: always display all events, as visibility:hidden?
  657. segHeights: Object.assign(Object.assign({}, oldSegHeights), newSegHeights),
  658. maxContentHeight: limitByContentHeight ? this.computeMaxContentHeight() : null,
  659. });
  660. }
  661. }
  662. querySegHeights() {
  663. let segElMap = this.segHarnessRefs.currentMap;
  664. let segHeights = {};
  665. // get the max height amongst instance segs
  666. for (let segUid in segElMap) {
  667. let height = Math.round(segElMap[segUid].getBoundingClientRect().height);
  668. segHeights[segUid] = Math.max(segHeights[segUid] || 0, height);
  669. }
  670. return segHeights;
  671. }
  672. computeMaxContentHeight() {
  673. let firstKey = this.props.cells[0].key;
  674. let cellEl = this.cellElRefs.currentMap[firstKey];
  675. let fcContainerEl = this.fgElRefs.currentMap[firstKey];
  676. return cellEl.getBoundingClientRect().bottom - fcContainerEl.getBoundingClientRect().top;
  677. }
  678. getCellEls() {
  679. let elMap = this.cellElRefs.currentMap;
  680. return this.props.cells.map((cell) => elMap[cell.key]);
  681. }
  682. }
  683. TableRow.addStateEquality({
  684. segHeights: internal_cjs.isPropsEqual,
  685. });
  686. function buildMirrorPlacements(mirrorSegs, colPlacements) {
  687. if (!mirrorSegs.length) {
  688. return [];
  689. }
  690. let topsByInstanceId = buildAbsoluteTopHash(colPlacements); // TODO: cache this at first render?
  691. return mirrorSegs.map((seg) => ({
  692. seg,
  693. isVisible: true,
  694. isAbsolute: true,
  695. absoluteTop: topsByInstanceId[seg.eventRange.instance.instanceId],
  696. marginTop: 0,
  697. }));
  698. }
  699. function buildAbsoluteTopHash(colPlacements) {
  700. let topsByInstanceId = {};
  701. for (let placements of colPlacements) {
  702. for (let placement of placements) {
  703. topsByInstanceId[placement.seg.eventRange.instance.instanceId] = placement.absoluteTop;
  704. }
  705. }
  706. return topsByInstanceId;
  707. }
  708. class TableRows extends internal_cjs.DateComponent {
  709. constructor() {
  710. super(...arguments);
  711. this.splitBusinessHourSegs = internal_cjs.memoize(splitSegsByRow);
  712. this.splitBgEventSegs = internal_cjs.memoize(splitSegsByRow);
  713. this.splitFgEventSegs = internal_cjs.memoize(splitSegsByRow);
  714. this.splitDateSelectionSegs = internal_cjs.memoize(splitSegsByRow);
  715. this.splitEventDrag = internal_cjs.memoize(splitInteractionByRow);
  716. this.splitEventResize = internal_cjs.memoize(splitInteractionByRow);
  717. this.rowRefs = new internal_cjs.RefMap();
  718. }
  719. render() {
  720. let { props, context } = this;
  721. let rowCnt = props.cells.length;
  722. let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
  723. let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
  724. let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
  725. let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
  726. let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
  727. let eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt);
  728. // for DayGrid view with many rows, force a min-height on cells so doesn't appear squished
  729. // choose 7 because a month view will have max 6 rows
  730. let cellMinHeight = (rowCnt >= 7 && props.clientWidth) ?
  731. props.clientWidth / context.options.aspectRatio / 6 :
  732. null;
  733. return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(preact_cjs.Fragment, null, props.cells.map((cells, row) => (preact_cjs.createElement(TableRow, { ref: this.rowRefs.createRef(row), key: cells.length
  734. ? cells[0].date.toISOString() /* best? or put key on cell? or use diff formatter? */
  735. : row // in case there are no cells (like when resource view is loading)
  736. , showDayNumbers: rowCnt > 1, showWeekNumbers: props.showWeekNumbers, todayRange: todayRange, dateProfile: props.dateProfile, cells: cells, renderIntro: props.renderRowIntro, businessHourSegs: businessHourSegsByRow[row], eventSelection: props.eventSelection, bgEventSegs: bgEventSegsByRow[row].filter(isSegAllDay) /* hack */, fgEventSegs: fgEventSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, clientWidth: props.clientWidth, clientHeight: props.clientHeight, cellMinHeight: cellMinHeight, forPrint: props.forPrint })))))));
  737. }
  738. componentDidMount() {
  739. this.registerInteractiveComponent();
  740. }
  741. componentDidUpdate() {
  742. // for if started with zero cells
  743. this.registerInteractiveComponent();
  744. }
  745. registerInteractiveComponent() {
  746. if (!this.rootEl) {
  747. // HACK: need a daygrid wrapper parent to do positioning
  748. // NOTE: a daygrid resource view w/o resources can have zero cells
  749. const firstCellEl = this.rowRefs.currentMap[0].getCellEls()[0];
  750. const rootEl = firstCellEl ? firstCellEl.closest('.fc-daygrid-body') : null;
  751. if (rootEl) {
  752. this.rootEl = rootEl;
  753. this.context.registerInteractiveComponent(this, {
  754. el: rootEl,
  755. isHitComboAllowed: this.props.isHitComboAllowed,
  756. });
  757. }
  758. }
  759. }
  760. componentWillUnmount() {
  761. if (this.rootEl) {
  762. this.context.unregisterInteractiveComponent(this);
  763. this.rootEl = null;
  764. }
  765. }
  766. // Hit System
  767. // ----------------------------------------------------------------------------------------------------
  768. prepareHits() {
  769. this.rowPositions = new internal_cjs.PositionCache(this.rootEl, this.rowRefs.collect().map((rowObj) => rowObj.getCellEls()[0]), // first cell el in each row. TODO: not optimal
  770. false, true);
  771. this.colPositions = new internal_cjs.PositionCache(this.rootEl, this.rowRefs.currentMap[0].getCellEls(), // cell els in first row
  772. true, // horizontal
  773. false);
  774. }
  775. queryHit(positionLeft, positionTop) {
  776. let { colPositions, rowPositions } = this;
  777. let col = colPositions.leftToIndex(positionLeft);
  778. let row = rowPositions.topToIndex(positionTop);
  779. if (row != null && col != null) {
  780. let cell = this.props.cells[row][col];
  781. return {
  782. dateProfile: this.props.dateProfile,
  783. dateSpan: Object.assign({ range: this.getCellRange(row, col), allDay: true }, cell.extraDateSpan),
  784. dayEl: this.getCellEl(row, col),
  785. rect: {
  786. left: colPositions.lefts[col],
  787. right: colPositions.rights[col],
  788. top: rowPositions.tops[row],
  789. bottom: rowPositions.bottoms[row],
  790. },
  791. layer: 0,
  792. };
  793. }
  794. return null;
  795. }
  796. getCellEl(row, col) {
  797. return this.rowRefs.currentMap[row].getCellEls()[col]; // TODO: not optimal
  798. }
  799. getCellRange(row, col) {
  800. let start = this.props.cells[row][col].date;
  801. let end = internal_cjs.addDays(start, 1);
  802. return { start, end };
  803. }
  804. }
  805. function isSegAllDay(seg) {
  806. return seg.eventRange.def.allDay;
  807. }
  808. class Table extends internal_cjs.DateComponent {
  809. constructor() {
  810. super(...arguments);
  811. this.elRef = preact_cjs.createRef();
  812. this.needsScrollReset = false;
  813. }
  814. render() {
  815. let { props } = this;
  816. let { dayMaxEventRows, dayMaxEvents, expandRows } = props;
  817. let limitViaBalanced = dayMaxEvents === true || dayMaxEventRows === true;
  818. // if rows can't expand to fill fixed height, can't do balanced-height event limit
  819. // TODO: best place to normalize these options?
  820. if (limitViaBalanced && !expandRows) {
  821. limitViaBalanced = false;
  822. dayMaxEventRows = null;
  823. dayMaxEvents = null;
  824. }
  825. let classNames = [
  826. 'fc-daygrid-body',
  827. limitViaBalanced ? 'fc-daygrid-body-balanced' : 'fc-daygrid-body-unbalanced',
  828. expandRows ? '' : 'fc-daygrid-body-natural', // will height of one row depend on the others?
  829. ];
  830. return (preact_cjs.createElement("div", { ref: this.elRef, className: classNames.join(' '), style: {
  831. // these props are important to give this wrapper correct dimensions for interactions
  832. // TODO: if we set it here, can we avoid giving to inner tables?
  833. width: props.clientWidth,
  834. minWidth: props.tableMinWidth,
  835. } },
  836. preact_cjs.createElement("table", { role: "presentation", className: "fc-scrollgrid-sync-table", style: {
  837. width: props.clientWidth,
  838. minWidth: props.tableMinWidth,
  839. height: expandRows ? props.clientHeight : '',
  840. } },
  841. props.colGroupNode,
  842. preact_cjs.createElement("tbody", { role: "presentation" },
  843. preact_cjs.createElement(TableRows, { dateProfile: props.dateProfile, cells: props.cells, renderRowIntro: props.renderRowIntro, showWeekNumbers: props.showWeekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed })))));
  844. }
  845. componentDidMount() {
  846. this.requestScrollReset();
  847. }
  848. componentDidUpdate(prevProps) {
  849. if (prevProps.dateProfile !== this.props.dateProfile) {
  850. this.requestScrollReset();
  851. }
  852. else {
  853. this.flushScrollReset();
  854. }
  855. }
  856. requestScrollReset() {
  857. this.needsScrollReset = true;
  858. this.flushScrollReset();
  859. }
  860. flushScrollReset() {
  861. if (this.needsScrollReset &&
  862. this.props.clientWidth // sizes computed?
  863. ) {
  864. const subjectEl = getScrollSubjectEl(this.elRef.current, this.props.dateProfile);
  865. if (subjectEl) {
  866. const originEl = subjectEl.closest('.fc-daygrid-body');
  867. const scrollEl = originEl.closest('.fc-scroller');
  868. const scrollTop = subjectEl.getBoundingClientRect().top -
  869. originEl.getBoundingClientRect().top;
  870. scrollEl.scrollTop = scrollTop ? (scrollTop + 1) : 0; // overcome border
  871. }
  872. this.needsScrollReset = false;
  873. }
  874. }
  875. }
  876. function getScrollSubjectEl(containerEl, dateProfile) {
  877. let el;
  878. if (dateProfile.currentRangeUnit.match(/year|month/)) {
  879. el = containerEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(dateProfile.currentDate)}-01"]`);
  880. // even if view is month-based, first-of-month might be hidden...
  881. }
  882. if (!el) {
  883. el = containerEl.querySelector(`[data-date="${internal_cjs.formatDayString(dateProfile.currentDate)}"]`);
  884. // could still be hidden if an interior-view hidden day
  885. }
  886. return el;
  887. }
  888. class DayTableSlicer extends internal_cjs.Slicer {
  889. constructor() {
  890. super(...arguments);
  891. this.forceDayIfListItem = true;
  892. }
  893. sliceRange(dateRange, dayTableModel) {
  894. return dayTableModel.sliceRange(dateRange);
  895. }
  896. }
  897. class DayTable extends internal_cjs.DateComponent {
  898. constructor() {
  899. super(...arguments);
  900. this.slicer = new DayTableSlicer();
  901. this.tableRef = preact_cjs.createRef();
  902. }
  903. render() {
  904. let { props, context } = this;
  905. return (preact_cjs.createElement(Table, Object.assign({ ref: this.tableRef }, this.slicer.sliceProps(props, props.dateProfile, props.nextDayThreshold, context, props.dayTableModel), { dateProfile: props.dateProfile, cells: props.dayTableModel.cells, colGroupNode: props.colGroupNode, tableMinWidth: props.tableMinWidth, renderRowIntro: props.renderRowIntro, dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, showWeekNumbers: props.showWeekNumbers, expandRows: props.expandRows, headerAlignElRef: props.headerAlignElRef, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: props.forPrint })));
  906. }
  907. }
  908. class DayTableView extends TableView {
  909. constructor() {
  910. super(...arguments);
  911. this.buildDayTableModel = internal_cjs.memoize(buildDayTableModel);
  912. this.headerRef = preact_cjs.createRef();
  913. this.tableRef = preact_cjs.createRef();
  914. // can't override any lifecycle methods from parent
  915. }
  916. render() {
  917. let { options, dateProfileGenerator } = this.context;
  918. let { props } = this;
  919. let dayTableModel = this.buildDayTableModel(props.dateProfile, dateProfileGenerator);
  920. let headerContent = options.dayHeaders && (preact_cjs.createElement(internal_cjs.DayHeader, { ref: this.headerRef, dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: dayTableModel.rowCnt === 1 }));
  921. let bodyContent = (contentArg) => (preact_cjs.createElement(DayTable, { ref: this.tableRef, dateProfile: props.dateProfile, dayTableModel: dayTableModel, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, nextDayThreshold: options.nextDayThreshold, colGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows, showWeekNumbers: options.weekNumbers, expandRows: !props.isHeightAuto, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }));
  922. return options.dayMinWidth
  923. ? this.renderHScrollLayout(headerContent, bodyContent, dayTableModel.colCnt, options.dayMinWidth)
  924. : this.renderSimpleLayout(headerContent, bodyContent);
  925. }
  926. }
  927. function buildDayTableModel(dateProfile, dateProfileGenerator) {
  928. let daySeries = new internal_cjs.DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
  929. return new internal_cjs.DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
  930. }
  931. class TableDateProfileGenerator extends internal_cjs.DateProfileGenerator {
  932. // Computes the date range that will be rendered
  933. buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
  934. let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);
  935. let { props } = this;
  936. return buildDayTableRenderRange({
  937. currentRange: renderRange,
  938. snapToWeek: /^(year|month)$/.test(currentRangeUnit),
  939. fixedWeekCount: props.fixedWeekCount,
  940. dateEnv: props.dateEnv,
  941. });
  942. }
  943. }
  944. function buildDayTableRenderRange(props) {
  945. let { dateEnv, currentRange } = props;
  946. let { start, end } = currentRange;
  947. let endOfWeek;
  948. // year and month views should be aligned with weeks. this is already done for week
  949. if (props.snapToWeek) {
  950. start = dateEnv.startOfWeek(start);
  951. // make end-of-week if not already
  952. endOfWeek = dateEnv.startOfWeek(end);
  953. if (endOfWeek.valueOf() !== end.valueOf()) {
  954. end = internal_cjs.addWeeks(endOfWeek, 1);
  955. }
  956. }
  957. // ensure 6 weeks
  958. if (props.fixedWeekCount) {
  959. // TODO: instead of these date-math gymnastics (for multimonth view),
  960. // compute dateprofiles of all months, then use start of first and end of last.
  961. let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(internal_cjs.addDays(currentRange.end, -1)));
  962. let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
  963. internal_cjs.diffWeeks(lastMonthRenderStart, end));
  964. end = internal_cjs.addWeeks(end, 6 - rowCnt);
  965. }
  966. return { start, end };
  967. }
  968. var css_248z = ":root{--fc-daygrid-event-dot-width:8px}.fc-daygrid-day-events:after,.fc-daygrid-day-events:before,.fc-daygrid-day-frame:after,.fc-daygrid-day-frame:before,.fc-daygrid-event-harness:after,.fc-daygrid-event-harness:before{clear:both;content:\"\";display:table}.fc .fc-daygrid-body{position:relative;z-index:1}.fc .fc-daygrid-day.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-daygrid-day-frame{min-height:100%;position:relative}.fc .fc-daygrid-day-top{display:flex;flex-direction:row-reverse}.fc .fc-day-other .fc-daygrid-day-top{opacity:.3}.fc .fc-daygrid-day-number{padding:4px;position:relative;z-index:4}.fc .fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc .fc-daygrid-day-events{margin-top:1px}.fc .fc-daygrid-body-balanced .fc-daygrid-day-events{left:0;position:absolute;right:0}.fc .fc-daygrid-body-unbalanced .fc-daygrid-day-events{min-height:2em;position:relative}.fc .fc-daygrid-body-natural .fc-daygrid-day-events{margin-bottom:1em}.fc .fc-daygrid-event-harness{position:relative}.fc .fc-daygrid-event-harness-abs{left:0;position:absolute;right:0;top:0}.fc .fc-daygrid-bg-harness{bottom:0;position:absolute;top:0}.fc .fc-daygrid-day-bg .fc-non-business{z-index:1}.fc .fc-daygrid-day-bg .fc-bg-event{z-index:2}.fc .fc-daygrid-day-bg .fc-highlight{z-index:3}.fc .fc-daygrid-event{margin-top:1px;z-index:6}.fc .fc-daygrid-event.fc-event-mirror{z-index:7}.fc .fc-daygrid-day-bottom{font-size:.85em;margin:0 2px}.fc .fc-daygrid-day-bottom:after,.fc .fc-daygrid-day-bottom:before{clear:both;content:\"\";display:table}.fc .fc-daygrid-more-link{border-radius:3px;cursor:pointer;line-height:1;margin-top:1px;max-width:100%;overflow:hidden;padding:2px;position:relative;white-space:nowrap;z-index:4}.fc .fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc .fc-daygrid-week-number{background-color:var(--fc-neutral-bg-color);color:var(--fc-neutral-text-color);min-width:1.5em;padding:2px;position:absolute;text-align:center;top:0;z-index:5}.fc .fc-more-popover .fc-popover-body{min-width:220px;padding:10px}.fc-direction-ltr .fc-daygrid-event.fc-event-start,.fc-direction-rtl .fc-daygrid-event.fc-event-end{margin-left:2px}.fc-direction-ltr .fc-daygrid-event.fc-event-end,.fc-direction-rtl .fc-daygrid-event.fc-event-start{margin-right:2px}.fc-direction-ltr .fc-daygrid-more-link{float:left}.fc-direction-ltr .fc-daygrid-week-number{border-radius:0 0 3px 0;left:0}.fc-direction-rtl .fc-daygrid-more-link{float:right}.fc-direction-rtl .fc-daygrid-week-number{border-radius:0 0 0 3px;right:0}.fc-liquid-hack .fc-daygrid-day-frame{position:static}.fc-daygrid-event{border-radius:3px;font-size:var(--fc-small-font-size);position:relative;white-space:nowrap}.fc-daygrid-block-event .fc-event-time{font-weight:700}.fc-daygrid-block-event .fc-event-time,.fc-daygrid-block-event .fc-event-title{padding:1px}.fc-daygrid-dot-event{align-items:center;display:flex;padding:2px 0}.fc-daygrid-dot-event .fc-event-title{flex-grow:1;flex-shrink:1;font-weight:700;min-width:0;overflow:hidden}.fc-daygrid-dot-event.fc-event-mirror,.fc-daygrid-dot-event:hover{background:rgba(0,0,0,.1)}.fc-daygrid-dot-event.fc-event-selected:before{bottom:-10px;top:-10px}.fc-daygrid-event-dot{border:calc(var(--fc-daygrid-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-daygrid-event-dot-width)/2);box-sizing:content-box;height:0;margin:0 4px;width:0}.fc-direction-ltr .fc-daygrid-event .fc-event-time{margin-right:3px}.fc-direction-rtl .fc-daygrid-event .fc-event-time{margin-left:3px}";
  969. internal_cjs.injectStyles(css_248z);
  970. exports.DayGridView = DayTableView;
  971. exports.DayTable = DayTable;
  972. exports.DayTableSlicer = DayTableSlicer;
  973. exports.Table = Table;
  974. exports.TableDateProfileGenerator = TableDateProfileGenerator;
  975. exports.TableRows = TableRows;
  976. exports.TableView = TableView;
  977. exports.buildDayTableModel = buildDayTableModel;
  978. exports.buildDayTableRenderRange = buildDayTableRenderRange;