@fullcalendar/core 5.11.3 → 6.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/{LICENSE.txt → LICENSE.md} +0 -0
  2. package/README.md +3 -3
  3. package/index.cjs +1545 -0
  4. package/index.d.ts +44 -0
  5. package/{main.global.js → index.global.js} +7130 -7704
  6. package/index.global.min.js +6 -0
  7. package/index.js +1536 -0
  8. package/internal-common.cjs +8064 -0
  9. package/internal-common.d.ts +2783 -0
  10. package/internal-common.js +7826 -0
  11. package/internal.cjs +198 -0
  12. package/internal.d.ts +4 -0
  13. package/internal.js +3 -0
  14. package/locales/af.cjs +26 -0
  15. package/locales/af.d.ts +5 -2
  16. package/locales/af.global.js +29 -24
  17. package/locales/af.global.min.js +6 -0
  18. package/locales/af.js +20 -24
  19. package/locales/ar-dz.cjs +27 -0
  20. package/locales/ar-dz.d.ts +5 -2
  21. package/locales/ar-dz.global.js +30 -25
  22. package/locales/ar-dz.global.min.js +6 -0
  23. package/locales/ar-dz.js +21 -25
  24. package/locales/ar-kw.cjs +27 -0
  25. package/locales/ar-kw.d.ts +5 -2
  26. package/locales/ar-kw.global.js +30 -25
  27. package/locales/ar-kw.global.min.js +6 -0
  28. package/locales/ar-kw.js +21 -25
  29. package/locales/ar-ly.cjs +27 -0
  30. package/locales/ar-ly.d.ts +5 -2
  31. package/locales/ar-ly.global.js +30 -25
  32. package/locales/ar-ly.global.min.js +6 -0
  33. package/locales/ar-ly.js +21 -25
  34. package/locales/ar-ma.cjs +27 -0
  35. package/locales/ar-ma.d.ts +5 -2
  36. package/locales/ar-ma.global.js +30 -25
  37. package/locales/ar-ma.global.min.js +6 -0
  38. package/locales/ar-ma.js +21 -25
  39. package/locales/ar-sa.cjs +27 -0
  40. package/locales/ar-sa.d.ts +5 -2
  41. package/locales/ar-sa.global.js +30 -25
  42. package/locales/ar-sa.global.min.js +6 -0
  43. package/locales/ar-sa.js +21 -25
  44. package/locales/ar-tn.cjs +27 -0
  45. package/locales/ar-tn.d.ts +5 -2
  46. package/locales/ar-tn.global.js +30 -25
  47. package/locales/ar-tn.global.min.js +6 -0
  48. package/locales/ar-tn.js +21 -25
  49. package/locales/ar.cjs +27 -0
  50. package/locales/ar.d.ts +5 -2
  51. package/locales/ar.global.js +30 -25
  52. package/locales/ar.global.min.js +6 -0
  53. package/locales/ar.js +21 -25
  54. package/locales/az.cjs +28 -0
  55. package/locales/az.d.ts +5 -2
  56. package/locales/az.global.js +31 -26
  57. package/locales/az.global.min.js +6 -0
  58. package/locales/az.js +22 -26
  59. package/locales/bg.cjs +27 -0
  60. package/locales/bg.d.ts +5 -2
  61. package/locales/bg.global.js +30 -25
  62. package/locales/bg.global.min.js +6 -0
  63. package/locales/bg.js +21 -25
  64. package/locales/bn.cjs +28 -0
  65. package/locales/bn.d.ts +5 -2
  66. package/locales/bn.global.js +31 -26
  67. package/locales/bn.global.min.js +6 -0
  68. package/locales/bn.js +22 -26
  69. package/locales/bs.cjs +28 -0
  70. package/locales/bs.d.ts +5 -2
  71. package/locales/bs.global.js +31 -26
  72. package/locales/bs.global.min.js +6 -0
  73. package/locales/bs.js +22 -26
  74. package/locales/ca.cjs +26 -0
  75. package/locales/ca.d.ts +5 -2
  76. package/locales/ca.global.js +29 -24
  77. package/locales/ca.global.min.js +6 -0
  78. package/locales/ca.js +20 -24
  79. package/locales/cs.cjs +28 -0
  80. package/locales/cs.d.ts +5 -2
  81. package/locales/cs.global.js +31 -26
  82. package/locales/cs.global.min.js +6 -0
  83. package/locales/cs.js +22 -26
  84. package/locales/cy.cjs +27 -0
  85. package/locales/cy.d.ts +5 -2
  86. package/locales/cy.global.js +30 -25
  87. package/locales/cy.global.min.js +6 -0
  88. package/locales/cy.js +21 -25
  89. package/locales/da.cjs +26 -0
  90. package/locales/da.d.ts +5 -2
  91. package/locales/da.global.js +29 -24
  92. package/locales/da.global.min.js +6 -0
  93. package/locales/da.js +20 -24
  94. package/locales/de-at.cjs +63 -0
  95. package/locales/de-at.d.ts +5 -2
  96. package/locales/de-at.global.js +66 -56
  97. package/locales/de-at.global.min.js +6 -0
  98. package/locales/de-at.js +53 -52
  99. package/locales/de.cjs +63 -0
  100. package/locales/de.d.ts +5 -2
  101. package/locales/de.global.js +66 -56
  102. package/locales/de.global.min.js +6 -0
  103. package/locales/de.js +53 -52
  104. package/locales/el.cjs +26 -0
  105. package/locales/el.d.ts +5 -2
  106. package/locales/el.global.js +29 -24
  107. package/locales/el.global.min.js +6 -0
  108. package/locales/el.js +20 -24
  109. package/locales/en-au.cjs +23 -0
  110. package/locales/en-au.d.ts +5 -2
  111. package/locales/en-au.global.js +26 -21
  112. package/locales/en-au.global.min.js +6 -0
  113. package/locales/en-au.js +17 -21
  114. package/locales/en-gb.cjs +23 -0
  115. package/locales/en-gb.d.ts +5 -2
  116. package/locales/en-gb.global.js +26 -21
  117. package/locales/en-gb.global.min.js +6 -0
  118. package/locales/en-gb.js +17 -21
  119. package/locales/en-nz.cjs +23 -0
  120. package/locales/en-nz.d.ts +5 -2
  121. package/locales/en-nz.global.js +26 -21
  122. package/locales/en-nz.global.min.js +6 -0
  123. package/locales/en-nz.js +17 -21
  124. package/locales/eo.cjs +26 -0
  125. package/locales/eo.d.ts +5 -2
  126. package/locales/eo.global.js +29 -24
  127. package/locales/eo.global.min.js +6 -0
  128. package/locales/eo.js +20 -24
  129. package/locales/es-us.cjs +26 -0
  130. package/locales/es-us.d.ts +5 -2
  131. package/locales/es-us.global.js +29 -24
  132. package/locales/es-us.global.min.js +6 -0
  133. package/locales/es-us.js +20 -24
  134. package/locales/es.cjs +45 -0
  135. package/locales/es.d.ts +5 -2
  136. package/locales/es.global.js +48 -42
  137. package/locales/es.global.min.js +6 -0
  138. package/locales/es.js +39 -42
  139. package/locales/et.cjs +28 -0
  140. package/locales/et.d.ts +5 -2
  141. package/locales/et.global.js +31 -26
  142. package/locales/et.global.min.js +6 -0
  143. package/locales/et.js +22 -26
  144. package/locales/eu.cjs +26 -0
  145. package/locales/eu.d.ts +5 -2
  146. package/locales/eu.global.js +29 -24
  147. package/locales/eu.global.min.js +6 -0
  148. package/locales/eu.js +20 -24
  149. package/locales/fa.cjs +29 -0
  150. package/locales/fa.d.ts +5 -2
  151. package/locales/fa.global.js +32 -27
  152. package/locales/fa.global.min.js +6 -0
  153. package/locales/fa.js +23 -27
  154. package/locales/fi.cjs +26 -0
  155. package/locales/fi.d.ts +5 -2
  156. package/locales/fi.global.js +29 -24
  157. package/locales/fi.global.min.js +6 -0
  158. package/locales/fi.js +20 -24
  159. package/locales/fr-ca.cjs +23 -0
  160. package/locales/fr-ca.d.ts +5 -2
  161. package/locales/fr-ca.global.js +26 -21
  162. package/locales/fr-ca.global.min.js +6 -0
  163. package/locales/fr-ca.js +17 -21
  164. package/locales/fr-ch.cjs +27 -0
  165. package/locales/fr-ch.d.ts +5 -2
  166. package/locales/fr-ch.global.js +30 -25
  167. package/locales/fr-ch.global.min.js +6 -0
  168. package/locales/fr-ch.js +21 -25
  169. package/locales/fr.cjs +27 -0
  170. package/locales/fr.d.ts +5 -2
  171. package/locales/fr.global.js +30 -25
  172. package/locales/fr.global.min.js +6 -0
  173. package/locales/fr.js +21 -25
  174. package/locales/gl.cjs +26 -0
  175. package/locales/gl.d.ts +5 -2
  176. package/locales/gl.global.js +29 -24
  177. package/locales/gl.global.min.js +6 -0
  178. package/locales/gl.js +20 -24
  179. package/locales/he.cjs +23 -0
  180. package/locales/he.d.ts +5 -2
  181. package/locales/he.global.js +26 -21
  182. package/locales/he.global.min.js +6 -0
  183. package/locales/he.js +17 -21
  184. package/locales/hi.cjs +28 -0
  185. package/locales/hi.d.ts +5 -2
  186. package/locales/hi.global.js +31 -26
  187. package/locales/hi.global.min.js +6 -0
  188. package/locales/hi.js +22 -26
  189. package/locales/hr.cjs +28 -0
  190. package/locales/hr.d.ts +5 -2
  191. package/locales/hr.global.js +31 -26
  192. package/locales/hr.global.min.js +6 -0
  193. package/locales/hr.js +22 -26
  194. package/locales/hu.cjs +26 -0
  195. package/locales/hu.d.ts +5 -2
  196. package/locales/hu.global.js +29 -24
  197. package/locales/hu.global.min.js +6 -0
  198. package/locales/hu.js +20 -24
  199. package/locales/hy-am.cjs +28 -0
  200. package/locales/hy-am.d.ts +5 -2
  201. package/locales/hy-am.global.js +31 -26
  202. package/locales/hy-am.global.min.js +6 -0
  203. package/locales/hy-am.js +22 -26
  204. package/locales/id.cjs +26 -0
  205. package/locales/id.d.ts +5 -2
  206. package/locales/id.global.js +29 -24
  207. package/locales/id.global.min.js +6 -0
  208. package/locales/id.js +20 -24
  209. package/locales/is.cjs +26 -0
  210. package/locales/is.d.ts +5 -2
  211. package/locales/is.global.js +29 -24
  212. package/locales/is.global.min.js +6 -0
  213. package/locales/is.js +20 -24
  214. package/locales/it.cjs +28 -0
  215. package/locales/it.d.ts +5 -2
  216. package/locales/it.global.js +31 -26
  217. package/locales/it.global.min.js +6 -0
  218. package/locales/it.js +22 -26
  219. package/locales/ja.cjs +24 -0
  220. package/locales/ja.d.ts +5 -2
  221. package/locales/ja.global.js +27 -22
  222. package/locales/ja.global.min.js +6 -0
  223. package/locales/ja.js +18 -22
  224. package/locales/ka.cjs +28 -0
  225. package/locales/ka.d.ts +5 -2
  226. package/locales/ka.global.js +31 -26
  227. package/locales/ka.global.min.js +6 -0
  228. package/locales/ka.js +22 -26
  229. package/locales/kk.cjs +28 -0
  230. package/locales/kk.d.ts +5 -2
  231. package/locales/kk.global.js +31 -26
  232. package/locales/kk.global.min.js +6 -0
  233. package/locales/kk.js +22 -26
  234. package/locales/km.cjs +27 -0
  235. package/locales/km.d.ts +5 -2
  236. package/locales/km.global.js +30 -25
  237. package/locales/km.global.min.js +6 -0
  238. package/locales/km.js +21 -25
  239. package/locales/ko.cjs +22 -0
  240. package/locales/ko.d.ts +5 -2
  241. package/locales/ko.global.js +25 -20
  242. package/locales/ko.global.min.js +6 -0
  243. package/locales/ko.js +16 -20
  244. package/locales/ku.cjs +27 -0
  245. package/locales/ku.d.ts +5 -2
  246. package/locales/ku.global.js +30 -25
  247. package/locales/ku.global.min.js +6 -0
  248. package/locales/ku.js +21 -25
  249. package/locales/lb.cjs +26 -0
  250. package/locales/lb.d.ts +5 -2
  251. package/locales/lb.global.js +29 -24
  252. package/locales/lb.global.min.js +6 -0
  253. package/locales/lb.js +20 -24
  254. package/locales/lt.cjs +26 -0
  255. package/locales/lt.d.ts +5 -2
  256. package/locales/lt.global.js +29 -24
  257. package/locales/lt.global.min.js +6 -0
  258. package/locales/lt.js +20 -24
  259. package/locales/lv.cjs +28 -0
  260. package/locales/lv.d.ts +5 -2
  261. package/locales/lv.global.js +31 -26
  262. package/locales/lv.global.min.js +6 -0
  263. package/locales/lv.js +22 -26
  264. package/locales/mk.cjs +24 -0
  265. package/locales/mk.d.ts +5 -2
  266. package/locales/mk.global.js +27 -22
  267. package/locales/mk.global.min.js +6 -0
  268. package/locales/mk.js +18 -22
  269. package/locales/ms.cjs +28 -0
  270. package/locales/ms.d.ts +5 -2
  271. package/locales/ms.global.js +31 -26
  272. package/locales/ms.global.min.js +6 -0
  273. package/locales/ms.js +22 -26
  274. package/locales/nb.cjs +37 -0
  275. package/locales/nb.d.ts +5 -2
  276. package/locales/nb.global.js +40 -35
  277. package/locales/nb.global.min.js +6 -0
  278. package/locales/nb.js +31 -35
  279. package/locales/ne.cjs +26 -0
  280. package/locales/ne.d.ts +5 -2
  281. package/locales/ne.global.js +29 -24
  282. package/locales/ne.global.min.js +6 -0
  283. package/locales/ne.js +20 -24
  284. package/locales/nl.cjs +26 -0
  285. package/locales/nl.d.ts +5 -2
  286. package/locales/nl.global.js +29 -24
  287. package/locales/nl.global.min.js +6 -0
  288. package/locales/nl.js +20 -24
  289. package/locales/nn.cjs +26 -0
  290. package/locales/nn.d.ts +5 -2
  291. package/locales/nn.global.js +29 -24
  292. package/locales/nn.global.min.js +6 -0
  293. package/locales/nn.js +20 -24
  294. package/locales/pl.cjs +26 -0
  295. package/locales/pl.d.ts +5 -2
  296. package/locales/pl.global.js +29 -24
  297. package/locales/pl.global.min.js +6 -0
  298. package/locales/pl.js +20 -24
  299. package/locales/pt-br.cjs +24 -0
  300. package/locales/pt-br.d.ts +5 -2
  301. package/locales/pt-br.global.js +27 -22
  302. package/locales/pt-br.global.min.js +6 -0
  303. package/locales/pt-br.js +18 -22
  304. package/locales/pt.cjs +26 -0
  305. package/locales/pt.d.ts +5 -2
  306. package/locales/pt.global.js +29 -24
  307. package/locales/pt.global.min.js +6 -0
  308. package/locales/pt.js +20 -24
  309. package/locales/ro.cjs +28 -0
  310. package/locales/ro.d.ts +5 -2
  311. package/locales/ro.global.js +31 -26
  312. package/locales/ro.global.min.js +6 -0
  313. package/locales/ro.js +22 -26
  314. package/locales/ru.cjs +28 -0
  315. package/locales/ru.d.ts +5 -2
  316. package/locales/ru.global.js +31 -26
  317. package/locales/ru.global.min.js +6 -0
  318. package/locales/ru.js +22 -26
  319. package/locales/si-lk.cjs +26 -0
  320. package/locales/si-lk.d.ts +5 -2
  321. package/locales/si-lk.global.js +29 -24
  322. package/locales/si-lk.global.min.js +6 -0
  323. package/locales/si-lk.js +20 -24
  324. package/locales/sk.cjs +28 -0
  325. package/locales/sk.d.ts +5 -2
  326. package/locales/sk.global.js +31 -26
  327. package/locales/sk.global.min.js +6 -0
  328. package/locales/sk.js +22 -26
  329. package/locales/sl.cjs +26 -0
  330. package/locales/sl.d.ts +5 -2
  331. package/locales/sl.global.js +29 -24
  332. package/locales/sl.global.min.js +6 -0
  333. package/locales/sl.js +20 -24
  334. package/locales/sm.cjs +22 -0
  335. package/locales/sm.d.ts +5 -2
  336. package/locales/sm.global.js +25 -20
  337. package/locales/sm.global.min.js +6 -0
  338. package/locales/sm.js +16 -20
  339. package/locales/sq.cjs +28 -0
  340. package/locales/sq.d.ts +5 -2
  341. package/locales/sq.global.js +31 -26
  342. package/locales/sq.global.min.js +6 -0
  343. package/locales/sq.js +22 -26
  344. package/locales/sr-cyrl.cjs +28 -0
  345. package/locales/sr-cyrl.d.ts +5 -2
  346. package/locales/sr-cyrl.global.js +31 -26
  347. package/locales/sr-cyrl.global.min.js +6 -0
  348. package/locales/sr-cyrl.js +22 -26
  349. package/locales/sr.cjs +28 -0
  350. package/locales/sr.d.ts +5 -2
  351. package/locales/sr.global.js +31 -26
  352. package/locales/sr.global.min.js +6 -0
  353. package/locales/sr.js +22 -26
  354. package/locales/sv.cjs +46 -0
  355. package/locales/sv.d.ts +5 -2
  356. package/locales/sv.global.js +49 -44
  357. package/locales/sv.global.min.js +6 -0
  358. package/locales/sv.js +38 -42
  359. package/locales/ta-in.cjs +28 -0
  360. package/locales/ta-in.d.ts +5 -2
  361. package/locales/ta-in.global.js +31 -26
  362. package/locales/ta-in.global.min.js +6 -0
  363. package/locales/ta-in.js +22 -26
  364. package/locales/th.cjs +29 -0
  365. package/locales/th.d.ts +5 -2
  366. package/locales/th.global.js +32 -27
  367. package/locales/th.global.min.js +6 -0
  368. package/locales/th.js +23 -27
  369. package/locales/tr.cjs +26 -0
  370. package/locales/tr.d.ts +5 -2
  371. package/locales/tr.global.js +29 -24
  372. package/locales/tr.global.min.js +6 -0
  373. package/locales/tr.js +20 -24
  374. package/locales/ug.cjs +16 -0
  375. package/locales/ug.d.ts +5 -2
  376. package/locales/ug.global.js +19 -14
  377. package/locales/ug.global.min.js +6 -0
  378. package/locales/ug.js +10 -14
  379. package/locales/uk.cjs +28 -0
  380. package/locales/uk.d.ts +5 -2
  381. package/locales/uk.global.js +31 -26
  382. package/locales/uk.global.min.js +6 -0
  383. package/locales/uk.js +22 -26
  384. package/locales/uz.cjs +20 -0
  385. package/locales/uz.d.ts +5 -2
  386. package/locales/uz.global.js +23 -18
  387. package/locales/uz.global.min.js +6 -0
  388. package/locales/uz.js +14 -18
  389. package/locales/vi.cjs +28 -0
  390. package/locales/vi.d.ts +5 -2
  391. package/locales/vi.global.js +31 -26
  392. package/locales/vi.global.min.js +6 -0
  393. package/locales/vi.js +22 -26
  394. package/locales/zh-cn.cjs +29 -0
  395. package/locales/zh-cn.d.ts +5 -2
  396. package/locales/zh-cn.global.js +32 -26
  397. package/locales/zh-cn.global.min.js +6 -0
  398. package/locales/zh-cn.js +23 -26
  399. package/locales/zh-tw.cjs +22 -0
  400. package/locales/zh-tw.d.ts +5 -2
  401. package/locales/zh-tw.global.js +25 -20
  402. package/locales/zh-tw.global.min.js +6 -0
  403. package/locales/zh-tw.js +16 -20
  404. package/locales-all.cjs +88 -0
  405. package/locales-all.d.ts +6 -2
  406. package/locales-all.global.js +1792 -1852
  407. package/locales-all.global.min.js +6 -1
  408. package/locales-all.js +80 -1849
  409. package/package.json +61 -18
  410. package/preact.cjs +22 -0
  411. package/preact.d.ts +8 -0
  412. package/preact.js +3 -0
  413. package/main.cjs.js +0 -138
  414. package/main.d.ts +0 -30
  415. package/main.global.min.js +0 -6
  416. package/main.js +0 -128
  417. package/main.js.map +0 -1
  418. package/vdom.cjs.js +0 -105
  419. package/vdom.d.ts +0 -23
  420. package/vdom.js +0 -80
package/index.cjs ADDED
@@ -0,0 +1,1545 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var internalCommon = require('./internal-common.cjs');
6
+ var preact = require('preact');
7
+ require('preact/compat');
8
+
9
+ var css_248z = "\n/*\nfor css vars only.\nthese values are automatically known in all stylesheets.\nthe :root statement itself is only included in the common stylesheet.\nthis file is not processed by postcss when imported into the postcss-custom-properties plugin,\nso only write standard css!\n\nNOTE: for old browsers, will need to restart watcher after changing a variable\n*/\n\n:root {\n --fc-small-font-size: .85em;\n --fc-page-bg-color: #fff;\n --fc-neutral-bg-color: rgba(208, 208, 208, 0.3);\n --fc-neutral-text-color: #808080;\n --fc-border-color: #ddd;\n\n --fc-button-text-color: #fff;\n --fc-button-bg-color: #2C3E50;\n --fc-button-border-color: #2C3E50;\n --fc-button-hover-bg-color: #1e2b37;\n --fc-button-hover-border-color: #1a252f;\n --fc-button-active-bg-color: #1a252f;\n --fc-button-active-border-color: #151e27;\n\n --fc-event-bg-color: #3788d8;\n --fc-event-border-color: #3788d8;\n --fc-event-text-color: #fff;\n --fc-event-selected-overlay-color: rgba(0, 0, 0, 0.25);\n\n --fc-more-link-bg-color: #d0d0d0;\n --fc-more-link-text-color: inherit;\n\n --fc-event-resizer-thickness: 8px;\n --fc-event-resizer-dot-total-width: 8px;\n --fc-event-resizer-dot-border-width: 1px;\n\n --fc-non-business-color: rgba(215, 215, 215, 0.3);\n --fc-bg-event-color: rgb(143, 223, 130);\n --fc-bg-event-opacity: 0.3;\n --fc-highlight-color: rgba(188, 232, 241, 0.3);\n --fc-today-bg-color: rgba(255, 220, 40, 0.15);\n --fc-now-indicator-color: red;\n}\n\n/* classes attached to <body> */\n\n/* TODO: make fc-event selector work when calender in shadow DOM */\n\n.fc-not-allowed,\n.fc-not-allowed .fc-event { /* override events' custom cursors */\n cursor: not-allowed;\n}\n\n/* TODO: not attached to body. attached to specific els. move */\n\n.fc-unselectable {\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n -webkit-touch-callout: none;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n.fc {\n /* layout of immediate children */\n display: flex;\n flex-direction: column;\n\n font-size: 1em\n}\n.fc,\n .fc *,\n .fc *:before,\n .fc *:after {\n box-sizing: border-box;\n }\n.fc table {\n border-collapse: collapse;\n border-spacing: 0;\n font-size: 1em; /* normalize cross-browser */\n }\n.fc th {\n text-align: center;\n }\n.fc th,\n .fc td {\n vertical-align: top;\n padding: 0;\n }\n.fc a[data-navlink] {\n cursor: pointer;\n }\n.fc a[data-navlink]:hover {\n text-decoration: underline;\n }\n.fc-direction-ltr {\n direction: ltr;\n text-align: left;\n}\n.fc-direction-rtl {\n direction: rtl;\n text-align: right;\n}\n.fc-theme-standard td,\n .fc-theme-standard th {\n border: 1px solid var(--fc-border-color);\n }\n/* for FF, which doesn't expand a 100% div within a table cell. use absolute positioning */\n/* inner-wrappers are responsible for being absolute */\n/* TODO: best place for this? */\n.fc-liquid-hack td,\n .fc-liquid-hack th {\n position: relative;\n }\n\n@font-face {\n font-family: 'fcicons';\n src: url(\"data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBfAAAAC8AAAAYGNtYXAXVtKNAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5ZgYydxIAAAF4AAAFNGhlYWQUJ7cIAAAGrAAAADZoaGVhB20DzAAABuQAAAAkaG10eCIABhQAAAcIAAAALGxvY2ED4AU6AAAHNAAAABhtYXhwAA8AjAAAB0wAAAAgbmFtZXsr690AAAdsAAABhnBvc3QAAwAAAAAI9AAAACAAAwPAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpBgPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6Qb//f//AAAAAAAg6QD//f//AAH/4xcEAAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAWIAjQKeAskAEwAAJSc3NjQnJiIHAQYUFwEWMjc2NCcCnuLiDQ0MJAz/AA0NAQAMJAwNDcni4gwjDQwM/wANIwz/AA0NDCMNAAAAAQFiAI0CngLJABMAACUBNjQnASYiBwYUHwEHBhQXFjI3AZ4BAA0N/wAMJAwNDeLiDQ0MJAyNAQAMIw0BAAwMDSMM4uINIwwNDQAAAAIA4gC3Ax4CngATACcAACUnNzY0JyYiDwEGFB8BFjI3NjQnISc3NjQnJiIPAQYUHwEWMjc2NCcB87e3DQ0MIw3VDQ3VDSMMDQ0BK7e3DQ0MJAzVDQ3VDCQMDQ3zuLcMJAwNDdUNIwzWDAwNIwy4twwkDA0N1Q0jDNYMDA0jDAAAAgDiALcDHgKeABMAJwAAJTc2NC8BJiIHBhQfAQcGFBcWMjchNzY0LwEmIgcGFB8BBwYUFxYyNwJJ1Q0N1Q0jDA0Nt7cNDQwjDf7V1Q0N1QwkDA0Nt7cNDQwkDLfWDCMN1Q0NDCQMt7gMIw0MDNYMIw3VDQ0MJAy3uAwjDQwMAAADAFUAAAOrA1UAMwBoAHcAABMiBgcOAQcOAQcOARURFBYXHgEXHgEXHgEzITI2Nz4BNz4BNz4BNRE0JicuAScuAScuASMFITIWFx4BFx4BFx4BFREUBgcOAQcOAQcOASMhIiYnLgEnLgEnLgE1ETQ2Nz4BNz4BNz4BMxMhMjY1NCYjISIGFRQWM9UNGAwLFQkJDgUFBQUFBQ4JCRULDBgNAlYNGAwLFQkJDgUFBQUFBQ4JCRULDBgN/aoCVgQIBAQHAwMFAQIBAQIBBQMDBwQECAT9qgQIBAQHAwMFAQIBAQIBBQMDBwQECASAAVYRGRkR/qoRGRkRA1UFBAUOCQkVDAsZDf2rDRkLDBUJCA4FBQUFBQUOCQgVDAsZDQJVDRkLDBUJCQ4FBAVVAgECBQMCBwQECAX9qwQJAwQHAwMFAQICAgIBBQMDBwQDCQQCVQUIBAQHAgMFAgEC/oAZEhEZGRESGQAAAAADAFUAAAOrA1UAMwBoAIkAABMiBgcOAQcOAQcOARURFBYXHgEXHgEXHgEzITI2Nz4BNz4BNz4BNRE0JicuAScuAScuASMFITIWFx4BFx4BFx4BFREUBgcOAQcOAQcOASMhIiYnLgEnLgEnLgE1ETQ2Nz4BNz4BNz4BMxMzFRQWMzI2PQEzMjY1NCYrATU0JiMiBh0BIyIGFRQWM9UNGAwLFQkJDgUFBQUFBQ4JCRULDBgNAlYNGAwLFQkJDgUFBQUFBQ4JCRULDBgN/aoCVgQIBAQHAwMFAQIBAQIBBQMDBwQECAT9qgQIBAQHAwMFAQIBAQIBBQMDBwQECASAgBkSEhmAERkZEYAZEhIZgBEZGREDVQUEBQ4JCRUMCxkN/asNGQsMFQkIDgUFBQUFBQ4JCBUMCxkNAlUNGQsMFQkJDgUEBVUCAQIFAwIHBAQIBf2rBAkDBAcDAwUBAgICAgEFAwMHBAMJBAJVBQgEBAcCAwUCAQL+gIASGRkSgBkSERmAEhkZEoAZERIZAAABAOIAjQMeAskAIAAAExcHBhQXFjI/ARcWMjc2NC8BNzY0JyYiDwEnJiIHBhQX4uLiDQ0MJAzi4gwkDA0N4uINDQwkDOLiDCQMDQ0CjeLiDSMMDQ3h4Q0NDCMN4uIMIw0MDOLiDAwNIwwAAAABAAAAAQAAa5n0y18PPPUACwQAAAAAANivOVsAAAAA2K85WwAAAAADqwNVAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAAAAAOrAAEAAAAAAAAAAAAAAAAAAAALBAAAAAAAAAAAAAAAAgAAAAQAAWIEAAFiBAAA4gQAAOIEAABVBAAAVQQAAOIAAAAAAAoAFAAeAEQAagCqAOoBngJkApoAAQAAAAsAigADAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGZjaWNvbnMAZgBjAGkAYwBvAG4Ac1ZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGZjaWNvbnMAZgBjAGkAYwBvAG4Ac2ZjaWNvbnMAZgBjAGkAYwBvAG4Ac1JlZ3VsYXIAUgBlAGcAdQBsAGEAcmZjaWNvbnMAZgBjAGkAYwBvAG4Ac0ZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\") format('truetype');\n font-weight: normal;\n font-style: normal;\n}\n\n.fc-icon {\n /* added for fc */\n display: inline-block;\n width: 1em;\n height: 1em;\n text-align: center;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n\n /* use !important to prevent issues with browser extensions that change fonts */\n font-family: 'fcicons' !important;\n speak: none;\n font-style: normal;\n font-weight: normal;\n font-variant: normal;\n text-transform: none;\n line-height: 1;\n\n /* Better Font Rendering =========== */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n.fc-icon-chevron-left:before {\n content: \"\\e900\";\n}\n\n.fc-icon-chevron-right:before {\n content: \"\\e901\";\n}\n\n.fc-icon-chevrons-left:before {\n content: \"\\e902\";\n}\n\n.fc-icon-chevrons-right:before {\n content: \"\\e903\";\n}\n\n.fc-icon-minus-square:before {\n content: \"\\e904\";\n}\n\n.fc-icon-plus-square:before {\n content: \"\\e905\";\n}\n\n.fc-icon-x:before {\n content: \"\\e906\";\n}\n/*\nLots taken from Flatly (MIT): https://bootswatch.com/4/flatly/bootstrap.css\n\nThese styles only apply when the standard-theme is activated.\nWhen it's NOT activated, the fc-button classes won't even be in the DOM.\n*/\n.fc {\n\n /* reset */\n\n}\n.fc .fc-button {\n border-radius: 0;\n overflow: visible;\n text-transform: none;\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n }\n.fc .fc-button:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n }\n.fc .fc-button {\n -webkit-appearance: button;\n }\n.fc .fc-button:not(:disabled) {\n cursor: pointer;\n }\n.fc .fc-button::-moz-focus-inner {\n padding: 0;\n border-style: none;\n }\n.fc {\n\n /* theme */\n\n}\n.fc .fc-button {\n display: inline-block;\n font-weight: 400;\n text-align: center;\n vertical-align: middle;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n background-color: transparent;\n border: 1px solid transparent;\n padding: 0.4em 0.65em;\n font-size: 1em;\n line-height: 1.5;\n border-radius: 0.25em;\n }\n.fc .fc-button:hover {\n text-decoration: none;\n }\n.fc .fc-button:focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(44, 62, 80, 0.25);\n }\n.fc .fc-button:disabled {\n opacity: 0.65;\n }\n.fc {\n\n /* \"primary\" coloring */\n\n}\n.fc .fc-button-primary {\n color: var(--fc-button-text-color);\n background-color: var(--fc-button-bg-color);\n border-color: var(--fc-button-border-color);\n }\n.fc .fc-button-primary:hover {\n color: var(--fc-button-text-color);\n background-color: var(--fc-button-hover-bg-color);\n border-color: var(--fc-button-hover-border-color);\n }\n.fc .fc-button-primary:disabled { /* not DRY */\n color: var(--fc-button-text-color);\n background-color: var(--fc-button-bg-color);\n border-color: var(--fc-button-border-color); /* overrides :hover */\n }\n.fc .fc-button-primary:focus {\n box-shadow: 0 0 0 0.2rem rgba(76, 91, 106, 0.5);\n }\n.fc .fc-button-primary:not(:disabled):active,\n .fc .fc-button-primary:not(:disabled).fc-button-active {\n color: var(--fc-button-text-color);\n background-color: var(--fc-button-active-bg-color);\n border-color: var(--fc-button-active-border-color);\n }\n.fc .fc-button-primary:not(:disabled):active:focus,\n .fc .fc-button-primary:not(:disabled).fc-button-active:focus {\n box-shadow: 0 0 0 0.2rem rgba(76, 91, 106, 0.5);\n }\n.fc {\n\n /* icons within buttons */\n\n}\n.fc .fc-button .fc-icon {\n vertical-align: middle;\n font-size: 1.5em; /* bump up the size (but don't make it bigger than line-height of button, which is 1.5em also) */\n }\n.fc .fc-button-group {\n position: relative;\n display: inline-flex;\n vertical-align: middle;\n }\n.fc .fc-button-group > .fc-button {\n position: relative;\n flex: 1 1 auto;\n }\n.fc .fc-button-group > .fc-button:hover {\n z-index: 1;\n }\n.fc .fc-button-group > .fc-button:focus,\n .fc .fc-button-group > .fc-button:active,\n .fc .fc-button-group > .fc-button.fc-button-active {\n z-index: 1;\n }\n.fc-direction-ltr .fc-button-group > .fc-button:not(:first-child) {\n margin-left: -1px;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n.fc-direction-ltr .fc-button-group > .fc-button:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n.fc-direction-rtl .fc-button-group > .fc-button:not(:first-child) {\n margin-right: -1px;\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n.fc-direction-rtl .fc-button-group > .fc-button:not(:last-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n.fc .fc-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n.fc .fc-toolbar.fc-header-toolbar {\n margin-bottom: 1.5em;\n }\n.fc .fc-toolbar.fc-footer-toolbar {\n margin-top: 1.5em;\n }\n.fc .fc-toolbar-title {\n font-size: 1.75em;\n margin: 0;\n }\n.fc-direction-ltr .fc-toolbar > * > :not(:first-child) {\n margin-left: .75em; /* space between */\n }\n.fc-direction-rtl .fc-toolbar > * > :not(:first-child) {\n margin-right: .75em; /* space between */\n }\n.fc-direction-rtl .fc-toolbar-ltr { /* when the toolbar-chunk positioning system is explicitly left-to-right */\n flex-direction: row-reverse;\n }\n.fc .fc-scroller {\n -webkit-overflow-scrolling: touch;\n position: relative; /* for abs-positioned elements within */\n }\n.fc .fc-scroller-liquid {\n height: 100%;\n }\n.fc .fc-scroller-liquid-absolute {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n bottom: 0;\n }\n.fc .fc-scroller-harness {\n position: relative;\n overflow: hidden;\n direction: ltr;\n /* hack for chrome computing the scroller's right/left wrong for rtl. undone below... */\n /* TODO: demonstrate in codepen */\n }\n.fc .fc-scroller-harness-liquid {\n height: 100%;\n }\n.fc-direction-rtl .fc-scroller-harness > .fc-scroller { /* undo above hack */\n direction: rtl;\n }\n.fc-theme-standard .fc-scrollgrid {\n border: 1px solid var(--fc-border-color); /* bootstrap does this. match */\n }\n.fc .fc-scrollgrid,\n .fc .fc-scrollgrid table { /* all tables (self included) */\n width: 100%; /* because tables don't normally do this */\n table-layout: fixed;\n }\n.fc .fc-scrollgrid table { /* inner tables */\n border-top-style: hidden;\n border-left-style: hidden;\n border-right-style: hidden;\n }\n.fc .fc-scrollgrid {\n\n border-collapse: separate;\n border-right-width: 0;\n border-bottom-width: 0;\n\n }\n.fc .fc-scrollgrid-liquid {\n height: 100%;\n }\n.fc .fc-scrollgrid-section { /* a <tr> */\n height: 1px /* better than 0, for firefox */\n\n }\n.fc .fc-scrollgrid-section > td {\n height: 1px; /* needs a height so inner div within grow. better than 0, for firefox */\n }\n.fc .fc-scrollgrid-section table {\n height: 1px;\n /* for most browsers, if a height isn't set on the table, can't do liquid-height within cells */\n /* serves as a min-height. harmless */\n }\n.fc .fc-scrollgrid-section-liquid > td {\n height: 100%; /* better than `auto`, for firefox */\n }\n.fc .fc-scrollgrid-section > * {\n border-top-width: 0;\n border-left-width: 0;\n }\n.fc .fc-scrollgrid-section-header > *,\n .fc .fc-scrollgrid-section-footer > * {\n border-bottom-width: 0;\n }\n.fc .fc-scrollgrid-section-body table,\n .fc .fc-scrollgrid-section-footer table {\n border-bottom-style: hidden; /* head keeps its bottom border tho */\n }\n.fc {\n\n /* stickiness */\n\n}\n.fc .fc-scrollgrid-section-sticky > * {\n background: var(--fc-page-bg-color);\n position: sticky;\n z-index: 3; /* TODO: var */\n /* TODO: box-shadow when sticking */\n }\n.fc .fc-scrollgrid-section-header.fc-scrollgrid-section-sticky > * {\n top: 0; /* because border-sharing causes a gap at the top */\n /* TODO: give safari -1. has bug */\n }\n.fc .fc-scrollgrid-section-footer.fc-scrollgrid-section-sticky > * {\n bottom: 0; /* known bug: bottom-stickiness doesn't work in safari */\n }\n.fc .fc-scrollgrid-sticky-shim { /* for horizontal scrollbar */\n height: 1px; /* needs height to create scrollbars */\n margin-bottom: -1px;\n }\n.fc-sticky { /* no .fc wrap because used as child of body */\n position: sticky;\n}\n.fc .fc-view-harness {\n flex-grow: 1; /* because this harness is WITHIN the .fc's flexbox */\n position: relative;\n }\n.fc {\n\n /* when the harness controls the height, make the view liquid */\n\n}\n.fc .fc-view-harness-active > .fc-view {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n.fc .fc-col-header-cell-cushion {\n display: inline-block; /* x-browser for when sticky (when multi-tier header) */\n padding: 2px 4px;\n }\n.fc .fc-bg-event,\n .fc .fc-non-business,\n .fc .fc-highlight {\n /* will always have a harness with position:relative/absolute, so absolutely expand */\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n }\n.fc .fc-non-business {\n background: var(--fc-non-business-color);\n }\n.fc .fc-bg-event {\n background: var(--fc-bg-event-color);\n opacity: var(--fc-bg-event-opacity)\n }\n.fc .fc-bg-event .fc-event-title {\n margin: .5em;\n font-size: var(--fc-small-font-size);\n font-style: italic;\n }\n.fc .fc-highlight {\n background: var(--fc-highlight-color);\n }\n.fc .fc-cell-shaded,\n .fc .fc-day-disabled {\n background: var(--fc-neutral-bg-color);\n }\n/* link resets */\n/* ---------------------------------------------------------------------------------------------------- */\na.fc-event,\na.fc-event:hover {\n text-decoration: none;\n}\n/* cursor */\n.fc-event[href],\n.fc-event.fc-event-draggable {\n cursor: pointer;\n}\n/* event text content */\n/* ---------------------------------------------------------------------------------------------------- */\n.fc-event .fc-event-main {\n position: relative;\n z-index: 2;\n }\n/* dragging */\n/* ---------------------------------------------------------------------------------------------------- */\n.fc-event-dragging:not(.fc-event-selected) { /* MOUSE */\n opacity: 0.75;\n }\n.fc-event-dragging.fc-event-selected { /* TOUCH */\n box-shadow: 0 2px 7px rgba(0, 0, 0, 0.3);\n }\n/* resizing */\n/* ---------------------------------------------------------------------------------------------------- */\n/* (subclasses should hone positioning for touch and non-touch) */\n.fc-event .fc-event-resizer {\n display: none;\n position: absolute;\n z-index: 4;\n }\n.fc-event:hover, /* MOUSE */\n.fc-event-selected { /* TOUCH */\n\n}\n.fc-event:hover .fc-event-resizer, .fc-event-selected .fc-event-resizer {\n display: block;\n }\n.fc-event-selected .fc-event-resizer {\n border-radius: calc(var(--fc-event-resizer-dot-total-width) / 2);\n border-width: var(--fc-event-resizer-dot-border-width);\n width: var(--fc-event-resizer-dot-total-width);\n height: var(--fc-event-resizer-dot-total-width);\n border-style: solid;\n border-color: inherit;\n background: var(--fc-page-bg-color)\n\n /* expand hit area */\n\n }\n.fc-event-selected .fc-event-resizer:before {\n content: '';\n position: absolute;\n top: -20px;\n left: -20px;\n right: -20px;\n bottom: -20px;\n }\n/* selecting (always TOUCH) */\n/* OR, focused by tab-index */\n/* (TODO: maybe not the best focus-styling for .fc-daygrid-dot-event) */\n/* ---------------------------------------------------------------------------------------------------- */\n.fc-event-selected,\n.fc-event:focus {\n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2)\n\n /* expand hit area (subclasses should expand) */\n\n}\n.fc-event-selected:before, .fc-event:focus:before {\n content: \"\";\n position: absolute;\n z-index: 3;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n }\n.fc-event-selected,\n.fc-event:focus {\n\n /* dimmer effect */\n\n}\n.fc-event-selected:after, .fc-event:focus:after {\n content: \"\";\n background: var(--fc-event-selected-overlay-color);\n position: absolute;\n z-index: 1;\n\n /* assume there's a border on all sides. overcome it. */\n /* sometimes there's NOT a border, in which case the dimmer will go over */\n /* an adjacent border, which looks fine. */\n top: -1px;\n left: -1px;\n right: -1px;\n bottom: -1px;\n }\n/*\nA HORIZONTAL event\n*/\n.fc-h-event { /* allowed to be top-level */\n display: block;\n border: 1px solid var(--fc-event-border-color);\n background-color: var(--fc-event-bg-color)\n\n}\n.fc-h-event .fc-event-main {\n color: var(--fc-event-text-color);\n }\n.fc-h-event .fc-event-main-frame {\n display: flex; /* for make fc-event-title-container expand */\n }\n.fc-h-event .fc-event-time {\n max-width: 100%; /* clip overflow on this element */\n overflow: hidden;\n }\n.fc-h-event .fc-event-title-container { /* serves as a container for the sticky cushion */\n flex-grow: 1;\n flex-shrink: 1;\n min-width: 0; /* important for allowing to shrink all the way */\n }\n.fc-h-event .fc-event-title {\n display: inline-block; /* need this to be sticky cross-browser */\n vertical-align: top; /* for not messing up line-height */\n left: 0; /* for sticky */\n right: 0; /* for sticky */\n max-width: 100%; /* clip overflow on this element */\n overflow: hidden;\n }\n.fc-h-event.fc-event-selected:before {\n /* expand hit area */\n top: -10px;\n bottom: -10px;\n }\n/* adjust border and border-radius (if there is any) for non-start/end */\n.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-start),\n.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-end) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n border-left-width: 0;\n}\n.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-end),\n.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-start) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n border-right-width: 0;\n}\n/* resizers */\n.fc-h-event:not(.fc-event-selected) .fc-event-resizer {\n top: 0;\n bottom: 0;\n width: var(--fc-event-resizer-thickness);\n}\n.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start,\n.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end {\n cursor: w-resize;\n left: calc(-0.5 * var(--fc-event-resizer-thickness));\n}\n.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end,\n.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start {\n cursor: e-resize;\n right: calc(-0.5 * var(--fc-event-resizer-thickness));\n}\n/* resizers for TOUCH */\n.fc-h-event.fc-event-selected .fc-event-resizer {\n top: 50%;\n margin-top: calc(-0.5 * var(--fc-event-resizer-dot-total-width));\n}\n.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-start,\n.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-end {\n left: calc(-0.5 * var(--fc-event-resizer-dot-total-width));\n}\n.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-end,\n.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-start {\n right: calc(-0.5 * var(--fc-event-resizer-dot-total-width));\n}\n.fc .fc-popover {\n position: absolute;\n z-index: 9999;\n box-shadow: 0 2px 6px rgba(0,0,0,.15);\n }\n.fc .fc-popover-header {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 3px 4px;\n }\n.fc .fc-popover-title {\n margin: 0 2px;\n }\n.fc .fc-popover-close {\n cursor: pointer;\n opacity: 0.65;\n font-size: 1.1em;\n }\n.fc-theme-standard .fc-popover {\n border: 1px solid var(--fc-border-color);\n background: var(--fc-page-bg-color);\n }\n.fc-theme-standard .fc-popover-header {\n background: var(--fc-neutral-bg-color);\n }\n";
10
+ internalCommon.injectStyles(css_248z);
11
+
12
+ const MINIMAL_RAW_EN_LOCALE = {
13
+ code: 'en',
14
+ week: {
15
+ dow: 0,
16
+ doy: 4, // 4 days need to be within the year to be considered the first week
17
+ },
18
+ direction: 'ltr',
19
+ buttonText: {
20
+ prev: 'prev',
21
+ next: 'next',
22
+ prevYear: 'prev year',
23
+ nextYear: 'next year',
24
+ year: 'year',
25
+ today: 'today',
26
+ month: 'month',
27
+ week: 'week',
28
+ day: 'day',
29
+ list: 'list',
30
+ },
31
+ weekText: 'W',
32
+ weekTextLong: 'Week',
33
+ closeHint: 'Close',
34
+ timeHint: 'Time',
35
+ eventHint: 'Event',
36
+ allDayText: 'all-day',
37
+ moreLinkText: 'more',
38
+ noEventsText: 'No events to display',
39
+ };
40
+ const RAW_EN_LOCALE = Object.assign(Object.assign({}, MINIMAL_RAW_EN_LOCALE), {
41
+ // Includes things we don't want other locales to inherit,
42
+ // things that derive from other translatable strings.
43
+ buttonHints: {
44
+ prev: 'Previous $0',
45
+ next: 'Next $0',
46
+ today(buttonText, unit) {
47
+ return (unit === 'day')
48
+ ? 'Today'
49
+ : `This ${buttonText}`;
50
+ },
51
+ }, viewHint: '$0 view', navLinkHint: 'Go to $0', moreLinkHint(eventCnt) {
52
+ return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`;
53
+ } });
54
+ function organizeRawLocales(explicitRawLocales) {
55
+ let defaultCode = explicitRawLocales.length > 0 ? explicitRawLocales[0].code : 'en';
56
+ let allRawLocales = internalCommon.globalLocales.concat(explicitRawLocales);
57
+ let rawLocaleMap = {
58
+ en: RAW_EN_LOCALE,
59
+ };
60
+ for (let rawLocale of allRawLocales) {
61
+ rawLocaleMap[rawLocale.code] = rawLocale;
62
+ }
63
+ return {
64
+ map: rawLocaleMap,
65
+ defaultCode,
66
+ };
67
+ }
68
+ function buildLocale(inputSingular, available) {
69
+ if (typeof inputSingular === 'object' && !Array.isArray(inputSingular)) {
70
+ return parseLocale(inputSingular.code, [inputSingular.code], inputSingular);
71
+ }
72
+ return queryLocale(inputSingular, available);
73
+ }
74
+ function queryLocale(codeArg, available) {
75
+ let codes = [].concat(codeArg || []); // will convert to array
76
+ let raw = queryRawLocale(codes, available) || RAW_EN_LOCALE;
77
+ return parseLocale(codeArg, codes, raw);
78
+ }
79
+ function queryRawLocale(codes, available) {
80
+ for (let i = 0; i < codes.length; i += 1) {
81
+ let parts = codes[i].toLocaleLowerCase().split('-');
82
+ for (let j = parts.length; j > 0; j -= 1) {
83
+ let simpleId = parts.slice(0, j).join('-');
84
+ if (available[simpleId]) {
85
+ return available[simpleId];
86
+ }
87
+ }
88
+ }
89
+ return null;
90
+ }
91
+ function parseLocale(codeArg, codes, raw) {
92
+ let merged = internalCommon.mergeProps([MINIMAL_RAW_EN_LOCALE, raw], ['buttonText']);
93
+ delete merged.code; // don't want this part of the options
94
+ let { week } = merged;
95
+ delete merged.week;
96
+ return {
97
+ codeArg,
98
+ codes,
99
+ week,
100
+ simpleNumberFormat: new Intl.NumberFormat(codeArg),
101
+ options: merged,
102
+ };
103
+ }
104
+
105
+ class StandardTheme extends internalCommon.Theme {
106
+ }
107
+ StandardTheme.prototype.classes = {
108
+ root: 'fc-theme-standard',
109
+ tableCellShaded: 'fc-cell-shaded',
110
+ buttonGroup: 'fc-button-group',
111
+ button: 'fc-button fc-button-primary',
112
+ buttonActive: 'fc-button-active',
113
+ };
114
+ StandardTheme.prototype.baseIconClass = 'fc-icon';
115
+ StandardTheme.prototype.iconClasses = {
116
+ close: 'fc-icon-x',
117
+ prev: 'fc-icon-chevron-left',
118
+ next: 'fc-icon-chevron-right',
119
+ prevYear: 'fc-icon-chevrons-left',
120
+ nextYear: 'fc-icon-chevrons-right',
121
+ };
122
+ StandardTheme.prototype.rtlIconClasses = {
123
+ prev: 'fc-icon-chevron-right',
124
+ next: 'fc-icon-chevron-left',
125
+ prevYear: 'fc-icon-chevrons-right',
126
+ nextYear: 'fc-icon-chevrons-left',
127
+ };
128
+ StandardTheme.prototype.iconOverrideOption = 'buttonIcons'; // TODO: make TS-friendly
129
+ StandardTheme.prototype.iconOverrideCustomButtonOption = 'icon';
130
+ StandardTheme.prototype.iconOverridePrefix = 'fc-icon-';
131
+
132
+ function compileViewDefs(defaultConfigs, overrideConfigs) {
133
+ let hash = {};
134
+ let viewType;
135
+ for (viewType in defaultConfigs) {
136
+ ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);
137
+ }
138
+ for (viewType in overrideConfigs) {
139
+ ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);
140
+ }
141
+ return hash;
142
+ }
143
+ function ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs) {
144
+ if (hash[viewType]) {
145
+ return hash[viewType];
146
+ }
147
+ let viewDef = buildViewDef(viewType, hash, defaultConfigs, overrideConfigs);
148
+ if (viewDef) {
149
+ hash[viewType] = viewDef;
150
+ }
151
+ return viewDef;
152
+ }
153
+ function buildViewDef(viewType, hash, defaultConfigs, overrideConfigs) {
154
+ let defaultConfig = defaultConfigs[viewType];
155
+ let overrideConfig = overrideConfigs[viewType];
156
+ let queryProp = (name) => ((defaultConfig && defaultConfig[name] !== null) ? defaultConfig[name] :
157
+ ((overrideConfig && overrideConfig[name] !== null) ? overrideConfig[name] : null));
158
+ let theComponent = queryProp('component');
159
+ let superType = queryProp('superType');
160
+ let superDef = null;
161
+ if (superType) {
162
+ if (superType === viewType) {
163
+ throw new Error('Can\'t have a custom view type that references itself');
164
+ }
165
+ superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs);
166
+ }
167
+ if (!theComponent && superDef) {
168
+ theComponent = superDef.component;
169
+ }
170
+ if (!theComponent) {
171
+ return null; // don't throw a warning, might be settings for a single-unit view
172
+ }
173
+ return {
174
+ type: viewType,
175
+ component: theComponent,
176
+ defaults: Object.assign(Object.assign({}, (superDef ? superDef.defaults : {})), (defaultConfig ? defaultConfig.rawOptions : {})),
177
+ overrides: Object.assign(Object.assign({}, (superDef ? superDef.overrides : {})), (overrideConfig ? overrideConfig.rawOptions : {})),
178
+ };
179
+ }
180
+
181
+ function parseViewConfigs(inputs) {
182
+ return internalCommon.mapHash(inputs, parseViewConfig);
183
+ }
184
+ function parseViewConfig(input) {
185
+ let rawOptions = typeof input === 'function' ?
186
+ { component: input } :
187
+ input;
188
+ let { component } = rawOptions;
189
+ if (rawOptions.content) {
190
+ component = createViewHookComponent(rawOptions);
191
+ // TODO: remove content/classNames/didMount/etc from options?
192
+ }
193
+ return {
194
+ superType: rawOptions.type,
195
+ component: component,
196
+ rawOptions, // includes type and component too :(
197
+ };
198
+ }
199
+ function createViewHookComponent(options) {
200
+ return (viewProps) => (preact.createElement(internalCommon.ViewContextType.Consumer, null, (context) => (preact.createElement(internalCommon.ContentContainer, { elTag: "div", elClasses: internalCommon.buildViewClassNames(context.viewSpec), renderProps: Object.assign(Object.assign({}, viewProps), { nextDayThreshold: context.options.nextDayThreshold }), generatorName: undefined, generator: options.content, classNameGenerator: options.classNames, didMount: options.didMount, willUnmount: options.willUnmount }))));
201
+ }
202
+
203
+ function buildViewSpecs(defaultInputs, optionOverrides, dynamicOptionOverrides, localeDefaults) {
204
+ let defaultConfigs = parseViewConfigs(defaultInputs);
205
+ let overrideConfigs = parseViewConfigs(optionOverrides.views);
206
+ let viewDefs = compileViewDefs(defaultConfigs, overrideConfigs);
207
+ return internalCommon.mapHash(viewDefs, (viewDef) => buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults));
208
+ }
209
+ function buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults) {
210
+ let durationInput = viewDef.overrides.duration ||
211
+ viewDef.defaults.duration ||
212
+ dynamicOptionOverrides.duration ||
213
+ optionOverrides.duration;
214
+ let duration = null;
215
+ let durationUnit = '';
216
+ let singleUnit = '';
217
+ let singleUnitOverrides = {};
218
+ if (durationInput) {
219
+ duration = createDurationCached(durationInput);
220
+ if (duration) { // valid?
221
+ let denom = internalCommon.greatestDurationDenominator(duration);
222
+ durationUnit = denom.unit;
223
+ if (denom.value === 1) {
224
+ singleUnit = durationUnit;
225
+ singleUnitOverrides = overrideConfigs[durationUnit] ? overrideConfigs[durationUnit].rawOptions : {};
226
+ }
227
+ }
228
+ }
229
+ let queryButtonText = (optionsSubset) => {
230
+ let buttonTextMap = optionsSubset.buttonText || {};
231
+ let buttonTextKey = viewDef.defaults.buttonTextKey;
232
+ if (buttonTextKey != null && buttonTextMap[buttonTextKey] != null) {
233
+ return buttonTextMap[buttonTextKey];
234
+ }
235
+ if (buttonTextMap[viewDef.type] != null) {
236
+ return buttonTextMap[viewDef.type];
237
+ }
238
+ if (buttonTextMap[singleUnit] != null) {
239
+ return buttonTextMap[singleUnit];
240
+ }
241
+ return null;
242
+ };
243
+ let queryButtonTitle = (optionsSubset) => {
244
+ let buttonHints = optionsSubset.buttonHints || {};
245
+ let buttonKey = viewDef.defaults.buttonTextKey; // use same key as text
246
+ if (buttonKey != null && buttonHints[buttonKey] != null) {
247
+ return buttonHints[buttonKey];
248
+ }
249
+ if (buttonHints[viewDef.type] != null) {
250
+ return buttonHints[viewDef.type];
251
+ }
252
+ if (buttonHints[singleUnit] != null) {
253
+ return buttonHints[singleUnit];
254
+ }
255
+ return null;
256
+ };
257
+ return {
258
+ type: viewDef.type,
259
+ component: viewDef.component,
260
+ duration,
261
+ durationUnit,
262
+ singleUnit,
263
+ optionDefaults: viewDef.defaults,
264
+ optionOverrides: Object.assign(Object.assign({}, singleUnitOverrides), viewDef.overrides),
265
+ buttonTextOverride: queryButtonText(dynamicOptionOverrides) ||
266
+ queryButtonText(optionOverrides) || // constructor-specified buttonText lookup hash takes precedence
267
+ viewDef.overrides.buttonText,
268
+ buttonTextDefault: queryButtonText(localeDefaults) ||
269
+ viewDef.defaults.buttonText ||
270
+ queryButtonText(internalCommon.BASE_OPTION_DEFAULTS) ||
271
+ viewDef.type,
272
+ // not DRY
273
+ buttonTitleOverride: queryButtonTitle(dynamicOptionOverrides) ||
274
+ queryButtonTitle(optionOverrides) ||
275
+ viewDef.overrides.buttonHint,
276
+ buttonTitleDefault: queryButtonTitle(localeDefaults) ||
277
+ viewDef.defaults.buttonHint ||
278
+ queryButtonTitle(internalCommon.BASE_OPTION_DEFAULTS),
279
+ // will eventually fall back to buttonText
280
+ };
281
+ }
282
+ // hack to get memoization working
283
+ let durationInputMap = {};
284
+ function createDurationCached(durationInput) {
285
+ let json = JSON.stringify(durationInput);
286
+ let res = durationInputMap[json];
287
+ if (res === undefined) {
288
+ res = internalCommon.createDuration(durationInput);
289
+ durationInputMap[json] = res;
290
+ }
291
+ return res;
292
+ }
293
+
294
+ function reduceViewType(viewType, action) {
295
+ switch (action.type) {
296
+ case 'CHANGE_VIEW_TYPE':
297
+ viewType = action.viewType;
298
+ }
299
+ return viewType;
300
+ }
301
+
302
+ function reduceDynamicOptionOverrides(dynamicOptionOverrides, action) {
303
+ switch (action.type) {
304
+ case 'SET_OPTION':
305
+ return Object.assign(Object.assign({}, dynamicOptionOverrides), { [action.optionName]: action.rawOptionValue });
306
+ default:
307
+ return dynamicOptionOverrides;
308
+ }
309
+ }
310
+
311
+ function reduceDateProfile(currentDateProfile, action, currentDate, dateProfileGenerator) {
312
+ let dp;
313
+ switch (action.type) {
314
+ case 'CHANGE_VIEW_TYPE':
315
+ return dateProfileGenerator.build(action.dateMarker || currentDate);
316
+ case 'CHANGE_DATE':
317
+ return dateProfileGenerator.build(action.dateMarker);
318
+ case 'PREV':
319
+ dp = dateProfileGenerator.buildPrev(currentDateProfile, currentDate);
320
+ if (dp.isValid) {
321
+ return dp;
322
+ }
323
+ break;
324
+ case 'NEXT':
325
+ dp = dateProfileGenerator.buildNext(currentDateProfile, currentDate);
326
+ if (dp.isValid) {
327
+ return dp;
328
+ }
329
+ break;
330
+ }
331
+ return currentDateProfile;
332
+ }
333
+
334
+ function reduceDateSelection(currentSelection, action) {
335
+ switch (action.type) {
336
+ case 'UNSELECT_DATES':
337
+ return null;
338
+ case 'SELECT_DATES':
339
+ return action.selection;
340
+ default:
341
+ return currentSelection;
342
+ }
343
+ }
344
+
345
+ function reduceSelectedEvent(currentInstanceId, action) {
346
+ switch (action.type) {
347
+ case 'UNSELECT_EVENT':
348
+ return '';
349
+ case 'SELECT_EVENT':
350
+ return action.eventInstanceId;
351
+ default:
352
+ return currentInstanceId;
353
+ }
354
+ }
355
+
356
+ function reduceEventDrag(currentDrag, action) {
357
+ let newDrag;
358
+ switch (action.type) {
359
+ case 'UNSET_EVENT_DRAG':
360
+ return null;
361
+ case 'SET_EVENT_DRAG':
362
+ newDrag = action.state;
363
+ return {
364
+ affectedEvents: newDrag.affectedEvents,
365
+ mutatedEvents: newDrag.mutatedEvents,
366
+ isEvent: newDrag.isEvent,
367
+ };
368
+ default:
369
+ return currentDrag;
370
+ }
371
+ }
372
+
373
+ function reduceEventResize(currentResize, action) {
374
+ let newResize;
375
+ switch (action.type) {
376
+ case 'UNSET_EVENT_RESIZE':
377
+ return null;
378
+ case 'SET_EVENT_RESIZE':
379
+ newResize = action.state;
380
+ return {
381
+ affectedEvents: newResize.affectedEvents,
382
+ mutatedEvents: newResize.mutatedEvents,
383
+ isEvent: newResize.isEvent,
384
+ };
385
+ default:
386
+ return currentResize;
387
+ }
388
+ }
389
+
390
+ function parseToolbars(calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {
391
+ let header = calendarOptions.headerToolbar ? parseToolbar(calendarOptions.headerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;
392
+ let footer = calendarOptions.footerToolbar ? parseToolbar(calendarOptions.footerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;
393
+ return { header, footer };
394
+ }
395
+ function parseToolbar(sectionStrHash, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {
396
+ let sectionWidgets = {};
397
+ let viewsWithButtons = [];
398
+ let hasTitle = false;
399
+ for (let sectionName in sectionStrHash) {
400
+ let sectionStr = sectionStrHash[sectionName];
401
+ let sectionRes = parseSection(sectionStr, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi);
402
+ sectionWidgets[sectionName] = sectionRes.widgets;
403
+ viewsWithButtons.push(...sectionRes.viewsWithButtons);
404
+ hasTitle = hasTitle || sectionRes.hasTitle;
405
+ }
406
+ return { sectionWidgets, viewsWithButtons, hasTitle };
407
+ }
408
+ /*
409
+ BAD: querying icons and text here. should be done at render time
410
+ */
411
+ function parseSection(sectionStr, calendarOptions, // defaults+overrides, then refined
412
+ calendarOptionOverrides, // overrides only!, unrefined :(
413
+ theme, viewSpecs, calendarApi) {
414
+ let isRtl = calendarOptions.direction === 'rtl';
415
+ let calendarCustomButtons = calendarOptions.customButtons || {};
416
+ let calendarButtonTextOverrides = calendarOptionOverrides.buttonText || {};
417
+ let calendarButtonText = calendarOptions.buttonText || {};
418
+ let calendarButtonHintOverrides = calendarOptionOverrides.buttonHints || {};
419
+ let calendarButtonHints = calendarOptions.buttonHints || {};
420
+ let sectionSubstrs = sectionStr ? sectionStr.split(' ') : [];
421
+ let viewsWithButtons = [];
422
+ let hasTitle = false;
423
+ let widgets = sectionSubstrs.map((buttonGroupStr) => (buttonGroupStr.split(',').map((buttonName) => {
424
+ if (buttonName === 'title') {
425
+ hasTitle = true;
426
+ return { buttonName };
427
+ }
428
+ let customButtonProps;
429
+ let viewSpec;
430
+ let buttonClick;
431
+ let buttonIcon; // only one of these will be set
432
+ let buttonText; // "
433
+ let buttonHint;
434
+ // ^ for the title="" attribute, for accessibility
435
+ if ((customButtonProps = calendarCustomButtons[buttonName])) {
436
+ buttonClick = (ev) => {
437
+ if (customButtonProps.click) {
438
+ customButtonProps.click.call(ev.target, ev, ev.target); // TODO: use Calendar this context?
439
+ }
440
+ };
441
+ (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) ||
442
+ (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
443
+ (buttonText = customButtonProps.text);
444
+ buttonHint = customButtonProps.hint || customButtonProps.text;
445
+ }
446
+ else if ((viewSpec = viewSpecs[buttonName])) {
447
+ viewsWithButtons.push(buttonName);
448
+ buttonClick = () => {
449
+ calendarApi.changeView(buttonName);
450
+ };
451
+ (buttonText = viewSpec.buttonTextOverride) ||
452
+ (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
453
+ (buttonText = viewSpec.buttonTextDefault);
454
+ let textFallback = viewSpec.buttonTextOverride ||
455
+ viewSpec.buttonTextDefault;
456
+ buttonHint = internalCommon.formatWithOrdinals(viewSpec.buttonTitleOverride ||
457
+ viewSpec.buttonTitleDefault ||
458
+ calendarOptions.viewHint, [textFallback, buttonName], // view-name = buttonName
459
+ textFallback);
460
+ }
461
+ else if (calendarApi[buttonName]) { // a calendarApi method
462
+ buttonClick = () => {
463
+ calendarApi[buttonName]();
464
+ };
465
+ (buttonText = calendarButtonTextOverrides[buttonName]) ||
466
+ (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
467
+ (buttonText = calendarButtonText[buttonName]); // everything else is considered default
468
+ if (buttonName === 'prevYear' || buttonName === 'nextYear') {
469
+ let prevOrNext = buttonName === 'prevYear' ? 'prev' : 'next';
470
+ buttonHint = internalCommon.formatWithOrdinals(calendarButtonHintOverrides[prevOrNext] ||
471
+ calendarButtonHints[prevOrNext], [
472
+ calendarButtonText.year || 'year',
473
+ 'year',
474
+ ], calendarButtonText[buttonName]);
475
+ }
476
+ else {
477
+ buttonHint = (navUnit) => internalCommon.formatWithOrdinals(calendarButtonHintOverrides[buttonName] ||
478
+ calendarButtonHints[buttonName], [
479
+ calendarButtonText[navUnit] || navUnit,
480
+ navUnit,
481
+ ], calendarButtonText[buttonName]);
482
+ }
483
+ }
484
+ return { buttonName, buttonClick, buttonIcon, buttonText, buttonHint };
485
+ })));
486
+ return { widgets, viewsWithButtons, hasTitle };
487
+ }
488
+
489
+ // always represents the current view. otherwise, it'd need to change value every time date changes
490
+ class ViewImpl {
491
+ constructor(type, getCurrentData, dateEnv) {
492
+ this.type = type;
493
+ this.getCurrentData = getCurrentData;
494
+ this.dateEnv = dateEnv;
495
+ }
496
+ get calendar() {
497
+ return this.getCurrentData().calendarApi;
498
+ }
499
+ get title() {
500
+ return this.getCurrentData().viewTitle;
501
+ }
502
+ get activeStart() {
503
+ return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.start);
504
+ }
505
+ get activeEnd() {
506
+ return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.end);
507
+ }
508
+ get currentStart() {
509
+ return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.start);
510
+ }
511
+ get currentEnd() {
512
+ return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.end);
513
+ }
514
+ getOption(name) {
515
+ return this.getCurrentData().options[name]; // are the view-specific options
516
+ }
517
+ }
518
+
519
+ class TaskRunner {
520
+ constructor(runTaskOption, drainedOption) {
521
+ this.runTaskOption = runTaskOption;
522
+ this.drainedOption = drainedOption;
523
+ this.queue = [];
524
+ this.delayedRunner = new internalCommon.DelayedRunner(this.drain.bind(this));
525
+ }
526
+ request(task, delay) {
527
+ this.queue.push(task);
528
+ this.delayedRunner.request(delay);
529
+ }
530
+ pause(scope) {
531
+ this.delayedRunner.pause(scope);
532
+ }
533
+ resume(scope, force) {
534
+ this.delayedRunner.resume(scope, force);
535
+ }
536
+ drain() {
537
+ let { queue } = this;
538
+ while (queue.length) {
539
+ let completedTasks = [];
540
+ let task;
541
+ while ((task = queue.shift())) {
542
+ this.runTask(task);
543
+ completedTasks.push(task);
544
+ }
545
+ this.drained(completedTasks);
546
+ } // keep going, in case new tasks were added in the drained handler
547
+ }
548
+ runTask(task) {
549
+ if (this.runTaskOption) {
550
+ this.runTaskOption(task);
551
+ }
552
+ }
553
+ drained(completedTasks) {
554
+ if (this.drainedOption) {
555
+ this.drainedOption(completedTasks);
556
+ }
557
+ }
558
+ }
559
+
560
+ // Computes what the title at the top of the calendarApi should be for this view
561
+ function buildTitle(dateProfile, viewOptions, dateEnv) {
562
+ let range;
563
+ // for views that span a large unit of time, show the proper interval, ignoring stray days before and after
564
+ if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) {
565
+ range = dateProfile.currentRange;
566
+ }
567
+ else { // for day units or smaller, use the actual day range
568
+ range = dateProfile.activeRange;
569
+ }
570
+ return dateEnv.formatRange(range.start, range.end, internalCommon.createFormatter(viewOptions.titleFormat || buildTitleFormat(dateProfile)), {
571
+ isEndExclusive: dateProfile.isRangeAllDay,
572
+ defaultSeparator: viewOptions.titleRangeSeparator,
573
+ });
574
+ }
575
+ // Generates the format string that should be used to generate the title for the current date range.
576
+ // Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`.
577
+ function buildTitleFormat(dateProfile) {
578
+ let { currentRangeUnit } = dateProfile;
579
+ if (currentRangeUnit === 'year') {
580
+ return { year: 'numeric' };
581
+ }
582
+ if (currentRangeUnit === 'month') {
583
+ return { year: 'numeric', month: 'long' }; // like "September 2014"
584
+ }
585
+ let days = internalCommon.diffWholeDays(dateProfile.currentRange.start, dateProfile.currentRange.end);
586
+ if (days !== null && days > 1) {
587
+ // multi-day range. shorter, like "Sep 9 - 10 2014"
588
+ return { year: 'numeric', month: 'short', day: 'numeric' };
589
+ }
590
+ // one day. longer, like "September 9 2014"
591
+ return { year: 'numeric', month: 'long', day: 'numeric' };
592
+ }
593
+
594
+ // in future refactor, do the redux-style function(state=initial) for initial-state
595
+ // also, whatever is happening in constructor, have it happen in action queue too
596
+ class CalendarDataManager {
597
+ constructor(props) {
598
+ this.computeOptionsData = internalCommon.memoize(this._computeOptionsData);
599
+ this.computeCurrentViewData = internalCommon.memoize(this._computeCurrentViewData);
600
+ this.organizeRawLocales = internalCommon.memoize(organizeRawLocales);
601
+ this.buildLocale = internalCommon.memoize(buildLocale);
602
+ this.buildPluginHooks = internalCommon.buildBuildPluginHooks();
603
+ this.buildDateEnv = internalCommon.memoize(buildDateEnv$1);
604
+ this.buildTheme = internalCommon.memoize(buildTheme);
605
+ this.parseToolbars = internalCommon.memoize(parseToolbars);
606
+ this.buildViewSpecs = internalCommon.memoize(buildViewSpecs);
607
+ this.buildDateProfileGenerator = internalCommon.memoizeObjArg(buildDateProfileGenerator);
608
+ this.buildViewApi = internalCommon.memoize(buildViewApi);
609
+ this.buildViewUiProps = internalCommon.memoizeObjArg(buildViewUiProps);
610
+ this.buildEventUiBySource = internalCommon.memoize(buildEventUiBySource, internalCommon.isPropsEqual);
611
+ this.buildEventUiBases = internalCommon.memoize(buildEventUiBases);
612
+ this.parseContextBusinessHours = internalCommon.memoizeObjArg(parseContextBusinessHours);
613
+ this.buildTitle = internalCommon.memoize(buildTitle);
614
+ this.emitter = new internalCommon.Emitter();
615
+ this.actionRunner = new TaskRunner(this._handleAction.bind(this), this.updateData.bind(this));
616
+ this.currentCalendarOptionsInput = {};
617
+ this.currentCalendarOptionsRefined = {};
618
+ this.currentViewOptionsInput = {};
619
+ this.currentViewOptionsRefined = {};
620
+ this.currentCalendarOptionsRefiners = {};
621
+ this.getCurrentData = () => this.data;
622
+ this.dispatch = (action) => {
623
+ this.actionRunner.request(action); // protects against recursive calls to _handleAction
624
+ };
625
+ this.props = props;
626
+ this.actionRunner.pause();
627
+ let dynamicOptionOverrides = {};
628
+ let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
629
+ let currentViewType = optionsData.calendarOptions.initialView || optionsData.pluginHooks.initialView;
630
+ let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
631
+ // wire things up
632
+ // TODO: not DRY
633
+ props.calendarApi.currentDataManager = this;
634
+ this.emitter.setThisContext(props.calendarApi);
635
+ this.emitter.setOptions(currentViewData.options);
636
+ let currentDate = internalCommon.getInitialDate(optionsData.calendarOptions, optionsData.dateEnv);
637
+ let dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
638
+ if (!internalCommon.rangeContainsMarker(dateProfile.activeRange, currentDate)) {
639
+ currentDate = dateProfile.currentRange.start;
640
+ }
641
+ let calendarContext = {
642
+ dateEnv: optionsData.dateEnv,
643
+ options: optionsData.calendarOptions,
644
+ pluginHooks: optionsData.pluginHooks,
645
+ calendarApi: props.calendarApi,
646
+ dispatch: this.dispatch,
647
+ emitter: this.emitter,
648
+ getCurrentData: this.getCurrentData,
649
+ };
650
+ // needs to be after setThisContext
651
+ for (let callback of optionsData.pluginHooks.contextInit) {
652
+ callback(calendarContext);
653
+ }
654
+ // NOT DRY
655
+ let eventSources = internalCommon.initEventSources(optionsData.calendarOptions, dateProfile, calendarContext);
656
+ let initialState = {
657
+ dynamicOptionOverrides,
658
+ currentViewType,
659
+ currentDate,
660
+ dateProfile,
661
+ businessHours: this.parseContextBusinessHours(calendarContext),
662
+ eventSources,
663
+ eventUiBases: {},
664
+ eventStore: internalCommon.createEmptyEventStore(),
665
+ renderableEventStore: internalCommon.createEmptyEventStore(),
666
+ dateSelection: null,
667
+ eventSelection: '',
668
+ eventDrag: null,
669
+ eventResize: null,
670
+ selectionConfig: this.buildViewUiProps(calendarContext).selectionConfig,
671
+ };
672
+ let contextAndState = Object.assign(Object.assign({}, calendarContext), initialState);
673
+ for (let reducer of optionsData.pluginHooks.reducers) {
674
+ Object.assign(initialState, reducer(null, null, contextAndState));
675
+ }
676
+ if (computeIsLoading(initialState, calendarContext)) {
677
+ this.emitter.trigger('loading', true); // NOT DRY
678
+ }
679
+ this.state = initialState;
680
+ this.updateData();
681
+ this.actionRunner.resume();
682
+ }
683
+ resetOptions(optionOverrides, append) {
684
+ let { props } = this;
685
+ props.optionOverrides = append
686
+ ? Object.assign(Object.assign({}, props.optionOverrides), optionOverrides) : optionOverrides;
687
+ this.actionRunner.request({
688
+ type: 'NOTHING',
689
+ });
690
+ }
691
+ _handleAction(action) {
692
+ let { props, state, emitter } = this;
693
+ let dynamicOptionOverrides = reduceDynamicOptionOverrides(state.dynamicOptionOverrides, action);
694
+ let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
695
+ let currentViewType = reduceViewType(state.currentViewType, action);
696
+ let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
697
+ // wire things up
698
+ // TODO: not DRY
699
+ props.calendarApi.currentDataManager = this;
700
+ emitter.setThisContext(props.calendarApi);
701
+ emitter.setOptions(currentViewData.options);
702
+ let calendarContext = {
703
+ dateEnv: optionsData.dateEnv,
704
+ options: optionsData.calendarOptions,
705
+ pluginHooks: optionsData.pluginHooks,
706
+ calendarApi: props.calendarApi,
707
+ dispatch: this.dispatch,
708
+ emitter,
709
+ getCurrentData: this.getCurrentData,
710
+ };
711
+ let { currentDate, dateProfile } = state;
712
+ if (this.data && this.data.dateProfileGenerator !== currentViewData.dateProfileGenerator) { // hack
713
+ dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
714
+ }
715
+ currentDate = internalCommon.reduceCurrentDate(currentDate, action);
716
+ dateProfile = reduceDateProfile(dateProfile, action, currentDate, currentViewData.dateProfileGenerator);
717
+ if (action.type === 'PREV' || // TODO: move this logic into DateProfileGenerator
718
+ action.type === 'NEXT' || // "
719
+ !internalCommon.rangeContainsMarker(dateProfile.currentRange, currentDate)) {
720
+ currentDate = dateProfile.currentRange.start;
721
+ }
722
+ let eventSources = internalCommon.reduceEventSources(state.eventSources, action, dateProfile, calendarContext);
723
+ let eventStore = internalCommon.reduceEventStore(state.eventStore, action, eventSources, dateProfile, calendarContext);
724
+ let isEventsLoading = internalCommon.computeEventSourcesLoading(eventSources); // BAD. also called in this func in computeIsLoading
725
+ let renderableEventStore = (isEventsLoading && !currentViewData.options.progressiveEventRendering) ?
726
+ (state.renderableEventStore || eventStore) : // try from previous state
727
+ eventStore;
728
+ let { eventUiSingleBase, selectionConfig } = this.buildViewUiProps(calendarContext); // will memoize obj
729
+ let eventUiBySource = this.buildEventUiBySource(eventSources);
730
+ let eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource);
731
+ let newState = {
732
+ dynamicOptionOverrides,
733
+ currentViewType,
734
+ currentDate,
735
+ dateProfile,
736
+ eventSources,
737
+ eventStore,
738
+ renderableEventStore,
739
+ selectionConfig,
740
+ eventUiBases,
741
+ businessHours: this.parseContextBusinessHours(calendarContext),
742
+ dateSelection: reduceDateSelection(state.dateSelection, action),
743
+ eventSelection: reduceSelectedEvent(state.eventSelection, action),
744
+ eventDrag: reduceEventDrag(state.eventDrag, action),
745
+ eventResize: reduceEventResize(state.eventResize, action),
746
+ };
747
+ let contextAndState = Object.assign(Object.assign({}, calendarContext), newState);
748
+ for (let reducer of optionsData.pluginHooks.reducers) {
749
+ Object.assign(newState, reducer(state, action, contextAndState)); // give the OLD state, for old value
750
+ }
751
+ let wasLoading = computeIsLoading(state, calendarContext);
752
+ let isLoading = computeIsLoading(newState, calendarContext);
753
+ // TODO: use propSetHandlers in plugin system
754
+ if (!wasLoading && isLoading) {
755
+ emitter.trigger('loading', true);
756
+ }
757
+ else if (wasLoading && !isLoading) {
758
+ emitter.trigger('loading', false);
759
+ }
760
+ this.state = newState;
761
+ if (props.onAction) {
762
+ props.onAction(action);
763
+ }
764
+ }
765
+ updateData() {
766
+ let { props, state } = this;
767
+ let oldData = this.data;
768
+ let optionsData = this.computeOptionsData(props.optionOverrides, state.dynamicOptionOverrides, props.calendarApi);
769
+ let currentViewData = this.computeCurrentViewData(state.currentViewType, optionsData, props.optionOverrides, state.dynamicOptionOverrides);
770
+ let data = this.data = Object.assign(Object.assign(Object.assign({ viewTitle: this.buildTitle(state.dateProfile, currentViewData.options, optionsData.dateEnv), calendarApi: props.calendarApi, dispatch: this.dispatch, emitter: this.emitter, getCurrentData: this.getCurrentData }, optionsData), currentViewData), state);
771
+ let changeHandlers = optionsData.pluginHooks.optionChangeHandlers;
772
+ let oldCalendarOptions = oldData && oldData.calendarOptions;
773
+ let newCalendarOptions = optionsData.calendarOptions;
774
+ if (oldCalendarOptions && oldCalendarOptions !== newCalendarOptions) {
775
+ if (oldCalendarOptions.timeZone !== newCalendarOptions.timeZone) {
776
+ // hack
777
+ state.eventSources = data.eventSources = internalCommon.reduceEventSourcesNewTimeZone(data.eventSources, state.dateProfile, data);
778
+ state.eventStore = data.eventStore = internalCommon.rezoneEventStoreDates(data.eventStore, oldData.dateEnv, data.dateEnv);
779
+ }
780
+ for (let optionName in changeHandlers) {
781
+ if (oldCalendarOptions[optionName] !== newCalendarOptions[optionName]) {
782
+ changeHandlers[optionName](newCalendarOptions[optionName], data);
783
+ }
784
+ }
785
+ }
786
+ if (props.onData) {
787
+ props.onData(data);
788
+ }
789
+ }
790
+ _computeOptionsData(optionOverrides, dynamicOptionOverrides, calendarApi) {
791
+ // TODO: blacklist options that are handled by optionChangeHandlers
792
+ let { refinedOptions, pluginHooks, localeDefaults, availableLocaleData, extra, } = this.processRawCalendarOptions(optionOverrides, dynamicOptionOverrides);
793
+ warnUnknownOptions(extra);
794
+ let dateEnv = this.buildDateEnv(refinedOptions.timeZone, refinedOptions.locale, refinedOptions.weekNumberCalculation, refinedOptions.firstDay, refinedOptions.weekText, pluginHooks, availableLocaleData, refinedOptions.defaultRangeSeparator);
795
+ let viewSpecs = this.buildViewSpecs(pluginHooks.views, optionOverrides, dynamicOptionOverrides, localeDefaults);
796
+ let theme = this.buildTheme(refinedOptions, pluginHooks);
797
+ let toolbarConfig = this.parseToolbars(refinedOptions, optionOverrides, theme, viewSpecs, calendarApi);
798
+ return {
799
+ calendarOptions: refinedOptions,
800
+ pluginHooks,
801
+ dateEnv,
802
+ viewSpecs,
803
+ theme,
804
+ toolbarConfig,
805
+ localeDefaults,
806
+ availableRawLocales: availableLocaleData.map,
807
+ };
808
+ }
809
+ // always called from behind a memoizer
810
+ processRawCalendarOptions(optionOverrides, dynamicOptionOverrides) {
811
+ let { locales, locale } = internalCommon.mergeRawOptions([
812
+ internalCommon.BASE_OPTION_DEFAULTS,
813
+ optionOverrides,
814
+ dynamicOptionOverrides,
815
+ ]);
816
+ let availableLocaleData = this.organizeRawLocales(locales);
817
+ let availableRawLocales = availableLocaleData.map;
818
+ let localeDefaults = this.buildLocale(locale || availableLocaleData.defaultCode, availableRawLocales).options;
819
+ let pluginHooks = this.buildPluginHooks(optionOverrides.plugins || [], internalCommon.globalPlugins);
820
+ let refiners = this.currentCalendarOptionsRefiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, internalCommon.BASE_OPTION_REFINERS), internalCommon.CALENDAR_LISTENER_REFINERS), internalCommon.CALENDAR_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
821
+ let extra = {};
822
+ let raw = internalCommon.mergeRawOptions([
823
+ internalCommon.BASE_OPTION_DEFAULTS,
824
+ localeDefaults,
825
+ optionOverrides,
826
+ dynamicOptionOverrides,
827
+ ]);
828
+ let refined = {};
829
+ let currentRaw = this.currentCalendarOptionsInput;
830
+ let currentRefined = this.currentCalendarOptionsRefined;
831
+ let anyChanges = false;
832
+ for (let optionName in raw) {
833
+ if (optionName !== 'plugins') { // because plugins is special-cased
834
+ if (raw[optionName] === currentRaw[optionName] ||
835
+ (internalCommon.COMPLEX_OPTION_COMPARATORS[optionName] &&
836
+ (optionName in currentRaw) &&
837
+ internalCommon.COMPLEX_OPTION_COMPARATORS[optionName](currentRaw[optionName], raw[optionName]))) {
838
+ refined[optionName] = currentRefined[optionName];
839
+ }
840
+ else if (refiners[optionName]) {
841
+ refined[optionName] = refiners[optionName](raw[optionName]);
842
+ anyChanges = true;
843
+ }
844
+ else {
845
+ extra[optionName] = currentRaw[optionName];
846
+ }
847
+ }
848
+ }
849
+ if (anyChanges) {
850
+ this.currentCalendarOptionsInput = raw;
851
+ this.currentCalendarOptionsRefined = refined;
852
+ }
853
+ return {
854
+ rawOptions: this.currentCalendarOptionsInput,
855
+ refinedOptions: this.currentCalendarOptionsRefined,
856
+ pluginHooks,
857
+ availableLocaleData,
858
+ localeDefaults,
859
+ extra,
860
+ };
861
+ }
862
+ _computeCurrentViewData(viewType, optionsData, optionOverrides, dynamicOptionOverrides) {
863
+ let viewSpec = optionsData.viewSpecs[viewType];
864
+ if (!viewSpec) {
865
+ throw new Error(`viewType "${viewType}" is not available. Please make sure you've loaded all neccessary plugins`);
866
+ }
867
+ let { refinedOptions, extra } = this.processRawViewOptions(viewSpec, optionsData.pluginHooks, optionsData.localeDefaults, optionOverrides, dynamicOptionOverrides);
868
+ warnUnknownOptions(extra);
869
+ let dateProfileGenerator = this.buildDateProfileGenerator({
870
+ dateProfileGeneratorClass: viewSpec.optionDefaults.dateProfileGeneratorClass,
871
+ duration: viewSpec.duration,
872
+ durationUnit: viewSpec.durationUnit,
873
+ usesMinMaxTime: viewSpec.optionDefaults.usesMinMaxTime,
874
+ dateEnv: optionsData.dateEnv,
875
+ calendarApi: this.props.calendarApi,
876
+ slotMinTime: refinedOptions.slotMinTime,
877
+ slotMaxTime: refinedOptions.slotMaxTime,
878
+ showNonCurrentDates: refinedOptions.showNonCurrentDates,
879
+ dayCount: refinedOptions.dayCount,
880
+ dateAlignment: refinedOptions.dateAlignment,
881
+ dateIncrement: refinedOptions.dateIncrement,
882
+ hiddenDays: refinedOptions.hiddenDays,
883
+ weekends: refinedOptions.weekends,
884
+ nowInput: refinedOptions.now,
885
+ validRangeInput: refinedOptions.validRange,
886
+ visibleRangeInput: refinedOptions.visibleRange,
887
+ monthMode: refinedOptions.monthMode,
888
+ fixedWeekCount: refinedOptions.fixedWeekCount,
889
+ });
890
+ let viewApi = this.buildViewApi(viewType, this.getCurrentData, optionsData.dateEnv);
891
+ return { viewSpec, options: refinedOptions, dateProfileGenerator, viewApi };
892
+ }
893
+ processRawViewOptions(viewSpec, pluginHooks, localeDefaults, optionOverrides, dynamicOptionOverrides) {
894
+ let raw = internalCommon.mergeRawOptions([
895
+ internalCommon.BASE_OPTION_DEFAULTS,
896
+ viewSpec.optionDefaults,
897
+ localeDefaults,
898
+ optionOverrides,
899
+ viewSpec.optionOverrides,
900
+ dynamicOptionOverrides,
901
+ ]);
902
+ let refiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, internalCommon.BASE_OPTION_REFINERS), internalCommon.CALENDAR_LISTENER_REFINERS), internalCommon.CALENDAR_OPTION_REFINERS), internalCommon.VIEW_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
903
+ let refined = {};
904
+ let currentRaw = this.currentViewOptionsInput;
905
+ let currentRefined = this.currentViewOptionsRefined;
906
+ let anyChanges = false;
907
+ let extra = {};
908
+ for (let optionName in raw) {
909
+ if (raw[optionName] === currentRaw[optionName] ||
910
+ (internalCommon.COMPLEX_OPTION_COMPARATORS[optionName] &&
911
+ internalCommon.COMPLEX_OPTION_COMPARATORS[optionName](raw[optionName], currentRaw[optionName]))) {
912
+ refined[optionName] = currentRefined[optionName];
913
+ }
914
+ else {
915
+ if (raw[optionName] === this.currentCalendarOptionsInput[optionName] ||
916
+ (internalCommon.COMPLEX_OPTION_COMPARATORS[optionName] &&
917
+ internalCommon.COMPLEX_OPTION_COMPARATORS[optionName](raw[optionName], this.currentCalendarOptionsInput[optionName]))) {
918
+ if (optionName in this.currentCalendarOptionsRefined) { // might be an "extra" prop
919
+ refined[optionName] = this.currentCalendarOptionsRefined[optionName];
920
+ }
921
+ }
922
+ else if (refiners[optionName]) {
923
+ refined[optionName] = refiners[optionName](raw[optionName]);
924
+ }
925
+ else {
926
+ extra[optionName] = raw[optionName];
927
+ }
928
+ anyChanges = true;
929
+ }
930
+ }
931
+ if (anyChanges) {
932
+ this.currentViewOptionsInput = raw;
933
+ this.currentViewOptionsRefined = refined;
934
+ }
935
+ return {
936
+ rawOptions: this.currentViewOptionsInput,
937
+ refinedOptions: this.currentViewOptionsRefined,
938
+ extra,
939
+ };
940
+ }
941
+ }
942
+ function buildDateEnv$1(timeZone, explicitLocale, weekNumberCalculation, firstDay, weekText, pluginHooks, availableLocaleData, defaultSeparator) {
943
+ let locale = buildLocale(explicitLocale || availableLocaleData.defaultCode, availableLocaleData.map);
944
+ return new internalCommon.DateEnv({
945
+ calendarSystem: 'gregory',
946
+ timeZone,
947
+ namedTimeZoneImpl: pluginHooks.namedTimeZonedImpl,
948
+ locale,
949
+ weekNumberCalculation,
950
+ firstDay,
951
+ weekText,
952
+ cmdFormatter: pluginHooks.cmdFormatter,
953
+ defaultSeparator,
954
+ });
955
+ }
956
+ function buildTheme(options, pluginHooks) {
957
+ let ThemeClass = pluginHooks.themeClasses[options.themeSystem] || StandardTheme;
958
+ return new ThemeClass(options);
959
+ }
960
+ function buildDateProfileGenerator(props) {
961
+ let DateProfileGeneratorClass = props.dateProfileGeneratorClass || internalCommon.DateProfileGenerator;
962
+ return new DateProfileGeneratorClass(props);
963
+ }
964
+ function buildViewApi(type, getCurrentData, dateEnv) {
965
+ return new ViewImpl(type, getCurrentData, dateEnv);
966
+ }
967
+ function buildEventUiBySource(eventSources) {
968
+ return internalCommon.mapHash(eventSources, (eventSource) => eventSource.ui);
969
+ }
970
+ function buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) {
971
+ let eventUiBases = { '': eventUiSingleBase };
972
+ for (let defId in eventDefs) {
973
+ let def = eventDefs[defId];
974
+ if (def.sourceId && eventUiBySource[def.sourceId]) {
975
+ eventUiBases[defId] = eventUiBySource[def.sourceId];
976
+ }
977
+ }
978
+ return eventUiBases;
979
+ }
980
+ function buildViewUiProps(calendarContext) {
981
+ let { options } = calendarContext;
982
+ return {
983
+ eventUiSingleBase: internalCommon.createEventUi({
984
+ display: options.eventDisplay,
985
+ editable: options.editable,
986
+ startEditable: options.eventStartEditable,
987
+ durationEditable: options.eventDurationEditable,
988
+ constraint: options.eventConstraint,
989
+ overlap: typeof options.eventOverlap === 'boolean' ? options.eventOverlap : undefined,
990
+ allow: options.eventAllow,
991
+ backgroundColor: options.eventBackgroundColor,
992
+ borderColor: options.eventBorderColor,
993
+ textColor: options.eventTextColor,
994
+ color: options.eventColor,
995
+ // classNames: options.eventClassNames // render hook will handle this
996
+ }, calendarContext),
997
+ selectionConfig: internalCommon.createEventUi({
998
+ constraint: options.selectConstraint,
999
+ overlap: typeof options.selectOverlap === 'boolean' ? options.selectOverlap : undefined,
1000
+ allow: options.selectAllow,
1001
+ }, calendarContext),
1002
+ };
1003
+ }
1004
+ function computeIsLoading(state, context) {
1005
+ for (let isLoadingFunc of context.pluginHooks.isLoadingFuncs) {
1006
+ if (isLoadingFunc(state)) {
1007
+ return true;
1008
+ }
1009
+ }
1010
+ return false;
1011
+ }
1012
+ function parseContextBusinessHours(calendarContext) {
1013
+ return internalCommon.parseBusinessHours(calendarContext.options.businessHours, calendarContext);
1014
+ }
1015
+ function warnUnknownOptions(options, viewName) {
1016
+ for (let optionName in options) {
1017
+ console.warn(`Unknown option '${optionName}'` +
1018
+ (viewName ? ` for view '${viewName}'` : ''));
1019
+ }
1020
+ }
1021
+
1022
+ class ToolbarSection extends internalCommon.BaseComponent {
1023
+ render() {
1024
+ let children = this.props.widgetGroups.map((widgetGroup) => this.renderWidgetGroup(widgetGroup));
1025
+ return preact.createElement('div', { className: 'fc-toolbar-chunk' }, ...children);
1026
+ }
1027
+ renderWidgetGroup(widgetGroup) {
1028
+ let { props } = this;
1029
+ let { theme } = this.context;
1030
+ let children = [];
1031
+ let isOnlyButtons = true;
1032
+ for (let widget of widgetGroup) {
1033
+ let { buttonName, buttonClick, buttonText, buttonIcon, buttonHint } = widget;
1034
+ if (buttonName === 'title') {
1035
+ isOnlyButtons = false;
1036
+ children.push(preact.createElement("h2", { className: "fc-toolbar-title", id: props.titleId }, props.title));
1037
+ }
1038
+ else {
1039
+ let isPressed = buttonName === props.activeButton;
1040
+ let isDisabled = (!props.isTodayEnabled && buttonName === 'today') ||
1041
+ (!props.isPrevEnabled && buttonName === 'prev') ||
1042
+ (!props.isNextEnabled && buttonName === 'next');
1043
+ let buttonClasses = [`fc-${buttonName}-button`, theme.getClass('button')];
1044
+ if (isPressed) {
1045
+ buttonClasses.push(theme.getClass('buttonActive'));
1046
+ }
1047
+ children.push(preact.createElement("button", { type: "button", title: typeof buttonHint === 'function' ? buttonHint(props.navUnit) : buttonHint, disabled: isDisabled, "aria-pressed": isPressed, className: buttonClasses.join(' '), onClick: buttonClick }, buttonText || (buttonIcon ? preact.createElement("span", { className: buttonIcon }) : '')));
1048
+ }
1049
+ }
1050
+ if (children.length > 1) {
1051
+ let groupClassName = (isOnlyButtons && theme.getClass('buttonGroup')) || '';
1052
+ return preact.createElement('div', { className: groupClassName }, ...children);
1053
+ }
1054
+ return children[0];
1055
+ }
1056
+ }
1057
+
1058
+ class Toolbar extends internalCommon.BaseComponent {
1059
+ render() {
1060
+ let { model, extraClassName } = this.props;
1061
+ let forceLtr = false;
1062
+ let startContent;
1063
+ let endContent;
1064
+ let sectionWidgets = model.sectionWidgets;
1065
+ let centerContent = sectionWidgets.center;
1066
+ if (sectionWidgets.left) {
1067
+ forceLtr = true;
1068
+ startContent = sectionWidgets.left;
1069
+ }
1070
+ else {
1071
+ startContent = sectionWidgets.start;
1072
+ }
1073
+ if (sectionWidgets.right) {
1074
+ forceLtr = true;
1075
+ endContent = sectionWidgets.right;
1076
+ }
1077
+ else {
1078
+ endContent = sectionWidgets.end;
1079
+ }
1080
+ let classNames = [
1081
+ extraClassName || '',
1082
+ 'fc-toolbar',
1083
+ forceLtr ? 'fc-toolbar-ltr' : '',
1084
+ ];
1085
+ return (preact.createElement("div", { className: classNames.join(' ') },
1086
+ this.renderSection('start', startContent || []),
1087
+ this.renderSection('center', centerContent || []),
1088
+ this.renderSection('end', endContent || [])));
1089
+ }
1090
+ renderSection(key, widgetGroups) {
1091
+ let { props } = this;
1092
+ return (preact.createElement(ToolbarSection, { key: key, widgetGroups: widgetGroups, title: props.title, navUnit: props.navUnit, activeButton: props.activeButton, isTodayEnabled: props.isTodayEnabled, isPrevEnabled: props.isPrevEnabled, isNextEnabled: props.isNextEnabled, titleId: props.titleId }));
1093
+ }
1094
+ }
1095
+
1096
+ // TODO: do function component?
1097
+ class ViewContainer extends internalCommon.BaseComponent {
1098
+ constructor() {
1099
+ super(...arguments);
1100
+ this.state = {
1101
+ availableWidth: null,
1102
+ };
1103
+ this.handleEl = (el) => {
1104
+ this.el = el;
1105
+ internalCommon.setRef(this.props.elRef, el);
1106
+ this.updateAvailableWidth();
1107
+ };
1108
+ this.handleResize = () => {
1109
+ this.updateAvailableWidth();
1110
+ };
1111
+ }
1112
+ render() {
1113
+ let { props, state } = this;
1114
+ let { aspectRatio } = props;
1115
+ let classNames = [
1116
+ 'fc-view-harness',
1117
+ (aspectRatio || props.liquid || props.height)
1118
+ ? 'fc-view-harness-active' // harness controls the height
1119
+ : 'fc-view-harness-passive', // let the view do the height
1120
+ ];
1121
+ let height = '';
1122
+ let paddingBottom = '';
1123
+ if (aspectRatio) {
1124
+ if (state.availableWidth !== null) {
1125
+ height = state.availableWidth / aspectRatio;
1126
+ }
1127
+ else {
1128
+ // while waiting to know availableWidth, we can't set height to *zero*
1129
+ // because will cause lots of unnecessary scrollbars within scrollgrid.
1130
+ // BETTER: don't start rendering ANYTHING yet until we know container width
1131
+ // NOTE: why not always use paddingBottom? Causes height oscillation (issue 5606)
1132
+ paddingBottom = `${(1 / aspectRatio) * 100}%`;
1133
+ }
1134
+ }
1135
+ else {
1136
+ height = props.height || '';
1137
+ }
1138
+ return (preact.createElement("div", { "aria-labelledby": props.labeledById, ref: this.handleEl, className: classNames.join(' '), style: { height, paddingBottom } }, props.children));
1139
+ }
1140
+ componentDidMount() {
1141
+ this.context.addResizeHandler(this.handleResize);
1142
+ }
1143
+ componentWillUnmount() {
1144
+ this.context.removeResizeHandler(this.handleResize);
1145
+ }
1146
+ updateAvailableWidth() {
1147
+ if (this.el && // needed. but why?
1148
+ this.props.aspectRatio // aspectRatio is the only height setting that needs availableWidth
1149
+ ) {
1150
+ this.setState({ availableWidth: this.el.offsetWidth });
1151
+ }
1152
+ }
1153
+ }
1154
+
1155
+ /*
1156
+ Detects when the user clicks on an event within a DateComponent
1157
+ */
1158
+ class EventClicking extends internalCommon.Interaction {
1159
+ constructor(settings) {
1160
+ super(settings);
1161
+ this.handleSegClick = (ev, segEl) => {
1162
+ let { component } = this;
1163
+ let { context } = component;
1164
+ let seg = internalCommon.getElSeg(segEl);
1165
+ if (seg && // might be the <div> surrounding the more link
1166
+ component.isValidSegDownEl(ev.target)) {
1167
+ // our way to simulate a link click for elements that can't be <a> tags
1168
+ // grab before trigger fired in case trigger trashes DOM thru rerendering
1169
+ let hasUrlContainer = internalCommon.elementClosest(ev.target, '.fc-event-forced-url');
1170
+ let url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : '';
1171
+ context.emitter.trigger('eventClick', {
1172
+ el: segEl,
1173
+ event: new internalCommon.EventImpl(component.context, seg.eventRange.def, seg.eventRange.instance),
1174
+ jsEvent: ev,
1175
+ view: context.viewApi,
1176
+ });
1177
+ if (url && !ev.defaultPrevented) {
1178
+ window.location.href = url;
1179
+ }
1180
+ }
1181
+ };
1182
+ this.destroy = internalCommon.listenBySelector(settings.el, 'click', '.fc-event', // on both fg and bg events
1183
+ this.handleSegClick);
1184
+ }
1185
+ }
1186
+
1187
+ /*
1188
+ Triggers events and adds/removes core classNames when the user's pointer
1189
+ enters/leaves event-elements of a component.
1190
+ */
1191
+ class EventHovering extends internalCommon.Interaction {
1192
+ constructor(settings) {
1193
+ super(settings);
1194
+ // for simulating an eventMouseLeave when the event el is destroyed while mouse is over it
1195
+ this.handleEventElRemove = (el) => {
1196
+ if (el === this.currentSegEl) {
1197
+ this.handleSegLeave(null, this.currentSegEl);
1198
+ }
1199
+ };
1200
+ this.handleSegEnter = (ev, segEl) => {
1201
+ if (internalCommon.getElSeg(segEl)) { // TODO: better way to make sure not hovering over more+ link or its wrapper
1202
+ this.currentSegEl = segEl;
1203
+ this.triggerEvent('eventMouseEnter', ev, segEl);
1204
+ }
1205
+ };
1206
+ this.handleSegLeave = (ev, segEl) => {
1207
+ if (this.currentSegEl) {
1208
+ this.currentSegEl = null;
1209
+ this.triggerEvent('eventMouseLeave', ev, segEl);
1210
+ }
1211
+ };
1212
+ this.removeHoverListeners = internalCommon.listenToHoverBySelector(settings.el, '.fc-event', // on both fg and bg events
1213
+ this.handleSegEnter, this.handleSegLeave);
1214
+ }
1215
+ destroy() {
1216
+ this.removeHoverListeners();
1217
+ }
1218
+ triggerEvent(publicEvName, ev, segEl) {
1219
+ let { component } = this;
1220
+ let { context } = component;
1221
+ let seg = internalCommon.getElSeg(segEl);
1222
+ if (!ev || component.isValidSegDownEl(ev.target)) {
1223
+ context.emitter.trigger(publicEvName, {
1224
+ el: segEl,
1225
+ event: new internalCommon.EventImpl(context, seg.eventRange.def, seg.eventRange.instance),
1226
+ jsEvent: ev,
1227
+ view: context.viewApi,
1228
+ });
1229
+ }
1230
+ }
1231
+ }
1232
+
1233
+ class CalendarContent extends internalCommon.PureComponent {
1234
+ constructor() {
1235
+ super(...arguments);
1236
+ this.buildViewContext = internalCommon.memoize(internalCommon.buildViewContext);
1237
+ this.buildViewPropTransformers = internalCommon.memoize(buildViewPropTransformers);
1238
+ this.buildToolbarProps = internalCommon.memoize(buildToolbarProps);
1239
+ this.headerRef = preact.createRef();
1240
+ this.footerRef = preact.createRef();
1241
+ this.interactionsStore = {};
1242
+ // eslint-disable-next-line
1243
+ this.state = {
1244
+ viewLabelId: internalCommon.getUniqueDomId(),
1245
+ };
1246
+ // Component Registration
1247
+ // -----------------------------------------------------------------------------------------------------------------
1248
+ this.registerInteractiveComponent = (component, settingsInput) => {
1249
+ let settings = internalCommon.parseInteractionSettings(component, settingsInput);
1250
+ let DEFAULT_INTERACTIONS = [
1251
+ EventClicking,
1252
+ EventHovering,
1253
+ ];
1254
+ let interactionClasses = DEFAULT_INTERACTIONS.concat(this.props.pluginHooks.componentInteractions);
1255
+ let interactions = interactionClasses.map((TheInteractionClass) => new TheInteractionClass(settings));
1256
+ this.interactionsStore[component.uid] = interactions;
1257
+ internalCommon.interactionSettingsStore[component.uid] = settings;
1258
+ };
1259
+ this.unregisterInteractiveComponent = (component) => {
1260
+ let listeners = this.interactionsStore[component.uid];
1261
+ if (listeners) {
1262
+ for (let listener of listeners) {
1263
+ listener.destroy();
1264
+ }
1265
+ delete this.interactionsStore[component.uid];
1266
+ }
1267
+ delete internalCommon.interactionSettingsStore[component.uid];
1268
+ };
1269
+ // Resizing
1270
+ // -----------------------------------------------------------------------------------------------------------------
1271
+ this.resizeRunner = new internalCommon.DelayedRunner(() => {
1272
+ this.props.emitter.trigger('_resize', true); // should window resizes be considered "forced" ?
1273
+ this.props.emitter.trigger('windowResize', { view: this.props.viewApi });
1274
+ });
1275
+ this.handleWindowResize = (ev) => {
1276
+ let { options } = this.props;
1277
+ if (options.handleWindowResize &&
1278
+ ev.target === window // avoid jqui events
1279
+ ) {
1280
+ this.resizeRunner.request(options.windowResizeDelay);
1281
+ }
1282
+ };
1283
+ }
1284
+ /*
1285
+ renders INSIDE of an outer div
1286
+ */
1287
+ render() {
1288
+ let { props } = this;
1289
+ let { toolbarConfig, options } = props;
1290
+ let toolbarProps = this.buildToolbarProps(props.viewSpec, props.dateProfile, props.dateProfileGenerator, props.currentDate, internalCommon.getNow(props.options.now, props.dateEnv), // TODO: use NowTimer????
1291
+ props.viewTitle);
1292
+ let viewVGrow = false;
1293
+ let viewHeight = '';
1294
+ let viewAspectRatio;
1295
+ if (props.isHeightAuto || props.forPrint) {
1296
+ viewHeight = '';
1297
+ }
1298
+ else if (options.height != null) {
1299
+ viewVGrow = true;
1300
+ }
1301
+ else if (options.contentHeight != null) {
1302
+ viewHeight = options.contentHeight;
1303
+ }
1304
+ else {
1305
+ viewAspectRatio = Math.max(options.aspectRatio, 0.5); // prevent from getting too tall
1306
+ }
1307
+ let viewContext = this.buildViewContext(props.viewSpec, props.viewApi, props.options, props.dateProfileGenerator, props.dateEnv, props.theme, props.pluginHooks, props.dispatch, props.getCurrentData, props.emitter, props.calendarApi, this.registerInteractiveComponent, this.unregisterInteractiveComponent);
1308
+ let viewLabelId = (toolbarConfig.header && toolbarConfig.header.hasTitle)
1309
+ ? this.state.viewLabelId
1310
+ : '';
1311
+ return (preact.createElement(internalCommon.ViewContextType.Provider, { value: viewContext },
1312
+ toolbarConfig.header && (preact.createElement(Toolbar, Object.assign({ ref: this.headerRef, extraClassName: "fc-header-toolbar", model: toolbarConfig.header, titleId: viewLabelId }, toolbarProps))),
1313
+ preact.createElement(ViewContainer, { liquid: viewVGrow, height: viewHeight, aspectRatio: viewAspectRatio, labeledById: viewLabelId },
1314
+ this.renderView(props),
1315
+ this.buildAppendContent()),
1316
+ toolbarConfig.footer && (preact.createElement(Toolbar, Object.assign({ ref: this.footerRef, extraClassName: "fc-footer-toolbar", model: toolbarConfig.footer, titleId: "" }, toolbarProps)))));
1317
+ }
1318
+ componentDidMount() {
1319
+ let { props } = this;
1320
+ this.calendarInteractions = props.pluginHooks.calendarInteractions
1321
+ .map((CalendarInteractionClass) => new CalendarInteractionClass(props));
1322
+ window.addEventListener('resize', this.handleWindowResize);
1323
+ let { propSetHandlers } = props.pluginHooks;
1324
+ for (let propName in propSetHandlers) {
1325
+ propSetHandlers[propName](props[propName], props);
1326
+ }
1327
+ }
1328
+ componentDidUpdate(prevProps) {
1329
+ let { props } = this;
1330
+ let { propSetHandlers } = props.pluginHooks;
1331
+ for (let propName in propSetHandlers) {
1332
+ if (props[propName] !== prevProps[propName]) {
1333
+ propSetHandlers[propName](props[propName], props);
1334
+ }
1335
+ }
1336
+ }
1337
+ componentWillUnmount() {
1338
+ window.removeEventListener('resize', this.handleWindowResize);
1339
+ this.resizeRunner.clear();
1340
+ for (let interaction of this.calendarInteractions) {
1341
+ interaction.destroy();
1342
+ }
1343
+ this.props.emitter.trigger('_unmount');
1344
+ }
1345
+ buildAppendContent() {
1346
+ let { props } = this;
1347
+ let children = props.pluginHooks.viewContainerAppends.map((buildAppendContent) => buildAppendContent(props));
1348
+ return preact.createElement(preact.Fragment, {}, ...children);
1349
+ }
1350
+ renderView(props) {
1351
+ let { pluginHooks } = props;
1352
+ let { viewSpec } = props;
1353
+ let viewProps = {
1354
+ dateProfile: props.dateProfile,
1355
+ businessHours: props.businessHours,
1356
+ eventStore: props.renderableEventStore,
1357
+ eventUiBases: props.eventUiBases,
1358
+ dateSelection: props.dateSelection,
1359
+ eventSelection: props.eventSelection,
1360
+ eventDrag: props.eventDrag,
1361
+ eventResize: props.eventResize,
1362
+ isHeightAuto: props.isHeightAuto,
1363
+ forPrint: props.forPrint,
1364
+ };
1365
+ let transformers = this.buildViewPropTransformers(pluginHooks.viewPropsTransformers);
1366
+ for (let transformer of transformers) {
1367
+ Object.assign(viewProps, transformer.transform(viewProps, props));
1368
+ }
1369
+ let ViewComponent = viewSpec.component;
1370
+ return (preact.createElement(ViewComponent, Object.assign({}, viewProps)));
1371
+ }
1372
+ }
1373
+ function buildToolbarProps(viewSpec, dateProfile, dateProfileGenerator, currentDate, now, title) {
1374
+ // don't force any date-profiles to valid date profiles (the `false`) so that we can tell if it's invalid
1375
+ let todayInfo = dateProfileGenerator.build(now, undefined, false); // TODO: need `undefined` or else INFINITE LOOP for some reason
1376
+ let prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate, false);
1377
+ let nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate, false);
1378
+ return {
1379
+ title,
1380
+ activeButton: viewSpec.type,
1381
+ navUnit: viewSpec.singleUnit,
1382
+ isTodayEnabled: todayInfo.isValid && !internalCommon.rangeContainsMarker(dateProfile.currentRange, now),
1383
+ isPrevEnabled: prevInfo.isValid,
1384
+ isNextEnabled: nextInfo.isValid,
1385
+ };
1386
+ }
1387
+ // Plugin
1388
+ // -----------------------------------------------------------------------------------------------------------------
1389
+ function buildViewPropTransformers(theClasses) {
1390
+ return theClasses.map((TheClass) => new TheClass());
1391
+ }
1392
+
1393
+ class Calendar extends internalCommon.CalendarImpl {
1394
+ constructor(el, optionOverrides = {}) {
1395
+ super();
1396
+ this.isRendering = false;
1397
+ this.isRendered = false;
1398
+ this.currentClassNames = [];
1399
+ this.customContentRenderId = 0;
1400
+ this.handleAction = (action) => {
1401
+ // actions we know we want to render immediately
1402
+ switch (action.type) {
1403
+ case 'SET_EVENT_DRAG':
1404
+ case 'SET_EVENT_RESIZE':
1405
+ this.renderRunner.tryDrain();
1406
+ }
1407
+ };
1408
+ this.handleData = (data) => {
1409
+ this.currentData = data;
1410
+ this.renderRunner.request(data.calendarOptions.rerenderDelay);
1411
+ };
1412
+ this.handleRenderRequest = () => {
1413
+ if (this.isRendering) {
1414
+ this.isRendered = true;
1415
+ let { currentData } = this;
1416
+ internalCommon.flushSync(() => {
1417
+ preact.render(preact.createElement(internalCommon.CalendarRoot, { options: currentData.calendarOptions, theme: currentData.theme, emitter: currentData.emitter }, (classNames, height, isHeightAuto, forPrint) => {
1418
+ this.setClassNames(classNames);
1419
+ this.setHeight(height);
1420
+ return (preact.createElement(internalCommon.RenderId.Provider, { value: this.customContentRenderId },
1421
+ preact.createElement(CalendarContent, Object.assign({ isHeightAuto: isHeightAuto, forPrint: forPrint }, currentData))));
1422
+ }), this.el);
1423
+ });
1424
+ }
1425
+ else if (this.isRendered) {
1426
+ this.isRendered = false;
1427
+ preact.render(null, this.el);
1428
+ this.setClassNames([]);
1429
+ this.setHeight('');
1430
+ }
1431
+ };
1432
+ this.el = el;
1433
+ this.renderRunner = new internalCommon.DelayedRunner(this.handleRenderRequest);
1434
+ new CalendarDataManager({
1435
+ optionOverrides,
1436
+ calendarApi: this,
1437
+ onAction: this.handleAction,
1438
+ onData: this.handleData,
1439
+ });
1440
+ }
1441
+ render() {
1442
+ let wasRendering = this.isRendering;
1443
+ if (!wasRendering) {
1444
+ this.isRendering = true;
1445
+ }
1446
+ else {
1447
+ this.customContentRenderId += 1;
1448
+ }
1449
+ this.renderRunner.request();
1450
+ if (wasRendering) {
1451
+ this.updateSize();
1452
+ }
1453
+ }
1454
+ destroy() {
1455
+ if (this.isRendering) {
1456
+ this.isRendering = false;
1457
+ this.renderRunner.request();
1458
+ }
1459
+ }
1460
+ updateSize() {
1461
+ internalCommon.flushSync(() => {
1462
+ super.updateSize();
1463
+ });
1464
+ }
1465
+ batchRendering(func) {
1466
+ this.renderRunner.pause('batchRendering');
1467
+ func();
1468
+ this.renderRunner.resume('batchRendering');
1469
+ }
1470
+ pauseRendering() {
1471
+ this.renderRunner.pause('pauseRendering');
1472
+ }
1473
+ resumeRendering() {
1474
+ this.renderRunner.resume('pauseRendering', true);
1475
+ }
1476
+ resetOptions(optionOverrides, append) {
1477
+ this.currentDataManager.resetOptions(optionOverrides, append);
1478
+ }
1479
+ setClassNames(classNames) {
1480
+ if (!internalCommon.isArraysEqual(classNames, this.currentClassNames)) {
1481
+ let { classList } = this.el;
1482
+ for (let className of this.currentClassNames) {
1483
+ classList.remove(className);
1484
+ }
1485
+ for (let className of classNames) {
1486
+ classList.add(className);
1487
+ }
1488
+ this.currentClassNames = classNames;
1489
+ }
1490
+ }
1491
+ setHeight(height) {
1492
+ internalCommon.applyStyleProp(this.el, 'height', height);
1493
+ }
1494
+ }
1495
+
1496
+ function formatDate(dateInput, options = {}) {
1497
+ let dateEnv = buildDateEnv(options);
1498
+ let formatter = internalCommon.createFormatter(options);
1499
+ let dateMeta = dateEnv.createMarkerMeta(dateInput);
1500
+ if (!dateMeta) { // TODO: warning?
1501
+ return '';
1502
+ }
1503
+ return dateEnv.format(dateMeta.marker, formatter, {
1504
+ forcedTzo: dateMeta.forcedTzo,
1505
+ });
1506
+ }
1507
+ function formatRange(startInput, endInput, options) {
1508
+ let dateEnv = buildDateEnv(typeof options === 'object' && options ? options : {}); // pass in if non-null object
1509
+ let formatter = internalCommon.createFormatter(options);
1510
+ let startMeta = dateEnv.createMarkerMeta(startInput);
1511
+ let endMeta = dateEnv.createMarkerMeta(endInput);
1512
+ if (!startMeta || !endMeta) { // TODO: warning?
1513
+ return '';
1514
+ }
1515
+ return dateEnv.formatRange(startMeta.marker, endMeta.marker, formatter, {
1516
+ forcedStartTzo: startMeta.forcedTzo,
1517
+ forcedEndTzo: endMeta.forcedTzo,
1518
+ isEndExclusive: options.isEndExclusive,
1519
+ defaultSeparator: internalCommon.BASE_OPTION_DEFAULTS.defaultRangeSeparator,
1520
+ });
1521
+ }
1522
+ // TODO: more DRY and optimized
1523
+ function buildDateEnv(settings) {
1524
+ let locale = buildLocale(settings.locale || 'en', organizeRawLocales([]).map); // TODO: don't hardcode 'en' everywhere
1525
+ return new internalCommon.DateEnv(Object.assign(Object.assign({ timeZone: internalCommon.BASE_OPTION_DEFAULTS.timeZone, calendarSystem: 'gregory' }, settings), { locale }));
1526
+ }
1527
+
1528
+ // HELPERS
1529
+ /*
1530
+ if nextDayThreshold is specified, slicing is done in an all-day fashion.
1531
+ you can get nextDayThreshold from context.nextDayThreshold
1532
+ */
1533
+ function sliceEvents(props, allDay) {
1534
+ return internalCommon.sliceEventStore(props.eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? props.nextDayThreshold : null).fg;
1535
+ }
1536
+
1537
+ const version = '6.0.0-beta.2';
1538
+
1539
+ exports.JsonRequestError = internalCommon.JsonRequestError;
1540
+ exports.createPlugin = internalCommon.createPlugin;
1541
+ exports.Calendar = Calendar;
1542
+ exports.formatDate = formatDate;
1543
+ exports.formatRange = formatRange;
1544
+ exports.sliceEvents = sliceEvents;
1545
+ exports.version = version;