main.esm.js 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017
  1. /*!
  2. FullCalendar Timeline Plugin v4.4.3
  3. Docs & License: https://fullcalendar.io/scheduler
  4. (c) 2019 Adam Shaw
  5. */
  6. import { htmlToElement, forceClassName, applyStyle, debounce, preventDefault, ScrollComponent, EmitterMixin, removeElement, createElement, computeEdges, asRoughMs, isSingleDay, getDayClasses, findElements, Component, PositionCache, findChildren, isInt, multiplyDuration, config, createFormatter, greatestDurationDenominator, createDuration, wholeDivideDurations, addDays, startOfDay, computeVisibleDayRange, asRoughMinutes, padStart, asRoughSeconds, diffWholeDays, buildGotoAnchorHtml, htmlEscape, translateRect, memoizeRendering, rangeContainsMarker, computeEventDraggable, computeEventStartResizable, computeEventEndResizable, cssToStr, computeHeightAndMargins, applyStyleProp, FgEventRenderer, FillRenderer, DateComponent, intersectRanges, addMs, Slicer, View, createPlugin } from '@fullcalendar/core';
  7. /*! *****************************************************************************
  8. Copyright (c) Microsoft Corporation.
  9. Permission to use, copy, modify, and/or distribute this software for any
  10. purpose with or without fee is hereby granted.
  11. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  12. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  13. AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  14. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  15. LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  16. OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  17. PERFORMANCE OF THIS SOFTWARE.
  18. ***************************************************************************** */
  19. /* global Reflect, Promise */
  20. var extendStatics = function(d, b) {
  21. extendStatics = Object.setPrototypeOf ||
  22. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  23. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  24. return extendStatics(d, b);
  25. };
  26. function __extends(d, b) {
  27. extendStatics(d, b);
  28. function __() { this.constructor = d; }
  29. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  30. }
  31. var __assign = function() {
  32. __assign = Object.assign || function __assign(t) {
  33. for (var s, i = 1, n = arguments.length; i < n; i++) {
  34. s = arguments[i];
  35. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
  36. }
  37. return t;
  38. };
  39. return __assign.apply(this, arguments);
  40. };
  41. /*
  42. A rectangular area of content that lives within a Scroller.
  43. Can have "gutters", areas of dead spacing around the perimeter.
  44. Also very useful for forcing a width, which a Scroller cannot do alone.
  45. Has a content area that lives above a background area.
  46. */
  47. var ScrollerCanvas = /** @class */ (function () {
  48. function ScrollerCanvas() {
  49. this.gutters = {};
  50. this.el = htmlToElement("<div class=\"fc-scroller-canvas\"> <div class=\"fc-content\"></div> <div class=\"fc-bg\"></div> </div>");
  51. this.contentEl = this.el.querySelector('.fc-content');
  52. this.bgEl = this.el.querySelector('.fc-bg');
  53. }
  54. /*
  55. If falsy, resets all the gutters to 0
  56. */
  57. ScrollerCanvas.prototype.setGutters = function (gutters) {
  58. if (!gutters) {
  59. this.gutters = {};
  60. }
  61. else {
  62. __assign(this.gutters, gutters);
  63. }
  64. this.updateSize();
  65. };
  66. ScrollerCanvas.prototype.setWidth = function (width) {
  67. this.width = width;
  68. this.updateSize();
  69. };
  70. ScrollerCanvas.prototype.setMinWidth = function (minWidth) {
  71. this.minWidth = minWidth;
  72. this.updateSize();
  73. };
  74. ScrollerCanvas.prototype.clearWidth = function () {
  75. this.width = null;
  76. this.minWidth = null;
  77. this.updateSize();
  78. };
  79. ScrollerCanvas.prototype.updateSize = function () {
  80. var _a = this, gutters = _a.gutters, el = _a.el;
  81. // is border-box (width includes padding)
  82. forceClassName(el, 'fc-gutter-left', gutters.left);
  83. forceClassName(el, 'fc-gutter-right', gutters.right);
  84. forceClassName(el, 'fc-gutter-top', gutters.top);
  85. forceClassName(el, 'fc-gutter-bottom', gutters.bottom);
  86. applyStyle(el, {
  87. paddingLeft: gutters.left || '',
  88. paddingRight: gutters.right || '',
  89. paddingTop: gutters.top || '',
  90. paddingBottom: gutters.bottom || '',
  91. width: (this.width != null) ?
  92. this.width + (gutters.left || 0) + (gutters.right || 0) :
  93. '',
  94. minWidth: (this.minWidth != null) ?
  95. this.minWidth + (gutters.left || 0) + (gutters.right || 0) :
  96. ''
  97. });
  98. applyStyle(this.bgEl, {
  99. left: gutters.left || '',
  100. right: gutters.right || '',
  101. top: gutters.top || '',
  102. bottom: gutters.bottom || ''
  103. });
  104. };
  105. return ScrollerCanvas;
  106. }());
  107. var EnhancedScroller = /** @class */ (function (_super) {
  108. __extends(EnhancedScroller, _super);
  109. function EnhancedScroller(overflowX, overflowY) {
  110. var _this = _super.call(this, overflowX, overflowY) || this;
  111. // Scroll Events
  112. // ----------------------------------------------------------------------------------------------
  113. _this.reportScroll = function () {
  114. if (!_this.isScrolling) {
  115. _this.reportScrollStart();
  116. }
  117. _this.trigger('scroll');
  118. _this.isMoving = true;
  119. _this.requestMovingEnd();
  120. };
  121. _this.reportScrollStart = function () {
  122. if (!_this.isScrolling) {
  123. _this.isScrolling = true;
  124. _this.trigger('scrollStart', _this.isTouching); // created in constructor
  125. }
  126. };
  127. // Touch Events
  128. // ----------------------------------------------------------------------------------------------
  129. // will fire *before* the scroll event is fired
  130. _this.reportTouchStart = function () {
  131. _this.isTouching = true;
  132. };
  133. _this.reportTouchEnd = function () {
  134. if (_this.isTouching) {
  135. _this.isTouching = false;
  136. // if touch scrolling was re-enabled during a recent touch scroll
  137. // then unbind the handlers that are preventing it from happening.
  138. if (_this.isTouchScrollEnabled) {
  139. _this.unbindPreventTouchScroll(); // won't do anything if not bound
  140. }
  141. // if the user ended their touch, and the scroll area wasn't moving,
  142. // we consider this to be the end of the scroll.
  143. if (!_this.isMoving) {
  144. _this.reportScrollEnd(); // won't fire if already ended
  145. }
  146. }
  147. };
  148. _this.isScrolling = false;
  149. _this.isTouching = false;
  150. _this.isMoving = false;
  151. _this.isTouchScrollEnabled = true;
  152. _this.requestMovingEnd = debounce(_this.reportMovingEnd, 500);
  153. _this.canvas = new ScrollerCanvas();
  154. _this.el.appendChild(_this.canvas.el);
  155. _this.applyOverflow();
  156. _this.bindHandlers();
  157. return _this;
  158. }
  159. EnhancedScroller.prototype.destroy = function () {
  160. _super.prototype.destroy.call(this);
  161. this.unbindHandlers();
  162. };
  163. // Touch scroll prevention
  164. // ----------------------------------------------------------------------------------------------
  165. EnhancedScroller.prototype.disableTouchScroll = function () {
  166. this.isTouchScrollEnabled = false;
  167. this.bindPreventTouchScroll(); // will be unbound in enableTouchScroll or reportTouchEnd
  168. };
  169. EnhancedScroller.prototype.enableTouchScroll = function () {
  170. this.isTouchScrollEnabled = true;
  171. // only immediately unbind if a touch event is NOT in progress.
  172. // otherwise, it will be handled by reportTouchEnd.
  173. if (!this.isTouching) {
  174. this.unbindPreventTouchScroll();
  175. }
  176. };
  177. EnhancedScroller.prototype.bindPreventTouchScroll = function () {
  178. if (!this.preventTouchScrollHandler) {
  179. this.el.addEventListener('touchmove', (this.preventTouchScrollHandler = preventDefault));
  180. }
  181. };
  182. EnhancedScroller.prototype.unbindPreventTouchScroll = function () {
  183. if (this.preventTouchScrollHandler) {
  184. this.el.removeEventListener('touchmove', this.preventTouchScrollHandler);
  185. this.preventTouchScrollHandler = null;
  186. }
  187. };
  188. // Handlers
  189. // ----------------------------------------------------------------------------------------------
  190. EnhancedScroller.prototype.bindHandlers = function () {
  191. this.el.addEventListener('scroll', this.reportScroll);
  192. this.el.addEventListener('touchstart', this.reportTouchStart, { passive: true });
  193. this.el.addEventListener('touchend', this.reportTouchEnd);
  194. };
  195. EnhancedScroller.prototype.unbindHandlers = function () {
  196. this.el.removeEventListener('scroll', this.reportScroll);
  197. this.el.removeEventListener('touchstart', this.reportTouchStart, { passive: true });
  198. this.el.removeEventListener('touchend', this.reportTouchEnd);
  199. };
  200. EnhancedScroller.prototype.reportMovingEnd = function () {
  201. this.isMoving = false;
  202. // only end the scroll if not currently touching.
  203. // if touching, the scrolling will end later, on touchend.
  204. if (!this.isTouching) {
  205. this.reportScrollEnd();
  206. }
  207. };
  208. EnhancedScroller.prototype.reportScrollEnd = function () {
  209. if (this.isScrolling) {
  210. this.trigger('scrollEnd');
  211. this.isScrolling = false;
  212. }
  213. };
  214. // Horizontal Scroll Normalization
  215. // ----------------------------------------------------------------------------------------------
  216. // http://stackoverflow.com/questions/24276619/better-way-to-get-the-viewport-of-a-scrollable-div-in-rtl-mode/24394376#24394376
  217. // TODO: move all this to util functions
  218. /*
  219. If RTL, and scrolled to the left, returns NEGATIVE value (like Firefox)
  220. */
  221. EnhancedScroller.prototype.getScrollLeft = function () {
  222. var el = this.el;
  223. var direction = window.getComputedStyle(el).direction;
  224. var val = el.scrollLeft;
  225. if (direction === 'rtl') {
  226. switch (getRtlScrollSystem()) {
  227. case 'positive':
  228. val = (val + el.clientWidth) - el.scrollWidth;
  229. break;
  230. case 'reverse':
  231. val = -val;
  232. break;
  233. }
  234. }
  235. return val;
  236. };
  237. /*
  238. Accepts a NEGATIVE value for when scrolled in RTL
  239. */
  240. EnhancedScroller.prototype.setScrollLeft = function (val) {
  241. var el = this.el;
  242. var direction = window.getComputedStyle(el).direction;
  243. if (direction === 'rtl') {
  244. switch (getRtlScrollSystem()) {
  245. case 'positive':
  246. val = (val - el.clientWidth) + el.scrollWidth;
  247. break;
  248. case 'reverse':
  249. val = -val;
  250. break;
  251. }
  252. }
  253. el.scrollLeft = val;
  254. };
  255. /*
  256. Always returns the number of pixels scrolled from the leftmost position (even if RTL).
  257. Always positive.
  258. */
  259. EnhancedScroller.prototype.getScrollFromLeft = function () {
  260. var el = this.el;
  261. var direction = window.getComputedStyle(el).direction;
  262. var val = el.scrollLeft;
  263. if (direction === 'rtl') {
  264. switch (getRtlScrollSystem()) {
  265. case 'negative':
  266. val = (val - el.clientWidth) + el.scrollWidth;
  267. break;
  268. case 'reverse':
  269. val = (-val - el.clientWidth) + el.scrollWidth;
  270. break;
  271. }
  272. }
  273. return val;
  274. };
  275. return EnhancedScroller;
  276. }(ScrollComponent));
  277. EmitterMixin.mixInto(EnhancedScroller);
  278. // Horizontal Scroll System Detection
  279. // ----------------------------------------------------------------------------------------------
  280. var _rtlScrollSystem;
  281. function getRtlScrollSystem() {
  282. return _rtlScrollSystem || (_rtlScrollSystem = detectRtlScrollSystem());
  283. }
  284. function detectRtlScrollSystem() {
  285. var el = htmlToElement("<div style=\" position: absolute; top: -1000px; width: 1px; height: 1px; overflow: scroll; direction: rtl; font-size: 100px; \">A</div>");
  286. document.body.appendChild(el);
  287. var system;
  288. if (el.scrollLeft > 0) {
  289. system = 'positive';
  290. }
  291. else {
  292. el.scrollLeft = 1;
  293. if (el.scrollLeft > 0) {
  294. system = 'reverse';
  295. }
  296. else {
  297. system = 'negative';
  298. }
  299. }
  300. removeElement(el);
  301. return system;
  302. }
  303. /*
  304. A Scroller, but with a wrapping div that allows "clipping" away of native scrollbars,
  305. giving the appearance that there are no scrollbars.
  306. */
  307. var ClippedScroller = /** @class */ (function () {
  308. /*
  309. Received overflows can be set to 'clipped', meaning scrollbars shouldn't be visible
  310. to the user, but the area should still scroll.
  311. */
  312. function ClippedScroller(overflowX, overflowY, parentEl) {
  313. this.isHScrollbarsClipped = false;
  314. this.isVScrollbarsClipped = false;
  315. if (overflowX === 'clipped-scroll') {
  316. overflowX = 'scroll';
  317. this.isHScrollbarsClipped = true;
  318. }
  319. if (overflowY === 'clipped-scroll') {
  320. overflowY = 'scroll';
  321. this.isVScrollbarsClipped = true;
  322. }
  323. this.enhancedScroll = new EnhancedScroller(overflowX, overflowY);
  324. parentEl.appendChild(this.el = createElement('div', {
  325. className: 'fc-scroller-clip'
  326. }));
  327. this.el.appendChild(this.enhancedScroll.el);
  328. }
  329. ClippedScroller.prototype.destroy = function () {
  330. removeElement(this.el);
  331. };
  332. ClippedScroller.prototype.updateSize = function () {
  333. var enhancedScroll = this.enhancedScroll;
  334. var scrollEl = enhancedScroll.el;
  335. var edges = computeEdges(scrollEl);
  336. var cssProps = { marginLeft: 0, marginRight: 0, marginTop: 0, marginBottom: 0 };
  337. // give the inner scrolling div negative margins so that its scrollbars
  338. // are nudged outside of the bounding box of the wrapper, which is overflow:hidden
  339. if (this.isVScrollbarsClipped) {
  340. cssProps.marginLeft = -edges.scrollbarLeft;
  341. cssProps.marginRight = -edges.scrollbarRight;
  342. }
  343. if (this.isHScrollbarsClipped) {
  344. cssProps.marginBottom = -edges.scrollbarBottom;
  345. }
  346. applyStyle(scrollEl, cssProps);
  347. // if we are attempting to hide the scrollbars offscreen, OSX/iOS will still
  348. // display the floating scrollbars. attach a className to force-hide them.
  349. if ((this.isHScrollbarsClipped || (enhancedScroll.overflowX === 'hidden')) && // should never show?
  350. (this.isVScrollbarsClipped || (enhancedScroll.overflowY === 'hidden')) && // should never show?
  351. !( // doesn't have any scrollbar mass
  352. edges.scrollbarLeft ||
  353. edges.scrollbarRight ||
  354. edges.scrollbarBottom)) {
  355. scrollEl.classList.add('fc-no-scrollbars');
  356. }
  357. else {
  358. scrollEl.classList.remove('fc-no-scrollbars');
  359. }
  360. };
  361. ClippedScroller.prototype.setHeight = function (height) {
  362. this.enhancedScroll.setHeight(height);
  363. };
  364. /*
  365. Accounts for 'clipped' scrollbars
  366. */
  367. ClippedScroller.prototype.getScrollbarWidths = function () {
  368. var widths = this.enhancedScroll.getScrollbarWidths();
  369. if (this.isVScrollbarsClipped) {
  370. widths.left = 0;
  371. widths.right = 0;
  372. }
  373. if (this.isHScrollbarsClipped) {
  374. widths.bottom = 0;
  375. }
  376. return widths;
  377. };
  378. return ClippedScroller;
  379. }());
  380. var ScrollJoiner = /** @class */ (function () {
  381. function ScrollJoiner(axis, scrollers) {
  382. this.axis = axis;
  383. this.scrollers = scrollers;
  384. for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
  385. var scroller = _a[_i];
  386. this.initScroller(scroller);
  387. }
  388. }
  389. ScrollJoiner.prototype.initScroller = function (scroller) {
  390. var _this = this;
  391. var enhancedScroll = scroller.enhancedScroll;
  392. // when the user scrolls via mousewheel, we know for sure the target
  393. // scroller should be the master. capture the various x-browser events that fire.
  394. var onScroll = function () {
  395. _this.assignMasterScroller(scroller);
  396. };
  397. 'wheel mousewheel DomMouseScroll MozMousePixelScroll'.split(' ').forEach(function (evName) {
  398. enhancedScroll.el.addEventListener(evName, onScroll);
  399. });
  400. enhancedScroll
  401. .on('scrollStart', function () {
  402. if (!_this.masterScroller) {
  403. _this.assignMasterScroller(scroller);
  404. }
  405. })
  406. .on('scroll', function () {
  407. if (scroller === _this.masterScroller) {
  408. for (var _i = 0, _a = _this.scrollers; _i < _a.length; _i++) {
  409. var otherScroller = _a[_i];
  410. if (otherScroller !== scroller) {
  411. switch (_this.axis) {
  412. case 'horizontal':
  413. otherScroller.enhancedScroll.el.scrollLeft = enhancedScroll.el.scrollLeft;
  414. break;
  415. case 'vertical':
  416. otherScroller.enhancedScroll.setScrollTop(enhancedScroll.getScrollTop());
  417. break;
  418. }
  419. }
  420. }
  421. }
  422. })
  423. .on('scrollEnd', function () {
  424. if (scroller === _this.masterScroller) {
  425. _this.unassignMasterScroller();
  426. }
  427. });
  428. };
  429. ScrollJoiner.prototype.assignMasterScroller = function (scroller) {
  430. this.unassignMasterScroller();
  431. this.masterScroller = scroller;
  432. for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
  433. var otherScroller = _a[_i];
  434. if (otherScroller !== scroller) {
  435. otherScroller.enhancedScroll.disableTouchScroll();
  436. }
  437. }
  438. };
  439. ScrollJoiner.prototype.unassignMasterScroller = function () {
  440. if (this.masterScroller) {
  441. for (var _i = 0, _a = this.scrollers; _i < _a.length; _i++) {
  442. var otherScroller = _a[_i];
  443. otherScroller.enhancedScroll.enableTouchScroll();
  444. }
  445. this.masterScroller = null;
  446. }
  447. };
  448. ScrollJoiner.prototype.update = function () {
  449. var allWidths = this.scrollers.map(function (scroller) { return scroller.getScrollbarWidths(); });
  450. var maxLeft = 0;
  451. var maxRight = 0;
  452. var maxTop = 0;
  453. var maxBottom = 0;
  454. var widths;
  455. var i;
  456. for (var _i = 0, allWidths_1 = allWidths; _i < allWidths_1.length; _i++) {
  457. widths = allWidths_1[_i];
  458. maxLeft = Math.max(maxLeft, widths.left);
  459. maxRight = Math.max(maxRight, widths.right);
  460. maxTop = Math.max(maxTop, widths.top);
  461. maxBottom = Math.max(maxBottom, widths.bottom);
  462. }
  463. for (i = 0; i < this.scrollers.length; i++) {
  464. var scroller = this.scrollers[i];
  465. widths = allWidths[i];
  466. scroller.enhancedScroll.canvas.setGutters(this.axis === 'horizontal' ?
  467. {
  468. left: maxLeft - widths.left,
  469. right: maxRight - widths.right
  470. } :
  471. {
  472. top: maxTop - widths.top,
  473. bottom: maxBottom - widths.bottom
  474. });
  475. }
  476. };
  477. return ScrollJoiner;
  478. }());
  479. var HeaderBodyLayout = /** @class */ (function () {
  480. /*
  481. verticalScroll = 'auto' | 'clipped-scroll'
  482. */
  483. function HeaderBodyLayout(headerContainerEl, bodyContainerEl, verticalScroll) {
  484. this.headerScroller = new ClippedScroller('clipped-scroll', 'hidden', headerContainerEl);
  485. this.bodyScroller = new ClippedScroller('auto', verticalScroll, bodyContainerEl);
  486. this.scrollJoiner = new ScrollJoiner('horizontal', [
  487. this.headerScroller,
  488. this.bodyScroller
  489. ]);
  490. }
  491. HeaderBodyLayout.prototype.destroy = function () {
  492. this.headerScroller.destroy();
  493. this.bodyScroller.destroy();
  494. };
  495. HeaderBodyLayout.prototype.setHeight = function (totalHeight, isAuto) {
  496. var bodyHeight;
  497. if (isAuto) {
  498. bodyHeight = 'auto';
  499. }
  500. else {
  501. bodyHeight = totalHeight - this.queryHeadHeight();
  502. }
  503. this.bodyScroller.setHeight(bodyHeight);
  504. this.headerScroller.updateSize(); // adjusts gutters and classNames
  505. this.bodyScroller.updateSize(); // adjusts gutters and classNames
  506. this.scrollJoiner.update();
  507. };
  508. HeaderBodyLayout.prototype.queryHeadHeight = function () {
  509. return this.headerScroller.enhancedScroll.canvas.contentEl.getBoundingClientRect().height;
  510. };
  511. return HeaderBodyLayout;
  512. }());
  513. var TimelineHeader = /** @class */ (function (_super) {
  514. __extends(TimelineHeader, _super);
  515. function TimelineHeader(parentEl) {
  516. var _this = _super.call(this) || this;
  517. _this.parentEl = parentEl;
  518. return _this;
  519. }
  520. TimelineHeader.prototype.firstContext = function (context) {
  521. this.parentEl.appendChild(this.tableEl = createElement('table', {
  522. className: context.theme.getClass('tableGrid')
  523. }));
  524. };
  525. TimelineHeader.prototype.destroy = function () {
  526. removeElement(this.tableEl);
  527. _super.prototype.destroy.call(this);
  528. };
  529. TimelineHeader.prototype.render = function (props) {
  530. this.renderDates(props.tDateProfile);
  531. };
  532. TimelineHeader.prototype.renderDates = function (tDateProfile) {
  533. var _a = this.context, dateEnv = _a.dateEnv, theme = _a.theme;
  534. var cellRows = tDateProfile.cellRows;
  535. var lastRow = cellRows[cellRows.length - 1];
  536. var isChrono = asRoughMs(tDateProfile.labelInterval) > asRoughMs(tDateProfile.slotDuration);
  537. var oneDay = isSingleDay(tDateProfile.slotDuration);
  538. var html = '<colgroup>';
  539. // needs to be a col for each body slat. header cells will have colspans
  540. for (var i = tDateProfile.slotCnt - 1; i >= 0; i--) {
  541. html += '<col/>';
  542. }
  543. html += '</colgroup>';
  544. html += '<tbody>';
  545. for (var _i = 0, cellRows_1 = cellRows; _i < cellRows_1.length; _i++) {
  546. var rowCells = cellRows_1[_i];
  547. var isLast = rowCells === lastRow;
  548. html += '<tr' + (isChrono && isLast ? ' class="fc-chrono"' : '') + '>';
  549. for (var _b = 0, rowCells_1 = rowCells; _b < rowCells_1.length; _b++) {
  550. var cell = rowCells_1[_b];
  551. var headerCellClassNames = [theme.getClass('widgetHeader')];
  552. if (cell.isWeekStart) {
  553. headerCellClassNames.push('fc-em-cell');
  554. }
  555. if (oneDay) {
  556. headerCellClassNames = headerCellClassNames.concat(getDayClasses(cell.date, this.props.dateProfile, this.context, true) // adds "today" class and other day-based classes
  557. );
  558. }
  559. html +=
  560. '<th class="' + headerCellClassNames.join(' ') + '"' +
  561. ' data-date="' + dateEnv.formatIso(cell.date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }) + '"' +
  562. (cell.colspan > 1 ? ' colspan="' + cell.colspan + '"' : '') +
  563. '>' +
  564. '<div class="fc-cell-content">' +
  565. cell.spanHtml +
  566. '</div>' +
  567. '</th>';
  568. }
  569. html += '</tr>';
  570. }
  571. html += '</tbody>';
  572. this.tableEl.innerHTML = html; // TODO: does this work cross-browser?
  573. this.slatColEls = findElements(this.tableEl, 'col');
  574. this.innerEls = findElements(this.tableEl.querySelector('tr:last-child'), // compound selector won't work because of query-root problem
  575. 'th .fc-cell-text');
  576. findElements(this.tableEl.querySelectorAll('tr:not(:last-child)'), // compound selector won't work because of query-root problem
  577. 'th .fc-cell-text').forEach(function (innerEl) {
  578. innerEl.classList.add('fc-sticky');
  579. });
  580. };
  581. return TimelineHeader;
  582. }(Component));
  583. var TimelineSlats = /** @class */ (function (_super) {
  584. __extends(TimelineSlats, _super);
  585. function TimelineSlats(parentEl) {
  586. var _this = _super.call(this) || this;
  587. parentEl.appendChild(_this.el = createElement('div', { className: 'fc-slats' }));
  588. return _this;
  589. }
  590. TimelineSlats.prototype.destroy = function () {
  591. removeElement(this.el);
  592. _super.prototype.destroy.call(this);
  593. };
  594. TimelineSlats.prototype.render = function (props) {
  595. this.renderDates(props.tDateProfile);
  596. };
  597. TimelineSlats.prototype.renderDates = function (tDateProfile) {
  598. var _a = this.context, calendar = _a.calendar, view = _a.view, theme = _a.theme, dateEnv = _a.dateEnv;
  599. var slotDates = tDateProfile.slotDates, isWeekStarts = tDateProfile.isWeekStarts;
  600. var html = '<table class="' + theme.getClass('tableGrid') + '">' +
  601. '<colgroup>';
  602. for (var i = 0; i < slotDates.length; i++) {
  603. html += '<col/>';
  604. }
  605. html += '</colgroup>';
  606. html += '<tbody><tr>';
  607. for (var i = 0; i < slotDates.length; i++) {
  608. html += this.slatCellHtml(slotDates[i], isWeekStarts[i], tDateProfile);
  609. }
  610. html += '</tr></tbody></table>';
  611. this.el.innerHTML = html;
  612. this.slatColEls = findElements(this.el, 'col');
  613. this.slatEls = findElements(this.el, 'td');
  614. for (var i = 0; i < slotDates.length; i++) {
  615. calendar.publiclyTrigger('dayRender', [
  616. {
  617. date: dateEnv.toDate(slotDates[i]),
  618. el: this.slatEls[i],
  619. view: view
  620. }
  621. ]);
  622. }
  623. this.outerCoordCache = new PositionCache(this.el, this.slatEls, true, // isHorizontal
  624. false // isVertical
  625. );
  626. // for the inner divs within the slats
  627. // used for event rendering and scrollTime, to disregard slat border
  628. this.innerCoordCache = new PositionCache(this.el, findChildren(this.slatEls, 'div'), true, // isHorizontal
  629. false // isVertical
  630. );
  631. };
  632. TimelineSlats.prototype.slatCellHtml = function (date, isEm, tDateProfile) {
  633. var _a = this.context, theme = _a.theme, dateEnv = _a.dateEnv;
  634. var classes;
  635. if (tDateProfile.isTimeScale) {
  636. classes = [];
  637. classes.push(isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval)) ?
  638. 'fc-major' :
  639. 'fc-minor');
  640. }
  641. else {
  642. classes = getDayClasses(date, this.props.dateProfile, this.context);
  643. classes.push('fc-day');
  644. }
  645. classes.unshift(theme.getClass('widgetContent'));
  646. if (isEm) {
  647. classes.push('fc-em-cell');
  648. }
  649. return '<td class="' + classes.join(' ') + '"' +
  650. ' data-date="' + dateEnv.formatIso(date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }) + '"' +
  651. '><div></div></td>';
  652. };
  653. TimelineSlats.prototype.updateSize = function () {
  654. this.outerCoordCache.build();
  655. this.innerCoordCache.build();
  656. };
  657. TimelineSlats.prototype.positionToHit = function (leftPosition) {
  658. var outerCoordCache = this.outerCoordCache;
  659. var _a = this.context, dateEnv = _a.dateEnv, isRtl = _a.isRtl;
  660. var tDateProfile = this.props.tDateProfile;
  661. var slatIndex = outerCoordCache.leftToIndex(leftPosition);
  662. if (slatIndex != null) {
  663. // somewhat similar to what TimeGrid does. consolidate?
  664. var slatWidth = outerCoordCache.getWidth(slatIndex);
  665. var partial = isRtl ?
  666. (outerCoordCache.rights[slatIndex] - leftPosition) / slatWidth :
  667. (leftPosition - outerCoordCache.lefts[slatIndex]) / slatWidth;
  668. var localSnapIndex = Math.floor(partial * tDateProfile.snapsPerSlot);
  669. var start = dateEnv.add(tDateProfile.slotDates[slatIndex], multiplyDuration(tDateProfile.snapDuration, localSnapIndex));
  670. var end = dateEnv.add(start, tDateProfile.snapDuration);
  671. return {
  672. dateSpan: {
  673. range: { start: start, end: end },
  674. allDay: !this.props.tDateProfile.isTimeScale
  675. },
  676. dayEl: this.slatColEls[slatIndex],
  677. left: outerCoordCache.lefts[slatIndex],
  678. right: outerCoordCache.rights[slatIndex]
  679. };
  680. }
  681. return null;
  682. };
  683. return TimelineSlats;
  684. }(Component));
  685. var MIN_AUTO_LABELS = 18; // more than `12` months but less that `24` hours
  686. var MAX_AUTO_SLOTS_PER_LABEL = 6; // allows 6 10-min slots in an hour
  687. var MAX_AUTO_CELLS = 200; // allows 4-days to have a :30 slot duration
  688. config.MAX_TIMELINE_SLOTS = 1000;
  689. // potential nice values for slot-duration and interval-duration
  690. var STOCK_SUB_DURATIONS = [
  691. { years: 1 },
  692. { months: 1 },
  693. { days: 1 },
  694. { hours: 1 },
  695. { minutes: 30 },
  696. { minutes: 15 },
  697. { minutes: 10 },
  698. { minutes: 5 },
  699. { minutes: 1 },
  700. { seconds: 30 },
  701. { seconds: 15 },
  702. { seconds: 10 },
  703. { seconds: 5 },
  704. { seconds: 1 },
  705. { milliseconds: 500 },
  706. { milliseconds: 100 },
  707. { milliseconds: 10 },
  708. { milliseconds: 1 }
  709. ];
  710. function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileGenerator) {
  711. var tDateProfile = {
  712. labelInterval: queryDurationOption(allOptions, 'slotLabelInterval'),
  713. slotDuration: queryDurationOption(allOptions, 'slotDuration')
  714. };
  715. validateLabelAndSlot(tDateProfile, dateProfile, dateEnv); // validate after computed grid duration
  716. ensureLabelInterval(tDateProfile, dateProfile, dateEnv);
  717. ensureSlotDuration(tDateProfile, dateProfile, dateEnv);
  718. var input = allOptions.slotLabelFormat;
  719. var rawFormats = Array.isArray(input) ?
  720. input
  721. : (input != null) ?
  722. [input]
  723. :
  724. computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions);
  725. tDateProfile.headerFormats = rawFormats.map(function (rawFormat) {
  726. return createFormatter(rawFormat);
  727. });
  728. tDateProfile.isTimeScale = Boolean(tDateProfile.slotDuration.milliseconds);
  729. var largeUnit = null;
  730. if (!tDateProfile.isTimeScale) {
  731. var slotUnit = greatestDurationDenominator(tDateProfile.slotDuration).unit;
  732. if (/year|month|week/.test(slotUnit)) {
  733. largeUnit = slotUnit;
  734. }
  735. }
  736. tDateProfile.largeUnit = largeUnit;
  737. tDateProfile.emphasizeWeeks =
  738. isSingleDay(tDateProfile.slotDuration) &&
  739. currentRangeAs('weeks', dateProfile, dateEnv) >= 2 &&
  740. !allOptions.businessHours;
  741. /*
  742. console.log('label interval =', timelineView.labelInterval.humanize())
  743. console.log('slot duration =', timelineView.slotDuration.humanize())
  744. console.log('header formats =', timelineView.headerFormats)
  745. console.log('isTimeScale', timelineView.isTimeScale)
  746. console.log('largeUnit', timelineView.largeUnit)
  747. */
  748. var rawSnapDuration = allOptions.snapDuration;
  749. var snapDuration;
  750. var snapsPerSlot;
  751. if (rawSnapDuration) {
  752. snapDuration = createDuration(rawSnapDuration);
  753. snapsPerSlot = wholeDivideDurations(tDateProfile.slotDuration, snapDuration);
  754. // ^ TODO: warning if not whole?
  755. }
  756. if (snapsPerSlot == null) {
  757. snapDuration = tDateProfile.slotDuration;
  758. snapsPerSlot = 1;
  759. }
  760. tDateProfile.snapDuration = snapDuration;
  761. tDateProfile.snapsPerSlot = snapsPerSlot;
  762. // more...
  763. var timeWindowMs = asRoughMs(dateProfile.maxTime) - asRoughMs(dateProfile.minTime);
  764. // TODO: why not use normalizeRange!?
  765. var normalizedStart = normalizeDate(dateProfile.renderRange.start, tDateProfile, dateEnv);
  766. var normalizedEnd = normalizeDate(dateProfile.renderRange.end, tDateProfile, dateEnv);
  767. // apply minTime/maxTime
  768. // TODO: View should be responsible.
  769. if (tDateProfile.isTimeScale) {
  770. normalizedStart = dateEnv.add(normalizedStart, dateProfile.minTime);
  771. normalizedEnd = dateEnv.add(addDays(normalizedEnd, -1), dateProfile.maxTime);
  772. }
  773. tDateProfile.timeWindowMs = timeWindowMs;
  774. tDateProfile.normalizedRange = { start: normalizedStart, end: normalizedEnd };
  775. var slotDates = [];
  776. var date = normalizedStart;
  777. while (date < normalizedEnd) {
  778. if (isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator)) {
  779. slotDates.push(date);
  780. }
  781. date = dateEnv.add(date, tDateProfile.slotDuration);
  782. }
  783. tDateProfile.slotDates = slotDates;
  784. // more...
  785. var snapIndex = -1;
  786. var snapDiff = 0; // index of the diff :(
  787. var snapDiffToIndex = [];
  788. var snapIndexToDiff = [];
  789. date = normalizedStart;
  790. while (date < normalizedEnd) {
  791. if (isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator)) {
  792. snapIndex++;
  793. snapDiffToIndex.push(snapIndex);
  794. snapIndexToDiff.push(snapDiff);
  795. }
  796. else {
  797. snapDiffToIndex.push(snapIndex + 0.5);
  798. }
  799. date = dateEnv.add(date, tDateProfile.snapDuration);
  800. snapDiff++;
  801. }
  802. tDateProfile.snapDiffToIndex = snapDiffToIndex;
  803. tDateProfile.snapIndexToDiff = snapIndexToDiff;
  804. tDateProfile.snapCnt = snapIndex + 1; // is always one behind
  805. tDateProfile.slotCnt = tDateProfile.snapCnt / tDateProfile.snapsPerSlot;
  806. // more...
  807. tDateProfile.isWeekStarts = buildIsWeekStarts(tDateProfile, dateEnv);
  808. tDateProfile.cellRows = buildCellRows(tDateProfile, dateEnv, allOptions);
  809. return tDateProfile;
  810. }
  811. /*
  812. snaps to appropriate unit
  813. */
  814. function normalizeDate(date, tDateProfile, dateEnv) {
  815. var normalDate = date;
  816. if (!tDateProfile.isTimeScale) {
  817. normalDate = startOfDay(normalDate);
  818. if (tDateProfile.largeUnit) {
  819. normalDate = dateEnv.startOf(normalDate, tDateProfile.largeUnit);
  820. }
  821. }
  822. return normalDate;
  823. }
  824. /*
  825. snaps to appropriate unit
  826. */
  827. function normalizeRange(range, tDateProfile, dateEnv) {
  828. if (!tDateProfile.isTimeScale) {
  829. range = computeVisibleDayRange(range);
  830. if (tDateProfile.largeUnit) {
  831. var dayRange = range; // preserve original result
  832. range = {
  833. start: dateEnv.startOf(range.start, tDateProfile.largeUnit),
  834. end: dateEnv.startOf(range.end, tDateProfile.largeUnit)
  835. };
  836. // if date is partially through the interval, or is in the same interval as the start,
  837. // make the exclusive end be the *next* interval
  838. if (range.end.valueOf() !== dayRange.end.valueOf() || range.end <= range.start) {
  839. range = {
  840. start: range.start,
  841. end: dateEnv.add(range.end, tDateProfile.slotDuration)
  842. };
  843. }
  844. }
  845. }
  846. return range;
  847. }
  848. function isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator) {
  849. if (dateProfileGenerator.isHiddenDay(date)) {
  850. return false;
  851. }
  852. else if (tDateProfile.isTimeScale) {
  853. // determine if the time is within minTime/maxTime, which may have wacky values
  854. var day = startOfDay(date);
  855. var timeMs = date.valueOf() - day.valueOf();
  856. var ms = timeMs - asRoughMs(dateProfile.minTime); // milliseconds since minTime
  857. ms = ((ms % 86400000) + 86400000) % 86400000; // make negative values wrap to 24hr clock
  858. return ms < tDateProfile.timeWindowMs; // before the maxTime?
  859. }
  860. else {
  861. return true;
  862. }
  863. }
  864. function queryDurationOption(allOptions, name) {
  865. var input = allOptions[name];
  866. if (input != null) {
  867. return createDuration(input);
  868. }
  869. }
  870. function validateLabelAndSlot(tDateProfile, dateProfile, dateEnv) {
  871. var currentRange = dateProfile.currentRange;
  872. // make sure labelInterval doesn't exceed the max number of cells
  873. if (tDateProfile.labelInterval) {
  874. var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.labelInterval);
  875. if (labelCnt > config.MAX_TIMELINE_SLOTS) {
  876. console.warn('slotLabelInterval results in too many cells');
  877. tDateProfile.labelInterval = null;
  878. }
  879. }
  880. // make sure slotDuration doesn't exceed the maximum number of cells
  881. if (tDateProfile.slotDuration) {
  882. var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.slotDuration);
  883. if (slotCnt > config.MAX_TIMELINE_SLOTS) {
  884. console.warn('slotDuration results in too many cells');
  885. tDateProfile.slotDuration = null;
  886. }
  887. }
  888. // make sure labelInterval is a multiple of slotDuration
  889. if (tDateProfile.labelInterval && tDateProfile.slotDuration) {
  890. var slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
  891. if (slotsPerLabel === null || slotsPerLabel < 1) {
  892. console.warn('slotLabelInterval must be a multiple of slotDuration');
  893. tDateProfile.slotDuration = null;
  894. }
  895. }
  896. }
  897. function ensureLabelInterval(tDateProfile, dateProfile, dateEnv) {
  898. var currentRange = dateProfile.currentRange;
  899. var labelInterval = tDateProfile.labelInterval;
  900. if (!labelInterval) {
  901. // compute based off the slot duration
  902. // find the largest label interval with an acceptable slots-per-label
  903. var input = void 0;
  904. if (tDateProfile.slotDuration) {
  905. for (var _i = 0, STOCK_SUB_DURATIONS_1 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_1.length; _i++) {
  906. input = STOCK_SUB_DURATIONS_1[_i];
  907. var tryLabelInterval = createDuration(input);
  908. var slotsPerLabel = wholeDivideDurations(tryLabelInterval, tDateProfile.slotDuration);
  909. if (slotsPerLabel !== null && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
  910. labelInterval = tryLabelInterval;
  911. break;
  912. }
  913. }
  914. // use the slot duration as a last resort
  915. if (!labelInterval) {
  916. labelInterval = tDateProfile.slotDuration;
  917. }
  918. // compute based off the view's duration
  919. // find the largest label interval that yields the minimum number of labels
  920. }
  921. else {
  922. for (var _a = 0, STOCK_SUB_DURATIONS_2 = STOCK_SUB_DURATIONS; _a < STOCK_SUB_DURATIONS_2.length; _a++) {
  923. input = STOCK_SUB_DURATIONS_2[_a];
  924. labelInterval = createDuration(input);
  925. var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, labelInterval);
  926. if (labelCnt >= MIN_AUTO_LABELS) {
  927. break;
  928. }
  929. }
  930. }
  931. tDateProfile.labelInterval = labelInterval;
  932. }
  933. return labelInterval;
  934. }
  935. function ensureSlotDuration(tDateProfile, dateProfile, dateEnv) {
  936. var currentRange = dateProfile.currentRange;
  937. var slotDuration = tDateProfile.slotDuration;
  938. if (!slotDuration) {
  939. var labelInterval = ensureLabelInterval(tDateProfile, dateProfile, dateEnv); // will compute if necessary
  940. // compute based off the label interval
  941. // find the largest slot duration that is different from labelInterval, but still acceptable
  942. for (var _i = 0, STOCK_SUB_DURATIONS_3 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_3.length; _i++) {
  943. var input = STOCK_SUB_DURATIONS_3[_i];
  944. var trySlotDuration = createDuration(input);
  945. var slotsPerLabel = wholeDivideDurations(labelInterval, trySlotDuration);
  946. if (slotsPerLabel !== null && slotsPerLabel > 1 && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
  947. slotDuration = trySlotDuration;
  948. break;
  949. }
  950. }
  951. // only allow the value if it won't exceed the view's # of slots limit
  952. if (slotDuration) {
  953. var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, slotDuration);
  954. if (slotCnt > MAX_AUTO_CELLS) {
  955. slotDuration = null;
  956. }
  957. }
  958. // use the label interval as a last resort
  959. if (!slotDuration) {
  960. slotDuration = labelInterval;
  961. }
  962. tDateProfile.slotDuration = slotDuration;
  963. }
  964. return slotDuration;
  965. }
  966. function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions) {
  967. var format1;
  968. var format2;
  969. var labelInterval = tDateProfile.labelInterval;
  970. var unit = greatestDurationDenominator(labelInterval).unit;
  971. var weekNumbersVisible = allOptions.weekNumbers;
  972. var format0 = (format1 = (format2 = null));
  973. // NOTE: weekNumber computation function wont work
  974. if ((unit === 'week') && !weekNumbersVisible) {
  975. unit = 'day';
  976. }
  977. switch (unit) {
  978. case 'year':
  979. format0 = { year: 'numeric' }; // '2015'
  980. break;
  981. case 'month':
  982. if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
  983. format0 = { year: 'numeric' }; // '2015'
  984. }
  985. format1 = { month: 'short' }; // 'Jan'
  986. break;
  987. case 'week':
  988. if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
  989. format0 = { year: 'numeric' }; // '2015'
  990. }
  991. format1 = { week: 'narrow' }; // 'Wk4'
  992. break;
  993. case 'day':
  994. if (currentRangeAs('years', dateProfile, dateEnv) > 1) {
  995. format0 = { year: 'numeric', month: 'long' }; // 'January 2014'
  996. }
  997. else if (currentRangeAs('months', dateProfile, dateEnv) > 1) {
  998. format0 = { month: 'long' }; // 'January'
  999. }
  1000. if (weekNumbersVisible) {
  1001. format1 = { week: 'short' }; // 'Wk 4'
  1002. }
  1003. format2 = { weekday: 'narrow', day: 'numeric' }; // 'Su 9'
  1004. break;
  1005. case 'hour':
  1006. if (weekNumbersVisible) {
  1007. format0 = { week: 'short' }; // 'Wk 4'
  1008. }
  1009. if (currentRangeAs('days', dateProfile, dateEnv) > 1) {
  1010. format1 = { weekday: 'short', day: 'numeric', month: 'numeric', omitCommas: true }; // Sat 4/7
  1011. }
  1012. format2 = {
  1013. hour: 'numeric',
  1014. minute: '2-digit',
  1015. omitZeroMinute: true,
  1016. meridiem: 'short'
  1017. };
  1018. break;
  1019. case 'minute':
  1020. // sufficiently large number of different minute cells?
  1021. if ((asRoughMinutes(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
  1022. format0 = {
  1023. hour: 'numeric',
  1024. meridiem: 'short'
  1025. };
  1026. format1 = function (params) {
  1027. return ':' + padStart(params.date.minute, 2); // ':30'
  1028. };
  1029. }
  1030. else {
  1031. format0 = {
  1032. hour: 'numeric',
  1033. minute: 'numeric',
  1034. meridiem: 'short'
  1035. };
  1036. }
  1037. break;
  1038. case 'second':
  1039. // sufficiently large number of different second cells?
  1040. if ((asRoughSeconds(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
  1041. format0 = { hour: 'numeric', minute: '2-digit', meridiem: 'lowercase' }; // '8:30 PM'
  1042. format1 = function (params) {
  1043. return ':' + padStart(params.date.second, 2); // ':30'
  1044. };
  1045. }
  1046. else {
  1047. format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM'
  1048. }
  1049. break;
  1050. case 'millisecond':
  1051. format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM'
  1052. format1 = function (params) {
  1053. return '.' + padStart(params.millisecond, 3);
  1054. };
  1055. break;
  1056. }
  1057. return [].concat(format0 || [], format1 || [], format2 || []);
  1058. }
  1059. // Compute the number of the give units in the "current" range.
  1060. // Won't go more precise than days.
  1061. // Will return `0` if there's not a clean whole interval.
  1062. function currentRangeAs(unit, dateProfile, dateEnv) {
  1063. var range = dateProfile.currentRange;
  1064. var res = null;
  1065. if (unit === 'years') {
  1066. res = dateEnv.diffWholeYears(range.start, range.end);
  1067. }
  1068. else if (unit === 'months') {
  1069. res = dateEnv.diffWholeMonths(range.start, range.end);
  1070. }
  1071. else if (unit === 'weeks') {
  1072. res = dateEnv.diffWholeMonths(range.start, range.end);
  1073. }
  1074. else if (unit === 'days') {
  1075. res = diffWholeDays(range.start, range.end);
  1076. }
  1077. return res || 0;
  1078. }
  1079. function buildIsWeekStarts(tDateProfile, dateEnv) {
  1080. var slotDates = tDateProfile.slotDates, emphasizeWeeks = tDateProfile.emphasizeWeeks;
  1081. var prevWeekNumber = null;
  1082. var isWeekStarts = [];
  1083. for (var _i = 0, slotDates_1 = slotDates; _i < slotDates_1.length; _i++) {
  1084. var slotDate = slotDates_1[_i];
  1085. var weekNumber = dateEnv.computeWeekNumber(slotDate);
  1086. var isWeekStart = emphasizeWeeks && (prevWeekNumber !== null) && (prevWeekNumber !== weekNumber);
  1087. prevWeekNumber = weekNumber;
  1088. isWeekStarts.push(isWeekStart);
  1089. }
  1090. return isWeekStarts;
  1091. }
  1092. function buildCellRows(tDateProfile, dateEnv, allOptions) {
  1093. var slotDates = tDateProfile.slotDates;
  1094. var formats = tDateProfile.headerFormats;
  1095. var cellRows = formats.map(function (format) { return []; }); // indexed by row,col
  1096. // specifically for navclicks
  1097. var rowUnits = formats.map(function (format) {
  1098. return format.getLargestUnit ? format.getLargestUnit() : null;
  1099. });
  1100. // builds cellRows and slotCells
  1101. for (var i = 0; i < slotDates.length; i++) {
  1102. var date = slotDates[i];
  1103. var isWeekStart = tDateProfile.isWeekStarts[i];
  1104. for (var row = 0; row < formats.length; row++) {
  1105. var format = formats[row];
  1106. var rowCells = cellRows[row];
  1107. var leadingCell = rowCells[rowCells.length - 1];
  1108. var isSuperRow = (formats.length > 1) && (row < (formats.length - 1)); // more than one row and not the last
  1109. var newCell = null;
  1110. if (isSuperRow) {
  1111. var text = dateEnv.format(date, format);
  1112. if (!leadingCell || (leadingCell.text !== text)) {
  1113. newCell = buildCellObject(date, text, rowUnits[row], allOptions, dateEnv);
  1114. }
  1115. else {
  1116. leadingCell.colspan += 1;
  1117. }
  1118. }
  1119. else {
  1120. if (!leadingCell ||
  1121. isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval))) {
  1122. var text = dateEnv.format(date, format);
  1123. newCell = buildCellObject(date, text, rowUnits[row], allOptions, dateEnv);
  1124. }
  1125. else {
  1126. leadingCell.colspan += 1;
  1127. }
  1128. }
  1129. if (newCell) {
  1130. newCell.weekStart = isWeekStart;
  1131. rowCells.push(newCell);
  1132. }
  1133. }
  1134. }
  1135. return cellRows;
  1136. }
  1137. function buildCellObject(date, text, rowUnit, allOptions, dateEnv) {
  1138. var spanHtml = buildGotoAnchorHtml(allOptions, dateEnv, {
  1139. date: date,
  1140. type: rowUnit,
  1141. forceOff: !rowUnit
  1142. }, {
  1143. 'class': 'fc-cell-text'
  1144. }, htmlEscape(text));
  1145. return { text: text, spanHtml: spanHtml, date: date, colspan: 1, isWeekStart: false };
  1146. }
  1147. var TimelineNowIndicator = /** @class */ (function () {
  1148. function TimelineNowIndicator(headParent, bodyParent) {
  1149. this.headParent = headParent;
  1150. this.bodyParent = bodyParent;
  1151. }
  1152. TimelineNowIndicator.prototype.render = function (coord, isRtl) {
  1153. var styleProps = isRtl ? { right: -coord } : { left: coord };
  1154. this.headParent.appendChild(this.arrowEl = createElement('div', {
  1155. className: 'fc-now-indicator fc-now-indicator-arrow',
  1156. style: styleProps
  1157. }));
  1158. this.bodyParent.appendChild(this.lineEl = createElement('div', {
  1159. className: 'fc-now-indicator fc-now-indicator-line',
  1160. style: styleProps
  1161. }));
  1162. };
  1163. TimelineNowIndicator.prototype.unrender = function () {
  1164. if (this.arrowEl) {
  1165. removeElement(this.arrowEl);
  1166. }
  1167. if (this.lineEl) {
  1168. removeElement(this.lineEl);
  1169. }
  1170. };
  1171. return TimelineNowIndicator;
  1172. }());
  1173. var STICKY_PROP_VAL = computeStickyPropVal(); // if null, means not supported at all
  1174. var IS_MS_EDGE = /Edge/.test(navigator.userAgent);
  1175. var IS_SAFARI = STICKY_PROP_VAL === '-webkit-sticky'; // good b/c doesn't confuse chrome
  1176. var STICKY_CLASSNAME = 'fc-sticky';
  1177. /*
  1178. useful beyond the native position:sticky for these reasons:
  1179. - support in IE11
  1180. - nice centering support
  1181. */
  1182. var StickyScroller = /** @class */ (function () {
  1183. function StickyScroller(scroller, isRtl, isVertical) {
  1184. var _this = this;
  1185. this.usingRelative = null;
  1186. /*
  1187. known bug: called twice on init. problem when mixing with ScrollJoiner
  1188. */
  1189. this.updateSize = function () {
  1190. var els = Array.prototype.slice.call(_this.scroller.canvas.el.querySelectorAll('.' + STICKY_CLASSNAME));
  1191. var elGeoms = _this.queryElGeoms(els);
  1192. var viewportWidth = _this.scroller.el.clientWidth;
  1193. if (_this.usingRelative) {
  1194. var elDestinations = _this.computeElDestinations(elGeoms, viewportWidth); // read before prepPositioning
  1195. assignRelativePositions(els, elGeoms, elDestinations);
  1196. }
  1197. else {
  1198. assignStickyPositions(els, elGeoms, viewportWidth);
  1199. }
  1200. };
  1201. this.scroller = scroller;
  1202. this.usingRelative =
  1203. !STICKY_PROP_VAL || // IE11
  1204. (IS_MS_EDGE && isRtl) || // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/18883305/
  1205. ((IS_MS_EDGE || IS_SAFARI) && isVertical); // because doesn't work with rowspan in tables, our only vertial use
  1206. if (this.usingRelative) {
  1207. scroller.on('scrollEnd', this.updateSize);
  1208. }
  1209. }
  1210. StickyScroller.prototype.destroy = function () {
  1211. this.scroller.off('scrollEnd', this.updateSize);
  1212. };
  1213. StickyScroller.prototype.queryElGeoms = function (els) {
  1214. var canvasOrigin = this.scroller.canvas.el.getBoundingClientRect();
  1215. var elGeoms = [];
  1216. for (var _i = 0, els_1 = els; _i < els_1.length; _i++) {
  1217. var el = els_1[_i];
  1218. var parentBound = translateRect(el.parentNode.getBoundingClientRect(), -canvasOrigin.left, -canvasOrigin.top);
  1219. var elRect = el.getBoundingClientRect();
  1220. var computedStyles = window.getComputedStyle(el);
  1221. var computedTextAlign = window.getComputedStyle(el.parentNode).textAlign; // ask the parent
  1222. var intendedTextAlign = computedTextAlign;
  1223. var naturalBound = null;
  1224. if (computedStyles.position !== 'sticky') {
  1225. naturalBound = translateRect(elRect, -canvasOrigin.left - (parseFloat(computedStyles.left) || 0), // could be 'auto'
  1226. -canvasOrigin.top - (parseFloat(computedStyles.top) || 0));
  1227. }
  1228. if (el.hasAttribute('data-sticky-center')) {
  1229. intendedTextAlign = 'center';
  1230. }
  1231. elGeoms.push({
  1232. parentBound: parentBound,
  1233. naturalBound: naturalBound,
  1234. elWidth: elRect.width,
  1235. elHeight: elRect.height,
  1236. computedTextAlign: computedTextAlign,
  1237. intendedTextAlign: intendedTextAlign
  1238. });
  1239. }
  1240. return elGeoms;
  1241. };
  1242. StickyScroller.prototype.computeElDestinations = function (elGeoms, viewportWidth) {
  1243. var viewportLeft = this.scroller.getScrollFromLeft();
  1244. var viewportTop = this.scroller.getScrollTop();
  1245. var viewportRight = viewportLeft + viewportWidth;
  1246. return elGeoms.map(function (elGeom) {
  1247. var elWidth = elGeom.elWidth, elHeight = elGeom.elHeight, parentBound = elGeom.parentBound, naturalBound = elGeom.naturalBound;
  1248. var destLeft; // relative to canvas topleft
  1249. var destTop; // "
  1250. switch (elGeom.intendedTextAlign) {
  1251. case 'left':
  1252. destLeft = viewportLeft;
  1253. break;
  1254. case 'right':
  1255. destLeft = viewportRight - elWidth;
  1256. break;
  1257. case 'center':
  1258. destLeft = (viewportLeft + viewportRight) / 2 - elWidth / 2;
  1259. break;
  1260. }
  1261. destLeft = Math.min(destLeft, parentBound.right - elWidth);
  1262. destLeft = Math.max(destLeft, parentBound.left);
  1263. destTop = viewportTop;
  1264. destTop = Math.min(destTop, parentBound.bottom - elHeight);
  1265. destTop = Math.max(destTop, naturalBound.top); // better to use natural top for upper bound
  1266. return { left: destLeft, top: destTop };
  1267. });
  1268. };
  1269. return StickyScroller;
  1270. }());
  1271. function assignRelativePositions(els, elGeoms, elDestinations) {
  1272. els.forEach(function (el, i) {
  1273. var naturalBound = elGeoms[i].naturalBound;
  1274. applyStyle(el, {
  1275. position: 'relative',
  1276. left: elDestinations[i].left - naturalBound.left,
  1277. top: elDestinations[i].top - naturalBound.top
  1278. });
  1279. });
  1280. }
  1281. function assignStickyPositions(els, elGeoms, viewportWidth) {
  1282. els.forEach(function (el, i) {
  1283. var stickyLeft = 0;
  1284. if (elGeoms[i].intendedTextAlign === 'center') {
  1285. stickyLeft = (viewportWidth - elGeoms[i].elWidth) / 2;
  1286. // needs to be forced to left?
  1287. if (elGeoms[i].computedTextAlign === 'center') {
  1288. el.setAttribute('data-sticky-center', '') // remember for next queryElGeoms
  1289. ;
  1290. el.parentNode.style.textAlign = 'left';
  1291. }
  1292. }
  1293. applyStyle(el, {
  1294. position: STICKY_PROP_VAL,
  1295. left: stickyLeft,
  1296. right: 0,
  1297. top: 0
  1298. });
  1299. });
  1300. }
  1301. function computeStickyPropVal() {
  1302. var el = htmlToElement('<div style="position:-webkit-sticky;position:sticky"></div>');
  1303. var val = el.style.position;
  1304. if (val.indexOf('sticky') !== -1) {
  1305. return val;
  1306. }
  1307. else {
  1308. return null;
  1309. }
  1310. }
  1311. var TimeAxis = /** @class */ (function (_super) {
  1312. __extends(TimeAxis, _super);
  1313. function TimeAxis(headerContainerEl, bodyContainerEl) {
  1314. var _this = _super.call(this) || this;
  1315. _this.renderSkeleton = memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton);
  1316. _this.layout = new HeaderBodyLayout(headerContainerEl, bodyContainerEl, 'auto');
  1317. return _this;
  1318. }
  1319. TimeAxis.prototype.render = function (props, context) {
  1320. var tDateProfile = this.tDateProfile =
  1321. buildTimelineDateProfile(props.dateProfile, context.dateEnv, context.options, props.dateProfileGenerator); // TODO: cache
  1322. this.renderSkeleton(context);
  1323. this.header.receiveProps({
  1324. dateProfile: props.dateProfile,
  1325. tDateProfile: tDateProfile
  1326. }, context);
  1327. this.slats.receiveProps({
  1328. dateProfile: props.dateProfile,
  1329. tDateProfile: tDateProfile
  1330. }, context);
  1331. };
  1332. TimeAxis.prototype.destroy = function () {
  1333. this.renderSkeleton.unrender();
  1334. this.layout.destroy();
  1335. _super.prototype.destroy.call(this);
  1336. };
  1337. TimeAxis.prototype._renderSkeleton = function (context) {
  1338. var layout = this.layout;
  1339. var headerEnhancedScroller = layout.headerScroller.enhancedScroll;
  1340. var bodyEnhancedScroller = layout.bodyScroller.enhancedScroll;
  1341. // needs to go after layout, which has ScrollJoiner
  1342. this.headStickyScroller = new StickyScroller(headerEnhancedScroller, context.isRtl, false); // isVertical=false
  1343. this.bodyStickyScroller = new StickyScroller(bodyEnhancedScroller, context.isRtl, false); // isVertical=false
  1344. this.header = new TimelineHeader(headerEnhancedScroller.canvas.contentEl);
  1345. this.slats = new TimelineSlats(bodyEnhancedScroller.canvas.bgEl);
  1346. this.nowIndicator = new TimelineNowIndicator(headerEnhancedScroller.canvas.el, bodyEnhancedScroller.canvas.el);
  1347. };
  1348. TimeAxis.prototype._unrenderSkeleton = function () {
  1349. this.header.destroy();
  1350. this.slats.destroy();
  1351. this.nowIndicator.unrender();
  1352. this.headStickyScroller.destroy();
  1353. this.bodyStickyScroller.destroy();
  1354. };
  1355. // Now Indicator
  1356. // ------------------------------------------------------------------------------------------
  1357. TimeAxis.prototype.getNowIndicatorUnit = function (dateProfile, dateProfileGenerator) {
  1358. var context = this.context;
  1359. // yuck
  1360. var tDateProfile = this.tDateProfile =
  1361. buildTimelineDateProfile(dateProfile, context.dateEnv, context.options, dateProfileGenerator); // TODO: cache
  1362. if (tDateProfile.isTimeScale) {
  1363. return greatestDurationDenominator(tDateProfile.slotDuration).unit;
  1364. }
  1365. };
  1366. // will only execute if isTimeScale
  1367. TimeAxis.prototype.renderNowIndicator = function (date) {
  1368. if (rangeContainsMarker(this.tDateProfile.normalizedRange, date)) {
  1369. this.nowIndicator.render(this.dateToCoord(date), this.context.isRtl);
  1370. }
  1371. };
  1372. // will only execute if isTimeScale
  1373. TimeAxis.prototype.unrenderNowIndicator = function () {
  1374. this.nowIndicator.unrender();
  1375. };
  1376. // Sizing
  1377. // ------------------------------------------------------------------------------------------
  1378. TimeAxis.prototype.updateSize = function (isResize, totalHeight, isAuto) {
  1379. this.applySlotWidth(this.computeSlotWidth());
  1380. // adjusts gutters. do after slot widths set
  1381. this.layout.setHeight(totalHeight, isAuto);
  1382. // pretty much just queries coords. do last
  1383. this.slats.updateSize();
  1384. };
  1385. TimeAxis.prototype.updateStickyScrollers = function () {
  1386. this.headStickyScroller.updateSize();
  1387. this.bodyStickyScroller.updateSize();
  1388. };
  1389. TimeAxis.prototype.computeSlotWidth = function () {
  1390. var slotWidth = this.context.options.slotWidth || '';
  1391. if (slotWidth === '') {
  1392. slotWidth = this.computeDefaultSlotWidth(this.tDateProfile);
  1393. }
  1394. return slotWidth;
  1395. };
  1396. TimeAxis.prototype.computeDefaultSlotWidth = function (tDateProfile) {
  1397. var maxInnerWidth = 0; // TODO: harness core's `matchCellWidths` for this
  1398. this.header.innerEls.forEach(function (innerEl, i) {
  1399. maxInnerWidth = Math.max(maxInnerWidth, innerEl.getBoundingClientRect().width);
  1400. });
  1401. var headingCellWidth = Math.ceil(maxInnerWidth) + 1; // assume no padding, and one pixel border
  1402. // in TimelineView.defaults we ensured that labelInterval is an interval of slotDuration
  1403. // TODO: rename labelDuration?
  1404. var slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
  1405. var slotWidth = Math.ceil(headingCellWidth / slotsPerLabel);
  1406. var minWidth = window.getComputedStyle(this.header.slatColEls[0]).minWidth;
  1407. if (minWidth) {
  1408. minWidth = parseInt(minWidth, 10);
  1409. if (minWidth) {
  1410. slotWidth = Math.max(slotWidth, minWidth);
  1411. }
  1412. }
  1413. return slotWidth;
  1414. };
  1415. TimeAxis.prototype.applySlotWidth = function (slotWidth) {
  1416. var _a = this, layout = _a.layout, tDateProfile = _a.tDateProfile;
  1417. var containerWidth = '';
  1418. var containerMinWidth = '';
  1419. var nonLastSlotWidth = '';
  1420. if (slotWidth !== '') {
  1421. slotWidth = Math.round(slotWidth);
  1422. containerWidth = slotWidth * tDateProfile.slotDates.length;
  1423. containerMinWidth = '';
  1424. nonLastSlotWidth = slotWidth;
  1425. var availableWidth = layout.bodyScroller.enhancedScroll.getClientWidth();
  1426. if (availableWidth > containerWidth) {
  1427. containerMinWidth = availableWidth;
  1428. containerWidth = '';
  1429. nonLastSlotWidth = Math.floor(availableWidth / tDateProfile.slotDates.length);
  1430. }
  1431. }
  1432. layout.headerScroller.enhancedScroll.canvas.setWidth(containerWidth);
  1433. layout.headerScroller.enhancedScroll.canvas.setMinWidth(containerMinWidth);
  1434. layout.bodyScroller.enhancedScroll.canvas.setWidth(containerWidth);
  1435. layout.bodyScroller.enhancedScroll.canvas.setMinWidth(containerMinWidth);
  1436. if (nonLastSlotWidth !== '') {
  1437. this.header.slatColEls.slice(0, -1).concat(this.slats.slatColEls.slice(0, -1)).forEach(function (el) {
  1438. el.style.width = nonLastSlotWidth + 'px';
  1439. el.style.minWidth = '0'; // prevent the browser from using the actual min-width (issue #6338)
  1440. });
  1441. }
  1442. };
  1443. // returned value is between 0 and the number of snaps
  1444. TimeAxis.prototype.computeDateSnapCoverage = function (date) {
  1445. var tDateProfile = this.tDateProfile;
  1446. var dateEnv = this.context.dateEnv;
  1447. var snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
  1448. if (snapDiff < 0) {
  1449. return 0;
  1450. }
  1451. else if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
  1452. return tDateProfile.snapCnt;
  1453. }
  1454. else {
  1455. var snapDiffInt = Math.floor(snapDiff);
  1456. var snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
  1457. if (isInt(snapCoverage)) { // not an in-between value
  1458. snapCoverage += snapDiff - snapDiffInt; // add the remainder
  1459. }
  1460. else {
  1461. // a fractional value, meaning the date is not visible
  1462. // always round up in this case. works for start AND end dates in a range.
  1463. snapCoverage = Math.ceil(snapCoverage);
  1464. }
  1465. return snapCoverage;
  1466. }
  1467. };
  1468. // for LTR, results range from 0 to width of area
  1469. // for RTL, results range from negative width of area to 0
  1470. TimeAxis.prototype.dateToCoord = function (date) {
  1471. var tDateProfile = this.tDateProfile;
  1472. var snapCoverage = this.computeDateSnapCoverage(date);
  1473. var slotCoverage = snapCoverage / tDateProfile.snapsPerSlot;
  1474. var slotIndex = Math.floor(slotCoverage);
  1475. slotIndex = Math.min(slotIndex, tDateProfile.slotCnt - 1);
  1476. var partial = slotCoverage - slotIndex;
  1477. var _a = this.slats, innerCoordCache = _a.innerCoordCache, outerCoordCache = _a.outerCoordCache;
  1478. if (this.context.isRtl) {
  1479. return (outerCoordCache.rights[slotIndex] -
  1480. (innerCoordCache.getWidth(slotIndex) * partial)) - outerCoordCache.originClientRect.width;
  1481. }
  1482. else {
  1483. return (outerCoordCache.lefts[slotIndex] +
  1484. (innerCoordCache.getWidth(slotIndex) * partial));
  1485. }
  1486. };
  1487. TimeAxis.prototype.rangeToCoords = function (range) {
  1488. if (this.context.isRtl) {
  1489. return { right: this.dateToCoord(range.start), left: this.dateToCoord(range.end) };
  1490. }
  1491. else {
  1492. return { left: this.dateToCoord(range.start), right: this.dateToCoord(range.end) };
  1493. }
  1494. };
  1495. // Scrolling
  1496. // ------------------------------------------------------------------------------------------
  1497. TimeAxis.prototype.computeDateScroll = function (duration) {
  1498. var _a = this.context, dateEnv = _a.dateEnv, isRtl = _a.isRtl;
  1499. var dateProfile = this.props.dateProfile;
  1500. var left = 0;
  1501. if (dateProfile) {
  1502. left = this.dateToCoord(dateEnv.add(startOfDay(dateProfile.activeRange.start), // startOfDay needed?
  1503. duration));
  1504. // hack to overcome the left borders of non-first slat
  1505. if (!isRtl && left) {
  1506. left += 1;
  1507. }
  1508. }
  1509. return { left: left };
  1510. };
  1511. TimeAxis.prototype.queryDateScroll = function () {
  1512. var enhancedScroll = this.layout.bodyScroller.enhancedScroll;
  1513. return {
  1514. left: enhancedScroll.getScrollLeft()
  1515. };
  1516. };
  1517. TimeAxis.prototype.applyDateScroll = function (scroll) {
  1518. // TODO: lame we have to update both. use the scrolljoiner instead maybe
  1519. this.layout.bodyScroller.enhancedScroll.setScrollLeft(scroll.left || 0);
  1520. this.layout.headerScroller.enhancedScroll.setScrollLeft(scroll.left || 0);
  1521. };
  1522. return TimeAxis;
  1523. }(Component));
  1524. var TimelineLaneEventRenderer = /** @class */ (function (_super) {
  1525. __extends(TimelineLaneEventRenderer, _super);
  1526. function TimelineLaneEventRenderer(masterContainerEl, timeAxis) {
  1527. var _this = _super.call(this) || this;
  1528. _this.masterContainerEl = masterContainerEl;
  1529. _this.timeAxis = timeAxis;
  1530. return _this;
  1531. }
  1532. TimelineLaneEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) {
  1533. var context = this.context;
  1534. var eventRange = seg.eventRange;
  1535. var eventDef = eventRange.def;
  1536. var eventUi = eventRange.ui;
  1537. var isDraggable = computeEventDraggable(context, eventDef, eventUi);
  1538. var isResizableFromStart = seg.isStart && computeEventStartResizable(context, eventDef, eventUi);
  1539. var isResizableFromEnd = seg.isEnd && computeEventEndResizable(context, eventDef, eventUi);
  1540. var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo);
  1541. classes.unshift('fc-timeline-event', 'fc-h-event');
  1542. var timeText = this.getTimeText(eventRange);
  1543. return '<a class="' + classes.join(' ') + '" style="' + cssToStr(this.getSkinCss(eventUi)) + '"' +
  1544. (eventDef.url ?
  1545. ' href="' + htmlEscape(eventDef.url) + '"' :
  1546. '') +
  1547. '>' +
  1548. (timeText ?
  1549. '<span class="fc-time-wrap">' +
  1550. '<span class="fc-time">' +
  1551. htmlEscape(timeText) +
  1552. '</span>' +
  1553. '</span>'
  1554. :
  1555. '') +
  1556. '<span class="fc-title-wrap">' +
  1557. '<span class="fc-title fc-sticky">' +
  1558. (eventDef.title ? htmlEscape(eventDef.title) : '&nbsp;') +
  1559. '</span>' +
  1560. '</span>' +
  1561. (isResizableFromStart ?
  1562. '<div class="fc-resizer fc-start-resizer"></div>' :
  1563. '') +
  1564. (isResizableFromEnd ?
  1565. '<div class="fc-resizer fc-end-resizer"></div>' :
  1566. '') +
  1567. '</a>';
  1568. };
  1569. TimelineLaneEventRenderer.prototype.computeDisplayEventTime = function () {
  1570. return !this.timeAxis.tDateProfile.isTimeScale; // because times should be obvious via axis
  1571. };
  1572. TimelineLaneEventRenderer.prototype.computeDisplayEventEnd = function () {
  1573. return false;
  1574. };
  1575. // Computes a default event time formatting string if `timeFormat` is not explicitly defined
  1576. TimelineLaneEventRenderer.prototype.computeEventTimeFormat = function () {
  1577. return {
  1578. hour: 'numeric',
  1579. minute: '2-digit',
  1580. omitZeroMinute: true,
  1581. meridiem: 'narrow'
  1582. };
  1583. };
  1584. TimelineLaneEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) {
  1585. if (!this.el && this.masterContainerEl) {
  1586. this.el = createElement('div', { className: 'fc-event-container' });
  1587. if (mirrorInfo) {
  1588. this.el.classList.add('fc-mirror-container');
  1589. }
  1590. this.masterContainerEl.appendChild(this.el);
  1591. }
  1592. if (this.el) {
  1593. for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
  1594. var seg = segs_1[_i];
  1595. this.el.appendChild(seg.el);
  1596. }
  1597. }
  1598. };
  1599. TimelineLaneEventRenderer.prototype.detachSegs = function (segs) {
  1600. for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
  1601. var seg = segs_2[_i];
  1602. removeElement(seg.el);
  1603. }
  1604. };
  1605. // computes AND assigns (assigns the left/right at least). bad
  1606. TimelineLaneEventRenderer.prototype.computeSegSizes = function (segs) {
  1607. var timeAxis = this.timeAxis;
  1608. for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) {
  1609. var seg = segs_3[_i];
  1610. var coords = timeAxis.rangeToCoords(seg); // works because Seg has start/end
  1611. applyStyle(seg.el, {
  1612. left: (seg.left = coords.left),
  1613. right: -(seg.right = coords.right)
  1614. });
  1615. }
  1616. };
  1617. TimelineLaneEventRenderer.prototype.assignSegSizes = function (segs) {
  1618. if (!this.el) {
  1619. return;
  1620. }
  1621. // compute seg verticals
  1622. for (var _i = 0, segs_4 = segs; _i < segs_4.length; _i++) {
  1623. var seg = segs_4[_i];
  1624. seg.height = computeHeightAndMargins(seg.el);
  1625. }
  1626. this.buildSegLevels(segs); // populates above/below props for computeOffsetForSegs
  1627. var totalHeight = computeOffsetForSegs(segs); // also assigns seg.top
  1628. applyStyleProp(this.el, 'height', totalHeight);
  1629. // assign seg verticals
  1630. for (var _a = 0, segs_5 = segs; _a < segs_5.length; _a++) {
  1631. var seg = segs_5[_a];
  1632. applyStyleProp(seg.el, 'top', seg.top);
  1633. }
  1634. };
  1635. TimelineLaneEventRenderer.prototype.buildSegLevels = function (segs) {
  1636. var segLevels = [];
  1637. segs = this.sortEventSegs(segs);
  1638. for (var _i = 0, segs_6 = segs; _i < segs_6.length; _i++) {
  1639. var unplacedSeg = segs_6[_i];
  1640. unplacedSeg.above = [];
  1641. // determine the first level with no collisions
  1642. var level = 0; // level index
  1643. while (level < segLevels.length) {
  1644. var isLevelCollision = false;
  1645. // determine collisions
  1646. for (var _a = 0, _b = segLevels[level]; _a < _b.length; _a++) {
  1647. var placedSeg = _b[_a];
  1648. if (timeRowSegsCollide(unplacedSeg, placedSeg)) {
  1649. unplacedSeg.above.push(placedSeg);
  1650. isLevelCollision = true;
  1651. }
  1652. }
  1653. if (isLevelCollision) {
  1654. level += 1;
  1655. }
  1656. else {
  1657. break;
  1658. }
  1659. }
  1660. // insert into the first non-colliding level. create if necessary
  1661. (segLevels[level] || (segLevels[level] = []))
  1662. .push(unplacedSeg);
  1663. // record possible colliding segments below (TODO: automated test for this)
  1664. level += 1;
  1665. while (level < segLevels.length) {
  1666. for (var _c = 0, _d = segLevels[level]; _c < _d.length; _c++) {
  1667. var belowSeg = _d[_c];
  1668. if (timeRowSegsCollide(unplacedSeg, belowSeg)) {
  1669. belowSeg.above.push(unplacedSeg);
  1670. }
  1671. }
  1672. level += 1;
  1673. }
  1674. }
  1675. return segLevels;
  1676. };
  1677. return TimelineLaneEventRenderer;
  1678. }(FgEventRenderer));
  1679. function computeOffsetForSegs(segs) {
  1680. var max = 0;
  1681. for (var _i = 0, segs_7 = segs; _i < segs_7.length; _i++) {
  1682. var seg = segs_7[_i];
  1683. max = Math.max(max, computeOffsetForSeg(seg));
  1684. }
  1685. return max;
  1686. }
  1687. function computeOffsetForSeg(seg) {
  1688. if ((seg.top == null)) {
  1689. seg.top = computeOffsetForSegs(seg.above);
  1690. }
  1691. return seg.top + seg.height;
  1692. }
  1693. function timeRowSegsCollide(seg0, seg1) {
  1694. return (seg0.left < seg1.right) && (seg0.right > seg1.left);
  1695. }
  1696. var TimelineLaneFillRenderer = /** @class */ (function (_super) {
  1697. __extends(TimelineLaneFillRenderer, _super);
  1698. function TimelineLaneFillRenderer(masterContainerEl, timeAxis) {
  1699. var _this = _super.call(this) || this;
  1700. _this.masterContainerEl = masterContainerEl;
  1701. _this.timeAxis = timeAxis;
  1702. return _this;
  1703. }
  1704. TimelineLaneFillRenderer.prototype.attachSegs = function (type, segs) {
  1705. if (segs.length) {
  1706. var className = void 0;
  1707. if (type === 'businessHours') {
  1708. className = 'bgevent';
  1709. }
  1710. else {
  1711. className = type.toLowerCase();
  1712. }
  1713. // making a new container each time is OKAY
  1714. // all types of segs (background or business hours or whatever) are rendered in one pass
  1715. var containerEl = createElement('div', { className: 'fc-' + className + '-container' });
  1716. this.masterContainerEl.appendChild(containerEl);
  1717. for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
  1718. var seg = segs_1[_i];
  1719. containerEl.appendChild(seg.el);
  1720. }
  1721. return [containerEl]; // return value
  1722. }
  1723. };
  1724. TimelineLaneFillRenderer.prototype.computeSegSizes = function (segs) {
  1725. var timeAxis = this.timeAxis;
  1726. for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
  1727. var seg = segs_2[_i];
  1728. var coords = timeAxis.rangeToCoords(seg);
  1729. seg.left = coords.left;
  1730. seg.right = coords.right;
  1731. }
  1732. };
  1733. TimelineLaneFillRenderer.prototype.assignSegSizes = function (segs) {
  1734. for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) {
  1735. var seg = segs_3[_i];
  1736. applyStyle(seg.el, {
  1737. left: seg.left,
  1738. right: -seg.right
  1739. });
  1740. }
  1741. };
  1742. return TimelineLaneFillRenderer;
  1743. }(FillRenderer));
  1744. var TimelineLane = /** @class */ (function (_super) {
  1745. __extends(TimelineLane, _super);
  1746. function TimelineLane(fgContainerEl, bgContainerEl, timeAxis) {
  1747. var _this = _super.call(this, bgContainerEl) || this;
  1748. _this.slicer = new TimelineLaneSlicer();
  1749. _this.renderEventDrag = memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag);
  1750. _this.renderEventResize = memoizeRendering(_this._renderEventResize, _this._unrenderEventResize);
  1751. _this.fgContainerEl = fgContainerEl;
  1752. _this.timeAxis = timeAxis;
  1753. var fillRenderer = _this.fillRenderer = new TimelineLaneFillRenderer(bgContainerEl, timeAxis);
  1754. var eventRenderer = _this.eventRenderer = new TimelineLaneEventRenderer(fgContainerEl, timeAxis);
  1755. _this.mirrorRenderer = new TimelineLaneEventRenderer(fgContainerEl, timeAxis);
  1756. _this.renderBusinessHours = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'));
  1757. _this.renderDateSelection = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'highlight'), fillRenderer.unrender.bind(fillRenderer, 'highlight'));
  1758. _this.renderBgEvents = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'));
  1759. _this.renderFgEvents = memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer));
  1760. _this.renderEventSelection = memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]);
  1761. return _this;
  1762. }
  1763. TimelineLane.prototype.render = function (props, context) {
  1764. var timeAxis = this.timeAxis;
  1765. var slicedProps = this.slicer.sliceProps(props, props.dateProfile, timeAxis.tDateProfile.isTimeScale ? null : props.nextDayThreshold, context.calendar, this, timeAxis);
  1766. this.renderBusinessHours(context, slicedProps.businessHourSegs);
  1767. this.renderDateSelection(context, slicedProps.dateSelectionSegs);
  1768. this.renderBgEvents(context, slicedProps.bgEventSegs);
  1769. this.renderFgEvents(context, slicedProps.fgEventSegs);
  1770. this.renderEventSelection(slicedProps.eventSelection);
  1771. this.renderEventDrag(slicedProps.eventDrag);
  1772. this.renderEventResize(slicedProps.eventResize);
  1773. };
  1774. TimelineLane.prototype.destroy = function () {
  1775. _super.prototype.destroy.call(this);
  1776. this.renderBusinessHours.unrender();
  1777. this.renderDateSelection.unrender();
  1778. this.renderBgEvents.unrender();
  1779. this.renderFgEvents.unrender();
  1780. this.renderEventSelection.unrender();
  1781. this.renderEventDrag.unrender();
  1782. this.renderEventResize.unrender();
  1783. };
  1784. TimelineLane.prototype._renderEventDrag = function (state) {
  1785. if (state) {
  1786. this.eventRenderer.hideByHash(state.affectedInstances);
  1787. this.mirrorRenderer.renderSegs(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
  1788. }
  1789. };
  1790. TimelineLane.prototype._unrenderEventDrag = function (state) {
  1791. if (state) {
  1792. this.eventRenderer.showByHash(state.affectedInstances);
  1793. this.mirrorRenderer.unrender(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
  1794. }
  1795. };
  1796. TimelineLane.prototype._renderEventResize = function (state) {
  1797. if (state) {
  1798. // HACK. eventRenderer and fillRenderer both use these segs. would compete over seg.el
  1799. var segsForHighlight = state.segs.map(function (seg) {
  1800. return __assign({}, seg);
  1801. });
  1802. this.eventRenderer.hideByHash(state.affectedInstances);
  1803. this.fillRenderer.renderSegs('highlight', this.context, segsForHighlight);
  1804. this.mirrorRenderer.renderSegs(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
  1805. }
  1806. };
  1807. TimelineLane.prototype._unrenderEventResize = function (state) {
  1808. if (state) {
  1809. this.eventRenderer.showByHash(state.affectedInstances);
  1810. this.fillRenderer.unrender('highlight', this.context);
  1811. this.mirrorRenderer.unrender(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
  1812. }
  1813. };
  1814. TimelineLane.prototype.updateSize = function (isResize) {
  1815. var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer;
  1816. fillRenderer.computeSizes(isResize);
  1817. eventRenderer.computeSizes(isResize);
  1818. mirrorRenderer.computeSizes(isResize);
  1819. fillRenderer.assignSizes(isResize);
  1820. eventRenderer.assignSizes(isResize);
  1821. mirrorRenderer.assignSizes(isResize);
  1822. };
  1823. return TimelineLane;
  1824. }(DateComponent));
  1825. var TimelineLaneSlicer = /** @class */ (function (_super) {
  1826. __extends(TimelineLaneSlicer, _super);
  1827. function TimelineLaneSlicer() {
  1828. return _super !== null && _super.apply(this, arguments) || this;
  1829. }
  1830. TimelineLaneSlicer.prototype.sliceRange = function (origRange, timeAxis) {
  1831. var tDateProfile = timeAxis.tDateProfile;
  1832. var _a = timeAxis.props, dateProfile = _a.dateProfile, dateProfileGenerator = _a.dateProfileGenerator;
  1833. var dateEnv = timeAxis.context.dateEnv;
  1834. var normalRange = normalizeRange(origRange, tDateProfile, dateEnv);
  1835. var segs = [];
  1836. // protect against when the span is entirely in an invalid date region
  1837. if (timeAxis.computeDateSnapCoverage(normalRange.start) < timeAxis.computeDateSnapCoverage(normalRange.end)) {
  1838. // intersect the footprint's range with the grid's range
  1839. var slicedRange = intersectRanges(normalRange, tDateProfile.normalizedRange);
  1840. if (slicedRange) {
  1841. segs.push({
  1842. start: slicedRange.start,
  1843. end: slicedRange.end,
  1844. isStart: slicedRange.start.valueOf() === normalRange.start.valueOf() && isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator),
  1845. isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf() && isValidDate(addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator)
  1846. });
  1847. }
  1848. }
  1849. return segs;
  1850. };
  1851. return TimelineLaneSlicer;
  1852. }(Slicer));
  1853. var TimelineView = /** @class */ (function (_super) {
  1854. __extends(TimelineView, _super);
  1855. function TimelineView() {
  1856. var _this = _super !== null && _super.apply(this, arguments) || this;
  1857. _this.renderSkeleton = memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton);
  1858. _this.startInteractive = memoizeRendering(_this._startInteractive, _this._stopInteractive);
  1859. return _this;
  1860. }
  1861. TimelineView.prototype._startInteractive = function (timeAxisEl) {
  1862. this.context.calendar.registerInteractiveComponent(this, {
  1863. el: timeAxisEl
  1864. });
  1865. };
  1866. TimelineView.prototype._stopInteractive = function () {
  1867. this.context.calendar.unregisterInteractiveComponent(this);
  1868. };
  1869. TimelineView.prototype.render = function (props, context) {
  1870. _super.prototype.render.call(this, props, context); // flags for updateSize, addScroll. and _renderSkeleton/_unrenderSkeleton
  1871. this.renderSkeleton(this.context);
  1872. this.timeAxis.receiveProps({
  1873. dateProfileGenerator: props.dateProfileGenerator,
  1874. dateProfile: props.dateProfile
  1875. }, context);
  1876. this.startInteractive(this.timeAxis.slats.el);
  1877. this.lane.receiveProps(__assign({}, props, { nextDayThreshold: this.context.nextDayThreshold }), context);
  1878. this.startNowIndicator(props.dateProfile, props.dateProfileGenerator);
  1879. };
  1880. TimelineView.prototype.destroy = function () {
  1881. this.startInteractive.unrender(); // "unrender" a weird name
  1882. this.renderSkeleton.unrender();
  1883. _super.prototype.destroy.call(this);
  1884. };
  1885. TimelineView.prototype._renderSkeleton = function (context) {
  1886. this.el.classList.add('fc-timeline');
  1887. if (context.options.eventOverlap === false) {
  1888. this.el.classList.add('fc-no-overlap');
  1889. }
  1890. this.el.innerHTML = this.renderSkeletonHtml();
  1891. this.timeAxis = new TimeAxis(this.el.querySelector('thead .fc-time-area'), this.el.querySelector('tbody .fc-time-area'));
  1892. this.lane = new TimelineLane(this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.contentEl, this.timeAxis.layout.bodyScroller.enhancedScroll.canvas.bgEl, this.timeAxis);
  1893. };
  1894. TimelineView.prototype._unrenderSkeleton = function () {
  1895. this.el.classList.remove('fc-timeline');
  1896. this.el.classList.remove('fc-no-overlap');
  1897. this.timeAxis.destroy();
  1898. this.lane.destroy();
  1899. };
  1900. TimelineView.prototype.renderSkeletonHtml = function () {
  1901. var theme = this.context.theme;
  1902. return "<table class=\"" + theme.getClass('tableGrid') + "\"> <thead class=\"fc-head\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetHeader') + "\"></td> </tr> </thead> <tbody class=\"fc-body\"> <tr> <td class=\"fc-time-area " + theme.getClass('widgetContent') + "\"></td> </tr> </tbody> </table>";
  1903. };
  1904. TimelineView.prototype.updateSize = function (isResize, totalHeight, isAuto) {
  1905. this.timeAxis.updateSize(isResize, totalHeight, isAuto);
  1906. this.lane.updateSize(isResize);
  1907. };
  1908. // Now Indicator
  1909. // ------------------------------------------------------------------------------------------
  1910. TimelineView.prototype.getNowIndicatorUnit = function (dateProfile, dateProfileGenerator) {
  1911. return this.timeAxis.getNowIndicatorUnit(dateProfile, dateProfileGenerator);
  1912. };
  1913. TimelineView.prototype.renderNowIndicator = function (date) {
  1914. this.timeAxis.renderNowIndicator(date);
  1915. };
  1916. TimelineView.prototype.unrenderNowIndicator = function () {
  1917. this.timeAxis.unrenderNowIndicator();
  1918. };
  1919. // Scroll System
  1920. // ------------------------------------------------------------------------------------------
  1921. TimelineView.prototype.computeDateScroll = function (duration) {
  1922. return this.timeAxis.computeDateScroll(duration);
  1923. };
  1924. TimelineView.prototype.applyScroll = function (scroll, isResize) {
  1925. _super.prototype.applyScroll.call(this, scroll, isResize); // will call applyDateScroll
  1926. var calendar = this.context.calendar;
  1927. // avoid updating stickyscroll too often
  1928. // TODO: repeat code as ResourceTimelineView::updateSize
  1929. if (isResize || calendar.isViewUpdated || calendar.isDatesUpdated || calendar.isEventsUpdated) {
  1930. this.timeAxis.updateStickyScrollers();
  1931. }
  1932. };
  1933. TimelineView.prototype.applyDateScroll = function (scroll) {
  1934. this.timeAxis.applyDateScroll(scroll);
  1935. };
  1936. TimelineView.prototype.queryScroll = function () {
  1937. var enhancedScroll = this.timeAxis.layout.bodyScroller.enhancedScroll;
  1938. return {
  1939. top: enhancedScroll.getScrollTop(),
  1940. left: enhancedScroll.getScrollLeft()
  1941. };
  1942. };
  1943. // Hit System
  1944. // ------------------------------------------------------------------------------------------
  1945. TimelineView.prototype.buildPositionCaches = function () {
  1946. this.timeAxis.slats.updateSize();
  1947. };
  1948. TimelineView.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) {
  1949. var slatHit = this.timeAxis.slats.positionToHit(positionLeft);
  1950. if (slatHit) {
  1951. return {
  1952. component: this,
  1953. dateSpan: slatHit.dateSpan,
  1954. rect: {
  1955. left: slatHit.left,
  1956. right: slatHit.right,
  1957. top: 0,
  1958. bottom: elHeight
  1959. },
  1960. dayEl: slatHit.dayEl,
  1961. layer: 0
  1962. };
  1963. }
  1964. };
  1965. return TimelineView;
  1966. }(View));
  1967. var main = createPlugin({
  1968. defaultView: 'timelineDay',
  1969. views: {
  1970. timeline: {
  1971. class: TimelineView,
  1972. eventResizableFromStart: true // how is this consumed for TimelineView tho?
  1973. },
  1974. timelineDay: {
  1975. type: 'timeline',
  1976. duration: { days: 1 }
  1977. },
  1978. timelineWeek: {
  1979. type: 'timeline',
  1980. duration: { weeks: 1 }
  1981. },
  1982. timelineMonth: {
  1983. type: 'timeline',
  1984. duration: { months: 1 }
  1985. },
  1986. timelineYear: {
  1987. type: 'timeline',
  1988. duration: { years: 1 }
  1989. }
  1990. }
  1991. });
  1992. export default main;
  1993. export { HeaderBodyLayout, ScrollJoiner, StickyScroller, TimeAxis, TimelineLane, TimelineView };