aboutsummaryrefslogtreecommitdiffstats
path: root/library/fullcalendar/dist/index.global.js
diff options
context:
space:
mode:
Diffstat (limited to 'library/fullcalendar/dist/index.global.js')
-rw-r--r--library/fullcalendar/dist/index.global.js5487
1 files changed, 2771 insertions, 2716 deletions
diff --git a/library/fullcalendar/dist/index.global.js b/library/fullcalendar/dist/index.global.js
index 0f67113d8..cbc6433ff 100644
--- a/library/fullcalendar/dist/index.global.js
+++ b/library/fullcalendar/dist/index.global.js
@@ -1,5 +1,5 @@
/*!
-FullCalendar Standard Bundle v6.1.8
+FullCalendar Standard Bundle v6.1.11
Docs & License: https://fullcalendar.io/docs/initialize-globals
(c) 2023 Adam Shaw
*/
@@ -21,7 +21,9 @@ var FullCalendar = (function (exports) {
});
}
function ensureElHasStyles(el) {
- if (el.isConnected) {
+ if (el.isConnected && // sometimes true if SSR system simulates DOM
+ el.getRootNode // sometimes undefined if SSR system simulates DOM
+ ) {
registerStylesRoot(el.getRootNode());
}
}
@@ -93,6 +95,79 @@ var FullCalendar = (function (exports) {
var css_248z$4 = ":root{--fc-small-font-size:.85em;--fc-page-bg-color:#fff;--fc-neutral-bg-color:hsla(0,0%,82%,.3);--fc-neutral-text-color:grey;--fc-border-color:#ddd;--fc-button-text-color:#fff;--fc-button-bg-color:#2c3e50;--fc-button-border-color:#2c3e50;--fc-button-hover-bg-color:#1e2b37;--fc-button-hover-border-color:#1a252f;--fc-button-active-bg-color:#1a252f;--fc-button-active-border-color:#151e27;--fc-event-bg-color:#3788d8;--fc-event-border-color:#3788d8;--fc-event-text-color:#fff;--fc-event-selected-overlay-color:rgba(0,0,0,.25);--fc-more-link-bg-color:#d0d0d0;--fc-more-link-text-color:inherit;--fc-event-resizer-thickness:8px;--fc-event-resizer-dot-total-width:8px;--fc-event-resizer-dot-border-width:1px;--fc-non-business-color:hsla(0,0%,84%,.3);--fc-bg-event-color:#8fdf82;--fc-bg-event-opacity:0.3;--fc-highlight-color:rgba(188,232,241,.3);--fc-today-bg-color:rgba(255,220,40,.15);--fc-now-indicator-color:red}.fc-not-allowed,.fc-not-allowed .fc-event{cursor:not-allowed}.fc{display:flex;flex-direction:column;font-size:1em}.fc,.fc *,.fc :after,.fc :before{box-sizing:border-box}.fc table{border-collapse:collapse;border-spacing:0;font-size:1em}.fc th{text-align:center}.fc td,.fc th{padding:0;vertical-align:top}.fc a[data-navlink]{cursor:pointer}.fc a[data-navlink]:hover{text-decoration:underline}.fc-direction-ltr{direction:ltr;text-align:left}.fc-direction-rtl{direction:rtl;text-align:right}.fc-theme-standard td,.fc-theme-standard th{border:1px solid var(--fc-border-color)}.fc-liquid-hack td,.fc-liquid-hack th{position:relative}@font-face{font-family:fcicons;font-style:normal;font-weight:400;src:url(\"data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBfAAAAC8AAAAYGNtYXAXVtKNAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5ZgYydxIAAAF4AAAFNGhlYWQUJ7cIAAAGrAAAADZoaGVhB20DzAAABuQAAAAkaG10eCIABhQAAAcIAAAALGxvY2ED4AU6AAAHNAAAABhtYXhwAA8AjAAAB0wAAAAgbmFtZXsr690AAAdsAAABhnBvc3QAAwAAAAAI9AAAACAAAwPAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpBgPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6Qb//f//AAAAAAAg6QD//f//AAH/4xcEAAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAWIAjQKeAskAEwAAJSc3NjQnJiIHAQYUFwEWMjc2NCcCnuLiDQ0MJAz/AA0NAQAMJAwNDcni4gwjDQwM/wANIwz/AA0NDCMNAAAAAQFiAI0CngLJABMAACUBNjQnASYiBwYUHwEHBhQXFjI3AZ4BAA0N/wAMJAwNDeLiDQ0MJAyNAQAMIw0BAAwMDSMM4uINIwwNDQAAAAIA4gC3Ax4CngATACcAACUnNzY0JyYiDwEGFB8BFjI3NjQnISc3NjQnJiIPAQYUHwEWMjc2NCcB87e3DQ0MIw3VDQ3VDSMMDQ0BK7e3DQ0MJAzVDQ3VDCQMDQ3zuLcMJAwNDdUNIwzWDAwNIwy4twwkDA0N1Q0jDNYMDA0jDAAAAgDiALcDHgKeABMAJwAAJTc2NC8BJiIHBhQfAQcGFBcWMjchNzY0LwEmIgcGFB8BBwYUFxYyNwJJ1Q0N1Q0jDA0Nt7cNDQwjDf7V1Q0N1QwkDA0Nt7cNDQwkDLfWDCMN1Q0NDCQMt7gMIw0MDNYMIw3VDQ0MJAy3uAwjDQwMAAADAFUAAAOrA1UAMwBoAHcAABMiBgcOAQcOAQcOARURFBYXHgEXHgEXHgEzITI2Nz4BNz4BNz4BNRE0JicuAScuAScuASMFITIWFx4BFx4BFx4BFREUBgcOAQcOAQcOASMhIiYnLgEnLgEnLgE1ETQ2Nz4BNz4BNz4BMxMhMjY1NCYjISIGFRQWM9UNGAwLFQkJDgUFBQUFBQ4JCRULDBgNAlYNGAwLFQkJDgUFBQUFBQ4JCRULDBgN/aoCVgQIBAQHAwMFAQIBAQIBBQMDBwQECAT9qgQIBAQHAwMFAQIBAQIBBQMDBwQECASAAVYRGRkR/qoRGRkRA1UFBAUOCQkVDAsZDf2rDRkLDBUJCA4FBQUFBQUOCQgVDAsZDQJVDRkLDBUJCQ4FBAVVAgECBQMCBwQECAX9qwQJAwQHAwMFAQICAgIBBQMDBwQDCQQCVQUIBAQHAgMFAgEC/oAZEhEZGRESGQAAAAADAFUAAAOrA1UAMwBoAIkAABMiBgcOAQcOAQcOARURFBYXHgEXHgEXHgEzITI2Nz4BNz4BNz4BNRE0JicuAScuAScuASMFITIWFx4BFx4BFx4BFREUBgcOAQcOAQcOASMhIiYnLgEnLgEnLgE1ETQ2Nz4BNz4BNz4BMxMzFRQWMzI2PQEzMjY1NCYrATU0JiMiBh0BIyIGFRQWM9UNGAwLFQkJDgUFBQUFBQ4JCRULDBgNAlYNGAwLFQkJDgUFBQUFBQ4JCRULDBgN/aoCVgQIBAQHAwMFAQIBAQIBBQMDBwQECAT9qgQIBAQHAwMFAQIBAQIBBQMDBwQECASAgBkSEhmAERkZEYAZEhIZgBEZGREDVQUEBQ4JCRUMCxkN/asNGQsMFQkIDgUFBQUFBQ4JCBUMCxkNAlUNGQsMFQkJDgUEBVUCAQIFAwIHBAQIBf2rBAkDBAcDAwUBAgICAgEFAwMHBAMJBAJVBQgEBAcCAwUCAQL+gIASGRkSgBkSERmAEhkZEoAZERIZAAABAOIAjQMeAskAIAAAExcHBhQXFjI/ARcWMjc2NC8BNzY0JyYiDwEnJiIHBhQX4uLiDQ0MJAzi4gwkDA0N4uINDQwkDOLiDCQMDQ0CjeLiDSMMDQ3h4Q0NDCMN4uIMIw0MDOLiDAwNIwwAAAABAAAAAQAAa5n0y18PPPUACwQAAAAAANivOVsAAAAA2K85WwAAAAADqwNVAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAAAAAOrAAEAAAAAAAAAAAAAAAAAAAALBAAAAAAAAAAAAAAAAgAAAAQAAWIEAAFiBAAA4gQAAOIEAABVBAAAVQQAAOIAAAAAAAoAFAAeAEQAagCqAOoBngJkApoAAQAAAAsAigADAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGZjaWNvbnMAZgBjAGkAYwBvAG4Ac1ZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGZjaWNvbnMAZgBjAGkAYwBvAG4Ac2ZjaWNvbnMAZgBjAGkAYwBvAG4Ac1JlZ3VsYXIAUgBlAGcAdQBsAGEAcmZjaWNvbnMAZgBjAGkAYwBvAG4Ac0ZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\") format(\"truetype\")}.fc-icon{speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;font-family:fcicons!important;font-style:normal;font-variant:normal;font-weight:400;height:1em;line-height:1;text-align:center;text-transform:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:1em}.fc-icon-chevron-left:before{content:\"\\e900\"}.fc-icon-chevron-right:before{content:\"\\e901\"}.fc-icon-chevrons-left:before{content:\"\\e902\"}.fc-icon-chevrons-right:before{content:\"\\e903\"}.fc-icon-minus-square:before{content:\"\\e904\"}.fc-icon-plus-square:before{content:\"\\e905\"}.fc-icon-x:before{content:\"\\e906\"}.fc .fc-button{border-radius:0;font-family:inherit;font-size:inherit;line-height:inherit;margin:0;overflow:visible;text-transform:none}.fc .fc-button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}.fc .fc-button{-webkit-appearance:button}.fc .fc-button:not(:disabled){cursor:pointer}.fc .fc-button{background-color:transparent;border:1px solid transparent;border-radius:.25em;display:inline-block;font-size:1em;font-weight:400;line-height:1.5;padding:.4em .65em;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle}.fc .fc-button:hover{text-decoration:none}.fc .fc-button:focus{box-shadow:0 0 0 .2rem rgba(44,62,80,.25);outline:0}.fc .fc-button:disabled{opacity:.65}.fc .fc-button-primary{background-color:var(--fc-button-bg-color);border-color:var(--fc-button-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:hover{background-color:var(--fc-button-hover-bg-color);border-color:var(--fc-button-hover-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:disabled{background-color:var(--fc-button-bg-color);border-color:var(--fc-button-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:focus{box-shadow:0 0 0 .2rem rgba(76,91,106,.5)}.fc .fc-button-primary:not(:disabled).fc-button-active,.fc .fc-button-primary:not(:disabled):active{background-color:var(--fc-button-active-bg-color);border-color:var(--fc-button-active-border-color);color:var(--fc-button-text-color)}.fc .fc-button-primary:not(:disabled).fc-button-active:focus,.fc .fc-button-primary:not(:disabled):active:focus{box-shadow:0 0 0 .2rem rgba(76,91,106,.5)}.fc .fc-button .fc-icon{font-size:1.5em;vertical-align:middle}.fc .fc-button-group{display:inline-flex;position:relative;vertical-align:middle}.fc .fc-button-group>.fc-button{flex:1 1 auto;position:relative}.fc .fc-button-group>.fc-button.fc-button-active,.fc .fc-button-group>.fc-button:active,.fc .fc-button-group>.fc-button:focus,.fc .fc-button-group>.fc-button:hover{z-index:1}.fc-direction-ltr .fc-button-group>.fc-button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0;margin-left:-1px}.fc-direction-ltr .fc-button-group>.fc-button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.fc-direction-rtl .fc-button-group>.fc-button:not(:first-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.fc-direction-rtl .fc-button-group>.fc-button:not(:last-child){border-bottom-left-radius:0;border-top-left-radius:0}.fc .fc-toolbar{align-items:center;display:flex;justify-content:space-between}.fc .fc-toolbar.fc-header-toolbar{margin-bottom:1.5em}.fc .fc-toolbar.fc-footer-toolbar{margin-top:1.5em}.fc .fc-toolbar-title{font-size:1.75em;margin:0}.fc-direction-ltr .fc-toolbar>*>:not(:first-child){margin-left:.75em}.fc-direction-rtl .fc-toolbar>*>:not(:first-child){margin-right:.75em}.fc-direction-rtl .fc-toolbar-ltr{flex-direction:row-reverse}.fc .fc-scroller{-webkit-overflow-scrolling:touch;position:relative}.fc .fc-scroller-liquid{height:100%}.fc .fc-scroller-liquid-absolute{bottom:0;left:0;position:absolute;right:0;top:0}.fc .fc-scroller-harness{direction:ltr;overflow:hidden;position:relative}.fc .fc-scroller-harness-liquid{height:100%}.fc-direction-rtl .fc-scroller-harness>.fc-scroller{direction:rtl}.fc-theme-standard .fc-scrollgrid{border:1px solid var(--fc-border-color)}.fc .fc-scrollgrid,.fc .fc-scrollgrid table{table-layout:fixed;width:100%}.fc .fc-scrollgrid table{border-left-style:hidden;border-right-style:hidden;border-top-style:hidden}.fc .fc-scrollgrid{border-bottom-width:0;border-collapse:separate;border-right-width:0}.fc .fc-scrollgrid-liquid{height:100%}.fc .fc-scrollgrid-section,.fc .fc-scrollgrid-section table,.fc .fc-scrollgrid-section>td{height:1px}.fc .fc-scrollgrid-section-liquid>td{height:100%}.fc .fc-scrollgrid-section>*{border-left-width:0;border-top-width:0}.fc .fc-scrollgrid-section-footer>*,.fc .fc-scrollgrid-section-header>*{border-bottom-width:0}.fc .fc-scrollgrid-section-body table,.fc .fc-scrollgrid-section-footer table{border-bottom-style:hidden}.fc .fc-scrollgrid-section-sticky>*{background:var(--fc-page-bg-color);position:sticky;z-index:3}.fc .fc-scrollgrid-section-header.fc-scrollgrid-section-sticky>*{top:0}.fc .fc-scrollgrid-section-footer.fc-scrollgrid-section-sticky>*{bottom:0}.fc .fc-scrollgrid-sticky-shim{height:1px;margin-bottom:-1px}.fc-sticky{position:sticky}.fc .fc-view-harness{flex-grow:1;position:relative}.fc .fc-view-harness-active>.fc-view{bottom:0;left:0;position:absolute;right:0;top:0}.fc .fc-col-header-cell-cushion{display:inline-block;padding:2px 4px}.fc .fc-bg-event,.fc .fc-highlight,.fc .fc-non-business{bottom:0;left:0;position:absolute;right:0;top:0}.fc .fc-non-business{background:var(--fc-non-business-color)}.fc .fc-bg-event{background:var(--fc-bg-event-color);opacity:var(--fc-bg-event-opacity)}.fc .fc-bg-event .fc-event-title{font-size:var(--fc-small-font-size);font-style:italic;margin:.5em}.fc .fc-highlight{background:var(--fc-highlight-color)}.fc .fc-cell-shaded,.fc .fc-day-disabled{background:var(--fc-neutral-bg-color)}a.fc-event,a.fc-event:hover{text-decoration:none}.fc-event.fc-event-draggable,.fc-event[href]{cursor:pointer}.fc-event .fc-event-main{position:relative;z-index:2}.fc-event-dragging:not(.fc-event-selected){opacity:.75}.fc-event-dragging.fc-event-selected{box-shadow:0 2px 7px rgba(0,0,0,.3)}.fc-event .fc-event-resizer{display:none;position:absolute;z-index:4}.fc-event-selected .fc-event-resizer,.fc-event:hover .fc-event-resizer{display:block}.fc-event-selected .fc-event-resizer{background:var(--fc-page-bg-color);border-color:inherit;border-radius:calc(var(--fc-event-resizer-dot-total-width)/2);border-style:solid;border-width:var(--fc-event-resizer-dot-border-width);height:var(--fc-event-resizer-dot-total-width);width:var(--fc-event-resizer-dot-total-width)}.fc-event-selected .fc-event-resizer:before{bottom:-20px;content:\"\";left:-20px;position:absolute;right:-20px;top:-20px}.fc-event-selected,.fc-event:focus{box-shadow:0 2px 5px rgba(0,0,0,.2)}.fc-event-selected:before,.fc-event:focus:before{bottom:0;content:\"\";left:0;position:absolute;right:0;top:0;z-index:3}.fc-event-selected:after,.fc-event:focus:after{background:var(--fc-event-selected-overlay-color);bottom:-1px;content:\"\";left:-1px;position:absolute;right:-1px;top:-1px;z-index:1}.fc-h-event{background-color:var(--fc-event-bg-color);border:1px solid var(--fc-event-border-color);display:block}.fc-h-event .fc-event-main{color:var(--fc-event-text-color)}.fc-h-event .fc-event-main-frame{display:flex}.fc-h-event .fc-event-time{max-width:100%;overflow:hidden}.fc-h-event .fc-event-title-container{flex-grow:1;flex-shrink:1;min-width:0}.fc-h-event .fc-event-title{display:inline-block;left:0;max-width:100%;overflow:hidden;right:0;vertical-align:top}.fc-h-event.fc-event-selected:before{bottom:-10px;top:-10px}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-start),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-end){border-bottom-left-radius:0;border-left-width:0;border-top-left-radius:0}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-end),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-start){border-bottom-right-radius:0;border-right-width:0;border-top-right-radius:0}.fc-h-event:not(.fc-event-selected) .fc-event-resizer{bottom:0;top:0;width:var(--fc-event-resizer-thickness)}.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start,.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end{cursor:w-resize;left:calc(var(--fc-event-resizer-thickness)*-.5)}.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end,.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start{cursor:e-resize;right:calc(var(--fc-event-resizer-thickness)*-.5)}.fc-h-event.fc-event-selected .fc-event-resizer{margin-top:calc(var(--fc-event-resizer-dot-total-width)*-.5);top:50%}.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-start,.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-end{left:calc(var(--fc-event-resizer-dot-total-width)*-.5)}.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-end,.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-start{right:calc(var(--fc-event-resizer-dot-total-width)*-.5)}.fc .fc-popover{box-shadow:0 2px 6px rgba(0,0,0,.15);position:absolute;z-index:9999}.fc .fc-popover-header{align-items:center;display:flex;flex-direction:row;justify-content:space-between;padding:3px 4px}.fc .fc-popover-title{margin:0 2px}.fc .fc-popover-close{cursor:pointer;font-size:1.1em;opacity:.65}.fc-theme-standard .fc-popover{background:var(--fc-page-bg-color);border:1px solid var(--fc-border-color)}.fc-theme-standard .fc-popover-header{background:var(--fc-neutral-bg-color)}";
injectStyles(css_248z$4);
+ class DelayedRunner {
+ constructor(drainedOption) {
+ this.drainedOption = drainedOption;
+ this.isRunning = false;
+ this.isDirty = false;
+ this.pauseDepths = {};
+ this.timeoutId = 0;
+ }
+ request(delay) {
+ this.isDirty = true;
+ if (!this.isPaused()) {
+ this.clearTimeout();
+ if (delay == null) {
+ this.tryDrain();
+ }
+ else {
+ this.timeoutId = setTimeout(// NOT OPTIMAL! TODO: look at debounce
+ this.tryDrain.bind(this), delay);
+ }
+ }
+ }
+ pause(scope = '') {
+ let { pauseDepths } = this;
+ pauseDepths[scope] = (pauseDepths[scope] || 0) + 1;
+ this.clearTimeout();
+ }
+ resume(scope = '', force) {
+ let { pauseDepths } = this;
+ if (scope in pauseDepths) {
+ if (force) {
+ delete pauseDepths[scope];
+ }
+ else {
+ pauseDepths[scope] -= 1;
+ let depth = pauseDepths[scope];
+ if (depth <= 0) {
+ delete pauseDepths[scope];
+ }
+ }
+ this.tryDrain();
+ }
+ }
+ isPaused() {
+ return Object.keys(this.pauseDepths).length;
+ }
+ tryDrain() {
+ if (!this.isRunning && !this.isPaused()) {
+ this.isRunning = true;
+ while (this.isDirty) {
+ this.isDirty = false;
+ this.drained(); // might set isDirty to true again
+ }
+ this.isRunning = false;
+ }
+ }
+ clear() {
+ this.clearTimeout();
+ this.isDirty = false;
+ this.pauseDepths = {};
+ }
+ clearTimeout() {
+ if (this.timeoutId) {
+ clearTimeout(this.timeoutId);
+ this.timeoutId = 0;
+ }
+ }
+ drained() {
+ if (this.drainedOption) {
+ this.drainedOption();
+ }
+ }
+ }
+
function removeElement(el) {
if (el.parentNode) {
el.parentNode.removeChild(el);
@@ -280,10 +355,12 @@ var FullCalendar = (function (exports) {
----------------------------------------------------------------------------------------------------------------------*/
function preventSelection(el) {
el.style.userSelect = 'none';
+ el.style.webkitUserSelect = 'none';
el.addEventListener('selectstart', preventDefault);
}
function allowSelection(el) {
el.style.userSelect = '';
+ el.style.webkitUserSelect = '';
el.removeEventListener('selectstart', preventDefault);
}
/* Context Menu
@@ -552,168 +629,6 @@ var FullCalendar = (function (exports) {
return { unit: 'millisecond', value: 0 };
}
- const { hasOwnProperty } = Object.prototype;
- // Merges an array of objects into a single object.
- // The second argument allows for an array of property names who's object values will be merged together.
- function mergeProps(propObjs, complexPropsMap) {
- let dest = {};
- if (complexPropsMap) {
- for (let name in complexPropsMap) {
- if (complexPropsMap[name] === isMaybeObjectsEqual) { // implies that it's object-mergeable
- let complexObjs = [];
- // collect the trailing object values, stopping when a non-object is discovered
- for (let i = propObjs.length - 1; i >= 0; i -= 1) {
- let val = propObjs[i][name];
- if (typeof val === 'object' && val) { // non-null object
- complexObjs.unshift(val);
- }
- else if (val !== undefined) {
- dest[name] = val; // if there were no objects, this value will be used
- break;
- }
- }
- // if the trailing values were objects, use the merged value
- if (complexObjs.length) {
- dest[name] = mergeProps(complexObjs);
- }
- }
- }
- }
- // copy values into the destination, going from last to first
- for (let i = propObjs.length - 1; i >= 0; i -= 1) {
- let props = propObjs[i];
- for (let name in props) {
- if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign
- dest[name] = props[name];
- }
- }
- }
- return dest;
- }
- function filterHash(hash, func) {
- let filtered = {};
- for (let key in hash) {
- if (func(hash[key], key)) {
- filtered[key] = hash[key];
- }
- }
- return filtered;
- }
- function mapHash(hash, func) {
- let newHash = {};
- for (let key in hash) {
- newHash[key] = func(hash[key], key);
- }
- return newHash;
- }
- function arrayToHash(a) {
- let hash = {};
- for (let item of a) {
- hash[item] = true;
- }
- return hash;
- }
- // TODO: reassess browser support
- // https://caniuse.com/?search=object.values
- function hashValuesToArray(obj) {
- let a = [];
- for (let key in obj) {
- a.push(obj[key]);
- }
- return a;
- }
- function isPropsEqual(obj0, obj1) {
- if (obj0 === obj1) {
- return true;
- }
- for (let key in obj0) {
- if (hasOwnProperty.call(obj0, key)) {
- if (!(key in obj1)) {
- return false;
- }
- }
- }
- for (let key in obj1) {
- if (hasOwnProperty.call(obj1, key)) {
- if (obj0[key] !== obj1[key]) {
- return false;
- }
- }
- }
- return true;
- }
- const HANDLER_RE = /^on[A-Z]/;
- function isNonHandlerPropsEqual(obj0, obj1) {
- const keys = getUnequalProps(obj0, obj1);
- for (let key of keys) {
- if (!HANDLER_RE.test(key)) {
- return false;
- }
- }
- return true;
- }
- function getUnequalProps(obj0, obj1) {
- let keys = [];
- for (let key in obj0) {
- if (hasOwnProperty.call(obj0, key)) {
- if (!(key in obj1)) {
- keys.push(key);
- }
- }
- }
- for (let key in obj1) {
- if (hasOwnProperty.call(obj1, key)) {
- if (obj0[key] !== obj1[key]) {
- keys.push(key);
- }
- }
- }
- return keys;
- }
- function compareObjs(oldProps, newProps, equalityFuncs = {}) {
- if (oldProps === newProps) {
- return true;
- }
- for (let key in newProps) {
- if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) ;
- else {
- return false;
- }
- }
- // check for props that were omitted in the new
- for (let key in oldProps) {
- if (!(key in newProps)) {
- return false;
- }
- }
- return true;
- }
- /*
- assumed "true" equality for handler names like "onReceiveSomething"
- */
- function isObjValsEqual(val0, val1, comparator) {
- if (val0 === val1 || comparator === true) {
- return true;
- }
- if (comparator) {
- return comparator(val0, val1);
- }
- return false;
- }
- function collectFromHash(hash, startIndex = 0, endIndex, step = 1) {
- let res = [];
- if (endIndex == null) {
- endIndex = Object.keys(hash).length;
- }
- for (let i = startIndex; i < endIndex; i += step) {
- let val = hash[i];
- if (val !== undefined) { // will disregard undefined for sparse arrays
- res.push(val);
- }
- }
- return res;
- }
-
// TODO: new util arrayify?
function removeExact(array, exactVal) {
let removeCnt = 0;
@@ -1571,7 +1486,7 @@ var FullCalendar = (function (exports) {
// (can't be part of plugin system b/c must be provided at runtime)
handleCustomRendering: identity,
customRenderingMetaMap: identity,
- customRenderingReplacesEl: Boolean,
+ customRenderingReplaces: Boolean,
};
// do NOT give a type here. need `typeof BASE_OPTION_DEFAULTS` to give real results.
// raw values.
@@ -1725,1245 +1640,535 @@ var FullCalendar = (function (exports) {
return raw;
}
- function createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) {
- return {
- instanceId: guid(),
- defId,
- range,
- forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo,
- forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo,
- };
- }
-
- function parseRecurring(refined, defaultAllDay, dateEnv, recurringTypes) {
- for (let i = 0; i < recurringTypes.length; i += 1) {
- let parsed = recurringTypes[i].parse(refined, dateEnv);
- if (parsed) {
- let { allDay } = refined;
- if (allDay == null) {
- allDay = defaultAllDay;
- if (allDay == null) {
- allDay = parsed.allDayGuess;
- if (allDay == null) {
- allDay = false;
+ const { hasOwnProperty } = Object.prototype;
+ // Merges an array of objects into a single object.
+ // The second argument allows for an array of property names who's object values will be merged together.
+ function mergeProps(propObjs, complexPropsMap) {
+ let dest = {};
+ if (complexPropsMap) {
+ for (let name in complexPropsMap) {
+ if (complexPropsMap[name] === isMaybeObjectsEqual) { // implies that it's object-mergeable
+ let complexObjs = [];
+ // collect the trailing object values, stopping when a non-object is discovered
+ for (let i = propObjs.length - 1; i >= 0; i -= 1) {
+ let val = propObjs[i][name];
+ if (typeof val === 'object' && val) { // non-null object
+ complexObjs.unshift(val);
+ }
+ else if (val !== undefined) {
+ dest[name] = val; // if there were no objects, this value will be used
+ break;
}
}
+ // if the trailing values were objects, use the merged value
+ if (complexObjs.length) {
+ dest[name] = mergeProps(complexObjs);
+ }
}
- return {
- allDay,
- duration: parsed.duration,
- typeData: parsed.typeData,
- typeId: i,
- };
}
}
- return null;
- }
- function expandRecurring(eventStore, framingRange, context) {
- let { dateEnv, pluginHooks, options } = context;
- let { defs, instances } = eventStore;
- // remove existing recurring instances
- // TODO: bad. always expand events as a second step
- instances = filterHash(instances, (instance) => !defs[instance.defId].recurringDef);
- for (let defId in defs) {
- let def = defs[defId];
- if (def.recurringDef) {
- let { duration } = def.recurringDef;
- if (!duration) {
- duration = def.allDay ?
- options.defaultAllDayEventDuration :
- options.defaultTimedEventDuration;
- }
- let starts = expandRecurringRanges(def, duration, framingRange, dateEnv, pluginHooks.recurringTypes);
- for (let start of starts) {
- let instance = createEventInstance(defId, {
- start,
- end: dateEnv.add(start, duration),
- });
- instances[instance.instanceId] = instance;
+ // copy values into the destination, going from last to first
+ for (let i = propObjs.length - 1; i >= 0; i -= 1) {
+ let props = propObjs[i];
+ for (let name in props) {
+ if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign
+ dest[name] = props[name];
}
}
}
- return { defs, instances };
- }
- /*
- Event MUST have a recurringDef
- */
- function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) {
- let typeDef = recurringTypes[eventDef.recurringDef.typeId];
- let markers = typeDef.expand(eventDef.recurringDef.typeData, {
- start: dateEnv.subtract(framingRange.start, duration),
- end: framingRange.end,
- }, dateEnv);
- // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to
- if (eventDef.allDay) {
- markers = markers.map(startOfDay);
- }
- return markers;
+ return dest;
}
-
- function parseEvents(rawEvents, eventSource, context, allowOpenRange, defIdMap, instanceIdMap) {
- let eventStore = createEmptyEventStore();
- let eventRefiners = buildEventRefiners(context);
- for (let rawEvent of rawEvents) {
- let tuple = parseEvent(rawEvent, eventSource, context, allowOpenRange, eventRefiners, defIdMap, instanceIdMap);
- if (tuple) {
- eventTupleToStore(tuple, eventStore);
+ function filterHash(hash, func) {
+ let filtered = {};
+ for (let key in hash) {
+ if (func(hash[key], key)) {
+ filtered[key] = hash[key];
}
}
- return eventStore;
+ return filtered;
}
- function eventTupleToStore(tuple, eventStore = createEmptyEventStore()) {
- eventStore.defs[tuple.def.defId] = tuple.def;
- if (tuple.instance) {
- eventStore.instances[tuple.instance.instanceId] = tuple.instance;
+ function mapHash(hash, func) {
+ let newHash = {};
+ for (let key in hash) {
+ newHash[key] = func(hash[key], key);
}
- return eventStore;
+ return newHash;
}
- // retrieves events that have the same groupId as the instance specified by `instanceId`
- // or they are the same as the instance.
- // why might instanceId not be in the store? an event from another calendar?
- function getRelevantEvents(eventStore, instanceId) {
- let instance = eventStore.instances[instanceId];
- if (instance) {
- let def = eventStore.defs[instance.defId];
- // get events/instances with same group
- let newStore = filterEventStoreDefs(eventStore, (lookDef) => isEventDefsGrouped(def, lookDef));
- // add the original
- // TODO: wish we could use eventTupleToStore or something like it
- newStore.defs[def.defId] = def;
- newStore.instances[instance.instanceId] = instance;
- return newStore;
+ function arrayToHash(a) {
+ let hash = {};
+ for (let item of a) {
+ hash[item] = true;
}
- return createEmptyEventStore();
- }
- function isEventDefsGrouped(def0, def1) {
- return Boolean(def0.groupId && def0.groupId === def1.groupId);
- }
- function createEmptyEventStore() {
- return { defs: {}, instances: {} };
- }
- function mergeEventStores(store0, store1) {
- return {
- defs: Object.assign(Object.assign({}, store0.defs), store1.defs),
- instances: Object.assign(Object.assign({}, store0.instances), store1.instances),
- };
- }
- function filterEventStoreDefs(eventStore, filterFunc) {
- let defs = filterHash(eventStore.defs, filterFunc);
- let instances = filterHash(eventStore.instances, (instance) => (defs[instance.defId] // still exists?
- ));
- return { defs, instances };
+ return hash;
}
- function excludeSubEventStore(master, sub) {
- let { defs, instances } = master;
- let filteredDefs = {};
- let filteredInstances = {};
- for (let defId in defs) {
- if (!sub.defs[defId]) { // not explicitly excluded
- filteredDefs[defId] = defs[defId];
- }
- }
- for (let instanceId in instances) {
- if (!sub.instances[instanceId] && // not explicitly excluded
- filteredDefs[instances[instanceId].defId] // def wasn't filtered away
- ) {
- filteredInstances[instanceId] = instances[instanceId];
- }
+ // TODO: reassess browser support
+ // https://caniuse.com/?search=object.values
+ function hashValuesToArray(obj) {
+ let a = [];
+ for (let key in obj) {
+ a.push(obj[key]);
}
- return {
- defs: filteredDefs,
- instances: filteredInstances,
- };
+ return a;
}
-
- function normalizeConstraint(input, context) {
- if (Array.isArray(input)) {
- return parseEvents(input, null, context, true); // allowOpenRange=true
+ function isPropsEqual(obj0, obj1) {
+ if (obj0 === obj1) {
+ return true;
}
- if (typeof input === 'object' && input) { // non-null object
- return parseEvents([input], null, context, true); // allowOpenRange=true
+ for (let key in obj0) {
+ if (hasOwnProperty.call(obj0, key)) {
+ if (!(key in obj1)) {
+ return false;
+ }
+ }
}
- if (input != null) {
- return String(input);
+ for (let key in obj1) {
+ if (hasOwnProperty.call(obj1, key)) {
+ if (obj0[key] !== obj1[key]) {
+ return false;
+ }
+ }
}
- return null;
+ return true;
}
-
- function parseClassNames(raw) {
- if (Array.isArray(raw)) {
- return raw;
- }
- if (typeof raw === 'string') {
- return raw.split(/\s+/);
+ const HANDLER_RE = /^on[A-Z]/;
+ function isNonHandlerPropsEqual(obj0, obj1) {
+ const keys = getUnequalProps(obj0, obj1);
+ for (let key of keys) {
+ if (!HANDLER_RE.test(key)) {
+ return false;
+ }
}
- return [];
- }
-
- // TODO: better called "EventSettings" or "EventConfig"
- // TODO: move this file into structs
- // TODO: separate constraint/overlap/allow, because selection uses only that, not other props
- const EVENT_UI_REFINERS = {
- display: String,
- editable: Boolean,
- startEditable: Boolean,
- durationEditable: Boolean,
- constraint: identity,
- overlap: identity,
- allow: identity,
- className: parseClassNames,
- classNames: parseClassNames,
- color: String,
- backgroundColor: String,
- borderColor: String,
- textColor: String,
- };
- const EMPTY_EVENT_UI = {
- display: null,
- startEditable: null,
- durationEditable: null,
- constraints: [],
- overlap: null,
- allows: [],
- backgroundColor: '',
- borderColor: '',
- textColor: '',
- classNames: [],
- };
- function createEventUi(refined, context) {
- let constraint = normalizeConstraint(refined.constraint, context);
- return {
- display: refined.display || null,
- startEditable: refined.startEditable != null ? refined.startEditable : refined.editable,
- durationEditable: refined.durationEditable != null ? refined.durationEditable : refined.editable,
- constraints: constraint != null ? [constraint] : [],
- overlap: refined.overlap != null ? refined.overlap : null,
- allows: refined.allow != null ? [refined.allow] : [],
- backgroundColor: refined.backgroundColor || refined.color || '',
- borderColor: refined.borderColor || refined.color || '',
- textColor: refined.textColor || '',
- classNames: (refined.className || []).concat(refined.classNames || []), // join singular and plural
- };
- }
- // TODO: prevent against problems with <2 args!
- function combineEventUis(uis) {
- return uis.reduce(combineTwoEventUis, EMPTY_EVENT_UI);
- }
- function combineTwoEventUis(item0, item1) {
- return {
- display: item1.display != null ? item1.display : item0.display,
- startEditable: item1.startEditable != null ? item1.startEditable : item0.startEditable,
- durationEditable: item1.durationEditable != null ? item1.durationEditable : item0.durationEditable,
- constraints: item0.constraints.concat(item1.constraints),
- overlap: typeof item1.overlap === 'boolean' ? item1.overlap : item0.overlap,
- allows: item0.allows.concat(item1.allows),
- backgroundColor: item1.backgroundColor || item0.backgroundColor,
- borderColor: item1.borderColor || item0.borderColor,
- textColor: item1.textColor || item0.textColor,
- classNames: item0.classNames.concat(item1.classNames),
- };
+ return true;
}
-
- const EVENT_NON_DATE_REFINERS = {
- id: String,
- groupId: String,
- title: String,
- url: String,
- interactive: Boolean,
- };
- const EVENT_DATE_REFINERS = {
- start: identity,
- end: identity,
- date: identity,
- allDay: Boolean,
- };
- const EVENT_REFINERS = Object.assign(Object.assign(Object.assign({}, EVENT_NON_DATE_REFINERS), EVENT_DATE_REFINERS), { extendedProps: identity });
- function parseEvent(raw, eventSource, context, allowOpenRange, refiners = buildEventRefiners(context), defIdMap, instanceIdMap) {
- let { refined, extra } = refineEventDef(raw, context, refiners);
- let defaultAllDay = computeIsDefaultAllDay(eventSource, context);
- let recurringRes = parseRecurring(refined, defaultAllDay, context.dateEnv, context.pluginHooks.recurringTypes);
- if (recurringRes) {
- let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', recurringRes.allDay, Boolean(recurringRes.duration), context, defIdMap);
- def.recurringDef = {
- typeId: recurringRes.typeId,
- typeData: recurringRes.typeData,
- duration: recurringRes.duration,
- };
- return { def, instance: null };
- }
- let singleRes = parseSingle(refined, defaultAllDay, context, allowOpenRange);
- if (singleRes) {
- let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', singleRes.allDay, singleRes.hasEnd, context, defIdMap);
- let instance = createEventInstance(def.defId, singleRes.range, singleRes.forcedStartTzo, singleRes.forcedEndTzo);
- if (instanceIdMap && def.publicId && instanceIdMap[def.publicId]) {
- instance.instanceId = instanceIdMap[def.publicId];
+ function getUnequalProps(obj0, obj1) {
+ let keys = [];
+ for (let key in obj0) {
+ if (hasOwnProperty.call(obj0, key)) {
+ if (!(key in obj1)) {
+ keys.push(key);
+ }
}
- return { def, instance };
}
- return null;
- }
- function refineEventDef(raw, context, refiners = buildEventRefiners(context)) {
- return refineProps(raw, refiners);
- }
- function buildEventRefiners(context) {
- return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_REFINERS), context.pluginHooks.eventRefiners);
- }
- /*
- Will NOT populate extendedProps with the leftover properties.
- Will NOT populate date-related props.
- */
- function parseEventDef(refined, extra, sourceId, allDay, hasEnd, context, defIdMap) {
- let def = {
- title: refined.title || '',
- groupId: refined.groupId || '',
- publicId: refined.id || '',
- url: refined.url || '',
- recurringDef: null,
- defId: ((defIdMap && refined.id) ? defIdMap[refined.id] : '') || guid(),
- sourceId,
- allDay,
- hasEnd,
- interactive: refined.interactive,
- ui: createEventUi(refined, context),
- extendedProps: Object.assign(Object.assign({}, (refined.extendedProps || {})), extra),
- };
- for (let memberAdder of context.pluginHooks.eventDefMemberAdders) {
- Object.assign(def, memberAdder(refined));
+ for (let key in obj1) {
+ if (hasOwnProperty.call(obj1, key)) {
+ if (obj0[key] !== obj1[key]) {
+ keys.push(key);
+ }
+ }
}
- // help out EventImpl from having user modify props
- Object.freeze(def.ui.classNames);
- Object.freeze(def.extendedProps);
- return def;
+ return keys;
}
- function parseSingle(refined, defaultAllDay, context, allowOpenRange) {
- let { allDay } = refined;
- let startMeta;
- let startMarker = null;
- let hasEnd = false;
- let endMeta;
- let endMarker = null;
- let startInput = refined.start != null ? refined.start : refined.date;
- startMeta = context.dateEnv.createMarkerMeta(startInput);
- if (startMeta) {
- startMarker = startMeta.marker;
- }
- else if (!allowOpenRange) {
- return null;
- }
- if (refined.end != null) {
- endMeta = context.dateEnv.createMarkerMeta(refined.end);
+ function compareObjs(oldProps, newProps, equalityFuncs = {}) {
+ if (oldProps === newProps) {
+ return true;
}
- if (allDay == null) {
- if (defaultAllDay != null) {
- allDay = defaultAllDay;
- }
+ for (let key in newProps) {
+ if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) ;
else {
- // fall back to the date props LAST
- allDay = (!startMeta || startMeta.isTimeUnspecified) &&
- (!endMeta || endMeta.isTimeUnspecified);
+ return false;
}
}
- if (allDay && startMarker) {
- startMarker = startOfDay(startMarker);
- }
- if (endMeta) {
- endMarker = endMeta.marker;
- if (allDay) {
- endMarker = startOfDay(endMarker);
- }
- if (startMarker && endMarker <= startMarker) {
- endMarker = null;
+ // check for props that were omitted in the new
+ for (let key in oldProps) {
+ if (!(key in newProps)) {
+ return false;
}
}
- if (endMarker) {
- hasEnd = true;
- }
- else if (!allowOpenRange) {
- hasEnd = context.options.forceEventDuration || false;
- endMarker = context.dateEnv.add(startMarker, allDay ?
- context.options.defaultAllDayEventDuration :
- context.options.defaultTimedEventDuration);
- }
- return {
- allDay,
- hasEnd,
- range: { start: startMarker, end: endMarker },
- forcedStartTzo: startMeta ? startMeta.forcedTzo : null,
- forcedEndTzo: endMeta ? endMeta.forcedTzo : null,
- };
- }
- function computeIsDefaultAllDay(eventSource, context) {
- let res = null;
- if (eventSource) {
- res = eventSource.defaultAllDay;
- }
- if (res == null) {
- res = context.options.defaultAllDay;
- }
- return res;
+ return true;
}
-
- const DEF_DEFAULTS = {
- startTime: '09:00',
- endTime: '17:00',
- daysOfWeek: [1, 2, 3, 4, 5],
- display: 'inverse-background',
- classNames: 'fc-non-business',
- groupId: '_businessHours', // so multiple defs get grouped
- };
/*
- TODO: pass around as EventDefHash!!!
+ assumed "true" equality for handler names like "onReceiveSomething"
*/
- function parseBusinessHours(input, context) {
- return parseEvents(refineInputs(input), null, context);
- }
- function refineInputs(input) {
- let rawDefs;
- if (input === true) {
- rawDefs = [{}]; // will get DEF_DEFAULTS verbatim
+ function isObjValsEqual(val0, val1, comparator) {
+ if (val0 === val1 || comparator === true) {
+ return true;
}
- else if (Array.isArray(input)) {
- // if specifying an array, every sub-definition NEEDS a day-of-week
- rawDefs = input.filter((rawDef) => rawDef.daysOfWeek);
+ if (comparator) {
+ return comparator(val0, val1);
}
- else if (typeof input === 'object' && input) { // non-null object
- rawDefs = [input];
+ return false;
+ }
+ function collectFromHash(hash, startIndex = 0, endIndex, step = 1) {
+ let res = [];
+ if (endIndex == null) {
+ endIndex = Object.keys(hash).length;
}
- else { // is probably false
- rawDefs = [];
+ for (let i = startIndex; i < endIndex; i += step) {
+ let val = hash[i];
+ if (val !== undefined) { // will disregard undefined for sparse arrays
+ res.push(val);
+ }
}
- rawDefs = rawDefs.map((rawDef) => (Object.assign(Object.assign({}, DEF_DEFAULTS), rawDef)));
- return rawDefs;
+ return res;
}
- /* Date stuff that doesn't belong in datelib core
- ----------------------------------------------------------------------------------------------------------------------*/
- // given a timed range, computes an all-day range that has the same exact duration,
- // but whose start time is aligned with the start of the day.
- function computeAlignedDayRange(timedRange) {
- let dayCnt = Math.floor(diffDays(timedRange.start, timedRange.end)) || 1;
- let start = startOfDay(timedRange.start);
- let end = addDays(start, dayCnt);
- return { start, end };
+ let calendarSystemClassMap = {};
+ function registerCalendarSystem(name, theClass) {
+ calendarSystemClassMap[name] = theClass;
}
- // given a timed range, computes an all-day range based on how for the end date bleeds into the next day
- // TODO: give nextDayThreshold a default arg
- function computeVisibleDayRange(timedRange, nextDayThreshold = createDuration(0)) {
- let startDay = null;
- let endDay = null;
- if (timedRange.end) {
- endDay = startOfDay(timedRange.end);
- let endTimeMS = timedRange.end.valueOf() - endDay.valueOf(); // # of milliseconds into `endDay`
- // If the end time is actually inclusively part of the next day and is equal to or
- // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
- // Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
- if (endTimeMS && endTimeMS >= asRoughMs(nextDayThreshold)) {
- endDay = addDays(endDay, 1);
- }
+ function createCalendarSystem(name) {
+ return new calendarSystemClassMap[name]();
+ }
+ class GregorianCalendarSystem {
+ getMarkerYear(d) {
+ return d.getUTCFullYear();
}
- if (timedRange.start) {
- startDay = startOfDay(timedRange.start); // the beginning of the day the range starts
- // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day.
- if (endDay && endDay <= startDay) {
- endDay = addDays(startDay, 1);
- }
+ getMarkerMonth(d) {
+ return d.getUTCMonth();
}
- return { start: startDay, end: endDay };
- }
- // spans from one day into another?
- function isMultiDayRange(range) {
- let visibleRange = computeVisibleDayRange(range);
- return diffDays(visibleRange.start, visibleRange.end) > 1;
- }
- function diffDates(date0, date1, dateEnv, largeUnit) {
- if (largeUnit === 'year') {
- return createDuration(dateEnv.diffWholeYears(date0, date1), 'year');
+ getMarkerDay(d) {
+ return d.getUTCDate();
}
- if (largeUnit === 'month') {
- return createDuration(dateEnv.diffWholeMonths(date0, date1), 'month');
+ arrayToMarker(arr) {
+ return arrayToUtcDate(arr);
}
- return diffDayAndTime(date0, date1); // returns a duration
- }
-
- function pointInsideRect(point, rect) {
- return point.left >= rect.left &&
- point.left < rect.right &&
- point.top >= rect.top &&
- point.top < rect.bottom;
- }
- // Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false
- function intersectRects(rect1, rect2) {
- let res = {
- left: Math.max(rect1.left, rect2.left),
- right: Math.min(rect1.right, rect2.right),
- top: Math.max(rect1.top, rect2.top),
- bottom: Math.min(rect1.bottom, rect2.bottom),
- };
- if (res.left < res.right && res.top < res.bottom) {
- return res;
+ markerToArray(marker) {
+ return dateToUtcArray(marker);
}
- return false;
- }
- function translateRect(rect, deltaX, deltaY) {
- return {
- left: rect.left + deltaX,
- right: rect.right + deltaX,
- top: rect.top + deltaY,
- bottom: rect.bottom + deltaY,
- };
- }
- // Returns a new point that will have been moved to reside within the given rectangle
- function constrainPoint(point, rect) {
- return {
- left: Math.min(Math.max(point.left, rect.left), rect.right),
- top: Math.min(Math.max(point.top, rect.top), rect.bottom),
- };
- }
- // Returns a point that is the center of the given rectangle
- function getRectCenter(rect) {
- return {
- left: (rect.left + rect.right) / 2,
- top: (rect.top + rect.bottom) / 2,
- };
- }
- // Subtracts point2's coordinates from point1's coordinates, returning a delta
- function diffPoints(point1, point2) {
- return {
- left: point1.left - point2.left,
- top: point1.top - point2.top,
- };
}
+ registerCalendarSystem('gregory', GregorianCalendarSystem);
- let canVGrowWithinCell;
- function getCanVGrowWithinCell() {
- if (canVGrowWithinCell == null) {
- canVGrowWithinCell = computeCanVGrowWithinCell();
- }
- return canVGrowWithinCell;
- }
- function computeCanVGrowWithinCell() {
- // for SSR, because this function is call immediately at top-level
- // TODO: just make this logic execute top-level, immediately, instead of doing lazily
- if (typeof document === 'undefined') {
- return true;
+ const ISO_RE = /^\s*(\d{4})(-?(\d{2})(-?(\d{2})([T ](\d{2}):?(\d{2})(:?(\d{2})(\.(\d+))?)?(Z|(([-+])(\d{2})(:?(\d{2}))?))?)?)?)?$/;
+ function parse(str) {
+ let m = ISO_RE.exec(str);
+ if (m) {
+ let 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));
+ if (isValidDate(marker)) {
+ let timeZoneOffset = null;
+ if (m[13]) {
+ timeZoneOffset = (m[15] === '-' ? -1 : 1) * (Number(m[16] || 0) * 60 +
+ Number(m[18] || 0));
+ }
+ return {
+ marker,
+ isTimeUnspecified: !m[6],
+ timeZoneOffset,
+ };
+ }
}
- let el = document.createElement('div');
- el.style.position = 'absolute';
- el.style.top = '0px';
- el.style.left = '0px';
- el.innerHTML = '<table><tr><td><div></div></td></tr></table>';
- el.querySelector('table').style.height = '100px';
- el.querySelector('div').style.height = '100%';
- document.body.appendChild(el);
- let div = el.querySelector('div');
- let possible = div.offsetHeight > 0;
- document.body.removeChild(el);
- return possible;
+ return null;
}
- const EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere
- class Splitter {
- constructor() {
- this.getKeysForEventDefs = memoize(this._getKeysForEventDefs);
- this.splitDateSelection = memoize(this._splitDateSpan);
- this.splitEventStore = memoize(this._splitEventStore);
- this.splitIndividualUi = memoize(this._splitIndividualUi);
- this.splitEventDrag = memoize(this._splitInteraction);
- this.splitEventResize = memoize(this._splitInteraction);
- this.eventUiBuilders = {}; // TODO: typescript protection
- }
- splitProps(props) {
- let keyInfos = this.getKeyInfo(props);
- let defKeys = this.getKeysForEventDefs(props.eventStore);
- let dateSelections = this.splitDateSelection(props.dateSelection);
- let individualUi = this.splitIndividualUi(props.eventUiBases, defKeys); // the individual *bases*
- let eventStores = this.splitEventStore(props.eventStore, defKeys);
- let eventDrags = this.splitEventDrag(props.eventDrag);
- let eventResizes = this.splitEventResize(props.eventResize);
- let splitProps = {};
- this.eventUiBuilders = mapHash(keyInfos, (info, key) => this.eventUiBuilders[key] || memoize(buildEventUiForKey));
- for (let key in keyInfos) {
- let keyInfo = keyInfos[key];
- let eventStore = eventStores[key] || EMPTY_EVENT_STORE;
- let buildEventUi = this.eventUiBuilders[key];
- splitProps[key] = {
- businessHours: keyInfo.businessHours || props.businessHours,
- dateSelection: dateSelections[key] || null,
- eventStore,
- eventUiBases: buildEventUi(props.eventUiBases[''], keyInfo.ui, individualUi[key]),
- eventSelection: eventStore.instances[props.eventSelection] ? props.eventSelection : '',
- eventDrag: eventDrags[key] || null,
- eventResize: eventResizes[key] || null,
- };
+ class DateEnv {
+ constructor(settings) {
+ let timeZone = this.timeZone = settings.timeZone;
+ let isNamedTimeZone = timeZone !== 'local' && timeZone !== 'UTC';
+ if (settings.namedTimeZoneImpl && isNamedTimeZone) {
+ this.namedTimeZoneImpl = new settings.namedTimeZoneImpl(timeZone);
}
- return splitProps;
+ this.canComputeOffset = Boolean(!isNamedTimeZone || this.namedTimeZoneImpl);
+ this.calendarSystem = createCalendarSystem(settings.calendarSystem);
+ this.locale = settings.locale;
+ this.weekDow = settings.locale.week.dow;
+ this.weekDoy = settings.locale.week.doy;
+ if (settings.weekNumberCalculation === 'ISO') {
+ this.weekDow = 1;
+ this.weekDoy = 4;
+ }
+ if (typeof settings.firstDay === 'number') {
+ this.weekDow = settings.firstDay;
+ }
+ if (typeof settings.weekNumberCalculation === 'function') {
+ this.weekNumberFunc = settings.weekNumberCalculation;
+ }
+ this.weekText = settings.weekText != null ? settings.weekText : settings.locale.options.weekText;
+ this.weekTextLong = (settings.weekTextLong != null ? settings.weekTextLong : settings.locale.options.weekTextLong) || this.weekText;
+ this.cmdFormatter = settings.cmdFormatter;
+ this.defaultSeparator = settings.defaultSeparator;
}
- _splitDateSpan(dateSpan) {
- let dateSpans = {};
- if (dateSpan) {
- let keys = this.getKeysForDateSpan(dateSpan);
- for (let key of keys) {
- dateSpans[key] = dateSpan;
- }
+ // Creating / Parsing
+ createMarker(input) {
+ let meta = this.createMarkerMeta(input);
+ if (meta === null) {
+ return null;
}
- return dateSpans;
+ return meta.marker;
}
- _getKeysForEventDefs(eventStore) {
- return mapHash(eventStore.defs, (eventDef) => this.getKeysForEventDef(eventDef));
+ createNowMarker() {
+ if (this.canComputeOffset) {
+ return this.timestampToMarker(new Date().valueOf());
+ }
+ // if we can't compute the current date val for a timezone,
+ // better to give the current local date vals than UTC
+ return arrayToUtcDate(dateToLocalArray(new Date()));
}
- _splitEventStore(eventStore, defKeys) {
- let { defs, instances } = eventStore;
- let splitStores = {};
- for (let defId in defs) {
- for (let key of defKeys[defId]) {
- if (!splitStores[key]) {
- splitStores[key] = createEmptyEventStore();
- }
- splitStores[key].defs[defId] = defs[defId];
- }
+ createMarkerMeta(input) {
+ if (typeof input === 'string') {
+ return this.parse(input);
}
- for (let instanceId in instances) {
- let instance = instances[instanceId];
- for (let key of defKeys[instance.defId]) {
- if (splitStores[key]) { // must have already been created
- splitStores[key].instances[instanceId] = instance;
- }
- }
+ let marker = null;
+ if (typeof input === 'number') {
+ marker = this.timestampToMarker(input);
}
- return splitStores;
- }
- _splitIndividualUi(eventUiBases, defKeys) {
- let splitHashes = {};
- for (let defId in eventUiBases) {
- if (defId) { // not the '' key
- for (let key of defKeys[defId]) {
- if (!splitHashes[key]) {
- splitHashes[key] = {};
- }
- splitHashes[key][defId] = eventUiBases[defId];
- }
+ else if (input instanceof Date) {
+ input = input.valueOf();
+ if (!isNaN(input)) {
+ marker = this.timestampToMarker(input);
}
}
- return splitHashes;
+ else if (Array.isArray(input)) {
+ marker = arrayToUtcDate(input);
+ }
+ if (marker === null || !isValidDate(marker)) {
+ return null;
+ }
+ return { marker, isTimeUnspecified: false, forcedTzo: null };
}
- _splitInteraction(interaction) {
- let splitStates = {};
- if (interaction) {
- let affectedStores = this._splitEventStore(interaction.affectedEvents, this._getKeysForEventDefs(interaction.affectedEvents));
- // can't rely on defKeys because event data is mutated
- let mutatedKeysByDefId = this._getKeysForEventDefs(interaction.mutatedEvents);
- let mutatedStores = this._splitEventStore(interaction.mutatedEvents, mutatedKeysByDefId);
- let populate = (key) => {
- if (!splitStates[key]) {
- splitStates[key] = {
- affectedEvents: affectedStores[key] || EMPTY_EVENT_STORE,
- mutatedEvents: mutatedStores[key] || EMPTY_EVENT_STORE,
- isEvent: interaction.isEvent,
- };
- }
- };
- for (let key in affectedStores) {
- populate(key);
+ parse(s) {
+ let parts = parse(s);
+ if (parts === null) {
+ return null;
+ }
+ let { marker } = parts;
+ let forcedTzo = null;
+ if (parts.timeZoneOffset !== null) {
+ if (this.canComputeOffset) {
+ marker = this.timestampToMarker(marker.valueOf() - parts.timeZoneOffset * 60 * 1000);
}
- for (let key in mutatedStores) {
- populate(key);
+ else {
+ forcedTzo = parts.timeZoneOffset;
}
}
- return splitStates;
- }
- }
- function buildEventUiForKey(allUi, eventUiForKey, individualUi) {
- let baseParts = [];
- if (allUi) {
- baseParts.push(allUi);
- }
- if (eventUiForKey) {
- baseParts.push(eventUiForKey);
+ return { marker, isTimeUnspecified: parts.isTimeUnspecified, forcedTzo };
}
- let stuff = {
- '': combineEventUis(baseParts),
- };
- if (individualUi) {
- Object.assign(stuff, individualUi);
+ // Accessors
+ getYear(marker) {
+ return this.calendarSystem.getMarkerYear(marker);
}
- return stuff;
- }
-
- function parseRange(input, dateEnv) {
- let start = null;
- let end = null;
- if (input.start) {
- start = dateEnv.createMarker(input.start);
+ getMonth(marker) {
+ return this.calendarSystem.getMarkerMonth(marker);
}
- if (input.end) {
- end = dateEnv.createMarker(input.end);
+ getDay(marker) {
+ return this.calendarSystem.getMarkerDay(marker);
}
- if (!start && !end) {
- return null;
+ // Adding / Subtracting
+ add(marker, dur) {
+ let a = this.calendarSystem.markerToArray(marker);
+ a[0] += dur.years;
+ a[1] += dur.months;
+ a[2] += dur.days;
+ a[6] += dur.milliseconds;
+ return this.calendarSystem.arrayToMarker(a);
}
- if (start && end && end < start) {
- return null;
+ subtract(marker, dur) {
+ let a = this.calendarSystem.markerToArray(marker);
+ a[0] -= dur.years;
+ a[1] -= dur.months;
+ a[2] -= dur.days;
+ a[6] -= dur.milliseconds;
+ return this.calendarSystem.arrayToMarker(a);
}
- return { start, end };
- }
- // SIDE-EFFECT: will mutate ranges.
- // Will return a new array result.
- function invertRanges(ranges, constraintRange) {
- let invertedRanges = [];
- let { start } = constraintRange; // the end of the previous range. the start of the new range
- let i;
- let dateRange;
- // ranges need to be in order. required for our date-walking algorithm
- ranges.sort(compareRanges);
- for (i = 0; i < ranges.length; i += 1) {
- dateRange = ranges[i];
- // add the span of time before the event (if there is any)
- if (dateRange.start > start) { // compare millisecond time (skip any ambig logic)
- invertedRanges.push({ start, end: dateRange.start });
- }
- if (dateRange.end > start) {
- start = dateRange.end;
- }
+ addYears(marker, n) {
+ let a = this.calendarSystem.markerToArray(marker);
+ a[0] += n;
+ return this.calendarSystem.arrayToMarker(a);
}
- // add the span of time after the last event (if there is any)
- if (start < constraintRange.end) { // compare millisecond time (skip any ambig logic)
- invertedRanges.push({ start, end: constraintRange.end });
+ addMonths(marker, n) {
+ let a = this.calendarSystem.markerToArray(marker);
+ a[1] += n;
+ return this.calendarSystem.arrayToMarker(a);
}
- return invertedRanges;
- }
- function compareRanges(range0, range1) {
- return range0.start.valueOf() - range1.start.valueOf(); // earlier ranges go first
- }
- function intersectRanges(range0, range1) {
- let { start, end } = range0;
- let newRange = null;
- if (range1.start !== null) {
- if (start === null) {
- start = range1.start;
- }
- else {
- start = new Date(Math.max(start.valueOf(), range1.start.valueOf()));
+ // Diffing Whole Units
+ diffWholeYears(m0, m1) {
+ let { calendarSystem } = this;
+ if (timeAsMs(m0) === timeAsMs(m1) &&
+ calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1) &&
+ calendarSystem.getMarkerMonth(m0) === calendarSystem.getMarkerMonth(m1)) {
+ return calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0);
}
+ return null;
}
- if (range1.end != null) {
- if (end === null) {
- end = range1.end;
- }
- else {
- end = new Date(Math.min(end.valueOf(), range1.end.valueOf()));
+ diffWholeMonths(m0, m1) {
+ let { calendarSystem } = this;
+ if (timeAsMs(m0) === timeAsMs(m1) &&
+ calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1)) {
+ return (calendarSystem.getMarkerMonth(m1) - calendarSystem.getMarkerMonth(m0)) +
+ (calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0)) * 12;
}
+ return null;
}
- if (start === null || end === null || start < end) {
- newRange = { start, end };
- }
- return newRange;
- }
- function rangesEqual(range0, range1) {
- return (range0.start === null ? null : range0.start.valueOf()) === (range1.start === null ? null : range1.start.valueOf()) &&
- (range0.end === null ? null : range0.end.valueOf()) === (range1.end === null ? null : range1.end.valueOf());
- }
- function rangesIntersect(range0, range1) {
- return (range0.end === null || range1.start === null || range0.end > range1.start) &&
- (range0.start === null || range1.end === null || range0.start < range1.end);
- }
- function rangeContainsRange(outerRange, innerRange) {
- return (outerRange.start === null || (innerRange.start !== null && innerRange.start >= outerRange.start)) &&
- (outerRange.end === null || (innerRange.end !== null && innerRange.end <= outerRange.end));
- }
- function rangeContainsMarker(range, date) {
- return (range.start === null || date >= range.start) &&
- (range.end === null || date < range.end);
- }
- // If the given date is not within the given range, move it inside.
- // (If it's past the end, make it one millisecond before the end).
- function constrainMarkerToRange(date, range) {
- if (range.start != null && date < range.start) {
- return range.start;
- }
- if (range.end != null && date >= range.end) {
- return new Date(range.end.valueOf() - 1);
- }
- return date;
- }
-
- function getDateMeta(date, todayRange, nowDate, dateProfile) {
- return {
- dow: date.getUTCDay(),
- isDisabled: Boolean(dateProfile && !rangeContainsMarker(dateProfile.activeRange, date)),
- isOther: Boolean(dateProfile && !rangeContainsMarker(dateProfile.currentRange, date)),
- isToday: Boolean(todayRange && rangeContainsMarker(todayRange, date)),
- isPast: Boolean(nowDate ? (date < nowDate) : todayRange ? (date < todayRange.start) : false),
- isFuture: Boolean(nowDate ? (date > nowDate) : todayRange ? (date >= todayRange.end) : false),
- };
- }
- function getDayClassNames(meta, theme) {
- let classNames = [
- 'fc-day',
- `fc-day-${DAY_IDS[meta.dow]}`,
- ];
- if (meta.isDisabled) {
- classNames.push('fc-day-disabled');
- }
- else {
- if (meta.isToday) {
- classNames.push('fc-day-today');
- classNames.push(theme.getClass('today'));
+ // Range / Duration
+ greatestWholeUnit(m0, m1) {
+ let n = this.diffWholeYears(m0, m1);
+ if (n !== null) {
+ return { unit: 'year', value: n };
}
- if (meta.isPast) {
- classNames.push('fc-day-past');
+ n = this.diffWholeMonths(m0, m1);
+ if (n !== null) {
+ return { unit: 'month', value: n };
}
- if (meta.isFuture) {
- classNames.push('fc-day-future');
+ n = diffWholeWeeks(m0, m1);
+ if (n !== null) {
+ return { unit: 'week', value: n };
}
- if (meta.isOther) {
- classNames.push('fc-day-other');
+ n = diffWholeDays(m0, m1);
+ if (n !== null) {
+ return { unit: 'day', value: n };
}
- }
- return classNames;
- }
- function getSlotClassNames(meta, theme) {
- let classNames = [
- 'fc-slot',
- `fc-slot-${DAY_IDS[meta.dow]}`,
- ];
- if (meta.isDisabled) {
- classNames.push('fc-slot-disabled');
- }
- else {
- if (meta.isToday) {
- classNames.push('fc-slot-today');
- classNames.push(theme.getClass('today'));
+ n = diffHours(m0, m1);
+ if (isInt(n)) {
+ return { unit: 'hour', value: n };
}
- if (meta.isPast) {
- classNames.push('fc-slot-past');
+ n = diffMinutes(m0, m1);
+ if (isInt(n)) {
+ return { unit: 'minute', value: n };
}
- if (meta.isFuture) {
- classNames.push('fc-slot-future');
+ n = diffSeconds(m0, m1);
+ if (isInt(n)) {
+ return { unit: 'second', value: n };
}
+ return { unit: 'millisecond', value: m1.valueOf() - m0.valueOf() };
}
- return classNames;
- }
-
- const DAY_FORMAT = createFormatter({ year: 'numeric', month: 'long', day: 'numeric' });
- const WEEK_FORMAT = createFormatter({ week: 'long' });
- function buildNavLinkAttrs(context, dateMarker, viewType = 'day', isTabbable = true) {
- const { dateEnv, options, calendarApi } = context;
- let dateStr = dateEnv.format(dateMarker, viewType === 'week' ? WEEK_FORMAT : DAY_FORMAT);
- if (options.navLinks) {
- let zonedDate = dateEnv.toDate(dateMarker);
- const handleInteraction = (ev) => {
- let customAction = viewType === 'day' ? options.navLinkDayClick :
- viewType === 'week' ? options.navLinkWeekClick : null;
- if (typeof customAction === 'function') {
- customAction.call(calendarApi, dateEnv.toDate(dateMarker), ev);
+ countDurationsBetween(m0, m1, d) {
+ // TODO: can use greatestWholeUnit
+ let diff;
+ if (d.years) {
+ diff = this.diffWholeYears(m0, m1);
+ if (diff !== null) {
+ return diff / asRoughYears(d);
}
- else {
- if (typeof customAction === 'string') {
- viewType = customAction;
- }
- calendarApi.zoomTo(dateMarker, viewType);
+ }
+ if (d.months) {
+ diff = this.diffWholeMonths(m0, m1);
+ if (diff !== null) {
+ return diff / asRoughMonths(d);
}
- };
- return Object.assign({ title: formatWithOrdinals(options.navLinkHint, [dateStr, zonedDate], dateStr), 'data-navlink': '' }, (isTabbable
- ? createAriaClickAttrs(handleInteraction)
- : { onClick: handleInteraction }));
- }
- return { 'aria-label': dateStr };
- }
-
- let _isRtlScrollbarOnLeft = null;
- function getIsRtlScrollbarOnLeft() {
- if (_isRtlScrollbarOnLeft === null) {
- _isRtlScrollbarOnLeft = computeIsRtlScrollbarOnLeft();
- }
- return _isRtlScrollbarOnLeft;
- }
- function computeIsRtlScrollbarOnLeft() {
- let outerEl = document.createElement('div');
- applyStyle(outerEl, {
- position: 'absolute',
- top: -1000,
- left: 0,
- border: 0,
- padding: 0,
- overflow: 'scroll',
- direction: 'rtl',
- });
- outerEl.innerHTML = '<div></div>';
- document.body.appendChild(outerEl);
- let innerEl = outerEl.firstChild;
- let res = innerEl.getBoundingClientRect().left > outerEl.getBoundingClientRect().left;
- removeElement(outerEl);
- return res;
- }
-
- let _scrollbarWidths;
- function getScrollbarWidths() {
- if (!_scrollbarWidths) {
- _scrollbarWidths = computeScrollbarWidths();
- }
- return _scrollbarWidths;
- }
- function computeScrollbarWidths() {
- let el = document.createElement('div');
- el.style.overflow = 'scroll';
- el.style.position = 'absolute';
- el.style.top = '-9999px';
- el.style.left = '-9999px';
- document.body.appendChild(el);
- let res = computeScrollbarWidthsForEl(el);
- document.body.removeChild(el);
- return res;
- }
- // WARNING: will include border
- function computeScrollbarWidthsForEl(el) {
- return {
- x: el.offsetHeight - el.clientHeight,
- y: el.offsetWidth - el.clientWidth,
- };
- }
-
- function computeEdges(el, getPadding = false) {
- let computedStyle = window.getComputedStyle(el);
- let borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0;
- let borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0;
- let borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0;
- let borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
- let badScrollbarWidths = computeScrollbarWidthsForEl(el); // includes border!
- let scrollbarLeftRight = badScrollbarWidths.y - borderLeft - borderRight;
- let scrollbarBottom = badScrollbarWidths.x - borderTop - borderBottom;
- let res = {
- borderLeft,
- borderRight,
- borderTop,
- borderBottom,
- scrollbarBottom,
- scrollbarLeft: 0,
- scrollbarRight: 0,
- };
- if (getIsRtlScrollbarOnLeft() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side?
- res.scrollbarLeft = scrollbarLeftRight;
- }
- else {
- res.scrollbarRight = scrollbarLeftRight;
- }
- if (getPadding) {
- res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0;
- res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0;
- res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0;
- res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0;
- }
- return res;
- }
- function computeInnerRect(el, goWithinPadding = false, doFromWindowViewport) {
- let outerRect = doFromWindowViewport ? el.getBoundingClientRect() : computeRect(el);
- let edges = computeEdges(el, goWithinPadding);
- let res = {
- left: outerRect.left + edges.borderLeft + edges.scrollbarLeft,
- right: outerRect.right - edges.borderRight - edges.scrollbarRight,
- top: outerRect.top + edges.borderTop,
- bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom,
- };
- if (goWithinPadding) {
- res.left += edges.paddingLeft;
- res.right -= edges.paddingRight;
- res.top += edges.paddingTop;
- res.bottom -= edges.paddingBottom;
- }
- return res;
- }
- function computeRect(el) {
- let rect = el.getBoundingClientRect();
- return {
- left: rect.left + window.pageXOffset,
- top: rect.top + window.pageYOffset,
- right: rect.right + window.pageXOffset,
- bottom: rect.bottom + window.pageYOffset,
- };
- }
- function computeClippedClientRect(el) {
- let clippingParents = getClippingParents(el);
- let rect = el.getBoundingClientRect();
- for (let clippingParent of clippingParents) {
- let intersection = intersectRects(rect, clippingParent.getBoundingClientRect());
- if (intersection) {
- rect = intersection;
}
- else {
- return null;
+ if (d.days) {
+ diff = diffWholeDays(m0, m1);
+ if (diff !== null) {
+ return diff / asRoughDays(d);
+ }
}
+ return (m1.valueOf() - m0.valueOf()) / asRoughMs(d);
}
- return rect;
- }
- // does not return window
- function getClippingParents(el) {
- let parents = [];
- while (el instanceof HTMLElement) { // will stop when gets to document or null
- let computedStyle = window.getComputedStyle(el);
- if (computedStyle.position === 'fixed') {
- break;
+ // Start-Of
+ // these DON'T return zoned-dates. only UTC start-of dates
+ startOf(m, unit) {
+ if (unit === 'year') {
+ return this.startOfYear(m);
}
- if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) {
- parents.push(el);
+ if (unit === 'month') {
+ return this.startOfMonth(m);
}
- el = el.parentNode;
- }
- return parents;
- }
-
- /*
- given a function that resolves a result asynchronously.
- the function can either call passed-in success and failure callbacks,
- or it can return a promise.
- if you need to pass additional params to func, bind them first.
- */
- function unpromisify(func, normalizedSuccessCallback, normalizedFailureCallback) {
- // guard against success/failure callbacks being called more than once
- // and guard against a promise AND callback being used together.
- let isResolved = false;
- let wrappedSuccess = function (res) {
- if (!isResolved) {
- isResolved = true;
- normalizedSuccessCallback(res);
+ if (unit === 'week') {
+ return this.startOfWeek(m);
}
- };
- let wrappedFailure = function (error) {
- if (!isResolved) {
- isResolved = true;
- normalizedFailureCallback(error);
+ if (unit === 'day') {
+ return startOfDay(m);
}
- };
- let res = func(wrappedSuccess, wrappedFailure);
- if (res && typeof res.then === 'function') {
- res.then(wrappedSuccess, wrappedFailure);
- }
- }
-
- class Emitter {
- constructor() {
- this.handlers = {};
- this.thisContext = null;
- }
- setThisContext(thisContext) {
- this.thisContext = thisContext;
+ if (unit === 'hour') {
+ return startOfHour(m);
+ }
+ if (unit === 'minute') {
+ return startOfMinute(m);
+ }
+ if (unit === 'second') {
+ return startOfSecond(m);
+ }
+ return null;
}
- setOptions(options) {
- this.options = options;
+ startOfYear(m) {
+ return this.calendarSystem.arrayToMarker([
+ this.calendarSystem.getMarkerYear(m),
+ ]);
}
- on(type, handler) {
- addToHash(this.handlers, type, handler);
+ startOfMonth(m) {
+ return this.calendarSystem.arrayToMarker([
+ this.calendarSystem.getMarkerYear(m),
+ this.calendarSystem.getMarkerMonth(m),
+ ]);
}
- off(type, handler) {
- removeFromHash(this.handlers, type, handler);
+ startOfWeek(m) {
+ return this.calendarSystem.arrayToMarker([
+ this.calendarSystem.getMarkerYear(m),
+ this.calendarSystem.getMarkerMonth(m),
+ m.getUTCDate() - ((m.getUTCDay() - this.weekDow + 7) % 7),
+ ]);
}
- trigger(type, ...args) {
- let attachedHandlers = this.handlers[type] || [];
- let optionHandler = this.options && this.options[type];
- let handlers = [].concat(optionHandler || [], attachedHandlers);
- for (let handler of handlers) {
- handler.apply(this.thisContext, args);
+ // Week Number
+ computeWeekNumber(marker) {
+ if (this.weekNumberFunc) {
+ return this.weekNumberFunc(this.toDate(marker));
}
+ return weekOfYear(marker, this.weekDow, this.weekDoy);
}
- hasHandlers(type) {
- return Boolean((this.handlers[type] && this.handlers[type].length) ||
- (this.options && this.options[type]));
+ // TODO: choke on timeZoneName: long
+ format(marker, formatter, dateOptions = {}) {
+ return formatter.format({
+ marker,
+ timeZoneOffset: dateOptions.forcedTzo != null ?
+ dateOptions.forcedTzo :
+ this.offsetForMarker(marker),
+ }, this);
}
- }
- function addToHash(hash, type, handler) {
- (hash[type] || (hash[type] = []))
- .push(handler);
- }
- function removeFromHash(hash, type, handler) {
- if (handler) {
- if (hash[type]) {
- hash[type] = hash[type].filter((func) => func !== handler);
+ formatRange(start, end, formatter, dateOptions = {}) {
+ if (dateOptions.isEndExclusive) {
+ end = addMs(end, -1);
}
+ return formatter.formatRange({
+ marker: start,
+ timeZoneOffset: dateOptions.forcedStartTzo != null ?
+ dateOptions.forcedStartTzo :
+ this.offsetForMarker(start),
+ }, {
+ marker: end,
+ timeZoneOffset: dateOptions.forcedEndTzo != null ?
+ dateOptions.forcedEndTzo :
+ this.offsetForMarker(end),
+ }, this, dateOptions.defaultSeparator);
}
- else {
- delete hash[type]; // remove all handler funcs for this type
+ /*
+ DUMB: the omitTime arg is dumb. if we omit the time, we want to omit the timezone offset. and if we do that,
+ might as well use buildIsoString or some other util directly
+ */
+ formatIso(marker, extraOptions = {}) {
+ let timeZoneOffset = null;
+ if (!extraOptions.omitTimeZoneOffset) {
+ if (extraOptions.forcedTzo != null) {
+ timeZoneOffset = extraOptions.forcedTzo;
+ }
+ else {
+ timeZoneOffset = this.offsetForMarker(marker);
+ }
+ }
+ return buildIsoString(marker, timeZoneOffset, extraOptions.omitTime);
}
- }
-
- /*
- Records offset information for a set of elements, relative to an origin element.
- Can record the left/right OR the top/bottom OR both.
- Provides methods for querying the cache by position.
- */
- class PositionCache {
- constructor(originEl, els, isHorizontal, isVertical) {
- this.els = els;
- let originClientRect = this.originClientRect = originEl.getBoundingClientRect(); // relative to viewport top-left
- if (isHorizontal) {
- this.buildElHorizontals(originClientRect.left);
+ // TimeZone
+ timestampToMarker(ms) {
+ if (this.timeZone === 'local') {
+ return arrayToUtcDate(dateToLocalArray(new Date(ms)));
}
- if (isVertical) {
- this.buildElVerticals(originClientRect.top);
+ if (this.timeZone === 'UTC' || !this.namedTimeZoneImpl) {
+ return new Date(ms);
}
+ return arrayToUtcDate(this.namedTimeZoneImpl.timestampToArray(ms));
}
- // Populates the left/right internal coordinate arrays
- buildElHorizontals(originClientLeft) {
- let lefts = [];
- let rights = [];
- for (let el of this.els) {
- let rect = el.getBoundingClientRect();
- lefts.push(rect.left - originClientLeft);
- rights.push(rect.right - originClientLeft);
+ offsetForMarker(m) {
+ if (this.timeZone === 'local') {
+ return -arrayToLocalDate(dateToUtcArray(m)).getTimezoneOffset(); // convert "inverse" offset to "normal" offset
}
- this.lefts = lefts;
- this.rights = rights;
- }
- // Populates the top/bottom internal coordinate arrays
- buildElVerticals(originClientTop) {
- let tops = [];
- let bottoms = [];
- for (let el of this.els) {
- let rect = el.getBoundingClientRect();
- tops.push(rect.top - originClientTop);
- bottoms.push(rect.bottom - originClientTop);
+ if (this.timeZone === 'UTC') {
+ return 0;
}
- this.tops = tops;
- this.bottoms = bottoms;
- }
- // Given a left offset (from document left), returns the index of the el that it horizontally intersects.
- // If no intersection is made, returns undefined.
- leftToIndex(leftPosition) {
- let { lefts, rights } = this;
- let len = lefts.length;
- let i;
- for (i = 0; i < len; i += 1) {
- if (leftPosition >= lefts[i] && leftPosition < rights[i]) {
- return i;
- }
+ if (this.namedTimeZoneImpl) {
+ return this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m));
}
- return undefined; // TODO: better
+ return null;
}
- // Given a top offset (from document top), returns the index of the el that it vertically intersects.
- // If no intersection is made, returns undefined.
- topToIndex(topPosition) {
- let { tops, bottoms } = this;
- let len = tops.length;
- let i;
- for (i = 0; i < len; i += 1) {
- if (topPosition >= tops[i] && topPosition < bottoms[i]) {
- return i;
- }
+ // Conversion
+ toDate(m, forcedTzo) {
+ if (this.timeZone === 'local') {
+ return arrayToLocalDate(dateToUtcArray(m));
}
- return undefined; // TODO: better
- }
- // Gets the width of the element at the given index
- getWidth(leftIndex) {
- return this.rights[leftIndex] - this.lefts[leftIndex];
- }
- // Gets the height of the element at the given index
- getHeight(topIndex) {
- return this.bottoms[topIndex] - this.tops[topIndex];
- }
- similarTo(otherCache) {
- return similarNumArrays(this.tops || [], otherCache.tops || []) &&
- similarNumArrays(this.bottoms || [], otherCache.bottoms || []) &&
- similarNumArrays(this.lefts || [], otherCache.lefts || []) &&
- similarNumArrays(this.rights || [], otherCache.rights || []);
- }
- }
- function similarNumArrays(a, b) {
- const len = a.length;
- if (len !== b.length) {
- return false;
- }
- for (let i = 0; i < len; i++) {
- if (Math.round(a[i]) !== Math.round(b[i])) {
- return false;
+ if (this.timeZone === 'UTC') {
+ return new Date(m.valueOf()); // make sure it's a copy
}
- }
- return true;
- }
-
- /* eslint max-classes-per-file: "off" */
- /*
- An object for getting/setting scroll-related information for an element.
- Internally, this is done very differently for window versus DOM element,
- so this object serves as a common interface.
- */
- class ScrollController {
- getMaxScrollTop() {
- return this.getScrollHeight() - this.getClientHeight();
- }
- getMaxScrollLeft() {
- return this.getScrollWidth() - this.getClientWidth();
- }
- canScrollVertically() {
- return this.getMaxScrollTop() > 0;
- }
- canScrollHorizontally() {
- return this.getMaxScrollLeft() > 0;
- }
- canScrollUp() {
- return this.getScrollTop() > 0;
- }
- canScrollDown() {
- return this.getScrollTop() < this.getMaxScrollTop();
- }
- canScrollLeft() {
- return this.getScrollLeft() > 0;
- }
- canScrollRight() {
- return this.getScrollLeft() < this.getMaxScrollLeft();
- }
- }
- class ElementScrollController extends ScrollController {
- constructor(el) {
- super();
- this.el = el;
- }
- getScrollTop() {
- return this.el.scrollTop;
- }
- getScrollLeft() {
- return this.el.scrollLeft;
- }
- setScrollTop(top) {
- this.el.scrollTop = top;
- }
- setScrollLeft(left) {
- this.el.scrollLeft = left;
- }
- getScrollWidth() {
- return this.el.scrollWidth;
- }
- getScrollHeight() {
- return this.el.scrollHeight;
- }
- getClientHeight() {
- return this.el.clientHeight;
- }
- getClientWidth() {
- return this.el.clientWidth;
- }
- }
- class WindowScrollController extends ScrollController {
- getScrollTop() {
- return window.pageYOffset;
- }
- getScrollLeft() {
- return window.pageXOffset;
- }
- setScrollTop(n) {
- window.scroll(window.pageXOffset, n);
- }
- setScrollLeft(n) {
- window.scroll(n, window.pageYOffset);
- }
- getScrollWidth() {
- return document.documentElement.scrollWidth;
- }
- getScrollHeight() {
- return document.documentElement.scrollHeight;
- }
- getClientHeight() {
- return document.documentElement.clientHeight;
- }
- getClientWidth() {
- return document.documentElement.clientWidth;
+ if (!this.namedTimeZoneImpl) {
+ return new Date(m.valueOf() - (forcedTzo || 0));
+ }
+ return new Date(m.valueOf() -
+ this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)) * 1000 * 60);
}
}
@@ -3190,39 +2395,366 @@ var FullCalendar = (function (exports) {
}
}
+ class ContentInjector extends BaseComponent {
+ constructor() {
+ super(...arguments);
+ this.id = guid();
+ this.queuedDomNodes = [];
+ this.currentDomNodes = [];
+ this.handleEl = (el) => {
+ const { options } = this.context;
+ const { generatorName } = this.props;
+ if (!options.customRenderingReplaces || !hasCustomRenderingHandler(generatorName, options)) {
+ this.updateElRef(el);
+ }
+ };
+ this.updateElRef = (el) => {
+ if (this.props.elRef) {
+ setRef(this.props.elRef, el);
+ }
+ };
+ }
+ render() {
+ const { props, context } = this;
+ const { options } = context;
+ const { customGenerator, defaultGenerator, renderProps } = props;
+ const attrs = buildElAttrs(props, [], this.handleEl);
+ let useDefault = false;
+ let innerContent;
+ let queuedDomNodes = [];
+ let currentGeneratorMeta;
+ if (customGenerator != null) {
+ const customGeneratorRes = typeof customGenerator === 'function' ?
+ customGenerator(renderProps, y) :
+ customGenerator;
+ if (customGeneratorRes === true) {
+ useDefault = true;
+ }
+ else {
+ const isObject = customGeneratorRes && typeof customGeneratorRes === 'object'; // non-null
+ if (isObject && ('html' in customGeneratorRes)) {
+ attrs.dangerouslySetInnerHTML = { __html: customGeneratorRes.html };
+ }
+ else if (isObject && ('domNodes' in customGeneratorRes)) {
+ queuedDomNodes = Array.prototype.slice.call(customGeneratorRes.domNodes);
+ }
+ else if (isObject
+ ? i$1(customGeneratorRes) // vdom node
+ : typeof customGeneratorRes !== 'function' // primitive value (like string or number)
+ ) {
+ // use in vdom
+ innerContent = customGeneratorRes;
+ }
+ else {
+ // an exotic object for handleCustomRendering
+ currentGeneratorMeta = customGeneratorRes;
+ }
+ }
+ }
+ else {
+ useDefault = !hasCustomRenderingHandler(props.generatorName, options);
+ }
+ if (useDefault && defaultGenerator) {
+ innerContent = defaultGenerator(renderProps);
+ }
+ this.queuedDomNodes = queuedDomNodes;
+ this.currentGeneratorMeta = currentGeneratorMeta;
+ return y(props.elTag, attrs, innerContent);
+ }
+ componentDidMount() {
+ this.applyQueueudDomNodes();
+ this.triggerCustomRendering(true);
+ }
+ componentDidUpdate() {
+ this.applyQueueudDomNodes();
+ this.triggerCustomRendering(true);
+ }
+ componentWillUnmount() {
+ this.triggerCustomRendering(false); // TODO: different API for removal?
+ }
+ triggerCustomRendering(isActive) {
+ var _a;
+ const { props, context } = this;
+ const { handleCustomRendering, customRenderingMetaMap } = context.options;
+ if (handleCustomRendering) {
+ const generatorMeta = (_a = this.currentGeneratorMeta) !== null && _a !== void 0 ? _a : customRenderingMetaMap === null || customRenderingMetaMap === void 0 ? void 0 : customRenderingMetaMap[props.generatorName];
+ if (generatorMeta) {
+ handleCustomRendering(Object.assign(Object.assign({ id: this.id, isActive, containerEl: this.base, reportNewContainerEl: this.updateElRef, // front-end framework tells us about new container els
+ generatorMeta }, props), { elClasses: (props.elClasses || []).filter(isTruthy) }));
+ }
+ }
+ }
+ applyQueueudDomNodes() {
+ const { queuedDomNodes, currentDomNodes } = this;
+ const el = this.base;
+ if (!isArraysEqual(queuedDomNodes, currentDomNodes)) {
+ currentDomNodes.forEach(removeElement);
+ for (let newNode of queuedDomNodes) {
+ el.appendChild(newNode);
+ }
+ this.currentDomNodes = queuedDomNodes;
+ }
+ }
+ }
+ ContentInjector.addPropsEquality({
+ elClasses: isArraysEqual,
+ elStyle: isPropsEqual,
+ elAttrs: isNonHandlerPropsEqual,
+ renderProps: isPropsEqual,
+ });
+ // Util
/*
- an INTERACTABLE date component
-
- PURPOSES:
- - hook up to fg, fill, and mirror renderers
- - interface for dragging and hits
+ Does UI-framework provide custom way of rendering that does not use Preact VDOM
+ AND does the calendar's options define custom rendering?
+ AKA. Should we NOT render the default content?
*/
- class DateComponent extends BaseComponent {
+ function hasCustomRenderingHandler(generatorName, options) {
+ var _a;
+ return Boolean(options.handleCustomRendering &&
+ generatorName &&
+ ((_a = options.customRenderingMetaMap) === null || _a === void 0 ? void 0 : _a[generatorName]));
+ }
+ function buildElAttrs(props, extraClassNames, elRef) {
+ const attrs = Object.assign(Object.assign({}, props.elAttrs), { ref: elRef });
+ if (props.elClasses || extraClassNames) {
+ attrs.className = (props.elClasses || [])
+ .concat(extraClassNames || [])
+ .concat(attrs.className || [])
+ .filter(Boolean)
+ .join(' ');
+ }
+ if (props.elStyle) {
+ attrs.style = props.elStyle;
+ }
+ return attrs;
+ }
+ function isTruthy(val) {
+ return Boolean(val);
+ }
+
+ const RenderId = createContext(0);
+
+ class ContentContainer extends x$1 {
constructor() {
super(...arguments);
- this.uid = guid();
+ this.InnerContent = InnerContentInjector.bind(undefined, this);
+ this.handleEl = (el) => {
+ this.el = el;
+ if (this.props.elRef) {
+ setRef(this.props.elRef, el);
+ if (el && this.didMountMisfire) {
+ this.componentDidMount();
+ }
+ }
+ };
}
- // Hit System
- // -----------------------------------------------------------------------------------------------------------------
- prepareHits() {
+ render() {
+ const { props } = this;
+ const generatedClassNames = generateClassNames(props.classNameGenerator, props.renderProps);
+ if (props.children) {
+ const elAttrs = buildElAttrs(props, generatedClassNames, this.handleEl);
+ const children = props.children(this.InnerContent, props.renderProps, elAttrs);
+ if (props.elTag) {
+ return y(props.elTag, elAttrs, children);
+ }
+ else {
+ return children;
+ }
+ }
+ else {
+ return y((ContentInjector), Object.assign(Object.assign({}, props), { elRef: this.handleEl, elTag: props.elTag || 'div', elClasses: (props.elClasses || []).concat(generatedClassNames), renderId: this.context }));
+ }
}
- queryHit(positionLeft, positionTop, elWidth, elHeight) {
- return null; // this should be abstract
+ componentDidMount() {
+ var _a, _b;
+ if (this.el) {
+ (_b = (_a = this.props).didMount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.el }));
+ }
+ else {
+ this.didMountMisfire = true;
+ }
}
- // Pointer Interaction Utils
- // -----------------------------------------------------------------------------------------------------------------
- isValidSegDownEl(el) {
- return !this.props.eventDrag && // HACK
- !this.props.eventResize && // HACK
- !elementClosest(el, '.fc-event-mirror');
+ componentWillUnmount() {
+ var _a, _b;
+ (_b = (_a = this.props).willUnmount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.el }));
}
- isValidDateDownEl(el) {
- return !elementClosest(el, '.fc-event:not(.fc-bg-event)') &&
- !elementClosest(el, '.fc-more-link') && // a "more.." link
- !elementClosest(el, 'a[data-navlink]') && // a clickable nav link
- !elementClosest(el, '.fc-popover'); // hack
+ }
+ ContentContainer.contextType = RenderId;
+ function InnerContentInjector(containerComponent, props) {
+ const parentProps = containerComponent.props;
+ return y((ContentInjector), Object.assign({ renderProps: parentProps.renderProps, generatorName: parentProps.generatorName, customGenerator: parentProps.customGenerator, defaultGenerator: parentProps.defaultGenerator, renderId: containerComponent.context }, props));
+ }
+ // Utils
+ function generateClassNames(classNameGenerator, renderProps) {
+ const classNames = typeof classNameGenerator === 'function' ?
+ classNameGenerator(renderProps) :
+ classNameGenerator || [];
+ return typeof classNames === 'string' ? [classNames] : classNames;
+ }
+
+ class ViewContainer extends BaseComponent {
+ render() {
+ let { props, context } = this;
+ let { options } = context;
+ let renderProps = { view: context.viewApi };
+ return (y(ContentContainer, Object.assign({}, props, { elTag: props.elTag || 'div', elClasses: [
+ ...buildViewClassNames(props.viewSpec),
+ ...(props.elClasses || []),
+ ], renderProps: renderProps, classNameGenerator: options.viewClassNames, generatorName: undefined, didMount: options.viewDidMount, willUnmount: options.viewWillUnmount }), () => props.children));
}
}
+ function buildViewClassNames(viewSpec) {
+ return [
+ `fc-${viewSpec.type}-view`,
+ 'fc-view',
+ ];
+ }
+
+ function parseRange(input, dateEnv) {
+ let start = null;
+ let end = null;
+ if (input.start) {
+ start = dateEnv.createMarker(input.start);
+ }
+ if (input.end) {
+ end = dateEnv.createMarker(input.end);
+ }
+ if (!start && !end) {
+ return null;
+ }
+ if (start && end && end < start) {
+ return null;
+ }
+ return { start, end };
+ }
+ // SIDE-EFFECT: will mutate ranges.
+ // Will return a new array result.
+ function invertRanges(ranges, constraintRange) {
+ let invertedRanges = [];
+ let { start } = constraintRange; // the end of the previous range. the start of the new range
+ let i;
+ let dateRange;
+ // ranges need to be in order. required for our date-walking algorithm
+ ranges.sort(compareRanges);
+ for (i = 0; i < ranges.length; i += 1) {
+ dateRange = ranges[i];
+ // add the span of time before the event (if there is any)
+ if (dateRange.start > start) { // compare millisecond time (skip any ambig logic)
+ invertedRanges.push({ start, end: dateRange.start });
+ }
+ if (dateRange.end > start) {
+ start = dateRange.end;
+ }
+ }
+ // add the span of time after the last event (if there is any)
+ if (start < constraintRange.end) { // compare millisecond time (skip any ambig logic)
+ invertedRanges.push({ start, end: constraintRange.end });
+ }
+ return invertedRanges;
+ }
+ function compareRanges(range0, range1) {
+ return range0.start.valueOf() - range1.start.valueOf(); // earlier ranges go first
+ }
+ function intersectRanges(range0, range1) {
+ let { start, end } = range0;
+ let newRange = null;
+ if (range1.start !== null) {
+ if (start === null) {
+ start = range1.start;
+ }
+ else {
+ start = new Date(Math.max(start.valueOf(), range1.start.valueOf()));
+ }
+ }
+ if (range1.end != null) {
+ if (end === null) {
+ end = range1.end;
+ }
+ else {
+ end = new Date(Math.min(end.valueOf(), range1.end.valueOf()));
+ }
+ }
+ if (start === null || end === null || start < end) {
+ newRange = { start, end };
+ }
+ return newRange;
+ }
+ function rangesEqual(range0, range1) {
+ return (range0.start === null ? null : range0.start.valueOf()) === (range1.start === null ? null : range1.start.valueOf()) &&
+ (range0.end === null ? null : range0.end.valueOf()) === (range1.end === null ? null : range1.end.valueOf());
+ }
+ function rangesIntersect(range0, range1) {
+ return (range0.end === null || range1.start === null || range0.end > range1.start) &&
+ (range0.start === null || range1.end === null || range0.start < range1.end);
+ }
+ function rangeContainsRange(outerRange, innerRange) {
+ return (outerRange.start === null || (innerRange.start !== null && innerRange.start >= outerRange.start)) &&
+ (outerRange.end === null || (innerRange.end !== null && innerRange.end <= outerRange.end));
+ }
+ function rangeContainsMarker(range, date) {
+ return (range.start === null || date >= range.start) &&
+ (range.end === null || date < range.end);
+ }
+ // If the given date is not within the given range, move it inside.
+ // (If it's past the end, make it one millisecond before the end).
+ function constrainMarkerToRange(date, range) {
+ if (range.start != null && date < range.start) {
+ return range.start;
+ }
+ if (range.end != null && date >= range.end) {
+ return new Date(range.end.valueOf() - 1);
+ }
+ return date;
+ }
+
+ /* Date stuff that doesn't belong in datelib core
+ ----------------------------------------------------------------------------------------------------------------------*/
+ // given a timed range, computes an all-day range that has the same exact duration,
+ // but whose start time is aligned with the start of the day.
+ function computeAlignedDayRange(timedRange) {
+ let dayCnt = Math.floor(diffDays(timedRange.start, timedRange.end)) || 1;
+ let start = startOfDay(timedRange.start);
+ let end = addDays(start, dayCnt);
+ return { start, end };
+ }
+ // given a timed range, computes an all-day range based on how for the end date bleeds into the next day
+ // TODO: give nextDayThreshold a default arg
+ function computeVisibleDayRange(timedRange, nextDayThreshold = createDuration(0)) {
+ let startDay = null;
+ let endDay = null;
+ if (timedRange.end) {
+ endDay = startOfDay(timedRange.end);
+ let endTimeMS = timedRange.end.valueOf() - endDay.valueOf(); // # of milliseconds into `endDay`
+ // If the end time is actually inclusively part of the next day and is equal to or
+ // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
+ // Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
+ if (endTimeMS && endTimeMS >= asRoughMs(nextDayThreshold)) {
+ endDay = addDays(endDay, 1);
+ }
+ }
+ if (timedRange.start) {
+ startDay = startOfDay(timedRange.start); // the beginning of the day the range starts
+ // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day.
+ if (endDay && endDay <= startDay) {
+ endDay = addDays(startDay, 1);
+ }
+ }
+ return { start: startDay, end: endDay };
+ }
+ // spans from one day into another?
+ function isMultiDayRange(range) {
+ let visibleRange = computeVisibleDayRange(range);
+ return diffDays(visibleRange.start, visibleRange.end) > 1;
+ }
+ function diffDates(date0, date1, dateEnv, largeUnit) {
+ if (largeUnit === 'year') {
+ return createDuration(dateEnv.diffWholeYears(date0, date1), 'year');
+ }
+ if (largeUnit === 'month') {
+ return createDuration(dateEnv.diffWholeMonths(date0, date1), 'month');
+ }
+ return diffDayAndTime(date0, date1); // returns a duration
+ }
function reduceCurrentDate(currentDate, action) {
switch (action.type) {
@@ -3561,6 +3093,656 @@ var FullCalendar = (function (exports) {
}
}
+ function createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) {
+ return {
+ instanceId: guid(),
+ defId,
+ range,
+ forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo,
+ forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo,
+ };
+ }
+
+ function parseRecurring(refined, defaultAllDay, dateEnv, recurringTypes) {
+ for (let i = 0; i < recurringTypes.length; i += 1) {
+ let parsed = recurringTypes[i].parse(refined, dateEnv);
+ if (parsed) {
+ let { allDay } = refined;
+ if (allDay == null) {
+ allDay = defaultAllDay;
+ if (allDay == null) {
+ allDay = parsed.allDayGuess;
+ if (allDay == null) {
+ allDay = false;
+ }
+ }
+ }
+ return {
+ allDay,
+ duration: parsed.duration,
+ typeData: parsed.typeData,
+ typeId: i,
+ };
+ }
+ }
+ return null;
+ }
+ function expandRecurring(eventStore, framingRange, context) {
+ let { dateEnv, pluginHooks, options } = context;
+ let { defs, instances } = eventStore;
+ // remove existing recurring instances
+ // TODO: bad. always expand events as a second step
+ instances = filterHash(instances, (instance) => !defs[instance.defId].recurringDef);
+ for (let defId in defs) {
+ let def = defs[defId];
+ if (def.recurringDef) {
+ let { duration } = def.recurringDef;
+ if (!duration) {
+ duration = def.allDay ?
+ options.defaultAllDayEventDuration :
+ options.defaultTimedEventDuration;
+ }
+ let starts = expandRecurringRanges(def, duration, framingRange, dateEnv, pluginHooks.recurringTypes);
+ for (let start of starts) {
+ let instance = createEventInstance(defId, {
+ start,
+ end: dateEnv.add(start, duration),
+ });
+ instances[instance.instanceId] = instance;
+ }
+ }
+ }
+ return { defs, instances };
+ }
+ /*
+ Event MUST have a recurringDef
+ */
+ function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) {
+ let typeDef = recurringTypes[eventDef.recurringDef.typeId];
+ let markers = typeDef.expand(eventDef.recurringDef.typeData, {
+ start: dateEnv.subtract(framingRange.start, duration),
+ end: framingRange.end,
+ }, dateEnv);
+ // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to
+ if (eventDef.allDay) {
+ markers = markers.map(startOfDay);
+ }
+ return markers;
+ }
+
+ const EVENT_NON_DATE_REFINERS = {
+ id: String,
+ groupId: String,
+ title: String,
+ url: String,
+ interactive: Boolean,
+ };
+ const EVENT_DATE_REFINERS = {
+ start: identity,
+ end: identity,
+ date: identity,
+ allDay: Boolean,
+ };
+ const EVENT_REFINERS = Object.assign(Object.assign(Object.assign({}, EVENT_NON_DATE_REFINERS), EVENT_DATE_REFINERS), { extendedProps: identity });
+ function parseEvent(raw, eventSource, context, allowOpenRange, refiners = buildEventRefiners(context), defIdMap, instanceIdMap) {
+ let { refined, extra } = refineEventDef(raw, context, refiners);
+ let defaultAllDay = computeIsDefaultAllDay(eventSource, context);
+ let recurringRes = parseRecurring(refined, defaultAllDay, context.dateEnv, context.pluginHooks.recurringTypes);
+ if (recurringRes) {
+ let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', recurringRes.allDay, Boolean(recurringRes.duration), context, defIdMap);
+ def.recurringDef = {
+ typeId: recurringRes.typeId,
+ typeData: recurringRes.typeData,
+ duration: recurringRes.duration,
+ };
+ return { def, instance: null };
+ }
+ let singleRes = parseSingle(refined, defaultAllDay, context, allowOpenRange);
+ if (singleRes) {
+ let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', singleRes.allDay, singleRes.hasEnd, context, defIdMap);
+ let instance = createEventInstance(def.defId, singleRes.range, singleRes.forcedStartTzo, singleRes.forcedEndTzo);
+ if (instanceIdMap && def.publicId && instanceIdMap[def.publicId]) {
+ instance.instanceId = instanceIdMap[def.publicId];
+ }
+ return { def, instance };
+ }
+ return null;
+ }
+ function refineEventDef(raw, context, refiners = buildEventRefiners(context)) {
+ return refineProps(raw, refiners);
+ }
+ function buildEventRefiners(context) {
+ return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_REFINERS), context.pluginHooks.eventRefiners);
+ }
+ /*
+ Will NOT populate extendedProps with the leftover properties.
+ Will NOT populate date-related props.
+ */
+ function parseEventDef(refined, extra, sourceId, allDay, hasEnd, context, defIdMap) {
+ let def = {
+ title: refined.title || '',
+ groupId: refined.groupId || '',
+ publicId: refined.id || '',
+ url: refined.url || '',
+ recurringDef: null,
+ defId: ((defIdMap && refined.id) ? defIdMap[refined.id] : '') || guid(),
+ sourceId,
+ allDay,
+ hasEnd,
+ interactive: refined.interactive,
+ ui: createEventUi(refined, context),
+ extendedProps: Object.assign(Object.assign({}, (refined.extendedProps || {})), extra),
+ };
+ for (let memberAdder of context.pluginHooks.eventDefMemberAdders) {
+ Object.assign(def, memberAdder(refined));
+ }
+ // help out EventImpl from having user modify props
+ Object.freeze(def.ui.classNames);
+ Object.freeze(def.extendedProps);
+ return def;
+ }
+ function parseSingle(refined, defaultAllDay, context, allowOpenRange) {
+ let { allDay } = refined;
+ let startMeta;
+ let startMarker = null;
+ let hasEnd = false;
+ let endMeta;
+ let endMarker = null;
+ let startInput = refined.start != null ? refined.start : refined.date;
+ startMeta = context.dateEnv.createMarkerMeta(startInput);
+ if (startMeta) {
+ startMarker = startMeta.marker;
+ }
+ else if (!allowOpenRange) {
+ return null;
+ }
+ if (refined.end != null) {
+ endMeta = context.dateEnv.createMarkerMeta(refined.end);
+ }
+ if (allDay == null) {
+ if (defaultAllDay != null) {
+ allDay = defaultAllDay;
+ }
+ else {
+ // fall back to the date props LAST
+ allDay = (!startMeta || startMeta.isTimeUnspecified) &&
+ (!endMeta || endMeta.isTimeUnspecified);
+ }
+ }
+ if (allDay && startMarker) {
+ startMarker = startOfDay(startMarker);
+ }
+ if (endMeta) {
+ endMarker = endMeta.marker;
+ if (allDay) {
+ endMarker = startOfDay(endMarker);
+ }
+ if (startMarker && endMarker <= startMarker) {
+ endMarker = null;
+ }
+ }
+ if (endMarker) {
+ hasEnd = true;
+ }
+ else if (!allowOpenRange) {
+ hasEnd = context.options.forceEventDuration || false;
+ endMarker = context.dateEnv.add(startMarker, allDay ?
+ context.options.defaultAllDayEventDuration :
+ context.options.defaultTimedEventDuration);
+ }
+ return {
+ allDay,
+ hasEnd,
+ range: { start: startMarker, end: endMarker },
+ forcedStartTzo: startMeta ? startMeta.forcedTzo : null,
+ forcedEndTzo: endMeta ? endMeta.forcedTzo : null,
+ };
+ }
+ function computeIsDefaultAllDay(eventSource, context) {
+ let res = null;
+ if (eventSource) {
+ res = eventSource.defaultAllDay;
+ }
+ if (res == null) {
+ res = context.options.defaultAllDay;
+ }
+ return res;
+ }
+
+ function parseEvents(rawEvents, eventSource, context, allowOpenRange, defIdMap, instanceIdMap) {
+ let eventStore = createEmptyEventStore();
+ let eventRefiners = buildEventRefiners(context);
+ for (let rawEvent of rawEvents) {
+ let tuple = parseEvent(rawEvent, eventSource, context, allowOpenRange, eventRefiners, defIdMap, instanceIdMap);
+ if (tuple) {
+ eventTupleToStore(tuple, eventStore);
+ }
+ }
+ return eventStore;
+ }
+ function eventTupleToStore(tuple, eventStore = createEmptyEventStore()) {
+ eventStore.defs[tuple.def.defId] = tuple.def;
+ if (tuple.instance) {
+ eventStore.instances[tuple.instance.instanceId] = tuple.instance;
+ }
+ return eventStore;
+ }
+ // retrieves events that have the same groupId as the instance specified by `instanceId`
+ // or they are the same as the instance.
+ // why might instanceId not be in the store? an event from another calendar?
+ function getRelevantEvents(eventStore, instanceId) {
+ let instance = eventStore.instances[instanceId];
+ if (instance) {
+ let def = eventStore.defs[instance.defId];
+ // get events/instances with same group
+ let newStore = filterEventStoreDefs(eventStore, (lookDef) => isEventDefsGrouped(def, lookDef));
+ // add the original
+ // TODO: wish we could use eventTupleToStore or something like it
+ newStore.defs[def.defId] = def;
+ newStore.instances[instance.instanceId] = instance;
+ return newStore;
+ }
+ return createEmptyEventStore();
+ }
+ function isEventDefsGrouped(def0, def1) {
+ return Boolean(def0.groupId && def0.groupId === def1.groupId);
+ }
+ function createEmptyEventStore() {
+ return { defs: {}, instances: {} };
+ }
+ function mergeEventStores(store0, store1) {
+ return {
+ defs: Object.assign(Object.assign({}, store0.defs), store1.defs),
+ instances: Object.assign(Object.assign({}, store0.instances), store1.instances),
+ };
+ }
+ function filterEventStoreDefs(eventStore, filterFunc) {
+ let defs = filterHash(eventStore.defs, filterFunc);
+ let instances = filterHash(eventStore.instances, (instance) => (defs[instance.defId] // still exists?
+ ));
+ return { defs, instances };
+ }
+ function excludeSubEventStore(master, sub) {
+ let { defs, instances } = master;
+ let filteredDefs = {};
+ let filteredInstances = {};
+ for (let defId in defs) {
+ if (!sub.defs[defId]) { // not explicitly excluded
+ filteredDefs[defId] = defs[defId];
+ }
+ }
+ for (let instanceId in instances) {
+ if (!sub.instances[instanceId] && // not explicitly excluded
+ filteredDefs[instances[instanceId].defId] // def wasn't filtered away
+ ) {
+ filteredInstances[instanceId] = instances[instanceId];
+ }
+ }
+ return {
+ defs: filteredDefs,
+ instances: filteredInstances,
+ };
+ }
+
+ function normalizeConstraint(input, context) {
+ if (Array.isArray(input)) {
+ return parseEvents(input, null, context, true); // allowOpenRange=true
+ }
+ if (typeof input === 'object' && input) { // non-null object
+ return parseEvents([input], null, context, true); // allowOpenRange=true
+ }
+ if (input != null) {
+ return String(input);
+ }
+ return null;
+ }
+
+ function parseClassNames(raw) {
+ if (Array.isArray(raw)) {
+ return raw;
+ }
+ if (typeof raw === 'string') {
+ return raw.split(/\s+/);
+ }
+ return [];
+ }
+
+ // TODO: better called "EventSettings" or "EventConfig"
+ // TODO: move this file into structs
+ // TODO: separate constraint/overlap/allow, because selection uses only that, not other props
+ const EVENT_UI_REFINERS = {
+ display: String,
+ editable: Boolean,
+ startEditable: Boolean,
+ durationEditable: Boolean,
+ constraint: identity,
+ overlap: identity,
+ allow: identity,
+ className: parseClassNames,
+ classNames: parseClassNames,
+ color: String,
+ backgroundColor: String,
+ borderColor: String,
+ textColor: String,
+ };
+ const EMPTY_EVENT_UI = {
+ display: null,
+ startEditable: null,
+ durationEditable: null,
+ constraints: [],
+ overlap: null,
+ allows: [],
+ backgroundColor: '',
+ borderColor: '',
+ textColor: '',
+ classNames: [],
+ };
+ function createEventUi(refined, context) {
+ let constraint = normalizeConstraint(refined.constraint, context);
+ return {
+ display: refined.display || null,
+ startEditable: refined.startEditable != null ? refined.startEditable : refined.editable,
+ durationEditable: refined.durationEditable != null ? refined.durationEditable : refined.editable,
+ constraints: constraint != null ? [constraint] : [],
+ overlap: refined.overlap != null ? refined.overlap : null,
+ allows: refined.allow != null ? [refined.allow] : [],
+ backgroundColor: refined.backgroundColor || refined.color || '',
+ borderColor: refined.borderColor || refined.color || '',
+ textColor: refined.textColor || '',
+ classNames: (refined.className || []).concat(refined.classNames || []), // join singular and plural
+ };
+ }
+ // TODO: prevent against problems with <2 args!
+ function combineEventUis(uis) {
+ return uis.reduce(combineTwoEventUis, EMPTY_EVENT_UI);
+ }
+ function combineTwoEventUis(item0, item1) {
+ return {
+ display: item1.display != null ? item1.display : item0.display,
+ startEditable: item1.startEditable != null ? item1.startEditable : item0.startEditable,
+ durationEditable: item1.durationEditable != null ? item1.durationEditable : item0.durationEditable,
+ constraints: item0.constraints.concat(item1.constraints),
+ overlap: typeof item1.overlap === 'boolean' ? item1.overlap : item0.overlap,
+ allows: item0.allows.concat(item1.allows),
+ backgroundColor: item1.backgroundColor || item0.backgroundColor,
+ borderColor: item1.borderColor || item0.borderColor,
+ textColor: item1.textColor || item0.textColor,
+ classNames: item0.classNames.concat(item1.classNames),
+ };
+ }
+
+ const EVENT_SOURCE_REFINERS = {
+ id: String,
+ defaultAllDay: Boolean,
+ url: String,
+ format: String,
+ events: identity,
+ eventDataTransform: identity,
+ // for any network-related sources
+ success: identity,
+ failure: identity,
+ };
+ function parseEventSource(raw, context, refiners = buildEventSourceRefiners(context)) {
+ let rawObj;
+ if (typeof raw === 'string') {
+ rawObj = { url: raw };
+ }
+ else if (typeof raw === 'function' || Array.isArray(raw)) {
+ rawObj = { events: raw };
+ }
+ else if (typeof raw === 'object' && raw) { // not null
+ rawObj = raw;
+ }
+ if (rawObj) {
+ let { refined, extra } = refineProps(rawObj, refiners);
+ let metaRes = buildEventSourceMeta(refined, context);
+ if (metaRes) {
+ return {
+ _raw: raw,
+ isFetching: false,
+ latestFetchId: '',
+ fetchRange: null,
+ defaultAllDay: refined.defaultAllDay,
+ eventDataTransform: refined.eventDataTransform,
+ success: refined.success,
+ failure: refined.failure,
+ publicId: refined.id || '',
+ sourceId: guid(),
+ sourceDefId: metaRes.sourceDefId,
+ meta: metaRes.meta,
+ ui: createEventUi(refined, context),
+ extendedProps: extra,
+ };
+ }
+ }
+ return null;
+ }
+ function buildEventSourceRefiners(context) {
+ return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_SOURCE_REFINERS), context.pluginHooks.eventSourceRefiners);
+ }
+ function buildEventSourceMeta(raw, context) {
+ let defs = context.pluginHooks.eventSourceDefs;
+ for (let i = defs.length - 1; i >= 0; i -= 1) { // later-added plugins take precedence
+ let def = defs[i];
+ let meta = def.parseMeta(raw);
+ if (meta) {
+ return { sourceDefId: i, meta };
+ }
+ }
+ return null;
+ }
+
+ function reduceEventStore(eventStore, action, eventSources, dateProfile, context) {
+ switch (action.type) {
+ case 'RECEIVE_EVENTS': // raw
+ return receiveRawEvents(eventStore, eventSources[action.sourceId], action.fetchId, action.fetchRange, action.rawEvents, context);
+ case 'RESET_RAW_EVENTS':
+ return resetRawEvents(eventStore, eventSources[action.sourceId], action.rawEvents, dateProfile.activeRange, context);
+ case 'ADD_EVENTS': // already parsed, but not expanded
+ return addEvent(eventStore, action.eventStore, // new ones
+ dateProfile ? dateProfile.activeRange : null, context);
+ case 'RESET_EVENTS':
+ return action.eventStore;
+ case 'MERGE_EVENTS': // already parsed and expanded
+ return mergeEventStores(eventStore, action.eventStore);
+ case 'PREV': // TODO: how do we track all actions that affect dateProfile :(
+ case 'NEXT':
+ case 'CHANGE_DATE':
+ case 'CHANGE_VIEW_TYPE':
+ if (dateProfile) {
+ return expandRecurring(eventStore, dateProfile.activeRange, context);
+ }
+ return eventStore;
+ case 'REMOVE_EVENTS':
+ return excludeSubEventStore(eventStore, action.eventStore);
+ case 'REMOVE_EVENT_SOURCE':
+ return excludeEventsBySourceId(eventStore, action.sourceId);
+ case 'REMOVE_ALL_EVENT_SOURCES':
+ return filterEventStoreDefs(eventStore, (eventDef) => (!eventDef.sourceId // only keep events with no source id
+ ));
+ case 'REMOVE_ALL_EVENTS':
+ return createEmptyEventStore();
+ default:
+ return eventStore;
+ }
+ }
+ function receiveRawEvents(eventStore, eventSource, fetchId, fetchRange, rawEvents, context) {
+ if (eventSource && // not already removed
+ fetchId === eventSource.latestFetchId // TODO: wish this logic was always in event-sources
+ ) {
+ let subset = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context);
+ if (fetchRange) {
+ subset = expandRecurring(subset, fetchRange, context);
+ }
+ return mergeEventStores(excludeEventsBySourceId(eventStore, eventSource.sourceId), subset);
+ }
+ return eventStore;
+ }
+ function resetRawEvents(existingEventStore, eventSource, rawEvents, activeRange, context) {
+ const { defIdMap, instanceIdMap } = buildPublicIdMaps(existingEventStore);
+ let newEventStore = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context, false, defIdMap, instanceIdMap);
+ return expandRecurring(newEventStore, activeRange, context);
+ }
+ function transformRawEvents(rawEvents, eventSource, context) {
+ let calEachTransform = context.options.eventDataTransform;
+ let sourceEachTransform = eventSource ? eventSource.eventDataTransform : null;
+ if (sourceEachTransform) {
+ rawEvents = transformEachRawEvent(rawEvents, sourceEachTransform);
+ }
+ if (calEachTransform) {
+ rawEvents = transformEachRawEvent(rawEvents, calEachTransform);
+ }
+ return rawEvents;
+ }
+ function transformEachRawEvent(rawEvents, func) {
+ let refinedEvents;
+ if (!func) {
+ refinedEvents = rawEvents;
+ }
+ else {
+ refinedEvents = [];
+ for (let rawEvent of rawEvents) {
+ let refinedEvent = func(rawEvent);
+ if (refinedEvent) {
+ refinedEvents.push(refinedEvent);
+ }
+ else if (refinedEvent == null) {
+ refinedEvents.push(rawEvent);
+ } // if a different falsy value, do nothing
+ }
+ }
+ return refinedEvents;
+ }
+ function addEvent(eventStore, subset, expandRange, context) {
+ if (expandRange) {
+ subset = expandRecurring(subset, expandRange, context);
+ }
+ return mergeEventStores(eventStore, subset);
+ }
+ function rezoneEventStoreDates(eventStore, oldDateEnv, newDateEnv) {
+ let { defs } = eventStore;
+ let instances = mapHash(eventStore.instances, (instance) => {
+ let def = defs[instance.defId];
+ if (def.allDay) {
+ return instance; // isn't dependent on timezone
+ }
+ return Object.assign(Object.assign({}, instance), { range: {
+ start: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.start, instance.forcedStartTzo)),
+ end: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.end, instance.forcedEndTzo)),
+ }, forcedStartTzo: newDateEnv.canComputeOffset ? null : instance.forcedStartTzo, forcedEndTzo: newDateEnv.canComputeOffset ? null : instance.forcedEndTzo });
+ });
+ return { defs, instances };
+ }
+ function excludeEventsBySourceId(eventStore, sourceId) {
+ return filterEventStoreDefs(eventStore, (eventDef) => eventDef.sourceId !== sourceId);
+ }
+ // QUESTION: why not just return instances? do a general object-property-exclusion util
+ function excludeInstances(eventStore, removals) {
+ return {
+ defs: eventStore.defs,
+ instances: filterHash(eventStore.instances, (instance) => !removals[instance.instanceId]),
+ };
+ }
+ function buildPublicIdMaps(eventStore) {
+ const { defs, instances } = eventStore;
+ const defIdMap = {};
+ const instanceIdMap = {};
+ for (let defId in defs) {
+ const def = defs[defId];
+ const { publicId } = def;
+ if (publicId) {
+ defIdMap[publicId] = defId;
+ }
+ }
+ for (let instanceId in instances) {
+ const instance = instances[instanceId];
+ const def = defs[instance.defId];
+ const { publicId } = def;
+ if (publicId) {
+ instanceIdMap[publicId] = instanceId;
+ }
+ }
+ return { defIdMap, instanceIdMap };
+ }
+
+ class Emitter {
+ constructor() {
+ this.handlers = {};
+ this.thisContext = null;
+ }
+ setThisContext(thisContext) {
+ this.thisContext = thisContext;
+ }
+ setOptions(options) {
+ this.options = options;
+ }
+ on(type, handler) {
+ addToHash(this.handlers, type, handler);
+ }
+ off(type, handler) {
+ removeFromHash(this.handlers, type, handler);
+ }
+ trigger(type, ...args) {
+ let attachedHandlers = this.handlers[type] || [];
+ let optionHandler = this.options && this.options[type];
+ let handlers = [].concat(optionHandler || [], attachedHandlers);
+ for (let handler of handlers) {
+ handler.apply(this.thisContext, args);
+ }
+ }
+ hasHandlers(type) {
+ return Boolean((this.handlers[type] && this.handlers[type].length) ||
+ (this.options && this.options[type]));
+ }
+ }
+ function addToHash(hash, type, handler) {
+ (hash[type] || (hash[type] = []))
+ .push(handler);
+ }
+ function removeFromHash(hash, type, handler) {
+ if (handler) {
+ if (hash[type]) {
+ hash[type] = hash[type].filter((func) => func !== handler);
+ }
+ }
+ else {
+ delete hash[type]; // remove all handler funcs for this type
+ }
+ }
+
+ const DEF_DEFAULTS = {
+ startTime: '09:00',
+ endTime: '17:00',
+ daysOfWeek: [1, 2, 3, 4, 5],
+ display: 'inverse-background',
+ classNames: 'fc-non-business',
+ groupId: '_businessHours', // so multiple defs get grouped
+ };
+ /*
+ TODO: pass around as EventDefHash!!!
+ */
+ function parseBusinessHours(input, context) {
+ return parseEvents(refineInputs(input), null, context);
+ }
+ function refineInputs(input) {
+ let rawDefs;
+ if (input === true) {
+ rawDefs = [{}]; // will get DEF_DEFAULTS verbatim
+ }
+ else if (Array.isArray(input)) {
+ // if specifying an array, every sub-definition NEEDS a day-of-week
+ rawDefs = input.filter((rawDef) => rawDef.daysOfWeek);
+ }
+ else if (typeof input === 'object' && input) { // non-null object
+ rawDefs = [input];
+ }
+ else { // is probably false
+ rawDefs = [];
+ }
+ rawDefs = rawDefs.map((rawDef) => (Object.assign(Object.assign({}, DEF_DEFAULTS), rawDef)));
+ return rawDefs;
+ }
+
function triggerDateSelect(selection, pev, context) {
context.emitter.trigger('select', Object.assign(Object.assign({}, buildDateSpanApiWithContext(selection, context)), { jsEvent: pev ? pev.origEvent : null, view: context.viewApi || context.calendarApi.view }));
}
@@ -4254,7 +4436,7 @@ var FullCalendar = (function (exports) {
function getSegMeta(seg, todayRange, nowDate) {
let segRange = seg.eventRange.range;
return {
- isPast: segRange.end < (nowDate || todayRange.start),
+ isPast: segRange.end <= (nowDate || todayRange.start),
isFuture: segRange.start >= (nowDate || todayRange.end),
isToday: todayRange && rangeContainsMarker(todayRange, segRange.start),
};
@@ -4420,373 +4602,1158 @@ var FullCalendar = (function (exports) {
};
}
- let calendarSystemClassMap = {};
- function registerCalendarSystem(name, theClass) {
- calendarSystemClassMap[name] = theClass;
- }
- function createCalendarSystem(name) {
- return new calendarSystemClassMap[name]();
+ /*
+ given a function that resolves a result asynchronously.
+ the function can either call passed-in success and failure callbacks,
+ or it can return a promise.
+ if you need to pass additional params to func, bind them first.
+ */
+ function unpromisify(func, normalizedSuccessCallback, normalizedFailureCallback) {
+ // guard against success/failure callbacks being called more than once
+ // and guard against a promise AND callback being used together.
+ let isResolved = false;
+ let wrappedSuccess = function (res) {
+ if (!isResolved) {
+ isResolved = true;
+ normalizedSuccessCallback(res);
+ }
+ };
+ let wrappedFailure = function (error) {
+ if (!isResolved) {
+ isResolved = true;
+ normalizedFailureCallback(error);
+ }
+ };
+ let res = func(wrappedSuccess, wrappedFailure);
+ if (res && typeof res.then === 'function') {
+ res.then(wrappedSuccess, wrappedFailure);
+ }
}
- class GregorianCalendarSystem {
- getMarkerYear(d) {
- return d.getUTCFullYear();
+
+ class JsonRequestError extends Error {
+ constructor(message, response) {
+ super(message);
+ this.response = response;
}
- getMarkerMonth(d) {
- return d.getUTCMonth();
+ }
+ function requestJson(method, url, params) {
+ method = method.toUpperCase();
+ const fetchOptions = {
+ method,
+ };
+ if (method === 'GET') {
+ url += (url.indexOf('?') === -1 ? '?' : '&') +
+ new URLSearchParams(params);
}
- getMarkerDay(d) {
- return d.getUTCDate();
+ else {
+ fetchOptions.body = new URLSearchParams(params);
+ fetchOptions.headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ };
}
- arrayToMarker(arr) {
- return arrayToUtcDate(arr);
+ return fetch(url, fetchOptions).then((fetchRes) => {
+ if (fetchRes.ok) {
+ return fetchRes.json().then((parsedResponse) => {
+ return [parsedResponse, fetchRes];
+ }, () => {
+ throw new JsonRequestError('Failure parsing JSON', fetchRes);
+ });
+ }
+ else {
+ throw new JsonRequestError('Request failed', fetchRes);
+ }
+ });
+ }
+
+ let canVGrowWithinCell;
+ function getCanVGrowWithinCell() {
+ if (canVGrowWithinCell == null) {
+ canVGrowWithinCell = computeCanVGrowWithinCell();
}
- markerToArray(marker) {
- return dateToUtcArray(marker);
+ return canVGrowWithinCell;
+ }
+ function computeCanVGrowWithinCell() {
+ // for SSR, because this function is call immediately at top-level
+ // TODO: just make this logic execute top-level, immediately, instead of doing lazily
+ if (typeof document === 'undefined') {
+ return true;
}
+ let el = document.createElement('div');
+ el.style.position = 'absolute';
+ el.style.top = '0px';
+ el.style.left = '0px';
+ el.innerHTML = '<table><tr><td><div></div></td></tr></table>';
+ el.querySelector('table').style.height = '100px';
+ el.querySelector('div').style.height = '100%';
+ document.body.appendChild(el);
+ let div = el.querySelector('div');
+ let possible = div.offsetHeight > 0;
+ document.body.removeChild(el);
+ return possible;
}
- registerCalendarSystem('gregory', GregorianCalendarSystem);
- const ISO_RE = /^\s*(\d{4})(-?(\d{2})(-?(\d{2})([T ](\d{2}):?(\d{2})(:?(\d{2})(\.(\d+))?)?(Z|(([-+])(\d{2})(:?(\d{2}))?))?)?)?)?$/;
- function parse(str) {
- let m = ISO_RE.exec(str);
- if (m) {
- let 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));
- if (isValidDate(marker)) {
- let timeZoneOffset = null;
- if (m[13]) {
- timeZoneOffset = (m[15] === '-' ? -1 : 1) * (Number(m[16] || 0) * 60 +
- Number(m[18] || 0));
- }
- return {
- marker,
- isTimeUnspecified: !m[6],
- timeZoneOffset,
- };
+ class CalendarRoot extends BaseComponent {
+ constructor() {
+ super(...arguments);
+ this.state = {
+ forPrint: false,
+ };
+ this.handleBeforePrint = () => {
+ flushSync(() => {
+ this.setState({ forPrint: true });
+ });
+ };
+ this.handleAfterPrint = () => {
+ flushSync(() => {
+ this.setState({ forPrint: false });
+ });
+ };
+ }
+ render() {
+ let { props } = this;
+ let { options } = props;
+ let { forPrint } = this.state;
+ let isHeightAuto = forPrint || options.height === 'auto' || options.contentHeight === 'auto';
+ let height = (!isHeightAuto && options.height != null) ? options.height : '';
+ let classNames = [
+ 'fc',
+ forPrint ? 'fc-media-print' : 'fc-media-screen',
+ `fc-direction-${options.direction}`,
+ props.theme.getClass('root'),
+ ];
+ if (!getCanVGrowWithinCell()) {
+ classNames.push('fc-liquid-hack');
}
+ return props.children(classNames, height, isHeightAuto, forPrint);
+ }
+ componentDidMount() {
+ let { emitter } = this.props;
+ emitter.on('_beforeprint', this.handleBeforePrint);
+ emitter.on('_afterprint', this.handleAfterPrint);
+ }
+ componentWillUnmount() {
+ let { emitter } = this.props;
+ emitter.off('_beforeprint', this.handleBeforePrint);
+ emitter.off('_afterprint', this.handleAfterPrint);
}
- return null;
}
- class DateEnv {
+ class Interaction {
constructor(settings) {
- let timeZone = this.timeZone = settings.timeZone;
- let isNamedTimeZone = timeZone !== 'local' && timeZone !== 'UTC';
- if (settings.namedTimeZoneImpl && isNamedTimeZone) {
- this.namedTimeZoneImpl = new settings.namedTimeZoneImpl(timeZone);
- }
- this.canComputeOffset = Boolean(!isNamedTimeZone || this.namedTimeZoneImpl);
- this.calendarSystem = createCalendarSystem(settings.calendarSystem);
- this.locale = settings.locale;
- this.weekDow = settings.locale.week.dow;
- this.weekDoy = settings.locale.week.doy;
- if (settings.weekNumberCalculation === 'ISO') {
- this.weekDow = 1;
- this.weekDoy = 4;
- }
- if (typeof settings.firstDay === 'number') {
- this.weekDow = settings.firstDay;
- }
- if (typeof settings.weekNumberCalculation === 'function') {
- this.weekNumberFunc = settings.weekNumberCalculation;
- }
- this.weekText = settings.weekText != null ? settings.weekText : settings.locale.options.weekText;
- this.weekTextLong = (settings.weekTextLong != null ? settings.weekTextLong : settings.locale.options.weekTextLong) || this.weekText;
- this.cmdFormatter = settings.cmdFormatter;
- this.defaultSeparator = settings.defaultSeparator;
+ this.component = settings.component;
+ this.isHitComboAllowed = settings.isHitComboAllowed || null;
}
- // Creating / Parsing
- createMarker(input) {
- let meta = this.createMarkerMeta(input);
- if (meta === null) {
- return null;
- }
- return meta.marker;
+ destroy() {
}
- createNowMarker() {
- if (this.canComputeOffset) {
- return this.timestampToMarker(new Date().valueOf());
- }
- // if we can't compute the current date val for a timezone,
- // better to give the current local date vals than UTC
- return arrayToUtcDate(dateToLocalArray(new Date()));
+ }
+ function parseInteractionSettings(component, input) {
+ return {
+ component,
+ el: input.el,
+ useEventCenter: input.useEventCenter != null ? input.useEventCenter : true,
+ isHitComboAllowed: input.isHitComboAllowed || null,
+ };
+ }
+ function interactionSettingsToStore(settings) {
+ return {
+ [settings.component.uid]: settings,
+ };
+ }
+ // global state
+ const interactionSettingsStore = {};
+
+ class CalendarImpl {
+ getCurrentData() {
+ return this.currentDataManager.getCurrentData();
}
- createMarkerMeta(input) {
- if (typeof input === 'string') {
- return this.parse(input);
+ dispatch(action) {
+ this.currentDataManager.dispatch(action);
+ }
+ get view() { return this.getCurrentData().viewApi; }
+ batchRendering(callback) {
+ callback();
+ }
+ updateSize() {
+ this.trigger('_resize', true);
+ }
+ // Options
+ // -----------------------------------------------------------------------------------------------------------------
+ setOption(name, val) {
+ this.dispatch({
+ type: 'SET_OPTION',
+ optionName: name,
+ rawOptionValue: val,
+ });
+ }
+ getOption(name) {
+ return this.currentDataManager.currentCalendarOptionsInput[name];
+ }
+ getAvailableLocaleCodes() {
+ return Object.keys(this.getCurrentData().availableRawLocales);
+ }
+ // Trigger
+ // -----------------------------------------------------------------------------------------------------------------
+ on(handlerName, handler) {
+ let { currentDataManager } = this;
+ if (currentDataManager.currentCalendarOptionsRefiners[handlerName]) {
+ currentDataManager.emitter.on(handlerName, handler);
}
- let marker = null;
- if (typeof input === 'number') {
- marker = this.timestampToMarker(input);
+ else {
+ console.warn(`Unknown listener name '${handlerName}'`);
}
- else if (input instanceof Date) {
- input = input.valueOf();
- if (!isNaN(input)) {
- marker = this.timestampToMarker(input);
+ }
+ off(handlerName, handler) {
+ this.currentDataManager.emitter.off(handlerName, handler);
+ }
+ // not meant for public use
+ trigger(handlerName, ...args) {
+ this.currentDataManager.emitter.trigger(handlerName, ...args);
+ }
+ // View
+ // -----------------------------------------------------------------------------------------------------------------
+ changeView(viewType, dateOrRange) {
+ this.batchRendering(() => {
+ this.unselect();
+ if (dateOrRange) {
+ if (dateOrRange.start && dateOrRange.end) { // a range
+ this.dispatch({
+ type: 'CHANGE_VIEW_TYPE',
+ viewType,
+ });
+ this.dispatch({
+ type: 'SET_OPTION',
+ optionName: 'visibleRange',
+ rawOptionValue: dateOrRange,
+ });
+ }
+ else {
+ let { dateEnv } = this.getCurrentData();
+ this.dispatch({
+ type: 'CHANGE_VIEW_TYPE',
+ viewType,
+ dateMarker: dateEnv.createMarker(dateOrRange),
+ });
+ }
}
+ else {
+ this.dispatch({
+ type: 'CHANGE_VIEW_TYPE',
+ viewType,
+ });
+ }
+ });
+ }
+ // Forces navigation to a view for the given date.
+ // `viewType` can be a specific view name or a generic one like "week" or "day".
+ // needs to change
+ zoomTo(dateMarker, viewType) {
+ let state = this.getCurrentData();
+ let spec;
+ viewType = viewType || 'day'; // day is default zoom
+ spec = state.viewSpecs[viewType] || this.getUnitViewSpec(viewType);
+ this.unselect();
+ if (spec) {
+ this.dispatch({
+ type: 'CHANGE_VIEW_TYPE',
+ viewType: spec.type,
+ dateMarker,
+ });
}
- else if (Array.isArray(input)) {
- marker = arrayToUtcDate(input);
- }
- if (marker === null || !isValidDate(marker)) {
- return null;
+ else {
+ this.dispatch({
+ type: 'CHANGE_DATE',
+ dateMarker,
+ });
}
- return { marker, isTimeUnspecified: false, forcedTzo: null };
}
- parse(s) {
- let parts = parse(s);
- if (parts === null) {
- return null;
+ // Given a duration singular unit, like "week" or "day", finds a matching view spec.
+ // Preference is given to views that have corresponding buttons.
+ getUnitViewSpec(unit) {
+ let { viewSpecs, toolbarConfig } = this.getCurrentData();
+ let viewTypes = [].concat(toolbarConfig.header ? toolbarConfig.header.viewsWithButtons : [], toolbarConfig.footer ? toolbarConfig.footer.viewsWithButtons : []);
+ let i;
+ let spec;
+ for (let viewType in viewSpecs) {
+ viewTypes.push(viewType);
}
- let { marker } = parts;
- let forcedTzo = null;
- if (parts.timeZoneOffset !== null) {
- if (this.canComputeOffset) {
- marker = this.timestampToMarker(marker.valueOf() - parts.timeZoneOffset * 60 * 1000);
- }
- else {
- forcedTzo = parts.timeZoneOffset;
+ for (i = 0; i < viewTypes.length; i += 1) {
+ spec = viewSpecs[viewTypes[i]];
+ if (spec) {
+ if (spec.singleUnit === unit) {
+ return spec;
+ }
}
}
- return { marker, isTimeUnspecified: parts.isTimeUnspecified, forcedTzo };
+ return null;
}
- // Accessors
- getYear(marker) {
- return this.calendarSystem.getMarkerYear(marker);
+ // Current Date
+ // -----------------------------------------------------------------------------------------------------------------
+ prev() {
+ this.unselect();
+ this.dispatch({ type: 'PREV' });
}
- getMonth(marker) {
- return this.calendarSystem.getMarkerMonth(marker);
+ next() {
+ this.unselect();
+ this.dispatch({ type: 'NEXT' });
}
- getDay(marker) {
- return this.calendarSystem.getMarkerDay(marker);
+ prevYear() {
+ let state = this.getCurrentData();
+ this.unselect();
+ this.dispatch({
+ type: 'CHANGE_DATE',
+ dateMarker: state.dateEnv.addYears(state.currentDate, -1),
+ });
}
- // Adding / Subtracting
- add(marker, dur) {
- let a = this.calendarSystem.markerToArray(marker);
- a[0] += dur.years;
- a[1] += dur.months;
- a[2] += dur.days;
- a[6] += dur.milliseconds;
- return this.calendarSystem.arrayToMarker(a);
+ nextYear() {
+ let state = this.getCurrentData();
+ this.unselect();
+ this.dispatch({
+ type: 'CHANGE_DATE',
+ dateMarker: state.dateEnv.addYears(state.currentDate, 1),
+ });
}
- subtract(marker, dur) {
- let a = this.calendarSystem.markerToArray(marker);
- a[0] -= dur.years;
- a[1] -= dur.months;
- a[2] -= dur.days;
- a[6] -= dur.milliseconds;
- return this.calendarSystem.arrayToMarker(a);
+ today() {
+ let state = this.getCurrentData();
+ this.unselect();
+ this.dispatch({
+ type: 'CHANGE_DATE',
+ dateMarker: getNow(state.calendarOptions.now, state.dateEnv),
+ });
}
- addYears(marker, n) {
- let a = this.calendarSystem.markerToArray(marker);
- a[0] += n;
- return this.calendarSystem.arrayToMarker(a);
+ gotoDate(zonedDateInput) {
+ let state = this.getCurrentData();
+ this.unselect();
+ this.dispatch({
+ type: 'CHANGE_DATE',
+ dateMarker: state.dateEnv.createMarker(zonedDateInput),
+ });
}
- addMonths(marker, n) {
- let a = this.calendarSystem.markerToArray(marker);
- a[1] += n;
- return this.calendarSystem.arrayToMarker(a);
+ incrementDate(deltaInput) {
+ let state = this.getCurrentData();
+ let delta = createDuration(deltaInput);
+ if (delta) { // else, warn about invalid input?
+ this.unselect();
+ this.dispatch({
+ type: 'CHANGE_DATE',
+ dateMarker: state.dateEnv.add(state.currentDate, delta),
+ });
+ }
}
- // Diffing Whole Units
- diffWholeYears(m0, m1) {
- let { calendarSystem } = this;
- if (timeAsMs(m0) === timeAsMs(m1) &&
- calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1) &&
- calendarSystem.getMarkerMonth(m0) === calendarSystem.getMarkerMonth(m1)) {
- return calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0);
+ getDate() {
+ let state = this.getCurrentData();
+ return state.dateEnv.toDate(state.currentDate);
+ }
+ // Date Formatting Utils
+ // -----------------------------------------------------------------------------------------------------------------
+ formatDate(d, formatter) {
+ let { dateEnv } = this.getCurrentData();
+ return dateEnv.format(dateEnv.createMarker(d), createFormatter(formatter));
+ }
+ // `settings` is for formatter AND isEndExclusive
+ formatRange(d0, d1, settings) {
+ let { dateEnv } = this.getCurrentData();
+ return dateEnv.formatRange(dateEnv.createMarker(d0), dateEnv.createMarker(d1), createFormatter(settings), settings);
+ }
+ formatIso(d, omitTime) {
+ let { dateEnv } = this.getCurrentData();
+ return dateEnv.formatIso(dateEnv.createMarker(d), { omitTime });
+ }
+ // Date Selection / Event Selection / DayClick
+ // -----------------------------------------------------------------------------------------------------------------
+ select(dateOrObj, endDate) {
+ let selectionInput;
+ if (endDate == null) {
+ if (dateOrObj.start != null) {
+ selectionInput = dateOrObj;
+ }
+ else {
+ selectionInput = {
+ start: dateOrObj,
+ end: null,
+ };
+ }
+ }
+ else {
+ selectionInput = {
+ start: dateOrObj,
+ end: endDate,
+ };
+ }
+ let state = this.getCurrentData();
+ let selection = parseDateSpan(selectionInput, state.dateEnv, createDuration({ days: 1 }));
+ if (selection) { // throw parse error otherwise?
+ this.dispatch({ type: 'SELECT_DATES', selection });
+ triggerDateSelect(selection, null, state);
}
- return null;
}
- diffWholeMonths(m0, m1) {
- let { calendarSystem } = this;
- if (timeAsMs(m0) === timeAsMs(m1) &&
- calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1)) {
- return (calendarSystem.getMarkerMonth(m1) - calendarSystem.getMarkerMonth(m0)) +
- (calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0)) * 12;
+ unselect(pev) {
+ let state = this.getCurrentData();
+ if (state.dateSelection) {
+ this.dispatch({ type: 'UNSELECT_DATES' });
+ triggerDateUnselect(pev, state);
}
- return null;
}
- // Range / Duration
- greatestWholeUnit(m0, m1) {
- let n = this.diffWholeYears(m0, m1);
- if (n !== null) {
- return { unit: 'year', value: n };
+ // Public Events API
+ // -----------------------------------------------------------------------------------------------------------------
+ addEvent(eventInput, sourceInput) {
+ if (eventInput instanceof EventImpl) {
+ let def = eventInput._def;
+ let instance = eventInput._instance;
+ let currentData = this.getCurrentData();
+ // not already present? don't want to add an old snapshot
+ if (!currentData.eventStore.defs[def.defId]) {
+ this.dispatch({
+ type: 'ADD_EVENTS',
+ eventStore: eventTupleToStore({ def, instance }), // TODO: better util for two args?
+ });
+ this.triggerEventAdd(eventInput);
+ }
+ return eventInput;
}
- n = this.diffWholeMonths(m0, m1);
- if (n !== null) {
- return { unit: 'month', value: n };
+ let state = this.getCurrentData();
+ let eventSource;
+ if (sourceInput instanceof EventSourceImpl) {
+ eventSource = sourceInput.internalEventSource;
}
- n = diffWholeWeeks(m0, m1);
- if (n !== null) {
- return { unit: 'week', value: n };
+ else if (typeof sourceInput === 'boolean') {
+ if (sourceInput) { // true. part of the first event source
+ [eventSource] = hashValuesToArray(state.eventSources);
+ }
}
- n = diffWholeDays(m0, m1);
- if (n !== null) {
- return { unit: 'day', value: n };
+ else if (sourceInput != null) { // an ID. accepts a number too
+ let sourceApi = this.getEventSourceById(sourceInput); // TODO: use an internal function
+ if (!sourceApi) {
+ console.warn(`Could not find an event source with ID "${sourceInput}"`); // TODO: test
+ return null;
+ }
+ eventSource = sourceApi.internalEventSource;
}
- n = diffHours(m0, m1);
- if (isInt(n)) {
- return { unit: 'hour', value: n };
+ let tuple = parseEvent(eventInput, eventSource, state, false);
+ if (tuple) {
+ let newEventApi = new EventImpl(state, tuple.def, tuple.def.recurringDef ? null : tuple.instance);
+ this.dispatch({
+ type: 'ADD_EVENTS',
+ eventStore: eventTupleToStore(tuple),
+ });
+ this.triggerEventAdd(newEventApi);
+ return newEventApi;
}
- n = diffMinutes(m0, m1);
- if (isInt(n)) {
- return { unit: 'minute', value: n };
+ return null;
+ }
+ triggerEventAdd(eventApi) {
+ let { emitter } = this.getCurrentData();
+ emitter.trigger('eventAdd', {
+ event: eventApi,
+ relatedEvents: [],
+ revert: () => {
+ this.dispatch({
+ type: 'REMOVE_EVENTS',
+ eventStore: eventApiToStore(eventApi),
+ });
+ },
+ });
+ }
+ // TODO: optimize
+ getEventById(id) {
+ let state = this.getCurrentData();
+ let { defs, instances } = state.eventStore;
+ id = String(id);
+ for (let defId in defs) {
+ let def = defs[defId];
+ if (def.publicId === id) {
+ if (def.recurringDef) {
+ return new EventImpl(state, def, null);
+ }
+ for (let instanceId in instances) {
+ let instance = instances[instanceId];
+ if (instance.defId === def.defId) {
+ return new EventImpl(state, def, instance);
+ }
+ }
+ }
}
- n = diffSeconds(m0, m1);
- if (isInt(n)) {
- return { unit: 'second', value: n };
+ return null;
+ }
+ getEvents() {
+ let currentData = this.getCurrentData();
+ return buildEventApis(currentData.eventStore, currentData);
+ }
+ removeAllEvents() {
+ this.dispatch({ type: 'REMOVE_ALL_EVENTS' });
+ }
+ // Public Event Sources API
+ // -----------------------------------------------------------------------------------------------------------------
+ getEventSources() {
+ let state = this.getCurrentData();
+ let sourceHash = state.eventSources;
+ let sourceApis = [];
+ for (let internalId in sourceHash) {
+ sourceApis.push(new EventSourceImpl(state, sourceHash[internalId]));
}
- return { unit: 'millisecond', value: m1.valueOf() - m0.valueOf() };
+ return sourceApis;
}
- countDurationsBetween(m0, m1, d) {
- // TODO: can use greatestWholeUnit
- let diff;
- if (d.years) {
- diff = this.diffWholeYears(m0, m1);
- if (diff !== null) {
- return diff / asRoughYears(d);
+ getEventSourceById(id) {
+ let state = this.getCurrentData();
+ let sourceHash = state.eventSources;
+ id = String(id);
+ for (let sourceId in sourceHash) {
+ if (sourceHash[sourceId].publicId === id) {
+ return new EventSourceImpl(state, sourceHash[sourceId]);
}
}
- if (d.months) {
- diff = this.diffWholeMonths(m0, m1);
- if (diff !== null) {
- return diff / asRoughMonths(d);
+ return null;
+ }
+ addEventSource(sourceInput) {
+ let state = this.getCurrentData();
+ if (sourceInput instanceof EventSourceImpl) {
+ // not already present? don't want to add an old snapshot
+ if (!state.eventSources[sourceInput.internalEventSource.sourceId]) {
+ this.dispatch({
+ type: 'ADD_EVENT_SOURCES',
+ sources: [sourceInput.internalEventSource],
+ });
}
+ return sourceInput;
}
- if (d.days) {
- diff = diffWholeDays(m0, m1);
- if (diff !== null) {
- return diff / asRoughDays(d);
- }
+ let eventSource = parseEventSource(sourceInput, state);
+ if (eventSource) { // TODO: error otherwise?
+ this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [eventSource] });
+ return new EventSourceImpl(state, eventSource);
}
- return (m1.valueOf() - m0.valueOf()) / asRoughMs(d);
+ return null;
}
- // Start-Of
- // these DON'T return zoned-dates. only UTC start-of dates
- startOf(m, unit) {
- if (unit === 'year') {
- return this.startOfYear(m);
+ removeAllEventSources() {
+ this.dispatch({ type: 'REMOVE_ALL_EVENT_SOURCES' });
+ }
+ refetchEvents() {
+ this.dispatch({ type: 'FETCH_EVENT_SOURCES', isRefetch: true });
+ }
+ // Scroll
+ // -----------------------------------------------------------------------------------------------------------------
+ scrollToTime(timeInput) {
+ let time = createDuration(timeInput);
+ if (time) {
+ this.trigger('_scrollRequest', { time });
}
- if (unit === 'month') {
- return this.startOfMonth(m);
+ }
+ }
+
+ function pointInsideRect(point, rect) {
+ return point.left >= rect.left &&
+ point.left < rect.right &&
+ point.top >= rect.top &&
+ point.top < rect.bottom;
+ }
+ // Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false
+ function intersectRects(rect1, rect2) {
+ let res = {
+ left: Math.max(rect1.left, rect2.left),
+ right: Math.min(rect1.right, rect2.right),
+ top: Math.max(rect1.top, rect2.top),
+ bottom: Math.min(rect1.bottom, rect2.bottom),
+ };
+ if (res.left < res.right && res.top < res.bottom) {
+ return res;
+ }
+ return false;
+ }
+ function translateRect(rect, deltaX, deltaY) {
+ return {
+ left: rect.left + deltaX,
+ right: rect.right + deltaX,
+ top: rect.top + deltaY,
+ bottom: rect.bottom + deltaY,
+ };
+ }
+ // Returns a new point that will have been moved to reside within the given rectangle
+ function constrainPoint(point, rect) {
+ return {
+ left: Math.min(Math.max(point.left, rect.left), rect.right),
+ top: Math.min(Math.max(point.top, rect.top), rect.bottom),
+ };
+ }
+ // Returns a point that is the center of the given rectangle
+ function getRectCenter(rect) {
+ return {
+ left: (rect.left + rect.right) / 2,
+ top: (rect.top + rect.bottom) / 2,
+ };
+ }
+ // Subtracts point2's coordinates from point1's coordinates, returning a delta
+ function diffPoints(point1, point2) {
+ return {
+ left: point1.left - point2.left,
+ top: point1.top - point2.top,
+ };
+ }
+
+ const EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere
+ class Splitter {
+ constructor() {
+ this.getKeysForEventDefs = memoize(this._getKeysForEventDefs);
+ this.splitDateSelection = memoize(this._splitDateSpan);
+ this.splitEventStore = memoize(this._splitEventStore);
+ this.splitIndividualUi = memoize(this._splitIndividualUi);
+ this.splitEventDrag = memoize(this._splitInteraction);
+ this.splitEventResize = memoize(this._splitInteraction);
+ this.eventUiBuilders = {}; // TODO: typescript protection
+ }
+ splitProps(props) {
+ let keyInfos = this.getKeyInfo(props);
+ let defKeys = this.getKeysForEventDefs(props.eventStore);
+ let dateSelections = this.splitDateSelection(props.dateSelection);
+ let individualUi = this.splitIndividualUi(props.eventUiBases, defKeys); // the individual *bases*
+ let eventStores = this.splitEventStore(props.eventStore, defKeys);
+ let eventDrags = this.splitEventDrag(props.eventDrag);
+ let eventResizes = this.splitEventResize(props.eventResize);
+ let splitProps = {};
+ this.eventUiBuilders = mapHash(keyInfos, (info, key) => this.eventUiBuilders[key] || memoize(buildEventUiForKey));
+ for (let key in keyInfos) {
+ let keyInfo = keyInfos[key];
+ let eventStore = eventStores[key] || EMPTY_EVENT_STORE;
+ let buildEventUi = this.eventUiBuilders[key];
+ splitProps[key] = {
+ businessHours: keyInfo.businessHours || props.businessHours,
+ dateSelection: dateSelections[key] || null,
+ eventStore,
+ eventUiBases: buildEventUi(props.eventUiBases[''], keyInfo.ui, individualUi[key]),
+ eventSelection: eventStore.instances[props.eventSelection] ? props.eventSelection : '',
+ eventDrag: eventDrags[key] || null,
+ eventResize: eventResizes[key] || null,
+ };
}
- if (unit === 'week') {
- return this.startOfWeek(m);
+ return splitProps;
+ }
+ _splitDateSpan(dateSpan) {
+ let dateSpans = {};
+ if (dateSpan) {
+ let keys = this.getKeysForDateSpan(dateSpan);
+ for (let key of keys) {
+ dateSpans[key] = dateSpan;
+ }
}
- if (unit === 'day') {
- return startOfDay(m);
+ return dateSpans;
+ }
+ _getKeysForEventDefs(eventStore) {
+ return mapHash(eventStore.defs, (eventDef) => this.getKeysForEventDef(eventDef));
+ }
+ _splitEventStore(eventStore, defKeys) {
+ let { defs, instances } = eventStore;
+ let splitStores = {};
+ for (let defId in defs) {
+ for (let key of defKeys[defId]) {
+ if (!splitStores[key]) {
+ splitStores[key] = createEmptyEventStore();
+ }
+ splitStores[key].defs[defId] = defs[defId];
+ }
}
- if (unit === 'hour') {
- return startOfHour(m);
+ for (let instanceId in instances) {
+ let instance = instances[instanceId];
+ for (let key of defKeys[instance.defId]) {
+ if (splitStores[key]) { // must have already been created
+ splitStores[key].instances[instanceId] = instance;
+ }
+ }
}
- if (unit === 'minute') {
- return startOfMinute(m);
+ return splitStores;
+ }
+ _splitIndividualUi(eventUiBases, defKeys) {
+ let splitHashes = {};
+ for (let defId in eventUiBases) {
+ if (defId) { // not the '' key
+ for (let key of defKeys[defId]) {
+ if (!splitHashes[key]) {
+ splitHashes[key] = {};
+ }
+ splitHashes[key][defId] = eventUiBases[defId];
+ }
+ }
}
- if (unit === 'second') {
- return startOfSecond(m);
+ return splitHashes;
+ }
+ _splitInteraction(interaction) {
+ let splitStates = {};
+ if (interaction) {
+ let affectedStores = this._splitEventStore(interaction.affectedEvents, this._getKeysForEventDefs(interaction.affectedEvents));
+ // can't rely on defKeys because event data is mutated
+ let mutatedKeysByDefId = this._getKeysForEventDefs(interaction.mutatedEvents);
+ let mutatedStores = this._splitEventStore(interaction.mutatedEvents, mutatedKeysByDefId);
+ let populate = (key) => {
+ if (!splitStates[key]) {
+ splitStates[key] = {
+ affectedEvents: affectedStores[key] || EMPTY_EVENT_STORE,
+ mutatedEvents: mutatedStores[key] || EMPTY_EVENT_STORE,
+ isEvent: interaction.isEvent,
+ };
+ }
+ };
+ for (let key in affectedStores) {
+ populate(key);
+ }
+ for (let key in mutatedStores) {
+ populate(key);
+ }
}
- return null;
+ return splitStates;
}
- startOfYear(m) {
- return this.calendarSystem.arrayToMarker([
- this.calendarSystem.getMarkerYear(m),
- ]);
+ }
+ function buildEventUiForKey(allUi, eventUiForKey, individualUi) {
+ let baseParts = [];
+ if (allUi) {
+ baseParts.push(allUi);
}
- startOfMonth(m) {
- return this.calendarSystem.arrayToMarker([
- this.calendarSystem.getMarkerYear(m),
- this.calendarSystem.getMarkerMonth(m),
- ]);
+ if (eventUiForKey) {
+ baseParts.push(eventUiForKey);
}
- startOfWeek(m) {
- return this.calendarSystem.arrayToMarker([
- this.calendarSystem.getMarkerYear(m),
- this.calendarSystem.getMarkerMonth(m),
- m.getUTCDate() - ((m.getUTCDay() - this.weekDow + 7) % 7),
- ]);
+ let stuff = {
+ '': combineEventUis(baseParts),
+ };
+ if (individualUi) {
+ Object.assign(stuff, individualUi);
}
- // Week Number
- computeWeekNumber(marker) {
- if (this.weekNumberFunc) {
- return this.weekNumberFunc(this.toDate(marker));
+ return stuff;
+ }
+
+ function getDateMeta(date, todayRange, nowDate, dateProfile) {
+ return {
+ dow: date.getUTCDay(),
+ isDisabled: Boolean(dateProfile && !rangeContainsMarker(dateProfile.activeRange, date)),
+ isOther: Boolean(dateProfile && !rangeContainsMarker(dateProfile.currentRange, date)),
+ isToday: Boolean(todayRange && rangeContainsMarker(todayRange, date)),
+ isPast: Boolean(nowDate ? (date < nowDate) : todayRange ? (date < todayRange.start) : false),
+ isFuture: Boolean(nowDate ? (date > nowDate) : todayRange ? (date >= todayRange.end) : false),
+ };
+ }
+ function getDayClassNames(meta, theme) {
+ let classNames = [
+ 'fc-day',
+ `fc-day-${DAY_IDS[meta.dow]}`,
+ ];
+ if (meta.isDisabled) {
+ classNames.push('fc-day-disabled');
+ }
+ else {
+ if (meta.isToday) {
+ classNames.push('fc-day-today');
+ classNames.push(theme.getClass('today'));
+ }
+ if (meta.isPast) {
+ classNames.push('fc-day-past');
+ }
+ if (meta.isFuture) {
+ classNames.push('fc-day-future');
+ }
+ if (meta.isOther) {
+ classNames.push('fc-day-other');
}
- return weekOfYear(marker, this.weekDow, this.weekDoy);
}
- // TODO: choke on timeZoneName: long
- format(marker, formatter, dateOptions = {}) {
- return formatter.format({
- marker,
- timeZoneOffset: dateOptions.forcedTzo != null ?
- dateOptions.forcedTzo :
- this.offsetForMarker(marker),
- }, this);
+ return classNames;
+ }
+ function getSlotClassNames(meta, theme) {
+ let classNames = [
+ 'fc-slot',
+ `fc-slot-${DAY_IDS[meta.dow]}`,
+ ];
+ if (meta.isDisabled) {
+ classNames.push('fc-slot-disabled');
}
- formatRange(start, end, formatter, dateOptions = {}) {
- if (dateOptions.isEndExclusive) {
- end = addMs(end, -1);
+ else {
+ if (meta.isToday) {
+ classNames.push('fc-slot-today');
+ classNames.push(theme.getClass('today'));
+ }
+ if (meta.isPast) {
+ classNames.push('fc-slot-past');
+ }
+ if (meta.isFuture) {
+ classNames.push('fc-slot-future');
}
- return formatter.formatRange({
- marker: start,
- timeZoneOffset: dateOptions.forcedStartTzo != null ?
- dateOptions.forcedStartTzo :
- this.offsetForMarker(start),
- }, {
- marker: end,
- timeZoneOffset: dateOptions.forcedEndTzo != null ?
- dateOptions.forcedEndTzo :
- this.offsetForMarker(end),
- }, this, dateOptions.defaultSeparator);
}
- /*
- DUMB: the omitTime arg is dumb. if we omit the time, we want to omit the timezone offset. and if we do that,
- might as well use buildIsoString or some other util directly
- */
- formatIso(marker, extraOptions = {}) {
- let timeZoneOffset = null;
- if (!extraOptions.omitTimeZoneOffset) {
- if (extraOptions.forcedTzo != null) {
- timeZoneOffset = extraOptions.forcedTzo;
+ return classNames;
+ }
+
+ const DAY_FORMAT = createFormatter({ year: 'numeric', month: 'long', day: 'numeric' });
+ const WEEK_FORMAT = createFormatter({ week: 'long' });
+ function buildNavLinkAttrs(context, dateMarker, viewType = 'day', isTabbable = true) {
+ const { dateEnv, options, calendarApi } = context;
+ let dateStr = dateEnv.format(dateMarker, viewType === 'week' ? WEEK_FORMAT : DAY_FORMAT);
+ if (options.navLinks) {
+ let zonedDate = dateEnv.toDate(dateMarker);
+ const handleInteraction = (ev) => {
+ let customAction = viewType === 'day' ? options.navLinkDayClick :
+ viewType === 'week' ? options.navLinkWeekClick : null;
+ if (typeof customAction === 'function') {
+ customAction.call(calendarApi, dateEnv.toDate(dateMarker), ev);
}
else {
- timeZoneOffset = this.offsetForMarker(marker);
+ if (typeof customAction === 'string') {
+ viewType = customAction;
+ }
+ calendarApi.zoomTo(dateMarker, viewType);
}
+ };
+ return Object.assign({ title: formatWithOrdinals(options.navLinkHint, [dateStr, zonedDate], dateStr), 'data-navlink': '' }, (isTabbable
+ ? createAriaClickAttrs(handleInteraction)
+ : { onClick: handleInteraction }));
+ }
+ return { 'aria-label': dateStr };
+ }
+
+ let _isRtlScrollbarOnLeft = null;
+ function getIsRtlScrollbarOnLeft() {
+ if (_isRtlScrollbarOnLeft === null) {
+ _isRtlScrollbarOnLeft = computeIsRtlScrollbarOnLeft();
+ }
+ return _isRtlScrollbarOnLeft;
+ }
+ function computeIsRtlScrollbarOnLeft() {
+ let outerEl = document.createElement('div');
+ applyStyle(outerEl, {
+ position: 'absolute',
+ top: -1000,
+ left: 0,
+ border: 0,
+ padding: 0,
+ overflow: 'scroll',
+ direction: 'rtl',
+ });
+ outerEl.innerHTML = '<div></div>';
+ document.body.appendChild(outerEl);
+ let innerEl = outerEl.firstChild;
+ let res = innerEl.getBoundingClientRect().left > outerEl.getBoundingClientRect().left;
+ removeElement(outerEl);
+ return res;
+ }
+
+ let _scrollbarWidths;
+ function getScrollbarWidths() {
+ if (!_scrollbarWidths) {
+ _scrollbarWidths = computeScrollbarWidths();
+ }
+ return _scrollbarWidths;
+ }
+ function computeScrollbarWidths() {
+ let el = document.createElement('div');
+ el.style.overflow = 'scroll';
+ el.style.position = 'absolute';
+ el.style.top = '-9999px';
+ el.style.left = '-9999px';
+ document.body.appendChild(el);
+ let res = computeScrollbarWidthsForEl(el);
+ document.body.removeChild(el);
+ return res;
+ }
+ // WARNING: will include border
+ function computeScrollbarWidthsForEl(el) {
+ return {
+ x: el.offsetHeight - el.clientHeight,
+ y: el.offsetWidth - el.clientWidth,
+ };
+ }
+
+ function computeEdges(el, getPadding = false) {
+ let computedStyle = window.getComputedStyle(el);
+ let borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0;
+ let borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0;
+ let borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0;
+ let borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
+ let badScrollbarWidths = computeScrollbarWidthsForEl(el); // includes border!
+ let scrollbarLeftRight = badScrollbarWidths.y - borderLeft - borderRight;
+ let scrollbarBottom = badScrollbarWidths.x - borderTop - borderBottom;
+ let res = {
+ borderLeft,
+ borderRight,
+ borderTop,
+ borderBottom,
+ scrollbarBottom,
+ scrollbarLeft: 0,
+ scrollbarRight: 0,
+ };
+ if (getIsRtlScrollbarOnLeft() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side?
+ res.scrollbarLeft = scrollbarLeftRight;
+ }
+ else {
+ res.scrollbarRight = scrollbarLeftRight;
+ }
+ if (getPadding) {
+ res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0;
+ res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0;
+ res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0;
+ res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0;
+ }
+ return res;
+ }
+ function computeInnerRect(el, goWithinPadding = false, doFromWindowViewport) {
+ let outerRect = doFromWindowViewport ? el.getBoundingClientRect() : computeRect(el);
+ let edges = computeEdges(el, goWithinPadding);
+ let res = {
+ left: outerRect.left + edges.borderLeft + edges.scrollbarLeft,
+ right: outerRect.right - edges.borderRight - edges.scrollbarRight,
+ top: outerRect.top + edges.borderTop,
+ bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom,
+ };
+ if (goWithinPadding) {
+ res.left += edges.paddingLeft;
+ res.right -= edges.paddingRight;
+ res.top += edges.paddingTop;
+ res.bottom -= edges.paddingBottom;
+ }
+ return res;
+ }
+ function computeRect(el) {
+ let rect = el.getBoundingClientRect();
+ return {
+ left: rect.left + window.pageXOffset,
+ top: rect.top + window.pageYOffset,
+ right: rect.right + window.pageXOffset,
+ bottom: rect.bottom + window.pageYOffset,
+ };
+ }
+ function computeClippedClientRect(el) {
+ let clippingParents = getClippingParents(el);
+ let rect = el.getBoundingClientRect();
+ for (let clippingParent of clippingParents) {
+ let intersection = intersectRects(rect, clippingParent.getBoundingClientRect());
+ if (intersection) {
+ rect = intersection;
+ }
+ else {
+ return null;
}
- return buildIsoString(marker, timeZoneOffset, extraOptions.omitTime);
}
- // TimeZone
- timestampToMarker(ms) {
- if (this.timeZone === 'local') {
- return arrayToUtcDate(dateToLocalArray(new Date(ms)));
+ return rect;
+ }
+ // does not return window
+ function getClippingParents(el) {
+ let parents = [];
+ while (el instanceof HTMLElement) { // will stop when gets to document or null
+ let computedStyle = window.getComputedStyle(el);
+ if (computedStyle.position === 'fixed') {
+ break;
}
- if (this.timeZone === 'UTC' || !this.namedTimeZoneImpl) {
- return new Date(ms);
+ if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) {
+ parents.push(el);
}
- return arrayToUtcDate(this.namedTimeZoneImpl.timestampToArray(ms));
+ el = el.parentNode;
}
- offsetForMarker(m) {
- if (this.timeZone === 'local') {
- return -arrayToLocalDate(dateToUtcArray(m)).getTimezoneOffset(); // convert "inverse" offset to "normal" offset
+ return parents;
+ }
+
+ /*
+ Records offset information for a set of elements, relative to an origin element.
+ Can record the left/right OR the top/bottom OR both.
+ Provides methods for querying the cache by position.
+ */
+ class PositionCache {
+ constructor(originEl, els, isHorizontal, isVertical) {
+ this.els = els;
+ let originClientRect = this.originClientRect = originEl.getBoundingClientRect(); // relative to viewport top-left
+ if (isHorizontal) {
+ this.buildElHorizontals(originClientRect.left);
}
- if (this.timeZone === 'UTC') {
- return 0;
+ if (isVertical) {
+ this.buildElVerticals(originClientRect.top);
}
- if (this.namedTimeZoneImpl) {
- return this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m));
+ }
+ // Populates the left/right internal coordinate arrays
+ buildElHorizontals(originClientLeft) {
+ let lefts = [];
+ let rights = [];
+ for (let el of this.els) {
+ let rect = el.getBoundingClientRect();
+ lefts.push(rect.left - originClientLeft);
+ rights.push(rect.right - originClientLeft);
}
- return null;
+ this.lefts = lefts;
+ this.rights = rights;
}
- // Conversion
- toDate(m, forcedTzo) {
- if (this.timeZone === 'local') {
- return arrayToLocalDate(dateToUtcArray(m));
+ // Populates the top/bottom internal coordinate arrays
+ buildElVerticals(originClientTop) {
+ let tops = [];
+ let bottoms = [];
+ for (let el of this.els) {
+ let rect = el.getBoundingClientRect();
+ tops.push(rect.top - originClientTop);
+ bottoms.push(rect.bottom - originClientTop);
}
- if (this.timeZone === 'UTC') {
- return new Date(m.valueOf()); // make sure it's a copy
+ this.tops = tops;
+ this.bottoms = bottoms;
+ }
+ // Given a left offset (from document left), returns the index of the el that it horizontally intersects.
+ // If no intersection is made, returns undefined.
+ leftToIndex(leftPosition) {
+ let { lefts, rights } = this;
+ let len = lefts.length;
+ let i;
+ for (i = 0; i < len; i += 1) {
+ if (leftPosition >= lefts[i] && leftPosition < rights[i]) {
+ return i;
+ }
}
- if (!this.namedTimeZoneImpl) {
- return new Date(m.valueOf() - (forcedTzo || 0));
+ return undefined; // TODO: better
+ }
+ // Given a top offset (from document top), returns the index of the el that it vertically intersects.
+ // If no intersection is made, returns undefined.
+ topToIndex(topPosition) {
+ let { tops, bottoms } = this;
+ let len = tops.length;
+ let i;
+ for (i = 0; i < len; i += 1) {
+ if (topPosition >= tops[i] && topPosition < bottoms[i]) {
+ return i;
+ }
}
- return new Date(m.valueOf() -
- this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)) * 1000 * 60);
+ return undefined; // TODO: better
+ }
+ // Gets the width of the element at the given index
+ getWidth(leftIndex) {
+ return this.rights[leftIndex] - this.lefts[leftIndex];
+ }
+ // Gets the height of the element at the given index
+ getHeight(topIndex) {
+ return this.bottoms[topIndex] - this.tops[topIndex];
+ }
+ similarTo(otherCache) {
+ return similarNumArrays(this.tops || [], otherCache.tops || []) &&
+ similarNumArrays(this.bottoms || [], otherCache.bottoms || []) &&
+ similarNumArrays(this.lefts || [], otherCache.lefts || []) &&
+ similarNumArrays(this.rights || [], otherCache.rights || []);
+ }
+ }
+ function similarNumArrays(a, b) {
+ const len = a.length;
+ if (len !== b.length) {
+ return false;
+ }
+ for (let i = 0; i < len; i++) {
+ if (Math.round(a[i]) !== Math.round(b[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* eslint max-classes-per-file: "off" */
+ /*
+ An object for getting/setting scroll-related information for an element.
+ Internally, this is done very differently for window versus DOM element,
+ so this object serves as a common interface.
+ */
+ class ScrollController {
+ getMaxScrollTop() {
+ return this.getScrollHeight() - this.getClientHeight();
+ }
+ getMaxScrollLeft() {
+ return this.getScrollWidth() - this.getClientWidth();
+ }
+ canScrollVertically() {
+ return this.getMaxScrollTop() > 0;
+ }
+ canScrollHorizontally() {
+ return this.getMaxScrollLeft() > 0;
+ }
+ canScrollUp() {
+ return this.getScrollTop() > 0;
+ }
+ canScrollDown() {
+ return this.getScrollTop() < this.getMaxScrollTop();
+ }
+ canScrollLeft() {
+ return this.getScrollLeft() > 0;
+ }
+ canScrollRight() {
+ return this.getScrollLeft() < this.getMaxScrollLeft();
+ }
+ }
+ class ElementScrollController extends ScrollController {
+ constructor(el) {
+ super();
+ this.el = el;
+ }
+ getScrollTop() {
+ return this.el.scrollTop;
+ }
+ getScrollLeft() {
+ return this.el.scrollLeft;
+ }
+ setScrollTop(top) {
+ this.el.scrollTop = top;
+ }
+ setScrollLeft(left) {
+ this.el.scrollLeft = left;
+ }
+ getScrollWidth() {
+ return this.el.scrollWidth;
+ }
+ getScrollHeight() {
+ return this.el.scrollHeight;
+ }
+ getClientHeight() {
+ return this.el.clientHeight;
+ }
+ getClientWidth() {
+ return this.el.clientWidth;
+ }
+ }
+ class WindowScrollController extends ScrollController {
+ getScrollTop() {
+ return window.pageYOffset;
+ }
+ getScrollLeft() {
+ return window.pageXOffset;
+ }
+ setScrollTop(n) {
+ window.scroll(window.pageXOffset, n);
+ }
+ setScrollLeft(n) {
+ window.scroll(n, window.pageYOffset);
+ }
+ getScrollWidth() {
+ return document.documentElement.scrollWidth;
+ }
+ getScrollHeight() {
+ return document.documentElement.scrollHeight;
+ }
+ getClientHeight() {
+ return document.documentElement.clientHeight;
+ }
+ getClientWidth() {
+ return document.documentElement.clientWidth;
+ }
+ }
+
+ /*
+ an INTERACTABLE date component
+
+ PURPOSES:
+ - hook up to fg, fill, and mirror renderers
+ - interface for dragging and hits
+ */
+ class DateComponent extends BaseComponent {
+ constructor() {
+ super(...arguments);
+ this.uid = guid();
+ }
+ // Hit System
+ // -----------------------------------------------------------------------------------------------------------------
+ prepareHits() {
+ }
+ queryHit(positionLeft, positionTop, elWidth, elHeight) {
+ return null; // this should be abstract
+ }
+ // Pointer Interaction Utils
+ // -----------------------------------------------------------------------------------------------------------------
+ isValidSegDownEl(el) {
+ return !this.props.eventDrag && // HACK
+ !this.props.eventResize && // HACK
+ !elementClosest(el, '.fc-event-mirror');
+ }
+ isValidDateDownEl(el) {
+ return !elementClosest(el, '.fc-event:not(.fc-bg-event)') &&
+ !elementClosest(el, '.fc-more-link') && // a "more.." link
+ !elementClosest(el, 'a[data-navlink]') && // a clickable nav link
+ !elementClosest(el, '.fc-popover'); // hack
}
}
@@ -4797,7 +5764,11 @@ var FullCalendar = (function (exports) {
}
class SegHierarchy {
- constructor() {
+ constructor(getEntryThickness = (entry) => {
+ // if no thickness known, assume 1 (if 0, so small it always fits)
+ return entry.thickness || 1;
+ }) {
+ this.getEntryThickness = getEntryThickness;
// settings
this.strictOrder = false;
this.allowReslicing = false;
@@ -4818,51 +5789,45 @@ var FullCalendar = (function (exports) {
let insertion = this.findInsertion(entry);
if (this.isInsertionValid(insertion, entry)) {
this.insertEntryAt(entry, insertion);
- return 1;
}
- return this.handleInvalidInsertion(insertion, entry, hiddenEntries);
+ else {
+ this.handleInvalidInsertion(insertion, entry, hiddenEntries);
+ }
}
isInsertionValid(insertion, entry) {
- return (this.maxCoord === -1 || insertion.levelCoord + entry.thickness <= this.maxCoord) &&
+ return (this.maxCoord === -1 || insertion.levelCoord + this.getEntryThickness(entry) <= this.maxCoord) &&
(this.maxStackCnt === -1 || insertion.stackCnt < this.maxStackCnt);
}
- // returns number of new entries inserted
handleInvalidInsertion(insertion, entry, hiddenEntries) {
if (this.allowReslicing && insertion.touchingEntry) {
- return this.splitEntry(entry, insertion.touchingEntry, hiddenEntries);
+ const hiddenEntry = Object.assign(Object.assign({}, entry), { span: intersectSpans(entry.span, insertion.touchingEntry.span) });
+ hiddenEntries.push(hiddenEntry);
+ this.splitEntry(entry, insertion.touchingEntry, hiddenEntries);
+ }
+ else {
+ hiddenEntries.push(entry);
}
- hiddenEntries.push(entry);
- return 0;
}
+ /*
+ Does NOT add what hit the `barrier` into hiddenEntries. Should already be done.
+ */
splitEntry(entry, barrier, hiddenEntries) {
- let partCnt = 0;
- let splitHiddenEntries = [];
let entrySpan = entry.span;
let barrierSpan = barrier.span;
if (entrySpan.start < barrierSpan.start) {
- partCnt += this.insertEntry({
+ this.insertEntry({
index: entry.index,
thickness: entry.thickness,
span: { start: entrySpan.start, end: barrierSpan.start },
- }, splitHiddenEntries);
+ }, hiddenEntries);
}
if (entrySpan.end > barrierSpan.end) {
- partCnt += this.insertEntry({
+ this.insertEntry({
index: entry.index,
thickness: entry.thickness,
span: { start: barrierSpan.end, end: entrySpan.end },
- }, splitHiddenEntries);
+ }, hiddenEntries);
}
- if (partCnt) {
- hiddenEntries.push({
- index: entry.index,
- thickness: entry.thickness,
- span: intersectSpans(barrierSpan, entrySpan), // guaranteed to intersect
- }, ...splitHiddenEntries);
- return partCnt;
- }
- hiddenEntries.push(entry);
- return 0;
}
insertEntryAt(entry, insertion) {
let { entriesByLevel, levelCoords } = this;
@@ -4877,6 +5842,9 @@ var FullCalendar = (function (exports) {
}
this.stackCnts[buildEntryKey(entry)] = insertion.stackCnt;
}
+ /*
+ does not care about limits
+ */
findInsertion(newEntry) {
let { levelCoords, entriesByLevel, strictOrder, stackCnts } = this;
let levelCnt = levelCoords.length;
@@ -4886,10 +5854,10 @@ var FullCalendar = (function (exports) {
let touchingEntry = null;
let stackCnt = 0;
for (let trackingLevel = 0; trackingLevel < levelCnt; trackingLevel += 1) {
- let trackingCoord = levelCoords[trackingLevel];
+ const trackingCoord = levelCoords[trackingLevel];
// if the current level is past the placed entry, we have found a good empty space and can stop.
// if strictOrder, keep finding more lateral intersections.
- if (!strictOrder && trackingCoord >= candidateCoord + newEntry.thickness) {
+ if (!strictOrder && trackingCoord >= candidateCoord + this.getEntryThickness(newEntry)) {
break;
}
let trackingEntries = entriesByLevel[trackingLevel];
@@ -4900,7 +5868,7 @@ var FullCalendar = (function (exports) {
(trackingEntry = trackingEntries[lateralIndex]) && // but not past the whole entry list
trackingEntry.span.start < newEntry.span.end // and not entirely past newEntry
) {
- let trackingEntryBottom = trackingCoord + trackingEntry.thickness;
+ let trackingEntryBottom = trackingCoord + this.getEntryThickness(trackingEntry);
// intersects into the top of the candidate?
if (trackingEntryBottom > candidateCoord) {
candidateCoord = trackingEntryBottom;
@@ -4948,7 +5916,7 @@ var FullCalendar = (function (exports) {
let entries = entriesByLevel[level];
let levelCoord = levelCoords[level];
for (let entry of entries) {
- rects.push(Object.assign(Object.assign({}, entry), { levelCoord }));
+ rects.push(Object.assign(Object.assign({}, entry), { thickness: this.getEntryThickness(entry), levelCoord }));
}
}
return rects;
@@ -5029,30 +5997,6 @@ var FullCalendar = (function (exports) {
return [startIndex, 0];
}
- class Interaction {
- constructor(settings) {
- this.component = settings.component;
- this.isHitComboAllowed = settings.isHitComboAllowed || null;
- }
- destroy() {
- }
- }
- function parseInteractionSettings(component, input) {
- return {
- component,
- el: input.el,
- useEventCenter: input.useEventCenter != null ? input.useEventCenter : true,
- isHitComboAllowed: input.isHitComboAllowed || null,
- };
- }
- function interactionSettingsToStore(settings) {
- return {
- [settings.component.uid]: settings,
- };
- }
- // global state
- const interactionSettingsStore = {};
-
/*
An abstraction for a dragging interaction originating on an event.
Does higher-level things than PointerDragger, such as possibly:
@@ -5108,48 +6052,6 @@ var FullCalendar = (function (exports) {
};
}
- class CalendarRoot extends BaseComponent {
- constructor() {
- super(...arguments);
- this.state = {
- forPrint: false,
- };
- this.handleBeforePrint = () => {
- this.setState({ forPrint: true });
- };
- this.handleAfterPrint = () => {
- this.setState({ forPrint: false });
- };
- }
- render() {
- let { props } = this;
- let { options } = props;
- let { forPrint } = this.state;
- let isHeightAuto = forPrint || options.height === 'auto' || options.contentHeight === 'auto';
- let height = (!isHeightAuto && options.height != null) ? options.height : '';
- let classNames = [
- 'fc',
- forPrint ? 'fc-media-print' : 'fc-media-screen',
- `fc-direction-${options.direction}`,
- props.theme.getClass('root'),
- ];
- if (!getCanVGrowWithinCell()) {
- classNames.push('fc-liquid-hack');
- }
- return props.children(classNames, height, isHeightAuto, forPrint);
- }
- componentDidMount() {
- let { emitter } = this.props;
- emitter.on('_beforeprint', this.handleBeforePrint);
- emitter.on('_afterprint', this.handleAfterPrint);
- }
- componentWillUnmount() {
- let { emitter } = this.props;
- emitter.off('_beforeprint', this.handleBeforePrint);
- emitter.off('_afterprint', this.handleAfterPrint);
- }
- }
-
// Computes a default column header formatting string if `colFormat` is not explicitly defined
function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
// if more than one week row, or if there are a lot of columns with not much space,
@@ -5168,183 +6070,6 @@ var FullCalendar = (function (exports) {
return renderProps.text;
}
- class ContentInjector extends BaseComponent {
- constructor() {
- super(...arguments);
- this.id = guid();
- this.queuedDomNodes = [];
- this.currentDomNodes = [];
- this.handleEl = (el) => {
- if (this.props.elRef) {
- setRef(this.props.elRef, el);
- }
- };
- }
- render() {
- const { props, context } = this;
- const { options } = context;
- const { customGenerator, defaultGenerator, renderProps } = props;
- const attrs = buildElAttrs(props);
- let useDefault = false;
- let innerContent;
- let queuedDomNodes = [];
- let currentGeneratorMeta;
- if (customGenerator != null) {
- const customGeneratorRes = typeof customGenerator === 'function' ?
- customGenerator(renderProps, y) :
- customGenerator;
- if (customGeneratorRes === true) {
- useDefault = true;
- }
- else {
- const isObject = customGeneratorRes && typeof customGeneratorRes === 'object'; // non-null
- if (isObject && ('html' in customGeneratorRes)) {
- attrs.dangerouslySetInnerHTML = { __html: customGeneratorRes.html };
- }
- else if (isObject && ('domNodes' in customGeneratorRes)) {
- queuedDomNodes = Array.prototype.slice.call(customGeneratorRes.domNodes);
- }
- else if (!isObject && typeof customGeneratorRes !== 'function') {
- // primitive value (like string or number)
- innerContent = customGeneratorRes;
- }
- else {
- // an exotic object for handleCustomRendering
- currentGeneratorMeta = customGeneratorRes;
- }
- }
- }
- else {
- useDefault = !hasCustomRenderingHandler(props.generatorName, options);
- }
- if (useDefault && defaultGenerator) {
- innerContent = defaultGenerator(renderProps);
- }
- this.queuedDomNodes = queuedDomNodes;
- this.currentGeneratorMeta = currentGeneratorMeta;
- return y(props.elTag, attrs, innerContent);
- }
- componentDidMount() {
- this.applyQueueudDomNodes();
- this.triggerCustomRendering(true);
- }
- componentDidUpdate() {
- this.applyQueueudDomNodes();
- this.triggerCustomRendering(true);
- }
- componentWillUnmount() {
- this.triggerCustomRendering(false); // TODO: different API for removal?
- }
- triggerCustomRendering(isActive) {
- var _a;
- const { props, context } = this;
- const { handleCustomRendering, customRenderingMetaMap } = context.options;
- if (handleCustomRendering) {
- const generatorMeta = (_a = this.currentGeneratorMeta) !== null && _a !== void 0 ? _a : customRenderingMetaMap === null || customRenderingMetaMap === void 0 ? void 0 : customRenderingMetaMap[props.generatorName];
- if (generatorMeta) {
- handleCustomRendering(Object.assign(Object.assign({ id: this.id, isActive, containerEl: this.base, reportNewContainerEl: this.handleEl, // for customRenderingReplacesEl
- generatorMeta }, props), { elClasses: (props.elClasses || []).filter(isTruthy) }));
- }
- }
- }
- applyQueueudDomNodes() {
- const { queuedDomNodes, currentDomNodes } = this;
- const el = this.base;
- if (!isArraysEqual(queuedDomNodes, currentDomNodes)) {
- currentDomNodes.forEach(removeElement);
- for (let newNode of queuedDomNodes) {
- el.appendChild(newNode);
- }
- this.currentDomNodes = queuedDomNodes;
- }
- }
- }
- ContentInjector.addPropsEquality({
- elClasses: isArraysEqual,
- elStyle: isPropsEqual,
- elAttrs: isNonHandlerPropsEqual,
- renderProps: isPropsEqual,
- });
- // Util
- /*
- Does UI-framework provide custom way of rendering?
- */
- function hasCustomRenderingHandler(generatorName, options) {
- var _a;
- return Boolean(options.handleCustomRendering &&
- generatorName &&
- ((_a = options.customRenderingMetaMap) === null || _a === void 0 ? void 0 : _a[generatorName]));
- }
- function buildElAttrs(props, extraClassNames) {
- const attrs = Object.assign(Object.assign({}, props.elAttrs), { ref: props.elRef });
- if (props.elClasses || extraClassNames) {
- attrs.className = (props.elClasses || [])
- .concat(extraClassNames || [])
- .concat(attrs.className || [])
- .filter(Boolean)
- .join(' ');
- }
- if (props.elStyle) {
- attrs.style = props.elStyle;
- }
- return attrs;
- }
- function isTruthy(val) {
- return Boolean(val);
- }
-
- const RenderId = createContext(0);
-
- class ContentContainer extends x$1 {
- constructor() {
- super(...arguments);
- this.InnerContent = InnerContentInjector.bind(undefined, this);
- this.handleRootEl = (el) => {
- this.rootEl = el;
- if (this.props.elRef) {
- setRef(this.props.elRef, el);
- }
- };
- }
- render() {
- const { props } = this;
- const generatedClassNames = generateClassNames(props.classNameGenerator, props.renderProps);
- if (props.children) {
- const elAttrs = buildElAttrs(props, generatedClassNames);
- const children = props.children(this.InnerContent, props.renderProps, elAttrs);
- if (props.elTag) {
- return y(props.elTag, elAttrs, children);
- }
- else {
- return children;
- }
- }
- else {
- return y((ContentInjector), Object.assign(Object.assign({}, props), { elRef: this.handleRootEl, elTag: props.elTag || 'div', elClasses: (props.elClasses || []).concat(generatedClassNames), renderId: this.context }));
- }
- }
- componentDidMount() {
- var _a, _b;
- (_b = (_a = this.props).didMount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.rootEl || this.base }));
- }
- componentWillUnmount() {
- var _a, _b;
- (_b = (_a = this.props).willUnmount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.rootEl || this.base }));
- }
- }
- ContentContainer.contextType = RenderId;
- function InnerContentInjector(containerComponent, props) {
- const parentProps = containerComponent.props;
- return y((ContentInjector), Object.assign({ renderProps: parentProps.renderProps, generatorName: parentProps.generatorName, customGenerator: parentProps.customGenerator, defaultGenerator: parentProps.defaultGenerator, renderId: containerComponent.context }, props));
- }
- // Utils
- function generateClassNames(classNameGenerator, renderProps) {
- const classNames = typeof classNameGenerator === 'function' ?
- classNameGenerator(renderProps) :
- classNameGenerator || [];
- return typeof classNames === 'string' ? [classNames] : classNames;
- }
-
// BAD name for this class now. used in the Header
class TableDateCell extends BaseComponent {
render() {
@@ -5725,139 +6450,6 @@ var FullCalendar = (function (exports) {
};
}
- function reduceEventStore(eventStore, action, eventSources, dateProfile, context) {
- switch (action.type) {
- case 'RECEIVE_EVENTS': // raw
- return receiveRawEvents(eventStore, eventSources[action.sourceId], action.fetchId, action.fetchRange, action.rawEvents, context);
- case 'RESET_RAW_EVENTS':
- return resetRawEvents(eventStore, eventSources[action.sourceId], action.rawEvents, dateProfile.activeRange, context);
- case 'ADD_EVENTS': // already parsed, but not expanded
- return addEvent(eventStore, action.eventStore, // new ones
- dateProfile ? dateProfile.activeRange : null, context);
- case 'RESET_EVENTS':
- return action.eventStore;
- case 'MERGE_EVENTS': // already parsed and expanded
- return mergeEventStores(eventStore, action.eventStore);
- case 'PREV': // TODO: how do we track all actions that affect dateProfile :(
- case 'NEXT':
- case 'CHANGE_DATE':
- case 'CHANGE_VIEW_TYPE':
- if (dateProfile) {
- return expandRecurring(eventStore, dateProfile.activeRange, context);
- }
- return eventStore;
- case 'REMOVE_EVENTS':
- return excludeSubEventStore(eventStore, action.eventStore);
- case 'REMOVE_EVENT_SOURCE':
- return excludeEventsBySourceId(eventStore, action.sourceId);
- case 'REMOVE_ALL_EVENT_SOURCES':
- return filterEventStoreDefs(eventStore, (eventDef) => (!eventDef.sourceId // only keep events with no source id
- ));
- case 'REMOVE_ALL_EVENTS':
- return createEmptyEventStore();
- default:
- return eventStore;
- }
- }
- function receiveRawEvents(eventStore, eventSource, fetchId, fetchRange, rawEvents, context) {
- if (eventSource && // not already removed
- fetchId === eventSource.latestFetchId // TODO: wish this logic was always in event-sources
- ) {
- let subset = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context);
- if (fetchRange) {
- subset = expandRecurring(subset, fetchRange, context);
- }
- return mergeEventStores(excludeEventsBySourceId(eventStore, eventSource.sourceId), subset);
- }
- return eventStore;
- }
- function resetRawEvents(existingEventStore, eventSource, rawEvents, activeRange, context) {
- const { defIdMap, instanceIdMap } = buildPublicIdMaps(existingEventStore);
- let newEventStore = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context, false, defIdMap, instanceIdMap);
- return expandRecurring(newEventStore, activeRange, context);
- }
- function transformRawEvents(rawEvents, eventSource, context) {
- let calEachTransform = context.options.eventDataTransform;
- let sourceEachTransform = eventSource ? eventSource.eventDataTransform : null;
- if (sourceEachTransform) {
- rawEvents = transformEachRawEvent(rawEvents, sourceEachTransform);
- }
- if (calEachTransform) {
- rawEvents = transformEachRawEvent(rawEvents, calEachTransform);
- }
- return rawEvents;
- }
- function transformEachRawEvent(rawEvents, func) {
- let refinedEvents;
- if (!func) {
- refinedEvents = rawEvents;
- }
- else {
- refinedEvents = [];
- for (let rawEvent of rawEvents) {
- let refinedEvent = func(rawEvent);
- if (refinedEvent) {
- refinedEvents.push(refinedEvent);
- }
- else if (refinedEvent == null) {
- refinedEvents.push(rawEvent);
- } // if a different falsy value, do nothing
- }
- }
- return refinedEvents;
- }
- function addEvent(eventStore, subset, expandRange, context) {
- if (expandRange) {
- subset = expandRecurring(subset, expandRange, context);
- }
- return mergeEventStores(eventStore, subset);
- }
- function rezoneEventStoreDates(eventStore, oldDateEnv, newDateEnv) {
- let { defs } = eventStore;
- let instances = mapHash(eventStore.instances, (instance) => {
- let def = defs[instance.defId];
- if (def.allDay) {
- return instance; // isn't dependent on timezone
- }
- return Object.assign(Object.assign({}, instance), { range: {
- start: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.start, instance.forcedStartTzo)),
- end: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.end, instance.forcedEndTzo)),
- }, forcedStartTzo: newDateEnv.canComputeOffset ? null : instance.forcedStartTzo, forcedEndTzo: newDateEnv.canComputeOffset ? null : instance.forcedEndTzo });
- });
- return { defs, instances };
- }
- function excludeEventsBySourceId(eventStore, sourceId) {
- return filterEventStoreDefs(eventStore, (eventDef) => eventDef.sourceId !== sourceId);
- }
- // QUESTION: why not just return instances? do a general object-property-exclusion util
- function excludeInstances(eventStore, removals) {
- return {
- defs: eventStore.defs,
- instances: filterHash(eventStore.instances, (instance) => !removals[instance.instanceId]),
- };
- }
- function buildPublicIdMaps(eventStore) {
- const { defs, instances } = eventStore;
- const defIdMap = {};
- const instanceIdMap = {};
- for (let defId in defs) {
- const def = defs[defId];
- const { publicId } = def;
- if (publicId) {
- defIdMap[publicId] = defId;
- }
- }
- for (let instanceId in instances) {
- const instance = instances[instanceId];
- const def = defs[instance.defId];
- const { publicId } = def;
- if (publicId) {
- instanceIdMap[publicId] = instanceId;
- }
- }
- return { defIdMap, instanceIdMap };
- }
-
// high-level segmenting-aware tester functions
// ------------------------------------------------------------------------------------------------------------------------
function isInteractionValid(interaction, dateProfile, context) {
@@ -6042,114 +6634,6 @@ var FullCalendar = (function (exports) {
return false;
}
- class JsonRequestError extends Error {
- constructor(message, response) {
- super(message);
- this.response = response;
- }
- }
- function requestJson(method, url, params) {
- method = method.toUpperCase();
- const fetchOptions = {
- method,
- };
- if (method === 'GET') {
- url += (url.indexOf('?') === -1 ? '?' : '&') +
- new URLSearchParams(params);
- }
- else {
- fetchOptions.body = new URLSearchParams(params);
- fetchOptions.headers = {
- 'Content-Type': 'application/x-www-form-urlencoded',
- };
- }
- return fetch(url, fetchOptions).then((fetchRes) => {
- if (fetchRes.ok) {
- return fetchRes.json().then((parsedResponse) => {
- return [parsedResponse, fetchRes];
- }, () => {
- throw new JsonRequestError('Failure parsing JSON', fetchRes);
- });
- }
- else {
- throw new JsonRequestError('Request failed', fetchRes);
- }
- });
- }
-
- class DelayedRunner {
- constructor(drainedOption) {
- this.drainedOption = drainedOption;
- this.isRunning = false;
- this.isDirty = false;
- this.pauseDepths = {};
- this.timeoutId = 0;
- }
- request(delay) {
- this.isDirty = true;
- if (!this.isPaused()) {
- this.clearTimeout();
- if (delay == null) {
- this.tryDrain();
- }
- else {
- this.timeoutId = setTimeout(// NOT OPTIMAL! TODO: look at debounce
- this.tryDrain.bind(this), delay);
- }
- }
- }
- pause(scope = '') {
- let { pauseDepths } = this;
- pauseDepths[scope] = (pauseDepths[scope] || 0) + 1;
- this.clearTimeout();
- }
- resume(scope = '', force) {
- let { pauseDepths } = this;
- if (scope in pauseDepths) {
- if (force) {
- delete pauseDepths[scope];
- }
- else {
- pauseDepths[scope] -= 1;
- let depth = pauseDepths[scope];
- if (depth <= 0) {
- delete pauseDepths[scope];
- }
- }
- this.tryDrain();
- }
- }
- isPaused() {
- return Object.keys(this.pauseDepths).length;
- }
- tryDrain() {
- if (!this.isRunning && !this.isPaused()) {
- this.isRunning = true;
- while (this.isDirty) {
- this.isDirty = false;
- this.drained(); // might set isDirty to true again
- }
- this.isRunning = false;
- }
- }
- clear() {
- this.clearTimeout();
- this.isDirty = false;
- this.pauseDepths = {};
- }
- clearTimeout() {
- if (this.timeoutId) {
- clearTimeout(this.timeoutId);
- this.timeoutId = 0;
- }
- }
- drained() {
- if (this.drainedOption) {
- this.drainedOption();
- }
- }
- }
-
const VISIBLE_HIDDEN_RE = /^(visible|hidden)$/;
class Scroller extends BaseComponent {
constructor() {
@@ -6966,461 +7450,6 @@ var FullCalendar = (function (exports) {
return seg0.eventRange.range.end > seg1.eventRange.range.end ? seg0 : seg1;
}
- class ViewContainer extends BaseComponent {
- render() {
- let { props, context } = this;
- let { options } = context;
- let renderProps = { view: context.viewApi };
- return (y(ContentContainer, Object.assign({}, props, { elTag: props.elTag || 'div', elClasses: [
- ...buildViewClassNames(props.viewSpec),
- ...(props.elClasses || []),
- ], renderProps: renderProps, classNameGenerator: options.viewClassNames, generatorName: undefined, didMount: options.viewDidMount, willUnmount: options.viewWillUnmount }), () => props.children));
- }
- }
- function buildViewClassNames(viewSpec) {
- return [
- `fc-${viewSpec.type}-view`,
- 'fc-view',
- ];
- }
-
- const EVENT_SOURCE_REFINERS = {
- id: String,
- defaultAllDay: Boolean,
- url: String,
- format: String,
- events: identity,
- eventDataTransform: identity,
- // for any network-related sources
- success: identity,
- failure: identity,
- };
- function parseEventSource(raw, context, refiners = buildEventSourceRefiners(context)) {
- let rawObj;
- if (typeof raw === 'string') {
- rawObj = { url: raw };
- }
- else if (typeof raw === 'function' || Array.isArray(raw)) {
- rawObj = { events: raw };
- }
- else if (typeof raw === 'object' && raw) { // not null
- rawObj = raw;
- }
- if (rawObj) {
- let { refined, extra } = refineProps(rawObj, refiners);
- let metaRes = buildEventSourceMeta(refined, context);
- if (metaRes) {
- return {
- _raw: raw,
- isFetching: false,
- latestFetchId: '',
- fetchRange: null,
- defaultAllDay: refined.defaultAllDay,
- eventDataTransform: refined.eventDataTransform,
- success: refined.success,
- failure: refined.failure,
- publicId: refined.id || '',
- sourceId: guid(),
- sourceDefId: metaRes.sourceDefId,
- meta: metaRes.meta,
- ui: createEventUi(refined, context),
- extendedProps: extra,
- };
- }
- }
- return null;
- }
- function buildEventSourceRefiners(context) {
- return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_SOURCE_REFINERS), context.pluginHooks.eventSourceRefiners);
- }
- function buildEventSourceMeta(raw, context) {
- let defs = context.pluginHooks.eventSourceDefs;
- for (let i = defs.length - 1; i >= 0; i -= 1) { // later-added plugins take precedence
- let def = defs[i];
- let meta = def.parseMeta(raw);
- if (meta) {
- return { sourceDefId: i, meta };
- }
- }
- return null;
- }
-
- class CalendarImpl {
- getCurrentData() {
- return this.currentDataManager.getCurrentData();
- }
- dispatch(action) {
- this.currentDataManager.dispatch(action);
- }
- get view() { return this.getCurrentData().viewApi; }
- batchRendering(callback) {
- callback();
- }
- updateSize() {
- this.trigger('_resize', true);
- }
- // Options
- // -----------------------------------------------------------------------------------------------------------------
- setOption(name, val) {
- this.dispatch({
- type: 'SET_OPTION',
- optionName: name,
- rawOptionValue: val,
- });
- }
- getOption(name) {
- return this.currentDataManager.currentCalendarOptionsInput[name];
- }
- getAvailableLocaleCodes() {
- return Object.keys(this.getCurrentData().availableRawLocales);
- }
- // Trigger
- // -----------------------------------------------------------------------------------------------------------------
- on(handlerName, handler) {
- let { currentDataManager } = this;
- if (currentDataManager.currentCalendarOptionsRefiners[handlerName]) {
- currentDataManager.emitter.on(handlerName, handler);
- }
- else {
- console.warn(`Unknown listener name '${handlerName}'`);
- }
- }
- off(handlerName, handler) {
- this.currentDataManager.emitter.off(handlerName, handler);
- }
- // not meant for public use
- trigger(handlerName, ...args) {
- this.currentDataManager.emitter.trigger(handlerName, ...args);
- }
- // View
- // -----------------------------------------------------------------------------------------------------------------
- changeView(viewType, dateOrRange) {
- this.batchRendering(() => {
- this.unselect();
- if (dateOrRange) {
- if (dateOrRange.start && dateOrRange.end) { // a range
- this.dispatch({
- type: 'CHANGE_VIEW_TYPE',
- viewType,
- });
- this.dispatch({
- type: 'SET_OPTION',
- optionName: 'visibleRange',
- rawOptionValue: dateOrRange,
- });
- }
- else {
- let { dateEnv } = this.getCurrentData();
- this.dispatch({
- type: 'CHANGE_VIEW_TYPE',
- viewType,
- dateMarker: dateEnv.createMarker(dateOrRange),
- });
- }
- }
- else {
- this.dispatch({
- type: 'CHANGE_VIEW_TYPE',
- viewType,
- });
- }
- });
- }
- // Forces navigation to a view for the given date.
- // `viewType` can be a specific view name or a generic one like "week" or "day".
- // needs to change
- zoomTo(dateMarker, viewType) {
- let state = this.getCurrentData();
- let spec;
- viewType = viewType || 'day'; // day is default zoom
- spec = state.viewSpecs[viewType] || this.getUnitViewSpec(viewType);
- this.unselect();
- if (spec) {
- this.dispatch({
- type: 'CHANGE_VIEW_TYPE',
- viewType: spec.type,
- dateMarker,
- });
- }
- else {
- this.dispatch({
- type: 'CHANGE_DATE',
- dateMarker,
- });
- }
- }
- // Given a duration singular unit, like "week" or "day", finds a matching view spec.
- // Preference is given to views that have corresponding buttons.
- getUnitViewSpec(unit) {
- let { viewSpecs, toolbarConfig } = this.getCurrentData();
- let viewTypes = [].concat(toolbarConfig.header ? toolbarConfig.header.viewsWithButtons : [], toolbarConfig.footer ? toolbarConfig.footer.viewsWithButtons : []);
- let i;
- let spec;
- for (let viewType in viewSpecs) {
- viewTypes.push(viewType);
- }
- for (i = 0; i < viewTypes.length; i += 1) {
- spec = viewSpecs[viewTypes[i]];
- if (spec) {
- if (spec.singleUnit === unit) {
- return spec;
- }
- }
- }
- return null;
- }
- // Current Date
- // -----------------------------------------------------------------------------------------------------------------
- prev() {
- this.unselect();
- this.dispatch({ type: 'PREV' });
- }
- next() {
- this.unselect();
- this.dispatch({ type: 'NEXT' });
- }
- prevYear() {
- let state = this.getCurrentData();
- this.unselect();
- this.dispatch({
- type: 'CHANGE_DATE',
- dateMarker: state.dateEnv.addYears(state.currentDate, -1),
- });
- }
- nextYear() {
- let state = this.getCurrentData();
- this.unselect();
- this.dispatch({
- type: 'CHANGE_DATE',
- dateMarker: state.dateEnv.addYears(state.currentDate, 1),
- });
- }
- today() {
- let state = this.getCurrentData();
- this.unselect();
- this.dispatch({
- type: 'CHANGE_DATE',
- dateMarker: getNow(state.calendarOptions.now, state.dateEnv),
- });
- }
- gotoDate(zonedDateInput) {
- let state = this.getCurrentData();
- this.unselect();
- this.dispatch({
- type: 'CHANGE_DATE',
- dateMarker: state.dateEnv.createMarker(zonedDateInput),
- });
- }
- incrementDate(deltaInput) {
- let state = this.getCurrentData();
- let delta = createDuration(deltaInput);
- if (delta) { // else, warn about invalid input?
- this.unselect();
- this.dispatch({
- type: 'CHANGE_DATE',
- dateMarker: state.dateEnv.add(state.currentDate, delta),
- });
- }
- }
- getDate() {
- let state = this.getCurrentData();
- return state.dateEnv.toDate(state.currentDate);
- }
- // Date Formatting Utils
- // -----------------------------------------------------------------------------------------------------------------
- formatDate(d, formatter) {
- let { dateEnv } = this.getCurrentData();
- return dateEnv.format(dateEnv.createMarker(d), createFormatter(formatter));
- }
- // `settings` is for formatter AND isEndExclusive
- formatRange(d0, d1, settings) {
- let { dateEnv } = this.getCurrentData();
- return dateEnv.formatRange(dateEnv.createMarker(d0), dateEnv.createMarker(d1), createFormatter(settings), settings);
- }
- formatIso(d, omitTime) {
- let { dateEnv } = this.getCurrentData();
- return dateEnv.formatIso(dateEnv.createMarker(d), { omitTime });
- }
- // Date Selection / Event Selection / DayClick
- // -----------------------------------------------------------------------------------------------------------------
- select(dateOrObj, endDate) {
- let selectionInput;
- if (endDate == null) {
- if (dateOrObj.start != null) {
- selectionInput = dateOrObj;
- }
- else {
- selectionInput = {
- start: dateOrObj,
- end: null,
- };
- }
- }
- else {
- selectionInput = {
- start: dateOrObj,
- end: endDate,
- };
- }
- let state = this.getCurrentData();
- let selection = parseDateSpan(selectionInput, state.dateEnv, createDuration({ days: 1 }));
- if (selection) { // throw parse error otherwise?
- this.dispatch({ type: 'SELECT_DATES', selection });
- triggerDateSelect(selection, null, state);
- }
- }
- unselect(pev) {
- let state = this.getCurrentData();
- if (state.dateSelection) {
- this.dispatch({ type: 'UNSELECT_DATES' });
- triggerDateUnselect(pev, state);
- }
- }
- // Public Events API
- // -----------------------------------------------------------------------------------------------------------------
- addEvent(eventInput, sourceInput) {
- if (eventInput instanceof EventImpl) {
- let def = eventInput._def;
- let instance = eventInput._instance;
- let currentData = this.getCurrentData();
- // not already present? don't want to add an old snapshot
- if (!currentData.eventStore.defs[def.defId]) {
- this.dispatch({
- type: 'ADD_EVENTS',
- eventStore: eventTupleToStore({ def, instance }), // TODO: better util for two args?
- });
- this.triggerEventAdd(eventInput);
- }
- return eventInput;
- }
- let state = this.getCurrentData();
- let eventSource;
- if (sourceInput instanceof EventSourceImpl) {
- eventSource = sourceInput.internalEventSource;
- }
- else if (typeof sourceInput === 'boolean') {
- if (sourceInput) { // true. part of the first event source
- [eventSource] = hashValuesToArray(state.eventSources);
- }
- }
- else if (sourceInput != null) { // an ID. accepts a number too
- let sourceApi = this.getEventSourceById(sourceInput); // TODO: use an internal function
- if (!sourceApi) {
- console.warn(`Could not find an event source with ID "${sourceInput}"`); // TODO: test
- return null;
- }
- eventSource = sourceApi.internalEventSource;
- }
- let tuple = parseEvent(eventInput, eventSource, state, false);
- if (tuple) {
- let newEventApi = new EventImpl(state, tuple.def, tuple.def.recurringDef ? null : tuple.instance);
- this.dispatch({
- type: 'ADD_EVENTS',
- eventStore: eventTupleToStore(tuple),
- });
- this.triggerEventAdd(newEventApi);
- return newEventApi;
- }
- return null;
- }
- triggerEventAdd(eventApi) {
- let { emitter } = this.getCurrentData();
- emitter.trigger('eventAdd', {
- event: eventApi,
- relatedEvents: [],
- revert: () => {
- this.dispatch({
- type: 'REMOVE_EVENTS',
- eventStore: eventApiToStore(eventApi),
- });
- },
- });
- }
- // TODO: optimize
- getEventById(id) {
- let state = this.getCurrentData();
- let { defs, instances } = state.eventStore;
- id = String(id);
- for (let defId in defs) {
- let def = defs[defId];
- if (def.publicId === id) {
- if (def.recurringDef) {
- return new EventImpl(state, def, null);
- }
- for (let instanceId in instances) {
- let instance = instances[instanceId];
- if (instance.defId === def.defId) {
- return new EventImpl(state, def, instance);
- }
- }
- }
- }
- return null;
- }
- getEvents() {
- let currentData = this.getCurrentData();
- return buildEventApis(currentData.eventStore, currentData);
- }
- removeAllEvents() {
- this.dispatch({ type: 'REMOVE_ALL_EVENTS' });
- }
- // Public Event Sources API
- // -----------------------------------------------------------------------------------------------------------------
- getEventSources() {
- let state = this.getCurrentData();
- let sourceHash = state.eventSources;
- let sourceApis = [];
- for (let internalId in sourceHash) {
- sourceApis.push(new EventSourceImpl(state, sourceHash[internalId]));
- }
- return sourceApis;
- }
- getEventSourceById(id) {
- let state = this.getCurrentData();
- let sourceHash = state.eventSources;
- id = String(id);
- for (let sourceId in sourceHash) {
- if (sourceHash[sourceId].publicId === id) {
- return new EventSourceImpl(state, sourceHash[sourceId]);
- }
- }
- return null;
- }
- addEventSource(sourceInput) {
- let state = this.getCurrentData();
- if (sourceInput instanceof EventSourceImpl) {
- // not already present? don't want to add an old snapshot
- if (!state.eventSources[sourceInput.internalEventSource.sourceId]) {
- this.dispatch({
- type: 'ADD_EVENT_SOURCES',
- sources: [sourceInput.internalEventSource],
- });
- }
- return sourceInput;
- }
- let eventSource = parseEventSource(sourceInput, state);
- if (eventSource) { // TODO: error otherwise?
- this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [eventSource] });
- return new EventSourceImpl(state, eventSource);
- }
- return null;
- }
- removeAllEventSources() {
- this.dispatch({ type: 'REMOVE_ALL_EVENT_SOURCES' });
- }
- refetchEvents() {
- this.dispatch({ type: 'FETCH_EVENT_SOURCES', isRefetch: true });
- }
- // Scroll
- // -----------------------------------------------------------------------------------------------------------------
- scrollToTime(timeInput) {
- let time = createDuration(timeInput);
- if (time) {
- this.trigger('_scrollRequest', { time });
- }
- }
- }
-
class Store {
constructor() {
this.handlers = [];
@@ -9316,7 +9345,7 @@ var FullCalendar = (function (exports) {
if (isPressed) {
buttonClasses.push(theme.getClass('buttonActive'));
}
- children.push(y("button", { type: "button", title: typeof buttonHint === 'function' ? buttonHint(props.navUnit) : buttonHint, disabled: isDisabled, "aria-pressed": isPressed, className: buttonClasses.join(' '), onClick: buttonClick }, buttonText || (buttonIcon ? y("span", { className: buttonIcon }) : '')));
+ children.push(y("button", { type: "button", title: typeof buttonHint === 'function' ? buttonHint(props.navUnit) : buttonHint, disabled: isDisabled, "aria-pressed": isPressed, className: buttonClasses.join(' '), onClick: buttonClick }, buttonText || (buttonIcon ? y("span", { className: buttonIcon, role: "img" }) : '')));
}
}
if (children.length > 1) {
@@ -9578,7 +9607,7 @@ var FullCalendar = (function (exports) {
let viewContext = this.buildViewContext(props.viewSpec, props.viewApi, props.options, props.dateProfileGenerator, props.dateEnv, props.theme, props.pluginHooks, props.dispatch, props.getCurrentData, props.emitter, props.calendarApi, this.registerInteractiveComponent, this.unregisterInteractiveComponent);
let viewLabelId = (toolbarConfig.header && toolbarConfig.header.hasTitle)
? this.state.viewLabelId
- : '';
+ : undefined;
return (y(ViewContextType.Provider, { value: viewContext },
toolbarConfig.header && (y(Toolbar, Object.assign({ ref: this.headerRef, extraClassName: "fc-header-toolbar", model: toolbarConfig.header, titleId: viewLabelId }, toolbarProps))),
y(ViewHarness, { liquid: viewVGrow, height: viewHeight, aspectRatio: viewAspectRatio, labeledById: viewLabelId },
@@ -9806,7 +9835,7 @@ var FullCalendar = (function (exports) {
return sliceEventStore(props.eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? props.nextDayThreshold : null).fg;
}
- const version = '6.1.8';
+ const version = '6.1.11';
config.touchMouseIgnoreWait = 500;
let ignoreMouseDepth = 0;
@@ -10183,6 +10212,7 @@ var FullCalendar = (function (exports) {
// we don't want long taps or any mouse interaction causing selection/menus.
// would use preventSelection(), but that prevents selectstart, causing problems.
mirrorEl.style.userSelect = 'none';
+ mirrorEl.style.webkitUserSelect = 'none';
mirrorEl.classList.add('fc-event-dragging');
applyStyle(mirrorEl, {
position: 'fixed',
@@ -11903,8 +11933,86 @@ var FullCalendar = (function (exports) {
listenerRefiners: LISTENER_REFINERS,
});
- var css_248z$3 = ":root{--fc-daygrid-event-dot-width:8px}.fc-daygrid-day-events:after,.fc-daygrid-day-events:before,.fc-daygrid-day-frame:after,.fc-daygrid-day-frame:before,.fc-daygrid-event-harness:after,.fc-daygrid-event-harness:before{clear:both;content:\"\";display:table}.fc .fc-daygrid-body{position:relative;z-index:1}.fc .fc-daygrid-day.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-daygrid-day-frame{min-height:100%;position:relative}.fc .fc-daygrid-day-top{display:flex;flex-direction:row-reverse}.fc .fc-day-other .fc-daygrid-day-top{opacity:.3}.fc .fc-daygrid-day-number{padding:4px;position:relative;z-index:4}.fc .fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc .fc-daygrid-day-events{margin-top:1px}.fc .fc-daygrid-body-balanced .fc-daygrid-day-events{left:0;position:absolute;right:0}.fc .fc-daygrid-body-unbalanced .fc-daygrid-day-events{min-height:2em;position:relative}.fc .fc-daygrid-body-natural .fc-daygrid-day-events{margin-bottom:1em}.fc .fc-daygrid-event-harness{position:relative}.fc .fc-daygrid-event-harness-abs{left:0;position:absolute;right:0;top:0}.fc .fc-daygrid-bg-harness{bottom:0;position:absolute;top:0}.fc .fc-daygrid-day-bg .fc-non-business{z-index:1}.fc .fc-daygrid-day-bg .fc-bg-event{z-index:2}.fc .fc-daygrid-day-bg .fc-highlight{z-index:3}.fc .fc-daygrid-event{margin-top:1px;z-index:6}.fc .fc-daygrid-event.fc-event-mirror{z-index:7}.fc .fc-daygrid-day-bottom{font-size:.85em;margin:0 2px}.fc .fc-daygrid-day-bottom:after,.fc .fc-daygrid-day-bottom:before{clear:both;content:\"\";display:table}.fc .fc-daygrid-more-link{border-radius:3px;cursor:pointer;line-height:1;margin-top:1px;max-width:100%;overflow:hidden;padding:2px;position:relative;white-space:nowrap;z-index:4}.fc .fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc .fc-daygrid-week-number{background-color:var(--fc-neutral-bg-color);color:var(--fc-neutral-text-color);min-width:1.5em;padding:2px;position:absolute;text-align:center;top:0;z-index:5}.fc .fc-more-popover .fc-popover-body{min-width:220px;padding:10px}.fc-direction-ltr .fc-daygrid-event.fc-event-start,.fc-direction-rtl .fc-daygrid-event.fc-event-end{margin-left:2px}.fc-direction-ltr .fc-daygrid-event.fc-event-end,.fc-direction-rtl .fc-daygrid-event.fc-event-start{margin-right:2px}.fc-direction-ltr .fc-daygrid-more-link{float:left}.fc-direction-ltr .fc-daygrid-week-number{border-radius:0 0 3px 0;left:0}.fc-direction-rtl .fc-daygrid-more-link{float:right}.fc-direction-rtl .fc-daygrid-week-number{border-radius:0 0 0 3px;right:0}.fc-liquid-hack .fc-daygrid-day-frame{position:static}.fc-daygrid-event{border-radius:3px;font-size:var(--fc-small-font-size);position:relative;white-space:nowrap}.fc-daygrid-block-event .fc-event-time{font-weight:700}.fc-daygrid-block-event .fc-event-time,.fc-daygrid-block-event .fc-event-title{padding:1px}.fc-daygrid-dot-event{align-items:center;display:flex;padding:2px 0}.fc-daygrid-dot-event .fc-event-title{flex-grow:1;flex-shrink:1;font-weight:700;min-width:0;overflow:hidden}.fc-daygrid-dot-event.fc-event-mirror,.fc-daygrid-dot-event:hover{background:rgba(0,0,0,.1)}.fc-daygrid-dot-event.fc-event-selected:before{bottom:-10px;top:-10px}.fc-daygrid-event-dot{border:calc(var(--fc-daygrid-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-daygrid-event-dot-width)/2);box-sizing:content-box;height:0;margin:0 4px;width:0}.fc-direction-ltr .fc-daygrid-event .fc-event-time{margin-right:3px}.fc-direction-rtl .fc-daygrid-event .fc-event-time{margin-left:3px}";
- injectStyles(css_248z$3);
+ /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells.
+ ----------------------------------------------------------------------------------------------------------------------*/
+ // It is a manager for a Table subcomponent, which does most of the heavy lifting.
+ // It is responsible for managing width/height.
+ class TableView extends DateComponent {
+ constructor() {
+ super(...arguments);
+ this.headerElRef = d();
+ }
+ renderSimpleLayout(headerRowContent, bodyContent) {
+ let { props, context } = this;
+ let sections = [];
+ let stickyHeaderDates = getStickyHeaderDates(context.options);
+ if (headerRowContent) {
+ sections.push({
+ type: 'header',
+ key: 'header',
+ isSticky: stickyHeaderDates,
+ chunk: {
+ elRef: this.headerElRef,
+ tableClassName: 'fc-col-header',
+ rowContent: headerRowContent,
+ },
+ });
+ }
+ sections.push({
+ type: 'body',
+ key: 'body',
+ liquid: true,
+ chunk: { content: bodyContent },
+ });
+ return (y(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
+ y(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections })));
+ }
+ renderHScrollLayout(headerRowContent, bodyContent, colCnt, dayMinWidth) {
+ let ScrollGrid = this.context.pluginHooks.scrollGridImpl;
+ if (!ScrollGrid) {
+ throw new Error('No ScrollGrid implementation');
+ }
+ let { props, context } = this;
+ let stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options);
+ let stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options);
+ let sections = [];
+ if (headerRowContent) {
+ sections.push({
+ type: 'header',
+ key: 'header',
+ isSticky: stickyHeaderDates,
+ chunks: [{
+ key: 'main',
+ elRef: this.headerElRef,
+ tableClassName: 'fc-col-header',
+ rowContent: headerRowContent,
+ }],
+ });
+ }
+ sections.push({
+ type: 'body',
+ key: 'body',
+ liquid: true,
+ chunks: [{
+ key: 'main',
+ content: bodyContent,
+ }],
+ });
+ if (stickyFooterScrollbar) {
+ sections.push({
+ type: 'footer',
+ key: 'footer',
+ isSticky: true,
+ chunks: [{
+ key: 'main',
+ content: renderScrollShim,
+ }],
+ });
+ }
+ return (y(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
+ y(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections })));
+ }
+ }
function splitSegsByRow(segs, rowCnt) {
let byRow = [];
@@ -12081,9 +12189,22 @@ var FullCalendar = (function (exports) {
(dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
}
+ function generateSegKey(seg) {
+ return seg.eventRange.instance.instanceId + ':' + seg.firstCol;
+ }
+ function generateSegUid(seg) {
+ return generateSegKey(seg) + ':' + seg.lastCol;
+ }
function computeFgSegPlacement(segs, // assumed already sorted
- dayMaxEvents, dayMaxEventRows, strictOrder, eventInstanceHeights, maxContentHeight, cells) {
- let hierarchy = new DayGridSegHierarchy();
+ dayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells) {
+ let hierarchy = new DayGridSegHierarchy((segEntry) => {
+ // TODO: more DRY with generateSegUid
+ let segUid = segs[segEntry.index].eventRange.instance.instanceId +
+ ':' + segEntry.span.start +
+ ':' + (segEntry.span.end - 1);
+ // if no thickness known, assume 1 (if 0, so small it always fits)
+ return segHeights[segUid] || 1;
+ });
hierarchy.allowReslicing = true;
hierarchy.strictOrder = strictOrder;
if (dayMaxEvents === true || dayMaxEventRows === true) {
@@ -12102,12 +12223,11 @@ var FullCalendar = (function (exports) {
let unknownHeightSegs = [];
for (let i = 0; i < segs.length; i += 1) {
let seg = segs[i];
- let { instanceId } = seg.eventRange.instance;
- let eventHeight = eventInstanceHeights[instanceId];
+ let segUid = generateSegUid(seg);
+ let eventHeight = segHeights[segUid];
if (eventHeight != null) {
segInputs.push({
index: i,
- thickness: eventHeight,
span: {
start: seg.firstCol,
end: seg.lastCol + 1,
@@ -12285,16 +12405,20 @@ var FullCalendar = (function (exports) {
handleInvalidInsertion(insertion, entry, hiddenEntries) {
const { entriesByLevel, forceHidden } = this;
const { touchingEntry, touchingLevel, touchingLateral } = insertion;
+ // the entry that the new insertion is touching must be hidden
if (this.hiddenConsumes && touchingEntry) {
const touchingEntryId = buildEntryKey(touchingEntry);
- // if not already hidden
if (!forceHidden[touchingEntryId]) {
if (this.allowReslicing) {
- const placeholderEntry = Object.assign(Object.assign({}, touchingEntry), { span: intersectSpans(touchingEntry.span, entry.span) });
- const placeholderEntryId = buildEntryKey(placeholderEntry);
- forceHidden[placeholderEntryId] = true;
- entriesByLevel[touchingLevel][touchingLateral] = placeholderEntry; // replace touchingEntry with our placeholder
- this.splitEntry(touchingEntry, entry, hiddenEntries); // split up the touchingEntry, reinsert it
+ // split up the touchingEntry, reinsert it
+ const hiddenEntry = Object.assign(Object.assign({}, touchingEntry), { span: intersectSpans(touchingEntry.span, entry.span) });
+ // reinsert the area that turned into a "more" link (so no other entries try to
+ // occupy the space) but mark it forced-hidden
+ const hiddenEntryId = buildEntryKey(hiddenEntry);
+ forceHidden[hiddenEntryId] = true;
+ entriesByLevel[touchingLevel][touchingLateral] = hiddenEntry;
+ hiddenEntries.push(hiddenEntry);
+ this.splitEntry(touchingEntry, entry, hiddenEntries);
}
else {
forceHidden[touchingEntryId] = true;
@@ -12302,7 +12426,8 @@ var FullCalendar = (function (exports) {
}
}
}
- return super.handleInvalidInsertion(insertion, entry, hiddenEntries);
+ // will try to reslice...
+ super.handleInvalidInsertion(insertion, entry, hiddenEntries);
}
}
@@ -12317,7 +12442,7 @@ var FullCalendar = (function (exports) {
this.state = {
framePositions: null,
maxContentHeight: null,
- eventInstanceHeights: {},
+ segHeights: {},
};
this.handleResize = (isForced) => {
if (isForced) {
@@ -12333,7 +12458,7 @@ var FullCalendar = (function (exports) {
let bgEventSegsByCol = splitSegsByFirstCol(props.bgEventSegs, colCnt);
let highlightSegsByCol = splitSegsByFirstCol(this.getHighlightSegs(), colCnt);
let mirrorSegsByCol = splitSegsByFirstCol(this.getMirrorSegs(), colCnt);
- let { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops } = computeFgSegPlacement(sortEventSegs(props.fgEventSegs, options.eventOrder), props.dayMaxEvents, props.dayMaxEventRows, options.eventOrderStrict, state.eventInstanceHeights, state.maxContentHeight, props.cells);
+ let { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops } = computeFgSegPlacement(sortEventSegs(props.fgEventSegs, options.eventOrder), props.dayMaxEvents, props.dayMaxEventRows, options.eventOrderStrict, state.segHeights, state.maxContentHeight, props.cells);
let isForcedInvisible = // TODO: messy way to compute this
(props.eventDrag && props.eventDrag.affectedInstances) ||
(props.eventResize && props.eventResize.affectedInstances) ||
@@ -12392,7 +12517,6 @@ var FullCalendar = (function (exports) {
for (let placement of segPlacements) {
let { seg } = placement;
let { instanceId } = seg.eventRange.instance;
- let key = instanceId + ':' + col;
let isVisible = placement.isVisible && !isForcedInvisible[instanceId];
let isAbsolute = placement.isAbsolute;
let left = '';
@@ -12411,7 +12535,7 @@ var FullCalendar = (function (exports) {
known bug: events that are force to be list-item but span multiple days still take up space in later columns
todo: in print view, for multi-day events, don't display title within non-start/end segs
*/
- nodes.push(y("div", { className: 'fc-daygrid-event-harness' + (isAbsolute ? ' fc-daygrid-event-harness-abs' : ''), key: key, ref: isMirror ? null : this.segHarnessRefs.createRef(key), style: {
+ nodes.push(y("div", { className: 'fc-daygrid-event-harness' + (isAbsolute ? ' fc-daygrid-event-harness-abs' : ''), key: generateSegKey(seg), ref: isMirror ? null : this.segHarnessRefs.createRef(generateSegUid(seg)), style: {
visibility: isVisible ? '' : 'hidden',
marginTop: isAbsolute ? '' : placement.marginTop,
top: isAbsolute ? placement.absoluteTop : '',
@@ -12462,28 +12586,27 @@ var FullCalendar = (function (exports) {
}
}
}
- const oldInstanceHeights = this.state.eventInstanceHeights;
- const newInstanceHeights = this.queryEventInstanceHeights();
+ const oldSegHeights = this.state.segHeights;
+ const newSegHeights = this.querySegHeights();
const limitByContentHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
this.safeSetState({
// HACK to prevent oscillations of events being shown/hidden from max-event-rows
// Essentially, once you compute an element's height, never null-out.
// TODO: always display all events, as visibility:hidden?
- eventInstanceHeights: Object.assign(Object.assign({}, oldInstanceHeights), newInstanceHeights),
+ segHeights: Object.assign(Object.assign({}, oldSegHeights), newSegHeights),
maxContentHeight: limitByContentHeight ? this.computeMaxContentHeight() : null,
});
}
}
- queryEventInstanceHeights() {
+ querySegHeights() {
let segElMap = this.segHarnessRefs.currentMap;
- let eventInstanceHeights = {};
+ let segHeights = {};
// get the max height amongst instance segs
- for (let key in segElMap) {
- let height = Math.round(segElMap[key].getBoundingClientRect().height);
- let instanceId = key.split(':')[0]; // deconstruct how renderFgSegs makes the key
- eventInstanceHeights[instanceId] = Math.max(eventInstanceHeights[instanceId] || 0, height);
+ for (let segUid in segElMap) {
+ let height = Math.round(segElMap[segUid].getBoundingClientRect().height);
+ segHeights[segUid] = Math.max(segHeights[segUid] || 0, height);
}
- return eventInstanceHeights;
+ return segHeights;
}
computeMaxContentHeight() {
let firstKey = this.props.cells[0].key;
@@ -12497,7 +12620,7 @@ var FullCalendar = (function (exports) {
}
}
TableRow.addStateEquality({
- eventInstanceHeights: isPropsEqual,
+ segHeights: isPropsEqual,
});
function buildMirrorPlacements(mirrorSegs, colPlacements) {
if (!mirrorSegs.length) {
@@ -12553,15 +12676,25 @@ var FullCalendar = (function (exports) {
, showDayNumbers: rowCnt > 1, showWeekNumbers: props.showWeekNumbers, todayRange: todayRange, dateProfile: props.dateProfile, cells: cells, renderIntro: props.renderRowIntro, businessHourSegs: businessHourSegsByRow[row], eventSelection: props.eventSelection, bgEventSegs: bgEventSegsByRow[row].filter(isSegAllDay) /* hack */, fgEventSegs: fgEventSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, clientWidth: props.clientWidth, clientHeight: props.clientHeight, cellMinHeight: cellMinHeight, forPrint: props.forPrint })))))));
}
componentDidMount() {
- // HACK: need a daygrid wrapper parent to do positioning
- // NOTE: a daygrid resource view w/o resources can have zero cells
- const firstCellEl = this.rowRefs.currentMap[0].getCellEls()[0];
- this.rootEl = firstCellEl ? firstCellEl.closest('.fc-daygrid-body') : null;
- if (this.rootEl) {
- this.context.registerInteractiveComponent(this, {
- el: this.rootEl,
- isHitComboAllowed: this.props.isHitComboAllowed,
- });
+ this.registerInteractiveComponent();
+ }
+ componentDidUpdate() {
+ // for if started with zero cells
+ this.registerInteractiveComponent();
+ }
+ registerInteractiveComponent() {
+ if (!this.rootEl) {
+ // HACK: need a daygrid wrapper parent to do positioning
+ // NOTE: a daygrid resource view w/o resources can have zero cells
+ const firstCellEl = this.rowRefs.currentMap[0].getCellEls()[0];
+ const rootEl = firstCellEl ? firstCellEl.closest('.fc-daygrid-body') : null;
+ if (rootEl) {
+ this.rootEl = rootEl;
+ this.context.registerInteractiveComponent(this, {
+ el: rootEl,
+ isHitComboAllowed: this.props.isHitComboAllowed,
+ });
+ }
}
}
componentWillUnmount() {
@@ -12716,6 +12849,30 @@ var FullCalendar = (function (exports) {
}
}
+ class DayTableView extends TableView {
+ constructor() {
+ super(...arguments);
+ this.buildDayTableModel = memoize(buildDayTableModel);
+ this.headerRef = d();
+ this.tableRef = d();
+ // can't override any lifecycle methods from parent
+ }
+ render() {
+ let { options, dateProfileGenerator } = this.context;
+ let { props } = this;
+ let dayTableModel = this.buildDayTableModel(props.dateProfile, dateProfileGenerator);
+ let headerContent = options.dayHeaders && (y(DayHeader, { ref: this.headerRef, dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: dayTableModel.rowCnt === 1 }));
+ let bodyContent = (contentArg) => (y(DayTable, { ref: this.tableRef, dateProfile: props.dateProfile, dayTableModel: dayTableModel, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, nextDayThreshold: options.nextDayThreshold, colGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows, showWeekNumbers: options.weekNumbers, expandRows: !props.isHeightAuto, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }));
+ return options.dayMinWidth
+ ? this.renderHScrollLayout(headerContent, bodyContent, dayTableModel.colCnt, options.dayMinWidth)
+ : this.renderSimpleLayout(headerContent, bodyContent);
+ }
+ }
+ function buildDayTableModel(dateProfile, dateProfileGenerator) {
+ let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
+ return new DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
+ }
+
class TableDateProfileGenerator extends DateProfileGenerator {
// Computes the date range that will be rendered
buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
@@ -12754,110 +12911,8 @@ var FullCalendar = (function (exports) {
return { start, end };
}
- /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells.
- ----------------------------------------------------------------------------------------------------------------------*/
- // It is a manager for a Table subcomponent, which does most of the heavy lifting.
- // It is responsible for managing width/height.
- class TableView extends DateComponent {
- constructor() {
- super(...arguments);
- this.headerElRef = d();
- }
- renderSimpleLayout(headerRowContent, bodyContent) {
- let { props, context } = this;
- let sections = [];
- let stickyHeaderDates = getStickyHeaderDates(context.options);
- if (headerRowContent) {
- sections.push({
- type: 'header',
- key: 'header',
- isSticky: stickyHeaderDates,
- chunk: {
- elRef: this.headerElRef,
- tableClassName: 'fc-col-header',
- rowContent: headerRowContent,
- },
- });
- }
- sections.push({
- type: 'body',
- key: 'body',
- liquid: true,
- chunk: { content: bodyContent },
- });
- return (y(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
- y(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections })));
- }
- renderHScrollLayout(headerRowContent, bodyContent, colCnt, dayMinWidth) {
- let ScrollGrid = this.context.pluginHooks.scrollGridImpl;
- if (!ScrollGrid) {
- throw new Error('No ScrollGrid implementation');
- }
- let { props, context } = this;
- let stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options);
- let stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options);
- let sections = [];
- if (headerRowContent) {
- sections.push({
- type: 'header',
- key: 'header',
- isSticky: stickyHeaderDates,
- chunks: [{
- key: 'main',
- elRef: this.headerElRef,
- tableClassName: 'fc-col-header',
- rowContent: headerRowContent,
- }],
- });
- }
- sections.push({
- type: 'body',
- key: 'body',
- liquid: true,
- chunks: [{
- key: 'main',
- content: bodyContent,
- }],
- });
- if (stickyFooterScrollbar) {
- sections.push({
- type: 'footer',
- key: 'footer',
- isSticky: true,
- chunks: [{
- key: 'main',
- content: renderScrollShim,
- }],
- });
- }
- return (y(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
- y(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections })));
- }
- }
-
- class DayTableView extends TableView {
- constructor() {
- super(...arguments);
- this.buildDayTableModel = memoize(buildDayTableModel);
- this.headerRef = d();
- this.tableRef = d();
- // can't override any lifecycle methods from parent
- }
- render() {
- let { options, dateProfileGenerator } = this.context;
- let { props } = this;
- let dayTableModel = this.buildDayTableModel(props.dateProfile, dateProfileGenerator);
- let headerContent = options.dayHeaders && (y(DayHeader, { ref: this.headerRef, dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: dayTableModel.rowCnt === 1 }));
- let bodyContent = (contentArg) => (y(DayTable, { ref: this.tableRef, dateProfile: props.dateProfile, dayTableModel: dayTableModel, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, nextDayThreshold: options.nextDayThreshold, colGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows, showWeekNumbers: options.weekNumbers, expandRows: !props.isHeightAuto, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }));
- return options.dayMinWidth
- ? this.renderHScrollLayout(headerContent, bodyContent, dayTableModel.colCnt, options.dayMinWidth)
- : this.renderSimpleLayout(headerContent, bodyContent);
- }
- }
- function buildDayTableModel(dateProfile, dateProfileGenerator) {
- let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
- return new DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
- }
+ var css_248z$3 = ":root{--fc-daygrid-event-dot-width:8px}.fc-daygrid-day-events:after,.fc-daygrid-day-events:before,.fc-daygrid-day-frame:after,.fc-daygrid-day-frame:before,.fc-daygrid-event-harness:after,.fc-daygrid-event-harness:before{clear:both;content:\"\";display:table}.fc .fc-daygrid-body{position:relative;z-index:1}.fc .fc-daygrid-day.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-daygrid-day-frame{min-height:100%;position:relative}.fc .fc-daygrid-day-top{display:flex;flex-direction:row-reverse}.fc .fc-day-other .fc-daygrid-day-top{opacity:.3}.fc .fc-daygrid-day-number{padding:4px;position:relative;z-index:4}.fc .fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc .fc-daygrid-day-events{margin-top:1px}.fc .fc-daygrid-body-balanced .fc-daygrid-day-events{left:0;position:absolute;right:0}.fc .fc-daygrid-body-unbalanced .fc-daygrid-day-events{min-height:2em;position:relative}.fc .fc-daygrid-body-natural .fc-daygrid-day-events{margin-bottom:1em}.fc .fc-daygrid-event-harness{position:relative}.fc .fc-daygrid-event-harness-abs{left:0;position:absolute;right:0;top:0}.fc .fc-daygrid-bg-harness{bottom:0;position:absolute;top:0}.fc .fc-daygrid-day-bg .fc-non-business{z-index:1}.fc .fc-daygrid-day-bg .fc-bg-event{z-index:2}.fc .fc-daygrid-day-bg .fc-highlight{z-index:3}.fc .fc-daygrid-event{margin-top:1px;z-index:6}.fc .fc-daygrid-event.fc-event-mirror{z-index:7}.fc .fc-daygrid-day-bottom{font-size:.85em;margin:0 2px}.fc .fc-daygrid-day-bottom:after,.fc .fc-daygrid-day-bottom:before{clear:both;content:\"\";display:table}.fc .fc-daygrid-more-link{border-radius:3px;cursor:pointer;line-height:1;margin-top:1px;max-width:100%;overflow:hidden;padding:2px;position:relative;white-space:nowrap;z-index:4}.fc .fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc .fc-daygrid-week-number{background-color:var(--fc-neutral-bg-color);color:var(--fc-neutral-text-color);min-width:1.5em;padding:2px;position:absolute;text-align:center;top:0;z-index:5}.fc .fc-more-popover .fc-popover-body{min-width:220px;padding:10px}.fc-direction-ltr .fc-daygrid-event.fc-event-start,.fc-direction-rtl .fc-daygrid-event.fc-event-end{margin-left:2px}.fc-direction-ltr .fc-daygrid-event.fc-event-end,.fc-direction-rtl .fc-daygrid-event.fc-event-start{margin-right:2px}.fc-direction-ltr .fc-daygrid-more-link{float:left}.fc-direction-ltr .fc-daygrid-week-number{border-radius:0 0 3px 0;left:0}.fc-direction-rtl .fc-daygrid-more-link{float:right}.fc-direction-rtl .fc-daygrid-week-number{border-radius:0 0 0 3px;right:0}.fc-liquid-hack .fc-daygrid-day-frame{position:static}.fc-daygrid-event{border-radius:3px;font-size:var(--fc-small-font-size);position:relative;white-space:nowrap}.fc-daygrid-block-event .fc-event-time{font-weight:700}.fc-daygrid-block-event .fc-event-time,.fc-daygrid-block-event .fc-event-title{padding:1px}.fc-daygrid-dot-event{align-items:center;display:flex;padding:2px 0}.fc-daygrid-dot-event .fc-event-title{flex-grow:1;flex-shrink:1;font-weight:700;min-width:0;overflow:hidden}.fc-daygrid-dot-event.fc-event-mirror,.fc-daygrid-dot-event:hover{background:rgba(0,0,0,.1)}.fc-daygrid-dot-event.fc-event-selected:before{bottom:-10px;top:-10px}.fc-daygrid-event-dot{border:calc(var(--fc-daygrid-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-daygrid-event-dot-width)/2);box-sizing:content-box;height:0;margin:0 4px;width:0}.fc-direction-ltr .fc-daygrid-event .fc-event-time{margin-right:3px}.fc-direction-rtl .fc-daygrid-event .fc-event-time{margin-left:3px}";
+ injectStyles(css_248z$3);
var index$3 = createPlugin({
name: '@fullcalendar/daygrid',
@@ -12887,9 +12942,6 @@ var FullCalendar = (function (exports) {
},
});
- var css_248z$2 = ".fc-v-event{background-color:var(--fc-event-bg-color);border:1px solid var(--fc-event-border-color);display:block}.fc-v-event .fc-event-main{color:var(--fc-event-text-color);height:100%}.fc-v-event .fc-event-main-frame{display:flex;flex-direction:column;height:100%}.fc-v-event .fc-event-time{flex-grow:0;flex-shrink:0;max-height:100%;overflow:hidden}.fc-v-event .fc-event-title-container{flex-grow:1;flex-shrink:1;min-height:0}.fc-v-event .fc-event-title{bottom:0;max-height:100%;overflow:hidden;top:0}.fc-v-event:not(.fc-event-start){border-top-left-radius:0;border-top-right-radius:0;border-top-width:0}.fc-v-event:not(.fc-event-end){border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-width:0}.fc-v-event.fc-event-selected:before{left:-10px;right:-10px}.fc-v-event .fc-event-resizer-start{cursor:n-resize}.fc-v-event .fc-event-resizer-end{cursor:s-resize}.fc-v-event:not(.fc-event-selected) .fc-event-resizer{height:var(--fc-event-resizer-thickness);left:0;right:0}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-start{top:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer{left:50%;margin-left:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-start{top:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc .fc-timegrid .fc-daygrid-body{z-index:2}.fc .fc-timegrid-divider{padding:0 0 2px}.fc .fc-timegrid-body{min-height:100%;position:relative;z-index:1}.fc .fc-timegrid-axis-chunk{position:relative}.fc .fc-timegrid-axis-chunk>table,.fc .fc-timegrid-slots{position:relative;z-index:1}.fc .fc-timegrid-slot{border-bottom:0;height:1.5em}.fc .fc-timegrid-slot:empty:before{content:\"\\00a0\"}.fc .fc-timegrid-slot-minor{border-top-style:dotted}.fc .fc-timegrid-slot-label-cushion{display:inline-block;white-space:nowrap}.fc .fc-timegrid-slot-label{vertical-align:middle}.fc .fc-timegrid-axis-cushion,.fc .fc-timegrid-slot-label-cushion{padding:0 4px}.fc .fc-timegrid-axis-frame-liquid{height:100%}.fc .fc-timegrid-axis-frame{align-items:center;display:flex;justify-content:flex-end;overflow:hidden}.fc .fc-timegrid-axis-cushion{flex-shrink:0;max-width:60px}.fc-direction-ltr .fc-timegrid-slot-label-frame{text-align:right}.fc-direction-rtl .fc-timegrid-slot-label-frame{text-align:left}.fc-liquid-hack .fc-timegrid-axis-frame-liquid{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-timegrid-col-frame{min-height:100%;position:relative}.fc-media-screen.fc-liquid-hack .fc-timegrid-col-frame{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols{bottom:0;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols>table{height:100%}.fc-media-screen .fc-timegrid-col-bg,.fc-media-screen .fc-timegrid-col-events,.fc-media-screen .fc-timegrid-now-indicator-container{left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col-bg{z-index:2}.fc .fc-timegrid-col-bg .fc-non-business{z-index:1}.fc .fc-timegrid-col-bg .fc-bg-event{z-index:2}.fc .fc-timegrid-col-bg .fc-highlight{z-index:3}.fc .fc-timegrid-bg-harness{left:0;position:absolute;right:0}.fc .fc-timegrid-col-events{z-index:3}.fc .fc-timegrid-now-indicator-container{bottom:0;overflow:hidden}.fc-direction-ltr .fc-timegrid-col-events{margin:0 2.5% 0 2px}.fc-direction-rtl .fc-timegrid-col-events{margin:0 2px 0 2.5%}.fc-timegrid-event-harness{position:absolute}.fc-timegrid-event-harness>.fc-timegrid-event{bottom:0;left:0;position:absolute;right:0;top:0}.fc-timegrid-event-harness-inset .fc-timegrid-event,.fc-timegrid-event.fc-event-mirror,.fc-timegrid-more-link{box-shadow:0 0 0 1px var(--fc-page-bg-color)}.fc-timegrid-event,.fc-timegrid-more-link{border-radius:3px;font-size:var(--fc-small-font-size)}.fc-timegrid-event{margin-bottom:1px}.fc-timegrid-event .fc-event-main{padding:1px 1px 0}.fc-timegrid-event .fc-event-time{font-size:var(--fc-small-font-size);margin-bottom:1px;white-space:nowrap}.fc-timegrid-event-short .fc-event-main-frame{flex-direction:row;overflow:hidden}.fc-timegrid-event-short .fc-event-time:after{content:\"\\00a0-\\00a0\"}.fc-timegrid-event-short .fc-event-title{font-size:var(--fc-small-font-size)}.fc-timegrid-more-link{background:var(--fc-more-link-bg-color);color:var(--fc-more-link-text-color);cursor:pointer;margin-bottom:1px;position:absolute;z-index:9999}.fc-timegrid-more-link-inner{padding:3px 2px;top:0}.fc-direction-ltr .fc-timegrid-more-link{right:0}.fc-direction-rtl .fc-timegrid-more-link{left:0}.fc .fc-timegrid-now-indicator-line{border-color:var(--fc-now-indicator-color);border-style:solid;border-width:1px 0 0;left:0;position:absolute;right:0;z-index:4}.fc .fc-timegrid-now-indicator-arrow{border-color:var(--fc-now-indicator-color);border-style:solid;margin-top:-5px;position:absolute;z-index:4}.fc-direction-ltr .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 0 5px 6px;left:0}.fc-direction-rtl .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 6px 5px 0;right:0}";
- injectStyles(css_248z$2);
-
class AllDaySplitter extends Splitter {
getKeyInfo() {
return {
@@ -14027,6 +14079,9 @@ var FullCalendar = (function (exports) {
return new DayTableModel(daySeries, false);
}
+ var css_248z$2 = ".fc-v-event{background-color:var(--fc-event-bg-color);border:1px solid var(--fc-event-border-color);display:block}.fc-v-event .fc-event-main{color:var(--fc-event-text-color);height:100%}.fc-v-event .fc-event-main-frame{display:flex;flex-direction:column;height:100%}.fc-v-event .fc-event-time{flex-grow:0;flex-shrink:0;max-height:100%;overflow:hidden}.fc-v-event .fc-event-title-container{flex-grow:1;flex-shrink:1;min-height:0}.fc-v-event .fc-event-title{bottom:0;max-height:100%;overflow:hidden;top:0}.fc-v-event:not(.fc-event-start){border-top-left-radius:0;border-top-right-radius:0;border-top-width:0}.fc-v-event:not(.fc-event-end){border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-width:0}.fc-v-event.fc-event-selected:before{left:-10px;right:-10px}.fc-v-event .fc-event-resizer-start{cursor:n-resize}.fc-v-event .fc-event-resizer-end{cursor:s-resize}.fc-v-event:not(.fc-event-selected) .fc-event-resizer{height:var(--fc-event-resizer-thickness);left:0;right:0}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-start{top:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer{left:50%;margin-left:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-start{top:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc .fc-timegrid .fc-daygrid-body{z-index:2}.fc .fc-timegrid-divider{padding:0 0 2px}.fc .fc-timegrid-body{min-height:100%;position:relative;z-index:1}.fc .fc-timegrid-axis-chunk{position:relative}.fc .fc-timegrid-axis-chunk>table,.fc .fc-timegrid-slots{position:relative;z-index:1}.fc .fc-timegrid-slot{border-bottom:0;height:1.5em}.fc .fc-timegrid-slot:empty:before{content:\"\\00a0\"}.fc .fc-timegrid-slot-minor{border-top-style:dotted}.fc .fc-timegrid-slot-label-cushion{display:inline-block;white-space:nowrap}.fc .fc-timegrid-slot-label{vertical-align:middle}.fc .fc-timegrid-axis-cushion,.fc .fc-timegrid-slot-label-cushion{padding:0 4px}.fc .fc-timegrid-axis-frame-liquid{height:100%}.fc .fc-timegrid-axis-frame{align-items:center;display:flex;justify-content:flex-end;overflow:hidden}.fc .fc-timegrid-axis-cushion{flex-shrink:0;max-width:60px}.fc-direction-ltr .fc-timegrid-slot-label-frame{text-align:right}.fc-direction-rtl .fc-timegrid-slot-label-frame{text-align:left}.fc-liquid-hack .fc-timegrid-axis-frame-liquid{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-timegrid-col-frame{min-height:100%;position:relative}.fc-media-screen.fc-liquid-hack .fc-timegrid-col-frame{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols{bottom:0;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols>table{height:100%}.fc-media-screen .fc-timegrid-col-bg,.fc-media-screen .fc-timegrid-col-events,.fc-media-screen .fc-timegrid-now-indicator-container{left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col-bg{z-index:2}.fc .fc-timegrid-col-bg .fc-non-business{z-index:1}.fc .fc-timegrid-col-bg .fc-bg-event{z-index:2}.fc .fc-timegrid-col-bg .fc-highlight{z-index:3}.fc .fc-timegrid-bg-harness{left:0;position:absolute;right:0}.fc .fc-timegrid-col-events{z-index:3}.fc .fc-timegrid-now-indicator-container{bottom:0;overflow:hidden}.fc-direction-ltr .fc-timegrid-col-events{margin:0 2.5% 0 2px}.fc-direction-rtl .fc-timegrid-col-events{margin:0 2px 0 2.5%}.fc-timegrid-event-harness{position:absolute}.fc-timegrid-event-harness>.fc-timegrid-event{bottom:0;left:0;position:absolute;right:0;top:0}.fc-timegrid-event-harness-inset .fc-timegrid-event,.fc-timegrid-event.fc-event-mirror,.fc-timegrid-more-link{box-shadow:0 0 0 1px var(--fc-page-bg-color)}.fc-timegrid-event,.fc-timegrid-more-link{border-radius:3px;font-size:var(--fc-small-font-size)}.fc-timegrid-event{margin-bottom:1px}.fc-timegrid-event .fc-event-main{padding:1px 1px 0}.fc-timegrid-event .fc-event-time{font-size:var(--fc-small-font-size);margin-bottom:1px;white-space:nowrap}.fc-timegrid-event-short .fc-event-main-frame{flex-direction:row;overflow:hidden}.fc-timegrid-event-short .fc-event-time:after{content:\"\\00a0-\\00a0\"}.fc-timegrid-event-short .fc-event-title{font-size:var(--fc-small-font-size)}.fc-timegrid-more-link{background:var(--fc-more-link-bg-color);color:var(--fc-more-link-text-color);cursor:pointer;margin-bottom:1px;position:absolute;z-index:9999}.fc-timegrid-more-link-inner{padding:3px 2px;top:0}.fc-direction-ltr .fc-timegrid-more-link{right:0}.fc-direction-rtl .fc-timegrid-more-link{left:0}.fc .fc-timegrid-now-indicator-line{border-color:var(--fc-now-indicator-color);border-style:solid;border-width:1px 0 0;left:0;position:absolute;right:0;z-index:4}.fc .fc-timegrid-now-indicator-arrow{border-color:var(--fc-now-indicator-color);border-style:solid;margin-top:-5px;position:absolute;z-index:4}.fc-direction-ltr .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 0 5px 6px;left:0}.fc-direction-rtl .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 6px 5px 0;right:0}";
+ injectStyles(css_248z$2);
+
const OPTION_REFINERS$2 = {
allDaySlot: Boolean,
};
@@ -14054,9 +14109,6 @@ var FullCalendar = (function (exports) {
},
});
- var css_248z$1 = ":root{--fc-list-event-dot-width:10px;--fc-list-event-hover-bg-color:#f5f5f5}.fc-theme-standard .fc-list{border:1px solid var(--fc-border-color)}.fc .fc-list-empty{align-items:center;background-color:var(--fc-neutral-bg-color);display:flex;height:100%;justify-content:center}.fc .fc-list-empty-cushion{margin:5em 0}.fc .fc-list-table{border-style:hidden;width:100%}.fc .fc-list-table tr>*{border-left:0;border-right:0}.fc .fc-list-sticky .fc-list-day>*{background:var(--fc-page-bg-color);position:sticky;top:0}.fc .fc-list-table thead{left:-10000px;position:absolute}.fc .fc-list-table tbody>tr:first-child th{border-top:0}.fc .fc-list-table th{padding:0}.fc .fc-list-day-cushion,.fc .fc-list-table td{padding:8px 14px}.fc .fc-list-day-cushion:after{clear:both;content:\"\";display:table}.fc-theme-standard .fc-list-day-cushion{background-color:var(--fc-neutral-bg-color)}.fc-direction-ltr .fc-list-day-text,.fc-direction-rtl .fc-list-day-side-text{float:left}.fc-direction-ltr .fc-list-day-side-text,.fc-direction-rtl .fc-list-day-text{float:right}.fc-direction-ltr .fc-list-table .fc-list-event-graphic{padding-right:0}.fc-direction-rtl .fc-list-table .fc-list-event-graphic{padding-left:0}.fc .fc-list-event.fc-event-forced-url{cursor:pointer}.fc .fc-list-event:hover td{background-color:var(--fc-list-event-hover-bg-color)}.fc .fc-list-event-graphic,.fc .fc-list-event-time{white-space:nowrap;width:1px}.fc .fc-list-event-dot{border:calc(var(--fc-list-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-list-event-dot-width)/2);box-sizing:content-box;display:inline-block;height:0;width:0}.fc .fc-list-event-title a{color:inherit;text-decoration:none}.fc .fc-list-event.fc-event-forced-url:hover a{text-decoration:underline}";
- injectStyles(css_248z$1);
-
class ListViewHeaderRow extends BaseComponent {
constructor() {
super(...arguments);
@@ -14317,6 +14369,9 @@ var FullCalendar = (function (exports) {
return segsByDay;
}
+ var css_248z$1 = ":root{--fc-list-event-dot-width:10px;--fc-list-event-hover-bg-color:#f5f5f5}.fc-theme-standard .fc-list{border:1px solid var(--fc-border-color)}.fc .fc-list-empty{align-items:center;background-color:var(--fc-neutral-bg-color);display:flex;height:100%;justify-content:center}.fc .fc-list-empty-cushion{margin:5em 0}.fc .fc-list-table{border-style:hidden;width:100%}.fc .fc-list-table tr>*{border-left:0;border-right:0}.fc .fc-list-sticky .fc-list-day>*{background:var(--fc-page-bg-color);position:sticky;top:0}.fc .fc-list-table thead{left:-10000px;position:absolute}.fc .fc-list-table tbody>tr:first-child th{border-top:0}.fc .fc-list-table th{padding:0}.fc .fc-list-day-cushion,.fc .fc-list-table td{padding:8px 14px}.fc .fc-list-day-cushion:after{clear:both;content:\"\";display:table}.fc-theme-standard .fc-list-day-cushion{background-color:var(--fc-neutral-bg-color)}.fc-direction-ltr .fc-list-day-text,.fc-direction-rtl .fc-list-day-side-text{float:left}.fc-direction-ltr .fc-list-day-side-text,.fc-direction-rtl .fc-list-day-text{float:right}.fc-direction-ltr .fc-list-table .fc-list-event-graphic{padding-right:0}.fc-direction-rtl .fc-list-table .fc-list-event-graphic{padding-left:0}.fc .fc-list-event.fc-event-forced-url{cursor:pointer}.fc .fc-list-event:hover td{background-color:var(--fc-list-event-hover-bg-color)}.fc .fc-list-event-graphic,.fc .fc-list-event-time{white-space:nowrap;width:1px}.fc .fc-list-event-dot{border:calc(var(--fc-list-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-list-event-dot-width)/2);box-sizing:content-box;display:inline-block;height:0;width:0}.fc .fc-list-event-title a{color:inherit;text-decoration:none}.fc .fc-list-event.fc-event-forced-url:hover a{text-decoration:underline}";
+ injectStyles(css_248z$1);
+
const OPTION_REFINERS$1 = {
listDayFormat: createFalsableFormatter,
listDaySideFormat: createFalsableFormatter,