1/*! 2FullCalendar Time Grid Plugin v4.4.0 3Docs & License: https://fullcalendar.io/ 4(c) 2019 Adam Shaw 5*/ 6 7(function (global, factory) { 8 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core'), require('@fullcalendar/daygrid')) : 9 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core', '@fullcalendar/daygrid'], factory) : 10 (global = global || self, factory(global.FullCalendarTimeGrid = {}, global.FullCalendar, global.FullCalendarDayGrid)); 11}(this, function (exports, core, daygrid) { 'use strict'; 12 13 /*! ***************************************************************************** 14 Copyright (c) Microsoft Corporation. All rights reserved. 15 Licensed under the Apache License, Version 2.0 (the "License"); you may not use 16 this file except in compliance with the License. You may obtain a copy of the 17 License at http://www.apache.org/licenses/LICENSE-2.0 18 19 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 21 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 22 MERCHANTABLITY OR NON-INFRINGEMENT. 23 24 See the Apache Version 2.0 License for specific language governing permissions 25 and limitations under the License. 26 ***************************************************************************** */ 27 /* global Reflect, Promise */ 28 29 var extendStatics = function(d, b) { 30 extendStatics = Object.setPrototypeOf || 31 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 32 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 33 return extendStatics(d, b); 34 }; 35 36 function __extends(d, b) { 37 extendStatics(d, b); 38 function __() { this.constructor = d; } 39 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 40 } 41 42 var __assign = function() { 43 __assign = Object.assign || function __assign(t) { 44 for (var s, i = 1, n = arguments.length; i < n; i++) { 45 s = arguments[i]; 46 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 47 } 48 return t; 49 }; 50 return __assign.apply(this, arguments); 51 }; 52 53 /* 54 Only handles foreground segs. 55 Does not own rendering. Use for low-level util methods by TimeGrid. 56 */ 57 var TimeGridEventRenderer = /** @class */ (function (_super) { 58 __extends(TimeGridEventRenderer, _super); 59 function TimeGridEventRenderer(timeGrid) { 60 var _this = _super.call(this) || this; 61 _this.timeGrid = timeGrid; 62 return _this; 63 } 64 TimeGridEventRenderer.prototype.renderSegs = function (context, segs, mirrorInfo) { 65 _super.prototype.renderSegs.call(this, context, segs, mirrorInfo); 66 // TODO: dont do every time. memoize 67 this.fullTimeFormat = core.createFormatter({ 68 hour: 'numeric', 69 minute: '2-digit', 70 separator: this.context.options.defaultRangeSeparator 71 }); 72 }; 73 // Given an array of foreground segments, render a DOM element for each, computes position, 74 // and attaches to the column inner-container elements. 75 TimeGridEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 76 var segsByCol = this.timeGrid.groupSegsByCol(segs); 77 // order the segs within each column 78 // TODO: have groupSegsByCol do this? 79 for (var col = 0; col < segsByCol.length; col++) { 80 segsByCol[col] = this.sortEventSegs(segsByCol[col]); 81 } 82 this.segsByCol = segsByCol; 83 this.timeGrid.attachSegsByCol(segsByCol, this.timeGrid.fgContainerEls); 84 }; 85 TimeGridEventRenderer.prototype.detachSegs = function (segs) { 86 segs.forEach(function (seg) { 87 core.removeElement(seg.el); 88 }); 89 this.segsByCol = null; 90 }; 91 TimeGridEventRenderer.prototype.computeSegSizes = function (allSegs) { 92 var _a = this, timeGrid = _a.timeGrid, segsByCol = _a.segsByCol; 93 var colCnt = timeGrid.colCnt; 94 timeGrid.computeSegVerticals(allSegs); // horizontals relies on this 95 if (segsByCol) { 96 for (var col = 0; col < colCnt; col++) { 97 this.computeSegHorizontals(segsByCol[col]); // compute horizontal coordinates, z-index's, and reorder the array 98 } 99 } 100 }; 101 TimeGridEventRenderer.prototype.assignSegSizes = function (allSegs) { 102 var _a = this, timeGrid = _a.timeGrid, segsByCol = _a.segsByCol; 103 var colCnt = timeGrid.colCnt; 104 timeGrid.assignSegVerticals(allSegs); // horizontals relies on this 105 if (segsByCol) { 106 for (var col = 0; col < colCnt; col++) { 107 this.assignSegCss(segsByCol[col]); 108 } 109 } 110 }; 111 // Computes a default event time formatting string if `eventTimeFormat` is not explicitly defined 112 TimeGridEventRenderer.prototype.computeEventTimeFormat = function () { 113 return { 114 hour: 'numeric', 115 minute: '2-digit', 116 meridiem: false 117 }; 118 }; 119 // Computes a default `displayEventEnd` value if one is not expliclty defined 120 TimeGridEventRenderer.prototype.computeDisplayEventEnd = function () { 121 return true; 122 }; 123 // Renders the HTML for a single event segment's default rendering 124 TimeGridEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) { 125 var eventRange = seg.eventRange; 126 var eventDef = eventRange.def; 127 var eventUi = eventRange.ui; 128 var allDay = eventDef.allDay; 129 var isDraggable = core.computeEventDraggable(this.context, eventDef, eventUi); 130 var isResizableFromStart = seg.isStart && core.computeEventStartResizable(this.context, eventDef, eventUi); 131 var isResizableFromEnd = seg.isEnd && core.computeEventEndResizable(this.context, eventDef, eventUi);
132 var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo); 133 var skinCss = core.cssToStr(this.getSkinCss(eventUi)); 134 var timeText; 135 var fullTimeText; // more verbose time text. for the print stylesheet 136 var startTimeText; // just the start time text 137 classes.unshift('fc-time-grid-event'); 138 // if the event appears to span more than one day... 139 if (core.isMultiDayRange(eventRange.range)) { 140 // Don't display time text on segments that run entirely through a day. 141 // That would appear as midnight-midnight and would look dumb. 142 // Otherwise, display the time text for the *segment's* times (like 6pm-midnight or midnight-10am) 143 if (seg.isStart || seg.isEnd) { 144 var unzonedStart = seg.start; 145 var unzonedEnd = seg.end; 146 timeText = this._getTimeText(unzonedStart, unzonedEnd, allDay); // TODO: give the timezones 147 fullTimeText = this._getTimeText(unzonedStart, unzonedEnd, allDay, this.fullTimeFormat); 148 startTimeText = this._getTimeText(unzonedStart, unzonedEnd, allDay, null, false); // displayEnd=false 149 } 150 } 151 else { 152 // Display the normal time text for the *event's* times 153 timeText = this.getTimeText(eventRange); 154 fullTimeText = this.getTimeText(eventRange, this.fullTimeFormat); 155 startTimeText = this.getTimeText(eventRange, null, false); // displayEnd=false 156 } 157 return '<a class="' + classes.join(' ') + '"' + 158 (eventDef.url ? 159 ' href="' + core.htmlEscape(eventDef.url) + '"' : 160 '') + 161 (skinCss ? 162 ' style="' + skinCss + '"' : 163 '') + 164 '>' + 165 '<div class="fc-content">' + 166 (timeText ? 167 '<div class="fc-time"' + 168 ' data-start="' + core.htmlEscape(startTimeText) + '"' + 169 ' data-full="' + core.htmlEscape(fullTimeText) + '"' + 170 '>' + 171 '<span>' + core.htmlEscape(timeText) + '</span>' + 172 '</div>' : 173 '') + 174 (eventDef.title ? 175 '<div class="fc-title">' + 176 core.htmlEscape(eventDef.title) + 177 '</div>' : 178 '') + 179 '</div>' + 180 /* TODO: write CSS for this 181 (isResizableFromStart ? 182 '<div class="fc-resizer fc-start-resizer"></div>' : 183 '' 184 ) + 185 */ 186 (isResizableFromEnd ? 187 '<div class="fc-resizer fc-end-resizer"></div>' : 188 '') + 189 '</a>'; 190 }; 191 // Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each. 192 // Assumed the segs are already ordered. 193 // NOTE: Also reorders the given array by date! 194 TimeGridEventRenderer.prototype.computeSegHorizontals = function (segs) { 195 var levels; 196 var level0; 197 var i; 198 levels = buildSlotSegLevels(segs); 199 computeForwardSlotSegs(levels); 200 if ((level0 = levels[0])) { 201 for (i = 0; i < level0.length; i++) { 202 computeSlotSegPressures(level0[i]); 203 } 204 for (i = 0; i < level0.length; i++) { 205 this.computeSegForwardBack(level0[i], 0, 0); 206 } 207 } 208 }; 209 // Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range 210 // from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and 211 // seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left. 212 // 213 // The segment might be part of a "series", which means consecutive segments with the same pressure 214 // who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of 215 // segments behind this one in the current series, and `seriesBackwardCoord` is the starting 216 // coordinate of the first segment in the series. 217 TimeGridEventRenderer.prototype.computeSegForwardBack = function (seg, seriesBackwardPressure, seriesBackwardCoord) { 218 var forwardSegs = seg.forwardSegs; 219 var i; 220 if (seg.forwardCoord === undefined) { // not already computed 221 if (!forwardSegs.length) { 222 // if there are no forward segments, this segment should butt up against the edge 223 seg.forwardCoord = 1; 224 } 225 else { 226 // sort highest pressure first 227 this.sortForwardSegs(forwardSegs); 228 // this segment's forwardCoord will be calculated from the backwardCoord of the 229 // highest-pressure forward segment. 230 this.computeSegForwardBack(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord); 231 seg.forwardCoord = forwardSegs[0].backwardCoord; 232 } 233 // calculate the backwardCoord from the forwardCoord. consider the series 234 seg.backwardCoord = seg.forwardCoord - 235 (seg.forwardCoord - seriesBackwardCoord) / // available width for series 236 (seriesBackwardPressure + 1); // # of segments in the series
237 // use this segment's coordinates to computed the coordinates of the less-pressurized 238 // forward segments 239 for (i = 0; i < forwardSegs.length; i++) { 240 this.computeSegForwardBack(forwardSegs[i], 0, seg.forwardCoord); 241 } 242 } 243 }; 244 TimeGridEventRenderer.prototype.sortForwardSegs = function (forwardSegs) { 245 var objs = forwardSegs.map(buildTimeGridSegCompareObj); 246 var specs = [ 247 // put higher-pressure first 248 { field: 'forwardPressure', order: -1 }, 249 // put segments that are closer to initial edge first (and favor ones with no coords yet) 250 { field: 'backwardCoord', order: 1 } 251 ].concat(this.context.eventOrderSpecs); 252 objs.sort(function (obj0, obj1) { 253 return core.compareByFieldSpecs(obj0, obj1, specs); 254 }); 255 return objs.map(function (c) { 256 return c._seg; 257 }); 258 }; 259 // Given foreground event segments that have already had their position coordinates computed, 260 // assigns position-related CSS values to their elements. 261 TimeGridEventRenderer.prototype.assignSegCss = function (segs) { 262 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 263 var seg = segs_1[_i]; 264 core.applyStyle(seg.el, this.generateSegCss(seg)); 265 if (seg.level > 0) { 266 seg.el.classList.add('fc-time-grid-event-inset'); 267 } 268 // if the event is short that the title will be cut off, 269 // attach a className that condenses the title into the time area. 270 if (seg.eventRange.def.title && seg.bottom - seg.top < 30) { 271 seg.el.classList.add('fc-short'); // TODO: "condensed" is a better name 272 } 273 } 274 }; 275 // Generates an object with CSS properties/values that should be applied to an event segment element. 276 // Contains important positioning-related properties that should be applied to any event element, customized or not. 277 TimeGridEventRenderer.prototype.generateSegCss = function (seg) { 278 var shouldOverlap = this.context.options.slotEventOverlap; 279 var backwardCoord = seg.backwardCoord; // the left side if LTR. the right side if RTL. floating-point 280 var forwardCoord = seg.forwardCoord; // the right side if LTR. the left side if RTL. floating-point 281 var props = this.timeGrid.generateSegVerticalCss(seg); // get top/bottom first 282 var isRtl = this.context.isRtl; 283 var left; // amount of space from left edge, a fraction of the total width 284 var right; // amount of space from right edge, a fraction of the total width 285 if (shouldOverlap) { 286 // double the width, but don't go beyond the maximum forward coordinate (1.0) 287 forwardCoord = Math.min(1, backwardCoord + (forwardCoord - backwardCoord) * 2); 288 } 289 if (isRtl) { 290 left = 1 - forwardCoord; 291 right = backwardCoord; 292 } 293 else { 294 left = backwardCoord; 295 right = 1 - forwardCoord; 296 } 297 props.zIndex = seg.level + 1; // convert from 0-base to 1-based 298 props.left = left * 100 + '%'; 299 props.right = right * 100 + '%'; 300 if (shouldOverlap && seg.forwardPressure) { 301 // add padding to the edge so that forward stacked events don't cover the resizer's icon 302 props[isRtl ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width 303 } 304 return props; 305 }; 306 return TimeGridEventRenderer; 307 }(core.FgEventRenderer)); 308 // Builds an array of segments "levels". The first level will be the leftmost tier of segments if the calendar is 309 // left-to-right, or the rightmost if the calendar is right-to-left. Assumes the segments are already ordered by date. 310 function buildSlotSegLevels(segs) { 311 var levels = []; 312 var i; 313 var seg; 314 var j; 315 for (i = 0; i < segs.length; i++) { 316 seg = segs[i]; 317 // go through all the levels and stop on the first level where there are no collisions 318 for (j = 0; j < levels.length; j++) { 319 if (!computeSlotSegCollisions(seg, levels[j]).length) { 320 break; 321 } 322 } 323 seg.level = j; 324 (levels[j] || (levels[j] = [])).push(seg); 325 } 326 return levels; 327 } 328 // For every segment, figure out the other segments that are in subsequent 329 // levels that also occupy the same vertical space. Accumulate in seg.forwardSegs 330 function computeForwardSlotSegs(levels) { 331 var i; 332 var level; 333 var j; 334 var seg; 335 var k; 336 for (i = 0; i < levels.length; i++) { 337 level = levels[i]; 338 for (j = 0; j < level.length; j++) { 339 seg = level[j]; 340 seg.forwardSegs = []; 341 for (k = i + 1; k < levels.length; k++) { 342 computeSlotSegCollisions(seg, levels[k], seg.forwardSegs); 343 } 344 } 345 } 346 } 347 // Figure out which path forward (via seg.forwardSegs) results in the longest path until 348 // the furthest edge is reached. The number of segments in this path will be seg.forwardPressure 349 function computeSlotSegPressures(seg) { 350 var forwardSegs = seg.forwardSegs; 351 var forwardPressure = 0; 352 var i; 353 var forwardSeg; 354 if (seg.forwardPressure === undefined) { // not already computed 355 for (i = 0; i < forwardSegs.length; i++) { 356 forwardSeg = forwardSegs[i]; 357 // figure out the child's maximum forward path 358 computeSlotSegPressures(forwardSeg); 359 // either use the existing maximum, or use the child's forward pressure 360 // plus one (for the forwardSeg itself) 361 forwardPressure = Math.max(forwardPressure, 1 + forwardSeg.forwardPressure); 362 } 363 seg.forwardPressure = forwardPressure; 364 } 365 } 366 // Find all the segments in `otherSegs` that vertically collide with `seg`. 367 // Append into an optionally-supplied `results` array and return. 368 function computeSlotSegCollisions(seg, otherSegs, results) { 369 if (results === void 0) { results = []; } 370 for (var i = 0; i < otherSegs.length; i++) { 371 if (isSlotSegCollision(seg, otherSegs[i])) { 372 results.push(otherSegs[i]); 373 } 374 } 375 return results; 376 } 377 // Do these segments occupy the same vertical space? 378 function isSlotSegCollision(seg1, seg2) { 379 return seg1.bottom > seg2.top && seg1.top < seg2.bottom; 380 } 381 function buildTimeGridSegCompareObj(seg) { 382 var obj = core.buildSegCompareObj(seg); 383 obj.forwardPressure = seg.forwardPressure; 384 obj.backwardCoord = seg.backwardCoord; 385 return obj; 386 } 387 388 var TimeGridMirrorRenderer = /** @class */ (function (_super) { 389 __extends(TimeGridMirrorRenderer, _super); 390 function TimeGridMirrorRenderer() { 391 return _super !== null && _super.apply(this, arguments) || this; 392 } 393 TimeGridMirrorRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 394 this.segsByCol = this.timeGrid.groupSegsByCol(segs); 395 this.timeGrid.attachSegsByCol(this.segsByCol, this.timeGrid.mirrorContainerEls); 396 this.sourceSeg = mirrorInfo.sourceSeg; 397 }; 398 TimeGridMirrorRenderer.prototype.generateSegCss = function (seg) { 399 var props = _super.prototype.generateSegCss.call(this, seg); 400 var sourceSeg = this.sourceSeg; 401 if (sourceSeg && sourceSeg.col === seg.col) { 402 var sourceSegProps = _super.prototype.generateSegCss.call(this, sourceSeg); 403 props.left = sourceSegProps.left; 404 props.right = sourceSegProps.right; 405 props.marginLeft = sourceSegProps.marginLeft; 406 props.marginRight = sourceSegProps.marginRight; 407 } 408 return props; 409 }; 410 return TimeGridMirrorRenderer; 411 }(TimeGridEventRenderer)); 412 413 var TimeGridFillRenderer = /** @class */ (function (_super) { 414 __extends(TimeGridFillRenderer, _super); 415 function TimeGridFillRenderer(timeGrid) { 416 var _this = _super.call(this) || this; 417 _this.timeGrid = timeGrid; 418 return _this; 419 } 420 TimeGridFillRenderer.prototype.attachSegs = function (type, segs) { 421 var timeGrid = this.timeGrid; 422 var containerEls; 423 // TODO: more efficient lookup 424 if (type === 'bgEvent') { 425 containerEls = timeGrid.bgContainerEls; 426 } 427 else if (type === 'businessHours') { 428 containerEls = timeGrid.businessContainerEls; 429 } 430 else if (type === 'highlight') { 431 containerEls = timeGrid.highlightContainerEls; 432 } 433 timeGrid.attachSegsByCol(timeGrid.groupSegsByCol(segs), containerEls); 434 return segs.map(function (seg) { 435 return seg.el; 436 }); 437 }; 438 TimeGridFillRenderer.prototype.computeSegSizes = function (segs) { 439 this.timeGrid.computeSegVerticals(segs); 440 }; 441 TimeGridFillRenderer.prototype.assignSegSizes = function (segs) { 442 this.timeGrid.assignSegVerticals(segs); 443 }; 444 return TimeGridFillRenderer; 445 }(core.FillRenderer)); 446 447 /* A component that renders one or more columns of vertical time slots 448 ----------------------------------------------------------------------------------------------------------------------*/ 449 // potential nice values for the slot-duration and interval-duration 450 // from largest to smallest 451 var AGENDA_STOCK_SUB_DURATIONS = [ 452 { hours: 1 }, 453 { minutes: 30 }, 454 { minutes: 15 }, 455 { seconds: 30 }, 456 { seconds: 15 } 457 ]; 458 var TimeGrid = /** @class */ (function (_super) { 459 __extends(TimeGrid, _super); 460 function TimeGrid(el, renderProps) { 461 var _this = _super.call(this, el) || this; 462 _this.isSlatSizesDirty = false;
463 _this.isColSizesDirty = false; 464 _this.processOptions = core.memoize(_this._processOptions); 465 _this.renderSkeleton = core.memoizeRendering(_this._renderSkeleton); 466 _this.renderSlats = core.memoizeRendering(_this._renderSlats, null, [_this.renderSkeleton]); 467 _this.renderColumns = core.memoizeRendering(_this._renderColumns, _this._unrenderColumns, [_this.renderSkeleton]); 468 _this.renderProps = renderProps; 469 var renderColumns = _this.renderColumns; 470 var eventRenderer = _this.eventRenderer = new TimeGridEventRenderer(_this); 471 var fillRenderer = _this.fillRenderer = new TimeGridFillRenderer(_this); 472 _this.mirrorRenderer = new TimeGridMirrorRenderer(_this); 473 _this.renderBusinessHours = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'), [renderColumns]); 474 _this.renderDateSelection = core.memoizeRendering(_this._renderDateSelection, _this._unrenderDateSelection, [renderColumns]); 475 _this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderColumns]); 476 _this.renderBgEvents = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'), [renderColumns]); 477 _this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); 478 _this.renderEventDrag = core.memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag, [renderColumns]); 479 _this.renderEventResize = core.memoizeRendering(_this._renderEventResize, _this._unrenderEventResize, [renderColumns]); 480 return _this; 481 } 482 /* Options 483 ------------------------------------------------------------------------------------------------------------------*/ 484 // Parses various options into properties of this object 485 // MUST have context already set 486 TimeGrid.prototype._processOptions = function (options) { 487 var slotDuration = options.slotDuration, snapDuration = options.snapDuration; 488 var snapsPerSlot; 489 var input; 490 slotDuration = core.createDuration(slotDuration); 491 snapDuration = snapDuration ? core.createDuration(snapDuration) : slotDuration; 492 snapsPerSlot = core.wholeDivideDurations(slotDuration, snapDuration); 493 if (snapsPerSlot === null) { 494 snapDuration = slotDuration; 495 snapsPerSlot = 1; 496 // TODO: say warning? 497 } 498 this.slotDuration = slotDuration; 499 this.snapDuration = snapDuration; 500 this.snapsPerSlot = snapsPerSlot; 501 // might be an array value (for TimelineView). 502 // if so, getting the most granular entry (the last one probably). 503 input = options.slotLabelFormat; 504 if (Array.isArray(input)) { 505 input = input[input.length - 1]; 506 } 507 this.labelFormat = core.createFormatter(input || { 508 hour: 'numeric', 509 minute: '2-digit', 510 omitZeroMinute: true, 511 meridiem: 'short' 512 }); 513 input = options.slotLabelInterval; 514 this.labelInterval = input ? 515 core.createDuration(input) : 516 this.computeLabelInterval(slotDuration); 517 }; 518 // Computes an automatic value for slotLabelInterval 519 TimeGrid.prototype.computeLabelInterval = function (slotDuration) { 520 var i; 521 var labelInterval; 522 var slotsPerLabel; 523 // find the smallest stock label interval that results in more than one slots-per-label 524 for (i = AGENDA_STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) { 525 labelInterval = core.createDuration(AGENDA_STOCK_SUB_DURATIONS[i]);
526 slotsPerLabel = core.wholeDivideDurations(labelInterval, slotDuration); 527 if (slotsPerLabel !== null && slotsPerLabel > 1) { 528 return labelInterval; 529 } 530 } 531 return slotDuration; // fall back 532 }; 533 /* Rendering 534 ------------------------------------------------------------------------------------------------------------------*/ 535 TimeGrid.prototype.render = function (props, context) { 536 this.processOptions(context.options); 537 var cells = props.cells; 538 this.colCnt = cells.length; 539 this.renderSkeleton(context.theme); 540 this.renderSlats(props.dateProfile); 541 this.renderColumns(props.cells, props.dateProfile); 542 this.renderBusinessHours(context, props.businessHourSegs); 543 this.renderDateSelection(props.dateSelectionSegs); 544 this.renderFgEvents(context, props.fgEventSegs); 545 this.renderBgEvents(context, props.bgEventSegs); 546 this.renderEventSelection(props.eventSelection); 547 this.renderEventDrag(props.eventDrag); 548 this.renderEventResize(props.eventResize); 549 }; 550 TimeGrid.prototype.destroy = function () { 551 _super.prototype.destroy.call(this); 552 // should unrender everything else too 553 this.renderSlats.unrender(); 554 this.renderColumns.unrender(); 555 this.renderSkeleton.unrender(); 556 }; 557 TimeGrid.prototype.updateSize = function (isResize) { 558 var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer; 559 if (isResize || this.isSlatSizesDirty) { 560 this.buildSlatPositions(); 561 this.isSlatSizesDirty = false; 562 } 563 if (isResize || this.isColSizesDirty) { 564 this.buildColPositions(); 565 this.isColSizesDirty = false; 566 } 567 fillRenderer.computeSizes(isResize); 568 eventRenderer.computeSizes(isResize); 569 mirrorRenderer.computeSizes(isResize); 570 fillRenderer.assignSizes(isResize); 571 eventRenderer.assignSizes(isResize); 572 mirrorRenderer.assignSizes(isResize); 573 }; 574 TimeGrid.prototype._renderSkeleton = function (theme) { 575 var el = this.el; 576 el.innerHTML = 577 '<div class="fc-bg"></div>' + 578 '<div class="fc-slats"></div>' + 579 '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" style="display:none" />'; 580 this.rootBgContainerEl = el.querySelector('.fc-bg'); 581 this.slatContainerEl = el.querySelector('.fc-slats'); 582 this.bottomRuleEl = el.querySelector('.fc-divider'); 583 }; 584 TimeGrid.prototype._renderSlats = function (dateProfile) { 585 var theme = this.context.theme; 586 this.slatContainerEl.innerHTML = 587 '<table class="' + theme.getClass('tableGrid') + '">' + 588 this.renderSlatRowHtml(dateProfile) + 589 '</table>'; 590 this.slatEls = core.findElements(this.slatContainerEl, 'tr'); 591 this.slatPositions = new core.PositionCache(this.el, this.slatEls, false, true // vertical 592 ); 593 this.isSlatSizesDirty = true; 594 }; 595 // Generates the HTML for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL. 596 TimeGrid.prototype.renderSlatRowHtml = function (dateProfile) { 597 var _a = this.context, dateEnv = _a.dateEnv, theme = _a.theme, isRtl = _a.isRtl; 598 var html = ''; 599 var dayStart = core.startOfDay(dateProfile.renderRange.start); 600 var slotTime = dateProfile.minTime; 601 var slotIterator = core.createDuration(0); 602 var slotDate; // will be on the view's first day, but we only care about its time 603 var isLabeled; 604 var axisHtml; 605 // Calculate the time for each slot 606 while (core.asRoughMs(slotTime) < core.asRoughMs(dateProfile.maxTime)) { 607 slotDate = dateEnv.add(dayStart, slotTime); 608 isLabeled = core.wholeDivideDurations(slotIterator, this.labelInterval) !== null; 609 axisHtml = 610 '<td class="fc-axis fc-time ' + theme.getClass('widgetContent') + '">' + 611 (isLabeled ? 612 '<span>' + // for matchCellWidths 613 core.htmlEscape(dateEnv.format(slotDate, this.labelFormat)) + 614 '</span>' : 615 '') + 616 '</td>'; 617 html += 618 '<tr data-time="' + core.formatIsoTimeString(slotDate) + '"' + 619 (isLabeled ? '' : ' class="fc-minor"') + 620 '>' + 621 (!isRtl ? axisHtml : '') + 622 '<td class="' + theme.getClass('widgetContent') + '"></td>' + 623 (isRtl ? axisHtml : '') + 624 '</tr>'; 625 slotTime = core.addDurations(slotTime, this.slotDuration); 626 slotIterator = core.addDurations(slotIterator, this.slotDuration); 627 } 628 return html; 629 }; 630 TimeGrid.prototype._renderColumns = function (cells, dateProfile) { 631 var _a = this.context, calendar = _a.calendar, view = _a.view, isRtl = _a.isRtl, theme = _a.theme, dateEnv = _a.dateEnv; 632 var bgRow = new daygrid.DayBgRow(this.context);
633 this.rootBgContainerEl.innerHTML = 634 '<table class="' + theme.getClass('tableGrid') + '">' + 635 bgRow.renderHtml({ 636 cells: cells, 637 dateProfile: dateProfile, 638 renderIntroHtml: this.renderProps.renderBgIntroHtml 639 }) + 640 '</table>'; 641 this.colEls = core.findElements(this.el, '.fc-day, .fc-disabled-day'); 642 for (var col = 0; col < this.colCnt; col++) { 643 calendar.publiclyTrigger('dayRender', [ 644 { 645 date: dateEnv.toDate(cells[col].date), 646 el: this.colEls[col], 647 view: view 648 } 649 ]); 650 } 651 if (isRtl) { 652 this.colEls.reverse(); 653 } 654 this.colPositions = new core.PositionCache(this.el, this.colEls, true, // horizontal 655 false); 656 this.renderContentSkeleton(); 657 this.isColSizesDirty = true; 658 }; 659 TimeGrid.prototype._unrenderColumns = function () { 660 this.unrenderContentSkeleton(); 661 }; 662 /* Content Skeleton 663 ------------------------------------------------------------------------------------------------------------------*/ 664 // Renders the DOM that the view's content will live in 665 TimeGrid.prototype.renderContentSkeleton = function () { 666 var isRtl = this.context.isRtl; 667 var parts = []; 668 var skeletonEl; 669 parts.push(this.renderProps.renderIntroHtml()); 670 for (var i = 0; i < this.colCnt; i++) { 671 parts.push('<td>' + 672 '<div class="fc-content-col">' + 673 '<div class="fc-event-container fc-mirror-container"></div>' + 674 '<div class="fc-event-container"></div>' + 675 '<div class="fc-highlight-container"></div>' + 676 '<div class="fc-bgevent-container"></div>' + 677 '<div class="fc-business-container"></div>' + 678 '</div>' + 679 '</td>'); 680 } 681 if (isRtl) { 682 parts.reverse(); 683 } 684 skeletonEl = this.contentSkeletonEl = core.htmlToElement('<div class="fc-content-skeleton">' + 685 '<table>' + 686 '<tr>' + parts.join('') + '</tr>' + 687 '</table>' + 688 '</div>'); 689 this.colContainerEls = core.findElements(skeletonEl, '.fc-content-col'); 690 this.mirrorContainerEls = core.findElements(skeletonEl, '.fc-mirror-container'); 691 this.fgContainerEls = core.findElements(skeletonEl, '.fc-event-container:not(.fc-mirror-container)'); 692 this.bgContainerEls = core.findElements(skeletonEl, '.fc-bgevent-container'); 693 this.highlightContainerEls = core.findElements(skeletonEl, '.fc-highlight-container'); 694 this.businessContainerEls = core.findElements(skeletonEl, '.fc-business-container'); 695 if (isRtl) { 696 this.colContainerEls.reverse(); 697 this.mirrorContainerEls.reverse(); 698 this.fgContainerEls.reverse(); 699 this.bgContainerEls.reverse(); 700 this.highlightContainerEls.reverse(); 701 this.businessContainerEls.reverse(); 702 } 703 this.el.appendChild(skeletonEl); 704 }; 705 TimeGrid.prototype.unrenderContentSkeleton = function () { 706 core.removeElement(this.contentSkeletonEl); 707 }; 708 // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's col 709 TimeGrid.prototype.groupSegsByCol = function (segs) { 710 var segsByCol = []; 711 var i; 712 for (i = 0; i < this.colCnt; i++) { 713 segsByCol.push([]); 714 } 715 for (i = 0; i < segs.length; i++) { 716 segsByCol[segs[i].col].push(segs[i]); 717 } 718 return segsByCol; 719 }; 720 // Given segments grouped by column, insert the segments' elements into a parallel array of container 721 // elements, each living within a column. 722 TimeGrid.prototype.attachSegsByCol = function (segsByCol, containerEls) { 723 var col; 724 var segs; 725 var i; 726 for (col = 0; col < this.colCnt; col++) { // iterate each column grouping 727 segs = segsByCol[col]; 728 for (i = 0; i < segs.length; i++) { 729 containerEls[col].appendChild(segs[i].el); 730 } 731 } 732 }; 733 /* Now Indicator 734 ------------------------------------------------------------------------------------------------------------------*/ 735 TimeGrid.prototype.getNowIndicatorUnit = function () { 736 return 'minute'; // will refresh on the minute 737 }; 738 TimeGrid.prototype.renderNowIndicator = function (segs, date) { 739 // HACK: if date columns not ready for some reason (scheduler) 740 if (!this.colContainerEls) { 741 return; 742 } 743 var top = this.computeDateTop(date); 744 var nodes = []; 745 var i; 746 // render lines within the columns 747 for (i = 0; i < segs.length; i++) { 748 var lineEl = core.createElement('div', { className: 'fc-now-indicator fc-now-indicator-line' }); 749 lineEl.style.top = top + 'px'; 750 this.colContainerEls[segs[i].col].appendChild(lineEl); 751 nodes.push(lineEl); 752 } 753 // render an arrow over the axis 754 if (segs.length > 0) { // is the current time in view? 755 var arrowEl = core.createElement('div', { className: 'fc-now-indicator fc-now-indicator-arrow' }); 756 arrowEl.style.top = top + 'px'; 757 this.contentSkeletonEl.appendChild(arrowEl); 758 nodes.push(arrowEl); 759 } 760 this.nowIndicatorEls = nodes; 761 }; 762 TimeGrid.prototype.unrenderNowIndicator = function () { 763 if (this.nowIndicatorEls) {
764 this.nowIndicatorEls.forEach(core.removeElement); 765 this.nowIndicatorEls = null; 766 } 767 }; 768 /* Coordinates 769 ------------------------------------------------------------------------------------------------------------------*/ 770 TimeGrid.prototype.getTotalSlatHeight = function () { 771 return this.slatContainerEl.getBoundingClientRect().height; 772 }; 773 // Computes the top coordinate, relative to the bounds of the grid, of the given date. 774 // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight. 775 TimeGrid.prototype.computeDateTop = function (when, startOfDayDate) { 776 if (!startOfDayDate) { 777 startOfDayDate = core.startOfDay(when); 778 } 779 return this.computeTimeTop(core.createDuration(when.valueOf() - startOfDayDate.valueOf())); 780 }; 781 // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration). 782 TimeGrid.prototype.computeTimeTop = function (duration) { 783 var len = this.slatEls.length; 784 var dateProfile = this.props.dateProfile; 785 var slatCoverage = (duration.milliseconds - core.asRoughMs(dateProfile.minTime)) / core.asRoughMs(this.slotDuration); // floating-point value of # of slots covered 786 var slatIndex; 787 var slatRemainder; 788 // compute a floating-point number for how many slats should be progressed through. 789 // from 0 to number of slats (inclusive) 790 // constrained because minTime/maxTime might be customized. 791 slatCoverage = Math.max(0, slatCoverage); 792 slatCoverage = Math.min(len, slatCoverage); 793 // an integer index of the furthest whole slat 794 // from 0 to number slats (*exclusive*, so len-1) 795 slatIndex = Math.floor(slatCoverage); 796 slatIndex = Math.min(slatIndex, len - 1); 797 // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition. 798 // could be 1.0 if slatCoverage is covering *all* the slots 799 slatRemainder = slatCoverage - slatIndex; 800 return this.slatPositions.tops[slatIndex] + 801 this.slatPositions.getHeight(slatIndex) * slatRemainder; 802 }; 803 // For each segment in an array, computes and assigns its top and bottom properties 804 TimeGrid.prototype.computeSegVerticals = function (segs) { 805 var options = this.context.options; 806 var eventMinHeight = options.timeGridEventMinHeight; 807 var i; 808 var seg; 809 var dayDate; 810 for (i = 0; i < segs.length; i++) { 811 seg = segs[i]; 812 dayDate = this.props.cells[seg.col].date; 813 seg.top = this.computeDateTop(seg.start, dayDate); 814 seg.bottom = Math.max(seg.top + eventMinHeight, this.computeDateTop(seg.end, dayDate)); 815 } 816 }; 817 // Given segments that already have their top/bottom properties computed, applies those values to 818 // the segments' elements. 819 TimeGrid.prototype.assignSegVerticals = function (segs) { 820 var i; 821 var seg; 822 for (i = 0; i < segs.length; i++) { 823 seg = segs[i]; 824 core.applyStyle(seg.el, this.generateSegVerticalCss(seg)); 825 } 826 }; 827 // Generates an object with CSS properties for the top/bottom coordinates of a segment element 828 TimeGrid.prototype.generateSegVerticalCss = function (seg) { 829 return { 830 top: seg.top, 831 bottom: -seg.bottom // flipped because needs to be space beyond bottom edge of event container 832 }; 833 }; 834 /* Sizing 835 ------------------------------------------------------------------------------------------------------------------*/ 836 TimeGrid.prototype.buildPositionCaches = function () { 837 this.buildColPositions(); 838 this.buildSlatPositions(); 839 }; 840 TimeGrid.prototype.buildColPositions = function () { 841 this.colPositions.build(); 842 }; 843 TimeGrid.prototype.buildSlatPositions = function () { 844 this.slatPositions.build(); 845 }; 846 /* Hit System 847 ------------------------------------------------------------------------------------------------------------------*/ 848 TimeGrid.prototype.positionToHit = function (positionLeft, positionTop) { 849 var dateEnv = this.context.dateEnv; 850 var _a = this, snapsPerSlot = _a.snapsPerSlot, slatPositions = _a.slatPositions, colPositions = _a.colPositions; 851 var colIndex = colPositions.leftToIndex(positionLeft); 852 var slatIndex = slatPositions.topToIndex(positionTop); 853 if (colIndex != null && slatIndex != null) { 854 var slatTop = slatPositions.tops[slatIndex]; 855 var slatHeight = slatPositions.getHeight(slatIndex); 856 var partial = (positionTop - slatTop) / slatHeight; // floating point number between 0 and 1 857 var localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat 858 var snapIndex = slatIndex * snapsPerSlot + localSnapIndex; 859 var dayDate = this.props.cells[colIndex].date; 860 var time = core.addDurations(this.props.dateProfile.minTime, core.multiplyDuration(this.snapDuration, snapIndex)); 861 var start = dateEnv.add(dayDate, time); 862 var end = dateEnv.add(start, this.snapDuration); 863 return { 864 col: colIndex, 865 dateSpan: { 866 range: { start: start, end: end }, 867 allDay: false 868 }, 869 dayEl: this.colEls[colIndex], 870 relativeRect: { 871 left: colPositions.lefts[colIndex], 872 right: colPositions.rights[colIndex], 873 top: slatTop, 874 bottom: slatTop + slatHeight 875 } 876 }; 877 } 878 }; 879 /* Event Drag Visualization 880 ------------------------------------------------------------------------------------------------------------------*/ 881 TimeGrid.prototype._renderEventDrag = function (state) { 882 if (state) { 883 this.eventRenderer.hideByHash(state.affectedInstances); 884 if (state.isEvent) { 885 this.mirrorRenderer.renderSegs(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg }); 886 } 887 else { 888 this.fillRenderer.renderSegs('highlight', this.context, state.segs); 889 } 890 } 891 }; 892 TimeGrid.prototype._unrenderEventDrag = function (state) { 893 if (state) { 894 this.eventRenderer.showByHash(state.affectedInstances); 895 if (state.isEvent) { 896 this.mirrorRenderer.unrender(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg }); 897 } 898 else { 899 this.fillRenderer.unrender('highlight', this.context); 900 } 901 } 902 }; 903 /* Event Resize Visualization 904 ------------------------------------------------------------------------------------------------------------------*/ 905 TimeGrid.prototype._renderEventResize = function (state) { 906 if (state) { 907 this.eventRenderer.hideByHash(state.affectedInstances); 908 this.mirrorRenderer.renderSegs(this.context, state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 909 } 910 }; 911 TimeGrid.prototype._unrenderEventResize = function (state) { 912 if (state) { 913 this.eventRenderer.showByHash(state.affectedInstances); 914 this.mirrorRenderer.unrender(this.context, state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 915 } 916 }; 917 /* Selection 918 ------------------------------------------------------------------------------------------------------------------*/ 919 // Renders a visual indication of a selection. Overrides the default, which was to simply render a highlight. 920 TimeGrid.prototype._renderDateSelection = function (segs) { 921 if (segs) { 922 if (this.context.options.selectMirror) { 923 this.mirrorRenderer.renderSegs(this.context, segs, { isSelecting: true }); 924 } 925 else { 926 this.fillRenderer.renderSegs('highlight', this.context, segs); 927 } 928 } 929 }; 930 TimeGrid.prototype._unrenderDateSelection = function (segs) { 931 if (segs) { 932 if (this.context.options.selectMirror) { 933 this.mirrorRenderer.unrender(this.context, segs, { isSelecting: true }); 934 } 935 else { 936 this.fillRenderer.unrender('highlight', this.context); 937 } 938 } 939 }; 940 return TimeGrid; 941 }(core.DateComponent)); 942 943 var AllDaySplitter = /** @class */ (function (_super) { 944 __extends(AllDaySplitter, _super); 945 function AllDaySplitter() { 946 return _super !== null && _super.apply(this, arguments) || this; 947 } 948 AllDaySplitter.prototype.getKeyInfo = function () { 949 return { 950 allDay: {}, 951 timed: {} 952 }; 953 }; 954 AllDaySplitter.prototype.getKeysForDateSpan = function (dateSpan) { 955 if (dateSpan.allDay) { 956 return ['allDay']; 957 } 958 else {
959 return ['timed']; 960 } 961 }; 962 AllDaySplitter.prototype.getKeysForEventDef = function (eventDef) { 963 if (!eventDef.allDay) { 964 return ['timed']; 965 } 966 else if (core.hasBgRendering(eventDef)) { 967 return ['timed', 'allDay']; 968 } 969 else { 970 return ['allDay']; 971 } 972 }; 973 return AllDaySplitter; 974 }(core.Splitter)); 975 976 var TIMEGRID_ALL_DAY_EVENT_LIMIT = 5; 977 var WEEK_HEADER_FORMAT = core.createFormatter({ week: 'short' }); 978 /* An abstract class for all timegrid-related views. Displays one more columns with time slots running vertically. 979 ----------------------------------------------------------------------------------------------------------------------*/ 980 // Is a manager for the TimeGrid subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on). 981 // Responsible for managing width/height. 982 var AbstractTimeGridView = /** @class */ (function (_super) { 983 __extends(AbstractTimeGridView, _super); 984 function AbstractTimeGridView() { 985 var _this = _super !== null && _super.apply(this, arguments) || this; 986 _this.splitter = new AllDaySplitter(); 987 _this.renderSkeleton = core.memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton); 988 /* Header Render Methods 989 ------------------------------------------------------------------------------------------------------------------*/ 990 // Generates the HTML that will go before the day-of week header cells 991 _this.renderHeadIntroHtml = function () { 992 var _a = _this.context, theme = _a.theme, dateEnv = _a.dateEnv, options = _a.options; 993 var range = _this.props.dateProfile.renderRange; 994 var dayCnt = core.diffDays(range.start, range.end); 995 var weekText; 996 if (options.weekNumbers) { 997 weekText = dateEnv.format(range.start, WEEK_HEADER_FORMAT); 998 return '' + 999 '<th class="fc-axis fc-week-number ' + theme.getClass('widgetHeader') + '" ' + _this.axisStyleAttr() + '>' + 1000 core.buildGotoAnchorHtml(// aside from link, important for matchCellWidths 1001 options, dateEnv, { date: range.start, type: 'week', forceOff: dayCnt > 1 }, core.htmlEscape(weekText) // inner HTML 1002 ) + 1003 '</th>'; 1004 } 1005 else { 1006 return '<th class="fc-axis ' + theme.getClass('widgetHeader') + '" ' + _this.axisStyleAttr() + '></th>'; 1007 } 1008 }; 1009 /* Time Grid Render Methods 1010 ------------------------------------------------------------------------------------------------------------------*/ 1011 // Generates the HTML that goes before the bg of the TimeGrid slot area. Long vertical column. 1012 _this.renderTimeGridBgIntroHtml = function () { 1013 var theme = _this.context.theme; 1014 return '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '></td>'; 1015 }; 1016 // Generates the HTML that goes before all other types of cells. 1017 // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid. 1018 _this.renderTimeGridIntroHtml = function () { 1019 return '<td class="fc-axis" ' + _this.axisStyleAttr() + '></td>'; 1020 }; 1021 /* Day Grid Render Methods 1022 ------------------------------------------------------------------------------------------------------------------*/ 1023 // Generates the HTML that goes before the all-day cells 1024 _this.renderDayGridBgIntroHtml = function () { 1025 var _a = _this.context, theme = _a.theme, options = _a.options; 1026 return '' + 1027 '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '>' + 1028 '<span>' + // needed for matchCellWidths 1029 core.getAllDayHtml(options) + 1030 '</span>' + 1031 '</td>'; 1032 }; 1033 // Generates the HTML that goes before all other types of cells. 1034 // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid. 1035 _this.renderDayGridIntroHtml = function () { 1036 return '<td class="fc-axis" ' + _this.axisStyleAttr() + '></td>'; 1037 }; 1038 return _this; 1039 } 1040 AbstractTimeGridView.prototype.render = function (props, context) { 1041 _super.prototype.render.call(this, props, context); 1042 this.renderSkeleton(context); 1043 }; 1044 AbstractTimeGridView.prototype.destroy = function () { 1045 _super.prototype.destroy.call(this); 1046 this.renderSkeleton.unrender(); 1047 }; 1048 AbstractTimeGridView.prototype._renderSkeleton = function (context) { 1049 this.el.classList.add('fc-timeGrid-view'); 1050 this.el.innerHTML = this.renderSkeletonHtml();
1051 this.scroller = new core.ScrollComponent('hidden', // overflow x 1052 'auto' // overflow y 1053 ); 1054 var timeGridWrapEl = this.scroller.el; 1055 this.el.querySelector('.fc-body > tr > td').appendChild(timeGridWrapEl); 1056 timeGridWrapEl.classList.add('fc-time-grid-container'); 1057 var timeGridEl = core.createElement('div', { className: 'fc-time-grid' }); 1058 timeGridWrapEl.appendChild(timeGridEl); 1059 this.timeGrid = new TimeGrid(timeGridEl, { 1060 renderBgIntroHtml: this.renderTimeGridBgIntroHtml, 1061 renderIntroHtml: this.renderTimeGridIntroHtml 1062 }); 1063 if (context.options.allDaySlot) { // should we display the "all-day" area? 1064 this.dayGrid = new daygrid.DayGrid(// the all-day subcomponent of this view 1065 this.el.querySelector('.fc-day-grid'), { 1066 renderNumberIntroHtml: this.renderDayGridIntroHtml, 1067 renderBgIntroHtml: this.renderDayGridBgIntroHtml, 1068 renderIntroHtml: this.renderDayGridIntroHtml, 1069 colWeekNumbersVisible: false, 1070 cellWeekNumbersVisible: false 1071 }); 1072 // have the day-grid extend it's coordinate area over the <hr> dividing the two grids 1073 var dividerEl = this.el.querySelector('.fc-divider'); 1074 this.dayGrid.bottomCoordPadding = dividerEl.getBoundingClientRect().height; 1075 } 1076 }; 1077 AbstractTimeGridView.prototype._unrenderSkeleton = function () { 1078 this.el.classList.remove('fc-timeGrid-view'); 1079 this.timeGrid.destroy(); 1080 if (this.dayGrid) { 1081 this.dayGrid.destroy(); 1082 } 1083 this.scroller.destroy(); 1084 }; 1085 /* Rendering 1086 ------------------------------------------------------------------------------------------------------------------*/ 1087 // Builds the HTML skeleton for the view. 1088 // The day-grid and time-grid components will render inside containers defined by this HTML. 1089 AbstractTimeGridView.prototype.renderSkeletonHtml = function () { 1090 var _a = this.context, theme = _a.theme, options = _a.options; 1091 return '' + 1092 '<table class="' + theme.getClass('tableGrid') + '">' + 1093 (options.columnHeader ? 1094 '<thead class="fc-head">' + 1095 '<tr>' + 1096 '<td class="fc-head-container ' + theme.getClass('widgetHeader') + '"> </td>' + 1097 '</tr>' + 1098 '</thead>' : 1099 '') + 1100 '<tbody class="fc-body">' + 1101 '<tr>' + 1102 '<td class="' + theme.getClass('widgetContent') + '">' + 1103 (options.allDaySlot ? 1104 '<div class="fc-day-grid"></div>' + 1105 '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" />' : 1106 '') + 1107 '</td>' + 1108 '</tr>' + 1109 '</tbody>' + 1110 '</table>'; 1111 }; 1112 /* Now Indicator 1113 ------------------------------------------------------------------------------------------------------------------*/ 1114 AbstractTimeGridView.prototype.getNowIndicatorUnit = function () { 1115 return this.timeGrid.getNowIndicatorUnit(); 1116 }; 1117 // subclasses should implement 1118 // renderNowIndicator(date: DateMarker) { 1119 // } 1120 AbstractTimeGridView.prototype.unrenderNowIndicator = function () { 1121 this.timeGrid.unrenderNowIndicator(); 1122 }; 1123 /* Dimensions 1124 ------------------------------------------------------------------------------------------------------------------*/ 1125 AbstractTimeGridView.prototype.updateSize = function (isResize, viewHeight, isAuto) { 1126 _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto); // will call updateBaseSize. important that executes first 1127 this.timeGrid.updateSize(isResize); 1128 if (this.dayGrid) { 1129 this.dayGrid.updateSize(isResize); 1130 } 1131 }; 1132 // Adjusts the vertical dimensions of the view to the specified values 1133 AbstractTimeGridView.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) { 1134 var _this = this; 1135 var eventLimit; 1136 var scrollerHeight; 1137 var scrollbarWidths; 1138 // make all axis cells line up 1139 this.axisWidth = core.matchCellWidths(core.findElements(this.el, '.fc-axis')); 1140 // hack to give the view some height prior to timeGrid's columns being rendered 1141 // TODO: separate setting height from scroller VS timeGrid. 1142 if (!this.timeGrid.colEls) { 1143 if (!isAuto) { 1144 scrollerHeight = this.computeScrollerHeight(viewHeight); 1145 this.scroller.setHeight(scrollerHeight); 1146 } 1147 return; 1148 } 1149 // set of fake row elements that must compensate when scroller has scrollbars 1150 var noScrollRowEls = core.findElements(this.el, '.fc-row').filter(function (node) { 1151 return !_this.scroller.el.contains(node); 1152 }); 1153 // reset all dimensions back to the original state 1154 this.timeGrid.bottomRuleEl.style.display = 'none'; // will be shown later if this <hr> is necessary 1155 this.scroller.clear(); // sets height to 'auto' and clears overflow
1156 noScrollRowEls.forEach(core.uncompensateScroll); 1157 // limit number of events in the all-day area 1158 if (this.dayGrid) { 1159 this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed 1160 eventLimit = this.context.options.eventLimit; 1161 if (eventLimit && typeof eventLimit !== 'number') { 1162 eventLimit = TIMEGRID_ALL_DAY_EVENT_LIMIT; // make sure "auto" goes to a real number 1163 } 1164 if (eventLimit) { 1165 this.dayGrid.limitRows(eventLimit); 1166 } 1167 } 1168 if (!isAuto) { // should we force dimensions of the scroll container? 1169 scrollerHeight = this.computeScrollerHeight(viewHeight); 1170 this.scroller.setHeight(scrollerHeight); 1171 scrollbarWidths = this.scroller.getScrollbarWidths(); 1172 if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars? 1173 // make the all-day and header rows lines up 1174 noScrollRowEls.forEach(function (rowEl) { 1175 core.compensateScroll(rowEl, scrollbarWidths); 1176 }); 1177 // the scrollbar compensation might have changed text flow, which might affect height, so recalculate 1178 // and reapply the desired height to the scroller. 1179 scrollerHeight = this.computeScrollerHeight(viewHeight); 1180 this.scroller.setHeight(scrollerHeight); 1181 } 1182 // guarantees the same scrollbar widths 1183 this.scroller.lockOverflow(scrollbarWidths); 1184 // if there's any space below the slats, show the horizontal rule. 1185 // this won't cause any new overflow, because lockOverflow already called. 1186 if (this.timeGrid.getTotalSlatHeight() < scrollerHeight) { 1187 this.timeGrid.bottomRuleEl.style.display = ''; 1188 } 1189 } 1190 }; 1191 // given a desired total height of the view, returns what the height of the scroller should be 1192 AbstractTimeGridView.prototype.computeScrollerHeight = function (viewHeight) { 1193 return viewHeight - 1194 core.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller 1195 }; 1196 /* Scroll 1197 ------------------------------------------------------------------------------------------------------------------*/ 1198 // Computes the initial pre-configured scroll state prior to allowing the user to change it 1199 AbstractTimeGridView.prototype.computeDateScroll = function (duration) { 1200 var top = this.timeGrid.computeTimeTop(duration); 1201 // zoom can give weird floating-point values. rather scroll a little bit further 1202 top = Math.ceil(top); 1203 if (top) { 1204 top++; // to overcome top border that slots beyond the first have. looks better 1205 } 1206 return { top: top }; 1207 }; 1208 AbstractTimeGridView.prototype.queryDateScroll = function () { 1209 return { top: this.scroller.getScrollTop() }; 1210 }; 1211 AbstractTimeGridView.prototype.applyDateScroll = function (scroll) { 1212 if (scroll.top !== undefined) { 1213 this.scroller.setScrollTop(scroll.top); 1214 } 1215 }; 1216 // Generates an HTML attribute string for setting the width of the axis, if it is known 1217 AbstractTimeGridView.prototype.axisStyleAttr = function () { 1218 if (this.axisWidth != null) { 1219 return 'style="width:' + this.axisWidth + 'px"'; 1220 } 1221 return ''; 1222 }; 1223 return AbstractTimeGridView; 1224 }(core.View)); 1225 AbstractTimeGridView.prototype.usesMinMaxTime = true; // indicates that minTime/maxTime affects rendering 1226 1227 var SimpleTimeGrid = /** @class */ (function (_super) { 1228 __extends(SimpleTimeGrid, _super); 1229 function SimpleTimeGrid(timeGrid) { 1230 var _this = _super.call(this, timeGrid.el) || this; 1231 _this.buildDayRanges = core.memoize(buildDayRanges); 1232 _this.slicer = new TimeGridSlicer(); 1233 _this.timeGrid = timeGrid; 1234 return _this; 1235 } 1236 SimpleTimeGrid.prototype.firstContext = function (context) { 1237 context.calendar.registerInteractiveComponent(this, { 1238 el: this.timeGrid.el 1239 }); 1240 }; 1241 SimpleTimeGrid.prototype.destroy = function () { 1242 _super.prototype.destroy.call(this); 1243 this.context.calendar.unregisterInteractiveComponent(this); 1244 }; 1245 SimpleTimeGrid.prototype.render = function (props, context) { 1246 var dateEnv = this.context.dateEnv; 1247 var dateProfile = props.dateProfile, dayTable = props.dayTable; 1248 var dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, dateEnv); 1249 this.timeGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, null, context.calendar, this.timeGrid, dayRanges), { dateProfile: dateProfile, cells: dayTable.cells[0] }), context); 1250 }; 1251 SimpleTimeGrid.prototype.renderNowIndicator = function (date) { 1252 this.timeGrid.renderNowIndicator(this.slicer.sliceNowDate(date, this.timeGrid, this.dayRanges), date); 1253 }; 1254 SimpleTimeGrid.prototype.buildPositionCaches = function () { 1255 this.timeGrid.buildPositionCaches(); 1256 }; 1257 SimpleTimeGrid.prototype.queryHit = function (positionLeft, positionTop) { 1258 var rawHit = this.timeGrid.positionToHit(positionLeft, positionTop); 1259 if (rawHit) { 1260 return { 1261 component: this.timeGrid, 1262 dateSpan: rawHit.dateSpan, 1263 dayEl: rawHit.dayEl, 1264 rect: { 1265 left: rawHit.relativeRect.left, 1266 right: rawHit.relativeRect.right, 1267 top: rawHit.relativeRect.top, 1268 bottom: rawHit.relativeRect.bottom 1269 }, 1270 layer: 0 1271 }; 1272 } 1273 }; 1274 return SimpleTimeGrid; 1275 }(core.DateComponent)); 1276 function buildDayRanges(dayTable, dateProfile, dateEnv) { 1277 var ranges = []; 1278 for (var _i = 0, _a = dayTable.headerDates; _i < _a.length; _i++) { 1279 var date = _a[_i]; 1280 ranges.push({ 1281 start: dateEnv.add(date, dateProfile.minTime), 1282 end: dateEnv.add(date, dateProfile.maxTime) 1283 }); 1284 } 1285 return ranges; 1286 } 1287 var TimeGridSlicer = /** @class */ (function (_super) { 1288 __extends(TimeGridSlicer, _super); 1289 function TimeGridSlicer() { 1290 return _super !== null && _super.apply(this, arguments) || this; 1291 } 1292 TimeGridSlicer.prototype.sliceRange = function (range, dayRanges) { 1293 var segs = []; 1294 for (var col = 0; col < dayRanges.length; col++) { 1295 var segRange = core.intersectRanges(range, dayRanges[col]); 1296 if (segRange) { 1297 segs.push({ 1298 start: segRange.start, 1299 end: segRange.end, 1300 isStart: segRange.start.valueOf() === range.start.valueOf(), 1301 isEnd: segRange.end.valueOf() === range.end.valueOf(), 1302 col: col 1303 }); 1304 } 1305 } 1306 return segs; 1307 }; 1308 return TimeGridSlicer; 1309 }(core.Slicer)); 1310 1311 var TimeGridView = /** @class */ (function (_super) { 1312 __extends(TimeGridView, _super); 1313 function TimeGridView() { 1314 var _this = _super !== null && _super.apply(this, arguments) || this; 1315 _this.buildDayTable = core.memoize(buildDayTable); 1316 return _this; 1317 } 1318 TimeGridView.prototype.render = function (props, context) { 1319 _super.prototype.render.call(this, props, context); // for flags for updateSize. also _renderSkeleton/_unrenderSkeleton 1320 var _a = this.props, dateProfile = _a.dateProfile, dateProfileGenerator = _a.dateProfileGenerator; 1321 var nextDayThreshold = context.nextDayThreshold; 1322 var dayTable = this.buildDayTable(dateProfile, dateProfileGenerator); 1323 var splitProps = this.splitter.splitProps(props); 1324 if (this.header) { 1325 this.header.receiveProps({ 1326 dateProfile: dateProfile, 1327 dates: dayTable.headerDates, 1328 datesRepDistinctDays: true, 1329 renderIntroHtml: this.renderHeadIntroHtml 1330 }, context); 1331 } 1332 this.simpleTimeGrid.receiveProps(__assign({}, splitProps['timed'], { dateProfile: dateProfile, 1333 dayTable: dayTable }), context); 1334 if (this.simpleDayGrid) { 1335 this.simpleDayGrid.receiveProps(__assign({}, splitProps['allDay'], { dateProfile: dateProfile, 1336 dayTable: dayTable, 1337 nextDayThreshold: nextDayThreshold, isRigid: false }), context); 1338 } 1339 this.startNowIndicator(dateProfile, dateProfileGenerator); 1340 }; 1341 TimeGridView.prototype._renderSkeleton = function (context) { 1342 _super.prototype._renderSkeleton.call(this, context); 1343 if (context.options.columnHeader) { 1344 this.header = new core.DayHeader(this.el.querySelector('.fc-head-container')); 1345 } 1346 this.simpleTimeGrid = new SimpleTimeGrid(this.timeGrid); 1347 if (this.dayGrid) { 1348 this.simpleDayGrid = new daygrid.SimpleDayGrid(this.dayGrid); 1349 } 1350 }; 1351 TimeGridView.prototype._unrenderSkeleton = function () { 1352 _super.prototype._unrenderSkeleton.call(this); 1353 if (this.header) { 1354 this.header.destroy(); 1355 } 1356 this.simpleTimeGrid.destroy(); 1357 if (this.simpleDayGrid) { 1358 this.simpleDayGrid.destroy(); 1359 } 1360 }; 1361 TimeGridView.prototype.renderNowIndicator = function (date) { 1362 this.simpleTimeGrid.renderNowIndicator(date); 1363 }; 1364 return TimeGridView; 1365 }(AbstractTimeGridView)); 1366 function buildDayTable(dateProfile, dateProfileGenerator) { 1367 var daySeries = new core.DaySeries(dateProfile.renderRange, dateProfileGenerator); 1368 return new core.DayTable(daySeries, false); 1369 } 1370 1371 var main = core.createPlugin({ 1372 defaultView: 'timeGridWeek', 1373 views: { 1374 timeGrid: { 1375 class: TimeGridView, 1376 allDaySlot: true, 1377 slotDuration: '00:30:00', 1378 slotEventOverlap: true // a bad name. confused with overlap/constraint system 1379 }, 1380 timeGridDay: { 1381 type: 'timeGrid', 1382 duration: { days: 1 } 1383 }, 1384 timeGridWeek: { 1385 type: 'timeGrid', 1386 duration: { weeks: 1 } 1387 } 1388 } 1389 }); 1390 1391 exports.AbstractTimeGridView = AbstractTimeGridView; 1392 exports.TimeGrid = TimeGrid; 1393 exports.TimeGridSlicer = TimeGridSlicer; 1394 exports.TimeGridView = TimeGridView; 1395 exports.buildDayRanges = buildDayRanges; 1396 exports.buildDayTable = buildDayTable; 1397 exports.default = main; 1398 1399 Object.defineProperty(exports, '__esModule', { value: true }); 1400 1401}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.