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