PageSourceSearch

https://jf-evoramonte.pt/plugins/fullcalendar-6.1.10/lib/index.global.js

js jf-evoramonte.pt collected 2026-10-03 18:56:13 UTC 692,008 bytes, 14,664 lines download raw bytes

vendor: 20,669 bytes, lines 1-80
1/*!
2FullCalendar Standard Bundle v6.1.10
3Docs & License: https://fullcalendar.io/docs/initialize-globals
4(c) 2023 Adam Shaw
5*/
6var FullCalendar = (function (exports) {
7    'use strict';
8
9    var n,l$1,u$1,i$1,t,r$1,o,f$1,e$1,c$1={},s=[],a$1=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function h(n,l){for(var u in l)n[u]=l[u];return n}function v$1(n){var l=n.parentNode;l&&l.removeChild(n);}function y(l,u,i){var t,r,o,f={};for(o in u)"key"==o?t=u[o]:"ref"==o?r=u[o]:f[o]=u[o];if(arguments.length>2&&(f.children=arguments.length>3?n.call(arguments,2):i),"function"==typeof l&&null!=l.defaultProps)for(o in l.defaultProps)void 0===f[o]&&(f[o]=l.defaultProps[o]);return p(l,f,t,r,null)}function p(n,i,t,r,o){var f={type:n,props:i,key:t,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++u$1:o};return null==o&&null!=l$1.vnode&&l$1.vnode(f),f}function d(){return {current:null}}function _(n){return n.children}function k$1(n,l,u,i,t){var r;for(r in u)"children"===r||"key"===r||r in l||g$2(n,r,null,u[r],i);for(r in l)t&&"function"!=typeof l[r]||"children"===r||"key"===r||"value"===r||"checked"===r||u[r]===l[r]||g$2(n,r,l[r],u[r],i);}function b$1(n,l,u){"-"===l[0]?n.setProperty(l,null==u?"":u):n[l]=null==u?"":"number"!=typeof u||a$1.test(l)?u:u+"px";}function g$2(n,l,u,i,t){var r;n:if("style"===l)if("string"==typeof u)n.style.cssText=u;else {if("string"==typeof i&&(n.style.cssText=i=""),i)for(l in i)u&&l in u||b$1(n.style,l,"");if(u)for(l in u)i&&u[l]===i[l]||b$1(n.style,l,u[l]);}else if("o"===l[0]&&"n"===l[1])r=l!==(l=l.replace(/Capture$/,"")),l=l.toLowerCase()in n?l.toLowerCase().slice(2):l.slice(2),n.l||(n.l={}),n.l[l+r]=u,u?i||n.addEventListener(l,r?w$2:m$1,r):n.removeEventListener(l,r?w$2:m$1,r);else if("dangerouslySetInnerHTML"!==l){if(t)l=l.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!==l&&"height"!==l&&"href"!==l&&"list"!==l&&"form"!==l&&"tabIndex"!==l&&"download"!==l&&l in n)try{n[l]=null==u?"":u;break n}catch(n){}"function"==typeof u||(null==u||!1===u&&-1==l.indexOf("-")?n.removeAttribute(l):n.setAttribute(l,u));}}function m$1(n){t=!0;try{return this.l[n.type+!1](l$1.event?l$1.event(n):n)}finally{t=!1;}}function w$2(n){t=!0;try{return this.l[n.type+!0](l$1.event?l$1.event(n):n)}finally{t=!1;}}function x$1(n,l){this.props=n,this.context=l;}function A(n,l){if(null==l)return n.__?A(n.__,n.__.__k.indexOf(n)+1):null;for(var u;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e)return u.__e;return "function"==typeof n.type?A(n):null}function P$1(n){var l,u;if(null!=(n=n.__)&&null!=n.__c){for(n.__e=n.__c.base=null,l=0;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e){n.__e=n.__c.base=u.__e;break}return P$1(n)}}function C$1(n){t?setTimeout(n):f$1(n);}function T$1(n){(!n.__d&&(n.__d=!0)&&r$1.push(n)&&!$$1.__r++||o!==l$1.debounceRendering)&&((o=l$1.debounceRendering)||C$1)($$1);}function $$1(){var n,l,u,i,t,o,f,e;for(r$1.sort(function(n,l){return n.__v.__b-l.__v.__b});n=r$1.shift();)n.__d&&(l=r$1.length,i=void 0,t=void 0,f=(o=(u=n).__v).__e,(e=u.__P)&&(i=[],(t=h({},o)).__v=o.__v+1,M(e,o,t,u.__n,void 0!==e.ownerSVGElement,null!=o.__h?[f]:null,i,null==f?A(o):f,o.__h),N(i,o),o.__e!=f&&P$1(o)),r$1.length>l&&r$1.sort(function(n,l){return n.__v.__b-l.__v.__b}));$$1.__r=0;}function H$1(n,l,u,i,t,r,o,f,e,a){var h,v,y,d,k,b,g,m=i&&i.__k||s,w=m.length;for(u.__k=[],h=0;h<l.length;h++)if(null!=(d=u.__k[h]=null==(d=l[h])||"boolean"==typeof d?null:"string"==typeof d||"number"==typeof d||"bigint"==typeof d?p(null,d,null,null,d):Array.isArray(d)?p(_,{children:d},null,null,null):d.__b>0?p(d.type,d.props,d.key,d.ref?d.ref:null,d.__v):d)){if(d.__=u,d.__b=u.__b+1,null===(y=m[h])||y&&d.key==y.key&&d.type===y.type)m[h]=void 0;else for(v=0;v<w;v++){if((y=m[v])&&d.key==y.key&&d.type===y.type){m[v]=void 0;break}y=null;}M(n,d,y=y||c$1,t,r,o,f,e,a),k=d.__e,(v=d.ref)&&y.ref!=v&&(g||(g=[]),y.ref&&g.push(y.ref,null,d),g.push(v,d.__c||k,d)),null!=k?(null==b&&(b=k),"function"==typeof d.type&&d.__k===y.__k?d.__d=e=I$1(d,e,n):e=z$1(n,d,y,m,k,e),"function"==typeof u.type&&(u.__d=e)):e&&y.__e==e&&e.parentNode!=n&&(e=A(y));}for(u.__e=b,h=w;h--;)null!=m[h]&&("function"==typeof u.type&&null!=m[h].__e&&m[h].__e==u.__d&&(u.__d=L$1(i).nextSibling),q(m[h],m[h]));if(g)for(h=0;h<g.length;h++)S(g[h],g[++h],g[++h]);}function I$1(n,l,u){for(var i,t=n.__k,r=0;t&&r<t.length;r++)(i=t[r])&&(i.__=n,l="function"==typeof i.type?I$1(i,l,u):z$1(u,i,i,t,i.__e,l));return l}function j$2(n,l){return l=l||[],null==n||"boolean"==typeof n||(Array.isArray(n)?n.some(function(n){j$2(n,l);}):l.push(n)),l}function z$1(n,l,u,i,t,r){var o,f,e;if(void 0!==l.__d)o=l.__d,l.__d=void 0;else if(null==u||t!=r||null==t.parentNode)n:if(null==r||r.parentNode!==n)n.appendChild(t),o=null;else {for(f=r,e=0;(f=f.nextSibling)&&e<i.length;e+=1)if(f==t)break n;n.insertBefore(t,r),o=r;}return void 0!==o?o:t.nextSibling}function L$1(n){var l,u,i;if(null==n.type||"string"==typeof n.type)return n.__e;if(n.__k)for(l=n.__k.length-1;l>=0;l--)if((u=n.__k[l])&&(i=L$1(u)))return i;return null}function M(n,u,i,t,r,o,f,e,c){var s,a,v,y,p,d,k,b,g,m,w,A,P,C,T,$=u.type;if(void 0!==u.constructor)return null;null!=i.__h&&(c=i.__h,e=u.__e=i.__e,u.__h=null,o=[e]),(s=l$1.__b)&&s(u);try{n:if("function"==typeof $){if(b=u.props,g=(s=$.contextType)&&t[s.__c],m=s?g?g.props.value:s.__:t,i.__c?k=(a=u.__c=i.__c).__=a.__E:("prototype"in $&&$.prototype.render?u.__c=a=new $(b,m):(u.__c=a=new x$1(b,m),a.constructor=$,a.render=B$1),g&&g.sub(a),a.props=b,a.state||(a.state={}),a.context=m,a.__n=t,v=a.__d=!0,a.__h=[],a._sb=[]),null==a.__s&&(a.__s=a.state),null!=$.getDerivedStateFromProps&&(a.__s==a.state&&(a.__s=h({},a.__s)),h(a.__s,$.getDerivedStateFromProps(b,a.__s))),y=a.props,p=a.state,a.__v=u,v)null==$.getDerivedStateFromProps&&null!=a.componentWillMount&&a.componentWillMount(),null!=a.componentDidMount&&a.__h.push(a.componentDidMount);else {if(null==$.getDerivedStateFromProps&&b!==y&&null!=a.componentWillReceiveProps&&a.componentWillReceiveProps(b,m),!a.__e&&null!=a.shouldComponentUpdate&&!1===a.shouldComponentUpdate(b,a.__s,m)||u.__v===i.__v){for(u.__v!==i.__v&&(a.props=b,a.state=a.__s,a.__d=!1),u.__e=i.__e,u.__k=i.__k,u.__k.forEach(function(n){n&&(n.__=u);}),w=0;w<a._sb.length;w++)a.__h.push(a._sb[w]);a._sb=[],a.__h.length&&f.push(a);break n}null!=a.componentWillUpdate&&a.componentWillUpdate(b,a.__s,m),null!=a.componentDidUpdate&&a.__h.push(function(){a.componentDidUpdate(y,p,d);});}if(a.context=m,a.props=b,a.__P=n,A=l$1.__r,P=0,"prototype"in $&&$.prototype.render){for(a.state=a.__s,a.__d=!1,A&&A(u),s=a.render(a.props,a.state,a.context),C=0;C<a._sb.length;C++)a.__h.push(a._sb[C]);a._sb=[];}else do{a.__d=!1,A&&A(u),s=a.render(a.props,a.state,a.context),a.state=a.__s;}while(a.__d&&++P<25);a.state=a.__s,null!=a.getChildContext&&(t=h(h({},t),a.getChildContext())),v||null==a.getSnapshotBeforeUpdate||(d=a.getSnapshotBeforeUpdate(y,p)),T=null!=s&&s.type===_&&null==s.key?s.props.children:s,H$1(n,Array.isArray(T)?T:[T],u,i,t,r,o,f,e,c),a.base=u.__e,u.__h=null,a.__h.length&&f.push(a),k&&(a.__E=a.__=null),a.__e=!1;}else null==o&&u.__v===i.__v?(u.__k=i.__k,u.__e=i.__e):u.__e=O(i.__e,u,i,t,r,o,f,c);(s=l$1.diffed)&&s(u);}catch(n){u.__v=null,(c||null!=o)&&(u.__e=e,u.__h=!!c,o[o.indexOf(e)]=null),l$1.__e(n,u,i);}}function N(n,u){l$1.__c&&l$1.__c(u,n),n.some(function(u){try{n=u.__h,u.__h=[],n.some(function(n){n.call(u);});}catch(n){l$1.__e(n,u.__v);}});}function O(l,u,i,t,r,o,f,e){var s,a,h,y=i.props,p=u.props,d=u.type,_=0;if("svg"===d&&(r=!0),null!=o)for(;_<o.length;_++)if((s=o[_])&&"setAttribute"in s==!!d&&(d?s.localName===d:3===s.nodeType)){l=s,o[_]=null;break}if(null==l){if(null===d)return document.createTextNode(p);l=r?document.createElementNS("http://www.w3.org/2000/svg",d):document.createElement(d,p.is&&p),o=null,e=!1;}if(null===d)y===p||e&&l.data===p||(l.data=p);else {if(o=o&&n.call(l.childNodes),a=(y=i.props||c$1).dangerouslySetInnerHTML,h=p.dangerouslySetInnerHTML,!e){if(null!=o)for(y={},_=0;_<l.attributes.length;_++)y[l.attributes[_].name]=l.attributes[_].value;(h||a)&&(h&&(a&&h.__html==a.__html||h.__html===l.innerHTML)||(l.innerHTML=h&&h.__html||""));}if(k$1(l,p,y,r,e),h)u.__k=[];else if(_=u.props.children,H$1(l,Array.isArray(_)?_:[_],u,i,t,r&&"foreignObject"!==d,o,f,o?o[0]:i.__k&&A(i,0),e),null!=o)for(_=o.length;_--;)null!=o[_]&&v$1(o[_]);e||("value"in p&&void 0!==(_=p.value)&&(_!==l.value||"progress"===d&&!_||"option"===d&&_!==y.value)&&g$2(l,"value",_,y.value,!1),"checked"in p&&void 0!==(_=p.checked)&&_!==l.checked&&g$2(l,"checked",_,y.checked,!1));}return l}function S(n,u,i){try{"function"==typeof n?n(u):n.current=u;}catch(n){l$1.__e(n,i);}}function q(n,u,i){var t,r;if(l$1.unmount&&l$1.unmount(n),(t=n.ref)&&(t.current&&t.current!==n.__e||S(t,null,u)),null!=(t=n.__c)){if(t.componentWillUnmount)try{t.componentWillUnmount();}catch(n){l$1.__e(n,u);}t.base=t.__P=null,n.__c=void 0;}if(t=n.__k)for(r=0;r<t.length;r++)t[r]&&q(t[r],u,i||"function"!=typeof n.type);i||null==n.__e||v$1(n.__e),n.__=n.__e=n.__d=void 0;}function B$1(n,l,u){return this.constructor(n,u)}function D$1(u,i,t){var r,o,f;l$1.__&&l$1.__(u,i),o=(r="function"==typeof t)?null:t&&t.__k||i.__k,f=[],M(i,u=(!r&&t||i).__k=y(_,null,[u]),o||c$1,c$1,void 0!==i.ownerSVGElement,!r&&t?[t]:o?null:i.firstChild?n.call(i.childNodes):null,f,!r&&t?t:o?o.__e:i.firstChild,r),N(f,u);}function E(n,l){D$1(n,l,E);}function F$1(l,u,i){var t,r,o,f=h({},l.props);for(o in u)"key"==o?t=u[o]:"ref"==o?r=u[o]:f[o]=u[o];return arguments.length>2&&(f.children=arguments.length>3?n.call(arguments,2):i),p(l.type,f,t||l.key,r||l.ref,null)}function G$1(n,l){var u={__c:l="__cC"+e$1++,__:n,Consumer:function(n,l){return n.children(l)},Provider:function(n){var u,i;return this.getChildContext||(u=[],(i={})[l]=this,this.getChildContext=function(){return i},this.shouldComponentUpdate=function(n){this.props.value!==n.value&&u.some(function(n){n.__e=!0,T$1(n);});},this.sub=function(n){u.push(n);var l=n.componentWillUnmount;n.componentWillUnmount=function(){u.splice(u.indexOf(n),1),l&&l.call(n);};}),n.children}};return u.Provider.__=u.Consumer.contextType=u}n=s.slice,l$1={__e:function(n,l,u,i){for(var t,r,o;l=l.__;)if((t=l.__c)&&!t.__)try{if((r=t.constructor)&&null!=r.getDerivedStateFromError&&(t.setState(r.getDerivedStateFromError(n)),o=t.__d),null!=t.componentDidCatch&&(t.componentDidCatch(n,i||{}),o=t.__d),o)return t.__E=t}catch(l){n=l;}throw n}},u$1=0,i$1=function(n){return null!=n&&void 0===n.constructor},t=!1,x$1.prototype.setState=function(n,l){var u;u=null!=this.__s&&this.__s!==this.state?this.__s:this.__s=h({},this.state),"function"==typeof n&&(n=n(h({},u),this.props)),n&&h(u,n),null!=n&&this.__v&&(l&&this._sb.push(l),T$1(this));},x$1.prototype.forceUpdate=function(n){this.__v&&(this.__e=!0,n&&this.__h.push(n),T$1(this));},x$1.prototype.render=_,r$1=[],f$1="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,$$1.__r=0,e$1=0;
10
11    var r,u,i,f=[],c=[],e=l$1.__b,a=l$1.__r,v=l$1.diffed,l=l$1.__c,m=l$1.unmount;function b(){for(var t;t=f.shift();)if(t.__P&&t.__H)try{t.__H.__h.forEach(k),t.__H.__h.forEach(w$1),t.__H.__h=[];}catch(r){t.__H.__h=[],l$1.__e(r,t.__v);}}l$1.__b=function(n){r=null,e&&e(n);},l$1.__r=function(n){a&&a(n);var i=(r=n.__c).__H;i&&(u===r?(i.__h=[],r.__h=[],i.__.forEach(function(n){n.__N&&(n.__=n.__N),n.__V=c,n.__N=n.i=void 0;})):(i.__h.forEach(k),i.__h.forEach(w$1),i.__h=[])),u=r;},l$1.diffed=function(t){v&&v(t);var o=t.__c;o&&o.__H&&(o.__H.__h.length&&(1!==f.push(o)&&i===l$1.requestAnimationFrame||((i=l$1.requestAnimationFrame)||j$1)(b)),o.__H.__.forEach(function(n){n.i&&(n.__H=n.i),n.__V!==c&&(n.__=n.__V),n.i=void 0,n.__V=c;})),u=r=null;},l$1.__c=function(t,r){r.some(function(t){try{t.__h.forEach(k),t.__h=t.__h.filter(function(n){return !n.__||w$1(n)});}catch(u){r.some(function(n){n.__h&&(n.__h=[]);}),r=[],l$1.__e(u,t.__v);}}),l&&l(t,r);},l$1.unmount=function(t){m&&m(t);var r,u=t.__c;u&&u.__H&&(u.__H.__.forEach(function(n){try{k(n);}catch(n){r=n;}}),u.__H=void 0,r&&l$1.__e(r,u.__v));};var g$1="function"==typeof requestAnimationFrame;function j$1(n){var t,r=function(){clearTimeout(u),g$1&&cancelAnimationFrame(t),setTimeout(n);},u=setTimeout(r,100);g$1&&(t=requestAnimationFrame(r));}function k(n){var t=r,u=n.__c;"function"==typeof u&&(n.__c=void 0,u()),r=t;}function w$1(n){var t=r;n.__c=n.__(),r=t;}
12
13    function g(n,t){for(var e in t)n[e]=t[e];return n}function C(n,t){for(var e in n)if("__source"!==e&&!(e in t))return !0;for(var r in t)if("__source"!==r&&n[r]!==t[r])return !0;return !1}function w(n){this.props=n;}(w.prototype=new x$1).isPureReactComponent=!0,w.prototype.shouldComponentUpdate=function(n,t){return C(this.props,n)||C(this.state,t)};var x=l$1.__b;l$1.__b=function(n){n.type&&n.type.__f&&n.ref&&(n.props.ref=n.ref,n.ref=null),x&&x(n);};var T=l$1.__e;l$1.__e=function(n,t,e,r){if(n.then)for(var u,o=t;o=o.__;)if((u=o.__c)&&u.__c)return null==t.__e&&(t.__e=e.__e,t.__k=e.__k),u.__c(n,t);T(n,t,e,r);};var I=l$1.unmount;function L(n,t,e){return n&&(n.__c&&n.__c.__H&&(n.__c.__H.__.forEach(function(n){"function"==typeof n.__c&&n.__c();}),n.__c.__H=null),null!=(n=g({},n)).__c&&(n.__c.__P===e&&(n.__c.__P=t),n.__c=null),n.__k=n.__k&&n.__k.map(function(n){return L(n,t,e)})),n}function U(n,t,e){return n&&(n.__v=null,n.__k=n.__k&&n.__k.map(function(n){return U(n,t,e)}),n.__c&&n.__c.__P===t&&(n.__e&&e.insertBefore(n.__e,n.__d),n.__c.__e=!0,n.__c.__P=e)),n}function D(){this.__u=0,this.t=null,this.__b=null;}function F(n){var t=n.__.__c;return t&&t.__a&&t.__a(n)}function V(){this.u=null,this.o=null;}l$1.unmount=function(n){var t=n.__c;t&&t.__R&&t.__R(),t&&!0===n.__h&&(n.type=null),I&&I(n);},(D.prototype=new x$1).__c=function(n,t){var e=t.__c,r=this;null==r.t&&(r.t=[]),r.t.push(e);var u=F(r.__v),o=!1,i=function(){o||(o=!0,e.__R=null,u?u(l):l());};e.__R=i;var l=function(){if(!--r.__u){if(r.state.__a){var n=r.state.__a;r.__v.__k[0]=U(n,n.__c.__P,n.__c.__O);}var t;for(r.setState({__a:r.__b=null});t=r.t.pop();)t.forceUpdate();}},c=!0===t.__h;r.__u++||c||r.setState({__a:r.__b=r.__v.__k[0]}),n.then(i,i);},D.prototype.componentWillUnmount=function(){this.t=[];},D.prototype.render=function(n,e){if(this.__b){if(this.__v.__k){var r=document.createElement("div"),o=this.__v.__k[0].__c;this.__v.__k[0]=L(this.__b,r,o.__O=o.__P);}this.__b=null;}var i=e.__a&&y(_,null,n.fallback);return i&&(i.__h=null),[y(_,null,e.__a?null:n.children),i]};var W=function(n,t,e){if(++e[1]===e[0]&&n.o.delete(t),n.props.revealOrder&&("t"!==n.props.revealOrder[0]||!n.o.size))for(e=n.u;e;){for(;e.length>3;)e.pop()();if(e[1]<e[0])break;n.u=e=e[2];}};function P(n){return this.getChildContext=function(){return n.context},n.children}function $(n){var e=this,r=n.i;e.componentWillUnmount=function(){D$1(null,e.l),e.l=null,e.i=null;},e.i&&e.i!==r&&e.componentWillUnmount(),n.__v?(e.l||(e.i=r,e.l={nodeType:1,parentNode:r,childNodes:[],appendChild:function(n){this.childNodes.push(n),e.i.appendChild(n);},insertBefore:function(n,t){this.childNodes.push(n),e.i.appendChild(n);},removeChild:function(n){this.childNodes.splice(this.childNodes.indexOf(n)>>>1,1),e.i.removeChild(n);}}),D$1(y(P,{context:e.context},n.__v),e.l)):e.l&&e.componentWillUnmount();}function j(n,e){var r=y($,{__v:n,i:e});return r.containerInfo=e,r}(V.prototype=new x$1).__a=function(n){var t=this,e=F(t.__v),r=t.o.get(n);return r[0]++,function(u){var o=function(){t.props.revealOrder?(r.push(u),W(t,n,r)):u();};e?e(o):o();}},V.prototype.render=function(n){this.u=null,this.o=new Map;var t=j$2(n.children);n.revealOrder&&"b"===n.revealOrder[0]&&t.reverse();for(var e=t.length;e--;)this.o.set(t[e],this.u=[1,0,this.u]);return n.children},V.prototype.componentDidUpdate=V.prototype.componentDidMount=function(){var n=this;this.o.forEach(function(t,e){W(n,e,t);});};var z="undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103,B=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,H="undefined"!=typeof document,Z=function(n){return ("undefined"!=typeof Symbol&&"symbol"==typeof Symbol()?/fil|che|rad/i:/fil|che|ra/i).test(n)};x$1.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(t){Object.defineProperty(x$1.prototype,t,{configurable:!0,get:function(){return this["UNSAFE_"+t]},set:function(n){Object.defineProperty(this,t,{configurable:!0,writable:!0,value:n});}});});var G=l$1.event;function J(){}function K(){return this.cancelBubble}function Q(){return this.defaultPrevented}l$1.event=function(n){return G&&(n=G(n)),n.persist=J,n.isPropagationStopped=K,n.isDefaultPrevented=Q,n.nativeEvent=n};var nn={configurable:!0,get:function(){return this.class}},tn=l$1.vnode;l$1.vnode=function(n){var t=n.type,e=n.props,u=e;if("string"==typeof t){var o=-1===t.indexOf("-");for(var i in u={},e){var l=e[i];H&&"children"===i&&"noscript"===t||"value"===i&&"defaultValue"in e&&null==l||("defaultValue"===i&&"value"in e&&null==e.value?i="value":"download"===i&&!0===l?l="":/ondoubleclick/i.test(i)?i="ondblclick":/^onchange(textarea|input)/i.test(i+t)&&!Z(e.type)?i="oninput":/^onfocus$/i.test(i)?i="onfocusin":/^onblur$/i.test(i)?i="onfocusout":/^on(Ani|Tra|Tou|BeforeInp|Compo)/.test(i)?i=i.toLowerCase():o&&B.test(i)?i=i.replace(/[A-Z0-9]/g,"-$&").toLowerCase():null===l&&(l=void 0),/^oninput$/i.test(i)&&(i=i.toLowerCase(),u[i]&&(i="oninputCapture")),u[i]=l);}"select"==t&&u.multiple&&Array.isArray(u.value)&&(u.value=j$2(e.children).forEach(function(n){n.props.selected=-1!=u.value.indexOf(n.props.value);})),"select"==t&&null!=u.defaultValue&&(u.value=j$2(e.children).forEach(function(n){n.props.selected=u.multiple?-1!=u.defaultValue.indexOf(n.props.value):u.defaultValue==n.props.value;})),n.props=u,e.class!=e.className&&(nn.enumerable="className"in e,null!=e.className&&(u.class=e.className),Object.defineProperty(u,"className",nn));}n.$$typeof=z,tn&&tn(n);};var en=l$1.__r;l$1.__r=function(n){en&&en(n),n.__c;};
14
15    const styleTexts = [];
16    const styleEls = new Map();
17    function injectStyles(styleText) {
18        styleTexts.push(styleText);
19        styleEls.forEach((styleEl) => {
20            appendStylesTo(styleEl, styleText);
21        });
22    }
23    function ensureElHasStyles(el) {
24        if (el.isConnected) {
25            registerStylesRoot(el.getRootNode());
26        }
27    }
28    function registerStylesRoot(rootNode) {
29        let styleEl = styleEls.get(rootNode);
30        if (!styleEl || !styleEl.isConnected) {
31            styleEl = rootNode.querySelector('style[data-fullcalendar]');
32            if (!styleEl) {
33                styleEl = document.createElement('style');
34                styleEl.setAttribute('data-fullcalendar', '');
35                const nonce = getNonceValue();
36                if (nonce) {
37                    styleEl.nonce = nonce;
38                }
39                const parentEl = rootNode === document ? document.head : rootNode;
40                const insertBefore = rootNode === document
41                    ? parentEl.querySelector('script,link[rel=stylesheet],link[as=style],style')
42                    : parentEl.firstChild;
43                parentEl.insertBefore(styleEl, insertBefore);
44            }
45            styleEls.set(rootNode, styleEl);
46            hydrateStylesRoot(styleEl);
47        }
48    }
49    function hydrateStylesRoot(styleEl) {
50        for (const styleText of styleTexts) {
51            appendStylesTo(styleEl, styleText);
52        }
53    }
54    function appendStylesTo(styleEl, styleText) {
55        const { sheet } = styleEl;
56        const ruleCnt = sheet.cssRules.length;
57        styleText.split('}').forEach((styleStr, i) => {
58            styleStr = styleStr.trim();
59            if (styleStr) {
60                sheet.insertRule(styleStr + '}', ruleCnt + i);
61            }
62        });
63    }
64    // nonce
65    // -------------------------------------------------------------------------------------------------
66    let queriedNonceValue;
67    function getNonceValue() {
68        if (queriedNonceValue === undefined) {
69            queriedNonceValue = queryNonceValue();
70        }
71        return queriedNonceValue;
72    }
73    /*
74    TODO: discourage meta tag and instead put nonce attribute on placeholder <style> tag
75    */
76    function queryNonceValue() {
77        const metaWithNonce = document.querySelector('meta[name="csp-nonce"]');
78        if (metaWithNonce && metaWithNonce.hasAttribute('content')) {
79            return metaWithNonce.getAttribute('content');
80        }
81        const elWithNonce = document.querySelector('script[nonce]');
82        if (elWithNonce) {
83            return elWithNonce.nonce || '';
84        }
85        return '';
86    }
87    // main
88    // -------------------------------------------------------------------------------------------------
89    if (typeof document !== 'undefined') {
90        registerStylesRoot(document);
91    }
92
93    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/ARcWMjc2NC8BNzY0JyY
93iDwEnJiIHBhQX4uLiDQ0MJAzi4gwkDA0N4uINDQwkDOLiDCQMDQ0CjeLiDSMMDQ3h4Q0NDCMN4uIMIw0MDOLiDAwNIwwAAAABAAAAAQAAa5n0y18PPPUACwQAAAAAANivOVsAAAAA2K85WwAAAAADqwNVAAAACAACAAAAAAAAAAEAAAPA/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}
93.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)}";
94    injectStyles(css_248z$4);
95
96    class DelayedRunner {
97        constructor(drainedOption) {
98            this.drainedOption = drainedOption;
99            this.isRunning = false;
100            this.isDirty = false;
101            this.pauseDepths = {};
102            this.timeoutId = 0;
103        }
104        request(delay) {
105            this.isDirty = true;
106            if (!this.isPaused()) {
107                this.clearTimeout();
108                if (delay == null) {
109                    this.tryDrain();
110                }
111                else {
112                    this.timeoutId = setTimeout(// NOT OPTIMAL! TODO: look at debounce
113                        this.tryDrain.bind(this), delay);
114                }
115            }
116        }
117        pause(scope = '') {
118            let { pauseDepths } = this;
119            pauseDepths[scope] = (pauseDepths[scope] || 0) + 1;
120            this.clearTimeout();
121        }
122        resume(scope = '', force) {
123            let { pauseDepths } = this;
124            if (scope in pauseDepths) {
125                if (force) {
126                    delete pauseDepths[scope];
127                }
128                else {
129                    pauseDepths[scope] -= 1;
130                    let depth = pauseDepths[scope];
131                    if (depth <= 0) {
132                        delete pauseDepths[scope];
133                    }
134                }
135                this.tryDrain();
136            }
137        }
138        isPaused() {
139            return Object.keys(this.pauseDepths).length;
140        }
141        tryDrain() {
142            if (!this.isRunning && !this.isPaused()) {
143                this.isRunning = true;
144                while (this.isDirty) {
145                    this.isDirty = false;
146                    this.drained(); // might set isDirty to true again
147                }
148                this.isRunning = false;
149            }
150        }
151        clear() {
152            this.clearTimeout();
153            this.isDirty = false;
154            this.pauseDepths = {};
155        }
156        clearTimeout() {
157            if (this.timeoutId) {
158                clearTimeout(this.timeoutId);
159                this.timeoutId = 0;
160            }
161        }
162        drained() {
163            if (this.drainedOption) {
164                this.drainedOption();
165            }
166        }
167    }
168
169    function removeElement(el) {
170        if (el.parentNode) {
171            el.parentNode.removeChild(el);
172        }
173    }
174    // Querying
175    // ----------------------------------------------------------------------------------------------------------------
176    function elementClosest(el, selector) {
177        if (el.closest) {
178            return el.closest(selector);
179            // really bad fallback for IE
180            // from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
181        }
182        if (!document.documentElement.contains(el)) {
183            return null;
184        }
185        do {
186            if (elementMatches(el, selector)) {
187                return el;
188            }
189            el = (el.parentElement || el.parentNode);
190        } while (el !== null && el.nodeType === 1);
191        return null;
192    }
193    function elementMatches(el, selector) {
194        let method = el.matches || el.matchesSelector || el.msMatchesSelector;
195        return method.call(el, selector);
196    }
197    // accepts multiple subject els
198    // returns a real array. good for methods like forEach
199    // TODO: accept the document
200    function findElements(container, selector) {
201        let containers = container instanceof HTMLElement ? [container] : container;
202        let allMatches = [];
203        for (let i = 0; i < containers.length; i += 1) {
204            let matches = containers[i].querySelectorAll(selector);
205            for (let j = 0; j < matches.length; j += 1) {
206                allMatches.push(matches[j]);
207            }
208        }
209        return allMatches;
210    }
211    // accepts multiple subject els
212    // only queries direct child elements // TODO: rename to findDirectChildren!
213    function findDirectChildren(parent, selector) {
214        let parents = parent instanceof HTMLElement ? [parent] : parent;
215        let allMatches = [];
216        for (let i = 0; i < parents.length; i += 1) {
217            let childNodes = parents[i].children; // only ever elements
218            for (let j = 0; j < childNodes.length; j += 1) {
219                let childNode = childNodes[j];
220                if (!selector || elementMatches(childNode, selector)) {
221                    allMatches.push(childNode);
222                }
223            }
224        }
225        return allMatches;
226    }
227    // Style
228    // ----------------------------------------------------------------------------------------------------------------
229    const PIXEL_PROP_RE = /(top|left|right|bottom|width|height)$/i;
230    function applyStyle(el, props) {
231        for (let propName in props) {
232            applyStyleProp(el, propName, props[propName]);
233        }
234    }
235    function applyStyleProp(el, name, val) {
236        if (val == null) {
237            el.style[name] = '';
238        }
239        else if (typeof val === 'number' && PIXEL_PROP_RE.test(name)) {
240            el.style[name] = `${val}px`;
241        }
242        else {
243            el.style[name] = val;
244        }
245    }
246    // Event Handling
247    // ----------------------------------------------------------------------------------------------------------------
248    // if intercepting bubbled events at the document/window/body level,
249    // and want to see originating element (the 'target'), use this util instead
250    // of `ev.target` because it goes within web-component boundaries.
251    function getEventTargetViaRoot(ev) {
252        var _a, _b;
253        return (_b = (_a = ev.composedPath) === null || _a === void 0 ? void 0 : _a.call(ev)[0]) !== null && _b !== void 0 ? _b : ev.target;
254    }
255    // Unique ID for DOM attribute
256    let guid$1 = 0;
257    function getUniqueDomId() {
258        guid$1 += 1;
259        return 'fc-dom-' + guid$1;
260    }
261
262    // Stops a mouse/touch event from doing it's native browser action
263    function preventDefault(ev) {
264        ev.preventDefault();
265    }
266    // Event Delegation
267    // ----------------------------------------------------------------------------------------------------------------
268    function buildDelegationHandler(selector, handler) {
269        return (ev) => {
vendor: 47,423 bytes, lines 270-1575
270            let matchedChild = elementClosest(ev.target, selector);
271            if (matchedChild) {
272                handler.call(matchedChild, ev, matchedChild);
273            }
274        };
275    }
276    function listenBySelector(container, eventType, selector, handler) {
277        let attachedHandler = buildDelegationHandler(selector, handler);
278        container.addEventListener(eventType, attachedHandler);
279        return () => {
280            container.removeEventListener(eventType, attachedHandler);
281        };
282    }
283    function listenToHoverBySelector(container, selector, onMouseEnter, onMouseLeave) {
284        let currentMatchedChild;
285        return listenBySelector(container, 'mouseover', selector, (mouseOverEv, matchedChild) => {
286            if (matchedChild !== currentMatchedChild) {
287                currentMatchedChild = matchedChild;
288                onMouseEnter(mouseOverEv, matchedChild);
289                let realOnMouseLeave = (mouseLeaveEv) => {
290                    currentMatchedChild = null;
291                    onMouseLeave(mouseLeaveEv, matchedChild);
292                    matchedChild.removeEventListener('mouseleave', realOnMouseLeave);
293                };
294                // listen to the next mouseleave, and then unattach
295                matchedChild.addEventListener('mouseleave', realOnMouseLeave);
296            }
297        });
298    }
299    // Animation
300    // ----------------------------------------------------------------------------------------------------------------
301    const transitionEventNames = [
302        'webkitTransitionEnd',
303        'otransitionend',
304        'oTransitionEnd',
305        'msTransitionEnd',
306        'transitionend',
307    ];
308    // triggered only when the next single subsequent transition finishes
309    function whenTransitionDone(el, callback) {
310        let realCallback = (ev) => {
311            callback(ev);
312            transitionEventNames.forEach((eventName) => {
313                el.removeEventListener(eventName, realCallback);
314            });
315        };
316        transitionEventNames.forEach((eventName) => {
317            el.addEventListener(eventName, realCallback); // cross-browser way to determine when the transition finishes
318        });
319    }
320    // ARIA workarounds
321    // ----------------------------------------------------------------------------------------------------------------
322    function createAriaClickAttrs(handler) {
323        return Object.assign({ onClick: handler }, createAriaKeyboardAttrs(handler));
324    }
325    function createAriaKeyboardAttrs(handler) {
326        return {
327            tabIndex: 0,
328            onKeyDown(ev) {
329                if (ev.key === 'Enter' || ev.key === ' ') {
330                    handler(ev);
331                    ev.preventDefault(); // if space, don't scroll down page
332                }
333            },
334        };
335    }
336
337    let guidNumber = 0;
338    function guid() {
339        guidNumber += 1;
340        return String(guidNumber);
341    }
342    /* FullCalendar-specific DOM Utilities
343    ----------------------------------------------------------------------------------------------------------------------*/
344    // Make the mouse cursor express that an event is not allowed in the current area
345    function disableCursor() {
346        document.body.classList.add('fc-not-allowed');
347    }
348    // Returns the mouse cursor to its original look
349    function enableCursor() {
350        document.body.classList.remove('fc-not-allowed');
351    }
352    /* Selection
353    ----------------------------------------------------------------------------------------------------------------------*/
354    function preventSelection(el) {
355        el.style.userSelect = 'none';
356        el.style.webkitUserSelect = 'none';
357        el.addEventListener('selectstart', preventDefault);
358    }
359    function allowSelection(el) {
360        el.style.userSelect = '';
361        el.style.webkitUserSelect = '';
362        el.removeEventListener('selectstart', preventDefault);
363    }
364    /* Context Menu
365    ----------------------------------------------------------------------------------------------------------------------*/
366    function preventContextMenu(el) {
367        el.addEventListener('contextmenu', preventDefault);
368    }
369    function allowContextMenu(el) {
370        el.removeEventListener('contextmenu', preventDefault);
371    }
372    function parseFieldSpecs(input) {
373        let specs = [];
374        let tokens = [];
375        let i;
376        let token;
377        if (typeof input === 'string') {
378            tokens = input.split(/\s*,\s*/);
379        }
380        else if (typeof input === 'function') {
381            tokens = [input];
382        }
383        else if (Array.isArray(input)) {
384            tokens = input;
385        }
386        for (i = 0; i < tokens.length; i += 1) {
387            token = tokens[i];
388            if (typeof token === 'string') {
389                specs.push(token.charAt(0) === '-' ?
390                    { field: token.substring(1), order: -1 } :
391                    { field: token, order: 1 });
392            }
393            else if (typeof token === 'function') {
394                specs.push({ func: token });
395            }
396        }
397        return specs;
398    }
399    function compareByFieldSpecs(obj0, obj1, fieldSpecs) {
400        let i;
401        let cmp;
402        for (i = 0; i < fieldSpecs.length; i += 1) {
403            cmp = compareByFieldSpec(obj0, obj1, fieldSpecs[i]);
404            if (cmp) {
405                return cmp;
406            }
407        }
408        return 0;
409    }
410    function compareByFieldSpec(obj0, obj1, fieldSpec) {
411        if (fieldSpec.func) {
412            return fieldSpec.func(obj0, obj1);
413        }
414        return flexibleCompare(obj0[fieldSpec.field], obj1[fieldSpec.field])
415            * (fieldSpec.order || 1);
416    }
417    function flexibleCompare(a, b) {
418        if (!a && !b) {
419            return 0;
420        }
421        if (b == null) {
422            return -1;
423        }
424        if (a == null) {
425            return 1;
426        }
427        if (typeof a === 'string' || typeof b === 'string') {
428            return String(a).localeCompare(String(b));
429        }
430        return a - b;
431    }
432    /* String Utilities
433    ----------------------------------------------------------------------------------------------------------------------*/
434    function padStart(val, len) {
435        let s = String(val);
436        return '000'.substr(0, len - s.length) + s;
437    }
438    function formatWithOrdinals(formatter, args, fallbackText) {
439        if (typeof formatter === 'function') {
440            return formatter(...args);
441        }
442        if (typeof formatter === 'string') { // non-blank string
443            return args.reduce((str, arg, index) => (str.replace('$' + index, arg || '')), formatter);
444        }
445        return fallbackText;
446    }
447    /* Number Utilities
448    ----------------------------------------------------------------------------------------------------------------------*/
449    function compareNumbers(a, b) {
450        return a - b;
451    }
452    function isInt(n) {
453        return n % 1 === 0;
454    }
455    /* FC-specific DOM dimension stuff
456    ----------------------------------------------------------------------------------------------------------------------*/
457    function computeSmallestCellWidth(cellEl) {
458        let allWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-frame');
459        let contentWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-cushion');
460        if (!allWidthEl) {
461            throw new Error('needs fc-scrollgrid-shrink-frame className'); // TODO: use const
462        }
463        if (!contentWidthEl) {
464            throw new Error('needs fc-scrollgrid-shrink-cushion className');
465        }
466        return cellEl.getBoundingClientRect().width - allWidthEl.getBoundingClientRect().width + // the cell padding+border
467            contentWidthEl.getBoundingClientRect().width;
468    }
469
470    const INTERNAL_UNITS = ['years', 'months', 'days', 'milliseconds'];
471    const PARSE_RE = /^(-?)(?:(\d+)\.)?(\d+):(\d\d)(?::(\d\d)(?:\.(\d\d\d))?)?/;
472    // Parsing and Creation
473    function createDuration(input, unit) {
474        if (typeof input === 'string') {
475            return parseString(input);
476        }
477        if (typeof input === 'object' && input) { // non-null object
478            return parseObject(input);
479        }
480        if (typeof input === 'number') {
481            return parseObject({ [unit || 'milliseconds']: input });
482        }
483        return null;
484    }
485    function parseString(s) {
486        let m = PARSE_RE.exec(s);
487        if (m) {
488            let sign = m[1] ? -1 : 1;
489            return {
490                years: 0,
491                months: 0,
492                days: sign * (m[2] ? parseInt(m[2], 10) : 0),
493                milliseconds: sign * ((m[3] ? parseInt(m[3], 10) : 0) * 60 * 60 * 1000 + // hours
494                    (m[4] ? parseInt(m[4], 10) : 0) * 60 * 1000 + // minutes
495                    (m[5] ? parseInt(m[5], 10) : 0) * 1000 + // seconds
496                    (m[6] ? parseInt(m[6], 10) : 0) // ms
497                ),
498            };
499        }
500        return null;
501    }
502    function parseObject(obj) {
503        let duration = {
504            years: obj.years || obj.year || 0,
505            months: obj.months || obj.month || 0,
506            days: obj.days || obj.day || 0,
507            milliseconds: (obj.hours || obj.hour || 0) * 60 * 60 * 1000 + // hours
508                (obj.minutes || obj.minute || 0) * 60 * 1000 + // minutes
509                (obj.seconds || obj.second || 0) * 1000 + // seconds
510                (obj.milliseconds || obj.millisecond || obj.ms || 0), // ms
511        };
512        let weeks = obj.weeks || obj.week;
513        if (weeks) {
514            duration.days += weeks * 7;
515            duration.specifiedWeeks = true;
516        }
517        return duration;
518    }
519    // Equality
520    function durationsEqual(d0, d1) {
521        return d0.years === d1.years &&
522            d0.months === d1.months &&
523            d0.days === d1.days &&
524            d0.milliseconds === d1.milliseconds;
525    }
526    function asCleanDays(dur) {
527        if (!dur.years && !dur.months && !dur.milliseconds) {
528            return dur.days;
529        }
530        return 0;
531    }
532    // Simple Math
533    function addDurations(d0, d1) {
534        return {
535            years: d0.years + d1.years,
536            months: d0.months + d1.months,
537            days: d0.days + d1.days,
538            milliseconds: d0.milliseconds + d1.milliseconds,
539        };
540    }
541    function subtractDurations(d1, d0) {
542        return {
543            years: d1.years - d0.years,
544            months: d1.months - d0.months,
545            days: d1.days - d0.days,
546            milliseconds: d1.milliseconds - d0.milliseconds,
547        };
548    }
549    function multiplyDuration(d, n) {
550        return {
551            years: d.years * n,
552            months: d.months * n,
553            days: d.days * n,
554            milliseconds: d.milliseconds * n,
555        };
556    }
557    // Conversions
558    // "Rough" because they are based on average-case Gregorian months/years
559    function asRoughYears(dur) {
560        return asRoughDays(dur) / 365;
561    }
562    function asRoughMonths(dur) {
563        return asRoughDays(dur) / 30;
564    }
565    function asRoughDays(dur) {
566        return asRoughMs(dur) / 864e5;
567    }
568    function asRoughMinutes(dur) {
569        return asRoughMs(dur) / (1000 * 60);
570    }
571    function asRoughSeconds(dur) {
572        return asRoughMs(dur) / 1000;
573    }
574    function asRoughMs(dur) {
575        return dur.years * (365 * 864e5) +
576            dur.months * (30 * 864e5) +
577            dur.days * 864e5 +
578            dur.milliseconds;
579    }
580    // Advanced Math
581    function wholeDivideDurations(numerator, denominator) {
582        let res = null;
583        for (let i = 0; i < INTERNAL_UNITS.length; i += 1) {
584            let unit = INTERNAL_UNITS[i];
585            if (denominator[unit]) {
586                let localRes = numerator[unit] / denominator[unit];
587                if (!isInt(localRes) || (res !== null && res !== localRes)) {
588                    return null;
589                }
590                res = localRes;
591            }
592            else if (numerator[unit]) {
593                // needs to divide by something but can't!
594                return null;
595            }
596        }
597        return res;
598    }
599    function greatestDurationDenominator(dur) {
600        let ms = dur.milliseconds;
601        if (ms) {
602            if (ms % 1000 !== 0) {
603                return { unit: 'millisecond', value: ms };
604            }
605            if (ms % (1000 * 60) !== 0) {
606                return { unit: 'second', value: ms / 1000 };
607            }
608            if (ms % (1000 * 60 * 60) !== 0) {
609                return { unit: 'minute', value: ms / (1000 * 60) };
610            }
611            if (ms) {
612                return { unit: 'hour', value: ms / (1000 * 60 * 60) };
613            }
614        }
615        if (dur.days) {
616            if (dur.specifiedWeeks && dur.days % 7 === 0) {
617                return { unit: 'week', value: dur.days / 7 };
618            }
619            return { unit: 'day', value: dur.days };
620        }
621        if (dur.months) {
622            return { unit: 'month', value: dur.months };
623        }
624        if (dur.years) {
625            return { unit: 'year', value: dur.years };
626        }
627        return { unit: 'millisecond', value: 0 };
628    }
629
630    // TODO: new util arrayify?
631    function removeExact(array, exactVal) {
632        let removeCnt = 0;
633        let i = 0;
634        while (i < array.length) {
635            if (array[i] === exactVal) {
636                array.splice(i, 1);
637                removeCnt += 1;
638            }
639            else {
640                i += 1;
641            }
642        }
643        return removeCnt;
644    }
645    function isArraysEqual(a0, a1, equalityFunc) {
646        if (a0 === a1) {
647            return true;
648        }
649        let len = a0.length;
650        let i;
651        if (len !== a1.length) { // not array? or not same length?
652            return false;
653        }
654        for (i = 0; i < len; i += 1) {
655            if (!(equalityFunc ? equalityFunc(a0[i], a1[i]) : a0[i] === a1[i])) {
656                return false;
657            }
658        }
659        return true;
660    }
661
662    const DAY_IDS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
663    // Adding
664    function addWeeks(m, n) {
665        let a = dateToUtcArray(m);
666        a[2] += n * 7;
667        return arrayToUtcDate(a);
668    }
669    function addDays(m, n) {
670        let a = dateToUtcArray(m);
671        a[2] += n;
672        return arrayToUtcDate(a);
673    }
674    function addMs(m, n) {
675        let a = dateToUtcArray(m);
676        a[6] += n;
677        return arrayToUtcDate(a);
678    }
679    // Diffing (all return floats)
680    // TODO: why not use ranges?
681    function diffWeeks(m0, m1) {
682        return diffDays(m0, m1) / 7;
683    }
684    function diffDays(m0, m1) {
685        return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60 * 24);
686    }
687    function diffHours(m0, m1) {
688        return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60);
689    }
690    function diffMinutes(m0, m1) {
691        return (m1.valueOf() - m0.valueOf()) / (1000 * 60);
692    }
693    function diffSeconds(m0, m1) {
694        return (m1.valueOf() - m0.valueOf()) / 1000;
695    }
696    function diffDayAndTime(m0, m1) {
697        let m0day = startOfDay(m0);
698        let m1day = startOfDay(m1);
699        return {
700            years: 0,
701            months: 0,
702            days: Math.round(diffDays(m0day, m1day)),
703            milliseconds: (m1.valueOf() - m1day.valueOf()) - (m0.valueOf() - m0day.valueOf()),
704        };
705    }
706    // Diffing Whole Units
707    function diffWholeWeeks(m0, m1) {
708        let d = diffWholeDays(m0, m1);
709        if (d !== null && d % 7 === 0) {
710            return d / 7;
711        }
712        return null;
713    }
714    function diffWholeDays(m0, m1) {
715        if (timeAsMs(m0) === timeAsMs(m1)) {
716            return Math.round(diffDays(m0, m1));
717        }
718        return null;
719    }
720    // Start-Of
721    function startOfDay(m) {
722        return arrayToUtcDate([
723            m.getUTCFullYear(),
724            m.getUTCMonth(),
725            m.getUTCDate(),
726        ]);
727    }
728    function startOfHour(m) {
729        return arrayToUtcDate([
730            m.getUTCFullYear(),
731            m.getUTCMonth(),
732            m.getUTCDate(),
733            m.getUTCHours(),
734        ]);
735    }
736    function startOfMinute(m) {
737        return arrayToUtcDate([
738            m.getUTCFullYear(),
739            m.getUTCMonth(),
740            m.getUTCDate(),
741            m.getUTCHours(),
742            m.getUTCMinutes(),
743        ]);
744    }
745    function startOfSecond(m) {
746        return arrayToUtcDate([
747            m.getUTCFullYear(),
748            m.getUTCMonth(),
749            m.getUTCDate(),
750            m.getUTCHours(),
751            m.getUTCMinutes(),
752            m.getUTCSeconds(),
753        ]);
754    }
755    // Week Computation
756    function weekOfYear(marker, dow, doy) {
757        let y = marker.getUTCFullYear();
758        let w = weekOfGivenYear(marker, y, dow, doy);
759        if (w < 1) {
760            return weekOfGivenYear(marker, y - 1, dow, doy);
761        }
762        let nextW = weekOfGivenYear(marker, y + 1, dow, doy);
763        if (nextW >= 1) {
764            return Math.min(w, nextW);
765        }
766        return w;
767    }
768    function weekOfGivenYear(marker, year, dow, doy) {
769        let firstWeekStart = arrayToUtcDate([year, 0, 1 + firstWeekOffset(year, dow, doy)]);
770        let dayStart = startOfDay(marker);
771        let days = Math.round(diffDays(firstWeekStart, dayStart));
772        return Math.floor(days / 7) + 1; // zero-indexed
773    }
774    // start-of-first-week - start-of-year
775    function firstWeekOffset(year, dow, doy) {
776        // first-week day -- which january is always in the first week (4 for iso, 1 for other)
777        let fwd = 7 + dow - doy;
778        // first-week day local weekday -- which local weekday is fwd
779        let fwdlw = (7 + arrayToUtcDate([year, 0, fwd]).getUTCDay() - dow) % 7;
780        return -fwdlw + fwd - 1;
781    }
782    // Array Conversion
783    function dateToLocalArray(date) {
784        return [
785            date.getFullYear(),
786            date.getMonth(),
787            date.getDate(),
788            date.getHours(),
789            date.getMinutes(),
790            date.getSeconds(),
791            date.getMilliseconds(),
792        ];
793    }
794    function arrayToLocalDate(a) {
795        return new Date(a[0], a[1] || 0, a[2] == null ? 1 : a[2], // day of month
796            a[3] || 0, a[4] || 0, a[5] || 0);
797    }
798    function dateToUtcArray(date) {
799        return [
800            date.getUTCFullYear(),
801            date.getUTCMonth(),
802            date.getUTCDate(),
803            date.getUTCHours(),
804            date.getUTCMinutes(),
805            date.getUTCSeconds(),
806            date.getUTCMilliseconds(),
807        ];
808    }
809    function arrayToUtcDate(a) {
810        // according to web standards (and Safari), a month index is required.
811        // massage if only given a year.
812        if (a.length === 1) {
813            a = a.concat([0]);
814        }
815        return new Date(Date.UTC(...a));
816    }
817    // Other Utils
818    function isValidDate(m) {
819        return !isNaN(m.valueOf());
820    }
821    function timeAsMs(m) {
822        return m.getUTCHours() * 1000 * 60 * 60 +
823            m.getUTCMinutes() * 1000 * 60 +
824            m.getUTCSeconds() * 1000 +
825            m.getUTCMilliseconds();
826    }
827
828    // timeZoneOffset is in minutes
829    function buildIsoString(marker, timeZoneOffset, stripZeroTime = false) {
830        let s = marker.toISOString();
831        s = s.replace('.000', '');
832        if (stripZeroTime) {
833            s = s.replace('T00:00:00Z', '');
834        }
835        if (s.length > 10) { // time part wasn't stripped, can add timezone info
836            if (timeZoneOffset == null) {
837                s = s.replace('Z', '');
838            }
839            else if (timeZoneOffset !== 0) {
840                s = s.replace('Z', formatTimeZoneOffset(timeZoneOffset, true));
841            }
842            // otherwise, its UTC-0 and we want to keep the Z
843        }
844        return s;
845    }
846    // formats the date, but with no time part
847    // TODO: somehow merge with buildIsoString and stripZeroTime
848    // TODO: rename. omit "string"
849    function formatDayString(marker) {
850        return marker.toISOString().replace(/T.*$/, '');
851    }
852    function formatIsoMonthStr(marker) {
853        return marker.toISOString().match(/^\d{4}-\d{2}/)[0];
854    }
855    // TODO: use Date::toISOString and use everything after the T?
856    function formatIsoTimeString(marker) {
857        return padStart(marker.getUTCHours(), 2) + ':' +
858            padStart(marker.getUTCMinutes(), 2) + ':' +
859            padStart(marker.getUTCSeconds(), 2);
860    }
861    function formatTimeZoneOffset(minutes, doIso = false) {
862        let sign = minutes < 0 ? '-' : '+';
863        let abs = Math.abs(minutes);
864        let hours = Math.floor(abs / 60);
865        let mins = Math.round(abs % 60);
866        if (doIso) {
867            return `${sign + padStart(hours, 2)}:${padStart(mins, 2)}`;
868        }
869        return `GMT${sign}${hours}${mins ? `:${padStart(mins, 2)}` : ''}`;
870    }
871
872    function memoize(workerFunc, resEquality, teardownFunc) {
873        let currentArgs;
874        let currentRes;
875        return function (...newArgs) {
876            if (!currentArgs) {
877                currentRes = workerFunc.apply(this, newArgs);
878            }
879            else if (!isArraysEqual(currentArgs, newArgs)) {
880                if (teardownFunc) {
881                    teardownFunc(currentRes);
882                }
883                let res = workerFunc.apply(this, newArgs);
884                if (!resEquality || !resEquality(res, currentRes)) {
885                    currentRes = res;
886                }
887            }
888            currentArgs = newArgs;
889            return currentRes;
890        };
891    }
892    function memoizeObjArg(workerFunc, resEquality, teardownFunc) {
893        let currentArg;
894        let currentRes;
895        return (newArg) => {
896            if (!currentArg) {
897                currentRes = workerFunc.call(this, newArg);
898            }
899            else if (!isPropsEqual(currentArg, newArg)) {
900                if (teardownFunc) {
901                    teardownFunc(currentRes);
902                }
903                let res = workerFunc.call(this, newArg);
904                if (!resEquality || !resEquality(res, currentRes)) {
905                    currentRes = res;
906                }
907            }
908            currentArg = newArg;
909            return currentRes;
910        };
911    }
912    function memoizeArraylike(// used at all?
913        workerFunc, resEquality, teardownFunc) {
914        let currentArgSets = [];
915        let currentResults = [];
916        return (newArgSets) => {
917            let currentLen = currentArgSets.length;
918            let newLen = newArgSets.length;
919            let i = 0;
920            for (; i < currentLen; i += 1) {
921                if (!newArgSets[i]) { // one of the old sets no longer exists
922                    if (teardownFunc) {
923                        teardownFunc(currentResults[i]);
924                    }
925                }
926                else if (!isArraysEqual(currentArgSets[i], newArgSets[i])) {
927                    if (teardownFunc) {
928                        teardownFunc(currentResults[i]);
929                    }
930                    let res = workerFunc.apply(this, newArgSets[i]);
931                    if (!resEquality || !resEquality(res, currentResults[i])) {
932                        currentResults[i] = res;
933                    }
934                }
935            }
936            for (; i < newLen; i += 1) {
937                currentResults[i] = workerFunc.apply(this, newArgSets[i]);
938            }
939            currentArgSets = newArgSets;
940            currentResults.splice(newLen); // remove excess
941            return currentResults;
942        };
943    }
944    function memoizeHashlike(workerFunc, resEquality, teardownFunc) {
945        let currentArgHash = {};
946        let currentResHash = {};
947        return (newArgHash) => {
948            let newResHash = {};
949            for (let key in newArgHash) {
950                if (!currentResHash[key]) {
951                    newResHash[key] = workerFunc.apply(this, newArgHash[key]);
952                }
953                else if (!isArraysEqual(currentArgHash[key], newArgHash[key])) {
954                    if (teardownFunc) {
955                        teardownFunc(currentResHash[key]);
956                    }
957                    let res = workerFunc.apply(this, newArgHash[key]);
958                    newResHash[key] = (resEquality && resEquality(res, currentResHash[key]))
959                        ? currentResHash[key]
960                        : res;
961                }
962                else {
963                    newResHash[key] = currentResHash[key];
964                }
965            }
966            currentArgHash = newArgHash;
967            currentResHash = newResHash;
968            return newResHash;
969        };
970    }
971
972    const EXTENDED_SETTINGS_AND_SEVERITIES = {
973        week: 3,
974        separator: 0,
975        omitZeroMinute: 0,
976        meridiem: 0,
977        omitCommas: 0,
978    };
979    const STANDARD_DATE_PROP_SEVERITIES = {
980        timeZoneName: 7,
981        era: 6,
982        year: 5,
983        month: 4,
984        day: 2,
985        weekday: 2,
986        hour: 1,
987        minute: 1,
988        second: 1,
989    };
990    const MERIDIEM_RE = /\s*([ap])\.?m\.?/i; // eats up leading spaces too
991    const COMMA_RE = /,/g; // we need re for globalness
992    const MULTI_SPACE_RE = /\s+/g;
993    const LTR_RE = /\u200e/g; // control character
994    const UTC_RE = /UTC|GMT/;
995    class NativeFormatter {
996        constructor(formatSettings) {
997            let standardDateProps = {};
998            let extendedSettings = {};
999            let severity = 0;
1000            for (let name in formatSettings) {
1001                if (name in EXTENDED_SETTINGS_AND_SEVERITIES) {
1002                    extendedSettings[name] = formatSettings[name];
1003                    severity = Math.max(EXTENDED_SETTINGS_AND_SEVERITIES[name], severity);
1004                }
1005                else {
1006                    standardDateProps[name] = formatSettings[name];
1007                    if (name in STANDARD_DATE_PROP_SEVERITIES) { // TODO: what about hour12? no severity
1008                        severity = Math.max(STANDARD_DATE_PROP_SEVERITIES[name], severity);
1009                    }
1010                }
1011            }
1012            this.standardDateProps = standardDateProps;
1013            this.extendedSettings = extendedSettings;
1014            this.severity = severity;
1015            this.buildFormattingFunc = memoize(buildFormattingFunc);
1016        }
1017        format(date, context) {
1018            return this.buildFormattingFunc(this.standardDateProps, this.extendedSettings, context)(date);
1019        }
1020        formatRange(start, end, context, betterDefaultSeparator) {
1021            let { standardDateProps, extendedSettings } = this;
1022            let diffSeverity = computeMarkerDiffSeverity(start.marker, end.marker, context.calendarSystem);
1023            if (!diffSeverity) {
1024                return this.format(start, context);
1025            }
1026            let biggestUnitForPartial = diffSeverity;
1027            if (biggestUnitForPartial > 1 && // the two dates are different in a way that's larger scale than time
1028                (standardDateProps.year === 'numeric' || standardDateProps.year === '2-digit') &&
1029                (standardDateProps.month === 'numeric' || standardDateProps.month === '2-digit') &&
1030                (standardDateProps.day === 'numeric' || standardDateProps.day === '2-digit')) {
1031                biggestUnitForPartial = 1; // make it look like the dates are only different in terms of time
1032            }
1033            let full0 = this.format(start, context);
1034            let full1 = this.format(end, context);
1035            if (full0 === full1) {
1036                return full0;
1037            }
1038            let partialDateProps = computePartialFormattingOptions(standardDateProps, biggestUnitForPartial);
1039            let partialFormattingFunc = buildFormattingFunc(partialDateProps, extendedSettings, context);
1040            let partial0 = partialFormattingFunc(start);
1041            let partial1 = partialFormattingFunc(end);
1042            let insertion = findCommonInsertion(full0, partial0, full1, partial1);
1043            let separator = extendedSettings.separator || betterDefaultSeparator || context.defaultSeparator || '';
1044            if (insertion) {
1045                return insertion.before + partial0 + separator + partial1 + insertion.after;
1046            }
1047            return full0 + separator + full1;
1048        }
1049        getLargestUnit() {
1050            switch (this.severity) {
1051                case 7:
1052                case 6:
1053                case 5:
1054                    return 'year';
1055                case 4:
1056                    return 'month';
1057                case 3:
1058                    return 'week';
1059                case 2:
1060                    return 'day';
1061                default:
1062                    return 'time'; // really?
1063            }
1064        }
1065    }
1066    function buildFormattingFunc(standardDateProps, extendedSettings, context) {
1067        let standardDatePropCnt = Object.keys(standardDateProps).length;
1068        if (standardDatePropCnt === 1 && standardDateProps.timeZoneName === 'short') {
1069            return (date) => (formatTimeZoneOffset(date.timeZoneOffset));
1070        }
1071        if (standardDatePropCnt === 0 && extendedSettings.week) {
1072            return (date) => (formatWeekNumber(context.computeWeekNumber(date.marker), context.weekText, context.weekTextLong, context.locale, extendedSettings.week));
1073        }
1074        return buildNativeFormattingFunc(standardDateProps, extendedSettings, context);
1075    }
1076    function buildNativeFormattingFunc(standardDateProps, extendedSettings, context) {
1077        standardDateProps = Object.assign({}, standardDateProps); // copy
1078        extendedSettings = Object.assign({}, extendedSettings); // copy
1079        sanitizeSettings(standardDateProps, extendedSettings);
1080        standardDateProps.timeZone = 'UTC'; // we leverage the only guaranteed timeZone for our UTC markers
1081        let normalFormat = new Intl.DateTimeFormat(context.locale.codes, standardDateProps);
1082        let zeroFormat; // needed?
1083        if (extendedSettings.omitZeroMinute) {
1084            let zeroProps = Object.assign({}, standardDateProps);
1085            delete zeroProps.minute; // seconds and ms were already considered in sanitizeSettings
1086            zeroFormat = new Intl.DateTimeFormat(context.locale.codes, zeroProps);
1087        }
1088        return (date) => {
1089            let { marker } = date;
1090            let format;
1091            if (zeroFormat && !marker.getUTCMinutes()) {
1092                format = zeroFormat;
1093            }
1094            else {
1095                format = normalFormat;
1096            }
1097            let s = format.format(marker);
1098            return postProcess(s, date, standardDateProps, extendedSettings, context);
1099        };
1100    }
1101    function sanitizeSettings(standardDateProps, extendedSettings) {
1102        // deal with a browser inconsistency where formatting the timezone
1103        // requires that the hour/minute be present.
1104        if (standardDateProps.timeZoneName) {
1105            if (!standardDateProps.hour) {
1106                standardDateProps.hour = '2-digit';
1107            }
1108            if (!standardDateProps.minute) {
1109                standardDateProps.minute = '2-digit';
1110            }
1111        }
1112        // only support short timezone names
1113        if (standardDateProps.timeZoneName === 'long') {
1114            standardDateProps.timeZoneName = 'short';
1115        }
1116        // if requesting to display seconds, MUST display minutes
1117        if (extendedSettings.omitZeroMinute && (standardDateProps.second || standardDateProps.millisecond)) {
1118            delete extendedSettings.omitZeroMinute;
1119        }
1120    }
1121    function postProcess(s, date, standardDateProps, extendedSettings, context) {
1122        s = s.replace(LTR_RE, ''); // remove left-to-right control chars. do first. good for other regexes
1123        if (standardDateProps.timeZoneName === 'short') {
1124            s = injectTzoStr(s, (context.timeZone === 'UTC' || date.timeZoneOffset == null) ?
1125                'UTC' : // important to normalize for IE, which does "GMT"
1126                formatTimeZoneOffset(date.timeZoneOffset));
1127        }
1128        if (extendedSettings.omitCommas) {
1129            s = s.replace(COMMA_RE, '').trim();
1130        }
1131        if (extendedSettings.omitZeroMinute) {
1132            s = s.replace(':00', ''); // zeroFormat doesn't always achieve this
1133        }
1134        // ^ do anything that might create adjacent spaces before this point,
1135        // because MERIDIEM_RE likes to eat up loading spaces
1136        if (extendedSettings.meridiem === false) {
1137            s = s.replace(MERIDIEM_RE, '').trim();
1138        }
1139        else if (extendedSettings.meridiem === 'narrow') { // a/p
1140            s = s.replace(MERIDIEM_RE, (m0, m1) => m1.toLocaleLowerCase());
1141        }
1142        else if (extendedSettings.meridiem === 'short') { // am/pm
1143            s = s.replace(MERIDIEM_RE, (m0, m1) => `${m1.toLocaleLowerCase()}m`);
1144        }
1145        else if (extendedSettings.meridiem === 'lowercase') { // other meridiem transformers already converted to lowercase
1146            s = s.replace(MERIDIEM_RE, (m0) => m0.toLocaleLowerCase());
1147        }
1148        s = s.replace(MULTI_SPACE_RE, ' ');
1149        s = s.trim();
1150        return s;
1151    }
1152    function injectTzoStr(s, tzoStr) {
1153        let replaced = false;
1154        s = s.replace(UTC_RE, () => {
1155            replaced = true;
1156            return tzoStr;
1157        });
1158        // IE11 doesn't include UTC/GMT in the original string, so append to end
1159        if (!replaced) {
1160            s += ` ${tzoStr}`;
1161        }
1162        return s;
1163    }
1164    function formatWeekNumber(num, weekText, weekTextLong, locale, display) {
1165        let parts = [];
1166        if (display === 'long') {
1167            parts.push(weekTextLong);
1168        }
1169        else if (display === 'short' || display === 'narrow') {
1170            parts.push(weekText);
1171        }
1172        if (display === 'long' || display === 'short') {
1173            parts.push(' ');
1174        }
1175        parts.push(locale.simpleNumberFormat.format(num));
1176        if (locale.options.direction === 'rtl') { // TODO: use control characters instead?
1177            parts.reverse();
1178        }
1179        return parts.join('');
1180    }
1181    // Range Formatting Utils
1182    // 0 = exactly the same
1183    // 1 = different by time
1184    // and bigger
1185    function computeMarkerDiffSeverity(d0, d1, ca) {
1186        if (ca.getMarkerYear(d0) !== ca.getMarkerYear(d1)) {
1187            return 5;
1188        }
1189        if (ca.getMarkerMonth(d0) !== ca.getMarkerMonth(d1)) {
1190            return 4;
1191        }
1192        if (ca.getMarkerDay(d0) !== ca.getMarkerDay(d1)) {
1193            return 2;
1194        }
1195        if (timeAsMs(d0) !== timeAsMs(d1)) {
1196            return 1;
1197        }
1198        return 0;
1199    }
1200    function computePartialFormattingOptions(options, biggestUnit) {
1201        let partialOptions = {};
1202        for (let name in options) {
1203            if (!(name in STANDARD_DATE_PROP_SEVERITIES) || // not a date part prop (like timeZone)
1204                STANDARD_DATE_PROP_SEVERITIES[name] <= biggestUnit) {
1205                partialOptions[name] = options[name];
1206            }
1207        }
1208        return partialOptions;
1209    }
1210    function findCommonInsertion(full0, partial0, full1, partial1) {
1211        let i0 = 0;
1212        while (i0 < full0.length) {
1213            let found0 = full0.indexOf(partial0, i0);
1214            if (found0 === -1) {
1215                break;
1216            }
1217            let before0 = full0.substr(0, found0);
1218            i0 = found0 + partial0.length;
1219            let after0 = full0.substr(i0);
1220            let i1 = 0;
1221            while (i1 < full1.length) {
1222                let found1 = full1.indexOf(partial1, i1);
1223                if (found1 === -1) {
1224                    break;
1225                }
1226                let before1 = full1.substr(0, found1);
1227                i1 = found1 + partial1.length;
1228                let after1 = full1.substr(i1);
1229                if (before0 === before1 && after0 === after1) {
1230                    return {
1231                        before: before0,
1232                        after: after0,
1233                    };
1234                }
1235            }
1236        }
1237        return null;
1238    }
1239
1240    function expandZonedMarker(dateInfo, calendarSystem) {
1241        let a = calendarSystem.markerToArray(dateInfo.marker);
1242        return {
1243            marker: dateInfo.marker,
1244            timeZoneOffset: dateInfo.timeZoneOffset,
1245            array: a,
1246            year: a[0],
1247            month: a[1],
1248            day: a[2],
1249            hour: a[3],
1250            minute: a[4],
1251            second: a[5],
1252            millisecond: a[6],
1253        };
1254    }
1255
1256    function createVerboseFormattingArg(start, end, context, betterDefaultSeparator) {
1257        let startInfo = expandZonedMarker(start, context.calendarSystem);
1258        let endInfo = end ? expandZonedMarker(end, context.calendarSystem) : null;
1259        return {
1260            date: startInfo,
1261            start: startInfo,
1262            end: endInfo,
1263            timeZone: context.timeZone,
1264            localeCodes: context.locale.codes,
1265            defaultSeparator: betterDefaultSeparator || context.defaultSeparator,
1266        };
1267    }
1268
1269    /*
1270    TODO: fix the terminology of "formatter" vs "formatting func"
1271    */
1272    /*
1273    At the time of instantiation, this object does not know which cmd-formatting system it will use.
1274    It receives this at the time of formatting, as a setting.
1275    */
1276    class CmdFormatter {
1277        constructor(cmdStr) {
1278            this.cmdStr = cmdStr;
1279        }
1280        format(date, context, betterDefaultSeparator) {
1281            return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(date, null, context, betterDefaultSeparator));
1282        }
1283        formatRange(start, end, context, betterDefaultSeparator) {
1284            return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(start, end, context, betterDefaultSeparator));
1285        }
1286    }
1287
1288    class FuncFormatter {
1289        constructor(func) {
1290            this.func = func;
1291        }
1292        format(date, context, betterDefaultSeparator) {
1293            return this.func(createVerboseFormattingArg(date, null, context, betterDefaultSeparator));
1294        }
1295        formatRange(start, end, context, betterDefaultSeparator) {
1296            return this.func(createVerboseFormattingArg(start, end, context, betterDefaultSeparator));
1297        }
1298    }
1299
1300    function createFormatter(input) {
1301        if (typeof input === 'object' && input) { // non-null object
1302            return new NativeFormatter(input);
1303        }
1304        if (typeof input === 'string') {
1305            return new CmdFormatter(input);
1306        }
1307        if (typeof input === 'function') {
1308            return new FuncFormatter(input);
1309        }
1310        return null;
1311    }
1312
1313    // base options
1314    // ------------
1315    const BASE_OPTION_REFINERS = {
1316        navLinkDayClick: identity,
1317        navLinkWeekClick: identity,
1318        duration: createDuration,
1319        bootstrapFontAwesome: identity,
1320        buttonIcons: identity,
1321        customButtons: identity,
1322        defaultAllDayEventDuration: createDuration,
1323        defaultTimedEventDuration: createDuration,
1324        nextDayThreshold: createDuration,
1325        scrollTime: createDuration,
1326        scrollTimeReset: Boolean,
1327        slotMinTime: createDuration,
1328        slotMaxTime: createDuration,
1329        dayPopoverFormat: createFormatter,
1330        slotDuration: createDuration,
1331        snapDuration: createDuration,
1332        headerToolbar: identity,
1333        footerToolbar: identity,
1334        defaultRangeSeparator: String,
1335        titleRangeSeparator: String,
1336        forceEventDuration: Boolean,
1337        dayHeaders: Boolean,
1338        dayHeaderFormat: createFormatter,
1339        dayHeaderClassNames: identity,
1340        dayHeaderContent: identity,
1341        dayHeaderDidMount: identity,
1342        dayHeaderWillUnmount: identity,
1343        dayCellClassNames: identity,
1344        dayCellContent: identity,
1345        dayCellDidMount: identity,
1346        dayCellWillUnmount: identity,
1347        initialView: String,
1348        aspectRatio: Number,
1349        weekends: Boolean,
1350        weekNumberCalculation: identity,
1351        weekNumbers: Boolean,
1352        weekNumberClassNames: identity,
1353        weekNumberContent: identity,
1354        weekNumberDidMount: identity,
1355        weekNumberWillUnmount: identity,
1356        editable: Boolean,
1357        viewClassNames: identity,
1358        viewDidMount: identity,
1359        viewWillUnmount: identity,
1360        nowIndicator: Boolean,
1361        nowIndicatorClassNames: identity,
1362        nowIndicatorContent: identity,
1363        nowIndicatorDidMount: identity,
1364        nowIndicatorWillUnmount: identity,
1365        showNonCurrentDates: Boolean,
1366        lazyFetching: Boolean,
1367        startParam: String,
1368        endParam: String,
1369        timeZoneParam: String,
1370        timeZone: String,
1371        locales: identity,
1372        locale: identity,
1373        themeSystem: String,
1374        dragRevertDuration: Number,
1375        dragScroll: Boolean,
1376        allDayMaintainDuration: Boolean,
1377        unselectAuto: Boolean,
1378        dropAccept: identity,
1379        eventOrder: parseFieldSpecs,
1380        eventOrderStrict: Boolean,
1381        handleWindowResize: Boolean,
1382        windowResizeDelay: Number,
1383        longPressDelay: Number,
1384        eventDragMinDistance: Number,
1385        expandRows: Boolean,
1386        height: identity,
1387        contentHeight: identity,
1388        direction: String,
1389        weekNumberFormat: createFormatter,
1390        eventResizableFromStart: Boolean,
1391        displayEventTime: Boolean,
1392        displayEventEnd: Boolean,
1393        weekText: String,
1394        weekTextLong: String,
1395        progressiveEventRendering: Boolean,
1396        businessHours: identity,
1397        initialDate: identity,
1398        now: identity,
1399        eventDataTransform: identity,
1400        stickyHeaderDates: identity,
1401        stickyFooterScrollbar: identity,
1402        viewHeight: identity,
1403        defaultAllDay: Boolean,
1404        eventSourceFailure: identity,
1405        eventSourceSuccess: identity,
1406        eventDisplay: String,
1407        eventStartEditable: Boolean,
1408        eventDurationEditable: Boolean,
1409        eventOverlap: identity,
1410        eventConstraint: identity,
1411        eventAllow: identity,
1412        eventBackgroundColor: String,
1413        eventBorderColor: String,
1414        eventTextColor: String,
1415        eventColor: String,
1416        eventClassNames: identity,
1417        eventContent: identity,
1418        eventDidMount: identity,
1419        eventWillUnmount: identity,
1420        selectConstraint: identity,
1421        selectOverlap: identity,
1422        selectAllow: identity,
1423        droppable: Boolean,
1424        unselectCancel: String,
1425        slotLabelFormat: identity,
1426        slotLaneClassNames: identity,
1427        slotLaneContent: identity,
1428        slotLaneDidMount: identity,
1429        slotLaneWillUnmount: identity,
1430        slotLabelClassNames: identity,
1431        slotLabelContent: identity,
1432        slotLabelDidMount: identity,
1433        slotLabelWillUnmount: identity,
1434        dayMaxEvents: identity,
1435        dayMaxEventRows: identity,
1436        dayMinWidth: Number,
1437        slotLabelInterval: createDuration,
1438        allDayText: String,
1439        allDayClassNames: identity,
1440        allDayContent: identity,
1441        allDayDidMount: identity,
1442        allDayWillUnmount: identity,
1443        slotMinWidth: Number,
1444        navLinks: Boolean,
1445        eventTimeFormat: createFormatter,
1446        rerenderDelay: Number,
1447        moreLinkText: identity,
1448        moreLinkHint: identity,
1449        selectMinDistance: Number,
1450        selectable: Boolean,
1451        selectLongPressDelay: Number,
1452        eventLongPressDelay: Number,
1453        selectMirror: Boolean,
1454        eventMaxStack: Number,
1455        eventMinHeight: Number,
1456        eventMinWidth: Number,
1457        eventShortHeight: Number,
1458        slotEventOverlap: Boolean,
1459        plugins: identity,
1460        firstDay: Number,
1461        dayCount: Number,
1462        dateAlignment: String,
1463        dateIncrement: createDuration,
1464        hiddenDays: identity,
1465        fixedWeekCount: Boolean,
1466        validRange: identity,
1467        visibleRange: identity,
1468        titleFormat: identity,
1469        eventInteractive: Boolean,
1470        // only used by list-view, but languages define the value, so we need it in base options
1471        noEventsText: String,
1472        viewHint: identity,
1473        navLinkHint: identity,
1474        closeHint: String,
1475        timeHint: String,
1476        eventHint: String,
1477        moreLinkClick: identity,
1478        moreLinkClassNames: identity,
1479        moreLinkContent: identity,
1480        moreLinkDidMount: identity,
1481        moreLinkWillUnmount: identity,
1482        monthStartFormat: createFormatter,
1483        // for connectors
1484        // (can't be part of plugin system b/c must be provided at runtime)
1485        handleCustomRendering: identity,
1486        customRenderingMetaMap: identity,
1487        customRenderingReplaces: Boolean,
1488    };
1489    // do NOT give a type here. need `typeof BASE_OPTION_DEFAULTS` to give real results.
1490    // raw values.
1491    const BASE_OPTION_DEFAULTS = {
1492        eventDisplay: 'auto',
1493        defaultRangeSeparator: ' - ',
1494        titleRangeSeparator: ' \u2013 ',
1495        defaultTimedEventDuration: '01:00:00',
1496        defaultAllDayEventDuration: { day: 1 },
1497        forceEventDuration: false,
1498        nextDayThreshold: '00:00:00',
1499        dayHeaders: true,
1500        initialView: '',
1501        aspectRatio: 1.35,
1502        headerToolbar: {
1503            start: 'title',
1504            center: '',
1505            end: 'today prev,next',
1506        },
1507        weekends: true,
1508        weekNumbers: false,
1509        weekNumberCalculation: 'local',
1510        editable: false,
1511        nowIndicator: false,
1512        scrollTime: '06:00:00',
1513        scrollTimeReset: true,
1514        slotMinTime: '00:00:00',
1515        slotMaxTime: '24:00:00',
1516        showNonCurrentDates: true,
1517        lazyFetching: true,
1518        startParam: 'start',
1519        endParam: 'end',
1520        timeZoneParam: 'timeZone',
1521        timeZone: 'local',
1522        locales: [],
1523        locale: '',
1524        themeSystem: 'standard',
1525        dragRevertDuration: 500,
1526        dragScroll: true,
1527        allDayMaintainDuration: false,
1528        unselectAuto: true,
1529        dropAccept: '*',
1530        eventOrder: 'start,-duration,allDay,title',
1531        dayPopoverFormat: { month: 'long', day: 'numeric', year: 'numeric' },
1532        handleWindowResize: true,
1533        windowResizeDelay: 100,
1534        longPressDelay: 1000,
1535        eventDragMinDistance: 5,
1536        expandRows: false,
1537        navLinks: false,
1538        selectable: false,
1539        eventMinHeight: 15,
1540        eventMinWidth: 30,
1541        eventShortHeight: 30,
1542        monthStartFormat: { month: 'long', day: 'numeric' },
1543    };
1544    // calendar listeners
1545    // ------------------
1546    const CALENDAR_LISTENER_REFINERS = {
1547        datesSet: identity,
1548        eventsSet: identity,
1549        eventAdd: identity,
1550        eventChange: identity,
1551        eventRemove: identity,
1552        windowResize: identity,
1553        eventClick: identity,
1554        eventMouseEnter: identity,
1555        eventMouseLeave: identity,
1556        select: identity,
1557        unselect: identity,
1558        loading: identity,
1559        // internal
1560        _unmount: identity,
1561        _beforeprint: identity,
1562        _afterprint: identity,
1563        _noEventDrop: identity,
1564        _noEventResize: identity,
1565        _resize: identity,
1566        _scrollRequest: identity,
1567    };
1568    // calendar-specific options
1569    // -------------------------
1570    const CALENDAR_OPTION_REFINERS = {
1571        buttonText: identity,
1572        buttonHints: identity,
1573        views: identity,
1574        plugins: identity,
1575        initialEvents: identity,
vendor: 10,012 bytes, lines 1576-1869
1576        events: identity,
1577        eventSources: identity,
1578    };
1579    const COMPLEX_OPTION_COMPARATORS = {
1580        headerToolbar: isMaybeObjectsEqual,
1581        footerToolbar: isMaybeObjectsEqual,
1582        buttonText: isMaybeObjectsEqual,
1583        buttonHints: isMaybeObjectsEqual,
1584        buttonIcons: isMaybeObjectsEqual,
1585        dateIncrement: isMaybeObjectsEqual,
1586        plugins: isMaybeArraysEqual,
1587        events: isMaybeArraysEqual,
1588        eventSources: isMaybeArraysEqual,
1589        ['resources']: isMaybeArraysEqual,
1590    };
1591    function isMaybeObjectsEqual(a, b) {
1592        if (typeof a === 'object' && typeof b === 'object' && a && b) { // both non-null objects
1593            return isPropsEqual(a, b);
1594        }
1595        return a === b;
1596    }
1597    function isMaybeArraysEqual(a, b) {
1598        if (Array.isArray(a) && Array.isArray(b)) {
1599            return isArraysEqual(a, b);
1600        }
1601        return a === b;
1602    }
1603    // view-specific options
1604    // ---------------------
1605    const VIEW_OPTION_REFINERS = {
1606        type: String,
1607        component: identity,
1608        buttonText: String,
1609        buttonTextKey: String,
1610        dateProfileGeneratorClass: identity,
1611        usesMinMaxTime: Boolean,
1612        classNames: identity,
1613        content: identity,
1614        didMount: identity,
1615        willUnmount: identity,
1616    };
1617    // util funcs
1618    // ----------------------------------------------------------------------------------------------------
1619    function mergeRawOptions(optionSets) {
1620        return mergeProps(optionSets, COMPLEX_OPTION_COMPARATORS);
1621    }
1622    function refineProps(input, refiners) {
1623        let refined = {};
1624        let extra = {};
1625        for (let propName in refiners) {
1626            if (propName in input) {
1627                refined[propName] = refiners[propName](input[propName]);
1628            }
1629        }
1630        for (let propName in input) {
1631            if (!(propName in refiners)) {
1632                extra[propName] = input[propName];
1633            }
1634        }
1635        return { refined, extra };
1636    }
1637    function identity(raw) {
1638        return raw;
1639    }
1640
1641    const { hasOwnProperty } = Object.prototype;
1642    // Merges an array of objects into a single object.
1643    // The second argument allows for an array of property names who's object values will be merged together.
1644    function mergeProps(propObjs, complexPropsMap) {
1645        let dest = {};
1646        if (complexPropsMap) {
1647            for (let name in complexPropsMap) {
1648                if (complexPropsMap[name] === isMaybeObjectsEqual) { // implies that it's object-mergeable
1649                    let complexObjs = [];
1650                    // collect the trailing object values, stopping when a non-object is discovered
1651                    for (let i = propObjs.length - 1; i >= 0; i -= 1) {
1652                        let val = propObjs[i][name];
1653                        if (typeof val === 'object' && val) { // non-null object
1654                            complexObjs.unshift(val);
1655                        }
1656                        else if (val !== undefined) {
1657                            dest[name] = val; // if there were no objects, this value will be used
1658                            break;
1659                        }
1660                    }
1661                    // if the trailing values were objects, use the merged value
1662                    if (complexObjs.length) {
1663                        dest[name] = mergeProps(complexObjs);
1664                    }
1665                }
1666            }
1667        }
1668        // copy values into the destination, going from last to first
1669        for (let i = propObjs.length - 1; i >= 0; i -= 1) {
1670            let props = propObjs[i];
1671            for (let name in props) {
1672                if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign
1673                    dest[name] = props[name];
1674                }
1675            }
1676        }
1677        return dest;
1678    }
1679    function filterHash(hash, func) {
1680        let filtered = {};
1681        for (let key in hash) {
1682            if (func(hash[key], key)) {
1683                filtered[key] = hash[key];
1684            }
1685        }
1686        return filtered;
1687    }
1688    function mapHash(hash, func) {
1689        let newHash = {};
1690        for (let key in hash) {
1691            newHash[key] = func(hash[key], key);
1692        }
1693        return newHash;
1694    }
1695    function arrayToHash(a) {
1696        let hash = {};
1697        for (let item of a) {
1698            hash[item] = true;
1699        }
1700        return hash;
1701    }
1702    // TODO: reassess browser support
1703    // https://caniuse.com/?search=object.values
1704    function hashValuesToArray(obj) {
1705        let a = [];
1706        for (let key in obj) {
1707            a.push(obj[key]);
1708        }
1709        return a;
1710    }
1711    function isPropsEqual(obj0, obj1) {
1712        if (obj0 === obj1) {
1713            return true;
1714        }
1715        for (let key in obj0) {
1716            if (hasOwnProperty.call(obj0, key)) {
1717                if (!(key in obj1)) {
1718                    return false;
1719                }
1720            }
1721        }
1722        for (let key in obj1) {
1723            if (hasOwnProperty.call(obj1, key)) {
1724                if (obj0[key] !== obj1[key]) {
1725                    return false;
1726                }
1727            }
1728        }
1729        return true;
1730    }
1731    const HANDLER_RE = /^on[A-Z]/;
1732    function isNonHandlerPropsEqual(obj0, obj1) {
1733        const keys = getUnequalProps(obj0, obj1);
1734        for (let key of keys) {
1735            if (!HANDLER_RE.test(key)) {
1736                return false;
1737            }
1738        }
1739        return true;
1740    }
1741    function getUnequalProps(obj0, obj1) {
1742        let keys = [];
1743        for (let key in obj0) {
1744            if (hasOwnProperty.call(obj0, key)) {
1745                if (!(key in obj1)) {
1746                    keys.push(key);
1747                }
1748            }
1749        }
1750        for (let key in obj1) {
1751            if (hasOwnProperty.call(obj1, key)) {
1752                if (obj0[key] !== obj1[key]) {
1753                    keys.push(key);
1754                }
1755            }
1756        }
1757        return keys;
1758    }
1759    function compareObjs(oldProps, newProps, equalityFuncs = {}) {
1760        if (oldProps === newProps) {
1761            return true;
1762        }
1763        for (let key in newProps) {
1764            if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) ;
1765            else {
1766                return false;
1767            }
1768        }
1769        // check for props that were omitted in the new
1770        for (let key in oldProps) {
1771            if (!(key in newProps)) {
1772                return false;
1773            }
1774        }
1775        return true;
1776    }
1777    /*
1778    assumed "true" equality for handler names like "onReceiveSomething"
1779    */
1780    function isObjValsEqual(val0, val1, comparator) {
1781        if (val0 === val1 || comparator === true) {
1782            return true;
1783        }
1784        if (comparator) {
1785            return comparator(val0, val1);
1786        }
1787        return false;
1788    }
1789    function collectFromHash(hash, startIndex = 0, endIndex, step = 1) {
1790        let res = [];
1791        if (endIndex == null) {
1792            endIndex = Object.keys(hash).length;
1793        }
1794        for (let i = startIndex; i < endIndex; i += step) {
1795            let val = hash[i];
1796            if (val !== undefined) { // will disregard undefined for sparse arrays
1797                res.push(val);
1798            }
1799        }
1800        return res;
1801    }
1802
1803    let calendarSystemClassMap = {};
1804    function registerCalendarSystem(name, theClass) {
1805        calendarSystemClassMap[name] = theClass;
1806    }
1807    function createCalendarSystem(name) {
1808        return new calendarSystemClassMap[name]();
1809    }
1810    class GregorianCalendarSystem {
1811        getMarkerYear(d) {
1812            return d.getUTCFullYear();
1813        }
1814        getMarkerMonth(d) {
1815            return d.getUTCMonth();
1816        }
1817        getMarkerDay(d) {
1818            return d.getUTCDate();
1819        }
1820        arrayToMarker(arr) {
1821            return arrayToUtcDate(arr);
1822        }
1823        markerToArray(marker) {
1824            return dateToUtcArray(marker);
1825        }
1826    }
1827    registerCalendarSystem('gregory', GregorianCalendarSystem);
1828
1829    const ISO_RE = /^\s*(\d{4})(-?(\d{2})(-?(\d{2})([T ](\d{2}):?(\d{2})(:?(\d{2})(\.(\d+))?)?(Z|(([-+])(\d{2})(:?(\d{2}))?))?)?)?)?$/;
1830    function parse(str) {
1831        let m = ISO_RE.exec(str);
1832        if (m) {
1833            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));
1834            if (isValidDate(marker)) {
1835                let timeZoneOffset = null;
1836                if (m[13]) {
1837                    timeZoneOffset = (m[15] === '-' ? -1 : 1) * (Number(m[16] || 0) * 60 +
1838                        Number(m[18] || 0));
1839                }
1840                return {
1841                    marker,
1842                    isTimeUnspecified: !m[6],
1843                    timeZoneOffset,
1844                };
1845            }
1846        }
1847        return null;
1848    }
1849
1850    class DateEnv {
1851        constructor(settings) {
1852            let timeZone = this.timeZone = settings.timeZone;
1853            let isNamedTimeZone = timeZone !== 'local' && timeZone !== 'UTC';
1854            if (settings.namedTimeZoneImpl && isNamedTimeZone) {
1855                this.namedTimeZoneImpl = new settings.namedTimeZoneImpl(timeZone);
1856            }
1857            this.canComputeOffset = Boolean(!isNamedTimeZone || this.namedTimeZoneImpl);
1858            this.calendarSystem = createCalendarSystem(settings.calendarSystem);
1859            this.locale = settings.locale;
1860            this.weekDow = settings.locale.week.dow;
1861            this.weekDoy = settings.locale.week.doy;
1862            if (settings.weekNumberCalculation === 'ISO') {
1863                this.weekDow = 1;
1864                this.weekDoy = 4;
1865            }
1866            if (typeof settings.firstDay === 'number') {
1867                this.weekDow = settings.firstDay;
1868            }
1869            if (typeof settings.weekNumberCalculation === 'function') {
vendor: 2,020 bytes, lines 1870-1920
1870                this.weekNumberFunc = settings.weekNumberCalculation;
1871            }
1872            this.weekText = settings.weekText != null ? settings.weekText : settings.locale.options.weekText;
1873            this.weekTextLong = (settings.weekTextLong != null ? settings.weekTextLong : settings.locale.options.weekTextLong) || this.weekText;
1874            this.cmdFormatter = settings.cmdFormatter;
1875            this.defaultSeparator = settings.defaultSeparator;
1876        }
1877        // Creating / Parsing
1878        createMarker(input) {
1879            let meta = this.createMarkerMeta(input);
1880            if (meta === null) {
1881                return null;
1882            }
1883            return meta.marker;
1884        }
1885        createNowMarker() {
1886            if (this.canComputeOffset) {
1887                return this.timestampToMarker(new Date().valueOf());
1888            }
1889            // if we can't compute the current date val for a timezone,
1890            // better to give the current local date vals than UTC
1891            return arrayToUtcDate(dateToLocalArray(new Date()));
1892        }
1893        createMarkerMeta(input) {
1894            if (typeof input === 'string') {
1895                return this.parse(input);
1896            }
1897            let marker = null;
1898            if (typeof input === 'number') {
1899                marker = this.timestampToMarker(input);
1900            }
1901            else if (input instanceof Date) {
1902                input = input.valueOf();
1903                if (!isNaN(input)) {
1904                    marker = this.timestampToMarker(input);
1905                }
1906            }
1907            else if (Array.isArray(input)) {
1908                marker = arrayToUtcDate(input);
1909            }
1910            if (marker === null || !isValidDate(marker)) {
1911                return null;
1912            }
1913            return { marker, isTimeUnspecified: false, forcedTzo: null };
1914        }
1915        parse(s) {
1916            let parts = parse(s);
1917            if (parts === null) {
1918                return null;
1919            }
1920            let { marker } = parts;
vendor: 32,328 bytes, lines 1921-2726
1921            let forcedTzo = null;
1922            if (parts.timeZoneOffset !== null) {
1923                if (this.canComputeOffset) {
1924                    marker = this.timestampToMarker(marker.valueOf() - parts.timeZoneOffset * 60 * 1000);
1925                }
1926                else {
1927                    forcedTzo = parts.timeZoneOffset;
1928                }
1929            }
1930            return { marker, isTimeUnspecified: parts.isTimeUnspecified, forcedTzo };
1931        }
1932        // Accessors
1933        getYear(marker) {
1934            return this.calendarSystem.getMarkerYear(marker);
1935        }
1936        getMonth(marker) {
1937            return this.calendarSystem.getMarkerMonth(marker);
1938        }
1939        getDay(marker) {
1940            return this.calendarSystem.getMarkerDay(marker);
1941        }
1942        // Adding / Subtracting
1943        add(marker, dur) {
1944            let a = this.calendarSystem.markerToArray(marker);
1945            a[0] += dur.years;
1946            a[1] += dur.months;
1947            a[2] += dur.days;
1948            a[6] += dur.milliseconds;
1949            return this.calendarSystem.arrayToMarker(a);
1950        }
1951        subtract(marker, dur) {
1952            let a = this.calendarSystem.markerToArray(marker);
1953            a[0] -= dur.years;
1954            a[1] -= dur.months;
1955            a[2] -= dur.days;
1956            a[6] -= dur.milliseconds;
1957            return this.calendarSystem.arrayToMarker(a);
1958        }
1959        addYears(marker, n) {
1960            let a = this.calendarSystem.markerToArray(marker);
1961            a[0] += n;
1962            return this.calendarSystem.arrayToMarker(a);
1963        }
1964        addMonths(marker, n) {
1965            let a = this.calendarSystem.markerToArray(marker);
1966            a[1] += n;
1967            return this.calendarSystem.arrayToMarker(a);
1968        }
1969        // Diffing Whole Units
1970        diffWholeYears(m0, m1) {
1971            let { calendarSystem } = this;
1972            if (timeAsMs(m0) === timeAsMs(m1) &&
1973                calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1) &&
1974                calendarSystem.getMarkerMonth(m0) === calendarSystem.getMarkerMonth(m1)) {
1975                return calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0);
1976            }
1977            return null;
1978        }
1979        diffWholeMonths(m0, m1) {
1980            let { calendarSystem } = this;
1981            if (timeAsMs(m0) === timeAsMs(m1) &&
1982                calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1)) {
1983                return (calendarSystem.getMarkerMonth(m1) - calendarSystem.getMarkerMonth(m0)) +
1984                    (calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0)) * 12;
1985            }
1986            return null;
1987        }
1988        // Range / Duration
1989        greatestWholeUnit(m0, m1) {
1990            let n = this.diffWholeYears(m0, m1);
1991            if (n !== null) {
1992                return { unit: 'year', value: n };
1993            }
1994            n = this.diffWholeMonths(m0, m1);
1995            if (n !== null) {
1996                return { unit: 'month', value: n };
1997            }
1998            n = diffWholeWeeks(m0, m1);
1999            if (n !== null) {
2000                return { unit: 'week', value: n };
2001            }
2002            n = diffWholeDays(m0, m1);
2003            if (n !== null) {
2004                return { unit: 'day', value: n };
2005            }
2006            n = diffHours(m0, m1);
2007            if (isInt(n)) {
2008                return { unit: 'hour', value: n };
2009            }
2010            n = diffMinutes(m0, m1);
2011            if (isInt(n)) {
2012                return { unit: 'minute', value: n };
2013            }
2014            n = diffSeconds(m0, m1);
2015            if (isInt(n)) {
2016                return { unit: 'second', value: n };
2017            }
2018            return { unit: 'millisecond', value: m1.valueOf() - m0.valueOf() };
2019        }
2020        countDurationsBetween(m0, m1, d) {
2021            // TODO: can use greatestWholeUnit
2022            let diff;
2023            if (d.years) {
2024                diff = this.diffWholeYears(m0, m1);
2025                if (diff !== null) {
2026                    return diff / asRoughYears(d);
2027                }
2028            }
2029            if (d.months) {
2030                diff = this.diffWholeMonths(m0, m1);
2031                if (diff !== null) {
2032                    return diff / asRoughMonths(d);
2033                }
2034            }
2035            if (d.days) {
2036                diff = diffWholeDays(m0, m1);
2037                if (diff !== null) {
2038                    return diff / asRoughDays(d);
2039                }
2040            }
2041            return (m1.valueOf() - m0.valueOf()) / asRoughMs(d);
2042        }
2043        // Start-Of
2044        // these DON'T return zoned-dates. only UTC start-of dates
2045        startOf(m, unit) {
2046            if (unit === 'year') {
2047                return this.startOfYear(m);
2048            }
2049            if (unit === 'month') {
2050                return this.startOfMonth(m);
2051            }
2052            if (unit === 'week') {
2053                return this.startOfWeek(m);
2054            }
2055            if (unit === 'day') {
2056                return startOfDay(m);
2057            }
2058            if (unit === 'hour') {
2059                return startOfHour(m);
2060            }
2061            if (unit === 'minute') {
2062                return startOfMinute(m);
2063            }
2064            if (unit === 'second') {
2065                return startOfSecond(m);
2066            }
2067            return null;
2068        }
2069        startOfYear(m) {
2070            return this.calendarSystem.arrayToMarker([
2071                this.calendarSystem.getMarkerYear(m),
2072            ]);
2073        }
2074        startOfMonth(m) {
2075            return this.calendarSystem.arrayToMarker([
2076                this.calendarSystem.getMarkerYear(m),
2077                this.calendarSystem.getMarkerMonth(m),
2078            ]);
2079        }
2080        startOfWeek(m) {
2081            return this.calendarSystem.arrayToMarker([
2082                this.calendarSystem.getMarkerYear(m),
2083                this.calendarSystem.getMarkerMonth(m),
2084                m.getUTCDate() - ((m.getUTCDay() - this.weekDow + 7) % 7),
2085            ]);
2086        }
2087        // Week Number
2088        computeWeekNumber(marker) {
2089            if (this.weekNumberFunc) {
2090                return this.weekNumberFunc(this.toDate(marker));
2091            }
2092            return weekOfYear(marker, this.weekDow, this.weekDoy);
2093        }
2094        // TODO: choke on timeZoneName: long
2095        format(marker, formatter, dateOptions = {}) {
2096            return formatter.format({
2097                marker,
2098                timeZoneOffset: dateOptions.forcedTzo != null ?
2099                    dateOptions.forcedTzo :
2100                    this.offsetForMarker(marker),
2101            }, this);
2102        }
2103        formatRange(start, end, formatter, dateOptions = {}) {
2104            if (dateOptions.isEndExclusive) {
2105                end = addMs(end, -1);
2106            }
2107            return formatter.formatRange({
2108                marker: start,
2109                timeZoneOffset: dateOptions.forcedStartTzo != null ?
2110                    dateOptions.forcedStartTzo :
2111                    this.offsetForMarker(start),
2112            }, {
2113                marker: end,
2114                timeZoneOffset: dateOptions.forcedEndTzo != null ?
2115                    dateOptions.forcedEndTzo :
2116                    this.offsetForMarker(end),
2117            }, this, dateOptions.defaultSeparator);
2118        }
2119        /*
2120        DUMB: the omitTime arg is dumb. if we omit the time, we want to omit the timezone offset. and if we do that,
2121        might as well use buildIsoString or some other util directly
2122        */
2123        formatIso(marker, extraOptions = {}) {
2124            let timeZoneOffset = null;
2125            if (!extraOptions.omitTimeZoneOffset) {
2126                if (extraOptions.forcedTzo != null) {
2127                    timeZoneOffset = extraOptions.forcedTzo;
2128                }
2129                else {
2130                    timeZoneOffset = this.offsetForMarker(marker);
2131                }
2132            }
2133            return buildIsoString(marker, timeZoneOffset, extraOptions.omitTime);
2134        }
2135        // TimeZone
2136        timestampToMarker(ms) {
2137            if (this.timeZone === 'local') {
2138                return arrayToUtcDate(dateToLocalArray(new Date(ms)));
2139            }
2140            if (this.timeZone === 'UTC' || !this.namedTimeZoneImpl) {
2141                return new Date(ms);
2142            }
2143            return arrayToUtcDate(this.namedTimeZoneImpl.timestampToArray(ms));
2144        }
2145        offsetForMarker(m) {
2146            if (this.timeZone === 'local') {
2147                return -arrayToLocalDate(dateToUtcArray(m)).getTimezoneOffset(); // convert "inverse" offset to "normal" offset
2148            }
2149            if (this.timeZone === 'UTC') {
2150                return 0;
2151            }
2152            if (this.namedTimeZoneImpl) {
2153                return this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m));
2154            }
2155            return null;
2156        }
2157        // Conversion
2158        toDate(m, forcedTzo) {
2159            if (this.timeZone === 'local') {
2160                return arrayToLocalDate(dateToUtcArray(m));
2161            }
2162            if (this.timeZone === 'UTC') {
2163                return new Date(m.valueOf()); // make sure it's a copy
2164            }
2165            if (!this.namedTimeZoneImpl) {
2166                return new Date(m.valueOf() - (forcedTzo || 0));
2167            }
2168            return new Date(m.valueOf() -
2169                this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)) * 1000 * 60);
2170        }
2171    }
2172
2173    class Theme {
2174        constructor(calendarOptions) {
2175            if (this.iconOverrideOption) {
2176                this.setIconOverride(calendarOptions[this.iconOverrideOption]);
2177            }
2178        }
2179        setIconOverride(iconOverrideHash) {
2180            let iconClassesCopy;
2181            let buttonName;
2182            if (typeof iconOverrideHash === 'object' && iconOverrideHash) { // non-null object
2183                iconClassesCopy = Object.assign({}, this.iconClasses);
2184                for (buttonName in iconOverrideHash) {
2185                    iconClassesCopy[buttonName] = this.applyIconOverridePrefix(iconOverrideHash[buttonName]);
2186                }
2187                this.iconClasses = iconClassesCopy;
2188            }
2189            else if (iconOverrideHash === false) {
2190                this.iconClasses = {};
2191            }
2192        }
2193        applyIconOverridePrefix(className) {
2194            let prefix = this.iconOverridePrefix;
2195            if (prefix && className.indexOf(prefix) !== 0) { // if not already present
2196                className = prefix + className;
2197            }
2198            return className;
2199        }
2200        getClass(key) {
2201            return this.classes[key] || '';
2202        }
2203        getIconClass(buttonName, isRtl) {
2204            let className;
2205            if (isRtl && this.rtlIconClasses) {
2206                className = this.rtlIconClasses[buttonName] || this.iconClasses[buttonName];
2207            }
2208            else {
2209                className = this.iconClasses[buttonName];
2210            }
2211            if (className) {
2212                return `${this.baseIconClass} ${className}`;
2213            }
2214            return '';
2215        }
2216        getCustomButtonIconClass(customButtonProps) {
2217            let className;
2218            if (this.iconOverrideCustomButtonOption) {
2219                className = customButtonProps[this.iconOverrideCustomButtonOption];
2220                if (className) {
2221                    return `${this.baseIconClass} ${this.applyIconOverridePrefix(className)}`;
2222                }
2223            }
2224            return '';
2225        }
2226    }
2227    Theme.prototype.classes = {};
2228    Theme.prototype.iconClasses = {};
2229    Theme.prototype.baseIconClass = '';
2230    Theme.prototype.iconOverridePrefix = '';
2231
2232    /*
2233    NOTE: this can be a public API, especially createElement for hooks.
2234    See examples/typescript-scheduler/src/index.ts
2235    */
2236    function flushSync(runBeforeFlush) {
2237        runBeforeFlush();
2238        let oldDebounceRendering = l$1.debounceRendering; // orig
2239        let callbackQ = [];
2240        function execCallbackSync(callback) {
2241            callbackQ.push(callback);
2242        }
2243        l$1.debounceRendering = execCallbackSync;
2244        D$1(y(FakeComponent, {}), document.createElement('div'));
2245        while (callbackQ.length) {
2246            callbackQ.shift()();
2247        }
2248        l$1.debounceRendering = oldDebounceRendering;
2249    }
2250    class FakeComponent extends x$1 {
2251        render() { return y('div', {}); }
2252        componentDidMount() { this.setState({}); }
2253    }
2254    // TODO: use preact/compat instead?
2255    function createContext(defaultValue) {
2256        let ContextType = G$1(defaultValue);
2257        let origProvider = ContextType.Provider;
2258        ContextType.Provider = function () {
2259            let isNew = !this.getChildContext;
2260            let children = origProvider.apply(this, arguments); // eslint-disable-line prefer-rest-params
2261            if (isNew) {
2262                let subs = [];
2263                this.shouldComponentUpdate = (_props) => {
2264                    if (this.props.value !== _props.value) {
2265                        subs.forEach((c) => {
2266                            c.context = _props.value;
2267                            c.forceUpdate();
2268                        });
2269                    }
2270                };
2271                this.sub = (c) => {
2272                    subs.push(c);
2273                    let old = c.componentWillUnmount;
2274                    c.componentWillUnmount = () => {
2275                        subs.splice(subs.indexOf(c), 1);
2276                        old && old.call(c);
2277                    };
2278                };
2279            }
2280            return children;
2281        };
2282        return ContextType;
2283    }
2284
2285    class ScrollResponder {
2286        constructor(execFunc, emitter, scrollTime, scrollTimeReset) {
2287            this.execFunc = execFunc;
2288            this.emitter = emitter;
2289            this.scrollTime = scrollTime;
2290            this.scrollTimeReset = scrollTimeReset;
2291            this.handleScrollRequest = (request) => {
2292                this.queuedRequest = Object.assign({}, this.queuedRequest || {}, request);
2293                this.drain();
2294            };
2295            emitter.on('_scrollRequest', this.handleScrollRequest);
2296            this.fireInitialScroll();
2297        }
2298        detach() {
2299            this.emitter.off('_scrollRequest', this.handleScrollRequest);
2300        }
2301        update(isDatesNew) {
2302            if (isDatesNew && this.scrollTimeReset) {
2303                this.fireInitialScroll(); // will drain
2304            }
2305            else {
2306                this.drain();
2307            }
2308        }
2309        fireInitialScroll() {
2310            this.handleScrollRequest({
2311                time: this.scrollTime,
2312            });
2313        }
2314        drain() {
2315            if (this.queuedRequest && this.execFunc(this.queuedRequest)) {
2316                this.queuedRequest = null;
2317            }
2318        }
2319    }
2320
2321    const ViewContextType = createContext({}); // for Components
2322    function buildViewContext(viewSpec, viewApi, viewOptions, dateProfileGenerator, dateEnv, theme, pluginHooks, dispatch, getCurrentData, emitter, calendarApi, registerInteractiveComponent, unregisterInteractiveComponent) {
2323        return {
2324            dateEnv,
2325            options: viewOptions,
2326            pluginHooks,
2327            emitter,
2328            dispatch,
2329            getCurrentData,
2330            calendarApi,
2331            viewSpec,
2332            viewApi,
2333            dateProfileGenerator,
2334            theme,
2335            isRtl: viewOptions.direction === 'rtl',
2336            addResizeHandler(handler) {
2337                emitter.on('_resize', handler);
2338            },
2339            removeResizeHandler(handler) {
2340                emitter.off('_resize', handler);
2341            },
2342            createScrollResponder(execFunc) {
2343                return new ScrollResponder(execFunc, emitter, createDuration(viewOptions.scrollTime), viewOptions.scrollTimeReset);
2344            },
2345            registerInteractiveComponent,
2346            unregisterInteractiveComponent,
2347        };
2348    }
2349
2350    /* eslint max-classes-per-file: off */
2351    class PureComponent extends x$1 {
2352        shouldComponentUpdate(nextProps, nextState) {
2353            if (this.debug) {
2354                // eslint-disable-next-line no-console
2355                console.log(getUnequalProps(nextProps, this.props), getUnequalProps(nextState, this.state));
2356            }
2357            return !compareObjs(this.props, nextProps, this.propEquality) ||
2358                !compareObjs(this.state, nextState, this.stateEquality);
2359        }
2360        // HACK for freakin' React StrictMode
2361        safeSetState(newState) {
2362            if (!compareObjs(this.state, Object.assign(Object.assign({}, this.state), newState), this.stateEquality)) {
2363                this.setState(newState);
2364            }
2365        }
2366    }
2367    PureComponent.addPropsEquality = addPropsEquality;
2368    PureComponent.addStateEquality = addStateEquality;
2369    PureComponent.contextType = ViewContextType;
2370    PureComponent.prototype.propEquality = {};
2371    PureComponent.prototype.stateEquality = {};
2372    class BaseComponent extends PureComponent {
2373    }
2374    BaseComponent.contextType = ViewContextType;
2375    function addPropsEquality(propEquality) {
2376        let hash = Object.create(this.prototype.propEquality);
2377        Object.assign(hash, propEquality);
2378        this.prototype.propEquality = hash;
2379    }
2380    function addStateEquality(stateEquality) {
2381        let hash = Object.create(this.prototype.stateEquality);
2382        Object.assign(hash, stateEquality);
2383        this.prototype.stateEquality = hash;
2384    }
2385    // use other one
2386    function setRef(ref, current) {
2387        if (typeof ref === 'function') {
2388            ref(current);
2389        }
2390        else if (ref) {
2391            // see https://github.com/facebook/react/issues/13029
2392            ref.current = current;
2393        }
2394    }
2395
2396    class ContentInjector extends BaseComponent {
2397        constructor() {
2398            super(...arguments);
2399            this.id = guid();
2400            this.queuedDomNodes = [];
2401            this.currentDomNodes = [];
2402            this.handleEl = (el) => {
2403                const { options } = this.context;
2404                const { generatorName } = this.props;
2405                if (!options.customRenderingReplaces || !hasCustomRenderingHandler(generatorName, options)) {
2406                    this.updateElRef(el);
2407                }
2408            };
2409            this.updateElRef = (el) => {
2410                if (this.props.elRef) {
2411                    setRef(this.props.elRef, el);
2412                }
2413            };
2414        }
2415        render() {
2416            const { props, context } = this;
2417            const { options } = context;
2418            const { customGenerator, defaultGenerator, renderProps } = props;
2419            const attrs = buildElAttrs(props, [], this.handleEl);
2420            let useDefault = false;
2421            let innerContent;
2422            let queuedDomNodes = [];
2423            let currentGeneratorMeta;
2424            if (customGenerator != null) {
2425                const customGeneratorRes = typeof customGenerator === 'function' ?
2426                    customGenerator(renderProps, y) :
2427                    customGenerator;
2428                if (customGeneratorRes === true) {
2429                    useDefault = true;
2430                }
2431                else {
2432                    const isObject = customGeneratorRes && typeof customGeneratorRes === 'object'; // non-null
2433                    if (isObject && ('html' in customGeneratorRes)) {
2434                        attrs.dangerouslySetInnerHTML = { __html: customGeneratorRes.html };
2435                    }
2436                    else if (isObject && ('domNodes' in customGeneratorRes)) {
2437                        queuedDomNodes = Array.prototype.slice.call(customGeneratorRes.domNodes);
2438                    }
2439                    else if (isObject
2440                        ? i$1(customGeneratorRes) // vdom node
2441                        : typeof customGeneratorRes !== 'function' // primitive value (like string or number)
2442                    ) {
2443                        // use in vdom
2444                        innerContent = customGeneratorRes;
2445                    }
2446                    else {
2447                        // an exotic object for handleCustomRendering
2448                        currentGeneratorMeta = customGeneratorRes;
2449                    }
2450                }
2451            }
2452            else {
2453                useDefault = !hasCustomRenderingHandler(props.generatorName, options);
2454            }
2455            if (useDefault && defaultGenerator) {
2456                innerContent = defaultGenerator(renderProps);
2457            }
2458            this.queuedDomNodes = queuedDomNodes;
2459            this.currentGeneratorMeta = currentGeneratorMeta;
2460            return y(props.elTag, attrs, innerContent);
2461        }
2462        componentDidMount() {
2463            this.applyQueueudDomNodes();
2464            this.triggerCustomRendering(true);
2465        }
2466        componentDidUpdate() {
2467            this.applyQueueudDomNodes();
2468            this.triggerCustomRendering(true);
2469        }
2470        componentWillUnmount() {
2471            this.triggerCustomRendering(false); // TODO: different API for removal?
2472        }
2473        triggerCustomRendering(isActive) {
2474            var _a;
2475            const { props, context } = this;
2476            const { handleCustomRendering, customRenderingMetaMap } = context.options;
2477            if (handleCustomRendering) {
2478                const generatorMeta = (_a = this.currentGeneratorMeta) !== null && _a !== void 0 ? _a : customRenderingMetaMap === null || customRenderingMetaMap === void 0 ? void 0 : customRenderingMetaMap[props.generatorName];
2479                if (generatorMeta) {
2480                    handleCustomRendering(Object.assign(Object.assign({ id: this.id, isActive, containerEl: this.base, reportNewContainerEl: this.updateElRef, // front-end framework tells us about new container els
2481                        generatorMeta }, props), { elClasses: (props.elClasses || []).filter(isTruthy) }));
2482                }
2483            }
2484        }
2485        applyQueueudDomNodes() {
2486            const { queuedDomNodes, currentDomNodes } = this;
2487            const el = this.base;
2488            if (!isArraysEqual(queuedDomNodes, currentDomNodes)) {
2489                currentDomNodes.forEach(removeElement);
2490                for (let newNode of queuedDomNodes) {
2491                    el.appendChild(newNode);
2492                }
2493                this.currentDomNodes = queuedDomNodes;
2494            }
2495        }
2496    }
2497    ContentInjector.addPropsEquality({
2498        elClasses: isArraysEqual,
2499        elStyle: isPropsEqual,
2500        elAttrs: isNonHandlerPropsEqual,
2501        renderProps: isPropsEqual,
2502    });
2503    // Util
2504    /*
2505    Does UI-framework provide custom way of rendering that does not use Preact VDOM
2506    AND does the calendar's options define custom rendering?
2507    AKA. Should we NOT render the default content?
2508    */
2509    function hasCustomRenderingHandler(generatorName, options) {
2510        var _a;
2511        return Boolean(options.handleCustomRendering &&
2512            generatorName &&
2513            ((_a = options.customRenderingMetaMap) === null || _a === void 0 ? void 0 : _a[generatorName]));
2514    }
2515    function buildElAttrs(props, extraClassNames, elRef) {
2516        const attrs = Object.assign(Object.assign({}, props.elAttrs), { ref: elRef });
2517        if (props.elClasses || extraClassNames) {
2518            attrs.className = (props.elClasses || [])
2519                .concat(extraClassNames || [])
2520                .concat(attrs.className || [])
2521                .filter(Boolean)
2522                .join(' ');
2523        }
2524        if (props.elStyle) {
2525            attrs.style = props.elStyle;
2526        }
2527        return attrs;
2528    }
2529    function isTruthy(val) {
2530        return Boolean(val);
2531    }
2532
2533    const RenderId = createContext(0);
2534
2535    class ContentContainer extends x$1 {
2536        constructor() {
2537            super(...arguments);
2538            this.InnerContent = InnerContentInjector.bind(undefined, this);
2539            this.handleEl = (el) => {
2540                this.el = el;
2541                if (this.props.elRef) {
2542                    setRef(this.props.elRef, el);
2543                    if (el && this.didMountMisfire) {
2544                        this.componentDidMount();
2545                    }
2546                }
2547            };
2548        }
2549        render() {
2550            const { props } = this;
2551            const generatedClassNames = generateClassNames(props.classNameGenerator, props.renderProps);
2552            if (props.children) {
2553                const elAttrs = buildElAttrs(props, generatedClassNames, this.handleEl);
2554                const children = props.children(this.InnerContent, props.renderProps, elAttrs);
2555                if (props.elTag) {
2556                    return y(props.elTag, elAttrs, children);
2557                }
2558                else {
2559                    return children;
2560                }
2561            }
2562            else {
2563                return y((ContentInjector), Object.assign(Object.assign({}, props), { elRef: this.handleEl, elTag: props.elTag || 'div', elClasses: (props.elClasses || []).concat(generatedClassNames), renderId: this.context }));
2564            }
2565        }
2566        componentDidMount() {
2567            var _a, _b;
2568            if (this.el) {
2569                (_b = (_a = this.props).didMount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.el }));
2570            }
2571            else {
2572                this.didMountMisfire = true;
2573            }
2574        }
2575        componentWillUnmount() {
2576            var _a, _b;
2577            (_b = (_a = this.props).willUnmount) === null || _b === void 0 ? void 0 : _b.call(_a, Object.assign(Object.assign({}, this.props.renderProps), { el: this.el }));
2578        }
2579    }
2580    ContentContainer.contextType = RenderId;
2581    function InnerContentInjector(containerComponent, props) {
2582        const parentProps = containerComponent.props;
2583        return y((ContentInjector), Object.assign({ renderProps: parentProps.renderProps, generatorName: parentProps.generatorName, customGenerator: parentProps.customGenerator, defaultGenerator: parentProps.defaultGenerator, renderId: containerComponent.context }, props));
2584    }
2585    // Utils
2586    function generateClassNames(classNameGenerator, renderProps) {
2587        const classNames = typeof classNameGenerator === 'function' ?
2588            classNameGenerator(renderProps) :
2589            classNameGenerator || [];
2590        return typeof classNames === 'string' ? [classNames] : classNames;
2591    }
2592
2593    class ViewContainer extends BaseComponent {
2594        render() {
2595            let { props, context } = this;
2596            let { options } = context;
2597            let renderProps = { view: context.viewApi };
2598            return (y(ContentContainer, Object.assign({}, props, { elTag: props.elTag || 'div', elClasses: [
2599                    ...buildViewClassNames(props.viewSpec),
2600                    ...(props.elClasses || []),
2601                ], renderProps: renderProps, classNameGenerator: options.viewClassNames, generatorName: undefined, didMount: options.viewDidMount, willUnmount: options.viewWillUnmount }), () => props.children));
2602        }
2603    }
2604    function buildViewClassNames(viewSpec) {
2605        return [
2606            `fc-${viewSpec.type}-view`,
2607            'fc-view',
2608        ];
2609    }
2610
2611    function parseRange(input, dateEnv) {
2612        let start = null;
2613        let end = null;
2614        if (input.start) {
2615            start = dateEnv.createMarker(input.start);
2616        }
2617        if (input.end) {
2618            end = dateEnv.createMarker(input.end);
2619        }
2620        if (!start && !end) {
2621            return null;
2622        }
2623        if (start && end && end < start) {
2624            return null;
2625        }
2626        return { start, end };
2627    }
2628    // SIDE-EFFECT: will mutate ranges.
2629    // Will return a new array result.
2630    function invertRanges(ranges, constraintRange) {
2631        let invertedRanges = [];
2632        let { start } = constraintRange; // the end of the previous range. the start of the new range
2633        let i;
2634        let dateRange;
2635        // ranges need to be in order. required for our date-walking algorithm
2636        ranges.sort(compareRanges);
2637        for (i = 0; i < ranges.length; i += 1) {
2638            dateRange = ranges[i];
2639            // add the span of time before the event (if there is any)
2640            if (dateRange.start > start) { // compare millisecond time (skip any ambig logic)
2641                invertedRanges.push({ start, end: dateRange.start });
2642            }
2643            if (dateRange.end > start) {
2644                start = dateRange.end;
2645            }
2646        }
2647        // add the span of time after the last event (if there is any)
2648        if (start < constraintRange.end) { // compare millisecond time (skip any ambig logic)
2649            invertedRanges.push({ start, end: constraintRange.end });
2650        }
2651        return invertedRanges;
2652    }
2653    function compareRanges(range0, range1) {
2654        return range0.start.valueOf() - range1.start.valueOf(); // earlier ranges go first
2655    }
2656    function intersectRanges(range0, range1) {
2657        let { start, end } = range0;
2658        let newRange = null;
2659        if (range1.start !== null) {
2660            if (start === null) {
2661                start = range1.start;
2662            }
2663            else {
2664                start = new Date(Math.max(start.valueOf(), range1.start.valueOf()));
2665            }
2666        }
2667        if (range1.end != null) {
2668            if (end === null) {
2669                end = range1.end;
2670            }
2671            else {
2672                end = new Date(Math.min(end.valueOf(), range1.end.valueOf()));
2673            }
2674        }
2675        if (start === null || end === null || start < end) {
2676            newRange = { start, end };
2677        }
2678        return newRange;
2679    }
2680    function rangesEqual(range0, range1) {
2681        return (range0.start === null ? null : range0.start.valueOf()) === (range1.start === null ? null : range1.start.valueOf()) &&
2682            (range0.end === null ? null : range0.end.valueOf()) === (range1.end === null ? null : range1.end.valueOf());
2683    }
2684    function rangesIntersect(range0, range1) {
2685        return (range0.end === null || range1.start === null || range0.end > range1.start) &&
2686            (range0.start === null || range1.end === null || range0.start < range1.end);
2687    }
2688    function rangeContainsRange(outerRange, innerRange) {
2689        return (outerRange.start === null || (innerRange.start !== null && innerRange.start >= outerRange.start)) &&
2690            (outerRange.end === null || (innerRange.end !== null && innerRange.end <= outerRange.end));
2691    }
2692    function rangeContainsMarker(range, date) {
2693        return (range.start === null || date >= range.start) &&
2694            (range.end === null || date < range.end);
2695    }
2696    // If the given date is not within the given range, move it inside.
2697    // (If it's past the end, make it one millisecond before the end).
2698    function constrainMarkerToRange(date, range) {
2699        if (range.start != null && date < range.start) {
2700            return range.start;
2701        }
2702        if (range.end != null && date >= range.end) {
2703            return new Date(range.end.valueOf() - 1);
2704        }
2705        return date;
2706    }
2707
2708    /* Date stuff that doesn't belong in datelib core
2709    ----------------------------------------------------------------------------------------------------------------------*/
2710    // given a timed range, computes an all-day range that has the same exact duration,
2711    // but whose start time is aligned with the start of the day.
2712    function computeAlignedDayRange(timedRange) {
2713        let dayCnt = Math.floor(diffDays(timedRange.start, timedRange.end)) || 1;
2714        let start = startOfDay(timedRange.start);
2715        let end = addDays(start, dayCnt);
2716        return { start, end };
2717    }
2718    // given a timed range, computes an all-day range based on how for the end date bleeds into the next day
2719    // TODO: give nextDayThreshold a default arg
2720    function computeVisibleDayRange(timedRange, nextDayThreshold = createDuration(0)) {
2721        let startDay = null;
2722        let endDay = null;
2723        if (timedRange.end) {
2724            endDay = startOfDay(timedRange.end);
2725            let endTimeMS = timedRange.end.valueOf() - endDay.valueOf(); // # of milliseconds into `endDay`
2726            // If the end time is actually inclusively part of the next day and is equal to or
vendor: 14,931 bytes, lines 2727-3048
2727            // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
2728            // Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
2729            if (endTimeMS && endTimeMS >= asRoughMs(nextDayThreshold)) {
2730                endDay = addDays(endDay, 1);
2731            }
2732        }
2733        if (timedRange.start) {
2734            startDay = startOfDay(timedRange.start); // the beginning of the day the range starts
2735            // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day.
2736            if (endDay && endDay <= startDay) {
2737                endDay = addDays(startDay, 1);
2738            }
2739        }
2740        return { start: startDay, end: endDay };
2741    }
2742    // spans from one day into another?
2743    function isMultiDayRange(range) {
2744        let visibleRange = computeVisibleDayRange(range);
2745        return diffDays(visibleRange.start, visibleRange.end) > 1;
2746    }
2747    function diffDates(date0, date1, dateEnv, largeUnit) {
2748        if (largeUnit === 'year') {
2749            return createDuration(dateEnv.diffWholeYears(date0, date1), 'year');
2750        }
2751        if (largeUnit === 'month') {
2752            return createDuration(dateEnv.diffWholeMonths(date0, date1), 'month');
2753        }
2754        return diffDayAndTime(date0, date1); // returns a duration
2755    }
2756
2757    function reduceCurrentDate(currentDate, action) {
2758        switch (action.type) {
2759            case 'CHANGE_DATE':
2760                return action.dateMarker;
2761            default:
2762                return currentDate;
2763        }
2764    }
2765    function getInitialDate(options, dateEnv) {
2766        let initialDateInput = options.initialDate;
2767        // compute the initial ambig-timezone date
2768        if (initialDateInput != null) {
2769            return dateEnv.createMarker(initialDateInput);
2770        }
2771        return getNow(options.now, dateEnv); // getNow already returns unzoned
2772    }
2773    function getNow(nowInput, dateEnv) {
2774        if (typeof nowInput === 'function') {
2775            nowInput = nowInput();
2776        }
2777        if (nowInput == null) {
2778            return dateEnv.createNowMarker();
2779        }
2780        return dateEnv.createMarker(nowInput);
2781    }
2782
2783    class DateProfileGenerator {
2784        constructor(props) {
2785            this.props = props;
2786            this.nowDate = getNow(props.nowInput, props.dateEnv);
2787            this.initHiddenDays();
2788        }
2789        /* Date Range Computation
2790        ------------------------------------------------------------------------------------------------------------------*/
2791        // Builds a structure with info about what the dates/ranges will be for the "prev" view.
2792        buildPrev(currentDateProfile, currentDate, forceToValid) {
2793            let { dateEnv } = this.props;
2794            let prevDate = dateEnv.subtract(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month
2795                currentDateProfile.dateIncrement);
2796            return this.build(prevDate, -1, forceToValid);
2797        }
2798        // Builds a structure with info about what the dates/ranges will be for the "next" view.
2799        buildNext(currentDateProfile, currentDate, forceToValid) {
2800            let { dateEnv } = this.props;
2801            let nextDate = dateEnv.add(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month
2802                currentDateProfile.dateIncrement);
2803            return this.build(nextDate, 1, forceToValid);
2804        }
2805        // Builds a structure holding dates/ranges for rendering around the given date.
2806        // Optional direction param indicates whether the date is being incremented/decremented
2807        // from its previous value. decremented = -1, incremented = 1 (default).
2808        build(currentDate, direction, forceToValid = true) {
2809            let { props } = this;
2810            let validRange;
2811            let currentInfo;
2812            let isRangeAllDay;
2813            let renderRange;
2814            let activeRange;
2815            let isValid;
2816            validRange = this.buildValidRange();
2817            validRange = this.trimHiddenDays(validRange);
2818            if (forceToValid) {
2819                currentDate = constrainMarkerToRange(currentDate, validRange);
2820            }
2821            currentInfo = this.buildCurrentRangeInfo(currentDate, direction);
2822            isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit);
2823            renderRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.range), currentInfo.unit, isRangeAllDay);
2824            renderRange = this.trimHiddenDays(renderRange);
2825            activeRange = renderRange;
2826            if (!props.showNonCurrentDates) {
2827                activeRange = intersectRanges(activeRange, currentInfo.range);
2828            }
2829            activeRange = this.adjustActiveRange(activeRange);
2830            activeRange = intersectRanges(activeRange, validRange); // might return null
2831            // it's invalid if the originally requested date is not contained,
2832            // or if the range is completely outside of the valid range.
2833            isValid = rangesIntersect(currentInfo.range, validRange);
2834            // HACK: constrain to render-range so `currentDate` is more useful to view rendering
2835            if (!rangeContainsMarker(renderRange, currentDate)) {
2836                currentDate = renderRange.start;
2837            }
2838            return {
2839                currentDate,
2840                // constraint for where prev/next operations can go and where events can be dragged/resized to.
2841                // an object with optional start and end properties.
2842                validRange,
2843                // range the view is formally responsible for.
2844                // for example, a month view might have 1st-31st, excluding padded dates
2845                currentRange: currentInfo.range,
2846                // name of largest unit being displayed, like "month" or "week"
2847                currentRangeUnit: currentInfo.unit,
2848                isRangeAllDay,
2849                // dates that display events and accept drag-n-drop
2850                // will be `null` if no dates accept events
2851                activeRange,
2852                // date range with a rendered skeleton
2853                // includes not-active days that need some sort of DOM
2854                renderRange,
2855                // Duration object that denotes the first visible time of any given day
2856                slotMinTime: props.slotMinTime,
2857                // Duration object that denotes the exclusive visible end time of any given day
2858                slotMaxTime: props.slotMaxTime,
2859                isValid,
2860                // how far the current date will move for a prev/next operation
2861                dateIncrement: this.buildDateIncrement(currentInfo.duration),
2862                // pass a fallback (might be null) ^
2863            };
2864        }
2865        // Builds an object with optional start/end properties.
2866        // Indicates the minimum/maximum dates to display.
2867        // not responsible for trimming hidden days.
2868        buildValidRange() {
2869            let input = this.props.validRangeInput;
2870            let simpleInput = typeof input === 'function'
2871                ? input.call(this.props.calendarApi, this.nowDate)
2872                : input;
2873            return this.refineRange(simpleInput) ||
2874                { start: null, end: null }; // completely open-ended
2875        }
2876        // Builds a structure with info about the "current" range, the range that is
2877        // highlighted as being the current month for example.
2878        // See build() for a description of `direction`.
2879        // Guaranteed to have `range` and `unit` properties. `duration` is optional.
2880        buildCurrentRangeInfo(date, direction) {
2881            let { props } = this;
2882            let duration = null;
2883            let unit = null;
2884            let range = null;
2885            let dayCount;
2886            if (props.duration) {
2887                duration = props.duration;
2888                unit = props.durationUnit;
2889                range = this.buildRangeFromDuration(date, direction, duration, unit);
2890            }
2891            else if ((dayCount = this.props.dayCount)) {
2892                unit = 'day';
2893                range = this.buildRangeFromDayCount(date, direction, dayCount);
2894            }
2895            else if ((range = this.buildCustomVisibleRange(date))) {
2896                unit = props.dateEnv.greatestWholeUnit(range.start, range.end).unit;
2897            }
2898            else {
2899                duration = this.getFallbackDuration();
2900                unit = greatestDurationDenominator(duration).unit;
2901                range = this.buildRangeFromDuration(date, direction, duration, unit);
2902            }
2903            return { duration, unit, range };
2904        }
2905        getFallbackDuration() {
2906            return createDuration({ day: 1 });
2907        }
2908        // Returns a new activeRange to have time values (un-ambiguate)
2909        // slotMinTime or slotMaxTime causes the range to expand.
2910        adjustActiveRange(range) {
2911            let { dateEnv, usesMinMaxTime, slotMinTime, slotMaxTime } = this.props;
2912            let { start, end } = range;
2913            if (usesMinMaxTime) {
2914                // expand active range if slotMinTime is negative (why not when positive?)
2915                if (asRoughDays(slotMinTime) < 0) {
2916                    start = startOfDay(start); // necessary?
2917                    start = dateEnv.add(start, slotMinTime);
2918                }
2919                // expand active range if slotMaxTime is beyond one day (why not when negative?)
2920                if (asRoughDays(slotMaxTime) > 1) {
2921                    end = startOfDay(end); // necessary?
2922                    end = addDays(end, -1);
2923                    end = dateEnv.add(end, slotMaxTime);
2924                }
2925            }
2926            return { start, end };
2927        }
2928        // Builds the "current" range when it is specified as an explicit duration.
2929        // `unit` is the already-computed greatestDurationDenominator unit of duration.
2930        buildRangeFromDuration(date, direction, duration, unit) {
2931            let { dateEnv, dateAlignment } = this.props;
2932            let start;
2933            let end;
2934            let res;
2935            // compute what the alignment should be
2936            if (!dateAlignment) {
2937                let { dateIncrement } = this.props;
2938                if (dateIncrement) {
2939                    // use the smaller of the two units
2940                    if (asRoughMs(dateIncrement) < asRoughMs(duration)) {
2941                        dateAlignment = greatestDurationDenominator(dateIncrement).unit;
2942                    }
2943                    else {
2944                        dateAlignment = unit;
2945                    }
2946                }
2947                else {
2948                    dateAlignment = unit;
2949                }
2950            }
2951            // if the view displays a single day or smaller
2952            if (asRoughDays(duration) <= 1) {
2953                if (this.isHiddenDay(start)) {
2954                    start = this.skipHiddenDays(start, direction);
2955                    start = startOfDay(start);
2956                }
2957            }
2958            function computeRes() {
2959                start = dateEnv.startOf(date, dateAlignment);
2960                end = dateEnv.add(start, duration);
2961                res = { start, end };
2962            }
2963            computeRes();
2964            // if range is completely enveloped by hidden days, go past the hidden days
2965            if (!this.trimHiddenDays(res)) {
2966                date = this.skipHiddenDays(date, direction);
2967                computeRes();
2968            }
2969            return res;
2970        }
2971        // Builds the "current" range when a dayCount is specified.
2972        buildRangeFromDayCount(date, direction, dayCount) {
2973            let { dateEnv, dateAlignment } = this.props;
2974            let runningCount = 0;
2975            let start = date;
2976            let end;
2977            if (dateAlignment) {
2978                start = dateEnv.startOf(start, dateAlignment);
2979            }
2980            start = startOfDay(start);
2981            start = this.skipHiddenDays(start, direction);
2982            end = start;
2983            do {
2984                end = addDays(end, 1);
2985                if (!this.isHiddenDay(end)) {
2986                    runningCount += 1;
2987                }
2988            } while (runningCount < dayCount);
2989            return { start, end };
2990        }
2991        // Builds a normalized range object for the "visible" range,
2992        // which is a way to define the currentRange and activeRange at the same time.
2993        buildCustomVisibleRange(date) {
2994            let { props } = this;
2995            let input = props.visibleRangeInput;
2996            let simpleInput = typeof input === 'function'
2997                ? input.call(props.calendarApi, props.dateEnv.toDate(date))
2998                : input;
2999            let range = this.refineRange(simpleInput);
3000            if (range && (range.start == null || range.end == null)) {
3001                return null;
3002            }
3003            return range;
3004        }
3005        // Computes the range that will represent the element/cells for *rendering*,
3006        // but which may have voided days/times.
3007        // not responsible for trimming hidden days.
3008        buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
3009            return currentRange;
3010        }
3011        // Compute the duration value that should be added/substracted to the current date
3012        // when a prev/next operation happens.
3013        buildDateIncrement(fallback) {
3014            let { dateIncrement } = this.props;
3015            let customAlignment;
3016            if (dateIncrement) {
3017                return dateIncrement;
3018            }
3019            if ((customAlignment = this.props.dateAlignment)) {
3020                return createDuration(1, customAlignment);
3021            }
3022            if (fallback) {
3023                return fallback;
3024            }
3025            return createDuration({ days: 1 });
3026        }
3027        refineRange(rangeInput) {
3028            if (rangeInput) {
3029                let range = parseRange(rangeInput, this.props.dateEnv);
3030                if (range) {
3031                    range = computeVisibleDayRange(range);
3032                }
3033                return range;
3034            }
3035            return null;
3036        }
3037        /* Hidden Days
3038        ------------------------------------------------------------------------------------------------------------------*/
3039        // Initializes internal variables related to calculating hidden days-of-week
3040        initHiddenDays() {
3041            let hiddenDays = this.props.hiddenDays || []; // array of day-of-week indices that are hidden
3042            let isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool)
3043            let dayCnt = 0;
3044            let i;
3045            if (this.props.weekends === false) {
3046                hiddenDays.push(0, 6); // 0=sunday, 6=saturday
3047            }
3048            for (i = 0; i < 7; i += 1) {
vendor: 13,107 bytes, lines 3049-3368
3049                if (!(isHiddenDayHash[i] = hiddenDays.indexOf(i) !== -1)) {
3050                    dayCnt += 1;
3051                }
3052            }
3053            if (!dayCnt) {
3054                throw new Error('invalid hiddenDays'); // all days were hidden? bad.
3055            }
3056            this.isHiddenDayHash = isHiddenDayHash;
3057        }
3058        // Remove days from the beginning and end of the range that are computed as hidden.
3059        // If the whole range is trimmed off, returns null
3060        trimHiddenDays(range) {
3061            let { start, end } = range;
3062            if (start) {
3063                start = this.skipHiddenDays(start);
3064            }
3065            if (end) {
3066                end = this.skipHiddenDays(end, -1, true);
3067            }
3068            if (start == null || end == null || start < end) {
3069                return { start, end };
3070            }
3071            return null;
3072        }
3073        // Is the current day hidden?
3074        // `day` is a day-of-week index (0-6), or a Date (used for UTC)
3075        isHiddenDay(day) {
3076            if (day instanceof Date) {
3077                day = day.getUTCDay();
3078            }
3079            return this.isHiddenDayHash[day];
3080        }
3081        // Incrementing the current day until it is no longer a hidden day, returning a copy.
3082        // DOES NOT CONSIDER validRange!
3083        // If the initial value of `date` is not a hidden day, don't do anything.
3084        // Pass `isExclusive` as `true` if you are dealing with an end date.
3085        // `inc` defaults to `1` (increment one day forward each time)
3086        skipHiddenDays(date, inc = 1, isExclusive = false) {
3087            while (this.isHiddenDayHash[(date.getUTCDay() + (isExclusive ? inc : 0) + 7) % 7]) {
3088                date = addDays(date, inc);
3089            }
3090            return date;
3091        }
3092    }
3093
3094    function createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) {
3095        return {
3096            instanceId: guid(),
3097            defId,
3098            range,
3099            forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo,
3100            forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo,
3101        };
3102    }
3103
3104    function parseRecurring(refined, defaultAllDay, dateEnv, recurringTypes) {
3105        for (let i = 0; i < recurringTypes.length; i += 1) {
3106            let parsed = recurringTypes[i].parse(refined, dateEnv);
3107            if (parsed) {
3108                let { allDay } = refined;
3109                if (allDay == null) {
3110                    allDay = defaultAllDay;
3111                    if (allDay == null) {
3112                        allDay = parsed.allDayGuess;
3113                        if (allDay == null) {
3114                            allDay = false;
3115                        }
3116                    }
3117                }
3118                return {
3119                    allDay,
3120                    duration: parsed.duration,
3121                    typeData: parsed.typeData,
3122                    typeId: i,
3123                };
3124            }
3125        }
3126        return null;
3127    }
3128    function expandRecurring(eventStore, framingRange, context) {
3129        let { dateEnv, pluginHooks, options } = context;
3130        let { defs, instances } = eventStore;
3131        // remove existing recurring instances
3132        // TODO: bad. always expand events as a second step
3133        instances = filterHash(instances, (instance) => !defs[instance.defId].recurringDef);
3134        for (let defId in defs) {
3135            let def = defs[defId];
3136            if (def.recurringDef) {
3137                let { duration } = def.recurringDef;
3138                if (!duration) {
3139                    duration = def.allDay ?
3140                        options.defaultAllDayEventDuration :
3141                        options.defaultTimedEventDuration;
3142                }
3143                let starts = expandRecurringRanges(def, duration, framingRange, dateEnv, pluginHooks.recurringTypes);
3144                for (let start of starts) {
3145                    let instance = createEventInstance(defId, {
3146                        start,
3147                        end: dateEnv.add(start, duration),
3148                    });
3149                    instances[instance.instanceId] = instance;
3150                }
3151            }
3152        }
3153        return { defs, instances };
3154    }
3155    /*
3156    Event MUST have a recurringDef
3157    */
3158    function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) {
3159        let typeDef = recurringTypes[eventDef.recurringDef.typeId];
3160        let markers = typeDef.expand(eventDef.recurringDef.typeData, {
3161            start: dateEnv.subtract(framingRange.start, duration),
3162            end: framingRange.end,
3163        }, dateEnv);
3164        // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to
3165        if (eventDef.allDay) {
3166            markers = markers.map(startOfDay);
3167        }
3168        return markers;
3169    }
3170
3171    const EVENT_NON_DATE_REFINERS = {
3172        id: String,
3173        groupId: String,
3174        title: String,
3175        url: String,
3176        interactive: Boolean,
3177    };
3178    const EVENT_DATE_REFINERS = {
3179        start: identity,
3180        end: identity,
3181        date: identity,
3182        allDay: Boolean,
3183    };
3184    const EVENT_REFINERS = Object.assign(Object.assign(Object.assign({}, EVENT_NON_DATE_REFINERS), EVENT_DATE_REFINERS), { extendedProps: identity });
3185    function parseEvent(raw, eventSource, context, allowOpenRange, refiners = buildEventRefiners(context), defIdMap, instanceIdMap) {
3186        let { refined, extra } = refineEventDef(raw, context, refiners);
3187        let defaultAllDay = computeIsDefaultAllDay(eventSource, context);
3188        let recurringRes = parseRecurring(refined, defaultAllDay, context.dateEnv, context.pluginHooks.recurringTypes);
3189        if (recurringRes) {
3190            let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', recurringRes.allDay, Boolean(recurringRes.duration), context, defIdMap);
3191            def.recurringDef = {
3192                typeId: recurringRes.typeId,
3193                typeData: recurringRes.typeData,
3194                duration: recurringRes.duration,
3195            };
3196            return { def, instance: null };
3197        }
3198        let singleRes = parseSingle(refined, defaultAllDay, context, allowOpenRange);
3199        if (singleRes) {
3200            let def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', singleRes.allDay, singleRes.hasEnd, context, defIdMap);
3201            let instance = createEventInstance(def.defId, singleRes.range, singleRes.forcedStartTzo, singleRes.forcedEndTzo);
3202            if (instanceIdMap && def.publicId && instanceIdMap[def.publicId]) {
3203                instance.instanceId = instanceIdMap[def.publicId];
3204            }
3205            return { def, instance };
3206        }
3207        return null;
3208    }
3209    function refineEventDef(raw, context, refiners = buildEventRefiners(context)) {
3210        return refineProps(raw, refiners);
3211    }
3212    function buildEventRefiners(context) {
3213        return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_REFINERS), context.pluginHooks.eventRefiners);
3214    }
3215    /*
3216    Will NOT populate extendedProps with the leftover properties.
3217    Will NOT populate date-related props.
3218    */
3219    function parseEventDef(refined, extra, sourceId, allDay, hasEnd, context, defIdMap) {
3220        let def = {
3221            title: refined.title || '',
3222            groupId: refined.groupId || '',
3223            publicId: refined.id || '',
3224            url: refined.url || '',
3225            recurringDef: null,
3226            defId: ((defIdMap && refined.id) ? defIdMap[refined.id] : '') || guid(),
3227            sourceId,
3228            allDay,
3229            hasEnd,
3230            interactive: refined.interactive,
3231            ui: createEventUi(refined, context),
3232            extendedProps: Object.assign(Object.assign({}, (refined.extendedProps || {})), extra),
3233        };
3234        for (let memberAdder of context.pluginHooks.eventDefMemberAdders) {
3235            Object.assign(def, memberAdder(refined));
3236        }
3237        // help out EventImpl from having user modify props
3238        Object.freeze(def.ui.classNames);
3239        Object.freeze(def.extendedProps);
3240        return def;
3241    }
3242    function parseSingle(refined, defaultAllDay, context, allowOpenRange) {
3243        let { allDay } = refined;
3244        let startMeta;
3245        let startMarker = null;
3246        let hasEnd = false;
3247        let endMeta;
3248        let endMarker = null;
3249        let startInput = refined.start != null ? refined.start : refined.date;
3250        startMeta = context.dateEnv.createMarkerMeta(startInput);
3251        if (startMeta) {
3252            startMarker = startMeta.marker;
3253        }
3254        else if (!allowOpenRange) {
3255            return null;
3256        }
3257        if (refined.end != null) {
3258            endMeta = context.dateEnv.createMarkerMeta(refined.end);
3259        }
3260        if (allDay == null) {
3261            if (defaultAllDay != null) {
3262                allDay = defaultAllDay;
3263            }
3264            else {
3265                // fall back to the date props LAST
3266                allDay = (!startMeta || startMeta.isTimeUnspecified) &&
3267                    (!endMeta || endMeta.isTimeUnspecified);
3268            }
3269        }
3270        if (allDay && startMarker) {
3271            startMarker = startOfDay(startMarker);
3272        }
3273        if (endMeta) {
3274            endMarker = endMeta.marker;
3275            if (allDay) {
3276                endMarker = startOfDay(endMarker);
3277            }
3278            if (startMarker && endMarker <= startMarker) {
3279                endMarker = null;
3280            }
3281        }
3282        if (endMarker) {
3283            hasEnd = true;
3284        }
3285        else if (!allowOpenRange) {
3286            hasEnd = context.options.forceEventDuration || false;
3287            endMarker = context.dateEnv.add(startMarker, allDay ?
3288                context.options.defaultAllDayEventDuration :
3289                context.options.defaultTimedEventDuration);
3290        }
3291        return {
3292            allDay,
3293            hasEnd,
3294            range: { start: startMarker, end: endMarker },
3295            forcedStartTzo: startMeta ? startMeta.forcedTzo : null,
3296            forcedEndTzo: endMeta ? endMeta.forcedTzo : null,
3297        };
3298    }
3299    function computeIsDefaultAllDay(eventSource, context) {
3300        let res = null;
3301        if (eventSource) {
3302            res = eventSource.defaultAllDay;
3303        }
3304        if (res == null) {
3305            res = context.options.defaultAllDay;
3306        }
3307        return res;
3308    }
3309
3310    function parseEvents(rawEvents, eventSource, context, allowOpenRange, defIdMap, instanceIdMap) {
3311        let eventStore = createEmptyEventStore();
3312        let eventRefiners = buildEventRefiners(context);
3313        for (let rawEvent of rawEvents) {
3314            let tuple = parseEvent(rawEvent, eventSource, context, allowOpenRange, eventRefiners, defIdMap, instanceIdMap);
3315            if (tuple) {
3316                eventTupleToStore(tuple, eventStore);
3317            }
3318        }
3319        return eventStore;
3320    }
3321    function eventTupleToStore(tuple, eventStore = createEmptyEventStore()) {
3322        eventStore.defs[tuple.def.defId] = tuple.def;
3323        if (tuple.instance) {
3324            eventStore.instances[tuple.instance.instanceId] = tuple.instance;
3325        }
3326        return eventStore;
3327    }
3328    // retrieves events that have the same groupId as the instance specified by `instanceId`
3329    // or they are the same as the instance.
3330    // why might instanceId not be in the store? an event from another calendar?
3331    function getRelevantEvents(eventStore, instanceId) {
3332        let instance = eventStore.instances[instanceId];
3333        if (instance) {
3334            let def = eventStore.defs[instance.defId];
3335            // get events/instances with same group
3336            let newStore = filterEventStoreDefs(eventStore, (lookDef) => isEventDefsGrouped(def, lookDef));
3337            // add the original
3338            // TODO: wish we could use eventTupleToStore or something like it
3339            newStore.defs[def.defId] = def;
3340            newStore.instances[instance.instanceId] = instance;
3341            return newStore;
3342        }
3343        return createEmptyEventStore();
3344    }
3345    function isEventDefsGrouped(def0, def1) {
3346        return Boolean(def0.groupId && def0.groupId === def1.groupId);
3347    }
3348    function createEmptyEventStore() {
3349        return { defs: {}, instances: {} };
3350    }
3351    function mergeEventStores(store0, store1) {
3352        return {
3353            defs: Object.assign(Object.assign({}, store0.defs), store1.defs),
3354            instances: Object.assign(Object.assign({}, store0.instances), store1.instances),
3355        };
3356    }
3357    function filterEventStoreDefs(eventStore, filterFunc) {
3358        let defs = filterHash(eventStore.defs, filterFunc);
3359        let instances = filterHash(eventStore.instances, (instance) => (defs[instance.defId] // still exists?
3360        ));
3361        return { defs, instances };
3362    }
3363    function excludeSubEventStore(master, sub) {
3364        let { defs, instances } = master;
3365        let filteredDefs = {};
3366        let filteredInstances = {};
3367        for (let defId in defs) {
3368            if (!sub.defs[defId]) { // not explicitly excluded
vendor: 7,507 bytes, lines 3369-3553
3369                filteredDefs[defId] = defs[defId];
3370            }
3371        }
3372        for (let instanceId in instances) {
3373            if (!sub.instances[instanceId] && // not explicitly excluded
3374                filteredDefs[instances[instanceId].defId] // def wasn't filtered away
3375            ) {
3376                filteredInstances[instanceId] = instances[instanceId];
3377            }
3378        }
3379        return {
3380            defs: filteredDefs,
3381            instances: filteredInstances,
3382        };
3383    }
3384
3385    function normalizeConstraint(input, context) {
3386        if (Array.isArray(input)) {
3387            return parseEvents(input, null, context, true); // allowOpenRange=true
3388        }
3389        if (typeof input === 'object' && input) { // non-null object
3390            return parseEvents([input], null, context, true); // allowOpenRange=true
3391        }
3392        if (input != null) {
3393            return String(input);
3394        }
3395        return null;
3396    }
3397
3398    function parseClassNames(raw) {
3399        if (Array.isArray(raw)) {
3400            return raw;
3401        }
3402        if (typeof raw === 'string') {
3403            return raw.split(/\s+/);
3404        }
3405        return [];
3406    }
3407
3408    // TODO: better called "EventSettings" or "EventConfig"
3409    // TODO: move this file into structs
3410    // TODO: separate constraint/overlap/allow, because selection uses only that, not other props
3411    const EVENT_UI_REFINERS = {
3412        display: String,
3413        editable: Boolean,
3414        startEditable: Boolean,
3415        durationEditable: Boolean,
3416        constraint: identity,
3417        overlap: identity,
3418        allow: identity,
3419        className: parseClassNames,
3420        classNames: parseClassNames,
3421        color: String,
3422        backgroundColor: String,
3423        borderColor: String,
3424        textColor: String,
3425    };
3426    const EMPTY_EVENT_UI = {
3427        display: null,
3428        startEditable: null,
3429        durationEditable: null,
3430        constraints: [],
3431        overlap: null,
3432        allows: [],
3433        backgroundColor: '',
3434        borderColor: '',
3435        textColor: '',
3436        classNames: [],
3437    };
3438    function createEventUi(refined, context) {
3439        let constraint = normalizeConstraint(refined.constraint, context);
3440        return {
3441            display: refined.display || null,
3442            startEditable: refined.startEditable != null ? refined.startEditable : refined.editable,
3443            durationEditable: refined.durationEditable != null ? refined.durationEditable : refined.editable,
3444            constraints: constraint != null ? [constraint] : [],
3445            overlap: refined.overlap != null ? refined.overlap : null,
3446            allows: refined.allow != null ? [refined.allow] : [],
3447            backgroundColor: refined.backgroundColor || refined.color || '',
3448            borderColor: refined.borderColor || refined.color || '',
3449            textColor: refined.textColor || '',
3450            classNames: (refined.className || []).concat(refined.classNames || []), // join singular and plural
3451        };
3452    }
3453    // TODO: prevent against problems with <2 args!
3454    function combineEventUis(uis) {
3455        return uis.reduce(combineTwoEventUis, EMPTY_EVENT_UI);
3456    }
3457    function combineTwoEventUis(item0, item1) {
3458        return {
3459            display: item1.display != null ? item1.display : item0.display,
3460            startEditable: item1.startEditable != null ? item1.startEditable : item0.startEditable,
3461            durationEditable: item1.durationEditable != null ? item1.durationEditable : item0.durationEditable,
3462            constraints: item0.constraints.concat(item1.constraints),
3463            overlap: typeof item1.overlap === 'boolean' ? item1.overlap : item0.overlap,
3464            allows: item0.allows.concat(item1.allows),
3465            backgroundColor: item1.backgroundColor || item0.backgroundColor,
3466            borderColor: item1.borderColor || item0.borderColor,
3467            textColor: item1.textColor || item0.textColor,
3468            classNames: item0.classNames.concat(item1.classNames),
3469        };
3470    }
3471
3472    const EVENT_SOURCE_REFINERS = {
3473        id: String,
3474        defaultAllDay: Boolean,
3475        url: String,
3476        format: String,
3477        events: identity,
3478        eventDataTransform: identity,
3479        // for any network-related sources
3480        success: identity,
3481        failure: identity,
3482    };
3483    function parseEventSource(raw, context, refiners = buildEventSourceRefiners(context)) {
3484        let rawObj;
3485        if (typeof raw === 'string') {
3486            rawObj = { url: raw };
3487        }
3488        else if (typeof raw === 'function' || Array.isArray(raw)) {
3489            rawObj = { events: raw };
3490        }
3491        else if (typeof raw === 'object' && raw) { // not null
3492            rawObj = raw;
3493        }
3494        if (rawObj) {
3495            let { refined, extra } = refineProps(rawObj, refiners);
3496            let metaRes = buildEventSourceMeta(refined, context);
3497            if (metaRes) {
3498                return {
3499                    _raw: raw,
3500                    isFetching: false,
3501                    latestFetchId: '',
3502                    fetchRange: null,
3503                    defaultAllDay: refined.defaultAllDay,
3504                    eventDataTransform: refined.eventDataTransform,
3505                    success: refined.success,
3506                    failure: refined.failure,
3507                    publicId: refined.id || '',
3508                    sourceId: guid(),
3509                    sourceDefId: metaRes.sourceDefId,
3510                    meta: metaRes.meta,
3511                    ui: createEventUi(refined, context),
3512                    extendedProps: extra,
3513                };
3514            }
3515        }
3516        return null;
3517    }
3518    function buildEventSourceRefiners(context) {
3519        return Object.assign(Object.assign(Object.assign({}, EVENT_UI_REFINERS), EVENT_SOURCE_REFINERS), context.pluginHooks.eventSourceRefiners);
3520    }
3521    function buildEventSourceMeta(raw, context) {
3522        let defs = context.pluginHooks.eventSourceDefs;
3523        for (let i = defs.length - 1; i >= 0; i -= 1) { // later-added plugins take precedence
3524            let def = defs[i];
3525            let meta = def.parseMeta(raw);
3526            if (meta) {
3527                return { sourceDefId: i, meta };
3528            }
3529        }
3530        return null;
3531    }
3532
3533    function reduceEventStore(eventStore, action, eventSources, dateProfile, context) {
3534        switch (action.type) {
3535            case 'RECEIVE_EVENTS': // raw
3536                return receiveRawEvents(eventStore, eventSources[action.sourceId], action.fetchId, action.fetchRange, action.rawEvents, context);
3537            case 'RESET_RAW_EVENTS':
3538                return resetRawEvents(eventStore, eventSources[action.sourceId], action.rawEvents, dateProfile.activeRange, context);
3539            case 'ADD_EVENTS': // already parsed, but not expanded
3540                return addEvent(eventStore, action.eventStore, // new ones
3541                    dateProfile ? dateProfile.activeRange : null, context);
3542            case 'RESET_EVENTS':
3543                return action.eventStore;
3544            case 'MERGE_EVENTS': // already parsed and expanded
3545                return mergeEventStores(eventStore, action.eventStore);
3546            case 'PREV': // TODO: how do we track all actions that affect dateProfile :(
3547            case 'NEXT':
3548            case 'CHANGE_DATE':
3549            case 'CHANGE_VIEW_TYPE':
3550                if (dateProfile) {
3551                    return expandRecurring(eventStore, dateProfile.activeRange, context);
3552                }
3553                return eventStore;
vendor: 13,249 bytes, lines 3554-3867
3554            case 'REMOVE_EVENTS':
3555                return excludeSubEventStore(eventStore, action.eventStore);
3556            case 'REMOVE_EVENT_SOURCE':
3557                return excludeEventsBySourceId(eventStore, action.sourceId);
3558            case 'REMOVE_ALL_EVENT_SOURCES':
3559                return filterEventStoreDefs(eventStore, (eventDef) => (!eventDef.sourceId // only keep events with no source id
3560                ));
3561            case 'REMOVE_ALL_EVENTS':
3562                return createEmptyEventStore();
3563            default:
3564                return eventStore;
3565        }
3566    }
3567    function receiveRawEvents(eventStore, eventSource, fetchId, fetchRange, rawEvents, context) {
3568        if (eventSource && // not already removed
3569            fetchId === eventSource.latestFetchId // TODO: wish this logic was always in event-sources
3570        ) {
3571            let subset = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context);
3572            if (fetchRange) {
3573                subset = expandRecurring(subset, fetchRange, context);
3574            }
3575            return mergeEventStores(excludeEventsBySourceId(eventStore, eventSource.sourceId), subset);
3576        }
3577        return eventStore;
3578    }
3579    function resetRawEvents(existingEventStore, eventSource, rawEvents, activeRange, context) {
3580        const { defIdMap, instanceIdMap } = buildPublicIdMaps(existingEventStore);
3581        let newEventStore = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context, false, defIdMap, instanceIdMap);
3582        return expandRecurring(newEventStore, activeRange, context);
3583    }
3584    function transformRawEvents(rawEvents, eventSource, context) {
3585        let calEachTransform = context.options.eventDataTransform;
3586        let sourceEachTransform = eventSource ? eventSource.eventDataTransform : null;
3587        if (sourceEachTransform) {
3588            rawEvents = transformEachRawEvent(rawEvents, sourceEachTransform);
3589        }
3590        if (calEachTransform) {
3591            rawEvents = transformEachRawEvent(rawEvents, calEachTransform);
3592        }
3593        return rawEvents;
3594    }
3595    function transformEachRawEvent(rawEvents, func) {
3596        let refinedEvents;
3597        if (!func) {
3598            refinedEvents = rawEvents;
3599        }
3600        else {
3601            refinedEvents = [];
3602            for (let rawEvent of rawEvents) {
3603                let refinedEvent = func(rawEvent);
3604                if (refinedEvent) {
3605                    refinedEvents.push(refinedEvent);
3606                }
3607                else if (refinedEvent == null) {
3608                    refinedEvents.push(rawEvent);
3609                } // if a different falsy value, do nothing
3610            }
3611        }
3612        return refinedEvents;
3613    }
3614    function addEvent(eventStore, subset, expandRange, context) {
3615        if (expandRange) {
3616            subset = expandRecurring(subset, expandRange, context);
3617        }
3618        return mergeEventStores(eventStore, subset);
3619    }
3620    function rezoneEventStoreDates(eventStore, oldDateEnv, newDateEnv) {
3621        let { defs } = eventStore;
3622        let instances = mapHash(eventStore.instances, (instance) => {
3623            let def = defs[instance.defId];
3624            if (def.allDay) {
3625                return instance; // isn't dependent on timezone
3626            }
3627            return Object.assign(Object.assign({}, instance), { range: {
3628                    start: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.start, instance.forcedStartTzo)),
3629                    end: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.end, instance.forcedEndTzo)),
3630                }, forcedStartTzo: newDateEnv.canComputeOffset ? null : instance.forcedStartTzo, forcedEndTzo: newDateEnv.canComputeOffset ? null : instance.forcedEndTzo });
3631        });
3632        return { defs, instances };
3633    }
3634    function excludeEventsBySourceId(eventStore, sourceId) {
3635        return filterEventStoreDefs(eventStore, (eventDef) => eventDef.sourceId !== sourceId);
3636    }
3637    // QUESTION: why not just return instances? do a general object-property-exclusion util
3638    function excludeInstances(eventStore, removals) {
3639        return {
3640            defs: eventStore.defs,
3641            instances: filterHash(eventStore.instances, (instance) => !removals[instance.instanceId]),
3642        };
3643    }
3644    function buildPublicIdMaps(eventStore) {
3645        const { defs, instances } = eventStore;
3646        const defIdMap = {};
3647        const instanceIdMap = {};
3648        for (let defId in defs) {
3649            const def = defs[defId];
3650            const { publicId } = def;
3651            if (publicId) {
3652                defIdMap[publicId] = defId;
3653            }
3654        }
3655        for (let instanceId in instances) {
3656            const instance = instances[instanceId];
3657            const def = defs[instance.defId];
3658            const { publicId } = def;
3659            if (publicId) {
3660                instanceIdMap[publicId] = instanceId;
3661            }
3662        }
3663        return { defIdMap, instanceIdMap };
3664    }
3665
3666    class Emitter {
3667        constructor() {
3668            this.handlers = {};
3669            this.thisContext = null;
3670        }
3671        setThisContext(thisContext) {
3672            this.thisContext = thisContext;
3673        }
3674        setOptions(options) {
3675            this.options = options;
3676        }
3677        on(type, handler) {
3678            addToHash(this.handlers, type, handler);
3679        }
3680        off(type, handler) {
3681            removeFromHash(this.handlers, type, handler);
3682        }
3683        trigger(type, ...args) {
3684            let attachedHandlers = this.handlers[type] || [];
3685            let optionHandler = this.options && this.options[type];
3686            let handlers = [].concat(optionHandler || [], attachedHandlers);
3687            for (let handler of handlers) {
3688                handler.apply(this.thisContext, args);
3689            }
3690        }
3691        hasHandlers(type) {
3692            return Boolean((this.handlers[type] && this.handlers[type].length) ||
3693                (this.options && this.options[type]));
3694        }
3695    }
3696    function addToHash(hash, type, handler) {
3697        (hash[type] || (hash[type] = []))
3698            .push(handler);
3699    }
3700    function removeFromHash(hash, type, handler) {
3701        if (handler) {
3702            if (hash[type]) {
3703                hash[type] = hash[type].filter((func) => func !== handler);
3704            }
3705        }
3706        else {
3707            delete hash[type]; // remove all handler funcs for this type
3708        }
3709    }
3710
3711    const DEF_DEFAULTS = {
3712        startTime: '09:00',
3713        endTime: '17:00',
3714        daysOfWeek: [1, 2, 3, 4, 5],
3715        display: 'inverse-background',
3716        classNames: 'fc-non-business',
3717        groupId: '_businessHours', // so multiple defs get grouped
3718    };
3719    /*
3720    TODO: pass around as EventDefHash!!!
3721    */
3722    function parseBusinessHours(input, context) {
3723        return parseEvents(refineInputs(input), null, context);
3724    }
3725    function refineInputs(input) {
3726        let rawDefs;
3727        if (input === true) {
3728            rawDefs = [{}]; // will get DEF_DEFAULTS verbatim
3729        }
3730        else if (Array.isArray(input)) {
3731            // if specifying an array, every sub-definition NEEDS a day-of-week
3732            rawDefs = input.filter((rawDef) => rawDef.daysOfWeek);
3733        }
3734        else if (typeof input === 'object' && input) { // non-null object
3735            rawDefs = [input];
3736        }
3737        else { // is probably false
3738            rawDefs = [];
3739        }
3740        rawDefs = rawDefs.map((rawDef) => (Object.assign(Object.assign({}, DEF_DEFAULTS), rawDef)));
3741        return rawDefs;
3742    }
3743
3744    function triggerDateSelect(selection, pev, context) {
3745        context.emitter.trigger('select', Object.assign(Object.assign({}, buildDateSpanApiWithContext(selection, context)), { jsEvent: pev ? pev.origEvent : null, view: context.viewApi || context.calendarApi.view }));
3746    }
3747    function triggerDateUnselect(pev, context) {
3748        context.emitter.trigger('unselect', {
3749            jsEvent: pev ? pev.origEvent : null,
3750            view: context.viewApi || context.calendarApi.view,
3751        });
3752    }
3753    function buildDateSpanApiWithContext(dateSpan, context) {
3754        let props = {};
3755        for (let transform of context.pluginHooks.dateSpanTransforms) {
3756            Object.assign(props, transform(dateSpan, context));
3757        }
3758        Object.assign(props, buildDateSpanApi(dateSpan, context.dateEnv));
3759        return props;
3760    }
3761    // Given an event's allDay status and start date, return what its fallback end date should be.
3762    // TODO: rename to computeDefaultEventEnd
3763    function getDefaultEventEnd(allDay, marker, context) {
3764        let { dateEnv, options } = context;
3765        let end = marker;
3766        if (allDay) {
3767            end = startOfDay(end);
3768            end = dateEnv.add(end, options.defaultAllDayEventDuration);
3769        }
3770        else {
3771            end = dateEnv.add(end, options.defaultTimedEventDuration);
3772        }
3773        return end;
3774    }
3775
3776    // applies the mutation to ALL defs/instances within the event store
3777    function applyMutationToEventStore(eventStore, eventConfigBase, mutation, context) {
3778        let eventConfigs = compileEventUis(eventStore.defs, eventConfigBase);
3779        let dest = createEmptyEventStore();
3780        for (let defId in eventStore.defs) {
3781            let def = eventStore.defs[defId];
3782            dest.defs[defId] = applyMutationToEventDef(def, eventConfigs[defId], mutation, context);
3783        }
3784        for (let instanceId in eventStore.instances) {
3785            let instance = eventStore.instances[instanceId];
3786            let def = dest.defs[instance.defId]; // important to grab the newly modified def
3787            dest.instances[instanceId] = applyMutationToEventInstance(instance, def, eventConfigs[instance.defId], mutation, context);
3788        }
3789        return dest;
3790    }
3791    function applyMutationToEventDef(eventDef, eventConfig, mutation, context) {
3792        let standardProps = mutation.standardProps || {};
3793        // if hasEnd has not been specified, guess a good value based on deltas.
3794        // if duration will change, there's no way the default duration will persist,
3795        // and thus, we need to mark the event as having a real end
3796        if (standardProps.hasEnd == null &&
3797            eventConfig.durationEditable &&
3798            (mutation.startDelta || mutation.endDelta)) {
3799            standardProps.hasEnd = true; // TODO: is this mutation okay?
3800        }
3801        let copy = Object.assign(Object.assign(Object.assign({}, eventDef), standardProps), { ui: Object.assign(Object.assign({}, eventDef.ui), standardProps.ui) });
3802        if (mutation.extendedProps) {
3803            copy.extendedProps = Object.assign(Object.assign({}, copy.extendedProps), mutation.extendedProps);
3804        }
3805        for (let applier of context.pluginHooks.eventDefMutationAppliers) {
3806            applier(copy, mutation, context);
3807        }
3808        if (!copy.hasEnd && context.options.forceEventDuration) {
3809            copy.hasEnd = true;
3810        }
3811        return copy;
3812    }
3813    function applyMutationToEventInstance(eventInstance, eventDef, // must first be modified by applyMutationToEventDef
3814                                          eventConfig, mutation, context) {
3815        let { dateEnv } = context;
3816        let forceAllDay = mutation.standardProps && mutation.standardProps.allDay === true;
3817        let clearEnd = mutation.standardProps && mutation.standardProps.hasEnd === false;
3818        let copy = Object.assign({}, eventInstance);
3819        if (forceAllDay) {
3820            copy.range = computeAlignedDayRange(copy.range);
3821        }
3822        if (mutation.datesDelta && eventConfig.startEditable) {
3823            copy.range = {
3824                start: dateEnv.add(copy.range.start, mutation.datesDelta),
3825                end: dateEnv.add(copy.range.end, mutation.datesDelta),
3826            };
3827        }
3828        if (mutation.startDelta && eventConfig.durationEditable) {
3829            copy.range = {
3830                start: dateEnv.add(copy.range.start, mutation.startDelta),
3831                end: copy.range.end,
3832            };
3833        }
3834        if (mutation.endDelta && eventConfig.durationEditable) {
3835            copy.range = {
3836                start: copy.range.start,
3837                end: dateEnv.add(copy.range.end, mutation.endDelta),
3838            };
3839        }
3840        if (clearEnd) {
3841            copy.range = {
3842                start: copy.range.start,
3843                end: getDefaultEventEnd(eventDef.allDay, copy.range.start, context),
3844            };
3845        }
3846        // in case event was all-day but the supplied deltas were not
3847        // better util for this?
3848        if (eventDef.allDay) {
3849            copy.range = {
3850                start: startOfDay(copy.range.start),
3851                end: startOfDay(copy.range.end),
3852            };
3853        }
3854        // handle invalid durations
3855        if (copy.range.end < copy.range.start) {
3856            copy.range.end = getDefaultEventEnd(eventDef.allDay, copy.range.start, context);
3857        }
3858        return copy;
3859    }
3860
3861    class EventSourceImpl {
3862        constructor(context, internalEventSource) {
3863            this.context = context;
3864            this.internalEventSource = internalEventSource;
3865        }
3866        remove() {
3867            this.context.dispatch({
vendor: 26,480 bytes, lines 3868-4535
3868                type: 'REMOVE_EVENT_SOURCE',
3869                sourceId: this.internalEventSource.sourceId,
3870            });
3871        }
3872        refetch() {
3873            this.context.dispatch({
3874                type: 'FETCH_EVENT_SOURCES',
3875                sourceIds: [this.internalEventSource.sourceId],
3876                isRefetch: true,
3877            });
3878        }
3879        get id() {
3880            return this.internalEventSource.publicId;
3881        }
3882        get url() {
3883            return this.internalEventSource.meta.url;
3884        }
3885        get format() {
3886            return this.internalEventSource.meta.format; // TODO: bad. not guaranteed
3887        }
3888    }
3889
3890    class EventImpl {
3891        // instance will be null if expressing a recurring event that has no current instances,
3892        // OR if trying to validate an incoming external event that has no dates assigned
3893        constructor(context, def, instance) {
3894            this._context = context;
3895            this._def = def;
3896            this._instance = instance || null;
3897        }
3898        /*
3899        TODO: make event struct more responsible for this
3900        */
3901        setProp(name, val) {
3902            if (name in EVENT_DATE_REFINERS) {
3903                console.warn('Could not set date-related prop \'name\'. Use one of the date-related methods instead.');
3904                // TODO: make proper aliasing system?
3905            }
3906            else if (name === 'id') {
3907                val = EVENT_NON_DATE_REFINERS[name](val);
3908                this.mutate({
3909                    standardProps: { publicId: val }, // hardcoded internal name
3910                });
3911            }
3912            else if (name in EVENT_NON_DATE_REFINERS) {
3913                val = EVENT_NON_DATE_REFINERS[name](val);
3914                this.mutate({
3915                    standardProps: { [name]: val },
3916                });
3917            }
3918            else if (name in EVENT_UI_REFINERS) {
3919                let ui = EVENT_UI_REFINERS[name](val);
3920                if (name === 'color') {
3921                    ui = { backgroundColor: val, borderColor: val };
3922                }
3923                else if (name === 'editable') {
3924                    ui = { startEditable: val, durationEditable: val };
3925                }
3926                else {
3927                    ui = { [name]: val };
3928                }
3929                this.mutate({
3930                    standardProps: { ui },
3931                });
3932            }
3933            else {
3934                console.warn(`Could not set prop '${name}'. Use setExtendedProp instead.`);
3935            }
3936        }
3937        setExtendedProp(name, val) {
3938            this.mutate({
3939                extendedProps: { [name]: val },
3940            });
3941        }
3942        setStart(startInput, options = {}) {
3943            let { dateEnv } = this._context;
3944            let start = dateEnv.createMarker(startInput);
3945            if (start && this._instance) { // TODO: warning if parsed bad
3946                let instanceRange = this._instance.range;
3947                let startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); // what if parsed bad!?
3948                if (options.maintainDuration) {
3949                    this.mutate({ datesDelta: startDelta });
3950                }
3951                else {
3952                    this.mutate({ startDelta });
3953                }
3954            }
3955        }
3956        setEnd(endInput, options = {}) {
3957            let { dateEnv } = this._context;
3958            let end;
3959            if (endInput != null) {
3960                end = dateEnv.createMarker(endInput);
3961                if (!end) {
3962                    return; // TODO: warning if parsed bad
3963                }
3964            }
3965            if (this._instance) {
3966                if (end) {
3967                    let endDelta = diffDates(this._instance.range.end, end, dateEnv, options.granularity);
3968                    this.mutate({ endDelta });
3969                }
3970                else {
3971                    this.mutate({ standardProps: { hasEnd: false } });
3972                }
3973            }
3974        }
3975        setDates(startInput, endInput, options = {}) {
3976            let { dateEnv } = this._context;
3977            let standardProps = { allDay: options.allDay };
3978            let start = dateEnv.createMarker(startInput);
3979            let end;
3980            if (!start) {
3981                return; // TODO: warning if parsed bad
3982            }
3983            if (endInput != null) {
3984                end = dateEnv.createMarker(endInput);
3985                if (!end) { // TODO: warning if parsed bad
3986                    return;
3987                }
3988            }
3989            if (this._instance) {
3990                let instanceRange = this._instance.range;
3991                // when computing the diff for an event being converted to all-day,
3992                // compute diff off of the all-day values the way event-mutation does.
3993                if (options.allDay === true) {
3994                    instanceRange = computeAlignedDayRange(instanceRange);
3995                }
3996                let startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity);
3997                if (end) {
3998                    let endDelta = diffDates(instanceRange.end, end, dateEnv, options.granularity);
3999                    if (durationsEqual(startDelta, endDelta)) {
4000                        this.mutate({ datesDelta: startDelta, standardProps });
4001                    }
4002                    else {
4003                        this.mutate({ startDelta, endDelta, standardProps });
4004                    }
4005                }
4006                else { // means "clear the end"
4007                    standardProps.hasEnd = false;
4008                    this.mutate({ datesDelta: startDelta, standardProps });
4009                }
4010            }
4011        }
4012        moveStart(deltaInput) {
4013            let delta = createDuration(deltaInput);
4014            if (delta) { // TODO: warning if parsed bad
4015                this.mutate({ startDelta: delta });
4016            }
4017        }
4018        moveEnd(deltaInput) {
4019            let delta = createDuration(deltaInput);
4020            if (delta) { // TODO: warning if parsed bad
4021                this.mutate({ endDelta: delta });
4022            }
4023        }
4024        moveDates(deltaInput) {
4025            let delta = createDuration(deltaInput);
4026            if (delta) { // TODO: warning if parsed bad
4027                this.mutate({ datesDelta: delta });
4028            }
4029        }
4030        setAllDay(allDay, options = {}) {
4031            let standardProps = { allDay };
4032            let { maintainDuration } = options;
4033            if (maintainDuration == null) {
4034                maintainDuration = this._context.options.allDayMaintainDuration;
4035            }
4036            if (this._def.allDay !== allDay) {
4037                standardProps.hasEnd = maintainDuration;
4038            }
4039            this.mutate({ standardProps });
4040        }
4041        formatRange(formatInput) {
4042            let { dateEnv } = this._context;
4043            let instance = this._instance;
4044            let formatter = createFormatter(formatInput);
4045            if (this._def.hasEnd) {
4046                return dateEnv.formatRange(instance.range.start, instance.range.end, formatter, {
4047                    forcedStartTzo: instance.forcedStartTzo,
4048                    forcedEndTzo: instance.forcedEndTzo,
4049                });
4050            }
4051            return dateEnv.format(instance.range.start, formatter, {
4052                forcedTzo: instance.forcedStartTzo,
4053            });
4054        }
4055        mutate(mutation) {
4056            let instance = this._instance;
4057            if (instance) {
4058                let def = this._def;
4059                let context = this._context;
4060                let { eventStore } = context.getCurrentData();
4061                let relevantEvents = getRelevantEvents(eventStore, instance.instanceId);
4062                let eventConfigBase = {
4063                    '': {
4064                        display: '',
4065                        startEditable: true,
4066                        durationEditable: true,
4067                        constraints: [],
4068                        overlap: null,
4069                        allows: [],
4070                        backgroundColor: '',
4071                        borderColor: '',
4072                        textColor: '',
4073                        classNames: [],
4074                    },
4075                };
4076                relevantEvents = applyMutationToEventStore(relevantEvents, eventConfigBase, mutation, context);
4077                let oldEvent = new EventImpl(context, def, instance); // snapshot
4078                this._def = relevantEvents.defs[def.defId];
4079                this._instance = relevantEvents.instances[instance.instanceId];
4080                context.dispatch({
4081                    type: 'MERGE_EVENTS',
4082                    eventStore: relevantEvents,
4083                });
4084                context.emitter.trigger('eventChange', {
4085                    oldEvent,
4086                    event: this,
4087                    relatedEvents: buildEventApis(relevantEvents, context, instance),
4088                    revert() {
4089                        context.dispatch({
4090                            type: 'RESET_EVENTS',
4091                            eventStore, // the ORIGINAL store
4092                        });
4093                    },
4094                });
4095            }
4096        }
4097        remove() {
4098            let context = this._context;
4099            let asStore = eventApiToStore(this);
4100            context.dispatch({
4101                type: 'REMOVE_EVENTS',
4102                eventStore: asStore,
4103            });
4104            context.emitter.trigger('eventRemove', {
4105                event: this,
4106                relatedEvents: [],
4107                revert() {
4108                    context.dispatch({
4109                        type: 'MERGE_EVENTS',
4110                        eventStore: asStore,
4111                    });
4112                },
4113            });
4114        }
4115        get source() {
4116            let { sourceId } = this._def;
4117            if (sourceId) {
4118                return new EventSourceImpl(this._context, this._context.getCurrentData().eventSources[sourceId]);
4119            }
4120            return null;
4121        }
4122        get start() {
4123            return this._instance ?
4124                this._context.dateEnv.toDate(this._instance.range.start) :
4125                null;
4126        }
4127        get end() {
4128            return (this._instance && this._def.hasEnd) ?
4129                this._context.dateEnv.toDate(this._instance.range.end) :
4130                null;
4131        }
4132        get startStr() {
4133            let instance = this._instance;
4134            if (instance) {
4135                return this._context.dateEnv.formatIso(instance.range.start, {
4136                    omitTime: this._def.allDay,
4137                    forcedTzo: instance.forcedStartTzo,
4138                });
4139            }
4140            return '';
4141        }
4142        get endStr() {
4143            let instance = this._instance;
4144            if (instance && this._def.hasEnd) {
4145                return this._context.dateEnv.formatIso(instance.range.end, {
4146                    omitTime: this._def.allDay,
4147                    forcedTzo: instance.forcedEndTzo,
4148                });
4149            }
4150            return '';
4151        }
4152        // computable props that all access the def
4153        // TODO: find a TypeScript-compatible way to do this at scale
4154        get id() { return this._def.publicId; }
4155        get groupId() { return this._def.groupId; }
4156        get allDay() { return this._def.allDay; }
4157        get title() { return this._def.title; }
4158        get url() { return this._def.url; }
4159        get display() { return this._def.ui.display || 'auto'; } // bad. just normalize the type earlier
4160        get startEditable() { return this._def.ui.startEditable; }
4161        get durationEditable() { return this._def.ui.durationEditable; }
4162        get constraint() { return this._def.ui.constraints[0] || null; }
4163        get overlap() { return this._def.ui.overlap; }
4164        get allow() { return this._def.ui.allows[0] || null; }
4165        get backgroundColor() { return this._def.ui.backgroundColor; }
4166        get borderColor() { return this._def.ui.borderColor; }
4167        get textColor() { return this._def.ui.textColor; }
4168        // NOTE: user can't modify these because Object.freeze was called in event-def parsing
4169        get classNames() { return this._def.ui.classNames; }
4170        get extendedProps() { return this._def.extendedProps; }
4171        toPlainObject(settings = {}) {
4172            let def = this._def;
4173            let { ui } = def;
4174            let { startStr, endStr } = this;
4175            let res = {
4176                allDay: def.allDay,
4177            };
4178            if (def.title) {
4179                res.title = def.title;
4180            }
4181            if (startStr) {
4182                res.start = startStr;
4183            }
4184            if (endStr) {
4185                res.end = endStr;
4186            }
4187            if (def.publicId) {
4188                res.id = def.publicId;
4189            }
4190            if (def.groupId) {
4191                res.groupId = def.groupId;
4192            }
4193            if (def.url) {
4194                res.url = def.url;
4195            }
4196            if (ui.display && ui.display !== 'auto') {
4197                res.display = ui.display;
4198            }
4199            // TODO: what about recurring-event properties???
4200            // TODO: include startEditable/durationEditable/constraint/overlap/allow
4201            if (settings.collapseColor && ui.backgroundColor && ui.backgroundColor === ui.borderColor) {
4202                res.color = ui.backgroundColor;
4203            }
4204            else {
4205                if (ui.backgroundColor) {
4206                    res.backgroundColor = ui.backgroundColor;
4207                }
4208                if (ui.borderColor) {
4209                    res.borderColor = ui.borderColor;
4210                }
4211            }
4212            if (ui.textColor) {
4213                res.textColor = ui.textColor;
4214            }
4215            if (ui.classNames.length) {
4216                res.classNames = ui.classNames;
4217            }
4218            if (Object.keys(def.extendedProps).length) {
4219                if (settings.collapseExtendedProps) {
4220                    Object.assign(res, def.extendedProps);
4221                }
4222                else {
4223                    res.extendedProps = def.extendedProps;
4224                }
4225            }
4226            return res;
4227        }
4228        toJSON() {
4229            return this.toPlainObject();
4230        }
4231    }
4232    function eventApiToStore(eventApi) {
4233        let def = eventApi._def;
4234        let instance = eventApi._instance;
4235        return {
4236            defs: { [def.defId]: def },
4237            instances: instance
4238                ? { [instance.instanceId]: instance }
4239                : {},
4240        };
4241    }
4242    function buildEventApis(eventStore, context, excludeInstance) {
4243        let { defs, instances } = eventStore;
4244        let eventApis = [];
4245        let excludeInstanceId = excludeInstance ? excludeInstance.instanceId : '';
4246        for (let id in instances) {
4247            let instance = instances[id];
4248            let def = defs[instance.defId];
4249            if (instance.instanceId !== excludeInstanceId) {
4250                eventApis.push(new EventImpl(context, def, instance));
4251            }
4252        }
4253        return eventApis;
4254    }
4255
4256    /*
4257    Specifying nextDayThreshold signals that all-day ranges should be sliced.
4258    */
4259    function sliceEventStore(eventStore, eventUiBases, framingRange, nextDayThreshold) {
4260        let inverseBgByGroupId = {};
4261        let inverseBgByDefId = {};
4262        let defByGroupId = {};
4263        let bgRanges = [];
4264        let fgRanges = [];
4265        let eventUis = compileEventUis(eventStore.defs, eventUiBases);
4266        for (let defId in eventStore.defs) {
4267            let def = eventStore.defs[defId];
4268            let ui = eventUis[def.defId];
4269            if (ui.display === 'inverse-background') {
4270                if (def.groupId) {
4271                    inverseBgByGroupId[def.groupId] = [];
4272                    if (!defByGroupId[def.groupId]) {
4273                        defByGroupId[def.groupId] = def;
4274                    }
4275                }
4276                else {
4277                    inverseBgByDefId[defId] = [];
4278                }
4279            }
4280        }
4281        for (let instanceId in eventStore.instances) {
4282            let instance = eventStore.instances[instanceId];
4283            let def = eventStore.defs[instance.defId];
4284            let ui = eventUis[def.defId];
4285            let origRange = instance.range;
4286            let normalRange = (!def.allDay && nextDayThreshold) ?
4287                computeVisibleDayRange(origRange, nextDayThreshold) :
4288                origRange;
4289            let slicedRange = intersectRanges(normalRange, framingRange);
4290            if (slicedRange) {
4291                if (ui.display === 'inverse-background') {
4292                    if (def.groupId) {
4293                        inverseBgByGroupId[def.groupId].push(slicedRange);
4294                    }
4295                    else {
4296                        inverseBgByDefId[instance.defId].push(slicedRange);
4297                    }
4298                }
4299                else if (ui.display !== 'none') {
4300                    (ui.display === 'background' ? bgRanges : fgRanges).push({
4301                        def,
4302                        ui,
4303                        instance,
4304                        range: slicedRange,
4305                        isStart: normalRange.start && normalRange.start.valueOf() === slicedRange.start.valueOf(),
4306                        isEnd: normalRange.end && normalRange.end.valueOf() === slicedRange.end.valueOf(),
4307                    });
4308                }
4309            }
4310        }
4311        for (let groupId in inverseBgByGroupId) { // BY GROUP
4312            let ranges = inverseBgByGroupId[groupId];
4313            let invertedRanges = invertRanges(ranges, framingRange);
4314            for (let invertedRange of invertedRanges) {
4315                let def = defByGroupId[groupId];
4316                let ui = eventUis[def.defId];
4317                bgRanges.push({
4318                    def,
4319                    ui,
4320                    instance: null,
4321                    range: invertedRange,
4322                    isStart: false,
4323                    isEnd: false,
4324                });
4325            }
4326        }
4327        for (let defId in inverseBgByDefId) {
4328            let ranges = inverseBgByDefId[defId];
4329            let invertedRanges = invertRanges(ranges, framingRange);
4330            for (let invertedRange of invertedRanges) {
4331                bgRanges.push({
4332                    def: eventStore.defs[defId],
4333                    ui: eventUis[defId],
4334                    instance: null,
4335                    range: invertedRange,
4336                    isStart: false,
4337                    isEnd: false,
4338                });
4339            }
4340        }
4341        return { bg: bgRanges, fg: fgRanges };
4342    }
4343    function hasBgRendering(def) {
4344        return def.ui.display === 'background' || def.ui.display === 'inverse-background';
4345    }
4346    function setElSeg(el, seg) {
4347        el.fcSeg = seg;
4348    }
4349    function getElSeg(el) {
4350        return el.fcSeg ||
4351            el.parentNode.fcSeg || // for the harness
4352            null;
4353    }
4354    // event ui computation
4355    function compileEventUis(eventDefs, eventUiBases) {
4356        return mapHash(eventDefs, (eventDef) => compileEventUi(eventDef, eventUiBases));
4357    }
4358    function compileEventUi(eventDef, eventUiBases) {
4359        let uis = [];
4360        if (eventUiBases['']) {
4361            uis.push(eventUiBases['']);
4362        }
4363        if (eventUiBases[eventDef.defId]) {
4364            uis.push(eventUiBases[eventDef.defId]);
4365        }
4366        uis.push(eventDef.ui);
4367        return combineEventUis(uis);
4368    }
4369    function sortEventSegs(segs, eventOrderSpecs) {
4370        let objs = segs.map(buildSegCompareObj);
4371        objs.sort((obj0, obj1) => compareByFieldSpecs(obj0, obj1, eventOrderSpecs));
4372        return objs.map((c) => c._seg);
4373    }
4374    // returns a object with all primitive props that can be compared
4375    function buildSegCompareObj(seg) {
4376        let { eventRange } = seg;
4377        let eventDef = eventRange.def;
4378        let range = eventRange.instance ? eventRange.instance.range : eventRange.range;
4379        let start = range.start ? range.start.valueOf() : 0; // TODO: better support for open-range events
4380        let end = range.end ? range.end.valueOf() : 0; // "
4381        return Object.assign(Object.assign(Object.assign({}, eventDef.extendedProps), eventDef), { id: eventDef.publicId, start,
4382            end, duration: end - start, allDay: Number(eventDef.allDay), _seg: seg });
4383    }
4384    function computeSegDraggable(seg, context) {
4385        let { pluginHooks } = context;
4386        let transformers = pluginHooks.isDraggableTransformers;
4387        let { def, ui } = seg.eventRange;
4388        let val = ui.startEditable;
4389        for (let transformer of transformers) {
4390            val = transformer(val, def, ui, context);
4391        }
4392        return val;
4393    }
4394    function computeSegStartResizable(seg, context) {
4395        return seg.isStart && seg.eventRange.ui.durationEditable && context.options.eventResizableFromStart;
4396    }
4397    function computeSegEndResizable(seg, context) {
4398        return seg.isEnd && seg.eventRange.ui.durationEditable;
4399    }
4400    function buildSegTimeText(seg, timeFormat, context, defaultDisplayEventTime, // defaults to true
4401                              defaultDisplayEventEnd, // defaults to true
4402                              startOverride, endOverride) {
4403        let { dateEnv, options } = context;
4404        let { displayEventTime, displayEventEnd } = options;
4405        let eventDef = seg.eventRange.def;
4406        let eventInstance = seg.eventRange.instance;
4407        if (displayEventTime == null) {
4408            displayEventTime = defaultDisplayEventTime !== false;
4409        }
4410        if (displayEventEnd == null) {
4411            displayEventEnd = defaultDisplayEventEnd !== false;
4412        }
4413        let wholeEventStart = eventInstance.range.start;
4414        let wholeEventEnd = eventInstance.range.end;
4415        let segStart = startOverride || seg.start || seg.eventRange.range.start;
4416        let segEnd = endOverride || seg.end || seg.eventRange.range.end;
4417        let isStartDay = startOfDay(wholeEventStart).valueOf() === startOfDay(segStart).valueOf();
4418        let isEndDay = startOfDay(addMs(wholeEventEnd, -1)).valueOf() === startOfDay(addMs(segEnd, -1)).valueOf();
4419        if (displayEventTime && !eventDef.allDay && (isStartDay || isEndDay)) {
4420            segStart = isStartDay ? wholeEventStart : segStart;
4421            segEnd = isEndDay ? wholeEventEnd : segEnd;
4422            if (displayEventEnd && eventDef.hasEnd) {
4423                return dateEnv.formatRange(segStart, segEnd, timeFormat, {
4424                    forcedStartTzo: startOverride ? null : eventInstance.forcedStartTzo,
4425                    forcedEndTzo: endOverride ? null : eventInstance.forcedEndTzo,
4426                });
4427            }
4428            return dateEnv.format(segStart, timeFormat, {
4429                forcedTzo: startOverride ? null : eventInstance.forcedStartTzo, // nooooo, same
4430            });
4431        }
4432        return '';
4433    }
4434    function getSegMeta(seg, todayRange, nowDate) {
4435        let segRange = seg.eventRange.range;
4436        return {
4437            isPast: segRange.end < (nowDate || todayRange.start),
4438            isFuture: segRange.start >= (nowDate || todayRange.end),
4439            isToday: todayRange && rangeContainsMarker(todayRange, segRange.start),
4440        };
4441    }
4442    function getEventClassNames(props) {
4443        let classNames = ['fc-event'];
4444        if (props.isMirror) {
4445            classNames.push('fc-event-mirror');
4446        }
4447        if (props.isDraggable) {
4448            classNames.push('fc-event-draggable');
4449        }
4450        if (props.isStartResizable || props.isEndResizable) {
4451            classNames.push('fc-event-resizable');
4452        }
4453        if (props.isDragging) {
4454            classNames.push('fc-event-dragging');
4455        }
4456        if (props.isResizing) {
4457            classNames.push('fc-event-resizing');
4458        }
4459        if (props.isSelected) {
4460            classNames.push('fc-event-selected');
4461        }
4462        if (props.isStart) {
4463            classNames.push('fc-event-start');
4464        }
4465        if (props.isEnd) {
4466            classNames.push('fc-event-end');
4467        }
4468        if (props.isPast) {
4469            classNames.push('fc-event-past');
4470        }
4471        if (props.isToday) {
4472            classNames.push('fc-event-today');
4473        }
4474        if (props.isFuture) {
4475            classNames.push('fc-event-future');
4476        }
4477        return classNames;
4478    }
4479    function buildEventRangeKey(eventRange) {
4480        return eventRange.instance
4481            ? eventRange.instance.instanceId
4482            : `${eventRange.def.defId}:${eventRange.range.start.toISOString()}`;
4483        // inverse-background events don't have specific instances. TODO: better solution
4484    }
4485    function getSegAnchorAttrs(seg, context) {
4486        let { def, instance } = seg.eventRange;
4487        let { url } = def;
4488        if (url) {
4489            return { href: url };
4490        }
4491        let { emitter, options } = context;
4492        let { eventInteractive } = options;
4493        if (eventInteractive == null) {
4494            eventInteractive = def.interactive;
4495            if (eventInteractive == null) {
4496                eventInteractive = Boolean(emitter.hasHandlers('eventClick'));
4497            }
4498        }
4499        // mock what happens in EventClicking
4500        if (eventInteractive) {
4501            // only attach keyboard-related handlers because click handler is already done in EventClicking
4502            return createAriaKeyboardAttrs((ev) => {
4503                emitter.trigger('eventClick', {
4504                    el: ev.target,
4505                    event: new EventImpl(context, def, instance),
4506                    jsEvent: ev,
4507                    view: context.viewApi,
4508                });
4509            });
4510        }
4511        return {};
4512    }
4513
4514    const STANDARD_PROPS = {
4515        start: identity,
4516        end: identity,
4517        allDay: Boolean,
4518    };
4519    function parseDateSpan(raw, dateEnv, defaultDuration) {
4520        let span = parseOpenDateSpan(raw, dateEnv);
4521        let { range } = span;
4522        if (!range.start) {
4523            return null;
4524        }
4525        if (!range.end) {
4526            if (defaultDuration == null) {
4527                return null;
4528            }
4529            range.end = dateEnv.add(range.start, defaultDuration);
4530        }
4531        return span;
4532    }
4533    /*
4534    TODO: somehow combine with parseRange?
4535    Will return null if the start/end props were present but parsed invali
vendor: 11,466 bytes, lines 4535-4839
4535dly.
4536    */
4537    function parseOpenDateSpan(raw, dateEnv) {
4538        let { refined: standardProps, extra } = refineProps(raw, STANDARD_PROPS);
4539        let startMeta = standardProps.start ? dateEnv.createMarkerMeta(standardProps.start) : null;
4540        let endMeta = standardProps.end ? dateEnv.createMarkerMeta(standardProps.end) : null;
4541        let { allDay } = standardProps;
4542        if (allDay == null) {
4543            allDay = (startMeta && startMeta.isTimeUnspecified) &&
4544                (!endMeta || endMeta.isTimeUnspecified);
4545        }
4546        return Object.assign({ range: {
4547                start: startMeta ? startMeta.marker : null,
4548                end: endMeta ? endMeta.marker : null,
4549            }, allDay }, extra);
4550    }
4551    function isDateSpansEqual(span0, span1) {
4552        return rangesEqual(span0.range, span1.range) &&
4553            span0.allDay === span1.allDay &&
4554            isSpanPropsEqual(span0, span1);
4555    }
4556    // the NON-DATE-RELATED props
4557    function isSpanPropsEqual(span0, span1) {
4558        for (let propName in span1) {
4559            if (propName !== 'range' && propName !== 'allDay') {
4560                if (span0[propName] !== span1[propName]) {
4561                    return false;
4562                }
4563            }
4564        }
4565        // are there any props that span0 has that span1 DOESN'T have?
4566        // both have range/allDay, so no need to special-case.
4567        for (let propName in span0) {
4568            if (!(propName in span1)) {
4569                return false;
4570            }
4571        }
4572        return true;
4573    }
4574    function buildDateSpanApi(span, dateEnv) {
4575        return Object.assign(Object.assign({}, buildRangeApi(span.range, dateEnv, span.allDay)), { allDay: span.allDay });
4576    }
4577    function buildRangeApiWithTimeZone(range, dateEnv, omitTime) {
4578        return Object.assign(Object.assign({}, buildRangeApi(range, dateEnv, omitTime)), { timeZone: dateEnv.timeZone });
4579    }
4580    function buildRangeApi(range, dateEnv, omitTime) {
4581        return {
4582            start: dateEnv.toDate(range.start),
4583            end: dateEnv.toDate(range.end),
4584            startStr: dateEnv.formatIso(range.start, { omitTime }),
4585            endStr: dateEnv.formatIso(range.end, { omitTime }),
4586        };
4587    }
4588    function fabricateEventRange(dateSpan, eventUiBases, context) {
4589        let res = refineEventDef({ editable: false }, context);
4590        let def = parseEventDef(res.refined, res.extra, '', // sourceId
4591            dateSpan.allDay, true, // hasEnd
4592            context);
4593        return {
4594            def,
4595            ui: compileEventUi(def, eventUiBases),
4596            instance: createEventInstance(def.defId, dateSpan.range),
4597            range: dateSpan.range,
4598            isStart: true,
4599            isEnd: true,
4600        };
4601    }
4602
4603    /*
4604    given a function that resolves a result asynchronously.
4605    the function can either call passed-in success and failure callbacks,
4606    or it can return a promise.
4607    if you need to pass additional params to func, bind them first.
4608    */
4609    function unpromisify(func, normalizedSuccessCallback, normalizedFailureCallback) {
4610        // guard against success/failure callbacks being called more than once
4611        // and guard against a promise AND callback being used together.
4612        let isResolved = false;
4613        let wrappedSuccess = function (res) {
4614            if (!isResolved) {
4615                isResolved = true;
4616                normalizedSuccessCallback(res);
4617            }
4618        };
4619        let wrappedFailure = function (error) {
4620            if (!isResolved) {
4621                isResolved = true;
4622                normalizedFailureCallback(error);
4623            }
4624        };
4625        let res = func(wrappedSuccess, wrappedFailure);
4626        if (res && typeof res.then === 'function') {
4627            res.then(wrappedSuccess, wrappedFailure);
4628        }
4629    }
4630
4631    class JsonRequestError extends Error {
4632        constructor(message, response) {
4633            super(message);
4634            this.response = response;
4635        }
4636    }
4637    function requestJson(method, url, params) {
4638        method = method.toUpperCase();
4639        const fetchOptions = {
4640            method,
4641        };
4642        if (method === 'GET') {
4643            url += (url.indexOf('?') === -1 ? '?' : '&') +
4644                new URLSearchParams(params);
4645        }
4646        else {
4647            fetchOptions.body = new URLSearchParams(params);
4648            fetchOptions.headers = {
4649                'Content-Type': 'application/x-www-form-urlencoded',
4650            };
4651        }
4652        return fetch(url, fetchOptions).then((fetchRes) => {
4653            if (fetchRes.ok) {
4654                return fetchRes.json().then((parsedResponse) => {
4655                    return [parsedResponse, fetchRes];
4656                }, () => {
4657                    throw new JsonRequestError('Failure parsing JSON', fetchRes);
4658                });
4659            }
4660            else {
4661                throw new JsonRequestError('Request failed', fetchRes);
4662            }
4663        });
4664    }
4665
4666    let canVGrowWithinCell;
4667    function getCanVGrowWithinCell() {
4668        if (canVGrowWithinCell == null) {
4669            canVGrowWithinCell = computeCanVGrowWithinCell();
4670        }
4671        return canVGrowWithinCell;
4672    }
4673    function computeCanVGrowWithinCell() {
4674        // for SSR, because this function is call immediately at top-level
4675        // TODO: just make this logic execute top-level, immediately, instead of doing lazily
4676        if (typeof document === 'undefined') {
4677            return true;
4678        }
4679        let el = document.createElement('div');
4680        el.style.position = 'absolute';
4681        el.style.top = '0px';
4682        el.style.left = '0px';
4683        el.innerHTML = '<table><tr><td><div></div></td></tr></table>';
4684        el.querySelector('table').style.height = '100px';
4685        el.querySelector('div').style.height = '100%';
4686        document.body.appendChild(el);
4687        let div = el.querySelector('div');
4688        let possible = div.offsetHeight > 0;
4689        document.body.removeChild(el);
4690        return possible;
4691    }
4692
4693    class CalendarRoot extends BaseComponent {
4694        constructor() {
4695            super(...arguments);
4696            this.state = {
4697                forPrint: false,
4698            };
4699            this.handleBeforePrint = () => {
4700                this.setState({ forPrint: true });
4701            };
4702            this.handleAfterPrint = () => {
4703                this.setState({ forPrint: false });
4704            };
4705        }
4706        render() {
4707            let { props } = this;
4708            let { options } = props;
4709            let { forPrint } = this.state;
4710            let isHeightAuto = forPrint || options.height === 'auto' || options.contentHeight === 'auto';
4711            let height = (!isHeightAuto && options.height != null) ? options.height : '';
4712            let classNames = [
4713                'fc',
4714                forPrint ? 'fc-media-print' : 'fc-media-screen',
4715                `fc-direction-${options.direction}`,
4716                props.theme.getClass('root'),
4717            ];
4718            if (!getCanVGrowWithinCell()) {
4719                classNames.push('fc-liquid-hack');
4720            }
4721            return props.children(classNames, height, isHeightAuto, forPrint);
4722        }
4723        componentDidMount() {
4724            let { emitter } = this.props;
4725            emitter.on('_beforeprint', this.handleBeforePrint);
4726            emitter.on('_afterprint', this.handleAfterPrint);
4727        }
4728        componentWillUnmount() {
4729            let { emitter } = this.props;
4730            emitter.off('_beforeprint', this.handleBeforePrint);
4731            emitter.off('_afterprint', this.handleAfterPrint);
4732        }
4733    }
4734
4735    class Interaction {
4736        constructor(settings) {
4737            this.component = settings.component;
4738            this.isHitComboAllowed = settings.isHitComboAllowed || null;
4739        }
4740        destroy() {
4741        }
4742    }
4743    function parseInteractionSettings(component, input) {
4744        return {
4745            component,
4746            el: input.el,
4747            useEventCenter: input.useEventCenter != null ? input.useEventCenter : true,
4748            isHitComboAllowed: input.isHitComboAllowed || null,
4749        };
4750    }
4751    function interactionSettingsToStore(settings) {
4752        return {
4753            [settings.component.uid]: settings,
4754        };
4755    }
4756    // global state
4757    const interactionSettingsStore = {};
4758
4759    class CalendarImpl {
4760        getCurrentData() {
4761            return this.currentDataManager.getCurrentData();
4762        }
4763        dispatch(action) {
4764            this.currentDataManager.dispatch(action);
4765        }
4766        get view() { return this.getCurrentData().viewApi; }
4767        batchRendering(callback) {
4768            callback();
4769        }
4770        updateSize() {
4771            this.trigger('_resize', true);
4772        }
4773        // Options
4774        // -----------------------------------------------------------------------------------------------------------------
4775        setOption(name, val) {
4776            this.dispatch({
4777                type: 'SET_OPTION',
4778                optionName: name,
4779                rawOptionValue: val,
4780            });
4781        }
4782        getOption(name) {
4783            return this.currentDataManager.currentCalendarOptionsInput[name];
4784        }
4785        getAvailableLocaleCodes() {
4786            return Object.keys(this.getCurrentData().availableRawLocales);
4787        }
4788        // Trigger
4789        // -----------------------------------------------------------------------------------------------------------------
4790        on(handlerName, handler) {
4791            let { currentDataManager } = this;
4792            if (currentDataManager.currentCalendarOptionsRefiners[handlerName]) {
4793                currentDataManager.emitter.on(handlerName, handler);
4794            }
4795            else {
4796                console.warn(`Unknown listener name '${handlerName}'`);
4797            }
4798        }
4799        off(handlerName, handler) {
4800            this.currentDataManager.emitter.off(handlerName, handler);
4801        }
4802        // not meant for public use
4803        trigger(handlerName, ...args) {
4804            this.currentDataManager.emitter.trigger(handlerName, ...args);
4805        }
4806        // View
4807        // -----------------------------------------------------------------------------------------------------------------
4808        changeView(viewType, dateOrRange) {
4809            this.batchRendering(() => {
4810                this.unselect();
4811                if (dateOrRange) {
4812                    if (dateOrRange.start && dateOrRange.end) { // a range
4813                        this.dispatch({
4814                            type: 'CHANGE_VIEW_TYPE',
4815                            viewType,
4816                        });
4817                        this.dispatch({
4818                            type: 'SET_OPTION',
4819                            optionName: 'visibleRange',
4820                            rawOptionValue: dateOrRange,
4821                        });
4822                    }
4823                    else {
4824                        let { dateEnv } = this.getCurrentData();
4825                        this.dispatch({
4826                            type: 'CHANGE_VIEW_TYPE',
4827                            viewType,
4828                            dateMarker: dateEnv.createMarker(dateOrRange),
4829                        });
4830                    }
4831                }
4832                else {
4833                    this.dispatch({
4834                        type: 'CHANGE_VIEW_TYPE',
4835                        viewType,
4836                    });
4837                }
4838            });
4839        }
vendor: 21,600 bytes, lines 4840-5371
4840        // Forces navigation to a view for the given date.
4841        // `viewType` can be a specific view name or a generic one like "week" or "day".
4842        // needs to change
4843        zoomTo(dateMarker, viewType) {
4844            let state = this.getCurrentData();
4845            let spec;
4846            viewType = viewType || 'day'; // day is default zoom
4847            spec = state.viewSpecs[viewType] || this.getUnitViewSpec(viewType);
4848            this.unselect();
4849            if (spec) {
4850                this.dispatch({
4851                    type: 'CHANGE_VIEW_TYPE',
4852                    viewType: spec.type,
4853                    dateMarker,
4854                });
4855            }
4856            else {
4857                this.dispatch({
4858                    type: 'CHANGE_DATE',
4859                    dateMarker,
4860                });
4861            }
4862        }
4863        // Given a duration singular unit, like "week" or "day", finds a matching view spec.
4864        // Preference is given to views that have corresponding buttons.
4865        getUnitViewSpec(unit) {
4866            let { viewSpecs, toolbarConfig } = this.getCurrentData();
4867            let viewTypes = [].concat(toolbarConfig.header ? toolbarConfig.header.viewsWithButtons : [], toolbarConfig.footer ? toolbarConfig.footer.viewsWithButtons : []);
4868            let i;
4869            let spec;
4870            for (let viewType in viewSpecs) {
4871                viewTypes.push(viewType);
4872            }
4873            for (i = 0; i < viewTypes.length; i += 1) {
4874                spec = viewSpecs[viewTypes[i]];
4875                if (spec) {
4876                    if (spec.singleUnit === unit) {
4877                        return spec;
4878                    }
4879                }
4880            }
4881            return null;
4882        }
4883        // Current Date
4884        // -----------------------------------------------------------------------------------------------------------------
4885        prev() {
4886            this.unselect();
4887            this.dispatch({ type: 'PREV' });
4888        }
4889        next() {
4890            this.unselect();
4891            this.dispatch({ type: 'NEXT' });
4892        }
4893        prevYear() {
4894            let state = this.getCurrentData();
4895            this.unselect();
4896            this.dispatch({
4897                type: 'CHANGE_DATE',
4898                dateMarker: state.dateEnv.addYears(state.currentDate, -1),
4899            });
4900        }
4901        nextYear() {
4902            let state = this.getCurrentData();
4903            this.unselect();
4904            this.dispatch({
4905                type: 'CHANGE_DATE',
4906                dateMarker: state.dateEnv.addYears(state.currentDate, 1),
4907            });
4908        }
4909        today() {
4910            let state = this.getCurrentData();
4911            this.unselect();
4912            this.dispatch({
4913                type: 'CHANGE_DATE',
4914                dateMarker: getNow(state.calendarOptions.now, state.dateEnv),
4915            });
4916        }
4917        gotoDate(zonedDateInput) {
4918            let state = this.getCurrentData();
4919            this.unselect();
4920            this.dispatch({
4921                type: 'CHANGE_DATE',
4922                dateMarker: state.dateEnv.createMarker(zonedDateInput),
4923            });
4924        }
4925        incrementDate(deltaInput) {
4926            let state = this.getCurrentData();
4927            let delta = createDuration(deltaInput);
4928            if (delta) { // else, warn about invalid input?
4929                this.unselect();
4930                this.dispatch({
4931                    type: 'CHANGE_DATE',
4932                    dateMarker: state.dateEnv.add(state.currentDate, delta),
4933                });
4934            }
4935        }
4936        getDate() {
4937            let state = this.getCurrentData();
4938            return state.dateEnv.toDate(state.currentDate);
4939        }
4940        // Date Formatting Utils
4941        // -----------------------------------------------------------------------------------------------------------------
4942        formatDate(d, formatter) {
4943            let { dateEnv } = this.getCurrentData();
4944            return dateEnv.format(dateEnv.createMarker(d), createFormatter(formatter));
4945        }
4946        // `settings` is for formatter AND isEndExclusive
4947        formatRange(d0, d1, settings) {
4948            let { dateEnv } = this.getCurrentData();
4949            return dateEnv.formatRange(dateEnv.createMarker(d0), dateEnv.createMarker(d1), createFormatter(settings), settings);
4950        }
4951        formatIso(d, omitTime) {
4952            let { dateEnv } = this.getCurrentData();
4953            return dateEnv.formatIso(dateEnv.createMarker(d), { omitTime });
4954        }
4955        // Date Selection / Event Selection / DayClick
4956        // -----------------------------------------------------------------------------------------------------------------
4957        select(dateOrObj, endDate) {
4958            let selectionInput;
4959            if (endDate == null) {
4960                if (dateOrObj.start != null) {
4961                    selectionInput = dateOrObj;
4962                }
4963                else {
4964                    selectionInput = {
4965                        start: dateOrObj,
4966                        end: null,
4967                    };
4968                }
4969            }
4970            else {
4971                selectionInput = {
4972                    start: dateOrObj,
4973                    end: endDate,
4974                };
4975            }
4976            let state = this.getCurrentData();
4977            let selection = parseDateSpan(selectionInput, state.dateEnv, createDuration({ days: 1 }));
4978            if (selection) { // throw parse error otherwise?
4979                this.dispatch({ type: 'SELECT_DATES', selection });
4980                triggerDateSelect(selection, null, state);
4981            }
4982        }
4983        unselect(pev) {
4984            let state = this.getCurrentData();
4985            if (state.dateSelection) {
4986                this.dispatch({ type: 'UNSELECT_DATES' });
4987                triggerDateUnselect(pev, state);
4988            }
4989        }
4990        // Public Events API
4991        // -----------------------------------------------------------------------------------------------------------------
4992        addEvent(eventInput, sourceInput) {
4993            if (eventInput instanceof EventImpl) {
4994                let def = eventInput._def;
4995                let instance = eventInput._instance;
4996                let currentData = this.getCurrentData();
4997                // not already present? don't want to add an old snapshot
4998                if (!currentData.eventStore.defs[def.defId]) {
4999                    this.dispatch({
5000                        type: 'ADD_EVENTS',
5001                        eventStore: eventTupleToStore({ def, instance }), // TODO: better util for two args?
5002                    });
5003                    this.triggerEventAdd(eventInput);
5004                }
5005                return eventInput;
5006            }
5007            let state = this.getCurrentData();
5008            let eventSource;
5009            if (sourceInput instanceof EventSourceImpl) {
5010                eventSource = sourceInput.internalEventSource;
5011            }
5012            else if (typeof sourceInput === 'boolean') {
5013                if (sourceInput) { // true. part of the first event source
5014                    [eventSource] = hashValuesToArray(state.eventSources);
5015                }
5016            }
5017            else if (sourceInput != null) { // an ID. accepts a number too
5018                let sourceApi = this.getEventSourceById(sourceInput); // TODO: use an internal function
5019                if (!sourceApi) {
5020                    console.warn(`Could not find an event source with ID "${sourceInput}"`); // TODO: test
5021                    return null;
5022                }
5023                eventSource = sourceApi.internalEventSource;
5024            }
5025            let tuple = parseEvent(eventInput, eventSource, state, false);
5026            if (tuple) {
5027                let newEventApi = new EventImpl(state, tuple.def, tuple.def.recurringDef ? null : tuple.instance);
5028                this.dispatch({
5029                    type: 'ADD_EVENTS',
5030                    eventStore: eventTupleToStore(tuple),
5031                });
5032                this.triggerEventAdd(newEventApi);
5033                return newEventApi;
5034            }
5035            return null;
5036        }
5037        triggerEventAdd(eventApi) {
5038            let { emitter } = this.getCurrentData();
5039            emitter.trigger('eventAdd', {
5040                event: eventApi,
5041                relatedEvents: [],
5042                revert: () => {
5043                    this.dispatch({
5044                        type: 'REMOVE_EVENTS',
5045                        eventStore: eventApiToStore(eventApi),
5046                    });
5047                },
5048            });
5049        }
5050        // TODO: optimize
5051        getEventById(id) {
5052            let state = this.getCurrentData();
5053            let { defs, instances } = state.eventStore;
5054            id = String(id);
5055            for (let defId in defs) {
5056                let def = defs[defId];
5057                if (def.publicId === id) {
5058                    if (def.recurringDef) {
5059                        return new EventImpl(state, def, null);
5060                    }
5061                    for (let instanceId in instances) {
5062                        let instance = instances[instanceId];
5063                        if (instance.defId === def.defId) {
5064                            return new EventImpl(state, def, instance);
5065                        }
5066                    }
5067                }
5068            }
5069            return null;
5070        }
5071        getEvents() {
5072            let currentData = this.getCurrentData();
5073            return buildEventApis(currentData.eventStore, currentData);
5074        }
5075        removeAllEvents() {
5076            this.dispatch({ type: 'REMOVE_ALL_EVENTS' });
5077        }
5078        // Public Event Sources API
5079        // -----------------------------------------------------------------------------------------------------------------
5080        getEventSources() {
5081            let state = this.getCurrentData();
5082            let sourceHash = state.eventSources;
5083            let sourceApis = [];
5084            for (let internalId in sourceHash) {
5085                sourceApis.push(new EventSourceImpl(state, sourceHash[internalId]));
5086            }
5087            return sourceApis;
5088        }
5089        getEventSourceById(id) {
5090            let state = this.getCurrentData();
5091            let sourceHash = state.eventSources;
5092            id = String(id);
5093            for (let sourceId in sourceHash) {
5094                if (sourceHash[sourceId].publicId === id) {
5095                    return new EventSourceImpl(state, sourceHash[sourceId]);
5096                }
5097            }
5098            return null;
5099        }
5100        addEventSource(sourceInput) {
5101            let state = this.getCurrentData();
5102            if (sourceInput instanceof EventSourceImpl) {
5103                // not already present? don't want to add an old snapshot
5104                if (!state.eventSources[sourceInput.internalEventSource.sourceId]) {
5105                    this.dispatch({
5106                        type: 'ADD_EVENT_SOURCES',
5107                        sources: [sourceInput.internalEventSource],
5108                    });
5109                }
5110                return sourceInput;
5111            }
5112            let eventSource = parseEventSource(sourceInput, state);
5113            if (eventSource) { // TODO: error otherwise?
5114                this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [eventSource] });
5115                return new EventSourceImpl(state, eventSource);
5116            }
5117            return null;
5118        }
5119        removeAllEventSources() {
5120            this.dispatch({ type: 'REMOVE_ALL_EVENT_SOURCES' });
5121        }
5122        refetchEvents() {
5123            this.dispatch({ type: 'FETCH_EVENT_SOURCES', isRefetch: true });
5124        }
5125        // Scroll
5126        // -----------------------------------------------------------------------------------------------------------------
5127        scrollToTime(timeInput) {
5128            let time = createDuration(timeInput);
5129            if (time) {
5130                this.trigger('_scrollRequest', { time });
5131            }
5132        }
5133    }
5134
5135    function pointInsideRect(point, rect) {
5136        return point.left >= rect.left &&
5137            point.left < rect.right &&
5138            point.top >= rect.top &&
5139            point.top < rect.bottom;
5140    }
5141    // Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false
5142    function intersectRects(rect1, rect2) {
5143        let res = {
5144            left: Math.max(rect1.left, rect2.left),
5145            right: Math.min(rect1.right, rect2.right),
5146            top: Math.max(rect1.top, rect2.top),
5147            bottom: Math.min(rect1.bottom, rect2.bottom),
5148        };
5149        if (res.left < res.right && res.top < res.bottom) {
5150            return res;
5151        }
5152        return false;
5153    }
5154    function translateRect(rect, deltaX, deltaY) {
5155        return {
5156            left: rect.left + deltaX,
5157            right: rect.right + deltaX,
5158            top: rect.top + deltaY,
5159            bottom: rect.bottom + deltaY,
5160        };
5161    }
5162    // Returns a new point that will have been moved to reside within the given rectangle
5163    function constrainPoint(point, rect) {
5164        return {
5165            left: Math.min(Math.max(point.left, rect.left), rect.right),
5166            top: Math.min(Math.max(point.top, rect.top), rect.bottom),
5167        };
5168    }
5169    // Returns a point that is the center of the given rectangle
5170    function getRectCenter(rect) {
5171        return {
5172            left: (rect.left + rect.right) / 2,
5173            top: (rect.top + rect.bottom) / 2,
5174        };
5175    }
5176    // Subtracts point2's coordinates from point1's coordinates, returning a delta
5177    function diffPoints(point1, point2) {
5178        return {
5179            left: point1.left - point2.left,
5180            top: point1.top - point2.top,
5181        };
5182    }
5183
5184    const EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere
5185    class Splitter {
5186        constructor() {
5187            this.getKeysForEventDefs = memoize(this._getKeysForEventDefs);
5188            this.splitDateSelection = memoize(this._splitDateSpan);
5189            this.splitEventStore = memoize(this._splitEventStore);
5190            this.splitIndividualUi = memoize(this._splitIndividualUi);
5191            this.splitEventDrag = memoize(this._splitInteraction);
5192            this.splitEventResize = memoize(this._splitInteraction);
5193            this.eventUiBuilders = {}; // TODO: typescript protection
5194        }
5195        splitProps(props) {
5196            let keyInfos = this.getKeyInfo(props);
5197            let defKeys = this.getKeysForEventDefs(props.eventStore);
5198            let dateSelections = this.splitDateSelection(props.dateSelection);
5199            let individualUi = this.splitIndividualUi(props.eventUiBases, defKeys); // the individual *bases*
5200            let eventStores = this.splitEventStore(props.eventStore, defKeys);
5201            let eventDrags = this.splitEventDrag(props.eventDrag);
5202            let eventResizes = this.splitEventResize(props.eventResize);
5203            let splitProps = {};
5204            this.eventUiBuilders = mapHash(keyInfos, (info, key) => this.eventUiBuilders[key] || memoize(buildEventUiForKey));
5205            for (let key in keyInfos) {
5206                let keyInfo = keyInfos[key];
5207                let eventStore = eventStores[key] || EMPTY_EVENT_STORE;
5208                let buildEventUi = this.eventUiBuilders[key];
5209                splitProps[key] = {
5210                    businessHours: keyInfo.businessHours || props.businessHours,
5211                    dateSelection: dateSelections[key] || null,
5212                    eventStore,
5213                    eventUiBases: buildEventUi(props.eventUiBases[''], keyInfo.ui, individualUi[key]),
5214                    eventSelection: eventStore.instances[props.eventSelection] ? props.eventSelection : '',
5215                    eventDrag: eventDrags[key] || null,
5216                    eventResize: eventResizes[key] || null,
5217                };
5218            }
5219            return splitProps;
5220        }
5221        _splitDateSpan(dateSpan) {
5222            let dateSpans = {};
5223            if (dateSpan) {
5224                let keys = this.getKeysForDateSpan(dateSpan);
5225                for (let key of keys) {
5226                    dateSpans[key] = dateSpan;
5227                }
5228            }
5229            return dateSpans;
5230        }
5231        _getKeysForEventDefs(eventStore) {
5232            return mapHash(eventStore.defs, (eventDef) => this.getKeysForEventDef(eventDef));
5233        }
5234        _splitEventStore(eventStore, defKeys) {
5235            let { defs, instances } = eventStore;
5236            let splitStores = {};
5237            for (let defId in defs) {
5238                for (let key of defKeys[defId]) {
5239                    if (!splitStores[key]) {
5240                        splitStores[key] = createEmptyEventStore();
5241                    }
5242                    splitStores[key].defs[defId] = defs[defId];
5243                }
5244            }
5245            for (let instanceId in instances) {
5246                let instance = instances[instanceId];
5247                for (let key of defKeys[instance.defId]) {
5248                    if (splitStores[key]) { // must have already been created
5249                        splitStores[key].instances[instanceId] = instance;
5250                    }
5251                }
5252            }
5253            return splitStores;
5254        }
5255        _splitIndividualUi(eventUiBases, defKeys) {
5256            let splitHashes = {};
5257            for (let defId in eventUiBases) {
5258                if (defId) { // not the '' key
5259                    for (let key of defKeys[defId]) {
5260                        if (!splitHashes[key]) {
5261                            splitHashes[key] = {};
5262                        }
5263                        splitHashes[key][defId] = eventUiBases[defId];
5264                    }
5265                }
5266            }
5267            return splitHashes;
5268        }
5269        _splitInteraction(interaction) {
5270            let splitStates = {};
5271            if (interaction) {
5272                let affectedStores = this._splitEventStore(interaction.affectedEvents, this._getKeysForEventDefs(interaction.affectedEvents));
5273                // can't rely on defKeys because event data is mutated
5274                let mutatedKeysByDefId = this._getKeysForEventDefs(interaction.mutatedEvents);
5275                let mutatedStores = this._splitEventStore(interaction.mutatedEvents, mutatedKeysByDefId);
5276                let populate = (key) => {
5277                    if (!splitStates[key]) {
5278                        splitStates[key] = {
5279                            affectedEvents: affectedStores[key] || EMPTY_EVENT_STORE,
5280                            mutatedEvents: mutatedStores[key] || EMPTY_EVENT_STORE,
5281                            isEvent: interaction.isEvent,
5282                        };
5283                    }
5284                };
5285                for (let key in affectedStores) {
5286                    populate(key);
5287                }
5288                for (let key in mutatedStores) {
5289                    populate(key);
5290                }
5291            }
5292            return splitStates;
5293        }
5294    }
5295    function buildEventUiForKey(allUi, eventUiForKey, individualUi) {
5296        let baseParts = [];
5297        if (allUi) {
5298            baseParts.push(allUi);
5299        }
5300        if (eventUiForKey) {
5301            baseParts.push(eventUiForKey);
5302        }
5303        let stuff = {
5304            '': combineEventUis(baseParts),
5305        };
5306        if (individualUi) {
5307            Object.assign(stuff, individualUi);
5308        }
5309        return stuff;
5310    }
5311
5312    function getDateMeta(date, todayRange, nowDate, dateProfile) {
5313        return {
5314            dow: date.getUTCDay(),
5315            isDisabled: Boolean(dateProfile && !rangeContainsMarker(dateProfile.activeRange, date)),
5316            isOther: Boolean(dateProfile && !rangeContainsMarker(dateProfile.currentRange, date)),
5317            isToday: Boolean(todayRange && rangeContainsMarker(todayRange, date)),
5318            isPast: Boolean(nowDate ? (date < nowDate) : todayRange ? (date < todayRange.start) : false),
5319            isFuture: Boolean(nowDate ? (date > nowDate) : todayRange ? (date >= todayRange.end) : false),
5320        };
5321    }
5322    function getDayClassNames(meta, theme) {
5323        let classNames = [
5324            'fc-day',
5325            `fc-day-${DAY_IDS[meta.dow]}`,
5326        ];
5327        if (meta.isDisabled) {
5328            classNames.push('fc-day-disabled');
5329        }
5330        else {
5331            if (meta.isToday) {
5332                classNames.push('fc-day-today');
5333                classNames.push(theme.getClass('today'));
5334            }
5335            if (meta.isPast) {
5336                classNames.push('fc-day-past');
5337            }
5338            if (meta.isFuture) {
5339                classNames.push('fc-day-future');
5340            }
5341            if (meta.isOther) {
5342                classNames.push('fc-day-other');
5343            }
5344        }
5345        return classNames;
5346    }
5347    function getSlotClassNames(meta, theme) {
5348        let classNames = [
5349            'fc-slot',
5350            `fc-slot-${DAY_IDS[meta.dow]}`,
5351        ];
5352        if (meta.isDisabled) {
5353            classNames.push('fc-slot-disabled');
5354        }
5355        else {
5356            if (meta.isToday) {
5357                classNames.push('fc-slot-today');
5358                classNames.push(theme.getClass('today'));
5359            }
5360            if (meta.isPast) {
5361                classNames.push('fc-slot-past');
5362            }
5363            if (meta.isFuture) {
5364                classNames.push('fc-slot-future');
5365            }
5366        }
5367        return classNames;
5368    }
5369
5370    const DAY_FORMAT = createFormatter({ year: 'numeric', month: 'long', day: 'numeric' });
5371    const WEEK_FORMAT = createFormatter({ week: 'long' });
vendor: 7,271 bytes, lines 5372-5552
5372    function buildNavLinkAttrs(context, dateMarker, viewType = 'day', isTabbable = true) {
5373        const { dateEnv, options, calendarApi } = context;
5374        let dateStr = dateEnv.format(dateMarker, viewType === 'week' ? WEEK_FORMAT : DAY_FORMAT);
5375        if (options.navLinks) {
5376            let zonedDate = dateEnv.toDate(dateMarker);
5377            const handleInteraction = (ev) => {
5378                let customAction = viewType === 'day' ? options.navLinkDayClick :
5379                    viewType === 'week' ? options.navLinkWeekClick : null;
5380                if (typeof customAction === 'function') {
5381                    customAction.call(calendarApi, dateEnv.toDate(dateMarker), ev);
5382                }
5383                else {
5384                    if (typeof customAction === 'string') {
5385                        viewType = customAction;
5386                    }
5387                    calendarApi.zoomTo(dateMarker, viewType);
5388                }
5389            };
5390            return Object.assign({ title: formatWithOrdinals(options.navLinkHint, [dateStr, zonedDate], dateStr), 'data-navlink': '' }, (isTabbable
5391                ? createAriaClickAttrs(handleInteraction)
5392                : { onClick: handleInteraction }));
5393        }
5394        return { 'aria-label': dateStr };
5395    }
5396
5397    let _isRtlScrollbarOnLeft = null;
5398    function getIsRtlScrollbarOnLeft() {
5399        if (_isRtlScrollbarOnLeft === null) {
5400            _isRtlScrollbarOnLeft = computeIsRtlScrollbarOnLeft();
5401        }
5402        return _isRtlScrollbarOnLeft;
5403    }
5404    function computeIsRtlScrollbarOnLeft() {
5405        let outerEl = document.createElement('div');
5406        applyStyle(outerEl, {
5407            position: 'absolute',
5408            top: -1000,
5409            left: 0,
5410            border: 0,
5411            padding: 0,
5412            overflow: 'scroll',
5413            direction: 'rtl',
5414        });
5415        outerEl.innerHTML = '<div></div>';
5416        document.body.appendChild(outerEl);
5417        let innerEl = outerEl.firstChild;
5418        let res = innerEl.getBoundingClientRect().left > outerEl.getBoundingClientRect().left;
5419        removeElement(outerEl);
5420        return res;
5421    }
5422
5423    let _scrollbarWidths;
5424    function getScrollbarWidths() {
5425        if (!_scrollbarWidths) {
5426            _scrollbarWidths = computeScrollbarWidths();
5427        }
5428        return _scrollbarWidths;
5429    }
5430    function computeScrollbarWidths() {
5431        let el = document.createElement('div');
5432        el.style.overflow = 'scroll';
5433        el.style.position = 'absolute';
5434        el.style.top = '-9999px';
5435        el.style.left = '-9999px';
5436        document.body.appendChild(el);
5437        let res = computeScrollbarWidthsForEl(el);
5438        document.body.removeChild(el);
5439        return res;
5440    }
5441    // WARNING: will include border
5442    function computeScrollbarWidthsForEl(el) {
5443        return {
5444            x: el.offsetHeight - el.clientHeight,
5445            y: el.offsetWidth - el.clientWidth,
5446        };
5447    }
5448
5449    function computeEdges(el, getPadding = false) {
5450        let computedStyle = window.getComputedStyle(el);
5451        let borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0;
5452        let borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0;
5453        let borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0;
5454        let borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
5455        let badScrollbarWidths = computeScrollbarWidthsForEl(el); // includes border!
5456        let scrollbarLeftRight = badScrollbarWidths.y - borderLeft - borderRight;
5457        let scrollbarBottom = badScrollbarWidths.x - borderTop - borderBottom;
5458        let res = {
5459            borderLeft,
5460            borderRight,
5461            borderTop,
5462            borderBottom,
5463            scrollbarBottom,
5464            scrollbarLeft: 0,
5465            scrollbarRight: 0,
5466        };
5467        if (getIsRtlScrollbarOnLeft() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side?
5468            res.scrollbarLeft = scrollbarLeftRight;
5469        }
5470        else {
5471            res.scrollbarRight = scrollbarLeftRight;
5472        }
5473        if (getPadding) {
5474            res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0;
5475            res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0;
5476            res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0;
5477            res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0;
5478        }
5479        return res;
5480    }
5481    function computeInnerRect(el, goWithinPadding = false, doFromWindowViewport) {
5482        let outerRect = doFromWindowViewport ? el.getBoundingClientRect() : computeRect(el);
5483        let edges = computeEdges(el, goWithinPadding);
5484        let res = {
5485            left: outerRect.left + edges.borderLeft + edges.scrollbarLeft,
5486            right: outerRect.right - edges.borderRight - edges.scrollbarRight,
5487            top: outerRect.top + edges.borderTop,
5488            bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom,
5489        };
5490        if (goWithinPadding) {
5491            res.left += edges.paddingLeft;
5492            res.right -= edges.paddingRight;
5493            res.top += edges.paddingTop;
5494            res.bottom -= edges.paddingBottom;
5495        }
5496        return res;
5497    }
5498    function computeRect(el) {
5499        let rect = el.getBoundingClientRect();
5500        return {
5501            left: rect.left + window.pageXOffset,
5502            top: rect.top + window.pageYOffset,
5503            right: rect.right + window.pageXOffset,
5504            bottom: rect.bottom + window.pageYOffset,
5505        };
5506    }
5507    function computeClippedClientRect(el) {
5508        let clippingParents = getClippingParents(el);
5509        let rect = el.getBoundingClientRect();
5510        for (let clippingParent of clippingParents) {
5511            let intersection = intersectRects(rect, clippingParent.getBoundingClientRect());
5512            if (intersection) {
5513                rect = intersection;
5514            }
5515            else {
5516                return null;
5517            }
5518        }
5519        return rect;
5520    }
5521    // does not return window
5522    function getClippingParents(el) {
5523        let parents = [];
5524        while (el instanceof HTMLElement) { // will stop when gets to document or null
5525            let computedStyle = window.getComputedStyle(el);
5526            if (computedStyle.position === 'fixed') {
5527                break;
5528            }
5529            if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) {
5530                parents.push(el);
5531            }
5532            el = el.parentNode;
5533        }
5534        return parents;
5535    }
5536
5537    /*
5538    Records offset information for a set of elements, relative to an origin element.
5539    Can record the left/right OR the top/bottom OR both.
5540    Provides methods for querying the cache by position.
5541    */
5542    class PositionCache {
5543        constructor(originEl, els, isHorizontal, isVertical) {
5544            this.els = els;
5545            let originClientRect = this.originClientRect = originEl.getBoundingClientRect(); // relative to viewport top-left
5546            if (isHorizontal) {
5547                this.buildElHorizontals(originClientRect.left);
5548            }
5549            if (isVertical) {
5550                this.buildElVerticals(originClientRect.top);
5551            }
5552        }
vendor: 4,074 bytes, lines 5553-5662
5553        // Populates the left/right internal coordinate arrays
5554        buildElHorizontals(originClientLeft) {
5555            let lefts = [];
5556            let rights = [];
5557            for (let el of this.els) {
5558                let rect = el.getBoundingClientRect();
5559                lefts.push(rect.left - originClientLeft);
5560                rights.push(rect.right - originClientLeft);
5561            }
5562            this.lefts = lefts;
5563            this.rights = rights;
5564        }
5565        // Populates the top/bottom internal coordinate arrays
5566        buildElVerticals(originClientTop) {
5567            let tops = [];
5568            let bottoms = [];
5569            for (let el of this.els) {
5570                let rect = el.getBoundingClientRect();
5571                tops.push(rect.top - originClientTop);
5572                bottoms.push(rect.bottom - originClientTop);
5573            }
5574            this.tops = tops;
5575            this.bottoms = bottoms;
5576        }
5577        // Given a left offset (from document left), returns the index of the el that it horizontally intersects.
5578        // If no intersection is made, returns undefined.
5579        leftToIndex(leftPosition) {
5580            let { lefts, rights } = this;
5581            let len = lefts.length;
5582            let i;
5583            for (i = 0; i < len; i += 1) {
5584                if (leftPosition >= lefts[i] && leftPosition < rights[i]) {
5585                    return i;
5586                }
5587            }
5588            return undefined; // TODO: better
5589        }
5590        // Given a top offset (from document top), returns the index of the el that it vertically intersects.
5591        // If no intersection is made, returns undefined.
5592        topToIndex(topPosition) {
5593            let { tops, bottoms } = this;
5594            let len = tops.length;
5595            let i;
5596            for (i = 0; i < len; i += 1) {
5597                if (topPosition >= tops[i] && topPosition < bottoms[i]) {
5598                    return i;
5599                }
5600            }
5601            return undefined; // TODO: better
5602        }
5603        // Gets the width of the element at the given index
5604        getWidth(leftIndex) {
5605            return this.rights[leftIndex] - this.lefts[leftIndex];
5606        }
5607        // Gets the height of the element at the given index
5608        getHeight(topIndex) {
5609            return this.bottoms[topIndex] - this.tops[topIndex];
5610        }
5611        similarTo(otherCache) {
5612            return similarNumArrays(this.tops || [], otherCache.tops || []) &&
5613                similarNumArrays(this.bottoms || [], otherCache.bottoms || []) &&
5614                similarNumArrays(this.lefts || [], otherCache.lefts || []) &&
5615                similarNumArrays(this.rights || [], otherCache.rights || []);
5616        }
5617    }
5618    function similarNumArrays(a, b) {
5619        const len = a.length;
5620        if (len !== b.length) {
5621            return false;
5622        }
5623        for (let i = 0; i < len; i++) {
5624            if (Math.round(a[i]) !== Math.round(b[i])) {
5625                return false;
5626            }
5627        }
5628        return true;
5629    }
5630
5631    /* eslint max-classes-per-file: "off" */
5632    /*
5633    An object for getting/setting scroll-related information for an element.
5634    Internally, this is done very differently for window versus DOM element,
5635    so this object serves as a common interface.
5636    */
5637    class ScrollController {
5638        getMaxScrollTop() {
5639            return this.getScrollHeight() - this.getClientHeight();
5640        }
5641        getMaxScrollLeft() {
5642            return this.getScrollWidth() - this.getClientWidth();
5643        }
5644        canScrollVertically() {
5645            return this.getMaxScrollTop() > 0;
5646        }
5647        canScrollHorizontally() {
5648            return this.getMaxScrollLeft() > 0;
5649        }
5650        canScrollUp() {
5651            return this.getScrollTop() > 0;
5652        }
5653        canScrollDown() {
5654            return this.getScrollTop() < this.getMaxScrollTop();
5655        }
5656        canScrollLeft() {
5657            return this.getScrollLeft() > 0;
5658        }
5659        canScrollRight() {
5660            return this.getScrollLeft() < this.getMaxScrollLeft();
5661        }
5662    }
vendor: 4,519 bytes, lines 5663-5795
5663    class ElementScrollController extends ScrollController {
5664        constructor(el) {
5665            super();
5666            this.el = el;
5667        }
5668        getScrollTop() {
5669            return this.el.scrollTop;
5670        }
5671        getScrollLeft() {
5672            return this.el.scrollLeft;
5673        }
5674        setScrollTop(top) {
5675            this.el.scrollTop = top;
5676        }
5677        setScrollLeft(left) {
5678            this.el.scrollLeft = left;
5679        }
5680        getScrollWidth() {
5681            return this.el.scrollWidth;
5682        }
5683        getScrollHeight() {
5684            return this.el.scrollHeight;
5685        }
5686        getClientHeight() {
5687            return this.el.clientHeight;
5688        }
5689        getClientWidth() {
5690            return this.el.clientWidth;
5691        }
5692    }
5693    class WindowScrollController extends ScrollController {
5694        getScrollTop() {
5695            return window.pageYOffset;
5696        }
5697        getScrollLeft() {
5698            return window.pageXOffset;
5699        }
5700        setScrollTop(n) {
5701            window.scroll(window.pageXOffset, n);
5702        }
5703        setScrollLeft(n) {
5704            window.scroll(n, window.pageYOffset);
5705        }
5706        getScrollWidth() {
5707            return document.documentElement.scrollWidth;
5708        }
5709        getScrollHeight() {
5710            return document.documentElement.scrollHeight;
5711        }
5712        getClientHeight() {
5713            return document.documentElement.clientHeight;
5714        }
5715        getClientWidth() {
5716            return document.documentElement.clientWidth;
5717        }
5718    }
5719
5720    /*
5721    an INTERACTABLE date component
5722
5723    PURPOSES:
5724    - hook up to fg, fill, and mirror renderers
5725    - interface for dragging and hits
5726    */
5727    class DateComponent extends BaseComponent {
5728        constructor() {
5729            super(...arguments);
5730            this.uid = guid();
5731        }
5732        // Hit System
5733        // -----------------------------------------------------------------------------------------------------------------
5734        prepareHits() {
5735        }
5736        queryHit(positionLeft, positionTop, elWidth, elHeight) {
5737            return null; // this should be abstract
5738        }
5739        // Pointer Interaction Utils
5740        // -----------------------------------------------------------------------------------------------------------------
5741        isValidSegDownEl(el) {
5742            return !this.props.eventDrag && // HACK
5743                !this.props.eventResize && // HACK
5744                !elementClosest(el, '.fc-event-mirror');
5745        }
5746        isValidDateDownEl(el) {
5747            return !elementClosest(el, '.fc-event:not(.fc-bg-event)') &&
5748                !elementClosest(el, '.fc-more-link') && // a "more.." link
5749                !elementClosest(el, 'a[data-navlink]') && // a clickable nav link
5750                !elementClosest(el, '.fc-popover'); // hack
5751        }
5752    }
5753
5754    class NamedTimeZoneImpl {
5755        constructor(timeZoneName) {
5756            this.timeZoneName = timeZoneName;
5757        }
5758    }
5759
5760    class SegHierarchy {
5761        constructor(getEntryThickness = (entry) => {
5762            // should return an integer
5763            return entry.thickness;
5764        }) {
5765            this.getEntryThickness = getEntryThickness;
5766            // settings
5767            this.strictOrder = false;
5768            this.allowReslicing = false;
5769            this.maxCoord = -1; // -1 means no max
5770            this.maxStackCnt = -1; // -1 means no max
5771            this.levelCoords = []; // ordered
5772            this.entriesByLevel = []; // parallel with levelCoords
5773            this.stackCnts = {}; // TODO: use better technique!?
5774        }
5775        addSegs(inputs) {
5776            let hiddenEntries = [];
5777            for (let input of inputs) {
5778                this.insertEntry(input, hiddenEntries);
5779            }
5780            return hiddenEntries;
5781        }
5782        insertEntry(entry, hiddenEntries) {
5783            let insertion = this.findInsertion(entry);
5784            if (this.isInsertionValid(insertion, entry)) {
5785                this.insertEntryAt(entry, insertion);
5786                return 1;
5787            }
5788            return this.handleInvalidInsertion(insertion, entry, hiddenEntries);
5789        }
5790        isInsertionValid(insertion, entry) {
5791            return (this.maxCoord === -1 || insertion.levelCoord + this.getEntryThickness(entry) <= this.maxCoord) &&
5792                (this.maxStackCnt === -1 || insertion.stackCnt < this.maxStackCnt);
5793        }
5794        // returns number of new entries inserted
5795        handleInvalidInsertion(insertion, entry, hiddenEntries) {
vendor: 8,288 bytes, lines 5796-5982
5796            if (this.allowReslicing && insertion.touchingEntry) {
5797                return this.splitEntry(entry, insertion.touchingEntry, hiddenEntries);
5798            }
5799            hiddenEntries.push(entry);
5800            return 0;
5801        }
5802        splitEntry(entry, barrier, hiddenEntries) {
5803            let partCnt = 0;
5804            let splitHiddenEntries = [];
5805            let entrySpan = entry.span;
5806            let barrierSpan = barrier.span;
5807            if (entrySpan.start < barrierSpan.start) {
5808                partCnt += this.insertEntry({
5809                    index: entry.index,
5810                    thickness: entry.thickness,
5811                    span: { start: entrySpan.start, end: barrierSpan.start },
5812                }, splitHiddenEntries);
5813            }
5814            if (entrySpan.end > barrierSpan.end) {
5815                partCnt += this.insertEntry({
5816                    index: entry.index,
5817                    thickness: entry.thickness,
5818                    span: { start: barrierSpan.end, end: entrySpan.end },
5819                }, splitHiddenEntries);
5820            }
5821            if (partCnt) {
5822                hiddenEntries.push({
5823                    index: entry.index,
5824                    thickness: entry.thickness,
5825                    span: intersectSpans(barrierSpan, entrySpan), // guaranteed to intersect
5826                }, ...splitHiddenEntries);
5827                return partCnt;
5828            }
5829            hiddenEntries.push(entry);
5830            return 0;
5831        }
5832        insertEntryAt(entry, insertion) {
5833            let { entriesByLevel, levelCoords } = this;
5834            if (insertion.lateral === -1) {
5835                // create a new level
5836                insertAt(levelCoords, insertion.level, insertion.levelCoord);
5837                insertAt(entriesByLevel, insertion.level, [entry]);
5838            }
5839            else {
5840                // insert into existing level
5841                insertAt(entriesByLevel[insertion.level], insertion.lateral, entry);
5842            }
5843            this.stackCnts[buildEntryKey(entry)] = insertion.stackCnt;
5844        }
5845        findInsertion(newEntry) {
5846            let { levelCoords, entriesByLevel, strictOrder, stackCnts } = this;
5847            let levelCnt = levelCoords.length;
5848            let candidateCoord = 0;
5849            let touchingLevel = -1;
5850            let touchingLateral = -1;
5851            let touchingEntry = null;
5852            let stackCnt = 0;
5853            for (let trackingLevel = 0; trackingLevel < levelCnt; trackingLevel += 1) {
5854                let trackingCoord = levelCoords[trackingLevel];
5855                // if the current level is past the placed entry, we have found a good empty space and can stop.
5856                // if strictOrder, keep finding more lateral intersections.
5857                if (!strictOrder && trackingCoord >= candidateCoord + this.getEntryThickness(newEntry)) {
5858                    break;
5859                }
5860                let trackingEntries = entriesByLevel[trackingLevel];
5861                let trackingEntry;
5862                let searchRes = binarySearch(trackingEntries, newEntry.span.start, getEntrySpanEnd); // find first entry after newEntry's end
5863                let lateralIndex = searchRes[0] + searchRes[1]; // if exact match (which doesn't collide), go to next one
5864                while ( // loop through entries that horizontally intersect
5865                (trackingEntry = trackingEntries[lateralIndex]) && // but not past the whole entry list
5866                trackingEntry.span.start < newEntry.span.end // and not entirely past newEntry
5867                    ) {
5868                    let trackingEntryBottom = trackingCoord + this.getEntryThickness(trackingEntry);
5869                    // intersects into the top of the candidate?
5870                    if (trackingEntryBottom > candidateCoord) {
5871                        candidateCoord = trackingEntryBottom;
5872                        touchingEntry = trackingEntry;
5873                        touchingLevel = trackingLevel;
5874                        touchingLateral = lateralIndex;
5875                    }
5876                    // butts up against top of candidate? (will happen if just intersected as well)
5877                    if (trackingEntryBottom === candidateCoord) {
5878                        // accumulate the highest possible stackCnt of the trackingEntries that butt up
5879                        stackCnt = Math.max(stackCnt, stackCnts[buildEntryKey(trackingEntry)] + 1);
5880                    }
5881                    lateralIndex += 1;
5882                }
5883            }
5884            // the destination level will be after touchingEntry's level. find it
5885            let destLevel = 0;
5886            if (touchingEntry) {
5887                destLevel = touchingLevel + 1;
5888                while (destLevel < levelCnt && levelCoords[destLevel] < candidateCoord) {
5889                    destLevel += 1;
5890                }
5891            }
5892            // if adding to an existing level, find where to insert
5893            let destLateral = -1;
5894            if (destLevel < levelCnt && levelCoords[destLevel] === candidateCoord) {
5895                destLateral = binarySearch(entriesByLevel[destLevel], newEntry.span.end, getEntrySpanEnd)[0];
5896            }
5897            return {
5898                touchingLevel,
5899                touchingLateral,
5900                touchingEntry,
5901                stackCnt,
5902                levelCoord: candidateCoord,
5903                level: destLevel,
5904                lateral: destLateral,
5905            };
5906        }
5907        // sorted by levelCoord (lowest to highest)
5908        toRects() {
5909            let { entriesByLevel, levelCoords } = this;
5910            let levelCnt = entriesByLevel.length;
5911            let rects = [];
5912            for (let level = 0; level < levelCnt; level += 1) {
5913                let entries = entriesByLevel[level];
5914                let levelCoord = levelCoords[level];
5915                for (let entry of entries) {
5916                    rects.push(Object.assign(Object.assign({}, entry), { thickness: this.getEntryThickness(entry), levelCoord }));
5917                }
5918            }
5919            return rects;
5920        }
5921    }
5922    function getEntrySpanEnd(entry) {
5923        return entry.span.end;
5924    }
5925    function buildEntryKey(entry) {
5926        return entry.index + ':' + entry.span.start;
5927    }
5928    // returns groups with entries sorted by input order
5929    function groupIntersectingEntries(entries) {
5930        let merges = [];
5931        for (let entry of entries) {
5932            let filteredMerges = [];
5933            let hungryMerge = {
5934                span: entry.span,
5935                entries: [entry],
5936            };
5937            for (let merge of merges) {
5938                if (intersectSpans(merge.span, hungryMerge.span)) {
5939                    hungryMerge = {
5940                        entries: merge.entries.concat(hungryMerge.entries),
5941                        span: joinSpans(merge.span, hungryMerge.span),
5942                    };
5943                }
5944                else {
5945                    filteredMerges.push(merge);
5946                }
5947            }
5948            filteredMerges.push(hungryMerge);
5949            merges = filteredMerges;
5950        }
5951        return merges;
5952    }
5953    function joinSpans(span0, span1) {
5954        return {
5955            start: Math.min(span0.start, span1.start),
5956            end: Math.max(span0.end, span1.end),
5957        };
5958    }
5959    function intersectSpans(span0, span1) {
5960        let start = Math.max(span0.start, span1.start);
5961        let end = Math.min(span0.end, span1.end);
5962        if (start < end) {
5963            return { start, end };
5964        }
5965        return null;
5966    }
5967    // general util
5968    // ---------------------------------------------------------------------------------------------------------------------
5969    function insertAt(arr, index, item) {
5970        arr.splice(index, 0, item);
5971    }
5972    function binarySearch(a, searchVal, getItemVal) {
5973        let startIndex = 0;
5974        let endIndex = a.length; // exclusive
5975        if (!endIndex || searchVal < getItemVal(a[startIndex])) { // no items OR before first item
5976            return [0, 0];
5977        }
5978        if (searchVal > getItemVal(a[endIndex - 1])) { // after last item
5979            return [endIndex, 0];
5980        }
5981        while (startIndex < endIndex) {
5982            let middleIndex = Math.floor(startIndex + (endIndex - startIndex) / 2);
vendor: 9,969 bytes, lines 5983-6198
5983            let middleVal = getItemVal(a[middleIndex]);
5984            if (searchVal < middleVal) {
5985                endIndex = middleIndex;
5986            }
5987            else if (searchVal > middleVal) {
5988                startIndex = middleIndex + 1;
5989            }
5990            else { // equal!
5991                return [middleIndex, 1];
5992            }
5993        }
5994        return [startIndex, 0];
5995    }
5996
5997    /*
5998    An abstraction for a dragging interaction originating on an event.
5999    Does higher-level things than PointerDragger, such as possibly:
6000    - a "mirror" that moves with the pointer
6001    - a minimum number of pixels or other criteria for a true drag to begin
6002
6003    subclasses must emit:
6004    - pointerdown
6005    - dragstart
6006    - dragmove
6007    - pointerup
6008    - dragend
6009    */
6010    class ElementDragging {
6011        constructor(el, selector) {
6012            this.emitter = new Emitter();
6013        }
6014        destroy() {
6015        }
6016        setMirrorIsVisible(bool) {
6017            // optional if subclass doesn't want to support a mirror
6018        }
6019        setMirrorNeedsRevert(bool) {
6020            // optional if subclass doesn't want to support a mirror
6021        }
6022        setAutoScrollEnabled(bool) {
6023            // optional
6024        }
6025    }
6026
6027    // TODO: get rid of this in favor of options system,
6028    // tho it's really easy to access this globally rather than pass thru options.
6029    const config = {};
6030
6031    /*
6032    Information about what will happen when an external element is dragged-and-dropped
6033    onto a calendar. Contains information for creating an event.
6034    */
6035    const DRAG_META_REFINERS = {
6036        startTime: createDuration,
6037        duration: createDuration,
6038        create: Boolean,
6039        sourceId: String,
6040    };
6041    function parseDragMeta(raw) {
6042        let { refined, extra } = refineProps(raw, DRAG_META_REFINERS);
6043        return {
6044            startTime: refined.startTime || null,
6045            duration: refined.duration || null,
6046            create: refined.create != null ? refined.create : true,
6047            sourceId: refined.sourceId,
6048            leftoverProps: extra,
6049        };
6050    }
6051
6052    // Computes a default column header formatting string if `colFormat` is not explicitly defined
6053    function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
6054        // if more than one week row, or if there are a lot of columns with not much space,
6055        // put just the day numbers will be in each cell
6056        if (!datesRepDistinctDays || dayCnt > 10) {
6057            return createFormatter({ weekday: 'short' }); // "Sat"
6058        }
6059        if (dayCnt > 1) {
6060            return createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12"
6061        }
6062        return createFormatter({ weekday: 'long' }); // "Saturday"
6063    }
6064
6065    const CLASS_NAME = 'fc-col-header-cell'; // do the cushion too? no
6066    function renderInner$1(renderProps) {
6067        return renderProps.text;
6068    }
6069
6070    // BAD name for this class now. used in the Header
6071    class TableDateCell extends BaseComponent {
6072        render() {
6073            let { dateEnv, options, theme, viewApi } = this.context;
6074            let { props } = this;
6075            let { date, dateProfile } = props;
6076            let dayMeta = getDateMeta(date, props.todayRange, null, dateProfile);
6077            let classNames = [CLASS_NAME].concat(getDayClassNames(dayMeta, theme));
6078            let text = dateEnv.format(date, props.dayHeaderFormat);
6079            // if colCnt is 1, we are already in a day-view and don't need a navlink
6080            let navLinkAttrs = (!dayMeta.isDisabled && props.colCnt > 1)
6081                ? buildNavLinkAttrs(this.context, date)
6082                : {};
6083            let renderProps = Object.assign(Object.assign(Object.assign({ date: dateEnv.toDate(date), view: viewApi }, props.extraRenderProps), { text }), dayMeta);
6084            return (y(ContentContainer, { elTag: "th", elClasses: classNames, elAttrs: Object.assign({ role: 'columnheader', colSpan: props.colSpan, 'data-date': !dayMeta.isDisabled ? formatDayString(date) : undefined }, props.extraDataAttrs), renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner$1, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContainer) => (y("div", { className: "fc-scrollgrid-sync-inner" }, !dayMeta.isDisabled && (y(InnerContainer, { elTag: "a", elAttrs: navLinkAttrs, elClasses: [
6085                    'fc-col-header-cell-cushion',
6086                    props.isSticky && 'fc-sticky',
6087                ] }))))));
6088        }
6089    }
6090
6091    const WEEKDAY_FORMAT = createFormatter({ weekday: 'long' });
6092    class TableDowCell extends BaseComponent {
6093        render() {
6094            let { props } = this;
6095            let { dateEnv, theme, viewApi, options } = this.context;
6096            let date = addDays(new Date(259200000), props.dow); // start with Sun, 04 Jan 1970 00:00:00 GMT
6097            let dateMeta = {
6098                dow: props.dow,
6099                isDisabled: false,
6100                isFuture: false,
6101                isPast: false,
6102                isToday: false,
6103                isOther: false,
6104            };
6105            let text = dateEnv.format(date, props.dayHeaderFormat);
6106            let renderProps = Object.assign(Object.assign(Object.assign(Object.assign({ // TODO: make this public?
6107                date }, dateMeta), { view: viewApi }), props.extraRenderProps), { text });
6108            return (y(ContentContainer, { elTag: "th", elClasses: [
6109                    CLASS_NAME,
6110                    ...getDayClassNames(dateMeta, theme),
6111                    ...(props.extraClassNames || []),
6112                ], elAttrs: Object.assign({ role: 'columnheader', colSpan: props.colSpan }, props.extraDataAttrs), renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner$1, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContent) => (y("div", { className: "fc-scrollgrid-sync-inner" },
6113                y(InnerContent, { elTag: "a", elClasses: [
6114                        'fc-col-header-cell-cushion',
6115                        props.isSticky && 'fc-sticky',
6116                    ], elAttrs: {
6117                        'aria-label': dateEnv.format(date, WEEKDAY_FORMAT),
6118                    } })))));
6119        }
6120    }
6121
6122    class NowTimer extends x$1 {
6123        constructor(props, context) {
6124            super(props, context);
6125            this.initialNowDate = getNow(context.options.now, context.dateEnv);
6126            this.initialNowQueriedMs = new Date().valueOf();
6127            this.state = this.computeTiming().currentState;
6128        }
6129        render() {
6130            let { props, state } = this;
6131            return props.children(state.nowDate, state.todayRange);
6132        }
6133        componentDidMount() {
6134            this.setTimeout();
6135        }
6136        componentDidUpdate(prevProps) {
6137            if (prevProps.unit !== this.props.unit) {
6138                this.clearTimeout();
6139                this.setTimeout();
6140            }
6141        }
6142        componentWillUnmount() {
6143            this.clearTimeout();
6144        }
6145        computeTiming() {
6146            let { props, context } = this;
6147            let unroundedNow = addMs(this.initialNowDate, new Date().valueOf() - this.initialNowQueriedMs);
6148            let currentUnitStart = context.dateEnv.startOf(unroundedNow, props.unit);
6149            let nextUnitStart = context.dateEnv.add(currentUnitStart, createDuration(1, props.unit));
6150            let waitMs = nextUnitStart.valueOf() - unroundedNow.valueOf();
6151            // there is a max setTimeout ms value (https://stackoverflow.com/a/3468650/96342)
6152            // ensure no longer than a day
6153            waitMs = Math.min(1000 * 60 * 60 * 24, waitMs);
6154            return {
6155                currentState: { nowDate: currentUnitStart, todayRange: buildDayRange(currentUnitStart) },
6156                nextState: { nowDate: nextUnitStart, todayRange: buildDayRange(nextUnitStart) },
6157                waitMs,
6158            };
6159        }
6160        setTimeout() {
6161            let { nextState, waitMs } = this.computeTiming();
6162            this.timeoutId = setTimeout(() => {
6163                this.setState(nextState, () => {
6164                    this.setTimeout();
6165                });
6166            }, waitMs);
6167        }
6168        clearTimeout() {
6169            if (this.timeoutId) {
6170                clearTimeout(this.timeoutId);
6171            }
6172        }
6173    }
6174    NowTimer.contextType = ViewContextType;
6175    function buildDayRange(date) {
6176        let start = startOfDay(date);
6177        let end = addDays(start, 1);
6178        return { start, end };
6179    }
6180
6181    class DayHeader extends BaseComponent {
6182        constructor() {
6183            super(...arguments);
6184            this.createDayHeaderFormatter = memoize(createDayHeaderFormatter);
6185        }
6186        render() {
6187            let { context } = this;
6188            let { dates, dateProfile, datesRepDistinctDays, renderIntro } = this.props;
6189            let dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dates.length);
6190            return (y(NowTimer, { unit: "day" }, (nowDate, todayRange) => (y("tr", { role: "row" },
6191                renderIntro && renderIntro('day'),
6192                dates.map((date) => (datesRepDistinctDays ? (y(TableDateCell, { key: date.toISOString(), date: date, dateProfile: dateProfile, todayRange: todayRange, colCnt: dates.length, dayHeaderFormat: dayHeaderFormat })) : (y(TableDowCell, { key: date.getUTCDay(), dow: date.getUTCDay(), dayHeaderFormat: dayHeaderFormat }))))))));
6193        }
6194    }
6195    function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
6196        return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
6197    }
6198
vendor: 16,771 bytes, lines 6199-6544
6199    class DaySeriesModel {
6200        constructor(range, dateProfileGenerator) {
6201            let date = range.start;
6202            let { end } = range;
6203            let indices = [];
6204            let dates = [];
6205            let dayIndex = -1;
6206            while (date < end) { // loop each day from start to end
6207                if (dateProfileGenerator.isHiddenDay(date)) {
6208                    indices.push(dayIndex + 0.5); // mark that it's between indices
6209                }
6210                else {
6211                    dayIndex += 1;
6212                    indices.push(dayIndex);
6213                    dates.push(date);
6214                }
6215                date = addDays(date, 1);
6216            }
6217            this.dates = dates;
6218            this.indices = indices;
6219            this.cnt = dates.length;
6220        }
6221        sliceRange(range) {
6222            let firstIndex = this.getDateDayIndex(range.start); // inclusive first index
6223            let lastIndex = this.getDateDayIndex(addDays(range.end, -1)); // inclusive last index
6224            let clippedFirstIndex = Math.max(0, firstIndex);
6225            let clippedLastIndex = Math.min(this.cnt - 1, lastIndex);
6226            // deal with in-between indices
6227            clippedFirstIndex = Math.ceil(clippedFirstIndex); // in-between starts round to next cell
6228            clippedLastIndex = Math.floor(clippedLastIndex); // in-between ends round to prev cell
6229            if (clippedFirstIndex <= clippedLastIndex) {
6230                return {
6231                    firstIndex: clippedFirstIndex,
6232                    lastIndex: clippedLastIndex,
6233                    isStart: firstIndex === clippedFirstIndex,
6234                    isEnd: lastIndex === clippedLastIndex,
6235                };
6236            }
6237            return null;
6238        }
6239        // Given a date, returns its chronolocial cell-index from the first cell of the grid.
6240        // If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets.
6241        // If before the first offset, returns a negative number.
6242        // If after the last offset, returns an offset past the last cell offset.
6243        // Only works for *start* dates of cells. Will not work for exclusive end dates for cells.
6244        getDateDayIndex(date) {
6245            let { indices } = this;
6246            let dayOffset = Math.floor(diffDays(this.dates[0], date));
6247            if (dayOffset < 0) {
6248                return indices[0] - 1;
6249            }
6250            if (dayOffset >= indices.length) {
6251                return indices[indices.length - 1] + 1;
6252            }
6253            return indices[dayOffset];
6254        }
6255    }
6256
6257    class DayTableModel {
6258        constructor(daySeries, breakOnWeeks) {
6259            let { dates } = daySeries;
6260            let daysPerRow;
6261            let firstDay;
6262            let rowCnt;
6263            if (breakOnWeeks) {
6264                // count columns until the day-of-week repeats
6265                firstDay = dates[0].getUTCDay();
6266                for (daysPerRow = 1; daysPerRow < dates.length; daysPerRow += 1) {
6267                    if (dates[daysPerRow].getUTCDay() === firstDay) {
6268                        break;
6269                    }
6270                }
6271                rowCnt = Math.ceil(dates.length / daysPerRow);
6272            }
6273            else {
6274                rowCnt = 1;
6275                daysPerRow = dates.length;
6276            }
6277            this.rowCnt = rowCnt;
6278            this.colCnt = daysPerRow;
6279            this.daySeries = daySeries;
6280            this.cells = this.buildCells();
6281            this.headerDates = this.buildHeaderDates();
6282        }
6283        buildCells() {
6284            let rows = [];
6285            for (let row = 0; row < this.rowCnt; row += 1) {
6286                let cells = [];
6287                for (let col = 0; col < this.colCnt; col += 1) {
6288                    cells.push(this.buildCell(row, col));
6289                }
6290                rows.push(cells);
6291            }
6292            return rows;
6293        }
6294        buildCell(row, col) {
6295            let date = this.daySeries.dates[row * this.colCnt + col];
6296            return {
6297                key: date.toISOString(),
6298                date,
6299            };
6300        }
6301        buildHeaderDates() {
6302            let dates = [];
6303            for (let col = 0; col < this.colCnt; col += 1) {
6304                dates.push(this.cells[0][col].date);
6305            }
6306            return dates;
6307        }
6308        sliceRange(range) {
6309            let { colCnt } = this;
6310            let seriesSeg = this.daySeries.sliceRange(range);
6311            let segs = [];
6312            if (seriesSeg) {
6313                let { firstIndex, lastIndex } = seriesSeg;
6314                let index = firstIndex;
6315                while (index <= lastIndex) {
6316                    let row = Math.floor(index / colCnt);
6317                    let nextIndex = Math.min((row + 1) * colCnt, lastIndex + 1);
6318                    segs.push({
6319                        row,
6320                        firstCol: index % colCnt,
6321                        lastCol: (nextIndex - 1) % colCnt,
6322                        isStart: seriesSeg.isStart && index === firstIndex,
6323                        isEnd: seriesSeg.isEnd && (nextIndex - 1) === lastIndex,
6324                    });
6325                    index = nextIndex;
6326                }
6327            }
6328            return segs;
6329        }
6330    }
6331
6332    class Slicer {
6333        constructor() {
6334            this.sliceBusinessHours = memoize(this._sliceBusinessHours);
6335            this.sliceDateSelection = memoize(this._sliceDateSpan);
6336            this.sliceEventStore = memoize(this._sliceEventStore);
6337            this.sliceEventDrag = memoize(this._sliceInteraction);
6338            this.sliceEventResize = memoize(this._sliceInteraction);
6339            this.forceDayIfListItem = false; // hack
6340        }
6341        sliceProps(props, dateProfile, nextDayThreshold, context, ...extraArgs) {
6342            let { eventUiBases } = props;
6343            let eventSegs = this.sliceEventStore(props.eventStore, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs);
6344            return {
6345                dateSelectionSegs: this.sliceDateSelection(props.dateSelection, dateProfile, nextDayThreshold, eventUiBases, context, ...extraArgs),
6346                businessHourSegs: this.sliceBusinessHours(props.businessHours, dateProfile, nextDayThreshold, context, ...extraArgs),
6347                fgEventSegs: eventSegs.fg,
6348                bgEventSegs: eventSegs.bg,
6349                eventDrag: this.sliceEventDrag(props.eventDrag, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs),
6350                eventResize: this.sliceEventResize(props.eventResize, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs),
6351                eventSelection: props.eventSelection,
6352            }; // TODO: give interactionSegs?
6353        }
6354        sliceNowDate(// does not memoize
6355            date, dateProfile, nextDayThreshold, context, ...extraArgs) {
6356            return this._sliceDateSpan({ range: { start: date, end: addMs(date, 1) }, allDay: false }, // add 1 ms, protect against null range
6357                dateProfile, nextDayThreshold, {}, context, ...extraArgs);
6358        }
6359        _sliceBusinessHours(businessHours, dateProfile, nextDayThreshold, context, ...extraArgs) {
6360            if (!businessHours) {
6361                return [];
6362            }
6363            return this._sliceEventStore(expandRecurring(businessHours, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), context), {}, dateProfile, nextDayThreshold, ...extraArgs).bg;
6364        }
6365        _sliceEventStore(eventStore, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs) {
6366            if (eventStore) {
6367                let rangeRes = sliceEventStore(eventStore, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold);
6368                return {
6369                    bg: this.sliceEventRanges(rangeRes.bg, extraArgs),
6370                    fg: this.sliceEventRanges(rangeRes.fg, extraArgs),
6371                };
6372            }
6373            return { bg: [], fg: [] };
6374        }
6375        _sliceInteraction(interaction, eventUiBases, dateProfile, nextDayThreshold, ...extraArgs) {
6376            if (!interaction) {
6377                return null;
6378            }
6379            let rangeRes = sliceEventStore(interaction.mutatedEvents, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold);
6380            return {
6381                segs: this.sliceEventRanges(rangeRes.fg, extraArgs),
6382                affectedInstances: interaction.affectedEvents.instances,
6383                isEvent: interaction.isEvent,
6384            };
6385        }
6386        _sliceDateSpan(dateSpan, dateProfile, nextDayThreshold, eventUiBases, context, ...extraArgs) {
6387            if (!dateSpan) {
6388                return [];
6389            }
6390            let activeRange = computeActiveRange(dateProfile, Boolean(nextDayThreshold));
6391            let activeDateSpanRange = intersectRanges(dateSpan.range, activeRange);
6392            if (activeDateSpanRange) {
6393                dateSpan = Object.assign(Object.assign({}, dateSpan), { range: activeDateSpanRange });
6394                let eventRange = fabricateEventRange(dateSpan, eventUiBases, context);
6395                let segs = this.sliceRange(dateSpan.range, ...extraArgs);
6396                for (let seg of segs) {
6397                    seg.eventRange = eventRange;
6398                }
6399                return segs;
6400            }
6401            return [];
6402        }
6403        /*
6404        "complete" seg means it has component and eventRange
6405        */
6406        sliceEventRanges(eventRanges, extraArgs) {
6407            let segs = [];
6408            for (let eventRange of eventRanges) {
6409                segs.push(...this.sliceEventRange(eventRange, extraArgs));
6410            }
6411            return segs;
6412        }
6413        /*
6414        "complete" seg means it has component and eventRange
6415        */
6416        sliceEventRange(eventRange, extraArgs) {
6417            let dateRange = eventRange.range;
6418            // hack to make multi-day events that are being force-displayed as list-items to take up only one day
6419            if (this.forceDayIfListItem && eventRange.ui.display === 'list-item') {
6420                dateRange = {
6421                    start: dateRange.start,
6422                    end: addDays(dateRange.start, 1),
6423                };
6424            }
6425            let segs = this.sliceRange(dateRange, ...extraArgs);
6426            for (let seg of segs) {
6427                seg.eventRange = eventRange;
6428                seg.isStart = eventRange.isStart && seg.isStart;
6429                seg.isEnd = eventRange.isEnd && seg.isEnd;
6430            }
6431            return segs;
6432        }
6433    }
6434    /*
6435    for incorporating slotMinTime/slotMaxTime if appropriate
6436    TODO: should be part of DateProfile!
6437    TimelineDateProfile already does this btw
6438    */
6439    function computeActiveRange(dateProfile, isComponentAllDay) {
6440        let range = dateProfile.activeRange;
6441        if (isComponentAllDay) {
6442            return range;
6443        }
6444        return {
6445            start: addMs(range.start, dateProfile.slotMinTime.milliseconds),
6446            end: addMs(range.end, dateProfile.slotMaxTime.milliseconds - 864e5), // 864e5 = ms in a day
6447        };
6448    }
6449
6450    // high-level segmenting-aware tester functions
6451    // ------------------------------------------------------------------------------------------------------------------------
6452    function isInteractionValid(interaction, dateProfile, context) {
6453        let { instances } = interaction.mutatedEvents;
6454        for (let instanceId in instances) {
6455            if (!rangeContainsRange(dateProfile.validRange, instances[instanceId].range)) {
6456                return false;
6457            }
6458        }
6459        return isNewPropsValid({ eventDrag: interaction }, context); // HACK: the eventDrag props is used for ALL interactions
6460    }
6461    function isDateSelectionValid(dateSelection, dateProfile, context) {
6462        if (!rangeContainsRange(dateProfile.validRange, dateSelection.range)) {
6463            return false;
6464        }
6465        return isNewPropsValid({ dateSelection }, context);
6466    }
6467    function isNewPropsValid(newProps, context) {
6468        let calendarState = context.getCurrentData();
6469        let props = Object.assign({ businessHours: calendarState.businessHours, dateSelection: '', eventStore: calendarState.eventStore, eventUiBases: calendarState.eventUiBases, eventSelection: '', eventDrag: null, eventResize: null }, newProps);
6470        return (context.pluginHooks.isPropsValid || isPropsValid)(props, context);
6471    }
6472    function isPropsValid(state, context, dateSpanMeta = {}, filterConfig) {
6473        if (state.eventDrag && !isInteractionPropsValid(state, context, dateSpanMeta, filterConfig)) {
6474            return false;
6475        }
6476        if (state.dateSelection && !isDateSelectionPropsValid(state, context, dateSpanMeta, filterConfig)) {
6477            return false;
6478        }
6479        return true;
6480    }
6481    // Moving Event Validation
6482    // ------------------------------------------------------------------------------------------------------------------------
6483    function isInteractionPropsValid(state, context, dateSpanMeta, filterConfig) {
6484        let currentState = context.getCurrentData();
6485        let interaction = state.eventDrag; // HACK: the eventDrag props is used for ALL interactions
6486        let subjectEventStore = interaction.mutatedEvents;
6487        let subjectDefs = subjectEventStore.defs;
6488        let subjectInstances = subjectEventStore.instances;
6489        let subjectConfigs = compileEventUis(subjectDefs, interaction.isEvent ?
6490            state.eventUiBases :
6491            { '': currentState.selectionConfig });
6492        if (filterConfig) {
6493            subjectConfigs = mapHash(subjectConfigs, filterConfig);
6494        }
6495        // exclude the subject events. TODO: exclude defs too?
6496        let otherEventStore = excludeInstances(state.eventStore, interaction.affectedEvents.instances);
6497        let otherDefs = otherEventStore.defs;
6498        let otherInstances = otherEventStore.instances;
6499        let otherConfigs = compileEventUis(otherDefs, state.eventUiBases);
6500        for (let subjectInstanceId in subjectInstances) {
6501            let subjectInstance = subjectInstances[subjectInstanceId];
6502            let subjectRange = subjectInstance.range;
6503            let subjectConfig = subjectConfigs[subjectInstance.defId];
6504            let subjectDef = subjectDefs[subjectInstance.defId];
6505            // constraint
6506            if (!allConstraintsPass(subjectConfig.constraints, subjectRange, otherEventStore, state.businessHours, context)) {
6507                return false;
6508            }
6509            // overlap
6510            let { eventOverlap } = context.options;
6511            let eventOverlapFunc = typeof eventOverlap === 'function' ? eventOverlap : null;
6512            for (let otherInstanceId in otherInstances) {
6513                let otherInstance = otherInstances[otherInstanceId];
6514                // intersect! evaluate
6515                if (rangesIntersect(subjectRange, otherInstance.range)) {
6516                    let otherOverlap = otherConfigs[otherInstance.defId].overlap;
6517                    // consider the other event's overlap. only do this if the subject event is a "real" event
6518                    if (otherOverlap === false && interaction.isEvent) {
6519                        return false;
6520                    }
6521                    if (subjectConfig.overlap === false) {
6522                        return false;
6523                    }
6524                    if (eventOverlapFunc && !eventOverlapFunc(new EventImpl(context, otherDefs[otherInstance.defId], otherInstance), // still event
6525                        new EventImpl(context, subjectDef, subjectInstance))) {
6526                        return false;
6527                    }
6528                }
6529            }
6530            // allow (a function)
6531            let calendarEventStore = currentState.eventStore; // need global-to-calendar, not local to component (splittable)state
6532            for (let subjectAllow of subjectConfig.allows) {
6533                let subjectDateSpan = Object.assign(Object.assign({}, dateSpanMeta), { range: subjectInstance.range, allDay: subjectDef.allDay });
6534                let origDef = calendarEventStore.defs[subjectDef.defId];
6535                let origInstance = calendarEventStore.instances[subjectInstanceId];
6536                let eventApi;
6537                if (origDef) { // was previously in the calendar
6538                    eventApi = new EventImpl(context, origDef, origInstance);
6539                }
6540                else { // was an external event
6541                    eventApi = new EventImpl(context, subjectDef); // no instance, because had no dates
6542                }
6543                if (!subjectAllow(buildDateSpanApiWithContext(subjectDateSpan, context), eventApi)) {
6544                    return false;
vendor: 41,014 bytes, lines 6545-7374
6545                }
6546            }
6547        }
6548        return true;
6549    }
6550    // Date Selection Validation
6551    // ------------------------------------------------------------------------------------------------------------------------
6552    function isDateSelectionPropsValid(state, context, dateSpanMeta, filterConfig) {
6553        let relevantEventStore = state.eventStore;
6554        let relevantDefs = relevantEventStore.defs;
6555        let relevantInstances = relevantEventStore.instances;
6556        let selection = state.dateSelection;
6557        let selectionRange = selection.range;
6558        let { selectionConfig } = context.getCurrentData();
6559        if (filterConfig) {
6560            selectionConfig = filterConfig(selectionConfig);
6561        }
6562        // constraint
6563        if (!allConstraintsPass(selectionConfig.constraints, selectionRange, relevantEventStore, state.businessHours, context)) {
6564            return false;
6565        }
6566        // overlap
6567        let { selectOverlap } = context.options;
6568        let selectOverlapFunc = typeof selectOverlap === 'function' ? selectOverlap : null;
6569        for (let relevantInstanceId in relevantInstances) {
6570            let relevantInstance = relevantInstances[relevantInstanceId];
6571            // intersect! evaluate
6572            if (rangesIntersect(selectionRange, relevantInstance.range)) {
6573                if (selectionConfig.overlap === false) {
6574                    return false;
6575                }
6576                if (selectOverlapFunc && !selectOverlapFunc(new EventImpl(context, relevantDefs[relevantInstance.defId], relevantInstance), null)) {
6577                    return false;
6578                }
6579            }
6580        }
6581        // allow (a function)
6582        for (let selectionAllow of selectionConfig.allows) {
6583            let fullDateSpan = Object.assign(Object.assign({}, dateSpanMeta), selection);
6584            if (!selectionAllow(buildDateSpanApiWithContext(fullDateSpan, context), null)) {
6585                return false;
6586            }
6587        }
6588        return true;
6589    }
6590    // Constraint Utils
6591    // ------------------------------------------------------------------------------------------------------------------------
6592    function allConstraintsPass(constraints, subjectRange, otherEventStore, businessHoursUnexpanded, context) {
6593        for (let constraint of constraints) {
6594            if (!anyRangesContainRange(constraintToRanges(constraint, subjectRange, otherEventStore, businessHoursUnexpanded, context), subjectRange)) {
6595                return false;
6596            }
6597        }
6598        return true;
6599    }
6600    function constraintToRanges(constraint, subjectRange, // for expanding a recurring constraint, or expanding business hours
6601                                otherEventStore, // for if constraint is an even group ID
6602                                businessHoursUnexpanded, // for if constraint is 'businessHours'
6603                                context) {
6604        if (constraint === 'businessHours') {
6605            return eventStoreToRanges(expandRecurring(businessHoursUnexpanded, subjectRange, context));
6606        }
6607        if (typeof constraint === 'string') { // an group ID
6608            return eventStoreToRanges(filterEventStoreDefs(otherEventStore, (eventDef) => eventDef.groupId === constraint));
6609        }
6610        if (typeof constraint === 'object' && constraint) { // non-null object
6611            return eventStoreToRanges(expandRecurring(constraint, subjectRange, context));
6612        }
6613        return []; // if it's false
6614    }
6615    // TODO: move to event-store file?
6616    function eventStoreToRanges(eventStore) {
6617        let { instances } = eventStore;
6618        let ranges = [];
6619        for (let instanceId in instances) {
6620            ranges.push(instances[instanceId].range);
6621        }
6622        return ranges;
6623    }
6624    // TODO: move to geom file?
6625    function anyRangesContainRange(outerRanges, innerRange) {
6626        for (let outerRange of outerRanges) {
6627            if (rangeContainsRange(outerRange, innerRange)) {
6628                return true;
6629            }
6630        }
6631        return false;
6632    }
6633
6634    const VISIBLE_HIDDEN_RE = /^(visible|hidden)$/;
6635    class Scroller extends BaseComponent {
6636        constructor() {
6637            super(...arguments);
6638            this.handleEl = (el) => {
6639                this.el = el;
6640                setRef(this.props.elRef, el);
6641            };
6642        }
6643        render() {
6644            let { props } = this;
6645            let { liquid, liquidIsAbsolute } = props;
6646            let isAbsolute = liquid && liquidIsAbsolute;
6647            let className = ['fc-scroller'];
6648            if (liquid) {
6649                if (liquidIsAbsolute) {
6650                    className.push('fc-scroller-liquid-absolute');
6651                }
6652                else {
6653                    className.push('fc-scroller-liquid');
6654                }
6655            }
6656            return (y("div", { ref: this.handleEl, className: className.join(' '), style: {
6657                    overflowX: props.overflowX,
6658                    overflowY: props.overflowY,
6659                    left: (isAbsolute && -(props.overcomeLeft || 0)) || '',
6660                    right: (isAbsolute && -(props.overcomeRight || 0)) || '',
6661                    bottom: (isAbsolute && -(props.overcomeBottom || 0)) || '',
6662                    marginLeft: (!isAbsolute && -(props.overcomeLeft || 0)) || '',
6663                    marginRight: (!isAbsolute && -(props.overcomeRight || 0)) || '',
6664                    marginBottom: (!isAbsolute && -(props.overcomeBottom || 0)) || '',
6665                    maxHeight: props.maxHeight || '',
6666                } }, props.children));
6667        }
6668        needsXScrolling() {
6669            if (VISIBLE_HIDDEN_RE.test(this.props.overflowX)) {
6670                return false;
6671            }
6672            // testing scrollWidth>clientWidth is unreliable cross-browser when pixel heights aren't integers.
6673            // much more reliable to see if children are taller than the scroller, even tho doesn't account for
6674            // inner-child margins and absolute positioning
6675            let { el } = this;
6676            let realClientWidth = this.el.getBoundingClientRect().width - this.getYScrollbarWidth();
6677            let { children } = el;
6678            for (let i = 0; i < children.length; i += 1) {
6679                let childEl = children[i];
6680                if (childEl.getBoundingClientRect().width > realClientWidth) {
6681                    return true;
6682                }
6683            }
6684            return false;
6685        }
6686        needsYScrolling() {
6687            if (VISIBLE_HIDDEN_RE.test(this.props.overflowY)) {
6688                return false;
6689            }
6690            // testing scrollHeight>clientHeight is unreliable cross-browser when pixel heights aren't integers.
6691            // much more reliable to see if children are taller than the scroller, even tho doesn't account for
6692            // inner-child margins and absolute positioning
6693            let { el } = this;
6694            let realClientHeight = this.el.getBoundingClientRect().height - this.getXScrollbarWidth();
6695            let { children } = el;
6696            for (let i = 0; i < children.length; i += 1) {
6697                let childEl = children[i];
6698                if (childEl.getBoundingClientRect().height > realClientHeight) {
6699                    return true;
6700                }
6701            }
6702            return false;
6703        }
6704        getXScrollbarWidth() {
6705            if (VISIBLE_HIDDEN_RE.test(this.props.overflowX)) {
6706                return 0;
6707            }
6708            return this.el.offsetHeight - this.el.clientHeight; // only works because we guarantee no borders. TODO: add to CSS with important?
6709        }
6710        getYScrollbarWidth() {
6711            if (VISIBLE_HIDDEN_RE.test(this.props.overflowY)) {
6712                return 0;
6713            }
6714            return this.el.offsetWidth - this.el.clientWidth; // only works because we guarantee no borders. TODO: add to CSS with important?
6715        }
6716    }
6717
6718    /*
6719    TODO: somehow infer OtherArgs from masterCallback?
6720    TODO: infer RefType from masterCallback if provided
6721    */
6722    class RefMap {
6723        constructor(masterCallback) {
6724            this.masterCallback = masterCallback;
6725            this.currentMap = {};
6726            this.depths = {};
6727            this.callbackMap = {};
6728            this.handleValue = (val, key) => {
6729                let { depths, currentMap } = this;
6730                let removed = false;
6731                let added = false;
6732                if (val !== null) {
6733                    // for bug... ACTUALLY: can probably do away with this now that callers don't share numeric indices anymore
6734                    removed = (key in currentMap);
6735                    currentMap[key] = val;
6736                    depths[key] = (depths[key] || 0) + 1;
6737                    added = true;
6738                }
6739                else {
6740                    depths[key] -= 1;
6741                    if (!depths[key]) {
6742                        delete currentMap[key];
6743                        delete this.callbackMap[key];
6744                        removed = true;
6745                    }
6746                }
6747                if (this.masterCallback) {
6748                    if (removed) {
6749                        this.masterCallback(null, String(key));
6750                    }
6751                    if (added) {
6752                        this.masterCallback(val, String(key));
6753                    }
6754                }
6755            };
6756        }
6757        createRef(key) {
6758            let refCallback = this.callbackMap[key];
6759            if (!refCallback) {
6760                refCallback = this.callbackMap[key] = (val) => {
6761                    this.handleValue(val, String(key));
6762                };
6763            }
6764            return refCallback;
6765        }
6766        // TODO: check callers that don't care about order. should use getAll instead
6767        // NOTE: this method has become less valuable now that we are encouraged to map order by some other index
6768        // TODO: provide ONE array-export function, buildArray, which fails on non-numeric indexes. caller can manipulate and "collect"
6769        collect(startIndex, endIndex, step) {
6770            return collectFromHash(this.currentMap, startIndex, endIndex, step);
6771        }
6772        getAll() {
6773            return hashValuesToArray(this.currentMap);
6774        }
6775    }
6776
6777    function computeShrinkWidth(chunkEls) {
6778        let shrinkCells = findElements(chunkEls, '.fc-scrollgrid-shrink');
6779        let largestWidth = 0;
6780        for (let shrinkCell of shrinkCells) {
6781            largestWidth = Math.max(largestWidth, computeSmallestCellWidth(shrinkCell));
6782        }
6783        return Math.ceil(largestWidth); // <table> elements work best with integers. round up to ensure contents fits
6784    }
6785    function getSectionHasLiquidHeight(props, sectionConfig) {
6786        return props.liquid && sectionConfig.liquid; // does the section do liquid-height? (need to have whole scrollgrid liquid-height as well)
6787    }
6788    function getAllowYScrolling(props, sectionConfig) {
6789        return sectionConfig.maxHeight != null || // if its possible for the height to max out, we might need scrollbars
6790            getSectionHasLiquidHeight(props, sectionConfig); // if the section is liquid height, it might condense enough to require scrollbars
6791    }
6792    // TODO: ONLY use `arg`. force out internal function to use same API
6793    function renderChunkContent(sectionConfig, chunkConfig, arg, isHeader) {
6794        let { expandRows } = arg;
6795        let content = typeof chunkConfig.content === 'function' ?
6796            chunkConfig.content(arg) :
6797            y('table', {
6798                role: 'presentation',
6799                className: [
6800                    chunkConfig.tableClassName,
6801                    sectionConfig.syncRowHeights ? 'fc-scrollgrid-sync-table' : '',
6802                ].join(' '),
6803                style: {
6804                    minWidth: arg.tableMinWidth,
6805                    width: arg.clientWidth,
6806                    height: expandRows ? arg.clientHeight : '', // css `height` on a <table> serves as a min-height
6807                },
6808            }, arg.tableColGroupNode, y(isHeader ? 'thead' : 'tbody', {
6809                role: 'presentation',
6810            }, typeof chunkConfig.rowContent === 'function'
6811                ? chunkConfig.rowContent(arg)
6812                : chunkConfig.rowContent));
6813        return content;
6814    }
6815    function isColPropsEqual(cols0, cols1) {
6816        return isArraysEqual(cols0, cols1, isPropsEqual);
6817    }
6818    function renderMicroColGroup(cols, shrinkWidth) {
6819        let colNodes = [];
6820        /*
6821        for ColProps with spans, it would have been great to make a single <col span="">
6822        HOWEVER, Chrome was getting messing up distributing the width to <td>/<th> elements with colspans.
6823        SOLUTION: making individual <col> elements makes Chrome behave.
6824        */
6825        for (let colProps of cols) {
6826            let span = colProps.span || 1;
6827            for (let i = 0; i < span; i += 1) {
6828                colNodes.push(y("col", { style: {
6829                        width: colProps.width === 'shrink' ? sanitizeShrinkWidth(shrinkWidth) : (colProps.width || ''),
6830                        minWidth: colProps.minWidth || '',
6831                    } }));
6832            }
6833        }
6834        return y('colgroup', {}, ...colNodes);
6835    }
6836    function sanitizeShrinkWidth(shrinkWidth) {
6837        /* why 4? if we do 0, it will kill any border, which are needed for computeSmallestCellWidth
6838        4 accounts for 2 2-pixel borders. TODO: better solution? */
6839        return shrinkWidth == null ? 4 : shrinkWidth;
6840    }
6841    function hasShrinkWidth(cols) {
6842        for (let col of cols) {
6843            if (col.width === 'shrink') {
6844                return true;
6845            }
6846        }
6847        return false;
6848    }
6849    function getScrollGridClassNames(liquid, context) {
6850        let classNames = [
6851            'fc-scrollgrid',
6852            context.theme.getClass('table'),
6853        ];
6854        if (liquid) {
6855            classNames.push('fc-scrollgrid-liquid');
6856        }
6857        return classNames;
6858    }
6859    function getSectionClassNames(sectionConfig, wholeTableVGrow) {
6860        let classNames = [
6861            'fc-scrollgrid-section',
6862            `fc-scrollgrid-section-${sectionConfig.type}`,
6863            sectionConfig.className, // used?
6864        ];
6865        if (wholeTableVGrow && sectionConfig.liquid && sectionConfig.maxHeight == null) {
6866            classNames.push('fc-scrollgrid-section-liquid');
6867        }
6868        if (sectionConfig.isSticky) {
6869            classNames.push('fc-scrollgrid-section-sticky');
6870        }
6871        return classNames;
6872    }
6873    function renderScrollShim(arg) {
6874        return (y("div", { className: "fc-scrollgrid-sticky-shim", style: {
6875                width: arg.clientWidth,
6876                minWidth: arg.tableMinWidth,
6877            } }));
6878    }
6879    function getStickyHeaderDates(options) {
6880        let { stickyHeaderDates } = options;
6881        if (stickyHeaderDates == null || stickyHeaderDates === 'auto') {
6882            stickyHeaderDates = options.height === 'auto' || options.viewHeight === 'auto';
6883        }
6884        return stickyHeaderDates;
6885    }
6886    function getStickyFooterScrollbar(options) {
6887        let { stickyFooterScrollbar } = options;
6888        if (stickyFooterScrollbar == null || stickyFooterScrollbar === 'auto') {
6889            stickyFooterScrollbar = options.height === 'auto' || options.viewHeight === 'auto';
6890        }
6891        return stickyFooterScrollbar;
6892    }
6893
6894    class SimpleScrollGrid extends BaseComponent {
6895        constructor() {
6896            super(...arguments);
6897            this.processCols = memoize((a) => a, isColPropsEqual); // so we get same `cols` props every time
6898            // yucky to memoize VNodes, but much more efficient for consumers
6899            this.renderMicroColGroup = memoize(renderMicroColGroup);
6900            this.scrollerRefs = new RefMap();
6901            this.scrollerElRefs = new RefMap(this._handleScrollerEl.bind(this));
6902            this.state = {
6903                shrinkWidth: null,
6904                forceYScrollbars: false,
6905                scrollerClientWidths: {},
6906                scrollerClientHeights: {},
6907            };
6908            // TODO: can do a really simple print-view. dont need to join rows
6909            this.handleSizing = () => {
6910                this.safeSetState(Object.assign({ shrinkWidth: this.computeShrinkWidth() }, this.computeScrollerDims()));
6911            };
6912        }
6913        render() {
6914            let { props, state, context } = this;
6915            let sectionConfigs = props.sections || [];
6916            let cols = this.processCols(props.cols);
6917            let microColGroupNode = this.renderMicroColGroup(cols, state.shrinkWidth);
6918            let classNames = getScrollGridClassNames(props.liquid, context);
6919            if (props.collapsibleWidth) {
6920                classNames.push('fc-scrollgrid-collapsible');
6921            }
6922            // TODO: make DRY
6923            let configCnt = sectionConfigs.length;
6924            let configI = 0;
6925            let currentConfig;
6926            let headSectionNodes = [];
6927            let bodySectionNodes = [];
6928            let footSectionNodes = [];
6929            while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'header') {
6930                headSectionNodes.push(this.renderSection(currentConfig, microColGroupNode, true));
6931                configI += 1;
6932            }
6933            while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'body') {
6934                bodySectionNodes.push(this.renderSection(currentConfig, microColGroupNode, false));
6935                configI += 1;
6936            }
6937            while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'footer') {
6938                footSectionNodes.push(this.renderSection(currentConfig, microColGroupNode, true));
6939                configI += 1;
6940            }
6941            // firefox bug: when setting height on table and there is a thead or tfoot,
6942            // the necessary height:100% on the liquid-height body section forces the *whole* table to be taller. (bug #5524)
6943            // use getCanVGrowWithinCell as a way to detect table-stupid firefox.
6944            // if so, use a simpler dom structure, jam everything into a lone tbody.
6945            let isBuggy = !getCanVGrowWithinCell();
6946            const roleAttrs = { role: 'rowgroup' };
6947            return y('table', {
6948                role: 'grid',
6949                className: classNames.join(' '),
6950                style: { height: props.height },
6951            }, Boolean(!isBuggy && headSectionNodes.length) && y('thead', roleAttrs, ...headSectionNodes), Boolean(!isBuggy && bodySectionNodes.length) && y('tbody', roleAttrs, ...bodySectionNodes), Boolean(!isBuggy && footSectionNodes.length) && y('tfoot', roleAttrs, ...footSectionNodes), isBuggy && y('tbody', roleAttrs, ...headSectionNodes, ...bodySectionNodes, ...footSectionNodes));
6952        }
6953        renderSection(sectionConfig, microColGroupNode, isHeader) {
6954            if ('outerContent' in sectionConfig) {
6955                return (y(_, { key: sectionConfig.key }, sectionConfig.outerContent));
6956            }
6957            return (y("tr", { key: sectionConfig.key, role: "presentation", className: getSectionClassNames(sectionConfig, this.props.liquid).join(' ') }, this.renderChunkTd(sectionConfig, microColGroupNode, sectionConfig.chunk, isHeader)));
6958        }
6959        renderChunkTd(sectionConfig, microColGroupNode, chunkConfig, isHeader) {
6960            if ('outerContent' in chunkConfig) {
6961                return chunkConfig.outerContent;
6962            }
6963            let { props } = this;
6964            let { forceYScrollbars, scrollerClientWidths, scrollerClientHeights } = this.state;
6965            let needsYScrolling = getAllowYScrolling(props, sectionConfig); // TODO: do lazily. do in section config?
6966            let isLiquid = getSectionHasLiquidHeight(props, sectionConfig);
6967            // for `!props.liquid` - is WHOLE scrollgrid natural height?
6968            // TODO: do same thing in advanced scrollgrid? prolly not b/c always has horizontal scrollbars
6969            let overflowY = !props.liquid ? 'visible' :
6970                forceYScrollbars ? 'scroll' :
6971                    !needsYScrolling ? 'hidden' :
6972                        'auto';
6973            let sectionKey = sectionConfig.key;
6974            let content = renderChunkContent(sectionConfig, chunkConfig, {
6975                tableColGroupNode: microColGroupNode,
6976                tableMinWidth: '',
6977                clientWidth: (!props.collapsibleWidth && scrollerClientWidths[sectionKey] !== undefined) ? scrollerClientWidths[sectionKey] : null,
6978                clientHeight: scrollerClientHeights[sectionKey] !== undefined ? scrollerClientHeights[sectionKey] : null,
6979                expandRows: sectionConfig.expandRows,
6980                syncRowHeights: false,
6981                rowSyncHeights: [],
6982                reportRowHeightChange: () => { },
6983            }, isHeader);
6984            return y(isHeader ? 'th' : 'td', {
6985                ref: chunkConfig.elRef,
6986                role: 'presentation',
6987            }, y("div", { className: `fc-scroller-harness${isLiquid ? ' fc-scroller-harness-liquid' : ''}` },
6988                y(Scroller, { ref: this.scrollerRefs.createRef(sectionKey), elRef: this.scrollerElRefs.createRef(sectionKey), overflowY: overflowY, overflowX: !props.liquid ? 'visible' : 'hidden' /* natural height? */, maxHeight: sectionConfig.maxHeight, liquid: isLiquid, liquidIsAbsolute // because its within a harness
6989                        : true }, content)));
6990        }
6991        _handleScrollerEl(scrollerEl, key) {
6992            let section = getSectionByKey(this.props.sections, key);
6993            if (section) {
6994                setRef(section.chunk.scrollerElRef, scrollerEl);
6995            }
6996        }
6997        componentDidMount() {
6998            this.handleSizing();
6999            this.context.addResizeHandler(this.handleSizing);
7000        }
7001        componentDidUpdate() {
7002            // TODO: need better solution when state contains non-sizing things
7003            this.handleSizing();
7004        }
7005        componentWillUnmount() {
7006            this.context.removeResizeHandler(this.handleSizing);
7007        }
7008        computeShrinkWidth() {
7009            return hasShrinkWidth(this.props.cols)
7010                ? computeShrinkWidth(this.scrollerElRefs.getAll())
7011                : 0;
7012        }
7013        computeScrollerDims() {
7014            let scrollbarWidth = getScrollbarWidths();
7015            let { scrollerRefs, scrollerElRefs } = this;
7016            let forceYScrollbars = false;
7017            let scrollerClientWidths = {};
7018            let scrollerClientHeights = {};
7019            for (let sectionKey in scrollerRefs.currentMap) {
7020                let scroller = scrollerRefs.currentMap[sectionKey];
7021                if (scroller && scroller.needsYScrolling()) {
7022                    forceYScrollbars = true;
7023                    break;
7024                }
7025            }
7026            for (let section of this.props.sections) {
7027                let sectionKey = section.key;
7028                let scrollerEl = scrollerElRefs.currentMap[sectionKey];
7029                if (scrollerEl) {
7030                    let harnessEl = scrollerEl.parentNode; // TODO: weird way to get this. need harness b/c doesn't include table borders
7031                    scrollerClientWidths[sectionKey] = Math.floor(harnessEl.getBoundingClientRect().width - (forceYScrollbars
7032                        ? scrollbarWidth.y // use global because scroller might not have scrollbars yet but will need them in future
7033                        : 0));
7034                    scrollerClientHeights[sectionKey] = Math.floor(harnessEl.getBoundingClientRect().height);
7035                }
7036            }
7037            return { forceYScrollbars, scrollerClientWidths, scrollerClientHeights };
7038        }
7039    }
7040    SimpleScrollGrid.addStateEquality({
7041        scrollerClientWidths: isPropsEqual,
7042        scrollerClientHeights: isPropsEqual,
7043    });
7044    function getSectionByKey(sections, key) {
7045        for (let section of sections) {
7046            if (section.key === key) {
7047                return section;
7048            }
7049        }
7050        return null;
7051    }
7052
7053    class EventContainer extends BaseComponent {
7054        constructor() {
7055            super(...arguments);
7056            this.handleEl = (el) => {
7057                this.el = el;
7058                if (el) {
7059                    setElSeg(el, this.props.seg);
7060                }
7061            };
7062        }
7063        render() {
7064            const { props, context } = this;
7065            const { options } = context;
7066            const { seg } = props;
7067            const { eventRange } = seg;
7068            const { ui } = eventRange;
7069            const renderProps = {
7070                event: new EventImpl(context, eventRange.def, eventRange.instance),
7071                view: context.viewApi,
7072                timeText: props.timeText,
7073                textColor: ui.textColor,
7074                backgroundColor: ui.backgroundColor,
7075                borderColor: ui.borderColor,
7076                isDraggable: !props.disableDragging && computeSegDraggable(seg, context),
7077                isStartResizable: !props.disableResizing && computeSegStartResizable(seg, context),
7078                isEndResizable: !props.disableResizing && computeSegEndResizable(seg),
7079                isMirror: Boolean(props.isDragging || props.isResizing || props.isDateSelecting),
7080                isStart: Boolean(seg.isStart),
7081                isEnd: Boolean(seg.isEnd),
7082                isPast: Boolean(props.isPast),
7083                isFuture: Boolean(props.isFuture),
7084                isToday: Boolean(props.isToday),
7085                isSelected: Boolean(props.isSelected),
7086                isDragging: Boolean(props.isDragging),
7087                isResizing: Boolean(props.isResizing),
7088            };
7089            return (y(ContentContainer, Object.assign({}, props /* contains children */, { elRef: this.handleEl, elClasses: [
7090                    ...getEventClassNames(renderProps),
7091                    ...seg.eventRange.ui.classNames,
7092                    ...(props.elClasses || []),
7093                ], renderProps: renderProps, generatorName: "eventContent", customGenerator: options.eventContent, defaultGenerator: props.defaultGenerator, classNameGenerator: options.eventClassNames, didMount: options.eventDidMount, willUnmount: options.eventWillUnmount })));
7094        }
7095        componentDidUpdate(prevProps) {
7096            if (this.el && this.props.seg !== prevProps.seg) {
7097                setElSeg(this.el, this.props.seg);
7098            }
7099        }
7100    }
7101
7102    // should not be a purecomponent
7103    class StandardEvent extends BaseComponent {
7104        render() {
7105            let { props, context } = this;
7106            let { options } = context;
7107            let { seg } = props;
7108            let { ui } = seg.eventRange;
7109            let timeFormat = options.eventTimeFormat || props.defaultTimeFormat;
7110            let timeText = buildSegTimeText(seg, timeFormat, context, props.defaultDisplayEventTime, props.defaultDisplayEventEnd);
7111            return (y(EventContainer, Object.assign({}, props /* includes elRef */, { elTag: "a", elStyle: {
7112                    borderColor: ui.borderColor,
7113                    backgroundColor: ui.backgroundColor,
7114                }, elAttrs: getSegAnchorAttrs(seg, context), defaultGenerator: renderInnerContent$1$1, timeText: timeText }), (InnerContent, eventContentArg) => (y(_, null,
7115                y(InnerContent, { elTag: "div", elClasses: ['fc-event-main'], elStyle: { color: eventContentArg.textColor } }),
7116                Boolean(eventContentArg.isStartResizable) && (y("div", { className: "fc-event-resizer fc-event-resizer-start" })),
7117                Boolean(eventContentArg.isEndResizable) && (y("div", { className: "fc-event-resizer fc-event-resizer-end" }))))));
7118        }
7119    }
7120    function renderInnerContent$1$1(innerProps) {
7121        return (y("div", { className: "fc-event-main-frame" },
7122            innerProps.timeText && (y("div", { className: "fc-event-time" }, innerProps.timeText)),
7123            y("div", { className: "fc-event-title-container" },
7124                y("div", { className: "fc-event-title fc-sticky" }, innerProps.event.title || y(_, null, "\u00A0")))));
7125    }
7126
7127    const NowIndicatorContainer = (props) => (y(ViewContextType.Consumer, null, (context) => {
7128        let { options } = context;
7129        let renderProps = {
7130            isAxis: props.isAxis,
7131            date: context.dateEnv.toDate(props.date),
7132            view: context.viewApi,
7133        };
7134        return (y(ContentContainer, Object.assign({}, props /* includes children */, { elTag: props.elTag || 'div', renderProps: renderProps, generatorName: "nowIndicatorContent", customGenerator: options.nowIndicatorContent, classNameGenerator: options.nowIndicatorClassNames, didMount: options.nowIndicatorDidMount, willUnmount: options.nowIndicatorWillUnmount })));
7135    }));
7136
7137    const DAY_NUM_FORMAT = createFormatter({ day: 'numeric' });
7138    class DayCellContainer extends BaseComponent {
7139        constructor() {
7140            super(...arguments);
7141            this.refineRenderProps = memoizeObjArg(refineRenderProps);
7142        }
7143        render() {
7144            let { props, context } = this;
7145            let { options } = context;
7146            let renderProps = this.refineRenderProps({
7147                date: props.date,
7148                dateProfile: props.dateProfile,
7149                todayRange: props.todayRange,
7150                isMonthStart: props.isMonthStart || false,
7151                showDayNumber: props.showDayNumber,
7152                extraRenderProps: props.extraRenderProps,
7153                viewApi: context.viewApi,
7154                dateEnv: context.dateEnv,
7155                monthStartFormat: options.monthStartFormat,
7156            });
7157            return (y(ContentContainer, Object.assign({}, props /* includes children */, { elClasses: [
7158                    ...getDayClassNames(renderProps, context.theme),
7159                    ...(props.elClasses || []),
7160                ], elAttrs: Object.assign(Object.assign({}, props.elAttrs), (renderProps.isDisabled ? {} : { 'data-date': formatDayString(props.date) })), renderProps: renderProps, generatorName: "dayCellContent", customGenerator: options.dayCellContent, defaultGenerator: props.defaultGenerator, classNameGenerator:
7161                // don't use custom classNames if disabled
7162                    renderProps.isDisabled ? undefined : options.dayCellClassNames, didMount: options.dayCellDidMount, willUnmount: options.dayCellWillUnmount })));
7163        }
7164    }
7165    function hasCustomDayCellContent(options) {
7166        return Boolean(options.dayCellContent || hasCustomRenderingHandler('dayCellContent', options));
7167    }
7168    function refineRenderProps(raw) {
7169        let { date, dateEnv, dateProfile, isMonthStart } = raw;
7170        let dayMeta = getDateMeta(date, raw.todayRange, null, dateProfile);
7171        let dayNumberText = raw.showDayNumber ? (dateEnv.format(date, isMonthStart ? raw.monthStartFormat : DAY_NUM_FORMAT)) : '';
7172        return Object.assign(Object.assign(Object.assign({ date: dateEnv.toDate(date), view: raw.viewApi }, dayMeta), { isMonthStart,
7173            dayNumberText }), raw.extraRenderProps);
7174    }
7175
7176    class BgEvent extends BaseComponent {
7177        render() {
7178            let { props } = this;
7179            let { seg } = props;
7180            return (y(EventContainer, { elTag: "div", elClasses: ['fc-bg-event'], elStyle: { backgroundColor: seg.eventRange.ui.backgroundColor }, defaultGenerator: renderInnerContent$3, seg: seg, timeText: "", isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false, isPast: props.isPast, isFuture: props.isFuture, isToday: props.isToday, disableDragging: true, disableResizing: true }));
7181        }
7182    }
7183    function renderInnerContent$3(props) {
7184        let { title } = props.event;
7185        return title && (y("div", { className: "fc-event-title" }, props.event.title));
7186    }
7187    function renderFill(fillType) {
7188        return (y("div", { className: `fc-${fillType}` }));
7189    }
7190
7191    const WeekNumberContainer = (props) => (y(ViewContextType.Consumer, null, (context) => {
7192        let { dateEnv, options } = context;
7193        let { date } = props;
7194        let format = options.weekNumberFormat || props.defaultFormat;
7195        let num = dateEnv.computeWeekNumber(date); // TODO: somehow use for formatting as well?
7196        let text = dateEnv.format(date, format);
7197        let renderProps = { num, text, date };
7198        return (y(ContentContainer // why isn't WeekNumberContentArg being auto-detected?
7199            , Object.assign({}, props /* includes children */, { renderProps: renderProps, generatorName: "weekNumberContent", customGenerator: options.weekNumberContent, defaultGenerator: renderInner, classNameGenerator: options.weekNumberClassNames, didMount: options.weekNumberDidMount, willUnmount: options.weekNumberWillUnmount })));
7200    }));
7201    function renderInner(innerProps) {
7202        return innerProps.text;
7203    }
7204
7205    const PADDING_FROM_VIEWPORT = 10;
7206    class Popover extends BaseComponent {
7207        constructor() {
7208            super(...arguments);
7209            this.state = {
7210                titleId: getUniqueDomId(),
7211            };
7212            this.handleRootEl = (el) => {
7213                this.rootEl = el;
7214                if (this.props.elRef) {
7215                    setRef(this.props.elRef, el);
7216                }
7217            };
7218            // Triggered when the user clicks *anywhere* in the document, for the autoHide feature
7219            this.handleDocumentMouseDown = (ev) => {
7220                // only hide the popover if the click happened outside the popover
7221                const target = getEventTargetViaRoot(ev);
7222                if (!this.rootEl.contains(target)) {
7223                    this.handleCloseClick();
7224                }
7225            };
7226            this.handleDocumentKeyDown = (ev) => {
7227                if (ev.key === 'Escape') {
7228                    this.handleCloseClick();
7229                }
7230            };
7231            this.handleCloseClick = () => {
7232                let { onClose } = this.props;
7233                if (onClose) {
7234                    onClose();
7235                }
7236            };
7237        }
7238        render() {
7239            let { theme, options } = this.context;
7240            let { props, state } = this;
7241            let classNames = [
7242                'fc-popover',
7243                theme.getClass('popover'),
7244            ].concat(props.extraClassNames || []);
7245            return j(y("div", Object.assign({}, props.extraAttrs, { id: props.id, className: classNames.join(' '), "aria-labelledby": state.titleId, ref: this.handleRootEl }),
7246                y("div", { className: 'fc-popover-header ' + theme.getClass('popoverHeader') },
7247                    y("span", { className: "fc-popover-title", id: state.titleId }, props.title),
7248                    y("span", { className: 'fc-popover-close ' + theme.getIconClass('close'), title: options.closeHint, onClick: this.handleCloseClick })),
7249                y("div", { className: 'fc-popover-body ' + theme.getClass('popoverContent') }, props.children)), props.parentEl);
7250        }
7251        componentDidMount() {
7252            document.addEventListener('mousedown', this.handleDocumentMouseDown);
7253            document.addEventListener('keydown', this.handleDocumentKeyDown);
7254            this.updateSize();
7255        }
7256        componentWillUnmount() {
7257            document.removeEventListener('mousedown', this.handleDocumentMouseDown);
7258            document.removeEventListener('keydown', this.handleDocumentKeyDown);
7259        }
7260        updateSize() {
7261            let { isRtl } = this.context;
7262            let { alignmentEl, alignGridTop } = this.props;
7263            let { rootEl } = this;
7264            let alignmentRect = computeClippedClientRect(alignmentEl);
7265            if (alignmentRect) {
7266                let popoverDims = rootEl.getBoundingClientRect();
7267                // position relative to viewport
7268                let popoverTop = alignGridTop
7269                    ? elementClosest(alignmentEl, '.fc-scrollgrid').getBoundingClientRect().top
7270                    : alignmentRect.top;
7271                let popoverLeft = isRtl ? alignmentRect.right - popoverDims.width : alignmentRect.left;
7272                // constrain
7273                popoverTop = Math.max(popoverTop, PADDING_FROM_VIEWPORT);
7274                popoverLeft = Math.min(popoverLeft, document.documentElement.clientWidth - PADDING_FROM_VIEWPORT - popoverDims.width);
7275                popoverLeft = Math.max(popoverLeft, PADDING_FROM_VIEWPORT);
7276                let origin = rootEl.offsetParent.getBoundingClientRect();
7277                applyStyle(rootEl, {
7278                    top: popoverTop - origin.top,
7279                    left: popoverLeft - origin.left,
7280                });
7281            }
7282        }
7283    }
7284
7285    class MorePopover extends DateComponent {
7286        constructor() {
7287            super(...arguments);
7288            this.handleRootEl = (rootEl) => {
7289                this.rootEl = rootEl;
7290                if (rootEl) {
7291                    this.context.registerInteractiveComponent(this, {
7292                        el: rootEl,
7293                        useEventCenter: false,
7294                    });
7295                }
7296                else {
7297                    this.context.unregisterInteractiveComponent(this);
7298                }
7299            };
7300        }
7301        render() {
7302            let { options, dateEnv } = this.context;
7303            let { props } = this;
7304            let { startDate, todayRange, dateProfile } = props;
7305            let title = dateEnv.format(startDate, options.dayPopoverFormat);
7306            return (y(DayCellContainer, { elRef: this.handleRootEl, date: startDate, dateProfile: dateProfile, todayRange: todayRange }, (InnerContent, renderProps, elAttrs) => (y(Popover, { elRef: elAttrs.ref, id: props.id, title: title, extraClassNames: ['fc-more-popover'].concat(elAttrs.className || []), extraAttrs: elAttrs /* TODO: make these time-based when not whole-day? */, parentEl: props.parentEl, alignmentEl: props.alignmentEl, alignGridTop: props.alignGridTop, onClose: props.onClose },
7307                hasCustomDayCellContent(options) && (y(InnerContent, { elTag: "div", elClasses: ['fc-more-popover-misc'] })),
7308                props.children))));
7309        }
7310        queryHit(positionLeft, positionTop, elWidth, elHeight) {
7311            let { rootEl, props } = this;
7312            if (positionLeft >= 0 && positionLeft < elWidth &&
7313                positionTop >= 0 && positionTop < elHeight) {
7314                return {
7315                    dateProfile: props.dateProfile,
7316                    dateSpan: Object.assign({ allDay: !props.forceTimed, range: {
7317                            start: props.startDate,
7318                            end: props.endDate,
7319                        } }, props.extraDateSpan),
7320                    dayEl: rootEl,
7321                    rect: {
7322                        left: 0,
7323                        top: 0,
7324                        right: elWidth,
7325                        bottom: elHeight,
7326                    },
7327                    layer: 1, // important when comparing with hits from other components
7328                };
7329            }
7330            return null;
7331        }
7332    }
7333
7334    class MoreLinkContainer extends BaseComponent {
7335        constructor() {
7336            super(...arguments);
7337            this.state = {
7338                isPopoverOpen: false,
7339                popoverId: getUniqueDomId(),
7340            };
7341            this.handleLinkEl = (linkEl) => {
7342                this.linkEl = linkEl;
7343                if (this.props.elRef) {
7344                    setRef(this.props.elRef, linkEl);
7345                }
7346            };
7347            this.handleClick = (ev) => {
7348                let { props, context } = this;
7349                let { moreLinkClick } = context.options;
7350                let date = computeRange(props).start;
7351                function buildPublicSeg(seg) {
7352                    let { def, instance, range } = seg.eventRange;
7353                    return {
7354                        event: new EventImpl(context, def, instance),
7355                        start: context.dateEnv.toDate(range.start),
7356                        end: context.dateEnv.toDate(range.end),
7357                        isStart: seg.isStart,
7358                        isEnd: seg.isEnd,
7359                    };
7360                }
7361                if (typeof moreLinkClick === 'function') {
7362                    moreLinkClick = moreLinkClick({
7363                        date,
7364                        allDay: Boolean(props.allDayDate),
7365                        allSegs: props.allSegs.map(buildPublicSeg),
7366                        hiddenSegs: props.hiddenSegs.map(buildPublicSeg),
7367                        jsEvent: ev,
7368                        view: context.viewApi,
7369                    });
7370                }
7371                if (!moreLinkClick || moreLinkClick === 'popover') {
7372                    this.setState({ isPopoverOpen: true });
7373                }
7374                else if (typeof moreLinkClick === 'string') { // a view n
vendor: 4,546 bytes, lines 7374-7479
7374ame
7375                    context.calendarApi.zoomTo(date, moreLinkClick);
7376                }
7377            };
7378            this.handlePopoverClose = () => {
7379                this.setState({ isPopoverOpen: false });
7380            };
7381        }
7382        render() {
7383            let { props, state } = this;
7384            return (y(ViewContextType.Consumer, null, (context) => {
7385                let { viewApi, options, calendarApi } = context;
7386                let { moreLinkText } = options;
7387                let { moreCnt } = props;
7388                let range = computeRange(props);
7389                let text = typeof moreLinkText === 'function' // TODO: eventually use formatWithOrdinals
7390                    ? moreLinkText.call(calendarApi, moreCnt)
7391                    : `+${moreCnt} ${moreLinkText}`;
7392                let hint = formatWithOrdinals(options.moreLinkHint, [moreCnt], text);
7393                let renderProps = {
7394                    num: moreCnt,
7395                    shortText: `+${moreCnt}`,
7396                    text,
7397                    view: viewApi,
7398                };
7399                return (y(_, null,
7400                    Boolean(props.moreCnt) && (y(ContentContainer, { elTag: props.elTag || 'a', elRef: this.handleLinkEl, elClasses: [
7401                            ...(props.elClasses || []),
7402                            'fc-more-link',
7403                        ], elStyle: props.elStyle, elAttrs: Object.assign(Object.assign(Object.assign({}, props.elAttrs), createAriaClickAttrs(this.handleClick)), { title: hint, 'aria-expanded': state.isPopoverOpen, 'aria-controls': state.isPopoverOpen ? state.popoverId : '' }), renderProps: renderProps, generatorName: "moreLinkContent", customGenerator: options.moreLinkContent, defaultGenerator: props.defaultGenerator || renderMoreLinkInner$1, classNameGenerator: options.moreLinkClassNames, didMount: options.moreLinkDidMount, willUnmount: options.moreLinkWillUnmount }, props.children)),
7404                    state.isPopoverOpen && (y(MorePopover, { id: state.popoverId, startDate: range.start, endDate: range.end, dateProfile: props.dateProfile, todayRange: props.todayRange, extraDateSpan: props.extraDateSpan, parentEl: this.parentEl, alignmentEl: props.alignmentElRef ?
7405                            props.alignmentElRef.current :
7406                            this.linkEl, alignGridTop: props.alignGridTop, forceTimed: props.forceTimed, onClose: this.handlePopoverClose }, props.popoverContent()))));
7407            }));
7408        }
7409        componentDidMount() {
7410            this.updateParentEl();
7411        }
7412        componentDidUpdate() {
7413            this.updateParentEl();
7414        }
7415        updateParentEl() {
7416            if (this.linkEl) {
7417                this.parentEl = elementClosest(this.linkEl, '.fc-view-harness');
7418            }
7419        }
7420    }
7421    function renderMoreLinkInner$1(props) {
7422        return props.text;
7423    }
7424    function computeRange(props) {
7425        if (props.allDayDate) {
7426            return {
7427                start: props.allDayDate,
7428                end: addDays(props.allDayDate, 1),
7429            };
7430        }
7431        let { hiddenSegs } = props;
7432        return {
7433            start: computeEarliestSegStart(hiddenSegs),
7434            end: computeLatestSegEnd(hiddenSegs),
7435        };
7436    }
7437    function computeEarliestSegStart(segs) {
7438        return segs.reduce(pickEarliestStart).eventRange.range.start;
7439    }
7440    function pickEarliestStart(seg0, seg1) {
7441        return seg0.eventRange.range.start < seg1.eventRange.range.start ? seg0 : seg1;
7442    }
7443    function computeLatestSegEnd(segs) {
7444        return segs.reduce(pickLatestEnd).eventRange.range.end;
7445    }
7446    function pickLatestEnd(seg0, seg1) {
7447        return seg0.eventRange.range.end > seg1.eventRange.range.end ? seg0 : seg1;
7448    }
7449
7450    class Store {
7451        constructor() {
7452            this.handlers = [];
7453        }
7454        set(value) {
7455            this.currentValue = value;
7456            for (let handler of this.handlers) {
7457                handler(value);
7458            }
7459        }
7460        subscribe(handler) {
7461            this.handlers.push(handler);
7462            if (this.currentValue !== undefined) {
7463                handler(this.currentValue);
7464            }
7465        }
7466    }
7467
7468    /*
7469    Subscribers will get a LIST of CustomRenderings
7470    */
7471    class CustomRenderingStore extends Store {
7472        constructor() {
7473            super(...arguments);
7474            this.map = new Map();
7475        }
7476        // for consistent order
7477        handle(customRendering) {
7478            const { map } = this;
7479            let updated = false;
7480            if (customRendering.isActive) {
7481                map.set(customRendering.id, customRendering);
7482                updated = true;
7483            }
7484            else if (map.has(customRendering.id)) {
7485                map.delete(customRendering.id);
7486                updated = true;
7487            }
7488            if (updated) {
7489                this.set(map);
7490            }
7491        }
7492    }
7493
7494    var internal = {
7495        __proto__: null,
7496        BASE_OPTION_DEFAULTS: BASE_OPTION_DEFAULTS,
7497        BaseComponent: BaseComponent,
7498        BgEvent: BgEvent,
7499        CalendarImpl: CalendarImpl,
7500        CalendarRoot: CalendarRoot,
7501        ContentContainer: ContentContainer,
7502        CustomRenderingStore: CustomRenderingStore,
7503        DateComponent: DateComponent,
7504        DateEnv: DateEnv,
7505        DateProfileGenerator: DateProfileGenerator,
7506        DayCellContainer: DayCellContainer,
7507        DayHeader: DayHeader,
7508        DaySeriesModel: DaySeriesModel,
7509        DayTableModel: DayTableModel,
7510        DelayedRunner: DelayedRunner,
7511        ElementDragging: ElementDragging,
7512        ElementScrollController: ElementScrollController,
7513        Emitter: Emitter,
7514        EventContainer: EventContainer,
7515        EventImpl: EventImpl,
7516        Interaction: Interaction,
7517        MoreLinkContainer: MoreLinkContainer,
7518        NamedTimeZoneImpl: NamedTimeZoneImpl,
7519        NowIndicatorContainer: NowIndicatorContainer,
7520        NowTimer: NowTimer,
7521        PositionCache: PositionCache,
7522        RefMap: RefMap,
7523        ScrollController: ScrollController,
7524        ScrollResponder: ScrollResponder,
7525        Scroller: Scroller,
7526        SegHierarchy: SegHierarchy,
7527        SimpleScrollGrid: SimpleScrollGrid,
7528        Slicer: Slicer,
7529        Splitter: Splitter,
7530        StandardEvent: StandardEvent,
7531        TableDateCell: TableDateCell,
7532        TableDowCell: TableDowCell,
7533        Theme: Theme,
7534        ViewContainer: ViewContainer,
7535        ViewContextType: ViewContextType,
7536        WeekNumberContainer: WeekNumberContainer,
7537        WindowScrollController: WindowScrollController,
7538        addDays: addDays,
7539        addDurations: addDurations,
7540        addMs: addMs,
7541        addWeeks: addWeeks,
7542        allowContextMenu: allowContextMenu,
7543        allowSelection: allowSelection,
7544        applyMutationToEventStore: applyMutationToEventStore,
7545        applyStyle: applyStyle,
7546        asCleanDays: asCleanDays,
7547        asRoughMinutes: asRoughMinutes,
7548        asRoughMs: asRoughMs,
7549        asRoughSeconds: asRoughSeconds,
7550        binarySearch: binarySearch,
7551        buildElAttrs: buildElAttrs,
7552        buildEntryKey: buildEntryKey,
7553        buildEventApis: buildEventApis,
7554        buildEventRangeKey: buildEventRangeKey,
7555        buildIsoString: buildIsoString,
7556        buildNavLinkAttrs: buildNavLinkAttrs,
7557        buildSegTimeText: buildSegTimeText,
7558        collectFromHash: collectFromHash,
7559        combineEventUis: combineEventUis,
7560        compareByFieldSpecs: compareByFieldSpecs,
7561        compareNumbers: compareNumbers,
7562        compareObjs: compareObjs,
7563        computeEarliestSegStart: computeEarliestSegStart,
7564        computeEdges: computeEdges,
7565        computeFallbackHeaderFormat: computeFallbackHeaderFormat,
7566        computeInnerRect: computeInnerRect,
7567        computeRect: computeRect,
7568        computeShrinkWidth: computeShrinkWidth,
7569        computeVisibleDayRange: computeVisibleDayRange,
7570        config: config,
7571        constrainPoint: constrainPoint,
7572        createDuration: createDuration,
7573        createEmptyEventStore: createEmptyEventStore,
7574        createEventInstance: createEventInstance,
7575        createEventUi: createEventUi,
7576        createFormatter: createFormatter,
7577        diffDates: diffDates,
7578        diffDayAndTime: diffDayAndTime,
7579        diffDays: diffDays,
7580        diffPoints: diffPoints,
7581        diffWeeks: diffWeeks,
7582        diffWholeDays: diffWholeDays,
7583        diffWholeWeeks: diffWholeWeeks,
7584        disableCursor: disableCursor,
7585        elementClosest: elementClosest,
7586        elementMatches: elementMatches,
7587        enableCursor: enableCursor,
7588        eventTupleToStore: eventTupleToStore,
7589        filterHash: filterHash,
7590        findDirectChildren: findDirectChildren,
7591        findElements: findElements,
7592        flexibleCompare: flexibleCompare,
7593        formatDayString: formatDayString,
7594        formatIsoMonthStr: formatIsoMonthStr,
7595        formatIsoTimeString: formatIsoTimeString,
7596        getAllowYScrolling: getAllowYScrolling,
7597        getCanVGrowWithinCell: getCanVGrowWithinCell,
7598        getClippingParents: getClippingParents,
7599        getDateMeta: getDateMeta,
7600        getDayClassNames: getDayClassNames,
7601        getDefaultEventEnd: getDefaultEventEnd,
7602        getElSeg: getElSeg,
7603        getEntrySpanEnd: getEntrySpanEnd,
7604        getEventTargetViaRoot: getEventTargetViaRoot,
7605        getIsRtlScrollbarOnLeft: getIsRtlScrollbarOnLeft,
7606        getRectCenter: getRectCenter,
7607        getRelevantEvents: getRelevantEvents,
7608        getScrollGridClassNames: getScrollGridClassNames,
7609        getScrollbarWidths: getScrollbarWidths,
7610        getSectionClassNames: getSectionClassNames,
7611        getSectionHasLiquidHeight: getSectionHasLiquidHeight,
7612        getSegAnchorAttrs: getSegAnchorAttrs,
7613        getSegMeta: getSegMeta,
7614        getSlotClassNames: getSlotClassNames,
7615        getStickyFooterScrollbar: getStickyFooterScrollbar,
7616        getStickyHeaderDates: getStickyHeaderDates,
7617        getUniqueDomId: getUniqueDomId,
7618        greatestDurationDenominator: greatestDurationDenominator,
7619        groupIntersectingEntries: groupIntersectingEntries,
7620        guid: guid,
7621        hasBgRendering: hasBgRendering,
7622        hasCustomDayCellContent: hasCustomDayCellContent,
7623        hasShrinkWidth: hasShrinkWidth,
7624        identity: identity,
7625        injectStyles: injectStyles,
7626        interactionSettingsStore: interactionSettingsStore,
7627        interactionSettingsToStore: interactionSettingsToStore,
7628        intersectRanges: intersectRanges,
vendor: 7,522 bytes, lines 7629-7823
7629        intersectRects: intersectRects,
7630        intersectSpans: intersectSpans,
7631        isArraysEqual: isArraysEqual,
7632        isColPropsEqual: isColPropsEqual,
7633        isDateSelectionValid: isDateSelectionValid,
7634        isDateSpansEqual: isDateSpansEqual,
7635        isInt: isInt,
7636        isInteractionValid: isInteractionValid,
7637        isMultiDayRange: isMultiDayRange,
7638        isPropsEqual: isPropsEqual,
7639        isPropsValid: isPropsValid,
7640        isValidDate: isValidDate,
7641        mapHash: mapHash,
7642        memoize: memoize,
7643        memoizeArraylike: memoizeArraylike,
7644        memoizeHashlike: memoizeHashlike,
7645        memoizeObjArg: memoizeObjArg,
7646        mergeEventStores: mergeEventStores,
7647        multiplyDuration: multiplyDuration,
7648        padStart: padStart,
7649        parseBusinessHours: parseBusinessHours,
7650        parseClassNames: parseClassNames,
7651        parseDragMeta: parseDragMeta,
7652        parseEventDef: parseEventDef,
7653        parseFieldSpecs: parseFieldSpecs,
7654        parseMarker: parse,
7655        pointInsideRect: pointInsideRect,
7656        preventContextMenu: preventContextMenu,
7657        preventDefault: preventDefault,
7658        preventSelection: preventSelection,
7659        rangeContainsMarker: rangeContainsMarker,
7660        rangeContainsRange: rangeContainsRange,
7661        rangesEqual: rangesEqual,
7662        rangesIntersect: rangesIntersect,
7663        refineEventDef: refineEventDef,
7664        refineProps: refineProps,
7665        removeElement: removeElement,
7666        removeExact: removeExact,
7667        renderChunkContent: renderChunkContent,
7668        renderFill: renderFill,
7669        renderMicroColGroup: renderMicroColGroup,
7670        renderScrollShim: renderScrollShim,
7671        requestJson: requestJson,
7672        sanitizeShrinkWidth: sanitizeShrinkWidth,
7673        setRef: setRef,
7674        sliceEventStore: sliceEventStore,
7675        sortEventSegs: sortEventSegs,
7676        startOfDay: startOfDay,
7677        translateRect: translateRect,
7678        triggerDateSelect: triggerDateSelect,
7679        unpromisify: unpromisify,
7680        whenTransitionDone: whenTransitionDone,
7681        wholeDivideDurations: wholeDivideDurations
7682    };
7683
7684    var preact = {
7685        __proto__: null,
7686        createPortal: j,
7687        createContext: createContext,
7688        flushSync: flushSync,
7689        Component: x$1,
7690        Fragment: _,
7691        cloneElement: F$1,
7692        createElement: y,
7693        createRef: d,
7694        h: y,
7695        hydrate: E,
7696        get isValidElement () { return i$1; },
7697        get options () { return l$1; },
7698        render: D$1,
7699        toChildArray: j$2
7700    };
7701
7702    const globalLocales = [];
7703
7704    const MINIMAL_RAW_EN_LOCALE = {
7705        code: 'en',
7706        week: {
7707            dow: 0,
7708            doy: 4, // 4 days need to be within the year to be considered the first week
7709        },
7710        direction: 'ltr',
7711        buttonText: {
7712            prev: 'prev',
7713            next: 'next',
7714            prevYear: 'prev year',
7715            nextYear: 'next year',
7716            year: 'year',
7717            today: 'today',
7718            month: 'month',
7719            week: 'week',
7720            day: 'day',
7721            list: 'list',
7722        },
7723        weekText: 'W',
7724        weekTextLong: 'Week',
7725        closeHint: 'Close',
7726        timeHint: 'Time',
7727        eventHint: 'Event',
7728        allDayText: 'all-day',
7729        moreLinkText: 'more',
7730        noEventsText: 'No events to display',
7731    };
7732    const RAW_EN_LOCALE = Object.assign(Object.assign({}, MINIMAL_RAW_EN_LOCALE), {
7733        // Includes things we don't want other locales to inherit,
7734        // things that derive from other translatable strings.
7735        buttonHints: {
7736            prev: 'Previous $0',
7737            next: 'Next $0',
7738            today(buttonText, unit) {
7739                return (unit === 'day')
7740                    ? 'Today'
7741                    : `This ${buttonText}`;
7742            },
7743        }, viewHint: '$0 view', navLinkHint: 'Go to $0', moreLinkHint(eventCnt) {
7744            return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`;
7745        } });
7746    function organizeRawLocales(explicitRawLocales) {
7747        let defaultCode = explicitRawLocales.length > 0 ? explicitRawLocales[0].code : 'en';
7748        let allRawLocales = globalLocales.concat(explicitRawLocales);
7749        let rawLocaleMap = {
7750            en: RAW_EN_LOCALE,
7751        };
7752        for (let rawLocale of allRawLocales) {
7753            rawLocaleMap[rawLocale.code] = rawLocale;
7754        }
7755        return {
7756            map: rawLocaleMap,
7757            defaultCode,
7758        };
7759    }
7760    function buildLocale(inputSingular, available) {
7761        if (typeof inputSingular === 'object' && !Array.isArray(inputSingular)) {
7762            return parseLocale(inputSingular.code, [inputSingular.code], inputSingular);
7763        }
7764        return queryLocale(inputSingular, available);
7765    }
7766    function queryLocale(codeArg, available) {
7767        let codes = [].concat(codeArg || []); // will convert to array
7768        let raw = queryRawLocale(codes, available) || RAW_EN_LOCALE;
7769        return parseLocale(codeArg, codes, raw);
7770    }
7771    function queryRawLocale(codes, available) {
7772        for (let i = 0; i < codes.length; i += 1) {
7773            let parts = codes[i].toLocaleLowerCase().split('-');
7774            for (let j = parts.length; j > 0; j -= 1) {
7775                let simpleId = parts.slice(0, j).join('-');
7776                if (available[simpleId]) {
7777                    return available[simpleId];
7778                }
7779            }
7780        }
7781        return null;
7782    }
7783    function parseLocale(codeArg, codes, raw) {
7784        let merged = mergeProps([MINIMAL_RAW_EN_LOCALE, raw], ['buttonText']);
7785        delete merged.code; // don't want this part of the options
7786        let { week } = merged;
7787        delete merged.week;
7788        return {
7789            codeArg,
7790            codes,
7791            week,
7792            simpleNumberFormat: new Intl.NumberFormat(codeArg),
7793            options: merged,
7794        };
7795    }
7796
7797    // TODO: easier way to add new hooks? need to update a million things
7798    function createPlugin(input) {
7799        return {
7800            id: guid(),
7801            name: input.name,
7802            premiumReleaseDate: input.premiumReleaseDate ? new Date(input.premiumReleaseDate) : undefined,
7803            deps: input.deps || [],
7804            reducers: input.reducers || [],
7805            isLoadingFuncs: input.isLoadingFuncs || [],
7806            contextInit: [].concat(input.contextInit || []),
7807            eventRefiners: input.eventRefiners || {},
7808            eventDefMemberAdders: input.eventDefMemberAdders || [],
7809            eventSourceRefiners: input.eventSourceRefiners || {},
7810            isDraggableTransformers: input.isDraggableTransformers || [],
7811            eventDragMutationMassagers: input.eventDragMutationMassagers || [],
7812            eventDefMutationAppliers: input.eventDefMutationAppliers || [],
7813            dateSelectionTransformers: input.dateSelectionTransformers || [],
7814            datePointTransforms: input.datePointTransforms || [],
7815            dateSpanTransforms: input.dateSpanTransforms || [],
7816            views: input.views || {},
7817            viewPropsTransformers: input.viewPropsTransformers || [],
7818            isPropsValid: input.isPropsValid || null,
7819            externalDefTransforms: input.externalDefTransforms || [],
7820            viewContainerAppends: input.viewContainerAppends || [],
7821            eventDropTransformers: input.eventDropTransformers || [],
7822            componentInteractions: input.componentInteractions || [],
7823            calendarInteractions: input.calendarInteractions || [],
vendor: 21,948 bytes, lines 7824-8298
7824            themeClasses: input.themeClasses || {},
7825            eventSourceDefs: input.eventSourceDefs || [],
7826            cmdFormatter: input.cmdFormatter,
7827            recurringTypes: input.recurringTypes || [],
7828            namedTimeZonedImpl: input.namedTimeZonedImpl,
7829            initialView: input.initialView || '',
7830            elementDraggingImpl: input.elementDraggingImpl,
7831            optionChangeHandlers: input.optionChangeHandlers || {},
7832            scrollGridImpl: input.scrollGridImpl || null,
7833            listenerRefiners: input.listenerRefiners || {},
7834            optionRefiners: input.optionRefiners || {},
7835            propSetHandlers: input.propSetHandlers || {},
7836        };
7837    }
7838    function buildPluginHooks(pluginDefs, globalDefs) {
7839        let currentPluginIds = {};
7840        let hooks = {
7841            premiumReleaseDate: undefined,
7842            reducers: [],
7843            isLoadingFuncs: [],
7844            contextInit: [],
7845            eventRefiners: {},
7846            eventDefMemberAdders: [],
7847            eventSourceRefiners: {},
7848            isDraggableTransformers: [],
7849            eventDragMutationMassagers: [],
7850            eventDefMutationAppliers: [],
7851            dateSelectionTransformers: [],
7852            datePointTransforms: [],
7853            dateSpanTransforms: [],
7854            views: {},
7855            viewPropsTransformers: [],
7856            isPropsValid: null,
7857            externalDefTransforms: [],
7858            viewContainerAppends: [],
7859            eventDropTransformers: [],
7860            componentInteractions: [],
7861            calendarInteractions: [],
7862            themeClasses: {},
7863            eventSourceDefs: [],
7864            cmdFormatter: null,
7865            recurringTypes: [],
7866            namedTimeZonedImpl: null,
7867            initialView: '',
7868            elementDraggingImpl: null,
7869            optionChangeHandlers: {},
7870            scrollGridImpl: null,
7871            listenerRefiners: {},
7872            optionRefiners: {},
7873            propSetHandlers: {},
7874        };
7875        function addDefs(defs) {
7876            for (let def of defs) {
7877                const pluginName = def.name;
7878                const currentId = currentPluginIds[pluginName];
7879                if (currentId === undefined) {
7880                    currentPluginIds[pluginName] = def.id;
7881                    addDefs(def.deps);
7882                    hooks = combineHooks(hooks, def);
7883                }
7884                else if (currentId !== def.id) {
7885                    // different ID than the one already added
7886                    console.warn(`Duplicate plugin '${pluginName}'`);
7887                }
7888            }
7889        }
7890        if (pluginDefs) {
7891            addDefs(pluginDefs);
7892        }
7893        addDefs(globalDefs);
7894        return hooks;
7895    }
7896    function buildBuildPluginHooks() {
7897        let currentOverrideDefs = [];
7898        let currentGlobalDefs = [];
7899        let currentHooks;
7900        return (overrideDefs, globalDefs) => {
7901            if (!currentHooks || !isArraysEqual(overrideDefs, currentOverrideDefs) || !isArraysEqual(globalDefs, currentGlobalDefs)) {
7902                currentHooks = buildPluginHooks(overrideDefs, globalDefs);
7903            }
7904            currentOverrideDefs = overrideDefs;
7905            currentGlobalDefs = globalDefs;
7906            return currentHooks;
7907        };
7908    }
7909    function combineHooks(hooks0, hooks1) {
7910        return {
7911            premiumReleaseDate: compareOptionalDates(hooks0.premiumReleaseDate, hooks1.premiumReleaseDate),
7912            reducers: hooks0.reducers.concat(hooks1.reducers),
7913            isLoadingFuncs: hooks0.isLoadingFuncs.concat(hooks1.isLoadingFuncs),
7914            contextInit: hooks0.contextInit.concat(hooks1.contextInit),
7915            eventRefiners: Object.assign(Object.assign({}, hooks0.eventRefiners), hooks1.eventRefiners),
7916            eventDefMemberAdders: hooks0.eventDefMemberAdders.concat(hooks1.eventDefMemberAdders),
7917            eventSourceRefiners: Object.assign(Object.assign({}, hooks0.eventSourceRefiners), hooks1.eventSourceRefiners),
7918            isDraggableTransformers: hooks0.isDraggableTransformers.concat(hooks1.isDraggableTransformers),
7919            eventDragMutationMassagers: hooks0.eventDragMutationMassagers.concat(hooks1.eventDragMutationMassagers),
7920            eventDefMutationAppliers: hooks0.eventDefMutationAppliers.concat(hooks1.eventDefMutationAppliers),
7921            dateSelectionTransformers: hooks0.dateSelectionTransformers.concat(hooks1.dateSelectionTransformers),
7922            datePointTransforms: hooks0.datePointTransforms.concat(hooks1.datePointTransforms),
7923            dateSpanTransforms: hooks0.dateSpanTransforms.concat(hooks1.dateSpanTransforms),
7924            views: Object.assign(Object.assign({}, hooks0.views), hooks1.views),
7925            viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers),
7926            isPropsValid: hooks1.isPropsValid || hooks0.isPropsValid,
7927            externalDefTransforms: hooks0.externalDefTransforms.concat(hooks1.externalDefTransforms),
7928            viewContainerAppends: hooks0.viewContainerAppends.concat(hooks1.viewContainerAppends),
7929            eventDropTransformers: hooks0.eventDropTransformers.concat(hooks1.eventDropTransformers),
7930            calendarInteractions: hooks0.calendarInteractions.concat(hooks1.calendarInteractions),
7931            componentInteractions: hooks0.componentInteractions.concat(hooks1.componentInteractions),
7932            themeClasses: Object.assign(Object.assign({}, hooks0.themeClasses), hooks1.themeClasses),
7933            eventSourceDefs: hooks0.eventSourceDefs.concat(hooks1.eventSourceDefs),
7934            cmdFormatter: hooks1.cmdFormatter || hooks0.cmdFormatter,
7935            recurringTypes: hooks0.recurringTypes.concat(hooks1.recurringTypes),
7936            namedTimeZonedImpl: hooks1.namedTimeZonedImpl || hooks0.namedTimeZonedImpl,
7937            initialView: hooks0.initialView || hooks1.initialView,
7938            elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl,
7939            optionChangeHandlers: Object.assign(Object.assign({}, hooks0.optionChangeHandlers), hooks1.optionChangeHandlers),
7940            scrollGridImpl: hooks1.scrollGridImpl || hooks0.scrollGridImpl,
7941            listenerRefiners: Object.assign(Object.assign({}, hooks0.listenerRefiners), hooks1.listenerRefiners),
7942            optionRefiners: Object.assign(Object.assign({}, hooks0.optionRefiners), hooks1.optionRefiners),
7943            propSetHandlers: Object.assign(Object.assign({}, hooks0.propSetHandlers), hooks1.propSetHandlers),
7944        };
7945    }
7946    function compareOptionalDates(date0, date1) {
7947        if (date0 === undefined) {
7948            return date1;
7949        }
7950        if (date1 === undefined) {
7951            return date0;
7952        }
7953        return new Date(Math.max(date0.valueOf(), date1.valueOf()));
7954    }
7955
7956    class StandardTheme extends Theme {
7957    }
7958    StandardTheme.prototype.classes = {
7959        root: 'fc-theme-standard',
7960        tableCellShaded: 'fc-cell-shaded',
7961        buttonGroup: 'fc-button-group',
7962        button: 'fc-button fc-button-primary',
7963        buttonActive: 'fc-button-active',
7964    };
7965    StandardTheme.prototype.baseIconClass = 'fc-icon';
7966    StandardTheme.prototype.iconClasses = {
7967        close: 'fc-icon-x',
7968        prev: 'fc-icon-chevron-left',
7969        next: 'fc-icon-chevron-right',
7970        prevYear: 'fc-icon-chevrons-left',
7971        nextYear: 'fc-icon-chevrons-right',
7972    };
7973    StandardTheme.prototype.rtlIconClasses = {
7974        prev: 'fc-icon-chevron-right',
7975        next: 'fc-icon-chevron-left',
7976        prevYear: 'fc-icon-chevrons-right',
7977        nextYear: 'fc-icon-chevrons-left',
7978    };
7979    StandardTheme.prototype.iconOverrideOption = 'buttonIcons'; // TODO: make TS-friendly
7980    StandardTheme.prototype.iconOverrideCustomButtonOption = 'icon';
7981    StandardTheme.prototype.iconOverridePrefix = 'fc-icon-';
7982
7983    function compileViewDefs(defaultConfigs, overrideConfigs) {
7984        let hash = {};
7985        let viewType;
7986        for (viewType in defaultConfigs) {
7987            ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);
7988        }
7989        for (viewType in overrideConfigs) {
7990            ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);
7991        }
7992        return hash;
7993    }
7994    function ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs) {
7995        if (hash[viewType]) {
7996            return hash[viewType];
7997        }
7998        let viewDef = buildViewDef(viewType, hash, defaultConfigs, overrideConfigs);
7999        if (viewDef) {
8000            hash[viewType] = viewDef;
8001        }
8002        return viewDef;
8003    }
8004    function buildViewDef(viewType, hash, defaultConfigs, overrideConfigs) {
8005        let defaultConfig = defaultConfigs[viewType];
8006        let overrideConfig = overrideConfigs[viewType];
8007        let queryProp = (name) => ((defaultConfig && defaultConfig[name] !== null) ? defaultConfig[name] :
8008            ((overrideConfig && overrideConfig[name] !== null) ? overrideConfig[name] : null));
8009        let theComponent = queryProp('component');
8010        let superType = queryProp('superType');
8011        let superDef = null;
8012        if (superType) {
8013            if (superType === viewType) {
8014                throw new Error('Can\'t have a custom view type that references itself');
8015            }
8016            superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs);
8017        }
8018        if (!theComponent && superDef) {
8019            theComponent = superDef.component;
8020        }
8021        if (!theComponent) {
8022            return null; // don't throw a warning, might be settings for a single-unit view
8023        }
8024        return {
8025            type: viewType,
8026            component: theComponent,
8027            defaults: Object.assign(Object.assign({}, (superDef ? superDef.defaults : {})), (defaultConfig ? defaultConfig.rawOptions : {})),
8028            overrides: Object.assign(Object.assign({}, (superDef ? superDef.overrides : {})), (overrideConfig ? overrideConfig.rawOptions : {})),
8029        };
8030    }
8031
8032    function parseViewConfigs(inputs) {
8033        return mapHash(inputs, parseViewConfig);
8034    }
8035    function parseViewConfig(input) {
8036        let rawOptions = typeof input === 'function' ?
8037            { component: input } :
8038            input;
8039        let { component } = rawOptions;
8040        if (rawOptions.content) {
8041            // TODO: remove content/classNames/didMount/etc from options?
8042            component = createViewHookComponent(rawOptions);
8043        }
8044        else if (component && !(component.prototype instanceof BaseComponent)) {
8045            // WHY?: people were using `component` property for `content`
8046            // TODO: converge on one setting name
8047            component = createViewHookComponent(Object.assign(Object.assign({}, rawOptions), { content: component }));
8048        }
8049        return {
8050            superType: rawOptions.type,
8051            component: component,
8052            rawOptions, // includes type and component too :(
8053        };
8054    }
8055    function createViewHookComponent(options) {
8056        return (viewProps) => (y(ViewContextType.Consumer, null, (context) => (y(ContentContainer, { elTag: "div", elClasses: buildViewClassNames(context.viewSpec), renderProps: Object.assign(Object.assign({}, viewProps), { nextDayThreshold: context.options.nextDayThreshold }), generatorName: undefined, customGenerator: options.content, classNameGenerator: options.classNames, didMount: options.didMount, willUnmount: options.willUnmount }))));
8057    }
8058
8059    function buildViewSpecs(defaultInputs, optionOverrides, dynamicOptionOverrides, localeDefaults) {
8060        let defaultConfigs = parseViewConfigs(defaultInputs);
8061        let overrideConfigs = parseViewConfigs(optionOverrides.views);
8062        let viewDefs = compileViewDefs(defaultConfigs, overrideConfigs);
8063        return mapHash(viewDefs, (viewDef) => buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults));
8064    }
8065    function buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults) {
8066        let durationInput = viewDef.overrides.duration ||
8067            viewDef.defaults.duration ||
8068            dynamicOptionOverrides.duration ||
8069            optionOverrides.duration;
8070        let duration = null;
8071        let durationUnit = '';
8072        let singleUnit = '';
8073        let singleUnitOverrides = {};
8074        if (durationInput) {
8075            duration = createDurationCached(durationInput);
8076            if (duration) { // valid?
8077                let denom = greatestDurationDenominator(duration);
8078                durationUnit = denom.unit;
8079                if (denom.value === 1) {
8080                    singleUnit = durationUnit;
8081                    singleUnitOverrides = overrideConfigs[durationUnit] ? overrideConfigs[durationUnit].rawOptions : {};
8082                }
8083            }
8084        }
8085        let queryButtonText = (optionsSubset) => {
8086            let buttonTextMap = optionsSubset.buttonText || {};
8087            let buttonTextKey = viewDef.defaults.buttonTextKey;
8088            if (buttonTextKey != null && buttonTextMap[buttonTextKey] != null) {
8089                return buttonTextMap[buttonTextKey];
8090            }
8091            if (buttonTextMap[viewDef.type] != null) {
8092                return buttonTextMap[viewDef.type];
8093            }
8094            if (buttonTextMap[singleUnit] != null) {
8095                return buttonTextMap[singleUnit];
8096            }
8097            return null;
8098        };
8099        let queryButtonTitle = (optionsSubset) => {
8100            let buttonHints = optionsSubset.buttonHints || {};
8101            let buttonKey = viewDef.defaults.buttonTextKey; // use same key as text
8102            if (buttonKey != null && buttonHints[buttonKey] != null) {
8103                return buttonHints[buttonKey];
8104            }
8105            if (buttonHints[viewDef.type] != null) {
8106                return buttonHints[viewDef.type];
8107            }
8108            if (buttonHints[singleUnit] != null) {
8109                return buttonHints[singleUnit];
8110            }
8111            return null;
8112        };
8113        return {
8114            type: viewDef.type,
8115            component: viewDef.component,
8116            duration,
8117            durationUnit,
8118            singleUnit,
8119            optionDefaults: viewDef.defaults,
8120            optionOverrides: Object.assign(Object.assign({}, singleUnitOverrides), viewDef.overrides),
8121            buttonTextOverride: queryButtonText(dynamicOptionOverrides) ||
8122                queryButtonText(optionOverrides) || // constructor-specified buttonText lookup hash takes precedence
8123                viewDef.overrides.buttonText,
8124            buttonTextDefault: queryButtonText(localeDefaults) ||
8125                viewDef.defaults.buttonText ||
8126                queryButtonText(BASE_OPTION_DEFAULTS) ||
8127                viewDef.type,
8128            // not DRY
8129            buttonTitleOverride: queryButtonTitle(dynamicOptionOverrides) ||
8130                queryButtonTitle(optionOverrides) ||
8131                viewDef.overrides.buttonHint,
8132            buttonTitleDefault: queryButtonTitle(localeDefaults) ||
8133                viewDef.defaults.buttonHint ||
8134                queryButtonTitle(BASE_OPTION_DEFAULTS),
8135            // will eventually fall back to buttonText
8136        };
8137    }
8138    // hack to get memoization working
8139    let durationInputMap = {};
8140    function createDurationCached(durationInput) {
8141        let json = JSON.stringify(durationInput);
8142        let res = durationInputMap[json];
8143        if (res === undefined) {
8144            res = createDuration(durationInput);
8145            durationInputMap[json] = res;
8146        }
8147        return res;
8148    }
8149
8150    function reduceViewType(viewType, action) {
8151        switch (action.type) {
8152            case 'CHANGE_VIEW_TYPE':
8153                viewType = action.viewType;
8154        }
8155        return viewType;
8156    }
8157
8158    function reduceDynamicOptionOverrides(dynamicOptionOverrides, action) {
8159        switch (action.type) {
8160            case 'SET_OPTION':
8161                return Object.assign(Object.assign({}, dynamicOptionOverrides), { [action.optionName]: action.rawOptionValue });
8162            default:
8163                return dynamicOptionOverrides;
8164        }
8165    }
8166
8167    function reduceDateProfile(currentDateProfile, action, currentDate, dateProfileGenerator) {
8168        let dp;
8169        switch (action.type) {
8170            case 'CHANGE_VIEW_TYPE':
8171                return dateProfileGenerator.build(action.dateMarker || currentDate);
8172            case 'CHANGE_DATE':
8173                return dateProfileGenerator.build(action.dateMarker);
8174            case 'PREV':
8175                dp = dateProfileGenerator.buildPrev(currentDateProfile, currentDate);
8176                if (dp.isValid) {
8177                    return dp;
8178                }
8179                break;
8180            case 'NEXT':
8181                dp = dateProfileGenerator.buildNext(currentDateProfile, currentDate);
8182                if (dp.isValid) {
8183                    return dp;
8184                }
8185                break;
8186        }
8187        return currentDateProfile;
8188    }
8189
8190    function initEventSources(calendarOptions, dateProfile, context) {
8191        let activeRange = dateProfile ? dateProfile.activeRange : null;
8192        return addSources({}, parseInitialSources(calendarOptions, context), activeRange, context);
8193    }
8194    function reduceEventSources(eventSources, action, dateProfile, context) {
8195        let activeRange = dateProfile ? dateProfile.activeRange : null; // need this check?
8196        switch (action.type) {
8197            case 'ADD_EVENT_SOURCES': // already parsed
8198                return addSources(eventSources, action.sources, activeRange, context);
8199            case 'REMOVE_EVENT_SOURCE':
8200                return removeSource(eventSources, action.sourceId);
8201            case 'PREV': // TODO: how do we track all actions that affect dateProfile :(
8202            case 'NEXT':
8203            case 'CHANGE_DATE':
8204            case 'CHANGE_VIEW_TYPE':
8205                if (dateProfile) {
8206                    return fetchDirtySources(eventSources, activeRange, context);
8207                }
8208                return eventSources;
8209            case 'FETCH_EVENT_SOURCES':
8210                return fetchSourcesByIds(eventSources, action.sourceIds ? // why no type?
8211                    arrayToHash(action.sourceIds) :
8212                    excludeStaticSources(eventSources, context), activeRange, action.isRefetch || false, context);
8213            case 'RECEIVE_EVENTS':
8214            case 'RECEIVE_EVENT_ERROR':
8215                return receiveResponse(eventSources, action.sourceId, action.fetchId, action.fetchRange);
8216            case 'REMOVE_ALL_EVENT_SOURCES':
8217                return {};
8218            default:
8219                return eventSources;
8220        }
8221    }
8222    function reduceEventSourcesNewTimeZone(eventSources, dateProfile, context) {
8223        let activeRange = dateProfile ? dateProfile.activeRange : null; // need this check?
8224        return fetchSourcesByIds(eventSources, excludeStaticSources(eventSources, context), activeRange, true, context);
8225    }
8226    function computeEventSourcesLoading(eventSources) {
8227        for (let sourceId in eventSources) {
8228            if (eventSources[sourceId].isFetching) {
8229                return true;
8230            }
8231        }
8232        return false;
8233    }
8234    function addSources(eventSourceHash, sources, fetchRange, context) {
8235        let hash = {};
8236        for (let source of sources) {
8237            hash[source.sourceId] = source;
8238        }
8239        if (fetchRange) {
8240            hash = fetchDirtySources(hash, fetchRange, context);
8241        }
8242        return Object.assign(Object.assign({}, eventSourceHash), hash);
8243    }
8244    function removeSource(eventSourceHash, sourceId) {
8245        return filterHash(eventSourceHash, (eventSource) => eventSource.sourceId !== sourceId);
8246    }
8247    function fetchDirtySources(sourceHash, fetchRange, context) {
8248        return fetchSourcesByIds(sourceHash, filterHash(sourceHash, (eventSource) => isSourceDirty(eventSource, fetchRange, context)), fetchRange, false, context);
8249    }
8250    function isSourceDirty(eventSource, fetchRange, context) {
8251        if (!doesSourceNeedRange(eventSource, context)) {
8252            return !eventSource.latestFetchId;
8253        }
8254        return !context.options.lazyFetching ||
8255            !eventSource.fetchRange ||
8256            eventSource.isFetching || // always cancel outdated in-progress fetches
8257            fetchRange.start < eventSource.fetchRange.start ||
8258            fetchRange.end > eventSource.fetchRange.end;
8259    }
8260    function fetchSourcesByIds(prevSources, sourceIdHash, fetchRange, isRefetch, context) {
8261        let nextSources = {};
8262        for (let sourceId in prevSources) {
8263            let source = prevSources[sourceId];
8264            if (sourceIdHash[sourceId]) {
8265                nextSources[sourceId] = fetchSource(source, fetchRange, isRefetch, context);
8266            }
8267            else {
8268                nextSources[sourceId] = source;
8269            }
8270        }
8271        return nextSources;
8272    }
8273    function fetchSource(eventSource, fetchRange, isRefetch, context) {
8274        let { options, calendarApi } = context;
8275        let sourceDef = context.pluginHooks.eventSourceDefs[eventSource.sourceDefId];
8276        let fetchId = guid();
8277        sourceDef.fetch({
8278            eventSource,
8279            range: fetchRange,
8280            isRefetch,
8281            context,
8282        }, (res) => {
8283            let { rawEvents } = res;
8284            if (options.eventSourceSuccess) {
8285                rawEvents = options.eventSourceSuccess.call(calendarApi, rawEvents, res.response) || rawEvents;
8286            }
8287            if (eventSource.success) {
8288                rawEvents = eventSource.success.call(calendarApi, rawEvents, res.response) || rawEvents;
8289            }
8290            context.dispatch({
8291                type: 'RECEIVE_EVENTS',
8292                sourceId: eventSource.sourceId,
8293                fetchId,
8294                fetchRange,
8295                rawEvents,
8296            });
8297        }, (error) => {
8298            let errorHandled = false;
vendor: 4,583 bytes, lines 8299-8418
8299            if (options.eventSourceFailure) {
8300                options.eventSourceFailure.call(calendarApi, error);
8301                errorHandled = true;
8302            }
8303            if (eventSource.failure) {
8304                eventSource.failure(error);
8305                errorHandled = true;
8306            }
8307            if (!errorHandled) {
8308                console.warn(error.message, error);
8309            }
8310            context.dispatch({
8311                type: 'RECEIVE_EVENT_ERROR',
8312                sourceId: eventSource.sourceId,
8313                fetchId,
8314                fetchRange,
8315                error,
8316            });
8317        });
8318        return Object.assign(Object.assign({}, eventSource), { isFetching: true, latestFetchId: fetchId });
8319    }
8320    function receiveResponse(sourceHash, sourceId, fetchId, fetchRange) {
8321        let eventSource = sourceHash[sourceId];
8322        if (eventSource && // not already removed
8323            fetchId === eventSource.latestFetchId) {
8324            return Object.assign(Object.assign({}, sourceHash), { [sourceId]: Object.assign(Object.assign({}, eventSource), { isFetching: false, fetchRange }) });
8325        }
8326        return sourceHash;
8327    }
8328    function excludeStaticSources(eventSources, context) {
8329        return filterHash(eventSources, (eventSource) => doesSourceNeedRange(eventSource, context));
8330    }
8331    function parseInitialSources(rawOptions, context) {
8332        let refiners = buildEventSourceRefiners(context);
8333        let rawSources = [].concat(rawOptions.eventSources || []);
8334        let sources = []; // parsed
8335        if (rawOptions.initialEvents) {
8336            rawSources.unshift(rawOptions.initialEvents);
8337        }
8338        if (rawOptions.events) {
8339            rawSources.unshift(rawOptions.events);
8340        }
8341        for (let rawSource of rawSources) {
8342            let source = parseEventSource(rawSource, context, refiners);
8343            if (source) {
8344                sources.push(source);
8345            }
8346        }
8347        return sources;
8348    }
8349    function doesSourceNeedRange(eventSource, context) {
8350        let defs = context.pluginHooks.eventSourceDefs;
8351        return !defs[eventSource.sourceDefId].ignoreRange;
8352    }
8353
8354    function reduceDateSelection(currentSelection, action) {
8355        switch (action.type) {
8356            case 'UNSELECT_DATES':
8357                return null;
8358            case 'SELECT_DATES':
8359                return action.selection;
8360            default:
8361                return currentSelection;
8362        }
8363    }
8364
8365    function reduceSelectedEvent(currentInstanceId, action) {
8366        switch (action.type) {
8367            case 'UNSELECT_EVENT':
8368                return '';
8369            case 'SELECT_EVENT':
8370                return action.eventInstanceId;
8371            default:
8372                return currentInstanceId;
8373        }
8374    }
8375
8376    function reduceEventDrag(currentDrag, action) {
8377        let newDrag;
8378        switch (action.type) {
8379            case 'UNSET_EVENT_DRAG':
8380                return null;
8381            case 'SET_EVENT_DRAG':
8382                newDrag = action.state;
8383                return {
8384                    affectedEvents: newDrag.affectedEvents,
8385                    mutatedEvents: newDrag.mutatedEvents,
8386                    isEvent: newDrag.isEvent,
8387                };
8388            default:
8389                return currentDrag;
8390        }
8391    }
8392
8393    function reduceEventResize(currentResize, action) {
8394        let newResize;
8395        switch (action.type) {
8396            case 'UNSET_EVENT_RESIZE':
8397                return null;
8398            case 'SET_EVENT_RESIZE':
8399                newResize = action.state;
8400                return {
8401                    affectedEvents: newResize.affectedEvents,
8402                    mutatedEvents: newResize.mutatedEvents,
8403                    isEvent: newResize.isEvent,
8404                };
8405            default:
8406                return currentResize;
8407        }
8408    }
8409
8410    function parseToolbars(calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {
8411        let header = calendarOptions.headerToolbar ? parseToolbar(calendarOptions.headerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;
8412        let footer = calendarOptions.footerToolbar ? parseToolbar(calendarOptions.footerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;
8413        return { header, footer };
8414    }
8415    function parseToolbar(sectionStrHash, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {
8416        let sectionWidgets = {};
8417        let viewsWithButtons = [];
8418        let hasTitle = false;
vendor: 60,628 bytes, lines 8419-9693
8419        for (let sectionName in sectionStrHash) {
8420            let sectionStr = sectionStrHash[sectionName];
8421            let sectionRes = parseSection(sectionStr, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi);
8422            sectionWidgets[sectionName] = sectionRes.widgets;
8423            viewsWithButtons.push(...sectionRes.viewsWithButtons);
8424            hasTitle = hasTitle || sectionRes.hasTitle;
8425        }
8426        return { sectionWidgets, viewsWithButtons, hasTitle };
8427    }
8428    /*
8429    BAD: querying icons and text here. should be done at render time
8430    */
8431    function parseSection(sectionStr, calendarOptions, // defaults+overrides, then refined
8432                          calendarOptionOverrides, // overrides only!, unrefined :(
8433                          theme, viewSpecs, calendarApi) {
8434        let isRtl = calendarOptions.direction === 'rtl';
8435        let calendarCustomButtons = calendarOptions.customButtons || {};
8436        let calendarButtonTextOverrides = calendarOptionOverrides.buttonText || {};
8437        let calendarButtonText = calendarOptions.buttonText || {};
8438        let calendarButtonHintOverrides = calendarOptionOverrides.buttonHints || {};
8439        let calendarButtonHints = calendarOptions.buttonHints || {};
8440        let sectionSubstrs = sectionStr ? sectionStr.split(' ') : [];
8441        let viewsWithButtons = [];
8442        let hasTitle = false;
8443        let widgets = sectionSubstrs.map((buttonGroupStr) => (buttonGroupStr.split(',').map((buttonName) => {
8444            if (buttonName === 'title') {
8445                hasTitle = true;
8446                return { buttonName };
8447            }
8448            let customButtonProps;
8449            let viewSpec;
8450            let buttonClick;
8451            let buttonIcon; // only one of these will be set
8452            let buttonText; // "
8453            let buttonHint;
8454            // ^ for the title="" attribute, for accessibility
8455            if ((customButtonProps = calendarCustomButtons[buttonName])) {
8456                buttonClick = (ev) => {
8457                    if (customButtonProps.click) {
8458                        customButtonProps.click.call(ev.target, ev, ev.target); // TODO: use Calendar this context?
8459                    }
8460                };
8461                (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) ||
8462                (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
8463                (buttonText = customButtonProps.text);
8464                buttonHint = customButtonProps.hint || customButtonProps.text;
8465            }
8466            else if ((viewSpec = viewSpecs[buttonName])) {
8467                viewsWithButtons.push(buttonName);
8468                buttonClick = () => {
8469                    calendarApi.changeView(buttonName);
8470                };
8471                (buttonText = viewSpec.buttonTextOverride) ||
8472                (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
8473                (buttonText = viewSpec.buttonTextDefault);
8474                let textFallback = viewSpec.buttonTextOverride ||
8475                    viewSpec.buttonTextDefault;
8476                buttonHint = formatWithOrdinals(viewSpec.buttonTitleOverride ||
8477                    viewSpec.buttonTitleDefault ||
8478                    calendarOptions.viewHint, [textFallback, buttonName], // view-name = buttonName
8479                    textFallback);
8480            }
8481            else if (calendarApi[buttonName]) { // a calendarApi method
8482                buttonClick = () => {
8483                    calendarApi[buttonName]();
8484                };
8485                (buttonText = calendarButtonTextOverrides[buttonName]) ||
8486                (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
8487                (buttonText = calendarButtonText[buttonName]); // everything else is considered default
8488                if (buttonName === 'prevYear' || buttonName === 'nextYear') {
8489                    let prevOrNext = buttonName === 'prevYear' ? 'prev' : 'next';
8490                    buttonHint = formatWithOrdinals(calendarButtonHintOverrides[prevOrNext] ||
8491                        calendarButtonHints[prevOrNext], [
8492                        calendarButtonText.year || 'year',
8493                        'year',
8494                    ], calendarButtonText[buttonName]);
8495                }
8496                else {
8497                    buttonHint = (navUnit) => formatWithOrdinals(calendarButtonHintOverrides[buttonName] ||
8498                        calendarButtonHints[buttonName], [
8499                        calendarButtonText[navUnit] || navUnit,
8500                        navUnit,
8501                    ], calendarButtonText[buttonName]);
8502                }
8503            }
8504            return { buttonName, buttonClick, buttonIcon, buttonText, buttonHint };
8505        })));
8506        return { widgets, viewsWithButtons, hasTitle };
8507    }
8508
8509    // always represents the current view. otherwise, it'd need to change value every time date changes
8510    class ViewImpl {
8511        constructor(type, getCurrentData, dateEnv) {
8512            this.type = type;
8513            this.getCurrentData = getCurrentData;
8514            this.dateEnv = dateEnv;
8515        }
8516        get calendar() {
8517            return this.getCurrentData().calendarApi;
8518        }
8519        get title() {
8520            return this.getCurrentData().viewTitle;
8521        }
8522        get activeStart() {
8523            return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.start);
8524        }
8525        get activeEnd() {
8526            return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.end);
8527        }
8528        get currentStart() {
8529            return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.start);
8530        }
8531        get currentEnd() {
8532            return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.end);
8533        }
8534        getOption(name) {
8535            return this.getCurrentData().options[name]; // are the view-specific options
8536        }
8537    }
8538
8539    let eventSourceDef$2 = {
8540        ignoreRange: true,
8541        parseMeta(refined) {
8542            if (Array.isArray(refined.events)) {
8543                return refined.events;
8544            }
8545            return null;
8546        },
8547        fetch(arg, successCallback) {
8548            successCallback({
8549                rawEvents: arg.eventSource.meta,
8550            });
8551        },
8552    };
8553    const arrayEventSourcePlugin = createPlugin({
8554        name: 'array-event-source',
8555        eventSourceDefs: [eventSourceDef$2],
8556    });
8557
8558    let eventSourceDef$1 = {
8559        parseMeta(refined) {
8560            if (typeof refined.events === 'function') {
8561                return refined.events;
8562            }
8563            return null;
8564        },
8565        fetch(arg, successCallback, errorCallback) {
8566            const { dateEnv } = arg.context;
8567            const func = arg.eventSource.meta;
8568            unpromisify(func.bind(null, buildRangeApiWithTimeZone(arg.range, dateEnv)), (rawEvents) => successCallback({ rawEvents }), errorCallback);
8569        },
8570    };
8571    const funcEventSourcePlugin = createPlugin({
8572        name: 'func-event-source',
8573        eventSourceDefs: [eventSourceDef$1],
8574    });
8575
8576    const JSON_FEED_EVENT_SOURCE_REFINERS = {
8577        method: String,
8578        extraParams: identity,
8579        startParam: String,
8580        endParam: String,
8581        timeZoneParam: String,
8582    };
8583
8584    let eventSourceDef = {
8585        parseMeta(refined) {
8586            if (refined.url && (refined.format === 'json' || !refined.format)) {
8587                return {
8588                    url: refined.url,
8589                    format: 'json',
8590                    method: (refined.method || 'GET').toUpperCase(),
8591                    extraParams: refined.extraParams,
8592                    startParam: refined.startParam,
8593                    endParam: refined.endParam,
8594                    timeZoneParam: refined.timeZoneParam,
8595                };
8596            }
8597            return null;
8598        },
8599        fetch(arg, successCallback, errorCallback) {
8600            const { meta } = arg.eventSource;
8601            const requestParams = buildRequestParams(meta, arg.range, arg.context);
8602            requestJson(meta.method, meta.url, requestParams).then(([rawEvents, response]) => {
8603                successCallback({ rawEvents, response });
8604            }, errorCallback);
8605        },
8606    };
8607    const jsonFeedEventSourcePlugin = createPlugin({
8608        name: 'json-event-source',
8609        eventSourceRefiners: JSON_FEED_EVENT_SOURCE_REFINERS,
8610        eventSourceDefs: [eventSourceDef],
8611    });
8612    function buildRequestParams(meta, range, context) {
8613        let { dateEnv, options } = context;
8614        let startParam;
8615        let endParam;
8616        let timeZoneParam;
8617        let customRequestParams;
8618        let params = {};
8619        startParam = meta.startParam;
8620        if (startParam == null) {
8621            startParam = options.startParam;
8622        }
8623        endParam = meta.endParam;
8624        if (endParam == null) {
8625            endParam = options.endParam;
8626        }
8627        timeZoneParam = meta.timeZoneParam;
8628        if (timeZoneParam == null) {
8629            timeZoneParam = options.timeZoneParam;
8630        }
8631        // retrieve any outbound GET/POST data from the options
8632        if (typeof meta.extraParams === 'function') {
8633            // supplied as a function that returns a key/value object
8634            customRequestParams = meta.extraParams();
8635        }
8636        else {
8637            // probably supplied as a straight key/value object
8638            customRequestParams = meta.extraParams || {};
8639        }
8640        Object.assign(params, customRequestParams);
8641        params[startParam] = dateEnv.formatIso(range.start);
8642        params[endParam] = dateEnv.formatIso(range.end);
8643        if (dateEnv.timeZone !== 'local') {
8644            params[timeZoneParam] = dateEnv.timeZone;
8645        }
8646        return params;
8647    }
8648
8649    const SIMPLE_RECURRING_REFINERS = {
8650        daysOfWeek: identity,
8651        startTime: createDuration,
8652        endTime: createDuration,
8653        duration: createDuration,
8654        startRecur: identity,
8655        endRecur: identity,
8656    };
8657
8658    let recurring = {
8659        parse(refined, dateEnv) {
8660            if (refined.daysOfWeek || refined.startTime || refined.endTime || refined.startRecur || refined.endRecur) {
8661                let recurringData = {
8662                    daysOfWeek: refined.daysOfWeek || null,
8663                    startTime: refined.startTime || null,
8664                    endTime: refined.endTime || null,
8665                    startRecur: refined.startRecur ? dateEnv.createMarker(refined.startRecur) : null,
8666                    endRecur: refined.endRecur ? dateEnv.createMarker(refined.endRecur) : null,
8667                };
8668                let duration;
8669                if (refined.duration) {
8670                    duration = refined.duration;
8671                }
8672                if (!duration && refined.startTime && refined.endTime) {
8673                    duration = subtractDurations(refined.endTime, refined.startTime);
8674                }
8675                return {
8676                    allDayGuess: Boolean(!refined.startTime && !refined.endTime),
8677                    duration,
8678                    typeData: recurringData, // doesn't need endTime anymore but oh well
8679                };
8680            }
8681            return null;
8682        },
8683        expand(typeData, framingRange, dateEnv) {
8684            let clippedFramingRange = intersectRanges(framingRange, { start: typeData.startRecur, end: typeData.endRecur });
8685            if (clippedFramingRange) {
8686                return expandRanges(typeData.daysOfWeek, typeData.startTime, clippedFramingRange, dateEnv);
8687            }
8688            return [];
8689        },
8690    };
8691    const simpleRecurringEventsPlugin = createPlugin({
8692        name: 'simple-recurring-event',
8693        recurringTypes: [recurring],
8694        eventRefiners: SIMPLE_RECURRING_REFINERS,
8695    });
8696    function expandRanges(daysOfWeek, startTime, framingRange, dateEnv) {
8697        let dowHash = daysOfWeek ? arrayToHash(daysOfWeek) : null;
8698        let dayMarker = startOfDay(framingRange.start);
8699        let endMarker = framingRange.end;
8700        let instanceStarts = [];
8701        while (dayMarker < endMarker) {
8702            let instanceStart;
8703            // if everyday, or this particular day-of-week
8704            if (!dowHash || dowHash[dayMarker.getUTCDay()]) {
8705                if (startTime) {
8706                    instanceStart = dateEnv.add(dayMarker, startTime);
8707                }
8708                else {
8709                    instanceStart = dayMarker;
8710                }
8711                instanceStarts.push(instanceStart);
8712            }
8713            dayMarker = addDays(dayMarker, 1);
8714        }
8715        return instanceStarts;
8716    }
8717
8718    const changeHandlerPlugin = createPlugin({
8719        name: 'change-handler',
8720        optionChangeHandlers: {
8721            events(events, context) {
8722                handleEventSources([events], context);
8723            },
8724            eventSources: handleEventSources,
8725        },
8726    });
8727    /*
8728    BUG: if `event` was supplied, all previously-given `eventSources` will be wiped out
8729    */
8730    function handleEventSources(inputs, context) {
8731        let unfoundSources = hashValuesToArray(context.getCurrentData().eventSources);
8732        if (unfoundSources.length === 1 &&
8733            inputs.length === 1 &&
8734            Array.isArray(unfoundSources[0]._raw) &&
8735            Array.isArray(inputs[0])) {
8736            context.dispatch({
8737                type: 'RESET_RAW_EVENTS',
8738                sourceId: unfoundSources[0].sourceId,
8739                rawEvents: inputs[0],
8740            });
8741            return;
8742        }
8743        let newInputs = [];
8744        for (let input of inputs) {
8745            let inputFound = false;
8746            for (let i = 0; i < unfoundSources.length; i += 1) {
8747                if (unfoundSources[i]._raw === input) {
8748                    unfoundSources.splice(i, 1); // delete
8749                    inputFound = true;
8750                    break;
8751                }
8752            }
8753            if (!inputFound) {
8754                newInputs.push(input);
8755            }
8756        }
8757        for (let unfoundSource of unfoundSources) {
8758            context.dispatch({
8759                type: 'REMOVE_EVENT_SOURCE',
8760                sourceId: unfoundSource.sourceId,
8761            });
8762        }
8763        for (let newInput of newInputs) {
8764            context.calendarApi.addEventSource(newInput);
8765        }
8766    }
8767
8768    function handleDateProfile(dateProfile, context) {
8769        context.emitter.trigger('datesSet', Object.assign(Object.assign({}, buildRangeApiWithTimeZone(dateProfile.activeRange, context.dateEnv)), { view: context.viewApi }));
8770    }
8771
8772    function handleEventStore(eventStore, context) {
8773        let { emitter } = context;
8774        if (emitter.hasHandlers('eventsSet')) {
8775            emitter.trigger('eventsSet', buildEventApis(eventStore, context));
8776        }
8777    }
8778
8779    /*
8780    this array is exposed on the root namespace so that UMD plugins can add to it.
8781    see the rollup-bundles script.
8782    */
8783    const globalPlugins = [
8784        arrayEventSourcePlugin,
8785        funcEventSourcePlugin,
8786        jsonFeedEventSourcePlugin,
8787        simpleRecurringEventsPlugin,
8788        changeHandlerPlugin,
8789        createPlugin({
8790            name: 'misc',
8791            isLoadingFuncs: [
8792                (state) => computeEventSourcesLoading(state.eventSources),
8793            ],
8794            propSetHandlers: {
8795                dateProfile: handleDateProfile,
8796                eventStore: handleEventStore,
8797            },
8798        }),
8799    ];
8800
8801    class TaskRunner {
8802        constructor(runTaskOption, drainedOption) {
8803            this.runTaskOption = runTaskOption;
8804            this.drainedOption = drainedOption;
8805            this.queue = [];
8806            this.delayedRunner = new DelayedRunner(this.drain.bind(this));
8807        }
8808        request(task, delay) {
8809            this.queue.push(task);
8810            this.delayedRunner.request(delay);
8811        }
8812        pause(scope) {
8813            this.delayedRunner.pause(scope);
8814        }
8815        resume(scope, force) {
8816            this.delayedRunner.resume(scope, force);
8817        }
8818        drain() {
8819            let { queue } = this;
8820            while (queue.length) {
8821                let completedTasks = [];
8822                let task;
8823                while ((task = queue.shift())) {
8824                    this.runTask(task);
8825                    completedTasks.push(task);
8826                }
8827                this.drained(completedTasks);
8828            } // keep going, in case new tasks were added in the drained handler
8829        }
8830        runTask(task) {
8831            if (this.runTaskOption) {
8832                this.runTaskOption(task);
8833            }
8834        }
8835        drained(completedTasks) {
8836            if (this.drainedOption) {
8837                this.drainedOption(completedTasks);
8838            }
8839        }
8840    }
8841
8842    // Computes what the title at the top of the calendarApi should be for this view
8843    function buildTitle(dateProfile, viewOptions, dateEnv) {
8844        let range;
8845        // for views that span a large unit of time, show the proper interval, ignoring stray days before and after
8846        if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) {
8847            range = dateProfile.currentRange;
8848        }
8849        else { // for day units or smaller, use the actual day range
8850            range = dateProfile.activeRange;
8851        }
8852        return dateEnv.formatRange(range.start, range.end, createFormatter(viewOptions.titleFormat || buildTitleFormat(dateProfile)), {
8853            isEndExclusive: dateProfile.isRangeAllDay,
8854            defaultSeparator: viewOptions.titleRangeSeparator,
8855        });
8856    }
8857    // Generates the format string that should be used to generate the title for the current date range.
8858    // Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`.
8859    function buildTitleFormat(dateProfile) {
8860        let { currentRangeUnit } = dateProfile;
8861        if (currentRangeUnit === 'year') {
8862            return { year: 'numeric' };
8863        }
8864        if (currentRangeUnit === 'month') {
8865            return { year: 'numeric', month: 'long' }; // like "September 2014"
8866        }
8867        let days = diffWholeDays(dateProfile.currentRange.start, dateProfile.currentRange.end);
8868        if (days !== null && days > 1) {
8869            // multi-day range. shorter, like "Sep 9 - 10 2014"
8870            return { year: 'numeric', month: 'short', day: 'numeric' };
8871        }
8872        // one day. longer, like "September 9 2014"
8873        return { year: 'numeric', month: 'long', day: 'numeric' };
8874    }
8875
8876    // in future refactor, do the redux-style function(state=initial) for initial-state
8877    // also, whatever is happening in constructor, have it happen in action queue too
8878    class CalendarDataManager {
8879        constructor(props) {
8880            this.computeCurrentViewData = memoize(this._computeCurrentViewData);
8881            this.organizeRawLocales = memoize(organizeRawLocales);
8882            this.buildLocale = memoize(buildLocale);
8883            this.buildPluginHooks = buildBuildPluginHooks();
8884            this.buildDateEnv = memoize(buildDateEnv$1);
8885            this.buildTheme = memoize(buildTheme);
8886            this.parseToolbars = memoize(parseToolbars);
8887            this.buildViewSpecs = memoize(buildViewSpecs);
8888            this.buildDateProfileGenerator = memoizeObjArg(buildDateProfileGenerator);
8889            this.buildViewApi = memoize(buildViewApi);
8890            this.buildViewUiProps = memoizeObjArg(buildViewUiProps);
8891            this.buildEventUiBySource = memoize(buildEventUiBySource, isPropsEqual);
8892            this.buildEventUiBases = memoize(buildEventUiBases);
8893            this.parseContextBusinessHours = memoizeObjArg(parseContextBusinessHours);
8894            this.buildTitle = memoize(buildTitle);
8895            this.emitter = new Emitter();
8896            this.actionRunner = new TaskRunner(this._handleAction.bind(this), this.updateData.bind(this));
8897            this.currentCalendarOptionsInput = {};
8898            this.currentCalendarOptionsRefined = {};
8899            this.currentViewOptionsInput = {};
8900            this.currentViewOptionsRefined = {};
8901            this.currentCalendarOptionsRefiners = {};
8902            this.optionsForRefining = [];
8903            this.optionsForHandling = [];
8904            this.getCurrentData = () => this.data;
8905            this.dispatch = (action) => {
8906                this.actionRunner.request(action); // protects against recursive calls to _handleAction
8907            };
8908            this.props = props;
8909            this.actionRunner.pause();
8910            let dynamicOptionOverrides = {};
8911            let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
8912            let currentViewType = optionsData.calendarOptions.initialView || optionsData.pluginHooks.initialView;
8913            let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
8914            // wire things up
8915            // TODO: not DRY
8916            props.calendarApi.currentDataManager = this;
8917            this.emitter.setThisContext(props.calendarApi);
8918            this.emitter.setOptions(currentViewData.options);
8919            let currentDate = getInitialDate(optionsData.calendarOptions, optionsData.dateEnv);
8920            let dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
8921            if (!rangeContainsMarker(dateProfile.activeRange, currentDate)) {
8922                currentDate = dateProfile.currentRange.start;
8923            }
8924            let calendarContext = {
8925                dateEnv: optionsData.dateEnv,
8926                options: optionsData.calendarOptions,
8927                pluginHooks: optionsData.pluginHooks,
8928                calendarApi: props.calendarApi,
8929                dispatch: this.dispatch,
8930                emitter: this.emitter,
8931                getCurrentData: this.getCurrentData,
8932            };
8933            // needs to be after setThisContext
8934            for (let callback of optionsData.pluginHooks.contextInit) {
8935                callback(calendarContext);
8936            }
8937            // NOT DRY
8938            let eventSources = initEventSources(optionsData.calendarOptions, dateProfile, calendarContext);
8939            let initialState = {
8940                dynamicOptionOverrides,
8941                currentViewType,
8942                currentDate,
8943                dateProfile,
8944                businessHours: this.parseContextBusinessHours(calendarContext),
8945                eventSources,
8946                eventUiBases: {},
8947                eventStore: createEmptyEventStore(),
8948                renderableEventStore: createEmptyEventStore(),
8949                dateSelection: null,
8950                eventSelection: '',
8951                eventDrag: null,
8952                eventResize: null,
8953                selectionConfig: this.buildViewUiProps(calendarContext).selectionConfig,
8954            };
8955            let contextAndState = Object.assign(Object.assign({}, calendarContext), initialState);
8956            for (let reducer of optionsData.pluginHooks.reducers) {
8957                Object.assign(initialState, reducer(null, null, contextAndState));
8958            }
8959            if (computeIsLoading(initialState, calendarContext)) {
8960                this.emitter.trigger('loading', true); // NOT DRY
8961            }
8962            this.state = initialState;
8963            this.updateData();
8964            this.actionRunner.resume();
8965        }
8966        resetOptions(optionOverrides, changedOptionNames) {
8967            let { props } = this;
8968            if (changedOptionNames === undefined) {
8969                props.optionOverrides = optionOverrides;
8970            }
8971            else {
8972                props.optionOverrides = Object.assign(Object.assign({}, (props.optionOverrides || {})), optionOverrides);
8973                this.optionsForRefining.push(...changedOptionNames);
8974            }
8975            if (changedOptionNames === undefined || changedOptionNames.length) {
8976                this.actionRunner.request({
8977                    type: 'NOTHING',
8978                });
8979            }
8980        }
8981        _handleAction(action) {
8982            let { props, state, emitter } = this;
8983            let dynamicOptionOverrides = reduceDynamicOptionOverrides(state.dynamicOptionOverrides, action);
8984            let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
8985            let currentViewType = reduceViewType(state.currentViewType, action);
8986            let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
8987            // wire things up
8988            // TODO: not DRY
8989            props.calendarApi.currentDataManager = this;
8990            emitter.setThisContext(props.calendarApi);
8991            emitter.setOptions(currentViewData.options);
8992            let calendarContext = {
8993                dateEnv: optionsData.dateEnv,
8994                options: optionsData.calendarOptions,
8995                pluginHooks: optionsData.pluginHooks,
8996                calendarApi: props.calendarApi,
8997                dispatch: this.dispatch,
8998                emitter,
8999                getCurrentData: this.getCurrentData,
9000            };
9001            let { currentDate, dateProfile } = state;
9002            if (this.data && this.data.dateProfileGenerator !== currentViewData.dateProfileGenerator) { // hack
9003                dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
9004            }
9005            currentDate = reduceCurrentDate(currentDate, action);
9006            dateProfile = reduceDateProfile(dateProfile, action, currentDate, currentViewData.dateProfileGenerator);
9007            if (action.type === 'PREV' || // TODO: move this logic into DateProfileGenerator
9008                action.type === 'NEXT' || // "
9009                !rangeContainsMarker(dateProfile.currentRange, currentDate)) {
9010                currentDate = dateProfile.currentRange.start;
9011            }
9012            let eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendarContext);
9013            let eventStore = reduceEventStore(state.eventStore, action, eventSources, dateProfile, calendarContext);
9014            let isEventsLoading = computeEventSourcesLoading(eventSources); // BAD. also called in this func in computeIsLoading
9015            let renderableEventStore = (isEventsLoading && !currentViewData.options.progressiveEventRendering) ?
9016                (state.renderableEventStore || eventStore) : // try from previous state
9017                eventStore;
9018            let { eventUiSingleBase, selectionConfig } = this.buildViewUiProps(calendarContext); // will memoize obj
9019            let eventUiBySource = this.buildEventUiBySource(eventSources);
9020            let eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource);
9021            let newState = {
9022                dynamicOptionOverrides,
9023                currentViewType,
9024                currentDate,
9025                dateProfile,
9026                eventSources,
9027                eventStore,
9028                renderableEventStore,
9029                selectionConfig,
9030                eventUiBases,
9031                businessHours: this.parseContextBusinessHours(calendarContext),
9032                dateSelection: reduceDateSelection(state.dateSelection, action),
9033                eventSelection: reduceSelectedEvent(state.eventSelection, action),
9034                eventDrag: reduceEventDrag(state.eventDrag, action),
9035                eventResize: reduceEventResize(state.eventResize, action),
9036            };
9037            let contextAndState = Object.assign(Object.assign({}, calendarContext), newState);
9038            for (let reducer of optionsData.pluginHooks.reducers) {
9039                Object.assign(newState, reducer(state, action, contextAndState)); // give the OLD state, for old value
9040            }
9041            let wasLoading = computeIsLoading(state, calendarContext);
9042            let isLoading = computeIsLoading(newState, calendarContext);
9043            // TODO: use propSetHandlers in plugin system
9044            if (!wasLoading && isLoading) {
9045                emitter.trigger('loading', true);
9046            }
9047            else if (wasLoading && !isLoading) {
9048                emitter.trigger('loading', false);
9049            }
9050            this.state = newState;
9051            if (props.onAction) {
9052                props.onAction(action);
9053            }
9054        }
9055        updateData() {
9056            let { props, state } = this;
9057            let oldData = this.data;
9058            let optionsData = this.computeOptionsData(props.optionOverrides, state.dynamicOptionOverrides, props.calendarApi);
9059            let currentViewData = this.computeCurrentViewData(state.currentViewType, optionsData, props.optionOverrides, state.dynamicOptionOverrides);
9060            let data = this.data = Object.assign(Object.assign(Object.assign({ viewTitle: this.buildTitle(state.dateProfile, currentViewData.options, optionsData.dateEnv), calendarApi: props.calendarApi, dispatch: this.dispatch, emitter: this.emitter, getCurrentData: this.getCurrentData }, optionsData), currentViewData), state);
9061            let changeHandlers = optionsData.pluginHooks.optionChangeHandlers;
9062            let oldCalendarOptions = oldData && oldData.calendarOptions;
9063            let newCalendarOptions = optionsData.calendarOptions;
9064            if (oldCalendarOptions && oldCalendarOptions !== newCalendarOptions) {
9065                if (oldCalendarOptions.timeZone !== newCalendarOptions.timeZone) {
9066                    // hack
9067                    state.eventSources = data.eventSources = reduceEventSourcesNewTimeZone(data.eventSources, state.dateProfile, data);
9068                    state.eventStore = data.eventStore = rezoneEventStoreDates(data.eventStore, oldData.dateEnv, data.dateEnv);
9069                    state.renderableEventStore = data.renderableEventStore = rezoneEventStoreDates(data.renderableEventStore, oldData.dateEnv, data.dateEnv);
9070                }
9071                for (let optionName in changeHandlers) {
9072                    if (this.optionsForHandling.indexOf(optionName) !== -1 ||
9073                        oldCalendarOptions[optionName] !== newCalendarOptions[optionName]) {
9074                        changeHandlers[optionName](newCalendarOptions[optionName], data);
9075                    }
9076                }
9077            }
9078            this.optionsForHandling = [];
9079            if (props.onData) {
9080                props.onData(data);
9081            }
9082        }
9083        computeOptionsData(optionOverrides, dynamicOptionOverrides, calendarApi) {
9084            // TODO: blacklist options that are handled by optionChangeHandlers
9085            if (!this.optionsForRefining.length &&
9086                optionOverrides === this.stableOptionOverrides &&
9087                dynamicOptionOverrides === this.stableDynamicOptionOverrides) {
9088                return this.stableCalendarOptionsData;
9089            }
9090            let { refinedOptions, pluginHooks, localeDefaults, availableLocaleData, extra, } = this.processRawCalendarOptions(optionOverrides, dynamicOptionOverrides);
9091            warnUnknownOptions(extra);
9092            let dateEnv = this.buildDateEnv(refinedOptions.timeZone, refinedOptions.locale, refinedOptions.weekNumberCalculation, refinedOptions.firstDay, refinedOptions.weekText, pluginHooks, availableLocaleData, refinedOptions.defaultRangeSeparator);
9093            let viewSpecs = this.buildViewSpecs(pluginHooks.views, this.stableOptionOverrides, this.stableDynamicOptionOverrides, localeDefaults);
9094            let theme = this.buildTheme(refinedOptions, pluginHooks);
9095            let toolbarConfig = this.parseToolbars(refinedOptions, this.stableOptionOverrides, theme, viewSpecs, calendarApi);
9096            return this.stableCalendarOptionsData = {
9097                calendarOptions: refinedOptions,
9098                pluginHooks,
9099                dateEnv,
9100                viewSpecs,
9101                theme,
9102                toolbarConfig,
9103                localeDefaults,
9104                availableRawLocales: availableLocaleData.map,
9105            };
9106        }
9107        // always called from behind a memoizer
9108        processRawCalendarOptions(optionOverrides, dynamicOptionOverrides) {
9109            let { locales, locale } = mergeRawOptions([
9110                BASE_OPTION_DEFAULTS,
9111                optionOverrides,
9112                dynamicOptionOverrides,
9113            ]);
9114            let availableLocaleData = this.organizeRawLocales(locales);
9115            let availableRawLocales = availableLocaleData.map;
9116            let localeDefaults = this.buildLocale(locale || availableLocaleData.defaultCode, availableRawLocales).options;
9117            let pluginHooks = this.buildPluginHooks(optionOverrides.plugins || [], globalPlugins);
9118            let refiners = this.currentCalendarOptionsRefiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
9119            let extra = {};
9120            let raw = mergeRawOptions([
9121                BASE_OPTION_DEFAULTS,
9122                localeDefaults,
9123                optionOverrides,
9124                dynamicOptionOverrides,
9125            ]);
9126            let refined = {};
9127            let currentRaw = this.currentCalendarOptionsInput;
9128            let currentRefined = this.currentCalendarOptionsRefined;
9129            let anyChanges = false;
9130            for (let optionName in raw) {
9131                if (this.optionsForRefining.indexOf(optionName) === -1 && (raw[optionName] === currentRaw[optionName] || (COMPLEX_OPTION_COMPARATORS[optionName] &&
9132                    (optionName in currentRaw) &&
9133                    COMPLEX_OPTION_COMPARATORS[optionName](currentRaw[optionName], raw[optionName])))) {
9134                    refined[optionName] = currentRefined[optionName];
9135                }
9136                else if (refiners[optionName]) {
9137                    refined[optionName] = refiners[optionName](raw[optionName]);
9138                    anyChanges = true;
9139                }
9140                else {
9141                    extra[optionName] = currentRaw[optionName];
9142                }
9143            }
9144            if (anyChanges) {
9145                this.currentCalendarOptionsInput = raw;
9146                this.currentCalendarOptionsRefined = refined;
9147                this.stableOptionOverrides = optionOverrides;
9148                this.stableDynamicOptionOverrides = dynamicOptionOverrides;
9149            }
9150            this.optionsForHandling.push(...this.optionsForRefining);
9151            this.optionsForRefining = [];
9152            return {
9153                rawOptions: this.currentCalendarOptionsInput,
9154                refinedOptions: this.currentCalendarOptionsRefined,
9155                pluginHooks,
9156                availableLocaleData,
9157                localeDefaults,
9158                extra,
9159            };
9160        }
9161        _computeCurrentViewData(viewType, optionsData, optionOverrides, dynamicOptionOverrides) {
9162            let viewSpec = optionsData.viewSpecs[viewType];
9163            if (!viewSpec) {
9164                throw new Error(`viewType "${viewType}" is not available. Please make sure you've loaded all neccessary plugins`);
9165            }
9166            let { refinedOptions, extra } = this.processRawViewOptions(viewSpec, optionsData.pluginHooks, optionsData.localeDefaults, optionOverrides, dynamicOptionOverrides);
9167            warnUnknownOptions(extra);
9168            let dateProfileGenerator = this.buildDateProfileGenerator({
9169                dateProfileGeneratorClass: viewSpec.optionDefaults.dateProfileGeneratorClass,
9170                duration: viewSpec.duration,
9171                durationUnit: viewSpec.durationUnit,
9172                usesMinMaxTime: viewSpec.optionDefaults.usesMinMaxTime,
9173                dateEnv: optionsData.dateEnv,
9174                calendarApi: this.props.calendarApi,
9175                slotMinTime: refinedOptions.slotMinTime,
9176                slotMaxTime: refinedOptions.slotMaxTime,
9177                showNonCurrentDates: refinedOptions.showNonCurrentDates,
9178                dayCount: refinedOptions.dayCount,
9179                dateAlignment: refinedOptions.dateAlignment,
9180                dateIncrement: refinedOptions.dateIncrement,
9181                hiddenDays: refinedOptions.hiddenDays,
9182                weekends: refinedOptions.weekends,
9183                nowInput: refinedOptions.now,
9184                validRangeInput: refinedOptions.validRange,
9185                visibleRangeInput: refinedOptions.visibleRange,
9186                fixedWeekCount: refinedOptions.fixedWeekCount,
9187            });
9188            let viewApi = this.buildViewApi(viewType, this.getCurrentData, optionsData.dateEnv);
9189            return { viewSpec, options: refinedOptions, dateProfileGenerator, viewApi };
9190        }
9191        processRawViewOptions(viewSpec, pluginHooks, localeDefaults, optionOverrides, dynamicOptionOverrides) {
9192            let raw = mergeRawOptions([
9193                BASE_OPTION_DEFAULTS,
9194                viewSpec.optionDefaults,
9195                localeDefaults,
9196                optionOverrides,
9197                viewSpec.optionOverrides,
9198                dynamicOptionOverrides,
9199            ]);
9200            let refiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), VIEW_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
9201            let refined = {};
9202            let currentRaw = this.currentViewOptionsInput;
9203            let currentRefined = this.currentViewOptionsRefined;
9204            let anyChanges = false;
9205            let extra = {};
9206            for (let optionName in raw) {
9207                if (raw[optionName] === currentRaw[optionName] ||
9208                    (COMPLEX_OPTION_COMPARATORS[optionName] &&
9209                        COMPLEX_OPTION_COMPARATORS[optionName](raw[optionName], currentRaw[optionName]))) {
9210                    refined[optionName] = currentRefined[optionName];
9211                }
9212                else {
9213                    if (raw[optionName] === this.currentCalendarOptionsInput[optionName] ||
9214                        (COMPLEX_OPTION_COMPARATORS[optionName] &&
9215                            COMPLEX_OPTION_COMPARATORS[optionName](raw[optionName], this.currentCalendarOptionsInput[optionName]))) {
9216                        if (optionName in this.currentCalendarOptionsRefined) { // might be an "extra" prop
9217                            refined[optionName] = this.currentCalendarOptionsRefined[optionName];
9218                        }
9219                    }
9220                    else if (refiners[optionName]) {
9221                        refined[optionName] = refiners[optionName](raw[optionName]);
9222                    }
9223                    else {
9224                        extra[optionName] = raw[optionName];
9225                    }
9226                    anyChanges = true;
9227                }
9228            }
9229            if (anyChanges) {
9230                this.currentViewOptionsInput = raw;
9231                this.currentViewOptionsRefined = refined;
9232            }
9233            return {
9234                rawOptions: this.currentViewOptionsInput,
9235                refinedOptions: this.currentViewOptionsRefined,
9236                extra,
9237            };
9238        }
9239    }
9240    function buildDateEnv$1(timeZone, explicitLocale, weekNumberCalculation, firstDay, weekText, pluginHooks, availableLocaleData, defaultSeparator) {
9241        let locale = buildLocale(explicitLocale || availableLocaleData.defaultCode, availableLocaleData.map);
9242        return new DateEnv({
9243            calendarSystem: 'gregory',
9244            timeZone,
9245            namedTimeZoneImpl: pluginHooks.namedTimeZonedImpl,
9246            locale,
9247            weekNumberCalculation,
9248            firstDay,
9249            weekText,
9250            cmdFormatter: pluginHooks.cmdFormatter,
9251            defaultSeparator,
9252        });
9253    }
9254    function buildTheme(options, pluginHooks) {
9255        let ThemeClass = pluginHooks.themeClasses[options.themeSystem] || StandardTheme;
9256        return new ThemeClass(options);
9257    }
9258    function buildDateProfileGenerator(props) {
9259        let DateProfileGeneratorClass = props.dateProfileGeneratorClass || DateProfileGenerator;
9260        return new DateProfileGeneratorClass(props);
9261    }
9262    function buildViewApi(type, getCurrentData, dateEnv) {
9263        return new ViewImpl(type, getCurrentData, dateEnv);
9264    }
9265    function buildEventUiBySource(eventSources) {
9266        return mapHash(eventSources, (eventSource) => eventSource.ui);
9267    }
9268    function buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) {
9269        let eventUiBases = { '': eventUiSingleBase };
9270        for (let defId in eventDefs) {
9271            let def = eventDefs[defId];
9272            if (def.sourceId && eventUiBySource[def.sourceId]) {
9273                eventUiBases[defId] = eventUiBySource[def.sourceId];
9274            }
9275        }
9276        return eventUiBases;
9277    }
9278    function buildViewUiProps(calendarContext) {
9279        let { options } = calendarContext;
9280        return {
9281            eventUiSingleBase: createEventUi({
9282                display: options.eventDisplay,
9283                editable: options.editable,
9284                startEditable: options.eventStartEditable,
9285                durationEditable: options.eventDurationEditable,
9286                constraint: options.eventConstraint,
9287                overlap: typeof options.eventOverlap === 'boolean' ? options.eventOverlap : undefined,
9288                allow: options.eventAllow,
9289                backgroundColor: options.eventBackgroundColor,
9290                borderColor: options.eventBorderColor,
9291                textColor: options.eventTextColor,
9292                color: options.eventColor,
9293                // classNames: options.eventClassNames // render hook will handle this
9294            }, calendarContext),
9295            selectionConfig: createEventUi({
9296                constraint: options.selectConstraint,
9297                overlap: typeof options.selectOverlap === 'boolean' ? options.selectOverlap : undefined,
9298                allow: options.selectAllow,
9299            }, calendarContext),
9300        };
9301    }
9302    function computeIsLoading(state, context) {
9303        for (let isLoadingFunc of context.pluginHooks.isLoadingFuncs) {
9304            if (isLoadingFunc(state)) {
9305                return true;
9306            }
9307        }
9308        return false;
9309    }
9310    function parseContextBusinessHours(calendarContext) {
9311        return parseBusinessHours(calendarContext.options.businessHours, calendarContext);
9312    }
9313    function warnUnknownOptions(options, viewName) {
9314        for (let optionName in options) {
9315            console.warn(`Unknown option '${optionName}'` +
9316                (viewName ? ` for view '${viewName}'` : ''));
9317        }
9318    }
9319
9320    class ToolbarSection extends BaseComponent {
9321        render() {
9322            let children = this.props.widgetGroups.map((widgetGroup) => this.renderWidgetGroup(widgetGroup));
9323            return y('div', { className: 'fc-toolbar-chunk' }, ...children);
9324        }
9325        renderWidgetGroup(widgetGroup) {
9326            let { props } = this;
9327            let { theme } = this.context;
9328            let children = [];
9329            let isOnlyButtons = true;
9330            for (let widget of widgetGroup) {
9331                let { buttonName, buttonClick, buttonText, buttonIcon, buttonHint } = widget;
9332                if (buttonName === 'title') {
9333                    isOnlyButtons = false;
9334                    children.push(y("h2", { className: "fc-toolbar-title", id: props.titleId }, props.title));
9335                }
9336                else {
9337                    let isPressed = buttonName === props.activeButton;
9338                    let isDisabled = (!props.isTodayEnabled && buttonName === 'today') ||
9339                        (!props.isPrevEnabled && buttonName === 'prev') ||
9340                        (!props.isNextEnabled && buttonName === 'next');
9341                    let buttonClasses = [`fc-${buttonName}-button`, theme.getClass('button')];
9342                    if (isPressed) {
9343                        buttonClasses.push(theme.getClass('buttonActive'));
9344                    }
9345                    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" }) : '')));
9346                }
9347            }
9348            if (children.length > 1) {
9349                let groupClassName = (isOnlyButtons && theme.getClass('buttonGroup')) || '';
9350                return y('div', { className: groupClassName }, ...children);
9351            }
9352            return children[0];
9353        }
9354    }
9355
9356    class Toolbar extends BaseComponent {
9357        render() {
9358            let { model, extraClassName } = this.props;
9359            let forceLtr = false;
9360            let startContent;
9361            let endContent;
9362            let sectionWidgets = model.sectionWidgets;
9363            let centerContent = sectionWidgets.center;
9364            if (sectionWidgets.left) {
9365                forceLtr = true;
9366                startContent = sectionWidgets.left;
9367            }
9368            else {
9369                startContent = sectionWidgets.start;
9370            }
9371            if (sectionWidgets.right) {
9372                forceLtr = true;
9373                endContent = sectionWidgets.right;
9374            }
9375            else {
9376                endContent = sectionWidgets.end;
9377            }
9378            let classNames = [
9379                extraClassName || '',
9380                'fc-toolbar',
9381                forceLtr ? 'fc-toolbar-ltr' : '',
9382            ];
9383            return (y("div", { className: classNames.join(' ') },
9384                this.renderSection('start', startContent || []),
9385                this.renderSection('center', centerContent || []),
9386                this.renderSection('end', endContent || [])));
9387        }
9388        renderSection(key, widgetGroups) {
9389            let { props } = this;
9390            return (y(ToolbarSection, { key: key, widgetGroups: widgetGroups, title: props.title, navUnit: props.navUnit, activeButton: props.activeButton, isTodayEnabled: props.isTodayEnabled, isPrevEnabled: props.isPrevEnabled, isNextEnabled: props.isNextEnabled, titleId: props.titleId }));
9391        }
9392    }
9393
9394    class ViewHarness extends BaseComponent {
9395        constructor() {
9396            super(...arguments);
9397            this.state = {
9398                availableWidth: null,
9399            };
9400            this.handleEl = (el) => {
9401                this.el = el;
9402                setRef(this.props.elRef, el);
9403                this.updateAvailableWidth();
9404            };
9405            this.handleResize = () => {
9406                this.updateAvailableWidth();
9407            };
9408        }
9409        render() {
9410            let { props, state } = this;
9411            let { aspectRatio } = props;
9412            let classNames = [
9413                'fc-view-harness',
9414                (aspectRatio || props.liquid || props.height)
9415                    ? 'fc-view-harness-active' // harness controls the height
9416                    : 'fc-view-harness-passive', // let the view do the height
9417            ];
9418            let height = '';
9419            let paddingBottom = '';
9420            if (aspectRatio) {
9421                if (state.availableWidth !== null) {
9422                    height = state.availableWidth / aspectRatio;
9423                }
9424                else {
9425                    // while waiting to know availableWidth, we can't set height to *zero*
9426                    // because will cause lots of unnecessary scrollbars within scrollgrid.
9427                    // BETTER: don't start rendering ANYTHING yet until we know container width
9428                    // NOTE: why not always use paddingBottom? Causes height oscillation (issue 5606)
9429                    paddingBottom = `${(1 / aspectRatio) * 100}%`;
9430                }
9431            }
9432            else {
9433                height = props.height || '';
9434            }
9435            return (y("div", { "aria-labelledby": props.labeledById, ref: this.handleEl, className: classNames.join(' '), style: { height, paddingBottom } }, props.children));
9436        }
9437        componentDidMount() {
9438            this.context.addResizeHandler(this.handleResize);
9439        }
9440        componentWillUnmount() {
9441            this.context.removeResizeHandler(this.handleResize);
9442        }
9443        updateAvailableWidth() {
9444            if (this.el && // needed. but why?
9445                this.props.aspectRatio // aspectRatio is the only height setting that needs availableWidth
9446            ) {
9447                this.setState({ availableWidth: this.el.offsetWidth });
9448            }
9449        }
9450    }
9451
9452    /*
9453    Detects when the user clicks on an event within a DateComponent
9454    */
9455    class EventClicking extends Interaction {
9456        constructor(settings) {
9457            super(settings);
9458            this.handleSegClick = (ev, segEl) => {
9459                let { component } = this;
9460                let { context } = component;
9461                let seg = getElSeg(segEl);
9462                if (seg && // might be the <div> surrounding the more link
9463                    component.isValidSegDownEl(ev.target)) {
9464                    // our way to simulate a link click for elements that can't be <a> tags
9465                    // grab before trigger fired in case trigger trashes DOM thru rerendering
9466                    let hasUrlContainer = elementClosest(ev.target, '.fc-event-forced-url');
9467                    let url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : '';
9468                    context.emitter.trigger('eventClick', {
9469                        el: segEl,
9470                        event: new EventImpl(component.context, seg.eventRange.def, seg.eventRange.instance),
9471                        jsEvent: ev,
9472                        view: context.viewApi,
9473                    });
9474                    if (url && !ev.defaultPrevented) {
9475                        window.location.href = url;
9476                    }
9477                }
9478            };
9479            this.destroy = listenBySelector(settings.el, 'click', '.fc-event', // on both fg and bg events
9480                this.handleSegClick);
9481        }
9482    }
9483
9484    /*
9485    Triggers events and adds/removes core classNames when the user's pointer
9486    enters/leaves event-elements of a component.
9487    */
9488    class EventHovering extends Interaction {
9489        constructor(settings) {
9490            super(settings);
9491            // for simulating an eventMouseLeave when the event el is destroyed while mouse is over it
9492            this.handleEventElRemove = (el) => {
9493                if (el === this.currentSegEl) {
9494                    this.handleSegLeave(null, this.currentSegEl);
9495                }
9496            };
9497            this.handleSegEnter = (ev, segEl) => {
9498                if (getElSeg(segEl)) { // TODO: better way to make sure not hovering over more+ link or its wrapper
9499                    this.currentSegEl = segEl;
9500                    this.triggerEvent('eventMouseEnter', ev, segEl);
9501                }
9502            };
9503            this.handleSegLeave = (ev, segEl) => {
9504                if (this.currentSegEl) {
9505                    this.currentSegEl = null;
9506                    this.triggerEvent('eventMouseLeave', ev, segEl);
9507                }
9508            };
9509            this.removeHoverListeners = listenToHoverBySelector(settings.el, '.fc-event', // on both fg and bg events
9510                this.handleSegEnter, this.handleSegLeave);
9511        }
9512        destroy() {
9513            this.removeHoverListeners();
9514        }
9515        triggerEvent(publicEvName, ev, segEl) {
9516            let { component } = this;
9517            let { context } = component;
9518            let seg = getElSeg(segEl);
9519            if (!ev || component.isValidSegDownEl(ev.target)) {
9520                context.emitter.trigger(publicEvName, {
9521                    el: segEl,
9522                    event: new EventImpl(context, seg.eventRange.def, seg.eventRange.instance),
9523                    jsEvent: ev,
9524                    view: context.viewApi,
9525                });
9526            }
9527        }
9528    }
9529
9530    class CalendarContent extends PureComponent {
9531        constructor() {
9532            super(...arguments);
9533            this.buildViewContext = memoize(buildViewContext);
9534            this.buildViewPropTransformers = memoize(buildViewPropTransformers);
9535            this.buildToolbarProps = memoize(buildToolbarProps);
9536            this.headerRef = d();
9537            this.footerRef = d();
9538            this.interactionsStore = {};
9539            // eslint-disable-next-line
9540            this.state = {
9541                viewLabelId: getUniqueDomId(),
9542            };
9543            // Component Registration
9544            // -----------------------------------------------------------------------------------------------------------------
9545            this.registerInteractiveComponent = (component, settingsInput) => {
9546                let settings = parseInteractionSettings(component, settingsInput);
9547                let DEFAULT_INTERACTIONS = [
9548                    EventClicking,
9549                    EventHovering,
9550                ];
9551                let interactionClasses = DEFAULT_INTERACTIONS.concat(this.props.pluginHooks.componentInteractions);
9552                let interactions = interactionClasses.map((TheInteractionClass) => new TheInteractionClass(settings));
9553                this.interactionsStore[component.uid] = interactions;
9554                interactionSettingsStore[component.uid] = settings;
9555            };
9556            this.unregisterInteractiveComponent = (component) => {
9557                let listeners = this.interactionsStore[component.uid];
9558                if (listeners) {
9559                    for (let listener of listeners) {
9560                        listener.destroy();
9561                    }
9562                    delete this.interactionsStore[component.uid];
9563                }
9564                delete interactionSettingsStore[component.uid];
9565            };
9566            // Resizing
9567            // -----------------------------------------------------------------------------------------------------------------
9568            this.resizeRunner = new DelayedRunner(() => {
9569                this.props.emitter.trigger('_resize', true); // should window resizes be considered "forced" ?
9570                this.props.emitter.trigger('windowResize', { view: this.props.viewApi });
9571            });
9572            this.handleWindowResize = (ev) => {
9573                let { options } = this.props;
9574                if (options.handleWindowResize &&
9575                    ev.target === window // avoid jqui events
9576                ) {
9577                    this.resizeRunner.request(options.windowResizeDelay);
9578                }
9579            };
9580        }
9581        /*
9582        renders INSIDE of an outer div
9583        */
9584        render() {
9585            let { props } = this;
9586            let { toolbarConfig, options } = props;
9587            let toolbarProps = this.buildToolbarProps(props.viewSpec, props.dateProfile, props.dateProfileGenerator, props.currentDate, getNow(props.options.now, props.dateEnv), // TODO: use NowTimer????
9588                props.viewTitle);
9589            let viewVGrow = false;
9590            let viewHeight = '';
9591            let viewAspectRatio;
9592            if (props.isHeightAuto || props.forPrint) {
9593                viewHeight = '';
9594            }
9595            else if (options.height != null) {
9596                viewVGrow = true;
9597            }
9598            else if (options.contentHeight != null) {
9599                viewHeight = options.contentHeight;
9600            }
9601            else {
9602                viewAspectRatio = Math.max(options.aspectRatio, 0.5); // prevent from getting too tall
9603            }
9604            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);
9605            let viewLabelId = (toolbarConfig.header && toolbarConfig.header.hasTitle)
9606                ? this.state.viewLabelId
9607                : '';
9608            return (y(ViewContextType.Provider, { value: viewContext },
9609                toolbarConfig.header && (y(Toolbar, Object.assign({ ref: this.headerRef, extraClassName: "fc-header-toolbar", model: toolbarConfig.header, titleId: viewLabelId }, toolbarProps))),
9610                y(ViewHarness, { liquid: viewVGrow, height: viewHeight, aspectRatio: viewAspectRatio, labeledById: viewLabelId },
9611                    this.renderView(props),
9612                    this.buildAppendContent()),
9613                toolbarConfig.footer && (y(Toolbar, Object.assign({ ref: this.footerRef, extraClassName: "fc-footer-toolbar", model: toolbarConfig.footer, titleId: "" }, toolbarProps)))));
9614        }
9615        componentDidMount() {
9616            let { props } = this;
9617            this.calendarInteractions = props.pluginHooks.calendarInteractions
9618                .map((CalendarInteractionClass) => new CalendarInteractionClass(props));
9619            window.addEventListener('resize', this.handleWindowResize);
9620            let { propSetHandlers } = props.pluginHooks;
9621            for (let propName in propSetHandlers) {
9622                propSetHandlers[propName](props[propName], props);
9623            }
9624        }
9625        componentDidUpdate(prevProps) {
9626            let { props } = this;
9627            let { propSetHandlers } = props.pluginHooks;
9628            for (let propName in propSetHandlers) {
9629                if (props[propName] !== prevProps[propName]) {
9630                    propSetHandlers[propName](props[propName], props);
9631                }
9632            }
9633        }
9634        componentWillUnmount() {
9635            window.removeEventListener('resize', this.handleWindowResize);
9636            this.resizeRunner.clear();
9637            for (let interaction of this.calendarInteractions) {
9638                interaction.destroy();
9639            }
9640            this.props.emitter.trigger('_unmount');
9641        }
9642        buildAppendContent() {
9643            let { props } = this;
9644            let children = props.pluginHooks.viewContainerAppends.map((buildAppendContent) => buildAppendContent(props));
9645            return y(_, {}, ...children);
9646        }
9647        renderView(props) {
9648            let { pluginHooks } = props;
9649            let { viewSpec } = props;
9650            let viewProps = {
9651                dateProfile: props.dateProfile,
9652                businessHours: props.businessHours,
9653                eventStore: props.renderableEventStore,
9654                eventUiBases: props.eventUiBases,
9655                dateSelection: props.dateSelection,
9656                eventSelection: props.eventSelection,
9657                eventDrag: props.eventDrag,
9658                eventResize: props.eventResize,
9659                isHeightAuto: props.isHeightAuto,
9660                forPrint: props.forPrint,
9661            };
9662            let transformers = this.buildViewPropTransformers(pluginHooks.viewPropsTransformers);
9663            for (let transformer of transformers) {
9664                Object.assign(viewProps, transformer.transform(viewProps, props));
9665            }
9666            let ViewComponent = viewSpec.component;
9667            return (y(ViewComponent, Object.assign({}, viewProps)));
9668        }
9669    }
9670    function buildToolbarProps(viewSpec, dateProfile, dateProfileGenerator, currentDate, now, title) {
9671        // don't force any date-profiles to valid date profiles (the `false`) so that we can tell if it's invalid
9672        let todayInfo = dateProfileGenerator.build(now, undefined, false); // TODO: need `undefined` or else INFINITE LOOP for some reason
9673        let prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate, false);
9674        let nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate, false);
9675        return {
9676            title,
9677            activeButton: viewSpec.type,
9678            navUnit: viewSpec.singleUnit,
9679            isTodayEnabled: todayInfo.isValid && !rangeContainsMarker(dateProfile.currentRange, now),
9680            isPrevEnabled: prevInfo.isValid,
9681            isNextEnabled: nextInfo.isValid,
9682        };
9683    }
9684    // Plugin
9685    // -----------------------------------------------------------------------------------------------------------------
9686    function buildViewPropTransformers(theClasses) {
9687        return theClasses.map((TheClass) => new TheClass());
9688    }
9689
9690    class Calendar extends CalendarImpl {
9691        constructor(el, optionOverrides = {}) {
9692            super();
9693            this.isRendering = false;
9694            this.isRendered = false;
9695            this.currentClassNames = [];
9696            this.customContentRenderId = 0;
9697            this.handleAction = (action) => {
9698                // actions we know we want to render immediately
9699                switch (action.type) {
9700                    case 'SET_EVENT_DRAG':
9701                    case 'SET_EVENT_RESIZE':
9702                        this.renderRunner.tryDrain();
9703                }
9704            };
9705            this.handleData = (data) => {
9706                this.currentData = data;
9707                this.renderRunner.request(data.calendarOptions.rerenderDelay);
9708            };
9709            this.handleRenderRequest = () => {
9710                if (this.isRendering) {
9711                    this.isRendered = true;
9712                    let { currentData } = this;
9713                    flushSync(() => {
9714                        D$1(y(CalendarRoot, { options: currentData.calendarOptions, theme: currentData.theme, emitter: currentData.emitter }, (classNames, height, isHeightAuto, forPrint) => {
9715                            this.setClassNames(classNames);
9716                            this.setHeight(height);
9717                            return (y(RenderId.Provider, { value: this.customContentRenderId },
9718                                y(CalendarContent, Object.assign({ isHeightAuto: isHeightAuto, forPrint: forPrint }, currentData))));
9719                        }), this.el);
9720                    });
9721                }
9722                else if (this.isRendered) {
9723                    this.isRendered = false;
9724                    D$1(null, this.el);
9725                    this.setClassNames([]);
9726                    this.setHeight('');
9727                }
9728            };
9729            ensureElHasStyles(el);
9730            this.el = el;
9731            this.renderRunner = new DelayedRunner(this.handleRenderRequest);
9732            new CalendarDataManager({
9733                optionOverrides,
9734                calendarApi: this,
9735                onAction: this.handleAction,
9736                onData: this.handleData,
9737            });
9738        }
9739        render() {
9740            let wasRendering = this.isRendering;
9741            if (!wasRendering) {
9742                this.isRendering = true;
9743            }
9744            else {
9745                this.customContentRenderId += 1;
9746            }
9747            this.renderRunner.request();
9748            if (wasRendering) {
9749                this.updateSize();
9750            }
9751        }
9752        destroy() {
9753            if (this.isRendering) {
9754                this.isRendering = false;
9755                this.renderRunner.request();
9756            }
9757        }
9758        updateSize() {
9759            flushSync(() => {
9760                super.updateSize();
9761            });
9762        }
9763        batchRendering(func) {
9764            this.renderRunner.pause('batchRendering');
9765            func();
9766            this.renderRunner.resume('batchRendering');
9767        }
9768        pauseRendering() {
9769            this.renderRunner.pause('pauseRendering');
9770        }
9771        resumeRendering() {
9772            this.renderRunner.resume('pauseRendering', true);
9773        }
9774        resetOptions(optionOverrides, changedOptionNames) {
9775            this.currentDataManager.resetOptions(optionOverrides, changedOptionNames);
9776        }
9777        setClassNames(classNames) {
9778            if (!isArraysEqual(classNames, this.currentClassNames)) {
9779                let { classList } = this.el;
9780                for (let className of this.currentClassNames) {
9781                    classList.remove(className);
9782                }
9783                for (let className of classNames) {
9784                    classList.add(className);
9785                }
9786                this.currentClassNames = classNames;
9787            }
9788        }
9789        setHeight(height) {
9790            applyStyleProp(this.el, 'height', height);
9791        }
9792    }
9793
9794    function formatDate(dateInput, options = {}) {
9795        let dateEnv = buildDateEnv(options);
9796        let formatter = createFormatter(options);
9797        let dateMeta = dateEnv.createMarkerMeta(dateInput);
9798        if (!dateMeta) { // TODO: warning?
9799            return '';
9800        }
9801        return dateEnv.format(dateMeta.marker, formatter, {
9802            forcedTzo: dateMeta.forcedTzo,
9803        });
9804    }
9805    function formatRange(startInput, endInput, options) {
9806        let dateEnv = buildDateEnv(typeof options === 'object' && options ? options : {}); // pass in if non-null object
9807        let formatter = createFormatter(options);
9808        let startMeta = dateEnv.createMarkerMeta(startInput);
9809        let endMeta = dateEnv.createMarkerMeta(endInput);
9810        if (!startMeta || !endMeta) { // TODO: warning?
9811            return '';
9812        }
9813        return dateEnv.formatRange(startMeta.marker, endMeta.marker, formatter, {
9814            forcedStartTzo: startMeta.forcedTzo,
9815            forcedEndTzo: endMeta.forcedTzo,
9816            isEndExclusive: options.isEndExclusive,
9817            defaultSeparator: BASE_OPTION_DEFAULTS.defaultRangeSeparator,
9818        });
9819    }
9820    // TODO: more DRY and optimized
9821    function buildDateEnv(settings) {
9822        let locale = buildLocale(settings.locale || 'en', organizeRawLocales([]).map); // TODO: don't hardcode 'en' everywhere
9823        return new DateEnv(Object.assign(Object.assign({ timeZone: BASE_OPTION_DEFAULTS.timeZone, calendarSystem: 'gregory' }, settings), { locale }));
9824    }
9825
9826    // HELPERS
9827    /*
9828    if nextDayThreshold is specified, slicing is done in an all-day fashion.
9829    you can get nextDayThreshold from context.nextDayThreshold
9830    */
9831    function sliceEvents(props, allDay) {
9832        return sliceEventStore(props.eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? props.nextDayThreshold : null).fg;
9833    }
9834
9835    const version = '6.1.10';
9836
9837    config.touchMouseIgnoreWait = 500;
9838    let ignoreMouseDepth = 0;
9839    let listenerCnt = 0;
9840    let isWindowTouchMoveCancelled = false;
vendor: 4,736 bytes, lines 9841-9928
9841    /*
9842    Uses a "pointer" abstraction, which monitors UI events for both mouse and touch.
9843    Tracks when the pointer "drags" on a certain element, meaning down+move+up.
9844
9845    Also, tracks if there was touch-scrolling.
9846    Also, can prevent touch-scrolling from happening.
9847    Also, can fire pointermove events when scrolling happens underneath, even when no real pointer movement.
9848
9849    emits:
9850    - pointerdown
9851    - pointermove
9852    - pointerup
9853    */
9854    class PointerDragging {
9855        constructor(containerEl) {
9856            this.subjectEl = null;
9857            // options that can be directly assigned by caller
9858            this.selector = ''; // will cause subjectEl in all emitted events to be this element
9859            this.handleSelector = '';
9860            this.shouldIgnoreMove = false;
9861            this.shouldWatchScroll = true; // for simulating pointermove on scroll
9862            // internal states
9863            this.isDragging = false;
9864            this.isTouchDragging = false;
9865            this.wasTouchScroll = false;
9866            // Mouse
9867            // ----------------------------------------------------------------------------------------------------
9868            this.handleMouseDown = (ev) => {
9869                if (!this.shouldIgnoreMouse() &&
9870                    isPrimaryMouseButton(ev) &&
9871                    this.tryStart(ev)) {
9872                    let pev = this.createEventFromMouse(ev, true);
9873                    this.emitter.trigger('pointerdown', pev);
9874                    this.initScrollWatch(pev);
9875                    if (!this.shouldIgnoreMove) {
9876                        document.addEventListener('mousemove', this.handleMouseMove);
9877                    }
9878                    document.addEventListener('mouseup', this.handleMouseUp);
9879                }
9880            };
9881            this.handleMouseMove = (ev) => {
9882                let pev = this.createEventFromMouse(ev);
9883                this.recordCoords(pev);
9884                this.emitter.trigger('pointermove', pev);
9885            };
9886            this.handleMouseUp = (ev) => {
9887                document.removeEventListener('mousemove', this.handleMouseMove);
9888                document.removeEventListener('mouseup', this.handleMouseUp);
9889                this.emitter.trigger('pointerup', this.createEventFromMouse(ev));
9890                this.cleanup(); // call last so that pointerup has access to props
9891            };
9892            // Touch
9893            // ----------------------------------------------------------------------------------------------------
9894            this.handleTouchStart = (ev) => {
9895                if (this.tryStart(ev)) {
9896                    this.isTouchDragging = true;
9897                    let pev = this.createEventFromTouch(ev, true);
9898                    this.emitter.trigger('pointerdown', pev);
9899                    this.initScrollWatch(pev);
9900                    // unlike mouse, need to attach to target, not document
9901                    // https://stackoverflow.com/a/45760014
9902                    let targetEl = ev.target;
9903                    if (!this.shouldIgnoreMove) {
9904                        targetEl.addEventListener('touchmove', this.handleTouchMove);
9905                    }
9906                    targetEl.addEventListener('touchend', this.handleTouchEnd);
9907                    targetEl.addEventListener('touchcancel', this.handleTouchEnd); // treat it as a touch end
9908                    // attach a handler to get called when ANY scroll action happens on the page.
9909                    // this was impossible to do with normal on/off because 'scroll' doesn't bubble.
9910                    // http://stackoverflow.com/a/32954565/96342
9911                    window.addEventListener('scroll', this.handleTouchScroll, true);
9912                }
9913            };
9914            this.handleTouchMove = (ev) => {
9915                let pev = this.createEventFromTouch(ev);
9916                this.recordCoords(pev);
9917                this.emitter.trigger('pointermove', pev);
9918            };
9919            this.handleTouchEnd = (ev) => {
9920                if (this.isDragging) { // done to guard against touchend followed by touchcancel
9921                    let targetEl = ev.target;
9922                    targetEl.removeEventListener('touchmove', this.handleTouchMove);
9923                    targetEl.removeEventListener('touchend', this.handleTouchEnd);
9924                    targetEl.removeEventListener('touchcancel', this.handleTouchEnd);
9925                    window.removeEventListener('scroll', this.handleTouchScroll, true); // useCaptured=true
9926                    this.emitter.trigger('pointerup', this.createEventFromTouch(ev));
9927                    this.cleanup(); // call last so that pointerup has access to props
9928                    this.isTouchDragging = false;
vendor: 16,857 bytes, lines 9929-10362
9929                    startIgnoringMouse();
9930                }
9931            };
9932            this.handleTouchScroll = () => {
9933                this.wasTouchScroll = true;
9934            };
9935            this.handleScroll = (ev) => {
9936                if (!this.shouldIgnoreMove) {
9937                    let pageX = (window.pageXOffset - this.prevScrollX) + this.prevPageX;
9938                    let pageY = (window.pageYOffset - this.prevScrollY) + this.prevPageY;
9939                    this.emitter.trigger('pointermove', {
9940                        origEvent: ev,
9941                        isTouch: this.isTouchDragging,
9942                        subjectEl: this.subjectEl,
9943                        pageX,
9944                        pageY,
9945                        deltaX: pageX - this.origPageX,
9946                        deltaY: pageY - this.origPageY,
9947                    });
9948                }
9949            };
9950            this.containerEl = containerEl;
9951            this.emitter = new Emitter();
9952            containerEl.addEventListener('mousedown', this.handleMouseDown);
9953            containerEl.addEventListener('touchstart', this.handleTouchStart, { passive: true });
9954            listenerCreated();
9955        }
9956        destroy() {
9957            this.containerEl.removeEventListener('mousedown', this.handleMouseDown);
9958            this.containerEl.removeEventListener('touchstart', this.handleTouchStart, { passive: true });
9959            listenerDestroyed();
9960        }
9961        tryStart(ev) {
9962            let subjectEl = this.querySubjectEl(ev);
9963            let downEl = ev.target;
9964            if (subjectEl &&
9965                (!this.handleSelector || elementClosest(downEl, this.handleSelector))) {
9966                this.subjectEl = subjectEl;
9967                this.isDragging = true; // do this first so cancelTouchScroll will work
9968                this.wasTouchScroll = false;
9969                return true;
9970            }
9971            return false;
9972        }
9973        cleanup() {
9974            isWindowTouchMoveCancelled = false;
9975            this.isDragging = false;
9976            this.subjectEl = null;
9977            // keep wasTouchScroll around for later access
9978            this.destroyScrollWatch();
9979        }
9980        querySubjectEl(ev) {
9981            if (this.selector) {
9982                return elementClosest(ev.target, this.selector);
9983            }
9984            return this.containerEl;
9985        }
9986        shouldIgnoreMouse() {
9987            return ignoreMouseDepth || this.isTouchDragging;
9988        }
9989        // can be called by user of this class, to cancel touch-based scrolling for the current drag
9990        cancelTouchScroll() {
9991            if (this.isDragging) {
9992                isWindowTouchMoveCancelled = true;
9993            }
9994        }
9995        // Scrolling that simulates pointermoves
9996        // ----------------------------------------------------------------------------------------------------
9997        initScrollWatch(ev) {
9998            if (this.shouldWatchScroll) {
9999                this.recordCoords(ev);
10000                window.addEventListener('scroll', this.handleScroll, true); // useCapture=true
10001            }
10002        }
10003        recordCoords(ev) {
10004            if (this.shouldWatchScroll) {
10005                this.prevPageX = ev.pageX;
10006                this.prevPageY = ev.pageY;
10007                this.prevScrollX = window.pageXOffset;
10008                this.prevScrollY = window.pageYOffset;
10009            }
10010        }
10011        destroyScrollWatch() {
10012            if (this.shouldWatchScroll) {
10013                window.removeEventListener('scroll', this.handleScroll, true); // useCaptured=true
10014            }
10015        }
10016        // Event Normalization
10017        // ----------------------------------------------------------------------------------------------------
10018        createEventFromMouse(ev, isFirst) {
10019            let deltaX = 0;
10020            let deltaY = 0;
10021            // TODO: repeat code
10022            if (isFirst) {
10023                this.origPageX = ev.pageX;
10024                this.origPageY = ev.pageY;
10025            }
10026            else {
10027                deltaX = ev.pageX - this.origPageX;
10028                deltaY = ev.pageY - this.origPageY;
10029            }
10030            return {
10031                origEvent: ev,
10032                isTouch: false,
10033                subjectEl: this.subjectEl,
10034                pageX: ev.pageX,
10035                pageY: ev.pageY,
10036                deltaX,
10037                deltaY,
10038            };
10039        }
10040        createEventFromTouch(ev, isFirst) {
10041            let touches = ev.touches;
10042            let pageX;
10043            let pageY;
10044            let deltaX = 0;
10045            let deltaY = 0;
10046            // if touch coords available, prefer,
10047            // because FF would give bad ev.pageX ev.pageY
10048            if (touches && touches.length) {
10049                pageX = touches[0].pageX;
10050                pageY = touches[0].pageY;
10051            }
10052            else {
10053                pageX = ev.pageX;
10054                pageY = ev.pageY;
10055            }
10056            // TODO: repeat code
10057            if (isFirst) {
10058                this.origPageX = pageX;
10059                this.origPageY = pageY;
10060            }
10061            else {
10062                deltaX = pageX - this.origPageX;
10063                deltaY = pageY - this.origPageY;
10064            }
10065            return {
10066                origEvent: ev,
10067                isTouch: true,
10068                subjectEl: this.subjectEl,
10069                pageX,
10070                pageY,
10071                deltaX,
10072                deltaY,
10073            };
10074        }
10075    }
10076    // Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac)
10077    function isPrimaryMouseButton(ev) {
10078        return ev.button === 0 && !ev.ctrlKey;
10079    }
10080    // Ignoring fake mouse events generated by touch
10081    // ----------------------------------------------------------------------------------------------------
10082    function startIgnoringMouse() {
10083        ignoreMouseDepth += 1;
10084        setTimeout(() => {
10085            ignoreMouseDepth -= 1;
10086        }, config.touchMouseIgnoreWait);
10087    }
10088    // We want to attach touchmove as early as possible for Safari
10089    // ----------------------------------------------------------------------------------------------------
10090    function listenerCreated() {
10091        listenerCnt += 1;
10092        if (listenerCnt === 1) {
10093            window.addEventListener('touchmove', onWindowTouchMove, { passive: false });
10094        }
10095    }
10096    function listenerDestroyed() {
10097        listenerCnt -= 1;
10098        if (!listenerCnt) {
10099            window.removeEventListener('touchmove', onWindowTouchMove, { passive: false });
10100        }
10101    }
10102    function onWindowTouchMove(ev) {
10103        if (isWindowTouchMoveCancelled) {
10104            ev.preventDefault();
10105        }
10106    }
10107
10108    /*
10109    An effect in which an element follows the movement of a pointer across the screen.
10110    The moving element is a clone of some other element.
10111    Must call start + handleMove + stop.
10112    */
10113    class ElementMirror {
10114        constructor() {
10115            this.isVisible = false; // must be explicitly enabled
10116            this.sourceEl = null;
10117            this.mirrorEl = null;
10118            this.sourceElRect = null; // screen coords relative to viewport
10119            // options that can be set directly by caller
10120            this.parentNode = document.body; // HIGHLY SUGGESTED to set this to sidestep ShadowDOM issues
10121            this.zIndex = 9999;
10122            this.revertDuration = 0;
10123        }
10124        start(sourceEl, pageX, pageY) {
10125            this.sourceEl = sourceEl;
10126            this.sourceElRect = this.sourceEl.getBoundingClientRect();
10127            this.origScreenX = pageX - window.pageXOffset;
10128            this.origScreenY = pageY - window.pageYOffset;
10129            this.deltaX = 0;
10130            this.deltaY = 0;
10131            this.updateElPosition();
10132        }
10133        handleMove(pageX, pageY) {
10134            this.deltaX = (pageX - window.pageXOffset) - this.origScreenX;
10135            this.deltaY = (pageY - window.pageYOffset) - this.origScreenY;
10136            this.updateElPosition();
10137        }
10138        // can be called before start
10139        setIsVisible(bool) {
10140            if (bool) {
10141                if (!this.isVisible) {
10142                    if (this.mirrorEl) {
10143                        this.mirrorEl.style.display = '';
10144                    }
10145                    this.isVisible = bool; // needs to happen before updateElPosition
10146                    this.updateElPosition(); // because was not updating the position while invisible
10147                }
10148            }
10149            else if (this.isVisible) {
10150                if (this.mirrorEl) {
10151                    this.mirrorEl.style.display = 'none';
10152                }
10153                this.isVisible = bool;
10154            }
10155        }
10156        // always async
10157        stop(needsRevertAnimation, callback) {
10158            let done = () => {
10159                this.cleanup();
10160                callback();
10161            };
10162            if (needsRevertAnimation &&
10163                this.mirrorEl &&
10164                this.isVisible &&
10165                this.revertDuration && // if 0, transition won't work
10166                (this.deltaX || this.deltaY) // if same coords, transition won't work
10167            ) {
10168                this.doRevertAnimation(done, this.revertDuration);
10169            }
10170            else {
10171                setTimeout(done, 0);
10172            }
10173        }
10174        doRevertAnimation(callback, revertDuration) {
10175            let mirrorEl = this.mirrorEl;
10176            let finalSourceElRect = this.sourceEl.getBoundingClientRect(); // because autoscrolling might have happened
10177            mirrorEl.style.transition =
10178                'top ' + revertDuration + 'ms,' +
10179                'left ' + revertDuration + 'ms';
10180            applyStyle(mirrorEl, {
10181                left: finalSourceElRect.left,
10182                top: finalSourceElRect.top,
10183            });
10184            whenTransitionDone(mirrorEl, () => {
10185                mirrorEl.style.transition = '';
10186                callback();
10187            });
10188        }
10189        cleanup() {
10190            if (this.mirrorEl) {
10191                removeElement(this.mirrorEl);
10192                this.mirrorEl = null;
10193            }
10194            this.sourceEl = null;
10195        }
10196        updateElPosition() {
10197            if (this.sourceEl && this.isVisible) {
10198                applyStyle(this.getMirrorEl(), {
10199                    left: this.sourceElRect.left + this.deltaX,
10200                    top: this.sourceElRect.top + this.deltaY,
10201                });
10202            }
10203        }
10204        getMirrorEl() {
10205            let sourceElRect = this.sourceElRect;
10206            let mirrorEl = this.mirrorEl;
10207            if (!mirrorEl) {
10208                mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true); // cloneChildren=true
10209                // we don't want long taps or any mouse interaction causing selection/menus.
10210                // would use preventSelection(), but that prevents selectstart, causing problems.
10211                mirrorEl.style.userSelect = 'none';
10212                mirrorEl.style.webkitUserSelect = 'none';
10213                mirrorEl.classList.add('fc-event-dragging');
10214                applyStyle(mirrorEl, {
10215                    position: 'fixed',
10216                    zIndex: this.zIndex,
10217                    visibility: '',
10218                    boxSizing: 'border-box',
10219                    width: sourceElRect.right - sourceElRect.left,
10220                    height: sourceElRect.bottom - sourceElRect.top,
10221                    right: 'auto',
10222                    bottom: 'auto',
10223                    margin: 0,
10224                });
10225                this.parentNode.appendChild(mirrorEl);
10226            }
10227            return mirrorEl;
10228        }
10229    }
10230
10231    /*
10232    Is a cache for a given element's scroll information (all the info that ScrollController stores)
10233    in addition the "client rectangle" of the element.. the area within the scrollbars.
10234
10235    The cache can be in one of two modes:
10236    - doesListening:false - ignores when the container is scrolled by someone else
10237    - doesListening:true - watch for scrolling and update the cache
10238    */
10239    class ScrollGeomCache extends ScrollController {
10240        constructor(scrollController, doesListening) {
10241            super();
10242            this.handleScroll = () => {
10243                this.scrollTop = this.scrollController.getScrollTop();
10244                this.scrollLeft = this.scrollController.getScrollLeft();
10245                this.handleScrollChange();
10246            };
10247            this.scrollController = scrollController;
10248            this.doesListening = doesListening;
10249            this.scrollTop = this.origScrollTop = scrollController.getScrollTop();
10250            this.scrollLeft = this.origScrollLeft = scrollController.getScrollLeft();
10251            this.scrollWidth = scrollController.getScrollWidth();
10252            this.scrollHeight = scrollController.getScrollHeight();
10253            this.clientWidth = scrollController.getClientWidth();
10254            this.clientHeight = scrollController.getClientHeight();
10255            this.clientRect = this.computeClientRect(); // do last in case it needs cached values
10256            if (this.doesListening) {
10257                this.getEventTarget().addEventListener('scroll', this.handleScroll);
10258            }
10259        }
10260        destroy() {
10261            if (this.doesListening) {
10262                this.getEventTarget().removeEventListener('scroll', this.handleScroll);
10263            }
10264        }
10265        getScrollTop() {
10266            return this.scrollTop;
10267        }
10268        getScrollLeft() {
10269            return this.scrollLeft;
10270        }
10271        setScrollTop(top) {
10272            this.scrollController.setScrollTop(top);
10273            if (!this.doesListening) {
10274                // we are not relying on the element to normalize out-of-bounds scroll values
10275                // so we need to sanitize ourselves
10276                this.scrollTop = Math.max(Math.min(top, this.getMaxScrollTop()), 0);
10277                this.handleScrollChange();
10278            }
10279        }
10280        setScrollLeft(top) {
10281            this.scrollController.setScrollLeft(top);
10282            if (!this.doesListening) {
10283                // we are not relying on the element to normalize out-of-bounds scroll values
10284                // so we need to sanitize ourselves
10285                this.scrollLeft = Math.max(Math.min(top, this.getMaxScrollLeft()), 0);
10286                this.handleScrollChange();
10287            }
10288        }
10289        getClientWidth() {
10290            return this.clientWidth;
10291        }
10292        getClientHeight() {
10293            return this.clientHeight;
10294        }
10295        getScrollWidth() {
10296            return this.scrollWidth;
10297        }
10298        getScrollHeight() {
10299            return this.scrollHeight;
10300        }
10301        handleScrollChange() {
10302        }
10303    }
10304
10305    class ElementScrollGeomCache extends ScrollGeomCache {
10306        constructor(el, doesListening) {
10307            super(new ElementScrollController(el), doesListening);
10308        }
10309        getEventTarget() {
10310            return this.scrollController.el;
10311        }
10312        computeClientRect() {
10313            return computeInnerRect(this.scrollController.el);
10314        }
10315    }
10316
10317    class WindowScrollGeomCache extends ScrollGeomCache {
10318        constructor(doesListening) {
10319            super(new WindowScrollController(), doesListening);
10320        }
10321        getEventTarget() {
10322            return window;
10323        }
10324        computeClientRect() {
10325            return {
10326                left: this.scrollLeft,
10327                right: this.scrollLeft + this.clientWidth,
10328                top: this.scrollTop,
10329                bottom: this.scrollTop + this.clientHeight,
10330            };
10331        }
10332        // the window is the only scroll object that changes it's rectangle relative
10333        // to the document's topleft as it scrolls
10334        handleScrollChange() {
10335            this.clientRect = this.computeClientRect();
10336        }
10337    }
10338
10339    // If available we are using native "performance" API instead of "Date"
10340    // Read more about it on MDN:
10341    // https://developer.mozilla.org/en-US/docs/Web/API/Performance
10342    const getTime = typeof performance === 'function' ? performance.now : Date.now;
10343    /*
10344    For a pointer interaction, automatically scrolls certain scroll containers when the pointer
10345    approaches the edge.
10346
10347    The caller must call start + handleMove + stop.
10348    */
10349    class AutoScroller {
10350        constructor() {
10351            // options that can be set by caller
10352            this.isEnabled = true;
10353            this.scrollQuery = [window, '.fc-scroller'];
10354            this.edgeThreshold = 50; // pixels
10355            this.maxVelocity = 300; // pixels per second
10356            // internal state
10357            this.pointerScreenX = null;
10358            this.pointerScreenY = null;
10359            this.isAnimating = false;
10360            this.scrollCaches = null;
10361            // protect against the initial pointerdown being too close to an edge and starting the scroll
10362            this.everMovedUp = false;
vendor: 6,701 bytes, lines 10363-10514
10363            this.everMovedDown = false;
10364            this.everMovedLeft = false;
10365            this.everMovedRight = false;
10366            this.animate = () => {
10367                if (this.isAnimating) { // wasn't cancelled between animation calls
10368                    let edge = this.computeBestEdge(this.pointerScreenX + window.pageXOffset, this.pointerScreenY + window.pageYOffset);
10369                    if (edge) {
10370                        let now = getTime();
10371                        this.handleSide(edge, (now - this.msSinceRequest) / 1000);
10372                        this.requestAnimation(now);
10373                    }
10374                    else {
10375                        this.isAnimating = false; // will stop animation
10376                    }
10377                }
10378            };
10379        }
10380        start(pageX, pageY, scrollStartEl) {
10381            if (this.isEnabled) {
10382                this.scrollCaches = this.buildCaches(scrollStartEl);
10383                this.pointerScreenX = null;
10384                this.pointerScreenY = null;
10385                this.everMovedUp = false;
10386                this.everMovedDown = false;
10387                this.everMovedLeft = false;
10388                this.everMovedRight = false;
10389                this.handleMove(pageX, pageY);
10390            }
10391        }
10392        handleMove(pageX, pageY) {
10393            if (this.isEnabled) {
10394                let pointerScreenX = pageX - window.pageXOffset;
10395                let pointerScreenY = pageY - window.pageYOffset;
10396                let yDelta = this.pointerScreenY === null ? 0 : pointerScreenY - this.pointerScreenY;
10397                let xDelta = this.pointerScreenX === null ? 0 : pointerScreenX - this.pointerScreenX;
10398                if (yDelta < 0) {
10399                    this.everMovedUp = true;
10400                }
10401                else if (yDelta > 0) {
10402                    this.everMovedDown = true;
10403                }
10404                if (xDelta < 0) {
10405                    this.everMovedLeft = true;
10406                }
10407                else if (xDelta > 0) {
10408                    this.everMovedRight = true;
10409                }
10410                this.pointerScreenX = pointerScreenX;
10411                this.pointerScreenY = pointerScreenY;
10412                if (!this.isAnimating) {
10413                    this.isAnimating = true;
10414                    this.requestAnimation(getTime());
10415                }
10416            }
10417        }
10418        stop() {
10419            if (this.isEnabled) {
10420                this.isAnimating = false; // will stop animation
10421                for (let scrollCache of this.scrollCaches) {
10422                    scrollCache.destroy();
10423                }
10424                this.scrollCaches = null;
10425            }
10426        }
10427        requestAnimation(now) {
10428            this.msSinceRequest = now;
10429            requestAnimationFrame(this.animate);
10430        }
10431        handleSide(edge, seconds) {
10432            let { scrollCache } = edge;
10433            let { edgeThreshold } = this;
10434            let invDistance = edgeThreshold - edge.distance;
10435            let velocity = // the closer to the edge, the faster we scroll
10436                ((invDistance * invDistance) / (edgeThreshold * edgeThreshold)) * // quadratic
10437                this.maxVelocity * seconds;
10438            let sign = 1;
10439            switch (edge.name) {
10440                case 'left':
10441                    sign = -1;
10442                // falls through
10443                case 'right':
10444                    scrollCache.setScrollLeft(scrollCache.getScrollLeft() + velocity * sign);
10445                    break;
10446                case 'top':
10447                    sign = -1;
10448                // falls through
10449                case 'bottom':
10450                    scrollCache.setScrollTop(scrollCache.getScrollTop() + velocity * sign);
10451                    break;
10452            }
10453        }
10454        // left/top are relative to document topleft
10455        computeBestEdge(left, top) {
10456            let { edgeThreshold } = this;
10457            let bestSide = null;
10458            let scrollCaches = this.scrollCaches || [];
10459            for (let scrollCache of scrollCaches) {
10460                let rect = scrollCache.clientRect;
10461                let leftDist = left - rect.left;
10462                let rightDist = rect.right - left;
10463                let topDist = top - rect.top;
10464                let bottomDist = rect.bottom - top;
10465                // completely within the rect?
10466                if (leftDist >= 0 && rightDist >= 0 && topDist >= 0 && bottomDist >= 0) {
10467                    if (topDist <= edgeThreshold && this.everMovedUp && scrollCache.canScrollUp() &&
10468                        (!bestSide || bestSide.distance > topDist)) {
10469                        bestSide = { scrollCache, name: 'top', distance: topDist };
10470                    }
10471                    if (bottomDist <= edgeThreshold && this.everMovedDown && scrollCache.canScrollDown() &&
10472                        (!bestSide || bestSide.distance > bottomDist)) {
10473                        bestSide = { scrollCache, name: 'bottom', distance: bottomDist };
10474                    }
10475                    if (leftDist <= edgeThreshold && this.everMovedLeft && scrollCache.canScrollLeft() &&
10476                        (!bestSide || bestSide.distance > leftDist)) {
10477                        bestSide = { scrollCache, name: 'left', distance: leftDist };
10478                    }
10479                    if (rightDist <= edgeThreshold && this.everMovedRight && scrollCache.canScrollRight() &&
10480                        (!bestSide || bestSide.distance > rightDist)) {
10481                        bestSide = { scrollCache, name: 'right', distance: rightDist };
10482                    }
10483                }
10484            }
10485            return bestSide;
10486        }
10487        buildCaches(scrollStartEl) {
10488            return this.queryScrollEls(scrollStartEl).map((el) => {
10489                if (el === window) {
10490                    return new WindowScrollGeomCache(false); // false = don't listen to user-generated scrolls
10491                }
10492                return new ElementScrollGeomCache(el, false); // false = don't listen to user-generated scrolls
10493            });
10494        }
10495        queryScrollEls(scrollStartEl) {
10496            let els = [];
10497            for (let query of this.scrollQuery) {
10498                if (typeof query === 'object') {
10499                    els.push(query);
10500                }
10501                else {
10502                    els.push(...Array.prototype.slice.call(scrollStartEl.getRootNode().querySelectorAll(query)));
10503                }
10504            }
10505            return els;
10506        }
10507    }
10508
10509    /*
10510    Monitors dragging on an element. Has a number of high-level features:
10511    - minimum distance required before dragging
10512    - minimum wait time ("delay") before dragging
10513    - a mirror element that follows the pointer
10514    */
vendor: 8,987 bytes, lines 10515-10710
10515    class FeaturefulElementDragging extends ElementDragging {
10516        constructor(containerEl, selector) {
10517            super(containerEl);
10518            this.containerEl = containerEl;
10519            // options that can be directly set by caller
10520            // the caller can also set the PointerDragging's options as well
10521            this.delay = null;
10522            this.minDistance = 0;
10523            this.touchScrollAllowed = true; // prevents drag from starting and blocks scrolling during drag
10524            this.mirrorNeedsRevert = false;
10525            this.isInteracting = false; // is the user validly moving the pointer? lasts until pointerup
10526            this.isDragging = false; // is it INTENTFULLY dragging? lasts until after revert animation
10527            this.isDelayEnded = false;
10528            this.isDistanceSurpassed = false;
10529            this.delayTimeoutId = null;
10530            this.onPointerDown = (ev) => {
10531                if (!this.isDragging) { // so new drag doesn't happen while revert animation is going
10532                    this.isInteracting = true;
10533                    this.isDelayEnded = false;
10534                    this.isDistanceSurpassed = false;
10535                    preventSelection(document.body);
10536                    preventContextMenu(document.body);
10537                    // prevent links from being visited if there's an eventual drag.
10538                    // also prevents selection in older browsers (maybe?).
10539                    // not necessary for touch, besides, browser would complain about passiveness.
10540                    if (!ev.isTouch) {
10541                        ev.origEvent.preventDefault();
10542                    }
10543                    this.emitter.trigger('pointerdown', ev);
10544                    if (this.isInteracting && // not destroyed via pointerdown handler
10545                        !this.pointer.shouldIgnoreMove) {
10546                        // actions related to initiating dragstart+dragmove+dragend...
10547                        this.mirror.setIsVisible(false); // reset. caller must set-visible
10548                        this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY); // must happen on first pointer down
10549                        this.startDelay(ev);
10550                        if (!this.minDistance) {
10551                            this.handleDistanceSurpassed(ev);
10552                        }
10553                    }
10554                }
10555            };
10556            this.onPointerMove = (ev) => {
10557                if (this.isInteracting) {
10558                    this.emitter.trigger('pointermove', ev);
10559                    if (!this.isDistanceSurpassed) {
10560                        let minDistance = this.minDistance;
10561                        let distanceSq; // current distance from the origin, squared
10562                        let { deltaX, deltaY } = ev;
10563                        distanceSq = deltaX * deltaX + deltaY * deltaY;
10564                        if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem
10565                            this.handleDistanceSurpassed(ev);
10566                        }
10567                    }
10568                    if (this.isDragging) {
10569                        // a real pointer move? (not one simulated by scrolling)
10570                        if (ev.origEvent.type !== 'scroll') {
10571                            this.mirror.handleMove(ev.pageX, ev.pageY);
10572                            this.autoScroller.handleMove(ev.pageX, ev.pageY);
10573                        }
10574                        this.emitter.trigger('dragmove', ev);
10575                    }
10576                }
10577            };
10578            this.onPointerUp = (ev) => {
10579                if (this.isInteracting) {
10580                    this.isInteracting = false;
10581                    allowSelection(document.body);
10582                    allowContextMenu(document.body);
10583                    this.emitter.trigger('pointerup', ev); // can potentially set mirrorNeedsRevert
10584                    if (this.isDragging) {
10585                        this.autoScroller.stop();
10586                        this.tryStopDrag(ev); // which will stop the mirror
10587                    }
10588                    if (this.delayTimeoutId) {
10589                        clearTimeout(this.delayTimeoutId);
10590                        this.delayTimeoutId = null;
10591                    }
10592                }
10593            };
10594            let pointer = this.pointer = new PointerDragging(containerEl);
10595            pointer.emitter.on('pointerdown', this.onPointerDown);
10596            pointer.emitter.on('pointermove', this.onPointerMove);
10597            pointer.emitter.on('pointerup', this.onPointerUp);
10598            if (selector) {
10599                pointer.selector = selector;
10600            }
10601            this.mirror = new ElementMirror();
10602            this.autoScroller = new AutoScroller();
10603        }
10604        destroy() {
10605            this.pointer.destroy();
10606            // HACK: simulate a pointer-up to end the current drag
10607            // TODO: fire 'dragend' directly and stop interaction. discourage use of pointerup event (b/c might not fire)
10608            this.onPointerUp({});
10609        }
10610        startDelay(ev) {
10611            if (typeof this.delay === 'number') {
10612                this.delayTimeoutId = setTimeout(() => {
10613                    this.delayTimeoutId = null;
10614                    this.handleDelayEnd(ev);
10615                }, this.delay); // not assignable to number!
10616            }
10617            else {
10618                this.handleDelayEnd(ev);
10619            }
10620        }
10621        handleDelayEnd(ev) {
10622            this.isDelayEnded = true;
10623            this.tryStartDrag(ev);
10624        }
10625        handleDistanceSurpassed(ev) {
10626            this.isDistanceSurpassed = true;
10627            this.tryStartDrag(ev);
10628        }
10629        tryStartDrag(ev) {
10630            if (this.isDelayEnded && this.isDistanceSurpassed) {
10631                if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) {
10632                    this.isDragging = true;
10633                    this.mirrorNeedsRevert = false;
10634                    this.autoScroller.start(ev.pageX, ev.pageY, this.containerEl);
10635                    this.emitter.trigger('dragstart', ev);
10636                    if (this.touchScrollAllowed === false) {
10637                        this.pointer.cancelTouchScroll();
10638                    }
10639                }
10640            }
10641        }
10642        tryStopDrag(ev) {
10643            // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events
10644            // that come from the document to fire beforehand. much more convenient this way.
10645            this.mirror.stop(this.mirrorNeedsRevert, this.stopDrag.bind(this, ev));
10646        }
10647        stopDrag(ev) {
10648            this.isDragging = false;
10649            this.emitter.trigger('dragend', ev);
10650        }
10651        // fill in the implementations...
10652        setIgnoreMove(bool) {
10653            this.pointer.shouldIgnoreMove = bool;
10654        }
10655        setMirrorIsVisible(bool) {
10656            this.mirror.setIsVisible(bool);
10657        }
10658        setMirrorNeedsRevert(bool) {
10659            this.mirrorNeedsRevert = bool;
10660        }
10661        setAutoScrollEnabled(bool) {
10662            this.autoScroller.isEnabled = bool;
10663        }
10664    }
10665
10666    /*
10667    When this class is instantiated, it records the offset of an element (relative to the document topleft),
10668    and continues to monitor scrolling, updating the cached coordinates if it needs to.
10669    Does not access the DOM after instantiation, so highly performant.
10670
10671    Also keeps track of all scrolling/overflow:hidden containers that are parents of the given element
10672    and an determine if a given point is inside the combined clipping rectangle.
10673    */
10674    class OffsetTracker {
10675        constructor(el) {
10676            this.origRect = computeRect(el);
10677            // will work fine for divs that have overflow:hidden
10678            this.scrollCaches = getClippingParents(el).map((scrollEl) => new ElementScrollGeomCache(scrollEl, true));
10679        }
10680        destroy() {
10681            for (let scrollCache of this.scrollCaches) {
10682                scrollCache.destroy();
10683            }
10684        }
10685        computeLeft() {
10686            let left = this.origRect.left;
10687            for (let scrollCache of this.scrollCaches) {
10688                left += scrollCache.origScrollLeft - scrollCache.getScrollLeft();
10689            }
10690            return left;
10691        }
10692        computeTop() {
10693            let top = this.origRect.top;
10694            for (let scrollCache of this.scrollCaches) {
10695                top += scrollCache.origScrollTop - scrollCache.getScrollTop();
10696            }
10697            return top;
10698        }
10699        isWithinClipping(pageX, pageY) {
10700            let point = { left: pageX, top: pageY };
10701            for (let scrollCache of this.scrollCaches) {
10702                if (!isIgnoredClipping(scrollCache.getEventTarget()) &&
10703                    !pointInsideRect(point, scrollCache.clientRect)) {
10704                    return false;
10705                }
10706            }
10707            return true;
10708        }
10709    }
10710    // certain clipping containers should never constrain interactions, like <html> and <body>
10711    // https://github.com/fullcalendar/fullcalendar/issues/3615
10712    function isIgnoredClipping(node) {
10713        let tagName = node.tagName;
10714        return tagName === 'HTML' || tagName === 'BODY';
10715    }
10716
10717    /*
10718    Tracks movement over multiple droppable areas (aka "hits")
10719    that exist in one or more DateComponents.
10720    Relies on an existing draggable.
10721
10722    emits:
10723    - pointerdown
10724    - dragstart
10725    - hitchange - fires initially, even if not over a hit
10726    - pointerup
10727    - (hitchange - again, to null, if ended over a hit)
10728    - dragend
10729    */
10730    class HitDragging {
10731        constructor(dragging, droppableStore) {
10732            // options that can be set by caller
10733            this.useSubjectCenter = false;
10734            this.requireInitial = true; // if doesn't start out on a hit, won't emit any events
10735            this.initialHit = null;
10736            this.movingHit = null;
10737            this.finalHit = null; // won't ever be populated if shouldIgnoreMove
10738            this.handlePointerDown = (ev) => {
10739                let { dragging } = this;
10740                this.initialHit = null;
10741                this.movingHit = null;
10742                this.finalHit = null;
10743                this.prepareHits();
10744                this.processFirstCoord(ev);
10745                if (this.initialHit || !this.requireInitial) {
10746                    dragging.setIgnoreMove(false);
vendor: 52,367 bytes, lines 10747-11810
10747                    // TODO: fire this before computing processFirstCoord, so listeners can cancel. this gets fired by almost every handler :(
10748                    this.emitter.trigger('pointerdown', ev);
10749                }
10750                else {
10751                    dragging.setIgnoreMove(true);
10752                }
10753            };
10754            this.handleDragStart = (ev) => {
10755                this.emitter.trigger('dragstart', ev);
10756                this.handleMove(ev, true); // force = fire even if initially null
10757            };
10758            this.handleDragMove = (ev) => {
10759                this.emitter.trigger('dragmove', ev);
10760                this.handleMove(ev);
10761            };
10762            this.handlePointerUp = (ev) => {
10763                this.releaseHits();
10764                this.emitter.trigger('pointerup', ev);
10765            };
10766            this.handleDragEnd = (ev) => {
10767                if (this.movingHit) {
10768                    this.emitter.trigger('hitupdate', null, true, ev);
10769                }
10770                this.finalHit = this.movingHit;
10771                this.movingHit = null;
10772                this.emitter.trigger('dragend', ev);
10773            };
10774            this.droppableStore = droppableStore;
10775            dragging.emitter.on('pointerdown', this.handlePointerDown);
10776            dragging.emitter.on('dragstart', this.handleDragStart);
10777            dragging.emitter.on('dragmove', this.handleDragMove);
10778            dragging.emitter.on('pointerup', this.handlePointerUp);
10779            dragging.emitter.on('dragend', this.handleDragEnd);
10780            this.dragging = dragging;
10781            this.emitter = new Emitter();
10782        }
10783        // sets initialHit
10784        // sets coordAdjust
10785        processFirstCoord(ev) {
10786            let origPoint = { left: ev.pageX, top: ev.pageY };
10787            let adjustedPoint = origPoint;
10788            let subjectEl = ev.subjectEl;
10789            let subjectRect;
10790            if (subjectEl instanceof HTMLElement) { // i.e. not a Document/ShadowRoot
10791                subjectRect = computeRect(subjectEl);
10792                adjustedPoint = constrainPoint(adjustedPoint, subjectRect);
10793            }
10794            let initialHit = this.initialHit = this.queryHitForOffset(adjustedPoint.left, adjustedPoint.top);
10795            if (initialHit) {
10796                if (this.useSubjectCenter && subjectRect) {
10797                    let slicedSubjectRect = intersectRects(subjectRect, initialHit.rect);
10798                    if (slicedSubjectRect) {
10799                        adjustedPoint = getRectCenter(slicedSubjectRect);
10800                    }
10801                }
10802                this.coordAdjust = diffPoints(adjustedPoint, origPoint);
10803            }
10804            else {
10805                this.coordAdjust = { left: 0, top: 0 };
10806            }
10807        }
10808        handleMove(ev, forceHandle) {
10809            let hit = this.queryHitForOffset(ev.pageX + this.coordAdjust.left, ev.pageY + this.coordAdjust.top);
10810            if (forceHandle || !isHitsEqual(this.movingHit, hit)) {
10811                this.movingHit = hit;
10812                this.emitter.trigger('hitupdate', hit, false, ev);
10813            }
10814        }
10815        prepareHits() {
10816            this.offsetTrackers = mapHash(this.droppableStore, (interactionSettings) => {
10817                interactionSettings.component.prepareHits();
10818                return new OffsetTracker(interactionSettings.el);
10819            });
10820        }
10821        releaseHits() {
10822            let { offsetTrackers } = this;
10823            for (let id in offsetTrackers) {
10824                offsetTrackers[id].destroy();
10825            }
10826            this.offsetTrackers = {};
10827        }
10828        queryHitForOffset(offsetLeft, offsetTop) {
10829            let { droppableStore, offsetTrackers } = this;
10830            let bestHit = null;
10831            for (let id in droppableStore) {
10832                let component = droppableStore[id].component;
10833                let offsetTracker = offsetTrackers[id];
10834                if (offsetTracker && // wasn't destroyed mid-drag
10835                    offsetTracker.isWithinClipping(offsetLeft, offsetTop)) {
10836                    let originLeft = offsetTracker.computeLeft();
10837                    let originTop = offsetTracker.computeTop();
10838                    let positionLeft = offsetLeft - originLeft;
10839                    let positionTop = offsetTop - originTop;
10840                    let { origRect } = offsetTracker;
10841                    let width = origRect.right - origRect.left;
10842                    let height = origRect.bottom - origRect.top;
10843                    if (
10844                        // must be within the element's bounds
10845                        positionLeft >= 0 && positionLeft < width &&
10846                        positionTop >= 0 && positionTop < height) {
10847                        let hit = component.queryHit(positionLeft, positionTop, width, height);
10848                        if (hit && (
10849                                // make sure the hit is within activeRange, meaning it's not a dead cell
10850                                rangeContainsRange(hit.dateProfile.activeRange, hit.dateSpan.range)) &&
10851                            (!bestHit || hit.layer > bestHit.layer)) {
10852                            hit.componentId = id;
10853                            hit.context = component.context;
10854                            // TODO: better way to re-orient rectangle
10855                            hit.rect.left += originLeft;
10856                            hit.rect.right += originLeft;
10857                            hit.rect.top += originTop;
10858                            hit.rect.bottom += originTop;
10859                            bestHit = hit;
10860                        }
10861                    }
10862                }
10863            }
10864            return bestHit;
10865        }
10866    }
10867    function isHitsEqual(hit0, hit1) {
10868        if (!hit0 && !hit1) {
10869            return true;
10870        }
10871        if (Boolean(hit0) !== Boolean(hit1)) {
10872            return false;
10873        }
10874        return isDateSpansEqual(hit0.dateSpan, hit1.dateSpan);
10875    }
10876
10877    function buildDatePointApiWithContext(dateSpan, context) {
10878        let props = {};
10879        for (let transform of context.pluginHooks.datePointTransforms) {
10880            Object.assign(props, transform(dateSpan, context));
10881        }
10882        Object.assign(props, buildDatePointApi(dateSpan, context.dateEnv));
10883        return props;
10884    }
10885    function buildDatePointApi(span, dateEnv) {
10886        return {
10887            date: dateEnv.toDate(span.range.start),
10888            dateStr: dateEnv.formatIso(span.range.start, { omitTime: span.allDay }),
10889            allDay: span.allDay,
10890        };
10891    }
10892
10893    /*
10894    Monitors when the user clicks on a specific date/time of a component.
10895    A pointerdown+pointerup on the same "hit" constitutes a click.
10896    */
10897    class DateClicking extends Interaction {
10898        constructor(settings) {
10899            super(settings);
10900            this.handlePointerDown = (pev) => {
10901                let { dragging } = this;
10902                let downEl = pev.origEvent.target;
10903                // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired
10904                dragging.setIgnoreMove(!this.component.isValidDateDownEl(downEl));
10905            };
10906            // won't even fire if moving was ignored
10907            this.handleDragEnd = (ev) => {
10908                let { component } = this;
10909                let { pointer } = this.dragging;
10910                if (!pointer.wasTouchScroll) {
10911                    let { initialHit, finalHit } = this.hitDragging;
10912                    if (initialHit && finalHit && isHitsEqual(initialHit, finalHit)) {
10913                        let { context } = component;
10914                        let arg = Object.assign(Object.assign({}, buildDatePointApiWithContext(initialHit.dateSpan, context)), { dayEl: initialHit.dayEl, jsEvent: ev.origEvent, view: context.viewApi || context.calendarApi.view });
10915                        context.emitter.trigger('dateClick', arg);
10916                    }
10917                }
10918            };
10919            // we DO want to watch pointer moves because otherwise finalHit won't get populated
10920            this.dragging = new FeaturefulElementDragging(settings.el);
10921            this.dragging.autoScroller.isEnabled = false;
10922            let hitDragging = this.hitDragging = new HitDragging(this.dragging, interactionSettingsToStore(settings));
10923            hitDragging.emitter.on('pointerdown', this.handlePointerDown);
10924            hitDragging.emitter.on('dragend', this.handleDragEnd);
10925        }
10926        destroy() {
10927            this.dragging.destroy();
10928        }
10929    }
10930
10931    /*
10932    Tracks when the user selects a portion of time of a component,
10933    constituted by a drag over date cells, with a possible delay at the beginning of the drag.
10934    */
10935    class DateSelecting extends Interaction {
10936        constructor(settings) {
10937            super(settings);
10938            this.dragSelection = null;
10939            this.handlePointerDown = (ev) => {
10940                let { component, dragging } = this;
10941                let { options } = component.context;
10942                let canSelect = options.selectable &&
10943                    component.isValidDateDownEl(ev.origEvent.target);
10944                // don't bother to watch expensive moves if component won't do selection
10945                dragging.setIgnoreMove(!canSelect);
10946                // if touch, require user to hold down
10947                dragging.delay = ev.isTouch ? getComponentTouchDelay$1(component) : null;
10948            };
10949            this.handleDragStart = (ev) => {
10950                this.component.context.calendarApi.unselect(ev); // unselect previous selections
10951            };
10952            this.handleHitUpdate = (hit, isFinal) => {
10953                let { context } = this.component;
10954                let dragSelection = null;
10955                let isInvalid = false;
10956                if (hit) {
10957                    let initialHit = this.hitDragging.initialHit;
10958                    let disallowed = hit.componentId === initialHit.componentId
10959                        && this.isHitComboAllowed
10960                        && !this.isHitComboAllowed(initialHit, hit);
10961                    if (!disallowed) {
10962                        dragSelection = joinHitsIntoSelection(initialHit, hit, context.pluginHooks.dateSelectionTransformers);
10963                    }
10964                    if (!dragSelection || !isDateSelectionValid(dragSelection, hit.dateProfile, context)) {
10965                        isInvalid = true;
10966                        dragSelection = null;
10967                    }
10968                }
10969                if (dragSelection) {
10970                    context.dispatch({ type: 'SELECT_DATES', selection: dragSelection });
10971                }
10972                else if (!isFinal) { // only unselect if moved away while dragging
10973                    context.dispatch({ type: 'UNSELECT_DATES' });
10974                }
10975                if (!isInvalid) {
10976                    enableCursor();
10977                }
10978                else {
10979                    disableCursor();
10980                }
10981                if (!isFinal) {
10982                    this.dragSelection = dragSelection; // only clear if moved away from all hits while dragging
10983                }
10984            };
10985            this.handlePointerUp = (pev) => {
10986                if (this.dragSelection) {
10987                    // selection is already rendered, so just need to report selection
10988                    triggerDateSelect(this.dragSelection, pev, this.component.context);
10989                    this.dragSelection = null;
10990                }
10991            };
10992            let { component } = settings;
10993            let { options } = component.context;
10994            let dragging = this.dragging = new FeaturefulElementDragging(settings.el);
10995            dragging.touchScrollAllowed = false;
10996            dragging.minDistance = options.selectMinDistance || 0;
10997            dragging.autoScroller.isEnabled = options.dragScroll;
10998            let hitDragging = this.hitDragging = new HitDragging(this.dragging, interactionSettingsToStore(settings));
10999            hitDragging.emitter.on('pointerdown', this.handlePointerDown);
11000            hitDragging.emitter.on('dragstart', this.handleDragStart);
11001            hitDragging.emitter.on('hitupdate', this.handleHitUpdate);
11002            hitDragging.emitter.on('pointerup', this.handlePointerUp);
11003        }
11004        destroy() {
11005            this.dragging.destroy();
11006        }
11007    }
11008    function getComponentTouchDelay$1(component) {
11009        let { options } = component.context;
11010        let delay = options.selectLongPressDelay;
11011        if (delay == null) {
11012            delay = options.longPressDelay;
11013        }
11014        return delay;
11015    }
11016    function joinHitsIntoSelection(hit0, hit1, dateSelectionTransformers) {
11017        let dateSpan0 = hit0.dateSpan;
11018        let dateSpan1 = hit1.dateSpan;
11019        let ms = [
11020            dateSpan0.range.start,
11021            dateSpan0.range.end,
11022            dateSpan1.range.start,
11023            dateSpan1.range.end,
11024        ];
11025        ms.sort(compareNumbers);
11026        let props = {};
11027        for (let transformer of dateSelectionTransformers) {
11028            let res = transformer(hit0, hit1);
11029            if (res === false) {
11030                return null;
11031            }
11032            if (res) {
11033                Object.assign(props, res);
11034            }
11035        }
11036        props.range = { start: ms[0], end: ms[3] };
11037        props.allDay = dateSpan0.allDay;
11038        return props;
11039    }
11040
11041    class EventDragging extends Interaction {
11042        constructor(settings) {
11043            super(settings);
11044            // internal state
11045            this.subjectEl = null;
11046            this.subjectSeg = null; // the seg being selected/dragged
11047            this.isDragging = false;
11048            this.eventRange = null;
11049            this.relevantEvents = null; // the events being dragged
11050            this.receivingContext = null;
11051            this.validMutation = null;
11052            this.mutatedRelevantEvents = null;
11053            this.handlePointerDown = (ev) => {
11054                let origTarget = ev.origEvent.target;
11055                let { component, dragging } = this;
11056                let { mirror } = dragging;
11057                let { options } = component.context;
11058                let initialContext = component.context;
11059                this.subjectEl = ev.subjectEl;
11060                let subjectSeg = this.subjectSeg = getElSeg(ev.subjectEl);
11061                let eventRange = this.eventRange = subjectSeg.eventRange;
11062                let eventInstanceId = eventRange.instance.instanceId;
11063                this.relevantEvents = getRelevantEvents(initialContext.getCurrentData().eventStore, eventInstanceId);
11064                dragging.minDistance = ev.isTouch ? 0 : options.eventDragMinDistance;
11065                dragging.delay =
11066                    // only do a touch delay if touch and this event hasn't been selected yet
11067                    (ev.isTouch && eventInstanceId !== component.props.eventSelection) ?
11068                        getComponentTouchDelay(component) :
11069                        null;
11070                if (options.fixedMirrorParent) {
11071                    mirror.parentNode = options.fixedMirrorParent;
11072                }
11073                else {
11074                    mirror.parentNode = elementClosest(origTarget, '.fc');
11075                }
11076                mirror.revertDuration = options.dragRevertDuration;
11077                let isValid = component.isValidSegDownEl(origTarget) &&
11078                    !elementClosest(origTarget, '.fc-event-resizer'); // NOT on a resizer
11079                dragging.setIgnoreMove(!isValid);
11080                // disable dragging for elements that are resizable (ie, selectable)
11081                // but are not draggable
11082                this.isDragging = isValid &&
11083                    ev.subjectEl.classList.contains('fc-event-draggable');
11084            };
11085            this.handleDragStart = (ev) => {
11086                let initialContext = this.component.context;
11087                let eventRange = this.eventRange;
11088                let eventInstanceId = eventRange.instance.instanceId;
11089                if (ev.isTouch) {
11090                    // need to select a different event?
11091                    if (eventInstanceId !== this.component.props.eventSelection) {
11092                        initialContext.dispatch({ type: 'SELECT_EVENT', eventInstanceId });
11093                    }
11094                }
11095                else {
11096                    // if now using mouse, but was previous touch interaction, clear selected event
11097                    initialContext.dispatch({ type: 'UNSELECT_EVENT' });
11098                }
11099                if (this.isDragging) {
11100                    initialContext.calendarApi.unselect(ev); // unselect *date* selection
11101                    initialContext.emitter.trigger('eventDragStart', {
11102                        el: this.subjectEl,
11103                        event: new EventImpl(initialContext, eventRange.def, eventRange.instance),
11104                        jsEvent: ev.origEvent,
11105                        view: initialContext.viewApi,
11106                    });
11107                }
11108            };
11109            this.handleHitUpdate = (hit, isFinal) => {
11110                if (!this.isDragging) {
11111                    return;
11112                }
11113                let relevantEvents = this.relevantEvents;
11114                let initialHit = this.hitDragging.initialHit;
11115                let initialContext = this.component.context;
11116                // states based on new hit
11117                let receivingContext = null;
11118                let mutation = null;
11119                let mutatedRelevantEvents = null;
11120                let isInvalid = false;
11121                let interaction = {
11122                    affectedEvents: relevantEvents,
11123                    mutatedEvents: createEmptyEventStore(),
11124                    isEvent: true,
11125                };
11126                if (hit) {
11127                    receivingContext = hit.context;
11128                    let receivingOptions = receivingContext.options;
11129                    if (initialContext === receivingContext ||
11130                        (receivingOptions.editable && receivingOptions.droppable)) {
11131                        mutation = computeEventMutation(initialHit, hit, receivingContext.getCurrentData().pluginHooks.eventDragMutationMassagers);
11132                        if (mutation) {
11133                            mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, receivingContext.getCurrentData().eventUiBases, mutation, receivingContext);
11134                            interaction.mutatedEvents = mutatedRelevantEvents;
11135                            if (!isInteractionValid(interaction, hit.dateProfile, receivingContext)) {
11136                                isInvalid = true;
11137                                mutation = null;
11138                                mutatedRelevantEvents = null;
11139                                interaction.mutatedEvents = createEmptyEventStore();
11140                            }
11141                        }
11142                    }
11143                    else {
11144                        receivingContext = null;
11145                    }
11146                }
11147                this.displayDrag(receivingContext, interaction);
11148                if (!isInvalid) {
11149                    enableCursor();
11150                }
11151                else {
11152                    disableCursor();
11153                }
11154                if (!isFinal) {
11155                    if (initialContext === receivingContext && // TODO: write test for this
11156                        isHitsEqual(initialHit, hit)) {
11157                        mutation = null;
11158                    }
11159                    this.dragging.setMirrorNeedsRevert(!mutation);
11160                    // render the mirror if no already-rendered mirror
11161                    // TODO: wish we could somehow wait for dispatch to guarantee render
11162                    this.dragging.setMirrorIsVisible(!hit || !this.subjectEl.getRootNode().querySelector('.fc-event-mirror'));
11163                    // assign states based on new hit
11164                    this.receivingContext = receivingContext;
11165                    this.validMutation = mutation;
11166                    this.mutatedRelevantEvents = mutatedRelevantEvents;
11167                }
11168            };
11169            this.handlePointerUp = () => {
11170                if (!this.isDragging) {
11171                    this.cleanup(); // because handleDragEnd won't fire
11172                }
11173            };
11174            this.handleDragEnd = (ev) => {
11175                if (this.isDragging) {
11176                    let initialContext = this.component.context;
11177                    let initialView = initialContext.viewApi;
11178                    let { receivingContext, validMutation } = this;
11179                    let eventDef = this.eventRange.def;
11180                    let eventInstance = this.eventRange.instance;
11181                    let eventApi = new EventImpl(initialContext, eventDef, eventInstance);
11182                    let relevantEvents = this.relevantEvents;
11183                    let mutatedRelevantEvents = this.mutatedRelevantEvents;
11184                    let { finalHit } = this.hitDragging;
11185                    this.clearDrag(); // must happen after revert animation
11186                    initialContext.emitter.trigger('eventDragStop', {
11187                        el: this.subjectEl,
11188                        event: eventApi,
11189                        jsEvent: ev.origEvent,
11190                        view: initialView,
11191                    });
11192                    if (validMutation) {
11193                        // dropped within same calendar
11194                        if (receivingContext === initialContext) {
11195                            let updatedEventApi = new EventImpl(initialContext, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null);
11196                            initialContext.dispatch({
11197                                type: 'MERGE_EVENTS',
11198                                eventStore: mutatedRelevantEvents,
11199                            });
11200                            let eventChangeArg = {
11201                                oldEvent: eventApi,
11202                                event: updatedEventApi,
11203                                relatedEvents: buildEventApis(mutatedRelevantEvents, initialContext, eventInstance),
11204                                revert() {
11205                                    initialContext.dispatch({
11206                                        type: 'MERGE_EVENTS',
11207                                        eventStore: relevantEvents, // the pre-change data
11208                                    });
11209                                },
11210                            };
11211                            let transformed = {};
11212                            for (let transformer of initialContext.getCurrentData().pluginHooks.eventDropTransformers) {
11213                                Object.assign(transformed, transformer(validMutation, initialContext));
11214                            }
11215                            initialContext.emitter.trigger('eventDrop', Object.assign(Object.assign(Object.assign({}, eventChangeArg), transformed), { el: ev.subjectEl, delta: validMutation.datesDelta, jsEvent: ev.origEvent, view: initialView }));
11216                            initialContext.emitter.trigger('eventChange', eventChangeArg);
11217                            // dropped in different calendar
11218                        }
11219                        else if (receivingContext) {
11220                            let eventRemoveArg = {
11221                                event: eventApi,
11222                                relatedEvents: buildEventApis(relevantEvents, initialContext, eventInstance),
11223                                revert() {
11224                                    initialContext.dispatch({
11225                                        type: 'MERGE_EVENTS',
11226                                        eventStore: relevantEvents,
11227                                    });
11228                                },
11229                            };
11230                            initialContext.emitter.trigger('eventLeave', Object.assign(Object.assign({}, eventRemoveArg), { draggedEl: ev.subjectEl, view: initialView }));
11231                            initialContext.dispatch({
11232                                type: 'REMOVE_EVENTS',
11233                                eventStore: relevantEvents,
11234                            });
11235                            initialContext.emitter.trigger('eventRemove', eventRemoveArg);
11236                            let addedEventDef = mutatedRelevantEvents.defs[eventDef.defId];
11237                            let addedEventInstance = mutatedRelevantEvents.instances[eventInstance.instanceId];
11238                            let addedEventApi = new EventImpl(receivingContext, addedEventDef, addedEventInstance);
11239                            receivingContext.dispatch({
11240                                type: 'MERGE_EVENTS',
11241                                eventStore: mutatedRelevantEvents,
11242                            });
11243                            let eventAddArg = {
11244                                event: addedEventApi,
11245                                relatedEvents: buildEventApis(mutatedRelevantEvents, receivingContext, addedEventInstance),
11246                                revert() {
11247                                    receivingContext.dispatch({
11248                                        type: 'REMOVE_EVENTS',
11249                                        eventStore: mutatedRelevantEvents,
11250                                    });
11251                                },
11252                            };
11253                            receivingContext.emitter.trigger('eventAdd', eventAddArg);
11254                            if (ev.isTouch) {
11255                                receivingContext.dispatch({
11256                                    type: 'SELECT_EVENT',
11257                                    eventInstanceId: eventInstance.instanceId,
11258                                });
11259                            }
11260                            receivingContext.emitter.trigger('drop', Object.assign(Object.assign({}, buildDatePointApiWithContext(finalHit.dateSpan, receivingContext)), { draggedEl: ev.subjectEl, jsEvent: ev.origEvent, view: finalHit.context.viewApi }));
11261                            receivingContext.emitter.trigger('eventReceive', Object.assign(Object.assign({}, eventAddArg), { draggedEl: ev.subjectEl, view: finalHit.context.viewApi }));
11262                        }
11263                    }
11264                    else {
11265                        initialContext.emitter.trigger('_noEventDrop');
11266                    }
11267                }
11268                this.cleanup();
11269            };
11270            let { component } = this;
11271            let { options } = component.context;
11272            let dragging = this.dragging = new FeaturefulElementDragging(settings.el);
11273            dragging.pointer.selector = EventDragging.SELECTOR;
11274            dragging.touchScrollAllowed = false;
11275            dragging.autoScroller.isEnabled = options.dragScroll;
11276            let hitDragging = this.hitDragging = new HitDragging(this.dragging, interactionSettingsStore);
11277            hitDragging.useSubjectCenter = settings.useEventCenter;
11278            hitDragging.emitter.on('pointerdown', this.handlePointerDown);
11279            hitDragging.emitter.on('dragstart', this.handleDragStart);
11280            hitDragging.emitter.on('hitupdate', this.handleHitUpdate);
11281            hitDragging.emitter.on('pointerup', this.handlePointerUp);
11282            hitDragging.emitter.on('dragend', this.handleDragEnd);
11283        }
11284        destroy() {
11285            this.dragging.destroy();
11286        }
11287        // render a drag state on the next receivingCalendar
11288        displayDrag(nextContext, state) {
11289            let initialContext = this.component.context;
11290            let prevContext = this.receivingContext;
11291            // does the previous calendar need to be cleared?
11292            if (prevContext && prevContext !== nextContext) {
11293                // does the initial calendar need to be cleared?
11294                // if so, don't clear all the way. we still need to to hide the affectedEvents
11295                if (prevContext === initialContext) {
11296                    prevContext.dispatch({
11297                        type: 'SET_EVENT_DRAG',
11298                        state: {
11299                            affectedEvents: state.affectedEvents,
11300                            mutatedEvents: createEmptyEventStore(),
11301                            isEvent: true,
11302                        },
11303                    });
11304                    // completely clear the old calendar if it wasn't the initial
11305                }
11306                else {
11307                    prevContext.dispatch({ type: 'UNSET_EVENT_DRAG' });
11308                }
11309            }
11310            if (nextContext) {
11311                nextContext.dispatch({ type: 'SET_EVENT_DRAG', state });
11312            }
11313        }
11314        clearDrag() {
11315            let initialCalendar = this.component.context;
11316            let { receivingContext } = this;
11317            if (receivingContext) {
11318                receivingContext.dispatch({ type: 'UNSET_EVENT_DRAG' });
11319            }
11320            // the initial calendar might have an dummy drag state from displayDrag
11321            if (initialCalendar !== receivingContext) {
11322                initialCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' });
11323            }
11324        }
11325        cleanup() {
11326            this.subjectSeg = null;
11327            this.isDragging = false;
11328            this.eventRange = null;
11329            this.relevantEvents = null;
11330            this.receivingContext = null;
11331            this.validMutation = null;
11332            this.mutatedRelevantEvents = null;
11333        }
11334    }
11335    // TODO: test this in IE11
11336    // QUESTION: why do we need it on the resizable???
11337    EventDragging.SELECTOR = '.fc-event-draggable, .fc-event-resizable';
11338    function computeEventMutation(hit0, hit1, massagers) {
11339        let dateSpan0 = hit0.dateSpan;
11340        let dateSpan1 = hit1.dateSpan;
11341        let date0 = dateSpan0.range.start;
11342        let date1 = dateSpan1.range.start;
11343        let standardProps = {};
11344        if (dateSpan0.allDay !== dateSpan1.allDay) {
11345            standardProps.allDay = dateSpan1.allDay;
11346            standardProps.hasEnd = hit1.context.options.allDayMaintainDuration;
11347            if (dateSpan1.allDay) {
11348                // means date1 is already start-of-day,
11349                // but date0 needs to be converted
11350                date0 = startOfDay(date0);
11351            }
11352        }
11353        let delta = diffDates(date0, date1, hit0.context.dateEnv, hit0.componentId === hit1.componentId ?
11354            hit0.largeUnit :
11355            null);
11356        if (delta.milliseconds) { // has hours/minutes/seconds
11357            standardProps.allDay = false;
11358        }
11359        let mutation = {
11360            datesDelta: delta,
11361            standardProps,
11362        };
11363        for (let massager of massagers) {
11364            massager(mutation, hit0, hit1);
11365        }
11366        return mutation;
11367    }
11368    function getComponentTouchDelay(component) {
11369        let { options } = component.context;
11370        let delay = options.eventLongPressDelay;
11371        if (delay == null) {
11372            delay = options.longPressDelay;
11373        }
11374        return delay;
11375    }
11376
11377    class EventResizing extends Interaction {
11378        constructor(settings) {
11379            super(settings);
11380            // internal state
11381            this.draggingSegEl = null;
11382            this.draggingSeg = null; // TODO: rename to resizingSeg? subjectSeg?
11383            this.eventRange = null;
11384            this.relevantEvents = null;
11385            this.validMutation = null;
11386            this.mutatedRelevantEvents = null;
11387            this.handlePointerDown = (ev) => {
11388                let { component } = this;
11389                let segEl = this.querySegEl(ev);
11390                let seg = getElSeg(segEl);
11391                let eventRange = this.eventRange = seg.eventRange;
11392                this.dragging.minDistance = component.context.options.eventDragMinDistance;
11393                // if touch, need to be working with a selected event
11394                this.dragging.setIgnoreMove(!this.component.isValidSegDownEl(ev.origEvent.target) ||
11395                    (ev.isTouch && this.component.props.eventSelection !== eventRange.instance.instanceId));
11396            };
11397            this.handleDragStart = (ev) => {
11398                let { context } = this.component;
11399                let eventRange = this.eventRange;
11400                this.relevantEvents = getRelevantEvents(context.getCurrentData().eventStore, this.eventRange.instance.instanceId);
11401                let segEl = this.querySegEl(ev);
11402                this.draggingSegEl = segEl;
11403                this.draggingSeg = getElSeg(segEl);
11404                context.calendarApi.unselect();
11405                context.emitter.trigger('eventResizeStart', {
11406                    el: segEl,
11407                    event: new EventImpl(context, eventRange.def, eventRange.instance),
11408                    jsEvent: ev.origEvent,
11409                    view: context.viewApi,
11410                });
11411            };
11412            this.handleHitUpdate = (hit, isFinal, ev) => {
11413                let { context } = this.component;
11414                let relevantEvents = this.relevantEvents;
11415                let initialHit = this.hitDragging.initialHit;
11416                let eventInstance = this.eventRange.instance;
11417                let mutation = null;
11418                let mutatedRelevantEvents = null;
11419                let isInvalid = false;
11420                let interaction = {
11421                    affectedEvents: relevantEvents,
11422                    mutatedEvents: createEmptyEventStore(),
11423                    isEvent: true,
11424                };
11425                if (hit) {
11426                    let disallowed = hit.componentId === initialHit.componentId
11427                        && this.isHitComboAllowed
11428                        && !this.isHitComboAllowed(initialHit, hit);
11429                    if (!disallowed) {
11430                        mutation = computeMutation(initialHit, hit, ev.subjectEl.classList.contains('fc-event-resizer-start'), eventInstance.range);
11431                    }
11432                }
11433                if (mutation) {
11434                    mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, context.getCurrentData().eventUiBases, mutation, context);
11435                    interaction.mutatedEvents = mutatedRelevantEvents;
11436                    if (!isInteractionValid(interaction, hit.dateProfile, context)) {
11437                        isInvalid = true;
11438                        mutation = null;
11439                        mutatedRelevantEvents = null;
11440                        interaction.mutatedEvents = null;
11441                    }
11442                }
11443                if (mutatedRelevantEvents) {
11444                    context.dispatch({
11445                        type: 'SET_EVENT_RESIZE',
11446                        state: interaction,
11447                    });
11448                }
11449                else {
11450                    context.dispatch({ type: 'UNSET_EVENT_RESIZE' });
11451                }
11452                if (!isInvalid) {
11453                    enableCursor();
11454                }
11455                else {
11456                    disableCursor();
11457                }
11458                if (!isFinal) {
11459                    if (mutation && isHitsEqual(initialHit, hit)) {
11460                        mutation = null;
11461                    }
11462                    this.validMutation = mutation;
11463                    this.mutatedRelevantEvents = mutatedRelevantEvents;
11464                }
11465            };
11466            this.handleDragEnd = (ev) => {
11467                let { context } = this.component;
11468                let eventDef = this.eventRange.def;
11469                let eventInstance = this.eventRange.instance;
11470                let eventApi = new EventImpl(context, eventDef, eventInstance);
11471                let relevantEvents = this.relevantEvents;
11472                let mutatedRelevantEvents = this.mutatedRelevantEvents;
11473                context.emitter.trigger('eventResizeStop', {
11474                    el: this.draggingSegEl,
11475                    event: eventApi,
11476                    jsEvent: ev.origEvent,
11477                    view: context.viewApi,
11478                });
11479                if (this.validMutation) {
11480                    let updatedEventApi = new EventImpl(context, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null);
11481                    context.dispatch({
11482                        type: 'MERGE_EVENTS',
11483                        eventStore: mutatedRelevantEvents,
11484                    });
11485                    let eventChangeArg = {
11486                        oldEvent: eventApi,
11487                        event: updatedEventApi,
11488                        relatedEvents: buildEventApis(mutatedRelevantEvents, context, eventInstance),
11489                        revert() {
11490                            context.dispatch({
11491                                type: 'MERGE_EVENTS',
11492                                eventStore: relevantEvents, // the pre-change events
11493                            });
11494                        },
11495                    };
11496                    context.emitter.trigger('eventResize', Object.assign(Object.assign({}, eventChangeArg), { el: this.draggingSegEl, startDelta: this.validMutation.startDelta || createDuration(0), endDelta: this.validMutation.endDelta || createDuration(0), jsEvent: ev.origEvent, view: context.viewApi }));
11497                    context.emitter.trigger('eventChange', eventChangeArg);
11498                }
11499                else {
11500                    context.emitter.trigger('_noEventResize');
11501                }
11502                // reset all internal state
11503                this.draggingSeg = null;
11504                this.relevantEvents = null;
11505                this.validMutation = null;
11506                // okay to keep eventInstance around. useful to set it in handlePointerDown
11507            };
11508            let { component } = settings;
11509            let dragging = this.dragging = new FeaturefulElementDragging(settings.el);
11510            dragging.pointer.selector = '.fc-event-resizer';
11511            dragging.touchScrollAllowed = false;
11512            dragging.autoScroller.isEnabled = component.context.options.dragScroll;
11513            let hitDragging = this.hitDragging = new HitDragging(this.dragging, interactionSettingsToStore(settings));
11514            hitDragging.emitter.on('pointerdown', this.handlePointerDown);
11515            hitDragging.emitter.on('dragstart', this.handleDragStart);
11516            hitDragging.emitter.on('hitupdate', this.handleHitUpdate);
11517            hitDragging.emitter.on('dragend', this.handleDragEnd);
11518        }
11519        destroy() {
11520            this.dragging.destroy();
11521        }
11522        querySegEl(ev) {
11523            return elementClosest(ev.subjectEl, '.fc-event');
11524        }
11525    }
11526    function computeMutation(hit0, hit1, isFromStart, instanceRange) {
11527        let dateEnv = hit0.context.dateEnv;
11528        let date0 = hit0.dateSpan.range.start;
11529        let date1 = hit1.dateSpan.range.start;
11530        let delta = diffDates(date0, date1, dateEnv, hit0.largeUnit);
11531        if (isFromStart) {
11532            if (dateEnv.add(instanceRange.start, delta) < instanceRange.end) {
11533                return { startDelta: delta };
11534            }
11535        }
11536        else if (dateEnv.add(instanceRange.end, delta) > instanceRange.start) {
11537            return { endDelta: delta };
11538        }
11539        return null;
11540    }
11541
11542    class UnselectAuto {
11543        constructor(context) {
11544            this.context = context;
11545            this.isRecentPointerDateSelect = false; // wish we could use a selector to detect date selection, but uses hit system
11546            this.matchesCancel = false;
11547            this.matchesEvent = false;
11548            this.onSelect = (selectInfo) => {
11549                if (selectInfo.jsEvent) {
11550                    this.isRecentPointerDateSelect = true;
11551                }
11552            };
11553            this.onDocumentPointerDown = (pev) => {
11554                let unselectCancel = this.context.options.unselectCancel;
11555                let downEl = getEventTargetViaRoot(pev.origEvent);
11556                this.matchesCancel = !!elementClosest(downEl, unselectCancel);
11557                this.matchesEvent = !!elementClosest(downEl, EventDragging.SELECTOR); // interaction started on an event?
11558            };
11559            this.onDocumentPointerUp = (pev) => {
11560                let { context } = this;
11561                let { documentPointer } = this;
11562                let calendarState = context.getCurrentData();
11563                // touch-scrolling should never unfocus any type of selection
11564                if (!documentPointer.wasTouchScroll) {
11565                    if (calendarState.dateSelection && // an existing date selection?
11566                        !this.isRecentPointerDateSelect // a new pointer-initiated date selection since last onDocumentPointerUp?
11567                    ) {
11568                        let unselectAuto = context.options.unselectAuto;
11569                        if (unselectAuto && (!unselectAuto || !this.matchesCancel)) {
11570                            context.calendarApi.unselect(pev);
11571                        }
11572                    }
11573                    if (calendarState.eventSelection && // an existing event selected?
11574                        !this.matchesEvent // interaction DIDN'T start on an event
11575                    ) {
11576                        context.dispatch({ type: 'UNSELECT_EVENT' });
11577                    }
11578                }
11579                this.isRecentPointerDateSelect = false;
11580            };
11581            let documentPointer = this.documentPointer = new PointerDragging(document);
11582            documentPointer.shouldIgnoreMove = true;
11583            documentPointer.shouldWatchScroll = false;
11584            documentPointer.emitter.on('pointerdown', this.onDocumentPointerDown);
11585            documentPointer.emitter.on('pointerup', this.onDocumentPointerUp);
11586            /*
11587            TODO: better way to know about whether there was a selection with the pointer
11588            */
11589            context.emitter.on('select', this.onSelect);
11590        }
11591        destroy() {
11592            this.context.emitter.off('select', this.onSelect);
11593            this.documentPointer.destroy();
11594        }
11595    }
11596
11597    const OPTION_REFINERS$3 = {
11598        fixedMirrorParent: identity,
11599    };
11600    const LISTENER_REFINERS = {
11601        dateClick: identity,
11602        eventDragStart: identity,
11603        eventDragStop: identity,
11604        eventDrop: identity,
11605        eventResizeStart: identity,
11606        eventResizeStop: identity,
11607        eventResize: identity,
11608        drop: identity,
11609        eventReceive: identity,
11610        eventLeave: identity,
11611    };
11612
11613    /*
11614    Given an already instantiated draggable object for one-or-more elements,
11615    Interprets any dragging as an attempt to drag an events that lives outside
11616    of a calendar onto a calendar.
11617    */
11618    class ExternalElementDragging {
11619        constructor(dragging, suppliedDragMeta) {
11620            this.receivingContext = null;
11621            this.droppableEvent = null; // will exist for all drags, even if create:false
11622            this.suppliedDragMeta = null;
11623            this.dragMeta = null;
11624            this.handleDragStart = (ev) => {
11625                this.dragMeta = this.buildDragMeta(ev.subjectEl);
11626            };
11627            this.handleHitUpdate = (hit, isFinal, ev) => {
11628                let { dragging } = this.hitDragging;
11629                let receivingContext = null;
11630                let droppableEvent = null;
11631                let isInvalid = false;
11632                let interaction = {
11633                    affectedEvents: createEmptyEventStore(),
11634                    mutatedEvents: createEmptyEventStore(),
11635                    isEvent: this.dragMeta.create,
11636                };
11637                if (hit) {
11638                    receivingContext = hit.context;
11639                    if (this.canDropElOnCalendar(ev.subjectEl, receivingContext)) {
11640                        droppableEvent = computeEventForDateSpan(hit.dateSpan, this.dragMeta, receivingContext);
11641                        interaction.mutatedEvents = eventTupleToStore(droppableEvent);
11642                        isInvalid = !isInteractionValid(interaction, hit.dateProfile, receivingContext);
11643                        if (isInvalid) {
11644                            interaction.mutatedEvents = createEmptyEventStore();
11645                            droppableEvent = null;
11646                        }
11647                    }
11648                }
11649                this.displayDrag(receivingContext, interaction);
11650                // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?)
11651                // TODO: wish we could somehow wait for dispatch to guarantee render
11652                dragging.setMirrorIsVisible(isFinal || !droppableEvent || !document.querySelector('.fc-event-mirror'));
11653                if (!isInvalid) {
11654                    enableCursor();
11655                }
11656                else {
11657                    disableCursor();
11658                }
11659                if (!isFinal) {
11660                    dragging.setMirrorNeedsRevert(!droppableEvent);
11661                    this.receivingContext = receivingContext;
11662                    this.droppableEvent = droppableEvent;
11663                }
11664            };
11665            this.handleDragEnd = (pev) => {
11666                let { receivingContext, droppableEvent } = this;
11667                this.clearDrag();
11668                if (receivingContext && droppableEvent) {
11669                    let finalHit = this.hitDragging.finalHit;
11670                    let finalView = finalHit.context.viewApi;
11671                    let dragMeta = this.dragMeta;
11672                    receivingContext.emitter.trigger('drop', Object.assign(Object.assign({}, buildDatePointApiWithContext(finalHit.dateSpan, receivingContext)), { draggedEl: pev.subjectEl, jsEvent: pev.origEvent, view: finalView }));
11673                    if (dragMeta.create) {
11674                        let addingEvents = eventTupleToStore(droppableEvent);
11675                        receivingContext.dispatch({
11676                            type: 'MERGE_EVENTS',
11677                            eventStore: addingEvents,
11678                        });
11679                        if (pev.isTouch) {
11680                            receivingContext.dispatch({
11681                                type: 'SELECT_EVENT',
11682                                eventInstanceId: droppableEvent.instance.instanceId,
11683                            });
11684                        }
11685                        // signal that an external event landed
11686                        receivingContext.emitter.trigger('eventReceive', {
11687                            event: new EventImpl(receivingContext, droppableEvent.def, droppableEvent.instance),
11688                            relatedEvents: [],
11689                            revert() {
11690                                receivingContext.dispatch({
11691                                    type: 'REMOVE_EVENTS',
11692                                    eventStore: addingEvents,
11693                                });
11694                            },
11695                            draggedEl: pev.subjectEl,
11696                            view: finalView,
11697                        });
11698                    }
11699                }
11700                this.receivingContext = null;
11701                this.droppableEvent = null;
11702            };
11703            let hitDragging = this.hitDragging = new HitDragging(dragging, interactionSettingsStore);
11704            hitDragging.requireInitial = false; // will start outside of a component
11705            hitDragging.emitter.on('dragstart', this.handleDragStart);
11706            hitDragging.emitter.on('hitupdate', this.handleHitUpdate);
11707            hitDragging.emitter.on('dragend', this.handleDragEnd);
11708            this.suppliedDragMeta = suppliedDragMeta;
11709        }
11710        buildDragMeta(subjectEl) {
11711            if (typeof this.suppliedDragMeta === 'object') {
11712                return parseDragMeta(this.suppliedDragMeta);
11713            }
11714            if (typeof this.suppliedDragMeta === 'function') {
11715                return parseDragMeta(this.suppliedDragMeta(subjectEl));
11716            }
11717            return getDragMetaFromEl(subjectEl);
11718        }
11719        displayDrag(nextContext, state) {
11720            let prevContext = this.receivingContext;
11721            if (prevContext && prevContext !== nextContext) {
11722                prevContext.dispatch({ type: 'UNSET_EVENT_DRAG' });
11723            }
11724            if (nextContext) {
11725                nextContext.dispatch({ type: 'SET_EVENT_DRAG', state });
11726            }
11727        }
11728        clearDrag() {
11729            if (this.receivingContext) {
11730                this.receivingContext.dispatch({ type: 'UNSET_EVENT_DRAG' });
11731            }
11732        }
11733        canDropElOnCalendar(el, receivingContext) {
11734            let dropAccept = receivingContext.options.dropAccept;
11735            if (typeof dropAccept === 'function') {
11736                return dropAccept.call(receivingContext.calendarApi, el);
11737            }
11738            if (typeof dropAccept === 'string' && dropAccept) {
11739                return Boolean(elementMatches(el, dropAccept));
11740            }
11741            return true;
11742        }
11743    }
11744    // Utils for computing event store from the DragMeta
11745    // ----------------------------------------------------------------------------------------------------
11746    function computeEventForDateSpan(dateSpan, dragMeta, context) {
11747        let defProps = Object.assign({}, dragMeta.leftoverProps);
11748        for (let transform of context.pluginHooks.externalDefTransforms) {
11749            Object.assign(defProps, transform(dateSpan, dragMeta));
11750        }
11751        let { refined, extra } = refineEventDef(defProps, context);
11752        let def = parseEventDef(refined, extra, dragMeta.sourceId, dateSpan.allDay, context.options.forceEventDuration || Boolean(dragMeta.duration), // hasEnd
11753            context);
11754        let start = dateSpan.range.start;
11755        // only rely on time info if drop zone is all-day,
11756        // otherwise, we already know the time
11757        if (dateSpan.allDay && dragMeta.startTime) {
11758            start = context.dateEnv.add(start, dragMeta.startTime);
11759        }
11760        let end = dragMeta.duration ?
11761            context.dateEnv.add(start, dragMeta.duration) :
11762            getDefaultEventEnd(dateSpan.allDay, start, context);
11763        let instance = createEventInstance(def.defId, { start, end });
11764        return { def, instance };
11765    }
11766    // Utils for extracting data from element
11767    // ----------------------------------------------------------------------------------------------------
11768    function getDragMetaFromEl(el) {
11769        let str = getEmbeddedElData(el, 'event');
11770        let obj = str ?
11771            JSON.parse(str) :
11772            { create: false }; // if no embedded data, assume no event creation
11773        return parseDragMeta(obj);
11774    }
11775    config.dataAttrPrefix = '';
11776    function getEmbeddedElData(el, name) {
11777        let prefix = config.dataAttrPrefix;
11778        let prefixedName = (prefix ? prefix + '-' : '') + name;
11779        return el.getAttribute('data-' + prefixedName) || '';
11780    }
11781
11782    /*
11783    Makes an element (that is *external* to any calendar) draggable.
11784    Can pass in data that determines how an event will be created when dropped onto a calendar.
11785    Leverages FullCalendar's internal drag-n-drop functionality WITHOUT a third-party drag system.
11786    */
11787    class ExternalDraggable {
11788        constructor(el, settings = {}) {
11789            this.handlePointerDown = (ev) => {
11790                let { dragging } = this;
11791                let { minDistance, longPressDelay } = this.settings;
11792                dragging.minDistance =
11793                    minDistance != null ?
11794                        minDistance :
11795                        (ev.isTouch ? 0 : BASE_OPTION_DEFAULTS.eventDragMinDistance);
11796                dragging.delay =
11797                    ev.isTouch ? // TODO: eventually read eventLongPressDelay instead vvv
11798                        (longPressDelay != null ? longPressDelay : BASE_OPTION_DEFAULTS.longPressDelay) :
11799                        0;
11800            };
11801            this.handleDragStart = (ev) => {
11802                if (ev.isTouch &&
11803                    this.dragging.delay &&
11804                    ev.subjectEl.classList.contains('fc-event')) {
11805                    this.dragging.mirror.getMirrorEl().classList.add('fc-event-selected');
11806                }
11807            };
11808            this.settings = settings;
11809            let dragging = this.dragging = new FeaturefulElementDragging(el);
11810            dragging.touchScrollAllowed = false;
vendor: 6,348 bytes, lines 11811-11963
11811            if (settings.itemSelector != null) {
11812                dragging.pointer.selector = settings.itemSelector;
11813            }
11814            if (settings.appendTo != null) {
11815                dragging.mirror.parentNode = settings.appendTo; // TODO: write tests
11816            }
11817            dragging.emitter.on('pointerdown', this.handlePointerDown);
11818            dragging.emitter.on('dragstart', this.handleDragStart);
11819            new ExternalElementDragging(dragging, settings.eventData); // eslint-disable-line no-new
11820        }
11821        destroy() {
11822            this.dragging.destroy();
11823        }
11824    }
11825
11826    /*
11827    Detects when a *THIRD-PARTY* drag-n-drop system interacts with elements.
11828    The third-party system is responsible for drawing the visuals effects of the drag.
11829    This class simply monitors for pointer movements and fires events.
11830    It also has the ability to hide the moving element (the "mirror") during the drag.
11831    */
11832    class InferredElementDragging extends ElementDragging {
11833        constructor(containerEl) {
11834            super(containerEl);
11835            this.shouldIgnoreMove = false;
11836            this.mirrorSelector = '';
11837            this.currentMirrorEl = null;
11838            this.handlePointerDown = (ev) => {
11839                this.emitter.trigger('pointerdown', ev);
11840                if (!this.shouldIgnoreMove) {
11841                    // fire dragstart right away. does not support delay or min-distance
11842                    this.emitter.trigger('dragstart', ev);
11843                }
11844            };
11845            this.handlePointerMove = (ev) => {
11846                if (!this.shouldIgnoreMove) {
11847                    this.emitter.trigger('dragmove', ev);
11848                }
11849            };
11850            this.handlePointerUp = (ev) => {
11851                this.emitter.trigger('pointerup', ev);
11852                if (!this.shouldIgnoreMove) {
11853                    // fire dragend right away. does not support a revert animation
11854                    this.emitter.trigger('dragend', ev);
11855                }
11856            };
11857            let pointer = this.pointer = new PointerDragging(containerEl);
11858            pointer.emitter.on('pointerdown', this.handlePointerDown);
11859            pointer.emitter.on('pointermove', this.handlePointerMove);
11860            pointer.emitter.on('pointerup', this.handlePointerUp);
11861        }
11862        destroy() {
11863            this.pointer.destroy();
11864        }
11865        setIgnoreMove(bool) {
11866            this.shouldIgnoreMove = bool;
11867        }
11868        setMirrorIsVisible(bool) {
11869            if (bool) {
11870                // restore a previously hidden element.
11871                // use the reference in case the selector class has already been removed.
11872                if (this.currentMirrorEl) {
11873                    this.currentMirrorEl.style.visibility = '';
11874                    this.currentMirrorEl = null;
11875                }
11876            }
11877            else {
11878                let mirrorEl = this.mirrorSelector
11879                    // TODO: somehow query FullCalendars WITHIN shadow-roots
11880                    ? document.querySelector(this.mirrorSelector)
11881                    : null;
11882                if (mirrorEl) {
11883                    this.currentMirrorEl = mirrorEl;
11884                    mirrorEl.style.visibility = 'hidden';
11885                }
11886            }
11887        }
11888    }
11889
11890    /*
11891    Bridges third-party drag-n-drop systems with FullCalendar.
11892    Must be instantiated and destroyed by caller.
11893    */
11894    class ThirdPartyDraggable {
11895        constructor(containerOrSettings, settings) {
11896            let containerEl = document;
11897            if (
11898                // wish we could just test instanceof EventTarget, but doesn't work in IE11
11899                containerOrSettings === document ||
11900                containerOrSettings instanceof Element) {
11901                containerEl = containerOrSettings;
11902                settings = settings || {};
11903            }
11904            else {
11905                settings = (containerOrSettings || {});
11906            }
11907            let dragging = this.dragging = new InferredElementDragging(containerEl);
11908            if (typeof settings.itemSelector === 'string') {
11909                dragging.pointer.selector = settings.itemSelector;
11910            }
11911            else if (containerEl === document) {
11912                dragging.pointer.selector = '[data-event]';
11913            }
11914            if (typeof settings.mirrorSelector === 'string') {
11915                dragging.mirrorSelector = settings.mirrorSelector;
11916            }
11917            new ExternalElementDragging(dragging, settings.eventData); // eslint-disable-line no-new
11918        }
11919        destroy() {
11920            this.dragging.destroy();
11921        }
11922    }
11923
11924    var index$4 = createPlugin({
11925        name: '@fullcalendar/interaction',
11926        componentInteractions: [DateClicking, DateSelecting, EventDragging, EventResizing],
11927        calendarInteractions: [UnselectAuto],
11928        elementDraggingImpl: FeaturefulElementDragging,
11929        optionRefiners: OPTION_REFINERS$3,
11930        listenerRefiners: LISTENER_REFINERS,
11931    });
11932
11933    /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells.
11934    ----------------------------------------------------------------------------------------------------------------------*/
11935    // It is a manager for a Table subcomponent, which does most of the heavy lifting.
11936    // It is responsible for managing width/height.
11937    class TableView extends DateComponent {
11938        constructor() {
11939            super(...arguments);
11940            this.headerElRef = d();
11941        }
11942        renderSimpleLayout(headerRowContent, bodyContent) {
11943            let { props, context } = this;
11944            let sections = [];
11945            let stickyHeaderDates = getStickyHeaderDates(context.options);
11946            if (headerRowContent) {
11947                sections.push({
11948                    type: 'header',
11949                    key: 'header',
11950                    isSticky: stickyHeaderDates,
11951                    chunk: {
11952                        elRef: this.headerElRef,
11953                        tableClassName: 'fc-col-header',
11954                        rowContent: headerRowContent,
11955                    },
11956                });
11957            }
11958            sections.push({
11959                type: 'body',
11960                key: 'body',
11961                liquid: true,
11962                chunk: { content: bodyContent },
11963            });
vendor: 28,031 bytes, lines 11964-12511
11964            return (y(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
11965                y(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections })));
11966        }
11967        renderHScrollLayout(headerRowContent, bodyContent, colCnt, dayMinWidth) {
11968            let ScrollGrid = this.context.pluginHooks.scrollGridImpl;
11969            if (!ScrollGrid) {
11970                throw new Error('No ScrollGrid implementation');
11971            }
11972            let { props, context } = this;
11973            let stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options);
11974            let stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options);
11975            let sections = [];
11976            if (headerRowContent) {
11977                sections.push({
11978                    type: 'header',
11979                    key: 'header',
11980                    isSticky: stickyHeaderDates,
11981                    chunks: [{
11982                        key: 'main',
11983                        elRef: this.headerElRef,
11984                        tableClassName: 'fc-col-header',
11985                        rowContent: headerRowContent,
11986                    }],
11987                });
11988            }
11989            sections.push({
11990                type: 'body',
11991                key: 'body',
11992                liquid: true,
11993                chunks: [{
11994                    key: 'main',
11995                    content: bodyContent,
11996                }],
11997            });
11998            if (stickyFooterScrollbar) {
11999                sections.push({
12000                    type: 'footer',
12001                    key: 'footer',
12002                    isSticky: true,
12003                    chunks: [{
12004                        key: 'main',
12005                        content: renderScrollShim,
12006                    }],
12007                });
12008            }
12009            return (y(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
12010                y(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections })));
12011        }
12012    }
12013
12014    function splitSegsByRow(segs, rowCnt) {
12015        let byRow = [];
12016        for (let i = 0; i < rowCnt; i += 1) {
12017            byRow[i] = [];
12018        }
12019        for (let seg of segs) {
12020            byRow[seg.row].push(seg);
12021        }
12022        return byRow;
12023    }
12024    function splitSegsByFirstCol(segs, colCnt) {
12025        let byCol = [];
12026        for (let i = 0; i < colCnt; i += 1) {
12027            byCol[i] = [];
12028        }
12029        for (let seg of segs) {
12030            byCol[seg.firstCol].push(seg);
12031        }
12032        return byCol;
12033    }
12034    function splitInteractionByRow(ui, rowCnt) {
12035        let byRow = [];
12036        if (!ui) {
12037            for (let i = 0; i < rowCnt; i += 1) {
12038                byRow[i] = null;
12039            }
12040        }
12041        else {
12042            for (let i = 0; i < rowCnt; i += 1) {
12043                byRow[i] = {
12044                    affectedInstances: ui.affectedInstances,
12045                    isEvent: ui.isEvent,
12046                    segs: [],
12047                };
12048            }
12049            for (let seg of ui.segs) {
12050                byRow[seg.row].segs.push(seg);
12051            }
12052        }
12053        return byRow;
12054    }
12055
12056    const DEFAULT_TABLE_EVENT_TIME_FORMAT = createFormatter({
12057        hour: 'numeric',
12058        minute: '2-digit',
12059        omitZeroMinute: true,
12060        meridiem: 'narrow',
12061    });
12062    function hasListItemDisplay(seg) {
12063        let { display } = seg.eventRange.ui;
12064        return display === 'list-item' || (display === 'auto' &&
12065            !seg.eventRange.def.allDay &&
12066            seg.firstCol === seg.lastCol && // can't be multi-day
12067            seg.isStart && // "
12068            seg.isEnd // "
12069        );
12070    }
12071
12072    class TableBlockEvent extends BaseComponent {
12073        render() {
12074            let { props } = this;
12075            return (y(StandardEvent, Object.assign({}, props, { elClasses: ['fc-daygrid-event', 'fc-daygrid-block-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.seg.eventRange.def.allDay })));
12076        }
12077    }
12078
12079    class TableListItemEvent extends BaseComponent {
12080        render() {
12081            let { props, context } = this;
12082            let { options } = context;
12083            let { seg } = props;
12084            let timeFormat = options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT;
12085            let timeText = buildSegTimeText(seg, timeFormat, context, true, props.defaultDisplayEventEnd);
12086            return (y(EventContainer, Object.assign({}, props, { elTag: "a", elClasses: ['fc-daygrid-event', 'fc-daygrid-dot-event'], elAttrs: getSegAnchorAttrs(props.seg, context), defaultGenerator: renderInnerContent$2, timeText: timeText, isResizing: false, isDateSelecting: false })));
12087        }
12088    }
12089    function renderInnerContent$2(renderProps) {
12090        return (y(_, null,
12091            y("div", { className: "fc-daygrid-event-dot", style: { borderColor: renderProps.borderColor || renderProps.backgroundColor } }),
12092            renderProps.timeText && (y("div", { className: "fc-event-time" }, renderProps.timeText)),
12093            y("div", { className: "fc-event-title" }, renderProps.event.title || y(_, null, "\u00A0"))));
12094    }
12095
12096    class TableCellMoreLink extends BaseComponent {
12097        constructor() {
12098            super(...arguments);
12099            this.compileSegs = memoize(compileSegs);
12100        }
12101        render() {
12102            let { props } = this;
12103            let { allSegs, invisibleSegs } = this.compileSegs(props.singlePlacements);
12104            return (y(MoreLinkContainer, { elClasses: ['fc-daygrid-more-link'], dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, moreCnt: props.moreCnt, allSegs: allSegs, hiddenSegs: invisibleSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: () => {
12105                    let isForcedInvisible = (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
12106                        (props.eventResize ? props.eventResize.affectedInstances : null) ||
12107                        {};
12108                    return (y(_, null, allSegs.map((seg) => {
12109                        let instanceId = seg.eventRange.instance.instanceId;
12110                        return (y("div", { className: "fc-daygrid-event-harness", key: instanceId, style: {
12111                                visibility: isForcedInvisible[instanceId] ? 'hidden' : '',
12112                            } }, hasListItemDisplay(seg) ? (y(TableListItemEvent, Object.assign({ seg: seg, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getSegMeta(seg, props.todayRange)))) : (y(TableBlockEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getSegMeta(seg, props.todayRange))))));
12113                    })));
12114                } }));
12115        }
12116    }
12117    function compileSegs(singlePlacements) {
12118        let allSegs = [];
12119        let invisibleSegs = [];
12120        for (let placement of singlePlacements) {
12121            allSegs.push(placement.seg);
12122            if (!placement.isVisible) {
12123                invisibleSegs.push(placement.seg);
12124            }
12125        }
12126        return { allSegs, invisibleSegs };
12127    }
12128
12129    const DEFAULT_WEEK_NUM_FORMAT$1 = createFormatter({ week: 'narrow' });
12130    class TableCell extends DateComponent {
12131        constructor() {
12132            super(...arguments);
12133            this.rootElRef = d();
12134            this.state = {
12135                dayNumberId: getUniqueDomId(),
12136            };
12137            this.handleRootEl = (el) => {
12138                setRef(this.rootElRef, el);
12139                setRef(this.props.elRef, el);
12140            };
12141        }
12142        render() {
12143            let { context, props, state, rootElRef } = this;
12144            let { options, dateEnv } = context;
12145            let { date, dateProfile } = props;
12146            // TODO: memoize this?
12147            const isMonthStart = props.showDayNumber &&
12148                shouldDisplayMonthStart(date, dateProfile.currentRange, dateEnv);
12149            return (y(DayCellContainer, { elTag: "td", elRef: this.handleRootEl, elClasses: [
12150                    'fc-daygrid-day',
12151                    ...(props.extraClassNames || []),
12152                ], elAttrs: Object.assign(Object.assign(Object.assign({}, props.extraDataAttrs), (props.showDayNumber ? { 'aria-labelledby': state.dayNumberId } : {})), { role: 'gridcell' }), defaultGenerator: renderTopInner, date: date, dateProfile: dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart, extraRenderProps: props.extraRenderProps }, (InnerContent, renderProps) => (y("div", { ref: props.innerElRef, className: "fc-daygrid-day-frame fc-scrollgrid-sync-inner", style: { minHeight: props.minHeight } },
12153                props.showWeekNumber && (y(WeekNumberContainer, { elTag: "a", elClasses: ['fc-daygrid-week-number'], elAttrs: buildNavLinkAttrs(context, date, 'week'), date: date, defaultFormat: DEFAULT_WEEK_NUM_FORMAT$1 })),
12154                !renderProps.isDisabled &&
12155                (props.showDayNumber || hasCustomDayCellContent(options) || props.forceDayTop) ? (y("div", { className: "fc-daygrid-day-top" },
12156                    y(InnerContent, { elTag: "a", elClasses: [
12157                            'fc-daygrid-day-number',
12158                            isMonthStart && 'fc-daygrid-month-start',
12159                        ], elAttrs: Object.assign(Object.assign({}, buildNavLinkAttrs(context, date)), { id: state.dayNumberId }) }))) : props.showDayNumber ? (
12160                    // for creating correct amount of space (see issue #7162)
12161                    y("div", { className: "fc-daygrid-day-top", style: { visibility: 'hidden' } },
12162                        y("a", { className: "fc-daygrid-day-number" }, "\u00A0"))) : undefined,
12163                y("div", { className: "fc-daygrid-day-events", ref: props.fgContentElRef },
12164                    props.fgContent,
12165                    y("div", { className: "fc-daygrid-day-bottom", style: { marginTop: props.moreMarginTop } },
12166                        y(TableCellMoreLink, { allDayDate: date, singlePlacements: props.singlePlacements, moreCnt: props.moreCnt, alignmentElRef: rootElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange }))),
12167                y("div", { className: "fc-daygrid-day-bg" }, props.bgContent)))));
12168        }
12169    }
12170    function renderTopInner(props) {
12171        return props.dayNumberText || y(_, null, "\u00A0");
12172    }
12173    function shouldDisplayMonthStart(date, currentRange, dateEnv) {
12174        const { start: currentStart, end: currentEnd } = currentRange;
12175        const currentEndIncl = addMs(currentEnd, -1);
12176        const currentFirstYear = dateEnv.getYear(currentStart);
12177        const currentFirstMonth = dateEnv.getMonth(currentStart);
12178        const currentLastYear = dateEnv.getYear(currentEndIncl);
12179        const currentLastMonth = dateEnv.getMonth(currentEndIncl);
12180        // spans more than one month?
12181        return !(currentFirstYear === currentLastYear && currentFirstMonth === currentLastMonth) &&
12182            Boolean(
12183                // first date in current view?
12184                date.valueOf() === currentStart.valueOf() ||
12185                // a month-start that's within the current range?
12186                (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
12187    }
12188
12189    function generateSegKey(seg) {
12190        return seg.eventRange.instance.instanceId + ':' + seg.firstCol;
12191    }
12192    function generateSegUid(seg) {
12193        return generateSegKey(seg) + ':' + seg.lastCol;
12194    }
12195    function computeFgSegPlacement(segs, // assumed already sorted
12196                                   dayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells) {
12197        let hierarchy = new DayGridSegHierarchy((segEntry) => {
12198            // TODO: more DRY with generateSegUid
12199            let segUid = segs[segEntry.index].eventRange.instance.instanceId +
12200                ':' + segEntry.span.start +
12201                ':' + (segEntry.span.end - 1);
12202            return segHeights[segUid];
12203        });
12204        hierarchy.allowReslicing = true;
12205        hierarchy.strictOrder = strictOrder;
12206        if (dayMaxEvents === true || dayMaxEventRows === true) {
12207            hierarchy.maxCoord = maxContentHeight;
12208            hierarchy.hiddenConsumes = true;
12209        }
12210        else if (typeof dayMaxEvents === 'number') {
12211            hierarchy.maxStackCnt = dayMaxEvents;
12212        }
12213        else if (typeof dayMaxEventRows === 'number') {
12214            hierarchy.maxStackCnt = dayMaxEventRows;
12215            hierarchy.hiddenConsumes = true;
12216        }
12217        // create segInputs only for segs with known heights
12218        let segInputs = [];
12219        let unknownHeightSegs = [];
12220        for (let i = 0; i < segs.length; i += 1) {
12221            let seg = segs[i];
12222            let segUid = generateSegUid(seg);
12223            let eventHeight = segHeights[segUid];
12224            if (eventHeight != null) {
12225                segInputs.push({
12226                    index: i,
12227                    span: {
12228                        start: seg.firstCol,
12229                        end: seg.lastCol + 1,
12230                    },
12231                });
12232            }
12233            else {
12234                unknownHeightSegs.push(seg);
12235            }
12236        }
12237        let hiddenEntries = hierarchy.addSegs(segInputs);
12238        let segRects = hierarchy.toRects();
12239        let { singleColPlacements, multiColPlacements, leftoverMargins } = placeRects(segRects, segs, cells);
12240        let moreCnts = [];
12241        let moreMarginTops = [];
12242        // add segs with unknown heights
12243        for (let seg of unknownHeightSegs) {
12244            multiColPlacements[seg.firstCol].push({
12245                seg,
12246                isVisible: false,
12247                isAbsolute: true,
12248                absoluteTop: 0,
12249                marginTop: 0,
12250            });
12251            for (let col = seg.firstCol; col <= seg.lastCol; col += 1) {
12252                singleColPlacements[col].push({
12253                    seg: resliceSeg(seg, col, col + 1, cells),
12254                    isVisible: false,
12255                    isAbsolute: false,
12256                    absoluteTop: 0,
12257                    marginTop: 0,
12258                });
12259            }
12260        }
12261        // add the hidden entries
12262        for (let col = 0; col < cells.length; col += 1) {
12263            moreCnts.push(0);
12264        }
12265        for (let hiddenEntry of hiddenEntries) {
12266            let seg = segs[hiddenEntry.index];
12267            let hiddenSpan = hiddenEntry.span;
12268            multiColPlacements[hiddenSpan.start].push({
12269                seg: resliceSeg(seg, hiddenSpan.start, hiddenSpan.end, cells),
12270                isVisible: false,
12271                isAbsolute: true,
12272                absoluteTop: 0,
12273                marginTop: 0,
12274            });
12275            for (let col = hiddenSpan.start; col < hiddenSpan.end; col += 1) {
12276                moreCnts[col] += 1;
12277                singleColPlacements[col].push({
12278                    seg: resliceSeg(seg, col, col + 1, cells),
12279                    isVisible: false,
12280                    isAbsolute: false,
12281                    absoluteTop: 0,
12282                    marginTop: 0,
12283                });
12284            }
12285        }
12286        // deal with leftover margins
12287        for (let col = 0; col < cells.length; col += 1) {
12288            moreMarginTops.push(leftoverMargins[col]);
12289        }
12290        return { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops };
12291    }
12292    // rects ordered by top coord, then left
12293    function placeRects(allRects, segs, cells) {
12294        let rectsByEachCol = groupRectsByEachCol(allRects, cells.length);
12295        let singleColPlacements = [];
12296        let multiColPlacements = [];
12297        let leftoverMargins = [];
12298        for (let col = 0; col < cells.length; col += 1) {
12299            let rects = rectsByEachCol[col];
12300            // compute all static segs in singlePlacements
12301            let singlePlacements = [];
12302            let currentHeight = 0;
12303            let currentMarginTop = 0;
12304            for (let rect of rects) {
12305                let seg = segs[rect.index];
12306                singlePlacements.push({
12307                    seg: resliceSeg(seg, col, col + 1, cells),
12308                    isVisible: true,
12309                    isAbsolute: false,
12310                    absoluteTop: rect.levelCoord,
12311                    marginTop: rect.levelCoord - currentHeight,
12312                });
12313                currentHeight = rect.levelCoord + rect.thickness;
12314            }
12315            // compute mixed static/absolute segs in multiPlacements
12316            let multiPlacements = [];
12317            currentHeight = 0;
12318            currentMarginTop = 0;
12319            for (let rect of rects) {
12320                let seg = segs[rect.index];
12321                let isAbsolute = rect.span.end - rect.span.start > 1; // multi-column?
12322                let isFirstCol = rect.span.start === col;
12323                currentMarginTop += rect.levelCoord - currentHeight; // amount of space since bottom of previous seg
12324                currentHeight = rect.levelCoord + rect.thickness; // height will now be bottom of current seg
12325                if (isAbsolute) {
12326                    currentMarginTop += rect.thickness;
12327                    if (isFirstCol) {
12328                        multiPlacements.push({
12329                            seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
12330                            isVisible: true,
12331                            isAbsolute: true,
12332                            absoluteTop: rect.levelCoord,
12333                            marginTop: 0,
12334                        });
12335                    }
12336                }
12337                else if (isFirstCol) {
12338                    multiPlacements.push({
12339                        seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
12340                        isVisible: true,
12341                        isAbsolute: false,
12342                        absoluteTop: rect.levelCoord,
12343                        marginTop: currentMarginTop, // claim the margin
12344                    });
12345                    currentMarginTop = 0;
12346                }
12347            }
12348            singleColPlacements.push(singlePlacements);
12349            multiColPlacements.push(multiPlacements);
12350            leftoverMargins.push(currentMarginTop);
12351        }
12352        return { singleColPlacements, multiColPlacements, leftoverMargins };
12353    }
12354    function groupRectsByEachCol(rects, colCnt) {
12355        let rectsByEachCol = [];
12356        for (let col = 0; col < colCnt; col += 1) {
12357            rectsByEachCol.push([]);
12358        }
12359        for (let rect of rects) {
12360            for (let col = rect.span.start; col < rect.span.end; col += 1) {
12361                rectsByEachCol[col].push(rect);
12362            }
12363        }
12364        return rectsByEachCol;
12365    }
12366    function resliceSeg(seg, spanStart, spanEnd, cells) {
12367        if (seg.firstCol === spanStart && seg.lastCol === spanEnd - 1) {
12368            return seg;
12369        }
12370        let eventRange = seg.eventRange;
12371        let origRange = eventRange.range;
12372        let slicedRange = intersectRanges(origRange, {
12373            start: cells[spanStart].date,
12374            end: addDays(cells[spanEnd - 1].date, 1),
12375        });
12376        return Object.assign(Object.assign({}, seg), { firstCol: spanStart, lastCol: spanEnd - 1, eventRange: {
12377                def: eventRange.def,
12378                ui: Object.assign(Object.assign({}, eventRange.ui), { durationEditable: false }),
12379                instance: eventRange.instance,
12380                range: slicedRange,
12381            }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() });
12382    }
12383    class DayGridSegHierarchy extends SegHierarchy {
12384        constructor() {
12385            super(...arguments);
12386            // config
12387            this.hiddenConsumes = false;
12388            // allows us to keep hidden entries in the hierarchy so they take up space
12389            this.forceHidden = {};
12390        }
12391        addSegs(segInputs) {
12392            const hiddenSegs = super.addSegs(segInputs);
12393            const { entriesByLevel } = this;
12394            const excludeHidden = (entry) => !this.forceHidden[buildEntryKey(entry)];
12395            // remove the forced-hidden segs
12396            for (let level = 0; level < entriesByLevel.length; level += 1) {
12397                entriesByLevel[level] = entriesByLevel[level].filter(excludeHidden);
12398            }
12399            return hiddenSegs;
12400        }
12401        handleInvalidInsertion(insertion, entry, hiddenEntries) {
12402            const { entriesByLevel, forceHidden } = this;
12403            const { touchingEntry, touchingLevel, touchingLateral } = insertion;
12404            if (this.hiddenConsumes && touchingEntry) {
12405                const touchingEntryId = buildEntryKey(touchingEntry);
12406                // if not already hidden
12407                if (!forceHidden[touchingEntryId]) {
12408                    if (this.allowReslicing) {
12409                        const placeholderEntry = Object.assign(Object.assign({}, touchingEntry), { span: intersectSpans(touchingEntry.span, entry.span) });
12410                        const placeholderEntryId = buildEntryKey(placeholderEntry);
12411                        forceHidden[placeholderEntryId] = true;
12412                        entriesByLevel[touchingLevel][touchingLateral] = placeholderEntry; // replace touchingEntry with our placeholder
12413                        this.splitEntry(touchingEntry, entry, hiddenEntries); // split up the touchingEntry, reinsert it
12414                    }
12415                    else {
12416                        forceHidden[touchingEntryId] = true;
12417                        hiddenEntries.push(touchingEntry);
12418                    }
12419                }
12420            }
12421            return super.handleInvalidInsertion(insertion, entry, hiddenEntries);
12422        }
12423    }
12424
12425    class TableRow extends DateComponent {
12426        constructor() {
12427            super(...arguments);
12428            this.cellElRefs = new RefMap(); // the <td>
12429            this.frameElRefs = new RefMap(); // the fc-daygrid-day-frame
12430            this.fgElRefs = new RefMap(); // the fc-daygrid-day-events
12431            this.segHarnessRefs = new RefMap(); // indexed by "instanceId:firstCol"
12432            this.rootElRef = d();
12433            this.state = {
12434                framePositions: null,
12435                maxContentHeight: null,
12436                segHeights: {},
12437            };
12438            this.handleResize = (isForced) => {
12439                if (isForced) {
12440                    this.updateSizing(true); // isExternal=true
12441                }
12442            };
12443        }
12444        render() {
12445            let { props, state, context } = this;
12446            let { options } = context;
12447            let colCnt = props.cells.length;
12448            let businessHoursByCol = splitSegsByFirstCol(props.businessHourSegs, colCnt);
12449            let bgEventSegsByCol = splitSegsByFirstCol(props.bgEventSegs, colCnt);
12450            let highlightSegsByCol = splitSegsByFirstCol(this.getHighlightSegs(), colCnt);
12451            let mirrorSegsByCol = splitSegsByFirstCol(this.getMirrorSegs(), colCnt);
12452            let { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops } = computeFgSegPlacement(sortEventSegs(props.fgEventSegs, options.eventOrder), props.dayMaxEvents, props.dayMaxEventRows, options.eventOrderStrict, state.segHeights, state.maxContentHeight, props.cells);
12453            let isForcedInvisible = // TODO: messy way to compute this
12454                (props.eventDrag && props.eventDrag.affectedInstances) ||
12455                (props.eventResize && props.eventResize.affectedInstances) ||
12456                {};
12457            return (y("tr", { ref: this.rootElRef, role: "row" },
12458                props.renderIntro && props.renderIntro(),
12459                props.cells.map((cell, col) => {
12460                    let normalFgNodes = this.renderFgSegs(col, props.forPrint ? singleColPlacements[col] : multiColPlacements[col], props.todayRange, isForcedInvisible);
12461                    let mirrorFgNodes = this.renderFgSegs(col, buildMirrorPlacements(mirrorSegsByCol[col], multiColPlacements), props.todayRange, {}, Boolean(props.eventDrag), Boolean(props.eventResize), false);
12462                    return (y(TableCell, { key: cell.key, elRef: this.cellElRefs.createRef(cell.key), innerElRef: this.frameElRefs.createRef(cell.key) /* FF <td> problem, but okay to use for left/right. TODO: rename prop */, dateProfile: props.dateProfile, date: cell.date, showDayNumber: props.showDayNumbers, showWeekNumber: props.showWeekNumbers && col === 0, forceDayTop: props.showWeekNumbers /* even displaying weeknum for row, not necessarily day */, todayRange: props.todayRange, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, extraRenderProps: cell.extraRenderProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, moreCnt: moreCnts[col], moreMarginTop: moreMarginTops[col], singlePlacements: singleColPlacements[col], fgContentElRef: this.fgElRefs.createRef(cell.key), fgContent: ( // Fragment scopes the keys
12463                            y(_, null,
12464                                y(_, null, normalFgNodes),
12465                                y(_, null, mirrorFgNodes))), bgContent: ( // Fragment scopes the keys
12466                            y(_, null,
12467                                this.renderFillSegs(highlightSegsByCol[col], 'highlight'),
12468                                this.renderFillSegs(businessHoursByCol[col], 'non-business'),
12469                                this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), minHeight: props.cellMinHeight }));
12470                })));
12471        }
12472        componentDidMount() {
12473            this.updateSizing(true);
12474            this.context.addResizeHandler(this.handleResize);
12475        }
12476        componentDidUpdate(prevProps, prevState) {
12477            let currentProps = this.props;
12478            this.updateSizing(!isPropsEqual(prevProps, currentProps));
12479        }
12480        componentWillUnmount() {
12481            this.context.removeResizeHandler(this.handleResize);
12482        }
12483        getHighlightSegs() {
12484            let { props } = this;
12485            if (props.eventDrag && props.eventDrag.segs.length) { // messy check
12486                return props.eventDrag.segs;
12487            }
12488            if (props.eventResize && props.eventResize.segs.length) { // messy check
12489                return props.eventResize.segs;
12490            }
12491            return props.dateSelectionSegs;
12492        }
12493        getMirrorSegs() {
12494            let { props } = this;
12495            if (props.eventResize && props.eventResize.segs.length) { // messy check
12496                return props.eventResize.segs;
12497            }
12498            return [];
12499        }
12500        renderFgSegs(col, segPlacements, todayRange, isForcedInvisible, isDragging, isResizing, isDateSelecting) {
12501            let { context } = this;
12502            let { eventSelection } = this.props;
12503            let { framePositions } = this.state;
12504            let defaultDisplayEventEnd = this.props.cells.length === 1; // colCnt === 1
12505            let isMirror = isDragging || isResizing || isDateSelecting;
12506            let nodes = [];
12507            if (framePositions) {
12508                for (let placement of segPlacements) {
12509                    let { seg } = placement;
12510                    let { instanceId } = seg.eventRange.instance;
12511                    let isVisible = placement.isVisible && !isForcedInvisible[instanceId];
vendor: 14,062 bytes, lines 12512-12772
12512                    let isAbsolute = placement.isAbsolute;
12513                    let left = '';
12514                    let right = '';
12515                    if (isAbsolute) {
12516                        if (context.isRtl) {
12517                            right = 0;
12518                            left = framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol];
12519                        }
12520                        else {
12521                            left = 0;
12522                            right = framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol];
12523                        }
12524                    }
12525                    /*
12526                    known bug: events that are force to be list-item but span multiple days still take up space in later columns
12527                    todo: in print view, for multi-day events, don't display title within non-start/end segs
12528                    */
12529                    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: {
12530                            visibility: isVisible ? '' : 'hidden',
12531                            marginTop: isAbsolute ? '' : placement.marginTop,
12532                            top: isAbsolute ? placement.absoluteTop : '',
12533                            left,
12534                            right,
12535                        } }, hasListItemDisplay(seg) ? (y(TableListItemEvent, Object.assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange)))) : (y(TableBlockEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange))))));
12536                }
12537            }
12538            return nodes;
12539        }
12540        renderFillSegs(segs, fillType) {
12541            let { isRtl } = this.context;
12542            let { todayRange } = this.props;
12543            let { framePositions } = this.state;
12544            let nodes = [];
12545            if (framePositions) {
12546                for (let seg of segs) {
12547                    let leftRightCss = isRtl ? {
12548                        right: 0,
12549                        left: framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol],
12550                    } : {
12551                        left: 0,
12552                        right: framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol],
12553                    };
12554                    nodes.push(y("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-daygrid-bg-harness", style: leftRightCss }, fillType === 'bg-event' ?
12555                        y(BgEvent, Object.assign({ seg: seg }, getSegMeta(seg, todayRange))) :
12556                        renderFill(fillType)));
12557                }
12558            }
12559            return y(_, {}, ...nodes);
12560        }
12561        updateSizing(isExternalSizingChange) {
12562            let { props, state, frameElRefs } = this;
12563            if (!props.forPrint &&
12564                props.clientWidth !== null // positioning ready?
12565            ) {
12566                if (isExternalSizingChange) {
12567                    let frameEls = props.cells.map((cell) => frameElRefs.currentMap[cell.key]);
12568                    if (frameEls.length) {
12569                        let originEl = this.rootElRef.current;
12570                        let newPositionCache = new PositionCache(originEl, frameEls, true, // isHorizontal
12571                            false);
12572                        if (!state.framePositions || !state.framePositions.similarTo(newPositionCache)) {
12573                            this.setState({
12574                                framePositions: new PositionCache(originEl, frameEls, true, // isHorizontal
12575                                    false),
12576                            });
12577                        }
12578                    }
12579                }
12580                const oldSegHeights = this.state.segHeights;
12581                const newSegHeights = this.querySegHeights();
12582                const limitByContentHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
12583                this.safeSetState({
12584                    // HACK to prevent oscillations of events being shown/hidden from max-event-rows
12585                    // Essentially, once you compute an element's height, never null-out.
12586                    // TODO: always display all events, as visibility:hidden?
12587                    segHeights: Object.assign(Object.assign({}, oldSegHeights), newSegHeights),
12588                    maxContentHeight: limitByContentHeight ? this.computeMaxContentHeight() : null,
12589                });
12590            }
12591        }
12592        querySegHeights() {
12593            let segElMap = this.segHarnessRefs.currentMap;
12594            let segHeights = {};
12595            // get the max height amongst instance segs
12596            for (let segUid in segElMap) {
12597                let height = Math.round(segElMap[segUid].getBoundingClientRect().height);
12598                segHeights[segUid] = Math.max(segHeights[segUid] || 0, height);
12599            }
12600            return segHeights;
12601        }
12602        computeMaxContentHeight() {
12603            let firstKey = this.props.cells[0].key;
12604            let cellEl = this.cellElRefs.currentMap[firstKey];
12605            let fcContainerEl = this.fgElRefs.currentMap[firstKey];
12606            return cellEl.getBoundingClientRect().bottom - fcContainerEl.getBoundingClientRect().top;
12607        }
12608        getCellEls() {
12609            let elMap = this.cellElRefs.currentMap;
12610            return this.props.cells.map((cell) => elMap[cell.key]);
12611        }
12612    }
12613    TableRow.addStateEquality({
12614        segHeights: isPropsEqual,
12615    });
12616    function buildMirrorPlacements(mirrorSegs, colPlacements) {
12617        if (!mirrorSegs.length) {
12618            return [];
12619        }
12620        let topsByInstanceId = buildAbsoluteTopHash(colPlacements); // TODO: cache this at first render?
12621        return mirrorSegs.map((seg) => ({
12622            seg,
12623            isVisible: true,
12624            isAbsolute: true,
12625            absoluteTop: topsByInstanceId[seg.eventRange.instance.instanceId],
12626            marginTop: 0,
12627        }));
12628    }
12629    function buildAbsoluteTopHash(colPlacements) {
12630        let topsByInstanceId = {};
12631        for (let placements of colPlacements) {
12632            for (let placement of placements) {
12633                topsByInstanceId[placement.seg.eventRange.instance.instanceId] = placement.absoluteTop;
12634            }
12635        }
12636        return topsByInstanceId;
12637    }
12638
12639    class TableRows extends DateComponent {
12640        constructor() {
12641            super(...arguments);
12642            this.splitBusinessHourSegs = memoize(splitSegsByRow);
12643            this.splitBgEventSegs = memoize(splitSegsByRow);
12644            this.splitFgEventSegs = memoize(splitSegsByRow);
12645            this.splitDateSelectionSegs = memoize(splitSegsByRow);
12646            this.splitEventDrag = memoize(splitInteractionByRow);
12647            this.splitEventResize = memoize(splitInteractionByRow);
12648            this.rowRefs = new RefMap();
12649        }
12650        render() {
12651            let { props, context } = this;
12652            let rowCnt = props.cells.length;
12653            let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
12654            let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
12655            let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
12656            let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
12657            let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
12658            let eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt);
12659            // for DayGrid view with many rows, force a min-height on cells so doesn't appear squished
12660            // choose 7 because a month view will have max 6 rows
12661            let cellMinHeight = (rowCnt >= 7 && props.clientWidth) ?
12662                props.clientWidth / context.options.aspectRatio / 6 :
12663                null;
12664            return (y(NowTimer, { unit: "day" }, (nowDate, todayRange) => (y(_, null, props.cells.map((cells, row) => (y(TableRow, { ref: this.rowRefs.createRef(row), key: cells.length
12665                    ? cells[0].date.toISOString() /* best? or put key on cell? or use diff formatter? */
12666                    : row // in case there are no cells (like when resource view is loading)
12667                , 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 })))))));
12668        }
12669        componentDidMount() {
12670            this.registerInteractiveComponent();
12671        }
12672        componentDidUpdate() {
12673            // for if started with zero cells
12674            this.registerInteractiveComponent();
12675        }
12676        registerInteractiveComponent() {
12677            if (!this.rootEl) {
12678                // HACK: need a daygrid wrapper parent to do positioning
12679                // NOTE: a daygrid resource view w/o resources can have zero cells
12680                const firstCellEl = this.rowRefs.currentMap[0].getCellEls()[0];
12681                const rootEl = firstCellEl ? firstCellEl.closest('.fc-daygrid-body') : null;
12682                if (rootEl) {
12683                    this.rootEl = rootEl;
12684                    this.context.registerInteractiveComponent(this, {
12685                        el: rootEl,
12686                        isHitComboAllowed: this.props.isHitComboAllowed,
12687                    });
12688                }
12689            }
12690        }
12691        componentWillUnmount() {
12692            if (this.rootEl) {
12693                this.context.unregisterInteractiveComponent(this);
12694                this.rootEl = null;
12695            }
12696        }
12697        // Hit System
12698        // ----------------------------------------------------------------------------------------------------
12699        prepareHits() {
12700            this.rowPositions = new PositionCache(this.rootEl, this.rowRefs.collect().map((rowObj) => rowObj.getCellEls()[0]), // first cell el in each row. TODO: not optimal
12701                false, true);
12702            this.colPositions = new PositionCache(this.rootEl, this.rowRefs.currentMap[0].getCellEls(), // cell els in first row
12703                true, // horizontal
12704                false);
12705        }
12706        queryHit(positionLeft, positionTop) {
12707            let { colPositions, rowPositions } = this;
12708            let col = colPositions.leftToIndex(positionLeft);
12709            let row = rowPositions.topToIndex(positionTop);
12710            if (row != null && col != null) {
12711                let cell = this.props.cells[row][col];
12712                return {
12713                    dateProfile: this.props.dateProfile,
12714                    dateSpan: Object.assign({ range: this.getCellRange(row, col), allDay: true }, cell.extraDateSpan),
12715                    dayEl: this.getCellEl(row, col),
12716                    rect: {
12717                        left: colPositions.lefts[col],
12718                        right: colPositions.rights[col],
12719                        top: rowPositions.tops[row],
12720                        bottom: rowPositions.bottoms[row],
12721                    },
12722                    layer: 0,
12723                };
12724            }
12725            return null;
12726        }
12727        getCellEl(row, col) {
12728            return this.rowRefs.currentMap[row].getCellEls()[col]; // TODO: not optimal
12729        }
12730        getCellRange(row, col) {
12731            let start = this.props.cells[row][col].date;
12732            let end = addDays(start, 1);
12733            return { start, end };
12734        }
12735    }
12736    function isSegAllDay(seg) {
12737        return seg.eventRange.def.allDay;
12738    }
12739
12740    class Table extends DateComponent {
12741        constructor() {
12742            super(...arguments);
12743            this.elRef = d();
12744            this.needsScrollReset = false;
12745        }
12746        render() {
12747            let { props } = this;
12748            let { dayMaxEventRows, dayMaxEvents, expandRows } = props;
12749            let limitViaBalanced = dayMaxEvents === true || dayMaxEventRows === true;
12750            // if rows can't expand to fill fixed height, can't do balanced-height event limit
12751            // TODO: best place to normalize these options?
12752            if (limitViaBalanced && !expandRows) {
12753                limitViaBalanced = false;
12754                dayMaxEventRows = null;
12755                dayMaxEvents = null;
12756            }
12757            let classNames = [
12758                'fc-daygrid-body',
12759                limitViaBalanced ? 'fc-daygrid-body-balanced' : 'fc-daygrid-body-unbalanced',
12760                expandRows ? '' : 'fc-daygrid-body-natural', // will height of one row depend on the others?
12761            ];
12762            return (y("div", { ref: this.elRef, className: classNames.join(' '), style: {
12763                        // these props are important to give this wrapper correct dimensions for interactions
12764                        // TODO: if we set it here, can we avoid giving to inner tables?
12765                        width: props.clientWidth,
12766                        minWidth: props.tableMinWidth,
12767                    } },
12768                y("table", { role: "presentation", className: "fc-scrollgrid-sync-table", style: {
12769                            width: props.clientWidth,
12770                            minWidth: props.tableMinWidth,
12771                            height: expandRows ? props.clientHeight : '',
12772                        } },
vendor: 7,472 bytes, lines 12773-12905
12773                    props.colGroupNode,
12774                    y("tbody", { role: "presentation" },
12775                        y(TableRows, { dateProfile: props.dateProfile, cells: props.cells, renderRowIntro: props.renderRowIntro, showWeekNumbers: props.showWeekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed })))));
12776        }
12777        componentDidMount() {
12778            this.requestScrollReset();
12779        }
12780        componentDidUpdate(prevProps) {
12781            if (prevProps.dateProfile !== this.props.dateProfile) {
12782                this.requestScrollReset();
12783            }
12784            else {
12785                this.flushScrollReset();
12786            }
12787        }
12788        requestScrollReset() {
12789            this.needsScrollReset = true;
12790            this.flushScrollReset();
12791        }
12792        flushScrollReset() {
12793            if (this.needsScrollReset &&
12794                this.props.clientWidth // sizes computed?
12795            ) {
12796                const subjectEl = getScrollSubjectEl(this.elRef.current, this.props.dateProfile);
12797                if (subjectEl) {
12798                    const originEl = subjectEl.closest('.fc-daygrid-body');
12799                    const scrollEl = originEl.closest('.fc-scroller');
12800                    const scrollTop = subjectEl.getBoundingClientRect().top -
12801                        originEl.getBoundingClientRect().top;
12802                    scrollEl.scrollTop = scrollTop ? (scrollTop + 1) : 0; // overcome border
12803                }
12804                this.needsScrollReset = false;
12805            }
12806        }
12807    }
12808    function getScrollSubjectEl(containerEl, dateProfile) {
12809        let el;
12810        if (dateProfile.currentRangeUnit.match(/year|month/)) {
12811            el = containerEl.querySelector(`[data-date="${formatIsoMonthStr(dateProfile.currentDate)}-01"]`);
12812            // even if view is month-based, first-of-month might be hidden...
12813        }
12814        if (!el) {
12815            el = containerEl.querySelector(`[data-date="${formatDayString(dateProfile.currentDate)}"]`);
12816            // could still be hidden if an interior-view hidden day
12817        }
12818        return el;
12819    }
12820
12821    class DayTableSlicer extends Slicer {
12822        constructor() {
12823            super(...arguments);
12824            this.forceDayIfListItem = true;
12825        }
12826        sliceRange(dateRange, dayTableModel) {
12827            return dayTableModel.sliceRange(dateRange);
12828        }
12829    }
12830
12831    class DayTable extends DateComponent {
12832        constructor() {
12833            super(...arguments);
12834            this.slicer = new DayTableSlicer();
12835            this.tableRef = d();
12836        }
12837        render() {
12838            let { props, context } = this;
12839            return (y(Table, Object.assign({ ref: this.tableRef }, this.slicer.sliceProps(props, props.dateProfile, props.nextDayThreshold, context, props.dayTableModel), { dateProfile: props.dateProfile, cells: props.dayTableModel.cells, colGroupNode: props.colGroupNode, tableMinWidth: props.tableMinWidth, renderRowIntro: props.renderRowIntro, dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, showWeekNumbers: props.showWeekNumbers, expandRows: props.expandRows, headerAlignElRef: props.headerAlignElRef, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: props.forPrint })));
12840        }
12841    }
12842
12843    class DayTableView extends TableView {
12844        constructor() {
12845            super(...arguments);
12846            this.buildDayTableModel = memoize(buildDayTableModel);
12847            this.headerRef = d();
12848            this.tableRef = d();
12849            // can't override any lifecycle methods from parent
12850        }
12851        render() {
12852            let { options, dateProfileGenerator } = this.context;
12853            let { props } = this;
12854            let dayTableModel = this.buildDayTableModel(props.dateProfile, dateProfileGenerator);
12855            let headerContent = options.dayHeaders && (y(DayHeader, { ref: this.headerRef, dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: dayTableModel.rowCnt === 1 }));
12856            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 }));
12857            return options.dayMinWidth
12858                ? this.renderHScrollLayout(headerContent, bodyContent, dayTableModel.colCnt, options.dayMinWidth)
12859                : this.renderSimpleLayout(headerContent, bodyContent);
12860        }
12861    }
12862    function buildDayTableModel(dateProfile, dateProfileGenerator) {
12863        let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
12864        return new DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
12865    }
12866
12867    class TableDateProfileGenerator extends DateProfileGenerator {
12868        // Computes the date range that will be rendered
12869        buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
12870            let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);
12871            let { props } = this;
12872            return buildDayTableRenderRange({
12873                currentRange: renderRange,
12874                snapToWeek: /^(year|month)$/.test(currentRangeUnit),
12875                fixedWeekCount: props.fixedWeekCount,
12876                dateEnv: props.dateEnv,
12877            });
12878        }
12879    }
12880    function buildDayTableRenderRange(props) {
12881        let { dateEnv, currentRange } = props;
12882        let { start, end } = currentRange;
12883        let endOfWeek;
12884        // year and month views should be aligned with weeks. this is already done for week
12885        if (props.snapToWeek) {
12886            start = dateEnv.startOfWeek(start);
12887            // make end-of-week if not already
12888            endOfWeek = dateEnv.startOfWeek(end);
12889            if (endOfWeek.valueOf() !== end.valueOf()) {
12890                end = addWeeks(endOfWeek, 1);
12891            }
12892        }
12893        // ensure 6 weeks
12894        if (props.fixedWeekCount) {
12895            // TODO: instead of these date-math gymnastics (for multimonth view),
12896            // compute dateprofiles of all months, then use start of first and end of last.
12897            let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(addDays(currentRange.end, -1)));
12898            let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
12899                diffWeeks(lastMonthRenderStart, end));
12900            end = addWeeks(end, 6 - rowCnt);
12901        }
12902        return { start, end };
12903    }
12904
12905    var css_248z$3
vendor: 3,531 bytes, line 12905
12905 = ":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}";
12906    injectStyles(css_248z$3);
12907
12908    var index$3 = createPlugin({
12909        name: '@fullcalendar/daygrid',
12910        initialView: 'dayGridMonth',
12911        views: {
12912            dayGrid: {
12913                component: DayTableView,
12914                dateProfileGeneratorClass: TableDateProfileGenerator,
12915            },
12916            dayGridDay: {
12917                type: 'dayGrid',
12918                duration: { days: 1 },
12919            },
12920            dayGridWeek: {
12921                type: 'dayGrid',
12922                duration: { weeks: 1 },
12923            },
12924            dayGridMonth: {
12925                type: 'dayGrid',
12926                duration: { months: 1 },
12927                fixedWeekCount: true,
12928            },
12929            dayGridYear: {
12930                type: 'dayGrid',
12931                duration: { years: 1 },
12932            },
12933        },
12934    });
12935
12936    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}";
12937    injectStyles(css_248z$2);
12938
12939    class AllDaySplitter extends Splitter {
12940        getKeyInfo() {
12941            return {
12942                allDay: {},
12943                timed: {},
12944            };
12945        }
vendor: 58,566 bytes, lines 12946-14070
12946        getKeysForDateSpan(dateSpan) {
12947            if (dateSpan.allDay) {
12948                return ['allDay'];
12949            }
12950            return ['timed'];
12951        }
12952        getKeysForEventDef(eventDef) {
12953            if (!eventDef.allDay) {
12954                return ['timed'];
12955            }
12956            if (hasBgRendering(eventDef)) {
12957                return ['timed', 'allDay'];
12958            }
12959            return ['allDay'];
12960        }
12961    }
12962
12963    const DEFAULT_SLAT_LABEL_FORMAT = createFormatter({
12964        hour: 'numeric',
12965        minute: '2-digit',
12966        omitZeroMinute: true,
12967        meridiem: 'short',
12968    });
12969    function TimeColsAxisCell(props) {
12970        let classNames = [
12971            'fc-timegrid-slot',
12972            'fc-timegrid-slot-label',
12973            props.isLabeled ? 'fc-scrollgrid-shrink' : 'fc-timegrid-slot-minor',
12974        ];
12975        return (y(ViewContextType.Consumer, null, (context) => {
12976            if (!props.isLabeled) {
12977                return (y("td", { className: classNames.join(' '), "data-time": props.isoTimeStr }));
12978            }
12979            let { dateEnv, options, viewApi } = context;
12980            let labelFormat = // TODO: fully pre-parse
12981                options.slotLabelFormat == null ? DEFAULT_SLAT_LABEL_FORMAT :
12982                    Array.isArray(options.slotLabelFormat) ? createFormatter(options.slotLabelFormat[0]) :
12983                        createFormatter(options.slotLabelFormat);
12984            let renderProps = {
12985                level: 0,
12986                time: props.time,
12987                date: dateEnv.toDate(props.date),
12988                view: viewApi,
12989                text: dateEnv.format(props.date, labelFormat),
12990            };
12991            return (y(ContentContainer, { elTag: "td", elClasses: classNames, elAttrs: {
12992                    'data-time': props.isoTimeStr,
12993                }, renderProps: renderProps, generatorName: "slotLabelContent", customGenerator: options.slotLabelContent, defaultGenerator: renderInnerContent$1, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => (y("div", { className: "fc-timegrid-slot-label-frame fc-scrollgrid-shrink-frame" },
12994                y(InnerContent, { elTag: "div", elClasses: [
12995                        'fc-timegrid-slot-label-cushion',
12996                        'fc-scrollgrid-shrink-cushion',
12997                    ] })))));
12998        }));
12999    }
13000    function renderInnerContent$1(props) {
13001        return props.text;
13002    }
13003
13004    class TimeBodyAxis extends BaseComponent {
13005        render() {
13006            return this.props.slatMetas.map((slatMeta) => (y("tr", { key: slatMeta.key },
13007                y(TimeColsAxisCell, Object.assign({}, slatMeta)))));
13008        }
13009    }
13010
13011    const DEFAULT_WEEK_NUM_FORMAT = createFormatter({ week: 'short' });
13012    const AUTO_ALL_DAY_MAX_EVENT_ROWS = 5;
13013    class TimeColsView extends DateComponent {
13014        constructor() {
13015            super(...arguments);
13016            this.allDaySplitter = new AllDaySplitter(); // for use by subclasses
13017            this.headerElRef = d();
13018            this.rootElRef = d();
13019            this.scrollerElRef = d();
13020            this.state = {
13021                slatCoords: null,
13022            };
13023            this.handleScrollTopRequest = (scrollTop) => {
13024                let scrollerEl = this.scrollerElRef.current;
13025                if (scrollerEl) { // TODO: not sure how this could ever be null. weirdness with the reducer
13026                    scrollerEl.scrollTop = scrollTop;
13027                }
13028            };
13029            /* Header Render Methods
13030            ------------------------------------------------------------------------------------------------------------------*/
13031            this.renderHeadAxis = (rowKey, frameHeight = '') => {
13032                let { options } = this.context;
13033                let { dateProfile } = this.props;
13034                let range = dateProfile.renderRange;
13035                let dayCnt = diffDays(range.start, range.end);
13036                // only do in day views (to avoid doing in week views that dont need it)
13037                let navLinkAttrs = (dayCnt === 1)
13038                    ? buildNavLinkAttrs(this.context, range.start, 'week')
13039                    : {};
13040                if (options.weekNumbers && rowKey === 'day') {
13041                    return (y(WeekNumberContainer, { elTag: "th", elClasses: [
13042                            'fc-timegrid-axis',
13043                            'fc-scrollgrid-shrink',
13044                        ], elAttrs: {
13045                            'aria-hidden': true,
13046                        }, date: range.start, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }, (InnerContent) => (y("div", { className: [
13047                                'fc-timegrid-axis-frame',
13048                                'fc-scrollgrid-shrink-frame',
13049                                'fc-timegrid-axis-frame-liquid',
13050                            ].join(' '), style: { height: frameHeight } },
13051                        y(InnerContent, { elTag: "a", elClasses: [
13052                                'fc-timegrid-axis-cushion',
13053                                'fc-scrollgrid-shrink-cushion',
13054                                'fc-scrollgrid-sync-inner',
13055                            ], elAttrs: navLinkAttrs })))));
13056                }
13057                return (y("th", { "aria-hidden": true, className: "fc-timegrid-axis" },
13058                    y("div", { className: "fc-timegrid-axis-frame", style: { height: frameHeight } })));
13059            };
13060            /* Table Component Render Methods
13061            ------------------------------------------------------------------------------------------------------------------*/
13062            // only a one-way height sync. we don't send the axis inner-content height to the DayGrid,
13063            // but DayGrid still needs to have classNames on inner elements in order to measure.
13064            this.renderTableRowAxis = (rowHeight) => {
13065                let { options, viewApi } = this.context;
13066                let renderProps = {
13067                    text: options.allDayText,
13068                    view: viewApi,
13069                };
13070                return (
13071                    // TODO: make reusable hook. used in list view too
13072                    y(ContentContainer, { elTag: "td", elClasses: [
13073                            'fc-timegrid-axis',
13074                            'fc-scrollgrid-shrink',
13075                        ], elAttrs: {
13076                            'aria-hidden': true,
13077                        }, renderProps: renderProps, generatorName: "allDayContent", customGenerator: options.allDayContent, defaultGenerator: renderAllDayInner$1, classNameGenerator: options.allDayClassNames, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }, (InnerContent) => (y("div", { className: [
13078                                'fc-timegrid-axis-frame',
13079                                'fc-scrollgrid-shrink-frame',
13080                                rowHeight == null ? ' fc-timegrid-axis-frame-liquid' : '',
13081                            ].join(' '), style: { height: rowHeight } },
13082                        y(InnerContent, { elTag: "span", elClasses: [
13083                                'fc-timegrid-axis-cushion',
13084                                'fc-scrollgrid-shrink-cushion',
13085                                'fc-scrollgrid-sync-inner',
13086                            ] })))));
13087            };
13088            this.handleSlatCoords = (slatCoords) => {
13089                this.setState({ slatCoords });
13090            };
13091        }
13092        // rendering
13093        // ----------------------------------------------------------------------------------------------------
13094        renderSimpleLayout(headerRowContent, allDayContent, timeContent) {
13095            let { context, props } = this;
13096            let sections = [];
13097            let stickyHeaderDates = getStickyHeaderDates(context.options);
13098            if (headerRowContent) {
13099                sections.push({
13100                    type: 'header',
13101                    key: 'header',
13102                    isSticky: stickyHeaderDates,
13103                    chunk: {
13104                        elRef: this.headerElRef,
13105                        tableClassName: 'fc-col-header',
13106                        rowContent: headerRowContent,
13107                    },
13108                });
13109            }
13110            if (allDayContent) {
13111                sections.push({
13112                    type: 'body',
13113                    key: 'all-day',
13114                    chunk: { content: allDayContent },
13115                });
13116                sections.push({
13117                    type: 'body',
13118                    key: 'all-day-divider',
13119                    outerContent: ( // TODO: rename to cellContent so don't need to define <tr>?
13120                        y("tr", { role: "presentation", className: "fc-scrollgrid-section" },
13121                            y("td", { className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))),
13122                });
13123            }
13124            sections.push({
13125                type: 'body',
13126                key: 'body',
13127                liquid: true,
13128                expandRows: Boolean(context.options.expandRows),
13129                chunk: {
13130                    scrollerElRef: this.scrollerElRef,
13131                    content: timeContent,
13132                },
13133            });
13134            return (y(ViewContainer, { elRef: this.rootElRef, elClasses: ['fc-timegrid'], viewSpec: context.viewSpec },
13135                y(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [{ width: 'shrink' }], sections: sections })));
13136        }
13137        renderHScrollLayout(headerRowContent, allDayContent, timeContent, colCnt, dayMinWidth, slatMetas, slatCoords) {
13138            let ScrollGrid = this.context.pluginHooks.scrollGridImpl;
13139            if (!ScrollGrid) {
13140                throw new Error('No ScrollGrid implementation');
13141            }
13142            let { context, props } = this;
13143            let stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options);
13144            let stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options);
13145            let sections = [];
13146            if (headerRowContent) {
13147                sections.push({
13148                    type: 'header',
13149                    key: 'header',
13150                    isSticky: stickyHeaderDates,
13151                    syncRowHeights: true,
13152                    chunks: [
13153                        {
13154                            key: 'axis',
13155                            rowContent: (arg) => (y("tr", { role: "presentation" }, this.renderHeadAxis('day', arg.rowSyncHeights[0]))),
13156                        },
13157                        {
13158                            key: 'cols',
13159                            elRef: this.headerElRef,
13160                            tableClassName: 'fc-col-header',
13161                            rowContent: headerRowContent,
13162                        },
13163                    ],
13164                });
13165            }
13166            if (allDayContent) {
13167                sections.push({
13168                    type: 'body',
13169                    key: 'all-day',
13170                    syncRowHeights: true,
13171                    chunks: [
13172                        {
13173                            key: 'axis',
13174                            rowContent: (contentArg) => (y("tr", { role: "presentation" }, this.renderTableRowAxis(contentArg.rowSyncHeights[0]))),
13175                        },
13176                        {
13177                            key: 'cols',
13178                            content: allDayContent,
13179                        },
13180                    ],
13181                });
13182                sections.push({
13183                    key: 'all-day-divider',
13184                    type: 'body',
13185                    outerContent: ( // TODO: rename to cellContent so don't need to define <tr>?
13186                        y("tr", { role: "presentation", className: "fc-scrollgrid-section" },
13187                            y("td", { colSpan: 2, className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))),
13188                });
13189            }
13190            let isNowIndicator = context.options.nowIndicator;
13191            sections.push({
13192                type: 'body',
13193                key: 'body',
13194                liquid: true,
13195                expandRows: Boolean(context.options.expandRows),
13196                chunks: [
13197                    {
13198                        key: 'axis',
13199                        content: (arg) => (
13200                            // TODO: make this now-indicator arrow more DRY with TimeColsContent
13201                            y("div", { className: "fc-timegrid-axis-chunk" },
13202                                y("table", { "aria-hidden": true, style: { height: arg.expandRows ? arg.clientHeight : '' } },
13203                                    arg.tableColGroupNode,
13204                                    y("tbody", null,
13205                                        y(TimeBodyAxis, { slatMetas: slatMetas }))),
13206                                y("div", { className: "fc-timegrid-now-indicator-container" },
13207                                    y(NowTimer, { unit: isNowIndicator ? 'minute' : 'day' /* hacky */ }, (nowDate) => {
13208                                        let nowIndicatorTop = isNowIndicator &&
13209                                            slatCoords &&
13210                                            slatCoords.safeComputeTop(nowDate); // might return void
13211                                        if (typeof nowIndicatorTop === 'number') {
13212                                            return (y(NowIndicatorContainer, { elClasses: ['fc-timegrid-now-indicator-arrow'], elStyle: { top: nowIndicatorTop }, isAxis: true, date: nowDate }));
13213                                        }
13214                                        return null;
13215                                    })))),
13216                    },
13217                    {
13218                        key: 'cols',
13219                        scrollerElRef: this.scrollerElRef,
13220                        content: timeContent,
13221                    },
13222                ],
13223            });
13224            if (stickyFooterScrollbar) {
13225                sections.push({
13226                    key: 'footer',
13227                    type: 'footer',
13228                    isSticky: true,
13229                    chunks: [
13230                        {
13231                            key: 'axis',
13232                            content: renderScrollShim,
13233                        },
13234                        {
13235                            key: 'cols',
13236                            content: renderScrollShim,
13237                        },
13238                    ],
13239                });
13240            }
13241            return (y(ViewContainer, { elRef: this.rootElRef, elClasses: ['fc-timegrid'], viewSpec: context.viewSpec },
13242                y(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: false, colGroups: [
13243                        { width: 'shrink', cols: [{ width: 'shrink' }] },
13244                        { cols: [{ span: colCnt, minWidth: dayMinWidth }] },
13245                    ], sections: sections })));
13246        }
13247        /* Dimensions
13248        ------------------------------------------------------------------------------------------------------------------*/
13249        getAllDayMaxEventProps() {
13250            let { dayMaxEvents, dayMaxEventRows } = this.context.options;
13251            if (dayMaxEvents === true || dayMaxEventRows === true) { // is auto?
13252                dayMaxEvents = undefined;
13253                dayMaxEventRows = AUTO_ALL_DAY_MAX_EVENT_ROWS; // make sure "auto" goes to a real number
13254            }
13255            return { dayMaxEvents, dayMaxEventRows };
13256        }
13257    }
13258    function renderAllDayInner$1(renderProps) {
13259        return renderProps.text;
13260    }
13261
13262    class TimeColsSlatsCoords {
13263        constructor(positions, dateProfile, slotDuration) {
13264            this.positions = positions;
13265            this.dateProfile = dateProfile;
13266            this.slotDuration = slotDuration;
13267        }
13268        safeComputeTop(date) {
13269            let { dateProfile } = this;
13270            if (rangeContainsMarker(dateProfile.currentRange, date)) {
13271                let startOfDayDate = startOfDay(date);
13272                let timeMs = date.valueOf() - startOfDayDate.valueOf();
13273                if (timeMs >= asRoughMs(dateProfile.slotMinTime) &&
13274                    timeMs < asRoughMs(dateProfile.slotMaxTime)) {
13275                    return this.computeTimeTop(createDuration(timeMs));
13276                }
13277            }
13278            return null;
13279        }
13280        // Computes the top coordinate, relative to the bounds of the grid, of the given date.
13281        // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.
13282        computeDateTop(when, startOfDayDate) {
13283            if (!startOfDayDate) {
13284                startOfDayDate = startOfDay(when);
13285            }
13286            return this.computeTimeTop(createDuration(when.valueOf() - startOfDayDate.valueOf()));
13287        }
13288        // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).
13289        // This is a makeshify way to compute the time-top. Assumes all slatMetas dates are uniform.
13290        // Eventually allow computation with arbirary slat dates.
13291        computeTimeTop(duration) {
13292            let { positions, dateProfile } = this;
13293            let len = positions.els.length;
13294            // floating-point value of # of slots covered
13295            let slatCoverage = (duration.milliseconds - asRoughMs(dateProfile.slotMinTime)) / asRoughMs(this.slotDuration);
13296            let slatIndex;
13297            let slatRemainder;
13298            // compute a floating-point number for how many slats should be progressed through.
13299            // from 0 to number of slats (inclusive)
13300            // constrained because slotMinTime/slotMaxTime might be customized.
13301            slatCoverage = Math.max(0, slatCoverage);
13302            slatCoverage = Math.min(len, slatCoverage);
13303            // an integer index of the furthest whole slat
13304            // from 0 to number slats (*exclusive*, so len-1)
13305            slatIndex = Math.floor(slatCoverage);
13306            slatIndex = Math.min(slatIndex, len - 1);
13307            // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition.
13308            // could be 1.0 if slatCoverage is covering *all* the slots
13309            slatRemainder = slatCoverage - slatIndex;
13310            return positions.tops[slatIndex] +
13311                positions.getHeight(slatIndex) * slatRemainder;
13312        }
13313    }
13314
13315    class TimeColsSlatsBody extends BaseComponent {
13316        render() {
13317            let { props, context } = this;
13318            let { options } = context;
13319            let { slatElRefs } = props;
13320            return (y("tbody", null, props.slatMetas.map((slatMeta, i) => {
13321                let renderProps = {
13322                    time: slatMeta.time,
13323                    date: context.dateEnv.toDate(slatMeta.date),
13324                    view: context.viewApi,
13325                };
13326                return (y("tr", { key: slatMeta.key, ref: slatElRefs.createRef(slatMeta.key) },
13327                    props.axis && (y(TimeColsAxisCell, Object.assign({}, slatMeta))),
13328                    y(ContentContainer, { elTag: "td", elClasses: [
13329                            'fc-timegrid-slot',
13330                            'fc-timegrid-slot-lane',
13331                            !slatMeta.isLabeled && 'fc-timegrid-slot-minor',
13332                        ], elAttrs: {
13333                            'data-time': slatMeta.isoTimeStr,
13334                        }, renderProps: renderProps, generatorName: "slotLaneContent", customGenerator: options.slotLaneContent, classNameGenerator: options.slotLaneClassNames, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount })));
13335            })));
13336        }
13337    }
13338
13339    /*
13340    for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL.
13341    */
13342    class TimeColsSlats extends BaseComponent {
13343        constructor() {
13344            super(...arguments);
13345            this.rootElRef = d();
13346            this.slatElRefs = new RefMap();
13347        }
13348        render() {
13349            let { props, context } = this;
13350            return (y("div", { ref: this.rootElRef, className: "fc-timegrid-slots" },
13351                y("table", { "aria-hidden": true, className: context.theme.getClass('table'), style: {
13352                            minWidth: props.tableMinWidth,
13353                            width: props.clientWidth,
13354                            height: props.minHeight,
13355                        } },
13356                    props.tableColGroupNode /* relies on there only being a single <col> for the axis */,
13357                    y(TimeColsSlatsBody, { slatElRefs: this.slatElRefs, axis: props.axis, slatMetas: props.slatMetas }))));
13358        }
13359        componentDidMount() {
13360            this.updateSizing();
13361        }
13362        componentDidUpdate() {
13363            this.updateSizing();
13364        }
13365        componentWillUnmount() {
13366            if (this.props.onCoords) {
13367                this.props.onCoords(null);
13368            }
13369        }
13370        updateSizing() {
13371            let { context, props } = this;
13372            if (props.onCoords &&
13373                props.clientWidth !== null // means sizing has stabilized
13374            ) {
13375                let rootEl = this.rootElRef.current;
13376                if (rootEl.offsetHeight) { // not hidden by css
13377                    props.onCoords(new TimeColsSlatsCoords(new PositionCache(this.rootElRef.current, collectSlatEls(this.slatElRefs.currentMap, props.slatMetas), false, true), this.props.dateProfile, context.options.slotDuration));
13378                }
13379            }
13380        }
13381    }
13382    function collectSlatEls(elMap, slatMetas) {
13383        return slatMetas.map((slatMeta) => elMap[slatMeta.key]);
13384    }
13385
13386    function splitSegsByCol(segs, colCnt) {
13387        let segsByCol = [];
13388        let i;
13389        for (i = 0; i < colCnt; i += 1) {
13390            segsByCol.push([]);
13391        }
13392        if (segs) {
13393            for (i = 0; i < segs.length; i += 1) {
13394                segsByCol[segs[i].col].push(segs[i]);
13395            }
13396        }
13397        return segsByCol;
13398    }
13399    function splitInteractionByCol(ui, colCnt) {
13400        let byRow = [];
13401        if (!ui) {
13402            for (let i = 0; i < colCnt; i += 1) {
13403                byRow[i] = null;
13404            }
13405        }
13406        else {
13407            for (let i = 0; i < colCnt; i += 1) {
13408                byRow[i] = {
13409                    affectedInstances: ui.affectedInstances,
13410                    isEvent: ui.isEvent,
13411                    segs: [],
13412                };
13413            }
13414            for (let seg of ui.segs) {
13415                byRow[seg.col].segs.push(seg);
13416            }
13417        }
13418        return byRow;
13419    }
13420
13421    class TimeColMoreLink extends BaseComponent {
13422        render() {
13423            let { props } = this;
13424            return (y(MoreLinkContainer, { elClasses: ['fc-timegrid-more-link'], elStyle: {
13425                    top: props.top,
13426                    bottom: props.bottom,
13427                }, allDayDate: null, moreCnt: props.hiddenSegs.length, allSegs: props.hiddenSegs, hiddenSegs: props.hiddenSegs, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, todayRange: props.todayRange, popoverContent: () => renderPlainFgSegs(props.hiddenSegs, props), defaultGenerator: renderMoreLinkInner, forceTimed: true }, (InnerContent) => (y(InnerContent, { elTag: "div", elClasses: ['fc-timegrid-more-link-inner', 'fc-sticky'] }))));
13428        }
13429    }
13430    function renderMoreLinkInner(props) {
13431        return props.shortText;
13432    }
13433
13434    // segInputs assumed sorted
13435    function buildPositioning(segInputs, strictOrder, maxStackCnt) {
13436        let hierarchy = new SegHierarchy();
13437        if (strictOrder != null) {
13438            hierarchy.strictOrder = strictOrder;
13439        }
13440        if (maxStackCnt != null) {
13441            hierarchy.maxStackCnt = maxStackCnt;
13442        }
13443        let hiddenEntries = hierarchy.addSegs(segInputs);
13444        let hiddenGroups = groupIntersectingEntries(hiddenEntries);
13445        let web = buildWeb(hierarchy);
13446        web = stretchWeb(web, 1); // all levelCoords/thickness will have 0.0-1.0
13447        let segRects = webToRects(web);
13448        return { segRects, hiddenGroups };
13449    }
13450    function buildWeb(hierarchy) {
13451        const { entriesByLevel } = hierarchy;
13452        const buildNode = cacheable((level, lateral) => level + ':' + lateral, (level, lateral) => {
13453            let siblingRange = findNextLevelSegs(hierarchy, level, lateral);
13454            let nextLevelRes = buildNodes(siblingRange, buildNode);
13455            let entry = entriesByLevel[level][lateral];
13456            return [
13457                Object.assign(Object.assign({}, entry), { nextLevelNodes: nextLevelRes[0] }),
13458                entry.thickness + nextLevelRes[1], // the pressure builds
13459            ];
13460        });
13461        return buildNodes(entriesByLevel.length
13462            ? { level: 0, lateralStart: 0, lateralEnd: entriesByLevel[0].length }
13463            : null, buildNode)[0];
13464    }
13465    function buildNodes(siblingRange, buildNode) {
13466        if (!siblingRange) {
13467            return [[], 0];
13468        }
13469        let { level, lateralStart, lateralEnd } = siblingRange;
13470        let lateral = lateralStart;
13471        let pairs = [];
13472        while (lateral < lateralEnd) {
13473            pairs.push(buildNode(level, lateral));
13474            lateral += 1;
13475        }
13476        pairs.sort(cmpDescPressures);
13477        return [
13478            pairs.map(extractNode),
13479            pairs[0][1], // first item's pressure
13480        ];
13481    }
13482    function cmpDescPressures(a, b) {
13483        return b[1] - a[1];
13484    }
13485    function extractNode(a) {
13486        return a[0];
13487    }
13488    function findNextLevelSegs(hierarchy, subjectLevel, subjectLateral) {
13489        let { levelCoords, entriesByLevel } = hierarchy;
13490        let subjectEntry = entriesByLevel[subjectLevel][subjectLateral];
13491        let afterSubject = levelCoords[subjectLevel] + subjectEntry.thickness;
13492        let levelCnt = levelCoords.length;
13493        let level = subjectLevel;
13494        // skip past levels that are too high up
13495        for (; level < levelCnt && levelCoords[level] < afterSubject; level += 1)
13496            ; // do nothing
13497        for (; level < levelCnt; level += 1) {
13498            let entries = entriesByLevel[level];
13499            let entry;
13500            let searchIndex = binarySearch(entries, subjectEntry.span.start, getEntrySpanEnd);
13501            let lateralStart = searchIndex[0] + searchIndex[1]; // if exact match (which doesn't collide), go to next one
13502            let lateralEnd = lateralStart;
13503            while ( // loop through entries that horizontally intersect
13504            (entry = entries[lateralEnd]) && // but not past the whole seg list
13505            entry.span.start < subjectEntry.span.end) {
13506                lateralEnd += 1;
13507            }
13508            if (lateralStart < lateralEnd) {
13509                return { level, lateralStart, lateralEnd };
13510            }
13511        }
13512        return null;
13513    }
13514    function stretchWeb(topLevelNodes, totalThickness) {
13515        const stretchNode = cacheable((node, startCoord, prevThickness) => buildEntryKey(node), (node, startCoord, prevThickness) => {
13516            let { nextLevelNodes, thickness } = node;
13517            let allThickness = thickness + prevThickness;
13518            let thicknessFraction = thickness / allThickness;
13519            let endCoord;
13520            let newChildren = [];
13521            if (!nextLevelNodes.length) {
13522                endCoord = totalThickness;
13523            }
13524            else {
13525                for (let childNode of nextLevelNodes) {
13526                    if (endCoord === undefined) {
13527                        let res = stretchNode(childNode, startCoord, allThickness);
13528                        endCoord = res[0];
13529                        newChildren.push(res[1]);
13530                    }
13531                    else {
13532                        let res = stretchNode(childNode, endCoord, 0);
13533                        newChildren.push(res[1]);
13534                    }
13535                }
13536            }
13537            let newThickness = (endCoord - startCoord) * thicknessFraction;
13538            return [endCoord - newThickness, Object.assign(Object.assign({}, node), { thickness: newThickness, nextLevelNodes: newChildren })];
13539        });
13540        return topLevelNodes.map((node) => stretchNode(node, 0, 0)[1]);
13541    }
13542    // not sorted in any particular order
13543    function webToRects(topLevelNodes) {
13544        let rects = [];
13545        const processNode = cacheable((node, levelCoord, stackDepth) => buildEntryKey(node), (node, levelCoord, stackDepth) => {
13546            let rect = Object.assign(Object.assign({}, node), { levelCoord,
13547                stackDepth, stackForward: 0 });
13548            rects.push(rect);
13549            return (rect.stackForward = processNodes(node.nextLevelNodes, levelCoord + node.thickness, stackDepth + 1) + 1);
13550        });
13551        function processNodes(nodes, levelCoord, stackDepth) {
13552            let stackForward = 0;
13553            for (let node of nodes) {
13554                stackForward = Math.max(processNode(node, levelCoord, stackDepth), stackForward);
13555            }
13556            return stackForward;
13557        }
13558        processNodes(topLevelNodes, 0, 0);
13559        return rects; // TODO: sort rects by levelCoord to be consistent with toRects?
13560    }
13561    // TODO: move to general util
13562    function cacheable(keyFunc, workFunc) {
13563        const cache = {};
13564        return (...args) => {
13565            let key = keyFunc(...args);
13566            return (key in cache)
13567                ? cache[key]
13568                : (cache[key] = workFunc(...args));
13569        };
13570    }
13571
13572    function computeSegVCoords(segs, colDate, slatCoords = null, eventMinHeight = 0) {
13573        let vcoords = [];
13574        if (slatCoords) {
13575            for (let i = 0; i < segs.length; i += 1) {
13576                let seg = segs[i];
13577                let spanStart = slatCoords.computeDateTop(seg.start, colDate);
13578                let spanEnd = Math.max(spanStart + (eventMinHeight || 0), // :(
13579                    slatCoords.computeDateTop(seg.end, colDate));
13580                vcoords.push({
13581                    start: Math.round(spanStart),
13582                    end: Math.round(spanEnd), //
13583                });
13584            }
13585        }
13586        return vcoords;
13587    }
13588    function computeFgSegPlacements(segs, segVCoords, // might not have for every seg
13589                                    eventOrderStrict, eventMaxStack) {
13590        let segInputs = [];
13591        let dumbSegs = []; // segs without coords
13592        for (let i = 0; i < segs.length; i += 1) {
13593            let vcoords = segVCoords[i];
13594            if (vcoords) {
13595                segInputs.push({
13596                    index: i,
13597                    thickness: 1,
13598                    span: vcoords,
13599                });
13600            }
13601            else {
13602                dumbSegs.push(segs[i]);
13603            }
13604        }
13605        let { segRects, hiddenGroups } = buildPositioning(segInputs, eventOrderStrict, eventMaxStack);
13606        let segPlacements = [];
13607        for (let segRect of segRects) {
13608            segPlacements.push({
13609                seg: segs[segRect.index],
13610                rect: segRect,
13611            });
13612        }
13613        for (let dumbSeg of dumbSegs) {
13614            segPlacements.push({ seg: dumbSeg, rect: null });
13615        }
13616        return { segPlacements, hiddenGroups };
13617    }
13618
13619    const DEFAULT_TIME_FORMAT$1 = createFormatter({
13620        hour: 'numeric',
13621        minute: '2-digit',
13622        meridiem: false,
13623    });
13624    class TimeColEvent extends BaseComponent {
13625        render() {
13626            return (y(StandardEvent, Object.assign({}, this.props, { elClasses: [
13627                    'fc-timegrid-event',
13628                    'fc-v-event',
13629                    this.props.isShort && 'fc-timegrid-event-short',
13630                ], defaultTimeFormat: DEFAULT_TIME_FORMAT$1 })));
13631        }
13632    }
13633
13634    class TimeCol extends BaseComponent {
13635        constructor() {
13636            super(...arguments);
13637            this.sortEventSegs = memoize(sortEventSegs);
13638        }
13639        // TODO: memoize event-placement?
13640        render() {
13641            let { props, context } = this;
13642            let { options } = context;
13643            let isSelectMirror = options.selectMirror;
13644            let mirrorSegs = // yuck
13645                (props.eventDrag && props.eventDrag.segs) ||
13646                (props.eventResize && props.eventResize.segs) ||
13647                (isSelectMirror && props.dateSelectionSegs) ||
13648                [];
13649            let interactionAffectedInstances = // TODO: messy way to compute this
13650                (props.eventDrag && props.eventDrag.affectedInstances) ||
13651                (props.eventResize && props.eventResize.affectedInstances) ||
13652                {};
13653            let sortedFgSegs = this.sortEventSegs(props.fgEventSegs, options.eventOrder);
13654            return (y(DayCellContainer, { elTag: "td", elRef: props.elRef, elClasses: [
13655                    'fc-timegrid-col',
13656                    ...(props.extraClassNames || []),
13657                ], elAttrs: Object.assign({ role: 'gridcell' }, props.extraDataAttrs), date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraRenderProps: props.extraRenderProps }, (InnerContent) => (y("div", { className: "fc-timegrid-col-frame" },
13658                y("div", { className: "fc-timegrid-col-bg" },
13659                    this.renderFillSegs(props.businessHourSegs, 'non-business'),
13660                    this.renderFillSegs(props.bgEventSegs, 'bg-event'),
13661                    this.renderFillSegs(props.dateSelectionSegs, 'highlight')),
13662                y("div", { className: "fc-timegrid-col-events" }, this.renderFgSegs(sortedFgSegs, interactionAffectedInstances, false, false, false)),
13663                y("div", { className: "fc-timegrid-col-events" }, this.renderFgSegs(mirrorSegs, {}, Boolean(props.eventDrag), Boolean(props.eventResize), Boolean(isSelectMirror), 'mirror')),
13664                y("div", { className: "fc-timegrid-now-indicator-container" }, this.renderNowIndicator(props.nowIndicatorSegs)),
13665                hasCustomDayCellContent(options) && (y(InnerContent, { elTag: "div", elClasses: ['fc-timegrid-col-misc'] }))))));
13666        }
13667        renderFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey) {
13668            let { props } = this;
13669            if (props.forPrint) {
13670                return renderPlainFgSegs(sortedFgSegs, props);
13671            }
13672            return this.renderPositionedFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey);
13673        }
13674        renderPositionedFgSegs(segs, // if not mirror, needs to be sorted
13675                               segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey) {
13676            let { eventMaxStack, eventShortHeight, eventOrderStrict, eventMinHeight } = this.context.options;
13677            let { date, slatCoords, eventSelection, todayRange, nowDate } = this.props;
13678            let isMirror = isDragging || isResizing || isDateSelecting;
13679            let segVCoords = computeSegVCoords(segs, date, slatCoords, eventMinHeight);
13680            let { segPlacements, hiddenGroups } = computeFgSegPlacements(segs, segVCoords, eventOrderStrict, eventMaxStack);
13681            return (y(_, null,
13682                this.renderHiddenGroups(hiddenGroups, segs),
13683                segPlacements.map((segPlacement) => {
13684                    let { seg, rect } = segPlacement;
13685                    let instanceId = seg.eventRange.instance.instanceId;
13686                    let isVisible = isMirror || Boolean(!segIsInvisible[instanceId] && rect);
13687                    let vStyle = computeSegVStyle(rect && rect.span);
13688                    let hStyle = (!isMirror && rect) ? this.computeSegHStyle(rect) : { left: 0, right: 0 };
13689                    let isInset = Boolean(rect) && rect.stackForward > 0;
13690                    let isShort = Boolean(rect) && (rect.span.end - rect.span.start) < eventShortHeight; // look at other places for this problem
13691                    return (y("div", { className: 'fc-timegrid-event-harness' +
13692                                (isInset ? ' fc-timegrid-event-harness-inset' : ''), key: forcedKey || instanceId, style: Object.assign(Object.assign({ visibility: isVisible ? '' : 'hidden' }, vStyle), hStyle) },
13693                        y(TimeColEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, isShort: isShort }, getSegMeta(seg, todayRange, nowDate)))));
13694                })));
13695        }
13696        // will already have eventMinHeight applied because segInputs already had it
13697        renderHiddenGroups(hiddenGroups, segs) {
13698            let { extraDateSpan, dateProfile, todayRange, nowDate, eventSelection, eventDrag, eventResize } = this.props;
13699            return (y(_, null, hiddenGroups.map((hiddenGroup) => {
13700                let positionCss = computeSegVStyle(hiddenGroup.span);
13701                let hiddenSegs = compileSegsFromEntries(hiddenGroup.entries, segs);
13702                return (y(TimeColMoreLink, { key: buildIsoString(computeEarliestSegStart(hiddenSegs)), hiddenSegs: hiddenSegs, top: positionCss.top, bottom: positionCss.bottom, extraDateSpan: extraDateSpan, dateProfile: dateProfile, todayRange: todayRange, nowDate: nowDate, eventSelection: eventSelection, eventDrag: eventDrag, eventResize: eventResize }));
13703            })));
13704        }
13705        renderFillSegs(segs, fillType) {
13706            let { props, context } = this;
13707            let segVCoords = computeSegVCoords(segs, props.date, props.slatCoords, context.options.eventMinHeight); // don't assume all populated
13708            let children = segVCoords.map((vcoords, i) => {
13709                let seg = segs[i];
13710                return (y("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-timegrid-bg-harness", style: computeSegVStyle(vcoords) }, fillType === 'bg-event' ?
13711                    y(BgEvent, Object.assign({ seg: seg }, getSegMeta(seg, props.todayRange, props.nowDate))) :
13712                    renderFill(fillType)));
13713            });
13714            return y(_, null, children);
13715        }
13716        renderNowIndicator(segs) {
13717            let { slatCoords, date } = this.props;
13718            if (!slatCoords) {
13719                return null;
13720            }
13721            return segs.map((seg, i) => (y(NowIndicatorContainer
13722                // key doesn't matter. will only ever be one
13723                , {
13724                    // key doesn't matter. will only ever be one
13725                    key: i, elClasses: ['fc-timegrid-now-indicator-line'], elStyle: {
13726                        top: slatCoords.computeDateTop(seg.start, date),
13727                    }, isAxis: false, date: date })));
13728        }
13729        computeSegHStyle(segHCoords) {
13730            let { isRtl, options } = this.context;
13731            let shouldOverlap = options.slotEventOverlap;
13732            let nearCoord = segHCoords.levelCoord; // the left side if LTR. the right side if RTL. floating-point
13733            let farCoord = segHCoords.levelCoord + segHCoords.thickness; // the right side if LTR. the left side if RTL. floating-point
13734            let left; // amount of space from left edge, a fraction of the total width
13735            let right; // amount of space from right edge, a fraction of the total width
13736            if (shouldOverlap) {
13737                // double the width, but don't go beyond the maximum forward coordinate (1.0)
13738                farCoord = Math.min(1, nearCoord + (farCoord - nearCoord) * 2);
13739            }
13740            if (isRtl) {
13741                left = 1 - farCoord;
13742                right = nearCoord;
13743            }
13744            else {
13745                left = nearCoord;
13746                right = 1 - farCoord;
13747            }
13748            let props = {
13749                zIndex: segHCoords.stackDepth + 1,
13750                left: left * 100 + '%',
13751                right: right * 100 + '%',
13752            };
13753            if (shouldOverlap && !segHCoords.stackForward) {
13754                // add padding to the edge so that forward stacked events don't cover the resizer's icon
13755                props[isRtl ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width
13756            }
13757            return props;
13758        }
13759    }
13760    function renderPlainFgSegs(sortedFgSegs, { todayRange, nowDate, eventSelection, eventDrag, eventResize }) {
13761        let hiddenInstances = (eventDrag ? eventDrag.affectedInstances : null) ||
13762            (eventResize ? eventResize.affectedInstances : null) ||
13763            {};
13764        return (y(_, null, sortedFgSegs.map((seg) => {
13765            let instanceId = seg.eventRange.instance.instanceId;
13766            return (y("div", { key: instanceId, style: { visibility: hiddenInstances[instanceId] ? 'hidden' : '' } },
13767                y(TimeColEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === eventSelection, isShort: false }, getSegMeta(seg, todayRange, nowDate)))));
13768        })));
13769    }
13770    function computeSegVStyle(segVCoords) {
13771        if (!segVCoords) {
13772            return { top: '', bottom: '' };
13773        }
13774        return {
13775            top: segVCoords.start,
13776            bottom: -segVCoords.end,
13777        };
13778    }
13779    function compileSegsFromEntries(segEntries, allSegs) {
13780        return segEntries.map((segEntry) => allSegs[segEntry.index]);
13781    }
13782
13783    class TimeColsContent extends BaseComponent {
13784        constructor() {
13785            super(...arguments);
13786            this.splitFgEventSegs = memoize(splitSegsByCol);
13787            this.splitBgEventSegs = memoize(splitSegsByCol);
13788            this.splitBusinessHourSegs = memoize(splitSegsByCol);
13789            this.splitNowIndicatorSegs = memoize(splitSegsByCol);
13790            this.splitDateSelectionSegs = memoize(splitSegsByCol);
13791            this.splitEventDrag = memoize(splitInteractionByCol);
13792            this.splitEventResize = memoize(splitInteractionByCol);
13793            this.rootElRef = d();
13794            this.cellElRefs = new RefMap();
13795        }
13796        render() {
13797            let { props, context } = this;
13798            let nowIndicatorTop = context.options.nowIndicator &&
13799                props.slatCoords &&
13800                props.slatCoords.safeComputeTop(props.nowDate); // might return void
13801            let colCnt = props.cells.length;
13802            let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, colCnt);
13803            let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, colCnt);
13804            let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, colCnt);
13805            let nowIndicatorSegsByRow = this.splitNowIndicatorSegs(props.nowIndicatorSegs, colCnt);
13806            let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, colCnt);
13807            let eventDragByRow = this.splitEventDrag(props.eventDrag, colCnt);
13808            let eventResizeByRow = this.splitEventResize(props.eventResize, colCnt);
13809            return (y("div", { className: "fc-timegrid-cols", ref: this.rootElRef },
13810                y("table", { role: "presentation", style: {
13811                            minWidth: props.tableMinWidth,
13812                            width: props.clientWidth,
13813                        } },
13814                    props.tableColGroupNode,
13815                    y("tbody", { role: "presentation" },
13816                        y("tr", { role: "row" },
13817                            props.axis && (y("td", { "aria-hidden": true, className: "fc-timegrid-col fc-timegrid-axis" },
13818                                y("div", { className: "fc-timegrid-col-frame" },
13819                                    y("div", { className: "fc-timegrid-now-indicator-container" }, typeof nowIndicatorTop === 'number' && (y(NowIndicatorContainer, { elClasses: ['fc-timegrid-now-indicator-arrow'], elStyle: { top: nowIndicatorTop }, isAxis: true, date: props.nowDate })))))),
13820                            props.cells.map((cell, i) => (y(TimeCol, { key: cell.key, elRef: this.cellElRefs.createRef(cell.key), dateProfile: props.dateProfile, date: cell.date, nowDate: props.nowDate, todayRange: props.todayRange, extraRenderProps: cell.extraRenderProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, fgEventSegs: fgEventSegsByRow[i], bgEventSegs: bgEventSegsByRow[i], businessHourSegs: businessHourSegsByRow[i], nowIndicatorSegs: nowIndicatorSegsByRow[i], dateSelectionSegs: dateSelectionSegsByRow[i], eventDrag: eventDragByRow[i], eventResize: eventResizeByRow[i], slatCoords: props.slatCoords, eventSelection: props.eventSelection, forPrint: props.forPrint }))))))));
13821        }
13822        componentDidMount() {
13823            this.updateCoords();
13824        }
13825        componentDidUpdate() {
13826            this.updateCoords();
13827        }
13828        updateCoords() {
13829            let { props } = this;
13830            if (props.onColCoords &&
13831                props.clientWidth !== null // means sizing has stabilized
13832            ) {
13833                props.onColCoords(new PositionCache(this.rootElRef.current, collectCellEls(this.cellElRefs.currentMap, props.cells), true, // horizontal
13834                    false));
13835            }
13836        }
13837    }
13838    function collectCellEls(elMap, cells) {
13839        return cells.map((cell) => elMap[cell.key]);
13840    }
13841
13842    /* A component that renders one or more columns of vertical time slots
13843    ----------------------------------------------------------------------------------------------------------------------*/
13844    class TimeCols extends DateComponent {
13845        constructor() {
13846            super(...arguments);
13847            this.processSlotOptions = memoize(processSlotOptions);
13848            this.state = {
13849                slatCoords: null,
13850            };
13851            this.handleRootEl = (el) => {
13852                if (el) {
13853                    this.context.registerInteractiveComponent(this, {
13854                        el,
13855                        isHitComboAllowed: this.props.isHitComboAllowed,
13856                    });
13857                }
13858                else {
13859                    this.context.unregisterInteractiveComponent(this);
13860                }
13861            };
13862            this.handleScrollRequest = (request) => {
13863                let { onScrollTopRequest } = this.props;
13864                let { slatCoords } = this.state;
13865                if (onScrollTopRequest && slatCoords) {
13866                    if (request.time) {
13867                        let top = slatCoords.computeTimeTop(request.time);
13868                        top = Math.ceil(top); // zoom can give weird floating-point values. rather scroll a little bit further
13869                        if (top) {
13870                            top += 1; // to overcome top border that slots beyond the first have. looks better
13871                        }
13872                        onScrollTopRequest(top);
13873                    }
13874                    return true;
13875                }
13876                return false;
13877            };
13878            this.handleColCoords = (colCoords) => {
13879                this.colCoords = colCoords;
13880            };
13881            this.handleSlatCoords = (slatCoords) => {
13882                this.setState({ slatCoords });
13883                if (this.props.onSlatCoords) {
13884                    this.props.onSlatCoords(slatCoords);
13885                }
13886            };
13887        }
13888        render() {
13889            let { props, state } = this;
13890            return (y("div", { className: "fc-timegrid-body", ref: this.handleRootEl, style: {
13891                        // these props are important to give this wrapper correct dimensions for interactions
13892                        // TODO: if we set it here, can we avoid giving to inner tables?
13893                        width: props.clientWidth,
13894                        minWidth: props.tableMinWidth,
13895                    } },
13896                y(TimeColsSlats, { axis: props.axis, dateProfile: props.dateProfile, slatMetas: props.slatMetas, clientWidth: props.clientWidth, minHeight: props.expandRows ? props.clientHeight : '', tableMinWidth: props.tableMinWidth, tableColGroupNode: props.axis ? props.tableColGroupNode : null /* axis depends on the colgroup's shrinking */, onCoords: this.handleSlatCoords }),
13897                y(TimeColsContent, { cells: props.cells, axis: props.axis, dateProfile: props.dateProfile, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange, nowDate: props.nowDate, nowIndicatorSegs: props.nowIndicatorSegs, clientWidth: props.clientWidth, tableMinWidth: props.tableMinWidth, tableColGroupNode: props.tableColGroupNode, slatCoords: state.slatCoords, onColCoords: this.handleColCoords, forPrint: props.forPrint })));
13898        }
13899        componentDidMount() {
13900            this.scrollResponder = this.context.createScrollResponder(this.handleScrollRequest);
13901        }
13902        componentDidUpdate(prevProps) {
13903            this.scrollResponder.update(prevProps.dateProfile !== this.props.dateProfile);
13904        }
13905        componentWillUnmount() {
13906            this.scrollResponder.detach();
13907        }
13908        queryHit(positionLeft, positionTop) {
13909            let { dateEnv, options } = this.context;
13910            let { colCoords } = this;
13911            let { dateProfile } = this.props;
13912            let { slatCoords } = this.state;
13913            let { snapDuration, snapsPerSlot } = this.processSlotOptions(this.props.slotDuration, options.snapDuration);
13914            let colIndex = colCoords.leftToIndex(positionLeft);
13915            let slatIndex = slatCoords.positions.topToIndex(positionTop);
13916            if (colIndex != null && slatIndex != null) {
13917                let cell = this.props.cells[colIndex];
13918                let slatTop = slatCoords.positions.tops[slatIndex];
13919                let slatHeight = slatCoords.positions.getHeight(slatIndex);
13920                let partial = (positionTop - slatTop) / slatHeight; // floating point number between 0 and 1
13921                let localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat
13922                let snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
13923                let dayDate = this.props.cells[colIndex].date;
13924                let time = addDurations(dateProfile.slotMinTime, multiplyDuration(snapDuration, snapIndex));
13925                let start = dateEnv.add(dayDate, time);
13926                let end = dateEnv.add(start, snapDuration);
13927                return {
13928                    dateProfile,
13929                    dateSpan: Object.assign({ range: { start, end }, allDay: false }, cell.extraDateSpan),
13930                    dayEl: colCoords.els[colIndex],
13931                    rect: {
13932                        left: colCoords.lefts[colIndex],
13933                        right: colCoords.rights[colIndex],
13934                        top: slatTop,
13935                        bottom: slatTop + slatHeight,
13936                    },
13937                    layer: 0,
13938                };
13939            }
13940            return null;
13941        }
13942    }
13943    function processSlotOptions(slotDuration, snapDurationOverride) {
13944        let snapDuration = snapDurationOverride || slotDuration;
13945        let snapsPerSlot = wholeDivideDurations(slotDuration, snapDuration);
13946        if (snapsPerSlot === null) {
13947            snapDuration = slotDuration;
13948            snapsPerSlot = 1;
13949            // TODO: say warning?
13950        }
13951        return { snapDuration, snapsPerSlot };
13952    }
13953
13954    class DayTimeColsSlicer extends Slicer {
13955        sliceRange(range, dayRanges) {
13956            let segs = [];
13957            for (let col = 0; col < dayRanges.length; col += 1) {
13958                let segRange = intersectRanges(range, dayRanges[col]);
13959                if (segRange) {
13960                    segs.push({
13961                        start: segRange.start,
13962                        end: segRange.end,
13963                        isStart: segRange.start.valueOf() === range.start.valueOf(),
13964                        isEnd: segRange.end.valueOf() === range.end.valueOf(),
13965                        col,
13966                    });
13967                }
13968            }
13969            return segs;
13970        }
13971    }
13972
13973    class DayTimeCols extends DateComponent {
13974        constructor() {
13975            super(...arguments);
13976            this.buildDayRanges = memoize(buildDayRanges);
13977            this.slicer = new DayTimeColsSlicer();
13978            this.timeColsRef = d();
13979        }
13980        render() {
13981            let { props, context } = this;
13982            let { dateProfile, dayTableModel } = props;
13983            let { nowIndicator, nextDayThreshold } = context.options;
13984            let dayRanges = this.buildDayRanges(dayTableModel, dateProfile, context.dateEnv);
13985            // give it the first row of cells
13986            // TODO: would move this further down hierarchy, but sliceNowDate needs it
13987            return (y(NowTimer, { unit: nowIndicator ? 'minute' : 'day' }, (nowDate, todayRange) => (y(TimeCols, Object.assign({ ref: this.timeColsRef }, this.slicer.sliceProps(props, dateProfile, null, context, dayRanges), { forPrint: props.forPrint, axis: props.axis, dateProfile: dateProfile, slatMetas: props.slatMetas, slotDuration: props.slotDuration, cells: dayTableModel.cells[0], tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, clientWidth: props.clientWidth, clientHeight: props.clientHeight, expandRows: props.expandRows, nowDate: nowDate, nowIndicatorSegs: nowIndicator && this.slicer.sliceNowDate(nowDate, dateProfile, nextDayThreshold, context, dayRanges), todayRange: todayRange, onScrollTopRequest: props.onScrollTopRequest, onSlatCoords: props.onSlatCoords })))));
13988        }
13989    }
13990    function buildDayRanges(dayTableModel, dateProfile, dateEnv) {
13991        let ranges = [];
13992        for (let date of dayTableModel.headerDates) {
13993            ranges.push({
13994                start: dateEnv.add(date, dateProfile.slotMinTime),
13995                end: dateEnv.add(date, dateProfile.slotMaxTime),
13996            });
13997        }
13998        return ranges;
13999    }
14000
14001    // potential nice values for the slot-duration and interval-duration
14002    // from largest to smallest
14003    const STOCK_SUB_DURATIONS = [
14004        { hours: 1 },
14005        { minutes: 30 },
14006        { minutes: 15 },
14007        { seconds: 30 },
14008        { seconds: 15 },
14009    ];
14010    function buildSlatMetas(slotMinTime, slotMaxTime, explicitLabelInterval, slotDuration, dateEnv) {
14011        let dayStart = new Date(0);
14012        let slatTime = slotMinTime;
14013        let slatIterator = createDuration(0);
14014        let labelInterval = explicitLabelInterval || computeLabelInterval(slotDuration);
14015        let metas = [];
14016        while (asRoughMs(slatTime) < asRoughMs(slotMaxTime)) {
14017            let date = dateEnv.add(dayStart, slatTime);
14018            let isLabeled = wholeDivideDurations(slatIterator, labelInterval) !== null;
14019            metas.push({
14020                date,
14021                time: slatTime,
14022                key: date.toISOString(),
14023                isoTimeStr: formatIsoTimeString(date),
14024                isLabeled,
14025            });
14026            slatTime = addDurations(slatTime, slotDuration);
14027            slatIterator = addDurations(slatIterator, slotDuration);
14028        }
14029        return metas;
14030    }
14031    // Computes an automatic value for slotLabelInterval
14032    function computeLabelInterval(slotDuration) {
14033        let i;
14034        let labelInterval;
14035        let slotsPerLabel;
14036        // find the smallest stock label interval that results in more than one slots-per-label
14037        for (i = STOCK_SUB_DURATIONS.length - 1; i >= 0; i -= 1) {
14038            labelInterval = createDuration(STOCK_SUB_DURATIONS[i]);
14039            slotsPerLabel = wholeDivideDurations(labelInterval, slotDuration);
14040            if (slotsPerLabel !== null && slotsPerLabel > 1) {
14041                return labelInterval;
14042            }
14043        }
14044        return slotDuration; // fall back
14045    }
14046
14047    class DayTimeColsView extends TimeColsView {
14048        constructor() {
14049            super(...arguments);
14050            this.buildTimeColsModel = memoize(buildTimeColsModel);
14051            this.buildSlatMetas = memoize(buildSlatMetas);
14052        }
14053        render() {
14054            let { options, dateEnv, dateProfileGenerator } = this.context;
14055            let { props } = this;
14056            let { dateProfile } = props;
14057            let dayTableModel = this.buildTimeColsModel(dateProfile, dateProfileGenerator);
14058            let splitProps = this.allDaySplitter.splitProps(props);
14059            let slatMetas = this.buildSlatMetas(dateProfile.slotMinTime, dateProfile.slotMaxTime, options.slotLabelInterval, options.slotDuration, dateEnv);
14060            let { dayMinWidth } = options;
14061            let hasAttachedAxis = !dayMinWidth;
14062            let hasDetachedAxis = dayMinWidth;
14063            let headerContent = options.dayHeaders && (y(DayHeader, { dates: dayTableModel.headerDates, dateProfile: dateProfile, datesRepDistinctDays: true, renderIntro: hasAttachedAxis ? this.renderHeadAxis : null }));
14064            let allDayContent = (options.allDaySlot !== false) && ((contentArg) => (y(DayTable, Object.assign({}, splitProps.allDay, { dateProfile: dateProfile, dayTableModel: dayTableModel, nextDayThreshold: options.nextDayThreshold, tableMinWidth: contentArg.tableMinWidth, colGroupNode: contentArg.tableColGroupNode, renderRowIntro: hasAttachedAxis ? this.renderTableRowAxis : null, showWeekNumbers: false, expandRows: false, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }, this.getAllDayMaxEventProps()))));
14065            let timeGridContent = (contentArg) => (y(DayTimeCols, Object.assign({}, splitProps.timed, { dayTableModel: dayTableModel, dateProfile: dateProfile, axis: hasAttachedAxis, slotDuration: options.slotDuration, slatMetas: slatMetas, forPrint: props.forPrint, tableColGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, onSlatCoords: this.handleSlatCoords, expandRows: contentArg.expandRows, onScrollTopRequest: this.handleScrollTopRequest })));
14066            return hasDetachedAxis
14067                ? this.renderHScrollLayout(headerContent, allDayContent, timeGridContent, dayTableModel.colCnt, dayMinWidth, slatMetas, this.state.slatCoords)
14068                : this.renderSimpleLayout(headerContent, allDayContent, timeGridContent);
14069        }
14070    }
vendor: 9,797 bytes, lines 14071-14261
14071    function buildTimeColsModel(dateProfile, dateProfileGenerator) {
14072        let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
14073        return new DayTableModel(daySeries, false);
14074    }
14075
14076    const OPTION_REFINERS$2 = {
14077        allDaySlot: Boolean,
14078    };
14079
14080    var index$2 = createPlugin({
14081        name: '@fullcalendar/timegrid',
14082        initialView: 'timeGridWeek',
14083        optionRefiners: OPTION_REFINERS$2,
14084        views: {
14085            timeGrid: {
14086                component: DayTimeColsView,
14087                usesMinMaxTime: true,
14088                allDaySlot: true,
14089                slotDuration: '00:30:00',
14090                slotEventOverlap: true, // a bad name. confused with overlap/constraint system
14091            },
14092            timeGridDay: {
14093                type: 'timeGrid',
14094                duration: { days: 1 },
14095            },
14096            timeGridWeek: {
14097                type: 'timeGrid',
14098                duration: { weeks: 1 },
14099            },
14100        },
14101    });
14102
14103    class ListViewHeaderRow extends BaseComponent {
14104        constructor() {
14105            super(...arguments);
14106            this.state = {
14107                textId: getUniqueDomId(),
14108            };
14109        }
14110        render() {
14111            let { theme, dateEnv, options, viewApi } = this.context;
14112            let { cellId, dayDate, todayRange } = this.props;
14113            let { textId } = this.state;
14114            let dayMeta = getDateMeta(dayDate, todayRange);
14115            // will ever be falsy?
14116            let text = options.listDayFormat ? dateEnv.format(dayDate, options.listDayFormat) : '';
14117            // will ever be falsy? also, BAD NAME "alt"
14118            let sideText = options.listDaySideFormat ? dateEnv.format(dayDate, options.listDaySideFormat) : '';
14119            let renderProps = Object.assign({ date: dateEnv.toDate(dayDate), view: viewApi, textId,
14120                text,
14121                sideText, navLinkAttrs: buildNavLinkAttrs(this.context, dayDate), sideNavLinkAttrs: buildNavLinkAttrs(this.context, dayDate, 'day', false) }, dayMeta);
14122            // TODO: make a reusable HOC for dayHeader (used in daygrid/timegrid too)
14123            return (y(ContentContainer, { elTag: "tr", elClasses: [
14124                    'fc-list-day',
14125                    ...getDayClassNames(dayMeta, theme),
14126                ], elAttrs: {
14127                    'data-date': formatDayString(dayDate),
14128                }, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContent) => ( // TODO: force-hide top border based on :first-child
14129                y("th", { scope: "colgroup", colSpan: 3, id: cellId, "aria-labelledby": textId },
14130                    y(InnerContent, { elTag: "div", elClasses: [
14131                            'fc-list-day-cushion',
14132                            theme.getClass('tableCellShaded'),
14133                        ] })))));
14134        }
14135    }
14136    function renderInnerContent(props) {
14137        return (y(_, null,
14138            props.text && (y("a", Object.assign({ id: props.textId, className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
14139            props.sideText && ( /* not keyboard tabbable */y("a", Object.assign({ "aria-hidden": true, className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
14140    }
14141
14142    const DEFAULT_TIME_FORMAT = createFormatter({
14143        hour: 'numeric',
14144        minute: '2-digit',
14145        meridiem: 'short',
14146    });
14147    class ListViewEventRow extends BaseComponent {
14148        render() {
14149            let { props, context } = this;
14150            let { options } = context;
14151            let { seg, timeHeaderId, eventHeaderId, dateHeaderId } = props;
14152            let timeFormat = options.eventTimeFormat || DEFAULT_TIME_FORMAT;
14153            return (y(EventContainer, Object.assign({}, props, { elTag: "tr", elClasses: [
14154                    'fc-list-event',
14155                    seg.eventRange.def.url && 'fc-event-forced-url',
14156                ], defaultGenerator: () => renderEventInnerContent(seg, context) /* weird */, seg: seg, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (y(_, null,
14157                buildTimeContent(seg, timeFormat, context, timeHeaderId, dateHeaderId),
14158                y("td", { "aria-hidden": true, className: "fc-list-event-graphic" },
14159                    y("span", { className: "fc-list-event-dot", style: {
14160                            borderColor: eventContentArg.borderColor || eventContentArg.backgroundColor,
14161                        } })),
14162                y(InnerContent, { elTag: "td", elClasses: ['fc-list-event-title'], elAttrs: { headers: `${eventHeaderId} ${dateHeaderId}` } })))));
14163        }
14164    }
14165    function renderEventInnerContent(seg, context) {
14166        let interactiveAttrs = getSegAnchorAttrs(seg, context);
14167        return (y("a", Object.assign({}, interactiveAttrs), seg.eventRange.def.title));
14168    }
14169    function buildTimeContent(seg, timeFormat, context, timeHeaderId, dateHeaderId) {
14170        let { options } = context;
14171        if (options.displayEventTime !== false) {
14172            let eventDef = seg.eventRange.def;
14173            let eventInstance = seg.eventRange.instance;
14174            let doAllDay = false;
14175            let timeText;
14176            if (eventDef.allDay) {
14177                doAllDay = true;
14178            }
14179            else if (isMultiDayRange(seg.eventRange.range)) { // TODO: use (!isStart || !isEnd) instead?
14180                if (seg.isStart) {
14181                    timeText = buildSegTimeText(seg, timeFormat, context, null, null, eventInstance.range.start, seg.end);
14182                }
14183                else if (seg.isEnd) {
14184                    timeText = buildSegTimeText(seg, timeFormat, context, null, null, seg.start, eventInstance.range.end);
14185                }
14186                else {
14187                    doAllDay = true;
14188                }
14189            }
14190            else {
14191                timeText = buildSegTimeText(seg, timeFormat, context);
14192            }
14193            if (doAllDay) {
14194                let renderProps = {
14195                    text: context.options.allDayText,
14196                    view: context.viewApi,
14197                };
14198                return (y(ContentContainer, { elTag: "td", elClasses: ['fc-list-event-time'], elAttrs: {
14199                        headers: `${timeHeaderId} ${dateHeaderId}`,
14200                    }, renderProps: renderProps, generatorName: "allDayContent", customGenerator: options.allDayContent, defaultGenerator: renderAllDayInner, classNameGenerator: options.allDayClassNames, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }));
14201            }
14202            return (y("td", { className: "fc-list-event-time" }, timeText));
14203        }
14204        return null;
14205    }
14206    function renderAllDayInner(renderProps) {
14207        return renderProps.text;
14208    }
14209
14210    /*
14211    Responsible for the scroller, and forwarding event-related actions into the "grid".
14212    */
14213    class ListView extends DateComponent {
14214        constructor() {
14215            super(...arguments);
14216            this.computeDateVars = memoize(computeDateVars);
14217            this.eventStoreToSegs = memoize(this._eventStoreToSegs);
14218            this.state = {
14219                timeHeaderId: getUniqueDomId(),
14220                eventHeaderId: getUniqueDomId(),
14221                dateHeaderIdRoot: getUniqueDomId(),
14222            };
14223            this.setRootEl = (rootEl) => {
14224                if (rootEl) {
14225                    this.context.registerInteractiveComponent(this, {
14226                        el: rootEl,
14227                    });
14228                }
14229                else {
14230                    this.context.unregisterInteractiveComponent(this);
14231                }
14232            };
14233        }
14234        render() {
14235            let { props, context } = this;
14236            let { dayDates, dayRanges } = this.computeDateVars(props.dateProfile);
14237            let eventSegs = this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges);
14238            return (y(ViewContainer, { elRef: this.setRootEl, elClasses: [
14239                        'fc-list',
14240                        context.theme.getClass('table'),
14241                        context.options.stickyHeaderDates !== false ?
14242                            'fc-list-sticky' :
14243                            '',
14244                    ], viewSpec: context.viewSpec },
14245                y(Scroller, { liquid: !props.isHeightAuto, overflowX: props.isHeightAuto ? 'visible' : 'hidden', overflowY: props.isHeightAuto ? 'visible' : 'auto' }, eventSegs.length > 0 ?
14246                    this.renderSegList(eventSegs, dayDates) :
14247                    this.renderEmptyMessage())));
14248        }
14249        renderEmptyMessage() {
14250            let { options, viewApi } = this.context;
14251            let renderProps = {
14252                text: options.noEventsText,
14253                view: viewApi,
14254            };
14255            return (y(ContentContainer, { elTag: "div", elClasses: ['fc-list-empty'], renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (y(InnerContent, { elTag: "div", elClasses: ['fc-list-empty-cushion'] }))));
14256        }
14257        renderSegList(allSegs, dayDates) {
14258            let { theme, options } = this.context;
14259            let { timeHeaderId, eventHeaderId, dateHeaderIdRoot } = this.state;
14260            let segsByDay = groupSegsByDay(allSegs); // sparse array
14261            return (y(NowTimer, { unit: "day" }, (nowDate, todayRange) => {
14262                let innerNodes = [];
14263                for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
14264                    let daySegs = segsByDay[dayIndex];
14265                    if (daySegs) { // sparse array, so might be undefined
14266                        let dayStr = formatDayString(dayDates[dayIndex]);
14267                        let dateHeaderId = dateHeaderIdRoot + '-' + dayStr;
14268                        // append a day header
14269                        innerNodes.push(y(ListViewHeaderRow, { key: dayStr, cellId: dateHeaderId, dayDate: dayDates[dayIndex], todayRange: todayRange }));
14270                        daySegs = sortEventSegs(daySegs, options.eventOrder);
14271                        for (let seg of daySegs) {
14272                            innerNodes.push(y(ListViewEventRow, Object.assign({ key: dayStr + ':' + seg.eventRange.instance.instanceId /* are multiple segs for an instanceId */, seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false, timeHeaderId: timeHeaderId, eventHeaderId: eventHeaderId, dateHeaderId: dateHeaderId }, getSegMeta(seg, todayRange, nowDate))));
14273                        }
14274                    }
14275                }
14276                return (y("table", { className: 'fc-list-table ' + theme.getClass('table') },
14277                    y("thead", null,
14278                        y("tr", null,
14279                            y("th", { scope: "col", id: timeHeaderId }, options.timeHint),
14280                            y("th", { scope: "col", "aria-hidden": true }),
14281                            y("th", { scope: "col", id: eventHeaderId }, options.eventHint))),
14282                    y("tbody", null, innerNodes)));
14283            }));
14284        }
14285        _eventStoreToSegs(eventStore, eventUiBases, dayRanges) {
14286            return this.eventRangesToSegs(sliceEventStore(eventStore, eventUiBases, this.props.dateProfile.activeRange, this.context.options.nextDayThreshold).fg, dayRanges);
14287        }
14288        eventRangesToSegs(eventRanges, dayRanges) {
14289            let segs = [];
14290            for (let eventRange of eventRanges) {
14291                segs.push(...this.eventRangeToSegs(eventRange, dayRanges));
14292            }
14293            return segs;
14294        }
14295        eventRangeToSegs(eventRange, dayRanges) {
14296            let { dateEnv } = this.context;
14297            let { nextDayThreshold } = this.context.options;
14298            let range = eventRange.range;
14299            let allDay = eventRange.def.allDay;
14300            let dayIndex;
14301            let segRange;
14302            let seg;
14303            let segs = [];
14304            for (dayIndex = 0; dayIndex < dayRanges.length; dayIndex += 1) {
14305                segRange = intersectRanges(range, dayRanges[dayIndex]);
14306                if (segRange) {
14307                    seg = {
14308                        component: this,
14309                        eventRange,
14310                        start: segRange.start,
14311                        end: segRange.end,
14312                        isStart: eventRange.isStart && segRange.start.valueOf() === range.start.valueOf(),
14313                        isEnd: eventRange.isEnd && segRange.end.valueOf() === range.end.valueOf(),
14314                        dayIndex,
14315                    };
14316                    segs.push(seg);
14317                    // detect when range won't go fully into the next day,
14318                    // and mutate the latest seg to the be the end.
14319                    if (!seg.isEnd && !allDay &&
14320                        dayIndex + 1 < dayRanges.length &&
14321                        range.end <
14322                        dateEnv.add(dayRanges[dayIndex + 1].start, nextDayThreshold)) {
14323                        seg.end = range.end;
14324                        seg.isEnd = true;
14325                        break;
14326                    }
14327                }
14328            }
14329            return segs;
14330        }
14331    }
14332    function renderNoEventsInner(renderProps) {
14333        return renderProps.text;
14334    }
14335    function computeDateVars(dateProfile) {
14336        let dayStart = startOfDay(dateProfile.renderRange.start);
14337        let viewEnd = dateProfile.renderRange.end;
14338        let dayDates = [];
14339        let dayRanges = [];
14340        while (dayStart < viewEnd) {
14341            dayDates.push(dayStart);
14342            dayRanges.push({
14343                start: dayStart,
14344                end: addDays(dayStart, 1),
14345            });
14346            dayStart = addDays(dayStart, 1);
14347        }
14348        return { dayDates, dayRanges };
14349    }
14350    // Returns a sparse array of arrays, segs grouped by their dayIndex
14351    function groupSegsByDay(segs) {
14352        let segsByDay = []; // sparse array
14353        let i;
14354        let seg;
14355        for (i = 0; i < segs.length; i += 1) {
14356            seg = segs[i];
14357            (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = []))
14358                .push(seg);
14359        }
14360        return segsByDay;
14361    }
14362
14363    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}";
14364    injectStyles(css_248z$1);
14365
14366    const OPTION_REFINERS$1 = {
14367        listDayFormat: createFalsableFormatter,
14368        listDaySideFormat: createFalsableFormatter,
14369        noEventsClassNames: identity,
14370        noEventsContent: identity,
14371        noEventsDidMount: identity,
14372        noEventsWillUnmount: identity,
14373        // noEventsText is defined in base options
14374    };
14375    function createFalsableFormatter(input) {
14376        return input === false ? null : createFormatter(input);
14377    }
14378
14379    var index$1 = createPlugin({
14380        name: '@fullcalendar/list',
14381        optionRefiners: OPTION_REFINERS$1,
14382        views: {
14383            list: {
14384                component: ListView,
14385                buttonTextKey: 'list',
14386                listDayFormat: { month: 'long', day: 'numeric', year: 'numeric' }, // like "January 1, 2016"
14387            },
14388            listDay: {
14389                type: 'list',
14390                duration: { days: 1 },
14391                listDayFormat: { weekday: 'long' }, // day-of-week is all we need. full date is probably in headerToolbar
14392            },
14393            listWeek: {
14394                type: 'list',
14395                duration: { weeks: 1 },
14396                listDayFormat: { weekday: 'long' },
14397                listDaySideFormat: { month: 'long', day: 'numeric', year: 'numeric' },
14398            },
14399            listMonth: {
14400                type: 'list',
14401                duration: { month: 1 },
14402                listDaySideFormat: { weekday: 'long' }, // day-of-week is nice-to-have
14403            },
14404            listYear: {
14405                type: 'list',
14406                duration: { year: 1 },
14407                listDaySideFormat: { weekday: 'long' }, // day-of-week is nice-to-have
14408            },
14409        },
14410    });
14411
14412    class SingleMonth extends DateComponent {
14413        constructor() {
14414            super(...arguments);
14415            this.buildDayTableModel = memoize(buildDayTableModel);
14416            this.slicer = new DayTableSlicer();
14417            this.state = {
14418                labelId: getUniqueDomId(),
14419            };
14420        }
14421        render() {
14422            const { props, state, context } = this;
14423            const { dateProfile, forPrint } = props;
14424            const { options } = context;
14425            const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
14426            const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
14427            // ensure single-month has aspect ratio
14428            const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
14429            const rowCnt = dayTableModel.cells.length;
14430            const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
14431            return (y("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
14432                y("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
14433                    y("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
14434                    y("table", { className: [
14435                                'fc-multimonth-header-table',
14436                                context.theme.getClass('table'),
14437                            ].join(' '), role: "presentation" },
14438                        y("thead", { role: "rowgroup" },
14439                            y(DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
14440                y("div", { className: [
14441                            'fc-multimonth-daygrid',
vendor: 9,907 bytes, lines 14442-14621
14442                            'fc-daygrid',
14443                            'fc-daygrid-body',
14444                            !forPrint && 'fc-daygrid-body-balanced',
14445                            forPrint && 'fc-daygrid-body-unbalanced',
14446                            forPrint && 'fc-daygrid-body-natural',
14447                        ].join(' '), style: { marginTop: -rowHeight } },
14448                    y("table", { className: [
14449                                'fc-multimonth-daygrid-table',
14450                                context.theme.getClass('table'),
14451                            ].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
14452                        y("tbody", { role: "rowgroup" },
14453                            y(TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
14454        }
14455    }
14456
14457    class MultiMonthView extends DateComponent {
14458        constructor() {
14459            super(...arguments);
14460            this.splitDateProfileByMonth = memoize(splitDateProfileByMonth);
14461            this.buildMonthFormat = memoize(buildMonthFormat);
14462            this.scrollElRef = d();
14463            this.firstMonthElRef = d();
14464            this.needsScrollReset = false;
14465            this.handleSizing = (isForced) => {
14466                if (isForced) {
14467                    this.updateSize();
14468                }
14469            };
14470        }
14471        render() {
14472            const { context, props, state } = this;
14473            const { options } = context;
14474            const { clientWidth, clientHeight } = state;
14475            const monthHPadding = state.monthHPadding || 0;
14476            const colCount = Math.min(clientWidth != null ?
14477                Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
14478                1, options.multiMonthMaxColumns) || 1;
14479            const monthWidthPct = (100 / colCount) + '%';
14480            const monthTableWidth = clientWidth == null ? null :
14481                (clientWidth / colCount) - monthHPadding;
14482            const isLegitSingleCol = clientWidth != null && colCount === 1;
14483            const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
14484            const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
14485            const rootClassNames = [
14486                'fc-multimonth',
14487                isLegitSingleCol ?
14488                    'fc-multimonth-singlecol' :
14489                    'fc-multimonth-multicol',
14490                (monthTableWidth != null && monthTableWidth < 400) ?
14491                    'fc-multimonth-compact' :
14492                    '',
14493            ];
14494            return (y(ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
14495                const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
14496                return (y(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
14497            })));
14498        }
14499        componentDidMount() {
14500            this.updateSize();
14501            this.context.addResizeHandler(this.handleSizing);
14502            this.requestScrollReset();
14503        }
14504        componentDidUpdate(prevProps) {
14505            if (!isPropsEqual(prevProps, this.props)) { // an external change?
14506                this.handleSizing(false);
14507            }
14508            if (prevProps.dateProfile !== this.props.dateProfile) {
14509                this.requestScrollReset();
14510            }
14511            else {
14512                this.flushScrollReset();
14513            }
14514        }
14515        componentWillUnmount() {
14516            this.context.removeResizeHandler(this.handleSizing);
14517        }
14518        updateSize() {
14519            const scrollEl = this.scrollElRef.current;
14520            const firstMonthEl = this.firstMonthElRef.current;
14521            if (scrollEl) {
14522                this.setState({
14523                    clientWidth: scrollEl.clientWidth,
14524                    clientHeight: scrollEl.clientHeight,
14525                });
14526            }
14527            if (firstMonthEl && scrollEl) {
14528                if (this.state.monthHPadding == null) { // always remember initial non-zero value
14529                    this.setState({
14530                        monthHPadding: scrollEl.clientWidth - // go within padding
14531                            firstMonthEl.firstChild.offsetWidth,
14532                    });
14533                }
14534            }
14535        }
14536        requestScrollReset() {
14537            this.needsScrollReset = true;
14538            this.flushScrollReset();
14539        }
14540        flushScrollReset() {
14541            if (this.needsScrollReset &&
14542                this.state.monthHPadding != null // indicates sizing already happened
14543            ) {
14544                const { currentDate } = this.props.dateProfile;
14545                const scrollEl = this.scrollElRef.current;
14546                const monthEl = scrollEl.querySelector(`[data-date="${formatIsoMonthStr(currentDate)}"]`);
14547                scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
14548                    this.firstMonthElRef.current.getBoundingClientRect().top;
14549                this.needsScrollReset = false;
14550            }
14551        }
14552        // workaround for when queued setState render (w/ clientWidth) gets cancelled because
14553        // subsequent update and shouldComponentUpdate says not to render :(
14554        shouldComponentUpdate() {
14555            return true;
14556        }
14557    }
14558    // date profile
14559    // -------------------------------------------------------------------------------------------------
14560    const oneMonthDuration = createDuration(1, 'month');
14561    function splitDateProfileByMonth(dateProfileGenerator, dateProfile, dateEnv, fixedWeekCount, showNonCurrentDates) {
14562        const { start, end } = dateProfile.currentRange;
14563        let monthStart = start;
14564        const monthDateProfiles = [];
14565        while (monthStart.valueOf() < end.valueOf()) {
14566            const monthEnd = dateEnv.add(monthStart, oneMonthDuration);
14567            const currentRange = {
14568                // yuck
14569                start: dateProfileGenerator.skipHiddenDays(monthStart),
14570                end: dateProfileGenerator.skipHiddenDays(monthEnd, -1, true),
14571            };
14572            let renderRange = buildDayTableRenderRange({
14573                currentRange,
14574                snapToWeek: true,
14575                fixedWeekCount,
14576                dateEnv,
14577            });
14578            renderRange = {
14579                // yuck
14580                start: dateProfileGenerator.skipHiddenDays(renderRange.start),
14581                end: dateProfileGenerator.skipHiddenDays(renderRange.end, -1, true),
14582            };
14583            const activeRange = dateProfile.activeRange ?
14584                intersectRanges(dateProfile.activeRange, showNonCurrentDates ? renderRange : currentRange) :
14585                null;
14586            monthDateProfiles.push({
14587                currentDate: dateProfile.currentDate,
14588                isValid: dateProfile.isValid,
14589                validRange: dateProfile.validRange,
14590                renderRange,
14591                activeRange,
14592                currentRange,
14593                currentRangeUnit: 'month',
14594                isRangeAllDay: true,
14595                dateIncrement: dateProfile.dateIncrement,
14596                slotMinTime: dateProfile.slotMaxTime,
14597                slotMaxTime: dateProfile.slotMinTime,
14598            });
14599            monthStart = monthEnd;
14600        }
14601        return monthDateProfiles;
14602    }
14603    // date formatting
14604    // -------------------------------------------------------------------------------------------------
14605    const YEAR_MONTH_FORMATTER = createFormatter({ year: 'numeric', month: 'long' });
14606    const YEAR_FORMATTER = createFormatter({ month: 'long' });
14607    function buildMonthFormat(formatOverride, monthDateProfiles) {
14608        return formatOverride ||
14609            ((monthDateProfiles[0].currentRange.start.getUTCFullYear() !==
14610                monthDateProfiles[monthDateProfiles.length - 1].currentRange.start.getUTCFullYear())
14611                ? YEAR_MONTH_FORMATTER
14612                : YEAR_FORMATTER);
14613    }
14614
14615    const OPTION_REFINERS = {
14616        multiMonthTitleFormat: createFormatter,
14617        multiMonthMaxColumns: Number,
14618        multiMonthMinWidth: Number,
14619    };
14620
14621    var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}
14621.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
14622    injectStyles(css_248z);
14623
14624    var index = createPlugin({
14625        name: '@fullcalendar/multimonth',
14626        initialView: 'multiMonthYear',
14627        optionRefiners: OPTION_REFINERS,
14628        views: {
14629            multiMonth: {
14630                component: MultiMonthView,
14631                dateProfileGeneratorClass: TableDateProfileGenerator,
14632                multiMonthMinWidth: 350,
14633                multiMonthMaxColumns: 3,
14634            },
14635            multiMonthYear: {
14636                type: 'multiMonth',
14637                duration: { years: 1 },
14638                fixedWeekCount: true,
14639                showNonCurrentDates: false,
14640            },
14641        },
14642    });
14643
14644    globalPlugins.push(index$4, index$3, index$2, index$1, index);
14645
14646    exports.Calendar = Calendar;
14647    exports.Draggable = ExternalDraggable;
14648    exports.Internal = internal;
14649    exports.JsonRequestError = JsonRequestError;
14650    exports.Preact = preact;
14651    exports.ThirdPartyDraggable = ThirdPartyDraggable;
14652    exports.createPlugin = createPlugin;
14653    exports.formatDate = formatDate;
14654    exports.formatRange = formatRange;
14655    exports.globalLocales = globalLocales;
14656    exports.globalPlugins = globalPlugins;
14657    exports.sliceEvents = sliceEvents;
14658    exports.version = version;
14659
14660    Object.defineProperty(exports, '__esModule', { value: true });
14661
14662    return exports;
14663
14664})({});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.