1/*! 2FullCalendar Core Package v4.3.1 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) : 9 typeof define === 'function' && define.amd ? define(['exports'], factory) : 10 (global = global || self, factory(global.FullCalendar = {})); 11}(this, function (exports) { 'use strict'; 12 13 // Creating 14 // ---------------------------------------------------------------------------------------------------------------- 15 var elementPropHash = { 16 className: true, 17 colSpan: true, 18 rowSpan: true 19 }; 20 var containerTagHash = { 21 '<tr': 'tbody', 22 '<td': 'tr' 23 }; 24 function createElement(tagName, attrs, content) { 25 var el = document.createElement(tagName); 26 if (attrs) { 27 for (var attrName in attrs) { 28 if (attrName === 'style') { 29 applyStyle(el, attrs[attrName]); 30 } 31 else if (elementPropHash[attrName]) { 32 el[attrName] = attrs[attrName]; 33 } 34 else { 35 el.setAttribute(attrName, attrs[attrName]); 36 } 37 } 38 } 39 if (typeof content === 'string') { 40 el.innerHTML = content; // shortcut. no need to process HTML in any way 41 } 42 else if (content != null) { 43 appendToElement(el, content); 44 } 45 return el; 46 } 47 function htmlToElement(html) { 48 html = html.trim(); 49 var container = document.createElement(computeContainerTag(html)); 50 container.innerHTML = html; 51 return container.firstChild; 52 } 53 function htmlToElements(html) { 54 return Array.prototype.slice.call(htmlToNodeList(html)); 55 } 56 function htmlToNodeList(html) { 57 html = html.trim(); 58 var container = document.createElement(computeContainerTag(html)); 59 container.innerHTML = html; 60 return container.childNodes; 61 } 62 // assumes html already trimmed and tag names are lowercase 63 function computeContainerTag(html) { 64 return containerTagHash[html.substr(0, 3) // faster than using regex 65 ] || 'div'; 66 } 67 function appendToElement(el, content) { 68 var childNodes = normalizeContent(content); 69 for (var i = 0; i < childNodes.length; i++) { 70 el.appendChild(childNodes[i]); 71 } 72 } 73 function prependToElement(parent, content) { 74 var newEls = normalizeContent(content); 75 var afterEl = parent.firstChild || null; // if no firstChild, will append to end, but that's okay, b/c there were no children 76 for (var i = 0; i < newEls.length; i++) { 77 parent.insertBefore(newEls[i], afterEl); 78 } 79 } 80 function insertAfterElement(refEl, content) { 81 var newEls = normalizeContent(content); 82 var afterEl = refEl.nextSibling || null; 83 for (var i = 0; i < newEls.length; i++) { 84 refEl.parentNode.insertBefore(newEls[i], afterEl); 85 } 86 } 87 function normalizeContent(content) { 88 var els; 89 if (typeof content === 'string') { 90 els = htmlToElements(content); 91 } 92 else if (content instanceof Node) { 93 els = [content]; 94 } 95 else { // Node[] or NodeList 96 els = Array.prototype.slice.call(content); 97 } 98 return els; 99 } 100 function removeElement(el) { 101 if (el.parentNode) { 102 el.parentNode.removeChild(el); 103 } 104 } 105 // Querying 106 // ---------------------------------------------------------------------------------------------------------------- 107 // from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest 108 var matchesMethod = Element.prototype.matches || 109 Element.prototype.matchesSelector || 110 Element.prototype.msMatchesSelector; 111 var closestMethod = Element.prototype.closest || function (selector) { 112 // polyfill 113 var el = this; 114 if (!document.documentElement.contains(el)) { 115 return null; 116 } 117 do { 118 if (elementMatches(el, selector)) { 119 return el; 120 } 121 el = el.parentElement || el.parentNode; 122 } while (el !== null && el.nodeType === 1); 123 return null; 124 }; 125 function elementClosest(el, selector) { 126 return closestMethod.call(el, selector); 127 } 128 function elementMatches(el, selector) { 129 return matchesMethod.call(el, selector); 130 } 131 // accepts multiple subject els 132 // returns a real array. good for methods like forEach 133 function findElements(container, selector) { 134 var containers = container instanceof HTMLElement ? [container] : container; 135 var allMatches = []; 136 for (var i = 0; i < containers.length; i++) { 137 var matches = containers[i].querySelectorAll(selector); 138 for (var j = 0; j < matches.length; j++) { 139 allMatches.push(matches[j]); 140 } 141 } 142 return allMatches; 143 } 144 // accepts multiple subject els 145 // only queries direct child elements 146 function findChildren(parent, selector) { 147 var parents = parent instanceof HTMLElement ? [parent] : parent; 148 var allMatches = []; 149 for (var i = 0; i < parents.length; i++) { 150 var childNodes = parents[i].children; // only ever elements 151 for (var j = 0; j < childNodes.length; j++) { 152 var childNode = childNodes[j]; 153 if (!selector || elementMatches(childNode, selector)) { 154 allMatches.push(childNode); 155 } 156 } 157 } 158 return allMatches; 159 } 160 // Attributes 161 // ---------------------------------------------------------------------------------------------------------------- 162 function forceClassName(el, className, bool) { 163 if (bool) { 164 el.classList.add(className); 165 } 166 else { 167 el.classList.remove(className); 168 } 169 } 170 // Style 171 // ---------------------------------------------------------------------------------------------------------------- 172 var PIXEL_PROP_RE = /(top|left|right|bottom|width|height)$/i; 173 function applyStyle(el, props) { 174 for (var propName in props) { 175 applyStyleProp(el, propName, props[propName]); 176 } 177 } 178 function applyStyleProp(el, name, val) { 179 if (val == null) { 180 el.style[name] = ''; 181 } 182 else if (typeof val === 'number' && PIXEL_PROP_RE.test(name)) { 183 el.style[name] = val + 'px'; 184 } 185 else { 186 el.style[name] = val; 187 } 188 } 189 190 function pointInsideRect(point, rect) { 191 return point.left >= rect.left && 192 point.left < rect.right && 193 point.top >
193= rect.top && 194 point.top < rect.bottom; 195 } 196 // Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false 197 function intersectRects(rect1, rect2) { 198 var res = { 199 left: Math.max(rect1.left, rect2.left), 200 right: Math.min(rect1.right, rect2.right), 201 top: Math.max(rect1.top, rect2.top), 202 bottom: Math.min(rect1.bottom, rect2.bottom) 203 }; 204 if (res.left < res.right && res.top < res.bottom) { 205 return res; 206 } 207 return false; 208 } 209 function translateRect(rect, deltaX, deltaY) { 210 return { 211 left: rect.left + deltaX, 212 right: rect.right + deltaX, 213 top: rect.top + deltaY, 214 bottom: rect.bottom + deltaY 215 }; 216 } 217 // Returns a new point that will have been moved to reside within the given rectangle 218 function constrainPoint(point, rect) { 219 return { 220 left: Math.min(Math.max(point.left, rect.left), rect.right), 221 top: Math.min(Math.max(point.top, rect.top), rect.bottom) 222 }; 223 } 224 // Returns a point that is the center of the given rectangle 225 function getRectCenter(rect) { 226 return { 227 left: (rect.left + rect.right) / 2, 228 top: (rect.top + rect.bottom) / 2 229 }; 230 } 231 // Subtracts point2's coordinates from point1's coordinates, returning a delta 232 function diffPoints(point1, point2) { 233 return { 234 left: point1.left - point2.left, 235 top: point1.top - point2.top 236 }; 237 } 238 239 // Logic for determining if, when the element is right-to-left, the scrollbar appears on the left side 240 var isRtlScrollbarOnLeft = null; 241 function getIsRtlScrollbarOnLeft() { 242 if (isRtlScrollbarOnLeft === null) { 243 isRtlScrollbarOnLeft = computeIsRtlScrollbarOnLeft(); 244 } 245 return isRtlScrollbarOnLeft; 246 } 247 function computeIsRtlScrollbarOnLeft() { 248 var outerEl = createElement('div', { 249 style: { 250 position: 'absolute', 251 top: -1000, 252 left: 0, 253 border: 0, 254 padding: 0, 255 overflow: 'scroll', 256 direction: 'rtl' 257 } 258 }, '<div></div>'); 259 document.body.appendChild(outerEl); 260 var innerEl = outerEl.firstChild; 261 var res = innerEl.getBoundingClientRect().left > outerEl.getBoundingClientRect().left; 262 removeElement(outerEl); 263 return res; 264 } 265 // The scrollbar width computations in computeEdges are sometimes flawed when it comes to 266 // retina displays, rounding, and IE11. Massage them into a usable value. 267 function sanitizeScrollbarWidth(width) { 268 width = Math.max(0, width); // no negatives 269 width = Math.round(width); 270 return width; 271 } 272 273 function computeEdges(el, getPadding) { 274 if (getPadding === void 0) { getPadding = false; } 275 var computedStyle = window.getComputedStyle(el); 276 var borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0; 277 var borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0; 278 var borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0; 279 var borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0; 280 // must use offset(Width|Height) because compatible with client(Width|Height) 281 var scrollbarLeftRight = sanitizeScrollbarWidth(el.offsetWidth - el.clientWidth - borderLeft - borderRight); 282 var scrollbarBottom = sanitizeScrollbarWidth(el.offsetHeight - el.clientHeight - borderTop - borderBottom); 283 var res = { 284 borderLeft: borderLeft, 285 borderRight: borderRight, 286 borderTop: borderTop, 287 borderBottom: borderBottom, 288 scrollbarBottom: scrollbarBottom, 289 scrollbarLeft: 0, 290 scrollbarRight: 0 291 }; 292 if (getIsRtlScrollbarOnLeft() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side? 293 res.scrollbarLeft = scrollbarLeftRight; 294 } 295 else { 296 res.scrollbarRight = scrollbarLeftRight; 297 } 298 if (getPadding) { 299 res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0; 300 res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0; 301 res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0; 302 res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0; 303 } 304 return res; 305 } 306 function computeInnerRect(el, goWithinPadding) { 307 if (goWithinPadding === void 0) { goWithinPadding = false; } 308 var outerRect = computeRect(el); 309 var edges = computeEdges(el, goWithinPadding); 310 var res = { 311 left: outerRect.left + edges.borderLeft + edges.scrollbarLeft, 312 right: outerRect.right - edges.borderRight - edges.scrollbarRight, 313 top: outerRect.top + edges.borderTop, 314 bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom 315 }; 316 if (goWithinPadding) { 317 res.left += edges.paddingLeft; 318 res.right -= edges.paddingRight; 319 res.top += edges.paddingTop; 320 res.bottom -= edges.paddingBottom; 321 } 322 return res; 323 } 324 function computeRect(el) { 325 var rect = el.getBoundingClientRect(); 326 return { 327 left: rect.left + window.pageXOffset, 328 top: rect.top + window.pageYOffset, 329 right: rect.right + window.pageXOffset, 330 bottom: rect.bottom + window.pageYOffset 331 }; 332 } 333 function computeViewportRect() { 334 return { 335 left: window.pageXOffset, 336 right: window.pageXOffset + document.documentElement.clientWidth, 337 top: window.pageYOffset, 338 bottom: window.pageYOffset + document.documentElement.clientHeight 339 }; 340 } 341 function computeHeightAndMargins(el) { 342 return el.getBoundingClientRect().height + computeVMargins(el); 343 } 344 function computeVMargins(el) { 345 var computed = window.getComputedStyle(el); 346 return parseInt(computed.marginTop, 10) + 347 parseInt(computed.marginBottom, 10); 348 } 349 // does not return window 350 function getClippingParents(el) { 351 var parents = []; 352 while (el instanceof HTMLElement) { // will stop when gets to document or null 353 var computedStyle = window.getComputedStyle(el); 354 if (computedStyle.position === 'fixed') { 355 break; 356 } 357 if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) { 358 parents.push(el); 359 } 360 el = el.parentNode; 361 } 362 return parents; 363 }
364 function computeClippingRect(el) { 365 return getClippingParents(el) 366 .map(function (el) { 367 return computeInnerRect(el); 368 }) 369 .concat(computeViewportRect()) 370 .reduce(function (rect0, rect1) { 371 return intersectRects(rect0, rect1) || rect1; // should always intersect 372 }); 373 } 374 375 // Stops a mouse/touch event from doing it's native browser action 376 function preventDefault(ev) { 377 ev.preventDefault(); 378 } 379 // Event Delegation 380 // ---------------------------------------------------------------------------------------------------------------- 381 function listenBySelector(container, eventType, selector, handler) { 382 function realHandler(ev) { 383 var matchedChild = elementClosest(ev.target, selector); 384 if (matchedChild) { 385 handler.call(matchedChild, ev, matchedChild); 386 } 387 } 388 container.addEventListener(eventType, realHandler); 389 return function () { 390 container.removeEventListener(eventType, realHandler); 391 }; 392 } 393 function listenToHoverBySelector(container, selector, onMouseEnter, onMouseLeave) { 394 var currentMatchedChild; 395 return listenBySelector(container, 'mouseover', selector, function (ev, matchedChild) { 396 if (matchedChild !== currentMatchedChild) { 397 currentMatchedChild = matchedChild; 398 onMouseEnter(ev, matchedChild); 399 var realOnMouseLeave_1 = function (ev) { 400 currentMatchedChild = null; 401 onMouseLeave(ev, matchedChild); 402 matchedChild.removeEventListener('mouseleave', realOnMouseLeave_1); 403 }; 404 // listen to the next mouseleave, and then unattach 405 matchedChild.addEventListener('mouseleave', realOnMouseLeave_1); 406 } 407 }); 408 } 409 // Animation 410 // ---------------------------------------------------------------------------------------------------------------- 411 var transitionEventNames = [ 412 'webkitTransitionEnd', 413 'otransitionend', 414 'oTransitionEnd', 415 'msTransitionEnd', 416 'transitionend' 417 ]; 418 // triggered only when the next single subsequent transition finishes 419 function whenTransitionDone(el, callback) { 420 var realCallback = function (ev) { 421 callback(ev); 422 transitionEventNames.forEach(function (eventName) { 423 el.removeEventListener(eventName, realCallback); 424 }); 425 }; 426 transitionEventNames.forEach(function (eventName) { 427 el.addEventListener(eventName, realCallback); // cross-browser way to determine when the transition finishes 428 }); 429 } 430 431 var DAY_IDS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; 432 // Adding 433 function addWeeks(m, n) { 434 var a = dateToUtcArray(m); 435 a[2] += n * 7; 436 return arrayToUtcDate(a); 437 } 438 function addDays(m, n) { 439 var a = dateToUtcArray(m); 440 a[2] += n; 441 return arrayToUtcDate(a); 442 } 443 function addMs(m, n) { 444 var a = dateToUtcArray(m); 445 a[6] += n; 446 return arrayToUtcDate(a); 447 } 448 // Diffing (all return floats) 449 function diffWeeks(m0, m1) { 450 return diffDays(m0, m1) / 7; 451 } 452 function diffDays(m0, m1) { 453 return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60 * 24); 454 } 455 function diffHours(m0, m1) { 456 return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60); 457 } 458 function diffMinutes(m0, m1) { 459 return (m1.valueOf() - m0.valueOf()) / (1000 * 60); 460 } 461 function diffSeconds(m0, m1) { 462 return (m1.valueOf() - m0.valueOf()) / 1000; 463 } 464 function diffDayAndTime(m0, m1) { 465 var m0day = startOfDay(m0); 466 var m1day = startOfDay(m1); 467 return { 468 years: 0, 469 months: 0, 470 days: Math.round(diffDays(m0day, m1day)), 471 milliseconds: (m1.valueOf() - m1day.valueOf()) - (m0.valueOf() - m0day.valueOf()) 472 }; 473 } 474 // Diffing Whole Units 475 function diffWholeWeeks(m0, m1) { 476 var d = diffWholeDays(m0, m1); 477 if (d !== null && d % 7 === 0) { 478 return d / 7; 479 } 480 return null; 481 } 482 function diffWholeDays(m0, m1) { 483 if (timeAsMs(m0) === timeAsMs(m1)) { 484 return Math.round(diffDays(m0, m1)); 485 } 486 return null; 487 } 488 // Start-Of 489 function startOfDay(m) { 490 return arrayToUtcDate([ 491 m.getUTCFullYear(), 492 m.getUTCMonth(), 493 m.getUTCDate() 494 ]); 495 } 496 function startOfHour(m) { 497 return arrayToUtcDate([ 498 m.getUTCFullYear(), 499 m.getUTCMonth(), 500 m.getUTCDate(), 501 m.getUTCHours() 502 ]); 503 } 504 function startOfMinute(m) { 505 return arrayToUtcDate([ 506 m.getUTCFullYear(), 507 m.getUTCMonth(), 508 m.getUTCDate(), 509 m.getUTCHours(), 510 m.getUTCMinutes() 511 ]); 512 } 513 function startOfSecond(m) { 514 return arrayToUtcDate([ 515 m.getUTCFullYear(), 516 m.getUTCMonth(), 517 m.getUTCDate(), 518 m.getUTCHours(), 519 m.getUTCMinutes(), 520 m.getUTCSeconds() 521 ]); 522 } 523 // Week Computation 524 function weekOfYear(marker, dow, doy) { 525 var y = marker.getUTCFullYear(); 526 var w = weekOfGivenYear(marker, y, dow, doy); 527 if (w < 1) { 528 return weekOfGivenYear(marker, y - 1, dow, doy); 529 } 530 var nextW = weekOfGivenYear(marker, y + 1, dow, doy); 531 if (nextW >= 1) { 532 return Math.min(w, nextW); 533 } 534 return w; 535 } 536 function weekOfGivenYear(marker, year, dow, doy) { 537 var firstWeekStart = arrayToUtcDate([year, 0, 1 + firstWeekOffset(year, dow, doy)]); 538 var dayStart = startOfDay(marker); 539 var days = Math.round(diffDays(firstWeekStart, dayStart)); 540 return Math.floor(days / 7) + 1; // zero-indexed 541 } 542 // start-of-first-week - start-of-year 543 function firstWeekOffset(year, dow, doy) { 544 // first-week day -- which january is always in the first week (4 for iso, 1 for other) 545 var fwd = 7 + dow - doy; 546 // first-week day local weekday -- which local weekday is fwd 547 var fwdlw = (7 + arrayToUtcDate([year, 0, fwd]).getUTCDay() - dow) % 7; 548 return -fwdlw + fwd - 1; 549 } 550 // Array Conversion 551 function dateToLocalArray(date) { 552 return [ 553 date.getFullYear(), 554 date.getMonth(), 555 date.getDate(), 556 date.getHours(), 557 date.getMinutes(), 558 date.getSeconds(), 559 date.getMilliseconds() 560 ]; 561 } 562 function arrayToLocalDate(a) { 563 return new Date(a[0], a[1] || 0, a[2] == null ? 1 : a[2], // day of month 564 a[3] || 0, a[4] || 0, a[5] || 0); 565 } 566 function dateToUtcArray(date) { 567 return [ 568 date.getUTCFullYear(), 569 date.getUTCMonth(), 570 date.getUTCDate(), 571 date.getUTCHours(), 572 date.getUTCMinutes(), 573 date.getUTCSeconds(), 574 date.getUTCMilliseconds() 575 ]; 576 } 577 function arrayToUtcDate(a) { 578 // according to web standards (and Safari), a month index is required. 579 // massage if only given a year. 580 if (a.length === 1) { 581 a = a.concat([0]); 582 } 583 return new Date(Date.UTC.apply(Date, a)); 584 } 585 // Other Utils 586 function isValidDate(m) { 587 return !isNaN(m.valueOf()); 588 } 589 function timeAsMs(m) { 590 return m.getUTCHours() * 1000 * 60 * 60 + 591 m.getUTCMinutes() * 1000 * 60 + 592 m.getUTCSeconds() * 1000 + 593 m.getUTCMilliseconds(); 594 } 595 596 var INTERNAL_UNITS = ['years', 'months', 'days', 'milliseconds'];
597 var PARSE_RE = /^(-?)(?:(\d+)\.)?(\d+):(\d\d)(?::(\d\d)(?:\.(\d\d\d))?)?/; 598 // Parsing and Creation 599 function createDuration(input, unit) { 600 var _a; 601 if (typeof input === 'string') { 602 return parseString(input); 603 } 604 else if (typeof input === 'object' && input) { // non-null object 605 return normalizeObject(input); 606 } 607 else if (typeof input === 'number') { 608 return normalizeObject((_a = {}, _a[unit || 'milliseconds'] = input, _a)); 609 } 610 else { 611 return null; 612 } 613 } 614 function parseString(s) { 615 var m = PARSE_RE.exec(s); 616 if (m) { 617 var sign = m[1] ? -1 : 1; 618 return { 619 years: 0, 620 months: 0, 621 days: sign * (m[2] ? parseInt(m[2], 10) : 0), 622 milliseconds: sign * ((m[3] ? parseInt(m[3], 10) : 0) * 60 * 60 * 1000 + // hours 623 (m[4] ? parseInt(m[4], 10) : 0) * 60 * 1000 + // minutes 624 (m[5] ? parseInt(m[5], 10) : 0) * 1000 + // seconds 625 (m[6] ? parseInt(m[6], 10) : 0) // ms 626 ) 627 }; 628 } 629 return null; 630 } 631 function normalizeObject(obj) { 632 return { 633 years: obj.years || obj.year || 0, 634 months: obj.months || obj.month || 0, 635 days: (obj.days || obj.day || 0) + 636 getWeeksFromInput(obj) * 7, 637 milliseconds: (obj.hours || obj.hour || 0) * 60 * 60 * 1000 + // hours 638 (obj.minutes || obj.minute || 0) * 60 * 1000 + // minutes 639 (obj.seconds || obj.second || 0) * 1000 + // seconds 640 (obj.milliseconds || obj.millisecond || obj.ms || 0) // ms 641 }; 642 } 643 function getWeeksFromInput(obj) { 644 return obj.weeks || obj.week || 0; 645 } 646 // Equality 647 function durationsEqual(d0, d1) { 648 return d0.years === d1.years && 649 d0.months === d1.months && 650 d0.days === d1.days && 651 d0.milliseconds === d1.milliseconds; 652 } 653 function isSingleDay(dur) { 654 return dur.years === 0 && dur.months === 0 && dur.days === 1 && dur.milliseconds === 0; 655 } 656 // Simple Math 657 function addDurations(d0, d1) { 658 return { 659 years: d0.years + d1.years, 660 months: d0.months + d1.months, 661 days: d0.days + d1.days, 662 milliseconds: d0.milliseconds + d1.milliseconds 663 }; 664 } 665 function subtractDurations(d1, d0) { 666 return { 667 years: d1.years - d0.years, 668 months: d1.months - d0.months, 669 days: d1.days - d0.days, 670 milliseconds: d1.milliseconds - d0.milliseconds 671 }; 672 } 673 function multiplyDuration(d, n) { 674 return { 675 years: d.years * n, 676 months: d.months * n, 677 days: d.days * n, 678 milliseconds: d.milliseconds * n 679 }; 680 } 681 // Conversions 682 // "Rough" because they are based on average-case Gregorian months/years 683 function asRoughYears(dur) { 684 return asRoughDays(dur) / 365; 685 } 686 function asRoughMonths(dur) { 687 return asRoughDays(dur) / 30; 688 } 689 function asRoughDays(dur) { 690 return asRoughMs(dur) / 864e5; 691 } 692 function asRoughMinutes(dur) { 693 return asRoughMs(dur) / (1000 * 60); 694 } 695 function asRoughSeconds(dur) { 696 return asRoughMs(dur) / 1000; 697 } 698 function asRoughMs(dur) { 699 return dur.years * (365 * 864e5) + 700 dur.months * (30 * 864e5) + 701 dur.days * 864e5 + 702 dur.milliseconds; 703 } 704 // Advanced Math 705 function wholeDivideDurations(numerator, denominator) { 706 var res = null; 707 for (var i = 0; i < INTERNAL_UNITS.length; i++) { 708 var unit = INTERNAL_UNITS[i]; 709 if (denominator[unit]) { 710 var localRes = numerator[unit] / denominator[unit]; 711 if (!isInt(localRes) || (res !== null && res !== localRes)) { 712 return null; 713 } 714 res = localRes; 715 } 716 else if (numerator[unit]) { 717 // needs to divide by something but can't! 718 return null; 719 } 720 } 721 return res; 722 } 723 function greatestDurationDenominator(dur, dontReturnWeeks) { 724 var ms = dur.milliseconds; 725 if (ms) { 726 if (ms % 1000 !== 0) { 727 return { unit: 'millisecond', value: ms }; 728 } 729 if (ms % (1000 * 60) !== 0) { 730 return { unit: 'second', value: ms / 1000 }; 731 } 732 if (ms % (1000 * 60 * 60) !== 0) { 733 return { unit: 'minute', value: ms / (1000 * 60) }; 734 } 735 if (ms) { 736 return { unit: 'hour', value: ms / (1000 * 60 * 60) }; 737 } 738 } 739 if (dur.days) { 740 if (!dontReturnWeeks && dur.days % 7 === 0) { 741 return { unit: 'week', value: dur.days / 7 }; 742 } 743 return { unit: 'day', value: dur.days }; 744 } 745 if (dur.months) { 746 return { unit: 'month', value: dur.months }; 747 } 748 if (dur.years) { 749 return { unit: 'year', value: dur.years }; 750 } 751 return { unit: 'millisecond', value: 0 }; 752 } 753 754 /* FullCalendar-specific DOM Utilities 755 ----------------------------------------------------------------------------------------------------------------------*/ 756 // Given the scrollbar widths of some other container, create borders/margins on rowEls in order to match the left 757 // and right space that was offset by the scrollbars. A 1-pixel border first, then margin beyond that. 758 function compensateScroll(rowEl, scrollbarWidths) { 759 if (scrollbarWidths.left) { 760 applyStyle(rowEl, { 761 borderLeftWidth: 1, 762 marginLeft: scrollbarWidths.left - 1 763 }); 764 } 765 if (scrollbarWidths.right) { 766 applyStyle(rowEl, { 767 borderRightWidth: 1, 768 marginRight: scrollbarWidths.right - 1 769 }); 770 } 771 } 772 // Undoes compensateScroll and restores all borders/margins 773 function uncompensateScroll(rowEl) { 774 applyStyle(rowEl, { 775 marginLeft: '', 776 marginRight: '', 777 borderLeftWidth: '', 778 borderRightWidth: '' 779 }); 780 }
781 // Make the mouse cursor express that an event is not allowed in the current area 782 function disableCursor() { 783 document.body.classList.add('fc-not-allowed'); 784 } 785 // Returns the mouse cursor to its original look 786 function enableCursor() { 787 document.body.classList.remove('fc-not-allowed'); 788 } 789 // Given a total available height to fill, have `els` (essentially child rows) expand to accomodate. 790 // By default, all elements that are shorter than the recommended height are expanded uniformly, not considering 791 // any other els that are already too tall. if `shouldRedistribute` is on, it considers these tall rows and 792 // reduces the available height. 793 function distributeHeight(els, availableHeight, shouldRedistribute) { 794 // *FLOORING NOTE*: we floor in certain places because zoom can give inaccurate floating-point dimensions, 795 // and it is better to be shorter than taller, to avoid creating unnecessary scrollbars. 796 var minOffset1 = Math.floor(availableHeight / els.length); // for non-last element 797 var minOffset2 = Math.floor(availableHeight - minOffset1 * (els.length - 1)); // for last element *FLOORING NOTE* 798 var flexEls = []; // elements that are allowed to expand. array of DOM nodes 799 var flexOffsets = []; // amount of vertical space it takes up 800 var flexHeights = []; // actual css height 801 var usedHeight = 0; 802 undistributeHeight(els); // give all elements their natural height 803 // find elements that are below the recommended height (expandable). 804 // important to query for heights in a single first pass (to avoid reflow oscillation). 805 els.forEach(function (el, i) { 806 var minOffset = i === els.length - 1 ? minOffset2 : minOffset1; 807 var naturalHeight = el.getBoundingClientRect().height; 808 var naturalOffset = naturalHeight + computeVMargins(el); 809 if (naturalOffset < minOffset) { 810 flexEls.push(el); 811 flexOffsets.push(naturalOffset); 812 flexHeights.push(naturalHeight); 813 } 814 else { 815 // this element stretches past recommended height (non-expandable). mark the space as occupied. 816 usedHeight += naturalOffset; 817 } 818 }); 819 // readjust the recommended height to only consider the height available to non-maxed-out rows. 820 if (shouldRedistribute) { 821 availableHeight -= usedHeight; 822 minOffset1 = Math.floor(availableHeight / flexEls.length); 823 minOffset2 = Math.floor(availableHeight - minOffset1 * (flexEls.length - 1)); // *FLOORING NOTE* 824 } 825 // assign heights to all expandable elements 826 flexEls.forEach(function (el, i) { 827 var minOffset = i === flexEls.length - 1 ? minOffset2 : minOffset1; 828 var naturalOffset = flexOffsets[i]; 829 var naturalHeight = flexHeights[i]; 830 var newHeight = minOffset - (naturalOffset - naturalHeight); // subtract the margin/padding 831 if (naturalOffset < minOffset) { // we check this again because redistribution might have changed things 832 el.style.height = newHeight + 'px'; 833 } 834 }); 835 } 836 // Undoes distrubuteHeight, restoring all els to their natural height 837 function undistributeHeight(els) { 838 els.forEach(function (el) { 839 el.style.height = ''; 840 }); 841 } 842 // Given `els`, a set of <td> cells, find the cell with the largest natural width and set the widths of all the 843 // cells to be that width. 844 // PREREQUISITE: if you want a cell to take up width, it needs to have a single inner element w/ display:inline 845 function matchCellWidths(els) { 846 var maxInnerWidth = 0; 847 els.forEach(function (el) { 848 var innerEl = el.firstChild; // hopefully an element 849 if (innerEl instanceof HTMLElement) { 850 var innerWidth_1 = innerEl.getBoundingClientRect().width; 851 if (innerWidth_1 > maxInnerWidth) { 852 maxInnerWidth = innerWidth_1; 853 } 854 } 855 }); 856 maxInnerWidth++; // sometimes not accurate of width the text needs to stay on one line. insurance
857 els.forEach(function (el) { 858 el.style.width = maxInnerWidth + 'px'; 859 }); 860 return maxInnerWidth; 861 } 862 // Given one element that resides inside another, 863 // Subtracts the height of the inner element from the outer element. 864 function subtractInnerElHeight(outerEl, innerEl) { 865 // effin' IE8/9/10/11 sometimes returns 0 for dimensions. this weird hack was the only thing that worked 866 var reflowStyleProps = { 867 position: 'relative', 868 left: -1 // ensure reflow in case the el was already relative. negative is less likely to cause new scroll 869 }; 870 applyStyle(outerEl, reflowStyleProps); 871 applyStyle(innerEl, reflowStyleProps); 872 var diff = // grab the dimensions 873 outerEl.getBoundingClientRect().height - 874 innerEl.getBoundingClientRect().height; 875 // undo hack 876 var resetStyleProps = { position: '', left: '' }; 877 applyStyle(outerEl, resetStyleProps); 878 applyStyle(innerEl, resetStyleProps); 879 return diff; 880 } 881 /* Selection 882 ----------------------------------------------------------------------------------------------------------------------*/ 883 function preventSelection(el) { 884 el.classList.add('fc-unselectable'); 885 el.addEventListener('selectstart', preventDefault); 886 } 887 function allowSelection(el) { 888 el.classList.remove('fc-unselectable'); 889 el.removeEventListener('selectstart', preventDefault); 890 } 891 /* Context Menu 892 ----------------------------------------------------------------------------------------------------------------------*/ 893 function preventContextMenu(el) { 894 el.addEventListener('contextmenu', preventDefault); 895 } 896 function allowContextMenu(el) { 897 el.removeEventListener('contextmenu', preventDefault); 898 } 899 /* Object Ordering by Field 900 ----------------------------------------------------------------------------------------------------------------------*/ 901 function parseFieldSpecs(input) { 902 var specs = []; 903 var tokens = []; 904 var i; 905 var token; 906 if (typeof input === 'string') { 907 tokens = input.split(/\s*,\s*/); 908 } 909 else if (typeof input === 'function') { 910 tokens = [input]; 911 } 912 else if (Array.isArray(input)) { 913 tokens = input; 914 } 915 for (i = 0; i < tokens.length; i++) { 916 token = tokens[i]; 917 if (typeof token === 'string') { 918 specs.push(token.charAt(0) === '-' ? 919 { field: token.substring(1), order: -1 } : 920 { field: token, order: 1 }); 921 } 922 else if (typeof token === 'function') { 923 specs.push({ func: token }); 924 } 925 } 926 return specs; 927 } 928 function compareByFieldSpecs(obj0, obj1, fieldSpecs) { 929 var i; 930 var cmp; 931 for (i = 0; i < fieldSpecs.length; i++) { 932 cmp = compareByFieldSpec(obj0, obj1, fieldSpecs[i]); 933 if (cmp) { 934 return cmp; 935 } 936 } 937 return 0; 938 } 939 function compareByFieldSpec(obj0, obj1, fieldSpec) { 940 if (fieldSpec.func) { 941 return fieldSpec.func(obj0, obj1); 942 } 943 return flexibleCompare(obj0[fieldSpec.field], obj1[fieldSpec.field]) 944 * (fieldSpec.order || 1); 945 } 946 function flexibleCompare(a, b) { 947 if (!a && !b) { 948 return 0; 949 } 950 if (b == null) { 951 return -1; 952 } 953 if (a == null) { 954 return 1; 955 } 956 if (typeof a === 'string' || typeof b === 'string') { 957 return String(a).localeCompare(String(b)); 958 } 959 return a - b; 960 } 961 /* String Utilities 962 ----------------------------------------------------------------------------------------------------------------------*/ 963 function capitaliseFirstLetter(str) { 964 return str.charAt(0).toUpperCase() + str.slice(1); 965 } 966 function padStart(val, len) { 967 var s = String(val); 968 return '000'.substr(0, len - s.length) + s; 969 } 970 /* Number Utilities 971 ----------------------------------------------------------------------------------------------------------------------*/ 972 function compareNumbers(a, b) { 973 return a - b; 974 } 975 function isInt(n) { 976 return n % 1 === 0; 977 } 978 /* Weird Utilities 979 ----------------------------------------------------------------------------------------------------------------------*/ 980 function applyAll(functions, thisObj, args) { 981 if (typeof functions === 'function') { // supplied a single function 982 functions = [functions]; 983 } 984 if (functions) { 985 var i = void 0; 986 var ret = void 0; 987 for (i = 0; i < functions.length; i++) { 988 ret = functions[i].apply(thisObj, args) || ret; 989 } 990 return ret; 991 } 992 } 993 function firstDefined() { 994 var args = []; 995 for (var _i = 0; _i < arguments.length; _i++) { 996 args[_i] = arguments[_i]; 997 } 998 for (var i = 0; i < args.length; i++) { 999 if (args[i] !== undefined) { 1000 return args[i]; 1001 } 1002 } 1003 } 1004 // Returns a function, that, as long as it continues to be invoked, will not 1005 // be triggered. The function will be called after it stops being called for 1006 // N milliseconds. If `immediate` is passed, trigger the function on the 1007 // leading edge, instead of the trailing. 1008 // https://github.com/jashkenas/underscore/blob/1.6.0/underscore.js#L714 1009 function debounce(func, wait) { 1010 var timeout; 1011 var args; 1012 var context; 1013 var timestamp; 1014 var result; 1015 var later = function () { 1016 var last = new Date().valueOf() - timestamp; 1017 if (last < wait) { 1018 timeout = setTimeout(later, wait - last); 1019 } 1020 else { 1021 timeout = null;
1022 result = func.apply(context, args); 1023 context = args = null; 1024 } 1025 }; 1026 return function () { 1027 context = this; 1028 args = arguments; 1029 timestamp = new Date().valueOf(); 1030 if (!timeout) { 1031 timeout = setTimeout(later, wait); 1032 } 1033 return result; 1034 }; 1035 } 1036 // Number and Boolean are only types that defaults or not computed for 1037 // TODO: write more comments 1038 function refineProps(rawProps, processors, defaults, leftoverProps) { 1039 if (defaults === void 0) { defaults = {}; } 1040 var refined = {}; 1041 for (var key in processors) { 1042 var processor = processors[key]; 1043 if (rawProps[key] !== undefined) { 1044 // found 1045 if (processor === Function) { 1046 refined[key] = typeof rawProps[key] === 'function' ? rawProps[key] : null; 1047 } 1048 else if (processor) { // a refining function? 1049 refined[key] = processor(rawProps[key]); 1050 } 1051 else { 1052 refined[key] = rawProps[key]; 1053 } 1054 } 1055 else if (defaults[key] !== undefined) { 1056 // there's an explicit default 1057 refined[key] = defaults[key]; 1058 } 1059 else { 1060 // must compute a default 1061 if (processor === String) { 1062 refined[key] = ''; // empty string is default for String 1063 } 1064 else if (!processor || processor === Number || processor === Boolean || processor === Function) { 1065 refined[key] = null; // assign null for other non-custom processor funcs 1066 } 1067 else { 1068 refined[key] = processor(null); // run the custom processor func 1069 } 1070 } 1071 } 1072 if (leftoverProps) { 1073 for (var key in rawProps) { 1074 if (processors[key] === undefined) { 1075 leftoverProps[key] = rawProps[key]; 1076 } 1077 } 1078 } 1079 return refined; 1080 } 1081 /* Date stuff that doesn't belong in datelib core 1082 ----------------------------------------------------------------------------------------------------------------------*/ 1083 // given a timed range, computes an all-day range that has the same exact duration, 1084 // but whose start time is aligned with the start of the day. 1085 function computeAlignedDayRange(timedRange) { 1086 var dayCnt = Math.floor(diffDays(timedRange.start, timedRange.end)) || 1; 1087 var start = startOfDay(timedRange.start); 1088 var end = addDays(start, dayCnt); 1089 return { start: start, end: end }; 1090 } 1091 // given a timed range, computes an all-day range based on how for the end date bleeds into the next day 1092 // TODO: give nextDayThreshold a default arg 1093 function computeVisibleDayRange(timedRange, nextDayThreshold) { 1094 if (nextDayThreshold === void 0) { nextDayThreshold = createDuration(0); } 1095 var startDay = null; 1096 var endDay = null; 1097 if (timedRange.end) { 1098 endDay = startOfDay(timedRange.end); 1099 var endTimeMS = timedRange.end.valueOf() - endDay.valueOf(); // # of milliseconds into `endDay` 1100 // If the end time is actually inclusively part of the next day and is equal to or 1101 // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`. 1102 // Otherwise, leaving it as inclusive will cause it to exclude `endDay`. 1103 if (endTimeMS && endTimeMS >= asRoughMs(nextDayThreshold)) { 1104 endDay = addDays(endDay, 1); 1105 } 1106 } 1107 if (timedRange.start) { 1108 startDay = startOfDay(timedRange.start); // the beginning of the day the range starts 1109 // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day. 1110 if (endDay && endDay <= startDay) { 1111 endDay = addDays(startDay, 1); 1112 } 1113 } 1114 return { start: startDay, end: endDay }; 1115 } 1116 // spans from one day into another? 1117 function isMultiDayRange(range) { 1118 var visibleRange = computeVisibleDayRange(range); 1119 return diffDays(visibleRange.start, visibleRange.end) > 1; 1120 } 1121 function diffDates(date0, date1, dateEnv, largeUnit) { 1122 if (largeUnit === 'year') { 1123 return createDuration(dateEnv.diffWholeYears(date0, date1), 'year'); 1124 } 1125 else if (largeUnit === 'month') { 1126 return createDuration(dateEnv.diffWholeMonths(date0, date1), 'month'); 1127 } 1128 else { 1129 return diffDayAndTime(date0, date1); // returns a duration 1130 } 1131 } 1132 1133 /*! ***************************************************************************** 1134 Copyright (c) Microsoft Corporation. All rights reserved. 1135 Licensed under the Apache License, Version 2.0 (the "License");
1135 you may not use 1136 this file except in compliance with the License. You may obtain a copy of the 1137 License at http://www.apache.org/licenses/LICENSE-2.0 1138 1139 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1140 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 1141 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 1142 MERCHANTABLITY OR NON-INFRINGEMENT. 1143 1144 See the Apache Version 2.0 License for specific language governing permissions 1145 and limitations under the License. 1146 ***************************************************************************** */ 1147 /* global Reflect, Promise */ 1148 1149 var extendStatics = function(d, b) { 1150 extendStatics = Object.setPrototypeOf || 1151 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 1152 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 1153 return extendStatics(d, b); 1154 }; 1155 1156 function __extends(d, b) { 1157 extendStatics(d, b); 1158 function __() { this.constructor = d; } 1159 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 1160 } 1161 1162 var __assign = function() { 1163 __assign = Object.assign || function __assign(t) { 1164 for (var s, i = 1, n = arguments.length; i < n; i++) { 1165 s = arguments[i]; 1166 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 1167 } 1168 return t; 1169 }; 1170 return __assign.apply(this, arguments); 1171 }; 1172 1173 function parseRecurring(eventInput, allDayDefault, dateEnv, recurringTypes, leftovers) { 1174 for (var i = 0; i < recurringTypes.length; i++) { 1175 var localLeftovers = {}; 1176 var parsed = recurringTypes[i].parse(eventInput, localLeftovers, dateEnv); 1177 if (parsed) { 1178 var allDay = localLeftovers.allDay; 1179 delete localLeftovers.allDay; // remove from leftovers 1180 if (allDay == null) { 1181 allDay = allDayDefault; 1182 if (allDay == null) { 1183 allDay = parsed.allDayGuess; 1184 if (allDay == null) { 1185 allDay = false; 1186 } 1187 } 1188 } 1189 __assign(leftovers, localLeftovers); 1190 return { 1191 allDay: allDay, 1192 duration: parsed.duration, 1193 typeData: parsed.typeData, 1194 typeId: i 1195 }; 1196 } 1197 } 1198 return null; 1199 } 1200 /* 1201 Event MUST have a recurringDef 1202 */ 1203 function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) { 1204 var typeDef = recurringTypes[eventDef.recurringDef.typeId]; 1205 var markers = typeDef.expand(eventDef.recurringDef.typeData, { 1206 start: dateEnv.subtract(framingRange.start, duration), 1207 end: framingRange.end 1208 }, dateEnv); 1209 // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to 1210 if (eventDef.allDay) { 1211 markers = markers.map(startOfDay); 1212 } 1213 return markers; 1214 } 1215 1216 var hasOwnProperty = Object.prototype.hasOwnProperty; 1217 // Merges an array of objects into a single object. 1218 // The second argument allows for an array of property names who's object values will be merged together. 1219 function mergeProps(propObjs, complexProps) { 1220 var dest = {}; 1221 var i; 1222 var name; 1223 var complexObjs; 1224 var j; 1225 var val; 1226 var props; 1227 if (complexProps) { 1228 for (i = 0; i < complexProps.length; i++) { 1229 name = complexProps[i]; 1230 complexObjs = []; 1231 // collect the trailing object values, stopping when a non-object is discovered 1232 for (j = propObjs.length - 1; j >= 0; j--) { 1233 val = propObjs[j][name]; 1234 if (typeof val === 'object' && val) { // non-null object 1235 complexObjs.unshift(val); 1236 } 1237 else if (val !== undefined) { 1238 dest[name] = val; // if there were no objects, this value will be used 1239 break; 1240 } 1241 } 1242 // if the trailing values were objects, use the merged value 1243 if (complexObjs.length) { 1244 dest[name] = mergeProps(complexObjs); 1245 } 1246 } 1247 } 1248 // copy values into the destination, going from last to first 1249 for (i = propObjs.length - 1; i >= 0; i--) { 1250 props = propObjs[i]; 1251 for (name in props) { 1252 if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign 1253 dest[name] = props[name]; 1254 } 1255 } 1256 } 1257 return dest; 1258 } 1259 function filterHash(hash, func) { 1260 var filtered = {}; 1261 for (var key in hash) { 1262 if (func(hash[key], key)) { 1263 filtered[key] = hash[key]; 1264 } 1265 } 1266 return filtered; 1267 } 1268 function mapHash(hash, func) { 1269 var newHash = {}; 1270 for (var key in hash) { 1271 newHash[key] = func(hash[key], key); 1272 } 1273 return newHash; 1274 } 1275 function arrayToHash(a) { 1276 var hash = {}; 1277 for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { 1278 var item = a_1[_i]; 1279 hash[item] = true; 1280 } 1281 return hash; 1282 } 1283 function hashValuesToArray(obj) { 1284 var a = []; 1285 for (var key in obj) { 1286 a.push(obj[key]); 1287 } 1288 return a; 1289 } 1290 function isPropsEqual(obj0, obj1) { 1291 for (var key in obj0) { 1292 if (hasOwnProperty.call(obj0, key)) { 1293 if (!(key in obj1)) { 1294 return false;
1295 } 1296 } 1297 } 1298 for (var key in obj1) { 1299 if (hasOwnProperty.call(obj1, key)) { 1300 if (obj0[key] !== obj1[key]) { 1301 return false; 1302 } 1303 } 1304 } 1305 return true; 1306 } 1307 1308 function parseEvents(rawEvents, sourceId, calendar, allowOpenRange) { 1309 var eventStore = createEmptyEventStore(); 1310 for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { 1311 var rawEvent = rawEvents_1[_i]; 1312 var tuple = parseEvent(rawEvent, sourceId, calendar, allowOpenRange); 1313 if (tuple) { 1314 eventTupleToStore(tuple, eventStore); 1315 } 1316 } 1317 return eventStore; 1318 } 1319 function eventTupleToStore(tuple, eventStore) { 1320 if (eventStore === void 0) { eventStore = createEmptyEventStore(); } 1321 eventStore.defs[tuple.def.defId] = tuple.def; 1322 if (tuple.instance) { 1323 eventStore.instances[tuple.instance.instanceId] = tuple.instance; 1324 } 1325 return eventStore; 1326 } 1327 function expandRecurring(eventStore, framingRange, calendar) { 1328 var dateEnv = calendar.dateEnv; 1329 var defs = eventStore.defs, instances = eventStore.instances; 1330 // remove existing recurring instances 1331 instances = filterHash(instances, function (instance) { 1332 return !defs[instance.defId].recurringDef; 1333 }); 1334 for (var defId in defs) { 1335 var def = defs[defId]; 1336 if (def.recurringDef) { 1337 var duration = def.recurringDef.duration; 1338 if (!duration) { 1339 duration = def.allDay ? 1340 calendar.defaultAllDayEventDuration : 1341 calendar.defaultTimedEventDuration; 1342 } 1343 var starts = expandRecurringRanges(def, duration, framingRange, calendar.dateEnv, calendar.pluginSystem.hooks.recurringTypes); 1344 for (var _i = 0, starts_1 = starts; _i < starts_1.length; _i++) { 1345 var start = starts_1[_i]; 1346 var instance = createEventInstance(defId, { 1347 start: start, 1348 end: dateEnv.add(start, duration) 1349 }); 1350 instances[instance.instanceId] = instance; 1351 } 1352 } 1353 } 1354 return { defs: defs, instances: instances }; 1355 } 1356 // retrieves events that have the same groupId as the instance specified by `instanceId` 1357 // or they are the same as the instance. 1358 // why might instanceId not be in the store? an event from another calendar? 1359 function getRelevantEvents(eventStore, instanceId) { 1360 var instance = eventStore.instances[instanceId]; 1361 if (instance) { 1362 var def_1 = eventStore.defs[instance.defId]; 1363 // get events/instances with same group 1364 var newStore = filterEventStoreDefs(eventStore, function (lookDef) { 1365 return isEventDefsGrouped(def_1, lookDef); 1366 }); 1367 // add the original 1368 // TODO: wish we could use eventTupleToStore or something like it 1369 newStore.defs[def_1.defId] = def_1; 1370 newStore.instances[instance.instanceId] = instance; 1371 return newStore; 1372 } 1373 return createEmptyEventStore(); 1374 } 1375 function isEventDefsGrouped(def0, def1) { 1376 return Boolean(def0.groupId && def0.groupId === def1.groupId); 1377 } 1378 function transformRawEvents(rawEvents, eventSource, calendar) { 1379 var calEachTransform = calendar.opt('eventDataTransform'); 1380 var sourceEachTransform = eventSource ? eventSource.eventDataTransform : null; 1381 if (sourceEachTransform) { 1382 rawEvents = transformEachRawEvent(rawEvents, sourceEachTransform); 1383 } 1384 if (calEachTransform) { 1385 rawEvents = transformEachRawEvent(rawEvents, calEachTransform); 1386 } 1387 return rawEvents; 1388 } 1389 function transformEachRawEvent(rawEvents, func) { 1390 var refinedEvents; 1391 if (!func) { 1392 refinedEvents = rawEvents; 1393 } 1394 else { 1395 refinedEvents = []; 1396 for (var _i = 0, rawEvents_2 = rawEvents; _i < rawEvents_2.length; _i++) { 1397 var rawEvent = rawEvents_2[_i]; 1398 var refinedEvent = func(rawEvent); 1399 if (refinedEvent) { 1400 refinedEvents.push(refinedEvent); 1401 } 1402 else if (refinedEvent == null) { 1403 refinedEvents.push(rawEvent); 1404 } // if a different falsy value, do nothing 1405 } 1406 } 1407 return refinedEvents; 1408 } 1409 function createEmptyEventStore() { 1410 return { defs: {}, instances: {} }; 1411 } 1412 function mergeEventStores(store0, store1) { 1413 return { 1414 defs: __assign({}, store0.defs, store1.defs), 1415 instances: __assign({}, store0.instances, store1.instances) 1416 }; 1417 } 1418 function filterEventStoreDefs(eventStore, filterFunc) { 1419 var defs = filterHash(eventStore.defs, filterFunc); 1420 var instances = filterHash(eventStore.instances, function (instance) { 1421 return defs[instance.defId]; // still exists? 1422 }); 1423 return { defs: defs, instances: instances }; 1424 } 1425 1426 function parseRange(input, dateEnv) { 1427 var start = null; 1428 var end = null; 1429 if (input.start) { 1430 start = dateEnv.createMarker(input.start); 1431 } 1432 if (input.end) { 1433 end = dateEnv.createMarker(input.end); 1434 } 1435 if (!start && !end) { 1436 return null; 1437 } 1438 if (start && end && end < start) { 1439 return null; 1440 } 1441 return { start: start, end: end }; 1442 } 1443 // SIDE-EFFECT: will mutate ranges. 1444 // Will return a new array result. 1445 function invertRanges(ranges, constraintRange) { 1446 var invertedRanges = []; 1447 var start = constraintRange.start; // the end of the previous range. the start of the new range 1448 var i; 1449 var dateRange; 1450 // ranges need to be in order. required for our date-walking algorithm 1451 ranges.sort(compareRanges); 1452 for (i = 0; i < ranges.length; i++) { 1453 dateRange = ranges[i]; 1454 // add the span of time before the event (if there is any) 1455 if (dateRange.start > start) { // compare millisecond time (skip any ambig logic) 1456 invertedRanges.push({ start: start, end: dateRange.start }); 1457 } 1458 if (dateRange.end > start) { 1459 start = dateRange.end; 1460 } 1461 } 1462 // add the span of time after the last event (if there is any) 1463 if (start < constraintRange.end) { // compare millisecond time (skip any ambig logic) 1464 invertedRanges.push({ start: start, end: constraintRange.end }); 1465 } 1466 return invertedRanges; 1467 } 1468 function compareRanges(range0, range1) { 1469 return range0.start.valueOf() - range1.start.valueOf(); // earlier ranges go first 1470 } 1471 function intersectRanges(range0, range1) { 1472 var start = range0.start; 1473 var end = range0.end; 1474 var newRange = null; 1475 if (range1.start !== null) { 1476 if (start === null) { 1477 start = range1.start; 1478 } 1479 else { 1480 start = new Date(Math.max(start.valueOf(), range1.start.valueOf())); 1481 } 1482 } 1483 if (range1.end != null) { 1484 if (end === null) { 1485 end = range1.end; 1486 } 1487 else { 1488 end = new Date(Math.min(end.valueOf(), range1.end.valueOf())); 1489 } 1490 } 1491 if (start === null || end === null || start < end) { 1492 newRange = { start: start, end: end }; 1493 } 1494 return newRange; 1495 } 1496 function rangesEqual(range0, range1) { 1497 return (range0.start === null ? null : range0.start.valueOf()) === (range1.start === null ? null : range1.start.valueOf()) && 1498 (range0.end === null ? null : range0.end.valueOf()) === (range1.end === null ? null : range1.end.valueOf()); 1499 } 1500 function rangesIntersect(range0, range1) { 1501 return (range0.end === null || range1.start === null || range0.end > range1.start) && 1502 (range0.start === null || range1.end === null || range0.start < range1.end); 1503 } 1504 function rangeContainsRange(outerRange, innerRange) { 1505 return (outerRange.start === null || (innerRange.start !== null && innerRange.start >= outerRange.start)) && 1506 (outerRange.end === null || (innerRange.end !== null && innerRange.end <= outerRange.end)); 1507 } 1508 function rangeContainsMarker(range, date) { 1509 return (range.start === null || date >= range.start) && 1510 (range.end === null || date < range.end); 1511 } 1512 // If the given date is not within the given range, move it inside. 1513 // (If it's past the end, make it one millisecond before the end). 1514 function constrainMarkerToRange(date, range) { 1515 if (range.start != null && date < range.start) { 1516 return range.start; 1517 } 1518 if (range.end != null && date >= range.end) { 1519 return new Date(range.end.valueOf() - 1); 1520 } 1521 return date; 1522 } 1523 1524 function removeExact(array, exactVal) { 1525 var removeCnt = 0; 1526 var i = 0; 1527 while (i < array.length) { 1528 if (array[i] === exactVal) { 1529 array.splice(i, 1); 1530 removeCnt++; 1531 } 1532 else { 1533 i++; 1534 } 1535 } 1536 return removeCnt; 1537 } 1538 function isArraysEqual(a0, a1) { 1539 var len = a0.length; 1540 var i; 1541 if (len !== a1.length) { // not array? or not same length? 1542 return false;
1543 } 1544 for (i = 0; i < len; i++) { 1545 if (a0[i] !== a1[i]) { 1546 return false; 1547 } 1548 } 1549 return true; 1550 } 1551 1552 function memoize(workerFunc) { 1553 var args; 1554 var res; 1555 return function () { 1556 if (!args || !isArraysEqual(args, arguments)) { 1557 args = arguments; 1558 res = workerFunc.apply(this, arguments); 1559 } 1560 return res; 1561 }; 1562 } 1563 /* 1564 always executes the workerFunc, but if the result is equal to the previous result, 1565 return the previous result instead. 1566 */ 1567 function memoizeOutput(workerFunc, equalityFunc) { 1568 var cachedRes = null; 1569 return function () { 1570 var newRes = workerFunc.apply(this, arguments); 1571 if (cachedRes === null || !(cachedRes === newRes || equalityFunc(cachedRes, newRes))) { 1572 cachedRes = newRes; 1573 } 1574 return cachedRes; 1575 }; 1576 } 1577 1578 var EXTENDED_SETTINGS_AND_SEVERITIES = { 1579 week: 3, 1580 separator: 0, 1581 omitZeroMinute: 0, 1582 meridiem: 0, 1583 omitCommas: 0 1584 }; 1585 var STANDARD_DATE_PROP_SEVERITIES = { 1586 timeZoneName: 7, 1587 era: 6, 1588 year: 5, 1589 month: 4, 1590 day: 2, 1591 weekday: 2, 1592 hour: 1, 1593 minute: 1, 1594 second: 1 1595 }; 1596 var MERIDIEM_RE = /\s*([ap])\.?m\.?/i; // eats up leading spaces too 1597 var COMMA_RE = /,/g; // we need re for globalness 1598 var MULTI_SPACE_RE = /\s+/g; 1599 var LTR_RE = /\u200e/g; // control character 1600 var UTC_RE = /UTC|GMT/; 1601 var NativeFormatter = /** @class */ (function () { 1602 function NativeFormatter(formatSettings) { 1603 var standardDateProps = {}; 1604 var extendedSettings = {}; 1605 var severity = 0; 1606 for (var name_1 in formatSettings) { 1607 if (name_1 in EXTENDED_SETTINGS_AND_SEVERITIES) { 1608 extendedSettings[name_1] = formatSettings[name_1]; 1609 severity = Math.max(EXTENDED_SETTINGS_AND_SEVERITIES[name_1], severity); 1610 } 1611 else { 1612 standardDateProps[name_1] = formatSettings[name_1]; 1613 if (name_1 in STANDARD_DATE_PROP_SEVERITIES) { 1614 severity = Math.max(STANDARD_DATE_PROP_SEVERITIES[name_1], severity); 1615 } 1616 } 1617 } 1618 this.standardDateProps = standardDateProps; 1619 this.extendedSettings = extendedSettings; 1620 this.severity = severity; 1621 this.buildFormattingFunc = memoize(buildFormattingFunc); 1622 } 1623 NativeFormatter.prototype.format = function (date, context) { 1624 return this.buildFormattingFunc(this.standardDateProps, this.extendedSettings, context)(date); 1625 }; 1626 NativeFormatter.prototype.formatRange = function (start, end, context) { 1627 var _a = this, standardDateProps = _a.standardDateProps, extendedSettings = _a.extendedSettings; 1628 var diffSeverity = computeMarkerDiffSeverity(start.marker, end.marker, context.calendarSystem); 1629 if (!diffSeverity) { 1630 return this.format(start, context); 1631 } 1632 var biggestUnitForPartial = diffSeverity; 1633 if (biggestUnitForPartial > 1 && // the two dates are different in a way that's larger scale than time 1634 (standardDateProps.year === 'numeric' || standardDateProps.year === '2-digit') && 1635 (standardDateProps.month === 'numeric' || standardDateProps.month === '2-digit') && 1636 (standardDateProps.day === 'numeric' || standardDateProps.day === '2-digit')) { 1637 biggestUnitForPartial = 1; // make it look like the dates are only different in terms of time 1638 } 1639 var full0 = this.format(start, context); 1640 var full1 = this.format(end, context); 1641 if (full0 === full1) { 1642 return full0; 1643 } 1644 var partialDateProps = computePartialFormattingOptions(standardDateProps, biggestUnitForParti
1644al); 1645 var partialFormattingFunc = buildFormattingFunc(partialDateProps, extendedSettings, context); 1646 var partial0 = partialFormattingFunc(start); 1647 var partial1 = partialFormattingFunc(end); 1648 var insertion = findCommonInsertion(full0, partial0, full1, partial1); 1649 var separator = extendedSettings.separator || ''; 1650 if (insertion) { 1651 return insertion.before + partial0 + separator + partial1 + insertion.after; 1652 } 1653 return full0 + separator + full1; 1654 }; 1655 NativeFormatter.prototype.getLargestUnit = function () { 1656 switch (this.severity) { 1657 case 7: 1658 case 6: 1659 case 5: 1660 return 'year'; 1661 case 4: 1662 return 'month'; 1663 case 3: 1664 return 'week'; 1665 default: 1666 return 'day'; 1667 } 1668 }; 1669 return NativeFormatter; 1670 }()); 1671 function buildFormattingFunc(standardDateProps, extendedSettings, context) { 1672 var standardDatePropCnt = Object.keys(standardDateProps).length; 1673 if (standardDatePropCnt === 1 && standardDateProps.timeZoneName === 'short') { 1674 return function (date) { 1675 return formatTimeZoneOffset(date.timeZoneOffset); 1676 }; 1677 } 1678 if (standardDatePropCnt === 0 && extendedSettings.week) { 1679 return function (date) { 1680 return formatWeekNumber(context.computeWeekNumber(date.marker), context.weekLabel, context.locale, extendedSettings.week); 1681 }; 1682 } 1683 return buildNativeFormattingFunc(standardDateProps, extendedSettings, context); 1684 } 1685 function buildNativeFormattingFunc(standardDateProps, extendedSettings, context) { 1686 standardDateProps = __assign({}, standardDateProps); // copy 1687 extendedSettings = __assign({}, extendedSettings); // copy 1688 sanitizeSettings(standardDateProps, extendedSettings); 1689 standardDateProps.timeZone = 'UTC'; // we leverage the only guaranteed timeZone for our UTC markers 1690 var normalFormat = new Intl.DateTimeFormat(context.locale.codes, standardDateProps); 1691 var zeroFormat; // needed? 1692 if (extendedSettings.omitZeroMinute) { 1693 var zeroProps = __assign({}, standardDateProps); 1694 delete zeroProps.minute; // seconds and ms were already considered in sanitizeSettings 1695 zeroFormat = new Intl.DateTimeFormat(context.locale.codes, zeroProps); 1696 } 1697 return function (date) { 1698 var marker = date.marker; 1699 var format; 1700 if (zeroFormat && !marker.getUTCMinutes()) { 1701 format = zeroFormat; 1702 } 1703 else { 1704 format = normalFormat; 1705 } 1706 var s = format.format(marker); 1707 return postProcess(s, date, standardDateProps, extendedSettings, context); 1708 }; 1709 } 1710 function sanitizeSettings(standardDateProps, extendedSettings) { 1711 // deal with a browser inconsistency where formatting the timezone 1712 // requires that the hour/minute be present. 1713 if (standardDateProps.timeZoneName) { 1714 if (!standardDateProps.hour) { 1715 standardDateProps.hour = '2-digit'; 1716 } 1717 if (!standardDateProps.minute) { 1718 standardDateProps.minute = '2-digit'; 1719 } 1720 } 1721 // only support short timezone names 1722 if (standardDateProps.timeZoneName === 'long') { 1723 standardDateProps.timeZoneName = 'short'; 1724 } 1725 // if requesting to display seconds, MUST display minutes 1726 if (extendedSettings.omitZeroMinute && (standardDateProps.second || standardDateProps.millisecond)) { 1727 delete extendedSettings.omitZeroMinute; 1728 } 1729 } 1730 function postProcess(s, date, standardDateProps, extendedSettings, context) { 1731 s = s.replace(LTR_RE, ''); // remove left-to-right control chars. do first. good for other regexes 1732 if (standardDateProps.timeZoneName === 'short') { 1733 s = injectTzoStr(s, (context.timeZone === 'UTC' || date.timeZoneOffset == null) ? 1734 'UTC' : // important to normalize for IE, which does "GMT" 1735 formatTimeZoneOffset(date.timeZoneOffset)); 1736 } 1737 if (extendedSettings.omitCommas) { 1738 s = s.replace(COMMA_RE, '').trim(); 1739 } 1740 if (extendedSettings.omitZeroMinute) { 1741 s = s.replace(':00', ''); // zeroFormat doesn't always achieve this 1742 } 1743 // ^ do anything that might create adjacent spaces before this point,
1744 // because MERIDIEM_RE likes to eat up loading spaces 1745 if (extendedSettings.meridiem === false) { 1746 s = s.replace(MERIDIEM_RE, '').trim(); 1747 } 1748 else if (extendedSettings.meridiem === 'narrow') { // a/p 1749 s = s.replace(MERIDIEM_RE, function (m0, m1) { 1750 return m1.toLocaleLowerCase(); 1751 }); 1752 } 1753 else if (extendedSettings.meridiem === 'short') { // am/pm 1754 s = s.replace(MERIDIEM_RE, function (m0, m1) { 1755 return m1.toLocaleLowerCase() + 'm'; 1756 }); 1757 } 1758 else if (extendedSettings.meridiem === 'lowercase') { // other meridiem transformers already converted to lowercase 1759 s = s.replace(MERIDIEM_RE, function (m0) { 1760 return m0.toLocaleLowerCase(); 1761 }); 1762 } 1763 s = s.replace(MULTI_SPACE_RE, ' '); 1764 s = s.trim(); 1765 return s; 1766 } 1767 function injectTzoStr(s, tzoStr) { 1768 var replaced = false; 1769 s = s.replace(UTC_RE, function () { 1770 replaced = true; 1771 return tzoStr; 1772 }); 1773 // IE11 doesn't include UTC/GMT in the original string, so append to end 1774 if (!replaced) { 1775 s += ' ' + tzoStr; 1776 } 1777 return s; 1778 } 1779 function formatWeekNumber(num, weekLabel, locale, display) { 1780 var parts = []; 1781 if (display === 'narrow') { 1782 parts.push(weekLabel); 1783 } 1784 else if (display === 'short') { 1785 parts.push(weekLabel, ' '); 1786 } 1787 // otherwise, considered 'numeric' 1788 parts.push(locale.simpleNumberFormat.format(num)); 1789 if (locale.options.isRtl) { // TODO: use control characters instead? 1790 parts.reverse(); 1791 } 1792 return parts.join(''); 1793 } 1794 // Range Formatting Utils 1795 // 0 = exactly the same 1796 // 1 = different by time 1797 // and bigger 1798 function computeMarkerDiffSeverity(d0, d1, ca) { 1799 if (ca.getMarkerYear(d0) !== ca.getMarkerYear(d1)) { 1800 return 5; 1801 } 1802 if (ca.getMarkerMonth(d0) !== ca.getMarkerMonth(d1)) { 1803 return 4; 1804 } 1805 if (ca.getMarkerDay(d0) !== ca.getMarkerDay(d1)) { 1806 return 2; 1807 } 1808 if (timeAsMs(d0) !== timeAsMs(d1)) { 1809 return 1; 1810 } 1811 return 0; 1812 } 1813 function computePartialFormattingOptions(options, biggestUnit) { 1814 var partialOptions = {}; 1815 for (var name_2 in options) { 1816 if (!(name_2 in STANDARD_DATE_PROP_SEVERITIES) || // not a date part prop (like timeZone) 1817 STANDARD_DATE_PROP_SEVERITIES[name_2] <= biggestUnit) { 1818 partialOptions[name_2] = options[name_2]; 1819 } 1820 } 1821 return partialOptions; 1822 } 1823 function findCommonInsertion(full0, partial0, full1, partial1) { 1824 var i0 = 0; 1825 while (i0 < full0.length) { 1826 var found0 = full0.indexOf(partial0, i0); 1827 if (found0 === -1) { 1828 break; 1829 } 1830 var before0 = full0.substr(0, found0); 1831 i0 = found0 + partial0.length; 1832 var after0 = full0.substr(i0); 1833 var i1 = 0; 1834 while (i1 < full1.length) { 1835 var found1 = full1.indexOf(partial1, i1); 1836 if (found1 === -1) { 1837 break; 1838 } 1839 var before1 = full1.substr(0, found1); 1840 i1 = found1 + partial1.length; 1841 var after1 = full1.substr(i1); 1842 if (before0 === before1 && after0 === after1) { 1843 return { 1844 before: before0, 1845 after: after0 1846 }; 1847 } 1848 } 1849 } 1850 return null; 1851 } 1852 1853 /* 1854 TODO: fix the terminology of "formatter" vs "formatting func" 1855 */ 1856 /* 1857 At the time of instantiation, this object does not know which cmd-formatting system it will use. 1858 It receives this at the time of formatting, as a setting. 1859 */ 1860 var CmdFormatter = /** @class */ (function () { 1861 function CmdFormatter(cmdStr, separator) { 1862 this.cmdStr = cmdStr; 1863 this.separator = separator; 1864 } 1865 CmdFormatter.prototype.format = function (date, context) { 1866 return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(date, null, context, this.separator)); 1867 }; 1868 CmdFormatter.prototype.formatRange = function (start, end, context) { 1869 return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(start, end, context, this.separator)); 1870 }; 1871 return CmdFormatter; 1872 }()); 1873 1874 var FuncFormatter = /** @class */ (function () { 1875 function FuncFormatter(func) { 1876 this.func = func; 1877 } 1878 FuncFormatter.prototype.format = function (date, context) { 1879 return this.func(createVerboseFormattingArg(date, null, context)); 1880 }; 1881 FuncFormatter.prototype.formatRange = function (start, end, context) { 1882 return this.func(createVerboseFormattingArg(start, end, context)); 1883 }; 1884 return FuncFormatter; 1885 }()); 1886 1887 // Formatter Object Creation 1888 function createFormatter(input, defaultSeparator) { 1889 if (typeof input === 'object' && input) { // non-null object 1890 if (typeof defaultSeparator === 'string') { 1891 input = __assign({ separator: defaultSeparator }, input); 1892 } 1893 return new NativeFormatter(input); 1894 } 1895 else if (typeof input === 'string') { 1896 return new CmdFormatter(input, defaultSeparator); 1897 } 1898 else if (typeof input === 'function') { 1899 return new FuncFormatter(input); 1900 } 1901 } 1902 // String Utils 1903 // timeZoneOffset is in minutes 1904 function buildIsoString(marker, timeZoneOffset, stripZeroTime) { 1905 if (stripZeroTime === void 0) { stripZeroTime = false; } 1906 var s = marker.toISOString(); 1907 s = s.replace('.000', ''); 1908 if (stripZeroTime) { 1909 s = s.replace('T00:00:00Z', ''); 1910 } 1911 if (s.length > 10) { // time part wasn't stripped, can add timezone info 1912 if (timeZoneOffset == null) { 1913 s = s.replace('Z', ''); 1914 } 1915 else if (timeZoneOffset !== 0) { 1916 s = s.replace('Z', formatTimeZoneOffset(timeZoneOffset, true)); 1917 } 1918 // otherwise, its UTC-0 and we want to keep the Z 1919 } 1920 return s; 1921 } 1922 function formatIsoTimeString(marker) { 1923 return padStart(marker.getUTCHours(), 2) + ':' + 1924 padStart(marker.getUTCMinutes(), 2) + ':' + 1925 padStart(marker.getUTCSeconds(), 2); 1926 } 1927 function formatTimeZoneOffset(minutes, doIso) { 1928 if (doIso === void 0) { doIso = false; } 1929 var sign = minutes < 0 ? '-' : '+'; 1930 var abs = Math.abs(minutes); 1931 var hours = Math.floor(abs / 60); 1932 var mins = Math.round(abs % 60); 1933 if (doIso) { 1934 return sign + padStart(hours, 2) + ':' + padStart(mins, 2); 1935 } 1936 else { 1937 return 'GMT' + sign + hours + (mins ? ':' + padStart(mins, 2) : ''); 1938 } 1939 } 1940 // Arg Utils 1941 function createVerboseFormattingArg(start, end, context, separator) { 1942 var startInfo = expandZonedMarker(start, context.calendarSystem); 1943 var endInfo = end ? expandZonedMarker(end, context.calendarSystem) : null; 1944 return { 1945 date: startInfo, 1946 start: startInfo, 1947 end: endInfo, 1948 timeZone: context.timeZone, 1949 localeCodes: context.locale.codes, 1950 separator: separator 1951 }; 1952 } 1953 function expandZonedMarker(dateInfo, calendarSystem) { 1954 var a = calendarSystem.markerToArray(dateInfo.marker); 1955 return { 1956 marker: dateInfo.marker, 1957 timeZoneOffset: dateInfo.timeZoneOffset, 1958 array: a, 1959 year: a[0], 1960 month: a[1], 1961 day: a[2], 1962 hour: a[3], 1963 minute: a[4], 1964 second: a[5], 1965 millisecond: a[6] 1966 }; 1967 } 1968 1969 var EventSourceApi = /** @class */ (function () { 1970 function EventSourceApi(calendar, internalEventSource) { 1971 this.calendar = calendar; 1972 this.internalEventSource = internalEventSource; 1973 } 1974 EventSourceApi.prototype.remove = function () { 1975 this.calendar.dispatch({
1976 type: 'REMOVE_EVENT_SOURCE', 1977 sourceId: this.internalEventSource.sourceId 1978 }); 1979 }; 1980 EventSourceApi.prototype.refetch = function () { 1981 this.calendar.dispatch({ 1982 type: 'FETCH_EVENT_SOURCES', 1983 sourceIds: [this.internalEventSource.sourceId] 1984 }); 1985 }; 1986 Object.defineProperty(EventSourceApi.prototype, "id", { 1987 get: function () { 1988 return this.internalEventSource.publicId; 1989 }, 1990 enumerable: true, 1991 configurable: true 1992 }); 1993 Object.defineProperty(EventSourceApi.prototype, "url", { 1994 // only relevant to json-feed event sources 1995 get: function () { 1996 return this.internalEventSource.meta.url; 1997 }, 1998 enumerable: true, 1999 configurable: true 2000 }); 2001 return EventSourceApi; 2002 }()); 2003 2004 var EventApi = /** @class */ (function () { 2005 function EventApi(calendar, def, instance) { 2006 this._calendar = calendar; 2007 this._def = def; 2008 this._instance = instance || null; 2009 } 2010 /* 2011 TODO: make event struct more responsible for this 2012 */ 2013 EventApi.prototype.setProp = function (name, val) { 2014 var _a, _b; 2015 if (name in DATE_PROPS) ; 2016 else if (name in NON_DATE_PROPS) { 2017 if (typeof NON_DATE_PROPS[name] === 'function') { 2018 val = NON_DATE_PROPS[name](val); 2019 } 2020 this.mutate({ 2021 standardProps: (_a = {}, _a[name] = val, _a) 2022 }); 2023 } 2024 else if (name in UNSCOPED_EVENT_UI_PROPS) { 2025 var ui = void 0; 2026 if (typeof UNSCOPED_EVENT_UI_PROPS[name] === 'function') { 2027 val = UNSCOPED_EVENT_UI_PROPS[name](val); 2028 } 2029 if (name === 'color') { 2030 ui = { backgroundColor: val, borderColor: val }; 2031 } 2032 else if (name === 'editable') { 2033 ui = { startEditable: val, durationEditable: val }; 2034 } 2035 else { 2036 ui = (_b = {}, _b[name] = val, _b); 2037 } 2038 this.mutate({ 2039 standardProps: { ui: ui } 2040 }); 2041 } 2042 }; 2043 EventApi.prototype.setExtendedProp = function (name, val) { 2044 var _a; 2045 this.mutate({ 2046 extendedProps: (_a = {}, _a[name] = val, _a) 2047 }); 2048 }; 2049 EventApi.prototype.setStart = function (startInput, options) { 2050 if (options === void 0) { options = {}; } 2051 var dateEnv = this._calendar.dateEnv; 2052 var start = dateEnv.createMarker(startInput); 2053 if (start && this._instance) { // TODO: warning if parsed bad 2054 var instanceRange = this._instance.range; 2055 var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); // what if parsed bad!? 2056 if (options.maintainDuration) { 2057 this.mutate({ datesDelta: startDelta }); 2058 } 2059 else { 2060 this.mutate({ startDelta: startDelta }); 2061 } 2062 } 2063 }; 2064 EventApi.prototype.setEnd = function (endInput, options) { 2065 if (options === void 0) { options = {}; } 2066 var dateEnv = this._calendar.dateEnv; 2067 var end; 2068 if (endInput != null) { 2069 end = dateEnv.createMarker(endInput); 2070 if (!end) { 2071 return; // TODO: warning if parsed bad 2072 } 2073 } 2074 if (this._instance) { 2075 if (end) { 2076 var endDelta = diffDates(this._instance.range.end, end, dateEnv, options.granularity); 2077 this.mutate({ endDelta: endDelta }); 2078 } 2079 else { 2080 this.mutate({ standardProps: { hasEnd: false } }); 2081 } 2082 } 2083 }; 2084 EventApi.prototype.setDates = function (startInput, endInput, options) { 2085 if (options === void 0) { options = {}; } 2086 var dateEnv = this._calendar.dateEnv; 2087 var standardProps = { allDay: options.allDay }; 2088 var start = dateEnv.createMarker(startInput); 2089 var end; 2090 if (!start) { 2091 return; // TODO: warning if parsed bad 2092 } 2093 if (endInput != null) { 2094 end = dateEnv.createMarker(endInput); 2095 if (!end) { // TODO: warning if parsed bad 2096 return; 2097 } 2098 } 2099 if (this._instance) { 2100 var instanceRange = this._instance.range; 2101 // when computing the diff for an event being converted to all-day, 2102 // compute diff off of the all-day values the way event-mutation does. 2103 if (options.allDay === true) { 2104 instanceRange = computeAlignedDayRange(instanceRange); 2105 } 2106 var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); 2107 if (end) { 2108 var endDelta = diffDates(instanceRange.end, end, dateEnv, options.granularity); 2109 if (durationsEqual(startDelta, endDelta)) { 2110 this.mutate({ datesDelta: startDelta, standardProps: standardProps }); 2111 } 2112 else { 2113 this.mutate({ startDelta: startDelta, endDelta: endDelta, standardProps: standardProps }); 2114 } 2115 } 2116 else { // means "clear the end" 2117 standardProps.hasEnd = false;
2118 this.mutate({ datesDelta: startDelta, standardProps: standardProps }); 2119 } 2120 } 2121 }; 2122 EventApi.prototype.moveStart = function (deltaInput) { 2123 var delta = createDuration(deltaInput); 2124 if (delta) { // TODO: warning if parsed bad 2125 this.mutate({ startDelta: delta }); 2126 } 2127 }; 2128 EventApi.prototype.moveEnd = function (deltaInput) { 2129 var delta = createDuration(deltaInput); 2130 if (delta) { // TODO: warning if parsed bad 2131 this.mutate({ endDelta: delta }); 2132 } 2133 }; 2134 EventApi.prototype.moveDates = function (deltaInput) { 2135 var delta = createDuration(deltaInput); 2136 if (delta) { // TODO: warning if parsed bad 2137 this.mutate({ datesDelta: delta }); 2138 } 2139 }; 2140 EventApi.prototype.setAllDay = function (allDay, options) { 2141 if (options === void 0) { options = {}; } 2142 var standardProps = { allDay: allDay }; 2143 var maintainDuration = options.maintainDuration; 2144 if (maintainDuration == null) { 2145 maintainDuration = this._calendar.opt('allDayMaintainDuration'); 2146 } 2147 if (this._def.allDay !== allDay) { 2148 standardProps.hasEnd = maintainDuration; 2149 } 2150 this.mutate({ standardProps: standardProps }); 2151 }; 2152 EventApi.prototype.formatRange = function (formatInput) { 2153 var dateEnv = this._calendar.dateEnv; 2154 var instance = this._instance; 2155 var formatter = createFormatter(formatInput, this._calendar.opt('defaultRangeSeparator')); 2156 if (this._def.hasEnd) { 2157 return dateEnv.formatRange(instance.range.start, instance.range.end, formatter, { 2158 forcedStartTzo: instance.forcedStartTzo, 2159 forcedEndTzo: instance.forcedEndTzo 2160 }); 2161 } 2162 else { 2163 return dateEnv.format(instance.range.start, formatter, { 2164 forcedTzo: instance.forcedStartTzo 2165 }); 2166 } 2167 }; 2168 EventApi.prototype.mutate = function (mutation) { 2169 var def = this._def; 2170 var instance = this._instance; 2171 if (instance) { 2172 this._calendar.dispatch({ 2173 type: 'MUTATE_EVENTS', 2174 instanceId: instance.instanceId, 2175 mutation: mutation, 2176 fromApi: true 2177 }); 2178 var eventStore = this._calendar.state.eventStore; 2179 this._def = eventStore.defs[def.defId]; 2180 this._instance = eventStore.instances[instance.instanceId]; 2181 } 2182 }; 2183 EventApi.prototype.remove = function () { 2184 this._calendar.dispatch({ 2185 type: 'REMOVE_EVENT_DEF', 2186 defId: this._def.defId 2187 }); 2188 }; 2189 Object.defineProperty(EventApi.prototype, "source", { 2190 get: function () { 2191 var sourceId = this._def.sourceId; 2192 if (sourceId) { 2193 return new EventSourceApi(this._calendar, this._calendar.state.eventSources[sourceId]); 2194 } 2195 return null; 2196 }, 2197 enumerable: true, 2198 configurable: true 2199 }); 2200 Object.defineProperty(EventApi.prototype, "start", { 2201 get: function () { 2202 return this._instance ? 2203 this._calendar.dateEnv.toDate(this._instance.range.start) : 2204 null; 2205 }, 2206 enumerable: true, 2207 configurable: true 2208 }); 2209 Object.defineProperty(EventApi.prototype, "end", { 2210 get: function () { 2211 return (this._instance && this._def.hasEnd) ? 2212 this._calendar.dateEnv.toDate(this._instance.range.end) : 2213 null; 2214 }, 2215 enumerable: true, 2216 configurable: true 2217 }); 2218 Object.defineProperty(EventApi.prototype, "id", { 2219 // computable props that all access the def
2220 // TODO: find a TypeScript-compatible way to do this at scale 2221 get: function () { return this._def.publicId; }, 2222 enumerable: true, 2223 configurable: true 2224 }); 2225 Object.defineProperty(EventApi.prototype, "groupId", { 2226 get: function () { return this._def.groupId; }, 2227 enumerable: true, 2228 configurable: true 2229 }); 2230 Object.defineProperty(EventApi.prototype, "allDay", { 2231 get: function () { return this._def.allDay; }, 2232 enumerable: true, 2233 configurable: true 2234 }); 2235 Object.defineProperty(EventApi.prototype, "title", { 2236 get: function () { return this._def.title; }, 2237 enumerable: true, 2238 configurable: true 2239 }); 2240 Object.defineProperty(EventApi.prototype, "url", { 2241 get: function () { return this._def.url; }, 2242 enumerable: true, 2243 configurable: true 2244 }); 2245 Object.defineProperty(EventApi.prototype, "rendering", { 2246 get: function () { return this._def.rendering; }, 2247 enumerable: true, 2248 configurable: true 2249 }); 2250 Object.defineProperty(EventApi.prototype, "startEditable", { 2251 get: function () { return this._def.ui.startEditable; }, 2252 enumerable: true, 2253 configurable: true 2254 }); 2255 Object.defineProperty(EventApi.prototype, "durationEditable", { 2256 get: function () { return this._def.ui.durationEditable; }, 2257 enumerable: true, 2258 configurable: true 2259 }); 2260 Object.defineProperty(EventApi.prototype, "constraint", { 2261 get: function () { return this._def.ui.constraints[0] || null; }, 2262 enumerable: true, 2263 configurable: true 2264 }); 2265 Object.defineProperty(EventApi.prototype, "overlap", { 2266 get: function () { return this._def.ui.overlap; }, 2267 enumerable: true, 2268 configurable: true 2269 }); 2270 Object.defineProperty(EventApi.prototype, "allow", { 2271 get: function () { return this._def.ui.allows[0] || null; }, 2272 enumerable: true, 2273 configurable: true 2274 }); 2275 Object.defineProperty(EventApi.prototype, "backgroundColor", { 2276 get: function () { return this._def.ui.backgroundColor; }, 2277 enumerable: true, 2278 configurable: true 2279 }); 2280 Object.defineProperty(EventApi.prototype, "borderColor", { 2281 get: function () { return this._def.ui.borderColor; }, 2282 enumerable: true, 2283 configurable: true 2284 }); 2285 Object.defineProperty(EventApi.prototype, "textColor", { 2286 get: function () { return this._def.ui.textColor; }, 2287 enumerable: true, 2288 configurable: true 2289 }); 2290 Object.defineProperty(EventApi.prototype, "classNames", { 2291 // NOTE: user can't modify these because Object.freeze was called in event-def parsing 2292 get: function () { return this._def.ui.classNames; }, 2293 enumerable: true, 2294 configurable: true 2295 }); 2296 Object.defineProperty(EventApi.prototype, "extendedProps", { 2297 get: function () { return this._def.extendedProps; }, 2298 enumerable: true, 2299 configurable: true 2300 }); 2301 return EventApi; 2302 }()); 2303 2304 /* 2305 Specifying nextDayThreshold signals that all-day ranges should be sliced. 2306 */ 2307 function sliceEventStore(eventStore, eventUiBases, framingRange, nextDayThreshold) { 2308 var inverseBgByGroupId = {}; 2309 var inverseBgByDefId = {}; 2310 var defByGroupId = {}; 2311 var bgRanges = []; 2312 var fgRanges = []; 2313 var eventUis = compileEventUis(eventStore.defs, eventUiBases); 2314 for (var defId in eventStore.defs) { 2315 var def = eventStore.defs[defId]; 2316 if (def.rendering === 'inverse-background') { 2317 if (def.groupId) { 2318 inverseBgByGroupId[def.groupId] = []; 2319 if (!defByGroupId[def.groupId]) { 2320 defByGroupId[def.groupId] = def; 2321 } 2322 } 2323 else { 2324 inverseBgByDefId[defId] = []; 2325 } 2326 } 2327 } 2328 for (var instanceId in eventStore.instances) { 2329 var instance = eventStore.instances[instanceId]; 2330 var def = eventStore.defs[instance.defId]; 2331 var ui = eventUis[def.defId]; 2332 var origRange = instance.range; 2333 var normalRange = (!def.allDay && nextDayThreshold) ? 2334 computeVisibleDayRange(origRange, nextDayThreshold) : 2335 origRange; 2336 var slicedRange = intersectRanges(normalRange, framingRange); 2337 if (slicedRange) { 2338 if (def.rendering === 'inverse-background') { 2339 if (def.groupId) { 2340 inverseBgByGroupId[def.groupId].push(slicedRange); 2341 } 2342 else { 2343 inverseBgByDefId[instance.defId].push(slicedRange); 2344 } 2345 } 2346 else { 2347 (def.rendering === 'background' ? bgRanges : fgRanges).push({ 2348 def: def, 2349 ui: ui, 2350 instance: instance, 2351 range: slicedRange, 2352 isStart: normalRange.start && normalRange.start.valueOf() === slicedRange.start.valueOf(), 2353 isEnd: normalRange.end && normalRange.end.valueOf() === slicedRange.end.valueOf() 2354 }); 2355 } 2356 } 2357 } 2358 for (var groupId in inverseBgByGroupId) { // BY GROUP 2359 var ranges = inverseBgByGroupId[groupId]; 2360 var invertedRanges = invertRanges(ranges, framingRange); 2361 for (var _i = 0, invertedRanges_1 = invertedRanges; _i < invertedRanges_1.length; _i++) { 2362 var invertedRange = invertedRanges_1[_i]; 2363 var def = defByGroupId[groupId]; 2364 var ui = eventUis[def.defId]; 2365 bgRanges.push({ 2366 def: def, 2367 ui: ui, 2368 instance: null, 2369 range: invertedRange, 2370 isStart: false, 2371 isEnd: false 2372 }); 2373 } 2374 } 2375 for (var defId in inverseBgByDefId) { 2376 var ranges = inverseBgByDefId[defId]; 2377 var invertedRanges = invertRanges(ranges, framingRange); 2378 for (var _a = 0, invertedRanges_2 = invertedRanges; _a < invertedRanges_2.length; _a++) { 2379 var invertedRange = invertedRanges_2[_a]; 2380 bgRanges.push({ 2381 def: eventStore.defs[defId], 2382 ui: eventUis[defId], 2383 instance: null, 2384 range: invertedRange, 2385 isStart: false, 2386 isEnd: false 2387 }); 2388 } 2389 } 2390 return { bg: bgRanges, fg: fgRanges }; 2391 } 2392 function hasBgRendering(def) { 2393 return def.rendering === 'background' || def.rendering === 'inverse-background'; 2394 } 2395 function filterSegsViaEls(view, segs, isMirror) { 2396 if (view.hasPublicHandlers('eventRender')) { 2397 segs = segs.filter(function (seg) { 2398 var custom = view.publiclyTrigger('eventRender', [ 2399 { 2400 event: new EventApi(view.calendar, seg.eventRange.def, seg.eventRange.instance), 2401 isMirror: isMirror, 2402 isStart: seg.isStart, 2403 isEnd: seg.isEnd, 2404 // TODO: include seg.range once all components consistently generate it 2405 el: seg.el, 2406 view: view 2407 } 2408 ]); 2409 if (custom === false) { // means don't render at all 2410 return false;
2411 } 2412 else if (custom && custom !== true) { 2413 seg.el = custom; 2414 } 2415 return true; 2416 }); 2417 } 2418 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 2419 var seg = segs_1[_i]; 2420 setElSeg(seg.el, seg); 2421 } 2422 return segs; 2423 } 2424 function setElSeg(el, seg) { 2425 el.fcSeg = seg; 2426 } 2427 function getElSeg(el) { 2428 return el.fcSeg || null; 2429 } 2430 // event ui computation 2431 function compileEventUis(eventDefs, eventUiBases) { 2432 return mapHash(eventDefs, function (eventDef) { 2433 return compileEventUi(eventDef, eventUiBases); 2434 }); 2435 } 2436 function compileEventUi(eventDef, eventUiBases) { 2437 var uis = []; 2438 if (eventUiBases['']) { 2439 uis.push(eventUiBases['']); 2440 } 2441 if (eventUiBases[eventDef.defId]) { 2442 uis.push(eventUiBases[eventDef.defId]); 2443 } 2444 uis.push(eventDef.ui); 2445 return combineEventUis(uis); 2446 } 2447 2448 // applies the mutation to ALL defs/instances within the event store 2449 function applyMutationToEventStore(eventStore, eventConfigBase, mutation, calendar) { 2450 var eventConfigs = compileEventUis(eventStore.defs, eventConfigBase); 2451 var dest = createEmptyEventStore(); 2452 for (var defId in eventStore.defs) { 2453 var def = eventStore.defs[defId]; 2454 dest.defs[defId] = applyMutationToEventDef(def, eventConfigs[defId], mutation, calendar.pluginSystem.hooks.eventDefMutationAppliers, calendar); 2455 } 2456 for (var instanceId in eventStore.instances) { 2457 var instance = eventStore.instances[instanceId]; 2458 var def = dest.defs[instance.defId]; // important to grab the newly modified def 2459 dest.instances[instanceId] = applyMutationToEventInstance(instance, def, eventConfigs[instance.defId], mutation, calendar); 2460 } 2461 return dest; 2462 } 2463 function applyMutationToEventDef(eventDef, eventConfig, mutation, appliers, calendar) { 2464 var standardProps = mutation.standardProps || {}; 2465 // if hasEnd has not been specified, guess a good value based on deltas. 2466 // if duration will change, there's no way the default duration will persist, 2467 // and thus, we need to mark the event as having a real end 2468 if (standardProps.hasEnd == null && 2469 eventConfig.durationEditable && 2470 (mutation.startDelta || mutation.endDelta)) { 2471 standardProps.hasEnd = true; // TODO: is this mutation okay? 2472 } 2473 var copy = __assign({}, eventDef, standardProps, { ui: __assign({}, eventDef.ui, standardProps.ui) }); 2474 if (mutation.extendedProps) { 2475 copy.extendedProps = __assign({}, copy.extendedProps, mutation.extendedProps); 2476 } 2477 for (var _i = 0, appliers_1 = appliers; _i < appliers_1.length; _i++) { 2478 var applier = appliers_1[_i]; 2479 applier(copy, mutation, calendar); 2480 } 2481 if (!copy.hasEnd && calendar.opt('forceEventDuration')) { 2482 copy.hasEnd = true; 2483 } 2484 return copy; 2485 } 2486 function applyMutationToEventInstance(eventInstance, eventDef, // must first be modified by applyMutationToEventDef 2487 eventConfig, mutation, calendar) { 2488 var dateEnv = calendar.dateEnv; 2489 var forceAllDay = mutation.standardProps && mutation.standardProps.allDay === true; 2490 var clearEnd = mutation.standardProps && mutation.standardProps.hasEnd === false; 2491 var copy = __assign({}, eventInstance); 2492 if (forceAllDay) { 2493 copy.range = computeAlignedDayRange(copy.range); 2494 } 2495 if (mutation.datesDelta && eventConfig.startEditable) { 2496 copy.range = { 2497 start: dateEnv.add(copy.range.start, mutation.datesDelta), 2498 end: dateEnv.add(copy.range.end, mutation.datesDelta) 2499 }; 2500 } 2501 if (mutation.startDelta && eventConfig.durationEditable) { 2502 copy.range = { 2503 start: dateEnv.add(copy.range.start, mutation.startDelta), 2504 end: copy.range.end 2505 }; 2506 } 2507 if (mutation.endDelta && eventConfig.durationEditable) { 2508 copy.range = { 2509 start: copy.range.start, 2510 end: dateEnv.add(copy.range.end, mutation.endDelta) 2511 }; 2512 } 2513 if (clearEnd) { 2514 copy.range = { 2515 start: copy.range.start, 2516 end: calendar.getDefaultEventEnd(eventDef.allDay, copy.range.start) 2517 }; 2518 } 2519 // in case event was all-day but the supplied deltas were not 2520 // better util for this? 2521 if (eventDef.allDay) { 2522 copy.range = { 2523 start: startOfDay(copy.range.start), 2524 end: startOfDay(copy.range.end) 2525 }; 2526 } 2527 // handle invalid durations 2528 if (copy.range.end < copy.range.start) { 2529 copy.range.end = calendar.getDefaultEventEnd(eventDef.allDay, copy.range.start); 2530 } 2531 return copy; 2532 } 2533 2534 function reduceEventStore (eventStore, action, eventSources, dateProfile, calendar) { 2535 switch (action.type) { 2536 case 'RECEIVE_EVENTS': // raw 2537 return receiveRawEvents(eventStore, eventSources[action.sourceId], action.fetchId, action.fetchRange, action.rawEvents, calendar); 2538 case 'ADD_EVENTS': // already parsed, but not expanded 2539 return addEvent(eventStore, action.eventStore, // new ones 2540 dateProfile ? dateProfile.activeRange : null, calendar); 2541 case 'MERGE_EVENTS': // already parsed and expanded 2542 return mergeEventStores(eventStore, action.eventStore); 2543 case 'PREV': // TODO: how do we track all actions that affect dateProfile :( 2544 case 'NEXT': 2545 case 'SET_DATE': 2546 case 'SET_VIEW_TYPE': 2547 if (dateProfile) { 2548 return expandRecurring(eventStore, dateProfile.activeRange, calendar); 2549 } 2550 else { 2551 return eventStore; 2552 } 2553 case 'CHANGE_TIMEZONE': 2554 return rezoneDates(eventStore, action.oldDateEnv, calendar.dateEnv); 2555 case 'MUTATE_EVENTS': 2556 return applyMutationToRelated(eventStore, action.instanceId, action.mutation, action.fromApi, calendar);
2557 case 'REMOVE_EVENT_INSTANCES': 2558 return excludeInstances(eventStore, action.instances); 2559 case 'REMOVE_EVENT_DEF': 2560 return filterEventStoreDefs(eventStore, function (eventDef) { 2561 return eventDef.defId !== action.defId; 2562 }); 2563 case 'REMOVE_EVENT_SOURCE': 2564 return excludeEventsBySourceId(eventStore, action.sourceId); 2565 case 'REMOVE_ALL_EVENT_SOURCES': 2566 return filterEventStoreDefs(eventStore, function (eventDef) { 2567 return !eventDef.sourceId; // only keep events with no source id 2568 }); 2569 case 'REMOVE_ALL_EVENTS': 2570 return createEmptyEventStore(); 2571 case 'RESET_EVENTS': 2572 return { 2573 defs: eventStore.defs, 2574 instances: eventStore.instances 2575 }; 2576 default: 2577 return eventStore; 2578 } 2579 } 2580 function receiveRawEvents(eventStore, eventSource, fetchId, fetchRange, rawEvents, calendar) { 2581 if (eventSource && // not already removed 2582 fetchId === eventSource.latestFetchId // TODO: wish this logic was always in event-sources 2583 ) { 2584 var subset = parseEvents(transformRawEvents(rawEvents, eventSource, calendar), eventSource.sourceId, calendar); 2585 if (fetchRange) { 2586 subset = expandRecurring(subset, fetchRange, calendar); 2587 } 2588 return mergeEventStores(excludeEventsBySourceId(eventStore, eventSource.sourceId), subset); 2589 } 2590 return eventStore; 2591 } 2592 function addEvent(eventStore, subset, expandRange, calendar) { 2593 if (expandRange) { 2594 subset = expandRecurring(subset, expandRange, calendar); 2595 } 2596 return mergeEventStores(eventStore, subset); 2597 } 2598 function rezoneDates(eventStore, oldDateEnv, newDateEnv) { 2599 var defs = eventStore.defs; 2600 var instances = mapHash(eventStore.instances, function (instance) { 2601 var def = defs[instance.defId]; 2602 if (def.allDay || def.recurringDef) { 2603 return instance; // isn't dependent on timezone 2604 } 2605 else { 2606 return __assign({}, instance, { range: { 2607 start: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.start, instance.forcedStartTzo)), 2608 end: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.end, instance.forcedEndTzo)) 2609 }, forcedStartTzo: newDateEnv.canComputeOffset ? null : instance.forcedStartTzo, forcedEndTzo: newDateEnv.canComputeOffset ? null : instance.forcedEndTzo }); 2610 } 2611 }); 2612 return { defs: defs, instances: instances }; 2613 } 2614 function applyMutationToRelated(eventStore, instanceId, mutation, fromApi, calendar) { 2615 var relevant = getRelevantEvents(eventStore, instanceId); 2616 var eventConfigBase = fromApi ? 2617 { '': { 2618 startEditable: true, 2619 durationEditable: true, 2620 constraints: [], 2621 overlap: null, 2622 allows: [], 2623 backgroundColor: '', 2624 borderColor: '', 2625 textColor: '', 2626 classNames: [] 2627 } } : 2628 calendar.eventUiBases; 2629 relevant = applyMutationToEventStore(relevant, eventConfigBase, mutation, calendar); 2630 return mergeEventStores(eventStore, relevant); 2631 } 2632 function excludeEventsBySourceId(eventStore, sourceId) { 2633 return filterEventStoreDefs(eventStore, function (eventDef) { 2634 return eventDef.sourceId !== sourceId; 2635 }); 2636 } 2637 // QUESTION: why not just return instances? do a general object-property-exclusion util 2638 function excludeInstances(eventStore, removals) { 2639 return { 2640 defs: eventStore.defs, 2641 instances: filterHash(eventStore.instances, function (instance) { 2642 return !removals[instance.instanceId]; 2643 }) 2644 }; 2645 } 2646 2647 // high-level segmenting-aware tester functions 2648 // ------------------------------------------------------------------------------------------------------------------------ 2649 function isInteractionValid(interaction, calendar) { 2650 return isNewPropsValid({ eventDrag: interaction }, calendar); // HACK: the eventDrag props is used for ALL interactions 2651 } 2652 function isDateSelectionValid(dateSelection, calendar) { 2653 return isNewPropsValid({ dateSelection: dateSelection }, calendar); 2654 } 2655 function isNewPropsValid(newProps, calendar) { 2656 var view = calendar.view; 2657 var props = __assign({ businessHours: view ? view.props.businessHours : createEmptyEventStore(), dateSelection: '', eventStore: calendar.state.eventStore, eventUiBases: calendar.eventUiBases, eventSelection: '', eventDrag: null, eventResize: null }, newProps); 2658 return (calendar.pluginSystem.hooks.isPropsValid || isPropsValid)(props, calendar); 2659 } 2660 function isPropsValid(state, calendar, dateSpanMeta, filterConfig) {
2661 if (dateSpanMeta === void 0) { dateSpanMeta = {}; } 2662 if (state.eventDrag && !isInteractionPropsValid(state, calendar, dateSpanMeta, filterConfig)) { 2663 return false; 2664 } 2665 if (state.dateSelection && !isDateSelectionPropsValid(state, calendar, dateSpanMeta, filterConfig)) { 2666 return false; 2667 } 2668 return true; 2669 } 2670 // Moving Event Validation 2671 // ------------------------------------------------------------------------------------------------------------------------ 2672 function isInteractionPropsValid(state, calendar, dateSpanMeta, filterConfig) { 2673 var interaction = state.eventDrag; // HACK: the eventDrag props is used for ALL interactions 2674 var subjectEventStore = interaction.mutatedEvents; 2675 var subjectDefs = subjectEventStore.defs; 2676 var subjectInstances = subjectEventStore.instances; 2677 var subjectConfigs = compileEventUis(subjectDefs, interaction.isEvent ? 2678 state.eventUiBases : 2679 { '': calendar.selectionConfig } // if not a real event, validate as a selection 2680 ); 2681 if (filterConfig) { 2682 subjectConfigs = mapHash(subjectConfigs, filterConfig); 2683 } 2684 var otherEventStore = excludeInstances(state.eventStore, interaction.affectedEvents.instances); // exclude the subject events. TODO: exclude defs too? 2685 var otherDefs = otherEventStore.defs; 2686 var otherInstances = otherEventStore.instances; 2687 var otherConfigs = compileEventUis(otherDefs, state.eventUiBases); 2688 for (var subjectInstanceId in subjectInstances) { 2689 var subjectInstance = subjectInstances[subjectInstanceId]; 2690 var subjectRange = subjectInstance.range; 2691 var subjectConfig = subjectConfigs[subjectInstance.defId]; 2692 var subjectDef = subjectDefs[subjectInstance.defId]; 2693 // constraint 2694 if (!allConstraintsPass(subjectConfig.constraints, subjectRange, otherEventStore, state.businessHours, calendar)) { 2695 return false; 2696 } 2697 // overlap 2698 var overlapFunc = calendar.opt('eventOverlap'); 2699 if (typeof overlapFunc !== 'function') { 2700 overlapFunc = null; 2701 } 2702 for (var otherInstanceId in otherInstances) { 2703 var otherInstance = otherInstances[otherInstanceId]; 2704 // intersect! evaluate 2705 if (rangesIntersect(subjectRange, otherInstance.range)) { 2706 var otherOverlap = otherConfigs[otherInstance.defId].overlap; 2707 // consider the other event's overlap. only do this if the subject event is a "real" event 2708 if (otherOverlap === false && interaction.isEvent) { 2709 return false; 2710 } 2711 if (subjectConfig.overlap === false) { 2712 return false; 2713 } 2714 if (overlapFunc && !overlapFunc(new EventApi(calendar, otherDefs[otherInstance.defId], otherInstance), // still event 2715 new EventApi(calendar, subjectDef, subjectInstance) // moving event 2716 )) { 2717 return false; 2718 } 2719 } 2720 } 2721 // allow (a function) 2722 var calendarEventStore = calendar.state.eventStore; // need global-to-calendar, not local to component (splittable)state 2723 for (var _i = 0, _a = subjectConfig.allows; _i < _a.length; _i++) { 2724 var subjectAllow = _a[_i]; 2725 var subjectDateSpan = __assign({}, dateSpanMeta, { range: subjectInstance.range, allDay: subjectDef.allDay }); 2726 var origDef = calendarEventStore.defs[subjectDef.defId]; 2727 var origInstance = calendarEventStore.instances[subjectInstanceId]; 2728 var eventApi = void 0; 2729 if (origDef) { // was previously in the calendar 2730 eventApi = new EventApi(calendar, origDef, origInstance); 2731 } 2732 else { // was an external event 2733 eventApi = new EventApi(calendar, subjectDef); // no instance, because had no dates 2734 } 2735 if (!subjectAllow(calendar.buildDateSpanApi(subjectDateSpan), eventApi)) { 2736 return false;
2737 } 2738 } 2739 } 2740 return true; 2741 } 2742 // Date Selection Validation 2743 // ------------------------------------------------------------------------------------------------------------------------ 2744 function isDateSelectionPropsValid(state, calendar, dateSpanMeta, filterConfig) { 2745 var relevantEventStore = state.eventStore; 2746 var relevantDefs = relevantEventStore.defs; 2747 var relevantInstances = relevantEventStore.instances; 2748 var selection = state.dateSelection; 2749 var selectionRange = selection.range; 2750 var selectionConfig = calendar.selectionConfig; 2751 if (filterConfig) { 2752 selectionConfig = filterConfig(selectionConfig); 2753 } 2754 // constraint 2755 if (!allConstraintsPass(selectionConfig.constraints, selectionRange, relevantEventStore, state.businessHours, calendar)) { 2756 return false; 2757 } 2758 // overlap 2759 var overlapFunc = calendar.opt('selectOverlap'); 2760 if (typeof overlapFunc !== 'function') { 2761 overlapFunc = null; 2762 } 2763 for (var relevantInstanceId in relevantInstances) { 2764 var relevantInstance = relevantInstances[relevantInstanceId]; 2765 // intersect! evaluate 2766 if (rangesIntersect(selectionRange, relevantInstance.range)) { 2767 if (selectionConfig.overlap === false) { 2768 return false; 2769 } 2770 if (overlapFunc && !overlapFunc(new EventApi(calendar, relevantDefs[relevantInstance.defId], relevantInstance))) { 2771 return false; 2772 } 2773 } 2774 } 2775 // allow (a function) 2776 for (var _i = 0, _a = selectionConfig.allows; _i < _a.length; _i++) { 2777 var selectionAllow = _a[_i]; 2778 var fullDateSpan = __assign({}, dateSpanMeta, selection); 2779 if (!selectionAllow(calendar.buildDateSpanApi(fullDateSpan), null)) { 2780 return false; 2781 } 2782 } 2783 return true; 2784 } 2785 // Constraint Utils 2786 // ------------------------------------------------------------------------------------------------------------------------ 2787 function allConstraintsPass(constraints, subjectRange, otherEventStore, businessHoursUnexpanded, calendar) { 2788 for (var _i = 0, constraints_1 = constraints; _i < constraints_1.length; _i++) { 2789 var constraint = constraints_1[_i]; 2790 if (!anyRangesContainRange(constraintToRanges(constraint, subjectRange, otherEventStore, businessHoursUnexpanded, calendar), subjectRange)) { 2791 return false; 2792 } 2793 } 2794 return true; 2795 } 2796 function constraintToRanges(constraint, subjectRange, // for expanding a recurring constraint, or expanding business hours 2797 otherEventStore, // for if constraint is an even group ID 2798 businessHoursUnexpanded, // for if constraint is 'businessHours' 2799 calendar // for expanding businesshours 2800 ) { 2801 if (constraint === 'businessHours') { 2802 return eventStoreToRanges(expandRecurring(businessHoursUnexpanded, subjectRange, calendar)); 2803 } 2804 else if (typeof constraint === 'string') { // an group ID 2805 return eventStoreToRanges(filterEventStoreDefs(otherEventStore, function (eventDef) { 2806 return eventDef.groupId === constraint; 2807 })); 2808 } 2809 else if (typeof constraint === 'object' && constraint) { // non-null object 2810 return eventStoreToRanges(expandRecurring(constraint, subjectRange, calendar)); 2811 } 2812 return []; // if it's false 2813 } 2814 // TODO: move to event-store file? 2815 function eventStoreToRanges(eventStore) { 2816 var instances = eventStore.instances; 2817 var ranges = []; 2818 for (var instanceId in instances) { 2819 ranges.push(instances[instanceId].range); 2820 } 2821 return ranges; 2822 } 2823 // TODO: move to geom file? 2824 function anyRangesContainRange(outerRanges, innerRange) { 2825 for (var _i = 0, outerRanges_1 = outerRanges; _i < outerRanges_1.length; _i++) { 2826 var outerRange = outerRanges_1[_i]; 2827 if (rangeContainsRange(outerRange, innerRange)) { 2828 return true; 2829 } 2830 } 2831 return false;
2832 } 2833 // Parsing 2834 // ------------------------------------------------------------------------------------------------------------------------ 2835 function normalizeConstraint(input, calendar) { 2836 if (Array.isArray(input)) { 2837 return parseEvents(input, '', calendar, true); // allowOpenRange=true 2838 } 2839 else if (typeof input === 'object' && input) { // non-null object 2840 return parseEvents([input], '', calendar, true); // allowOpenRange=true 2841 } 2842 else if (input != null) { 2843 return String(input); 2844 } 2845 else { 2846 return null; 2847 } 2848 } 2849 2850 function htmlEscape(s) { 2851 return (s + '').replace(/&/g, '&') 2852 .replace(/</g, '<') 2853 .replace(/>/g, '>') 2854 .replace(/'/g, ''') 2855 .replace(/"/g, '"') 2856 .replace(/\n/g, '<br />'); 2857 } 2858 // Given a hash of CSS properties, returns a string of CSS. 2859 // Uses property names as-is (no camel-case conversion). Will not make statements for null/undefined values. 2860 function cssToStr(cssProps) { 2861 var statements = []; 2862 for (var name_1 in cssProps) { 2863 var val = cssProps[name_1]; 2864 if (val != null && val !== '') { 2865 statements.push(name_1 + ':' + val); 2866 } 2867 } 2868 return statements.join(';'); 2869 } 2870 // Given an object hash of HTML attribute names to values, 2871 // generates a string that can be injected between < > in HTML 2872 function attrsToStr(attrs) { 2873 var parts = []; 2874 for (var name_2 in attrs) { 2875 var val = attrs[name_2]; 2876 if (val != null) { 2877 parts.push(name_2 + '="' + htmlEscape(val) + '"'); 2878 } 2879 } 2880 return parts.join(' '); 2881 } 2882 function parseClassName(raw) { 2883 if (Array.isArray(raw)) { 2884 return raw; 2885 } 2886 else if (typeof raw === 'string') { 2887 return raw.split(/\s+/); 2888 } 2889 else { 2890 return []; 2891 } 2892 } 2893 2894 var UNSCOPED_EVENT_UI_PROPS = { 2895 editable: Boolean, 2896 startEditable: Boolean, 2897 durationEditable: Boolean, 2898 constraint: null, 2899 overlap: null, 2900 allow: null, 2901 className: parseClassName, 2902 classNames: parseClassName, 2903 color: String, 2904 backgroundColor: String, 2905 borderColor: String, 2906 textColor: String 2907 }; 2908 function processUnscopedUiProps(rawProps, calendar, leftovers) { 2909 var props = refineProps(rawProps, UNSCOPED_EVENT_UI_PROPS, {}, leftovers); 2910 var constraint = normalizeConstraint(props.constraint, calendar); 2911 return { 2912 startEditable: props.startEditable != null ? props.startEditable : props.editable, 2913 durationEditable: props.durationEditable != null ? props.durationEditable : props.editable, 2914 constraints: constraint != null ? [constraint] : [], 2915 overlap: props.overlap, 2916 allows: props.allow != null ? [props.allow] : [], 2917 backgroundColor: props.backgroundColor || props.color, 2918 borderColor: props.borderColor || props.color, 2919 textColor: props.textColor, 2920 classNames: props.classNames.concat(props.className) 2921 }; 2922 } 2923 function processScopedUiProps(prefix, rawScoped, calendar, leftovers) { 2924 var rawUnscoped = {}; 2925 var wasFound = {}; 2926 for (var key in UNSCOPED_EVENT_UI_PROPS) { 2927 var scopedKey = prefix + capitaliseFirstLetter(key); 2928 rawUnscoped[key] = rawScoped[scopedKey]; 2929 wasFound[scopedKey] = true; 2930 } 2931 if (prefix === 'event') { 2932 rawUnscoped.editable = rawScoped.editable; // special case. there is no 'eventEditable', just 'editable' 2933 } 2934 if (leftovers) { 2935 for (var key in rawScoped) { 2936 if (!wasFound[key]) { 2937 leftovers[key] = rawScoped[key]; 2938 } 2939 } 2940 } 2941 return processUnscopedUiProps(rawUnscoped, calendar); 2942 } 2943 var EMPTY_EVENT_UI = { 2944 startEditable: null, 2945 durationEditable: null, 2946 constraints: [], 2947 overlap: null, 2948 allows: [], 2949 backgroundColor: '', 2950 borderColor: '', 2951 textColor: '', 2952 classNames: [] 2953 }; 2954 // prevent against problems with <2 args! 2955 function combineEventUis(uis) { 2956 return uis.reduce(combineTwoEventUis, EMPTY_EVENT_UI); 2957 } 2958 function combineTwoEventUis(item0, item1) { 2959 return { 2960 startEditable: item1.startEditable != null ? item1.startEditable : item0.startEditable, 2961 durationEditable: item1.durationEditable != null ? item1.durationEditable : item0.durationEditable, 2962 constraints: item0.constraints.concat(item1.constraints), 2963 overlap: typeof item1.overlap === 'boolean' ? item1.overlap : item0.overlap, 2964 allows: item0.allows.concat(item1.allows), 2965 backgroundColor: item1.backgroundColor || item0.backgroundColor, 2966 borderColor: item1.borderColor || item0.borderColor, 2967 textColor: item1.textColor || item0.textColor,
2968 classNames: item0.classNames.concat(item1.classNames) 2969 }; 2970 } 2971 2972 var NON_DATE_PROPS = { 2973 id: String, 2974 groupId: String, 2975 title: String, 2976 url: String, 2977 rendering: String, 2978 extendedProps: null 2979 }; 2980 var DATE_PROPS = { 2981 start: null, 2982 date: null, 2983 end: null, 2984 allDay: null 2985 }; 2986 var uid = 0; 2987 function parseEvent(raw, sourceId, calendar, allowOpenRange) { 2988 var allDayDefault = computeIsAllDayDefault(sourceId, calendar); 2989 var leftovers0 = {}; 2990 var recurringRes = parseRecurring(raw, // raw, but with single-event stuff stripped out 2991 allDayDefault, calendar.dateEnv, calendar.pluginSystem.hooks.recurringTypes, leftovers0 // will populate with non-recurring props 2992 ); 2993 if (recurringRes) { 2994 var def = parseEventDef(leftovers0, sourceId, recurringRes.allDay, Boolean(recurringRes.duration), calendar); 2995 def.recurringDef = { 2996 typeId: recurringRes.typeId, 2997 typeData: recurringRes.typeData, 2998 duration: recurringRes.duration 2999 }; 3000 return { def: def, instance: null }; 3001 } 3002 else { 3003 var leftovers1 = {}; 3004 var singleRes = parseSingle(raw, allDayDefault, calendar, leftovers1, allowOpenRange); 3005 if (singleRes) { 3006 var def = parseEventDef(leftovers1, sourceId, singleRes.allDay, singleRes.hasEnd, calendar); 3007 var instance = createEventInstance(def.defId, singleRes.range, singleRes.forcedStartTzo, singleRes.forcedEndTzo); 3008 return { def: def, instance: instance }; 3009 } 3010 } 3011 return null; 3012 } 3013 /* 3014 Will NOT populate extendedProps with the leftover properties. 3015 Will NOT populate date-related props. 3016 The EventNonDateInput has been normalized (id => publicId, etc). 3017 */ 3018 function parseEventDef(raw, sourceId, allDay, hasEnd, calendar) { 3019 var leftovers = {}; 3020 var def = pluckNonDateProps(raw, calendar, leftovers); 3021 def.defId = String(uid++); 3022 def.sourceId = sourceId; 3023 def.allDay = allDay; 3024 def.hasEnd = hasEnd; 3025 for (var _i = 0, _a = calendar.pluginSystem.hooks.eventDefParsers; _i < _a.length; _i++) { 3026 var eventDefParser = _a[_i]; 3027 var newLeftovers = {}; 3028 eventDefParser(def, leftovers, newLeftovers); 3029 leftovers = newLeftovers; 3030 } 3031 def.extendedProps = __assign(leftovers, def.extendedProps || {}); 3032 // help out EventApi from having user modify props 3033 Object.freeze(def.ui.classNames); 3034 Object.freeze(def.extendedProps); 3035 return def; 3036 } 3037 function createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) { 3038 return { 3039 instanceId: String(uid++), 3040 defId: defId, 3041 range: range, 3042 forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo, 3043 forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo 3044 }; 3045 } 3046 function parseSingle(raw, allDayDefault, calendar, leftovers, allowOpenRange) { 3047 var props = pluckDateProps(raw, leftovers); 3048 var allDay = props.allDay; 3049 var startMeta; 3050 var startMarker = null; 3051 var hasEnd = false; 3052 var endMeta; 3053 var endMarker = null; 3054 startMeta = calendar.dateEnv.createMarkerMeta(props.start); 3055 if (startMeta) { 3056 startMarker = startMeta.marker; 3057 } 3058 else if (!allowOpenRange) { 3059 return null; 3060 } 3061 if (props.end != null) { 3062 endMeta = calendar.dateEnv.createMarkerMeta(props.end); 3063 } 3064 if (allDay == null) { 3065 if (allDayDefault != null) { 3066 allDay = allDayDefault; 3067 } 3068 else { 3069 // fall back to the date props LAST 3070 allDay = (!startMeta || startMeta.isTimeUnspecified) && 3071 (!endMeta || endMeta.isTimeUnspecified); 3072 } 3073 } 3074 if (allDay && startMarker) { 3075 startMarker = startOfDay(startMarker); 3076 } 3077 if (endMeta) { 3078 endMarker = endMeta.marker; 3079 if (allDay) { 3080 endMarker = startOfDay(endMarker); 3081 } 3082 if (startMarker && endMarker <= startMarker) { 3083 endMarker = null; 3084 } 3085 } 3086 if (endMarker) { 3087 hasEnd = true; 3088 } 3089 else if (!allowOpenRange) { 3090 hasEnd = calendar.opt('forceEventDuration') || false; 3091 endMarker = calendar.dateEnv.add(startMarker, allDay ? 3092 calendar.defaultAllDayEventDuration : 3093 calendar.defaultTimedEventDuration); 3094 } 3095 return { 3096 allDay: allDay, 3097 hasEnd: hasEnd, 3098 range: { start: startMarker, end: endMarker }, 3099 forcedStartTzo: startMeta ? startMeta.forcedTzo : null, 3100 forcedEndTzo: endMeta ? endMeta.forcedTzo : null 3101 }; 3102 } 3103 function pluckDateProps(raw, leftovers) { 3104 var props = refineProps(raw, DATE_PROPS, {}, leftovers); 3105 props.start = (props.start !== null) ? props.start : props.date; 3106 delete props.date; 3107 return props; 3108 } 3109 function pluckNonDateProps(raw, calendar, leftovers) { 3110 var preLeftovers = {}; 3111 var props = refineProps(raw, NON_DATE_PROPS, {}, preLeftovers); 3112 var ui = processUnscopedUiProps(preLeftovers, calendar, leftovers); 3113 props.publicId = props.id; 3114 delete props.id; 3115 props.ui = ui; 3116 return props; 3117 } 3118 function computeIsAllDayDefault(sourceId, calendar) { 3119 var res = null; 3120 if (sourceId) { 3121 var source = calendar.state.eventSources[sourceId]; 3122 res = source.allDayDefault; 3123 } 3124 if (res == null) { 3125 res = calendar.opt('allDayDefault'); 3126 } 3127 return res; 3128 } 3129 3130 var DEF_DEFAULTS = { 3131 startTime: '09:00', 3132 endTime: '17:00', 3133 daysOfWeek: [1, 2, 3, 4, 5], 3134 rendering: 'inverse-background', 3135 classNames: 'fc-nonbusiness', 3136 groupId: '_businessHours' // so multiple defs get grouped 3137 }; 3138 /* 3139 TODO: pass around as EventDefHash!!! 3140 */ 3141 function parseBusinessHours(input, calendar) { 3142 return parseEvents(refineInputs(input), '', calendar); 3143 } 3144 function refineInputs(input) { 3145 var rawDefs; 3146 if (input === true) { 3147 rawDefs = [{}]; // will get DEF_DEFAULTS verbatim 3148 } 3149 else if (Array.isArray(input)) { 3150 // if specifying an array, every sub-definition NEEDS a day-of-week 3151 rawDefs = input.filter(function (rawDef) { 3152 return rawDef.daysOfWeek; 3153 }); 3154 } 3155 else if (typeof input === 'object' && input) { // non-null object 3156 rawDefs = [input]; 3157 } 3158 else { // is probably false 3159 rawDefs = []; 3160 } 3161 rawDefs = rawDefs.map(function (rawDef) { 3162 return __assign({}, DEF_DEFAULTS, rawDef); 3163 }); 3164 return rawDefs; 3165 } 3166 3167 function memoizeRendering(renderFunc, unrenderFunc, dependencies) { 3168 if (dependencies === void 0) { dependencies = []; } 3169 var dependents = []; 3170 var thisContext; 3171 var prevArgs; 3172 function unrender() { 3173 if (prevArgs) {
3174 for (var _i = 0, dependents_1 = dependents; _i < dependents_1.length; _i++) { 3175 var dependent = dependents_1[_i]; 3176 dependent.unrender(); 3177 } 3178 if (unrenderFunc) { 3179 unrenderFunc.apply(thisContext, prevArgs); 3180 } 3181 prevArgs = null; 3182 } 3183 } 3184 function res() { 3185 if (!prevArgs || !isArraysEqual(prevArgs, arguments)) { 3186 unrender(); 3187 thisContext = this; 3188 prevArgs = arguments; 3189 renderFunc.apply(this, arguments); 3190 } 3191 } 3192 res.dependents = dependents; 3193 res.unrender = unrender; 3194 for (var _i = 0, dependencies_1 = dependencies; _i < dependencies_1.length; _i++) { 3195 var dependency = dependencies_1[_i]; 3196 dependency.dependents.push(res); 3197 } 3198 return res; 3199 } 3200 3201 var EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere 3202 var Splitter = /** @class */ (function () { 3203 function Splitter() { 3204 this.getKeysForEventDefs = memoize(this._getKeysForEventDefs); 3205 this.splitDateSelection = memoize(this._splitDateSpan); 3206 this.splitEventStore = memoize(this._splitEventStore); 3207 this.splitIndividualUi = memoize(this._splitIndividualUi); 3208 this.splitEventDrag = memoize(this._splitInteraction); 3209 this.splitEventResize = memoize(this._splitInteraction); 3210 this.eventUiBuilders = {}; // TODO: typescript protection 3211 } 3212 Splitter.prototype.splitProps = function (props) { 3213 var _this = this; 3214 var keyInfos = this.getKeyInfo(props); 3215 var defKeys = this.getKeysForEventDefs(props.eventStore); 3216 var dateSelections = this.splitDateSelection(props.dateSelection); 3217 var individualUi = this.splitIndividualUi(props.eventUiBases, defKeys); // the individual *bases* 3218 var eventStores = this.splitEventStore(props.eventStore, defKeys); 3219 var eventDrags = this.splitEventDrag(props.eventDrag); 3220 var eventResizes = this.splitEventResize(props.eventResize); 3221 var splitProps = {}; 3222 this.eventUiBuilders = mapHash(keyInfos, function (info, key) { 3223 return _this.eventUiBuilders[key] || memoize(buildEventUiForKey); 3224 }); 3225 for (var key in keyInfos) { 3226 var keyInfo = keyInfos[key]; 3227 var eventStore = eventStores[key] || EMPTY_EVENT_STORE; 3228 var buildEventUi = this.eventUiBuilders[key]; 3229 splitProps[key] = { 3230 businessHours: keyInfo.businessHours || props.businessHours, 3231 dateSelection: dateSelections[key] || null, 3232 eventStore: eventStore, 3233 eventUiBases: buildEventUi(props.eventUiBases[''], keyInfo.ui, individualUi[key]), 3234 eventSelection: eventStore.instances[props.eventSelection] ? props.eventSelection : '', 3235 eventDrag: eventDrags[key] || null, 3236 eventResize: eventResizes[key] || null 3237 }; 3238 } 3239 return splitProps; 3240 }; 3241 Splitter.prototype._splitDateSpan = function (dateSpan) { 3242 var dateSpans = {}; 3243 if (dateSpan) { 3244 var keys = this.getKeysForDateSpan(dateSpan); 3245 for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { 3246 var key = keys_1[_i]; 3247 dateSpans[key] = dateSpan; 3248 } 3249 } 3250 return dateSpans; 3251 }; 3252 Splitter.prototype._getKeysForEventDefs = function (eventStore) { 3253 var _this = this; 3254 return mapHash(eventStore.defs, function (eventDef) { 3255 return _this.getKeysForEventDef(eventDef); 3256 }); 3257 }; 3258 Splitter.prototype._splitEventStore = function (eventStore, defKeys) { 3259 var defs = eventStore.defs, instances = eventStore.instances; 3260 var splitStores = {}; 3261 for (var defId in defs) { 3262 for (var _i = 0, _a = defKeys[defId]; _i < _a.length; _i++) { 3263 var key = _a[_i]; 3264 if (!splitStores[key]) { 3265 splitStores[key] = createEmptyEventStore(); 3266 }
3267 splitStores[key].defs[defId] = defs[defId]; 3268 } 3269 } 3270 for (var instanceId in instances) { 3271 var instance = instances[instanceId]; 3272 for (var _b = 0, _c = defKeys[instance.defId]; _b < _c.length; _b++) { 3273 var key = _c[_b]; 3274 if (splitStores[key]) { // must have already been created 3275 splitStores[key].instances[instanceId] = instance; 3276 } 3277 } 3278 } 3279 return splitStores; 3280 }; 3281 Splitter.prototype._splitIndividualUi = function (eventUiBases, defKeys) { 3282 var splitHashes = {}; 3283 for (var defId in eventUiBases) { 3284 if (defId) { // not the '' key 3285 for (var _i = 0, _a = defKeys[defId]; _i < _a.length; _i++) { 3286 var key = _a[_i]; 3287 if (!splitHashes[key]) { 3288 splitHashes[key] = {}; 3289 } 3290 splitHashes[key][defId] = eventUiBases[defId]; 3291 } 3292 } 3293 } 3294 return splitHashes; 3295 }; 3296 Splitter.prototype._splitInteraction = function (interaction) { 3297 var splitStates = {}; 3298 if (interaction) { 3299 var affectedStores_1 = this._splitEventStore(interaction.affectedEvents, this._getKeysForEventDefs(interaction.affectedEvents) // can't use cached. might be events from other calendar 3300 ); 3301 // can't rely on defKeys because event data is mutated 3302 var mutatedKeysByDefId = this._getKeysForEventDefs(interaction.mutatedEvents); 3303 var mutatedStores_1 = this._splitEventStore(interaction.mutatedEvents, mutatedKeysByDefId); 3304 var populate = function (key) { 3305 if (!splitStates[key]) { 3306 splitStates[key] = { 3307 affectedEvents: affectedStores_1[key] || EMPTY_EVENT_STORE, 3308 mutatedEvents: mutatedStores_1[key] || EMPTY_EVENT_STORE, 3309 isEvent: interaction.isEvent, 3310 origSeg: interaction.origSeg 3311 }; 3312 } 3313 }; 3314 for (var key in affectedStores_1) { 3315 populate(key); 3316 } 3317 for (var key in mutatedStores_1) { 3318 populate(key); 3319 } 3320 } 3321 return splitStates; 3322 }; 3323 return Splitter; 3324 }()); 3325 function buildEventUiForKey(allUi, eventUiForKey, individualUi) { 3326 var baseParts = []; 3327 if (allUi) { 3328 baseParts.push(allUi); 3329 } 3330 if (eventUiForKey) { 3331 baseParts.push(eventUiForKey); 3332 } 3333 var stuff = { 3334 '': combineEventUis(baseParts) 3335 }; 3336 if (individualUi) { 3337 __assign(stuff, individualUi); 3338 } 3339 return stuff; 3340 } 3341 3342 // Generates HTML for an anchor to another view into the calendar. 3343 // Will either generate an <a> tag or a non-clickable <span> tag, depending on enabled settings. 3344 // `gotoOptions` can either be a DateMarker, or an object with the form: 3345 // { date, type, forceOff } 3346 // `type` is a view-type like "day" or "week". default value is "day". 3347 // `attrs` and `innerHtml` are use to generate the rest of the HTML tag. 3348 function buildGotoAnchorHtml(component, gotoOptions, attrs, innerHtml) { 3349 var dateEnv = component.dateEnv; 3350 var date; 3351 var type; 3352 var forceOff; 3353 var finalOptions; 3354 if (gotoOptions instanceof Date) { 3355 date = gotoOptions; // a single date-like input 3356 } 3357 else { 3358 date = gotoOptions.date; 3359 type = gotoOptions.type; 3360 forceOff = gotoOptions.forceOff; 3361 } 3362 finalOptions = { 3363 date: dateEnv.formatIso(date, { omitTime: true }), 3364 type: type || 'day' 3365 }; 3366 if (typeof attrs === 'string') { 3367 innerHtml = attrs; 3368 attrs = null; 3369 } 3370 attrs = attrs ? ' ' + attrsToStr(attrs) : ''; // will have a leading space 3371 innerHtml = innerHtml || ''; 3372 if (!forceOff && component.opt('navLinks')) { 3373 return '<a' + attrs + 3374 ' data-goto="' + htmlEscape(JSON.stringify(finalOptions)) + '">' + 3375 innerHtml + 3376 '</a>'; 3377 } 3378 else { 3379 return '<span' + attrs + '>' + 3380 innerHtml + 3381 '</span>'; 3382 } 3383 } 3384 function getAllDayHtml(component) { 3385 return component.opt('allDayHtml') || htmlEscape(component.opt('allDayText')); 3386 } 3387 // Computes HTML classNames for a single-day element 3388 function getDayClasses(date, dateProfile, context, noThemeHighlight) { 3389 var calendar = context.calendar, view = context.view, theme = context.theme, dateEnv = context.dateEnv; 3390 var classes = []; 3391 var todayStart; 3392 var todayEnd; 3393 if (!rangeContainsMarker(dateProfile.activeRange, date)) { 3394 classes.push('fc-disabled-day'); 3395 } 3396 else { 3397 classes.push('fc-' + DAY_IDS[date.getUTCDay()]); 3398 if (view.opt('monthMode') && 3399 dateEnv.getMonth(date) !== dateEnv.getMonth(dateProfile.currentRange.start)) { 3400 classes.push('fc-other-month'); 3401 } 3402 todayStart = startOfDay(calendar.getNow()); 3403 todayEnd = addDays(todayStart, 1); 3404 if (date < todayStart) { 3405 classes.push('fc-past'); 3406 } 3407 else if (date >= todayEnd) { 3408 classes.push('fc-future'); 3409 } 3410 else { 3411 classes.push('fc-today'); 3412 if (noThemeHighlight !== true) { 3413 classes.push(theme.getClass('today')); 3414 } 3415 } 3416 } 3417 return classes; 3418 } 3419 3420 // given a function that resolves a result asynchronously. 3421 // the function can either call passed-in success and failure callbacks, 3422 // or it can return a promise. 3423 // if you need to pass additional params to func, bind them first. 3424 function unpromisify(func, success, failure) { 3425 // guard against success/failure callbacks being called more than once 3426 // and guard against a promise AND callback being used together. 3427 var isResolved = false;
3428 var wrappedSuccess = function () { 3429 if (!isResolved) { 3430 isResolved = true; 3431 success.apply(this, arguments); 3432 } 3433 }; 3434 var wrappedFailure = function () { 3435 if (!isResolved) { 3436 isResolved = true; 3437 if (failure) { 3438 failure.apply(this, arguments); 3439 } 3440 } 3441 }; 3442 var res = func(wrappedSuccess, wrappedFailure); 3443 if (res && typeof res.then === 'function') { 3444 res.then(wrappedSuccess, wrappedFailure); 3445 } 3446 } 3447 3448 var Mixin = /** @class */ (function () { 3449 function Mixin() { 3450 } 3451 // mix into a CLASS 3452 Mixin.mixInto = function (destClass) { 3453 this.mixIntoObj(destClass.prototype); 3454 }; 3455 // mix into ANY object 3456 Mixin.mixIntoObj = function (destObj) { 3457 var _this = this; 3458 Object.getOwnPropertyNames(this.prototype).forEach(function (name) { 3459 if (!destObj[name]) { // if destination doesn't already define it 3460 destObj[name] = _this.prototype[name]; 3461 } 3462 }); 3463 }; 3464 /* 3465 will override existing methods 3466 TODO: remove! not used anymore 3467 */ 3468 Mixin.mixOver = function (destClass) { 3469 var _this = this; 3470 Object.getOwnPropertyNames(this.prototype).forEach(function (name) { 3471 destClass.prototype[name] = _this.prototype[name]; 3472 }); 3473 }; 3474 return Mixin; 3475 }()); 3476 3477 /* 3478 USAGE: 3479 import { default as EmitterMixin, EmitterInterface } from './EmitterMixin' 3480 in class: 3481 on: EmitterInterface['on'] 3482 one: EmitterInterface['one'] 3483 off: EmitterInterface['off'] 3484 trigger: EmitterInterface['trigger'] 3485 triggerWith: EmitterInterface['triggerWith'] 3486 hasHandlers: EmitterInterface['hasHandlers'] 3487 after class: 3488 EmitterMixin.mixInto(TheClass) 3489 */ 3490 var EmitterMixin = /** @class */ (function (_super) { 3491 __extends(EmitterMixin, _super); 3492 function EmitterMixin() { 3493 return _super !== null && _super.apply(this, arguments) || this; 3494 } 3495 EmitterMixin.prototype.on = function (type, handler) { 3496 addToHash(this._handlers || (this._handlers = {}), type, handler); 3497 return this; // for chaining 3498 }; 3499 // todo: add comments 3500 EmitterMixin.prototype.one = function (type, handler) { 3501 addToHash(this._oneHandlers || (this._oneHandlers = {}), type, handler); 3502 return this; // for chaining 3503 }; 3504 EmitterMixin.prototype.off = function (type, handler) { 3505 if (this._handlers) { 3506 removeFromHash(this._handlers, type, handler); 3507 } 3508 if (this._oneHandlers) { 3509 removeFromHash(this._oneHandlers, type, handler); 3510 } 3511 return this; // for chaining 3512 }; 3513 EmitterMixin.prototype.trigger = function (type) { 3514 var args = []; 3515 for (var _i = 1; _i < arguments.length; _i++) { 3516 args[_i - 1] = arguments[_i]; 3517 } 3518 this.triggerWith(type, this, args); 3519 return this; // for chaining 3520 }; 3521 EmitterMixin.prototype.triggerWith = function (type, context, args) { 3522 if (this._handlers) { 3523 applyAll(this._handlers[type], context, args); 3524 } 3525 if (this._oneHandlers) { 3526 applyAll(this._oneHandlers[type], context, args); 3527 delete this._oneHandlers[type]; // will never fire again 3528 } 3529 return this; // for chaining 3530 }; 3531 EmitterMixin.prototype.hasHandlers = function (type) { 3532 return (this._handlers && this._handlers[type] && this._handlers[type].length) || 3533 (this._oneHandlers && this._oneHandlers[type] && this._oneHandlers[type].length); 3534 }; 3535 return EmitterMixin; 3536 }(Mixin)); 3537 function addToHash(hash, type, handler) { 3538 (hash[type] || (hash[type] = [])) 3539 .push(handler); 3540 } 3541 function removeFromHash(hash, type, handler) { 3542 if (handler) { 3543 if (hash[type]) { 3544 hash[type] = hash[type].filter(function (func) { 3545 return func !== handler; 3546 }); 3547 } 3548 } 3549 else { 3550 delete hash[type]; // remove all handler funcs for this type 3551 } 3552 } 3553 3554 /* 3555 Records offset information for a set of elements, relative to an origin element. 3556 Can record the left/right OR the top/bottom OR both. 3557 Provides methods for querying the cache by position. 3558 */ 3559 var PositionCache = /** @class */ (function () { 3560 function PositionCache(originEl, els, isHorizontal, isVertical) { 3561 this.originEl = originEl; 3562 this.els = els; 3563 this.isHorizontal = isHorizontal; 3564 this.isVertical = isVertical; 3565 } 3566 // Queries the els for coordinates and stores them. 3567 // Call this method before using and of the get* methods below. 3568 PositionCache.prototype.build = function () { 3569 var originEl = this.originEl; 3570 var originClientRect = this.originClientRect = 3571 originEl.getBoundingClientRect(); // relative to viewport top-left 3572 if (this.isHorizontal) { 3573 this.buildElHorizontals(originClientRect.left); 3574 } 3575 if (this.isVertical) { 3576 this.buildElVerticals(originClientRect.top); 3577 } 3578 };
3579 // Populates the left/right internal coordinate arrays 3580 PositionCache.prototype.buildElHorizontals = function (originClientLeft) { 3581 var lefts = []; 3582 var rights = []; 3583 for (var _i = 0, _a = this.els; _i < _a.length; _i++) { 3584 var el = _a[_i]; 3585 var rect = el.getBoundingClientRect(); 3586 lefts.push(rect.left - originClientLeft); 3587 rights.push(rect.right - originClientLeft); 3588 } 3589 this.lefts = lefts; 3590 this.rights = rights; 3591 }; 3592 // Populates the top/bottom internal coordinate arrays 3593 PositionCache.prototype.buildElVerticals = function (originClientTop) { 3594 var tops = []; 3595 var bottoms = []; 3596 for (var _i = 0, _a = this.els; _i < _a.length; _i++) { 3597 var el = _a[_i]; 3598 var rect = el.getBoundingClientRect(); 3599 tops.push(rect.top - originClientTop); 3600 bottoms.push(rect.bottom - originClientTop); 3601 } 3602 this.tops = tops; 3603 this.bottoms = bottoms; 3604 }; 3605 // Given a left offset (from document left), returns the index of the el that it horizontally intersects. 3606 // If no intersection is made, returns undefined. 3607 PositionCache.prototype.leftToIndex = function (leftPosition) { 3608 var lefts = this.lefts; 3609 var rights = this.rights; 3610 var len = lefts.length; 3611 var i; 3612 for (i = 0; i < len; i++) { 3613 if (leftPosition >= lefts[i] && leftPosition < rights[i]) { 3614 return i; 3615 } 3616 } 3617 }; 3618 // Given a top offset (from document top), returns the index of the el that it vertically intersects. 3619 // If no intersection is made, returns undefined. 3620 PositionCache.prototype.topToIndex = function (topPosition) { 3621 var tops = this.tops; 3622 var bottoms = this.bottoms; 3623 var len = tops.length; 3624 var i; 3625 for (i = 0; i < len; i++) { 3626 if (topPosition >= tops[i] && topPosition < bottoms[i]) { 3627 return i; 3628 } 3629 } 3630 }; 3631 // Gets the width of the element at the given index 3632 PositionCache.prototype.getWidth = function (leftIndex) { 3633 return this.rights[leftIndex] - this.lefts[leftIndex]; 3634 }; 3635 // Gets the height of the element at the given index 3636 PositionCache.prototype.getHeight = function (topIndex) { 3637 return this.bottoms[topIndex] - this.tops[topIndex]; 3638 }; 3639 return PositionCache; 3640 }()); 3641 3642 /* 3643 An object for getting/setting scroll-related information for an element. 3644 Internally, this is done very differently for window versus DOM element, 3645 so this object serves as a common interface. 3646 */ 3647 var ScrollController = /** @class */ (function () { 3648 function ScrollController() { 3649 } 3650 ScrollController.prototype.getMaxScrollTop = function () { 3651 return this.getScrollHeight() - this.getClientHeight(); 3652 }; 3653 ScrollController.prototype.getMaxScrollLeft = function () { 3654 return this.getScrollWidth() - this.getClientWidth(); 3655 }; 3656 ScrollController.prototype.canScrollVertically = function () { 3657 return this.getMaxScrollTop() > 0; 3658 }; 3659 ScrollController.prototype.canScrollHorizontally = function () { 3660 return this.getMaxScrollLeft() > 0; 3661 }; 3662 ScrollController.prototype.canScrollUp = function () { 3663 return this.getScrollTop() > 0; 3664 }; 3665 ScrollController.prototype.canScrollDown = function () { 3666 return this.getScrollTop() < this.getMaxScrollTop(); 3667 }; 3668 ScrollController.prototype.canScrollLeft = function () { 3669 return this.getScrollLeft() > 0; 3670 }; 3671 ScrollController.prototype.canScrollRight = function () { 3672 return this.getScrollLeft() < this.getMaxScrollLeft(); 3673 };
3674 return ScrollController; 3675 }()); 3676 var ElementScrollController = /** @class */ (function (_super) { 3677 __extends(ElementScrollController, _super); 3678 function ElementScrollController(el) { 3679 var _this = _super.call(this) || this; 3680 _this.el = el; 3681 return _this; 3682 } 3683 ElementScrollController.prototype.getScrollTop = function () { 3684 return this.el.scrollTop; 3685 }; 3686 ElementScrollController.prototype.getScrollLeft = function () { 3687 return this.el.scrollLeft; 3688 }; 3689 ElementScrollController.prototype.setScrollTop = function (top) { 3690 this.el.scrollTop = top; 3691 }; 3692 ElementScrollController.prototype.setScrollLeft = function (left) { 3693 this.el.scrollLeft = left; 3694 }; 3695 ElementScrollController.prototype.getScrollWidth = function () { 3696 return this.el.scrollWidth; 3697 }; 3698 ElementScrollController.prototype.getScrollHeight = function () { 3699 return this.el.scrollHeight; 3700 }; 3701 ElementScrollController.prototype.getClientHeight = function () { 3702 return this.el.clientHeight; 3703 }; 3704 ElementScrollController.prototype.getClientWidth = function () { 3705 return this.el.clientWidth; 3706 }; 3707 return ElementScrollController; 3708 }(ScrollController)); 3709 var WindowScrollController = /** @class */ (function (_super) { 3710 __extends(WindowScrollController, _super); 3711 function WindowScrollController() { 3712 return _super !== null && _super.apply(this, arguments) || this; 3713 } 3714 WindowScrollController.prototype.getScrollTop = function () { 3715 return window.pageYOffset; 3716 }; 3717 WindowScrollController.prototype.getScrollLeft = function () { 3718 return window.pageXOffset; 3719 }; 3720 WindowScrollController.prototype.setScrollTop = function (n) { 3721 window.scroll(window.pageXOffset, n); 3722 }; 3723 WindowScrollController.prototype.setScrollLeft = function (n) { 3724 window.scroll(n, window.pageYOffset); 3725 }; 3726 WindowScrollController.prototype.getScrollWidth = function () { 3727 return document.documentElement.scrollWidth; 3728 }; 3729 WindowScrollController.prototype.getScrollHeight = function () { 3730 return document.documentElement.scrollHeight; 3731 }; 3732 WindowScrollController.prototype.getClientHeight = function () { 3733 return document.documentElement.clientHeight; 3734 }; 3735 WindowScrollController.prototype.getClientWidth = function () { 3736 return document.documentElement.clientWidth; 3737 }; 3738 return WindowScrollController; 3739 }(ScrollController)); 3740 3741 /* 3742 Embodies a div that has potential scrollbars 3743 */ 3744 var ScrollComponent = /** @class */ (function (_super) { 3745 __extends(ScrollComponent, _super); 3746 function ScrollComponent(overflowX, overflowY) { 3747 var _this = _super.call(this, createElement('div', { 3748 className: 'fc-scroller' 3749 })) || this; 3750 _this.overflowX = overflowX; 3751 _this.overflowY = overflowY; 3752 _this.applyOverflow(); 3753 return _this; 3754 } 3755 // sets to natural height, unlocks overflow 3756 ScrollComponent.prototype.clear = function () { 3757 this.setHeight('auto'); 3758 this.applyOverflow(); 3759 }; 3760 ScrollComponent.prototype.destroy = function () { 3761 removeElement(this.el); 3762 }; 3763 // Overflow 3764 // ----------------------------------------------------------------------------------------------------------------- 3765 ScrollComponent.prototype.applyOverflow = function () { 3766 applyStyle(this.el, { 3767 overflowX: this.overflowX, 3768 overflowY: this.overflowY 3769 }); 3770 }; 3771 // Causes any 'auto' overflow values to resolves to 'scroll' or 'hidden'. 3772 // Useful for preserving scrollbar widths regardless of future resizes. 3773 // Can pass in scrollbarWidths for optimization. 3774 ScrollComponent.prototype.lockOverflow = function (scrollbarWidths) { 3775 var overflowX = this.overflowX; 3776 var overflowY = this.overflowY;
3777 scrollbarWidths = scrollbarWidths || this.getScrollbarWidths(); 3778 if (overflowX === 'auto') { 3779 overflowX = (scrollbarWidths.bottom || // horizontal scrollbars? 3780 this.canScrollHorizontally() // OR scrolling pane with massless scrollbars? 3781 ) ? 'scroll' : 'hidden'; 3782 } 3783 if (overflowY === 'auto') { 3784 overflowY = (scrollbarWidths.left || scrollbarWidths.right || // horizontal scrollbars? 3785 this.canScrollVertically() // OR scrolling pane with massless scrollbars? 3786 ) ? 'scroll' : 'hidden'; 3787 } 3788 applyStyle(this.el, { overflowX: overflowX, overflowY: overflowY }); 3789 }; 3790 ScrollComponent.prototype.setHeight = function (height) { 3791 applyStyleProp(this.el, 'height', height); 3792 }; 3793 ScrollComponent.prototype.getScrollbarWidths = function () { 3794 var edges = computeEdges(this.el); 3795 return { 3796 left: edges.scrollbarLeft, 3797 right: edges.scrollbarRight, 3798 bottom: edges.scrollbarBottom 3799 }; 3800 }; 3801 return ScrollComponent; 3802 }(ElementScrollController)); 3803 3804 var Theme = /** @class */ (function () { 3805 function Theme(calendarOptions) { 3806 this.calendarOptions = calendarOptions; 3807 this.processIconOverride(); 3808 } 3809 Theme.prototype.processIconOverride = function () { 3810 if (this.iconOverrideOption) { 3811 this.setIconOverride(this.calendarOptions[this.iconOverrideOption]); 3812 } 3813 }; 3814 Theme.prototype.setIconOverride = function (iconOverrideHash) { 3815 var iconClassesCopy; 3816 var buttonName; 3817 if (typeof iconOverrideHash === 'object' && iconOverrideHash) { // non-null object 3818 iconClassesCopy = __assign({}, this.iconClasses); 3819 for (buttonName in iconOverrideHash) { 3820 iconClassesCopy[buttonName] = this.applyIconOverridePrefix(iconOverrideHash[buttonName]); 3821 } 3822 this.iconClasses = iconClassesCopy; 3823 } 3824 else if (iconOverrideHash === false) { 3825 this.iconClasses = {}; 3826 } 3827 }; 3828 Theme.prototype.applyIconOverridePrefix = function (className) { 3829 var prefix = this.iconOverridePrefix; 3830 if (prefix && className.indexOf(prefix) !== 0) { // if not already present 3831 className = prefix + className; 3832 } 3833 return className; 3834 }; 3835 Theme.prototype.getClass = function (key) { 3836 return this.classes[key] || ''; 3837 }; 3838 Theme.prototype.getIconClass = function (buttonName) { 3839 var className = this.iconClasses[buttonName]; 3840 if (className) { 3841 return this.baseIconClass + ' ' + className; 3842 } 3843 return ''; 3844 }; 3845 Theme.prototype.getCustomButtonIconClass = function (customButtonProps) { 3846 var className; 3847 if (this.iconOverrideCustomButtonOption) { 3848 className = customButtonProps[this.iconOverrideCustomButtonOption]; 3849 if (className) { 3850 return this.baseIconClass + ' ' + this.applyIconOverridePrefix(className); 3851 } 3852 } 3853 return ''; 3854 }; 3855 return Theme; 3856 }()); 3857 Theme.prototype.classes = {}; 3858 Theme.prototype.iconClasses = {}; 3859 Theme.prototype.baseIconClass = ''; 3860 Theme.prototype.iconOverridePrefix = ''; 3861 3862 var guid = 0; 3863 var Component = /** @class */ (function () { 3864 function Component(context, isView) { 3865 // HACK to populate view at top of component instantiation call chain 3866 if (isView) { 3867 context.view = this; 3868 } 3869 this.uid = String(guid++); 3870 this.context = context; 3871 this.dateEnv = context.dateEnv; 3872 this.theme = context.theme; 3873 this.view = context.view; 3874 this.calendar = context.calendar; 3875 this.isRtl = this.opt('dir') === 'rtl'; 3876 } 3877 Component.addEqualityFuncs = function (newFuncs) { 3878 this.prototype.equalityFuncs = __assign({}, this.prototype.equalityFuncs, newFuncs); 3879 }; 3880 Component.prototype.opt = function (name) { 3881 return this.context.options[name]; 3882 }; 3883 Component.prototype.receiveProps = function (props) { 3884 var _a = recycleProps(this.props || {}, props, this.equalityFuncs), anyChanges = _a.anyChanges, comboProps = _a.comboProps; 3885 this.props = comboProps;
3886 if (anyChanges) { 3887 this.render(comboProps); 3888 } 3889 }; 3890 Component.prototype.render = function (props) { 3891 }; 3892 // after destroy is called, this component won't ever be used again 3893 Component.prototype.destroy = function () { 3894 }; 3895 return Component; 3896 }()); 3897 Component.prototype.equalityFuncs = {}; 3898 /* 3899 Reuses old values when equal. If anything is unequal, returns newProps as-is. 3900 Great for PureComponent, but won't be feasible with React, so just eliminate and use React's DOM diffing. 3901 */ 3902 function recycleProps(oldProps, newProps, equalityFuncs) { 3903 var comboProps = {}; // some old, some new 3904 var anyChanges = false; 3905 for (var key in newProps) { 3906 if (key in oldProps && (oldProps[key] === newProps[key] || 3907 (equalityFuncs[key] && equalityFuncs[key](oldProps[key], newProps[key])))) { 3908 // equal to old? use old prop 3909 comboProps[key] = oldProps[key]; 3910 } 3911 else { 3912 comboProps[key] = newProps[key]; 3913 anyChanges = true; 3914 } 3915 } 3916 for (var key in oldProps) { 3917 if (!(key in newProps)) { 3918 anyChanges = true; 3919 break; 3920 } 3921 } 3922 return { anyChanges: anyChanges, comboProps: comboProps }; 3923 } 3924 3925 /* 3926 PURPOSES: 3927 - hook up to fg, fill, and mirror renderers 3928 - interface for dragging and hits 3929 */ 3930 var DateComponent = /** @class */ (function (_super) { 3931 __extends(DateComponent, _super); 3932 function DateComponent(context, el, isView) { 3933 var _this = _super.call(this, context, isView) || this; 3934 _this.el = el; 3935 return _this; 3936 } 3937 DateComponent.prototype.destroy = function () { 3938 _super.prototype.destroy.call(this); 3939 removeElement(this.el); 3940 }; 3941 // TODO: WHAT ABOUT (sourceSeg && sourceSeg.component.doesDragMirror) 3942 // 3943 // Event Drag-n-Drop Rendering (for both events and external elements) 3944 // --------------------------------------------------------------------------------------------------------------- 3945 /* 3946 renderEventDragSegs(state: EventSegUiInteractionState) { 3947 if (state) { 3948 let { isEvent, segs, sourceSeg } = state 3949 3950 if (this.eventRenderer) { 3951 this.eventRenderer.hideByHash(state.affectedInstances) 3952 } 3953 3954 // if the user is dragging something that is considered an event with real event data, 3955 // and this component likes to do drag mirrors OR the component where the seg came from 3956 // likes to do drag mirrors, then render a drag mirror. 3957 if (isEvent && (this.doesDragMirror || sourceSeg && sourceSeg.component.doesDragMirror)) { 3958 if (this.mirrorRenderer) { 3959 this.mirrorRenderer.renderSegs(segs, { isDragging: true, sourceSeg }) 3960 } 3961 } 3962 3963 // if it would be impossible to render a drag mirror OR this component likes to render 3964 // highlights, then render a highlight. 3965 if (!isEvent || this.doesDragHighlight) { 3966 if (this.fillRenderer) { 3967 this.fillRenderer.renderSegs('highlight', segs) 3968 } 3969 } 3970 } 3971 } 3972 */ 3973 // Hit System 3974 // ----------------------------------------------------------------------------------------------------------------- 3975 DateComponent.prototype.buildPositionCaches = function () { 3976 }; 3977 DateComponent.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { 3978 return null; // this should be abstract 3979 }; 3980 // Validation 3981 // ----------------------------------------------------------------------------------------------------------------- 3982 DateComponent.prototype.isInteractionValid = function (interaction) { 3983 var calendar = this.calendar; 3984 var dateProfile = this.props.dateProfile; // HACK 3985 var instances = interaction.mutatedEvents.instances; 3986 if (dateProfile) { // HACK for DayTile 3987 for (var instanceId in instances) { 3988 if (!rangeContainsRange(dateProfile.validRange, instances[instanceId].range)) { 3989 return false;
3990 } 3991 } 3992 } 3993 return isInteractionValid(interaction, calendar); 3994 }; 3995 DateComponent.prototype.isDateSelectionValid = function (selection) { 3996 var dateProfile = this.props.dateProfile; // HACK 3997 if (dateProfile && // HACK for DayTile 3998 !rangeContainsRange(dateProfile.validRange, selection.range)) { 3999 return false; 4000 } 4001 return isDateSelectionValid(selection, this.calendar); 4002 }; 4003 // Triggering 4004 // ----------------------------------------------------------------------------------------------------------------- 4005 // TODO: move to Calendar 4006 DateComponent.prototype.publiclyTrigger = function (name, args) { 4007 var calendar = this.calendar; 4008 return calendar.publiclyTrigger(name, args); 4009 }; 4010 DateComponent.prototype.publiclyTriggerAfterSizing = function (name, args) { 4011 var calendar = this.calendar; 4012 return calendar.publiclyTriggerAfterSizing(name, args); 4013 }; 4014 DateComponent.prototype.hasPublicHandlers = function (name) { 4015 var calendar = this.calendar; 4016 return calendar.hasPublicHandlers(name); 4017 }; 4018 DateComponent.prototype.triggerRenderedSegs = function (segs, isMirrors) { 4019 var calendar = this.calendar; 4020 if (this.hasPublicHandlers('eventPositioned')) { 4021 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 4022 var seg = segs_1[_i]; 4023 this.publiclyTriggerAfterSizing('eventPositioned', [ 4024 { 4025 event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance), 4026 isMirror: isMirrors, 4027 isStart: seg.isStart, 4028 isEnd: seg.isEnd, 4029 el: seg.el, 4030 view: this // safe to cast because this method is only called on context.view 4031 } 4032 ]); 4033 } 4034 } 4035 if (!calendar.state.loadingLevel) { // avoid initial empty state while pending 4036 calendar.afterSizingTriggers._eventsPositioned = [null]; // fire once 4037 } 4038 }; 4039 DateComponent.prototype.triggerWillRemoveSegs = function (segs, isMirrors) { 4040 var calendar = this.calendar; 4041 for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { 4042 var seg = segs_2[_i]; 4043 calendar.trigger('eventElRemove', seg.el); 4044 } 4045 if (this.hasPublicHandlers('eventDestroy')) { 4046 for (var _a = 0, segs_3 = segs; _a < segs_3.length; _a++) { 4047 var seg = segs_3[_a]; 4048 this.publiclyTrigger('eventDestroy', [ 4049 { 4050 event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance), 4051 isMirror: isMirrors, 4052 el: seg.el, 4053 view: this // safe to cast because this method is only called on context.view 4054 } 4055 ]); 4056 } 4057 } 4058 }; 4059 // Pointer Interaction Utils 4060 // ----------------------------------------------------------------------------------------------------------------- 4061 DateComponent.prototype.isValidSegDownEl = function (el) { 4062 return !this.props.eventDrag && // HACK 4063 !this.props.eventResize && // HACK 4064 !elementClosest(el, '.fc-mirror') && 4065 (this.isPopover() || !this.isInPopover(el)); 4066 // ^above line ensures we don't detect a seg interaction within a nested component. 4067 // it's a HACK because it only supports a popover as the nested component. 4068 }; 4069 DateComponent.prototype.isValidDateDownEl = function (el) { 4070 var segEl = elementClosest(el, this.fgSegSelector); 4071 return (!segEl || segEl.classList.contains('fc-mirror')) && 4072 !elementClosest(el, '.fc-more') && // a "more.." link 4073 !elementClosest(el, 'a[data-goto]') && // a clickable nav link 4074 !this.isInPopover(el); 4075 }; 4076 DateComponent.prototype.isPopover = function () { 4077 return this.el.classList.contains('fc-popover'); 4078 }; 4079 DateComponent.prototype.isInPopover = function (el) { 4080 return Boolean(elementClosest(el, '.fc-popover')); 4081 }; 4082 return DateComponent; 4083 }(Component)); 4084 DateComponent.prototype.fgSegSelector = '.fc-event-container > *'; 4085 DateComponent.prototype.bgSegSelector = '.fc-bgevent:not(.fc-nonbusiness)'; 4086 4087 var uid$1 = 0; 4088 function createPlugin(input) { 4089 return { 4090 id: String(uid$1++), 4091 deps: input.deps || [], 4092 reducers: input.reducers || [], 4093 eventDefParsers: input.eventDefParsers || [], 4094 isDraggableTransformers: input.isDraggableTransformers || [], 4095 eventDragMutationMassagers: input.eventDragMutationMassagers || [], 4096 eventDefMutationAppliers: input.eventDefMutationAppliers || [], 4097 dateSelectionTransformers: input.dateSelectionTransformers || [], 4098 datePointTransforms: input.datePointTransforms || [], 4099 dateSpanTransforms: input.dateSpanTransforms || [], 4100 views: input.views || {}, 4101 viewPropsTransformers: input.viewPropsTransformers || [], 4102 isPropsValid: input.isPropsValid || null, 4103 externalDefTransforms: input.externalDefTransforms || [], 4104 eventResizeJoinTransforms: input.eventResizeJoinTransforms || [], 4105 viewContainerModifiers: input.viewContainerModifiers || [], 4106 eventDropTransformers: input.eventDropTransformers || [], 4107 componentInteractions: input.componentInteractions || [], 4108 calendarInteractions: input.calendarInteractions || [],
4109 themeClasses: input.themeClasses || {}, 4110 eventSourceDefs: input.eventSourceDefs || [], 4111 cmdFormatter: input.cmdFormatter, 4112 recurringTypes: input.recurringTypes || [], 4113 namedTimeZonedImpl: input.namedTimeZonedImpl, 4114 defaultView: input.defaultView || '', 4115 elementDraggingImpl: input.elementDraggingImpl, 4116 optionChangeHandlers: input.optionChangeHandlers || {} 4117 }; 4118 } 4119 var PluginSystem = /** @class */ (function () { 4120 function PluginSystem() { 4121 this.hooks = { 4122 reducers: [], 4123 eventDefParsers: [], 4124 isDraggableTransformers: [], 4125 eventDragMutationMassagers: [], 4126 eventDefMutationAppliers: [], 4127 dateSelectionTransformers: [], 4128 datePointTransforms: [], 4129 dateSpanTransforms: [], 4130 views: {}, 4131 viewPropsTransformers: [], 4132 isPropsValid: null, 4133 externalDefTransforms: [], 4134 eventResizeJoinTransforms: [], 4135 viewContainerModifiers: [], 4136 eventDropTransformers: [], 4137 componentInteractions: [], 4138 calendarInteractions: [], 4139 themeClasses: {}, 4140 eventSourceDefs: [], 4141 cmdFormatter: null, 4142 recurringTypes: [], 4143 namedTimeZonedImpl: null, 4144 defaultView: '', 4145 elementDraggingImpl: null, 4146 optionChangeHandlers: {} 4147 }; 4148 this.addedHash = {}; 4149 } 4150 PluginSystem.prototype.add = function (plugin) { 4151 if (!this.addedHash[plugin.id]) { 4152 this.addedHash[plugin.id] = true; 4153 for (var _i = 0, _a = plugin.deps; _i < _a.length; _i++) { 4154 var dep = _a[_i]; 4155 this.add(dep); 4156 } 4157 this.hooks = combineHooks(this.hooks, plugin); 4158 } 4159 }; 4160 return PluginSystem; 4161 }()); 4162 function combineHooks(hooks0, hooks1) { 4163 return { 4164 reducers: hooks0.reducers.concat(hooks1.reducers), 4165 eventDefParsers: hooks0.eventDefParsers.concat(hooks1.eventDefParsers), 4166 isDraggableTransformers: hooks0.isDraggableTransformers.concat(hooks1.isDraggableTransformers), 4167 eventDragMutationMassagers: hooks0.eventDragMutationMassagers.concat(hooks1.eventDragMutationMassagers), 4168 eventDefMutationAppliers: hooks0.eventDefMutationAppliers.concat(hooks1.eventDefMutationAppliers), 4169 dateSelectionTransformers: hooks0.dateSelectionTransformers.concat(hooks1.dateSelectionTransformers), 4170 datePointTransforms: hooks0.datePointTransforms.concat(hooks1.datePointTransforms), 4171 dateSpanTransforms: hooks0.dateSpanTransforms.concat(hooks1.dateSpanTransforms), 4172 views: __assign({}, hooks0.views, hooks1.views), 4173 viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers), 4174 isPropsValid: hooks1.isPropsValid || hooks0.isPropsValid, 4175 externalDefTransforms: hooks0.externalDefTransforms.concat(hooks1.externalDefTransforms), 4176 eventResizeJoinTransforms: hooks0.eventResizeJoinTransforms.concat(hooks1.eventResizeJoinTransforms), 4177 viewContainerModifiers: hooks0.viewContainerModifiers.concat(hooks1.viewContainerModifiers), 4178 eventDropTransformers: hooks0.eventDropTransformers.concat(hooks1.eventDropTransformers), 4179 calendarInteractions: hooks0.calendarInteractions.concat(hooks1.calendarInteractions), 4180 componentInteractions: hooks0.componentInteractions.concat(hooks1.componentInteractions), 4181 themeClasses: __assign({}, hooks0.themeClasses, hooks1.themeClasses), 4182 eventSourceDefs: hooks0.eventSourceDefs.concat(hooks1.eventSourceDefs), 4183 cmdFormatter: hooks1.cmdFormatter || hooks0.cmdFormatter, 4184 recurringTypes: hooks0.recurringTypes.concat(hooks1.recurringTypes), 4185 namedTimeZonedImpl: hooks1.namedTimeZonedImpl || hooks0.namedTimeZonedImpl, 4186 defaultView: hooks0.defaultView || hooks1.defaultView, 4187 elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl, 4188 optionChangeHandlers: __assign({}, hooks0.optionChangeHandlers, hooks1.optionChangeHandlers) 4189 }; 4190 } 4191 4192 var eventSourceDef = { 4193 ignoreRange: true, 4194 parseMeta: function (raw) { 4195 if (Array.isArray(raw)) { // short form 4196 return raw; 4197 } 4198 else if (Array.isArray(raw.events)) { 4199 return raw.events; 4200 } 4201 return null; 4202 }, 4203 fetch: function (arg, success) { 4204 success({ 4205 rawEvents: arg.eventSource.meta 4206 }); 4207 } 4208 }; 4209 var ArrayEventSourcePlugin = createPlugin({ 4210 eventSourceDefs: [eventSourceDef] 4211 }); 4212 4213 var eventSourceDef$1 = { 4214 parseMeta: function (raw) { 4215 if (typeof raw === 'function') { // short form 4216 return raw; 4217 } 4218 else if (typeof raw.events === 'function') { 4219 return raw.events; 4220 } 4221 return null; 4222 }, 4223 fetch: function (arg, success, failure) { 4224 var dateEnv = arg.calendar.dateEnv; 4225 var func = arg.eventSource.meta; 4226 unpromisify(func.bind(null, { 4227 start: dateEnv.toDate(arg.range.start), 4228 end: dateEnv.toDate(arg.range.end), 4229 startStr: dateEnv.formatIso(arg.range.start), 4230 endStr: dateEnv.formatIso(arg.range.end), 4231 timeZone: dateEnv.timeZone 4232 }), function (rawEvents) { 4233 success({ rawEvents: rawEvents }); // needs an object response 4234 }, failure // send errorObj directly to failure callback 4235 ); 4236 } 4237 }; 4238 var FuncEventSourcePlugin = createPlugin({ 4239 eventSourceDefs: [eventSourceDef$1] 4240 }); 4241 4242 function requestJson(method, url, params, successCallback, failureCallback) { 4243 method = method.toUpperCase(); 4244 var body = null; 4245 if (method === 'GET') { 4246 url = injectQueryStringParams(url, params); 4247 } 4248 else { 4249 body = encodeParams(params); 4250 } 4251 var xhr = new XMLHttpRequest(); 4252 xhr.open(method, url, true); 4253 if (method !== 'GET') { 4254 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 4255 } 4256 xhr.onload = function () { 4257 if (xhr.status >= 200 && xhr.status < 400) { 4258 try { 4259 var res = JSON.parse(xhr.responseText); 4260 successCallback(res, xhr); 4261 } 4262 catch (err) { 4263 failureCallback('Failure parsing JSON', xhr); 4264 } 4265 } 4266 else { 4267 failureCallback('Request failed', xhr); 4268 } 4269 }; 4270 xhr.onerror = function () { 4271 failureCallback('Request failed', xhr); 4272 }; 4273 xhr.send(body); 4274 } 4275 function injectQueryStringParams(url, params) { 4276 return url + 4277 (url.indexOf('?') === -1 ? '?' : '&') + 4278 encodeParams(params); 4279 } 4280 function encodeParams(params) { 4281 var parts = []; 4282 for (var key in params) { 4283 parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key])); 4284 } 4285 return parts.join('&'); 4286 } 4287 4288 var eventSourceDef$2 = { 4289 parseMeta: function (raw) { 4290 if (typeof raw === 'string') { // short form 4291 raw = { url: raw }; 4292 } 4293 else if (!raw || typeof raw !== 'object' || !raw.url) { 4294 return null; 4295 } 4296 return { 4297 url: raw.url, 4298 method: (raw.method || 'GET').toUpperCase(), 4299 extraParams: raw.extraParams, 4300 startParam: raw.startParam, 4301 endParam: raw.endParam, 4302 timeZoneParam: raw.timeZoneParam 4303 }; 4304 }, 4305 fetch: function (arg, success, failure) { 4306 var meta = arg.eventSource.meta;
4307 var requestParams = buildRequestParams(meta, arg.range, arg.calendar); 4308 requestJson(meta.method, meta.url, requestParams, function (rawEvents, xhr) { 4309 success({ rawEvents: rawEvents, xhr: xhr }); 4310 }, function (errorMessage, xhr) { 4311 failure({ message: errorMessage, xhr: xhr }); 4312 }); 4313 } 4314 }; 4315 var JsonFeedEventSourcePlugin = createPlugin({ 4316 eventSourceDefs: [eventSourceDef$2] 4317 }); 4318 function buildRequestParams(meta, range, calendar) { 4319 var dateEnv = calendar.dateEnv; 4320 var startParam; 4321 var endParam; 4322 var timeZoneParam; 4323 var customRequestParams; 4324 var params = {}; 4325 startParam = meta.startParam; 4326 if (startParam == null) { 4327 startParam = calendar.opt('startParam'); 4328 } 4329 endParam = meta.endParam; 4330 if (endParam == null) { 4331 endParam = calendar.opt('endParam'); 4332 } 4333 timeZoneParam = meta.timeZoneParam; 4334 if (timeZoneParam == null) { 4335 timeZoneParam = calendar.opt('timeZoneParam'); 4336 } 4337 // retrieve any outbound GET/POST data from the options 4338 if (typeof meta.extraParams === 'function') { 4339 // supplied as a function that returns a key/value object
4340 customRequestParams = meta.extraParams(); 4341 } 4342 else { 4343 // probably supplied as a straight key/value object 4344 customRequestParams = meta.extraParams || {}; 4345 } 4346 __assign(params, customRequestParams); 4347 params[startParam] = dateEnv.formatIso(range.start); 4348 params[endParam] = dateEnv.formatIso(range.end); 4349 if (dateEnv.timeZone !== 'local') { 4350 params[timeZoneParam] = dateEnv.timeZone; 4351 } 4352 return params; 4353 } 4354 4355 var recurring = { 4356 parse: function (rawEvent, leftoverProps, dateEnv) { 4357 var createMarker = dateEnv.createMarker.bind(dateEnv); 4358 var processors = { 4359 daysOfWeek: null, 4360 startTime: createDuration, 4361 endTime: createDuration, 4362 startRecur: createMarker, 4363 endRecur: createMarker 4364 }; 4365 var props = refineProps(rawEvent, processors, {}, leftoverProps); 4366 var anyValid = false; 4367 for (var propName in props) { 4368 if (props[propName] != null) { 4369 anyValid = true; 4370 break; 4371 } 4372 } 4373 if (anyValid) { 4374 var duration = null; 4375 if ('duration' in leftoverProps) { 4376 duration = createDuration(leftoverProps.duration); 4377 delete leftoverProps.duration; 4378 } 4379 if (!duration && props.startTime && props.endTime) { 4380 duration = subtractDurations(props.endTime, props.startTime); 4381 } 4382 return { 4383 allDayGuess: Boolean(!props.startTime && !props.endTime), 4384 duration: duration, 4385 typeData: props // doesn't need endTime anymore but oh well 4386 }; 4387 } 4388 return null; 4389 }, 4390 expand: function (typeData, framingRange, dateEnv) { 4391 var clippedFramingRange = intersectRanges(framingRange, { start: typeData.startRecur, end: typeData.endRecur }); 4392 if (clippedFramingRange) { 4393 return expandRanges(typeData.daysOfWeek, typeData.startTime, clippedFramingRange, dateEnv); 4394 } 4395 else { 4396 return []; 4397 } 4398 } 4399 }; 4400 var SimpleRecurrencePlugin = createPlugin({ 4401 recurringTypes: [recurring] 4402 }); 4403 function expandRanges(daysOfWeek, startTime, framingRange, dateEnv) { 4404 var dowHash = daysOfWeek ? arrayToHash(daysOfWeek) : null; 4405 var dayMarker = startOfDay(framingRange.start); 4406 var endMarker = framingRange.end; 4407 var instanceStarts = []; 4408 while (dayMarker < endMarker) { 4409 var instanceStart 4410 // if everyday, or this particular day-of-week 4411 = void 0; 4412 // if everyday, or this particular day-of-week 4413 if (!dowHash || dowHash[dayMarker.getUTCDay()]) { 4414 if (startTime) { 4415 instanceStart = dateEnv.add(dayMarker, startTime); 4416 } 4417 else { 4418 instanceStart = dayMarker; 4419 } 4420 instanceStarts.push(instanceStart); 4421 } 4422 dayMarker = addDays(dayMarker, 1); 4423 } 4424 return instanceStarts; 4425 } 4426 4427 var DefaultOptionChangeHandlers = createPlugin({ 4428 optionChangeHandlers: { 4429 events: function (events, calendar, deepEqual) { 4430 handleEventSources([events], calendar, deepEqual); 4431 }, 4432 eventSources: handleEventSources, 4433 plugins: handlePlugins 4434 } 4435 }); 4436 function handleEventSources(inputs, calendar, deepEqual) { 4437 var unfoundSources = hashValuesToArray(calendar.state.eventSources);
4438 var newInputs = []; 4439 for (var _i = 0, inputs_1 = inputs; _i < inputs_1.length; _i++) { 4440 var input = inputs_1[_i]; 4441 var inputFound = false; 4442 for (var i = 0; i < unfoundSources.length; i++) { 4443 if (deepEqual(unfoundSources[i]._raw, input)) { 4444 unfoundSources.splice(i, 1); // delete 4445 inputFound = true; 4446 break; 4447 } 4448 } 4449 if (!inputFound) { 4450 newInputs.push(input); 4451 } 4452 } 4453 for (var _a = 0, unfoundSources_1 = unfoundSources; _a < unfoundSources_1.length; _a++) { 4454 var unfoundSource = unfoundSources_1[_a]; 4455 calendar.dispatch({ 4456 type: 'REMOVE_EVENT_SOURCE', 4457 sourceId: unfoundSource.sourceId 4458 }); 4459 } 4460 for (var _b = 0, newInputs_1 = newInputs; _b < newInputs_1.length; _b++) { 4461 var newInput = newInputs_1[_b]; 4462 calendar.addEventSource(newInput); 4463 } 4464 } 4465 // shortcoming: won't remove plugins 4466 function handlePlugins(inputs, calendar) { 4467 calendar.addPluginInputs(inputs); // will gracefully handle duplicates 4468 } 4469 4470 var config = {}; // TODO: make these options 4471 var globalDefaults = { 4472 defaultRangeSeparator: ' - ', 4473 titleRangeSeparator: ' \u2013 ', 4474 defaultTimedEventDuration: '01:00:00', 4475 defaultAllDayEventDuration: { day: 1 }, 4476 forceEventDuration: false, 4477 nextDayThreshold: '00:00:00', 4478 // display 4479 columnHeader: true, 4480 defaultView: '', 4481 aspectRatio: 1.35, 4482 header: { 4483 left: 'title', 4484 center: '', 4485 right: 'today prev,next' 4486 }, 4487 weekends: true, 4488 weekNumbers: false, 4489 weekNumberCalculation: 'local', 4490 editable: false, 4491 // nowIndicator: false, 4492 scrollTime: '06:00:00', 4493 minTime: '00:00:00', 4494 maxTime: '24:00:00', 4495 showNonCurrentDates: true, 4496 // event ajax 4497 lazyFetching: true, 4498 startParam: 'start', 4499 endParam: 'end', 4500 timeZoneParam: 'timeZone', 4501 timeZone: 'local', 4502 // allDayDefault: undefined, 4503 // locale 4504 locales: [], 4505 locale: '', 4506 // dir: will get this from the default locale 4507 // buttonIcons: null, 4508 // allows setting a min-height to the event segment to prevent short events overlapping each other 4509 timeGridEventMinHeight: 0, 4510 themeSystem: 'standard', 4511 // eventResizableFromStart: false, 4512 dragRevertDuration: 500, 4513 dragScroll: true, 4514 allDayMaintainDuration: false, 4515 // selectable: false, 4516 unselectAuto: true, 4517 // selectMinDistance: 0, 4518 dropAccept: '*', 4519 eventOrder: 'start,-duration,allDay,title', 4520 // ^ if start tie, longer events go before shorter. final tie-breaker is title text 4521 // rerenderDelay: null, 4522 eventLimit: false, 4523 eventLimitClick: 'popover', 4524 dayPopoverFormat: { month: 'long', day: 'numeric', year: 'numeric' }, 4525 handleWindowResize: true, 4526 windowResizeDelay: 100, 4527 longPressDelay: 1000, 4528 eventDragMinDistance: 5 // only applies to mouse 4529 }; 4530 var rtlDefaults = { 4531 header: { 4532 left: 'next,prev today', 4533 center: '', 4534 right: 'title' 4535 }, 4536 buttonIcons: { 4537 // TODO: make RTL support the responibility of the theme 4538 prev: 'fc-icon-chevron-right', 4539 next: 'fc-icon-chevron-left', 4540 prevYear: 'fc-icon-chevrons-right', 4541 nextYear: 'fc-icon-chevrons-left' 4542 } 4543 }; 4544 var complexOptions = [ 4545 'header', 4546 'footer', 4547 'buttonText', 4548 'buttonIcons' 4549 ]; 4550 // Merges an array of option objects into a single object 4551 function mergeOptions(optionObjs) { 4552 return mergeProps(optionObjs, complexOptions); 4553 } 4554 // TODO: move this stuff to a "plugin"-related file... 4555 var INTERNAL_PLUGINS = [ 4556 ArrayEventSourcePlugin, 4557 FuncEventSourcePlugin, 4558 JsonFeedEventSourcePlugin, 4559 SimpleRecurrencePlugin, 4560 DefaultOptionChangeHandlers 4561 ]; 4562 function refinePluginDefs(pluginInputs) { 4563 var plugins = []; 4564 for (var _i = 0, pluginInputs_1 = pluginInputs; _i < pluginInputs_1.length; _i++) { 4565 var pluginInput = pluginInputs_1[_i]; 4566 if (typeof pluginInput === 'string') { 4567 var globalName = 'FullCalendar' + capitaliseFirstLetter(pluginInput); 4568 if (!window[globalName]) { 4569 console.warn('Plugin file not loaded for ' + pluginInput); 4570 } 4571 else { 4572 plugins.push(window[globalName].default); // is an ES6 module 4573 } 4574 } 4575 else { 4576 plugins.push(pluginInput); 4577 } 4578 } 4579 return INTERNAL_PLUGINS.concat(plugins); 4580 } 4581 4582 var RAW_EN_LOCALE = { 4583 code: 'en', 4584 week: { 4585 dow: 0, 4586 doy: 4 // 4 days need to be within the year to be considered the first week 4587 }, 4588 dir: 'ltr', 4589 buttonText: { 4590 prev: 'prev', 4591 next: 'next', 4592 prevYear: 'prev year', 4593 nextYear: 'next year', 4594 year: 'year', 4595 today: 'today', 4596 month: 'month', 4597 week: 'week', 4598 day: 'day', 4599 list: 'list' 4600 }, 4601 weekLabel: 'W', 4602 allDayText: 'all-day', 4603 eventLimitText: 'more', 4604 noEventsMessage: 'No events to display' 4605 }; 4606 function parseRawLocales(explicitRawLocales) { 4607 var defaultCode = explicitRawLocales.length > 0 ? explicitRawLocales[0].code : 'en'; 4608 var globalArray = window['FullCalendarLocalesAll'] || []; // from locales-all.js 4609 var globalObject = window['FullCalendarLocales'] || {}; // from locales/*.js. keys are meaningless 4610 var allRawLocales = globalArray.concat(// globalArray is low prio 4611 hashValuesToArray(globalObject), // medium prio 4612 explicitRawLocales // highest prio 4613 ); 4614 var rawLocaleMap = { 4615 en: RAW_EN_LOCALE // necessary? 4616 }; 4617 for (var _i = 0, allRawLocales_1 = allRawLocales; _i < allRawLocales_1.length; _i++) { 4618 var rawLocale = allRawLocales_1[_i]; 4619 rawLocaleMap[rawLocale.code] = rawLocale; 4620 } 4621 return { 4622 map: rawLocaleMap, 4623 defaultCode: defaultCode 4624 }; 4625 } 4626 function buildLocale(inputSingular, available) { 4627 if (typeof inputSingular === 'object' && !Array.isArray(inputSingular)) { 4628 return parseLocale(inputSingular.code, [inputSingular.code], inputSingular); 4629 } 4630 else { 4631 return queryLocale(inputSingular, available); 4632 } 4633 } 4634 function queryLocale(codeArg, available) { 4635 var codes = [].concat(codeArg || []); // will convert to array 4636 var raw = queryRawLocale(codes, available) || RAW_EN_LOCALE; 4637 return parseLocale(codeArg, codes, raw); 4638 } 4639 function queryRawLocale(codes, available) { 4640 for (var i = 0; i < codes.length; i++) { 4641 var parts = codes[i].toLocaleLowerCase().split('-'); 4642 for (var j = parts.length; j > 0; j--) { 4643 var simpleId = parts.slice(0, j).join('-'); 4644 if (available[simpleId]) { 4645 return available[simpleId]; 4646 } 4647 } 4648 } 4649 return null; 4650 } 4651 function parseLocale(codeArg, codes, raw) { 4652 var merged = mergeProps([RAW_EN_LOCALE, raw], ['buttonText']); 4653 delete merged.code; // don't want this part of the options 4654 var week = merged.week; 4655 delete merged.week; 4656 return { 4657 codeArg: codeArg, 4658 codes: codes, 4659 week: week, 4660 simpleNumberFormat: new Intl.NumberFormat(codeArg), 4661 options: merged 4662 }; 4663 } 4664 4665 var OptionsManager = /** @class */ (function () { 4666 function OptionsManager(overrides) { 4667 this.overrides = __assign({}, overrides); // make a copy 4668 this.dynamicOverrides = {}; 4669 this.compute(); 4670 } 4671 OptionsManager.prototype.mutate = function (updates, removals, isDynamic) { 4672 var overrideHash = isDynamic ? this.dynamicOverrides : this.overrides; 4673 __assign(overrideHash, updates); 4674 for (var _i = 0, removals_1 = removals; _i < removals_1.length; _i++) { 4675 var propName = removals_1[_i]; 4676 delete overrideHash[propName]; 4677 } 4678 this.compute(); 4679 }; 4680 // Computes the flattened options hash for the calendar and assigns to `this.options`. 4681 // Assumes this.overrides and this.dynamicOverrides have already been initialized. 4682 OptionsManager.prototype.compute = function () {
4683 // TODO: not a very efficient system 4684 var locales = firstDefined(// explicit locale option given? 4685 this.dynamicOverrides.locales, this.overrides.locales, globalDefaults.locales); 4686 var locale = firstDefined(// explicit locales option given? 4687 this.dynamicOverrides.locale, this.overrides.locale, globalDefaults.locale); 4688 var available = parseRawLocales(locales); 4689 var localeDefaults = buildLocale(locale || available.defaultCode, available.map).options; 4690 var dir = firstDefined(// based on options computed so far, is direction RTL? 4691 this.dynamicOverrides.dir, this.overrides.dir, localeDefaults.dir); 4692 var dirDefaults = dir === 'rtl' ? rtlDefaults : {}; 4693 this.dirDefaults = dirDefaults; 4694 this.localeDefaults = localeDefaults; 4695 this.computed = mergeOptions([ 4696 globalDefaults, 4697 dirDefaults, 4698 localeDefaults, 4699 this.overrides, 4700 this.dynamicOverrides 4701 ]); 4702 }; 4703 return OptionsManager; 4704 }()); 4705 4706 var calendarSystemClassMap = {}; 4707 function registerCalendarSystem(name, theClass) { 4708 calendarSystemClassMap[name] = theClass; 4709 } 4710 function createCalendarSystem(name) { 4711 return new calendarSystemClassMap[name](); 4712 } 4713 var GregorianCalendarSystem = /** @class */ (function () { 4714 function GregorianCalendarSystem() { 4715 } 4716 GregorianCalendarSystem.prototype.getMarkerYear = function (d) { 4717 return d.getUTCFullYear(); 4718 }; 4719 GregorianCalendarSystem.prototype.getMarkerMonth = function (d) { 4720 return d.getUTCMonth(); 4721 }; 4722 GregorianCalendarSystem.prototype.getMarkerDay = function (d) { 4723 return d.getUTCDate(); 4724 }; 4725 GregorianCalendarSystem.prototype.arrayToMarker = function (arr) { 4726 return arrayToUtcDate(arr); 4727 }; 4728 GregorianCalendarSystem.prototype.markerToArray = function (marker) { 4729 return dateToUtcArray(marker); 4730 }; 4731 return GregorianCalendarSystem; 4732 }()); 4733 registerCalendarSystem('gregory', GregorianCalendarSystem); 4734 4735 var ISO_RE = /^\s*(\d{4})(-(\d{2})(-(\d{2})([T ](\d{2}):(\d{2})(:(\d{2})(\.(\d+))?)?(Z|(([-+])(\d{2})(:?(\d{2}))?))?)?)?)?$/; 4736 function parse(str) { 4737 var m = ISO_RE.exec(str); 4738 if (m) { 4739 var marker = new Date(Date.UTC(Number(m[1]), m[3] ? Number(m[3]) - 1 : 0, Number(m[5] || 1), Number(m[7] || 0), Number(m[8] || 0), Number(m[10] || 0), m[12] ? Number('0.' + m[12]) * 1000 : 0)); 4740 if (isValidDate(marker)) { 4741 var timeZoneOffset = null; 4742 if (m[13]) { 4743 timeZoneOffset = (m[15] === '-' ? -1 : 1) * (Number(m[16] || 0) * 60 + 4744 Number(m[18] || 0)); 4745 } 4746 return { 4747 marker: marker, 4748 isTimeUnspecified: !m[6], 4749 timeZoneOffset: timeZoneOffset 4750 }; 4751 } 4752 } 4753 return null; 4754 } 4755 4756 var DateEnv = /** @class */ (function () { 4757 function DateEnv(settings) { 4758 var timeZone = this.timeZone = settings.timeZone; 4759 var isNamedTimeZone = timeZone !== 'local' && timeZone !== 'UTC'; 4760 if (settings.namedTimeZoneImpl && isNamedTimeZone) { 4761 this.namedTimeZoneImpl = new settings.namedTimeZoneImpl(timeZone); 4762 } 4763 this.canComputeOffset = Boolean(!isNamedTimeZone || this.namedTimeZoneImpl); 4764 this.calendarSystem = createCalendarSystem(settings.calendarSystem); 4765 this.locale = settings.locale; 4766 this.weekDow = settings.locale.week.dow; 4767 this.weekDoy = settings.locale.week.doy; 4768 if (settings.weekNumberCalculation === 'ISO') { 4769 this.weekDow = 1; 4770 this.weekDoy = 4; 4771 } 4772 if (typeof settings.firstDay === 'number') { 4773 this.weekDow = settings.firstDay; 4774 } 4775 if (typeof settings.weekNumberCalculation === 'function') {
4776 this.weekNumberFunc = settings.weekNumberCalculation; 4777 } 4778 this.weekLabel = settings.weekLabel != null ? settings.weekLabel : settings.locale.options.weekLabel; 4779 this.cmdFormatter = settings.cmdFormatter; 4780 } 4781 // Creating / Parsing 4782 DateEnv.prototype.createMarker = function (input) { 4783 var meta = this.createMarkerMeta(input); 4784 if (meta === null) { 4785 return null; 4786 } 4787 return meta.marker; 4788 }; 4789 DateEnv.prototype.createNowMarker = function () { 4790 if (this.canComputeOffset) { 4791 return this.timestampToMarker(new Date().valueOf()); 4792 } 4793 else { 4794 // if we can't compute the current date val for a timezone, 4795 // better to give the current local date vals than UTC 4796 return arrayToUtcDate(dateToLocalArray(new Date())); 4797 } 4798 }; 4799 DateEnv.prototype.createMarkerMeta = function (input) { 4800 if (typeof input === 'string') { 4801 return this.parse(input); 4802 } 4803 var marker = null; 4804 if (typeof input === 'number') { 4805 marker = this.timestampToMarker(input); 4806 } 4807 else if (input instanceof Date) { 4808 input = input.valueOf(); 4809 if (!isNaN(input)) { 4810 marker = this.timestampToMarker(input); 4811 } 4812 } 4813 else if (Array.isArray(input)) { 4814 marker = arrayToUtcDate(input); 4815 } 4816 if (marker === null || !isValidDate(marker)) { 4817 return null; 4818 } 4819 return { marker: marker, isTimeUnspecified: false, forcedTzo: null }; 4820 }; 4821 DateEnv.prototype.parse = function (s) { 4822 var parts = parse(s); 4823 if (parts === null) { 4824 return null; 4825 } 4826 var marker = parts.marker; 4827 var forcedTzo = null; 4828 if (parts.timeZoneOffset !== null) { 4829 if (this.canComputeOffset) { 4830 marker = this.timestampToMarker(marker.valueOf() - parts.timeZoneOffset * 60 * 1000); 4831 } 4832 else { 4833 forcedTzo = parts.timeZoneOffset; 4834 } 4835 } 4836 return { marker: marker, isTimeUnspecified: parts.isTimeUnspecified, forcedTzo: forcedTzo }; 4837 }; 4838 // Accessors 4839 DateEnv.prototype.getYear = function (marker) { 4840 return this.calendarSystem.getMarkerYear(marker); 4841 }; 4842 DateEnv.prototype.getMonth = function (marker) { 4843 return this.calendarSystem.getMarkerMonth(marker); 4844 }; 4845 // Adding / Subtracting 4846 DateEnv.prototype.add = function (marker, dur) { 4847 var a = this.calendarSystem.markerToArray(marker); 4848 a[0] += dur.years; 4849 a[1] += dur.months; 4850 a[2] += dur.days; 4851 a[6] += dur.milliseconds; 4852 return this.calendarSystem.arrayToMarker(a); 4853 }; 4854 DateEnv.prototype.subtract = function (marker, dur) { 4855 var a = this.calendarSystem.markerToArray(marker); 4856 a[0] -= dur.years; 4857 a[1] -= dur.months; 4858 a[2] -= dur.days; 4859 a[6] -= dur.milliseconds; 4860 return this.calendarSystem.arrayToMarker(a); 4861 }; 4862 DateEnv.prototype.addYears = function (marker, n) { 4863 var a = this.calendarSystem.markerToArray(marker); 4864 a[0] += n; 4865 return this.calendarSystem.arrayToMarker(a); 4866 }; 4867 DateEnv.prototype.addMonths = function (marker, n) { 4868 var a = this.calendarSystem.markerToArray(marker); 4869 a[1] += n; 4870 return this.calendarSystem.arrayToMarker(a); 4871 }; 4872 // Diffing Whole Units 4873 DateEnv.prototype.diffWholeYears = function (m0, m1) { 4874 var calendarSystem = this.calendarSystem; 4875 if (timeAsMs(m0) === timeAsMs(m1) && 4876 calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1) && 4877 calendarSystem.getMarkerMonth(m0) === calendarSystem.getMarkerMonth(m1)) { 4878 return calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0); 4879 } 4880 return null; 4881 }; 4882 DateEnv.prototype.diffWholeMonths = function (m0, m1) { 4883 var calendarSystem = this.calendarSystem; 4884 if (timeAsMs(m0) === timeAsMs(m1) && 4885 calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1)) { 4886 return (calendarSystem.getMarkerMonth(m1) - calendarSystem.getMarkerMonth(m0)) + 4887 (calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0)) * 12; 4888 } 4889 return null; 4890 }; 4891 // Range / Duration 4892 DateEnv.prototype.greatestWholeUnit = function (m0, m1) { 4893 var n = this.diffWholeYears(m0, m1); 4894 if (n !== null) { 4895 return { unit: 'year', value: n }; 4896 } 4897 n = this.diffWholeMonths(m0, m1); 4898 if (n !== null) { 4899 return { unit: 'month', value: n }; 4900 } 4901 n = diffWholeWeeks(m0, m1); 4902 if (n !== null) { 4903 return { unit: 'week', value: n }; 4904 } 4905 n = diffWholeDays(m0, m1); 4906 if (n !== null) { 4907 return { unit: 'day', value: n }; 4908 } 4909 n = diffHours(m0, m1); 4910 if (isInt(n)) { 4911 return { unit: 'hour', value: n }; 4912 } 4913 n = diffMinutes(m0, m1); 4914 if (isInt(n)) { 4915 return { unit: 'minute', value: n }; 4916 } 4917 n = diffSeconds(m0, m1); 4918 if (isInt(n)) { 4919 return { unit: 'second', value: n }; 4920 } 4921 return { unit: 'millisecond', value: m1.valueOf() - m0.valueOf() }; 4922 }; 4923 DateEnv.prototype.countDurationsBetween = function (m0, m1, d) { 4924 // TODO: can use greatestWholeUnit 4925 var diff; 4926 if (d.years) { 4927 diff = this.diffWholeYears(m0, m1); 4928 if (diff !== null) { 4929 return diff / asRoughYears(d); 4930 } 4931 } 4932 if (d.months) { 4933 diff = this.diffWholeMonths(m0, m1); 4934 if (diff !== null) { 4935 return diff / asRoughMonths(d); 4936 } 4937 } 4938 if (d.days) { 4939 diff = diffWholeDays(m0, m1); 4940 if (diff !== null) { 4941 return diff / asRoughDays(d); 4942 } 4943 } 4944 return (m1.valueOf() - m0.valueOf()) / asRoughMs(d); 4945 }; 4946 // Start-Of 4947 DateEnv.prototype.startOf = function (m, unit) { 4948 if (unit === 'year') { 4949 return this.startOfYear(m); 4950 } 4951 else if (unit === 'month') { 4952 return this.startOfMonth(m); 4953 } 4954 else if (unit === 'week') { 4955 return this.startOfWeek(m); 4956 } 4957 else if (unit === 'day') { 4958 return startOfDay(m); 4959 } 4960 else if (unit === 'hour') { 4961 return startOfHour(m); 4962 } 4963 else if (unit === 'minute') { 4964 return startOfMinute(m); 4965 } 4966 else if (unit === 'second') { 4967 return startOfSecond(m); 4968 } 4969 }; 4970 DateEnv.prototype.startOfYear = function (m) { 4971 return this.calendarSystem.arrayToMarker([ 4972 this.calendarSystem.getMarkerYear(m) 4973 ]); 4974 }; 4975 DateEnv.prototype.startOfMonth = function (m) { 4976 return this.calendarSystem.arrayToMarker([ 4977 this.calendarSystem.getMarkerYear(m), 4978 this.calendarSystem.getMarkerMonth(m) 4979 ]); 4980 }; 4981 DateEnv.prototype.startOfWeek = function (m) { 4982 return this.calendarSystem.arrayToMarker([ 4983 this.calendarSystem.getMarkerYear(m), 4984 this.calendarSystem.getMarkerMonth(m), 4985 m.getUTCDate() - ((m.getUTCDay() - this.weekDow + 7) % 7) 4986 ]); 4987 }; 4988 // Week Number 4989 DateEnv.prototype.computeWeekNumber = function (marker) { 4990 if (this.weekNumberFunc) { 4991 return this.weekNumberFunc(this.toDate(marker)); 4992 } 4993 else { 4994 return weekOfYear(marker, this.weekDow, this.weekDoy); 4995 } 4996 }; 4997 // TODO: choke on timeZoneName: long 4998 DateEnv.prototype.format = function (marker, formatter, dateOptions) { 4999 if (dateOptions === void 0) { dateOptions = {}; } 5000 return formatter.format({ 5001 marker: marker, 5002 timeZoneOffset: dateOptions.forcedTzo != null ? 5003 dateOptions.forcedTzo : 5004 this.offsetForMarker(marker) 5005 }, this); 5006 }; 5007 DateEnv.prototype.formatRange = function (start, end, formatter, dateOptions) { 5008 if (dateOptions === void 0) { dateOptions = {}; } 5009 if (dateOptions.isEndExclusive) { 5010 end = addMs(end, -1); 5011 } 5012 return formatter.formatRange({ 5013 marker: start, 5014 timeZoneOffset: dateOptions.forcedStartTzo != null ? 5015 dateOptions.forcedStartTzo : 5016 this.offsetForMarker(start) 5017 }, { 5018 marker: end, 5019 timeZoneOffset: dateOptions.forcedEndTzo != null ? 5020 dateOptions.forcedEndTzo : 5021 this.offsetForMarker(end) 5022 }, this); 5023 }; 5024 DateEnv.prototype.formatIso = function (marker, extraOptions) { 5025 if (extraOptions === void 0) { extraOptions = {}; } 5026 var timeZoneOffset = null; 5027 if (!extraOptions.omitTimeZoneOffset) { 5028 if (extraOptions.forcedTzo != null) { 5029 timeZoneOffset = extraOptions.forcedTzo; 5030 } 5031 else { 5032 timeZoneOffset = this.offsetForMarker(marker); 5033 } 5034 } 5035 return buildIsoString(marker, timeZoneOffset, extraOptions.omitTime); 5036 }; 5037 // TimeZone 5038 DateEnv.prototype.timestampToMarker = function (ms) { 5039 if (this.timeZone === 'local') { 5040 return arrayToUtcDate(dateToLocalArray(new Date(ms))); 5041 } 5042 else if (this.timeZone === 'UTC' || !this.namedTimeZoneImpl) { 5043 return new Date(ms); 5044 } 5045 else { 5046 return arrayToUtcDate(this.namedTimeZoneImpl.timestampToArray(ms)); 5047 } 5048 }; 5049 DateEnv.prototype.offsetForMarker = function (m) { 5050 if (this.timeZone === 'local') { 5051 return -arrayToLocalDate(dateToUtcArray(m)).getTimezoneOffset(); // convert "inverse" offset to "normal" offset 5052 } 5053 else if (this.timeZone === 'UTC') { 5054 return 0; 5055 } 5056 else if (this.namedTimeZoneImpl) { 5057 return this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)); 5058 } 5059 return null; 5060 }; 5061 // Conversion 5062 DateEnv.prototype.toDate = function (m, forcedTzo) { 5063 if (this.timeZone === 'local') { 5064 return arrayToLocalDate(dateToUtcArray(m)); 5065 } 5066 else if (this.timeZone === 'UTC') { 5067 return new Date(m.valueOf()); // make sure it's a copy 5068 } 5069 else if (!this.namedTimeZoneImpl) { 5070 return new Date(m.valueOf() - (forcedTzo || 0)); 5071 } 5072 else { 5073 return new Date(m.valueOf() - 5074 this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)) * 1000 * 60 // convert minutes -> ms 5075 ); 5076 } 5077 }; 5078 return DateEnv; 5079 }()); 5080 5081 var SIMPLE_SOURCE_PROPS = { 5082 id: String, 5083 allDayDefault: Boolean, 5084 eventDataTransform: Function, 5085 success: Function, 5086 failure: Function 5087 }; 5088 var uid$2 = 0; 5089 function doesSourceNeedRange(eventSource, calendar) { 5090 var defs = calendar.pluginSystem.hooks.eventSourceDefs; 5091 return !defs[eventSource.sourceDefId].ignoreRange; 5092 } 5093 function parseEventSource(raw, calendar) { 5094 var defs = calendar.pluginSystem.hooks.eventSourceDefs;
5095 for (var i = defs.length - 1; i >= 0; i--) { // later-added plugins take precedence 5096 var def = defs[i]; 5097 var meta = def.parseMeta(raw); 5098 if (meta) { 5099 var res = parseEventSourceProps(typeof raw === 'object' ? raw : {}, meta, i, calendar); 5100 res._raw = raw; 5101 return res; 5102 } 5103 } 5104 return null; 5105 } 5106 function parseEventSourceProps(raw, meta, sourceDefId, calendar) { 5107 var leftovers0 = {}; 5108 var props = refineProps(raw, SIMPLE_SOURCE_PROPS, {}, leftovers0); 5109 var leftovers1 = {}; 5110 var ui = processUnscopedUiProps(leftovers0, calendar, leftovers1); 5111 props.isFetching = false; 5112 props.latestFetchId = ''; 5113 props.fetchRange = null; 5114 props.publicId = String(raw.id || ''); 5115 props.sourceId = String(uid$2++); 5116 props.sourceDefId = sourceDefId; 5117 props.meta = meta; 5118 props.ui = ui; 5119 props.extendedProps = leftovers1; 5120 return props; 5121 } 5122 5123 function reduceEventSources (eventSources, action, dateProfile, calendar) { 5124 switch (action.type) { 5125 case 'ADD_EVENT_SOURCES': // already parsed 5126 return addSources(eventSources, action.sources, dateProfile ? dateProfile.activeRange : null, calendar);
5127 case 'REMOVE_EVENT_SOURCE': 5128 return removeSource(eventSources, action.sourceId); 5129 case 'PREV': // TODO: how do we track all actions that affect dateProfile :( 5130 case 'NEXT': 5131 case 'SET_DATE': 5132 case 'SET_VIEW_TYPE': 5133 if (dateProfile) { 5134 return fetchDirtySources(eventSources, dateProfile.activeRange, calendar); 5135 } 5136 else { 5137 return eventSources; 5138 } 5139 case 'FETCH_EVENT_SOURCES': 5140 case 'CHANGE_TIMEZONE': 5141 return fetchSourcesByIds(eventSources, action.sourceIds ? 5142 arrayToHash(action.sourceIds) : 5143 excludeStaticSources(eventSources, calendar), dateProfile ? dateProfile.activeRange : null, calendar); 5144 case 'RECEIVE_EVENTS': 5145 case 'RECEIVE_EVENT_ERROR': 5146 return receiveResponse(eventSources, action.sourceId, action.fetchId, action.fetchRange); 5147 case 'REMOVE_ALL_EVENT_SOURCES': 5148 return {}; 5149 default: 5150 return eventSources; 5151 } 5152 } 5153 var uid$3 = 0; 5154 function addSources(eventSourceHash, sources, fetchRange, calendar) { 5155 var hash = {}; 5156 for (var _i = 0, sources_1 = sources; _i < sources_1.length; _i++) { 5157 var source = sources_1[_i]; 5158 hash[source.sourceId] = source; 5159 } 5160 if (fetchRange) { 5161 hash = fetchDirtySources(hash, fetchRange, calendar); 5162 } 5163 return __assign({}, eventSourceHash, hash); 5164 } 5165 function removeSource(eventSourceHash, sourceId) { 5166 return filterHash(eventSourceHash, function (eventSource) { 5167 return eventSource.sourceId !== sourceId; 5168 }); 5169 } 5170 function fetchDirtySources(sourceHash, fetchRange, calendar) { 5171 return fetchSourcesByIds(sourceHash, filterHash(sourceHash, function (eventSource) { 5172 return isSourceDirty(eventSource, fetchRange, calendar); 5173 }), fetchRange, calendar); 5174 } 5175 function isSourceDirty(eventSource, fetchRange, calendar) { 5176 if (!doesSourceNeedRange(eventSource, calendar)) { 5177 return !eventSource.latestFetchId; 5178 } 5179 else { 5180 return !calendar.opt('lazyFetching') || 5181 !eventSource.fetchRange || 5182 fetchRange.start < eventSource.fetchRange.start || 5183 fetchRange.end > eventSource.fetchRange.end; 5184 } 5185 } 5186 function fetchSourcesByIds(prevSources, sourceIdHash, fetchRange, calendar) { 5187 var nextSources = {}; 5188 for (var sourceId in prevSources) { 5189 var source = prevSources[sourceId]; 5190 if (sourceIdHash[sourceId]) { 5191 nextSources[sourceId] = fetchSource(source, fetchRange, calendar); 5192 } 5193 else { 5194 nextSources[sourceId] = source; 5195 } 5196 } 5197 return nextSources; 5198 } 5199 function fetchSource(eventSource, fetchRange, calendar) { 5200 var sourceDef = calendar.pluginSystem.hooks.eventSourceDefs[eventSource.sourceDefId]; 5201 var fetchId = String(uid$3++); 5202 sourceDef.fetch({ 5203 eventSource: eventSource, 5204 calendar: calendar, 5205 range: fetchRange 5206 }, function (res) { 5207 var rawEvents = res.rawEvents; 5208 var calSuccess = calendar.opt('eventSourceSuccess'); 5209 var calSuccessRes; 5210 var sourceSuccessRes; 5211 if (eventSource.success) { 5212 sourceSuccessRes = eventSource.success(rawEvents, res.xhr); 5213 } 5214 if (calSuccess) { 5215 calSuccessRes = calSuccess(rawEvents, res.xhr); 5216 } 5217 rawEvents = sourceSuccessRes || calSuccessRes || rawEvents; 5218 calendar.dispatch({ 5219 type: 'RECEIVE_EVENTS', 5220 sourceId: eventSource.sourceId, 5221 fetchId: fetchId, 5222 fetchRange: fetchRange, 5223 rawEvents: rawEvents 5224 }); 5225 }, function (error) { 5226 var callFailure = calendar.opt('eventSourceFailure'); 5227 console.warn(error.message, error); 5228 if (eventSource.failure) { 5229 eventSource.failure(error); 5230 } 5231 if (callFailure) { 5232 callFailure(error); 5233 } 5234 calendar.dispatch({ 5235 type: 'RECEIVE_EVENT_ERROR', 5236 sourceId: eventSource.sourceId, 5237 fetchId: fetchId, 5238 fetchRange: fetchRange, 5239 error: error 5240 }); 5241 }); 5242 return __assign({}, eventSource, { isFetching: true, latestFetchId: fetchId }); 5243 } 5244 function receiveResponse(sourceHash, sourceId, fetchId, fetchRange) { 5245 var _a; 5246 var eventSource = sourceHash[sourceId]; 5247 if (eventSource && // not already removed 5248 fetchId === eventSource.latestFetchId) { 5249 return __assign({}, sourceHash, (_a = {}, _a[sourceId] = __assign({}, eventSource, { isFetching: false, fetchRange: fetchRange }), _a)); 5250 } 5251 return sourceHash; 5252 } 5253 function excludeStaticSources(eventSources, calendar) { 5254 return filterHash(eventSources, function (eventSource) { 5255 return doesSourceNeedRange(eventSource, calendar); 5256 }); 5257 } 5258 5259 var DateProfileGenerator = /** @class */ (function () { 5260 function DateProfileGenerator(viewSpec, calendar) { 5261 this.viewSpec = viewSpec; 5262 this.options = viewSpec.options; 5263 this.dateEnv = calendar.dateEnv; 5264 this.calendar = calendar; 5265 this.initHiddenDays(); 5266 } 5267 /* Date Range Computation 5268 ------------------------------------------------------------------------------------------------------------------*/ 5269 // Builds a structure with info about what the dates/ranges will be for the "prev" view. 5270 DateProfileGenerator.prototype.buildPrev = function (currentDateProfile, currentDate) { 5271 var dateEnv = this.dateEnv; 5272 var prevDate = dateEnv.subtract(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month 5273 currentDateProfile.dateIncrement); 5274 return this.build(prevDate, -1); 5275 }; 5276 // Builds a structure with info about what the dates/ranges will be for the "next" view. 5277 DateProfileGenerator.prototype.buildNext = function (currentDateProfile, currentDate) { 5278 var dateEnv = this.dateEnv; 5279 var nextDate = dateEnv.add(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month 5280 currentDateProfile.dateIncrement); 5281 return this.build(nextDate, 1); 5282 }; 5283 // Builds a structure holding dates/ranges for rendering around the given date. 5284 // Optional direction param indicates whether the date is being incremented/decremented 5285 // from its previous value. decremented = -1, incremented = 1 (default). 5286 DateProfileGenerator.prototype.build = function (currentDate, direction, forceToValid) { 5287 if (forceToValid === void 0) { forceToValid = false; }
5288 var validRange; 5289 var minTime = null; 5290 var maxTime = null; 5291 var currentInfo; 5292 var isRangeAllDay; 5293 var renderRange; 5294 var activeRange; 5295 var isValid; 5296 validRange = this.buildValidRange(); 5297 validRange = this.trimHiddenDays(validRange); 5298 if (forceToValid) { 5299 currentDate = constrainMarkerToRange(currentDate, validRange); 5300 } 5301 currentInfo = this.buildCurrentRangeInfo(currentDate, direction); 5302 isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit); 5303 renderRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.range), currentInfo.unit, isRangeAllDay); 5304 renderRange = this.trimHiddenDays(renderRange); 5305 activeRange = renderRange; 5306 if (!this.options.showNonCurrentDates) { 5307 activeRange = intersectRanges(activeRange, currentInfo.range); 5308 } 5309 minTime = createDuration(this.options.minTime); 5310 maxTime = createDuration(this.options.maxTime); 5311 activeRange = this.adjustActiveRange(activeRange, minTime, maxTime); 5312 activeRange = intersectRanges(activeRange, validRange); // might return null 5313 // it's invalid if the originally requested date is not contained, 5314 // or if the range is completely outside of the valid range. 5315 isValid = rangesIntersect(currentInfo.range, validRange); 5316 return { 5317 // constraint for where prev/next operations can go and where events can be dragged/resized to. 5318 // an object with optional start and end properties. 5319 validRange: validRange, 5320 // range the view is formally responsible for. 5321 // for example, a month view might have 1st-31st, excluding padded dates 5322 currentRange: currentInfo.range, 5323 // name of largest unit being displayed, like "month" or "week" 5324 currentRangeUnit: currentInfo.unit, 5325 isRangeAllDay: isRangeAllDay, 5326 // dates that display events and accept drag-n-drop 5327 // will be `null` if no dates accept events 5328 activeRange: activeRange, 5329 // date range with a rendered skeleton 5330 // includes not-active days that need some sort of DOM 5331 renderRange: renderRange, 5332 // Duration object that denotes the first visible time of any given day 5333 minTime: minTime, 5334 // Duration object that denotes the exclusive visible end time of any given day 5335 maxTime: maxTime, 5336 isValid: isValid, 5337 // how far the current date will move for a prev/next operation 5338 dateIncrement: this.buildDateIncrement(currentInfo.duration) 5339 // pass a fallback (might be null) ^ 5340 }; 5341 }; 5342 // Builds an object with optional start/end properties. 5343 // Indicates the minimum/maximum dates to display. 5344 // not responsible for trimming hidden days. 5345 DateProfileGenerator.prototype.buildValidRange = function () { 5346 return this.getRangeOption('validRange', this.calendar.getNow()) || 5347 { start: null, end: null }; // completely open-ended 5348 }; 5349 // Builds a structure with info about the "current" range, the range that is 5350 // highlighted as being the current month for example. 5351 // See build() for a description of `direction`. 5352 // Guaranteed to have `range` and `unit` properties. `duration` is optional. 5353 DateProfileGenerator.prototype.buildCurrentRangeInfo = function (date, direction) { 5354 var _a = this, viewSpec = _a.viewSpec, dateEnv = _a.dateEnv; 5355 var duration = null; 5356 var unit = null; 5357 var range = null; 5358 var dayCount; 5359 if (viewSpec.duration) { 5360 duration = viewSpec.duration; 5361 unit = viewSpec.durationUnit; 5362 range = this.buildRangeFromDuration(date, direction, duration, unit); 5363 } 5364 else if ((dayCount = this.options.dayCount)) { 5365 unit = 'day'; 5366 range = this.buildRangeFromDayCount(date, direction, dayCount); 5367 } 5368 else if ((range = this.buildCustomVisibleRange(date))) { 5369 unit = dateEnv.greatestWholeUnit(range.start, range.end).unit; 5370 } 5371 else { 5372 duration = this.getFallbackDuration(); 5373 unit = greatestDurationDenominator(duration).unit; 5374 range = this.buildRangeFromDuration(date, direction, duration, unit); 5375 } 5376 return { duration: duration, unit: unit, range: range }; 5377 }; 5378 DateProfileGenerator.prototype.getFallbackDuration = function () { 5379 return createDuration({ day: 1 }); 5380 }; 5381 // Returns a new activeRange to have time values (un-ambiguate) 5382 // minTime or maxTime causes the range to expand. 5383 DateProfileGenerator.prototype.adjustActiveRange = function (range, minTime, maxTime) { 5384 var dateEnv = this.dateEnv; 5385 var start = range.start; 5386 var end = range.end; 5387 if (this.viewSpec.class.prototype.usesMinMaxTime) { 5388 // expand active range if minTime is negative (why not when positive?) 5389 if (asRoughDays(minTime) < 0) { 5390 start = startOfDay(start); // necessary? 5391 start = dateEnv.add(start, minTime); 5392 } 5393 // expand active range if maxTime is beyond one day (why not when positive?) 5394 if (asRoughDays(maxTime) > 1) { 5395 end = startOfDay(end); // necessary? 5396 end = addDays(end, -1); 5397 end = dateEnv.add(end, maxTime); 5398 } 5399 } 5400 return { start: start, end: end }; 5401 }; 5402 // Builds the "current" range when it is specified as an explicit duration. 5403 // `unit` is the already-computed greatestDurationDenominator unit of duration. 5404 DateProfileGenerator.prototype.buildRangeFromDuration = function (date, direction, duration, unit) { 5405 var dateEnv = this.dateEnv; 5406 var alignment = this.options.dateAlignment; 5407 var dateIncrementInput; 5408 var dateIncrementDuration; 5409 var start; 5410 var end; 5411 var res; 5412 // compute what the alignment should be 5413 if (!alignment) { 5414 dateIncrementInput = this.options.dateIncrement; 5415 if (dateIncrementInput) { 5416 dateIncrementDuration = createDuration(dateIncrementInput); 5417 // use the smaller of the two units 5418 if (asRoughMs(dateIncrementDuration) < asRoughMs(duration)) { 5419 alignment = greatestDurationDenominator(dateIncrementDuration, !getWeeksFromInput(dateIncrementInput)).unit; 5420 } 5421 else { 5422 alignment = unit; 5423 } 5424 } 5425 else { 5426 alignment = unit; 5427 } 5428 }
5429 // if the view displays a single day or smaller 5430 if (asRoughDays(duration) <= 1) { 5431 if (this.isHiddenDay(start)) { 5432 start = this.skipHiddenDays(start, direction); 5433 start = startOfDay(start); 5434 } 5435 } 5436 function computeRes() { 5437 start = dateEnv.startOf(date, alignment); 5438 end = dateEnv.add(start, duration); 5439 res = { start: start, end: end }; 5440 } 5441 computeRes(); 5442 // if range is completely enveloped by hidden days, go past the hidden days 5443 if (!this.trimHiddenDays(res)) { 5444 date = this.skipHiddenDays(date, direction); 5445 computeRes(); 5446 } 5447 return res; 5448 }; 5449 // Builds the "current" range when a dayCount is specified. 5450 DateProfileGenerator.prototype.buildRangeFromDayCount = function (date, direction, dayCount) { 5451 var dateEnv = this.dateEnv; 5452 var customAlignment = this.options.dateAlignment; 5453 var runningCount = 0; 5454 var start = date; 5455 var end; 5456 if (customAlignment) { 5457 start = dateEnv.startOf(start, customAlignment); 5458 } 5459 start = startOfDay(start); 5460 start = this.skipHiddenDays(start, direction); 5461 end = start; 5462 do { 5463 end = addDays(end, 1); 5464 if (!this.isHiddenDay(end)) { 5465 runningCount++; 5466 } 5467 } while (runningCount < dayCount); 5468 return { start: start, end: end }; 5469 }; 5470 // Builds a normalized range object for the "visible" range, 5471 // which is a way to define the currentRange and activeRange at the same time. 5472 DateProfileGenerator.prototype.buildCustomVisibleRange = function (date) { 5473 var dateEnv = this.dateEnv; 5474 var visibleRange = this.getRangeOption('visibleRange', dateEnv.toDate(date)); 5475 if (visibleRange && (visibleRange.start == null || visibleRange.end == null)) { 5476 return null; 5477 } 5478 return visibleRange; 5479 }; 5480 // Computes the range that will represent the element/cells for *rendering*, 5481 // but which may have voided days/times. 5482 // not responsible for trimming hidden days. 5483 DateProfileGenerator.prototype.buildRenderRange = function (currentRange, currentRangeUnit, isRangeAllDay) { 5484 return currentRange; 5485 }; 5486 // Compute the duration value that should be added/substracted to the current date 5487 // when a prev/next operation happens. 5488 DateProfileGenerator.prototype.buildDateIncrement = function (fallback) { 5489 var dateIncrementInput = this.options.dateIncrement; 5490 var customAlignment; 5491 if (dateIncrementInput) { 5492 return createDuration(dateIncrementInput); 5493 } 5494 else if ((customAlignment = this.options.dateAlignment)) { 5495 return createDuration(1, customAlignment); 5496 } 5497 else if (fallback) { 5498 return fallback; 5499 } 5500 else { 5501 return createDuration({ days: 1 }); 5502 } 5503 }; 5504 // Arguments after name will be forwarded to a hypothetical function value 5505 // WARNING: passed-in arguments will be given to generator functions as-is and can cause side-effects. 5506 // Always clone your objects if you fear mutation. 5507 DateProfileGenerator.prototype.getRangeOption = function (name) { 5508 var otherArgs = []; 5509 for (var _i = 1; _i < arguments.length; _i++) { 5510 otherArgs[_i - 1] = arguments[_i]; 5511 } 5512 var val = this.options[name]; 5513 if (typeof val === 'function') { 5514 val = val.apply(null, otherArgs); 5515 } 5516 if (val) { 5517 val = parseRange(val, this.dateEnv); 5518 } 5519 if (val) { 5520 val = computeVisibleDayRange(val); 5521 } 5522 return val; 5523 }; 5524 /* Hidden Days 5525 ------------------------------------------------------------------------------------------------------------------*/ 5526 // Initializes internal variables related to calculating hidden days-of-week 5527 DateProfileGenerator.prototype.initHiddenDays = function () { 5528 var hiddenDays = this.options.hiddenDays || []; // array of day-of-week indices that are hidden
5529 var isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool) 5530 var dayCnt = 0; 5531 var i; 5532 if (this.options.weekends === false) { 5533 hiddenDays.push(0, 6); // 0=sunday, 6=saturday 5534 } 5535 for (i = 0; i < 7; i++) { 5536 if (!(isHiddenDayHash[i] = hiddenDays.indexOf(i) !== -1)) { 5537 dayCnt++; 5538 } 5539 } 5540 if (!dayCnt) { 5541 throw new Error('invalid hiddenDays'); // all days were hidden? bad. 5542 } 5543 this.isHiddenDayHash = isHiddenDayHash; 5544 }; 5545 // Remove days from the beginning and end of the range that are computed as hidden. 5546 // If the whole range is trimmed off, returns null 5547 DateProfileGenerator.prototype.trimHiddenDays = function (range) { 5548 var start = range.start; 5549 var end = range.end; 5550 if (start) { 5551 start = this.skipHiddenDays(start); 5552 } 5553 if (end) { 5554 end = this.skipHiddenDays(end, -1, true); 5555 } 5556 if (start == null || end == null || start < end) { 5557 return { start: start, end: end }; 5558 } 5559 return null; 5560 }; 5561 // Is the current day hidden? 5562 // `day` is a day-of-week index (0-6), or a Date (used for UTC) 5563 DateProfileGenerator.prototype.isHiddenDay = function (day) { 5564 if (day instanceof Date) { 5565 day = day.getUTCDay(); 5566 } 5567 return this.isHiddenDayHash[day]; 5568 }; 5569 // Incrementing the current day until it is no longer a hidden day, returning a copy. 5570 // DOES NOT CONSIDER validRange! 5571 // If the initial value of `date` is not a hidden day, don't do anything. 5572 // Pass `isExclusive` as `true` if you are dealing with an end date. 5573 // `inc` defaults to `1` (increment one day forward each time) 5574 DateProfileGenerator.prototype.skipHiddenDays = function (date, inc, isExclusive) { 5575 if (inc === void 0) { inc = 1; } 5576 if (isExclusive === void 0) { isExclusive = false; } 5577 while (this.isHiddenDayHash[(date.getUTCDay() + (isExclusive ? inc : 0) + 7) % 7]) { 5578 date = addDays(date, inc); 5579 } 5580 return date; 5581 }; 5582 return DateProfileGenerator; 5583 }());
5584 // TODO: find a way to avoid comparing DateProfiles. it's tedious 5585 function isDateProfilesEqual(p0, p1) { 5586 return rangesEqual(p0.validRange, p1.validRange) && 5587 rangesEqual(p0.activeRange, p1.activeRange) && 5588 rangesEqual(p0.renderRange, p1.renderRange) && 5589 durationsEqual(p0.minTime, p1.minTime) && 5590 durationsEqual(p0.maxTime, p1.maxTime); 5591 /* 5592 TODO: compare more? 5593 currentRange: DateRange 5594 currentRangeUnit: string 5595 isRangeAllDay: boolean 5596 isValid: boolean 5597 dateIncrement: Duration 5598 */ 5599 } 5600 5601 function reduce (state, action, calendar) { 5602 var viewType = reduceViewType(state.viewType, action); 5603 var dateProfile = reduceDateProfile(state.dateProfile, action, state.currentDate, viewType, calendar); 5604 var eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendar); 5605 var nextState = __assign({}, state, { viewType: viewType, 5606 dateProfile: dateProfile, currentDate: reduceCurrentDate(state.currentDate, action, dateProfile), eventSources: eventSources, eventStore: reduceEventStore(state.eventStore, action, eventSources, dateProfile, calendar), dateSelection: reduceDateSelection(state.dateSelection, action, calendar), eventSelection: reduceSelectedEvent(state.eventSelection, action), eventDrag: reduceEventDrag(state.eventDrag, action, eventSources, calendar), eventResize: reduceEventResize(state.eventResize, action, eventSources, calendar), eventSourceLoadingLevel: computeLoadingLevel(eventSources), loadingLevel: computeLoadingLevel(eventSources) }); 5607 for (var _i = 0, _a = calendar.pluginSystem.hooks.reducers; _i < _a.length; _i++) { 5608 var reducerFunc = _a[_i]; 5609 nextState = reducerFunc(nextState, action, calendar); 5610 } 5611 // console.log(action.type, nextState) 5612 return nextState; 5613 } 5614 function reduceViewType(currentViewType, action) { 5615 switch (action.type) { 5616 case 'SET_VIEW_TYPE': 5617 return action.viewType; 5618 default: 5619 return currentViewType; 5620 } 5621 } 5622 function reduceDateProfile(currentDateProfile, action, currentDate, viewType, calendar) { 5623 var newDateProfile; 5624 switch (action.type) { 5625 case 'PREV': 5626 newDateProfile = calendar.dateProfileGenerators[viewType].buildPrev(currentDateProfile, currentDate); 5627 break; 5628 case 'NEXT': 5629 newDateProfile = calendar.dateProfileGenerators[viewType].buildNext(currentDateProfile, currentDate); 5630 break; 5631 case 'SET_DATE': 5632 if (!currentDateProfile.activeRange || 5633 !rangeContainsMarker(currentDateProfile.currentRange, action.dateMarker)) { 5634 newDateProfile = calendar.dateProfileGenerators[viewType].build(action.dateMarker, undefined, true // forceToValid 5635 ); 5636 } 5637 break; 5638 case 'SET_VIEW_TYPE': 5639 var generator = calendar.dateProfileGenerators[viewType]; 5640 if (!generator) { 5641 throw new Error(viewType ? 5642 'The FullCalendar view "' + viewType + '" does not exist. Make sure your plugins are loaded correctly.' : 5643 'No available FullCalendar view plugins.'); 5644 } 5645 newDateProfile = generator.build(action.dateMarker || currentDate, undefined, true // forceToValid 5646 ); 5647 break; 5648 } 5649 if (newDateProfile && 5650 newDateProfile.isValid && 5651 !(currentDateProfile && isDateProfilesEqual(currentDateProfile, newDateProfile))) { 5652 return newDateProfile; 5653 } 5654 else { 5655 return currentDateProfile; 5656 } 5657 } 5658 function reduceCurrentDate(currentDate, action, dateProfile) { 5659 switch (action.type) { 5660 case 'PREV': 5661 case 'NEXT': 5662 if (!rangeContainsMarker(dateProfile.currentRange, currentDate)) { 5663 return dateProfile.currentRange.start; 5664 } 5665 else { 5666 return currentDate; 5667 } 5668 case 'SET_DATE': 5669 case 'SET_VIEW_TYPE': 5670 var newDate = action.dateMarker || currentDate; 5671 if (dateProfile.activeRange && !rangeContainsMarker(dateProfile.activeRange, newD
5671ate)) { 5672 return dateProfile.currentRange.start; 5673 } 5674 else { 5675 return newDate; 5676 } 5677 default: 5678 return currentDate; 5679 } 5680 } 5681 function reduceDateSelection(currentSelection, action, calendar) { 5682 switch (action.type) { 5683 case 'SELECT_DATES': 5684 return action.selection; 5685 case 'UNSELECT_DATES': 5686 return null; 5687 default: 5688 return currentSelection; 5689 } 5690 } 5691 function reduceSelectedEvent(currentInstanceId, action) { 5692 switch (action.type) { 5693 case 'SELECT_EVENT': 5694 return action.eventInstanceId; 5695 case 'UNSELECT_EVENT': 5696 return ''; 5697 default: 5698 return currentInstanceId; 5699 } 5700 } 5701 function reduceEventDrag(currentDrag, action, sources, calendar) { 5702 switch (action.type) { 5703 case 'SET_EVENT_DRAG': 5704 var newDrag = action.state; 5705 return { 5706 affectedEvents: newDrag.affectedEvents, 5707 mutatedEvents: newDrag.mutatedEvents, 5708 isEvent: newDrag.isEvent, 5709 origSeg: newDrag.origSeg 5710 }; 5711 case 'UNSET_EVENT_DRAG': 5712 return null; 5713 default: 5714 return currentDrag; 5715 } 5716 } 5717 function reduceEventResize(currentResize, action, sources, calendar) { 5718 switch (action.type) { 5719 case 'SET_EVENT_RESIZE': 5720 var newResize = action.state; 5721 return { 5722 affectedEvents: newResize.affectedEvents, 5723 mutatedEvents: newResize.mutatedEvents, 5724 isEvent: newResize.isEvent, 5725 origSeg: newResize.origSeg 5726 }; 5727 case 'UNSET_EVENT_RESIZE': 5728 return null; 5729 default: 5730 return currentResize; 5731 } 5732 } 5733 function computeLoadingLevel(eventSources) { 5734 var cnt = 0; 5735 for (var sourceId in eventSources) { 5736 if (eventSources[sourceId].isFetching) { 5737 cnt++; 5738 } 5739 } 5740 return cnt; 5741 } 5742 5743 var STANDARD_PROPS = { 5744 start: null, 5745 end: null, 5746 allDay: Boolean 5747 }; 5748 function parseDateSpan(raw, dateEnv, defaultDuration) { 5749 var span = parseOpenDateSpan(raw, dateEnv); 5750 var range = span.range; 5751 if (!range.start) { 5752 return null; 5753 } 5754 if (!range.end) { 5755 if (defaultDuration == null) { 5756 return null; 5757 } 5758 else { 5759 range.end = dateEnv.add(range.start, defaultDuration); 5760 } 5761 } 5762 return span; 5763 } 5764 /* 5765 TODO: somehow combine with parseRange? 5766 Will return null if the start/end props were present but parsed invalidly. 5767 */ 5768 function parseOpenDateSpan(raw, dateEnv) { 5769 var leftovers = {}; 5770 var standardProps = refineProps(raw, STANDARD_PROPS, {}, leftovers); 5771 var startMeta = standardProps.start ? dateEnv.createMarkerMeta(standardProps.start) : null; 5772 var endMeta = standardProps.end ? dateEnv.createMarkerMeta(standardProps.end) : null; 5773 var allDay = standardProps.allDay; 5774 if (allDay == null) { 5775 allDay = (startMeta && startMeta.isTimeUnspecified) && 5776 (!endMeta || endMeta.isTimeUnspecified); 5777 } 5778 // use this leftover object as the selection object 5779 leftovers.range = { 5780 start: startMeta ? startMeta.marker : null, 5781 end: endMeta ? endMeta.marker : null 5782 }; 5783 leftovers.allDay = allDay; 5784 return leftovers; 5785 } 5786 function isDateSpansEqual(span0, span1) { 5787 return rangesEqual(span0.range, span1.range) && 5788 span0.allDay === span1.allDay && 5789 isSpanPropsEqual(span0, span1); 5790 } 5791 // the NON-DATE-RELATED props 5792 function isSpanPropsEqual(span0, span1) { 5793 for (var propName in span1) { 5794 if (propName !== 'range' && propName !== 'allDay') { 5795 if (span0[propName] !== span1[propName]) { 5796 return false;
5797 } 5798 } 5799 } 5800 // are there any props that span0 has that span1 DOESN'T have? 5801 // both have range/allDay, so no need to special-case. 5802 for (var propName in span0) { 5803 if (!(propName in span1)) { 5804 return false; 5805 } 5806 } 5807 return true; 5808 } 5809 function buildDateSpanApi(span, dateEnv) { 5810 return { 5811 start: dateEnv.toDate(span.range.start), 5812 end: dateEnv.toDate(span.range.end), 5813 startStr: dateEnv.formatIso(span.range.start, { omitTime: span.allDay }), 5814 endStr: dateEnv.formatIso(span.range.end, { omitTime: span.allDay }), 5815 allDay: span.allDay 5816 }; 5817 } 5818 function buildDatePointApi(span, dateEnv) { 5819 return { 5820 date: dateEnv.toDate(span.range.start), 5821 dateStr: dateEnv.formatIso(span.range.start, { omitTime: span.allDay }), 5822 allDay: span.allDay 5823 }; 5824 } 5825 function fabricateEventRange(dateSpan, eventUiBases, calendar) { 5826 var def = parseEventDef({ editable: false }, '', // sourceId 5827 dateSpan.allDay, true, // hasEnd 5828 calendar); 5829 return { 5830 def: def, 5831 ui: compileEventUi(def, eventUiBases), 5832 instance: createEventInstance(def.defId, dateSpan.range), 5833 range: dateSpan.range, 5834 isStart: true, 5835 isEnd: true 5836 }; 5837 } 5838 5839 function compileViewDefs(defaultConfigs, overrideConfigs) { 5840 var hash = {}; 5841 var viewType; 5842 for (viewType in defaultConfigs) { 5843 ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs); 5844 } 5845 for (viewType in overrideConfigs) { 5846 ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs); 5847 } 5848 return hash; 5849 } 5850 function ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs) { 5851 if (hash[viewType]) { 5852 return hash[viewType]; 5853 } 5854 var viewDef = buildViewDef(viewType, hash, defaultConfigs, overrideConfigs); 5855 if (viewDef) { 5856 hash[viewType] = viewDef; 5857 } 5858 return viewDef; 5859 } 5860 function buildViewDef(viewType, hash, defaultConfigs, overrideConfigs) { 5861 var defaultConfig = defaultConfigs[viewType]; 5862 var overrideConfig = overrideConfigs[viewType]; 5863 var queryProp = function (name) { 5864 return (defaultConfig && defaultConfig[name] !== null) ? defaultConfig[name] : 5865 ((overrideConfig && overrideConfig[name] !== null) ? overrideConfig[name] : null); 5866 }; 5867 var theClass = queryProp('class'); 5868 var superType = queryProp('superType'); 5869 if (!superType && theClass) { 5870 superType = 5871 findViewNameBySubclass(theClass, overrideConfigs) || 5872 findViewNameBySubclass(theClass, defaultConfigs); 5873 } 5874 var superDef = null; 5875 if (superType) { 5876 if (superType === viewType) { 5877 throw new Error('Can\'t have a custom view type that references itself'); 5878 } 5879 superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs); 5880 } 5881 if (!theClass && superDef) { 5882 theClass = superDef.class; 5883 } 5884 if (!theClass) { 5885 return null; // don't throw a warning, might be settings for a single-unit view 5886 } 5887 return { 5888 type: viewType, 5889 class: theClass, 5890 defaults: __assign({}, (superDef ? superDef.defaults : {}), (defaultConfig ? defaultConfig.options : {})), 5891 overrides: __assign({}, (superDef ? superDef.overrides : {}), (overrideConfig ? overrideConfig.options : {})) 5892 }; 5893 } 5894 function findViewNameBySubclass(viewSubclass, configs) { 5895 var superProto = Object.getPrototypeOf(viewSubclass.prototype); 5896 for (var viewType in configs) { 5897 var parsed = configs[viewType]; 5898 // need DIRECT subclass, so instanceof won't do it 5899 if (parsed.class && parsed.class.prototype === superProto) { 5900 return viewType; 5901 } 5902 } 5903 return ''; 5904 } 5905 5906 function parseViewConfigs(inputs) { 5907 return mapHash(inputs, parseViewConfig); 5908 } 5909 var VIEW_DEF_PROPS = { 5910 type: String, 5911 class: null 5912 }; 5913 function parseViewConfig(input) { 5914 if (typeof input === 'function') { 5915 input = { class: input }; 5916 } 5917 var options = {}; 5918 var props = refineProps(input, VIEW_DEF_PROPS, {}, options); 5919 return { 5920 superType: props.type, 5921 class: props.class, 5922 options: options 5923 }; 5924 } 5925 5926 function buildViewSpecs(defaultInputs, optionsManager) { 5927 var defaultConfigs = parseViewConfigs(defaultInputs); 5928 var overrideConfigs = parseViewConfigs(optionsManager.overrides.views); 5929 var viewDefs = compileViewDefs(defaultConfigs, overrideConfigs); 5930 return mapHash(viewDefs, function (viewDef) { 5931 return buildViewSpec(viewDef, overrideConfigs, optionsManager); 5932 }); 5933 } 5934 function buildViewSpec(viewDef, overrideConfigs, optionsManager) { 5935 var durationInput = viewDef.overrides.duration || 5936 viewDef.defaults.duration || 5937 optionsManager.dynamicOverrides.duration || 5938 optionsManager.overrides.duration; 5939 var duration = null; 5940 var durationUnit = ''; 5941 var singleUnit = ''; 5942 var singleUnitOverrides = {}; 5943 if (durationInput) { 5944 duration = createDuration(durationInput); 5945 if (duration) { // valid? 5946 var denom = greatestDurationDenominator(duration, !getWeeksFromInput(durationInput)); 5947 durationUnit = denom.unit; 5948 if (denom.value === 1) { 5949 singleUnit = durationUnit; 5950 singleUnitOverrides = overrideConfigs[durationUnit] ? overrideConfigs[durationUnit].options : {}; 5951 } 5952 } 5953 } 5954 var queryButtonText = function (options) { 5955 var buttonTextMap = options.buttonText || {}; 5956 var buttonTextKey = viewDef.defaults.buttonTextKey; 5957 if (buttonTextKey != null && buttonTextMap[buttonTextKey] != null) { 5958 return buttonTextMap[buttonTextKey]; 5959 } 5960 if (buttonTextMap[viewDef.type] != null) { 5961 return buttonTextMap[viewDef.type]; 5962 } 5963 if (buttonTextMap[singleUnit] != null) { 5964 return buttonTextMap[singleUnit]; 5965 } 5966 }; 5967 return { 5968 type: viewDef.type, 5969 class: viewDef.class, 5970 duration: duration, 5971 durationUnit: durationUnit, 5972 singleUnit: singleUnit, 5973 options: __assign({}, globalDefaults, viewDef.defaults, optionsManager.dirDefaults, optionsManager.localeDefaults, optionsManager.overrides, singleUnitOverrides, viewDef.overrides, optionsManager.dynamicOverrides), 5974 buttonTextOverride: queryButtonText(optionsManager.dynamicOverrides) || 5975 queryButtonText(optionsManager.overrides) || // constructor-specified buttonText lookup hash takes precedence 5976 viewDef.overrides.buttonText, 5977 buttonTextDefault: queryButtonText(optionsManager.localeDefaults) || 5978 queryButtonText(optionsManager.dirDefaults) || 5979 viewDef.defaults.buttonText || 5980 queryButtonText(globalDefaults) || 5981 viewDef.type // fall back to given view name 5982 }; 5983 } 5984 5985 var Toolbar = /** @class */ (function (_super) { 5986 __extends(Toolbar, _super); 5987 function Toolbar(context, extraClassName) { 5988 var _this = _super.call(this, context) || this; 5989 _this._renderLayout = memoizeRendering(_this.renderLayout, _this.unrenderLayout); 5990 _this._updateTitle = memoizeRendering(_this.updateTitle, null, [_this._renderLayout]); 5991 _this._updateActiveButton = memoizeRendering(_this.updateActiveButton, null, [_this._renderLayout]); 5992 _this._updateToday = memoizeRendering(_this.updateToday, null, [_this._renderLayout]); 5993 _this._updatePrev = memoizeRendering(_this.updatePrev, null, [_this._renderLayout]); 5994 _this._updateNext = memoizeRendering(_this.updateNext, null, [_this._renderLayout]); 5995 _this.el = createElement('div', { className: 'fc-toolbar ' + extraClassName }); 5996 return _this; 5997 } 5998 Toolbar.prototype.destroy = function () { 5999 _super.prototype.destroy.call(this); 6000 this._renderLayout.unrender(); // should unrender everything else 6001 removeElement(this.el); 6002 }; 6003 Toolbar.prototype.render = function (props) { 6004 this._renderLayout(props.layout); 6005 this._updateTitle(props.title); 6006 this._updateActiveButton(props.activeButton); 6007 this._updateToday(props.isTodayEnabled); 6008 this._updatePrev(props.isPrevEnabled); 6009 this._updateNext(props.isNextEnabled); 6010 }; 6011 Toolbar.prototype.renderLayout = function (layout) { 6012 var el = this.el; 6013 this.viewsWithButtons = []; 6014 appendToElement(el, this.renderSection('left', layout.left)); 6015 appendToElement(el, this.renderSection('center', layout.center)); 6016 appendToElement(el, this.renderSection('right', layout.right)); 6017 }; 6018 Toolbar.prototype.unrenderLayout = function () { 6019 this.el.innerHTML = ''; 6020 }; 6021 Toolbar.prototype.renderSection = function (position, buttonStr) { 6022 var _this = this; 6023 var _a = this, theme = _a.theme, calendar = _a.calendar; 6024 var optionsManager = calendar.optionsManager; 6025 var viewSpecs = calendar.viewSpecs; 6026 var sectionEl = createElement('div', { className: 'fc-' + position }); 6027 var calendarCustomButtons = optionsManager.computed.customButtons || {}; 6028 var calendarButtonTextOverrides = optionsManager.overrides.buttonText || {}; 6029 var calendarButtonText = optionsManager.computed.buttonText || {}; 6030 if (buttonStr) { 6031 buttonStr.split(' ').forEach(function (buttonGroupStr, i) { 6032 var groupChildren = []; 6033 var isOnlyButtons = true; 6034 var groupEl; 6035 buttonGroupStr.split(',').forEach(function (buttonName, j) { 6036 var customButtonProps; 6037 var viewSpec; 6038 var buttonClick; 6039 var buttonIcon; // only one of these will be set 6040 var buttonText; // " 6041 var buttonInnerHtml;
6042 var buttonClasses; 6043 var buttonEl; 6044 var buttonAriaAttr; 6045 if (buttonName === 'title') { 6046 groupChildren.push(htmlToElement('<h2> </h2>')); // we always want it to take up height 6047 isOnlyButtons = false; 6048 } 6049 else { 6050 if ((customButtonProps = calendarCustomButtons[buttonName])) { 6051 buttonClick = function (ev) { 6052 if (customButtonProps.click) { 6053 customButtonProps.click.call(buttonEl, ev); 6054 } 6055 }; 6056 (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) || 6057 (buttonIcon = theme.getIconClass(buttonName)) || 6058 (buttonText = customButtonProps.text); 6059 } 6060 else if ((viewSpec = viewSpecs[buttonName])) { 6061 _this.viewsWithButtons.push(buttonName); 6062 buttonClick = function () { 6063 calendar.changeView(buttonName); 6064 }; 6065 (buttonText = viewSpec.buttonTextOverride) || 6066 (buttonIcon = theme.getIconClass(buttonName)) || 6067 (buttonText = viewSpec.buttonTextDefault); 6068 } 6069 else if (calendar[buttonName]) { // a calendar method 6070 buttonClick = function () { 6071 calendar[buttonName](); 6072 }; 6073 (buttonText = calendarButtonTextOverrides[buttonName]) || 6074 (buttonIcon = theme.getIconClass(buttonName)) || 6075 (buttonText = calendarButtonText[buttonName]); 6076 // ^ everything else is considered default 6077 } 6078 if (buttonClick) { 6079 buttonClasses = [ 6080 'fc-' + buttonName + '-button', 6081 theme.getClass('button') 6082 ]; 6083 if (buttonText) { 6084 buttonInnerHtml = htmlEscape(buttonText); 6085 buttonAriaAttr = ''; 6086 } 6087 else if (buttonIcon) { 6088 buttonInnerHtml = "<span class='" + buttonIcon + "'></span>"; 6089 buttonAriaAttr = ' aria-label="' + buttonName + '"'; 6090 } 6091 buttonEl = htmlToElement(// type="button" so that it doesn't submit a form 6092 '<button type="button" class="' + buttonClasses.join(' ') + '"' + 6093 buttonAriaAttr + 6094 '>' + buttonInnerHtml + '</button>'); 6095 buttonEl.addEventListener('click', buttonClick); 6096 groupChildren.push(buttonEl); 6097 } 6098 } 6099 }); 6100 if (groupChildren.length > 1) { 6101 groupEl = document.createElement('div'); 6102 var buttonGroupClassName = theme.getClass('buttonGroup'); 6103 if (isOnlyButtons && buttonGroupClassName) { 6104 groupEl.classList.add(buttonGroupClassName); 6105 } 6106 appendToElement(groupEl, groupChildren); 6107 sectionEl.appendChild(groupEl); 6108 } 6109 else { 6110 appendToElement(sectionEl, groupChildren); // 1 or 0 children 6111 } 6112 }); 6113 } 6114 return sectionEl; 6115 }; 6116 Toolbar.prototype.updateToday = function (isTodayEnabled) { 6117 this.toggleButtonEnabled('today', isTodayEnabled); 6118 }; 6119 Toolbar.prototype.updatePrev = function (isPrevEnabled) { 6120 this.toggleButtonEnabled('prev', isPrevEnabled); 6121 }; 6122 Toolbar.prototype.updateNext = function (isNextEnabled) { 6123 this.toggleButtonEnabled('next', isNextEnabled); 6124 }; 6125 Toolbar.prototype.updateTitle = function (text) { 6126 findElements(this.el, 'h2').forEach(function (titleEl) { 6127 titleEl.innerText = text; 6128 }); 6129 }; 6130 Toolbar.prototype.updateActiveButton = function (buttonName) { 6131 var className = this.theme.getClass('buttonActive'); 6132 findElements(this.el, 'button').forEach(function (buttonEl) { 6133 if (buttonName && buttonEl.classList.contains('fc-'
6133+ buttonName + '-button')) { 6134 buttonEl.classList.add(className); 6135 } 6136 else { 6137 buttonEl.classList.remove(className); 6138 } 6139 }); 6140 }; 6141 Toolbar.prototype.toggleButtonEnabled = function (buttonName, bool) { 6142 findElements(this.el, '.fc-' + buttonName + '-button').forEach(function (buttonEl) { 6143 buttonEl.disabled = !bool; 6144 }); 6145 }; 6146 return Toolbar; 6147 }(Component)); 6148 6149 var CalendarComponent = /** @class */ (function (_super) { 6150 __extends(CalendarComponent, _super); 6151 function CalendarComponent(context, el) { 6152 var _this = _super.call(this, context) || this; 6153 _this._renderToolbars = memoizeRendering(_this.renderToolbars); 6154 _this.buildViewPropTransformers = memoize(buildViewPropTransformers); 6155 _this.el = el; 6156 prependToElement(el, _this.contentEl = createElement('div', { className: 'fc-view-container' })); 6157 var calendar = _this.calendar; 6158 for (var _i = 0, _a = calendar.pluginSystem.hooks.viewContainerModifiers; _i < _a.length; _i++) { 6159 var modifyViewContainer = _a[_i]; 6160 modifyViewContainer(_this.contentEl, calendar); 6161 } 6162 _this.toggleElClassNames(true); 6163 _this.computeTitle = memoize(computeTitle); 6164 _this.parseBusinessHours = memoize(function (input) { 6165 return parseBusinessHours(input, _this.calendar); 6166 }); 6167 return _this; 6168 } 6169 CalendarComponent.prototype.destroy = function () { 6170 if (this.header) { 6171 this.header.destroy(); 6172 } 6173 if (this.footer) { 6174 this.footer.destroy(); 6175 } 6176 if (this.view) { 6177 this.view.destroy(); 6178 } 6179 removeElement(this.contentEl); 6180 this.toggleElClassNames(false); 6181 _super.prototype.destroy.call(this); 6182 }; 6183 CalendarComponent.prototype.toggleElClassNames = function (bool) { 6184 var classList = this.el.classList; 6185 var dirClassName = 'fc-' + this.opt('dir'); 6186 var themeClassName = this.theme.getClass('widget'); 6187 if (bool) { 6188 classList.add('fc'); 6189 classList.add(dirClassName); 6190 classList.add(themeClassName); 6191 } 6192 else { 6193 classList.remove('fc'); 6194 classList.remove(dirClassName); 6195 classList.remove(themeClassName); 6196 } 6197 }; 6198 CalendarComponent.prototype.render = function (props) { 6199 this.freezeHeight(); 6200 var title = this.computeTitle(props.dateProfile, props.viewSpec.options); 6201 this._renderToolbars(props.viewSpec, props.dateProfile, props.currentDate, props.dateProfileGenerator, title); 6202 this.renderView(props, title); 6203 this.updateSize(); 6204 this.thawHeight(); 6205 }; 6206 CalendarComponent.prototype.renderToolbars = function (viewSpec, dateProfile, currentDate, dateProfileGenerator, title) { 6207 var headerLayout = this.opt('header'); 6208 var footerLayout = this.opt('footer'); 6209 var now = this.calendar.getNow(); 6210 var todayInfo = dateProfileGenerator.build(now); 6211 var prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate); 6212 var nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate); 6213 var toolbarProps = { 6214 title: title, 6215 activeButton: viewSpec.type, 6216 isTodayEnabled: todayInfo.isValid && !rangeContainsMarker(dateProfile.currentRange, now), 6217 isPrevEnabled: prevInfo.isValid, 6218 isNextEnabled: nextInfo.isValid 6219 }; 6220 if (headerLayout) { 6221 if (!this.header) { 6222 this.header = new Toolbar(this.context, 'fc-header-toolbar'); 6223 prependToElement(this.el, this.header.el); 6224 } 6225 this.header.receiveProps(__assign({ layout: headerLayout }, toolbarProps)); 6226 } 6227 else if (this.header) { 6228 this.header.destroy(); 6229 this.header = null; 6230 }
6231 if (footerLayout) { 6232 if (!this.footer) { 6233 this.footer = new Toolbar(this.context, 'fc-footer-toolbar'); 6234 appendToElement(this.el, this.footer.el); 6235 } 6236 this.footer.receiveProps(__assign({ layout: footerLayout }, toolbarProps)); 6237 } 6238 else if (this.footer) { 6239 this.footer.destroy(); 6240 this.footer = null; 6241 } 6242 }; 6243 CalendarComponent.prototype.renderView = function (props, title) { 6244 var view = this.view; 6245 var viewSpec = props.viewSpec, dateProfileGenerator = props.dateProfileGenerator; 6246 if (!view || view.viewSpec !== viewSpec) { 6247 if (view) { 6248 view.destroy(); 6249 } 6250 view = this.view = new viewSpec['class']({ 6251 calendar: this.calendar, 6252 view: null, 6253 dateEnv: this.dateEnv, 6254 theme: this.theme, 6255 options: viewSpec.options 6256 }, viewSpec, dateProfileGenerator, this.contentEl); 6257 } 6258 else { 6259 view.addScroll(view.queryScroll()); 6260 } 6261 view.title = title; // for the API 6262 var viewProps = { 6263 dateProfile: props.dateProfile, 6264 businessHours: this.parseBusinessHours(viewSpec.options.businessHours), 6265 eventStore: props.eventStore, 6266 eventUiBases: props.eventUiBases, 6267 dateSelection: props.dateSelection, 6268 eventSelection: props.eventSelection, 6269 eventDrag: props.eventDrag, 6270 eventResize: props.eventResize 6271 }; 6272 var transformers = this.buildViewPropTransformers(this.calendar.pluginSystem.hooks.viewPropsTransformers); 6273 for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) { 6274 var transformer = transformers_1[_i]; 6275 __assign(viewProps, transformer.transform(viewProps, viewSpec, props, view)); 6276 } 6277 view.receiveProps(viewProps); 6278 }; 6279 // Sizing 6280 // ----------------------------------------------------------------------------------------------------------------- 6281 CalendarComponent.prototype.updateSize = function (isResize) { 6282 if (isResize === void 0) { isResize = false; } 6283 var view = this.view; 6284 if (isResize) { 6285 view.addScroll(view.queryScroll()); 6286 } 6287 if (isResize || this.isHeightAuto == null) { 6288 this.computeHeightVars(); 6289 } 6290 view.updateSize(isResize, this.viewHeight, this.isHeightAuto); 6291 view.updateNowIndicator(); // we need to guarantee this will run after updateSize 6292 view.popScroll(isResize); 6293 }; 6294 CalendarComponent.prototype.computeHeightVars = function () { 6295 var calendar = this.calendar; // yuck. need to handle dynamic options 6296 var heightInput = calendar.opt('height'); 6297 var contentHeightInput = calendar.opt('contentHeight'); 6298 this.isHeightAuto = heightInput === 'auto' || contentHeightInput === 'auto'; 6299 if (typeof contentHeightInput === 'number') { // exists and not 'auto' 6300 this.viewHeight = contentHeightInput; 6301 } 6302 else if (typeof contentHeightInput === 'function') { // exists and is a function 6303 this.viewHeight = contentHeightInput(); 6304 } 6305 else if (typeof heightInput === 'number') { // exists and not 'auto' 6306 this.viewHeight = heightInput - this.queryToolbarsHeight(); 6307 } 6308 else if (typeof heightInput === 'function') { // exists and is a function 6309 this.viewHeight = heightInput() - this.queryToolbarsHeight(); 6310 } 6311 else if (heightInput === 'parent') { // set to height of parent element 6312 var parentEl = this.el.parentNode; 6313 this.viewHeight = parentEl.getBoundingClientRect().height - this.queryToolbarsHeight(); 6314 } 6315 else { 6316 this.viewHeight = Math.round(this.contentEl.getBoundingClientRect().width / 6317 Math.max(calendar.opt('aspectRatio'), .5)); 6318 } 6319 }; 6320 CalendarComponent.prototype.queryToolbarsHeight = function () { 6321 var height = 0; 6322 if (this.header) { 6323 height += computeHeightAndMargins(this.header.el); 6324 } 6325 if (this.footer) { 6326 height += computeHeightAndMargins(this.footer.el); 6327 } 6328 return height; 6329 }; 6330 // Height "Freezing" 6331 // ----------------------------------------------------------------------------------------------------------------- 6332 CalendarComponent.prototype.freezeHeight = function () { 6333 applyStyle(this.el, { 6334 height: this.el.getBoundingClientRect().height, 6335 overflow: 'hidden' 6336 }); 6337 }; 6338 CalendarComponent.prototype.thawHeight = function () { 6339 applyStyle(this.el, { 6340 height: '', 6341 overflow: '' 6342 }); 6343 }; 6344 return CalendarComponent; 6345 }(Component)); 6346 // Title and Date Formatting 6347 // ----------------------------------------------------------------------------------------------------------------- 6348 // Computes what the title at the top of the calendar should be for this view 6349 function computeTitle(dateProfile, viewOptions) { 6350 var range; 6351 // for views that span a large unit of time, show the proper interval, ignoring stray days before and after 6352 if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) { 6353 range = dateProfile.currentRange; 6354 } 6355 else { // for day units or smaller, use the actual day range 6356 range = dateProfile.activeRange; 6357 } 6358 return this.dateEnv.formatRange(range.start, range.end, createFormatter(viewOptions.titleFormat || computeTitleFormat(dateProfile), viewOptions.titleRangeSeparator), { isEndExclusive: dateProfile.isRangeAllDay }); 6359 }
6360 // Generates the format string that should be used to generate the title for the current date range. 6361 // Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`. 6362 function computeTitleFormat(dateProfile) { 6363 var currentRangeUnit = dateProfile.currentRangeUnit; 6364 if (currentRangeUnit === 'year') { 6365 return { year: 'numeric' }; 6366 } 6367 else if (currentRangeUnit === 'month') { 6368 return { year: 'numeric', month: 'long' }; // like "September 2014" 6369 } 6370 else { 6371 var days = diffWholeDays(dateProfile.currentRange.start, dateProfile.currentRange.end); 6372 if (days !== null && days > 1) { 6373 // multi-day range. shorter, like "Sep 9 - 10 2014" 6374 return { year: 'numeric', month: 'short', day: 'numeric' }; 6375 } 6376 else { 6377 // one day. longer, like "September 9 2014" 6378 return { year: 'numeric', month: 'long', day: 'numeric' }; 6379 } 6380 } 6381 } 6382 // Plugin 6383 // ----------------------------------------------------------------------------------------------------------------- 6384 function buildViewPropTransformers(theClasses) { 6385 return theClasses.map(function (theClass) { 6386 return new theClass(); 6387 }); 6388 } 6389 6390 var Interaction = /** @class */ (function () { 6391 function Interaction(settings) { 6392 this.component = settings.component; 6393 } 6394 Interaction.prototype.destroy = function () { 6395 }; 6396 return Interaction; 6397 }()); 6398 function parseInteractionSettings(component, input) { 6399 return { 6400 component: component, 6401 el: input.el, 6402 useEventCenter: input.useEventCenter != null ? input.useEventCenter : true 6403 }; 6404 } 6405 function interactionSettingsToStore(settings) { 6406 var _a; 6407 return _a = {}, 6408 _a[settings.component.uid] = settings, 6409 _a; 6410 } 6411 // global state 6412 var interactionSettingsStore = {}; 6413 6414 /* 6415 Detects when the user clicks on an event within a DateComponent 6416 */ 6417 var EventClicking = /** @class */ (function (_super) { 6418 __extends(EventClicking, _super); 6419 function EventClicking(settings) { 6420 var _this = _super.call(this, settings) || this; 6421 _this.handleSegClick = function (ev, segEl) { 6422 var component = _this.component; 6423 var seg = getElSeg(segEl); 6424 if (seg && // might be the <div> surrounding the more link 6425 component.isValidSegDownEl(ev.target)) { 6426 // our way to simulate a link click for elements that can't be <a> tags 6427 // grab before trigger fired in case trigger trashes DOM thru rerendering 6428 var hasUrlContainer = elementClosest(ev.target, '.fc-has-url'); 6429 var url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : ''; 6430 component.publiclyTrigger('eventClick', [ 6431 { 6432 el: segEl, 6433 event: new EventApi(component.calendar, seg.eventRange.def, seg.eventRange.instance), 6434 jsEvent: ev, 6435 view: component.view 6436 } 6437 ]); 6438 if (url && !ev.defaultPrevented) { 6439 window.location.href = url; 6440 } 6441 } 6442 }; 6443 var component = settings.component; 6444 _this.destroy = listenBySelector(component.el, 'click', component.fgSegSelector + ',' + component.bgSegSelector, _this.handleSegClick); 6445 return _this; 6446 } 6447 return EventClicking; 6448 }(Interaction)); 6449 6450 /* 6451 Triggers events and adds/removes core classNames when the user's pointer 6452 enters/leaves event-elements of a component. 6453 */ 6454 var EventHovering = /** @class */ (function (_super) { 6455 __extends(EventHovering, _super); 6456 function EventHovering(settings) { 6457 var _this = _super.call(this, settings) || this; 6458 // for simulating an eventMouseLeave when the event el is destroyed while mouse is over it 6459 _this.handleEventElRemove = function (el) { 6460 if (el === _this.currentSegEl) { 6461 _this.handleSegLeave(null, _this.currentSegEl); 6462 } 6463 }; 6464 _this.handleSegEnter = function (ev, segEl) { 6465 if (getElSeg(segEl)) { // TODO: better way to make sure not hovering over more+ link or its wrapper 6466 segEl.classList.add('fc-allow-mouse-resize'); 6467 _this.currentSegEl = segEl; 6468 _this.triggerEvent('eventMouseEnter', ev, segEl); 6469 } 6470 }; 6471 _this.handleSegLeave = function (ev, segEl) { 6472 if (_this.currentSegEl) { 6473 segEl.classList.remove('fc-allow-mouse-resize'); 6474 _this.currentSegEl = null; 6475 _this.triggerEvent('eventMouseLeave', ev, segEl); 6476 } 6477 }; 6478 var component = settings.component; 6479 _this.removeHoverListeners = listenToHoverBySelector(component.el, component.fgSegSelector + ',' + component.bgSegSelector, _this.handleSegEnter, _this.handleSegLeave); 6480 component.calendar.on('eventElRemove', _this.handleEventElRemove); 6481 return _this; 6482 } 6483 EventHovering.prototype.destroy = function () { 6484 this.removeHoverListeners(); 6485 this.component.calendar.off('eventElRemove', this.handleEventElRemove); 6486 }; 6487 EventHovering.prototype.triggerEvent = function (publicEvName, ev, segEl) { 6488 var component = this.component; 6489 var seg = getElSeg(segEl); 6490 if (!ev || component.isValidSegDownEl(ev.target)) { 6491 component.publiclyTrigger(publicEvName, [ 6492 { 6493 el: segEl, 6494 event: new EventApi(this.component.calendar, seg.eventRange.def, seg.eventRange.instance), 6495 jsEvent: ev, 6496 view: component.view 6497 } 6498 ]); 6499 } 6500 }; 6501 return EventHovering; 6502 }(Interaction)); 6503 6504 var StandardTheme = /** @class */ (function (_super) { 6505 __extends(StandardTheme, _super); 6506 function StandardTheme() { 6507 return _super !== null && _super.apply(this, arguments) || this; 6508 } 6509 return StandardTheme; 6510 }(Theme)); 6511 StandardTheme.prototype.classes = { 6512 widget: 'fc-unthemed', 6513 widgetHeader: 'fc-widget-header', 6514 widgetContent: 'fc-widget-content', 6515 buttonGroup: 'fc-button-group', 6516 button: 'fc-button fc-button-primary', 6517 buttonActive: 'fc-button-active', 6518 popoverHeader: 'fc-widget-header', 6519 popoverContent: 'fc-widget-content', 6520 // day grid 6521 headerRow: 'fc-widget-header', 6522 dayRow: 'fc-widget-content', 6523 // list view 6524 listView: 'fc-widget-content' 6525 }; 6526 StandardTheme.prototype.baseIconClass = 'fc-icon'; 6527 StandardTheme.prototype.iconClasses = { 6528 close: 'fc-icon-x', 6529 prev: 'fc-icon-chevron-left', 6530 next: 'fc-icon-chevron-right', 6531 prevYear: 'fc-icon-chevrons-left', 6532 nextYear: 'fc-icon-chevrons-right' 6533 }; 6534 StandardTheme.prototype.iconOverrideOption = 'buttonIcons'; 6535 StandardTheme.prototype.iconOverrideCustomButtonOption = 'icon'; 6536 StandardTheme.prototype.iconOverridePrefix = 'fc-icon-'; 6537 6538 var Calendar = /** @class */ (function () { 6539 function Calendar(el, overrides) { 6540 var _this = this; 6541 this.parseRawLocales = memoize(parseRawLocales); 6542 this.buildLocale = memoize(buildLocale); 6543 this.buildDateEnv = memoize(buildDateEnv); 6544 this.buildTheme = memoize(buildTheme); 6545 this.buildEventUiSingleBase = memoize(this._buildEventUiSingleBase); 6546 this.buildSelectionConfig = memoize(this._buildSelectionConfig); 6547 this.buildEventUiBySource = memoizeOutput(buildEventUiBySource, isPropsEqual); 6548 this.buildEventUiBases = memoize(buildEventUiBases); 6549 this.interactionsStore = {}; 6550 this.actionQueue = []; 6551 this.isReducing = false;
6552 // isDisplaying: boolean = false // installed in DOM? accepting renders? 6553 this.needsRerender = false; // needs a render? 6554 this.needsFullRerender = false; 6555 this.isRendering = false; // currently in the executeRender function? 6556 this.renderingPauseDepth = 0; 6557 this.buildDelayedRerender = memoize(buildDelayedRerender); 6558 this.afterSizingTriggers = {}; 6559 this.isViewUpdated = false; 6560 this.isDatesUpdated = false; 6561 this.isEventsUpdated = false; 6562 this.el = el; 6563 this.optionsManager = new OptionsManager(overrides || {}); 6564 this.pluginSystem = new PluginSystem(); 6565 // only do once. don't do in handleOptions. because can't remove plugins 6566 this.addPluginInputs(this.optionsManager.computed.plugins || []); 6567 this.handleOptions(this.optionsManager.computed); 6568 this.publiclyTrigger('_init'); // for tests 6569 this.hydrate(); 6570 this.calendarInteractions = this.pluginSystem.hooks.calendarInteractions 6571 .map(function (calendarInteractionClass) { 6572 return new calendarInteractionClass(_this); 6573 }); 6574 } 6575 Calendar.prototype.addPluginInputs = function (pluginInputs) { 6576 var pluginDefs = refinePluginDefs(pluginInputs); 6577 for (var _i = 0, pluginDefs_1 = pluginDefs; _i < pluginDefs_1.length; _i++) { 6578 var pluginDef = pluginDefs_1[_i]; 6579 this.pluginSystem.add(pluginDef); 6580 } 6581 }; 6582 Object.defineProperty(Calendar.prototype, "view", { 6583 // public API 6584 get: function () { 6585 return this.component ? this.component.view : null; 6586 }, 6587 enumerable: true, 6588 configurable: true 6589 }); 6590 // Public API for rendering 6591 // ----------------------------------------------------------------------------------------------------------------- 6592 Calendar.prototype.render = function () { 6593 if (!this.component) { 6594 this.renderableEventStore = createEmptyEventStore(); 6595 this.bindHandlers(); 6596 this.executeRender(); 6597 } 6598 else { 6599 this.requestRerender(true); 6600 } 6601 }; 6602 Calendar.prototype.destroy = function () { 6603 if (this.component) { 6604 this.unbindHandlers(); 6605 this.component.destroy(); // don't null-out. in case API needs access 6606 this.component = null; // umm ??? 6607 for (var _i = 0, _a = this.calendarInteractions; _i < _a.length; _i++) { 6608 var interaction = _a[_i]; 6609 interaction.destroy(); 6610 } 6611 this.publiclyTrigger('_destroyed'); 6612 } 6613 }; 6614 // Handlers 6615 // ----------------------------------------------------------------------------------------------------------------- 6616 Calendar.prototype.bindHandlers = function () { 6617 var _this = this; 6618 // event delegation for nav links 6619 this.removeNavLinkListener = listenBySelector(this.el, 'click', 'a[data-goto]', function (ev, anchorEl) { 6620 var gotoOptions = anchorEl.getAttribute('data-goto'); 6621 gotoOptions = gotoOptions ? JSON.parse(gotoOptions) : {}; 6622 var dateEnv = _this.dateEnv; 6623 var dateMarker = dateEnv.createMarker(gotoOptions.date); 6624 var viewType = gotoOptions.type; 6625 // property like "navLinkDayClick". might be a string or a function 6626 var customAction = _this.viewOpt('navLink' + capitaliseFirstLetter(viewType) + 'Click'); 6627 if (typeof customAction === 'function') { 6628 customAction(dateEnv.toDate(dateMarker), ev); 6629 } 6630 else { 6631 if (typeof customAction === 'string') { 6632 viewType = customAction; 6633 }
6634 _this.zoomTo(dateMarker, viewType); 6635 } 6636 }); 6637 if (this.opt('handleWindowResize')) { 6638 window.addEventListener('resize', this.windowResizeProxy = debounce(// prevents rapid calls 6639 this.windowResize.bind(this), this.opt('windowResizeDelay'))); 6640 } 6641 }; 6642 Calendar.prototype.unbindHandlers = function () { 6643 this.removeNavLinkListener(); 6644 if (this.windowResizeProxy) { 6645 window.removeEventListener('resize', this.windowResizeProxy); 6646 this.windowResizeProxy = null; 6647 } 6648 }; 6649 // Dispatcher 6650 // ----------------------------------------------------------------------------------------------------------------- 6651 Calendar.prototype.hydrate = function () { 6652 var _this = this; 6653 this.state = this.buildInitialState(); 6654 var rawSources = this.opt('eventSources') || []; 6655 var singleRawSource = this.opt('events'); 6656 var sources = []; // parsed 6657 if (singleRawSource) { 6658 rawSources.unshift(singleRawSource); 6659 } 6660 for (var _i = 0, rawSources_1 = rawSources; _i < rawSources_1.length; _i++) { 6661 var rawSource = rawSources_1[_i]; 6662 var source = parseEventSource(rawSource, this); 6663 if (source) { 6664 sources.push(source); 6665 } 6666 } 6667 this.batchRendering(function () { 6668 _this.dispatch({ type: 'INIT' }); // pass in sources here? 6669 _this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: sources }); 6670 _this.dispatch({ 6671 type: 'SET_VIEW_TYPE', 6672 viewType: _this.opt('defaultView') || _this.pluginSystem.hooks.defaultView 6673 }); 6674 }); 6675 }; 6676 Calendar.prototype.buildInitialState = function () { 6677 return { 6678 viewType: null, 6679 loadingLevel: 0, 6680 eventSourceLoadingLevel: 0, 6681 currentDate: this.getInitialDate(), 6682 dateProfile: null, 6683 eventSources: {}, 6684 eventStore: createEmptyEventStore(), 6685 dateSelection: null, 6686 eventSelection: '', 6687 eventDrag: null, 6688 eventResize: null 6689 }; 6690 }; 6691 Calendar.prototype.dispatch = function (action) { 6692 this.actionQueue.push(action); 6693 if (!this.isReducing) { 6694 this.isReducing = true; 6695 var oldState = this.state; 6696 while (this.actionQueue.length) { 6697 this.state = this.reduce(this.state, this.actionQueue.shift(), this); 6698 } 6699 var newState = this.state; 6700 this.isReducing = false; 6701 if (!oldState.loadingLevel && newState.loadingLevel) { 6702 this.publiclyTrigger('loading', [true]); 6703 } 6704 else if (oldState.loadingLevel && !newState.loadingLevel) { 6705 this.publiclyTrigger('loading', [false]); 6706 } 6707 var view = this.component && this.component.view; 6708 if (oldState.eventStore !== newState.eventStore || this.needsFullRerender) { 6709 if (oldState.eventStore) { 6710 this.isEventsUpdated = true; 6711 } 6712 } 6713 if (oldState.dateProfile !== newState.dateProfile || this.needsFullRerender) { 6714 if (oldState.dateProfile && view) { // why would view be null!? 6715 this.publiclyTrigger('datesDestroy', [ 6716 { 6717 view: view, 6718 el: view.el 6719 } 6720 ]); 6721 } 6722 this.isDatesUpdated = true; 6723 } 6724 if (oldState.viewType !== newState.viewType || this.needsFullRerender) { 6725 if (oldState.viewType && view) { // why would view be null!? 6726 this.publiclyTrigger('viewSkeletonDestroy', [ 6727 { 6728 view: view, 6729 el: view.el 6730 } 6731 ]); 6732 } 6733 this.isViewUpdated = true; 6734 } 6735 this.requestRerender(); 6736 } 6737 }; 6738 Calendar.prototype.reduce = function (state, action, calendar) { 6739 return reduce(state, action, calendar); 6740 }; 6741 // Render Queue 6742 // ----------------------------------------------------------------------------------------------------------------- 6743 Calendar.prototype.requestRerender = function (needsFull) { 6744 if (needsFull === void 0) { needsFull = false; } 6745 this.needsRerender = true; 6746 this.needsFullRerender = this.needsFullRerender || needsFull; 6747 this.delayedRerender(); // will call a debounced-version of tryRerender 6748 }; 6749 Calendar.prototype.tryRerender = function () { 6750 if (this.component && // must be accepting renders 6751 this.needsRerender && // indicates that a rerender was requested 6752 !this.renderingPauseDepth && // not paused 6753 !this.isRendering // not currently in the render loop 6754 ) {
6755 this.executeRender(); 6756 } 6757 }; 6758 Calendar.prototype.batchRendering = function (func) { 6759 this.renderingPauseDepth++; 6760 func(); 6761 this.renderingPauseDepth--; 6762 if (this.needsRerender) { 6763 this.requestRerender(); 6764 } 6765 }; 6766 // Rendering 6767 // ----------------------------------------------------------------------------------------------------------------- 6768 Calendar.prototype.executeRender = function () { 6769 var needsFullRerender = this.needsFullRerender; // save before clearing 6770 // clear these BEFORE the render so that new values will accumulate during render 6771 this.needsRerender = false; 6772 this.needsFullRerender = false; 6773 this.isRendering = true; 6774 this.renderComponent(needsFullRerender); 6775 this.isRendering = false; 6776 // received a rerender request while rendering 6777 if (this.needsRerender) { 6778 this.delayedRerender(); 6779 } 6780 }; 6781 /* 6782 don't call this directly. use executeRender instead 6783 */ 6784 Calendar.prototype.renderComponent = function (needsFull) { 6785 var _a = this, state = _a.state, component = _a.component; 6786 var viewType = state.viewType; 6787 var viewSpec = this.viewSpecs[viewType]; 6788 var savedScroll = (needsFull && component) ? component.view.queryScroll() : null; 6789 if (!viewSpec) { 6790 throw new Error("View type \"" + viewType + "\" is not valid"); 6791 } 6792 // if event sources are still loading and progressive rendering hasn't been enabled, 6793 // keep rendering the last fully loaded set of events 6794 var renderableEventStore = this.renderableEventStore = 6795 (state.eventSourceLoadingLevel && !this.opt('progressiveEventRendering')) ? 6796 this.renderableEventStore : 6797 state.eventStore; 6798 var eventUiSingleBase = this.buildEventUiSingleBase(viewSpec.options); 6799 var eventUiBySource = this.buildEventUiBySource(state.eventSources); 6800 var eventUiBases = this.eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource); 6801 if (needsFull || !component) { 6802 if (component) { 6803 component.freezeHeight(); // next component will unfreeze it 6804 component.destroy(); 6805 } 6806 component = this.component = new CalendarComponent({ 6807 calendar: this, 6808 view: null, 6809 dateEnv: this.dateEnv, 6810 theme: this.theme, 6811 options: this.optionsManager.computed 6812 }, this.el); 6813 this.isViewUpdated = true; 6814 this.isDatesUpdated = true; 6815 this.isEventsUpdated = true; 6816 } 6817 component.receiveProps(__assign({}, state, { viewSpec: viewSpec, dateProfile: state.dateProfile, dateProfileGenerator: this.dateProfileGenerators[viewType], eventStore: renderableEventStore, eventUiBases: eventUiBases, dateSelection: state.dateSelection, eventSelection: state.eventSelection, eventDrag: state.eventDrag, eventResize: state.eventResize })); 6818 if (savedScroll) { 6819 component.view.applyScroll(savedScroll, false); 6820 } 6821 if (this.isViewUpdated) { 6822 this.isViewUpdated = false; 6823 this.publiclyTrigger('viewSkeletonRender', [ 6824 { 6825 view: component.view, 6826 el: component.view.el 6827 } 6828 ]); 6829 } 6830 if (this.isDatesUpdated) { 6831 this.isDatesUpdated = false; 6832 this.publiclyTrigger('datesRender', [ 6833 { 6834 view: component.view, 6835 el: component.view.el 6836 } 6837 ]); 6838 } 6839 if (this.isEventsUpdated) { 6840 this.isEventsUpdated = false;
6841 } 6842 this.releaseAfterSizingTriggers(); 6843 }; 6844 // Options 6845 // ----------------------------------------------------------------------------------------------------------------- 6846 Calendar.prototype.setOption = function (name, val) { 6847 var _a; 6848 this.mutateOptions((_a = {}, _a[name] = val, _a), [], true); 6849 }; 6850 Calendar.prototype.getOption = function (name) { 6851 return this.optionsManager.computed[name]; 6852 }; 6853 Calendar.prototype.opt = function (name) { 6854 return this.optionsManager.computed[name]; 6855 }; 6856 Calendar.prototype.viewOpt = function (name) { 6857 return this.viewOpts()[name]; 6858 }; 6859 Calendar.prototype.viewOpts = function () { 6860 return this.viewSpecs[this.state.viewType].options; 6861 }; 6862 /* 6863 handles option changes (like a diff) 6864 */ 6865 Calendar.prototype.mutateOptions = function (updates, removals, isDynamic, deepEqual) { 6866 var _this = this; 6867 var changeHandlers = this.pluginSystem.hooks.optionChangeHandlers; 6868 var normalUpdates = {}; 6869 var specialUpdates = {}; 6870 var oldDateEnv = this.dateEnv; // do this before handleOptions 6871 var isTimeZoneDirty = false; 6872 var isSizeDirty = false; 6873 var anyDifficultOptions = Boolean(removals.length); 6874 for (var name_1 in updates) { 6875 if (changeHandlers[name_1]) { 6876 specialUpdates[name_1] = updates[name_1]; 6877 } 6878 else { 6879 normalUpdates[name_1] = updates[name_1]; 6880 } 6881 } 6882 for (var name_2 in normalUpdates) { 6883 if (/^(height|contentHeight|aspectRatio)$/.test(name_2)) { 6884 isSizeDirty = true; 6885 } 6886 else if (/^(defaultDate|defaultView)$/.test(name_2)) ; 6887 else { 6888 anyDifficultOptions = true; 6889 if (name_2 === 'timeZone') { 6890 isTimeZoneDirty = true; 6891 } 6892 } 6893 } 6894 this.optionsManager.mutate(normalUpdates, removals, isDynamic); 6895 if (anyDifficultOptions) { 6896 this.handleOptions(this.optionsManager.computed); 6897 this.needsFullRerender = true; 6898 } 6899 this.batchRendering(function () { 6900 if (anyDifficultOptions) { 6901 if (isTimeZoneDirty) { 6902 _this.dispatch({ 6903 type: 'CHANGE_TIMEZONE', 6904 oldDateEnv: oldDateEnv 6905 }); 6906 } 6907 /* HACK 6908 has the same effect as calling this.requestRerender(true) 6909 but recomputes the state's dateProfile 6910 */ 6911 _this.dispatch({ 6912 type: 'SET_VIEW_TYPE', 6913 viewType: _this.state.viewType 6914 }); 6915 } 6916 else if (isSizeDirty) { 6917 _this.updateSize(); 6918 } 6919 // special updates 6920 if (deepEqual) { 6921 for (var name_3 in specialUpdates) { 6922 changeHandlers[name_3](specialUpdates[name_3], _this, deepEqual); 6923 } 6924 } 6925 }); 6926 }; 6927 /* 6928 rebuilds things based off of a complete set of refined options 6929 */ 6930 Calendar.prototype.handleOptions = function (options) { 6931 var _this = this; 6932 var pluginHooks = this.pluginSystem.hooks; 6933 this.defaultAllDayEventDuration = createDuration(options.defaultAllDayEventDuration); 6934 this.defaultTimedEventDuration = createDuration(options.defaultTimedEventDuration); 6935 this.delayedRerender = this.buildDelayedRerender(options.rerenderDelay); 6936 this.theme = this.buildTheme(options); 6937 var available = this.parseRawLocales(options.locales); 6938 this.availableRawLocales = available.map; 6939 var locale = this.buildLocale(options.locale || available.defaultCode, available.map); 6940 this.dateEnv = this.buildDateEnv(locale, options.timeZone, pluginHooks.namedTimeZonedImpl, options.firstDay, options.weekNumberCalculation, options.weekLabel, pluginHooks.cmdFormatter); 6941 this.selectionConfig = this.buildSelectionConfig(options); // needs dateEnv. do after :( 6942 // ineffecient to do every time? 6943 this.viewSpecs = buildViewSpecs(pluginHooks.views, this.optionsManager); 6944 // ineffecient to do every time? 6945 this.dateProfileGenerators = mapHash(this.viewSpecs, function (viewSpec) { 6946 return new viewSpec.class.prototype.dateProfileGeneratorClass(viewSpec, _this); 6947 }); 6948 }; 6949 Calendar.prototype.getAvailableLocaleCodes = function () { 6950 return Object.keys(this.availableRawLocales); 6951 }; 6952 Calendar.prototype._buildSelectionConfig = function (rawOpts) { 6953 return processScopedUiProps('select', rawOpts, this); 6954 }; 6955 Calendar.prototype._buildEventUiSingleBase = function (rawOpts) { 6956 if (rawOpts.editable) { // so 'editable' affected events 6957 rawOpts = __assign({}, rawOpts, { eventEditable: true }); 6958 } 6959 return processScopedUiProps('event', rawOpts, this); 6960 }; 6961 // Trigger 6962 // ----------------------------------------------------------------------------------------------------------------- 6963 Calendar.prototype.hasPublicHandlers = function (name) { 6964 return this.hasHandlers(name) || 6965 this.opt(name); // handler specified in options 6966 }; 6967 Calendar.prototype.publiclyTrigger = function (name, args) { 6968 var optHandler = this.opt(name); 6969 this.triggerWith(name, this, args); 6970 if (optHandler) { 6971 return optHandler.apply(this, args); 6972 } 6973 }; 6974 Calendar.prototype.publiclyTriggerAfterSizing = function (name, args) { 6975 var afterSizingTriggers = this.afterSizingTriggers; 6976 (afterSizingTriggers[name] || (afterSizingTriggers[name] = [])).push(args); 6977 }; 6978 Calendar.prototype.releaseAfterSizingTriggers = function () { 6979 var afterSizingTriggers = this.afterSizingTriggers; 6980 for (var name_4 in afterSizingTriggers) { 6981 for (var _i = 0, _a = afterSizingTriggers[name_4]; _i < _a.length; _i++) { 6982 var args = _a[_i]; 6983 this.publiclyTrigger(name_4, args); 6984 } 6985 } 6986 this.afterSizingTriggers = {}; 6987 }; 6988 // View 6989 // ----------------------------------------------------------------------------------------------------------------- 6990 // Returns a boolean about whether the view is okay to instantiate at some point 6991 Calendar.prototype.isValidViewType = function (viewType) { 6992 return Boolean(this.viewSpecs[viewType]); 6993 }; 6994 Calendar.prototype.changeView = function (viewType, dateOrRange) { 6995 var dateMarker = null; 6996 if (dateOrRange) { 6997 if (dateOrRange.start && dateOrRange.end) { // a range 6998 this.optionsManager.mutate({ visibleRange: dateOrRange }, []); // will not rerender 6999 this.handleOptions(this.optionsManager.computed); // ...but yuck 7000 } 7001 else { // a date 7002 dateMarker = this.dateEnv.createMarker(dateOrRange); // just like gotoDate 7003 } 7004 } 7005 this.unselect(); 7006 this.dispatch({ 7007 type: 'SET_VIEW_TYPE', 7008 viewType: viewType, 7009 dateMarker: dateMarker 7010 }); 7011 };
7012 // Forces navigation to a view for the given date. 7013 // `viewType` can be a specific view name or a generic one like "week" or "day". 7014 // needs to change 7015 Calendar.prototype.zoomTo = function (dateMarker, viewType) { 7016 var spec; 7017 viewType = viewType || 'day'; // day is default zoom 7018 spec = this.viewSpecs[viewType] || 7019 this.getUnitViewSpec(viewType); 7020 this.unselect(); 7021 if (spec) { 7022 this.dispatch({ 7023 type: 'SET_VIEW_TYPE', 7024 viewType: spec.type, 7025 dateMarker: dateMarker 7026 }); 7027 } 7028 else { 7029 this.dispatch({ 7030 type: 'SET_DATE', 7031 dateMarker: dateMarker 7032 }); 7033 } 7034 }; 7035 // Given a duration singular unit, like "week" or "day", finds a matching view spec. 7036 // Preference is given to views that have corresponding buttons. 7037 Calendar.prototype.getUnitViewSpec = function (unit) { 7038 var component = this.component; 7039 var viewTypes = []; 7040 var i; 7041 var spec; 7042 // put views that have buttons first. there will be duplicates, but oh 7043 if (component.header) { 7044 viewTypes.push.apply(viewTypes, component.header.viewsWithButtons); 7045 } 7046 if (component.footer) { 7047 viewTypes.push.apply(viewTypes, component.footer.viewsWithButtons); 7048 } 7049 for (var viewType in this.viewSpecs) { 7050 viewTypes.push(viewType); 7051 } 7052 for (i = 0; i < viewTypes.length; i++) { 7053 spec = this.viewSpecs[viewTypes[i]]; 7054 if (spec) { 7055 if (spec.singleUnit === unit) { 7056 return spec; 7057 } 7058 } 7059 } 7060 }; 7061 // Current Date 7062 // ----------------------------------------------------------------------------------------------------------------- 7063 Calendar.prototype.getInitialDate = function () { 7064 var defaultDateInput = this.opt('defaultDate'); 7065 // compute the initial ambig-timezone date 7066 if (defaultDateInput != null) { 7067 return this.dateEnv.createMarker(defaultDateInput); 7068 } 7069 else { 7070 return this.getNow(); // getNow already returns unzoned 7071 } 7072 }; 7073 Calendar.prototype.prev = function () { 7074 this.unselect(); 7075 this.dispatch({ type: 'PREV' }); 7076 }; 7077 Calendar.prototype.next = function () { 7078 this.unselect(); 7079 this.dispatch({ type: 'NEXT' }); 7080 }; 7081 Calendar.prototype.prevYear = function () { 7082 this.unselect(); 7083 this.dispatch({ 7084 type: 'SET_DATE', 7085 dateMarker: this.dateEnv.addYears(this.state.currentDate, -1) 7086 }); 7087 }; 7088 Calendar.prototype.nextYear = function () { 7089 this.unselect(); 7090 this.dispatch({ 7091 type: 'SET_DATE', 7092 dateMarker: this.dateEnv.addYears(this.state.currentDate, 1) 7093 }); 7094 }; 7095 Calendar.prototype.today = function () { 7096 this.unselect(); 7097 this.dispatch({ 7098 type: 'SET_DATE', 7099 dateMarker: this.getNow() 7100 }); 7101 }; 7102 Calendar.prototype.gotoDate = function (zonedDateInput) { 7103 this.unselect(); 7104 this.dispatch({ 7105 type: 'SET_DATE', 7106 dateMarker: this.dateEnv.createMarker(zonedDateInput) 7107 }); 7108 }; 7109 Calendar.prototype.incrementDate = function (deltaInput) { 7110 var delta = createDuration(deltaInput); 7111 if (delta) { // else, warn about invalid input? 7112 this.unselect(); 7113 this.dispatch({ 7114 type: 'SET_DATE', 7115 dateMarker: this.dateEnv.add(this.state.currentDate, delta) 7116 }); 7117 } 7118 }; 7119 // for external API 7120 Calendar.prototype.getDate = function () { 7121 return this.dateEnv.toDate(this.state.currentDate); 7122 }; 7123 // Date Formatting Utils 7124 // ----------------------------------------------------------------------------------------------------------------- 7125 Calendar.prototype.formatDate = function (d, formatter) { 7126 var dateEnv = this.dateEnv; 7127 return dateEnv.format(dateEnv.createMarker(d), createFormatter(formatter)); 7128 }; 7129 // `settings` is for formatter AND isEndExclusive 7130 Calendar.prototype.formatRange = function (d0, d1, settings) { 7131 var dateEnv = this.dateEnv; 7132 return dateEnv.formatRange(dateEnv.createMarker(d0), dateEnv.createMarker(d1), createFormatter(settings, this.opt('defaultRangeSeparator')), settings); 7133 }; 7134 Calendar.prototype.formatIso = function (d, omitTime) { 7135 var dateEnv = this.dateEnv; 7136 return dateEnv.formatIso(dateEnv.createMarker(d), { omitTime: omitTime }); 7137 }; 7138 // Sizing 7139 // ----------------------------------------------------------------------------------------------------------------- 7140 Calendar.prototype.windowResize = function (ev) { 7141 if (!this.isHandlingWindowResize && 7142 this.component && // why? 7143 ev.target === window // not a jqui resize event 7144 ) { 7145 this.isHandlingWindowResize = true; 7146 this.updateSize(); 7147 this.publiclyTrigger('windowResize', [this.view]); 7148 this.isHandlingWindowResize = false;
7149 } 7150 }; 7151 Calendar.prototype.updateSize = function () { 7152 if (this.component) { // when? 7153 this.component.updateSize(true); 7154 } 7155 }; 7156 // Component Registration 7157 // ----------------------------------------------------------------------------------------------------------------- 7158 Calendar.prototype.registerInteractiveComponent = function (component, settingsInput) { 7159 var settings = parseInteractionSettings(component, settingsInput); 7160 var DEFAULT_INTERACTIONS = [ 7161 EventClicking, 7162 EventHovering 7163 ]; 7164 var interactionClasses = DEFAULT_INTERACTIONS.concat(this.pluginSystem.hooks.componentInteractions); 7165 var interactions = interactionClasses.map(function (interactionClass) { 7166 return new interactionClass(settings); 7167 }); 7168 this.interactionsStore[component.uid] = interactions; 7169 interactionSettingsStore[component.uid] = settings; 7170 }; 7171 Calendar.prototype.unregisterInteractiveComponent = function (component) { 7172 for (var _i = 0, _a = this.interactionsStore[component.uid]; _i < _a.length; _i++) { 7173 var listener = _a[_i]; 7174 listener.destroy(); 7175 } 7176 delete this.interactionsStore[component.uid]; 7177 delete interactionSettingsStore[component.uid]; 7178 }; 7179 // Date Selection / Event Selection / DayClick 7180 // ----------------------------------------------------------------------------------------------------------------- 7181 // this public method receives start/end dates in any format, with any timezone 7182 // NOTE: args were changed from v3 7183 Calendar.prototype.select = function (dateOrObj, endDate) { 7184 var selectionInput; 7185 if (endDate == null) { 7186 if (dateOrObj.start != null) { 7187 selectionInput = dateOrObj; 7188 } 7189 else { 7190 selectionInput = { 7191 start: dateOrObj, 7192 end: null 7193 }; 7194 } 7195 } 7196 else { 7197 selectionInput = { 7198 start: dateOrObj, 7199 end: endDate 7200 }; 7201 } 7202 var selection = parseDateSpan(selectionInput, this.dateEnv, createDuration({ days: 1 }) // TODO: cache this? 7203 ); 7204 if (selection) { // throw parse error otherwise? 7205 this.dispatch({ type: 'SELECT_DATES', selection: selection }); 7206 this.triggerDateSelect(selection); 7207 } 7208 }; 7209 // public method 7210 Calendar.prototype.unselect = function (pev) { 7211 if (this.state.dateSelection) { 7212 this.dispatch({ type: 'UNSELECT_DATES' }); 7213 this.triggerDateUnselect(pev); 7214 } 7215 }; 7216 Calendar.prototype.triggerDateSelect = function (selection, pev) { 7217 var arg = __assign({}, this.buildDateSpanApi(selection), { jsEvent: pev ? pev.origEvent : null, view: this.view }); 7218 this.publiclyTrigger('select', [arg]); 7219 }; 7220 Calendar.prototype.triggerDateUnselect = function (pev) { 7221 this.publiclyTrigger('unselect', [ 7222 { 7223 jsEvent: pev ? pev.origEvent : null, 7224 view: this.view 7225 } 7226 ]); 7227 }; 7228 // TODO: receive pev? 7229 Calendar.prototype.triggerDateClick = function (dateSpan, dayEl, view, ev) { 7230 var arg = __assign({}, this.buildDatePointApi(dateSpan), { dayEl: dayEl, jsEvent: ev, // Is this always a mouse event? See #4655 7231 view: view }); 7232 this.publiclyTrigger('dateClick', [arg]); 7233 }; 7234 Calendar.prototype.buildDatePointApi = function (dateSpan) { 7235 var props = {}; 7236 for (var _i = 0, _a = this.pluginSystem.hooks.datePointTransforms; _i < _a.length; _i++) { 7237 var transform = _a[_i]; 7238 __assign(props, transform(dateSpan, this)); 7239 } 7240 __assign(props, buildDatePointApi(dateSpan, this.dateEnv)); 7241 return props; 7242 }; 7243 Calendar.prototype.buildDateSpanApi = function (dateSpan) { 7244 var props = {}; 7245 for (var _i = 0, _a = this.pluginSystem.hooks.dateSpanTransforms; _i < _a.length; _i++) { 7246 var transform = _a[_i]; 7247 __assign(props, transform(dateSpan, this)); 7248 } 7249 __assign(props, buildDateSpanApi(dateSpan, this.dateEnv)); 7250 return props; 7251 }; 7252 // Date Utils 7253 // ----------------------------------------------------------------------------------------------------------------- 7254 // Returns a DateMarker for the current date, as defined by the client's computer or from the `now` option 7255 Calendar.prototype.getNow = function () { 7256 var now = this.opt('now'); 7257 if (typeof now === 'function') { 7258 now = now(); 7259 } 7260 if (now == null) { 7261 return this.dateEnv.createNowMarker(); 7262 } 7263 return this.dateEnv.createMarker(now); 7264 }; 7265 // Event-Date Utilities 7266 // ----------------------------------------------------------------------------------------------------------------- 7267 // Given an event's allDay status and start date, return what its fallback end date should be. 7268 // TODO: rename to computeDefaultEventEnd 7269 Calendar.prototype.getDefaultEventEnd = function (allDay, marker) { 7270 var end = marker; 7271 if (allDay) { 7272 end = startOfDay(end); 7273 end = this.dateEnv.add(end, this.defaultAllDayEventDuration); 7274 } 7275 else { 7276 end = this.dateEnv.add(end, this.defaultTimedEventDuration); 7277 } 7278 return end; 7279 }; 7280 // Public Events API 7281 // ----------------------------------------------------------------------------------------------------------------- 7282 Calendar.prototype.addEvent = function (eventInput, sourceIn
7282put) { 7283 if (eventInput instanceof EventApi) { 7284 var def = eventInput._def; 7285 var instance = eventInput._instance; 7286 // not already present? don't want to add an old snapshot 7287 if (!this.state.eventStore.defs[def.defId]) { 7288 this.dispatch({ 7289 type: 'ADD_EVENTS', 7290 eventStore: eventTupleToStore({ def: def, instance: instance }) // TODO: better util for two args? 7291 }); 7292 } 7293 return eventInput; 7294 } 7295 var sourceId; 7296 if (sourceInput instanceof EventSourceApi) { 7297 sourceId = sourceInput.internalEventSource.sourceId; 7298 } 7299 else if (sourceInput != null) { 7300 var sourceApi = this.getEventSourceById(sourceInput); // TODO: use an internal function 7301 if (!sourceApi) { 7302 console.warn('Could not find an event source with ID "' + sourceInput + '"'); // TODO: test 7303 return null; 7304 } 7305 else { 7306 sourceId = sourceApi.internalEventSource.sourceId; 7307 } 7308 } 7309 var tuple = parseEvent(eventInput, sourceId, this); 7310 if (tuple) { 7311 this.dispatch({ 7312 type: 'ADD_EVENTS', 7313 eventStore: eventTupleToStore(tuple) 7314 }); 7315 return new EventApi(this, tuple.def, tuple.def.recurringDef ? null : tuple.instance); 7316 } 7317 return null; 7318 }; 7319 // TODO: optimize 7320 Calendar.prototype.getEventById = function (id) { 7321 var _a = this.state.eventStore, defs = _a.defs, instances = _a.instances; 7322 id = String(id); 7323 for (var defId in defs) { 7324 var def = defs[defId]; 7325 if (def.publicId === id) { 7326 if (def.recurringDef) { 7327 return new EventApi(this, def, null); 7328 } 7329 else { 7330 for (var instanceId in instances) { 7331 var instance = instances[instanceId]; 7332 if (instance.defId === def.defId) { 7333 return new EventApi(this, def, instance); 7334 } 7335 } 7336 } 7337 } 7338 } 7339 return null; 7340 }; 7341 Calendar.prototype.getEvents = function () { 7342 var _a = this.state.eventStore, defs = _a.defs, instances = _a.instances; 7343 var eventApis = []; 7344 for (var id in instances) { 7345 var instance = instances[id]; 7346 var def = defs[instance.defId]; 7347 eventApis.push(new EventApi(this, def, instance)); 7348 } 7349 return eventApis; 7350 }; 7351 Calendar.prototype.removeAllEvents = function () { 7352 this.dispatch({ type: 'REMOVE_ALL_EVENTS' }); 7353 }; 7354 Calendar.prototype.rerenderEvents = function () { 7355 this.dispatch({ type: 'RESET_EVENTS' }); 7356 }; 7357 // Public Event Sources API 7358 // ----------------------------------------------------------------------------------------------------------------- 7359 Calendar.prototype.getEventSources = function () { 7360 var sourceHash = this.state.eventSources; 7361 var sourceApis = []; 7362 for (var internalId in sourceHash) { 7363 sourceApis.push(new EventSourceApi(this, sourceHash[internalId])); 7364 } 7365 return sourceApis; 7366 }; 7367 Calendar.prototype.getEventSourceById = function (id) { 7368 var sourceHash = this.state.eventSources; 7369 id = String(id); 7370 for (var sourceId in sourceHash) { 7371 if (sourceHash[sourceId].publicId === id) { 7372 return new EventSourceApi(this, sourceHash[sourceId]); 7373 } 7374 } 7375 return null; 7376 }; 7377 Calendar.prototype.addEventSource = function (sourceInput) { 7378 if (sourceInput instanceof EventSourceApi) { 7379 // not already present? don't want to add an old snapshot
7380 if (!this.state.eventSources[sourceInput.internalEventSource.sourceId]) { 7381 this.dispatch({ 7382 type: 'ADD_EVENT_SOURCES', 7383 sources: [sourceInput.internalEventSource] 7384 }); 7385 } 7386 return sourceInput; 7387 } 7388 var eventSource = parseEventSource(sourceInput, this); 7389 if (eventSource) { // TODO: error otherwise? 7390 this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [eventSource] }); 7391 return new EventSourceApi(this, eventSource); 7392 } 7393 return null; 7394 }; 7395 Calendar.prototype.removeAllEventSources = function () { 7396 this.dispatch({ type: 'REMOVE_ALL_EVENT_SOURCES' }); 7397 }; 7398 Calendar.prototype.refetchEvents = function () { 7399 this.dispatch({ type: 'FETCH_EVENT_SOURCES' }); 7400 }; 7401 // Scroll 7402 // ----------------------------------------------------------------------------------------------------------------- 7403 Calendar.prototype.scrollToTime = function (timeInput) { 7404 var duration = createDuration(timeInput); 7405 if (duration) { 7406 this.component.view.scrollToDuration(duration); 7407 } 7408 }; 7409 return Calendar; 7410 }()); 7411 EmitterMixin.mixInto(Calendar); 7412 // for memoizers 7413 // ----------------------------------------------------------------------------------------------------------------- 7414 function buildDateEnv(locale, timeZone, namedTimeZoneImpl, firstDay, weekNumberCalculation, weekLabel, cmdFormatter) { 7415 return new DateEnv({ 7416 calendarSystem: 'gregory', 7417 timeZone: timeZone, 7418 namedTimeZoneImpl: namedTimeZoneImpl, 7419 locale: locale, 7420 weekNumberCalculation: weekNumberCalculation, 7421 firstDay: firstDay, 7422 weekLabel: weekLabel, 7423 cmdFormatter: cmdFormatter 7424 }); 7425 } 7426 function buildTheme(calendarOptions) { 7427 var themeClass = this.pluginSystem.hooks.themeClasses[calendarOptions.themeSystem] || StandardTheme; 7428 return new themeClass(calendarOptions); 7429 } 7430 function buildDelayedRerender(wait) { 7431 var func = this.tryRerender.bind(this); 7432 if (wait != null) { 7433 func = debounce(func, wait); 7434 } 7435 return func; 7436 } 7437 function buildEventUiBySource(eventSources) { 7438 return mapHash(eventSources, function (eventSource) { 7439 return eventSource.ui; 7440 }); 7441 } 7442 function buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) { 7443 var eventUiBases = { '': eventUiSingleBase }; 7444 for (var defId in eventDefs) { 7445 var def = eventDefs[defId]; 7446 if (def.sourceId && eventUiBySource[def.sourceId]) { 7447 eventUiBases[defId] = eventUiBySource[def.sourceId]; 7448 } 7449 } 7450 return eventUiBases; 7451 } 7452 7453 var View = /** @class */ (function (_super) { 7454 __extends(View, _super); 7455 function View(context, viewSpec, dateProfileGenerator, parentEl) { 7456 var _this = _super.call(this, context, createElement('div', { className: 'fc-view fc-' + viewSpec.type + '-view' }), true // isView (HACK) 7457 ) || this; 7458 _this.renderDatesMem = memoizeRendering(_this.renderDatesWrap, _this.unrenderDatesWrap); 7459 _this.renderBusinessHoursMem = memoizeRendering(_this.renderBusinessHours, _this.unrenderBusinessHours, [_this.renderDatesMem]); 7460 _this.renderDateSelectionMem = memoizeRendering(_this.renderDateSelectionWrap, _this.unrenderDateSelectionWrap, [_this.renderDatesMem]); 7461 _this.renderEventsMem = memoizeRendering(_this.renderEvents, _this.unrenderEvents, [_this.renderDatesMem]); 7462 _this.renderEventSelectionMem = memoizeRendering(_this.renderEventSelectionWrap, _this.unrenderEventSelectionWrap, [_this.renderEventsMem]); 7463 _this.renderEventDragMem = memoizeRendering(_this.renderEventDragWrap, _this.unrenderEventDragWrap, [_this.renderDatesMem]); 7464 _this.renderEventResizeMem = memoizeRendering(_this.renderEventResizeWrap, _this.unrenderEventResizeWrap, [_this.renderDatesMem]); 7465 _this.viewSpec = viewSpec; 7466 _this.dateProfileGenerator = dateProfileGenerator; 7467 _this.type = viewSpec.type; 7468 _this.eventOrderSpecs = parseFieldSpecs(_this.opt('eventOrder')); 7469 _this.nextDayThreshold = createDuration(_this.opt('nextDayThreshold')); 7470 parentEl.appendChild(_this.el); 7471 _this.initialize(); 7472 return _this; 7473 } 7474 View.prototype.initialize = function () { 7475 }; 7476 Object.defineProperty(View.prototype, "activeStart", { 7477 // Date Setting/Unsetting 7478 // ----------------------------------------------------------------------------------------------------------------- 7479 get: function () { 7480 return this.dateEnv.toDate(this.props.dateProfile.activeRange.start); 7481 }, 7482 enumerable: true, 7483 configurable: true 7484 }); 7485 Object.defineProperty(View.prototype, "activeEnd", { 7486 get: function () { 7487 return this.dateEnv.toDate(this.props.dateProfile.activeRange.end); 7488 }, 7489 enumerable: true, 7490 configurable: true 7491 }); 7492 Object.defineProperty(View.prototype, "currentStart", { 7493 get: function () { 7494 return this.dateEnv.toDate(this.props.dateProfile.currentRange.start); 7495 }, 7496 enumerable: true, 7497 configurable: true 7498 }); 7499 Object.defineProperty(View.prototype, "currentEnd", { 7500 get: function () { 7501 return this.dateEnv.toDate(this.props.dateProfile.currentRange.end); 7502 }, 7503 enumerable: true, 7504 configurable: true 7505 }); 7506 // General Rendering 7507 // ----------------------------------------------------------------------------------------------------------------- 7508 View.prototype.render = function (props) { 7509 this.renderDatesMem(props.dateProfile); 7510 this.renderBusinessHoursMem(props.businessHours); 7511 this.renderDateSelectionMem(props.dateSelection); 7512 this.renderEventsMem(props.eventStore); 7513 this.renderEventSelectionMem(props.eventSelection); 7514 this.renderEventDragMem(props.eventDrag); 7515 this.renderEventResizeMem(props.eventResize); 7516 }; 7517 View.prototype.destroy = function () { 7518 _super.prototype.destroy.call(this); 7519 this.renderDatesMem.unrender(); // should unrender everything else 7520 }; 7521 // Sizing 7522 // ----------------------------------------------------------------------------------------------------------------- 7523 View.prototype.updateSize = function (isResize, viewHeight, isAuto) { 7524 var calendar = this.calendar; 7525 if (isResize || // HACKS... 7526 calendar.isViewUpdated || 7527 calendar.isDatesUpdated || 7528 calendar.isEventsUpdated) {
7529 // sort of the catch-all sizing 7530 // anything that might cause dimension changes 7531 this.updateBaseSize(isResize, viewHeight, isAuto); 7532 } 7533 }; 7534 View.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) { 7535 }; 7536 // Date Rendering 7537 // ----------------------------------------------------------------------------------------------------------------- 7538 View.prototype.renderDatesWrap = function (dateProfile) { 7539 this.renderDates(dateProfile); 7540 this.addScroll({ 7541 duration: createDuration(this.opt('scrollTime')) 7542 }); 7543 this.startNowIndicator(dateProfile); // shouldn't render yet because updateSize will be called soon 7544 }; 7545 View.prototype.unrenderDatesWrap = function () { 7546 this.stopNowIndicator(); 7547 this.unrenderDates(); 7548 }; 7549 View.prototype.renderDates = function (dateProfile) { }; 7550 View.prototype.unrenderDates = function () { }; 7551 // Business Hours 7552 // ----------------------------------------------------------------------------------------------------------------- 7553 View.prototype.renderBusinessHours = function (businessHours) { }; 7554 View.prototype.unrenderBusinessHours = function () { }; 7555 // Date Selection 7556 // ----------------------------------------------------------------------------------------------------------------- 7557 View.prototype.renderDateSelectionWrap = function (selection) { 7558 if (selection) { 7559 this.renderDateSelection(selection); 7560 } 7561 }; 7562 View.prototype.unrenderDateSelectionWrap = function (selection) { 7563 if (selection) { 7564 this.unrenderDateSelection(selection); 7565 } 7566 }; 7567 View.prototype.renderDateSelection = function (selection) { }; 7568 View.prototype.unrenderDateSelection = function (selection) { }; 7569 // Event Rendering 7570 // ----------------------------------------------------------------------------------------------------------------- 7571 View.prototype.renderEvents = function (eventStore) { }; 7572 View.prototype.unrenderEvents = function () { }; 7573 // util for subclasses 7574 View.prototype.sliceEvents = function (eventStore, allDay) { 7575 var props = this.props; 7576 return sliceEventStore(eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? this.nextDayThreshold : null).fg; 7577 }; 7578 View.prototype.computeEventDraggable = function (eventDef, eventUi) { 7579 var transformers = this.calendar.pluginSystem.hooks.isDraggableTransformers; 7580 var val = eventUi.startEditable; 7581 for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) { 7582 var transformer = transformers_1[_i]; 7583 val = transformer(val, eventDef, eventUi, this); 7584 } 7585 return val; 7586 }; 7587 View.prototype.computeEventStartResizable = function (eventDef, eventUi) { 7588 return eventUi.durationEditable && this.opt('eventResizableFromStart'); 7589 }; 7590 View.prototype.computeEventEndResizable = function (eventDef, eventUi) { 7591 return eventUi.durationEditable; 7592 }; 7593 // Event Selection 7594 // ----------------------------------------------------------------------------------------------------------------- 7595 View.prototype.renderEventSelectionWrap = function (instanceId) { 7596 if (instanceId) { 7597 this.renderEventSelection(instanceId); 7598 } 7599 }; 7600 View.prototype.unrenderEventSelectionWrap = function (instanceId) { 7601 if (instanceId) { 7602 this.unrenderEventSelection(instanceId); 7603 } 7604 }; 7605 View.prototype.renderEventSelection = function (instanceId) { }; 7606 View.prototype.unrenderEventSelection = function (instanceId) { }; 7607 // Event Drag 7608 // ----------------------------------------------------------------------------------------------------------------- 7609 View.prototype.renderEventDragWrap = function (state) { 7610 if (state) { 7611 this.renderEventDrag(state); 7612 } 7613 }; 7614 View.prototype.unrenderEventDragWrap = function (state) { 7615 if (state) { 7616 this.unrenderEventDrag(state); 7617 } 7618 }; 7619 View.prototype.renderEventDrag = function (state) { }; 7620 View.prototype.unrenderEventDrag = function (state) { }; 7621 // Event Resize 7622 // ----------------------------------------------------------------------------------------------------------------- 7623 View.prototype.renderEventResizeWrap = function (state) { 7624 if (state) { 7625 this.renderEventResize(state); 7626 } 7627 }; 7628 View.prototype.unrenderEventResizeWrap = function (state) { 7629 if (state) { 7630 this.unrenderEventResize(state); 7631 } 7632 }; 7633 View.prototype.renderEventResize = function (state) { }; 7634 View.prototype.unrenderEventResize = function (state) { }; 7635 /* Now Indicator 7636 ------------------------------------------------------------------------------------------------------------------*/ 7637 // Immediately render the current time indicator and begins re-rendering it at an interval, 7638 // which is defined by this.getNowIndicatorUnit(). 7639 // TODO: somehow do this for the current whole day's background too 7640 View.prototype.startNowIndicator = function (dateProfile) { 7641 var _this = this; 7642 var dateEnv = this.dateEnv; 7643 var unit; 7644 var update; 7645 var delay; // ms wait value 7646 if (this.opt('nowIndicator')) { 7647 unit = this.getNowIndicatorUnit(dateProfile); 7648 if (unit) { 7649 update = this.updateNowIndicator.bind(this); 7650 this.initialNowDate = this.calendar.getNow(); 7651 this.initialNowQueriedMs = new Date().valueOf(); 7652 // wait until the beginning of the next interval
7653 delay = dateEnv.add(dateEnv.startOf(this.initialNowDate, unit), createDuration(1, unit)).valueOf() - this.initialNowDate.valueOf(); 7654 // TODO: maybe always use setTimeout, waiting until start of next unit 7655 this.nowIndicatorTimeoutID = setTimeout(function () { 7656 _this.nowIndicatorTimeoutID = null; 7657 update(); 7658 if (unit === 'second') { 7659 delay = 1000; // every second 7660 } 7661 else { 7662 delay = 1000 * 60; // otherwise, every minute 7663 } 7664 _this.nowIndicatorIntervalID = setInterval(update, delay); // update every interval 7665 }, delay); 7666 } 7667 // rendering will be initiated in updateSize 7668 } 7669 }; 7670 // rerenders the now indicator, computing the new current time from the amount of time that has passed 7671 // since the initial getNow call. 7672 View.prototype.updateNowIndicator = function () { 7673 if (this.props.dateProfile && // a way to determine if dates were rendered yet 7674 this.initialNowDate // activated before? 7675 ) { 7676 this.unrenderNowIndicator(); // won't unrender if unnecessary 7677 this.renderNowIndicator(addMs(this.initialNowDate, new Date().valueOf() - this.initialNowQueriedMs)); 7678 this.isNowIndicatorRendered = true; 7679 } 7680 }; 7681 // Immediately unrenders the view's current time indicator and stops any re-rendering timers. 7682 // Won't cause side effects if indicator isn't rendered. 7683 View.prototype.stopNowIndicator = function () { 7684 if (this.isNowIndicatorRendered) { 7685 if (this.nowIndicatorTimeoutID) { 7686 clearTimeout(this.nowIndicatorTimeoutID); 7687 this.nowIndicatorTimeoutID = null; 7688 } 7689 if (this.nowIndicatorIntervalID) { 7690 clearInterval(this.nowIndicatorIntervalID); 7691 this.nowIndicatorIntervalID = null; 7692 } 7693 this.unrenderNowIndicator(); 7694 this.isNowIndicatorRendered = false; 7695 } 7696 }; 7697 View.prototype.getNowIndicatorUnit = function (dateProfile) { 7698 // subclasses should implement 7699 }; 7700 // Renders a current time indicator at the given datetime 7701 View.prototype.renderNowIndicator = function (date) { 7702 // SUBCLASSES MUST PASS TO CHILDREN! 7703 }; 7704 // Undoes the rendering actions from renderNowIndicator 7705 View.prototype.unrenderNowIndicator = function () { 7706 // SUBCLASSES MUST PASS TO CHILDREN! 7707 }; 7708 /* Scroller 7709 ------------------------------------------------------------------------------------------------------------------*/ 7710 View.prototype.addScroll = function (scroll) { 7711 var queuedScroll = this.queuedScroll || (this.queuedScroll = {}); 7712 __assign(queuedScroll, scroll); 7713 }; 7714 View.prototype.popScroll = function (isResize) { 7715 this.applyQueuedScroll(isResize); 7716 this.queuedScroll = null; 7717 }; 7718 View.prototype.applyQueuedScroll = function (isResize) { 7719 this.applyScroll(this.queuedScroll || {}, isResize); 7720 }; 7721 View.prototype.queryScroll = function () { 7722 var scroll = {}; 7723 if (this.props.dateProfile) { // dates rendered yet? 7724 __assign(scroll, this.queryDateScroll()); 7725 } 7726 return scroll; 7727 }; 7728 View.prototype.applyScroll = function (scroll, isResize) { 7729 var duration = scroll.duration; 7730 if (duration != null) { 7731 delete scroll.duration; 7732 if (this.props.dateProfile) { // dates rendered yet? 7733 __assign(scroll, this.computeDateScroll(duration)); 7734 } 7735 } 7736 if (this.props.dateProfile) { // dates rendered yet? 7737 this.applyDateScroll(scroll); 7738 } 7739 }; 7740 View.prototype.computeDateScroll = function (duration) { 7741 return {}; // subclasses must implement 7742 }; 7743 View.prototype.queryDateScroll = function () { 7744 return {}; // subclasses must implement 7745 }; 7746 View.prototype.applyDateScroll = function (scroll) { 7747 // subclasses must implement 7748 }; 7749 // for API 7750 View.prototype.scrollToDuration = function (duration) { 7751 this.applyScroll({ duration: duration }, false); 7752 }; 7753 return View; 7754 }(DateComponent)); 7755 EmitterMixin.mixInto(View); 7756 View.prototype.usesMinMaxTime = false;
7757 View.prototype.dateProfileGeneratorClass = DateProfileGenerator; 7758 7759 var FgEventRenderer = /** @class */ (function () { 7760 function FgEventRenderer(context) { 7761 this.segs = []; 7762 this.isSizeDirty = false; 7763 this.context = context; 7764 } 7765 FgEventRenderer.prototype.renderSegs = function (segs, mirrorInfo) { 7766 this.rangeUpdated(); // called too frequently :( 7767 // render an `.el` on each seg 7768 // returns a subset of the segs. segs that were actually rendered 7769 segs = this.renderSegEls(segs, mirrorInfo); 7770 this.segs = segs; 7771 this.attachSegs(segs, mirrorInfo); 7772 this.isSizeDirty = true; 7773 this.context.view.triggerRenderedSegs(this.segs, Boolean(mirrorInfo)); 7774 }; 7775 FgEventRenderer.prototype.unrender = function (_segs, mirrorInfo) { 7776 this.context.view.triggerWillRemoveSegs(this.segs, Boolean(mirrorInfo)); 7777 this.detachSegs(this.segs); 7778 this.segs = []; 7779 }; 7780 // Updates values that rely on options and also relate to range 7781 FgEventRenderer.prototype.rangeUpdated = function () { 7782 var options = this.context.options; 7783 var displayEventTime; 7784 var displayEventEnd; 7785 this.eventTimeFormat = createFormatter(options.eventTimeFormat || this.computeEventTimeFormat(), options.defaultRangeSeparator); 7786 displayEventTime = options.displayEventTime; 7787 if (displayEventTime == null) { 7788 displayEventTime = this.computeDisplayEventTime(); // might be based off of range 7789 } 7790 displayEventEnd = options.displayEventEnd; 7791 if (displayEventEnd == null) { 7792 displayEventEnd = this.computeDisplayEventEnd(); // might be based off of range 7793 } 7794 this.displayEventTime = displayEventTime; 7795 this.displayEventEnd = displayEventEnd; 7796 }; 7797 // Renders and assigns an `el` property for each foreground event segment. 7798 // Only returns segments that successfully rendered. 7799 FgEventRenderer.prototype.renderSegEls = function (segs, mirrorInfo) { 7800 var html = ''; 7801 var i; 7802 if (segs.length) { // don't build an empty html string 7803 // build a large concatenation of event segment HTML 7804 for (i = 0; i < segs.length; i++) { 7805 html += this.renderSegHtml(segs[i], mirrorInfo); 7806 } 7807 // Grab individual elements from the combined HTML string. Use each as the default rendering. 7808 // Then, compute the 'el' for each segment. An el might be null if the eventRender callback returned false. 7809 htmlToElements(html).forEach(function (el, i) { 7810 var seg = segs[i]; 7811 if (el) { 7812 seg.el = el; 7813 } 7814 }); 7815 segs = filterSegsViaEls(this.context.view, segs, Boolean(mirrorInfo)); 7816 } 7817 return segs; 7818 }; 7819 // Generic utility for generating the HTML classNames for an event segment's element 7820 FgEventRenderer.prototype.getSegClasses = function (seg, isDraggable, isResizable, mirrorInfo) { 7821 var classes = [ 7822 'fc-event', 7823 seg.isStart ? 'fc-start' : 'fc-not-start', 7824 seg.isEnd ? 'fc-end' : 'fc-not-end' 7825 ].concat(seg.eventRange.ui.classNames); 7826 if (isDraggable) { 7827 classes.push('fc-draggable'); 7828 } 7829 if (isResizable) { 7830 classes.push('fc-resizable'); 7831 } 7832 if (mirrorInfo) { 7833 classes.push('fc-mirror'); 7834 if (mirrorInfo.isDragging) { 7835 classes.push('fc-dragging'); 7836 } 7837 if (mirrorInfo.isResizing) { 7838 classes.push('fc-resizing'); 7839 } 7840 } 7841 return classes; 7842 }; 7843 // Compute the text that should be displayed on an event's element. 7844 // `range` can be the Event object itself, or something range-like, with at least a `start`. 7845 // If event times are disabled, or the event has no time, will return a blank string. 7846 // If not specified, formatter will default to the eventTimeFormat setting, 7847 // and displayEnd will default to the displayEventEnd setting. 7848 FgEventRenderer.prototype.getTimeText = function (eventRange, formatter, displayEnd) { 7849 var def = eventRange.def, instance = eventRange.instance; 7850 return this._getTimeText(instance.range.start, def.hasEnd ? instance.range.end : null, def.allDay, formatter, displayEnd, instance.forcedStartTzo, instance.forcedEndTzo); 7851 }; 7852 FgEventRenderer.prototype._getTimeText = function (start, end, allDay, formatter, displayEnd, forcedStartTzo, forcedEndTzo) { 7853 var dateEnv = this.context.dateEnv; 7854 if (formatter == null) { 7855 formatter = this.eventTimeFormat; 7856 } 7857 if (displayEnd == null) { 7858 displayEnd = this.displayEventEnd; 7859 } 7860 if (this.displayEventTime && !allDay) { 7861 if (displayEnd && end) { 7862 return dateEnv.formatRange(start, end, formatter, { 7863 forcedStartTzo: forcedStartTzo, 7864 forcedEndTzo: forcedEndTzo 7865 }); 7866 } 7867 else { 7868 return dateEnv.format(start, formatter, { 7869 forcedTzo: forcedStartTzo 7870 }); 7871 } 7872 } 7873 return ''; 7874 }; 7875 FgEventRenderer.prototype.computeEventTimeFormat = function () { 7876 return { 7877 hour: 'numeric', 7878 minute: '2-digit', 7879 omitZeroMinute: true 7880 }; 7881 }; 7882 FgEventRenderer.prototype.computeDisplayEventTime = function () { 7883 return true; 7884 }; 7885 FgEventRenderer.prototype.computeDisplayEventEnd = function () { 7886 return true; 7887 }; 7888 // Utility for generating event skin-related CSS properties 7889 FgEventRenderer.prototype.getSkinCss = function (ui) { 7890 return { 7891 'background-color': ui.backgroundColor, 7892 'border-color': ui.borderColor, 7893 color: ui.textColor 7894 }; 7895 }; 7896 FgEventRenderer.prototype.sortEventSegs = function (segs) { 7897 var specs = this.context.view.eventOrderSpecs; 7898 var objs = segs.map(buildSegCompareObj); 7899 objs.sort(function (obj0, obj1) { 7900 return compareByFieldSpecs(obj0, obj1, specs); 7901 }); 7902 return objs.map(function (c) { 7903 return c._seg; 7904 }); 7905 }; 7906 FgEventRenderer.prototype.computeSizes = function (force) { 7907 if (force || this.isSizeDirty) { 7908 this.computeSegSizes(this.segs); 7909 } 7910 }; 7911 FgEventRenderer.prototype.assignSizes = function (force) { 7912 if (force || this.isSizeDirty) { 7913 this.assignSegSizes(this.segs); 7914 this.isSizeDirty = false;
7915 } 7916 }; 7917 FgEventRenderer.prototype.computeSegSizes = function (segs) { 7918 }; 7919 FgEventRenderer.prototype.assignSegSizes = function (segs) { 7920 }; 7921 // Manipulation on rendered segs 7922 FgEventRenderer.prototype.hideByHash = function (hash) { 7923 if (hash) { 7924 for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { 7925 var seg = _a[_i]; 7926 if (hash[seg.eventRange.instance.instanceId]) { 7927 seg.el.style.visibility = 'hidden'; 7928 } 7929 } 7930 } 7931 }; 7932 FgEventRenderer.prototype.showByHash = function (hash) { 7933 if (hash) { 7934 for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { 7935 var seg = _a[_i]; 7936 if (hash[seg.eventRange.instance.instanceId]) { 7937 seg.el.style.visibility = ''; 7938 } 7939 } 7940 } 7941 }; 7942 FgEventRenderer.prototype.selectByInstanceId = function (instanceId) { 7943 if (instanceId) { 7944 for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { 7945 var seg = _a[_i]; 7946 var eventInstance = seg.eventRange.instance; 7947 if (eventInstance && eventInstance.instanceId === instanceId && 7948 seg.el // necessary? 7949 ) { 7950 seg.el.classList.add('fc-selected'); 7951 } 7952 } 7953 } 7954 }; 7955 FgEventRenderer.prototype.unselectByInstanceId = function (instanceId) { 7956 if (instanceId) { 7957 for (var _i = 0, _a = this.segs; _i < _a.length; _i++) { 7958 var seg = _a[_i]; 7959 if (seg.el) { // necessary? 7960 seg.el.classList.remove('fc-selected'); 7961 } 7962 } 7963 } 7964 }; 7965 return FgEventRenderer; 7966 }()); 7967 // returns a object with all primitive props that can be compared 7968 function buildSegCompareObj(seg) { 7969 var eventDef = seg.eventRange.def; 7970 var range = seg.eventRange.instance.range; 7971 var start = range.start ? range.start.valueOf() : 0; // TODO: better support for open-range events 7972 var end = range.end ? range.end.valueOf() : 0; // " 7973 return __assign({}, eventDef.extendedProps, eventDef, { id: eventDef.publicId, start: start, 7974 end: end, duration: end - start, allDay: Number(eventDef.allDay), _seg: seg // for later retrieval 7975 }); 7976 } 7977 7978 var FillRenderer = /** @class */ (function () { 7979 function FillRenderer(context) { 7980 this.fillSegTag = 'div'; 7981 this.dirtySizeFlags = {}; 7982 this.context = context; 7983 this.containerElsByType = {}; 7984 this.segsByType = {}; 7985 } 7986 FillRenderer.prototype.getSegsByType = function (type) { 7987 return this.segsByType[type] || []; 7988 }; 7989 FillRenderer.prototype.renderSegs = function (type, segs) { 7990 var _a; 7991 var renderedSegs = this.renderSegEls(type, segs); // assignes `.el` to each seg. returns successfully rendered segs 7992 var containerEls = this.attachSegs(type, renderedSegs); 7993 if (containerEls) { 7994 (_a = (this.containerElsByType[type] || (this.containerElsByType[type] = []))).push.apply(_a, containerEls); 7995 } 7996 this.segsByType[type] = renderedSegs; 7997 if (type === 'bgEvent') { 7998 this.context.view.triggerRenderedSegs(renderedSegs, false); // isMirror=false 7999 } 8000 this.dirtySizeFlags[type] = true; 8001 }; 8002 // Unrenders a specific type of fill that is currently rendered on the grid 8003 FillRenderer.prototype.unrender = function (type) { 8004 var segs = this.segsByType[type]; 8005 if (segs) { 8006 if (type === 'bgEvent') { 8007 this.context.view.triggerWillRemoveSegs(segs, false); // isMirror=false 8008 } 8009 this.detachSegs(type, segs); 8010 } 8011 }; 8012 // Renders and assigns an `el` property for each fill segment. Generic enough to work with different types. 8013 // Only returns segments that successfully rendered.
8014 FillRenderer.prototype.renderSegEls = function (type, segs) { 8015 var _this = this; 8016 var html = ''; 8017 var i; 8018 if (segs.length) { 8019 // build a large concatenation of segment HTML 8020 for (i = 0; i < segs.length; i++) { 8021 html += this.renderSegHtml(type, segs[i]); 8022 } 8023 // Grab individual elements from the combined HTML string. Use each as the default rendering. 8024 // Then, compute the 'el' for each segment. 8025 htmlToElements(html).forEach(function (el, i) { 8026 var seg = segs[i]; 8027 if (el) { 8028 seg.el = el; 8029 } 8030 }); 8031 if (type === 'bgEvent') { 8032 segs = filterSegsViaEls(this.context.view, segs, false // isMirror. background events can never be mirror elements 8033 ); 8034 } 8035 // correct element type? (would be bad if a non-TD were inserted into a table for example) 8036 segs = segs.filter(function (seg) { 8037 return elementMatches(seg.el, _this.fillSegTag); 8038 }); 8039 } 8040 return segs; 8041 }; 8042 // Builds the HTML needed for one fill segment. Generic enough to work with different types. 8043 FillRenderer.prototype.renderSegHtml = function (type, seg) { 8044 var css = null; 8045 var classNames = []; 8046 if (type !== 'highlight' && type !== 'businessHours') { 8047 css = { 8048 'background-color': seg.eventRange.ui.backgroundColor 8049 }; 8050 } 8051 if (type !== 'highlight') { 8052 classNames = classNames.concat(seg.eventRange.ui.classNames); 8053 } 8054 if (type === 'businessHours') { 8055 classNames.push('fc-bgevent'); 8056 } 8057 else { 8058 classNames.push('fc-' + type.toLowerCase()); 8059 } 8060 return '<' + this.fillSegTag + 8061 (classNames.length ? ' class="' + classNames.join(' ') + '"' : '') + 8062 (css ? ' style="' + cssToStr(css) + '"' : '') + 8063 '></' + this.fillSegTag + '>'; 8064 }; 8065 FillRenderer.prototype.detachSegs = function (type, segs) { 8066 var containerEls = this.containerElsByType[type]; 8067 if (containerEls) { 8068 containerEls.forEach(removeElement); 8069 delete this.containerElsByType[type]; 8070 } 8071 }; 8072 FillRenderer.prototype.computeSizes = function (force) { 8073 for (var type in this.segsByType) { 8074 if (force || this.dirtySizeFlags[type]) { 8075 this.computeSegSizes(this.segsByType[type]); 8076 } 8077 } 8078 }; 8079 FillRenderer.prototype.assignSizes = function (force) { 8080 for (var type in this.segsByType) { 8081 if (force || this.dirtySizeFlags[type]) { 8082 this.assignSegSizes(this.segsByType[type]); 8083 } 8084 } 8085 this.dirtySizeFlags = {}; 8086 }; 8087 FillRenderer.prototype.computeSegSizes = function (segs) { 8088 }; 8089 FillRenderer.prototype.assignSegSizes = function (segs) { 8090 }; 8091 return FillRenderer; 8092 }()); 8093 8094 var NamedTimeZoneImpl = /** @class */ (function () { 8095 function NamedTimeZoneImpl(timeZoneName) { 8096 this.timeZoneName = timeZoneName; 8097 } 8098 return NamedTimeZoneImpl; 8099 }()); 8100 8101 /* 8102 An abstraction for a dragging interaction originating on an event. 8103 Does higher-level things than PointerDragger, such as possibly: 8104 - a "mirror" that moves with the pointer 8105 - a minimum number of pixels or other criteria for a true drag to begin 8106 8107 subclasses must emit: 8108 - pointerdown 8109 - dragstart 8110 - dragmove 8111 - pointerup 8112 - dragend 8113 */ 8114 var ElementDragging = /** @class */ (function () { 8115 function ElementDragging(el) { 8116 this.emitter = new EmitterMixin(); 8117 } 8118 ElementDragging.prototype.destroy = function () { 8119 }; 8120 ElementDragging.prototype.setMirrorIsVisible = function (bool) {
8121 // optional if subclass doesn't want to support a mirror 8122 }; 8123 ElementDragging.prototype.setMirrorNeedsRevert = function (bool) { 8124 // optional if subclass doesn't want to support a mirror 8125 }; 8126 ElementDragging.prototype.setAutoScrollEnabled = function (bool) { 8127 // optional 8128 }; 8129 return ElementDragging; 8130 }()); 8131 8132 function formatDate(dateInput, settings) { 8133 if (settings === void 0) { settings = {}; } 8134 var dateEnv = buildDateEnv$1(settings); 8135 var formatter = createFormatter(settings); 8136 var dateMeta = dateEnv.createMarkerMeta(dateInput); 8137 if (!dateMeta) { // TODO: warning? 8138 return ''; 8139 } 8140 return dateEnv.format(dateMeta.marker, formatter, { 8141 forcedTzo: dateMeta.forcedTzo 8142 }); 8143 } 8144 function formatRange(startInput, endInput, settings // mixture of env and formatter settings 8145 ) { 8146 var dateEnv = buildDateEnv$1(typeof settings === 'object' && settings ? settings : {}); // pass in if non-null object 8147 var formatter = createFormatter(settings, globalDefaults.defaultRangeSeparator); 8148 var startMeta = dateEnv.createMarkerMeta(startInput); 8149 var endMeta = dateEnv.createMarkerMeta(endInput); 8150 if (!startMeta || !endMeta) { // TODO: warning? 8151 return ''; 8152 } 8153 return dateEnv.formatRange(startMeta.marker, endMeta.marker, formatter, { 8154 forcedStartTzo: startMeta.forcedTzo, 8155 forcedEndTzo: endMeta.forcedTzo, 8156 isEndExclusive: settings.isEndExclusive 8157 }); 8158 } 8159 // TODO: more DRY and optimized 8160 function buildDateEnv$1(settings) { 8161 var locale = buildLocale(settings.locale || 'en', parseRawLocales([]).map); // TODO: don't hardcode 'en' everywhere 8162 // ensure required settings 8163 settings = __assign({ timeZone: globalDefaults.timeZone, calendarSystem: 'gregory' }, settings, { locale: locale }); 8164 return new DateEnv(settings); 8165 } 8166 8167 var DRAG_META_PROPS = { 8168 startTime: createDuration, 8169 duration: createDuration, 8170 create: Boolean, 8171 sourceId: String 8172 }; 8173 var DRAG_META_DEFAULTS = { 8174 create: true 8175 }; 8176 function parseDragMeta(raw) { 8177 var leftoverProps = {}; 8178 var refined = refineProps(raw, DRAG_META_PROPS, DRAG_META_DEFAULTS, leftoverProps); 8179 refined.leftoverProps = leftoverProps; 8180 return refined; 8181 } 8182 8183 // Computes a default column header formatting string if `colFormat` is not explicitly defined 8184 function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) { 8185 // if more than one week row, or if there are a lot of columns with not much space, 8186 // put just the day numbers will be in each cell 8187 if (!datesRepDistinctDays || dayCnt > 10) { 8188 return { weekday: 'short' }; // "Sat" 8189 } 8190 else if (dayCnt > 1) { 8191 return { weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }; // "Sat 11/12" 8192 } 8193 else { 8194 return { weekday: 'long' }; // "Saturday" 8195 } 8196 } 8197 function renderDateCell(dateMarker, dateProfile, datesRepDistinctDays, colCnt, colHeadFormat, context, colspan, otherAttrs) { 8198 var view = context.view, dateEnv = context.dateEnv, theme = context.theme, options = context.options; 8199 var isDateValid = rangeContainsMarker(dateProfile.activeRange, dateMarker); // TODO: called too frequently. cache somehow. 8200 var classNames = [ 8201 'fc-day-header', 8202 theme.getClass('widgetHeader') 8203 ]; 8204 var innerHtml; 8205 if (typeof options.columnHeaderHtml === 'function') { 8206 innerHtml = options.columnHeaderHtml(dateEnv.toDate(dateMarker)); 8207 } 8208 else if (typeof options.columnHeaderText === 'function') { 8209 innerHtml = htmlEscape(options.columnHeaderText(dateEnv.toDate(dateMarker))); 8210 } 8211 else { 8212 innerHtml = htmlEscape(dateEnv.format(dateMarker, colHeadFormat)); 8213 } 8214 // if only one row of days, the classNames on the header can represent the specific days beneath 8215 if (datesRepDistinctDays) {
8216 classNames = classNames.concat( 8217 // includes the day-of-week class 8218 // noThemeHighlight=true (don't highlight the header) 8219 getDayClasses(dateMarker, dateProfile, context, true)); 8220 } 8221 else { 8222 classNames.push('fc-' + DAY_IDS[dateMarker.getUTCDay()]); // only add the day-of-week class 8223 } 8224 return '' + 8225 '<th class="' + classNames.join(' ') + '"' + 8226 ((isDateValid && datesRepDistinctDays) ? 8227 ' data-date="' + dateEnv.formatIso(dateMarker, { omitTime: true }) + '"' : 8228 '') + 8229 (colspan > 1 ? 8230 ' colspan="' + colspan + '"' : 8231 '') + 8232 (otherAttrs ? 8233 ' ' + otherAttrs : 8234 '') + 8235 '>' + 8236 (isDateValid ? 8237 // don't make a link if the heading could represent multiple days, or if there's only one day (forceOff) 8238 buildGotoAnchorHtml(view, { date: dateMarker, forceOff: !datesRepDistinctDays || colCnt === 1 }, innerHtml) : 8239 // if not valid, display text, but no link 8240 innerHtml) + 8241 '</th>'; 8242 } 8243 8244 var DayHeader = /** @class */ (function (_super) { 8245 __extends(DayHeader, _super); 8246 function DayHeader(context, parentEl) { 8247 var _this = _super.call(this, context) || this; 8248 parentEl.innerHTML = ''; // because might be nbsp 8249 parentEl.appendChild(_this.el = htmlToElement('<div class="fc-row ' + _this.theme.getClass('headerRow') + '">' + 8250 '<table class="' + _this.theme.getClass('tableGrid') + '">' + 8251 '<thead></thead>' + 8252 '</table>' + 8253 '</div>')); 8254 _this.thead = _this.el.querySelector('thead'); 8255 return _this; 8256 } 8257 DayHeader.prototype.destroy = function () { 8258 removeElement(this.el); 8259 }; 8260 DayHeader.prototype.render = function (props) { 8261 var dates = props.dates, datesRepDistinctDays = props.datesRepDistinctDays; 8262 var parts = []; 8263 if (props.renderIntroHtml) { 8264 parts.push(props.renderIntroHtml()); 8265 } 8266 var colHeadFormat = createFormatter(this.opt('columnHeaderFormat') || 8267 computeFallbackHeaderFormat(datesRepDistinctDays, dates.length)); 8268 for (var _i = 0, dates_1 = dates; _i < dates_1.length; _i++) { 8269 var date = dates_1[_i]; 8270 parts.push(renderDateCell(date, props.dateProfile, datesRepDistinctDays, dates.length, colHeadFormat, this.context)); 8271 } 8272 if (this.isRtl) { 8273 parts.reverse(); 8274 } 8275 this.thead.innerHTML = '<tr>' + parts.join('') + '</tr>'; 8276 }; 8277 return DayHeader; 8278 }(Component)); 8279 8280 var DaySeries = /** @class */ (function () { 8281 function DaySeries(range, dateProfileGenerator) { 8282 var date = range.start; 8283 var end = range.end; 8284 var indices = []; 8285 var dates = []; 8286 var dayIndex = -1; 8287 while (date < end) { // loop each day from start to end 8288 if (dateProfileGenerator.isHiddenDay(date)) { 8289 indices.push(dayIndex + 0.5); // mark that it's between indices 8290 } 8291 else { 8292 dayIndex++; 8293 indices.push(dayIndex); 8294 dates.push(date); 8295 } 8296 date = addDays(date, 1); 8297 } 8298 this.dates = dates; 8299 this.indices = indices; 8300 this.cnt = dates.length; 8301 } 8302 DaySeries.prototype.sliceRange = function (range) { 8303 var firstIndex = this.getDateDayIndex(range.start); // inclusive first index 8304 var lastIndex = this.getDateDayIndex(addDays(range.end, -1)); // inclusive last index 8305 var clippedFirstIndex = Math.max(0, firstIndex); 8306 var clippedLastIndex = Math.min(this.cnt - 1, lastIndex); 8307 // deal with in-between indices 8308 clippedFirstIndex = Math.ceil(clippedFirstIndex); // in-between starts round to next cell 8309 clippedLastIndex = Math.floor(clippedLastIndex); // in-between ends round to prev cell 8310 if (clippedFirstIndex <= clippedLastIndex) { 8311 return { 8312 firstIndex: clippedFirstIndex, 8313 lastIndex: clippedLastIndex, 8314 isStart: firstIndex === clippedFirstIndex, 8315 isEnd: lastIndex === clippedLastIndex 8316 }; 8317 } 8318 else { 8319 return null; 8320 } 8321 }; 8322 // Given a date, returns its chronolocial cell-index from the first cell of the grid. 8323 // If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets. 8324 // If before the first offset, returns a negative number. 8325 // If after the last offset, returns an offset past the last cell offset. 8326 // Only works for *start* dates of cells. Will not work for exclusive end dates for cells. 8327 DaySeries.prototype.getDateDayIndex = function (date) { 8328 var indices = this.indices; 8329 var dayOffset = Math.floor(diffDays(this.dates[0], date)); 8330 if (dayOffset < 0) {
8331 return indices[0] - 1; 8332 } 8333 else if (dayOffset >= indices.length) { 8334 return indices[indices.length - 1] + 1; 8335 } 8336 else { 8337 return indices[dayOffset]; 8338 } 8339 }; 8340 return DaySeries; 8341 }()); 8342 8343 var DayTable = /** @class */ (function () { 8344 function DayTable(daySeries, breakOnWeeks) { 8345 var dates = daySeries.dates; 8346 var daysPerRow; 8347 var firstDay; 8348 var rowCnt; 8349 if (breakOnWeeks) { 8350 // count columns until the day-of-week repeats 8351 firstDay = dates[0].getUTCDay(); 8352 for (daysPerRow = 1; daysPerRow < dates.length; daysPerRow++) { 8353 if (dates[daysPerRow].getUTCDay() === firstDay) { 8354 break; 8355 } 8356 } 8357 rowCnt = Math.ceil(dates.length / daysPerRow); 8358 } 8359 else { 8360 rowCnt = 1; 8361 daysPerRow = dates.length; 8362 } 8363 this.rowCnt = rowCnt; 8364 this.colCnt = daysPerRow; 8365 this.daySeries = daySeries; 8366 this.cells = this.buildCells(); 8367 this.headerDates = this.buildHeaderDates(); 8368 } 8369 DayTable.prototype.buildCells = function () { 8370 var rows = []; 8371 for (var row = 0; row < this.rowCnt; row++) { 8372 var cells = []; 8373 for (var col = 0; col < this.colCnt; col++) { 8374 cells.push(this.buildCell(row, col)); 8375 } 8376 rows.push(cells); 8377 } 8378 return rows; 8379 }; 8380 DayTable.prototype.buildCell = function (row, col) { 8381 return { 8382 date: this.daySeries.dates[row * this.colCnt + col] 8383 }; 8384 }; 8385 DayTable.prototype.buildHeaderDates = function () { 8386 var dates = []; 8387 for (var col = 0; col < this.colCnt; col++) { 8388 dates.push(this.cells[0][col].date); 8389 } 8390 return dates; 8391 }; 8392 DayTable.prototype.sliceRange = function (range) { 8393 var colCnt = this.colCnt; 8394 var seriesSeg = this.daySeries.sliceRange(range); 8395 var segs = []; 8396 if (seriesSeg) { 8397 var firstIndex = seriesSeg.firstIndex, lastIndex = seriesSeg.lastIndex; 8398 var index = firstIndex; 8399 while (index <= lastIndex) { 8400 var row = Math.floor(index / colCnt); 8401 var nextIndex = Math.min((row + 1) * colCnt, lastIndex + 1); 8402 segs.push({ 8403 row: row, 8404 firstCol: index % colCnt, 8405 lastCol: (nextIndex - 1) % colCnt, 8406 isStart: seriesSeg.isStart && index === firstIndex, 8407 isEnd: seriesSeg.isEnd && (nextIndex - 1) === lastIndex 8408 }); 8409 index = nextIndex; 8410 } 8411 } 8412 return segs; 8413 }; 8414 return DayTable; 8415 }()); 8416 8417 var Slicer = /** @class */ (function () { 8418 function Slicer() { 8419 this.sliceBusinessHours = memoize(this._sliceBusinessHours); 8420 this.sliceDateSelection = memoize(this._sliceDateSpan); 8421 this.sliceEventStore = memoize(this._sliceEventStore); 8422 this.sliceEventDrag = memoize(this._sliceInteraction); 8423 this.sliceEventResize = memoize(this._sliceInteraction); 8424 } 8425 Slicer.prototype.sliceProps = function (props, dateProfile, nextDayThreshold, component) { 8426 var extraArgs = []; 8427 for (var _i = 4; _i < arguments.length; _i++) { 8428 extraArgs[_i - 4] = arguments[_i]; 8429 } 8430 var eventUiBases = props.eventUiBases; 8431 var eventSegs = this.sliceEventStore.apply(this, [props.eventStore, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs)); 8432 return { 8433 dateSelectionSegs: this.sliceDateSelection.apply(this, [props.dateSelection, eventUiBases, component].concat(extraArgs)), 8434 businessHourSegs: this.sliceBusinessHours.apply(this, [props.businessHours, dateProfile, nextDayThreshold, component].concat(extraArgs)), 8435 fgEventSegs: eventSegs.fg, 8436 bgEventSegs: eventSegs.bg, 8437 eventDrag: this.sliceEventDrag.apply(this, [props.eventDrag, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs)), 8438 eventResize: this.sliceEventResize.apply(this, [props.eventResize, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs)), 8439 eventSelection: props.eventSelection 8440 }; // TODO: give interactionSegs? 8441 }; 8442 Slicer.prototype.sliceNowDate = function (// does not memoize 8443 date, component) { 8444 var extraArgs = []; 8445 for (var _i = 2; _i < arguments.length; _i++) { 8446 extraArgs[_i - 2] = arguments[_i]; 8447 } 8448 return this._sliceDateSpan.apply(this, [{ range: { start: date, end: addMs(date, 1) }, allDay: false }, 8449 {}, 8450 component].concat(extraArgs)); 8451 }; 8452 Slicer.prototype._sliceBusinessHours = function (businessHours, dateProfile, nextDayThreshold, component) { 8453 var extraArgs = []; 8454 for (var _i = 4; _i < arguments.length; _i++) { 8455 extraArgs[_i - 4] = arguments[_i]; 8456 } 8457 if (!businessHours) { 8458 return []; 8459 } 8460 return this._sliceEventStore.apply(this, [expandRecurring(businessHours, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), component.calendar), 8461 {}, 8462 dateProfile, 8463 nextDayThreshold, 8464 component].concat(extraArgs)).bg; 8465 }; 8466 Slicer.prototype._sliceEventStore = function (eventStore, eventUiBases, dateProfile, nextDayThreshold, component) { 8467 var extraArgs = []; 8468 for (var _i = 5; _i < arguments.length; _i++) { 8469 extraArgs[_i - 5] = arguments[_i]; 8470 } 8471 if (eventStore) { 8472 var rangeRes = sliceEventStore(eventStore, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold); 8473 return { 8474 bg: this.sliceEventRanges(rangeRes.bg, component, extraArgs), 8475 fg: this.sliceEventRanges(rangeRes.fg, component, extraArgs) 8476 }; 8477 } 8478 else { 8479 return { bg: [], fg: [] }; 8480 } 8481 }; 8482 Slicer.prototype._sliceInteraction = function (interaction, eventUiBases, dateProfile, nextDayThreshold, component) { 8483 var extraArgs = []; 8484 for (var _i = 5; _i < arguments.length; _i++) { 8485 extraArgs[_i - 5] = arguments[_i]; 8486 } 8487 if (!interaction) { 8488 return null; 8489 } 8490 var rangeRes = sliceEventStore(interaction.mutatedEvents, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold); 8491 return { 8492 segs: this.sliceEventRanges(rangeRes.fg, component, extraArgs), 8493 affectedInstances: interaction.affectedEvents.instances, 8494 isEvent: interaction.isEvent, 8495 sourceSeg: interaction.origSeg 8496 }; 8497 }; 8498 Slicer.prototype._sliceDateSpan = function (dateSpan, eventUiBases, component) { 8499 var extraArgs = []; 8500 for (var _i = 3; _i < arguments.length; _i++) { 8501 extraArgs[_i - 3] = arguments[_i]; 8502 } 8503 if (!dateSpan) { 8504 return []; 8505 } 8506 var eventRange = fabricateEventRange(dateSpan, eventUiBases, component.calendar); 8507 var segs = this.sliceRange.apply(this, [dateSpan.range].concat(extraArgs)); 8508 for (var _a = 0, segs_1 = segs; _a < segs_1.length; _a++) { 8509 var seg = segs_1[_a]; 8510 seg.component = component; 8511 seg.eventRange = eventRange; 8512 } 8513 return segs; 8514 }; 8515 /* 8516 "complete" seg means it has component and eventRange 8517 */ 8518 Slicer.prototype.sliceEventRanges = function (eventRanges, component, // TODO: kill 8519 extraArgs) { 8520 var segs = []; 8521 for (var _i = 0, eventRanges_1 = eventRanges; _i < eventRanges_1.length; _i++) { 8522 var eventRange = eventRanges_1[_i]; 8523 segs.push.apply(segs, this.sliceEventRange(eventRange, component, extraArgs)); 8524 } 8525 return segs; 8526 }; 8527 /* 8528 "complete" seg means it has component and eventRange 8529 */ 8530 Slicer.prototype.sliceEventRange = function (eventRange, component, // TODO: kill 8531 extraArgs) { 8532 var segs = this.sliceRange.apply(this, [eventRange.range].concat(extraArgs)); 8533 for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { 8534 var seg = segs_2[_i]; 8535 seg.component = component; 8536 seg.eventRange = eventRange; 8537 seg.isStart = eventRange.isStart && seg.isStart; 8538 seg.isEnd = eventRange.isEnd && seg.isEnd; 8539 } 8540 return segs; 8541 }; 8542 return Slicer; 8543 }()); 8544 /* 8545 for incorporating minTime/maxTime if appropriate 8546 TODO: should be part of DateProfile! 8547 TimelineDateProfile already does this btw 8548 */ 8549 function computeActiveRange(dateProfile, isComponentAllDay) { 8550 var range = dateProfile.activeRange; 8551 if (isComponentAllDay) { 8552 return range; 8553 } 8554 return { 8555 start: addMs(range.start, dateProfile.minTime.milliseconds), 8556 end: addMs(range.end, dateProfile.maxTime.milliseconds - 864e5) // 864e5 = ms in a day 8557 }; 8558 } 8559 8560 // exports 8561 // -------------------------------------------------------------------------------------------------- 8562 var version = '4.3.1'; 8563 8564 exports.Calendar = Calendar; 8565 exports.Component = Component; 8566 exports.DateComponent = DateComponent; 8567 exports.DateEnv = DateEnv; 8568 exports.DateProfileGenerator = DateProfileGenerator; 8569 exports.DayHeader = DayHeader; 8570 exports.DaySeries = DaySeries; 8571 exports.DayTable = DayTable; 8572 exports.ElementDragging = ElementDragging; 8573 exports.ElementScrollController = ElementScrollController; 8574 exports.EmitterMixin = EmitterMixin; 8575 exports.EventApi = EventApi; 8576 exports.FgEventRenderer = FgEventRenderer;
8577 exports.FillRenderer = FillRenderer; 8578 exports.Interaction = Interaction; 8579 exports.Mixin = Mixin; 8580 exports.NamedTimeZoneImpl = NamedTimeZoneImpl; 8581 exports.PositionCache = PositionCache; 8582 exports.ScrollComponent = ScrollComponent; 8583 exports.ScrollController = ScrollController; 8584 exports.Slicer = Slicer; 8585 exports.Splitter = Splitter; 8586 exports.Theme = Theme; 8587 exports.View = View; 8588 exports.WindowScrollController = WindowScrollController; 8589 exports.addDays = addDays; 8590 exports.addDurations = addDurations; 8591 exports.addMs = addMs; 8592 exports.addWeeks = addWeeks; 8593 exports.allowContextMenu = allowContextMenu; 8594 exports.allowSelection = allowSelection; 8595 exports.appendToElement = appendToElement; 8596 exports.applyAll = applyAll; 8597 exports.applyMutationToEventStore = applyMutationToEventStore; 8598 exports.applyStyle = applyStyle; 8599 exports.applyStyleProp = applyStyleProp; 8600 exports.asRoughMinutes = asRoughMinutes; 8601 exports.asRoughMs = asRoughMs; 8602 exports.asRoughSeconds = asRoughSeconds; 8603 exports.buildGotoAnchorHtml = buildGotoAnchorHtml; 8604 exports.buildSegCompareObj = buildSegCompareObj; 8605 exports.capitaliseFirstLetter = capitaliseFirstLetter; 8606 exports.combineEventUis = combineEventUis; 8607 exports.compareByFieldSpec = compareByFieldSpec; 8608 exports.compareByFieldSpecs = compareByFieldSpecs; 8609 exports.compareNumbers = compareNumbers; 8610 exports.compensateScroll = compensateScroll; 8611 exports.computeClippingRect = computeClippingRect; 8612 exports.computeEdges = computeEdges; 8613 exports.computeFallbackHeaderFormat = computeFallbackHeaderFormat; 8614 exports.computeHeightAndMargins = computeHeightAndMargins; 8615 exports.computeInnerRect = computeInnerRect; 8616 exports.computeRect = computeRect; 8617 exports.computeVisibleDayRange = computeVisibleDayRange; 8618 exports.config = config; 8619 exports.constrainPoint = constrainPoint; 8620 exports.createDuration = createDuration; 8621 exports.createElement = createElement; 8622 exports.createEmptyEventStore = createEmptyEventStore; 8623 exports.createEventInstance = createEventInstance; 8624 exports.createFormatter = createFormatter; 8625 exports.createPlugin = createPlugin; 8626 exports.cssToStr = cssToStr; 8627 exports.debounce = debounce; 8628 exports.diffDates = diffDates; 8629 exports.diffDayAndTime = diffDayAndTime; 8630 exports.diffDays = diffDays; 8631 exports.diffPoints = diffPoints; 8632 exports.diffWeeks = diffWeeks; 8633 exports.diffWholeDays = diffWholeDays; 8634 exports.diffWholeWeeks = diffWholeWeeks; 8635 exports.disableCursor = disableCursor; 8636 exports.distributeHeight = distributeHeight; 8637 exports.elementClosest = elementClosest; 8638 exports.elementMatches = elementMatches; 8639 exports.enableCursor = enableCursor; 8640 exports.eventTupleToStore = eventTupleToStore; 8641 exports.filterEventStoreDefs = filterEventStoreDefs; 8642 exports.filterHash = filterHash; 8643 exports.findChildren = findChildren; 8644 exports.findElements = findElements; 8645 exports.flexibleCompare = flexibleCompare; 8646 exports.forceClassName = forceClassName; 8647 exports.formatDate = formatDate; 8648 exports.formatIsoTimeString = formatIsoTimeString; 8649 exports.formatRange = formatRange; 8650 exports.getAllDayHtml = getAllDayHtml; 8651 exports.getClippingParents = getClippingParents; 8652 exports.getDayClasses = getDayClasses; 8653 exports.getElSeg = getElSeg; 8654 exports.getRectCenter = getRectCenter; 8655 exports.getRelevantEvents = getRelevantEvents; 8656 exports.globalDefaults = globalDefaults; 8657 exports.greatestDurationDenominator = greatestDurationDenominator; 8658 exports.hasBgRendering = hasBgRendering; 8659 exports.htmlEscape = htmlEscape; 8660 exports.htmlToElement = htmlToElement; 8661 exports.insertAfterElement = insertAfterElement; 8662 exports.interactionSettingsStore = interactionSettingsStore; 8663 exports.interactionSettingsToStore = interactionSettingsToStore; 8664 exports.intersectRanges = intersectRanges; 8665 exports.intersectRects = intersectRects; 8666 exports.isArraysEqual = isArraysEqual; 8667 exports.isDateSpansEqual = isDateSpansEqual; 8668 exports.isInt = isInt; 8669 exports.isInteractionValid = isInteractionValid; 8670 exports.isMultiDayRange = isMultiDayRange; 8671 exports.isPropsEqual = isPropsEqual; 8672 exports.isPropsValid = isPropsValid; 8673 exports.isSingleDay = isSingleDay; 8674 exports.isValidDate = isValidDate; 8675 exports.listenBySelector = listenBySelector; 8676 exports.mapHash = mapHash;
8677 exports.matchCellWidths = matchCellWidths; 8678 exports.memoize = memoize; 8679 exports.memoizeOutput = memoizeOutput; 8680 exports.memoizeRendering = memoizeRendering; 8681 exports.mergeEventStores = mergeEventStores; 8682 exports.multiplyDuration = multiplyDuration; 8683 exports.padStart = padStart; 8684 exports.parseBusinessHours = parseBusinessHours; 8685 exports.parseDragMeta = parseDragMeta; 8686 exports.parseEventDef = parseEventDef; 8687 exports.parseFieldSpecs = parseFieldSpecs; 8688 exports.parseMarker = parse; 8689 exports.pointInsideRect = pointInsideRect; 8690 exports.prependToElement = prependToElement; 8691 exports.preventContextMenu = preventContextMenu; 8692 exports.preventDefault = preventDefault; 8693 exports.preventSelection = preventSelection; 8694 exports.processScopedUiProps = processScopedUiProps; 8695 exports.rangeContainsMarker = rangeContainsMarker; 8696 exports.rangeContainsRange = rangeContainsRange; 8697 exports.rangesEqual = rangesEqual; 8698 exports.rangesIntersect = rangesIntersect; 8699 exports.refineProps = refineProps; 8700 exports.removeElement = removeElement; 8701 exports.removeExact = removeExact; 8702 exports.renderDateCell = renderDateCell; 8703 exports.requestJson = requestJson; 8704 exports.sliceEventStore = sliceEventStore; 8705 exports.startOfDay = startOfDay; 8706 exports.subtractInnerElHeight = subtractInnerElHeight; 8707 exports.translateRect = translateRect; 8708 exports.uncompensateScroll = uncompensateScroll; 8709 exports.undistributeHeight = undistributeHeight; 8710 exports.unpromisify = unpromisify; 8711 exports.version = version; 8712 exports.whenTransitionDone = whenTransitionDone; 8713 exports.wholeDivideDurations = wholeDivideDurations; 8714 8715 Object.defineProperty(exports, '__esModule', { value: true }); 8716 8717})); 8718 8719/*! 8720FullCalendar Day Grid Plugin v4.3.0 8721Docs & License: https://fullcalendar.io/ 8722(c) 2019 Adam Shaw 8723*/ 8724 8725(function (global, factory) { 8726 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core')) : 8727 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) : 8728 (global = global || self, factory(global.FullCalendarDayGrid = {}, global.FullCalendar)); 8729}(this, function (exports, core) { 'use strict'; 8730 8731 /*! ***************************************************************************** 8732 Copyright (c) Microsoft Corporation. All rights reserved. 8733 Licensed under the Apache License, Version 2.0 (the "License"); you may not use 8734 this file except in compliance with the License. You may obtain a copy of the 8735 License at http://www.apache.org/licenses/LICENSE-2.0 8736 8737 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 8738 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 8739 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 8740 MERCHANTABLITY OR NON-INFRINGEMENT. 8741 8742 See the Apache Version 2.0 License for specific language governing permissions 8743 and limitations under the License. 8744 ***************************************************************************** */ 8745 /* global Reflect, Promise */ 8746 8747 var extendStatics = function(d, b) { 8748 extendStatics = Object.setPrototypeOf || 8749 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 8750 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 8751 return extendStatics(d, b); 8752 }; 8753 8754 function __extends(d, b) { 8755 extendStatics(d, b); 8756 function __() { this.constructor = d; } 8757 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 8758 } 8759 8760 var __assign = function() { 8761 __assign = Object.assign || function __assign(t) { 8762 for (var s, i = 1, n = arguments.length; i < n; i++) { 8763 s = arguments[i]; 8764 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 8765 } 8766 return t; 8767 }; 8768 return __assign.apply(this, arguments); 8769 }; 8770 8771 var DayGridDateProfileGenerator = /** @class */ (function (_super) { 8772 __extends(DayGridDateProfileGenerator, _super); 8773 function DayGridDateProfileGenerator() { 8774 return _super !== null && _super.apply(this, arguments) || this; 8775 } 8776 // Computes the date range that will be rendered. 8777 DayGridDateProfileGenerator.prototype.buildRenderRange = function (currentRange, currentRangeUnit, isRangeAllDay) { 8778 var dateEnv = this.dateEnv; 8779 var renderRange = _super.prototype.buildRenderRange.call(this, currentRange, currentRangeUnit, isRangeAllDay); 8780 var start = renderRange.start; 8781 var end = renderRange.end; 8782 var endOfWeek; 8783 // year and month views should be aligned with weeks. this is already done for week 8784 if (/^(year|month)$/.test(currentRangeUnit)) { 8785 start = dateEnv.startOfWeek(start); 8786 // make end-of-week if not already 8787 endOfWeek = dateEnv.startOfWeek(end); 8788 if (endOfWeek.valueOf() !== end.valueOf()) { 8789 end = core.addWeeks(endOfWeek, 1); 8790 } 8791 } 8792 // ensure 6 weeks 8793 if (this.options.monthMode && 8794 this.options.fixedWeekCount) {
8795 var rowCnt = Math.ceil(// could be partial weeks due to hiddenDays 8796 core.diffWeeks(start, end)); 8797 end = core.addWeeks(end, 6 - rowCnt); 8798 } 8799 return { start: start, end: end }; 8800 }; 8801 return DayGridDateProfileGenerator; 8802 }(core.DateProfileGenerator)); 8803 8804 /* A rectangular panel that is absolutely positioned over other content 8805 ------------------------------------------------------------------------------------------------------------------------ 8806 Options: 8807 - className (string) 8808 - content (HTML string, element, or element array) 8809 - parentEl 8810 - top 8811 - left 8812 - right (the x coord of where the right edge should be. not a "CSS" right) 8813 - autoHide (boolean) 8814 - show (callback) 8815 - hide (callback) 8816 */ 8817 var Popover = /** @class */ (function () { 8818 function Popover(options) { 8819 var _this = this; 8820 this.isHidden = true; 8821 this.margin = 10; // the space required between the popover and the edges of the scroll container 8822 // Triggered when the user clicks *anywhere* in the document, for the autoHide feature 8823 this.documentMousedown = function (ev) { 8824 // only hide the popover if the click happened outside the popover 8825 if (_this.el && !_this.el.contains(ev.target)) { 8826 _this.hide(); 8827 } 8828 }; 8829 this.options = options; 8830 } 8831 // Shows the popover on the specified position. Renders it if not already 8832 Popover.prototype.show = function () { 8833 if (this.isHidden) { 8834 if (!this.el) { 8835 this.render(); 8836 } 8837 this.el.style.display = ''; 8838 this.position(); 8839 this.isHidden = false; 8840 this.trigger('show'); 8841 } 8842 }; 8843 // Hides the popover, through CSS, but does not remove it from the DOM 8844 Popover.prototype.hide = function () { 8845 if (!this.isHidden) { 8846 this.el.style.display = 'none'; 8847 this.isHidden = true; 8848 this.trigger('hide'); 8849 } 8850 }; 8851 // Creates `this.el` and renders content inside of it 8852 Popover.prototype.render = function () { 8853 var _this = this; 8854 var options = this.options; 8855 var el = this.el = core.createElement('div', { 8856 className: 'fc-popover ' + (options.className || ''), 8857 style: { 8858 top: '0', 8859 left: '0' 8860 } 8861 }); 8862 if (typeof options.content === 'function') { 8863 options.content(el); 8864 } 8865 options.parentEl.appendChild(el); 8866 // when a click happens on anything inside with a 'fc-close' className, hide the popover 8867 core.listenBySelector(el, 'click', '.fc-close', function (ev) { 8868 _this.hide(); 8869 }); 8870 if (options.autoHide) { 8871 document.addEventListener('mousedown', this.documentMousedown); 8872 } 8873 }; 8874 // Hides and unregisters any handlers 8875 Popover.prototype.destroy = function () { 8876 this.hide(); 8877 if (this.el) { 8878 core.removeElement(this.el); 8879 this.el = null; 8880 } 8881 document.removeEventListener('mousedown', this.documentMousedown); 8882 }; 8883 // Positions the popover optimally, using the top/left/right options 8884 Popover.prototype.position = function () { 8885 var options = this.options; 8886 var el = this.el; 8887 var elDims = el.getBoundingClientRect(); // only used for width,height 8888 var origin = core.computeRect(el.offsetParent); 8889 var clippingRect = core.computeClippingRect(options.parentEl); 8890 var top; // the "position" (not "offset") values for the popover 8891 var left; // 8892 // compute top and left 8893 top = options.top || 0; 8894 if (options.left !== undefined) { 8895 left = options.left; 8896 } 8897 else if (options.right !== undefined) { 8898 left = options.right - elDims.width; // derive the left value from the right value 8899 } 8900 else { 8901 left = 0; 8902 } 8903 // constrain to the view port. if constrained by two edges, give precedence to top/left 8904 top = Math.min(top, clippingRect.bottom - elDims.height - this.margin); 8905 top = Math.max(top, clippingRect.top + this.margin); 8906 left = Math.min(left, clippingRect.right - elDims.width - this.margin); 8907 left = Math.max(left, clippingRect.left + this.margin); 8908 core.applyStyle(el, { 8909 top: top - origin.top, 8910 left: left - origin.left 8911 }); 8912 }; 8913 // Triggers a callback. Calls a function in the option hash of the same name. 8914 // Arguments beyond the first `name` are forwarded on. 8915 // TODO: better code reuse for this. Repeat code 8916 // can kill this??? 8917 Popover.prototype.trigger = function (name) { 8918 if (this.options[name]) { 8919 this.options[name].apply(this, Array.prototype.slice.call(arguments, 1)); 8920 } 8921 }; 8922 return Popover; 8923 }()); 8924 8925 /* Event-rendering methods for the DayGrid class 8926 ----------------------------------------------------------------------------------------------------------------------*/ 8927 // "Simple" is bad a name. has nothing to do with SimpleDayGrid 8928 var SimpleDayGridEventRenderer = /** @class */ (function (_super) { 8929 __extends(SimpleDayGridEventRenderer, _super); 8930 function SimpleDayGridEventRenderer() { 8931 return _super !== null && _super.apply(this, arguments) || this; 8932 } 8933 // Builds the HTML to be used for the default element for an individual segment 8934 SimpleDayGridEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) { 8935 var _a = this.context, view = _a.view, options = _a.options; 8936 var eventRange = seg.eventRange; 8937 var eventDef = eventRange.def; 8938 var eventUi = eventRange.ui; 8939 var allDay = eventDef.allDay; 8940 var isDraggable = view.computeEventDraggable(eventDef, eventUi); 8941 var isResizableFromStart = allDay && seg.isStart && view.computeEventStartResizable(eventDef, eventUi); 8942 var isResizableFromEnd = allDay && seg.isEnd && view.computeEventEndResizable(eventDef, eventUi);
8943 var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo); 8944 var skinCss = core.cssToStr(this.getSkinCss(eventUi)); 8945 var timeHtml = ''; 8946 var timeText; 8947 var titleHtml; 8948 classes.unshift('fc-day-grid-event', 'fc-h-event'); 8949 // Only display a timed events time if it is the starting segment 8950 if (seg.isStart) { 8951 timeText = this.getTimeText(eventRange); 8952 if (timeText) { 8953 timeHtml = '<span class="fc-time">' + core.htmlEscape(timeText) + '</span>'; 8954 } 8955 } 8956 titleHtml = 8957 '<span class="fc-title">' + 8958 (core.htmlEscape(eventDef.title || '') || ' ') + // we always want one line of height 8959 '</span>'; 8960 return '<a class="' + classes.join(' ') + '"' + 8961 (eventDef.url ? 8962 ' href="' + core.htmlEscape(eventDef.url) + '"' : 8963 '') + 8964 (skinCss ? 8965 ' style="' + skinCss + '"' : 8966 '') + 8967 '>' + 8968 '<div class="fc-content">' + 8969 (options.dir === 'rtl' ? 8970 titleHtml + ' ' + timeHtml : // put a natural space in between 8971 timeHtml + ' ' + titleHtml // 8972 ) + 8973 '</div>' + 8974 (isResizableFromStart ? 8975 '<div class="fc-resizer fc-start-resizer"></div>' : 8976 '') + 8977 (isResizableFromEnd ? 8978 '<div class="fc-resizer fc-end-resizer"></div>' : 8979 '') + 8980 '</a>'; 8981 }; 8982 // Computes a default event time formatting string if `eventTimeFormat` is not explicitly defined 8983 SimpleDayGridEventRenderer.prototype.computeEventTimeFormat = function () { 8984 return { 8985 hour: 'numeric', 8986 minute: '2-digit', 8987 omitZeroMinute: true, 8988 meridiem: 'narrow' 8989 }; 8990 }; 8991 SimpleDayGridEventRenderer.prototype.computeDisplayEventEnd = function () { 8992 return false; // TODO: somehow consider the originating DayGrid's column count 8993 }; 8994 return SimpleDayGridEventRenderer; 8995 }(core.FgEventRenderer)); 8996 8997 /* Event-rendering methods for the DayGrid class 8998 ----------------------------------------------------------------------------------------------------------------------*/ 8999 var DayGridEventRenderer = /** @class */ (function (_super) { 9000 __extends(DayGridEventRenderer, _super); 9001 function DayGridEventRenderer(dayGrid) { 9002 var _this = _super.call(this, dayGrid.context) || this; 9003 _this.dayGrid = dayGrid; 9004 return _this; 9005 } 9006 // Renders the given foreground event segments onto the grid 9007 DayGridEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 9008 var rowStructs = this.rowStructs = this.renderSegRows(segs); 9009 // append to each row's content skeleton 9010 this.dayGrid.rowEls.forEach(function (rowNode, i) { 9011 rowNode.querySelector('.fc-content-skeleton > table').appendChild(rowStructs[i].tbodyEl); 9012 }); 9013 // removes the "more.." events popover 9014 if (!mirrorInfo) { 9015 this.dayGrid.removeSegPopover(); 9016 } 9017 }; 9018 // Unrenders all currently rendered foreground event segments 9019 DayGridEventRenderer.prototype.detachSegs = function () { 9020 var rowStructs = this.rowStructs || []; 9021 var rowStruct; 9022 while ((rowStruct = rowStructs.pop())) { 9023 core.removeElement(rowStruct.tbodyEl); 9024 } 9025 this.rowStructs = null; 9026 }; 9027 // Uses the given events array to generate <tbody> elements that should be appended to each row's content skeleton. 9028 // Returns an array of rowStruct objects (see the bottom of `renderSegRow`). 9029 // PRECONDITION: each segment shoud already have a rendered and assigned `.el` 9030 DayGridEventRenderer.prototype.renderSegRows = function (segs) { 9031 var rowStructs = []; 9032 var segRows; 9033 var row; 9034 segRows = this.groupSegRows(segs); // group into nested arrays 9035 // iterate each row of segment groupings 9036 for (row = 0; row < segRows.length; row++) { 9037 rowStructs.push(this.renderSegRow(row, segRows[row])); 9038 } 9039 return rowStructs; 9040 }; 9041 // Given a row # and an array of segments all in the same row, render a <tbody> element, a skeleton that contains 9042 // the segments. Returns object with a bunch of internal data about how the render was calculated. 9043 // NOTE: modifies rowSegs 9044 DayGridEventRenderer.prototype.renderSegRow = function (row, rowSegs) { 9045 var dayGrid = this.dayGrid; 9046 var colCnt = dayGrid.colCnt, isRtl = dayGrid.isRtl; 9047 var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels 9048 var levelCnt = Math.max(1, segLevels.length); // ensure at least one level 9049 var tbody = document.createElement('tbody'); 9050 var segMatrix = []; // lookup for which segments are rendered into which level+col cells 9051 var cellMatrix = []; // lookup for all <td> elements of the level+col matrix 9052 var loneCellMatrix = []; // lookup for <td> elements that only take up a single column 9053 var i; 9054 var levelSegs; 9055 var col; 9056 var tr; 9057 var j; 9058 var seg; 9059 var td; 9060 // populates empty cells from the current column (`col`) to `endCol` 9061 function emptyCellsUntil(endCol) { 9062 while (col < endCol) { 9063 // try to grab a cell from the level above and extend its rowspan. otherwise, create a fresh cell 9064 td = (loneCellMatrix[i - 1] || [])[col]; 9065 if (td) { 9066 td.rowSpan = (td.rowSpan || 1) + 1; 9067 } 9068 else { 9069 td = document.createElement('td'); 9070 tr.appendChild(td); 9071 } 9072 cellMatrix[i][col] = td; 9073 loneCellMatrix[i][col] = td; 9074 col++; 9075 } 9076 } 9077 for (i = 0; i < levelCnt; i++) { // iterate through all levels 9078 levelSegs = segLevels[i]; 9079 col = 0; 9080 tr = document.createElement('tr'); 9081 segMatrix.push([]); 9082 cellMatrix.push([]); 9083 loneCellMatrix.push([]); 9084 // levelCnt might be 1 even though there are no actual levels. protect against this. 9085 // this single empty row is useful for styling. 9086 if (levelSegs) { 9087 for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level 9088 seg = levelSegs[j]; 9089 var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; 9090 var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; 9091 emptyCellsUntil(leftCol); 9092 // create a container that occupies or more columns. append the event element. 9093 td = core.createElement('td', { className: 'fc-event-container' }, seg.el); 9094 if (leftCol !== rightCol) { 9095 td.colSpan = rightCol - leftCol + 1; 9096 } 9097 else { // a single-column segment 9098 loneCellMatrix[i][col] = td; 9099 } 9100 while (col <= rightCol) { 9101 cellMatrix[i][col] = td; 9102 segMatrix[i][col] = seg; 9103 col++; 9104 } 9105 tr.appendChild(td); 9106 } 9107 } 9108 emptyCellsUntil(colCnt); // finish off the row 9109 var introHtml = dayGrid.renderProps.renderIntroHtml(); 9110 if (introHtml) { 9111 if (dayGrid.isRtl) { 9112 core.appendToElement(tr, introHtml); 9113 } 9114 else { 9115 core.prependToElement(tr, introHtml); 9116 } 9117 } 9118 tbody.appendChild(tr); 9119 } 9120 return { 9121 row: row, 9122 tbodyEl: tbody, 9123 cellMatrix: cellMatrix, 9124 segMatrix: segMatrix, 9125 segLevels: segLevels, 9126 segs: rowSegs 9127 }; 9128 }; 9129 // Stacks a flat array of segments, which are all assumed to be in the same row, into subarrays of vertical levels. 9130 // NOTE: modifies segs 9131 DayGridEventRenderer.prototype.buildSegLevels = function (segs) { 9132 var _a = this.dayGrid, isRtl = _a.isRtl, colCnt = _a.colCnt; 9133 var levels = []; 9134 var i; 9135 var seg; 9136 var j; 9137 // Give preference to elements with certain criteria, so they have 9138 // a chance to be closer to the top. 9139 segs = this.sortEventSegs(segs); 9140 for (i = 0; i < segs.length; i++) { 9141 seg = segs[i]; 9142 // loop through levels, starting with the topmost, until the segment doesn't collide with other segments 9143 for (j = 0; j < levels.length; j++) {
9144 if (!isDaySegCollision(seg, levels[j])) { 9145 break; 9146 } 9147 } 9148 // `j` now holds the desired subrow index 9149 seg.level = j; 9150 seg.leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; // for sorting only 9151 seg.rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol // for sorting only 9152 ; 9153 (levels[j] || (levels[j] = [])).push(seg); 9154 } 9155 // order segments left-to-right. very important if calendar is RTL 9156 for (j = 0; j < levels.length; j++) { 9157 levels[j].sort(compareDaySegCols); 9158 } 9159 return levels; 9160 }; 9161 // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's row 9162 DayGridEventRenderer.prototype.groupSegRows = function (segs) { 9163 var segRows = []; 9164 var i; 9165 for (i = 0; i < this.dayGrid.rowCnt; i++) { 9166 segRows.push([]); 9167 } 9168 for (i = 0; i < segs.length; i++) { 9169 segRows[segs[i].row].push(segs[i]); 9170 } 9171 return segRows; 9172 }; 9173 // Computes a default `displayEventEnd` value if one is not expliclty defined 9174 DayGridEventRenderer.prototype.computeDisplayEventEnd = function () { 9175 return this.dayGrid.colCnt === 1; // we'll likely have space if there's only one day 9176 }; 9177 return DayGridEventRenderer; 9178 }(SimpleDayGridEventRenderer)); 9179 // Computes whether two segments' columns collide. They are assumed to be in the same row. 9180 function isDaySegCollision(seg, otherSegs) { 9181 var i; 9182 var otherSeg; 9183 for (i = 0; i < otherSegs.length; i++) { 9184 otherSeg = otherSegs[i]; 9185 if (otherSeg.firstCol <= seg.lastCol && 9186 otherSeg.lastCol >= seg.firstCol) { 9187 return true; 9188 } 9189 } 9190 return false; 9191 } 9192 // A cmp function for determining the leftmost event 9193 function compareDaySegCols(a, b) { 9194 return a.leftCol - b.leftCol; 9195 } 9196 9197 var DayGridMirrorRenderer = /** @class */ (function (_super) { 9198 __extends(DayGridMirrorRenderer, _super); 9199 function DayGridMirrorRenderer() { 9200 return _super !== null && _super.apply(this, arguments) || this; 9201 } 9202 DayGridMirrorRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 9203 var sourceSeg = mirrorInfo.sourceSeg; 9204 var rowStructs = this.rowStructs = this.renderSegRows(segs); 9205 // inject each new event skeleton into each associated row 9206 this.dayGrid.rowEls.forEach(function (rowNode, row) { 9207 var skeletonEl = core.htmlToElement('<div class="fc-mirror-skeleton"><table></table></div>'); // will be absolutely positioned 9208 var skeletonTopEl; 9209 var skeletonTop; 9210 // If there is an original segment, match the top position. Otherwise, put it at the row's top level 9211 if (sourceSeg && sourceSeg.row === row) { 9212 skeletonTopEl = sourceSeg.el; 9213 } 9214 else { 9215 skeletonTopEl = rowNode.querySelector('.fc-content-skeleton tbody'); 9216 if (!skeletonTopEl) { // when no events 9217 skeletonTopEl = rowNode.querySelector('.fc-content-skeleton table'); 9218 } 9219 } 9220 skeletonTop = skeletonTopEl.getBoundingClientRect().top - 9221 rowNode.getBoundingClientRect().top; // the offsetParent origin 9222 skeletonEl.style.top = skeletonTop + 'px'; 9223 skeletonEl.querySelector('table').appendChild(rowStructs[row].tbodyEl); 9224 rowNode.appendChild(skeletonEl); 9225 }); 9226 }; 9227 return DayGridMirrorRenderer; 9228 }(DayGridEventRenderer)); 9229 9230 var EMPTY_CELL_HTML = '<td style="pointer-events:none"></td>'; 9231 var DayGridFillRenderer = /** @class */ (function (_super) { 9232 __extends(DayGridFillRenderer, _super); 9233 function DayGridFillRenderer(dayGrid) { 9234 var _this = _super.call(this, dayGrid.context) || this; 9235 _this.fillSegTag = 'td'; // override the default tag name 9236 _this.dayGrid = dayGrid; 9237 return _this; 9238 } 9239 DayGridFillRenderer.prototype.renderSegs = function (type, segs) { 9240 // don't render timed background events 9241 if (type === 'bgEvent') { 9242 segs = segs.filter(function (seg) { 9243 return seg.eventRange.def.allDay; 9244 }); 9245 }
9246 _super.prototype.renderSegs.call(this, type, segs); 9247 }; 9248 DayGridFillRenderer.prototype.attachSegs = function (type, segs) { 9249 var els = []; 9250 var i; 9251 var seg; 9252 var skeletonEl; 9253 for (i = 0; i < segs.length; i++) { 9254 seg = segs[i]; 9255 skeletonEl = this.renderFillRow(type, seg); 9256 this.dayGrid.rowEls[seg.row].appendChild(skeletonEl); 9257 els.push(skeletonEl); 9258 } 9259 return els; 9260 }; 9261 // Generates the HTML needed for one row of a fill. Requires the seg's el to be rendered. 9262 DayGridFillRenderer.prototype.renderFillRow = function (type, seg) { 9263 var dayGrid = this.dayGrid; 9264 var colCnt = dayGrid.colCnt, isRtl = dayGrid.isRtl; 9265 var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; 9266 var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; 9267 var startCol = leftCol; 9268 var endCol = rightCol + 1; 9269 var className; 9270 var skeletonEl; 9271 var trEl; 9272 if (type === 'businessHours') { 9273 className = 'bgevent'; 9274 } 9275 else { 9276 className = type.toLowerCase(); 9277 } 9278 skeletonEl = core.htmlToElement('<div class="fc-' + className + '-skeleton">' + 9279 '<table><tr></tr></table>' + 9280 '</div>'); 9281 trEl = skeletonEl.getElementsByTagName('tr')[0]; 9282 if (startCol > 0) { 9283 core.appendToElement(trEl, 9284 // will create (startCol + 1) td's 9285 new Array(startCol + 1).join(EMPTY_CELL_HTML)); 9286 } 9287 seg.el.colSpan = endCol - startCol; 9288 trEl.appendChild(seg.el); 9289 if (endCol < colCnt) { 9290 core.appendToElement(trEl, 9291 // will create (colCnt - endCol) td's 9292 new Array(colCnt - endCol + 1).join(EMPTY_CELL_HTML)); 9293 } 9294 var introHtml = dayGrid.renderProps.renderIntroHtml(); 9295 if (introHtml) { 9296 if (dayGrid.isRtl) { 9297 core.appendToElement(trEl, introHtml); 9298 } 9299 else { 9300 core.prependToElement(trEl, introHtml); 9301 } 9302 } 9303 return skeletonEl; 9304 }; 9305 return DayGridFillRenderer; 9306 }(core.FillRenderer)); 9307 9308 var DayTile = /** @class */ (function (_super) { 9309 __extends(DayTile, _super); 9310 function DayTile(context, el) { 9311 var _this = _super.call(this, context, el) || this; 9312 var eventRenderer = _this.eventRenderer = new DayTileEventRenderer(_this); 9313 var renderFrame = _this.renderFrame = core.memoizeRendering(_this._renderFrame); 9314 _this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderFrame]); 9315 _this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); 9316 _this.renderEventDrag = core.memoizeRendering(eventRenderer.hideByHash.bind(eventRenderer), eventRenderer.showByHash.bind(eventRenderer), [renderFrame]); 9317 _this.renderEventResize = core.memoizeRendering(eventRenderer.hideByHash.bind(eventRenderer), eventRenderer.showByHash.bind(eventRenderer), [renderFrame]); 9318 context.calendar.registerInteractiveComponent(_this, { 9319 el: _this.el, 9320 useEventCenter: false 9321 }); 9322 return _this; 9323 } 9324 DayTile.prototype.render = function (props) { 9325 this.renderFrame(props.date); 9326 this.renderFgEvents(props.fgSegs); 9327 this.renderEventSelection(props.eventSelection); 9328 this.renderEventDrag(props.eventDragInstances); 9329 this.renderEventResize(props.eventResizeInstances); 9330 }; 9331 DayTile.prototype.destroy = function () { 9332 _super.prototype.destroy.call(this); 9333 this.renderFrame.unrender(); // should unrender everything else 9334 this.calendar.unregisterInteractiveComponent(this); 9335 }; 9336 DayTile.prototype._renderFrame = function (date) { 9337 var _a = this, theme = _a.theme, dateEnv = _a.dateEnv; 9338 var title = dateEnv.format(date, core.createFormatter(this.opt('dayPopoverFormat')) // TODO: cache 9339 ); 9340 this.el.innerHTML = 9341 '<div class="fc-header ' + theme.getClass('popoverHeader') + '">' + 9342 '<span class="fc-title">' + 9343 core.htmlEscape(title) + 9344 '</span>' + 9345 '<span class="fc-close ' + theme.getIconClass('close') + '"></span>' + 9346 '</div>' + 9347 '<div class="fc-body ' + theme.getClass('popoverContent') + '">' + 9348 '<div class="fc-event-container"></div>' + 9349 '</div>'; 9350 this.segContainerEl = this.el.querySelector('.fc-event-container'); 9351 }; 9352 DayTile.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { 9353 var date = this.props.date; // HACK 9354 if (positionLeft < elWidth && positionTop < elHeight) { 9355 return { 9356 component: this, 9357 dateSpan: { 9358 allDay: true, 9359 range: { start: date, end: core.addDays(date, 1) } 9360 }, 9361 dayEl: this.el, 9362 rect: { 9363 left: 0, 9364 top: 0, 9365 right: elWidth, 9366 bottom: elHeight 9367 }, 9368 layer: 1 9369 }; 9370 } 9371 }; 9372 return DayTile; 9373 }(core.DateComponent)); 9374 var DayTileEventRenderer = /** @class */ (function (_super) { 9375 __extends(DayTileEventRenderer, _super); 9376 function DayTileEventRenderer(dayTile) { 9377 var _this = _super.call(this, dayTile.context) || this; 9378 _this.dayTile = dayTile; 9379 return _this; 9380 } 9381 DayTileEventRenderer.prototype.attachSegs = function (segs) { 9382 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 9383 var seg = segs_1[_i]; 9384 this.dayTile.segContainerEl.appendChild(seg.el); 9385 } 9386 }; 9387 DayTileEventRenderer.prototype.detachSegs = function (segs) { 9388 for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { 9389 var seg = segs_2[_i]; 9390 core.removeElement(seg.el); 9391 } 9392 }; 9393 return DayTileEventRenderer; 9394 }(SimpleDayGridEventRenderer)); 9395 9396 var DayBgRow = /** @class */ (function () { 9397 function DayBgRow(context) { 9398 this.context = context; 9399 } 9400 DayBgRow.prototype.renderHtml = function (props) { 9401 var parts = []; 9402 if (props.renderIntroHtml) { 9403 parts.push(props.renderIntroHtml()); 9404 } 9405 for (var _i = 0, _a = props.cells; _i < _a.length; _i++) { 9406 var cell = _a[_i]; 9407 parts.push(renderCellHtml(cell.date, props.dateProfile, this.context, cell.htmlAttrs)); 9408 } 9409 if (!props.cells.length) { 9410 parts.push('<td class="fc-day ' + this.context.theme.getClass('widgetContent') + '"></td>'); 9411 } 9412 if (this.context.options.dir === 'rtl') { 9413 parts.reverse(); 9414 } 9415 return '<tr>' + parts.join('') + '</tr>'; 9416 }; 9417 return DayBgRow; 9418 }()); 9419 function renderCellHtml(date, dateProfile, context, otherAttrs) { 9420 var dateEnv = context.dateEnv, theme = context.theme; 9421 var isDateValid = core.rangeContainsMarker(dateProfile.activeRange, date); // TODO: called too frequently. cache somehow. 9422 var classes = core.getDayClasses(date, dateProfile, context); 9423 classes.unshift('fc-day', theme.getClass('widgetContent')); 9424 return '<td class="' + classes.join(' ') + '"' + 9425 (isDateValid ? 9426 ' data-date="' + dateEnv.formatIso(date, { omitTime: true }) + '"' : 9427 '') + 9428 (otherAttrs ?
9429 ' ' + otherAttrs : 9430 '') + 9431 '></td>'; 9432 } 9433 9434 var DAY_NUM_FORMAT = core.createFormatter({ day: 'numeric' }); 9435 var WEEK_NUM_FORMAT = core.createFormatter({ week: 'numeric' }); 9436 var DayGrid = /** @class */ (function (_super) { 9437 __extends(DayGrid, _super); 9438 function DayGrid(context, el, renderProps) { 9439 var _this = _super.call(this, context, el) || this; 9440 _this.bottomCoordPadding = 0; // hack for extending the hit area for the last row of the coordinate grid 9441 _this.isCellSizesDirty = false; 9442 var eventRenderer = _this.eventRenderer = new DayGridEventRenderer(_this); 9443 var fillRenderer = _this.fillRenderer = new DayGridFillRenderer(_this); 9444 _this.mirrorRenderer = new DayGridMirrorRenderer(_this); 9445 var renderCells = _this.renderCells = core.memoizeRendering(_this._renderCells, _this._unrenderCells); 9446 _this.renderBusinessHours = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'), [renderCells]); 9447 _this.renderDateSelection = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'highlight'), fillRenderer.unrender.bind(fillRenderer, 'highlight'), [renderCells]); 9448 _this.renderBgEvents = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'), [renderCells]); 9449 _this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderCells]); 9450 _this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); 9451 _this.renderEventDrag = core.memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag, [renderCells]); 9452 _this.renderEventResize = core.memoizeRendering(_this._renderEventResize, _this._unrenderEventResize, [renderCells]); 9453 _this.renderProps = renderProps; 9454 return _this; 9455 } 9456 DayGrid.prototype.render = function (props) { 9457 var cells = props.cells; 9458 this.rowCnt = cells.length; 9459 this.colCnt = cells[0].length; 9460 this.renderCells(cells, props.isRigid); 9461 this.renderBusinessHours(props.businessHourSegs); 9462 this.renderDateSelection(props.dateSelectionSegs); 9463 this.renderBgEvents(props.bgEventSegs); 9464 this.renderFgEvents(props.fgEventSegs); 9465 this.renderEventSelection(props.eventSelection); 9466 this.renderEventDrag(props.eventDrag); 9467 this.renderEventResize(props.eventResize); 9468 if (this.segPopoverTile) { 9469 this.updateSegPopoverTile(); 9470 } 9471 }; 9472 DayGrid.prototype.destroy = function () { 9473 _super.prototype.destroy.call(this); 9474 this.renderCells.unrender(); // will unrender everything else 9475 }; 9476 DayGrid.prototype.getCellRange = function (row, col) { 9477 var start = this.props.cells[row][col].date; 9478 var end = core.addDays(start, 1); 9479 return { start: start, end: end }; 9480 }; 9481 DayGrid.prototype.updateSegPopoverTile = function (date, segs) { 9482 var ownProps = this.props; 9483 this.segPopoverTile.receiveProps({ 9484 date: date || this.segPopoverTile.props.date, 9485 fgSegs: segs || this.segPopoverTile.props.fgSegs, 9486 eventSelection: ownProps.eventSelection, 9487 eventDragInstances: ownProps.eventDrag ? ownProps.eventDrag.affectedInstances : null, 9488 eventResizeInstances: ownProps.eventResize ? ownProps.eventResize.affectedInstances : null 9489 }); 9490 }; 9491 /* Date Rendering 9492 ------------------------------------------------------------------------------------------------------------------*/ 9493 DayGrid.prototype._renderCells = function (cells, isRigid) { 9494 var _a = this, view = _a.view, dateEnv = _a.dateEnv; 9495 var _b = this, rowCnt = _b.rowCnt, colCnt = _b.colCnt; 9496 var html = ''; 9497 var row; 9498 var col; 9499 for (row = 0; row < rowCnt; row++) { 9500 html += this.renderDayRowHtml(row, isRigid); 9501 } 9502 this.el.innerHTML = html; 9503 this.rowEls = core.findElements(this.el, '.fc-row'); 9504 this.cellEls = core.findElements(this.el, '.fc-day, .fc-disabled-day'); 9505 if (this.isRtl) { 9506 this.cellEls.reverse(); 9507 } 9508 this.rowPositions = new core.PositionCache(this.el, this.rowEls, false, true // vertical 9509 ); 9510 this.colPositions = new core.PositionCache(this.el, this.cellEls.slice(0, colCnt), // only the first row 9511 true, false // horizontal 9512 ); 9513 // trigger dayRender with each cell's element 9514 for (row = 0; row < rowCnt; row++) { 9515 for (col = 0; col < colCnt; col++) { 9516 this.publiclyTrigger('dayRender', [ 9517 { 9518 date: dateEnv.toDate(cells[row][col].date), 9519 el: this.getCellEl(row, col), 9520 view: view 9521 } 9522 ]); 9523 } 9524 } 9525 this.isCellSizesDirty = true; 9526 }; 9527 DayGrid.prototype._unrenderCells = function () { 9528 this.removeSegPopover(); 9529 }; 9530 // Generates the HTML for a single row, which is a div that wraps a table. 9531 // `row` is the row number. 9532 DayGrid.prototype.renderDayRowHtml = function (row, isRigid) { 9533 var theme = this.theme; 9534 var classes = ['fc-row', 'fc-week', theme.getClass('dayRow')]; 9535 if (isRigid) { 9536 classes.push('fc-rigid'); 9537 } 9538 var bgRow = new DayBgRow(this.context); 9539 return '' + 9540 '<div class="' + classes.join(' ') + '">' + 9541 '<div class="fc-bg">' + 9542 '<table class="' + theme.getClass('tableGrid') + '">' + 9543 bgRow.renderHtml({ 9544 cells: this.props.cells[row], 9545 dateProfile: this.props.dateProfile, 9546 renderIntroHtml: this.renderProps.renderBgIntroHtml 9547 }) + 9548 '</table>' + 9549 '</div>' + 9550 '<div class="fc-content-skeleton">' + 9551 '<table>' + 9552 (this.getIsNumbersVisible() ? 9553 '<thead>' + 9554 this.renderNumberTrHtml(row) + 9555 '</thead>' : 9556 '') + 9557 '</table>' + 9558 '</div>' + 9559 '</div>'; 9560 }; 9561 DayGrid.prototype.getIsNumbersVisible = function () { 9562 return this.getIsDayNumbersVisible() || 9563 this.renderProps.cellWeekNumbersVisible || 9564 this.renderProps.colWeekNumbersVisible; 9565 }; 9566 DayGrid.prototype.getIsDayNumbersVisible = function () { 9567 return this.rowCnt > 1; 9568 }; 9569 /* Grid Number Rendering 9570 ------------------------------------------------------------------------------------------------------------------*/ 9571 DayGrid.prototype.renderNumberTrHtml = function (row) { 9572 var intro = this.renderProps.renderNumberIntroHtml(row, this); 9573 return '' + 9574 '<tr>' + 9575 (this.isRtl ? '' : intro) + 9576 this.renderNumberCellsHtml(row) + 9577 (this.isRtl ? intro : '') + 9578 '</tr>'; 9579 }; 9580 DayGrid.prototype.renderNumberCellsHtml = function (row) { 9581 var htmls = []; 9582 var col; 9583 var date; 9584 for (col = 0; col < this.colCnt; col++) { 9585 date = this.props.cells[row][col].date; 9586 htmls.push(this.renderNumberCellHtml(date)); 9587 } 9588 if (this.isRtl) { 9589 htmls.reverse(); 9590 } 9591 return htmls.join(''); 9592 }; 9593 // Generates the HTML for the <td>s of the "number" row in the DayGrid's content skeleton. 9594 // The number row will only exist if either day numbers or week numbers are turned on. 9595 DayGrid.prototype.renderNumberCellHtml = function (date) { 9596 var _a = this, view = _a.view, dateEnv = _a.dateEnv; 9597 var html = ''; 9598 var isDateValid = core.rangeContainsMarker(this.props.dateProfile.activeRange, date); // TODO: called too frequently. cache somehow. 9599 var isDayNumberVisible = this.getIsDayNumbersVisible() && isDateValid; 9600 var classes; 9601 var weekCalcFirstDow; 9602 if (!isDayNumberVisible && !this.renderProps.cellWeekNumbersVisible) { 9603 // no numbers in day cell (week number must be along the side) 9604 return '<td></td>'; // will create an empty space above events :( 9605 } 9606 classes = core.getDayClasses(date, this.props.dateProfile, this.context); 9607 classes.unshift('fc-day-top'); 9608 if (this.renderProps.cellWeekNumbersVisible) { 9609 weekCalcFirstDow = dateEnv.weekDow; 9610 } 9611 html += '<td class="' + classes.join(' ') + '"' + 9612 (isDateValid ? 9613 ' data-date="' + dateEnv.formatIso(date, { omitTime: true }) + '"' : 9614 '') + 9615 '>'; 9616 if (this.renderProps.cellWeekNumbersVisible && (date.getUTCDay() === weekCalcFirstDow)) { 9617 html += core.buildGotoAnchorHtml(view, { date: date, type: 'week' }, { 'class': 'fc-week-number' }, dateEnv.format(date, WEEK_NUM_FORMAT) // inner HTML 9618 ); 9619 } 9620 if (isDayNumberVisible) { 9621 html += core.buildGotoAnchorHtml(view, date, { 'class': 'fc-day-number' }, dateEnv.format(date, DAY_NUM_FORMAT) // inner HTML 9622 ); 9623 } 9624 html += '</td>'; 9625 return html; 9626 }; 9627 /* Sizing 9628 ------------------------------------------------------------------------------------------------------------------*/ 9629 DayGrid.prototype.updateSize = function (isResize) { 9630 var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer; 9631 if (isResize || 9632 this.isCellSizesDirty || 9633 this.view.calendar.isEventsUpdated // hack 9634 ) { 9635 this.buildPositionCaches(); 9636 this.isCellSizesDirty = false;
9637 } 9638 fillRenderer.computeSizes(isResize); 9639 eventRenderer.computeSizes(isResize); 9640 mirrorRenderer.computeSizes(isResize); 9641 fillRenderer.assignSizes(isResize); 9642 eventRenderer.assignSizes(isResize); 9643 mirrorRenderer.assignSizes(isResize); 9644 }; 9645 DayGrid.prototype.buildPositionCaches = function () { 9646 this.buildColPositions(); 9647 this.buildRowPositions(); 9648 }; 9649 DayGrid.prototype.buildColPositions = function () { 9650 this.colPositions.build(); 9651 }; 9652 DayGrid.prototype.buildRowPositions = function () { 9653 this.rowPositions.build(); 9654 this.rowPositions.bottoms[this.rowCnt - 1] += this.bottomCoordPadding; // hack 9655 }; 9656 /* Hit System 9657 ------------------------------------------------------------------------------------------------------------------*/ 9658 DayGrid.prototype.positionToHit = function (leftPosition, topPosition) { 9659 var _a = this, colPositions = _a.colPositions, rowPositions = _a.rowPositions; 9660 var col = colPositions.leftToIndex(leftPosition); 9661 var row = rowPositions.topToIndex(topPosition); 9662 if (row != null && col != null) { 9663 return { 9664 row: row, 9665 col: col, 9666 dateSpan: { 9667 range: this.getCellRange(row, col), 9668 allDay: true 9669 }, 9670 dayEl: this.getCellEl(row, col), 9671 relativeRect: { 9672 left: colPositions.lefts[col], 9673 right: colPositions.rights[col], 9674 top: rowPositions.tops[row], 9675 bottom: rowPositions.bottoms[row] 9676 } 9677 }; 9678 } 9679 }; 9680 /* Cell System 9681 ------------------------------------------------------------------------------------------------------------------*/ 9682 // FYI: the first column is the leftmost column, regardless of date 9683 DayGrid.prototype.getCellEl = function (row, col) { 9684 return this.cellEls[row * this.colCnt + col]; 9685 }; 9686 /* Event Drag Visualization 9687 ------------------------------------------------------------------------------------------------------------------*/ 9688 DayGrid.prototype._renderEventDrag = function (state) { 9689 if (state) { 9690 this.eventRenderer.hideByHash(state.affectedInstances); 9691 this.fillRenderer.renderSegs('highlight', state.segs); 9692 } 9693 }; 9694 DayGrid.prototype._unrenderEventDrag = function (state) { 9695 if (state) { 9696 this.eventRenderer.showByHash(state.affectedInstances); 9697 this.fillRenderer.unrender('highlight'); 9698 } 9699 }; 9700 /* Event Resize Visualization 9701 ------------------------------------------------------------------------------------------------------------------*/ 9702 DayGrid.prototype._renderEventResize = function (state) { 9703 if (state) { 9704 this.eventRenderer.hideByHash(state.affectedInstances); 9705 this.fillRenderer.renderSegs('highlight', state.segs); 9706 this.mirrorRenderer.renderSegs(state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 9707 } 9708 }; 9709 DayGrid.prototype._unrenderEventResize = function (state) { 9710 if (state) { 9711 this.eventRenderer.showByHash(state.affectedInstances); 9712 this.fillRenderer.unrender('highlight'); 9713 this.mirrorRenderer.unrender(state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 9714 } 9715 }; 9716 /* More+ Link Popover 9717 ------------------------------------------------------------------------------------------------------------------*/ 9718 DayGrid.prototype.removeSegPopover = function () { 9719 if (this.segPopover) { 9720 this.segPopover.hide(); // in handler, will call segPopover's removeElement 9721 } 9722 }; 9723 // Limits the number of "levels" (vertically stacking layers of events) for each row of the grid. 9724 // `levelLimit` can be false (don't limit), a number, or true (should be computed). 9725 DayGrid.prototype.limitRows = function (levelLimit) { 9726 var rowStructs = this.eventRenderer.rowStructs || []; 9727 var row; // row # 9728 var rowLevelLimit; 9729 for (row = 0; row < rowStructs.length; row++) { 9730 this.unlimitRow(row); 9731 if (!levelLimit) { 9732 rowLevelLimit = false;
9733 } 9734 else if (typeof levelLimit === 'number') { 9735 rowLevelLimit = levelLimit; 9736 } 9737 else { 9738 rowLevelLimit = this.computeRowLevelLimit(row); 9739 } 9740 if (rowLevelLimit !== false) { 9741 this.limitRow(row, rowLevelLimit); 9742 } 9743 } 9744 }; 9745 // Computes the number of levels a row will accomodate without going outside its bounds. 9746 // Assumes the row is "rigid" (maintains a constant height regardless of what is inside). 9747 // `row` is the row number. 9748 DayGrid.prototype.computeRowLevelLimit = function (row) { 9749 var rowEl = this.rowEls[row]; // the containing "fake" row div 9750 var rowBottom = rowEl.getBoundingClientRect().bottom; // relative to viewport! 9751 var trEls = core.findChildren(this.eventRenderer.rowStructs[row].tbodyEl); 9752 var i; 9753 var trEl; 9754 // Reveal one level <tr> at a time and stop when we find one out of bounds 9755 for (i = 0; i < trEls.length; i++) { 9756 trEl = trEls[i]; 9757 trEl.classList.remove('fc-limited'); // reset to original state (reveal) 9758 if (trEl.getBoundingClientRect().bottom > rowBottom) { 9759 return i; 9760 } 9761 } 9762 return false; // should not limit at all 9763 }; 9764 // Limits the given grid row to the maximum number of levels and injects "more" links if necessary. 9765 // `row` is the row number. 9766 // `levelLimit` is a number for the maximum (inclusive) number of levels allowed. 9767 DayGrid.prototype.limitRow = function (row, levelLimit) { 9768 var _this = this; 9769 var _a = this, colCnt = _a.colCnt, isRtl = _a.isRtl; 9770 var rowStruct = this.eventRenderer.rowStructs[row]; 9771 var moreNodes = []; // array of "more" <a> links and <td> DOM nodes 9772 var col = 0; // col #, left-to-right (not chronologically) 9773 var levelSegs; // array of segment objects in the last allowable level, ordered left-to-right 9774 var cellMatrix; // a matrix (by level, then column) of all <td> elements in the row 9775 var limitedNodes; // array of temporarily hidden level <tr> and segment <td> DOM nodes 9776 var i; 9777 var seg; 9778 var segsBelow; // array of segment objects below `seg` in the current `col` 9779 var totalSegsBelow; // total number of segments below `seg` in any of the columns `seg` occupies 9780 var colSegsBelow; // array of segment arrays, below seg, one for each column (offset from segs's first column) 9781 var td; 9782 var rowSpan; 9783 var segMoreNodes; // array of "more" <td> cells that will stand-in for the current seg's cell 9784 var j; 9785 var moreTd; 9786 var moreWrap; 9787 var moreLink; 9788 // Iterates through empty level cells and places "more" links inside if need be 9789 var emptyCellsUntil = function (endCol) { 9790 while (col < endCol) { 9791 segsBelow = _this.getCellSegs(row, col, levelLimit); 9792 if (segsBelow.length) { 9793 td = cellMatrix[levelLimit - 1][col]; 9794 moreLink = _this.renderMoreLink(row, col, segsBelow); 9795 moreWrap = core.createElement('div', null, moreLink); 9796 td.appendChild(moreWrap); 9797 moreNodes.push(moreWrap); 9798 } 9799 col++; 9800 } 9801 }; 9802 if (levelLimit && levelLimit < rowStruct.segLevels.length) { // is it actually over the limit? 9803 levelSegs = rowStruct.segLevels[levelLimit - 1]; 9804 cellMatrix = rowStruct.cellMatrix; 9805 limitedNodes = core.findChildren(rowStruct.tbodyEl).slice(levelLimit); // get level <tr> elements past the limit 9806 limitedNodes.forEach(function (node) { 9807 node.classList.add('fc-limited'); // hide elements and get a simple DOM-nodes array 9808 }); 9809 // iterate though segments in the last allowable level 9810 for (i = 0; i < levelSegs.length; i++) { 9811 seg = levelSegs[i]; 9812 var leftCol = isRtl ? (colCnt - 1 - seg.lastCol) : seg.firstCol; 9813 var rightCol = isRtl ? (colCnt - 1 - seg.firstCol) : seg.lastCol; 9814 emptyCellsUntil(leftCol); // process empty cells before the segment 9815 // determine *all* segments below `seg` that occupy the same columns 9816 colSegsBelow = []; 9817 totalSegsBelow = 0; 9818 while (col <= rightCol) { 9819 segsBelow = this.getCellSegs(row, col, levelLimit); 9820 colSegsBelow.push(segsBelow); 9821 totalSegsBelow += segsBelow.length; 9822 col++; 9823 } 9824 if (totalSegsBelow) { // do we need to replace this segment with one or many "more" links? 9825 td = cellMatrix[levelLimit - 1][leftCol]; // the segment's parent cell 9826 rowSpan = td.rowSpan || 1; 9827 segMoreNodes = []; 9828 // make a replacement <td> for each column the segment occupies. will be one for each colspan 9829 for (j = 0; j < colSegsBelow.length; j++) { 9830 moreTd = core.createElement('td', { className: 'fc-more-cell', rowSpan: rowSpan }); 9831 segsBelow = colSegsBelow[j]; 9832 moreLink = this.renderMoreLink(row, leftCol + j, [seg].concat(segsBelow) // count seg as hidden too 9833 ); 9834 moreWrap = core.createElement('div', null, moreLink); 9835 moreTd.appendChild(moreWrap); 9836 segMoreNodes.push(moreTd); 9837 moreNodes.push(moreTd); 9838 } 9839 td.classList.add('fc-limited'); 9840 core.insertAfterElement(td, segMoreNodes); 9841 limitedNodes.push(td); 9842 } 9843 } 9844 emptyCellsUntil(this.colCnt); // finish off the level 9845 rowStruct.moreEls = moreNodes; // for easy undoing later 9846 rowStruct.limitedEls = limitedNodes; // for easy undoing later 9847 } 9848 }; 9849 // Reveals all levels and removes all "more"-related elements for a grid's row. 9850 // `row` is a row number. 9851 DayGrid.prototype.unlimitRow = function (row) { 9852 var rowStruct = this.eventRenderer.rowStructs[row]; 9853 if (rowStruct.moreEls) {
9854 rowStruct.moreEls.forEach(core.removeElement); 9855 rowStruct.moreEls = null; 9856 } 9857 if (rowStruct.limitedEls) { 9858 rowStruct.limitedEls.forEach(function (limitedEl) { 9859 limitedEl.classList.remove('fc-limited'); 9860 }); 9861 rowStruct.limitedEls = null; 9862 } 9863 }; 9864 // Renders an <a> element that represents hidden event element for a cell. 9865 // Responsible for attaching click handler as well. 9866 DayGrid.prototype.renderMoreLink = function (row, col, hiddenSegs) { 9867 var _this = this; 9868 var _a = this, view = _a.view, dateEnv = _a.dateEnv; 9869 var a = core.createElement('a', { className: 'fc-more' }); 9870 a.innerText = this.getMoreLinkText(hiddenSegs.length); 9871 a.addEventListener('click', function (ev) { 9872 var clickOption = _this.opt('eventLimitClick'); 9873 var _col = _this.isRtl ? _this.colCnt - col - 1 : col; // HACK: props.cells has different dir system? 9874 var date = _this.props.cells[row][_col].date; 9875 var moreEl = ev.currentTarget; 9876 var dayEl = _this.getCellEl(row, col); 9877 var allSegs = _this.getCellSegs(row, col); 9878 // rescope the segments to be within the cell's date 9879 var reslicedAllSegs = _this.resliceDaySegs(allSegs, date); 9880 var reslicedHiddenSegs = _this.resliceDaySegs(hiddenSegs, date); 9881 if (typeof clickOption === 'function') { 9882 // the returned value can be an atomic option 9883 clickOption = _this.publiclyTrigger('eventLimitClick', [ 9884 { 9885 date: dateEnv.toDate(date), 9886 allDay: true, 9887 dayEl: dayEl, 9888 moreEl: moreEl, 9889 segs: reslicedAllSegs, 9890 hiddenSegs: reslicedHiddenSegs, 9891 jsEvent: ev, 9892 view: view 9893 } 9894 ]); 9895 } 9896 if (clickOption === 'popover') { 9897 _this.showSegPopover(row, col, moreEl, reslicedAllSegs); 9898 } 9899 else if (typeof clickOption === 'string') { // a view name 9900 view.calendar.zoomTo(date, clickOption); 9901 } 9902 }); 9903 return a; 9904 }; 9905 // Reveals the popover that displays all events within a cell 9906 DayGrid.prototype.showSegPopover = function (row, col, moreLink, segs) { 9907 var _this = this; 9908 var _a = this, calendar = _a.calendar, view = _a.view, theme = _a.theme; 9909 var _col = this.isRtl ? this.colCnt - col - 1 : col; // HACK: props.cells has different dir system? 9910 var moreWrap = moreLink.parentNode; // the <div> wrapper around the <a> 9911 var topEl; // the element we want to match the top coordinate of 9912 var options; 9913 if (this.rowCnt === 1) { 9914 topEl = view.el; // will cause the popover to cover any sort of header 9915 } 9916 else { 9917 topEl = this.rowEls[row]; // will align with top of row 9918 } 9919 options = { 9920 className: 'fc-more-popover ' + theme.getClass('popover'), 9921 parentEl: view.el, 9922 top: core.computeRect(topEl).top, 9923 autoHide: true, 9924 content: function (el) { 9925 _this.segPopoverTile = new DayTile(_this.context, el); 9926 _this.updateSegPopoverTile(_this.props.cells[row][_col].date, segs); 9927 }, 9928 hide: function () { 9929 _this.segPopoverTile.destroy(); 9930 _this.segPopoverTile = null; 9931 _this.segPopover.destroy(); 9932 _this.segPopover = null; 9933 } 9934 }; 9935 // Determine horizontal coordinate. 9936 // We use the moreWrap instead of the <td> to avoid border confusion. 9937 if (this.isRtl) { 9938 options.right = core.computeRect(moreWrap).right + 1; // +1 to be over cell border 9939 } 9940 else { 9941 options.left = core.computeRect(moreWrap).left - 1; // -1 to be over cell border 9942 } 9943 this.segPopover = new Popover(options); 9944 this.segPopover.show(); 9945 calendar.releaseAfterSizingTriggers(); // hack for eventPositioned 9946 }; 9947 // Given the events within an array of segment objects, reslice them to be in a single day
9948 DayGrid.prototype.resliceDaySegs = function (segs, dayDate) { 9949 var dayStart = dayDate; 9950 var dayEnd = core.addDays(dayStart, 1); 9951 var dayRange = { start: dayStart, end: dayEnd }; 9952 var newSegs = []; 9953 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 9954 var seg = segs_1[_i]; 9955 var eventRange = seg.eventRange; 9956 var origRange = eventRange.range; 9957 var slicedRange = core.intersectRanges(origRange, dayRange); 9958 if (slicedRange) { 9959 newSegs.push(__assign({}, seg, { eventRange: { 9960 def: eventRange.def, 9961 ui: __assign({}, eventRange.ui, { durationEditable: false }), 9962 instance: eventRange.instance, 9963 range: slicedRange 9964 }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() })); 9965 } 9966 } 9967 return newSegs; 9968 }; 9969 // Generates the text that should be inside a "more" link, given the number of events it represents 9970 DayGrid.prototype.getMoreLinkText = function (num) { 9971 var opt = this.opt('eventLimitText'); 9972 if (typeof opt === 'function') { 9973 return opt(num); 9974 } 9975 else { 9976 return '+' + num + ' ' + opt; 9977 } 9978 }; 9979 // Returns segments within a given cell. 9980 // If `startLevel` is specified, returns only events including and below that level. Otherwise returns all segs. 9981 DayGrid.prototype.getCellSegs = function (row, col, startLevel) { 9982 var segMatrix = this.eventRenderer.rowStructs[row].segMatrix; 9983 var level = startLevel || 0; 9984 var segs = []; 9985 var seg; 9986 while (level < segMatrix.length) { 9987 seg = segMatrix[level][col]; 9988 if (seg) { 9989 segs.push(seg); 9990 } 9991 level++; 9992 } 9993 return segs; 9994 }; 9995 return DayGrid; 9996 }(core.DateComponent)); 9997 9998 var WEEK_NUM_FORMAT$1 = core.createFormatter({ week: 'numeric' }); 9999 /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells. 10000 ----------------------------------------------------------------------------------------------------------------------*/ 10001 // It is a manager for a DayGrid subcomponent, which does most of the heavy lifting. 10002 // It is responsible for managing width/height. 10003 var DayGridView = /** @class */ (function (_super) { 10004 __extends(DayGridView, _super); 10005 function DayGridView(context, viewSpec, dateProfileGenerator, parentEl) { 10006 var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this; 10007 /* Header Rendering 10008 ------------------------------------------------------------------------------------------------------------------*/ 10009 // Generates the HTML that will go before the day-of week header cells 10010 _this.renderHeadIntroHtml = function () { 10011 var theme = _this.theme; 10012 if (_this.colWeekNumbersVisible) { 10013 return '' + 10014 '<th class="fc-week-number ' + theme.getClass('widgetHeader') + '" ' + _this.weekNumberStyleAttr() + '>' + 10015 '<span>' + // needed for matchCellWidths 10016 core.htmlEscape(_this.opt('weekLabel')) + 10017 '</span>' + 10018 '</th>'; 10019 } 10020 return ''; 10021 }; 10022 /* Day Grid Rendering 10023 ------------------------------------------------------------------------------------------------------------------*/ 10024 // Generates the HTML that will go before content-skeleton cells that display the day/week numbers 10025 _this.renderDayGridNumberIntroHtml = function (row, dayGrid) { 10026 var dateEnv = _this.dateEnv; 10027 var weekStart = dayGrid.props.cells[row][0].date; 10028 if (_this.colWeekNumbersVisible) { 10029 return '' + 10030 '<td class="fc-week-number" ' + _this.weekNumberStyleAttr() + '>' + 10031 core.buildGotoAnchorHtml(// aside from link, important for matchCellWidths 10032 _this, { date: weekStart, type: 'week', forceOff: dayGrid.colCnt === 1 }, dateEnv.format(weekStart, WEEK_NUM_FORMAT$1) // inner HTML 10033 ) + 10034 '</td>'; 10035 } 10036 return ''; 10037 }; 10038 // Generates the HTML that goes before the day bg cells for each day-row 10039 _this.renderDayGridBgIntroHtml = function () { 10040 var theme = _this.theme; 10041 if (_this.colWeekNumbersVisible) { 10042 return '<td class="fc-week-number ' + theme.getClass('widgetContent') + '" ' + _this.weekNumberStyleAttr() + '></td>'; 10043 } 10044 return ''; 10045 }; 10046 // Generates the HTML that goes before every other type of row generated by DayGrid. 10047 // Affects mirror-skeleton and highlight-skeleton rows. 10048 _this.renderDayGridIntroHtml = function () { 10049 if (_this.colWeekNumbersVisible) { 10050 return '<td class="fc-week-number" ' + _this.weekNumberStyleAttr() + '></td>'; 10051 } 10052 return ''; 10053 }; 10054 _this.el.classList.add('fc-dayGrid-view'); 10055 _this.el.innerHTML = _this.renderSkeletonHtml();
10056 _this.scroller = new core.ScrollComponent('hidden', // overflow x 10057 'auto' // overflow y 10058 ); 10059 var dayGridContainerEl = _this.scroller.el; 10060 _this.el.querySelector('.fc-body > tr > td').appendChild(dayGridContainerEl); 10061 dayGridContainerEl.classList.add('fc-day-grid-container'); 10062 var dayGridEl = core.createElement('div', { className: 'fc-day-grid' }); 10063 dayGridContainerEl.appendChild(dayGridEl); 10064 var cellWeekNumbersVisible; 10065 if (_this.opt('weekNumbers')) { 10066 if (_this.opt('weekNumbersWithinDays')) { 10067 cellWeekNumbersVisible = true; 10068 _this.colWeekNumbersVisible = false; 10069 } 10070 else { 10071 cellWeekNumbersVisible = false; 10072 _this.colWeekNumbersVisible = true; 10073 } 10074 } 10075 else { 10076 _this.colWeekNumbersVisible = false; 10077 cellWeekNumbersVisible = false; 10078 } 10079 _this.dayGrid = new DayGrid(_this.context, dayGridEl, { 10080 renderNumberIntroHtml: _this.renderDayGridNumberIntroHtml, 10081 renderBgIntroHtml: _this.renderDayGridBgIntroHtml, 10082 renderIntroHtml: _this.renderDayGridIntroHtml, 10083 colWeekNumbersVisible: _this.colWeekNumbersVisible, 10084 cellWeekNumbersVisible: cellWeekNumbersVisible 10085 }); 10086 return _this; 10087 } 10088 DayGridView.prototype.destroy = function () { 10089 _super.prototype.destroy.call(this); 10090 this.dayGrid.destroy(); 10091 this.scroller.destroy(); 10092 }; 10093 // Builds the HTML skeleton for the view. 10094 // The day-grid component will render inside of a container defined by this HTML. 10095 DayGridView.prototype.renderSkeletonHtml = function () { 10096 var theme = this.theme; 10097 return '' + 10098 '<table class="' + theme.getClass('tableGrid') + '">' + 10099 (this.opt('columnHeader') ? 10100 '<thead class="fc-head">' + 10101 '<tr>' + 10102 '<td class="fc-head-container ' + theme.getClass('widgetHeader') + '"> </td>' + 10103 '</tr>' + 10104 '</thead>' : 10105 '') + 10106 '<tbody class="fc-body">' + 10107 '<tr>' + 10108 '<td class="' + theme.getClass('widgetContent') + '"></td>' + 10109 '</tr>' + 10110 '</tbody>' + 10111 '</table>'; 10112 }; 10113 // Generates an HTML attribute string for setting the width of the week number column, if it is known 10114 DayGridView.prototype.weekNumberStyleAttr = function () { 10115 if (this.weekNumberWidth != null) { 10116 return 'style="width:' + this.weekNumberWidth + 'px"'; 10117 } 10118 return ''; 10119 }; 10120 // Determines whether each row should have a constant height 10121 DayGridView.prototype.hasRigidRows = function () { 10122 var eventLimit = this.opt('eventLimit'); 10123 return eventLimit && typeof eventLimit !== 'number'; 10124 }; 10125 /* Dimensions 10126 ------------------------------------------------------------------------------------------------------------------*/ 10127 DayGridView.prototype.updateSize = function (isResize, viewHeight, isAuto) { 10128 _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto); // will call updateBaseSize. important that executes first 10129 this.dayGrid.updateSize(isResize); 10130 }; 10131 // Refreshes the horizontal dimensions of the view 10132 DayGridView.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) { 10133 var dayGrid = this.dayGrid; 10134 var eventLimit = this.opt('eventLimit'); 10135 var headRowEl = this.header ? this.header.el : null; // HACK 10136 var scrollerHeight; 10137 var scrollbarWidths; 10138 // hack to give the view some height prior to dayGrid's columns being rendered 10139 // TODO: separate setting height from scroller VS dayGrid. 10140 if (!dayGrid.rowEls) { 10141 if (!isAuto) { 10142 scrollerHeight = this.computeScrollerHeight(viewHeight); 10143 this.scroller.setHeight(scrollerHeight); 10144 } 10145 return; 10146 } 10147 if (this.colWeekNumbersVisible) { 10148 // Make sure all week number cells running down the side have the same width. 10149 this.weekNumberWidth = core.matchCellWidths(core.findElements(this.el, '.fc-week-number')); 10150 } 10151 // reset all heights to be natural 10152 this.scroller.clear(); 10153 if (headRowEl) { 10154 core.uncompensateScroll(headRowEl); 10155 } 10156 dayGrid.removeSegPopover(); // kill the "more" popover if displayed 10157 // is the event limit a constant level number? 10158 if (eventLimit && typeof eventLimit === 'number') { 10159 dayGrid.limitRows(eventLimit); // limit the levels first so the height can redistribute after 10160 } 10161 // distribute the height to the rows 10162 // (viewHeight is a "recommended" value if isAuto) 10163 scrollerHeight = this.computeScrollerHeight(viewHeight); 10164 this.setGridHeight(scrollerHeight, isAuto); 10165 // is the event limit dynamically calculated? 10166 if (eventLimit && typeof eventLimit !== 'number') { 10167 dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set 10168 } 10169 if (!isAuto) { // should we force dimensions of the scroll container? 10170 this.scroller.setHeight(scrollerHeight);
10171 scrollbarWidths = this.scroller.getScrollbarWidths(); 10172 if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars? 10173 if (headRowEl) { 10174 core.compensateScroll(headRowEl, scrollbarWidths); 10175 } 10176 // doing the scrollbar compensation might have created text overflow which created more height. redo 10177 scrollerHeight = this.computeScrollerHeight(viewHeight); 10178 this.scroller.setHeight(scrollerHeight); 10179 } 10180 // guarantees the same scrollbar widths 10181 this.scroller.lockOverflow(scrollbarWidths); 10182 } 10183 }; 10184 // given a desired total height of the view, returns what the height of the scroller should be 10185 DayGridView.prototype.computeScrollerHeight = function (viewHeight) { 10186 return viewHeight - 10187 core.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller 10188 }; 10189 // Sets the height of just the DayGrid component in this view 10190 DayGridView.prototype.setGridHeight = function (height, isAuto) { 10191 if (this.opt('monthMode')) { 10192 // if auto, make the height of each row the height that it would be if there were 6 weeks 10193 if (isAuto) { 10194 height *= this.dayGrid.rowCnt / 6; 10195 } 10196 core.distributeHeight(this.dayGrid.rowEls, height, !isAuto); // if auto, don't compensate for height-hogging rows 10197 } 10198 else { 10199 if (isAuto) { 10200 core.undistributeHeight(this.dayGrid.rowEls); // let the rows be their natural height with no expanding 10201 } 10202 else { 10203 core.distributeHeight(this.dayGrid.rowEls, height, true); // true = compensate for height-hogging rows 10204 } 10205 } 10206 }; 10207 /* Scroll 10208 ------------------------------------------------------------------------------------------------------------------*/ 10209 DayGridView.prototype.computeDateScroll = function (duration) { 10210 return { top: 0 }; 10211 }; 10212 DayGridView.prototype.queryDateScroll = function () { 10213 return { top: this.scroller.getScrollTop() }; 10214 }; 10215 DayGridView.prototype.applyDateScroll = function (scroll) { 10216 if (scroll.top !== undefined) { 10217 this.scroller.setScrollTop(scroll.top); 10218 } 10219 }; 10220 return DayGridView; 10221 }(core.View)); 10222 DayGridView.prototype.dateProfileGeneratorClass = DayGridDateProfileGenerator; 10223 10224 var SimpleDayGrid = /** @class */ (function (_super) { 10225 __extends(SimpleDayGrid, _super); 10226 function SimpleDayGrid(context, dayGrid) { 10227 var _this = _super.call(this, context, dayGrid.el) || this; 10228 _this.slicer = new DayGridSlicer(); 10229 _this.dayGrid = dayGrid; 10230 context.calendar.registerInteractiveComponent(_this, { el: _this.dayGrid.el }); 10231 return _this; 10232 } 10233 SimpleDayGrid.prototype.destroy = function () { 10234 _super.prototype.destroy.call(this); 10235 this.calendar.unregisterInteractiveComponent(this); 10236 }; 10237 SimpleDayGrid.prototype.render = function (props) { 10238 var dayGrid = this.dayGrid; 10239 var dateProfile = props.dateProfile, dayTable = props.dayTable; 10240 dayGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, props.nextDayThreshold, dayGrid, dayTable), { dateProfile: dateProfile, cells: dayTable.cells, isRigid: props.isRigid })); 10241 }; 10242 SimpleDayGrid.prototype.buildPositionCaches = function () { 10243 this.dayGrid.buildPositionCaches(); 10244 }; 10245 SimpleDayGrid.prototype.queryHit = function (positionLeft, positionTop) { 10246 var rawHit = this.dayGrid.positionToHit(positionLeft, positionTop); 10247 if (rawHit) { 10248 return { 10249 component: this.dayGrid, 10250 dateSpan: rawHit.dateSpan, 10251 dayEl: rawHit.dayEl, 10252 rect: { 10253 left: rawHit.relativeRect.left, 10254 right: rawHit.relativeRect.right, 10255 top: rawHit.relativeRect.top, 10256 bottom: rawHit.relativeRect.bottom 10257 }, 10258 layer: 0 10259 }; 10260 } 10261 }; 10262 return SimpleDayGrid; 10263 }(core.DateComponent));
10264 var DayGridSlicer = /** @class */ (function (_super) { 10265 __extends(DayGridSlicer, _super); 10266 function DayGridSlicer() { 10267 return _super !== null && _super.apply(this, arguments) || this; 10268 } 10269 DayGridSlicer.prototype.sliceRange = function (dateRange, dayTable) { 10270 return dayTable.sliceRange(dateRange); 10271 }; 10272 return DayGridSlicer; 10273 }(core.Slicer)); 10274 10275 var DayGridView$1 = /** @class */ (function (_super) { 10276 __extends(DayGridView, _super); 10277 function DayGridView(_context, viewSpec, dateProfileGenerator, parentEl) { 10278 var _this = _super.call(this, _context, viewSpec, dateProfileGenerator, parentEl) || this; 10279 _this.buildDayTable = core.memoize(buildDayTable); 10280 if (_this.opt('columnHeader')) { 10281 _this.header = new core.DayHeader(_this.context, _this.el.querySelector('.fc-head-container')); 10282 } 10283 _this.simpleDayGrid = new SimpleDayGrid(_this.context, _this.dayGrid); 10284 return _this; 10285 } 10286 DayGridView.prototype.destroy = function () { 10287 _super.prototype.destroy.call(this); 10288 if (this.header) { 10289 this.header.destroy(); 10290 } 10291 this.simpleDayGrid.destroy(); 10292 }; 10293 DayGridView.prototype.render = function (props) { 10294 _super.prototype.render.call(this, props); 10295 var dateProfile = this.props.dateProfile; 10296 var dayTable = this.dayTable = 10297 this.buildDayTable(dateProfile, this.dateProfileGenerator); 10298 if (this.header) { 10299 this.header.receiveProps({ 10300 dateProfile: dateProfile, 10301 dates: dayTable.headerDates, 10302 datesRepDistinctDays: dayTable.rowCnt === 1, 10303 renderIntroHtml: this.renderHeadIntroHtml 10304 }); 10305 } 10306 this.simpleDayGrid.receiveProps({ 10307 dateProfile: dateProfile, 10308 dayTable: dayTable, 10309 businessHours: props.businessHours, 10310 dateSelection: props.dateSelection, 10311 eventStore: props.eventStore, 10312 eventUiBases: props.eventUiBases, 10313 eventSelection: props.eventSelection, 10314 eventDrag: props.eventDrag, 10315 eventResize: props.eventResize, 10316 isRigid: this.hasRigidRows(), 10317 nextDayThreshold: this.nextDayThreshold 10318 }); 10319 }; 10320 return DayGridView; 10321 }(DayGridView)); 10322 function buildDayTable(dateProfile, dateProfileGenerator) { 10323 var daySeries = new core.DaySeries(dateProfile.renderRange, dateProfileGenerator); 10324 return new core.DayTable(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit)); 10325 } 10326 10327 var main = core.createPlugin({ 10328 defaultView: 'dayGridMonth', 10329 views: { 10330 dayGrid: DayGridView$1, 10331 dayGridDay: { 10332 type: 'dayGrid', 10333 duration: { days: 1 } 10334 }, 10335 dayGridWeek: { 10336 type: 'dayGrid', 10337 duration: { weeks: 1 } 10338 }, 10339 dayGridMonth: { 10340 type: 'dayGrid', 10341 duration: { months: 1 }, 10342 monthMode: true, 10343 fixedWeekCount: true 10344 } 10345 } 10346 }); 10347 10348 exports.AbstractDayGridView = DayGridView; 10349 exports.DayBgRow = DayBgRow; 10350 exports.DayGrid = DayGrid; 10351 exports.DayGridSlicer = DayGridSlicer; 10352 exports.DayGridView = DayGridView$1; 10353 exports.SimpleDayGrid = SimpleDayGrid; 10354 exports.buildBasicDayTable = buildDayTable; 10355 exports.default = main; 10356 10357 Object.defineProperty(exports, '__esModule', { value: true }); 10358 10359})); 10360 10361/*! 10362FullCalendar Google Calendar Plugin v4.3.0 10363Docs & License: https://fullcalendar.io/ 10364(c) 2019 Adam Shaw 10365*/ 10366 10367(function (global, factory) { 10368 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core')) : 10369 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) : 10370 (global = global || self, factory(global.FullCalendarGoogleCalendar = {}, global.FullCalendar)); 10371}(this, function (exports, core) { 'use strict'; 10372 10373 /*! ***************************************************************************** 10374 Copyright (c) Microsoft Corporation. All rights reserved. 10375 Licensed under the Apache License, Version 2.0 (the "License");
10375 you may not use 10376 this file except in compliance with the License. You may obtain a copy of the 10377 License at http://www.apache.org/licenses/LICENSE-2.0 10378 10379 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 10380 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 10381 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10382 MERCHANTABLITY OR NON-INFRINGEMENT. 10383 10384 See the Apache Version 2.0 License for specific language governing permissions 10385 and limitations under the License. 10386 ***************************************************************************** */ 10387 10388 var __assign = function() { 10389 __assign = Object.assign || function __assign(t) { 10390 for (var s, i = 1, n = arguments.length; i < n; i++) { 10391 s = arguments[i]; 10392 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 10393 } 10394 return t; 10395 }; 10396 return __assign.apply(this, arguments); 10397 }; 10398 10399 // TODO: expose somehow 10400 var API_BASE = 'https://www.googleapis.com/calendar/v3/calendars'; 10401 var STANDARD_PROPS = { 10402 url: String, 10403 googleCalendarApiKey: String, 10404 googleCalendarId: String, 10405 data: null 10406 }; 10407 var eventSourceDef = { 10408 parseMeta: function (raw) { 10409 if (typeof raw === 'string') { 10410 raw = { url: raw }; 10411 } 10412 if (typeof raw === 'object') { 10413 var standardProps = core.refineProps(raw, STANDARD_PROPS); 10414 if (!standardProps.googleCalendarId && standardProps.url) { 10415 standardProps.googleCalendarId = parseGoogleCalendarId(standardProps.url); 10416 } 10417 delete standardProps.url; 10418 if (standardProps.googleCalendarId) { 10419 return standardProps; 10420 } 10421 } 10422 return null; 10423 }, 10424 fetch: function (arg, onSuccess, onFailure) { 10425 var calendar = arg.calendar; 10426 var meta = arg.eventSource.meta; 10427 var apiKey = meta.googleCalendarApiKey || calendar.opt('googleCalendarApiKey'); 10428 if (!apiKey) { 10429 onFailure({ 10430 message: 'Specify a googleCalendarApiKey. See http://fullcalendar.io/docs/google_calendar/' 10431 }); 10432 } 10433 else { 10434 var url = buildUrl(meta); 10435 var requestParams_1 = buildRequestParams(arg.range, apiKey, meta.data, calendar.dateEnv); 10436 core.requestJson('GET', url, requestParams_1, function (body, xhr) { 10437 if (body.error) { 10438 onFailure({ 10439 message: 'Google Calendar API: ' + body.error.message, 10440 errors: body.error.errors, 10441 xhr: xhr 10442 }); 10443 } 10444 else { 10445 onSuccess({ 10446 rawEvents: gcalItemsToRawEventDefs(body.items, requestParams_1.timeZone), 10447 xhr: xhr 10448 }); 10449 } 10450 }, function (message, xhr) { 10451 onFailure({ message: message, xhr: xhr }); 10452 }); 10453 } 10454 } 10455 }; 10456 function parseGoogleCalendarId(url) { 10457 var match; 10458 // detect if the ID was specified as a single string. 10459 // will match calendars like "[email protected]" in addition to person email calendars. 10460 if (/^[^\/]+@([^\/\.]+\.)*(google|googlemail|gmail)\.com$/.test(url)) { 10461 return url; 10462 } 10463 else if ((match = /^https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/([^\/]*)/.exec(url)) || 10464 (match = /^https?:\/\/www.google.com\/calendar\/feeds\/([^\/]*)/.exec(url))) { 10465 return decodeURIComponent(match[1]); 10466 } 10467 } 10468 function buildUrl(meta) { 10469 return API_BASE + '/' + encodeURIComponent(meta.googleCalendarId) + '/events'; 10470 }
10471 function buildRequestParams(range, apiKey, extraParams, dateEnv) { 10472 var params; 10473 var startStr; 10474 var endStr; 10475 if (dateEnv.canComputeOffset) { 10476 // strings will naturally have offsets, which GCal needs 10477 startStr = dateEnv.formatIso(range.start); 10478 endStr = dateEnv.formatIso(range.end); 10479 } 10480 else { 10481 // when timezone isn't known, we don't know what the UTC offset should be, so ask for +/- 1 day 10482 // from the UTC day-start to guarantee we're getting all the events 10483 // (start/end will be UTC-coerced dates, so toISOString is okay) 10484 startStr = core.addDays(range.start, -1).toISOString(); 10485 endStr = core.addDays(range.end, 1).toISOString(); 10486 } 10487 params = __assign({}, (extraParams || {}), { key: apiKey, timeMin: startStr, timeMax: endStr, singleEvents: true, maxResults: 9999 }); 10488 if (dateEnv.timeZone !== 'local') { 10489 params.timeZone = dateEnv.timeZone; 10490 } 10491 return params; 10492 } 10493 function gcalItemsToRawEventDefs(items, gcalTimezone) { 10494 return items.map(function (item) { 10495 return gcalItemToRawEventDef(item, gcalTimezone); 10496 }); 10497 } 10498 function gcalItemToRawEventDef(item, gcalTimezone) { 10499 var url = item.htmlLink || null; 10500 // make the URLs for each event show times in the correct timezone 10501 if (url && gcalTimezone) { 10502 url = injectQsComponent(url, 'ctz=' + gcalTimezone); 10503 } 10504 return { 10505 id: item.id, 10506 title: item.summary, 10507 start: item.start.dateTime || item.start.date, 10508 end: item.end.dateTime || item.end.date, 10509 url: url, 10510 location: item.location, 10511 description: item.description 10512 }; 10513 } 10514 // Injects a string like "arg=value" into the querystring of a URL 10515 // TODO: move to a general util file? 10516 function injectQsComponent(url, component) { 10517 // inject it after the querystring but before the fragment 10518 return url.replace(/(\?.*?)?(#|$)/, function (whole, qs, hash) { 10519 return (qs ? qs + '&' : '?') + component + hash; 10520 }); 10521 } 10522 var main = core.createPlugin({ 10523 eventSourceDefs: [eventSourceDef] 10524 }); 10525 10526 exports.default = main; 10527 10528 Object.defineProperty(exports, '__esModule', { value: true }); 10529 10530})); 10531 10532/*! 10533FullCalendar Interaction Plugin v4.3.0 10534Docs & License: https://fullcalendar.io/ 10535(c) 2019 Adam Shaw 10536*/ 10537 10538(function (global, factory) { 10539 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core')) : 10540 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) : 10541 (global = global || self, factory(global.FullCalendarInteraction = {}, global.FullCalendar)); 10542}(this, function (exports, core) { 'use strict'; 10543 10544 /*! ***************************************************************************** 10545 Copyright (c) Microsoft Corporation. All rights reserved. 10546 Licensed under the Apache License, Version 2.0 (the "License"); you may not use 10547 this file except in compliance with the License. You may obtain a copy of the 10548 License at http://www.apache.org/licenses/LICENSE-2.0 10549 10550 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 10551 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 10552 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10553 MERCHANTABLITY OR NON-INFRINGEMENT. 10554 10555 See the Apache Version 2.0 License for specific language governing permissions 10556 and limitations under the License. 10557 ***************************************************************************** */ 10558 /* global Reflect, Promise */ 10559 10560 var extendStatics = function(d, b) { 10561 extendStatics = Object.setPrototypeOf || 10562 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 10563 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 10564 return extendStatics(d, b); 10565 }; 10566 10567 function __extends(d, b) { 10568 extendStatics(d, b); 10569 function __() { this.constructor = d; } 10570 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 10571 } 10572 10573 var __assign = function() { 10574 __assign = Object.assign || function __assign(t) { 10575 for (var s, i = 1, n = arguments.length; i < n; i++) { 10576 s = arguments[i]; 10577 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 10578 } 10579 return t; 10580 }; 10581 return __assign.apply(this, arguments); 10582 }; 10583 10584 core.config.touchMouseIgnoreWait = 500; 10585 var ignoreMouseDepth = 0; 10586 var listenerCnt = 0; 10587 var isWindowTouchMoveCancelled = false;
10588 /* 10589 Uses a "pointer" abstraction, which monitors UI events for both mouse and touch. 10590 Tracks when the pointer "drags" on a certain element, meaning down+move+up. 10591 10592 Also, tracks if there was touch-scrolling. 10593 Also, can prevent touch-scrolling from happening. 10594 Also, can fire pointermove events when scrolling happens underneath, even when no real pointer movement. 10595 10596 emits: 10597 - pointerdown 10598 - pointermove 10599 - pointerup 10600 */ 10601 var PointerDragging = /** @class */ (function () { 10602 function PointerDragging(containerEl) { 10603 var _this = this; 10604 this.subjectEl = null; 10605 this.downEl = null; 10606 // options that can be directly assigned by caller 10607 this.selector = ''; // will cause subjectEl in all emitted events to be this element 10608 this.handleSelector = ''; 10609 this.shouldIgnoreMove = false; 10610 this.shouldWatchScroll = true; // for simulating pointermove on scroll 10611 // internal states 10612 this.isDragging = false; 10613 this.isTouchDragging = false; 10614 this.wasTouchScroll = false; 10615 // Mouse 10616 // ---------------------------------------------------------------------------------------------------- 10617 this.handleMouseDown = function (ev) { 10618 if (!_this.shouldIgnoreMouse() && 10619 isPrimaryMouseButton(ev) && 10620 _this.tryStart(ev)) { 10621 var pev = _this.createEventFromMouse(ev, true); 10622 _this.emitter.trigger('pointerdown', pev); 10623 _this.initScrollWatch(pev); 10624 if (!_this.shouldIgnoreMove) { 10625 document.addEventListener('mousemove', _this.handleMouseMove); 10626 } 10627 document.addEventListener('mouseup', _this.handleMouseUp); 10628 } 10629 }; 10630 this.handleMouseMove = function (ev) { 10631 var pev = _this.createEventFromMouse(ev); 10632 _this.recordCoords(pev); 10633 _this.emitter.trigger('pointermove', pev); 10634 }; 10635 this.handleMouseUp = function (ev) { 10636 document.removeEventListener('mousemove', _this.handleMouseMove); 10637 document.removeEventListener('mouseup', _this.handleMouseUp); 10638 _this.emitter.trigger('pointerup', _this.createEventFromMouse(ev)); 10639 _this.cleanup(); // call last so that pointerup has access to props 10640 }; 10641 // Touch 10642 // ---------------------------------------------------------------------------------------------------- 10643 this.handleTouchStart = function (ev) { 10644 if (_this.tryStart(ev)) { 10645 _this.isTouchDragging = true; 10646 var pev = _this.createEventFromTouch(ev, true); 10647 _this.emitter.trigger('pointerdown', pev); 10648 _this.initScrollWatch(pev); 10649 // unlike mouse, need to attach to target, not document 10650 // https://stackoverflow.com/a/45760014 10651 var target = ev.target; 10652 if (!_this.shouldIgnoreMove) { 10653 target.addEventListener('touchmove', _this.handleTouchMove); 10654 } 10655 target.addEventListener('touchend', _this.handleTouchEnd); 10656 target.addEventListener('touchcancel', _this.handleTouchEnd); // treat it as a touch end 10657 // attach a handler to get called when ANY scroll action happens on the page. 10658 // this was impossible to do with normal on/off because 'scroll' doesn't bubble. 10659 // http://stackoverflow.com/a/32954565/96342 10660 window.addEventListener('scroll', _this.handleTouchScroll, true // useCapture 10661 ); 10662 } 10663 }; 10664 this.handleTouchMove = function (ev) { 10665 var pev = _this.createEventFromTouch(ev); 10666 _this.recordCoords(pev); 10667 _this.emitter.trigger('pointermove', pev); 10668 }; 10669 this.handleTouchEnd = function (ev) { 10670 if (_this.isDragging) { // done to guard against touchend followed by touchcancel 10671 var target = ev.target; 10672 target.removeEventListener('touchmove', _this.handleTouchMove); 10673 target.removeEventListener('touchend', _this.handleTouchEnd); 10674 target.removeEventListener('touchcancel', _this.handleTouchEnd); 10675 window.removeEventListener('scroll', _this.handleTouchScroll, true); // useCaptured=true 10676 _this.emitter.trigger('pointerup', _this.createEventFromTouch(ev)); 10677 _this.cleanup(); // call last so that pointerup has access to props 10678 _this.isTouchDragging = false;
10679 startIgnoringMouse(); 10680 } 10681 }; 10682 this.handleTouchScroll = function () { 10683 _this.wasTouchScroll = true; 10684 }; 10685 this.handleScroll = function (ev) { 10686 if (!_this.shouldIgnoreMove) { 10687 var pageX = (window.pageXOffset - _this.prevScrollX) + _this.prevPageX; 10688 var pageY = (window.pageYOffset - _this.prevScrollY) + _this.prevPageY; 10689 _this.emitter.trigger('pointermove', { 10690 origEvent: ev, 10691 isTouch: _this.isTouchDragging, 10692 subjectEl: _this.subjectEl, 10693 pageX: pageX, 10694 pageY: pageY, 10695 deltaX: pageX - _this.origPageX, 10696 deltaY: pageY - _this.origPageY 10697 }); 10698 } 10699 }; 10700 this.containerEl = containerEl; 10701 this.emitter = new core.EmitterMixin(); 10702 containerEl.addEventListener('mousedown', this.handleMouseDown); 10703 containerEl.addEventListener('touchstart', this.handleTouchStart, { passive: true }); 10704 listenerCreated(); 10705 } 10706 PointerDragging.prototype.destroy = function () { 10707 this.containerEl.removeEventListener('mousedown', this.handleMouseDown); 10708 this.containerEl.removeEventListener('touchstart', this.handleTouchStart, { passive: true }); 10709 listenerDestroyed(); 10710 }; 10711 PointerDragging.prototype.tryStart = function (ev) { 10712 var subjectEl = this.querySubjectEl(ev); 10713 var downEl = ev.target; 10714 if (subjectEl && 10715 (!this.handleSelector || core.elementClosest(downEl, this.handleSelector))) { 10716 this.subjectEl = subjectEl; 10717 this.downEl = downEl; 10718 this.isDragging = true; // do this first so cancelTouchScroll will work 10719 this.wasTouchScroll = false; 10720 return true; 10721 } 10722 return false; 10723 }; 10724 PointerDragging.prototype.cleanup = function () { 10725 isWindowTouchMoveCancelled = false; 10726 this.isDragging = false; 10727 this.subjectEl = null; 10728 this.downEl = null; 10729 // keep wasTouchScroll around for later access 10730 this.destroyScrollWatch(); 10731 }; 10732 PointerDragging.prototype.querySubjectEl = function (ev) { 10733 if (this.selector) { 10734 return core.elementClosest(ev.target, this.selector); 10735 } 10736 else { 10737 return this.containerEl; 10738 } 10739 }; 10740 PointerDragging.prototype.shouldIgnoreMouse = function () { 10741 return ignoreMouseDepth || this.isTouchDragging; 10742 }; 10743 // can be called by user of this class, to cancel touch-based scrolling for the current drag 10744 PointerDragging.prototype.cancelTouchScroll = function () { 10745 if (this.isDragging) { 10746 isWindowTouchMoveCancelled = true; 10747 } 10748 }; 10749 // Scrolling that simulates pointermoves 10750 // ---------------------------------------------------------------------------------------------------- 10751 PointerDragging.prototype.initScrollWatch = function (ev) { 10752 if (this.shouldWatchScroll) { 10753 this.recordCoords(ev); 10754 window.addEventListener('scroll', this.handleScroll, true); // useCapture=true 10755 } 10756 }; 10757 PointerDragging.prototype.recordCoords = function (ev) { 10758 if (this.shouldWatchScroll) { 10759 this.prevPageX = ev.pageX; 10760 this.prevPageY = ev.pageY; 10761 this.prevScrollX = window.pageXOffset; 10762 this.prevScrollY = window.pageYOffset; 10763 } 10764 }; 10765 PointerDragging.prototype.destroyScrollWatch = function () { 10766 if (this.shouldWatchScroll) { 10767 window.removeEventListener('scroll', this.handleScroll, true); // useCaptured=true 10768 } 10769 }; 10770 // Event Normalization 10771 // ---------------------------------------------------------------------------------------------------- 10772 PointerDragging.prototype.createEventFromMouse = function (ev, isFirst) { 10773 var deltaX = 0; 10774 var deltaY = 0; 10775 // TODO: repeat code 10776 if (isFirst) { 10777 this.origPageX = ev.pageX; 10778 this.origPageY = ev.pageY; 10779 } 10780 else { 10781 deltaX = ev.pageX - this.origPageX; 10782 deltaY = ev.pageY - this.origPageY; 10783 } 10784 return { 10785 origEvent: ev, 10786 isTouch: false, 10787 subjectEl: this.subjectEl, 10788 pageX: ev.pageX, 10789 pageY: ev.pageY, 10790 deltaX: deltaX, 10791 deltaY: deltaY 10792 }; 10793 }; 10794 PointerDragging.prototype.createEventFromTouch = function (ev, isFirst) { 10795 var touches = ev.touches; 10796 var pageX; 10797 var pageY; 10798 var deltaX = 0; 10799 var deltaY = 0; 10800 // if touch coords available, prefer, 10801 // because FF would give bad ev.pageX ev.pageY 10802 if (touches && touches.length) { 10803 pageX = touches[0].pageX; 10804 pageY = touches[0].pageY; 10805 } 10806 else { 10807 pageX = ev.pageX; 10808 pageY = ev.pageY; 10809 } 10810 // TODO: repeat code 10811 if (isFirst) { 10812 this.origPageX = pageX; 10813 this.origPageY = pageY; 10814 } 10815 else { 10816 deltaX = pageX - this.origPageX; 10817 deltaY = pageY - this.origPageY; 10818 } 10819 return { 10820 origEvent: ev, 10821 isTouch: true, 10822 subjectEl: this.subjectEl, 10823 pageX: pageX, 10824 pageY: pageY, 10825 deltaX: deltaX, 10826 deltaY: deltaY 10827 }; 10828 }; 10829 return PointerDragging; 10830 }());
10831 // Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac) 10832 function isPrimaryMouseButton(ev) { 10833 return ev.button === 0 && !ev.ctrlKey; 10834 } 10835 // Ignoring fake mouse events generated by touch 10836 // ---------------------------------------------------------------------------------------------------- 10837 function startIgnoringMouse() { 10838 ignoreMouseDepth++; 10839 setTimeout(function () { 10840 ignoreMouseDepth--; 10841 }, core.config.touchMouseIgnoreWait); 10842 } 10843 // We want to attach touchmove as early as possible for Safari 10844 // ---------------------------------------------------------------------------------------------------- 10845 function listenerCreated() { 10846 if (!(listenerCnt++)) { 10847 window.addEventListener('touchmove', onWindowTouchMove, { passive: false }); 10848 } 10849 } 10850 function listenerDestroyed() { 10851 if (!(--listenerCnt)) { 10852 window.removeEventListener('touchmove', onWindowTouchMove, { passive: false }); 10853 } 10854 } 10855 function onWindowTouchMove(ev) { 10856 if (isWindowTouchMoveCancelled) { 10857 ev.preventDefault(); 10858 } 10859 } 10860 10861 /* 10862 An effect in which an element follows the movement of a pointer across the screen. 10863 The moving element is a clone of some other element. 10864 Must call start + handleMove + stop. 10865 */ 10866 var ElementMirror = /** @class */ (function () { 10867 function ElementMirror() { 10868 this.isVisible = false; // must be explicitly enabled 10869 this.sourceEl = null; 10870 this.mirrorEl = null; 10871 this.sourceElRect = null; // screen coords relative to viewport 10872 // options that can be set directly by caller 10873 this.parentNode = document.body; 10874 this.zIndex = 9999; 10875 this.revertDuration = 0; 10876 } 10877 ElementMirror.prototype.start = function (sourceEl, pageX, pageY) { 10878 this.sourceEl = sourceEl; 10879 this.sourceElRect = this.sourceEl.getBoundingClientRect(); 10880 this.origScreenX = pageX - window.pageXOffset; 10881 this.origScreenY = pageY - window.pageYOffset; 10882 this.deltaX = 0; 10883 this.deltaY = 0; 10884 this.updateElPosition(); 10885 }; 10886 ElementMirror.prototype.handleMove = function (pageX, pageY) { 10887 this.deltaX = (pageX - window.pageXOffset) - this.origScreenX; 10888 this.deltaY = (pageY - window.pageYOffset) - this.origScreenY; 10889 this.updateElPosition(); 10890 }; 10891 // can be called before start 10892 ElementMirror.prototype.setIsVisible = function (bool) { 10893 if (bool) { 10894 if (!this.isVisible) { 10895 if (this.mirrorEl) { 10896 this.mirrorEl.style.display = ''; 10897 } 10898 this.isVisible = bool; // needs to happen before updateElPosition 10899 this.updateElPosition(); // because was not updating the position while invisible 10900 } 10901 } 10902 else { 10903 if (this.isVisible) { 10904 if (this.mirrorEl) { 10905 this.mirrorEl.style.display = 'none'; 10906 } 10907 this.isVisible = bool; 10908 } 10909 } 10910 }; 10911 // always async 10912 ElementMirror.prototype.stop = function (needsRevertAnimation, callback) { 10913 var _this = this; 10914 var done = function () { 10915 _this.cleanup(); 10916 callback(); 10917 }; 10918 if (needsRevertAnimation && 10919 this.mirrorEl && 10920 this.isVisible && 10921 this.revertDuration && // if 0, transition won't work 10922 (this.deltaX || this.deltaY) // if same coords, transition won't work 10923 ) { 10924 this.doRevertAnimation(done, this.revertDuration); 10925 } 10926 else { 10927 setTimeout(done, 0); 10928 } 10929 }; 10930 ElementMirror.prototype.doRevertAnimation = function (callback, revertDuration) { 10931 var mirrorEl = this.mirrorEl; 10932 var finalSourceElRect = this.sourceEl.getBoundingClientRect(); // because autoscrolling might have happened 10933 mirrorEl.style.transition = 10934 'top ' + revertDuration + 'ms,' + 10935 'left ' + revertDuration + 'ms'; 10936 core.applyStyle(mirrorEl, { 10937 left: finalSourceElRect.left, 10938 top: finalSourceElRect.top 10939 }); 10940 core.whenTransitionDone(mirrorEl, function () { 10941 mirrorEl.style.transition = ''; 10942 callback(); 10943 }); 10944 }; 10945 ElementMirror.prototype.cleanup = function () { 10946 if (this.mirrorEl) { 10947 core.removeElement(this.mirrorEl); 10948 this.mirrorEl = null; 10949 } 10950 this.sourceEl = null; 10951 }; 10952 ElementMirror.prototype.updateElPosition = function () { 10953 if (this.sourceEl && this.isVisible) { 10954 core.applyStyle(this.getMirrorEl(), { 10955 left: this.sourceElRect.left + this.deltaX,
10956 top: this.sourceElRect.top + this.deltaY 10957 }); 10958 } 10959 }; 10960 ElementMirror.prototype.getMirrorEl = function () { 10961 var sourceElRect = this.sourceElRect; 10962 var mirrorEl = this.mirrorEl; 10963 if (!mirrorEl) { 10964 mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true); // cloneChildren=true 10965 // we don't want long taps or any mouse interaction causing selection/menus. 10966 // would use preventSelection(), but that prevents selectstart, causing problems. 10967 mirrorEl.classList.add('fc-unselectable'); 10968 mirrorEl.classList.add('fc-dragging'); 10969 core.applyStyle(mirrorEl, { 10970 position: 'fixed', 10971 zIndex: this.zIndex, 10972 visibility: '', 10973 boxSizing: 'border-box', 10974 width: sourceElRect.right - sourceElRect.left, 10975 height: sourceElRect.bottom - sourceElRect.top, 10976 right: 'auto', 10977 bottom: 'auto', 10978 margin: 0 10979 }); 10980 this.parentNode.appendChild(mirrorEl); 10981 } 10982 return mirrorEl; 10983 }; 10984 return ElementMirror; 10985 }()); 10986 10987 /* 10988 Is a cache for a given element's scroll information (all the info that ScrollController stores) 10989 in addition the "client rectangle" of the element.. the area within the scrollbars. 10990 10991 The cache can be in one of two modes: 10992 - doesListening:false - ignores when the container is scrolled by someone else 10993 - doesListening:true - watch for scrolling and update the cache 10994 */ 10995 var ScrollGeomCache = /** @class */ (function (_super) { 10996 __extends(ScrollGeomCache, _super); 10997 function ScrollGeomCache(scrollController, doesListening) { 10998 var _this = _super.call(this) || this; 10999 _this.handleScroll = function () { 11000 _this.scrollTop = _this.scrollController.getScrollTop(); 11001 _this.scrollLeft = _this.scrollController.getScrollLeft(); 11002 _this.handleScrollChange(); 11003 }; 11004 _this.scrollController = scrollController; 11005 _this.doesListening = doesListening; 11006 _this.scrollTop = _this.origScrollTop = scrollController.getScrollTop(); 11007 _this.scrollLeft = _this.origScrollLeft = scrollController.getScrollLeft();
11008 _this.scrollWidth = scrollController.getScrollWidth(); 11009 _this.scrollHeight = scrollController.getScrollHeight(); 11010 _this.clientWidth = scrollController.getClientWidth(); 11011 _this.clientHeight = scrollController.getClientHeight(); 11012 _this.clientRect = _this.computeClientRect(); // do last in case it needs cached values 11013 if (_this.doesListening) { 11014 _this.getEventTarget().addEventListener('scroll', _this.handleScroll); 11015 } 11016 return _this; 11017 } 11018 ScrollGeomCache.prototype.destroy = function () { 11019 if (this.doesListening) { 11020 this.getEventTarget().removeEventListener('scroll', this.handleScroll); 11021 } 11022 }; 11023 ScrollGeomCache.prototype.getScrollTop = function () { 11024 return this.scrollTop; 11025 }; 11026 ScrollGeomCache.prototype.getScrollLeft = function () { 11027 return this.scrollLeft; 11028 }; 11029 ScrollGeomCache.prototype.setScrollTop = function (top) { 11030 this.scrollController.setScrollTop(top); 11031 if (!this.doesListening) { 11032 // we are not relying on the element to normalize out-of-bounds scroll values 11033 // so we need to sanitize ourselves 11034 this.scrollTop = Math.max(Math.min(top, this.getMaxScrollTop()), 0); 11035 this.handleScrollChange(); 11036 } 11037 }; 11038 ScrollGeomCache.prototype.setScrollLeft = function (top) { 11039 this.scrollController.setScrollLeft(top); 11040 if (!this.doesListening) { 11041 // we are not relying on the element to normalize out-of-bounds scroll values 11042 // so we need to sanitize ourselves 11043 this.scrollLeft = Math.max(Math.min(top, this.getMaxScrollLeft()), 0); 11044 this.handleScrollChange(); 11045 } 11046 }; 11047 ScrollGeomCache.prototype.getClientWidth = function () { 11048 return this.clientWidth; 11049 }; 11050 ScrollGeomCache.prototype.getClientHeight = function () { 11051 return this.clientHeight; 11052 }; 11053 ScrollGeomCache.prototype.getScrollWidth = function () { 11054 return this.scrollWidth; 11055 }; 11056 ScrollGeomCache.prototype.getScrollHeight = function () { 11057 return this.scrollHeight; 11058 }; 11059 ScrollGeomCache.prototype.handleScrollChange = function () { 11060 }; 11061 return ScrollGeomCache; 11062 }(core.ScrollController)); 11063 var ElementScrollGeomCache = /** @class */ (function (_super) { 11064 __extends(ElementScrollGeomCache, _super); 11065 function ElementScrollGeomCache(el, doesListening) { 11066 return _super.call(this, new core.ElementScrollController(el), doesListening) || this; 11067 } 11068 ElementScrollGeomCache.prototype.getEventTarget = function () { 11069 return this.scrollController.el; 11070 }; 11071 ElementScrollGeomCache.prototype.computeClientRect = function () { 11072 return core.computeInnerRect(this.scrollController.el); 11073 }; 11074 return ElementScrollGeomCache; 11075 }(ScrollGeomCache)); 11076 var WindowScrollGeomCache = /** @class */ (function (_super) { 11077 __extends(WindowScrollGeomCache, _super); 11078 function WindowScrollGeomCache(doesListening) { 11079 return _super.call(this, new core.WindowScrollController(), doesListening) || this; 11080 } 11081 WindowScrollGeomCache.prototype.getEventTarget = function () { 11082 return window; 11083 }; 11084 WindowScrollGeomCache.prototype.computeClientRect = function () { 11085 return { 11086 left: this.scrollLeft, 11087 right: this.scrollLeft + this.clientWidth, 11088 top: this.scrollTop, 11089 bottom: this.scrollTop + this.clientHeight 11090 }; 11091 }; 11092 // the window is the only scroll object that changes it's rectangle relative 11093 // to the document's topleft as it scrolls 11094 WindowScrollGeomCache.prototype.handleScrollChange = function () { 11095 this.clientRect = this.computeClientRect(); 11096 }; 11097 return WindowScrollGeomCache; 11098 }(ScrollGeomCache)); 11099 11100 // If available we are using native "performance" API instead of "Date" 11101 // Read more about it on MDN: 11102 // https://developer.mozilla.org/en-US/docs/Web/API/Performance 11103 var getTime = typeof performance === 'function' ? performance.now : Date.now; 11104 /* 11105 For a pointer interaction, automatically scrolls certain scroll containers when the pointer 11106 approaches the edge. 11107 11108 The caller must call start + handleMove + stop. 11109 */ 11110 var AutoScroller = /** @class */ (function () { 11111 function AutoScroller() { 11112 var _this = this; 11113 // options that can be set by caller 11114 this.isEnabled = true; 11115 this.scrollQuery = [window, '.fc-scroller']; 11116 this.edgeThreshold = 50; // pixels 11117 this.maxVelocity = 300; // pixels per second 11118 // internal state 11119 this.pointerScreenX = null; 11120 this.pointerScreenY = null; 11121 this.isAnimating = false;
11122 this.scrollCaches = null; 11123 // protect against the initial pointerdown being too close to an edge and starting the scroll 11124 this.everMovedUp = false; 11125 this.everMovedDown = false; 11126 this.everMovedLeft = false; 11127 this.everMovedRight = false; 11128 this.animate = function () { 11129 if (_this.isAnimating) { // wasn't cancelled between animation calls 11130 var edge = _this.computeBestEdge(_this.pointerScreenX + window.pageXOffset, _this.pointerScreenY + window.pageYOffset); 11131 if (edge) { 11132 var now = getTime(); 11133 _this.handleSide(edge, (now - _this.msSinceRequest) / 1000); 11134 _this.requestAnimation(now); 11135 } 11136 else { 11137 _this.isAnimating = false; // will stop animation 11138 } 11139 } 11140 }; 11141 } 11142 AutoScroller.prototype.start = function (pageX, pageY) { 11143 if (this.isEnabled) { 11144 this.scrollCaches = this.buildCaches(); 11145 this.pointerScreenX = null; 11146 this.pointerScreenY = null; 11147 this.everMovedUp = false; 11148 this.everMovedDown = false; 11149 this.everMovedLeft = false; 11150 this.everMovedRight = false; 11151 this.handleMove(pageX, pageY); 11152 } 11153 }; 11154 AutoScroller.prototype.handleMove = function (pageX, pageY) { 11155 if (this.isEnabled) { 11156 var pointerScreenX = pageX - window.pageXOffset; 11157 var pointerScreenY = pageY - window.pageYOffset; 11158 var yDelta = this.pointerScreenY === null ? 0 : pointerScreenY - this.pointerScreenY; 11159 var xDelta = this.pointerScreenX === null ? 0 : pointerScreenX - this.pointerScreenX; 11160 if (yDelta < 0) { 11161 this.everMovedUp = true; 11162 } 11163 else if (yDelta > 0) { 11164 this.everMovedDown = true; 11165 } 11166 if (xDelta < 0) { 11167 this.everMovedLeft = true; 11168 } 11169 else if (xDelta > 0) { 11170 this.everMovedRight = true; 11171 } 11172 this.pointerScreenX = pointerScreenX; 11173 this.pointerScreenY = pointerScreenY; 11174 if (!this.isAnimating) { 11175 this.isAnimating = true; 11176 this.requestAnimation(getTime()); 11177 } 11178 } 11179 }; 11180 AutoScroller.prototype.stop = function () { 11181 if (this.isEnabled) { 11182 this.isAnimating = false; // will stop animation 11183 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 11184 var scrollCache = _a[_i]; 11185 scrollCache.destroy(); 11186 } 11187 this.scrollCaches = null; 11188 } 11189 }; 11190 AutoScroller.prototype.requestAnimation = function (now) { 11191 this.msSinceRequest = now; 11192 requestAnimationFrame(this.animate); 11193 }; 11194 AutoScroller.prototype.handleSide = function (edge, seconds) { 11195 var scrollCache = edge.scrollCache; 11196 var edgeThreshold = this.edgeThreshold; 11197 var invDistance = edgeThreshold - edge.distance; 11198 var velocity = // the closer to the edge, the faster we scroll 11199 (invDistance * invDistance) / (edgeThreshold * edgeThreshold) * // quadratic 11200 this.maxVelocity * seconds; 11201 var sign = 1; 11202 switch (edge.name) { 11203 case 'left': 11204 sign = -1; 11205 // falls through 11206 case 'right': 11207 scrollCache.setScrollLeft(scrollCache.getScrollLeft() + velocity * sign); 11208 break; 11209 case 'top': 11210 sign = -1; 11211 // falls through 11212 case 'bottom': 11213 scrollCache.setScrollTop(scrollCache.getScrollTop() + velocity * sign); 11214 break; 11215 } 11216 }; 11217 // left/top are relative to document topleft 11218 AutoScroller.prototype.computeBestEdge = function (left, top) { 11219 var edgeThreshold = this.edgeThreshold; 11220 var bestSide = null; 11221 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 11222 var scrollCache = _a[_i]; 11223 var rect = scrollCache.clientRect; 11224 var leftDist = left - rect.left; 11225 var rightDist = rect.right - left; 11226 var topDist = top - rect.top; 11227 var bottomDist = rect.bottom - top; 11228 // completely within the rect? 11229 if (leftDist >= 0 && rightDist >= 0 && topDist >= 0 && bottomDist >= 0) { 11230 if (topDist <= edgeThreshold && this.everMovedUp && scrollCache.canScrollUp() && 11231 (!bestSide || bestSide.distance > topDist)) { 11232 bestSide = { scrollCache: scrollCache, name: 'top', distance: topDist }; 11233 } 11234 if (bottomDist <= edgeThreshold && this.everMovedDown && scrollCache.canScrollDown() && 11235 (!bestSide || bestSide.distance > bottomDist)) { 11236 bestSide = { scrollCache: scrollCache, name: 'bottom', distance: bottomDist }; 11237 } 11238 if (leftDist <= edgeThreshold && this.everMovedLeft && scrollCache.canScrollLeft() && 11239 (!bestSide || bestSide.distance > leftDist)) { 11240 bestSide = { scrollCache: scrollCache, name: 'left', distance: leftDist }; 11241 } 11242 if (rightDist <= edgeThreshold && this.everMovedRight && scrollCache.canScrollRight() && 11243 (!bestSide || bestSide.distance > rightDist)) { 11244 bestSide = { scrollCache: scrollCache, name: 'right', distance: rightDist }; 11245 } 11246 } 11247 } 11248 return bestSide; 11249 }; 11250 AutoScroller.prototype.buildCaches = function () { 11251 return this.queryScrollEls().map(function (el) { 11252 if (el === window) { 11253 return new WindowScrollGeomCache(false); // false = don't listen to user-generated scrolls 11254 } 11255 else { 11256 return new ElementScrollGeomCache(el, false); // false = don't listen to user-generated scrolls 11257 } 11258 }); 11259 }; 11260 AutoScroller.prototype.queryScrollEls = function () { 11261 var els = []; 11262 for (var _i = 0, _a = this.scrollQuery; _i < _a.length; _i++) { 11263 var query = _a[_i]; 11264 if (typeof query === 'object') { 11265 els.push(query); 11266 } 11267 else { 11268 els.push.apply(els, Array.prototype.slice.call(document.querySelectorAll(query))); 11269 } 11270 } 11271 return els; 11272 }; 11273 return AutoScroller; 11274 }()); 11275 11276 /* 11277 Monitors dragging on an element. Has a number of high-level features: 11278 - minimum distance required before dragging 11279 - minimum wait time ("delay") before dragging 11280 - a mirror element that follows the pointer 11281 */ 11282 var FeaturefulElementDragging = /** @class */ (function (_super) { 11283 __extends(FeaturefulElementDragging, _super); 11284 function FeaturefulElementDragging(containerEl) { 11285 var _this = _super.call(this, containerEl) || this; 11286 // options that can be directly set by caller 11287 // the caller can also set the PointerDragging's options as well 11288 _this.delay = null; 11289 _this.minDistance = 0; 11290 _this.touchScrollAllowed = true; // prevents drag from starting and blocks scrolling during drag 11291 _this.mirrorNeedsRevert = false;
11292 _this.isInteracting = false; // is the user validly moving the pointer? lasts until pointerup 11293 _this.isDragging = false; // is it INTENTFULLY dragging? lasts until after revert animation 11294 _this.isDelayEnded = false; 11295 _this.isDistanceSurpassed = false; 11296 _this.delayTimeoutId = null; 11297 _this.onPointerDown = function (ev) { 11298 if (!_this.isDragging) { // so new drag doesn't happen while revert animation is going 11299 _this.isInteracting = true; 11300 _this.isDelayEnded = false; 11301 _this.isDistanceSurpassed = false; 11302 core.preventSelection(document.body); 11303 core.preventContextMenu(document.body); 11304 // prevent links from being visited if there's an eventual drag. 11305 // also prevents selection in older browsers (maybe?). 11306 // not necessary for touch, besides, browser would complain about passiveness. 11307 if (!ev.isTouch) { 11308 ev.origEvent.preventDefault(); 11309 } 11310 _this.emitter.trigger('pointerdown', ev); 11311 if (!_this.pointer.shouldIgnoreMove) { 11312 // actions related to initiating dragstart+dragmove+dragend... 11313 _this.mirror.setIsVisible(false); // reset. caller must set-visible 11314 _this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY); // must happen on first pointer down 11315 _this.startDelay(ev); 11316 if (!_this.minDistance) { 11317 _this.handleDistanceSurpassed(ev); 11318 } 11319 } 11320 } 11321 }; 11322 _this.onPointerMove = function (ev) { 11323 if (_this.isInteracting) { // if false, still waiting for previous drag's revert 11324 _this.emitter.trigger('pointermove', ev); 11325 if (!_this.isDistanceSurpassed) { 11326 var minDistance = _this.minDistance; 11327 var distanceSq = void 0; // current distance from the origin, squared 11328 var deltaX = ev.deltaX, deltaY = ev.deltaY; 11329 distanceSq = deltaX * deltaX + deltaY * deltaY; 11330 if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem 11331 _this.handleDistanceSurpassed(ev); 11332 } 11333 } 11334 if (_this.isDragging) { 11335 // a real pointer move? (not one simulated by scrolling) 11336 if (ev.origEvent.type !== 'scroll') { 11337 _this.mirror.handleMove(ev.pageX, ev.pageY); 11338 _this.autoScroller.handleMove(ev.pageX, ev.pageY); 11339 } 11340 _this.emitter.trigger('dragmove', ev); 11341 } 11342 } 11343 }; 11344 _this.onPointerUp = function (ev) { 11345 if (_this.isInteracting) { // if false, still waiting for previous drag's revert 11346 _this.isInteracting = false; 11347 core.allowSelection(document.body); 11348 core.allowContextMenu(document.body); 11349 _this.emitter.trigger('pointerup', ev); // can potentially set mirrorNeedsRevert 11350 if (_this.isDragging) { 11351 _this.autoScroller.stop(); 11352 _this.tryStopDrag(ev); // which will stop the mirror 11353 } 11354 if (_this.delayTimeoutId) { 11355 clearTimeout(_this.delayTimeoutId); 11356 _this.delayTimeoutId = null; 11357 } 11358 } 11359 }; 11360 var pointer = _this.pointer = new PointerDragging(containerEl); 11361 pointer.emitter.on('pointerdown', _this.onPointerDown); 11362 pointer.emitter.on('pointermove', _this.onPointerMove); 11363 pointer.emitter.on('pointerup', _this.onPointerUp); 11364 _this.mirror = new ElementMirror(); 11365 _this.autoScroller = new AutoScroller(); 11366 return _this; 11367 } 11368 FeaturefulElementDragging.prototype.destroy = function () { 11369 this.pointer.destroy(); 11370 }; 11371 FeaturefulElementDragging.prototype.startDelay = function (ev) { 11372 var _this = this; 11373 if (typeof this.delay === 'number') { 11374 this.delayTimeoutId = setTimeout(function () { 11375 _this.delayTimeoutId = null; 11376 _this.handleDelayEnd(ev); 11377 }, this.delay); // not assignable to number! 11378 } 11379 else { 11380 this.handleDelayEnd(ev); 11381 } 11382 }; 11383 FeaturefulElementDragging.prototype.handleDelayEnd = function (ev) { 11384 this.isDelayEnded = true; 11385 this.tryStartDrag(ev); 11386 }; 11387 FeaturefulElementDragging.prototype.handleDistanceSurpassed = function (ev) { 11388 this.isDistanceSurpassed = true; 11389 this.tryStartDrag(ev); 11390 }; 11391 FeaturefulElementDragging.prototype.tryStartDrag = function (ev) { 11392 if (this.isDelayEnded && this.isDistanceSurpassed) { 11393 if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) { 11394 this.isDragging = true; 11395 this.mirrorNeedsRevert = false;
11396 this.autoScroller.start(ev.pageX, ev.pageY); 11397 this.emitter.trigger('dragstart', ev); 11398 if (this.touchScrollAllowed === false) { 11399 this.pointer.cancelTouchScroll(); 11400 } 11401 } 11402 } 11403 }; 11404 FeaturefulElementDragging.prototype.tryStopDrag = function (ev) { 11405 // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events 11406 // that come from the document to fire beforehand. much more convenient this way. 11407 this.mirror.stop(this.mirrorNeedsRevert, this.stopDrag.bind(this, ev) // bound with args 11408 ); 11409 }; 11410 FeaturefulElementDragging.prototype.stopDrag = function (ev) { 11411 this.isDragging = false; 11412 this.emitter.trigger('dragend', ev); 11413 }; 11414 // fill in the implementations... 11415 FeaturefulElementDragging.prototype.setIgnoreMove = function (bool) { 11416 this.pointer.shouldIgnoreMove = bool; 11417 }; 11418 FeaturefulElementDragging.prototype.setMirrorIsVisible = function (bool) { 11419 this.mirror.setIsVisible(bool); 11420 }; 11421 FeaturefulElementDragging.prototype.setMirrorNeedsRevert = function (bool) { 11422 this.mirrorNeedsRevert = bool; 11423 }; 11424 FeaturefulElementDragging.prototype.setAutoScrollEnabled = function (bool) { 11425 this.autoScroller.isEnabled = bool; 11426 }; 11427 return FeaturefulElementDragging; 11428 }(core.ElementDragging)); 11429 11430 /* 11431 When this class is instantiated, it records the offset of an element (relative to the document topleft), 11432 and continues to monitor scrolling, updating the cached coordinates if it needs to. 11433 Does not access the DOM after instantiation, so highly performant. 11434 11435 Also keeps track of all scrolling/overflow:hidden containers that are parents of the given element 11436 and an determine if a given point is inside the combined clipping rectangle. 11437 */ 11438 var OffsetTracker = /** @class */ (function () { 11439 function OffsetTracker(el) { 11440 this.origRect = core.computeRect(el); 11441 // will work fine for divs that have overflow:hidden 11442 this.scrollCaches = core.getClippingParents(el).map(function (el) { 11443 return new ElementScrollGeomCache(el, true); // listen=true 11444 }); 11445 } 11446 OffsetTracker.prototype.destroy = function () { 11447 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 11448 var scrollCache = _a[_i]; 11449 scrollCache.destroy(); 11450 } 11451 }; 11452 OffsetTracker.prototype.computeLeft = function () { 11453 var left = this.origRect.left; 11454 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 11455 var scrollCache = _a[_i]; 11456 left += scrollCache.origScrollLeft - scrollCache.getScrollLeft(); 11457 } 11458 return left; 11459 }; 11460 OffsetTracker.prototype.computeTop = function () { 11461 var top = this.origRect.top; 11462 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 11463 var scrollCache = _a[_i]; 11464 top += scrollCache.origScrollTop - scrollCache.getScrollTop(); 11465 } 11466 return top; 11467 }; 11468 OffsetTracker.prototype.isWithinClipping = function (pageX, pageY) { 11469 var point = { left: pageX, top: pageY }; 11470 for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { 11471 var scrollCache = _a[_i]; 11472 if (!isIgnoredClipping(scrollCache.getEventTarget()) && 11473 !core.pointInsideRect(point, scrollCache.clientRect)) { 11474 return false; 11475 } 11476 } 11477 return true; 11478 }; 11479 return OffsetTracker; 11480 }()); 11481 // certain clipping containers should never constrain interactions, like <html> and <body> 11482 // https://github.com/fullcalendar/fullcalendar/issues/3615 11483 function isIgnoredClipping(node) { 11484 var tagName = node.tagName; 11485 return tagName === 'HTML' || tagName === 'BODY'; 11486 } 11487 11488 /* 11489 Tracks movement over multiple droppable areas (aka "hits") 11490 that exist in one or more DateComponents. 11491 Relies on an existing draggable. 11492 11493 emits: 11494 - pointerdown 11495 - dragstart 11496 - hitchange - fires initially, even if not over a hit 11497 - pointerup 11498 - (hitchange - again, to null, if ended over a hit) 11499 - dragend 11500 */ 11501 var HitDragging = /** @class */ (function () { 11502 function HitDragging(dragging, droppableStore) { 11503 var _this = this; 11504 // options that can be set by caller 11505 this.useSubjectCenter = false;
11506 this.requireInitial = true; // if doesn't start out on a hit, won't emit any events 11507 this.initialHit = null; 11508 this.movingHit = null; 11509 this.finalHit = null; // won't ever be populated if shouldIgnoreMove 11510 this.handlePointerDown = function (ev) { 11511 var dragging = _this.dragging; 11512 _this.initialHit = null; 11513 _this.movingHit = null; 11514 _this.finalHit = null; 11515 _this.prepareHits(); 11516 _this.processFirstCoord(ev); 11517 if (_this.initialHit || !_this.requireInitial) { 11518 dragging.setIgnoreMove(false); 11519 _this.emitter.trigger('pointerdown', ev); // TODO: fire this before computing processFirstCoord, so listeners can cancel. this gets fired by almost every handler :( 11520 } 11521 else { 11522 dragging.setIgnoreMove(true); 11523 } 11524 }; 11525 this.handleDragStart = function (ev) { 11526 _this.emitter.trigger('dragstart', ev); 11527 _this.handleMove(ev, true); // force = fire even if initially null 11528 }; 11529 this.handleDragMove = function (ev) { 11530 _this.emitter.trigger('dragmove', ev); 11531 _this.handleMove(ev); 11532 }; 11533 this.handlePointerUp = function (ev) { 11534 _this.releaseHits(); 11535 _this.emitter.trigger('pointerup', ev); 11536 }; 11537 this.handleDragEnd = function (ev) { 11538 if (_this.movingHit) { 11539 _this.emitter.trigger('hitupdate', null, true, ev); 11540 } 11541 _this.finalHit = _this.movingHit; 11542 _this.movingHit = null; 11543 _this.emitter.trigger('dragend', ev); 11544 }; 11545 this.droppableStore = droppableStore; 11546 dragging.emitter.on('pointerdown', this.handlePointerDown); 11547 dragging.emitter.on('dragstart', this.handleDragStart); 11548 dragging.emitter.on('dragmove', this.handleDragMove); 11549 dragging.emitter.on('pointerup', this.handlePointerUp); 11550 dragging.emitter.on('dragend', this.handleDragEnd); 11551 this.dragging = dragging; 11552 this.emitter = new core.EmitterMixin(); 11553 } 11554 // sets initialHit 11555 // sets coordAdjust 11556 HitDragging.prototype.processFirstCoord = function (ev) { 11557 var origPoint = { left: ev.pageX, top: ev.pageY }; 11558 var adjustedPoint = origPoint; 11559 var subjectEl = ev.subjectEl; 11560 var subjectRect; 11561 if (subjectEl !== document) { 11562 subjectRect = core.computeRect(subjectEl); 11563 adjustedPoint = core.constrainPoint(adjustedPoint, subjectRect); 11564 } 11565 var initialHit = this.initialHit = this.queryHitForOffset(adjustedPoint.left, adjustedPoint.top); 11566 if (initialHit) { 11567 if (this.useSubjectCenter && subjectRect) { 11568 var slicedSubjectRect = core.intersectRects(subjectRect, initialHit.rect); 11569 if (slicedSubjectRect) { 11570 adjustedPoint = core.getRectCenter(slicedSubjectRect); 11571 } 11572 } 11573 this.coordAdjust = core.diffPoints(adjustedPoint, origPoint); 11574 } 11575 else { 11576 this.coordAdjust = { left: 0, top: 0 }; 11577 } 11578 }; 11579 HitDragging.prototype.handleMove = function (ev, forceHandle) { 11580 var hit = this.queryHitForOffset(ev.pageX + this.coordAdjust.left, ev.pageY + this.coordAdjust.top); 11581 if (forceHandle || !isHitsEqual(this.movingHit, hit)) { 11582 this.movingHit = hit; 11583 this.emitter.trigger('hitupdate', hit, false, ev); 11584 } 11585 }; 11586 HitDragging.prototype.prepareHits = function () { 11587 this.offsetTrackers = core.mapHash(this.droppableStore, function (interactionSettings) { 11588 interactionSettings.component.buildPositionCaches(); 11589 return new OffsetTracker(interactionSettings.el); 11590 }); 11591 }; 11592 HitDragging.prototype.releaseHits = function () { 11593 var offsetTrackers = this.offsetTrackers; 11594 for (var id in offsetTrackers) { 11595 offsetTrackers[id].destroy(); 11596 } 11597 this.offsetTrackers = {}; 11598 }; 11599 HitDragging.prototype.queryHitForOffset = function (offsetLeft, offsetTop) { 11600 var _a = this, droppableStore = _a.droppableStore, offsetTrackers = _a.offsetTrackers; 11601 var bestHit = null; 11602 for (var id in droppableStore) { 11603 var component = droppableStore[id].component; 11604 var offsetTracker = offsetTrackers[id]; 11605 if (offsetTracker.isWithinClipping(offsetLeft, offsetTop)) { 11606 var originLeft = offsetTracker.computeLeft(); 11607 var originTop = offsetTracker.computeTop(); 11608 var positionLeft = offsetLeft - originLeft; 11609 var positionTop = offsetTop - originTop; 11610 var origRect = offsetTracker.origRect; 11611 var width = origRect.right - origRect.left; 11612 var height = origRect.bottom - origRect.top; 11613 if ( 11614 // must be within the element's bounds 11615 positionLeft >= 0 && positionLeft < width && 11616 positionTop >= 0 && positionTop < height) { 11617 var hit = component.queryHit(positionLeft, positionTop, width, height); 11618 if (hit && 11619 ( 11620 // make sure the hit is within activeRange, meaning it's not a deal cell 11621 !component.props.dateProfile || // hack for DayTile 11622 core.rangeContainsRange(component.props.dateProfile.activeRange, hit.dateSpan.range)) && 11623 (!bestHit || hit.layer > bestHit.layer)) { 11624 // TODO: better way to re-orient rectangle 11625 hit.rect.left += originLeft; 11626 hit.rect.right += originLeft; 11627 hit.rect.top += originTop; 11628 hit.rect.bottom += originTop; 11629 bestHit = hit; 11630 } 11631 } 11632 } 11633 } 11634 return bestHit; 11635 }; 11636 return HitDragging; 11637 }()); 11638 function isHitsEqual(hit0, hit1) { 11639 if (!hit0 && !hit1) { 11640 return true; 11641 } 11642 if (Boolean(hit0) !== Boolean(hit1)) { 11643 return false;
11644 } 11645 return core.isDateSpansEqual(hit0.dateSpan, hit1.dateSpan); 11646 } 11647 11648 /* 11649 Monitors when the user clicks on a specific date/time of a component. 11650 A pointerdown+pointerup on the same "hit" constitutes a click. 11651 */ 11652 var DateClicking = /** @class */ (function (_super) { 11653 __extends(DateClicking, _super); 11654 function DateClicking(settings) { 11655 var _this = _super.call(this, settings) || this; 11656 _this.handlePointerDown = function (ev) { 11657 var dragging = _this.dragging; 11658 // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired 11659 dragging.setIgnoreMove(!_this.component.isValidDateDownEl(dragging.pointer.downEl)); 11660 }; 11661 // won't even fire if moving was ignored 11662 _this.handleDragEnd = function (ev) { 11663 var component = _this.component; 11664 var pointer = _this.dragging.pointer; 11665 if (!pointer.wasTouchScroll) { 11666 var _a = _this.hitDragging, initialHit = _a.initialHit, finalHit = _a.finalHit; 11667 if (initialHit && finalHit && isHitsEqual(initialHit, finalHit)) { 11668 component.calendar.triggerDateClick(initialHit.dateSpan, initialHit.dayEl, component.view, ev.origEvent); 11669 } 11670 } 11671 }; 11672 var component = settings.component; 11673 // we DO want to watch pointer moves because otherwise finalHit won't get populated 11674 _this.dragging = new FeaturefulElementDragging(component.el); 11675 _this.dragging.autoScroller.isEnabled = false; 11676 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsToStore(settings)); 11677 hitDragging.emitter.on('pointerdown', _this.handlePointerDown); 11678 hitDragging.emitter.on('dragend', _this.handleDragEnd); 11679 return _this; 11680 } 11681 DateClicking.prototype.destroy = function () { 11682 this.dragging.destroy(); 11683 }; 11684 return DateClicking; 11685 }(core.Interaction)); 11686 11687 /* 11688 Tracks when the user selects a portion of time of a component, 11689 constituted by a drag over date cells, with a possible delay at the beginning of the drag. 11690 */ 11691 var DateSelecting = /** @class */ (function (_super) { 11692 __extends(DateSelecting, _super); 11693 function DateSelecting(settings) { 11694 var _this = _super.call(this, settings) || this; 11695 _this.dragSelection = null; 11696 _this.handlePointerDown = function (ev) { 11697 var _a = _this, component = _a.component, dragging = _a.dragging; 11698 var canSelect = component.opt('selectable') && 11699 component.isValidDateDownEl(ev.origEvent.target); 11700 // don't bother to watch expensive moves if component won't do selection 11701 dragging.setIgnoreMove(!canSelect); 11702 // if touch, require user to hold down 11703 dragging.delay = ev.isTouch ? getComponentTouchDelay(component) : null; 11704 }; 11705 _this.handleDragStart = function (ev) { 11706 _this.component.calendar.unselect(ev); // unselect previous selections 11707 }; 11708 _this.handleHitUpdate = function (hit, isFinal) { 11709 var calendar = _this.component.calendar; 11710 var dragSelection = null; 11711 var isInvalid = false; 11712 if (hit) { 11713 dragSelection = joinHitsIntoSelection(_this.hitDragging.initialHit, hit, calendar.pluginSystem.hooks.dateSelectionTransformers); 11714 if (!dragSelection || !_this.component.isDateSelectionValid(dragSelection)) { 11715 isInvalid = true; 11716 dragSelection = null; 11717 } 11718 } 11719 if (dragSelection) { 11720 calendar.dispatch({ type: 'SELECT_DATES', selection: dragSelection }); 11721 } 11722 else if (!isFinal) { // only unselect if moved away while dragging 11723 calendar.dispatch({ type: 'UNSELECT_DATES' }); 11724 } 11725 if (!isInvalid) {
11726 core.enableCursor(); 11727 } 11728 else { 11729 core.disableCursor(); 11730 } 11731 if (!isFinal) { 11732 _this.dragSelection = dragSelection; // only clear if moved away from all hits while dragging 11733 } 11734 }; 11735 _this.handlePointerUp = function (pev) { 11736 if (_this.dragSelection) { 11737 // selection is already rendered, so just need to report selection 11738 _this.component.calendar.triggerDateSelect(_this.dragSelection, pev); 11739 _this.dragSelection = null; 11740 } 11741 }; 11742 var component = settings.component; 11743 var dragging = _this.dragging = new FeaturefulElementDragging(component.el); 11744 dragging.touchScrollAllowed = false; 11745 dragging.minDistance = component.opt('selectMinDistance') || 0; 11746 dragging.autoScroller.isEnabled = component.opt('dragScroll'); 11747 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsToStore(settings)); 11748 hitDragging.emitter.on('pointerdown', _this.handlePointerDown); 11749 hitDragging.emitter.on('dragstart', _this.handleDragStart); 11750 hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); 11751 hitDragging.emitter.on('pointerup', _this.handlePointerUp); 11752 return _this; 11753 } 11754 DateSelecting.prototype.destroy = function () { 11755 this.dragging.destroy(); 11756 }; 11757 return DateSelecting; 11758 }(core.Interaction)); 11759 function getComponentTouchDelay(component) { 11760 var delay = component.opt('selectLongPressDelay'); 11761 if (delay == null) { 11762 delay = component.opt('longPressDelay'); 11763 } 11764 return delay; 11765 } 11766 function joinHitsIntoSelection(hit0, hit1, dateSelectionTransformers) { 11767 var dateSpan0 = hit0.dateSpan; 11768 var dateSpan1 = hit1.dateSpan; 11769 var ms = [ 11770 dateSpan0.range.start, 11771 dateSpan0.range.end, 11772 dateSpan1.range.start, 11773 dateSpan1.range.end 11774 ]; 11775 ms.sort(core.compareNumbers); 11776 var props = {}; 11777 for (var _i = 0, dateSelectionTransformers_1 = dateSelectionTransformers; _i < dateSelectionTransformers_1.length; _i++) { 11778 var transformer = dateSelectionTransformers_1[_i]; 11779 var res = transformer(hit0, hit1); 11780 if (res === false) { 11781 return null; 11782 } 11783 else if (res) { 11784 __assign(props, res); 11785 } 11786 } 11787 props.range = { start: ms[0], end: ms[3] }; 11788 props.allDay = dateSpan0.allDay; 11789 return props; 11790 } 11791 11792 var EventDragging = /** @class */ (function (_super) { 11793 __extends(EventDragging, _super); 11794 function EventDragging(settings) { 11795 var _this = _super.call(this, settings) || this; 11796 // internal state 11797 _this.subjectSeg = null; // the seg being selected/dragged 11798 _this.isDragging = false; 11799 _this.eventRange = null; 11800 _this.relevantEvents = null; // the events being dragged 11801 _this.receivingCalendar = null; 11802 _this.validMutation = null; 11803 _this.mutatedRelevantEvents = null; 11804 _this.handlePointerDown = function (ev) { 11805 var origTarget = ev.origEvent.target; 11806 var _a = _this, component = _a.component, dragging = _a.dragging; 11807 var mirror = dragging.mirror; 11808 var initialCalendar = component.calendar; 11809 var subjectSeg = _this.subjectSeg = core.getElSeg(ev.subjectEl); 11810 var eventRange = _this.eventRange = subjectSeg.eventRange; 11811 var eventInstanceId = eventRange.instance.instanceId; 11812 _this.relevantEvents = core.getRelevantEvents(initialCalendar.state.eventStore, eventInstanceId); 11813 dragging.minDistance = ev.isTouch ? 0 : component.opt('eventDragMinDistance'); 11814 dragging.delay = 11815 // only do a touch delay if touch and this event hasn't been selected yet 11816 (ev.isTouch && eventInstanceId !== component.props.eventSelection) ? 11817 getComponentTouchDelay$1(component) : 11818 null; 11819 mirror.parentNode = initialCalendar.el; 11820 mirror.revertDuration = component.opt('dragRevertDuration'); 11821 var isValid = component.isValidSegDownEl(origTarget) && 11822 !core.elementClosest(origTarget, '.fc-resizer'); // NOT on a resizer 11823 dragging.setIgnoreMove(!isValid); 11824 // disable dragging for elements that are resizable (ie, selectable) 11825 // but are not draggable 11826 _this.isDragging = isValid && 11827 ev.subjectEl.classList.contains('fc-draggable'); 11828 }; 11829 _this.handleDragStart = function (ev) { 11830 var initialCalendar = _this.component.calendar; 11831 var eventRange = _this.eventRange; 11832 var eventInstanceId = eventRange.instance.instanceId; 11833 if (ev.isTouch) { 11834 // need to select a different event? 11835 if (eventInstanceId !== _this.component.props.eventSelection) { 11836 initialCalendar.dispatch({ type: 'SELECT_EVENT', eventInstanceId: eventInstanceId }); 11837 } 11838 } 11839 else { 11840 // if now using mouse, but was previous touch interaction, clear selected event 11841 initialCalendar.dispatch({ type: 'UNSELECT_EVENT' }); 11842 } 11843 if (_this.isDragging) { 11844 initialCalendar.unselect(ev); // unselect *date* selection 11845 initialCalendar.publiclyTrigger('eventDragStart', [ 11846 { 11847 el: _this.subjectSeg.el, 11848 event: new core.EventApi(initialCalendar, eventRange.def, eventRange.instance), 11849 jsEvent: ev.origEvent, 11850 view: _this.component.view 11851 } 11852 ]); 11853 } 11854 }; 11855 _this.handleHitUpdate = function (hit, isFinal) { 11856 if (!_this.isDragging) { 11857 return; 11858 } 11859 var relevantEvents = _this.relevantEvents; 11860 var initialHit = _this.hitDragging.initialHit; 11861 var initialCalendar = _this.component.calendar; 11862 // states based on new hit 11863 var receivingCalendar = null; 11864 var mutation = null; 11865 var mutatedRelevantEvents = null; 11866 var isInvalid = false;
11867 var interaction = { 11868 affectedEvents: relevantEvents, 11869 mutatedEvents: core.createEmptyEventStore(), 11870 isEvent: true, 11871 origSeg: _this.subjectSeg 11872 }; 11873 if (hit) { 11874 var receivingComponent = hit.component; 11875 receivingCalendar = receivingComponent.calendar; 11876 if (initialCalendar === receivingCalendar || 11877 receivingComponent.opt('editable') && receivingComponent.opt('droppable')) { 11878 mutation = computeEventMutation(initialHit, hit, receivingCalendar.pluginSystem.hooks.eventDragMutationMassagers); 11879 if (mutation) { 11880 mutatedRelevantEvents = core.applyMutationToEventStore(relevantEvents, receivingCalendar.eventUiBases, mutation, receivingCalendar); 11881 interaction.mutatedEvents = mutatedRelevantEvents; 11882 if (!receivingComponent.isInteractionValid(interaction)) { 11883 isInvalid = true; 11884 mutation = null; 11885 mutatedRelevantEvents = null; 11886 interaction.mutatedEvents = core.createEmptyEventStore(); 11887 } 11888 } 11889 } 11890 else { 11891 receivingCalendar = null; 11892 } 11893 } 11894 _this.displayDrag(receivingCalendar, interaction); 11895 if (!isInvalid) { 11896 core.enableCursor(); 11897 } 11898 else { 11899 core.disableCursor(); 11900 } 11901 if (!isFinal) { 11902 if (initialCalendar === receivingCalendar && // TODO: write test for this 11903 isHitsEqual(initialHit, hit)) { 11904 mutation = null; 11905 } 11906 _this.dragging.setMirrorNeedsRevert(!mutation); 11907 // render the mirror if no already-rendered mirror 11908 // TODO: wish we could somehow wait for dispatch to guarantee render 11909 _this.dragging.setMirrorIsVisible(!hit || !document.querySelector('.fc-mirror')); 11910 // assign states based on new hit 11911 _this.receivingCalendar = receivingCalendar; 11912 _this.validMutation = mutation; 11913 _this.mutatedRelevantEvents = mutatedRelevantEvents; 11914 } 11915 }; 11916 _this.handlePointerUp = function () { 11917 if (!_this.isDragging) { 11918 _this.cleanup(); // because handleDragEnd won't fire 11919 } 11920 }; 11921 _this.handleDragEnd = function (ev) { 11922 if (_this.isDragging) { 11923 var initialCalendar_1 = _this.component.calendar; 11924 var initialView = _this.component.view; 11925 var _a = _this, receivingCalendar = _a.receivingCalendar, validMutation = _a.validMutation; 11926 var eventDef = _this.eventRange.def; 11927 var eventInstance = _this.eventRange.instance; 11928 var eventApi = new core.EventApi(initialCalendar_1, eventDef, eventInstance); 11929 var relevantEvents_1 = _this.relevantEvents; 11930 var mutatedRelevantEvents = _this.mutatedRelevantEvents; 11931 var finalHit = _this.hitDragging.finalHit; 11932 _this.clearDrag(); // must happen after revert animation 11933 initialCalendar_1.publiclyTrigger('eventDragStop', [ 11934 { 11935 el: _this.subjectSeg.el, 11936 event: eventApi, 11937 jsEvent: ev.origEvent, 11938 view: initialView 11939 } 11940 ]); 11941 if (validMutation) { 11942 // dropped within same calendar 11943 if (receivingCalendar === initialCalendar_1) { 11944 initialCalendar_1.dispatch({ 11945 type: 'MERGE_EVENTS', 11946 eventStore: mutatedRelevantEvents 11947 }); 11948 var transformed = {}; 11949 for (var _i = 0, _b = initialCalendar_1.pluginSystem.hooks.eventDropTransformers; _i < _b.length; _i++) { 11950 var transformer = _b[_i]; 11951 __assign(transformed, transformer(validMutation, initialCalendar_1)); 11952 } 11953 var eventDropArg = __assign({}, transformed, { el: ev.subjectEl, delta: validMutation.datesDelta, oldEvent: eventApi, event: new core.EventApi(// the data AFT
11953ER the mutation 11954 initialCalendar_1, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null), revert: function () { 11955 initialCalendar_1.dispatch({ 11956 type: 'MERGE_EVENTS', 11957 eventStore: relevantEvents_1 11958 }); 11959 }, jsEvent: ev.origEvent, view: initialView }); 11960 initialCalendar_1.publiclyTrigger('eventDrop', [eventDropArg]); 11961 // dropped in different calendar 11962 } 11963 else if (receivingCalendar) { 11964 initialCalendar_1.publiclyTrigger('eventLeave', [ 11965 { 11966 draggedEl: ev.subjectEl, 11967 event: eventApi, 11968 view: initialView 11969 } 11970 ]); 11971 initialCalendar_1.dispatch({ 11972 type: 'REMOVE_EVENT_INSTANCES', 11973 instances: _this.mutatedRelevantEvents.instances 11974 }); 11975 receivingCalendar.dispatch({ 11976 type: 'MERGE_EVENTS', 11977 eventStore: _this.mutatedRelevantEvents 11978 }); 11979 if (ev.isTouch) { 11980 receivingCalendar.dispatch({ 11981 type: 'SELECT_EVENT', 11982 eventInstanceId: eventInstance.instanceId 11983 }); 11984 } 11985 var dropArg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: ev.subjectEl, jsEvent: ev.origEvent, view: finalHit.component // should this be finalHit.component.view? See #4644 11986 }); 11987 receivingCalendar.publiclyTrigger('drop', [dropArg]); 11988 receivingCalendar.publiclyTrigger('eventReceive', [ 11989 { 11990 draggedEl: ev.subjectEl, 11991 event: new core.EventApi(// the data AFTER the mutation 11992 receivingCalendar, mutatedRelevantEvents.defs[eventDef.defId], mutatedRelevantEvents.instances[eventInstance.instanceId]), 11993 view: finalHit.component // should this be finalHit.component.view? See #4644 11994 } 11995 ]); 11996 } 11997 } 11998 else { 11999 initialCalendar_1.publiclyTrigger('_noEventDrop'); 12000 } 12001 } 12002 _this.cleanup(); 12003 }; 12004 var component = _this.component; 12005 var dragging = _this.dragging = new FeaturefulElementDragging(component.el); 12006 dragging.pointer.selector = EventDragging.SELECTOR; 12007 dragging.touchScrollAllowed = false; 12008 dragging.autoScroller.isEnabled = component.opt('dragScroll'); 12009 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsStore); 12010 hitDragging.useSubjectCenter = settings.useEventCenter; 12011 hitDragging.emitter.on('pointerdown', _this.handlePointerDown); 12012 hitDragging.emitter.on('dragstart', _this.handleDragStart); 12013 hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); 12014 hitDragging.emitter.on('pointerup', _this.handlePointerUp); 12015 hitDragging.emitter.on('dragend', _this.handleDragEnd); 12016 return _this; 12017 } 12018 EventDragging.prototype.destroy = function () { 12019 this.dragging.destroy(); 12020 }; 12021 // render a drag state on the next receivingCalendar 12022 EventDragging.prototype.displayDrag = function (nextCalendar, state) { 12023 var initialCalendar = this.component.calendar; 12024 var prevCalendar = this.receivingCalendar; 12025 // does the previous calendar need to be cleared? 12026 if (prevCalendar && prevCalendar !== nextCalendar) { 12027 // does the initial calendar need to be cleared? 12028 // if so, don't clear all the way. we still need to to hide the affectedEvents 12029 if (prevCalendar === initialCalendar) { 12030 prevCalendar.dispatch({ 12031 type: 'SET_EVENT_DRAG', 12032 state: { 12033 affectedEvents: state.affectedEvents, 12034 mutatedEvents: core.createEmptyEventStore(), 12035 isEvent: true, 12036 origSeg: state.origSeg 12037 } 12038 }); 12039 // completely clear the old calendar if it wasn't the initial 12040 } 12041 else { 12042 prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 12043 } 12044 } 12045 if (nextCalendar) { 12046 nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state }); 12047 } 12048 }; 12049 EventDragging.prototype.clearDrag = function () { 12050 var initialCalendar = this.component.calendar; 12051 var receivingCalendar = this.receivingCalendar; 12052 if (receivingCalendar) { 12053 receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 12054 } 12055 // the initial calendar might have an dummy drag state from displayDrag 12056 if (initialCalendar !== receivingCalendar) { 12057 initialCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 12058 } 12059 }; 12060 EventDragging.prototype.cleanup = function () { 12061 this.subjectSeg = null; 12062 this.isDragging = false;
12063 this.eventRange = null; 12064 this.relevantEvents = null; 12065 this.receivingCalendar = null; 12066 this.validMutation = null; 12067 this.mutatedRelevantEvents = null; 12068 }; 12069 EventDragging.SELECTOR = '.fc-draggable, .fc-resizable'; // TODO: test this in IE11 12070 return EventDragging; 12071 }(core.Interaction)); 12072 function computeEventMutation(hit0, hit1, massagers) { 12073 var dateSpan0 = hit0.dateSpan; 12074 var dateSpan1 = hit1.dateSpan; 12075 var date0 = dateSpan0.range.start; 12076 var date1 = dateSpan1.range.start; 12077 var standardProps = {}; 12078 if (dateSpan0.allDay !== dateSpan1.allDay) { 12079 standardProps.allDay = dateSpan1.allDay; 12080 standardProps.hasEnd = hit1.component.opt('allDayMaintainDuration'); 12081 if (dateSpan1.allDay) { 12082 // means date1 is already start-of-day, 12083 // but date0 needs to be converted 12084 date0 = core.startOfDay(date0); 12085 } 12086 } 12087 var delta = core.diffDates(date0, date1, hit0.component.dateEnv, hit0.component === hit1.component ? 12088 hit0.component.largeUnit : 12089 null); 12090 if (delta.milliseconds) { // has hours/minutes/seconds 12091 standardProps.allDay = false; 12092 } 12093 var mutation = { 12094 datesDelta: delta, 12095 standardProps: standardProps 12096 }; 12097 for (var _i = 0, massagers_1 = massagers; _i < massagers_1.length; _i++) { 12098 var massager = massagers_1[_i]; 12099 massager(mutation, hit0, hit1); 12100 } 12101 return mutation; 12102 } 12103 function getComponentTouchDelay$1(component) { 12104 var delay = component.opt('eventLongPressDelay'); 12105 if (delay == null) { 12106 delay = component.opt('longPressDelay'); 12107 } 12108 return delay; 12109 } 12110 12111 var EventDragging$1 = /** @class */ (function (_super) { 12112 __extends(EventDragging, _super); 12113 function EventDragging(settings) { 12114 var _this = _super.call(this, settings) || this; 12115 // internal state 12116 _this.draggingSeg = null; // TODO: rename to resizingSeg? subjectSeg? 12117 _this.eventRange = null; 12118 _this.relevantEvents = null; 12119 _this.validMutation = null; 12120 _this.mutatedRelevantEvents = null; 12121 _this.handlePointerDown = function (ev) { 12122 var component = _this.component; 12123 var seg = _this.querySeg(ev); 12124 var eventRange = _this.eventRange = seg.eventRange; 12125 _this.dragging.minDistance = component.opt('eventDragMinDistance'); 12126 // if touch, need to be working with a selected event 12127 _this.dragging.setIgnoreMove(!_this.component.isValidSegDownEl(ev.origEvent.target) || 12128 (ev.isTouch && _this.component.props.eventSelection !== eventRange.instance.instanceId)); 12129 }; 12130 _this.handleDragStart = function (ev) { 12131 var calendar = _this.component.calendar; 12132 var eventRange = _this.eventRange; 12133 _this.relevantEvents = core.getRelevantEvents(calendar.state.eventStore, _this.eventRange.instance.instanceId); 12134 _this.draggingSeg = _this.querySeg(ev); 12135 calendar.unselect(); 12136 calendar.publiclyTrigger('eventResizeStart', [ 12137 { 12138 el: _this.draggingSeg.el, 12139 event: new core.EventApi(calendar, eventRange.def, eventRange.instance), 12140 jsEvent: ev.origEvent, 12141 view: _this.component.view 12142 } 12143 ]); 12144 }; 12145 _this.handleHitUpdate = function (hit, isFinal, ev) { 12146 var calendar = _this.component.calendar; 12147 var relevantEvents = _this.relevantEvents; 12148 var initialHit = _this.hitDragging.initialHit; 12149 var eventInstance = _this.eventRange.instance; 12150 var mutation = null; 12151 var mutatedRelevantEvents = null; 12152 var isInvalid = false;
12153 var interaction = { 12154 affectedEvents: relevantEvents, 12155 mutatedEvents: core.createEmptyEventStore(), 12156 isEvent: true, 12157 origSeg: _this.draggingSeg 12158 }; 12159 if (hit) { 12160 mutation = computeMutation(initialHit, hit, ev.subjectEl.classList.contains('fc-start-resizer'), eventInstance.range, calendar.pluginSystem.hooks.eventResizeJoinTransforms); 12161 } 12162 if (mutation) { 12163 mutatedRelevantEvents = core.applyMutationToEventStore(relevantEvents, calendar.eventUiBases, mutation, calendar); 12164 interaction.mutatedEvents = mutatedRelevantEvents; 12165 if (!_this.component.isInteractionValid(interaction)) { 12166 isInvalid = true; 12167 mutation = null; 12168 mutatedRelevantEvents = null; 12169 interaction.mutatedEvents = null; 12170 } 12171 } 12172 if (mutatedRelevantEvents) { 12173 calendar.dispatch({ 12174 type: 'SET_EVENT_RESIZE', 12175 state: interaction 12176 }); 12177 } 12178 else { 12179 calendar.dispatch({ type: 'UNSET_EVENT_RESIZE' }); 12180 } 12181 if (!isInvalid) { 12182 core.enableCursor(); 12183 } 12184 else { 12185 core.disableCursor(); 12186 } 12187 if (!isFinal) { 12188 if (mutation && isHitsEqual(initialHit, hit)) { 12189 mutation = null; 12190 } 12191 _this.validMutation = mutation; 12192 _this.mutatedRelevantEvents = mutatedRelevantEvents; 12193 } 12194 }; 12195 _this.handleDragEnd = function (ev) { 12196 var calendar = _this.component.calendar; 12197 var view = _this.component.view; 12198 var eventDef = _this.eventRange.def; 12199 var eventInstance = _this.eventRange.instance; 12200 var eventApi = new core.EventApi(calendar, eventDef, eventInstance); 12201 var relevantEvents = _this.relevantEvents; 12202 var mutatedRelevantEvents = _this.mutatedRelevantEvents; 12203 calendar.publiclyTrigger('eventResizeStop', [ 12204 { 12205 el: _this.draggingSeg.el, 12206 event: eventApi, 12207 jsEvent: ev.origEvent, 12208 view: view 12209 } 12210 ]); 12211 if (_this.validMutation) { 12212 calendar.dispatch({ 12213 type: 'MERGE_EVENTS', 12214 eventStore: mutatedRelevantEvents 12215 }); 12216 calendar.publiclyTrigger('eventResize', [ 12217 { 12218 el: _this.draggingSeg.el, 12219 startDelta: _this.validMutation.startDelta || core.createDuration(0), 12220 endDelta: _this.validMutation.endDelta || core.createDuration(0), 12221 prevEvent: eventApi, 12222 event: new core.EventApi(// the data AFTER the mutation 12223 calendar, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null), 12224 revert: function () { 12225 calendar.dispatch({ 12226 type: 'MERGE_EVENTS', 12227 eventStore: relevantEvents 12228 }); 12229 }, 12230 jsEvent: ev.origEvent, 12231 view: view 12232 } 12233 ]); 12234 } 12235 else { 12236 calendar.publiclyTrigger('_noEventResize'); 12237 } 12238 // reset all internal state 12239 _this.draggingSeg = null; 12240 _this.relevantEvents = null; 12241 _this.validMutation = null; 12242 // okay to keep eventInstance around. useful to set it in handlePointerDown 12243 }; 12244 var component = settings.component; 12245 var dragging = _this.dragging = new FeaturefulElementDragging(component.el); 12246 dragging.pointer.selector = '.fc-resizer'; 12247 dragging.touchScrollAllowed = false;
12248 dragging.autoScroller.isEnabled = component.opt('dragScroll'); 12249 var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, core.interactionSettingsToStore(settings)); 12250 hitDragging.emitter.on('pointerdown', _this.handlePointerDown); 12251 hitDragging.emitter.on('dragstart', _this.handleDragStart); 12252 hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); 12253 hitDragging.emitter.on('dragend', _this.handleDragEnd); 12254 return _this; 12255 } 12256 EventDragging.prototype.destroy = function () { 12257 this.dragging.destroy(); 12258 }; 12259 EventDragging.prototype.querySeg = function (ev) { 12260 return core.getElSeg(core.elementClosest(ev.subjectEl, this.component.fgSegSelector)); 12261 }; 12262 return EventDragging; 12263 }(core.Interaction)); 12264 function computeMutation(hit0, hit1, isFromStart, instanceRange, transforms) { 12265 var dateEnv = hit0.component.dateEnv; 12266 var date0 = hit0.dateSpan.range.start; 12267 var date1 = hit1.dateSpan.range.start; 12268 var delta = core.diffDates(date0, date1, dateEnv, hit0.component.largeUnit); 12269 var props = {}; 12270 for (var _i = 0, transforms_1 = transforms; _i < transforms_1.length; _i++) { 12271 var transform = transforms_1[_i]; 12272 var res = transform(hit0, hit1); 12273 if (res === false) { 12274 return null; 12275 } 12276 else if (res) { 12277 __assign(props, res); 12278 } 12279 } 12280 if (isFromStart) { 12281 if (dateEnv.add(instanceRange.start, delta) < instanceRange.end) { 12282 props.startDelta = delta; 12283 return props; 12284 } 12285 } 12286 else { 12287 if (dateEnv.add(instanceRange.end, delta) > instanceRange.start) { 12288 props.endDelta = delta; 12289 return props; 12290 } 12291 } 12292 return null; 12293 } 12294 12295 var UnselectAuto = /** @class */ (function () { 12296 function UnselectAuto(calendar) { 12297 var _this = this; 12298 this.isRecentPointerDateSelect = false; // wish we could use a selector to detect date selection, but uses hit system 12299 this.onSelect = function (selectInfo) { 12300 if (selectInfo.jsEvent) { 12301 _this.isRecentPointerDateSelect = true; 12302 } 12303 }; 12304 this.onDocumentPointerUp = function (pev) { 12305 var _a = _this, calendar = _a.calendar, documentPointer = _a.documentPointer; 12306 var state = calendar.state; 12307 // touch-scrolling should never unfocus any type of selection 12308 if (!documentPointer.wasTouchScroll) { 12309 if (state.dateSelection && // an existing date selection? 12310 !_this.isRecentPointerDateSelect // a new pointer-initiated date selection since last onDocumentPointerUp? 12311 ) { 12312 var unselectAuto = calendar.viewOpt('unselectAuto'); 12313 var unselectCancel = calendar.viewOpt('unselectCancel'); 12314 if (unselectAuto && (!unselectAuto || !core.elementClosest(documentPointer.downEl, unselectCancel))) { 12315 calendar.unselect(pev); 12316 } 12317 } 12318 if (state.eventSelection && // an existing event selected? 12319 !core.elementClosest(documentPointer.downEl, EventDragging.SELECTOR) // interaction DIDN'T start on an event 12320 ) { 12321 calendar.dispatch({ type: 'UNSELECT_EVENT' }); 12322 } 12323 } 12324 _this.isRecentPointerDateSelect = false; 12325 }; 12326 this.calendar = calendar; 12327 var documentPointer = this.documentPointer = new PointerDragging(document); 12328 documentPointer.shouldIgnoreMove = true; 12329 documentPointer.shouldWatchScroll = false; 12330 documentPointer.emitter.on('pointerup', this.onDocumentPointerUp); 12331 /* 12332 TODO: better way to know about whether there was a selection with the pointer 12333 */ 12334 calendar.on('select', this.onSelect); 12335 } 12336 UnselectAuto.prototype.destroy = function () { 12337 this.calendar.off('select', this.onSelect); 12338 this.documentPointer.destroy(); 12339 }; 12340 return UnselectAuto; 12341 }()); 12342 12343 /* 12344 Given an already instantiated draggable object for one-or-more elements, 12345 Interprets any dragging as an attempt to drag an events that lives outside 12346 of a calendar onto a calendar. 12347 */
12348 var ExternalElementDragging = /** @class */ (function () { 12349 function ExternalElementDragging(dragging, suppliedDragMeta) { 12350 var _this = this; 12351 this.receivingCalendar = null; 12352 this.droppableEvent = null; // will exist for all drags, even if create:false 12353 this.suppliedDragMeta = null; 12354 this.dragMeta = null; 12355 this.handleDragStart = function (ev) { 12356 _this.dragMeta = _this.buildDragMeta(ev.subjectEl); 12357 }; 12358 this.handleHitUpdate = function (hit, isFinal, ev) { 12359 var dragging = _this.hitDragging.dragging; 12360 var receivingCalendar = null; 12361 var droppableEvent = null; 12362 var isInvalid = false; 12363 var interaction = { 12364 affectedEvents: core.createEmptyEventStore(), 12365 mutatedEvents: core.createEmptyEventStore(), 12366 isEvent: _this.dragMeta.create, 12367 origSeg: null 12368 }; 12369 if (hit) { 12370 receivingCalendar = hit.component.calendar; 12371 if (_this.canDropElOnCalendar(ev.subjectEl, receivingCalendar)) { 12372 droppableEvent = computeEventForDateSpan(hit.dateSpan, _this.dragMeta, receivingCalendar); 12373 interaction.mutatedEvents = core.eventTupleToStore(droppableEvent); 12374 isInvalid = !core.isInteractionValid(interaction, receivingCalendar); 12375 if (isInvalid) { 12376 interaction.mutatedEvents = core.createEmptyEventStore(); 12377 droppableEvent = null; 12378 } 12379 } 12380 } 12381 _this.displayDrag(receivingCalendar, interaction); 12382 // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?) 12383 // TODO: wish we could somehow wait for dispatch to guarantee render 12384 dragging.setMirrorIsVisible(isFinal || !droppableEvent || !document.querySelector('.fc-mirror')); 12385 if (!isInvalid) { 12386 core.enableCursor(); 12387 } 12388 else { 12389 core.disableCursor(); 12390 } 12391 if (!isFinal) { 12392 dragging.setMirrorNeedsRevert(!droppableEvent); 12393 _this.receivingCalendar = receivingCalendar; 12394 _this.droppableEvent = droppableEvent; 12395 } 12396 }; 12397 this.handleDragEnd = function (pev) { 12398 var _a = _this, receivingCalendar = _a.receivingCalendar, droppableEvent = _a.droppableEvent; 12399 _this.clearDrag(); 12400 if (receivingCalendar && droppableEvent) { 12401 var finalHit = _this.hitDragging.finalHit; 12402 var finalView = finalHit.component.view; 12403 var dragMeta = _this.dragMeta; 12404 var arg = __assign({}, receivingCalendar.buildDatePointApi(finalHit.dateSpan), { draggedEl: pev.subjectEl, jsEvent: pev.origEvent, view: finalView }); 12405 receivingCalendar.publiclyTrigger('drop', [arg]); 12406 if (dragMeta.create) { 12407 receivingCalendar.dispatch({ 12408 type: 'MERGE_EVENTS', 12409 eventStore: core.eventTupleToStore(droppableEvent) 12410 }); 12411 if (pev.isTouch) { 12412 receivingCalendar.dispatch({ 12413 type: 'SELECT_EVENT', 12414 eventInstanceId: droppableEvent.instance.instanceId 12415 }); 12416 } 12417 // signal that an external event landed 12418 receivingCalendar.publiclyTrigger('eventReceive', [ 12419 { 12420 draggedEl: pev.subjectEl, 12421 event: new core.EventApi(receivingCalendar, droppableEvent.def, droppableEvent.instance), 12422 view: finalView 12423 } 12424 ]); 12425 } 12426 } 12427 _this.receivingCalendar = null; 12428 _this.droppableEvent = null; 12429 }; 12430 var hitDragging = this.hitDragging = new HitDragging(dragging, core.interactionSettingsStore); 12431 hitDragging.requireInitial = false; // will start outside of a component 12432 hitDragging.emitter.on('dragstart', this.handleDragStart); 12433 hitDragging.emitter.on('hitupdate', this.handleHitUpdate); 12434 hitDragging.emitter.on('dragend', this.handleDragEnd); 12435 this.suppliedDragMeta = suppliedDragMeta; 12436 } 12437 ExternalElementDragging.prototype.buildDragMeta = function (sub
12437jectEl) { 12438 if (typeof this.suppliedDragMeta === 'object') { 12439 return core.parseDragMeta(this.suppliedDragMeta); 12440 } 12441 else if (typeof this.suppliedDragMeta === 'function') { 12442 return core.parseDragMeta(this.suppliedDragMeta(subjectEl)); 12443 } 12444 else { 12445 return getDragMetaFromEl(subjectEl); 12446 } 12447 }; 12448 ExternalElementDragging.prototype.displayDrag = function (nextCalendar, state) { 12449 var prevCalendar = this.receivingCalendar; 12450 if (prevCalendar && prevCalendar !== nextCalendar) { 12451 prevCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 12452 } 12453 if (nextCalendar) { 12454 nextCalendar.dispatch({ type: 'SET_EVENT_DRAG', state: state }); 12455 } 12456 }; 12457 ExternalElementDragging.prototype.clearDrag = function () { 12458 if (this.receivingCalendar) { 12459 this.receivingCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); 12460 } 12461 }; 12462 ExternalElementDragging.prototype.canDropElOnCalendar = function (el, receivingCalendar) { 12463 var dropAccept = receivingCalendar.opt('dropAccept'); 12464 if (typeof dropAccept === 'function') { 12465 return dropAccept(el); 12466 } 12467 else if (typeof dropAccept === 'string' && dropAccept) { 12468 return Boolean(core.elementMatches(el, dropAccept)); 12469 } 12470 return true; 12471 }; 12472 return ExternalElementDragging; 12473 }()); 12474 // Utils for computing event store from the DragMeta 12475 // ---------------------------------------------------------------------------------------------------- 12476 function computeEventForDateSpan(dateSpan, dragMeta, calendar) { 12477 var defProps = __assign({}, dragMeta.leftoverProps); 12478 for (var _i = 0, _a = calendar.pluginSystem.hooks.externalDefTransforms; _i < _a.length; _i++) { 12479 var transform = _a[_i]; 12480 __assign(defProps, transform(dateSpan, dragMeta)); 12481 } 12482 var def = core.parseEventDef(defProps, dragMeta.sourceId, dateSpan.allDay, calendar.opt('forceEventDuration') || Boolean(dragMeta.duration), // hasEnd 12483 calendar); 12484 var start = dateSpan.range.start; 12485 // only rely on time info if drop zone is all-day, 12486 // otherwise, we already know the time 12487 if (dateSpan.allDay && dragMeta.startTime) { 12488 start = calendar.dateEnv.add(start, dragMeta.startTime); 12489 } 12490 var end = dragMeta.duration ? 12491 calendar.dateEnv.add(start, dragMeta.duration) : 12492 calendar.getDefaultEventEnd(dateSpan.allDay, start); 12493 var instance = core.createEventInstance(def.defId, { start: start, end: end }); 12494 return { def: def, instance: instance }; 12495 } 12496 // Utils for extracting data from element 12497 // ---------------------------------------------------------------------------------------------------- 12498 function getDragMetaFromEl(el) { 12499 var str = getEmbeddedElData(el, 'event'); 12500 var obj = str ? 12501 JSON.parse(str) : 12502 { create: false }; // if no embedded data, assume no event creation 12503 return core.parseDragMeta(obj); 12504 } 12505 core.config.dataAttrPrefix = ''; 12506 function getEmbeddedElData(el, name) { 12507 var prefix = core.config.dataAttrPrefix; 12508 var prefixedName = (prefix ? prefix + '-' : '') + name; 12509 return el.getAttribute('data-' + prefixedName) || ''; 12510 } 12511 12512 /* 12513 Makes an element (that is *external* to any calendar) draggable. 12514 Can pass in data that determines how an event will be created when dropped onto a calendar. 12515 Leverages FullCalendar's internal drag-n-drop functionality WITHOUT a third-party drag system. 12516 */ 12517 var ExternalDraggable = /** @class */ (function () { 12518 function ExternalDraggable(el, settings) { 12519 var _this = this; 12520 if (settings === void 0) { settings = {}; } 12521 this.handlePointerDown = function (ev) { 12522 var dragging = _this.dragging; 12523 var _a = _this.settings, minDistance = _a.minDistance, longPressDelay = _a.longPressDelay; 12524 dragging.minDistance = 12525 minDistance != null ? 12526 minDistance : 12527 (ev.isTouch ? 0 : core.globalDefaults.eventDragMinDistance); 12528 dragging.delay = 12529 ev.isTouch ? // TODO: eventually read eventLongPressDelay instead vvv 12530 (longPressDelay != null ? longPressDelay : core.globalDefaults.longPressDelay) : 12531 0; 12532 }; 12533 this.handleDragStart = function (ev) { 12534 if (ev.isTouch && 12535 _this.dragging.delay && 12536 ev.subjectEl.classList.contains('fc-event')) { 12537 _this.dragging.mirror.getMirrorEl().classList.add('fc-selected'); 12538 } 12539 }; 12540 this.settings = settings; 12541 var dragging = this.dragging = new FeaturefulElementDragging(el); 12542 dragging.touchScrollAllowed = false;
12543 if (settings.itemSelector != null) { 12544 dragging.pointer.selector = settings.itemSelector; 12545 } 12546 if (settings.appendTo != null) { 12547 dragging.mirror.parentNode = settings.appendTo; // TODO: write tests 12548 } 12549 dragging.emitter.on('pointerdown', this.handlePointerDown); 12550 dragging.emitter.on('dragstart', this.handleDragStart); 12551 new ExternalElementDragging(dragging, settings.eventData); 12552 } 12553 ExternalDraggable.prototype.destroy = function () { 12554 this.dragging.destroy(); 12555 }; 12556 return ExternalDraggable; 12557 }()); 12558 12559 /* 12560 Detects when a *THIRD-PARTY* drag-n-drop system interacts with elements. 12561 The third-party system is responsible for drawing the visuals effects of the drag. 12562 This class simply monitors for pointer movements and fires events. 12563 It also has the ability to hide the moving element (the "mirror") during the drag. 12564 */ 12565 var InferredElementDragging = /** @class */ (function (_super) { 12566 __extends(InferredElementDragging, _super); 12567 function InferredElementDragging(containerEl) { 12568 var _this = _super.call(this, containerEl) || this; 12569 _this.shouldIgnoreMove = false; 12570 _this.mirrorSelector = ''; 12571 _this.currentMirrorEl = null; 12572 _this.handlePointerDown = function (ev) { 12573 _this.emitter.trigger('pointerdown', ev); 12574 if (!_this.shouldIgnoreMove) { 12575 // fire dragstart right away. does not support delay or min-distance 12576 _this.emitter.trigger('dragstart', ev); 12577 } 12578 }; 12579 _this.handlePointerMove = function (ev) { 12580 if (!_this.shouldIgnoreMove) { 12581 _this.emitter.trigger('dragmove', ev); 12582 } 12583 }; 12584 _this.handlePointerUp = function (ev) { 12585 _this.emitter.trigger('pointerup', ev); 12586 if (!_this.shouldIgnoreMove) { 12587 // fire dragend right away. does not support a revert animation 12588 _this.emitter.trigger('dragend', ev); 12589 } 12590 }; 12591 var pointer = _this.pointer = new PointerDragging(containerEl); 12592 pointer.emitter.on('pointerdown', _this.handlePointerDown); 12593 pointer.emitter.on('pointermove', _this.handlePointerMove); 12594 pointer.emitter.on('pointerup', _this.handlePointerUp); 12595 return _this; 12596 } 12597 InferredElementDragging.prototype.destroy = function () { 12598 this.pointer.destroy(); 12599 }; 12600 InferredElementDragging.prototype.setIgnoreMove = function (bool) { 12601 this.shouldIgnoreMove = bool; 12602 }; 12603 InferredElementDragging.prototype.setMirrorIsVisible = function (bool) { 12604 if (bool) { 12605 // restore a previously hidden element. 12606 // use the reference in case the selector class has already been removed. 12607 if (this.currentMirrorEl) { 12608 this.currentMirrorEl.style.visibility = ''; 12609 this.currentMirrorEl = null; 12610 } 12611 } 12612 else { 12613 var mirrorEl = this.mirrorSelector ? 12614 document.querySelector(this.mirrorSelector) : 12615 null; 12616 if (mirrorEl) { 12617 this.currentMirrorEl = mirrorEl; 12618 mirrorEl.style.visibility = 'hidden'; 12619 } 12620 } 12621 }; 12622 return InferredElementDragging; 12623 }(core.ElementDragging)); 12624 12625 /* 12626 Bridges third-party drag-n-drop systems with FullCalendar. 12627 Must be instantiated and destroyed by caller. 12628 */ 12629 var ThirdPartyDraggable = /** @class */ (function () { 12630 function ThirdPartyDraggable(containerOrSettings, settings) { 12631 var containerEl = document; 12632 if ( 12633 // wish we could just test instanceof EventTarget, but doesn't work in IE11 12634 containerOrSettings === document || 12635 containerOrSettings instanceof Element) { 12636 containerEl = containerOrSettings; 12637 settings = settings || {}; 12638 } 12639 else { 12640 settings = (containerOrSettings || {}); 12641 } 12642 var dragging = this.dragging = new InferredElementDragging(containerEl); 12643 if (typeof settings.itemSelector === 'string') { 12644 dragging.pointer.selector = settings.itemSelector; 12645 } 12646 else if (containerEl === document) { 12647 dragging.pointer.selector = '[data-event]'; 12648 } 12649 if (typeof settings.mirrorSelector === 'string') { 12650 dragging.mirrorSelector = settings.mirrorSelector; 12651 } 12652 new ExternalElementDragging(dragging, settings.eventData); 12653 } 12654 ThirdPartyDraggable.prototype.destroy = function () { 12655 this.dragging.destroy(); 12656 }; 12657 return ThirdPartyDraggable; 12658 }()); 12659 12660 var main = core.createPlugin({ 12661 componentInteractions: [DateClicking, DateSelecting, EventDragging, EventDragging$1], 12662 calendarInteractions: [UnselectAuto], 12663 elementDraggingImpl: FeaturefulElementDragging 12664 }); 12665 12666 exports.Draggable = ExternalDraggable; 12667 exports.FeaturefulElementDragging = FeaturefulElementDragging; 12668 exports.PointerDragging = PointerDragging; 12669 exports.ThirdPartyDraggable = ThirdPartyDraggable; 12670 exports.default = main; 12671 12672 Object.defineProperty(exports, '__esModule', { value: true }); 12673 12674})); 12675 12676/*!
12677FullCalendar List View Plugin v4.3.0 12678Docs & License: https://fullcalendar.io/ 12679(c) 2019 Adam Shaw 12680*/ 12681 12682(function (global, factory) { 12683 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core')) : 12684 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) : 12685 (global = global || self, factory(global.FullCalendarList = {}, global.FullCalendar)); 12686}(this, function (exports, core) { 'use strict'; 12687 12688 /*! ***************************************************************************** 12689 Copyright (c) Microsoft Corporation. All rights reserved. 12690 Licensed under the Apache License, Version 2.0 (the "License"); you may not use 12691 this file except in compliance with the License. You may obtain a copy of the 12692 License at http://www.apache.org/licenses/LICENSE-2.0 12693 12694 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 12695 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 12696 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 12697 MERCHANTABLITY OR NON-INFRINGEMENT. 12698 12699 See the Apache Version 2.0 License for specific language governing permissions 12700 and limitations under the License. 12701 ***************************************************************************** */ 12702 /* global Reflect, Promise */ 12703 12704 var extendStatics = function(d, b) { 12705 extendStatics = Object.setPrototypeOf || 12706 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 12707 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 12708 return extendStatics(d, b); 12709 }; 12710 12711 function __extends(d, b) { 12712 extendStatics(d, b); 12713 function __() { this.constructor = d; } 12714 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 12715 } 12716 12717 var ListEventRenderer = /** @class */ (function (_super) { 12718 __extends(ListEventRenderer, _super); 12719 function ListEventRenderer(listView) { 12720 var _this = _super.call(this, listView.context) || this; 12721 _this.listView = listView; 12722 return _this; 12723 } 12724 ListEventRenderer.prototype.attachSegs = function (segs) { 12725 if (!segs.length) { 12726 this.listView.renderEmptyMessage(); 12727 } 12728 else { 12729 this.listView.renderSegList(segs); 12730 } 12731 }; 12732 ListEventRenderer.prototype.detachSegs = function () { 12733 }; 12734 // generates the HTML for a single event row 12735 ListEventRenderer.prototype.renderSegHtml = function (seg) { 12736 var _a = this.context, view = _a.view, theme = _a.theme; 12737 var eventRange = seg.eventRange; 12738 var eventDef = eventRange.def; 12739 var eventInstance = eventRange.instance; 12740 var eventUi = eventRange.ui; 12741 var url = eventDef.url; 12742 var classes = ['fc-list-item'].concat(eventUi.classNames); 12743 var bgColor = eventUi.backgroundColor; 12744 var timeHtml; 12745 if (eventDef.allDay) { 12746 timeHtml = core.getAllDayHtml(view); 12747 } 12748 else if (core.isMultiDayRange(eventRange.range)) { 12749 if (seg.isStart) { 12750 timeHtml = core.htmlEscape(this._getTimeText(eventInstance.range.start, seg.end, false // allDay 12751 )); 12752 } 12753 else if (seg.isEnd) { 12754 timeHtml = core.htmlEscape(this._getTimeText(seg.start, eventInstance.range.end, false // allDay 12755 )); 12756 } 12757 else { // inner segment that lasts the whole day 12758 timeHtml = core.getAllDayHtml(view); 12759 } 12760 } 12761 else { 12762 // Display the normal time text for the *event's* times 12763 timeHtml = core.htmlEscape(this.getTimeText(eventRange)); 12764 } 12765 if (url) { 12766 classes.push('fc-has-url'); 12767 } 12768 return '<tr class="' + classes.join(' ') + '">' + 12769 (this.displayEventTime ? 12770 '<td class="fc-list-item-time ' + theme.getClass('widgetContent') + '">' + 12771 (timeHtml || '') + 12772 '</td>' : 12773 '') + 12774 '<td class="fc-list-item-marker ' + theme.getClass('widgetContent') + '">' + 12775 '<span class="fc-event-dot"' + 12776 (bgColor ? 12777 ' style="background-color:' + bgColor + '"' : 12778 '') + 12779 '></span>' + 12780 '</td>' + 12781 '<td class="fc-list-item-title ' + theme.getClass('widgetContent') + '">' + 12782 '<a' + (url ? ' href="' + core.htmlEscape(url) + '"' : '') + '>
12782' + 12783 core.htmlEscape(eventDef.title || '') + 12784 '</a>' + 12785 '</td>' + 12786 '</tr>'; 12787 }; 12788 // like "4:00am" 12789 ListEventRenderer.prototype.computeEventTimeFormat = function () { 12790 return { 12791 hour: 'numeric', 12792 minute: '2-digit', 12793 meridiem: 'short' 12794 }; 12795 }; 12796 return ListEventRenderer; 12797 }(core.FgEventRenderer)); 12798 12799 /* 12800 Responsible for the scroller, and forwarding event-related actions into the "grid". 12801 */ 12802 var ListView = /** @class */ (function (_super) { 12803 __extends(ListView, _super); 12804 function ListView(context, viewSpec, dateProfileGenerator, parentEl) { 12805 var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this; 12806 _this.computeDateVars = core.memoize(computeDateVars); 12807 _this.eventStoreToSegs = core.memoize(_this._eventStoreToSegs); 12808 var eventRenderer = _this.eventRenderer = new ListEventRenderer(_this); 12809 _this.renderContent = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer)); 12810 _this.el.classList.add('fc-list-view'); 12811 var listViewClassNames = (_this.theme.getClass('listView') || '').split(' '); // wish we didn't have to do this 12812 for (var _i = 0, listViewClassNames_1 = listViewClassNames; _i < listViewClassNames_1.length; _i++) { 12813 var listViewClassName = listViewClassNames_1[_i]; 12814 if (listViewClassName) { // in case input was empty string 12815 _this.el.classList.add(listViewClassName); 12816 } 12817 } 12818 _this.scroller = new core.ScrollComponent('hidden', // overflow x 12819 'auto' // overflow y 12820 ); 12821 _this.el.appendChild(_this.scroller.el); 12822 _this.contentEl = _this.scroller.el; // shortcut 12823 context.calendar.registerInteractiveComponent(_this, { 12824 el: _this.el 12825 // TODO: make aware that it doesn't do Hits 12826 }); 12827 return _this; 12828 } 12829 ListView.prototype.render = function (props) { 12830 var _a = this.computeDateVars(props.dateProfile), dayDates = _a.dayDates, dayRanges = _a.dayRanges; 12831 this.dayDates = dayDates; 12832 this.renderContent(this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges)); 12833 }; 12834 ListView.prototype.destroy = function () { 12835 _super.prototype.destroy.call(this); 12836 this.renderContent.unrender(); 12837 this.scroller.destroy(); // will remove the Grid too 12838 this.calendar.unregisterInteractiveComponent(this); 12839 }; 12840 ListView.prototype.updateSize = function (isResize, viewHeight, isAuto) { 12841 _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto); 12842 this.eventRenderer.computeSizes(isResize); 12843 this.eventRenderer.assignSizes(isResize); 12844 this.scroller.clear(); // sets height to 'auto' and clears overflow 12845 if (!isAuto) { 12846 this.scroller.setHeight(this.computeScrollerHeight(viewHeight)); 12847 } 12848 }; 12849 ListView.prototype.computeScrollerHeight = function (viewHeight) { 12850 return viewHeight - 12851 core.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller 12852 }; 12853 ListView.prototype._eventStoreToSegs = function (eventStore, eventUiBases, dayRanges) { 12854 return this.eventRangesToSegs(core.sliceEventStore(eventStore, eventUiBases, this.props.dateProfile.activeRange, this.nextDayThreshold).fg, dayRanges); 12855 }; 12856 ListView.prototype.eventRangesToSegs = function (eventRanges, dayRanges) { 12857 var segs = []; 12858 for (var _i = 0, eventRanges_1 = eventRanges; _i < eventRanges_1.length; _i++) { 12859 var eventRange = eventRanges_1[_i]; 12860 segs.push.apply(segs, this.eventRangeToSegs(eventRange, dayRanges)); 12861 } 12862 return segs; 12863 }; 12864 ListView.prototype.eventRangeToSegs = function (eventRange, dayRanges) { 12865 var _a = this, dateEnv = _a.dateEnv, nextDayThreshold = _a.nextDayThreshold; 12866 var range = eventRange.range; 12867 var allDay = eventRange.def.allDay; 12868 var dayIndex; 12869 var segRange; 12870 var seg; 12871 var segs = []; 12872 for (dayIndex = 0; dayIndex < dayRanges.length; dayIndex++) { 12873 segRange = core.intersectRanges(range, dayRanges[dayIndex]); 12874 if (segRange) { 12875 seg = { 12876 component: this, 12877 eventRange: eventRange, 12878 start: segRange.start, 12879 end: segRange.end, 12880 isStart: eventRange.isStart && segRange.start.valueOf() === range.start.valueOf(), 12881 isEnd: eventRange.isEnd && segRange.end.valueOf() === range.end.valueOf(), 12882 dayIndex: dayIndex 12883 }; 12884 segs.push(seg); 12885 // detect when range won't go fully into the next day, 12886 // and mutate the latest seg to the be the end. 12887 if (!seg.isEnd && !allDay && 12888 dayIndex + 1 < dayRanges.length && 12889 range.end < 12890 dateEnv.add(dayRanges[dayIndex + 1].start, nextDayThreshold)) { 12891 seg.end = range.end; 12892 seg.isEnd = true; 12893 break; 12894 } 12895 } 12896 } 12897 return segs; 12898 }; 12899 ListView.prototype.renderEmptyMessage = function () { 12900 this.contentEl.innerHTML = 12901 '<div class="fc-list-empty-wrap2">' + // TODO: try less wraps 12902 '<div class="fc-list-empty-wrap1">' + 12903 '<div class="fc-list-empty">' + 12904 core.htmlEscape(this.opt('noEventsMessage')) + 12905 '</div>' + 12906 '</div>' + 12907 '</div>'; 12908 }; 12909 // called by ListEventRenderer 12910 ListView.prototype.renderSegList = function (allSegs) { 12911 var segsByDay = this.groupSegsByDay(allSegs); // sparse array 12912 var dayIndex; 12913 var daySegs; 12914 var i; 12915 var tableEl = core.htmlToElement('<table class="fc-list-table ' + this.calendar.theme.getClass('tableList') + '"><tbody></tbody></table>'); 12916 var tbodyEl = tableEl.querySelector('tbody'); 12917 for (dayIndex = 0; dayIndex < segsByDay.length; dayIndex++) { 12918 daySegs = segsByDay[dayIndex]; 12919 if (daySegs) { // sparse array, so might be undefined 12920 // append a day header 12921 tbodyEl.appendChild(this.buildDayHeaderRow(this.dayDates[dayIndex])); 12922 daySegs = this.eventRenderer.sortEventSegs(daySegs); 12923 for (i = 0;
12923 i < daySegs.length; i++) { 12924 tbodyEl.appendChild(daySegs[i].el); // append event row 12925 } 12926 } 12927 } 12928 this.contentEl.innerHTML = ''; 12929 this.contentEl.appendChild(tableEl); 12930 }; 12931 // Returns a sparse array of arrays, segs grouped by their dayIndex 12932 ListView.prototype.groupSegsByDay = function (segs) { 12933 var segsByDay = []; // sparse array 12934 var i; 12935 var seg; 12936 for (i = 0; i < segs.length; i++) { 12937 seg = segs[i]; 12938 (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = [])) 12939 .push(seg); 12940 } 12941 return segsByDay; 12942 }; 12943 // generates the HTML for the day headers that live amongst the event rows 12944 ListView.prototype.buildDayHeaderRow = function (dayDate) { 12945 var dateEnv = this.dateEnv; 12946 var mainFormat = core.createFormatter(this.opt('listDayFormat')); // TODO: cache 12947 var altFormat = core.createFormatter(this.opt('listDayAltFormat')); // TODO: cache 12948 return core.createElement('tr', { 12949 className: 'fc-list-heading', 12950 'data-date': dateEnv.formatIso(dayDate, { omitTime: true }) 12951 }, '<td class="' + (this.calendar.theme.getClass('tableListHeading') || 12952 this.calendar.theme.getClass('widgetHeader')) + '" colspan="3">' + 12953 (mainFormat ? 12954 core.buildGotoAnchorHtml(this, dayDate, { 'class': 'fc-list-heading-main' }, core.htmlEscape(dateEnv.format(dayDate, mainFormat)) // inner HTML 12955 ) : 12956 '') + 12957 (altFormat ? 12958 core.buildGotoAnchorHtml(this, dayDate, { 'class': 'fc-list-heading-alt' }, core.htmlEscape(dateEnv.format(dayDate, altFormat)) // inner HTML 12959 ) : 12960 '') + 12961 '</td>'); 12962 }; 12963 return ListView; 12964 }(core.View)); 12965 ListView.prototype.fgSegSelector = '.fc-list-item'; // which elements accept event actions 12966 function computeDateVars(dateProfile) { 12967 var dayStart = core.startOfDay(dateProfile.renderRange.start); 12968 var viewEnd = dateProfile.renderRange.end; 12969 var dayDates = []; 12970 var dayRanges = []; 12971 while (dayStart < viewEnd) { 12972 dayDates.push(dayStart); 12973 dayRanges.push({ 12974 start: dayStart, 12975 end: core.addDays(dayStart, 1) 12976 }); 12977 dayStart = core.addDays(dayStart, 1); 12978 } 12979 return { dayDates: dayDates, dayRanges: dayRanges }; 12980 } 12981 12982 var main = core.createPlugin({ 12983 views: { 12984 list: { 12985 class: ListView, 12986 buttonTextKey: 'list', 12987 listDayFormat: { month: 'long', day: 'numeric', year: 'numeric' } // like "January 1, 2016" 12988 }, 12989 listDay: { 12990 type: 'list', 12991 duration: { days: 1 }, 12992 listDayFormat: { weekday: 'long' } // day-of-week is all we need. full date is probably in header 12993 }, 12994 listWeek: { 12995 type: 'list', 12996 duration: { weeks: 1 }, 12997 listDayFormat: { weekday: 'long' }, 12998 listDayAltFormat: { month: 'long', day: 'numeric', year: 'numeric' } 12999 }, 13000 listMonth: { 13001 type: 'list', 13002 duration: { month: 1 }, 13003 listDayAltFormat: { weekday: 'long' } // day-of-week is nice-to-have 13004 }, 13005 listYear: { 13006 type: 'list', 13007 duration: { year: 1 }, 13008 listDayAltFormat: { weekday: 'long' } // day-of-week is nice-to-have 13009 } 13010 } 13011 }); 13012 13013 exports.ListView = ListView; 13014 exports.default = main; 13015 13016 Object.defineProperty(exports, '__esModule', { value: true }); 13017 13018})); 13019 13020/*! 13021FullCalendar Time Grid Plugin v4.3.0 13022Docs & License: https://fullcalendar.io/ 13023(c) 2019 Adam Shaw 13024*/ 13025 13026(function (global, factory) { 13027 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core'), require('@fullcalendar/daygri
13027d')) : 13028 typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core', '@fullcalendar/daygrid'], factory) : 13029 (global = global || self, factory(global.FullCalendarTimeGrid = {}, global.FullCalendar, global.FullCalendarDayGrid)); 13030}(this, function (exports, core, daygrid) { 'use strict'; 13031 13032 /*! ***************************************************************************** 13033 Copyright (c) Microsoft Corporation. All rights reserved. 13034 Licensed under the Apache License, Version 2.0 (the "License"); you may not use 13035 this file except in compliance with the License. You may obtain a copy of the 13036 License at http://www.apache.org/licenses/LICENSE-2.0 13037 13038 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13039 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 13040 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 13041 MERCHANTABLITY OR NON-INFRINGEMENT. 13042 13043 See the Apache Version 2.0 License for specific language governing permissions 13044 and limitations under the License. 13045 ***************************************************************************** */ 13046 /* global Reflect, Promise */ 13047 13048 var extendStatics = function(d, b) { 13049 extendStatics = Object.setPrototypeOf || 13050 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 13051 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 13052 return extendStatics(d, b); 13053 }; 13054 13055 function __extends(d, b) { 13056 extendStatics(d, b); 13057 function __() { this.constructor = d; } 13058 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 13059 } 13060 13061 var __assign = function() { 13062 __assign = Object.assign || function __assign(t) { 13063 for (var s, i = 1, n = arguments.length; i < n; i++) { 13064 s = arguments[i]; 13065 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 13066 } 13067 return t; 13068 }; 13069 return __assign.apply(this, arguments); 13070 }; 13071 13072 /* 13073 Only handles foreground segs. 13074 Does not own rendering. Use for low-level util methods by TimeGrid. 13075 */ 13076 var TimeGridEventRenderer = /** @class */ (function (_super) { 13077 __extends(TimeGridEventRenderer, _super); 13078 function TimeGridEventRenderer(timeGrid) { 13079 var _this = _super.call(this, timeGrid.context) || this; 13080 _this.timeGrid = timeGrid; 13081 _this.fullTimeFormat = core.createFormatter({ 13082 hour: 'numeric', 13083 minute: '2-digit', 13084 separator: _this.context.options.defaultRangeSeparator 13085 }); 13086 return _this; 13087 } 13088 // Given an array of foreground segments, render a DOM element for each, computes position, 13089 // and attaches to the column inner-container elements. 13090 TimeGridEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 13091 var segsByCol = this.timeGrid.groupSegsByCol(segs); 13092 // order the segs within each column 13093 // TODO: have groupSegsByCol do this? 13094 for (var col = 0; col < segsByCol.length; col++) { 13095 segsByCol[col] = this.sortEventSegs(segsByCol[col]); 13096 } 13097 this.segsByCol = segsByCol; 13098 this.timeGrid.attachSegsByCol(segsByCol, this.timeGrid.fgContainerEls); 13099 }; 13100 TimeGridEventRenderer.prototype.detachSegs = function (segs) { 13101 segs.forEach(function (seg) { 13102 core.removeElement(seg.el); 13103 }); 13104 this.segsByCol = null; 13105 }; 13106 TimeGridEventRenderer.prototype.computeSegSizes = function (allSegs) { 13107 var _a = this, timeGrid = _a.timeGrid, segsByCol = _a.segsByCol; 13108 var colCnt = timeGrid.colCnt; 13109 timeGrid.computeSegVerticals(allSegs); // horizontals relies on this 13110 if (segsByCol) { 13111 for (var col = 0; col < colCnt; col++) { 13112 this.computeSegHorizontals(segsByCol[col]); // compute horizontal coordinates, z-index's, and reorder the array 13113 } 13114 } 13115 }; 13116 TimeGridEventRenderer.prototype.assignSegSizes = function (allSegs) { 13117 var _a = this, timeGrid = _a.timeGrid, segsByCol = _a.segsByCol; 13118 var colCnt = timeGrid.colCnt; 13119 timeGrid.assignSegVerticals(allSegs); // horizontals relies on this 13120 if (segsByCol) { 13121 for (var col = 0; col < colCnt; col++) { 13122 this.assignSegCss(segsByCol[col]); 13123 } 13124 } 13125 }; 13126 // Computes a default event time formatting string if `eventTimeFormat` is not explicitly defined 13127 TimeGridEventRenderer.prototype.computeEventTimeFormat = function () { 13128 return { 13129 hour: 'numeric', 13130 minute: '2-digit', 13131 meridiem: false 13132 }; 13133 }; 13134 // Computes a default `displayEventEnd` value if one is not expliclty defined 13135 TimeGridEventRenderer.prototype.computeDisplayEventEnd = function () { 13136 return true; 13137 }; 13138 // Renders the HTML for a single event segment's default rendering 13139 TimeGridEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) { 13140 var view = this.context.view; 13141 var eventRange = seg.eventRange; 13142 var eventDef = eventRange.def; 13143 var eventUi = eventRange.ui; 13144 var allDay = eventDef.allDay; 13145 var isDraggable = view.computeEventDraggable(eventDef, eventUi); 13146 var isResizableFromStart = seg.isStart && view.computeEventStartResizable(eventDef, eventUi); 13147 var isResizableFromEnd = seg.isEnd && view.computeEventEndResizable(eventDef, eventUi);
13148 var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo); 13149 var skinCss = core.cssToStr(this.getSkinCss(eventUi)); 13150 var timeText; 13151 var fullTimeText; // more verbose time text. for the print stylesheet 13152 var startTimeText; // just the start time text 13153 classes.unshift('fc-time-grid-event'); 13154 // if the event appears to span more than one day... 13155 if (core.isMultiDayRange(eventRange.range)) { 13156 // Don't display time text on segments that run entirely through a day. 13157 // That would appear as midnight-midnight and would look dumb. 13158 // Otherwise, display the time text for the *segment's* times (like 6pm-midnight or midnight-10am) 13159 if (seg.isStart || seg.isEnd) { 13160 var unzonedStart = seg.start; 13161 var unzonedEnd = seg.end; 13162 timeText = this._getTimeText(unzonedStart, unzonedEnd, allDay); // TODO: give the timezones 13163 fullTimeText = this._getTimeText(unzonedStart, unzonedEnd, allDay, this.fullTimeFormat); 13164 startTimeText = this._getTimeText(unzonedStart, unzonedEnd, allDay, null, false); // displayEnd=false 13165 } 13166 } 13167 else { 13168 // Display the normal time text for the *event's* times 13169 timeText = this.getTimeText(eventRange); 13170 fullTimeText = this.getTimeText(eventRange, this.fullTimeFormat); 13171 startTimeText = this.getTimeText(eventRange, null, false); // displayEnd=false 13172 } 13173 return '<a class="' + classes.join(' ') + '"' + 13174 (eventDef.url ? 13175 ' href="' + core.htmlEscape(eventDef.url) + '"' : 13176 '') + 13177 (skinCss ? 13178 ' style="' + skinCss + '"' : 13179 '') + 13180 '>' + 13181 '<div class="fc-content">' + 13182 (timeText ? 13183 '<div class="fc-time"' + 13184 ' data-start="' + core.htmlEscape(startTimeText) + '"' + 13185 ' data-full="' + core.htmlEscape(fullTimeText) + '"' + 13186 '>' + 13187 '<span>' + core.htmlEscape(timeText) + '</span>' + 13188 '</div>' : 13189 '') + 13190 (eventDef.title ? 13191 '<div class="fc-title">' + 13192 core.htmlEscape(eventDef.title) + 13193 '</div>' : 13194 '') + 13195 '</div>' + 13196 /* TODO: write CSS for this 13197 (isResizableFromStart ? 13198 '<div class="fc-resizer fc-start-resizer"></div>' : 13199 '' 13200 ) + 13201 */ 13202 (isResizableFromEnd ? 13203 '<div class="fc-resizer fc-end-resizer"></div>' : 13204 '') + 13205 '</a>'; 13206 }; 13207 // Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each. 13208 // Assumed the segs are already ordered. 13209 // NOTE: Also reorders the given array by date! 13210 TimeGridEventRenderer.prototype.computeSegHorizontals = function (segs) { 13211 var levels; 13212 var level0; 13213 var i; 13214 levels = buildSlotSegLevels(segs); 13215 computeForwardSlotSegs(levels); 13216 if ((level0 = levels[0])) { 13217 for (i = 0; i < level0.length; i++) { 13218 computeSlotSegPressures(level0[i]); 13219 } 13220 for (i = 0; i < level0.length; i++) { 13221 this.computeSegForwardBack(level0[i], 0, 0); 13222 } 13223 } 13224 }; 13225 // Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range 13226 // from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and 13227 // seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left. 13228 // 13229 // The segment might be part of a "series", which means consecutive segments with the same pressure 13230 // who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of 13231 // segments behind this one in the current series, and `seriesBackwardCoord` is the starting 13232 // coordinate of the first segment in the series. 13233 TimeGridEventRenderer.prototype.computeSegForwardBack = function (seg, seriesBackwardPressure, seriesBackwardCoord) { 13234 var forwardSegs = seg.forwardSegs; 13235 var i; 13236 if (seg.forwardCoord === undefined) { // not already computed 13237 if (!forwardSegs.length) { 13238 // if there are no forward segments, this segment should butt up against the edge 13239 seg.forwardCoord = 1; 13240 } 13241 else { 13242 // sort highest pressure first 13243 this.sortForwardSegs(forwardSegs); 13244 // this segment's forwardCoord will be calculated from the backwardCoord of the 13245 // highest-pressure forward segment. 13246 this.computeSegForwardBack(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord); 13247 seg.forwardCoord = forwardSegs[0].backwardCoord; 13248 } 13249 // calculate the backwardCoord from the forwardCoord. consider the series 13250 seg.backwardCoord = seg.forwardCoord - 13251 (seg.forwardCoord - seriesBackwardCoord) / // available width for series 13252 (seriesBackwardPressure + 1); // # of segments in the series
13253 // use this segment's coordinates to computed the coordinates of the less-pressurized 13254 // forward segments 13255 for (i = 0; i < forwardSegs.length; i++) { 13256 this.computeSegForwardBack(forwardSegs[i], 0, seg.forwardCoord); 13257 } 13258 } 13259 }; 13260 TimeGridEventRenderer.prototype.sortForwardSegs = function (forwardSegs) { 13261 var objs = forwardSegs.map(buildTimeGridSegCompareObj); 13262 var specs = [ 13263 // put higher-pressure first 13264 { field: 'forwardPressure', order: -1 }, 13265 // put segments that are closer to initial edge first (and favor ones with no coords yet) 13266 { field: 'backwardCoord', order: 1 } 13267 ].concat(this.context.view.eventOrderSpecs); 13268 objs.sort(function (obj0, obj1) { 13269 return core.compareByFieldSpecs(obj0, obj1, specs); 13270 }); 13271 return objs.map(function (c) { 13272 return c._seg; 13273 }); 13274 }; 13275 // Given foreground event segments that have already had their position coordinates computed, 13276 // assigns position-related CSS values to their elements. 13277 TimeGridEventRenderer.prototype.assignSegCss = function (segs) { 13278 for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { 13279 var seg = segs_1[_i]; 13280 core.applyStyle(seg.el, this.generateSegCss(seg)); 13281 if (seg.level > 0) { 13282 seg.el.classList.add('fc-time-grid-event-inset'); 13283 } 13284 // if the event is short that the title will be cut off, 13285 // attach a className that condenses the title into the time area. 13286 if (seg.eventRange.def.title && seg.bottom - seg.top < 30) { 13287 seg.el.classList.add('fc-short'); // TODO: "condensed" is a better name 13288 } 13289 } 13290 }; 13291 // Generates an object with CSS properties/values that should be applied to an event segment element. 13292 // Contains important positioning-related properties that should be applied to any event element, customized or not. 13293 TimeGridEventRenderer.prototype.generateSegCss = function (seg) { 13294 var shouldOverlap = this.context.options.slotEventOverlap; 13295 var backwardCoord = seg.backwardCoord; // the left side if LTR. the right side if RTL. floating-point 13296 var forwardCoord = seg.forwardCoord; // the right side if LTR. the left side if RTL. floating-point 13297 var props = this.timeGrid.generateSegVerticalCss(seg); // get top/bottom first 13298 var isRtl = this.timeGrid.isRtl; 13299 var left; // amount of space from left edge, a fraction of the total width 13300 var right; // amount of space from right edge, a fraction of the total width 13301 if (shouldOverlap) { 13302 // double the width, but don't go beyond the maximum forward coordinate (1.0) 13303 forwardCoord = Math.min(1, backwardCoord + (forwardCoord - backwardCoord) * 2); 13304 } 13305 if (isRtl) { 13306 left = 1 - forwardCoord; 13307 right = backwardCoord; 13308 } 13309 else { 13310 left = backwardCoord; 13311 right = 1 - forwardCoord; 13312 } 13313 props.zIndex = seg.level + 1; // convert from 0-base to 1-based 13314 props.left = left * 100 + '%'; 13315 props.right = right * 100 + '%'; 13316 if (shouldOverlap && seg.forwardPressure) { 13317 // add padding to the edge so that forward stacked events don't cover the resizer's icon 13318 props[isRtl ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width 13319 } 13320 return props; 13321 }; 13322 return TimeGridEventRenderer; 13323 }(core.FgEventRenderer)); 13324 // Builds an array of segments "levels". The first level will be the leftmost tier of segments if the calendar is 13325 // left-to-right, or the rightmost if the calendar is right-to-left. Assumes the segments are already ordered by date. 13326 function buildSlotSegLevels(segs) { 13327 var levels = []; 13328 var i; 13329 var seg; 13330 var j; 13331 for (i = 0; i < segs.length; i++) { 13332 seg = segs[i]; 13333 // go through all the levels and stop on the first level where there are no collisions 13334 for (j = 0; j < levels.length; j++) { 13335 if (!computeSlotSegCollisions(seg, levels[j]).length) { 13336 break; 13337 } 13338 } 13339 seg.level = j; 13340 (levels[j] || (levels[j] = [])).push(seg); 13341 } 13342 return levels; 13343 } 13344 // For every segment, figure out the other segments that are in subsequent 13345 // levels that also occupy the same vertical space. Accumulate in seg.forwardSegs 13346 function computeForwardSlotSegs(levels) { 13347 var i; 13348 var level; 13349 var j; 13350 var seg; 13351 var k; 13352 for (i = 0; i < levels.length; i++) { 13353 level = levels[i]; 13354 for (j = 0; j < level.length; j++) { 13355 seg = level[j]; 13356 seg.forwardSegs = []; 13357 for (k = i + 1; k < levels.length; k++) { 13358 computeSlotSegCollisions(seg, levels[k], seg.forwardSegs); 13359 } 13360 } 13361 } 13362 } 13363 // Figure out which path forward (via seg.forwardSegs) results in the longest path until 13364 // the furthest edge is reached. The number of segments in this path will be seg.forwardPressure 13365 function computeSlotSegPressures(seg) { 13366 var forwardSegs = seg.forwardSegs; 13367 var forwardPressure = 0; 13368 var i; 13369 var forwardSeg; 13370 if (seg.forwardPressure === undefined) { // not already computed 13371 for (i = 0; i < forwardSegs.length; i++) { 13372 forwardSeg = forwardSegs[i]; 13373 // figure out the child's maximum forward path 13374 computeSlotSegPressures(forwardSeg); 13375 // either use the existing maximum, or use the child's forward pressure 13376 // plus one (for the forwardSeg itself) 13377 forwardPressure = Math.max(forwardPressure, 1 + forwardSeg.forwardPressure); 13378 } 13379 seg.forwardPressure = forwardPressure; 13380 } 13381 } 13382 // Find all the segments in `otherSegs` that vertically collide with `seg`. 13383 // Append into an optionally-supplied `results` array and return. 13384 function computeSlotSegCollisions(seg, otherSegs, results) { 13385 if (results === void 0) { results = []; } 13386 for (var i = 0; i < otherSegs.length; i++) { 13387 if (isSlotSegCollision(seg, otherSegs[i])) { 13388 results.push(otherSegs[i]); 13389 } 13390 } 13391 return results; 13392 } 13393 // Do these segments occupy the same vertical space? 13394 function isSlotSegCollision(seg1, seg2) { 13395 return seg1.bottom > seg2.top && seg1.top < seg2.bottom; 13396 } 13397 function buildTimeGridSegCompareObj(seg) { 13398 var obj = core.buildSegCompareObj(seg); 13399 obj.forwardPressure = seg.forwardPressure; 13400 obj.backwardCoord = seg.backwardCoord; 13401 return obj; 13402 } 13403 13404 var TimeGridMirrorRenderer = /** @class */ (function (_super) { 13405 __extends(TimeGridMirrorRenderer, _super); 13406 function TimeGridMirrorRenderer() { 13407 return _super !== null && _super.apply(this, arguments) || this; 13408 } 13409 TimeGridMirrorRenderer.prototype.attachSegs = function (segs, mirrorInfo) { 13410 this.segsByCol = this.timeGrid.groupSegsByCol(segs); 13411 this.timeGrid.attachSegsByCol(this.segsByCol, this.timeGrid.mirrorContainerEls); 13412 this.sourceSeg = mirrorInfo.sourceSeg; 13413 }; 13414 TimeGridMirrorRenderer.prototype.generateSegCss = function (seg) { 13415 var props = _super.prototype.generateSegCss.call(this, seg); 13416 var sourceSeg = this.sourceSeg; 13417 if (sourceSeg && sourceSeg.col === seg.col) { 13418 var sourceSegProps = _super.prototype.generateSegCss.call(this, sourceSeg); 13419 props.left = sourceSegProps.left; 13420 props.right = sourceSegProps.right; 13421 props.marginLeft = sourceSegProps.marginLeft; 13422 props.marginRight = sourceSegProps.marginRight; 13423 } 13424 return props; 13425 }; 13426 return TimeGridMirrorRenderer; 13427 }(TimeGridEventRenderer)); 13428 13429 var TimeGridFillRenderer = /** @class */ (function (_super) { 13430 __extends(TimeGridFillRenderer, _super); 13431 function TimeGridFillRenderer(timeGrid) { 13432 var _this = _super.call(this, timeGrid.context) || this; 13433 _this.timeGrid = timeGrid; 13434 return _this; 13435 } 13436 TimeGridFillRenderer.prototype.attachSegs = function (type, segs) { 13437 var timeGrid = this.timeGrid; 13438 var containerEls; 13439 // TODO: more efficient lookup 13440 if (type === 'bgEvent') { 13441 containerEls = timeGrid.bgContainerEls; 13442 } 13443 else if (type === 'businessHours') { 13444 containerEls = timeGrid.businessContainerEls; 13445 } 13446 else if (type === 'highlight') { 13447 containerEls = timeGrid.highlightContainerEls; 13448 } 13449 timeGrid.attachSegsByCol(timeGrid.groupSegsByCol(segs), containerEls); 13450 return segs.map(function (seg) { 13451 return seg.el; 13452 }); 13453 }; 13454 TimeGridFillRenderer.prototype.computeSegSizes = function (segs) { 13455 this.timeGrid.computeSegVerticals(segs); 13456 }; 13457 TimeGridFillRenderer.prototype.assignSegSizes = function (segs) { 13458 this.timeGrid.assignSegVerticals(segs); 13459 }; 13460 return TimeGridFillRenderer; 13461 }(core.FillRenderer)); 13462 13463 /* A component that renders one or more columns of vertical time slots 13464 ----------------------------------------------------------------------------------------------------------------------*/ 13465 // potential nice values for the slot-duration and interval-duration 13466 // from largest to smallest 13467 var AGENDA_STOCK_SUB_DURATIONS = [ 13468 { hours: 1 }, 13469 { minutes: 30 }, 13470 { minutes: 15 }, 13471 { seconds: 30 }, 13472 { seconds: 15 } 13473 ]; 13474 var TimeGrid = /** @class */ (function (_super) { 13475 __extends(TimeGrid, _super); 13476 function TimeGrid(context, el, renderProps) { 13477 var _this = _super.call(this, context, el) || this; 13478 _this.isSlatSizesDirty = false;
13479 _this.isColSizesDirty = false; 13480 _this.renderSlats = core.memoizeRendering(_this._renderSlats); 13481 var eventRenderer = _this.eventRenderer = new TimeGridEventRenderer(_this); 13482 var fillRenderer = _this.fillRenderer = new TimeGridFillRenderer(_this); 13483 _this.mirrorRenderer = new TimeGridMirrorRenderer(_this); 13484 var renderColumns = _this.renderColumns = core.memoizeRendering(_this._renderColumns, _this._unrenderColumns); 13485 _this.renderBusinessHours = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'), [renderColumns]); 13486 _this.renderDateSelection = core.memoizeRendering(_this._renderDateSelection, _this._unrenderDateSelection, [renderColumns]); 13487 _this.renderFgEvents = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderColumns]); 13488 _this.renderBgEvents = core.memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'), [renderColumns]); 13489 _this.renderEventSelection = core.memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]); 13490 _this.renderEventDrag = core.memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag, [renderColumns]); 13491 _this.renderEventResize = core.memoizeRendering(_this._renderEventResize, _this._unrenderEventResize, [renderColumns]); 13492 _this.processOptions(); 13493 el.innerHTML = 13494 '<div class="fc-bg"></div>' + 13495 '<div class="fc-slats"></div>' + 13496 '<hr class="fc-divider ' + _this.theme.getClass('widgetHeader') + '" style="display:none" />'; 13497 _this.rootBgContainerEl = el.querySelector('.fc-bg'); 13498 _this.slatContainerEl = el.querySelector('.fc-slats'); 13499 _this.bottomRuleEl = el.querySelector('.fc-divider'); 13500 _this.renderProps = renderProps; 13501 return _this; 13502 } 13503 /* Options 13504 ------------------------------------------------------------------------------------------------------------------*/ 13505 // Parses various options into properties of this object 13506 TimeGrid.prototype.processOptions = function () { 13507 var slotDuration = this.opt('slotDuration'); 13508 var snapDuration = this.opt('snapDuration'); 13509 var snapsPerSlot; 13510 var input; 13511 slotDuration = core.createDuration(slotDuration); 13512 snapDuration = snapDuration ? core.createDuration(snapDuration) : slotDuration; 13513 snapsPerSlot = core.wholeDivideDurations(slotDuration, snapDuration); 13514 if (snapsPerSlot === null) { 13515 snapDuration = slotDuration; 13516 snapsPerSlot = 1; 13517 // TODO: say warning? 13518 } 13519 this.slotDuration = slotDuration; 13520 this.snapDuration = snapDuration; 13521 this.snapsPerSlot = snapsPerSlot; 13522 // might be an array value (for TimelineView). 13523 // if so, getting the most granular entry (the last one probably). 13524 input = this.opt('slotLabelFormat'); 13525 if (Array.isArray(input)) { 13526 input = input[input.length - 1]; 13527 } 13528 this.labelFormat = core.createFormatter(input || { 13529 hour: 'numeric', 13530 minute: '2-digit', 13531 omitZeroMinute: true, 13532 meridiem: 'short' 13533 }); 13534 input = this.opt('slotLabelInterval'); 13535 this.labelInterval = input ? 13536 core.createDuration(input) : 13537 this.computeLabelInterval(slotDuration); 13538 }; 13539 // Computes an automatic value for slotLabelInterval 13540 TimeGrid.prototype.computeLabelInterval = function (slotDuration) { 13541 var i; 13542 var labelInterval; 13543 var slotsPerLabel; 13544 // find the smallest stock label interval that results in more than one slots-per-label 13545 for (i = AGENDA_STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) { 13546 labelInterval = core.createDuration(AGENDA_STOCK_SUB_DURATIONS[i]);
13547 slotsPerLabel = core.wholeDivideDurations(labelInterval, slotDuration); 13548 if (slotsPerLabel !== null && slotsPerLabel > 1) { 13549 return labelInterval; 13550 } 13551 } 13552 return slotDuration; // fall back 13553 }; 13554 /* Rendering 13555 ------------------------------------------------------------------------------------------------------------------*/ 13556 TimeGrid.prototype.render = function (props) { 13557 var cells = props.cells; 13558 this.colCnt = cells.length; 13559 this.renderSlats(props.dateProfile); 13560 this.renderColumns(props.cells, props.dateProfile); 13561 this.renderBusinessHours(props.businessHourSegs); 13562 this.renderDateSelection(props.dateSelectionSegs); 13563 this.renderFgEvents(props.fgEventSegs); 13564 this.renderBgEvents(props.bgEventSegs); 13565 this.renderEventSelection(props.eventSelection); 13566 this.renderEventDrag(props.eventDrag); 13567 this.renderEventResize(props.eventResize); 13568 }; 13569 TimeGrid.prototype.destroy = function () { 13570 _super.prototype.destroy.call(this); 13571 // should unrender everything else too 13572 this.renderSlats.unrender(); 13573 this.renderColumns.unrender(); 13574 }; 13575 TimeGrid.prototype.updateSize = function (isResize) { 13576 var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer; 13577 if (isResize || this.isSlatSizesDirty) { 13578 this.buildSlatPositions(); 13579 this.isSlatSizesDirty = false; 13580 } 13581 if (isResize || this.isColSizesDirty) { 13582 this.buildColPositions(); 13583 this.isColSizesDirty = false; 13584 } 13585 fillRenderer.computeSizes(isResize); 13586 eventRenderer.computeSizes(isResize); 13587 mirrorRenderer.computeSizes(isResize); 13588 fillRenderer.assignSizes(isResize); 13589 eventRenderer.assignSizes(isResize); 13590 mirrorRenderer.assignSizes(isResize); 13591 }; 13592 TimeGrid.prototype._renderSlats = function (dateProfile) { 13593 var theme = this.theme; 13594 this.slatContainerEl.innerHTML = 13595 '<table class="' + theme.getClass('tableGrid') + '">' + 13596 this.renderSlatRowHtml(dateProfile) + 13597 '</table>'; 13598 this.slatEls = core.findElements(this.slatContainerEl, 'tr'); 13599 this.slatPositions = new core.PositionCache(this.el, this.slatEls, false, true // vertical 13600 ); 13601 this.isSlatSizesDirty = true; 13602 }; 13603 // Generates the HTML for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL. 13604 TimeGrid.prototype.renderSlatRowHtml = function (dateProfile) { 13605 var _a = this, dateEnv = _a.dateEnv, theme = _a.theme, isRtl = _a.isRtl; 13606 var html = ''; 13607 var dayStart = core.startOfDay(dateProfile.renderRange.start); 13608 var slotTime = dateProfile.minTime; 13609 var slotIterator = core.createDuration(0); 13610 var slotDate; // will be on the view's first day, but we only care about its time 13611 var isLabeled; 13612 var axisHtml; 13613 // Calculate the time for each slot 13614 while (core.asRoughMs(slotTime) < core.asRoughMs(dateProfile.maxTime)) { 13615 slotDate = dateEnv.add(dayStart, slotTime); 13616 isLabeled = core.wholeDivideDurations(slotIterator, this.labelInterval) !== null; 13617 axisHtml = 13618 '<td class="fc-axis fc-time ' + theme.getClass('widgetContent') + '">' + 13619 (isLabeled ? 13620 '<span>' + // for matchCellWidths 13621 core.htmlEscape(dateEnv.format(slotDate, this.labelFormat)) + 13622 '</span>' : 13623 '') + 13624 '</td>'; 13625 html += 13626 '<tr data-time="' + core.formatIsoTimeString(slotDate) + '"' + 13627 (isLabeled ? '' : ' class="fc-minor"') + 13628 '>' + 13629 (!isRtl ? axisHtml : '') + 13630 '<td class="' + theme.getClass('widgetContent') + '"></td>' + 13631 (isRtl ? axisHtml : '') + 13632 '</tr>'; 13633 slotTime = core.addDurations(slotTime, this.slotDuration); 13634 slotIterator = core.addDurations(slotIterator, this.slotDuration); 13635 } 13636 return html; 13637 }; 13638 TimeGrid.prototype._renderColumns = function (cells, dateProfile) { 13639 var _a = this, theme = _a.theme, dateEnv = _a.dateEnv, view = _a.view; 13640 var bgRow = new daygrid.DayBgRow(this.context);
13641 this.rootBgContainerEl.innerHTML = 13642 '<table class="' + theme.getClass('tableGrid') + '">' + 13643 bgRow.renderHtml({ 13644 cells: cells, 13645 dateProfile: dateProfile, 13646 renderIntroHtml: this.renderProps.renderBgIntroHtml 13647 }) + 13648 '</table>'; 13649 this.colEls = core.findElements(this.el, '.fc-day, .fc-disabled-day'); 13650 for (var col = 0; col < this.colCnt; col++) { 13651 this.publiclyTrigger('dayRender', [ 13652 { 13653 date: dateEnv.toDate(cells[col].date), 13654 el: this.colEls[col], 13655 view: view 13656 } 13657 ]); 13658 } 13659 if (this.isRtl) { 13660 this.colEls.reverse(); 13661 } 13662 this.colPositions = new core.PositionCache(this.el, this.colEls, true, // horizontal 13663 false); 13664 this.renderContentSkeleton(); 13665 this.isColSizesDirty = true; 13666 }; 13667 TimeGrid.prototype._unrenderColumns = function () { 13668 this.unrenderContentSkeleton(); 13669 }; 13670 /* Content Skeleton 13671 ------------------------------------------------------------------------------------------------------------------*/ 13672 // Renders the DOM that the view's content will live in 13673 TimeGrid.prototype.renderContentSkeleton = function () { 13674 var parts = []; 13675 var skeletonEl; 13676 parts.push(this.renderProps.renderIntroHtml()); 13677 for (var i = 0; i < this.colCnt; i++) { 13678 parts.push('<td>' + 13679 '<div class="fc-content-col">' + 13680 '<div class="fc-event-container fc-mirror-container"></div>' + 13681 '<div class="fc-event-container"></div>' + 13682 '<div class="fc-highlight-container"></div>' + 13683 '<div class="fc-bgevent-container"></div>' + 13684 '<div class="fc-business-container"></div>' + 13685 '</div>' + 13686 '</td>'); 13687 } 13688 if (this.isRtl) { 13689 parts.reverse(); 13690 } 13691 skeletonEl = this.contentSkeletonEl = core.htmlToElement('<div class="fc-content-skeleton">' + 13692 '<table>' + 13693 '<tr>' + parts.join('') + '</tr>' + 13694 '</table>' + 13695 '</div>'); 13696 this.colContainerEls = core.findElements(skeletonEl, '.fc-content-col'); 13697 this.mirrorContainerEls = core.findElements(skeletonEl, '.fc-mirror-container'); 13698 this.fgContainerEls = core.findElements(skeletonEl, '.fc-event-container:not(.fc-mirror-container)'); 13699 this.bgContainerEls = core.findElements(skeletonEl, '.fc-bgevent-container'); 13700 this.highlightContainerEls = core.findElements(skeletonEl, '.fc-highlight-container'); 13701 this.businessContainerEls = core.findElements(skeletonEl, '.fc-business-container'); 13702 if (this.isRtl) { 13703 this.colContainerEls.reverse(); 13704 this.mirrorContainerEls.reverse(); 13705 this.fgContainerEls.reverse(); 13706 this.bgContainerEls.reverse(); 13707 this.highlightContainerEls.reverse(); 13708 this.businessContainerEls.reverse(); 13709 } 13710 this.el.appendChild(skeletonEl); 13711 }; 13712 TimeGrid.prototype.unrenderContentSkeleton = function () { 13713 core.removeElement(this.contentSkeletonEl); 13714 }; 13715 // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's col 13716 TimeGrid.prototype.groupSegsByCol = function (segs) { 13717 var segsByCol = []; 13718 var i; 13719 for (i = 0; i < this.colCnt; i++) { 13720 segsByCol.push([]); 13721 } 13722 for (i = 0; i < segs.length; i++) { 13723 segsByCol[segs[i].col].push(segs[i]); 13724 } 13725 return segsByCol; 13726 }; 13727 // Given segments grouped by column, insert the segments' elements into a parallel array of container 13728 // elements, each living within a column. 13729 TimeGrid.prototype.attachSegsByCol = function (segsByCol, containerEls) { 13730 var col; 13731 var segs; 13732 var i; 13733 for (col = 0; col < this.colCnt; col++) { // iterate each column grouping 13734 segs = segsByCol[col]; 13735 for (i = 0; i < segs.length; i++) { 13736 containerEls[col].appendChild(segs[i].el); 13737 } 13738 } 13739 }; 13740 /* Now Indicator 13741 ------------------------------------------------------------------------------------------------------------------*/ 13742 TimeGrid.prototype.getNowIndicatorUnit = function () { 13743 return 'minute'; // will refresh on the minute 13744 }; 13745 TimeGrid.prototype.renderNowIndicator = function (segs, date) { 13746 // HACK: if date columns not ready for some reason (scheduler) 13747 if (!this.colContainerEls) { 13748 return; 13749 } 13750 var top = this.computeDateTop(date); 13751 var nodes = []; 13752 var i; 13753 // render lines within the columns 13754 for (i = 0; i < segs.length; i++) { 13755 var lineEl = core.createElement('div', { className: 'fc-now-indicator fc-now-indicator-line' }); 13756 lineEl.style.top = top + 'px'; 13757 this.colContainerEls[segs[i].col].appendChild(lineEl); 13758 nodes.push(lineEl); 13759 } 13760 // render an arrow over the axis 13761 if (segs.length > 0) { // is the current time in view? 13762 var arrowEl = core.createElement('div', { className: 'fc-now-indicator fc-now-indicator-arrow' }); 13763 arrowEl.style.top = top + 'px'; 13764 this.contentSkeletonEl.appendChild(arrowEl); 13765 nodes.push(arrowEl); 13766 } 13767 this.nowIndicatorEls = nodes; 13768 }; 13769 TimeGrid.prototype.unrenderNowIndicator = function () { 13770 if (this.nowIndicatorEls) {
13771 this.nowIndicatorEls.forEach(core.removeElement); 13772 this.nowIndicatorEls = null; 13773 } 13774 }; 13775 /* Coordinates 13776 ------------------------------------------------------------------------------------------------------------------*/ 13777 TimeGrid.prototype.getTotalSlatHeight = function () { 13778 return this.slatContainerEl.getBoundingClientRect().height; 13779 }; 13780 // Computes the top coordinate, relative to the bounds of the grid, of the given date. 13781 // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight. 13782 TimeGrid.prototype.computeDateTop = function (when, startOfDayDate) { 13783 if (!startOfDayDate) { 13784 startOfDayDate = core.startOfDay(when); 13785 } 13786 return this.computeTimeTop(core.createDuration(when.valueOf() - startOfDayDate.valueOf())); 13787 }; 13788 // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration). 13789 TimeGrid.prototype.computeTimeTop = function (duration) { 13790 var len = this.slatEls.length; 13791 var dateProfile = this.props.dateProfile; 13792 var slatCoverage = (duration.milliseconds - core.asRoughMs(dateProfile.minTime)) / core.asRoughMs(this.slotDuration); // floating-point value of # of slots covered 13793 var slatIndex; 13794 var slatRemainder; 13795 // compute a floating-point number for how many slats should be progressed through. 13796 // from 0 to number of slats (inclusive) 13797 // constrained because minTime/maxTime might be customized. 13798 slatCoverage = Math.max(0, slatCoverage); 13799 slatCoverage = Math.min(len, slatCoverage); 13800 // an integer index of the furthest whole slat 13801 // from 0 to number slats (*exclusive*, so len-1) 13802 slatIndex = Math.floor(slatCoverage); 13803 slatIndex = Math.min(slatIndex, len - 1); 13804 // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition. 13805 // could be 1.0 if slatCoverage is covering *all* the slots 13806 slatRemainder = slatCoverage - slatIndex; 13807 return this.slatPositions.tops[slatIndex] + 13808 this.slatPositions.getHeight(slatIndex) * slatRemainder; 13809 }; 13810 // For each segment in an array, computes and assigns its top and bottom properties 13811 TimeGrid.prototype.computeSegVerticals = function (segs) { 13812 var eventMinHeight = this.opt('timeGridEventMinHeight'); 13813 var i; 13814 var seg; 13815 var dayDate; 13816 for (i = 0; i < segs.length; i++) { 13817 seg = segs[i]; 13818 dayDate = this.props.cells[seg.col].date; 13819 seg.top = this.computeDateTop(seg.start, dayDate); 13820 seg.bottom = Math.max(seg.top + eventMinHeight, this.computeDateTop(seg.end, dayDate)); 13821 } 13822 }; 13823 // Given segments that already have their top/bottom properties computed, applies those values to 13824 // the segments' elements. 13825 TimeGrid.prototype.assignSegVerticals = function (segs) { 13826 var i; 13827 var seg; 13828 for (i = 0; i < segs.length; i++) { 13829 seg = segs[i]; 13830 core.applyStyle(seg.el, this.generateSegVerticalCss(seg)); 13831 } 13832 }; 13833 // Generates an object with CSS properties for the top/bottom coordinates of a segment element 13834 TimeGrid.prototype.generateSegVerticalCss = function (seg) { 13835 return { 13836 top: seg.top, 13837 bottom: -seg.bottom // flipped because needs to be space beyond bottom edge of event container 13838 }; 13839 }; 13840 /* Sizing 13841 ------------------------------------------------------------------------------------------------------------------*/ 13842 TimeGrid.prototype.buildPositionCaches = function () { 13843 this.buildColPositions(); 13844 this.buildSlatPositions(); 13845 }; 13846 TimeGrid.prototype.buildColPositions = function () { 13847 this.colPositions.build(); 13848 }; 13849 TimeGrid.prototype.buildSlatPositions = function () { 13850 this.slatPositions.build(); 13851 }; 13852 /* Hit System 13853 ------------------------------------------------------------------------------------------------------------------*/ 13854 TimeGrid.prototype.positionToHit = function (positionLeft, positionTop) { 13855 var _a = this, dateEnv = _a.dateEnv, snapsPerSlot = _a.snapsPerSlot, slatPositions = _a.slatPositions, colPositions = _a.colPositions; 13856 var colIndex = colPositions.leftToIndex(positionLeft); 13857 var slatIndex = slatPositions.topToIndex(positionTop); 13858 if (colIndex != null && slatIndex != null) { 13859 var slatTop = slatPositions.tops[slatIndex]; 13860 var slatHeight = slatPositions.getHeight(slatIndex); 13861 var partial = (positionTop - slatTop) / slatHeight; // floating point number between 0 and 1 13862 var localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat 13863 var snapIndex = slatIndex * snapsPerSlot + localSnapIndex; 13864 var dayDate = this.props.cells[colIndex].date; 13865 var time = core.addDurations(this.props.dateProfile.minTime, core.multiplyDuration(this.snapDuration, snapIndex)); 13866 var start = dateEnv.add(dayDate, time); 13867 var end = dateEnv.add(start, this.snapDuration); 13868 return { 13869 col: colIndex, 13870 dateSpan: { 13871 range: { start: start, end: end }, 13872 allDay: false 13873 }, 13874 dayEl: this.colEls[colIndex], 13875 relativeRect: { 13876 left: colPositions.lefts[colIndex], 13877 right: colPositions.rights[colIndex], 13878 top: slatTop, 13879 bottom: slatTop + slatHeight 13880 } 13881 }; 13882 } 13883 }; 13884 /* Event Drag Visualization 13885 ------------------------------------------------------------------------------------------------------------------*/ 13886 TimeGrid.prototype._renderEventDrag = function (state) { 13887 if (state) { 13888 this.eventRenderer.hideByHash(state.affectedInstances); 13889 if (state.isEvent) { 13890 this.mirrorRenderer.renderSegs(state.segs, { isDragging: true, sourceSeg: state.sourceSeg }); 13891 } 13892 else { 13893 this.fillRenderer.renderSegs('highlight', state.segs); 13894 } 13895 } 13896 }; 13897 TimeGrid.prototype._unrenderEventDrag = function (state) { 13898 if (state) { 13899 this.eventRenderer.showByHash(state.affectedInstances); 13900 this.mirrorRenderer.unrender(state.segs, { isDragging: true, sourceSeg: state.sourceSeg }); 13901 this.fillRenderer.unrender('highlight'); 13902 } 13903 }; 13904 /* Event Resize Visualization 13905 ------------------------------------------------------------------------------------------------------------------*/ 13906 TimeGrid.prototype._renderEventResize = function (state) { 13907 if (state) { 13908 this.eventRenderer.hideByHash(state.affectedInstances); 13909 this.mirrorRenderer.renderSegs(state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 13910 } 13911 }; 13912 TimeGrid.prototype._unrenderEventResize = function (state) { 13913 if (state) { 13914 this.eventRenderer.showByHash(state.affectedInstances); 13915 this.mirrorRenderer.unrender(state.segs, { isResizing: true, sourceSeg: state.sourceSeg }); 13916 } 13917 }; 13918 /* Selection 13919 ------------------------------------------------------------------------------------------------------------------*/ 13920 // Renders a visual indication of a selection. Overrides the default, which was to simply render a highlight. 13921 TimeGrid.prototype._renderDateSelection = function (segs) { 13922 if (segs) { 13923 if (this.opt('selectMirror')) { 13924 this.mirrorRenderer.renderSegs(segs, { isSelecting: true }); 13925 } 13926 else { 13927 this.fillRenderer.renderSegs('highlight', segs); 13928 } 13929 } 13930 }; 13931 TimeGrid.prototype._unrenderDateSelection = function (segs) { 13932 this.mirrorRenderer.unrender(segs, { isSelecting: true }); 13933 this.fillRenderer.unrender('highlight'); 13934 }; 13935 return TimeGrid; 13936 }(core.DateComponent)); 13937 13938 var AllDaySplitter = /** @class */ (function (_super) { 13939 __extends(AllDaySplitter, _super); 13940 function AllDaySplitter() { 13941 return _super !== null && _super.apply(this, arguments) || this; 13942 } 13943 AllDaySplitter.prototype.getKeyInfo = function () { 13944 return { 13945 allDay: {}, 13946 timed: {} 13947 }; 13948 }; 13949 AllDaySplitter.prototype.getKeysForDateSpan = function (dateSpan) { 13950 if (dateSpan.allDay) { 13951 return ['allDay']; 13952 } 13953 else {
13954 return ['timed']; 13955 } 13956 }; 13957 AllDaySplitter.prototype.getKeysForEventDef = function (eventDef) { 13958 if (!eventDef.allDay) { 13959 return ['timed']; 13960 } 13961 else if (core.hasBgRendering(eventDef)) { 13962 return ['timed', 'allDay']; 13963 } 13964 else { 13965 return ['allDay']; 13966 } 13967 }; 13968 return AllDaySplitter; 13969 }(core.Splitter)); 13970 13971 var TIMEGRID_ALL_DAY_EVENT_LIMIT = 5; 13972 var WEEK_HEADER_FORMAT = core.createFormatter({ week: 'short' }); 13973 /* An abstract class for all timegrid-related views. Displays one more columns with time slots running vertically. 13974 ----------------------------------------------------------------------------------------------------------------------*/ 13975 // Is a manager for the TimeGrid subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on). 13976 // Responsible for managing width/height. 13977 var TimeGridView = /** @class */ (function (_super) { 13978 __extends(TimeGridView, _super); 13979 function TimeGridView(context, viewSpec, dateProfileGenerator, parentEl) { 13980 var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this; 13981 _this.splitter = new AllDaySplitter(); 13982 /* Header Render Methods 13983 ------------------------------------------------------------------------------------------------------------------*/ 13984 // Generates the HTML that will go before the day-of week header cells 13985 _this.renderHeadIntroHtml = function () { 13986 var _a = _this, theme = _a.theme, dateEnv = _a.dateEnv; 13987 var range = _this.props.dateProfile.renderRange; 13988 var dayCnt = core.diffDays(range.start, range.end); 13989 var weekText; 13990 if (_this.opt('weekNumbers')) { 13991 weekText = dateEnv.format(range.start, WEEK_HEADER_FORMAT); 13992 return '' + 13993 '<th class="fc-axis fc-week-number ' + theme.getClass('widgetHeader') + '" ' + _this.axisStyleAttr() + '>' + 13994 core.buildGotoAnchorHtml(// aside from link, important for matchCellWidths 13995 _this, { date: range.start, type: 'week', forceOff: dayCnt > 1 }, core.htmlEscape(weekText) // inner HTML 13996 ) + 13997 '</th>'; 13998 } 13999 else { 14000 return '<th class="fc-axis ' + theme.getClass('widgetHeader') + '" ' + _this.axisStyleAttr() + '></th>'; 14001 } 14002 }; 14003 /* Time Grid Render Methods 14004 ------------------------------------------------------------------------------------------------------------------*/ 14005 // Generates the HTML that goes before the bg of the TimeGrid slot area. Long vertical column. 14006 _this.renderTimeGridBgIntroHtml = function () { 14007 var theme = _this.theme; 14008 return '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '></td>'; 14009 }; 14010 // Generates the HTML that goes before all other types of cells. 14011 // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid. 14012 _this.renderTimeGridIntroHtml = function () { 14013 return '<td class="fc-axis" ' + _this.axisStyleAttr() + '></td>'; 14014 }; 14015 /* Day Grid Render Methods 14016 ------------------------------------------------------------------------------------------------------------------*/ 14017 // Generates the HTML that goes before the all-day cells 14018 _this.renderDayGridBgIntroHtml = function () { 14019 var theme = _this.theme; 14020 return '' + 14021 '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '>' + 14022 '<span>' + // needed for matchCellWidths 14023 core.getAllDayHtml(_this) + 14024 '</span>' + 14025 '</td>'; 14026 }; 14027 // Generates the HTML that goes before all other types of cells. 14028 // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid. 14029 _this.renderDayGridIntroHtml = function () { 14030 return '<td class="fc-axis" ' + _this.axisStyleAttr() + '></td>'; 14031 }; 14032 _this.el.classList.add('fc-timeGrid-view'); 14033 _this.el.innerHTML = _this.renderSkeletonHtml();
14034 _this.scroller = new core.ScrollComponent('hidden', // overflow x 14035 'auto' // overflow y 14036 ); 14037 var timeGridWrapEl = _this.scroller.el; 14038 _this.el.querySelector('.fc-body > tr > td').appendChild(timeGridWrapEl); 14039 timeGridWrapEl.classList.add('fc-time-grid-container'); 14040 var timeGridEl = core.createElement('div', { className: 'fc-time-grid' }); 14041 timeGridWrapEl.appendChild(timeGridEl); 14042 _this.timeGrid = new TimeGrid(_this.context, timeGridEl, { 14043 renderBgIntroHtml: _this.renderTimeGridBgIntroHtml, 14044 renderIntroHtml: _this.renderTimeGridIntroHtml 14045 }); 14046 if (_this.opt('allDaySlot')) { // should we display the "all-day" area? 14047 _this.dayGrid = new daygrid.DayGrid(// the all-day subcomponent of this view 14048 _this.context, _this.el.querySelector('.fc-day-grid'), { 14049 renderNumberIntroHtml: _this.renderDayGridIntroHtml, 14050 renderBgIntroHtml: _this.renderDayGridBgIntroHtml, 14051 renderIntroHtml: _this.renderDayGridIntroHtml, 14052 colWeekNumbersVisible: false, 14053 cellWeekNumbersVisible: false 14054 }); 14055 // have the day-grid extend it's coordinate area over the <hr> dividing the two grids 14056 var dividerEl = _this.el.querySelector('.fc-divider'); 14057 _this.dayGrid.bottomCoordPadding = dividerEl.getBoundingClientRect().height; 14058 } 14059 return _this; 14060 } 14061 TimeGridView.prototype.destroy = function () { 14062 _super.prototype.destroy.call(this); 14063 this.timeGrid.destroy(); 14064 if (this.dayGrid) { 14065 this.dayGrid.destroy(); 14066 } 14067 this.scroller.destroy(); 14068 }; 14069 /* Rendering 14070 ------------------------------------------------------------------------------------------------------------------*/ 14071 // Builds the HTML skeleton for the view. 14072 // The day-grid and time-grid components will render inside containers defined by this HTML. 14073 TimeGridView.prototype.renderSkeletonHtml = function () { 14074 var theme = this.theme; 14075 return '' + 14076 '<table class="' + theme.getClass('tableGrid') + '">' + 14077 (this.opt('columnHeader') ? 14078 '<thead class="fc-head">' + 14079 '<tr>' + 14080 '<td class="fc-head-container ' + theme.getClass('widgetHeader') + '"> </td>' + 14081 '</tr>' + 14082 '</thead>' : 14083 '') + 14084 '<tbody class="fc-body">' + 14085 '<tr>' + 14086 '<td class="' + theme.getClass('widgetContent') + '">' + 14087 (this.opt('allDaySlot') ? 14088 '<div class="fc-day-grid"></div>' + 14089 '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" />' : 14090 '') + 14091 '</td>' + 14092 '</tr>' + 14093 '</tbody>' + 14094 '</table>'; 14095 }; 14096 /* Now Indicator 14097 ------------------------------------------------------------------------------------------------------------------*/ 14098 TimeGridView.prototype.getNowIndicatorUnit = function () { 14099 return this.timeGrid.getNowIndicatorUnit(); 14100 }; 14101 // subclasses should implement 14102 // renderNowIndicator(date: DateMarker) { 14103 // } 14104 TimeGridView.prototype.unrenderNowIndicator = function () { 14105 this.timeGrid.unrenderNowIndicator(); 14106 }; 14107 /* Dimensions 14108 ------------------------------------------------------------------------------------------------------------------*/ 14109 TimeGridView.prototype.updateSize = function (isResize, viewHeight, isAuto) { 14110 _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto); // will call updateBaseSize. important that executes first 14111 this.timeGrid.updateSize(isResize); 14112 if (this.dayGrid) { 14113 this.dayGrid.updateSize(isResize); 14114 } 14115 }; 14116 // Adjusts the vertical dimensions of the view to the specified values 14117 TimeGridView.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) { 14118 var _this = this; 14119 var eventLimit; 14120 var scrollerHeight; 14121 var scrollbarWidths; 14122 // make all axis cells line up 14123 this.axisWidth = core.matchCellWidths(core.findElements(this.el, '.fc-axis')); 14124 // hack to give the view some height prior to timeGrid's columns being rendered 14125 // TODO: separate setting height from scroller VS timeGrid. 14126 if (!this.timeGrid.colEls) { 14127 if (!isAuto) { 14128 scrollerHeight = this.computeScrollerHeight(viewHeight); 14129 this.scroller.setHeight(scrollerHeight); 14130 } 14131 return; 14132 } 14133 // set of fake row elements that must compensate when scroller has scrollbars 14134 var noScrollRowEls = core.findElements(this.el, '.fc-row').filter(function (node) { 14135 return !_this.scroller.el.contains(node); 14136 }); 14137 // reset all dimensions back to the original state 14138 this.timeGrid.bottomRuleEl.style.display = 'none'; // will be shown later if this <hr> is necessary 14139 this.scroller.clear(); // sets height to 'auto' and clears overflow
14140 noScrollRowEls.forEach(core.uncompensateScroll); 14141 // limit number of events in the all-day area 14142 if (this.dayGrid) { 14143 this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed 14144 eventLimit = this.opt('eventLimit'); 14145 if (eventLimit && typeof eventLimit !== 'number') { 14146 eventLimit = TIMEGRID_ALL_DAY_EVENT_LIMIT; // make sure "auto" goes to a real number 14147 } 14148 if (eventLimit) { 14149 this.dayGrid.limitRows(eventLimit); 14150 } 14151 } 14152 if (!isAuto) { // should we force dimensions of the scroll container? 14153 scrollerHeight = this.computeScrollerHeight(viewHeight); 14154 this.scroller.setHeight(scrollerHeight); 14155 scrollbarWidths = this.scroller.getScrollbarWidths(); 14156 if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars? 14157 // make the all-day and header rows lines up 14158 noScrollRowEls.forEach(function (rowEl) { 14159 core.compensateScroll(rowEl, scrollbarWidths); 14160 }); 14161 // the scrollbar compensation might have changed text flow, which might affect height, so recalculate 14162 // and reapply the desired height to the scroller. 14163 scrollerHeight = this.computeScrollerHeight(viewHeight); 14164 this.scroller.setHeight(scrollerHeight); 14165 } 14166 // guarantees the same scrollbar widths 14167 this.scroller.lockOverflow(scrollbarWidths); 14168 // if there's any space below the slats, show the horizontal rule. 14169 // this won't cause any new overflow, because lockOverflow already called. 14170 if (this.timeGrid.getTotalSlatHeight() < scrollerHeight) { 14171 this.timeGrid.bottomRuleEl.style.display = ''; 14172 } 14173 } 14174 }; 14175 // given a desired total height of the view, returns what the height of the scroller should be 14176 TimeGridView.prototype.computeScrollerHeight = function (viewHeight) { 14177 return viewHeight - 14178 core.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller 14179 }; 14180 /* Scroll 14181 ------------------------------------------------------------------------------------------------------------------*/ 14182 // Computes the initial pre-configured scroll state prior to allowing the user to change it 14183 TimeGridView.prototype.computeDateScroll = function (duration) { 14184 var top = this.timeGrid.computeTimeTop(duration); 14185 // zoom can give weird floating-point values. rather scroll a little bit further 14186 top = Math.ceil(top); 14187 if (top) { 14188 top++; // to overcome top border that slots beyond the first have. looks better 14189 } 14190 return { top: top }; 14191 }; 14192 TimeGridView.prototype.queryDateScroll = function () { 14193 return { top: this.scroller.getScrollTop() }; 14194 }; 14195 TimeGridView.prototype.applyDateScroll = function (scroll) { 14196 if (scroll.top !== undefined) { 14197 this.scroller.setScrollTop(scroll.top); 14198 } 14199 }; 14200 // Generates an HTML attribute string for setting the width of the axis, if it is known 14201 TimeGridView.prototype.axisStyleAttr = function () { 14202 if (this.axisWidth != null) { 14203 return 'style="width:' + this.axisWidth + 'px"'; 14204 } 14205 return ''; 14206 }; 14207 return TimeGridView; 14208 }(core.View)); 14209 TimeGridView.prototype.usesMinMaxTime = true; // indicates that minTime/maxTime affects rendering 14210 14211 var SimpleTimeGrid = /** @class */ (function (_super) { 14212 __extends(SimpleTimeGrid, _super); 14213 function SimpleTimeGrid(context, timeGrid) { 14214 var _this = _super.call(this, context, timeGrid.el) || this; 14215 _this.buildDayRanges = core.memoize(buildDayRanges); 14216 _this.slicer = new TimeGridSlicer(); 14217 _this.timeGrid = timeGrid; 14218 context.calendar.registerInteractiveComponent(_this, { 14219 el: _this.timeGrid.el 14220 }); 14221 return _this; 14222 } 14223 SimpleTimeGrid.prototype.destroy = function () { 14224 _super.prototype.destroy.call(this); 14225 this.calendar.unregisterInteractiveComponent(this); 14226 }; 14227 SimpleTimeGrid.prototype.render = function (props) { 14228 var dateProfile = props.dateProfile, dayTable = props.dayTable; 14229 var dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, this.dateEnv); 14230 this.timeGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, null, this.timeGrid, dayRanges), { dateProfile: dateProfile, cells: dayTable.cells[0] })); 14231 }; 14232 SimpleTimeGrid.prototype.renderNowIndicator = function (date) { 14233 this.timeGrid.renderNowIndicator(this.slicer.sliceNowDate(date, this.timeGrid, this.dayRanges), date); 14234 }; 14235 SimpleTimeGrid.prototype.buildPositionCaches = function () { 14236 this.timeGrid.buildPositionCaches(); 14237 }; 14238 SimpleTimeGrid.prototype.queryHit = function (positionLeft, positionTop) { 14239 var rawHit = this.timeGrid.positionToHit(positionLeft, positionTop); 14240 if (rawHit) { 14241 return { 14242 component: this.timeGrid, 14243 dateSpan: rawHit.dateSpan, 14244 dayEl: rawHit.dayEl, 14245 rect: { 14246 left: rawHit.relativeRect.left, 14247 right: rawHit.relativeRect.right, 14248 top: rawHit.relativeRect.top, 14249 bottom: rawHit.relativeRect.bottom 14250 }, 14251 layer: 0 14252 }; 14253 } 14254 }; 14255 return SimpleTimeGrid; 14256 }(core.DateComponent)); 14257 function buildDayRanges(dayTable, dateProfile, dateEnv) { 14258 var ranges = []; 14259 for (var _i = 0, _a = dayTable.headerDates; _i < _a.length; _i++) { 14260 var date = _a[_i]; 14261 ranges.push({ 14262 start: dateEnv.add(date, dateProfile.minTime), 14263 end: dateEnv.add(date, dateProfile.maxTime) 14264 }); 14265 } 14266 return ranges; 14267 } 14268 var TimeGridSlicer = /** @class */ (function (_super) { 14269 __extends(TimeGridSlicer, _super); 14270 function TimeGridSlicer() { 14271 return _super !== null && _super.apply(this, arguments) || this; 14272 } 14273 TimeGridSlicer.prototype.sliceRange = function (range, dayRanges) { 14274 var segs = []; 14275 for (var col = 0; col < dayRanges.length; col++) { 14276 var segRange = core.intersectRanges(range, dayRanges[col]); 14277 if (segRange) { 14278 segs.push({ 14279 start: segRange.start, 14280 end: segRange.end, 14281 isStart: segRange.start.valueOf() === range.start.valueOf(), 14282 isEnd: segRange.end.valueOf() === range.end.valueOf(), 14283 col: col 14284 }); 14285 } 14286 } 14287 return segs; 14288 }; 14289 return TimeGridSlicer; 14290 }(core.Slicer)); 14291 14292 var TimeGridView$1 = /** @class */ (function (_super) { 14293 __extends(TimeGridView, _super); 14294 function TimeGridView(_context, viewSpec, dateProfileGenerator, parentEl) { 14295 var _this = _super.call(this, _context, viewSpec, dateProfileGenerator, parentEl) || this; 14296 _this.buildDayTable = core.memoize(buildDayTable); 14297 if (_this.opt('columnHeader')) { 14298 _this.header = new core.DayHeader(_this.context, _this.el.querySelector('.fc-head-container')); 14299 } 14300 _this.simpleTimeGrid = new SimpleTimeGrid(_this.context, _this.timeGrid); 14301 if (_this.dayGrid) { 14302 _this.simpleDayGrid = new daygrid.SimpleDayGrid(_this.context, _this.dayGrid); 14303 } 14304 return _this; 14305 } 14306 TimeGridView.prototype.destroy = function () { 14307 _super.prototype.destroy.call(this); 14308 if (this.header) { 14309 this.header.destroy(); 14310 } 14311 this.simpleTimeGrid.destroy(); 14312 if (this.simpleDayGrid) { 14313 this.simpleDayGrid.destroy(); 14314 } 14315 }; 14316 TimeGridView.prototype.render = function (props) { 14317 _super.prototype.render.call(this, props); // for flags for updateSize 14318 var dateProfile = this.props.dateProfile; 14319 var dayTable = this.buildDayTable(dateProfile, this.dateProfileGenerator); 14320 var splitProps = this.splitter.splitProps(props); 14321 if (this.header) { 14322 this.header.receiveProps({ 14323 dateProfile: dateProfile, 14324 dates: dayTable.headerDates, 14325 datesRepDistinctDays: true, 14326 renderIntroHtml: this.renderHeadIntroHtml 14327 }); 14328 } 14329 this.simpleTimeGrid.receiveProps(__assign({}, splitProps['timed'], { dateProfile: dateProfile, 14330 dayTable: dayTable })); 14331 if (this.simpleDayGrid) { 14332 this.simpleDayGrid.receiveProps(__assign({}, splitProps['allDay'], { dateProfile: dateProfile, 14333 dayTable: dayTable, nextDayThreshold: this.nextDayThreshold, isRigid: false })); 14334 } 14335 }; 14336 TimeGridView.prototype.renderNowIndicator = function (date) { 14337 this.simpleTimeGrid.renderNowIndicator(date); 14338 }; 14339 return TimeGridView; 14340 }(TimeGridView)); 14341 function buildDayTable(dateProfile, dateProfileGenerator) { 14342 var daySeries = new core.DaySeries(dateProfile.renderRange, dateProfileGenerator); 14343 return new core.DayTable(daySeries, false); 14344 } 14345 14346 var main = core.createPlugin({ 14347 defaultView: 'timeGridWeek', 14348 views: { 14349 timeGrid: { 14350 class: TimeGridView$1, 14351 allDaySlot: true, 14352 slotDuration: '00:30:00', 14353 slotEventOverlap: true // a bad name. confused with overlap/constraint system 14354 }, 14355 timeGridDay: { 14356 type: 'timeGrid', 14357 duration: { days: 1 } 14358 }, 14359 timeGridWeek: { 14360 type: 'timeGrid', 14361 duration: { weeks: 1 } 14362 } 14363 } 14364 }); 14365 14366 exports.AbstractTimeGridView = TimeGridView; 14367 exports.TimeGrid = TimeGrid; 14368 exports.TimeGridSlicer = TimeGridSlicer; 14369 exports.TimeGridView = TimeGridView$1; 14370 exports.buildDayRanges = buildDayRanges; 14371 exports.buildDayTable = buildDayTable; 14372 exports.default = main; 14373 14374 Object.defineProperty(exports, '__esModule', { value: true }); 14375 14376}));
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.