1/*! 2FullCalendar Day 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')) : 9 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) : 10 (global = global || self, factory(global.FullCalendarDayGrid = {}, global.FullCalendar)); 11}(this, function (exports, core) { '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 var DayGridDateProfileGenerator = /** @class */ (function (_super) { 54 __extends(DayGridDateProfileGenerator, _super); 55 function DayGridDateProfileGenerator() { 56 return _super !== null && _super.apply(this, arguments) || this; 57 } 58 // Computes the date range that will be rendered. 59 DayGridDateProfileGenerator.prototype.buildRenderRange = function (currentRange, currentRangeUnit, isRangeAllDay) { 60 var dateEnv = this.dateEnv; 61 var renderRange = _super.prototype.buildRenderRange.call(this, currentRange, currentRangeUnit, isRangeAllDay); 62 var start = renderRange.start; 63 var end = renderRange.end; 64 var endOfWeek; 65 // year and month views should be aligned with weeks. this is already done for week 66 if (/^(year|month)$/.test(currentRangeUnit)) { 67 start = dateEnv.startOfWeek(start); 68 // make end-of-week if not already 69 endOfWeek = dateEnv.startOfWeek(end); 70 if (endOfWeek.valueOf() !== end.valueOf()) { 71 end = core.addWeeks(endOfWeek, 1); 72 } 73 } 74 // ensure 6 weeks 75 if (this.options.monthMode && 76 this.options.fixedWeekCount) { 77 var rowCnt = Math.ceil(// could be partial weeks due to hiddenDays 78 core.diffWeeks(start, end)); 79 end = core.addWeeks(end, 6 - rowCnt); 80 } 81 return { start: start, end: end }; 82 }; 83 return DayGridDateProfileGenerator; 84 }(core.DateProfileGenerator)); 85 86 /* A rectangular panel that is absolutely positioned over other content 87 ------------------------------------------------------------------------------------------------------------------------ 88 Options: 89 - className (string) 90 - content (HTML string, element, or element array) 91 - parentEl 92 - top 93 - left 94 - right (the x coord of where the right edge should be. not a "CSS" right) 95 - autoHide (boolean) 96 - show (callback) 97 - hide (callback) 98 */ 99 var Popover = /** @class */ (function () { 100 function Popover(options) { 101 var _this = this; 102 this.isHidden = true; 103 this.margin = 10; // the space required between the popover and the edges of the scroll container 104 // Triggered when the user clicks *anywhere* in the document, for the autoHide feature 105 this.documentMousedown = function (ev) { 106 // only hide the popover if the click happened outside the popover 107 if (_this.el && !_this.el.contains(ev.target)) { 108 _this.hide(); 109 } 110 }; 111 this.options = options; 112 } 113 // Shows the popover on the specified position. Renders it if not already 114 Popover.prototype.show = function () { 115 if (this.isHidden) { 116 if (!this.el) { 117 this.render(); 118 } 119 this.el.style.display = ''; 120 this.position(); 121 this.isHidden = false;
122 this.trigger('show'); 123 } 124 }; 125 // Hides the popover, through CSS, but does not remove it from the DOM 126 Popover.prototype.hide = function () { 127 if (!this.isHidden) { 128 this.el.style.display = 'none'; 129 this.isHidden = true; 130 this.trigger('hide'); 131 } 132 }; 133 // Creates `this.el` and renders content inside of it 134 Popover.prototype.render = function () { 135 var _this = this; 136 var options = this.options; 137 var el = this.el = core.createElement('div', { 138 className: 'fc-popover ' + (options.className || ''), 139 style: { 140 top: '0', 141 left: '0' 142 } 143 }); 144 if (typeof options.content === 'function') { 145 options.content(el); 146 } 147 options.parentEl.appendChild(el); 148 // when a click happens on anything inside with a 'fc-close' className, hide the popover 149 core.listenBySelector(el, 'click', '.fc-close', function (ev) { 150 _this.hide(); 151 }); 152 if (options.autoHide) { 153 document.addEventListener('mousedown', this.documentMousedown); 154 } 155 }; 156 // Hides and unregisters any handlers 157 Popover.prototype.destroy = function () { 158 this.hide(); 159 if (this.el) { 160 core.removeElement(this.el); 161 this.el = null; 162 } 163 document.removeEventListener('mousedown', this.documentMousedown); 164 }; 165 // Positions the popover optimally, using the top/left/right options 166 Popover.prototype.position = function () { 167 var options = this.options; 168 var el = this.el; 169 var elDims = el.getBoundingClientRect(); // only used for width,height 170 var origin = core.computeRect(el.offsetParent); 171 var clippingRect = core.computeClippingRect(options.parentEl); 172 var top; // the "position" (not "offset") values for the popover 173 var left; // 174 // compute top and left 175 top = options.top || 0; 176 if (options.left !== undefined) { 177 left = options.left; 178 } 179 else if (options.right !== undefined) { 180 left = options.right - elDims.width; // derive the left value from the right value 181 } 182 else { 183 left = 0; 184 } 185 // constrain to the view port. if constrained by two edges, give precedence to top/left 186 top = Math.min(top, clippingRect.bottom - elDims.height - this.margin); 187 top = Math.max(top, clippingRect.top + this.margin); 188 left = Math.min(left, clippingRect.right - elDims.width - this.margin); 189 left = Math.max(left, clippingRect.left + this.margin); 190 core.applyStyle(el, { 191 top: top - origin.top, 192 left: left - origin.left 193 }); 194 }; 195 // Triggers a callback. Calls a function in the option hash of the same name. 196 // Arguments beyond the first `name` are forwarded on. 197 // TODO: better code reuse for this. Repeat code 198 // can kill this??? 199 Popover.prototype.trigger = function (name) { 200 if (this.options[name]) { 201 this.options[name].apply(this, Array.prototype.slice.call(arguments, 1)); 202 } 203 }; 204 return Popover; 205 }()); 206 207 /* Event-rendering methods for the DayGrid class 208 ----------------------------------------------------------------------------------------------------------------------*/ 209 // "Simple" is bad a name. has nothing to do with SimpleDayGrid 210 var SimpleDayGridEventRenderer = /** @class */ (function (_super) { 211 __extends(SimpleDayGridEventRenderer, _super); 212 function SimpleDayGridEventRenderer() { 213 return _super !== null && _super.apply(this, arguments) || this; 214 } 215 // Builds the HTML to be used for the default element for an individual segment 216 SimpleDayGridEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) { 217 var _a = this.context, view = _a.view, options = _a.options; 218 var eventRange = seg.eventRange; 219 var eventDef = eventRange.def; 220 var eventUi = eventRange.ui; 221 var allDay = eventDef.allDay; 222 var isDraggable = view.computeEventDraggable(eventDef, eventUi); 223 var isResizableFromStart = allDay && seg.isStart && view.computeEventStartResizable(eventDef, eventUi); 224 var isResizableFromEnd = allDay && seg.isEnd && view.computeEventEndResizable(eventDef, eventUi);
225 var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo); 226 var skinCss = core.cssToStr(this.getSkinCss(eventUi)); 227 var timeHtml = ''; 228 var timeText; 229 var titleHtml; 230 classes.unshift('fc-day-grid-event', 'fc-h-event'); 231 // Only display a timed events time if it is the starting segment 232 if (seg.isStart) { 233 timeText = this.getTimeText(eventRange); 234 if (timeText) { 235 timeHtml = '<span class="fc-time">' + core.htmlEscape(timeText) + '</span>'; 236 } 237 } 238 titleHtml = 239 '<span class="fc-title">' + 240 (core.htmlEscape(eventDef.title || '') || ' ') + // we always want one line of height 241 '</span>'; 242 return '<a class="' + classes.join(' ') + '"' + 243 (eventDef.url ? 244 ' href="' + core.htmlEscape(eventDef.url) + '"' : 245 '') + 246 (skinCss ? 247 ' style="' + skinCss + '"' : 248 '') + 249 '>' + 250 '<div class="fc-content">' + 251 (options.dir === 'rtl' ? 252 titleHtml + ' ' + timeHtml : // put a natural space in between 253 timeHtml + ' ' + titleHtml // 254 ) + 255 '</div>' + 256 (isResizableFromStart ? 257 '<div class="fc-resizer fc-start-resizer"></div>' : 258 '') + 259 (isResizableFromEnd ? 260 '<div class="fc-resizer fc-end-resizer"></div>' : 261 '') + 262 '</a>'; 263 }; 264 // Computes a default event time formatting string if `eventTimeFormat` is not explicitly defined 265 SimpleDayGridEventRenderer.prototype.computeEventTimeFormat = function () { 266 return { 267 hour: 'numeric', 268 minute: '2-digit', 269 omitZeroMinute: true, 270 meridiem: 'narrow' 271 }; 272 }; 273 SimpleDayGridEventRenderer.prototype.computeDisplayEventEnd = function () { 274 return false; // TODO: somehow consider the originating DayGrid's column count 275 }; 276 return SimpleDayGridEventRenderer; 277 }(core.FgEventRenderer)); 278 279 /* Event-rendering methods for the DayGrid class 280 ----------------------------------------------------------------------------------------------------------------------*/ 281 var DayGridEventRenderer = /** @class */ (function (_super) { 282 __extends(DayGridEventRenderer, _super); 283 function DayGridEventRenderer(dayGrid) { 284 var _this = _super.call(this, dayGrid.context) || this; 285 _this.dayGrid = dayGrid; 286 return _this; 287 } 288 // Renders the given foreground event segments onto the grid 289 DayGridEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 290 var rowStructs = this.rowStructs = this.renderSegRows(segs); 291 // append to each row's content skeleton 292 this.dayGrid.rowEls.forEach(function (rowNode, i) { 293 rowNode.querySelector('.fc-content-skeleton > table').appendChild(rowStructs[i].tbodyEl); 294 }); 295 // removes the "more.." events popover 296 if (!mirrorInfo) { 297 this.dayGrid.removeSegPopover(); 298 } 299 }; 300 // Unrenders all currently rendered foreground event segments 301 DayGridEventRenderer.prototype.detachSegs = function () { 302 var rowStructs = this.rowStructs || []; 303 var rowStruct; 304 while ((rowStruct = rowStructs.pop())) { 305 core.removeElement(rowStruct.tbodyEl); 306 } 307 this.rowStructs = null; 308 }; 309 // Uses the given events array to generate <tbody> elements that should be appended to each row's content skeleton. 310 // Returns an array of rowStruct objects (see the bottom of `renderSegRow`). 311 // PRECONDITION: each segment shoud already have a rendered and assigned `.el` 312 DayGridEventRenderer.prototype.renderSegRows = function (segs) { 313 var rowStructs = []; 314 var segRows; 315 var row; 316 segRows = this.groupSegRows(segs); // group into nested arrays 317 // iterate each row of segment groupings 318 for (row = 0; row < segRows.length; row++) { 319 rowStructs.push(this.renderSegRow(row, segRows[row])); 320 } 321 return rowStructs; 322 }; 323 // Given a row # and an array of segments all in the same row, render a <tbody> element, a skeleton that contains 324 // the segments. Returns object with a bunch of internal data about how the render was calculated. 325 // NOTE: modifies rowSegs 326 DayGridEventRenderer.prototype.renderSegRow = function (row, rowSegs) { 327 var dayGrid = this.dayGrid; 328 var colCnt = dayGrid.colCnt, isRtl = dayGrid.isRtl; 329 var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels 330 var levelCnt = Math.max(1, segLevels.length); // ensure at least one level 331 var tbody = document.createElement('tbody'); 332 var segMatrix = []; // lookup for which segments are rendered into which level+col cells 333 var cellMatrix = []; // lookup for all <td> elements of the level+col matrix 334 var loneCellMatrix = []; // lookup for <td> elements that only take up a single column 335 var i; 336 var levelSegs; 337 var col; 338 var tr; 339 var j; 340 var seg; 341 var td; 342 // populates empty cells from the current column (`col`) to `endCol` 343 function emptyCellsUntil(endCol) { 344 while (col < endCol) { 345 // try to grab a cell from the level above and extend its rowspan. otherwise, create a fresh cell 346 td = (loneCellMatrix[i - 1] || [])[col]; 347 if (td) { 348 td.rowSpan = (td.rowSpan || 1) + 1; 349 } 350 else { 351 td = document.createElement('td'); 352 tr.appendChild(td); 353 } 354 cellMatrix[i][col] = td; 355 loneCellMatrix[i][col] = td; 356 col++; 357 } 358 } 359 for (i = 0; i < levelCnt; i++) { // iterate through all levels 360 levelSegs = segLevels[i]; 361 col = 0; 362 tr = document.createElement('tr'); 363 segMatrix.push([]); 364 cellMatrix.push([]); 365 loneCellMatrix.push([]); 366 // levelCnt might be 1 even though there are no actual levels. protect against this. 367 // this single empty row is useful for styling. 368 if (levelSegs) { 369 for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level 370 seg = levelSegs[j]; 371 var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; 372 var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; 373 emptyCellsUntil(leftCol); 374 // create a container that occupies or more columns. append the event element. 375 td = core.createElement('td', { className: 'fc-event-container' }, seg.el); 376 if (leftCol !== rightCol) { 377 td.colSpan = rightCol - leftCol + 1; 378 } 379 else { // a single-column segment 380 loneCellMatrix[i][col] = td; 381 } 382 while (col <= rightCol) { 383 cellMatrix[i][col] = td; 384 segMatrix[i][col] = seg; 385 col++; 386 } 387 tr.appendChild(td); 388 } 389 } 390 emptyCellsUntil(colCnt); // finish off the row 391 var introHtml = dayGrid.renderProps.renderIntroHtml(); 392 if (introHtml) { 393 if (dayGrid.isRtl) { 394 core.appendToElement(tr, introHtml); 395 } 396 else { 397 core.prependToElement(tr, introHtml); 398 } 399 } 400 tbody.appendChild(tr); 401 } 402 return { 403 row: row, 404 tbodyEl: tbody, 405 cellMatrix: cellMatrix, 406 segMatrix: segMatrix, 407 segLevels: segLevels, 408 segs: rowSegs 409 }; 410 }; 411 // Stacks a flat array of segments, which are all assumed to be in the same row, into subarrays of vertical levels. 412 // NOTE: modifies segs 413 DayGridEventRenderer.prototype.buildSegLevels = function (segs) { 414 var _a = this.dayGrid, isRtl = _a.isRtl, colCnt = _a.colCnt; 415 var levels = []; 416 var i; 417 var seg; 418 var j; 419 // Give preference to elements with certain criteria, so they have 420 // a chance to be closer to the top. 421 segs = this.sortEventSegs(segs); 422 for (i = 0; i < segs.length; i++) { 423 seg = segs[i]; 424 // loop through levels, starting with the topmost, until the segment doesn't collide with other segments 425 for (j = 0; j < levels.length; j++) {
426 if (!isDaySegCollision(seg, levels[j])) { 427 break; 428 } 429 } 430 // `j` now holds the desired subrow index 431 seg.level = j; 432 seg.leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; // for sorting only 433 seg.rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol // for sorting only 434 ; 435 (levels[j] || (levels[j] = [])).push(seg); 436 } 437 // order segments left-to-right. very important if calendar is RTL 438 for (j = 0; j < levels.length; j++) { 439 levels[j].sort(compareDaySegCols); 440 } 441 return levels; 442 }; 443 // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's row 444 DayGridEventRenderer.prototype.groupSegRows = function (segs) { 445 var segRows = []; 446 var i; 447 for (i = 0; i < this.dayGrid.rowCnt; i++) { 448 segRows.push([]); 449 } 450 for (i = 0; i < segs.length; i++) { 451 segRows[segs[i].row].push(segs[i]); 452 } 453 return segRows; 454 }; 455 // Computes a default `displayEventEnd` value if one is not expliclty defined 456 DayGridEventRenderer.prototype.computeDisplayEventEnd = function () { 457 return this.dayGrid.colCnt === 1; // we'll likely have space if there's only one day 458 }; 459 return DayGridEventRenderer; 460 }(SimpleDayGridEventRenderer)); 461 // Computes whether two segments' columns collide. They are assumed to be in the same row. 462 function isDaySegCollision(seg, otherSegs) { 463 var i; 464 var otherSeg; 465 for (i = 0; i < otherSegs.length; i++) { 466 otherSeg = otherSegs[i]; 467 if (otherSeg.firstCol <= seg.lastCol && 468 otherSeg.lastCol >= seg.firstCol) { 469 return true; 470 } 471 } 472 return false; 473 } 474 // A cmp function for determining the leftmost event 475 function compareDaySegCols(a, b) { 476 return a.leftCol - b.leftCol; 477 } 478 479 var DayGridMirrorRenderer = /** @class */ (function (_super) { 480 __extends(DayGridMirrorRenderer, _super); 481 function DayGridMirrorRenderer() { 482 return _super !== null && _super.apply(this, arguments) || this; 483 } 484 DayGridMirrorRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 485 var sourceSeg = mirrorInfo.sourceSeg; 486 var rowStructs = this.rowStructs = this.renderSegRows(segs); 487 // inject each new event skeleton into each associated row 488 this.dayGrid.rowEls.forEach(function (rowNode, row) { 489 var skeletonEl = core.htmlToElement('<div class="fc-mirror-skeleton"><table></table></div>'); // will be absolutely positioned 490 var skeletonTopEl; 491 var skeletonTop; 492 // If there is an original segment, match the top position. Otherwise, put it at the row's top level 493 if (sourceSeg && sourceSeg.row === row) { 494 skeletonTopEl = sourceSeg.el; 495 } 496 else { 497 skeletonTopEl = rowNode.querySelector('.fc-content-skeleton tbody'); 498 if (!skeletonTopEl) { // when no events 499 skeletonTopEl = rowNode.querySelector('.fc-content-skeleton table'); 500 } 501 } 502 skeletonTop = skeletonTopEl.getBoundingClientRect().top - 503 rowNode.getBoundingClientRect().top; // the offsetParent origin 504 skeletonEl.style.top = skeletonTop + 'px'; 505 skeletonEl.querySelector('table').appendChild(rowStructs[row].tbodyEl); 506 rowNode.appendChild(skeletonEl); 507 }); 508 }; 509 return DayGridMirrorRenderer; 510 }(DayGridEventRenderer)); 511 512 var EMPTY_CELL_HTML = '<td style="pointer-events:none"></td>'; 513 var DayGridFillRenderer = /** @class */ (function (_super) { 514 __extends(DayGridFillRenderer, _super); 515 function DayGridFillRenderer(dayGrid) { 516 var _this = _super.call(this, dayGrid.context) || this; 517 _this.fillSegTag = 'td'; // override the default tag name 518 _this.dayGrid = dayGrid; 519 return _this; 520 } 521 DayGridFillRenderer.prototype.renderSegs = function (type, segs) { 522 // don't render timed background events 523 if (type === 'bgEvent') { 524 segs = segs.filter(function (seg) { 525 return seg.eventRange.def.allDay; 526 }); 527 }
528 _super.prototype.renderSegs.call(this, type, segs); 529 }; 530 DayGridFillRenderer.prototype.attachSegs = function (type, segs) { 531 var els = []; 532 var i; 533 var seg; 534 var skeletonEl; 535 for (i = 0; i < segs.length; i++) { 536 seg = segs[i]; 537 skeletonEl = this.renderFillRow(type, seg); 538 this.dayGrid.rowEls[seg.row].appendChild(skeletonEl); 539 els.push(skeletonEl); 540 } 541 return els; 542 }; 543 // Generates the HTML needed for one row of a fill. Requires the seg's el to be rendered. 544 DayGridFillRenderer.prototype.renderFillRow = function (type, seg) { 545 var dayGrid = this.dayGrid; 546 var colCnt = dayGrid.colCnt, isRtl = dayGrid.isRtl; 547 var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; 548 var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; 549 var startCol = leftCol; 550 var endCol = rightCol + 1; 551 var className; 552 var skeletonEl; 553 var trEl; 554 if (type === 'businessHours') { 555 className = 'bgevent'; 556 } 557 else { 558 className = type.toLowerCase(); 559 } 560 skeletonEl = core.htmlToElement('<div class="fc-' + className + '-skeleton">' + 561 '<table><tr></tr></table>' + 562 '</div>'); 563 trEl = skeletonEl.getElementsByTagName('tr')[0]; 564 if (startCol > 0) { 565 core.appendToElement(trEl, 566 // will create (startCol + 1) td's 567 new Array(startCol + 1).join(EMPTY_CELL_HTML)); 568 } 569 seg.el.colSpan = endCol - startCol; 570 trEl.appendChild(seg.el); 571 if (endCol < colCnt) { 572 core.appendToElement(trEl, 573 // will create (colCnt - endCol) td's 574 new Array(colCnt - endCol + 1).join(EMPTY_CELL_HTML)); 575 } 576 var introHtml = dayGrid.renderProps.renderIntroHtml(); 577 if (introHtml) { 578 if (dayGrid.isRtl) { 579 core.appendToElement(trEl, introHtml); 580 } 581 else { 582 core.prependToElement(trEl, introHtml); 583 } 584 } 585 return skeletonEl; 586 }; 587 return DayGridFillRenderer; 588 }(core.FillRenderer)); 589 590 var DayTile = /** @class */ (function (_super) { 591 __extends(DayTile, _super); 592 function DayTile(context, el) { 593 var _this = _super.call(this, context, el) || this; 594 var eventRenderer = _this.eventRenderer = new DayTileEventRenderer(_this); 595 var renderFrame = _this.renderFrame = core.memoizeRendering(_this._renderFrame); 596 _this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderFrame]); 597 _this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); 598 _this.renderEventDrag = core.memoizeRendering(eventRenderer.hideByHash.bind(eventRenderer), eventRenderer.showByHash.bind(eventRenderer), [renderFrame]); 599 _this.renderEventResize = core.memoizeRendering(eventRenderer.hideByHash.bind(eventRenderer), eventRenderer.showByHash.bind(eventRenderer), [renderFrame]); 600 context.calendar.registerInteractiveComponent(_this, { 601 el: _this.el, 602 useEventCenter: false 603 }); 604 return _this; 605 } 606 DayTile.prototype.render = function (props) { 607 this.renderFrame(props.date); 608 this.renderFgEvents(props.fgSegs); 609 this.renderEventSelection(props.eventSelection); 610 this.renderEventDrag(props.eventDragInstances); 611 this.renderEventResize(props.eventResizeInstances); 612 }; 613 DayTile.prototype.destroy = function () { 614 _super.prototype.destroy.call(this); 615 this.renderFrame.unrender(); // should unrender everything else 616 this.calendar.unregisterInteractiveComponent(this); 617 }; 618 DayTile.prototype._renderFrame = function (date) { 619 var _a = this, theme = _a.theme, dateEnv = _a.dateEnv; 620 var title = dateEnv.format(date, core.createFormatter(this.opt('dayPopoverFormat')) // TODO: cache 621 ); 622 this.el.innerHTML = 623 '<div class="fc-header ' + theme.getClass('popoverHeader') + '">' + 624 '<span class="fc-title">' + 625 core.htmlEscape(title) + 626 '</span>' + 627 '<span class="fc-close ' + theme.getIconClass('close') + '"></span>' + 628 '</div>' + 629 '<div class="fc-body ' + theme.getClass('popoverContent') + '">' + 630 '<div class="fc-event-container"></div>' + 631 '</div>'; 632 this.segContainerEl = this.el.querySelector('.fc-event-container'); 633 }; 634 DayTile.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { 635 var date = this.props.date; // HACK 636 if (positionLeft < elWidth && positionTop < elHeight) { 637 return { 638 component: this, 639 dateSpan: { 640 allDay: true, 641 range: { start: date, end: core.addDays(date, 1) } 642 }, 643 dayEl: this.el, 644 rect: { 645 left: 0, 646 top: 0, 647 right: elWidth, 648 bottom: elHeight 649 }, 650 layer: 1 651 }; 652 } 653 }; 654 return DayTile; 655 }(core.DateComponent)); 656 var DayTileEventRenderer = /** @class */ (function (_super) { 657 __extends(DayTileEventRenderer, _super); 658 function DayTileEventRenderer(dayTile) { 659 var _this = _super.call(this, dayTile.context) || this; 660 _this.dayTile = dayTile; 661 return _this; 662 } 663 DayTileEventRenderer.prototype.attachSegs = function (segs) { 664 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 665 var seg = segs_1[_i]; 666 this.dayTile.segContainerEl.appendChild(seg.el); 667 } 668 }; 669 DayTileEventRenderer.prototype.detachSegs = function (segs) { 670 for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { 671 var seg = segs_2[_i]; 672 core.removeElement(seg.el); 673 } 674 }; 675 return DayTileEventRenderer; 676 }(SimpleDayGridEventRenderer)); 677 678 var DayBgRow = /** @class */ (function () { 679 function DayBgRow(context) { 680 this.context = context; 681 } 682 DayBgRow.prototype.renderHtml = function (props) { 683 var parts = []; 684 if (props.renderIntroHtml) { 685 parts.push(props.renderIntroHtml()); 686 } 687 for (var _i = 0, _a = props.cells; _i < _a.length; _i++) { 688 var cell = _a[_i]; 689 parts.push(renderCellHtml(cell.date, props.dateProfile, this.context, cell.htmlAttrs)); 690 } 691 if (!props.cells.length) { 692 parts.push('<td class="fc-day ' + this.context.theme.getClass('widgetContent') + '"></td>'); 693 } 694 if (this.context.options.dir === 'rtl') { 695 parts.reverse(); 696 } 697 return '<tr>' + parts.join('') + '</tr>'; 698 }; 699 return DayBgRow; 700 }()); 701 function renderCellHtml(date, dateProfile, context, otherAttrs) { 702 var dateEnv = context.dateEnv, theme = context.theme; 703 var isDateValid = core.rangeContainsMarker(dateProfile.activeRange, date); // TODO: called too frequently. cache somehow. 704 var classes = core.getDayClasses(date, dateProfile, context); 705 classes.unshift('fc-day', theme.getClass('widgetContent')); 706 return '<td class="' + classes.join(' ') + '"' + 707 (isDateValid ? 708 ' data-date="' + dateEnv.formatIso(date, { omitTime: true }) + '"' : 709 '') + 710 (otherAttrs ?
711 ' ' + otherAttrs : 712 '') + 713 '></td>'; 714 } 715 716 var DAY_NUM_FORMAT = core.createFormatter({ day: 'numeric' }); 717 var WEEK_NUM_FORMAT = core.createFormatter({ week: 'numeric' }); 718 var DayGrid = /** @class */ (function (_super) { 719 __extends(DayGrid, _super); 720 function DayGrid(context, el, renderProps) { 721 var _this = _super.call(this, context, el) || this; 722 _this.bottomCoordPadding = 0; // hack for extending the hit area for the last row of the coordinate grid 723 _this.isCellSizesDirty = false; 724 var eventRenderer = _this.eventRenderer = new DayGridEventRenderer(_this); 725 var fillRenderer = _this.fillRenderer = new DayGridFillRenderer(_this); 726 _this.mirrorRenderer = new DayGridMirrorRenderer(_this); 727 var renderCells = _this.renderCells = core.memoizeRendering(_this._renderCells, _this._unrenderCells); 728 _this.renderBusinessHours = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'), [renderCells]); 729 _this.renderDateSelection = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'highlight'), fillRenderer.unrender.bind(fillRenderer, 'highlight'), [renderCells]); 730 _this.renderBgEvents = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'), [renderCells]); 731 _this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderCells]); 732 _this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); 733 _this.renderEventDrag = core.memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag, [renderCells]); 734 _this.renderEventResize = core.memoizeRendering(_this._renderEventResize, _this._unrenderEventResize, [renderCells]); 735 _this.renderProps = renderProps; 736 return _this; 737 } 738 DayGrid.prototype.render = function (props) { 739 var cells = props.cells; 740 this.rowCnt = cells.length; 741 this.colCnt = cells[0].length; 742 this.renderCells(cells, props.isRigid); 743 this.renderBusinessHours(props.businessHourSegs); 744 this.renderDateSelection(props.dateSelectionSegs); 745 this.renderBgEvents(props.bgEventSegs); 746 this.renderFgEvents(props.fgEventSegs); 747 this.renderEventSelection(props.eventSelection); 748 this.renderEventDrag(props.eventDrag); 749 this.renderEventResize(props.eventResize); 750 if (this.segPopoverTile) { 751 this.updateSegPopoverTile(); 752 } 753 }; 754 DayGrid.prototype.destroy = function () { 755 _super.prototype.destroy.call(this); 756 this.renderCells.unrender(); // will unrender everything else 757 }; 758 DayGrid.prototype.getCellRange = function (row, col) { 759 var start = this.props.cells[row][col].date; 760 var end = core.addDays(start, 1); 761 return { start: start, end: end }; 762 }; 763 DayGrid.prototype.updateSegPopoverTile = function (date, segs) { 764 var ownProps = this.props; 765 this.segPopoverTile.receiveProps({ 766 date: date || this.segPopoverTile.props.date, 767 fgSegs: segs || this.segPopoverTile.props.fgSegs, 768 eventSelection: ownProps.eventSelection, 769 eventDragInstances: ownProps.eventDrag ? ownProps.eventDrag.affectedInstances : null, 770 eventResizeInstances: ownProps.eventResize ? ownProps.eventResize.affectedInstances : null 771 }); 772 }; 773 /* Date Rendering 774 ------------------------------------------------------------------------------------------------------------------*/ 775 DayGrid.prototype._renderCells = function (cells, isRigid) { 776 var _a = this, view = _a.view, dateEnv = _a.dateEnv; 777 var _b = this, rowCnt = _b.rowCnt, colCnt = _b.colCnt; 778 var html = ''; 779 var row; 780 var col; 781 for (row = 0; row < rowCnt; row++) { 782 html += this.renderDayRowHtml(row, isRigid); 783 } 784 this.el.innerHTML = html; 785 this.rowEls = core.findElements(this.el, '.fc-row'); 786 this.cellEls = core.findElements(this.el, '.fc-day, .fc-disabled-day'); 787 if (this.isRtl) { 788 this.cellEls.reverse(); 789 } 790 this.rowPositions = new core.PositionCache(this.el, this.rowEls, false, true // vertical 791 ); 792 this.colPositions = new core.PositionCache(this.el, this.cellEls.slice(0, colCnt), // only the first row 793 true, false // horizontal 794 ); 795 // trigger dayRender with each cell's element 796 for (row = 0; row < rowCnt; row++) { 797 for (col = 0; col < colCnt; col++) { 798 this.publiclyTrigger('dayRender', [ 799 { 800 date: dateEnv.toDate(cells[row][col].date), 801 el: this.getCellEl(row, col), 802 view: view 803 } 804 ]); 805 } 806 } 807 this.isCellSizesDirty = true; 808 }; 809 DayGrid.prototype._unrenderCells = function () { 810 this.removeSegPopover(); 811 }; 812 // Generates the HTML for a single row, which is a div that wraps a table. 813 // `row` is the row number. 814 DayGrid.prototype.renderDayRowHtml = function (row, isRigid) { 815 var theme = this.theme; 816 var classes = ['fc-row', 'fc-week', theme.getClass('dayRow')]; 817 if (isRigid) { 818 classes.push('fc-rigid'); 819 } 820 var bgRow = new DayBgRow(this.context); 821 return '' + 822 '<div class="' + classes.join(' ') + '">' + 823 '<div class="fc-bg">' + 824 '<table class="' + theme.getClass('tableGrid') + '">' + 825 bgRow.renderHtml({ 826 cells: this.props.cells[row], 827 dateProfile: this.props.dateProfile, 828 renderIntroHtml: this.renderProps.renderBgIntroHtml 829 }) + 830 '</table>' + 831 '</div>' + 832 '<div class="fc-content-skeleton">' + 833 '<table>' + 834 (this.getIsNumbersVisible() ? 835 '<thead>' + 836 this.renderNumberTrHtml(row) + 837 '</thead>' : 838 '') + 839 '</table>' + 840 '</div>' + 841 '</div>'; 842 }; 843 DayGrid.prototype.getIsNumbersVisible = function () { 844 return this.getIsDayNumbersVisible() || 845 this.renderProps.cellWeekNumbersVisible || 846 this.renderProps.colWeekNumbersVisible; 847 }; 848 DayGrid.prototype.getIsDayNumbersVisible = function () { 849 return this.rowCnt > 1; 850 }; 851 /* Grid Number Rendering 852 ------------------------------------------------------------------------------------------------------------------*/ 853 DayGrid.prototype.renderNumberTrHtml = function (row) { 854 var intro = this.renderProps.renderNumberIntroHtml(row, this); 855 return '' + 856 '<tr>' + 857 (this.isRtl ? '' : intro) + 858 this.renderNumberCellsHtml(row) + 859 (this.isRtl ? intro : '') + 860 '</tr>'; 861 }; 862 DayGrid.prototype.renderNumberCellsHtml = function (row) { 863 var htmls = []; 864 var col; 865 var date; 866 for (col = 0; col < this.colCnt; col++) { 867 date = this.props.cells[row][col].date; 868 htmls.push(this.renderNumberCellHtml(date)); 869 } 870 if (this.isRtl) { 871 htmls.reverse(); 872 } 873 return htmls.join(''); 874 }; 875 // Generates the HTML for the <td>s of the "number" row in the DayGrid's content skeleton. 876 // The number row will only exist if either day numbers or week numbers are turned on. 877 DayGrid.prototype.renderNumberCellHtml = function (date) { 878 var _a = this, view = _a.view, dateEnv = _a.dateEnv; 879 var html = ''; 880 var isDateValid = core.rangeContainsMarker(this.props.dateProfile.activeRange, date); // TODO: called too frequently. cache somehow. 881 var isDayNumberVisible = this.getIsDayNumbersVisible() && isDateValid; 882 var classes; 883 var weekCalcFirstDow; 884 if (!isDayNumberVisible && !this.renderProps.cellWeekNumbersVisible) { 885 // no numbers in day cell (week number must be along the side) 886 return '<td></td>'; // will create an empty space above events :( 887 } 888 classes = core.getDayClasses(date, this.props.dateProfile, this.context); 889 classes.unshift('fc-day-top'); 890 if (this.renderProps.cellWeekNumbersVisible) { 891 weekCalcFirstDow = dateEnv.weekDow; 892 } 893 html += '<td class="' + classes.join(' ') + '"' + 894 (isDateValid ? 895 ' data-date="' + dateEnv.formatIso(date, { omitTime: true }) + '"' : 896 '') + 897 '>'; 898 if (this.renderProps.cellWeekNumbersVisible && (date.getUTCDay() === weekCalcFirstDow)) { 899 html += core.buildGotoAnchorHtml(view, { date: date, type: 'week' }, { 'class': 'fc-week-number' }, dateEnv.format(date, WEEK_NUM_FORMAT) // inner HTML 900 ); 901 } 902 if (isDayNumberVisible) { 903 html += core.buildGotoAnchorHtml(view, date, { 'class': 'fc-day-number' }, dateEnv.format(date, DAY_NUM_FORMAT) // inner HTML 904 ); 905 } 906 html += '</td>'; 907 return html; 908 }; 909 /* Sizing 910 ------------------------------------------------------------------------------------------------------------------*/ 911 DayGrid.prototype.updateSize = function (isResize) { 912 var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer; 913 if (isResize || 914 this.isCellSizesDirty || 915 this.view.calendar.isEventsUpdated // hack 916 ) { 917 this.buildPositionCaches(); 918 this.isCellSizesDirty = false;
919 } 920 fillRenderer.computeSizes(isResize); 921 eventRenderer.computeSizes(isResize); 922 mirrorRenderer.computeSizes(isResize); 923 fillRenderer.assignSizes(isResize); 924 eventRenderer.assignSizes(isResize); 925 mirrorRenderer.assignSizes(isResize); 926 }; 927 DayGrid.prototype.buildPositionCaches = function () { 928 this.buildColPositions(); 929 this.buildRowPositions(); 930 }; 931 DayGrid.prototype.buildColPositions = function () { 932 this.colPositions.build(); 933 }; 934 DayGrid.prototype.buildRowPositions = function () { 935 this.rowPositions.build(); 936 this.rowPositions.bottoms[this.rowCnt - 1] += this.bottomCoordPadding; // hack 937 }; 938 /* Hit System 939 ------------------------------------------------------------------------------------------------------------------*/ 940 DayGrid.prototype.positionToHit = function (leftPosition, topPosition) { 941 var _a = this, colPositions = _a.colPositions, rowPositions = _a.rowPositions; 942 var col = colPositions.leftToIndex(leftPosition); 943 var row = rowPositions.topToIndex(topPosition); 944 if (row != null && col != null) { 945 return { 946 row: row, 947 col: col, 948 dateSpan: { 949 range: this.getCellRange(row, col), 950 allDay: true 951 }, 952 dayEl: this.getCellEl(row, col), 953 relativeRect: { 954 left: colPositions.lefts[col], 955 right: colPositions.rights[col], 956 top: rowPositions.tops[row], 957 bottom: rowPositions.bottoms[row] 958 } 959 }; 960 } 961 }; 962 /* Cell System 963 ------------------------------------------------------------------------------------------------------------------*/ 964 // FYI: the first column is the leftmost column, regardless of date 965 DayGrid.prototype.getCellEl = function (row, col) { 966 return this.cellEls[row * this.colCnt + col]; 967 }; 968 /* Event Drag Visualization 969 ------------------------------------------------------------------------------------------------------------------*/ 970 DayGrid.prototype._renderEventDrag = function (state) { 971 if (state) { 972 this.eventRenderer.hideByHash(state.affectedInstances); 973 this.fillRenderer.renderSegs('highlight', state.segs); 974 } 975 }; 976 DayGrid.prototype._unrenderEventDrag = function (state) { 977 if (state) { 978 this.eventRenderer.showByHash(state.affectedInstances); 979 this.fillRenderer.unrender('highlight'); 980 } 981 }; 982 /* Event Resize Visualization 983 ------------------------------------------------------------------------------------------------------------------*/ 984 DayGrid.prototype._renderEventResize = function (state) { 985 if (state) { 986 this.eventRenderer.hideByHash(state.affectedInstances); 987 this.fillRenderer.renderSegs('highlight', state.segs); 988 this.mirrorRenderer.renderSegs(state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 989 } 990 }; 991 DayGrid.prototype._unrenderEventResize = function (state) { 992 if (state) { 993 this.eventRenderer.showByHash(state.affectedInstances); 994 this.fillRenderer.unrender('highlight'); 995 this.mirrorRenderer.unrender(state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 996 } 997 }; 998 /* More+ Link Popover 999 ------------------------------------------------------------------------------------------------------------------*/ 1000 DayGrid.prototype.removeSegPopover = function () { 1001 if (this.segPopover) { 1002 this.segPopover.hide(); // in handler, will call segPopover's removeElement 1003 } 1004 }; 1005 // Limits the number of "levels" (vertically stacking layers of events) for each row of the grid. 1006 // `levelLimit` can be false (don't limit), a number, or true (should be computed). 1007 DayGrid.prototype.limitRows = function (levelLimit) { 1008 var rowStructs = this.eventRenderer.rowStructs || []; 1009 var row; // row # 1010 var rowLevelLimit; 1011 for (row = 0; row < rowStructs.length; row++) { 1012 this.unlimitRow(row); 1013 if (!levelLimit) { 1014 rowLevelLimit = false;
1015 } 1016 else if (typeof levelLimit === 'number') { 1017 rowLevelLimit = levelLimit; 1018 } 1019 else { 1020 rowLevelLimit = this.computeRowLevelLimit(row); 1021 } 1022 if (rowLevelLimit !== false) { 1023 this.limitRow(row, rowLevelLimit); 1024 } 1025 } 1026 }; 1027 // Computes the number of levels a row will accomodate without going outside its bounds. 1028 // Assumes the row is "rigid" (maintains a constant height regardless of what is inside). 1029 // `row` is the row number. 1030 DayGrid.prototype.computeRowLevelLimit = function (row) { 1031 var rowEl = this.rowEls[row]; // the containing "fake" row div 1032 var rowBottom = rowEl.getBoundingClientRect().bottom; // relative to viewport! 1033 var trEls = core.findChildren(this.eventRenderer.rowStructs[row].tbodyEl); 1034 var i; 1035 var trEl; 1036 // Reveal one level <tr> at a time and stop when we find one out of bounds 1037 for (i = 0; i < trEls.length; i++) { 1038 trEl = trEls[i]; 1039 trEl.classList.remove('fc-limited'); // reset to original state (reveal) 1040 if (trEl.getBoundingClientRect().bottom > rowBottom) { 1041 return i; 1042 } 1043 } 1044 return false; // should not limit at all 1045 }; 1046 // Limits the given grid row to the maximum number of levels and injects "more" links if necessary. 1047 // `row` is the row number. 1048 // `levelLimit` is a number for the maximum (inclusive) number of levels allowed. 1049 DayGrid.prototype.limitRow = function (row, levelLimit) { 1050 var _this = this; 1051 var _a = this, colCnt = _a.colCnt, isRtl = _a.isRtl; 1052 var rowStruct = this.eventRenderer.rowStructs[row]; 1053 var moreNodes = []; // array of "more" <a> links and <td> DOM nodes 1054 var col = 0; // col #, left-to-right (not chronologically) 1055 var levelSegs; // array of segment objects in the last allowable level, ordered left-to-right 1056 var cellMatrix; // a matrix (by level, then column) of all <td> elements in the row 1057 var limitedNodes; // array of temporarily hidden level <tr> and segment <td> DOM nodes 1058 var i; 1059 var seg; 1060 var segsBelow; // array of segment objects below `seg` in the current `col` 1061 var totalSegsBelow; // total number of segments below `seg` in any of the columns `seg` occupies 1062 var colSegsBelow; // array of segment arrays, below seg, one for each column (offset from segs's first column) 1063 var td; 1064 var rowSpan; 1065 var segMoreNodes; // array of "more" <td> cells that will stand-in for the current seg's cell 1066 var j; 1067 var moreTd; 1068 var moreWrap; 1069 var moreLink; 1070 // Iterates through empty level cells and places "more" links inside if need be 1071 var emptyCellsUntil = function (endCol) { 1072 while (col < endCol) { 1073 segsBelow = _this.getCellSegs(row, col, levelLimit); 1074 if (segsBelow.length) { 1075 td = cellMatrix[levelLimit - 1][col]; 1076 moreLink = _this.renderMoreLink(row, col, segsBelow); 1077 moreWrap = core.createElement('div', null, moreLink); 1078 td.appendChild(moreWrap); 1079 moreNodes.push(moreWrap); 1080 } 1081 col++; 1082 } 1083 }; 1084 if (levelLimit && levelLimit < rowStruct.segLevels.length) { // is it actually over the limit? 1085 levelSegs = rowStruct.segLevels[levelLimit - 1]; 1086 cellMatrix = rowStruct.cellMatrix; 1087 limitedNodes = core.findChildren(rowStruct.tbodyEl).slice(levelLimit); // get level <tr> elements past the limit 1088 limitedNodes.forEach(function (node) { 1089 node.classList.add('fc-limited'); // hide elements and get a simple DOM-nodes array 1090 }); 1091 // iterate though segments in the last allowable level 1092 for (i = 0; i < levelSegs.length; i++) { 1093 seg = levelSegs[i]; 1094 var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; 1095 var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; 1096 emptyCellsUntil(leftCol); // process empty cells before the segment 1097 // determine *all* segments below `seg` that occupy the same columns 1098 colSegsBelow = []; 1099 totalSegsBelow = 0; 1100 while (col <= rightCol) { 1101 segsBelow = this.getCellSegs(row, col, levelLimit); 1102 colSegsBelow.push(segsBelow); 1103 totalSegsBelow += segsBelow.length; 1104 col++; 1105 } 1106 if (totalSegsBelow) { // do we need to replace this segment with one or many "more" links? 1107 td = cellMatrix[levelLimit - 1][leftCol]; // the segment's parent cell 1108 rowSpan = td.rowSpan || 1; 1109 segMoreNodes = []; 1110 // make a replacement <td> for each column the segment occupies. will be one for each colspan 1111 for (j = 0; j < colSegsBelow.length; j++) { 1112 moreTd = core.createElement('td', { className: 'fc-more-cell', rowSpan: rowSpan }); 1113 segsBelow = colSegsBelow[j]; 1114 moreLink = this.renderMoreLink(row, leftCol + j, [seg].concat(segsBelow) // count seg as hidden too 1115 ); 1116 moreWrap = core.createElement('div', null, moreLink); 1117 moreTd.appendChild(moreWrap); 1118 segMoreNodes.push(moreTd); 1119 moreNodes.push(moreTd); 1120 } 1121 td.classList.add('fc-limited'); 1122 core.insertAfterElement(td, segMoreNodes); 1123 limitedNodes.push(td); 1124 } 1125 } 1126 emptyCellsUntil(this.colCnt); // finish off the level 1127 rowStruct.moreEls = moreNodes; // for easy undoing later 1128 rowStruct.limitedEls = limitedNodes; // for easy undoing later 1129 } 1130 }; 1131 // Reveals all levels and removes all "more"-related elements for a grid's row. 1132 // `row` is a row number. 1133 DayGrid.prototype.unlimitRow = function (row) { 1134 var rowStruct = this.eventRenderer.rowStructs[row]; 1135 if (rowStruct.moreEls) {
1136 rowStruct.moreEls.forEach(core.removeElement); 1137 rowStruct.moreEls = null; 1138 } 1139 if (rowStruct.limitedEls) { 1140 rowStruct.limitedEls.forEach(function (limitedEl) { 1141 limitedEl.classList.remove('fc-limited'); 1142 }); 1143 rowStruct.limitedEls = null; 1144 } 1145 }; 1146 // Renders an <a> element that represents hidden event element for a cell. 1147 // Responsible for attaching click handler as well. 1148 DayGrid.prototype.renderMoreLink = function (row, col, hiddenSegs) { 1149 var _this = this; 1150 var _a = this, view = _a.view, dateEnv = _a.dateEnv; 1151 var a = core.createElement('a', { className: 'fc-more' }); 1152 a.innerText = this.getMoreLinkText(hiddenSegs.length); 1153 a.addEventListener('click', function (ev) { 1154 var clickOption = _this.opt('eventLimitClick'); 1155 var _col = _this.isRtl ? _this.colCnt - col - 1 : col; // HACK: props.cells has different dir system? 1156 var date = _this.props.cells[row][_col].date; 1157 var moreEl = ev.currentTarget; 1158 var dayEl = _this.getCellEl(row, col); 1159 var allSegs = _this.getCellSegs(row, col); 1160 // rescope the segments to be within the cell's date 1161 var reslicedAllSegs = _this.resliceDaySegs(allSegs, date); 1162 var reslicedHiddenSegs = _this.resliceDaySegs(hiddenSegs, date); 1163 if (typeof clickOption === 'function') { 1164 // the returned value can be an atomic option 1165 clickOption = _this.publiclyTrigger('eventLimitClick', [ 1166 { 1167 date: dateEnv.toDate(date), 1168 allDay: true, 1169 dayEl: dayEl, 1170 moreEl: moreEl, 1171 segs: reslicedAllSegs, 1172 hiddenSegs: reslicedHiddenSegs, 1173 jsEvent: ev, 1174 view: view 1175 } 1176 ]); 1177 } 1178 if (clickOption === 'popover') { 1179 _this.showSegPopover(row, col, moreEl, reslicedAllSegs); 1180 } 1181 else if (typeof clickOption === 'string') { // a view name 1182 view.calendar.zoomTo(date, clickOption); 1183 } 1184 }); 1185 return a; 1186 }; 1187 // Reveals the popover that displays all events within a cell 1188 DayGrid.prototype.showSegPopover = function (row, col, moreLink, segs) { 1189 var _this = this; 1190 var _a = this, calendar = _a.calendar, view = _a.view, theme = _a.theme; 1191 var _col = this.isRtl ? this.colCnt - col - 1 : col; // HACK: props.cells has different dir system? 1192 var moreWrap = moreLink.parentNode; // the <div> wrapper around the <a> 1193 var topEl; // the element we want to match the top coordinate of 1194 var options; 1195 if (this.rowCnt === 1) { 1196 topEl = view.el; // will cause the popover to cover any sort of header 1197 } 1198 else { 1199 topEl = this.rowEls[row]; // will align with top of row 1200 } 1201 options = { 1202 className: 'fc-more-popover ' + theme.getClass('popover'), 1203 parentEl: view.el, 1204 top: core.computeRect(topEl).top, 1205 autoHide: true, 1206 content: function (el) { 1207 _this.segPopoverTile = new DayTile(_this.context, el); 1208 _this.updateSegPopoverTile(_this.props.cells[row][_col].date, segs); 1209 }, 1210 hide: function () { 1211 _this.segPopoverTile.destroy(); 1212 _this.segPopoverTile = null; 1213 _this.segPopover.destroy(); 1214 _this.segPopover = null; 1215 } 1216 }; 1217 // Determine horizontal coordinate. 1218 // We use the moreWrap instead of the <td> to avoid border confusion. 1219 if (this.isRtl) { 1220 options.right = core.computeRect(moreWrap).right + 1; // +1 to be over cell border 1221 } 1222 else { 1223 options.left = core.computeRect(moreWrap).left - 1; // -1 to be over cell border 1224 } 1225 this.segPopover = new Popover(options); 1226 this.segPopover.show(); 1227 calendar.releaseAfterSizingTriggers(); // hack for eventPositioned 1228 }; 1229 // Given the events within an array of segment objects, reslice them to be in a single day
1230 DayGrid.prototype.resliceDaySegs = function (segs, dayDate) { 1231 var dayStart = dayDate; 1232 var dayEnd = core.addDays(dayStart, 1); 1233 var dayRange = { start: dayStart, end: dayEnd }; 1234 var newSegs = []; 1235 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 1236 var seg = segs_1[_i]; 1237 var eventRange = seg.eventRange; 1238 var origRange = eventRange.range; 1239 var slicedRange = core.intersectRanges(origRange, dayRange); 1240 if (slicedRange) { 1241 newSegs.push(__assign({}, seg, { eventRange: { 1242 def: eventRange.def, 1243 ui: __assign({}, eventRange.ui, { durationEditable: false }), 1244 instance: eventRange.instance, 1245 range: slicedRange 1246 }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() })); 1247 } 1248 } 1249 return newSegs; 1250 }; 1251 // Generates the text that should be inside a "more" link, given the number of events it represents 1252 DayGrid.prototype.getMoreLinkText = function (num) { 1253 var opt = this.opt('eventLimitText'); 1254 if (typeof opt === 'function') { 1255 return opt(num); 1256 } 1257 else { 1258 return '+' + num + ' ' + opt; 1259 } 1260 }; 1261 // Returns segments within a given cell. 1262 // If `startLevel` is specified, returns only events including and below that level. Otherwise returns all segs. 1263 DayGrid.prototype.getCellSegs = function (row, col, startLevel) { 1264 var segMatrix = this.eventRenderer.rowStructs[row].segMatrix; 1265 var level = startLevel || 0; 1266 var segs = []; 1267 var seg; 1268 while (level < segMatrix.length) { 1269 seg = segMatrix[level][col]; 1270 if (seg) { 1271 segs.push(seg); 1272 } 1273 level++; 1274 } 1275 return segs; 1276 }; 1277 return DayGrid; 1278 }(core.DateComponent)); 1279 1280 var WEEK_NUM_FORMAT$1 = core.createFormatter({ week: 'numeric' }); 1281 /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells. 1282 ----------------------------------------------------------------------------------------------------------------------*/ 1283 // It is a manager for a DayGrid subcomponent, which does most of the heavy lifting. 1284 // It is responsible for managing width/height. 1285 var DayGridView = /** @class */ (function (_super) { 1286 __extends(DayGridView, _super); 1287 function DayGridView(context, viewSpec, dateProfileGenerator, parentEl) { 1288 var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this; 1289 /* Header Rendering 1290 ------------------------------------------------------------------------------------------------------------------*/ 1291 // Generates the HTML that will go before the day-of week header cells 1292 _this.renderHeadIntroHtml = function () { 1293 var theme = _this.theme; 1294 if (_this.colWeekNumbersVisible) { 1295 return '' + 1296 '<th class="fc-week-number ' + theme.getClass('widgetHeader') + '" ' + _this.weekNumberStyleAttr() + '>' + 1297 '<span>' + // needed for matchCellWidths 1298 core.htmlEscape(_this.opt('weekLabel')) + 1299 '</span>' + 1300 '</th>'; 1301 } 1302 return ''; 1303 }; 1304 /* Day Grid Rendering 1305 ------------------------------------------------------------------------------------------------------------------*/ 1306 // Generates the HTML that will go before content-skeleton cells that display the day/week numbers 1307 _this.renderDayGridNumberIntroHtml = function (row, dayGrid) { 1308 var dateEnv = _this.dateEnv; 1309 var weekStart = dayGrid.props.cells[row][0].date; 1310 if (_this.colWeekNumbersVisible) { 1311 return '' + 1312 '<td class="fc-week-number" ' + _this.weekNumberStyleAttr() + '>' + 1313 core.buildGotoAnchorHtml(// aside from link, important for matchCellWidths 1314 _this, { date: weekStart, type: 'week', forceOff: dayGrid.colCnt === 1 }, dateEnv.format(weekStart, WEEK_NUM_FORMAT$1) // inner HTML 1315 ) + 1316 '</td>'; 1317 } 1318 return ''; 1319 }; 1320 // Generates the HTML that goes before the day bg cells for each day-row 1321 _this.renderDayGridBgIntroHtml = function () { 1322 var theme = _this.theme; 1323 if (_this.colWeekNumbersVisible) { 1324 return '<td class="fc-week-number ' + theme.getClass('widgetContent') + '" ' + _this.weekNumberStyleAttr() + '></td>'; 1325 } 1326 return ''; 1327 }; 1328 // Generates the HTML that goes before every other type of row generated by DayGrid. 1329 // Affects mirror-skeleton and highlight-skeleton rows. 1330 _this.renderDayGridIntroHtml = function () { 1331 if (_this.colWeekNumbersVisible) { 1332 return '<td class="fc-week-number" ' + _this.weekNumberStyleAttr() + '></td>'; 1333 } 1334 return ''; 1335 }; 1336 _this.el.classList.add('fc-dayGrid-view'); 1337 _this.el.innerHTML = _this.renderSkeletonHtml();
1338 _this.scroller = new core.ScrollComponent('hidden', // overflow x 1339 'auto' // overflow y 1340 ); 1341 var dayGridContainerEl = _this.scroller.el; 1342 _this.el.querySelector('.fc-body > tr > td').appendChild(dayGridContainerEl); 1343 dayGridContainerEl.classList.add('fc-day-grid-container'); 1344 var dayGridEl = core.createElement('div', { className: 'fc-day-grid' }); 1345 dayGridContainerEl.appendChild(dayGridEl); 1346 var cellWeekNumbersVisible; 1347 if (_this.opt('weekNumbers')) { 1348 if (_this.opt('weekNumbersWithinDays')) { 1349 cellWeekNumbersVisible = true; 1350 _this.colWeekNumbersVisible = false; 1351 } 1352 else { 1353 cellWeekNumbersVisible = false; 1354 _this.colWeekNumbersVisible = true; 1355 } 1356 } 1357 else { 1358 _this.colWeekNumbersVisible = false; 1359 cellWeekNumbersVisible = false; 1360 } 1361 _this.dayGrid = new DayGrid(_this.context, dayGridEl, { 1362 renderNumberIntroHtml: _this.renderDayGridNumberIntroHtml, 1363 renderBgIntroHtml: _this.renderDayGridBgIntroHtml, 1364 renderIntroHtml: _this.renderDayGridIntroHtml, 1365 colWeekNumbersVisible: _this.colWeekNumbersVisible, 1366 cellWeekNumbersVisible: cellWeekNumbersVisible 1367 }); 1368 return _this; 1369 } 1370 DayGridView.prototype.destroy = function () { 1371 _super.prototype.destroy.call(this); 1372 this.dayGrid.destroy(); 1373 this.scroller.destroy(); 1374 }; 1375 // Builds the HTML skeleton for the view. 1376 // The day-grid component will render inside of a container defined by this HTML. 1377 DayGridView.prototype.renderSkeletonHtml = function () { 1378 var theme = this.theme; 1379 return '' + 1380 '<table class="' + theme.getClass('tableGrid') + '">' + 1381 (this.opt('columnHeader') ? 1382 '<thead class="fc-head">' + 1383 '<tr>' + 1384 '<td class="fc-head-container ' + theme.getClass('widgetHeader') + '"> </td>' + 1385 '</tr>' + 1386 '</thead>' : 1387 '') + 1388 '<tbody class="fc-body">' + 1389 '<tr>' + 1390 '<td class="' + theme.getClass('widgetContent') + '"></td>' + 1391 '</tr>' + 1392 '</tbody>' + 1393 '</table>'; 1394 }; 1395 // Generates an HTML attribute string for setting the width of the week number column, if it is known 1396 DayGridView.prototype.weekNumberStyleAttr = function () { 1397 if (this.weekNumberWidth != null) { 1398 return 'style="width:' + this.weekNumberWidth + 'px"'; 1399 } 1400 return ''; 1401 }; 1402 // Determines whether each row should have a constant height 1403 DayGridView.prototype.hasRigidRows = function () { 1404 var eventLimit = this.opt('eventLimit'); 1405 return eventLimit && typeof eventLimit !== 'number'; 1406 }; 1407 /* Dimensions 1408 ------------------------------------------------------------------------------------------------------------------*/ 1409 DayGridView.prototype.updateSize = function (isResize, viewHeight, isAuto) { 1410 _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto); // will call updateBaseSize. important that executes first 1411 this.dayGrid.updateSize(isResize); 1412 }; 1413 // Refreshes the horizontal dimensions of the view 1414 DayGridView.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) { 1415 var dayGrid = this.dayGrid; 1416 var eventLimit = this.opt('eventLimit'); 1417 var headRowEl = this.header ? this.header.el : null; // HACK 1418 var scrollerHeight; 1419 var scrollbarWidths; 1420 // hack to give the view some height prior to dayGrid's columns being rendered 1421 // TODO: separate setting height from scroller VS dayGrid. 1422 if (!dayGrid.rowEls) { 1423 if (!isAuto) { 1424 scrollerHeight = this.computeScrollerHeight(viewHeight); 1425 this.scroller.setHeight(scrollerHeight); 1426 } 1427 return; 1428 } 1429 if (this.colWeekNumbersVisible) { 1430 // Make sure all week number cells running down the side have the same width. 1431 this.weekNumberWidth = core.matchCellWidths(core.findElements(this.el, '.fc-week-number')); 1432 } 1433 // reset all heights to be natural 1434 this.scroller.clear(); 1435 if (headRowEl) { 1436 core.uncompensateScroll(headRowEl); 1437 } 1438 dayGrid.removeSegPopover(); // kill the "more" popover if displayed 1439 // is the event limit a constant level number? 1440 if (eventLimit && typeof eventLimit === 'number') { 1441 dayGrid.limitRows(eventLimit); // limit the levels first so the height can redistribute after 1442 } 1443 // distribute the height to the rows 1444 // (viewHeight is a "recommended" value if isAuto) 1445 scrollerHeight = this.computeScrollerHeight(viewHeight); 1446 this.setGridHeight(scrollerHeight, isAuto); 1447 // is the event limit dynamically calculated? 1448 if (eventLimit && typeof eventLimit !== 'number') { 1449 dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set 1450 } 1451 if (!isAuto) { // should we force dimensions of the scroll container? 1452 this.scroller.setHeight(scrollerHeight);
1453 scrollbarWidths = this.scroller.getScrollbarWidths(); 1454 if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars? 1455 if (headRowEl) { 1456 core.compensateScroll(headRowEl, scrollbarWidths); 1457 } 1458 // doing the scrollbar compensation might have created text overflow which created more height. redo 1459 scrollerHeight = this.computeScrollerHeight(viewHeight); 1460 this.scroller.setHeight(scrollerHeight); 1461 } 1462 // guarantees the same scrollbar widths 1463 this.scroller.lockOverflow(scrollbarWidths); 1464 } 1465 }; 1466 // given a desired total height of the view, returns what the height of the scroller should be 1467 DayGridView.prototype.computeScrollerHeight = function (viewHeight) { 1468 return viewHeight - 1469 core.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller 1470 }; 1471 // Sets the height of just the DayGrid component in this view 1472 DayGridView.prototype.setGridHeight = function (height, isAuto) { 1473 if (this.opt('monthMode')) { 1474 // if auto, make the height of each row the height that it would be if there were 6 weeks 1475 if (isAuto) { 1476 height *= this.dayGrid.rowCnt / 6; 1477 } 1478 core.distributeHeight(this.dayGrid.rowEls, height, !isAuto); // if auto, don't compensate for height-hogging rows 1479 } 1480 else { 1481 if (isAuto) { 1482 core.undistributeHeight(this.dayGrid.rowEls); // let the rows be their natural height with no expanding 1483 } 1484 else { 1485 core.distributeHeight(this.dayGrid.rowEls, height, true); // true = compensate for height-hogging rows 1486 } 1487 } 1488 }; 1489 /* Scroll 1490 ------------------------------------------------------------------------------------------------------------------*/ 1491 DayGridView.prototype.computeDateScroll = function (duration) { 1492 return { top: 0 }; 1493 }; 1494 DayGridView.prototype.queryDateScroll = function () { 1495 return { top: this.scroller.getScrollTop() }; 1496 }; 1497 DayGridView.prototype.applyDateScroll = function (scroll) { 1498 if (scroll.top !== undefined) { 1499 this.scroller.setScrollTop(scroll.top); 1500 } 1501 }; 1502 return DayGridView; 1503 }(core.View)); 1504 DayGridView.prototype.dateProfileGeneratorClass = DayGridDateProfileGenerator; 1505 1506 var SimpleDayGrid = /** @class */ (function (_super) { 1507 __extends(SimpleDayGrid, _super); 1508 function SimpleDayGrid(context, dayGrid) { 1509 var _this = _super.call(this, context, dayGrid.el) || this; 1510 _this.slicer = new DayGridSlicer(); 1511 _this.dayGrid = dayGrid; 1512 context.calendar.registerInteractiveComponent(_this, { el: _this.dayGrid.el }); 1513 return _this; 1514 } 1515 SimpleDayGrid.prototype.destroy = function () { 1516 _super.prototype.destroy.call(this); 1517 this.calendar.unregisterInteractiveComponent(this); 1518 }; 1519 SimpleDayGrid.prototype.render = function (props) { 1520 var dayGrid = this.dayGrid; 1521 var dateProfile = props.dateProfile, dayTable = props.dayTable; 1522 dayGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, props.nextDayThreshold, dayGrid, dayTable), { dateProfile: dateProfile, cells: dayTable.cells, isRigid: props.isRigid })); 1523 }; 1524 SimpleDayGrid.prototype.buildPositionCaches = function () { 1525 this.dayGrid.buildPositionCaches(); 1526 }; 1527 SimpleDayGrid.prototype.queryHit = function (positionLeft, positionTop) { 1528 var rawHit = this.dayGrid.positionToHit(positionLeft, positionTop); 1529 if (rawHit) { 1530 return { 1531 component: this.dayGrid, 1532 dateSpan: rawHit.dateSpan, 1533 dayEl: rawHit.dayEl, 1534 rect: { 1535 left: rawHit.relativeRect.left, 1536 right: rawHit.relativeRect.right, 1537 top: rawHit.relativeRect.top, 1538 bottom: rawHit.relativeRect.bottom 1539 }, 1540 layer: 0 1541 }; 1542 } 1543 }; 1544 return SimpleDayGrid; 1545 }(core.DateComponent));
1546 var DayGridSlicer = /** @class */ (function (_super) { 1547 __extends(DayGridSlicer, _super); 1548 function DayGridSlicer() { 1549 return _super !== null && _super.apply(this, arguments) || this; 1550 } 1551 DayGridSlicer.prototype.sliceRange = function (dateRange, dayTable) { 1552 return dayTable.sliceRange(dateRange); 1553 }; 1554 return DayGridSlicer; 1555 }(core.Slicer)); 1556 1557 var DayGridView$1 = /** @class */ (function (_super) { 1558 __extends(DayGridView, _super); 1559 function DayGridView(_context, viewSpec, dateProfileGenerator, parentEl) { 1560 var _this = _super.call(this, _context, viewSpec, dateProfileGenerator, parentEl) || this; 1561 _this.buildDayTable = core.memoize(buildDayTable); 1562 if (_this.opt('columnHeader')) { 1563 _this.header = new core.DayHeader(_this.context, _this.el.querySelector('.fc-head-container')); 1564 } 1565 _this.simpleDayGrid = new SimpleDayGrid(_this.context, _this.dayGrid); 1566 return _this; 1567 } 1568 DayGridView.prototype.destroy = function () { 1569 _super.prototype.destroy.call(this); 1570 if (this.header) { 1571 this.header.destroy(); 1572 } 1573 this.simpleDayGrid.destroy(); 1574 }; 1575 DayGridView.prototype.render = function (props) { 1576 _super.prototype.render.call(this, props); 1577 var dateProfile = this.props.dateProfile; 1578 var dayTable = this.dayTable = 1579 this.buildDayTable(dateProfile, this.dateProfileGenerator); 1580 if (this.header) { 1581 this.header.receiveProps({ 1582 dateProfile: dateProfile, 1583 dates: dayTable.headerDates, 1584 datesRepDistinctDays: dayTable.rowCnt === 1, 1585 renderIntroHtml: this.renderHeadIntroHtml 1586 }); 1587 } 1588 this.simpleDayGrid.receiveProps({ 1589 dateProfile: dateProfile, 1590 dayTable: dayTable, 1591 businessHours: props.businessHours, 1592 dateSelection: props.dateSelection, 1593 eventStore: props.eventStore, 1594 eventUiBases: props.eventUiBases, 1595 eventSelection: props.eventSelection, 1596 eventDrag: props.eventDrag, 1597 eventResize: props.eventResize, 1598 isRigid: this.hasRigidRows(), 1599 nextDayThreshold: this.nextDayThreshold 1600 }); 1601 }; 1602 return DayGridView; 1603 }(DayGridView)); 1604 function buildDayTable(dateProfile, dateProfileGenerator) { 1605 var daySeries = new core.DaySeries(dateProfile.renderRange, dateProfileGenerator); 1606 return new core.DayTable(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit)); 1607 } 1608 1609 var main = core.createPlugin({ 1610 defaultView: 'dayGridMonth', 1611 views: { 1612 dayGrid: DayGridView$1, 1613 dayGridDay: { 1614 type: 'dayGrid', 1615 duration: { days: 1 } 1616 }, 1617 dayGridWeek: { 1618 type: 'dayGrid', 1619 duration: { weeks: 1 } 1620 }, 1621 dayGridMonth: { 1622 type: 'dayGrid', 1623 duration: { months: 1 }, 1624 monthMode: true, 1625 fixedWeekCount: true 1626 } 1627 } 1628 }); 1629 1630 exports.AbstractDayGridView = DayGridView; 1631 exports.DayBgRow = DayBgRow; 1632 exports.DayGrid = DayGrid; 1633 exports.DayGridSlicer = DayGridSlicer; 1634 exports.DayGridView = DayGridView$1; 1635 exports.SimpleDayGrid = SimpleDayGrid; 1636 exports.buildBasicDayTable = buildDayTable; 1637 exports.default = main; 1638 1639 Object.defineProperty(exports, '__esModule', { value: true }); 1640 1641}));
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.