@iamproperty/components 7.3.0 → 7.5.0

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 (327) hide show
  1. package/README.md +1 -1
  2. package/assets/css/components/actionbar.component.css +1 -1
  3. package/assets/css/components/actionbar.component.css.map +1 -1
  4. package/assets/css/components/actionbar.global.css +1 -1
  5. package/assets/css/components/actionbar.global.css.map +1 -1
  6. package/assets/css/components/address-lookup.component.css +1 -0
  7. package/assets/css/components/address-lookup.component.css.map +1 -0
  8. package/assets/css/components/barchart.component.css +1 -1
  9. package/assets/css/components/barchart.component.css.map +1 -1
  10. package/assets/css/components/calendar.component.css +1 -0
  11. package/assets/css/components/calendar.component.css.map +1 -0
  12. package/assets/css/components/calendar.config.css +1 -0
  13. package/assets/css/components/calendar.config.css.map +1 -0
  14. package/assets/css/components/card.component.css +1 -1
  15. package/assets/css/components/card.component.css.map +1 -1
  16. package/assets/css/components/carousel.component.css +1 -1
  17. package/assets/css/components/carousel.component.css.map +1 -1
  18. package/assets/css/components/charts.css +1 -1
  19. package/assets/css/components/charts.css.map +1 -1
  20. package/assets/css/components/collapsible-side.css +1 -1
  21. package/assets/css/components/collapsible-side.css.map +1 -1
  22. package/assets/css/components/content.component.css +1 -0
  23. package/assets/css/components/content.component.css.map +1 -0
  24. package/assets/css/components/darkmode.component.css +1 -0
  25. package/assets/css/components/darkmode.component.css.map +1 -0
  26. package/assets/css/components/doughnutchart.component.css +1 -1
  27. package/assets/css/components/doughnutchart.component.css.map +1 -1
  28. package/assets/css/components/fileupload.css.map +1 -1
  29. package/assets/css/components/inline-edit.css +1 -1
  30. package/assets/css/components/inline-edit.css.map +1 -1
  31. package/assets/css/components/marketing.component.css +1 -0
  32. package/assets/css/components/marketing.component.css.map +1 -0
  33. package/assets/css/components/menu.component.css.map +1 -1
  34. package/assets/css/components/{menu.css → menu.global.css} +1 -1
  35. package/assets/css/components/menu.global.css.map +1 -0
  36. package/assets/css/components/milestone.css +1 -0
  37. package/assets/css/components/milestone.css.map +1 -0
  38. package/assets/css/components/multi-step.component.css +1 -1
  39. package/assets/css/components/multi-step.component.css.map +1 -1
  40. package/assets/css/components/multiselect.css +1 -1
  41. package/assets/css/components/multiselect.css.map +1 -1
  42. package/assets/css/components/multiselect.preload.css +1 -1
  43. package/assets/css/components/multiselect.preload.css.map +1 -1
  44. package/assets/css/components/nav.component.css +1 -1
  45. package/assets/css/components/nav.component.css.map +1 -1
  46. package/assets/css/components/nav.global.css +1 -1
  47. package/assets/css/components/nav.global.css.map +1 -1
  48. package/assets/css/components/notification.css +1 -1
  49. package/assets/css/components/notification.css.map +1 -1
  50. package/assets/css/components/pagination.css.map +1 -1
  51. package/assets/css/components/property-searchbar.css +1 -1
  52. package/assets/css/components/property-searchbar.css.map +1 -1
  53. package/assets/css/components/rank.component.css +1 -1
  54. package/assets/css/components/rank.component.css.map +1 -1
  55. package/assets/css/components/rankings.component.css +1 -1
  56. package/assets/css/components/rankings.component.css.map +1 -1
  57. package/assets/css/components/rankings.global.css +1 -1
  58. package/assets/css/components/rankings.global.css.map +1 -1
  59. package/assets/css/components/slider.css.map +1 -1
  60. package/assets/css/components/split-button.component.css +1 -0
  61. package/assets/css/components/split-button.component.css.map +1 -0
  62. package/assets/css/components/word-count.component.css +1 -0
  63. package/assets/css/components/word-count.component.css.map +1 -0
  64. package/assets/css/core.min.css +1 -1
  65. package/assets/css/core.min.css.map +1 -1
  66. package/assets/css/mobile-core.min.css +1 -1
  67. package/assets/css/mobile-core.min.css.map +1 -1
  68. package/assets/css/mobile.min.css +1 -1
  69. package/assets/css/mobile.min.css.map +1 -1
  70. package/assets/css/style.min.css +1 -1
  71. package/assets/css/style.min.css.map +1 -1
  72. package/assets/js/components/accordion/accordion.component.js +40 -19
  73. package/assets/js/components/accordion/accordion.component.min.js +15 -15
  74. package/assets/js/components/accordion/accordion.component.min.js.map +1 -1
  75. package/assets/js/components/actionbar/actionbar.component.js +59 -31
  76. package/assets/js/components/actionbar/actionbar.component.min.js +18 -17
  77. package/assets/js/components/actionbar/actionbar.component.min.js.map +1 -1
  78. package/assets/js/components/address-lookup/address-lookup.component.js +6 -8
  79. package/assets/js/components/address-lookup/address-lookup.component.min.js +10 -12
  80. package/assets/js/components/address-lookup/address-lookup.component.min.js.map +1 -1
  81. package/assets/js/components/advanced-select/advanced-select.component.js +63 -0
  82. package/assets/js/components/advanced-select/advanced-select.component.min.js +23 -0
  83. package/assets/js/components/advanced-select/advanced-select.component.min.js.map +1 -0
  84. package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
  85. package/assets/js/components/applied-filters/applied-filters.component.min.js.map +1 -1
  86. package/assets/js/components/barchart/barchart.component.min.js +2 -2
  87. package/assets/js/components/barchart/barchart.component.min.js.map +1 -1
  88. package/assets/js/components/bento-grid/bento-grid.component.min.js +1 -1
  89. package/assets/js/components/bento-grid/bento-grid.component.min.js.map +1 -1
  90. package/assets/js/components/calendar/calendar.component.js +1100 -0
  91. package/assets/js/components/calendar/calendar.component.min.js +170 -0
  92. package/assets/js/components/calendar/calendar.component.min.js.map +1 -0
  93. package/assets/js/components/card/card.component.js +14 -8
  94. package/assets/js/components/card/card.component.min.js +16 -10
  95. package/assets/js/components/card/card.component.min.js.map +1 -1
  96. package/assets/js/components/carousel/carousel.component.js +17 -19
  97. package/assets/js/components/carousel/carousel.component.min.js +17 -19
  98. package/assets/js/components/carousel/carousel.component.min.js.map +1 -1
  99. package/assets/js/components/collapsible-side/collapsible-side.component.js +47 -12
  100. package/assets/js/components/collapsible-side/collapsible-side.component.min.js +6 -5
  101. package/assets/js/components/collapsible-side/collapsible-side.component.min.js.map +1 -1
  102. package/assets/js/components/content/content.component.js +66 -0
  103. package/assets/js/components/content/content.component.min.js +15 -0
  104. package/assets/js/components/content/content.component.min.js.map +1 -0
  105. package/assets/js/components/darkmode/darkmode.component.js +70 -0
  106. package/assets/js/components/darkmode/darkmode.component.min.js +10 -0
  107. package/assets/js/components/darkmode/darkmode.component.min.js.map +1 -0
  108. package/assets/js/components/doughnutchart/doughnutchart.component.min.js +2 -2
  109. package/assets/js/components/doughnutchart/doughnutchart.component.min.js.map +1 -1
  110. package/assets/js/components/fileupload/fileupload.component.min.js +1 -1
  111. package/assets/js/components/fileupload/fileupload.component.min.js.map +1 -1
  112. package/assets/js/components/filter-card/filter-card.component.min.js +1 -1
  113. package/assets/js/components/filter-card/filter-card.component.min.js.map +1 -1
  114. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  115. package/assets/js/components/filterlist/filterlist.component.min.js.map +1 -1
  116. package/assets/js/components/header/header.component.min.js +1 -1
  117. package/assets/js/components/header/header.component.min.js.map +1 -1
  118. package/assets/js/components/inline-edit/inline-edit.component.min.js +5 -5
  119. package/assets/js/components/inline-edit/inline-edit.component.min.js.map +1 -1
  120. package/assets/js/components/marketing/marketing.component.js +1 -1
  121. package/assets/js/components/marketing/marketing.component.min.js +2 -2
  122. package/assets/js/components/marketing/marketing.component.min.js.map +1 -1
  123. package/assets/js/components/menu/menu.component.js +12 -4
  124. package/assets/js/components/menu/menu.component.min.js +4 -5
  125. package/assets/js/components/menu/menu.component.min.js.map +1 -1
  126. package/assets/js/components/milestone/milestone.component.js +36 -0
  127. package/assets/js/components/milestone/milestone.component.min.js +15 -0
  128. package/assets/js/components/milestone/milestone.component.min.js.map +1 -0
  129. package/assets/js/components/milestone-group/milestone-group.component.js +33 -0
  130. package/assets/js/components/milestone-group/milestone-group.component.min.js +13 -0
  131. package/assets/js/components/milestone-group/milestone-group.component.min.js.map +1 -0
  132. package/assets/js/components/multi-step/multi-step.component.min.js +3 -3
  133. package/assets/js/components/multi-step/multi-step.component.min.js.map +1 -1
  134. package/assets/js/components/multiselect/multiselect.component.js +54 -2
  135. package/assets/js/components/multiselect/multiselect.component.min.js +5 -5
  136. package/assets/js/components/multiselect/multiselect.component.min.js.map +1 -1
  137. package/assets/js/components/nav/nav.component.js +18 -0
  138. package/assets/js/components/nav/nav.component.min.js +6 -6
  139. package/assets/js/components/nav/nav.component.min.js.map +1 -1
  140. package/assets/js/components/notification/notification.component.js +15 -11
  141. package/assets/js/components/notification/notification.component.min.js +4 -4
  142. package/assets/js/components/notification/notification.component.min.js.map +1 -1
  143. package/assets/js/components/pagination/pagination.component.min.js +1 -1
  144. package/assets/js/components/pagination/pagination.component.min.js.map +1 -1
  145. package/assets/js/components/rank/rank.component.js +346 -210
  146. package/assets/js/components/rank/rank.component.min.js +346 -211
  147. package/assets/js/components/rank/rank.component.min.js.map +1 -1
  148. package/assets/js/components/rankings/rankings.component.js +17 -8
  149. package/assets/js/components/rankings/rankings.component.min.js +14 -8
  150. package/assets/js/components/rankings/rankings.component.min.js.map +1 -1
  151. package/assets/js/components/record-card/record-card.component.min.js +1 -1
  152. package/assets/js/components/record-card/record-card.component.min.js.map +1 -1
  153. package/assets/js/components/search/search.component.js +5 -3
  154. package/assets/js/components/search/search.component.min.js +6 -6
  155. package/assets/js/components/search/search.component.min.js.map +1 -1
  156. package/assets/js/components/slider/slider.component.min.js +1 -1
  157. package/assets/js/components/slider/slider.component.min.js.map +1 -1
  158. package/assets/js/components/split-button/split-button.component.js +58 -0
  159. package/assets/js/components/split-button/split-button.component.min.js +31 -0
  160. package/assets/js/components/split-button/split-button.component.min.js.map +1 -0
  161. package/assets/js/components/table/table.component.js +12 -0
  162. package/assets/js/components/table/table.component.min.js +3 -3
  163. package/assets/js/components/table/table.component.min.js.map +1 -1
  164. package/assets/js/components/table-ajax/table-ajax.component.js +12 -0
  165. package/assets/js/components/table-ajax/table-ajax.component.min.js +3 -3
  166. package/assets/js/components/table-ajax/table-ajax.component.min.js.map +1 -1
  167. package/assets/js/components/table-basic/table-basic.component.min.js +1 -1
  168. package/assets/js/components/table-basic/table-basic.component.min.js.map +1 -1
  169. package/assets/js/components/table-no-submit/table-no-submit.component.js +12 -0
  170. package/assets/js/components/table-no-submit/table-no-submit.component.min.js +3 -3
  171. package/assets/js/components/table-no-submit/table-no-submit.component.min.js.map +1 -1
  172. package/assets/js/components/table-submit/table-submit.component.js +12 -0
  173. package/assets/js/components/table-submit/table-submit.component.min.js +3 -3
  174. package/assets/js/components/table-submit/table-submit.component.min.js.map +1 -1
  175. package/assets/js/components/tabs/tabs.component.min.js +1 -1
  176. package/assets/js/components/tabs/tabs.component.min.js.map +1 -1
  177. package/assets/js/components/video-card/video-card.component.min.js +1 -1
  178. package/assets/js/components/video-card/video-card.component.min.js.map +1 -1
  179. package/assets/js/components/word-count/word-count.component.js +81 -0
  180. package/assets/js/components/word-count/word-count.component.min.js +12 -0
  181. package/assets/js/components/word-count/word-count.component.min.js.map +1 -0
  182. package/assets/js/components.js +59 -0
  183. package/assets/js/modules/advanced-select.js +106 -0
  184. package/assets/js/modules/dialogs.js +53 -51
  185. package/assets/js/modules/dynamicEvents.js +7 -0
  186. package/assets/js/modules/inputs.js +0 -18
  187. package/assets/js/modules/milestone-group.js +30 -0
  188. package/assets/js/modules/milestone.js +89 -0
  189. package/assets/js/modules/table.js +11 -1
  190. package/assets/js/modules/videos.js +1 -1
  191. package/assets/js/scripts.bundle.js +3 -3
  192. package/assets/js/scripts.bundle.js.map +1 -1
  193. package/assets/js/scripts.bundle.min.js +2 -2
  194. package/assets/js/scripts.bundle.min.js.map +1 -1
  195. package/assets/js/scripts.js +5 -0
  196. package/assets/sass/_components.scss +15 -4
  197. package/assets/sass/_example.scss +1 -1
  198. package/assets/sass/_functions/utility-mixins.scss +40 -0
  199. package/assets/sass/_functions/variables.scss +11 -5
  200. package/assets/sass/components/actionbar.component.scss +23 -1
  201. package/assets/sass/components/actionbar.global.scss +5 -5
  202. package/assets/sass/components/{address-lookup.scss → address-lookup.component.scss} +10 -0
  203. package/assets/sass/components/calendar.component.scss +1272 -0
  204. package/assets/sass/components/calendar.config.scss +423 -0
  205. package/assets/sass/components/card.component.scss +4 -34
  206. package/assets/sass/components/carousel.component.scss +5 -0
  207. package/assets/sass/components/collapsible-side.scss +91 -95
  208. package/assets/sass/components/content.component.scss +18 -0
  209. package/assets/sass/components/darkmode.component.scss +22 -0
  210. package/assets/sass/components/inline-edit.scss +2 -0
  211. package/assets/sass/components/{marketing.scss → marketing.component.scss} +2 -6
  212. package/assets/sass/components/menu.component.scss +3 -8
  213. package/assets/sass/components/milestone.scss +216 -0
  214. package/assets/sass/components/multi-step.component.scss +1 -1
  215. package/assets/sass/components/multiselect.preload.scss +1 -1
  216. package/assets/sass/components/multiselect.scss +2 -0
  217. package/assets/sass/components/nav.component.scss +17 -6
  218. package/assets/sass/components/nav.global.scss +29 -3
  219. package/assets/sass/components/notification.scss +32 -13
  220. package/assets/sass/components/rank.component.scss +197 -24
  221. package/assets/sass/components/rankings.component.scss +38 -28
  222. package/assets/sass/components/rankings.global.scss +64 -2
  223. package/assets/sass/components/split-button.component.scss +79 -0
  224. package/assets/sass/components/table-basic.global.scss +32 -32
  225. package/assets/sass/components/word-count.component.scss +26 -0
  226. package/assets/sass/elements/admin-panel.scss +1 -1
  227. package/assets/sass/elements/badge-tag.scss +5 -1
  228. package/assets/sass/elements/buttons--compact.scss +4 -0
  229. package/assets/sass/elements/details.scss +33 -7
  230. package/assets/sass/elements/forms.scss +135 -28
  231. package/assets/sass/elements/links.scss +132 -4
  232. package/assets/sass/elements/lists.scss +62 -1
  233. package/assets/sass/elements/popover.scss +64 -10
  234. package/assets/sass/elements/toggle-button.scss +8 -8
  235. package/assets/sass/elements/type.scss +7 -10
  236. package/assets/sass/foundations/colours.scss +0 -0
  237. package/assets/sass/foundations/reboot.scss +8 -1
  238. package/assets/sass/foundations/root.scss +41 -51
  239. package/assets/sass/templates/form.scss +0 -2
  240. package/assets/ts/components/accordion/accordion.component.ts +47 -26
  241. package/assets/ts/components/actionbar/actionbar.component.ts +58 -22
  242. package/assets/ts/components/address-lookup/address-lookup.component.ts +6 -8
  243. package/assets/ts/components/advanced-select/advanced-select.component.ts +74 -0
  244. package/assets/ts/components/calendar/calendar.component.ts +1330 -0
  245. package/assets/ts/components/card/card.component.ts +15 -14
  246. package/assets/ts/components/carousel/carousel.component.ts +17 -19
  247. package/assets/ts/components/collapsible-side/collapsible-side.component.ts +53 -12
  248. package/assets/ts/components/content/content.component.ts +78 -0
  249. package/assets/ts/components/darkmode/darkmode.component.ts +85 -0
  250. package/assets/ts/components/marketing/marketing.component.ts +1 -1
  251. package/assets/ts/components/menu/menu.component.ts +18 -10
  252. package/assets/ts/components/milestone/milestone.component.ts +43 -0
  253. package/assets/ts/components/milestone-group/milestone-group.component.ts +39 -0
  254. package/assets/ts/components/multiselect/multiselect.component.ts +60 -3
  255. package/assets/ts/components/nav/nav.component.ts +18 -0
  256. package/assets/ts/components/notification/notification.component.ts +30 -11
  257. package/assets/ts/components/rank/rank.component.ts +345 -209
  258. package/assets/ts/components/rankings/rankings.component.ts +27 -8
  259. package/assets/ts/components/search/search.component.ts +6 -4
  260. package/assets/ts/components/split-button/split-button.component.ts +67 -0
  261. package/assets/ts/components/table/table.component.ts +14 -0
  262. package/assets/ts/components/table-ajax/table-ajax.component.ts +14 -0
  263. package/assets/ts/components/table-no-submit/table-no-submit.component.ts +14 -0
  264. package/assets/ts/components/table-submit/table-submit.component.ts +14 -0
  265. package/assets/ts/components/video-card/video-card.component.ts +2 -3
  266. package/assets/ts/components/word-count/word-count.component.ts +91 -0
  267. package/assets/ts/components.ts +64 -0
  268. package/assets/ts/modules/advanced-select.ts +120 -0
  269. package/assets/ts/modules/data-layer.md +0 -5
  270. package/assets/ts/modules/dialogs.ts +64 -61
  271. package/assets/ts/modules/dynamicEvents.ts +10 -0
  272. package/assets/ts/modules/inputs.ts +0 -25
  273. package/assets/ts/modules/milestone-group.ts +39 -0
  274. package/assets/ts/modules/milestone.ts +119 -0
  275. package/assets/ts/modules/table.ts +15 -1
  276. package/assets/ts/modules/videos.ts +19 -37
  277. package/assets/ts/scripts.ts +6 -3
  278. package/dist/components.es.js +849 -1079
  279. package/dist/components.umd.js +1052 -220
  280. package/package.json +6 -6
  281. package/src/components/Accordion/Accordion.vue +14 -23
  282. package/src/components/Accordion/AccordionItem.vue +27 -43
  283. package/src/components/Actionbar/Actionbar.vue +17 -19
  284. package/src/components/AddressLookup/AddressLookup.vue +17 -18
  285. package/src/components/AdvancedSelect/AdvancedSelect.vue +22 -0
  286. package/src/components/AppliedFilters/AppliedFilters.vue +16 -18
  287. package/src/components/Banner/Banner.vue +18 -21
  288. package/src/components/BarChart/BarChart.vue +17 -18
  289. package/src/components/Calendar/Calendar.vue +20 -0
  290. package/src/components/Card/Card.vue +17 -17
  291. package/src/components/Carousel/Carousel.vue +17 -20
  292. package/src/components/CollapsibleSideMenu/CollapsibleSideMenu.vue +7 -13
  293. package/src/components/Content/Content.vue +22 -0
  294. package/src/components/DarkMode/DarkMode.vue +19 -0
  295. package/src/components/DoughnutChart/DoughnutChart.vue +17 -18
  296. package/src/components/FileUpload/FileUpload.vue +22 -28
  297. package/src/components/FilterCard/FilterCard.vue +17 -18
  298. package/src/components/Filterlist/Filterlist.vue +17 -0
  299. package/src/components/Header/Header.vue +28 -29
  300. package/src/components/InlineEdit/InlineEdit.vue +11 -19
  301. package/src/components/Menu/Menu.vue +17 -17
  302. package/src/components/Milestones/Milestone.vue +22 -0
  303. package/src/components/Milestones/MilestoneGroup.vue +24 -0
  304. package/src/components/Multiselect/Multiselect.vue +17 -18
  305. package/src/components/Nav/Nav.vue +17 -19
  306. package/src/components/Notification/Notification.vue +17 -15
  307. package/src/components/Pagination/Pagination.vue +16 -16
  308. package/src/components/Rank/Rank.vue +17 -18
  309. package/src/components/Rankings/Rankings.vue +17 -27
  310. package/src/components/RecordCard/RecordCard.vue +17 -18
  311. package/src/components/Search/Search.vue +17 -17
  312. package/src/components/Slider/Slider.vue +17 -17
  313. package/src/components/SplitButton/README.md +19 -0
  314. package/src/components/SplitButton/SplitButton.vue +23 -0
  315. package/src/components/Tabs/Tabs.vue +17 -17
  316. package/src/components/VideoCard/VideoCard.vue +17 -18
  317. package/src/components/WordCount/WordCount.vue +22 -0
  318. package/src/index.js +2 -0
  319. package/assets/css/components/address-lookup.css +0 -1
  320. package/assets/css/components/address-lookup.css.map +0 -1
  321. package/assets/css/components/marketing.css +0 -1
  322. package/assets/css/components/marketing.css.map +0 -1
  323. package/assets/css/components/menu.css.map +0 -1
  324. package/assets/css/components/nav.old.css +0 -1
  325. package/assets/css/components/nav.old.css.map +0 -1
  326. package/assets/sass/components/nav.old.scss +0 -891
  327. /package/assets/sass/components/{menu.scss → menu.global.scss} +0 -0
@@ -0,0 +1,1330 @@
1
+ import { trackComponent, trackComponentRegistered } from '../_global';
2
+ import { uniqueID } from '../../modules/helpers';
3
+
4
+ trackComponentRegistered('iam-calendar');
5
+
6
+ class iamCalendar extends HTMLElement {
7
+ constructor() {
8
+ super();
9
+ this.attachShadow({ mode: 'open' });
10
+
11
+ const assetLocation = document.body.hasAttribute('data-assets-location')
12
+ ? document.body.getAttribute('data-assets-location')
13
+ : '/assets';
14
+
15
+ const loadCSS = `@import "${assetLocation}/css/components/calendar.component.css";`;
16
+
17
+ const weekViewOnly = `<table class="table--day" role="presentation"><tbody>
18
+ <tr class="allday"><th>All day</th></tr>
19
+ <tr><th data-hour="0">00</th></tr>
20
+ <tr><th data-hour="1">01</th></tr>
21
+ <tr><th data-hour="2">02</th></tr>
22
+ <tr><th data-hour="3">03</th></tr>
23
+ <tr><th data-hour="4">04</th></tr>
24
+ <tr><th data-hour="5">05</th></tr>
25
+ <tr><th data-hour="6">06</th></tr>
26
+ <tr><th data-hour="7">07</th></tr>
27
+ <tr><th data-hour="8">08</th></tr>
28
+ <tr><th data-hour="9">09</th></tr>
29
+ <tr><th data-hour="10">10</th></tr>
30
+ <tr><th data-hour="11">11</th></tr>
31
+ <tr><th data-hour="12">12</th></tr>
32
+ <tr><th data-hour="13">13</th></tr>
33
+ <tr><th data-hour="14">14</th></tr>
34
+ <tr><th data-hour="15">15</th></tr>
35
+ <tr><th data-hour="16">16</th></tr>
36
+ <tr><th data-hour="17">17</th></tr>
37
+ <tr><th data-hour="18">18</th></tr>
38
+ <tr><th data-hour="19">19</th></tr>
39
+ <tr><th data-hour="20">20</th></tr>
40
+ <tr><th data-hour="21">21</th></tr>
41
+ <tr><th data-hour="22">22</th></tr>
42
+ <tr><th data-hour="23">23</th></tr>
43
+ </tbody></table>`;
44
+
45
+ const template = document.createElement('template');
46
+
47
+ template.innerHTML = `
48
+ <style>
49
+ ${loadCSS}
50
+ ${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
51
+ </style>
52
+ <div class="calendar__container">
53
+
54
+ <div class="calendar__controls">
55
+ <button id="today-button" class="btn btn-action">Today</button>
56
+
57
+
58
+ <button id="prev-button" class="btn btn-action fa-chevron-left border-0"><span class="visually-hidden">previous</span></button>
59
+ <div class="calendar__datepicker">
60
+ <span class="calendar__title"></span>
61
+ <input type="date" id="date" name="date" />
62
+ </div>
63
+ <button id="next-button" class="btn btn-action fa-chevron-right border-0"><span class="visually-hidden">Next</span></button>
64
+
65
+ <hr/>
66
+
67
+
68
+ <select name="view" id="view" class="btn btn-action">
69
+
70
+ <button>
71
+ <selectedcontent></selectedcontent> <i class="fa-regular fa-chevron-down"></i>
72
+ </button>
73
+
74
+ <option value="month"><i class="fa-light fa-calendar-days"></i>Month</option>
75
+ <option value="week"><i class="fa-light fa-calendar-week"></i>Week</option>
76
+ <option value="day"><i class="fa-light fa-calendar-day"></i>Day</option>
77
+ <option value="list"><i class="fa-light fa-list"></i>List</option>
78
+ <option value="year"><i class="fa-light fa-calendars"></i>Year</option>
79
+ </select>
80
+
81
+ <label class="tag tag--toggle"><input type="checkbox" name="split" value="true">Split view</label>
82
+
83
+ <button id="filters-button" class="btn btn-action"><i class="fa-light fa-sliders"></i><span class="visually-hidden">Filters</span></button>
84
+
85
+ <button id="settings-button" class="btn btn-action"><i class="fa-light fa-gear"></i><span class="visually-hidden">Settings</span></button>
86
+
87
+ </div>
88
+
89
+ <dialog id="settings">
90
+ <button class="dialog__close">Close</button>
91
+ <span class="h3">Calendar settings</span>
92
+
93
+ <fieldset id="workday" class="mb-5">
94
+ <label>Start time <span><input type="time" id="start-time" name="start-time" step="3600" value="08:00" /><span class="suffix fa-regular fa-clock" aria-hidden="true"></span></span></label>
95
+ <label>End time <span><input type="time" id="end-time" name="end-time" step="3600" value="18:00" /><span class="suffix fa-regular fa-clock" aria-hidden="true"></span></span></label>
96
+
97
+ </fieldset>
98
+
99
+ <hr/>
100
+ <fieldset>
101
+ <span class="label">Show weekends</span>
102
+ <input type="radio" name="weekends" id="weekends-yes" tabindex="-1">
103
+ <label for="weekends-yes" class="d-inline-block">Yes</label>
104
+ <input type="radio" name="weekends" id="weekends-no" tabindex="-1">
105
+ <label for="weekends-no" class="d-inline-block">No</label>
106
+ </fieldset>
107
+ <hr/>
108
+ <button class="btn btn-primary">Save settings</button>
109
+ <button class="btn btn-secondary">Cancel</button>
110
+
111
+ </dialog>
112
+
113
+
114
+ <div class="calendar__wrapper">
115
+
116
+ <div id="week-view-corner" class="calendar">
117
+ <table>
118
+ <thead>
119
+ <tr>
120
+ <th class="column-header">Empty</th>
121
+ </tr>
122
+ </thead>
123
+ <tbody>
124
+ <tr class="allday">
125
+ <th>All day</th>
126
+ </tr>
127
+ </tbody>
128
+ </table>
129
+ </div>
130
+
131
+ <div id="week-view-header" class="calendar">
132
+ <table>
133
+ <thead>
134
+ </thead>
135
+ <tbody>
136
+ </tbody>
137
+ </table>
138
+ </div>
139
+
140
+ <div id="week-view-side">${weekViewOnly}</div>
141
+
142
+ <div class="calendar month-wrapper" id="calendar" part="calendar">
143
+ <table>
144
+ <thead>
145
+ </thead>
146
+ <tbody>
147
+ </tbody>
148
+ </table>
149
+ </div>
150
+
151
+ <div id="year-view">
152
+ </div>
153
+ </div>
154
+
155
+
156
+ <slot></slot>
157
+
158
+ </div>
159
+ `;
160
+ this.shadowRoot.appendChild(template.content.cloneNode(true));
161
+
162
+ this.monthArray = [
163
+ 'January',
164
+ 'February',
165
+ 'March',
166
+ 'April',
167
+ 'May',
168
+ 'June',
169
+ 'July',
170
+ 'August',
171
+ 'September',
172
+ 'October',
173
+ 'November',
174
+ 'December',
175
+ ];
176
+ this.dayArray = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
177
+
178
+ this.english_ordinal_rules = new Intl.PluralRules('en', { type: 'ordinal' });
179
+ this.suffixes = {
180
+ one: 'st',
181
+ two: 'nd',
182
+ few: 'rd',
183
+ other: 'th',
184
+ };
185
+
186
+ this.calendars = ['Default']; // TO DO allow for these to be set via the component data attributes
187
+ this.eventTypes = []; // TO DO allow for these to be set via the component data attributes
188
+
189
+ this.pauseObserver = false;
190
+ }
191
+
192
+ createThead(sundayFirst: false): string {
193
+ if (sundayFirst)
194
+ return `<tr>
195
+ <th class="column-header sunday"><span class="long-day-name">Sunday</span><span class="short-day-name" role="presentation">Sun</span></th>
196
+ <th class="column-header monday"><span class="long-day-name">Monday</span><span class="short-day-name" role="presentation">Mon</span></th>
197
+ <th class="column-header tuesday"><span class="long-day-name">Tuesday</span><span class="short-day-name" role="presentation">Tues</span></th>
198
+ <th class="column-header wednesday"><span class="long-day-name">Wednesday</span><span class="short-day-name" role="presentation">Wed</span></th>
199
+ <th class="column-header thursday"><span class="long-day-name">Thursday</span><span class="short-day-name" role="presentation">Thurs</span></th>
200
+ <th class="column-header friday"><span class="long-day-name">Friday</span><span class="short-day-name" role="presentation">Fri</span></th>
201
+ <th class="column-header saturday"><span class="long-day-name">Saturday</span><span class="short-day-name" role="presentation">Sat</span></th>
202
+ </tr>`;
203
+
204
+ return `<tr>
205
+ <th class="column-header monday"><span class="long-day-name">Monday</span><span class="short-day-name" role="presentation">Mon</span></th>
206
+ <th class="column-header tuesday"><span class="long-day-name">Tuesday</span><span class="short-day-name" role="presentation">Tues</span></th>
207
+ <th class="column-header wednesday"><span class="long-day-name">Wednesday</span><span class="short-day-name" role="presentation">Wed</span></th>
208
+ <th class="column-header thursday"><span class="long-day-name">Thursday</span><span class="short-day-name" role="presentation">Thurs</span></th>
209
+ <th class="column-header friday"><span class="long-day-name">Friday</span><span class="short-day-name" role="presentation">Fri</span></th>
210
+ <th class="column-header saturday"><span class="long-day-name">Saturday</span><span class="short-day-name" role="presentation">Sat</span></th>
211
+ <th class="column-header sunday"><span class="long-day-name">Sunday</span><span class="short-day-name" role="presentation">Sun</span></th>
212
+ </tr>`;
213
+ }
214
+
215
+ numberDaysInMonth(year, month): Date {
216
+ return new Date(year, month, 0).getDate();
217
+ }
218
+
219
+ getOrdinalNumber(number): string {
220
+ const category = this.english_ordinal_rules.select(number);
221
+ const suffix = this.suffixes[category];
222
+ return number + suffix;
223
+ }
224
+
225
+ setToMonday(date): Date {
226
+ const day = date.getDay() || 7;
227
+ if (day !== 1) date.setHours(-24 * (day - 1));
228
+ return date;
229
+ }
230
+
231
+ setToSunday(date): Date {
232
+ const monday = this.setToMonday(date);
233
+ const sunday = new Date(monday);
234
+
235
+ sunday.setDate(sunday.getDate() + 6);
236
+ return sunday;
237
+ }
238
+
239
+ getTitle(dateStr, view): string {
240
+ const date = new Date(dateStr);
241
+ const month = date.getMonth();
242
+ const year = date.getFullYear();
243
+ const day = date.getDate();
244
+ const dayOfWeek = date.getDay() ? date.getDay() : 7;
245
+
246
+ if (view == 'week') {
247
+ const monday = this.setToMonday(new Date(dateStr));
248
+ const sunday = this.setToSunday(new Date(dateStr));
249
+
250
+ const mondayMonth = monday.getMonth();
251
+ const mondayYear = monday.getFullYear();
252
+ const mondayDay = monday.getDate();
253
+
254
+ const sundayMonth = sunday.getMonth();
255
+ const sundayYear = sunday.getFullYear();
256
+ const sundayDay = sunday.getDate();
257
+
258
+ return `${this.getOrdinalNumber(mondayDay)} ${mondayMonth != sundayMonth ? this.monthArray[sundayMonth] : ''} ${mondayYear != sundayYear ? mondayYear : ''} - ${this.getOrdinalNumber(sundayDay)} ${this.monthArray[sundayMonth]} ${sundayYear}`;
259
+ } else if (view == 'day') {
260
+ return `${this.dayArray[dayOfWeek]} ${this.getOrdinalNumber(day)} ${this.monthArray[month]} ${year}`;
261
+ } else if (view == 'year') {
262
+ return `${year}`;
263
+ }
264
+
265
+ return `${this.monthArray[month]} ${year}`;
266
+ }
267
+
268
+ createCalendar(selectedDate, today, sundayFirst: false): string {
269
+ const date = new Date(selectedDate);
270
+ const month = date.getMonth();
271
+ const year = date.getFullYear();
272
+ const day = date.getDate();
273
+ const selectedDateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
274
+ const daysThisMonth = this.numberDaysInMonth(year, month + 1);
275
+ const startOfMonth = new Date(`${year}-${String(month + 1).padStart(2, '0')}-01`);
276
+ const endOfMonth = new Date(`${year}-${String(month + 1).padStart(2, '0')}-${daysThisMonth}`);
277
+ const startDay = startOfMonth.getDay() != 0 ? startOfMonth.getDay() : 7;
278
+ const endDay = endOfMonth.getDay() != 0 ? endOfMonth.getDay() : 7;
279
+ const loopDays = daysThisMonth + startDay + (7 - endDay - 1);
280
+
281
+ // Get the previous month
282
+ const prevMonthDate = new Date(selectedDate);
283
+ prevMonthDate.setMonth(prevMonthDate.getMonth() - 1);
284
+ const prevMonth = prevMonthDate.getMonth();
285
+ const prevMonthYear = prevMonthDate.getFullYear();
286
+ const daysPrevMonth = this.numberDaysInMonth(year, month);
287
+
288
+ // Get the next month
289
+ const nextMonthDate = new Date(selectedDate);
290
+ nextMonthDate.setMonth(nextMonthDate.getMonth() + 1);
291
+ const nextMonth = nextMonthDate.getMonth();
292
+ const nextMonthYear = nextMonthDate.getFullYear();
293
+
294
+ // Get calendars
295
+
296
+ if (!this.hasAttribute('data-calendars')) {
297
+ Array.from(this.querySelectorAll('button[data-calendar]')).forEach((element) => {
298
+ // Scan through the buttons and look forunique calendar names
299
+ if (!this.calendars.includes(element.getAttribute('data-calendar')))
300
+ this.calendars.push(element.getAttribute('data-calendar'));
301
+ });
302
+ }
303
+
304
+ // Create tbody string by looping through the number of days in month plus some days before and after
305
+ let tbodyContent = `<tr>`;
306
+
307
+ for (let i = sundayFirst ? 0 : 1; i <= loopDays; i++) {
308
+ const loopDay = i - (startDay - 1);
309
+ const loopDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(loopDay).padStart(2, '0')}`;
310
+ const dayOfWeek = i % 7;
311
+
312
+ tbodyContent += `<td class="day--${this.dayArray[dayOfWeek].toLowerCase()} ${loopDate == today ? 'today' : ''} ${loopDate == selectedDateStr ? 'selected' : ''} ${i < startDay ? 'prev-month' : ''} ${loopDay > daysThisMonth ? 'next-month' : ''}">`;
313
+
314
+ // prev month days
315
+ if (i < startDay) {
316
+ const adjustedLoopDay = daysPrevMonth - (startDay - 1 - i);
317
+ const adjustedLoopDate = `${prevMonthYear}-${String(prevMonth + 1).padStart(2, '0')}-${String(adjustedLoopDay).padStart(2, '0')}`;
318
+
319
+ tbodyContent += `<time class="column-header" datetime="${adjustedLoopDate}" title="${this.dayArray[dayOfWeek]} ${loopDay} ${this.monthArray[prevMonth]} ${year}"><span class="day-of-week">${this.dayArray[dayOfWeek]} </span><span class="day">${adjustedLoopDay}</span> <span class="month">${this.monthArray[prevMonth]}</span></time>`;
320
+ tbodyContent += this.addDay(adjustedLoopDate, this.calendars);
321
+ }
322
+
323
+ if (i >= startDay && loopDay <= daysThisMonth) {
324
+ tbodyContent += `<time class="column-header" datetime="${loopDate}" title="${this.dayArray[dayOfWeek]} ${loopDay} ${this.monthArray[month]} ${year}"><span class="day-of-week">${this.dayArray[dayOfWeek]} </span><span class="day">${loopDay}</span> <span class="month">${this.monthArray[month]}</span></time>`;
325
+ tbodyContent += this.addDay(loopDate, this.calendars);
326
+ }
327
+
328
+ // next month days
329
+ if (loopDay > daysThisMonth) {
330
+ const adjustedLoopDay = i - (startDay - 1) - daysThisMonth;
331
+ const adjustedLoopDate = `${nextMonthYear}-${String(nextMonth + 1).padStart(2, '0')}-${String(adjustedLoopDay).padStart(2, '0')}`;
332
+
333
+ tbodyContent += `<time class="column-header" datetime="${adjustedLoopDate}" title="${this.dayArray[dayOfWeek]} ${loopDay} ${this.monthArray[nextMonth]} ${year}"><span class="day-of-week">${this.dayArray[dayOfWeek]} </span><span class="day">${adjustedLoopDay}</span> <span class="month">${this.monthArray[nextMonth]}</span></time>`;
334
+ tbodyContent += this.addDay(adjustedLoopDate, this.calendars);
335
+ }
336
+
337
+ tbodyContent += '</td>';
338
+
339
+ // Close row and start a new one
340
+ if ((sundayFirst ? i + 1 : i) % 7 === 0 && i != loopDays) {
341
+ tbodyContent += `</tr><tr>`;
342
+ }
343
+ }
344
+ tbodyContent += '</tr>';
345
+
346
+ return tbodyContent;
347
+ }
348
+
349
+ addDay(day, calendars: []): string {
350
+ let htmlTable = '<table class="table--day">';
351
+ htmlTable += `<thead><tr><th>time</th>`;
352
+ calendars.forEach((calendarTitle) => {
353
+ htmlTable += `<th class="column-header">${calendarTitle}</th>`;
354
+ });
355
+ htmlTable += `</tr></thead>`;
356
+
357
+ htmlTable += `<tbody>`;
358
+ htmlTable += `<tr class="allday"><th>All day</th>`;
359
+ calendars.forEach((calendarTitle) => {
360
+ htmlTable += `<td datetime="${day}" data-calendar="${calendarTitle}"><span datetime="${day}"></span></td>`;
361
+ });
362
+ htmlTable += `</tr>`;
363
+
364
+ for (let i = 0; i < 24; i++) {
365
+ htmlTable += `<tr class="hour${i}"><th data-hour="${i}">${i}${i < 12 ? 'am' : 'pm'}</th>`;
366
+ calendars.forEach((calendarTitle) => {
367
+ htmlTable += `<td datetime="${day}T${String(i).padStart(2, '0')}:00" data-calendar="${calendarTitle}"><span datetime="${day}T${String(i).padStart(2, '0')}:00"></span><span datetime="${day}T${String(i).padStart(2, '0')}:15"></span><span datetime="${day}T${String(i).padStart(2, '0')}:30"></span><span datetime="${day}T${String(i).padStart(2, '0')}:45"></span></td>`;
368
+ });
369
+ htmlTable += `</tr>`;
370
+ }
371
+ htmlTable += `</tbody>`;
372
+ htmlTable += '</table>';
373
+
374
+ return htmlTable;
375
+ }
376
+
377
+ addEvents(): void {
378
+ function setDefaultEventValues(component, element, index): void {
379
+ const datetime = element.getAttribute('datetime');
380
+ const datetimeArr = datetime.split('T');
381
+ let id = element.getAttribute('id');
382
+
383
+ // Add ID
384
+ if (!element.hasAttribute('id')) {
385
+ id = `event${uniqueID(index)}`;
386
+ element.setAttribute('id', id);
387
+ }
388
+
389
+ // Wrap content in span for formatting in week/day view
390
+ if (!element.querySelector('span:not(.tooltip__content')) {
391
+ element.innerHTML = `<span>${element.innerHTML}</span>`;
392
+ }
393
+
394
+ // Add event type enum so we can set the correct colours
395
+ //if(!element.hasAttribute('data-event-type-enum') && element.hasAttribute('data-event-type')){
396
+
397
+ const eventType = element.getAttribute('data-event-type');
398
+
399
+ if (!component.eventTypes.includes(eventType)) component.eventTypes.push(eventType);
400
+
401
+ element.setAttribute('data-event-type-enum', component.eventTypes.indexOf(eventType) + 1);
402
+ //}
403
+
404
+ // Add calendar enum so we can set the correct colours
405
+ if (element.hasAttribute('data-calendar')) {
406
+ const calendar = element.getAttribute('data-calendar');
407
+
408
+ if (!component.calendars.includes(calendar)) component.calendars.push(calendar);
409
+
410
+ element.setAttribute('data-calendar-enum', component.calendars.indexOf(calendar) + 1);
411
+ }
412
+
413
+ if (!element.hasAttribute('data-calendar-enum')) {
414
+ element.setAttribute('data-calendar-enum', 1);
415
+ }
416
+
417
+ if (!element.hasAttribute('data-hours') && !element.hasAttribute('data-days')) {
418
+ if (datetimeArr[1]) {
419
+ element.setAttribute('data-hours', 1);
420
+ } else {
421
+ element.setAttribute('data-days', 1);
422
+ }
423
+ }
424
+
425
+ const getRoundedDate = (minutes, d = new Date()): void => {
426
+ const ms = 1000 * 60 * minutes; // convert minutes to ms
427
+ const roundedDate = new Date(Math.round(d.getTime() / ms) * ms);
428
+
429
+ const newMonth = roundedDate.getMonth();
430
+ const newYear = roundedDate.getFullYear();
431
+ const newDay = roundedDate.getDate();
432
+ const newMinutes = roundedDate.getMinutes();
433
+ const newHour = roundedDate.getHours();
434
+
435
+ const strRoundedDate = `${newYear}-${String(newMonth + 1).padStart(2, '0')}-${String(newDay).padStart(2, '0')}T${String(newHour).padStart(2, '0')}:${String(newMinutes).padStart(2, '0')}`;
436
+
437
+ return strRoundedDate;
438
+ };
439
+
440
+ if (datetimeArr[1]) {
441
+ element.setAttribute('data-start', datetimeArr[1]);
442
+ element.querySelector(':scope > span').setAttribute('data-start', datetimeArr[1]);
443
+
444
+ const roundedDatetime = getRoundedDate(15, new Date(datetime));
445
+ element.setAttribute('datetime', roundedDatetime);
446
+ }
447
+
448
+ if (element.querySelector('.tooltip__content')) {
449
+ const tooltip = element.querySelector('.tooltip__content');
450
+
451
+ tooltip.style.positionAnchor = `--${id}`;
452
+
453
+ element.style.anchorName = `--${id}`;
454
+ }
455
+
456
+ element.classList.add('defaults-added');
457
+ }
458
+
459
+ function adjustEvent(component, element, continued: false): void {
460
+ const datetime = element.getAttribute('datetime');
461
+
462
+ const date = new Date(datetime);
463
+ const dayOfWeek = date.getDay() ? date.getDay() : 7;
464
+
465
+ // Locate where we need to add slots for the buttons to go - We need duplicate slots for the split view and fixed header
466
+ const timeTd = component.shadowRoot.querySelector(
467
+ `.month-wrapper .table--day td:has(span[datetime="${datetime}"])${element.hasAttribute('data-calendar') ? `[data-calendar="${element.getAttribute('data-calendar').replace('_', '')}"]` : ''}`
468
+ );
469
+ const timeTdHeader = component.shadowRoot.querySelector(
470
+ `#week-view-header .table--day td:has(span[datetime="${datetime}"])${element.hasAttribute('data-calendar') ? `[data-calendar="${element.getAttribute('data-calendar').replace('_', '')}"]` : ''}`
471
+ );
472
+
473
+ if (timeTdHeader && timeTdHeader.closest('tr').classList.contains('allday')) {
474
+ // Add the alldays slot for the fixed header
475
+ if (
476
+ !timeTdHeader.querySelector(
477
+ `slot[name="${datetime}${element.hasAttribute('data-calendar') ? `-${element.getAttribute('data-calendar').replace('_', '')}` : ''}-header]"`
478
+ )
479
+ ) {
480
+ timeTdHeader
481
+ .querySelector(`span[datetime="${datetime}"]`)
482
+ .insertAdjacentHTML(
483
+ 'beforeEnd',
484
+ `<slot name="${datetime}${element.hasAttribute('data-calendar') ? `-${element.getAttribute('data-calendar').replace('_', '')}` : ''}-header" class="${continued ? 'continued' : ''}"></slot>`
485
+ );
486
+ }
487
+ }
488
+
489
+ const dateTd = timeTd?.parentElement?.closest('td');
490
+
491
+ // original event needs a slot name adding
492
+ element.setAttribute(
493
+ 'slot',
494
+ `${datetime}${element.hasAttribute('data-calendar') ? `-${element.getAttribute('data-calendar').replace('_', '')}` : ''}`
495
+ );
496
+
497
+ // Add matching slot to the event element to have it show in the correct place on the calendar
498
+ if (timeTd) {
499
+ // Add the default slot
500
+ if (
501
+ !timeTd.querySelector(
502
+ `slot[name="${datetime}${element.hasAttribute('data-calendar') ? `-${element.getAttribute('data-calendar').replace('_', '')}` : ''}"]`
503
+ )
504
+ ) {
505
+ timeTd
506
+ .querySelector(`span[datetime="${datetime}"]`)
507
+ .insertAdjacentHTML(
508
+ 'beforeEnd',
509
+ `<slot name="${datetime}${element.hasAttribute('data-calendar') ? `-${element.getAttribute('data-calendar').replace('_', '')}` : ''}" class="${continued ? 'continued' : ''}"></slot>`
510
+ );
511
+ }
512
+
513
+ // Set the classes need to create the grey bars in the mobile month view
514
+ const events = dateTd.hasAttribute('data-events') ? parseInt(dateTd.getAttribute('data-events')) : 0;
515
+ let hours = dateTd.hasAttribute('data-hours') ? parseFloat(dateTd.getAttribute('data-hours')) : 0;
516
+ hours += element.hasAttribute('data-hours') ? parseFloat(element.getAttribute('data-hours')) : 0;
517
+
518
+ dateTd.setAttribute('data-events', parseInt(events) + 1);
519
+
520
+ if (events + 1 > 2) dateTd.setAttribute('data-more', parseInt(events) + 1 - 2);
521
+
522
+ dateTd.setAttribute('data-hours', hours);
523
+
524
+ dateTd.classList.add('has-event');
525
+
526
+ if (timeTd.closest('tr').classList.contains('has-event')) timeTd.closest('tr').classList.add('multiple-event');
527
+ else timeTd.closest('tr').classList.add('has-event');
528
+
529
+ if (hours > 2) dateTd.classList.add('multi-events');
530
+
531
+ if (hours > 4) dateTd.classList.add('busy-day');
532
+
533
+ if (element.hasAttribute('data-days')) dateTd.classList.add('all-day');
534
+
535
+ if (element.classList.contains('continued')) dateTd.classList.add('continued-day');
536
+ }
537
+
538
+ // Add CSS properties so we can control the size of the event elements for day and week view
539
+ if (element.hasAttribute('data-hours'))
540
+ element.style.setProperty(
541
+ '--event-height',
542
+ `${parseInt(element.getAttribute('data-hours')) * (1.09375 * 4)}rem`
543
+ );
544
+
545
+ if (element.hasAttribute('data-days') && !element.classList.contains('processed')) {
546
+ const eventDayTotal = element.getAttribute('data-days');
547
+
548
+ element.style.setProperty('--event-width', `${eventDayTotal * 100}%`);
549
+ element.style.setProperty('--event-max-width', `${(8 - dayOfWeek) * 100}%`);
550
+ element.classList.add('allday-event');
551
+
552
+ // Create a duplicate event for each day the orginal
553
+ for (let i = 1; i < eventDayTotal; i++) {
554
+ const cloneElement = element.cloneNode(true);
555
+ cloneElement.removeAttribute('data-days');
556
+ cloneElement.removeAttribute('style');
557
+ cloneElement.classList.add('continued');
558
+ cloneElement.classList.add('allday-event');
559
+
560
+ const id = `event${uniqueID(i)}`;
561
+ cloneElement.setAttribute('id', id);
562
+
563
+ if (cloneElement.querySelector('.tooltip__content')) {
564
+ const tooltip = cloneElement.querySelector('.tooltip__content');
565
+ tooltip.style.positionAnchor = `--${id}`;
566
+ cloneElement.style.anchorName = `--${id}`;
567
+ }
568
+
569
+ const newDate = new Date(datetime);
570
+ newDate.setDate(newDate.getDate() + i);
571
+
572
+ const newMonth = newDate.getMonth();
573
+ const newYear = newDate.getFullYear();
574
+ const newDay = newDate.getDate();
575
+ const newDayOfWeek = newDate.getDay() ? newDate.getDay() : 7;
576
+
577
+ const strCloneEvent = `${newYear}-${String(newMonth + 1).padStart(2, '0')}-${String(newDay).padStart(2, '0')}`;
578
+
579
+ cloneElement.setAttribute('data-original-datetime', element.getAttribute('datetime'));
580
+ cloneElement.setAttribute('datetime', strCloneEvent);
581
+
582
+ element.after(cloneElement); // Add after original
583
+ adjustEvent(component, cloneElement, true);
584
+
585
+ if (newDayOfWeek == 1) {
586
+ // Monday
587
+
588
+ cloneElement.style.setProperty('--event-width', `${(eventDayTotal - i) * 100}%`);
589
+ cloneElement.style.setProperty('--event-max-width', `${(8 - newDayOfWeek) * 100}%`);
590
+
591
+ cloneElement.classList.remove('continued');
592
+ }
593
+ }
594
+ }
595
+
596
+ // Add flag so we dont have to re-do the above
597
+ element.classList.add('processed');
598
+ }
599
+
600
+ this.pauseObserver = true;
601
+
602
+ Array.from(this.querySelectorAll('button[datetime]')).forEach((element, index) => {
603
+ setDefaultEventValues(this, element, index);
604
+ adjustEvent(this, element);
605
+ });
606
+
607
+ setTimeout(() => {
608
+ this.pauseObserver = false;
609
+ }, '500');
610
+ }
611
+
612
+ addJSEvents(component): void {
613
+ // Add events to the newly created calendar
614
+ const title = component.shadowRoot?.querySelector('.calendar__title');
615
+ const datePicker = component.shadowRoot?.querySelector(`#date`);
616
+ const viewPicker = component.shadowRoot?.querySelector(`#view`);
617
+ const yearView = this.shadowRoot?.querySelector('#year-view');
618
+
619
+ const today = new Date();
620
+ const date = today.getDate();
621
+ const month = today.getMonth();
622
+ const year = today.getFullYear();
623
+ const strToday = `${year}-${String(month + 1).padStart(2, '0')}-${String(date).padStart(2, '0')}`;
624
+
625
+ const tbody = component.shadowRoot?.querySelector('#calendar > table > tbody');
626
+
627
+ // clicking on the day istelf
628
+ Array.from(component.shadowRoot.querySelectorAll('.month-wrapper > table > tbody > tr > td:has(slot)')).forEach(
629
+ (element) => {
630
+ element.addEventListener('click', (event) => {
631
+ if (!event.target.matches('button')) {
632
+ const elementDate = element.querySelector('time').getAttribute('datetime');
633
+ datePicker.value = elementDate;
634
+
635
+ Array.from(tbody.querySelectorAll(':scope > tr > td')).forEach((innerelement) => {
636
+ innerelement.classList.remove('selected');
637
+ });
638
+
639
+ element.classList.add('selected');
640
+
641
+ // Go to day if the in month view with out split view enabled
642
+
643
+ if (component.shadowRoot.querySelector('[name="split"]:checked') && viewPicker.value == 'month') {
644
+ Array.from(component.querySelectorAll(`[data-slot]`)).forEach((button) => {
645
+ button.setAttribute('slot', button.getAttribute('data-slot'));
646
+ });
647
+
648
+ Array.from(component.querySelectorAll(`[slot^="${datePicker.value}"]`)).forEach((button) => {
649
+ button.setAttribute('data-slot', button.getAttribute('slot'));
650
+ button.removeAttribute('slot');
651
+ });
652
+ } else if (!component.shadowRoot.querySelector('[name="split"]:checked') && viewPicker.value == 'month') {
653
+ viewPicker.value = 'day';
654
+ title?.innerHTML = this.getTitle(datePicker.value, viewPicker.value);
655
+ component.scrollIntoPlace();
656
+ }
657
+ if (viewPicker.value == 'year') {
658
+ viewPicker.value = 'month';
659
+ yearView?.innerHTML = '';
660
+ tbody?.innerHTML = component.createCalendar(datePicker.value, strToday);
661
+ component.addEvents();
662
+ }
663
+ }
664
+ });
665
+ }
666
+ );
667
+
668
+ // Drag and drop
669
+ component.shadowRoot?.querySelectorAll(`#calendar .table--day td span`).forEach((element) => {
670
+ element.addEventListener('dragover', (ev) => {
671
+ ev.preventDefault();
672
+ return false;
673
+ });
674
+
675
+ element.addEventListener('dragenter', (ev) => {
676
+ ev.preventDefault();
677
+ element.classList.add('dragover');
678
+ });
679
+
680
+ element.addEventListener('dragleave', (ev) => {
681
+ ev.preventDefault();
682
+ element.classList.remove('dragover');
683
+ });
684
+
685
+ element.addEventListener('drop', (ev) => {
686
+ ev.preventDefault();
687
+
688
+ const droppedElement = component.querySelector(`#${ev.dataTransfer.getData('text')}`);
689
+ const td = element.closest('td');
690
+ const datetime = element.getAttribute('datetime');
691
+
692
+ element.classList.remove('dragover');
693
+
694
+ // Add a new slot to te span if needed
695
+ if (
696
+ !element.querySelector(
697
+ `slot[name="${datetime}${td.hasAttribute('data-calendar') ? `-${td.getAttribute('data-calendar').replace('_', '')}]` : ''}]"`
698
+ )
699
+ ) {
700
+ element.insertAdjacentHTML(
701
+ 'beforeEnd',
702
+ `<slot name="${datetime}${td.hasAttribute('data-calendar') ? `-${td.getAttribute('data-calendar').replace('_', '')}` : ''}" class=""></slot>`
703
+ );
704
+ }
705
+
706
+ // Update the slot attribute to match the slot the event has been dropped on
707
+ droppedElement?.setAttribute(
708
+ 'slot',
709
+ `${datetime}${td.hasAttribute('data-calendar') ? `-${td.getAttribute('data-calendar').replace('_', '')}` : ''}`
710
+ );
711
+ });
712
+ });
713
+
714
+ // Watch for the event being resized
715
+ const resizeObserver = new ResizeObserver((entries) => {
716
+ for (const entry of entries) {
717
+ if (entry.target.classList.contains('mousedown')) entry.target.classList.add('resizing');
718
+ }
719
+ });
720
+
721
+ if (component.hasAttribute('data-drag')) {
722
+ component.querySelectorAll(`button:not([draggable])`).forEach((element) => {
723
+ element.setAttribute('draggable', 'true');
724
+ element.addEventListener('dragstart', (ev) => {
725
+ ev.dataTransfer.setData('text', ev.target.id); // save the id for when dropped
726
+ });
727
+
728
+ // set onbserver
729
+ resizeObserver.observe(element);
730
+
731
+ element.addEventListener('mousedown', (ev) => {
732
+ element.classList.add('mousedown');
733
+ });
734
+
735
+ element.addEventListener('click', (ev) => {
736
+ if (element.classList.contains('resizing')) {
737
+ ev.stopPropagation();
738
+ ev.stopImmediatePropagation();
739
+
740
+ element.classList.remove('mousedown');
741
+ element.classList.remove('resizing');
742
+
743
+ // Work out the evnt length in hours and set the height
744
+ const span = this.shadowRoot.querySelector(`span[datetime="${element.getAttribute('datetime')}"]`);
745
+ const spanStyles = window.getComputedStyle(span);
746
+ const hours =
747
+ Math.round(parseInt(element.style.height) / parseInt(spanStyles.getPropertyValue('height'))) / 4;
748
+
749
+ element.setAttribute('data-hours', hours);
750
+ element.style.setProperty('--event-height', `${hours * (1.09375 * 4)}rem`);
751
+
752
+ element.style.height = '';
753
+
754
+ // to do dispatch event
755
+ }
756
+ });
757
+ });
758
+ }
759
+
760
+ component.querySelectorAll(`button`).forEach((element) => {
761
+ element.addEventListener('contextmenu', (event) => {
762
+ event.preventDefault();
763
+ event.stopPropagation();
764
+ });
765
+ });
766
+
767
+ component.shadowRoot?.querySelectorAll(`.month-wrapper > table > tbody > tr > td`).forEach((element) => {
768
+ element.addEventListener('contextmenu', (event) => {
769
+ event.preventDefault();
770
+
771
+ const customEvent = new CustomEvent('right-click', {
772
+ detail: {
773
+ clientX: event.clientX,
774
+ clientY: event.clientY,
775
+ element: element,
776
+ datetime: element.querySelector('time').getAttribute('datetime'),
777
+ },
778
+ });
779
+
780
+ console.log(element);
781
+ this.dispatchEvent(customEvent);
782
+ });
783
+ });
784
+ }
785
+
786
+ paginateDate(direction, view, currentDate): string {
787
+ if (view == 'month' || view == 'list') {
788
+ const selectedDate = new Date(currentDate);
789
+
790
+ if (direction == 'next') selectedDate.setMonth(selectedDate.getMonth() + 1);
791
+ else selectedDate.setMonth(selectedDate.getMonth() - 1);
792
+
793
+ const month = selectedDate.getMonth() + 1;
794
+ const year = selectedDate.getFullYear();
795
+
796
+ const strNextMonth = `${year}-${String(month).padStart(2, '0')}-01`;
797
+
798
+ return strNextMonth;
799
+ } else if (view == 'week') {
800
+ //const selectedDate = new Date(currentDate);
801
+ const monday = this.setToMonday(new Date(currentDate));
802
+
803
+ if (direction == 'next') monday.setDate(monday.getDate() + 7);
804
+ else monday.setDate(monday.getDate() - 7);
805
+
806
+ const date = monday.getDate();
807
+ const month = monday.getMonth() + 1;
808
+ const year = monday.getFullYear();
809
+ const strNextWeek = `${year}-${String(month).padStart(2, '0')}-${String(date).padStart(2, '0')}`;
810
+
811
+ return strNextWeek;
812
+ } else if (view == 'year') {
813
+ const selectedDate = new Date(currentDate);
814
+
815
+ if (direction == 'next') selectedDate.setYear(selectedDate.getFullYear() + 1);
816
+ else selectedDate.setYear(selectedDate.getFullYear() - 1);
817
+
818
+ const year = selectedDate.getFullYear();
819
+ const month = selectedDate.getMonth() + 1;
820
+
821
+ const strNextMonth = `${year}-${String(month).padStart(2, '0')}-01`;
822
+
823
+ return strNextMonth;
824
+ }
825
+
826
+ const nextDay = new Date(currentDate);
827
+
828
+ if (direction == 'next') nextDay.setDate(nextDay.getDate() + 1);
829
+ else nextDay.setDate(nextDay.getDate() - 1);
830
+
831
+ const date = nextDay.getDate();
832
+ const month = nextDay.getMonth() + 1;
833
+ const year = nextDay.getFullYear();
834
+ const strNextDay = `${year}-${String(month).padStart(2, '0')}-${String(date).padStart(2, '0')}`;
835
+
836
+ return strNextDay;
837
+ }
838
+
839
+ setWeekDay(): void {
840
+ this.shadowRoot?.querySelectorAll('.out-of-hours').forEach((element) => {
841
+ element.classList.remove('out-of-hours');
842
+ });
843
+
844
+ const startTime = parseInt(this.shadowRoot?.querySelector('#start-time').value.split(':')[0]);
845
+ const endTime = parseInt(this.shadowRoot?.querySelector('#end-time').value.split(':')[0]);
846
+
847
+ this.shadowRoot?.querySelectorAll('[data-hour]').forEach((element) => {
848
+ const hour = parseInt(element.getAttribute('data-hour'));
849
+
850
+ if (hour < startTime) element.classList.add('out-of-hours');
851
+
852
+ if (hour >= endTime) element.classList.add('out-of-hours');
853
+ });
854
+ }
855
+
856
+ scrollIntoPlace(): void {
857
+ const fs = parseInt(window.getComputedStyle(document.body).getPropertyValue('font-size'));
858
+ const startTime = parseInt(this.shadowRoot?.querySelector('#start-time').value.split(':')[0]);
859
+ const scrollPos = startTime * (4.5 * fs);
860
+ const viewPicker = this.shadowRoot?.querySelector(`#view`);
861
+ const wrapper = this.shadowRoot.querySelector('.calendar__wrapper');
862
+
863
+ // scroll
864
+ if (viewPicker.value == 'week')
865
+ wrapper.scrollTo(0, scrollPos); // TO DO work out how much to scroll by
866
+ else if (viewPicker.value == 'day') {
867
+ wrapper.scrollTo(0, scrollPos); // TO DO work out how much to scroll by
868
+ }
869
+ }
870
+
871
+ setupSettings(): void {
872
+ const settingsButton = this.shadowRoot?.querySelector('#settings-button');
873
+ const settingsDialog = this.shadowRoot?.querySelector('#settings');
874
+
875
+ // Setup the pre-defined attributes and display the form elements to match
876
+ if (this.hasAttribute('data-hide-weekends')) settingsDialog.querySelector('#weekends-no').checked = true;
877
+ else settingsDialog.querySelector('#weekends-yes').checked = true;
878
+
879
+ if (this.hasAttribute('data-start-time'))
880
+ settingsDialog.querySelector('#start-time').value = this.getAttribute('data-start-time');
881
+ else this.setAttribute('data-start-time', settingsDialog.querySelector('#start-time').value);
882
+
883
+ if (this.hasAttribute('data-end-time'))
884
+ settingsDialog.querySelector('#end-time').value = this.getAttribute('data-end-time');
885
+ else this.setAttribute('data-end-time', settingsDialog.querySelector('#end-time').value);
886
+
887
+ // open dialog
888
+ settingsButton?.addEventListener('click', () => {
889
+ settingsDialog.showModal();
890
+ settingsDialog.focus();
891
+
892
+ const customEvent = new CustomEvent('open-settings');
893
+
894
+ this.dispatchEvent(customEvent);
895
+ });
896
+
897
+ // On clicking the save button, adjust the data attributes
898
+ settingsDialog?.addEventListener('click', (event) => {
899
+ if (event && event.target.matches('button')) {
900
+ if (event.target.matches('.btn-primary')) {
901
+ if (settingsDialog.querySelector('#weekends-no:checked')) this.setAttribute('data-hide-weekends', 'true');
902
+ else this.removeAttribute('data-hide-weekends');
903
+
904
+ this.setAttribute('data-start-time', settingsDialog.querySelector('#start-time').value);
905
+ this.setAttribute('data-end-time', settingsDialog.querySelector('#end-time').value);
906
+
907
+ this.setWeekDay();
908
+
909
+ const customEvent = new CustomEvent('save-settings');
910
+ this.dispatchEvent(customEvent);
911
+ }
912
+
913
+ const customEvent = new CustomEvent('close-settings');
914
+ this.dispatchEvent(customEvent);
915
+
916
+ settingsDialog.close();
917
+ }
918
+ });
919
+ }
920
+
921
+ setTime(): void {
922
+ if (!this.hasAttribute('data-time')) {
923
+ const today = new Date();
924
+
925
+ const hour = today.getHours();
926
+ const minute = today.getMinutes();
927
+ const time = `${hour}:${minute}`;
928
+
929
+ this.setAttribute('data-time', time);
930
+ }
931
+
932
+ if (this.hasAttribute('data-time')) {
933
+ const time = this.getAttribute('data-time');
934
+ const hour = parseInt(time.split(':')[0]);
935
+ const minute = parseInt(time.split(':')[1]);
936
+
937
+ this.shadowRoot?.querySelectorAll(`[data-hour="${hour}"]`).forEach((element) => {
938
+ element.setAttribute('data-time', time);
939
+ element.classList.add('column-header');
940
+ element.closest('tr')?.style.setProperty('--minute-pos', (minute / 60) * 100 + '%');
941
+ });
942
+ }
943
+ }
944
+
945
+ getYearView(selectedDate, today, sundayFirst: false): string {
946
+ let yearViewStr = '';
947
+
948
+ for (let i = 0; i < 12; i++) {
949
+ console.log(selectedDate);
950
+ const selectedDateObj = new Date(selectedDate);
951
+ const selectedYear = selectedDateObj.getFullYear();
952
+ const selectedFormattedDate = `${selectedYear}-${String(i + 1).padStart(2, '0')}-01`;
953
+
954
+ yearViewStr += `<div class='month-wrapper'>
955
+ <time class="column-header">${this.monthArray[i]}</time>
956
+ <table>
957
+ <thead>
958
+ ${this.createThead(sundayFirst)}
959
+ </thead>
960
+ <tbody>
961
+ ${this.createCalendar(selectedFormattedDate, today, sundayFirst)}
962
+ </tbody>
963
+ </table>
964
+ </div>`;
965
+ }
966
+
967
+ return yearViewStr;
968
+ }
969
+
970
+ connectedCallback(): void {
971
+ // To to transform the below into variables of component to make more re-usable
972
+ const title = this.shadowRoot?.querySelector('.calendar__title');
973
+ const tbody = this.shadowRoot?.querySelector('#calendar > table > tbody');
974
+ const thead = this.shadowRoot?.querySelector('#calendar > table > thead');
975
+ //const tbodySplit = this.shadowRoot?.querySelector('#split > table > tbody');
976
+ //const theadSplit = this.shadowRoot?.querySelector('#split > table > thead');
977
+ const weekViewHeader = this.shadowRoot?.querySelector('#week-view-header > table > tbody');
978
+ const yearView = this.shadowRoot?.querySelector('#year-view');
979
+ const datePicker = this.shadowRoot?.querySelector(`#date`);
980
+ const viewPicker = this.shadowRoot?.querySelector(`#view`);
981
+ const todayButton = this.shadowRoot?.querySelector('#today-button');
982
+ const filtersButton = this.shadowRoot?.querySelector('#filters-button');
983
+ const prevButton = this.shadowRoot?.querySelector('#prev-button');
984
+ const nextButton = this.shadowRoot?.querySelector('#next-button');
985
+ const sundayFirst = this.hasAttribute('data-sunday-first');
986
+
987
+ const splitButton = this.shadowRoot?.querySelector(`[name="split"]`);
988
+
989
+ // set the table head - starting by monday by default but can be changed to sunday
990
+ thead?.innerHTML = this.createThead(sundayFirst);
991
+ //theadSplit?.innerHTML = this.createThead(sundayFirst);
992
+
993
+ // Get a formatted version of todays date
994
+ const today = new Date();
995
+ const date = today.getDate();
996
+ const month = today.getMonth();
997
+ const year = today.getFullYear();
998
+ const strToday = `${year}-${String(month + 1).padStart(2, '0')}-${String(date).padStart(2, '0')}`;
999
+
1000
+ datePicker.value = strToday;
1001
+
1002
+ // Setup the view, month being default
1003
+ if (this.hasAttribute('data-view')) viewPicker.value = this.getAttribute('data-view');
1004
+ else {
1005
+ this.setAttribute('data-view', 'month');
1006
+ viewPicker.value = 'month';
1007
+ }
1008
+
1009
+ if (this.hasAttribute('data-views')) viewPicker?.setAttribute('data-views', this.getAttribute('data-views'));
1010
+
1011
+ // Create the calendars
1012
+ if (this.hasAttribute('data-calendars')) {
1013
+ this.calendars = this.getAttribute('data-calendars').split(',');
1014
+
1015
+ this.calendars.forEach((item, index) => {
1016
+ this.calendars[index] = item.trim();
1017
+ });
1018
+ }
1019
+
1020
+ // Setup the settings dialog
1021
+ this.setupSettings();
1022
+
1023
+ // Setup the calendar then adjust and add events
1024
+ title?.innerHTML = this.getTitle(strToday, viewPicker.value);
1025
+
1026
+ const calendarHtml = this.createCalendar(strToday, strToday, sundayFirst);
1027
+ tbody?.innerHTML = calendarHtml;
1028
+ //tbodySplit?.innerHTML = calendarHtml;
1029
+ weekViewHeader?.innerHTML = calendarHtml;
1030
+
1031
+ if (viewPicker.value == 'year') {
1032
+ yearView?.innerHTML = this.getYearView(datePicker.value, strToday, sundayFirst);
1033
+ tbody?.innerHTML = '';
1034
+ }
1035
+
1036
+ this.addEvents();
1037
+ this.addJSEvents(this);
1038
+ this.setWeekDay(); // Working hours
1039
+ this.setTime(); // Month and day view has a current time indicator
1040
+ this.scrollIntoPlace(); // Scroll into place - month and day view needs have the weekday hours in place
1041
+
1042
+ // #region Add events for the basic top controls
1043
+
1044
+ // Remove the slot attribute on selected days when in split mode
1045
+ splitButton?.addEventListener('change', () => {
1046
+ if (splitButton.checked) {
1047
+ Array.from(this.querySelectorAll(`[slot^="${datePicker.value}"]`)).forEach((button) => {
1048
+ button.setAttribute('data-slot', button.getAttribute('slot'));
1049
+ button.removeAttribute('slot');
1050
+ });
1051
+ } else {
1052
+ Array.from(this.querySelectorAll(`[data-slot]`)).forEach((button) => {
1053
+ button.setAttribute('slot', button.getAttribute('data-slot'));
1054
+ });
1055
+ }
1056
+ });
1057
+
1058
+ const resizeObserver = new ResizeObserver((entries) => {
1059
+ const splitButtonDisplayed = window.getComputedStyle(splitButton?.parentElement, null).display;
1060
+ if (splitButtonDisplayed == 'none') {
1061
+ Array.from(this.querySelectorAll(`[data-slot]`)).forEach((button) => {
1062
+ button.setAttribute('slot', button.getAttribute('data-slot'));
1063
+ });
1064
+ splitButton.checked = false;
1065
+ }
1066
+ });
1067
+
1068
+ resizeObserver.observe(this);
1069
+
1070
+ viewPicker?.addEventListener('change', () => {
1071
+ title?.innerHTML = this.getTitle(datePicker.value, viewPicker.value);
1072
+ this.setAttribute('data-view', viewPicker.value);
1073
+
1074
+ if (viewPicker.value == 'week') {
1075
+ Array.from(this.querySelectorAll(`.allday-event`)).forEach((button) => {
1076
+ button.setAttribute('slot', button.getAttribute('slot') + '-header');
1077
+ });
1078
+ } else {
1079
+ Array.from(this.querySelectorAll(`.allday-event`)).forEach((button) => {
1080
+ button.setAttribute('slot', button.getAttribute('slot')?.replace('-header', ''));
1081
+ });
1082
+ }
1083
+
1084
+ if (viewPicker.value == 'week' || viewPicker.value == 'day') this.scrollIntoPlace();
1085
+
1086
+ if (viewPicker.value != 'month') {
1087
+ Array.from(this.querySelectorAll(`[data-slot^="${datePicker.value}"]`)).forEach((button) => {
1088
+ button.setAttribute('slot', button.getAttribute('data-slot'));
1089
+ });
1090
+ }
1091
+
1092
+ if (viewPicker.value == 'year') {
1093
+ yearView?.innerHTML = this.getYearView(datePicker.value, strToday, sundayFirst);
1094
+ tbody?.innerHTML = '';
1095
+ this.addEvents();
1096
+ this.addJSEvents(this);
1097
+ this.setWeekDay(); // Working hours
1098
+ this.setTime(); // Month and day view has a current time indicator
1099
+ this.scrollIntoPlace();
1100
+ } else if (tbody?.innerHTML == '') {
1101
+ yearView?.innerHTML = '';
1102
+ tbody?.innerHTML = this.createCalendar(datePicker.value, strToday);
1103
+ this.addEvents();
1104
+ this.addJSEvents(this);
1105
+ this.setWeekDay(); // Working hours
1106
+ this.setTime(); // Month and day view has a current time indicator
1107
+ this.scrollIntoPlace();
1108
+ }
1109
+
1110
+ const customEvent = new CustomEvent('change-view', {
1111
+ detail: {
1112
+ view: viewPicker.value,
1113
+ date: datePicker.value,
1114
+ },
1115
+ });
1116
+
1117
+ this.dispatchEvent(customEvent);
1118
+ });
1119
+
1120
+ function resetCalendar(component): void {
1121
+ if (viewPicker.value == 'year') {
1122
+ yearView?.innerHTML = component.getYearView(datePicker.value, strToday, sundayFirst);
1123
+ tbody?.innerHTML = '';
1124
+ component.addEvents();
1125
+ component.addJSEvents(component);
1126
+ component.setWeekDay(); // Working hours
1127
+ component.setTime(); // Month and day view has a current time indicator
1128
+ } else {
1129
+ const calendarHtml = component.createCalendar(datePicker.value, strToday);
1130
+ tbody?.innerHTML = calendarHtml;
1131
+ //tbodySplit?.innerHTML = calendarHtml;
1132
+ weekViewHeader?.innerHTML = calendarHtml;
1133
+
1134
+ component.addEvents();
1135
+ component.addJSEvents(component);
1136
+ component.setWeekDay();
1137
+ component.setTime();
1138
+ }
1139
+ }
1140
+
1141
+ function updateCalendar(component): void {
1142
+ Array.from(component.shadowRoot.querySelectorAll('.selected')).forEach((element) => {
1143
+ element.classList.remove('selected');
1144
+ });
1145
+
1146
+ Array.from(
1147
+ component.shadowRoot.querySelectorAll(
1148
+ `td:has(time[datetime="${datePicker.value}"]):not(.prev-month, .next-month)`
1149
+ )
1150
+ ).forEach((element) => {
1151
+ element.classList.add('selected');
1152
+ });
1153
+ }
1154
+
1155
+ datePicker?.addEventListener('change', () => {
1156
+ title?.innerHTML = this.getTitle(datePicker.value, viewPicker.value);
1157
+
1158
+ if (this.shadowRoot.querySelector(`td:has(time[datetime="${datePicker.value}"]):not(.prev-month, .next-month)`))
1159
+ updateCalendar(this);
1160
+ else resetCalendar(this);
1161
+
1162
+ const customEvent = new CustomEvent('change-date', {
1163
+ detail: {
1164
+ view: viewPicker.value,
1165
+ date: datePicker.value,
1166
+ },
1167
+ });
1168
+
1169
+ this.dispatchEvent(customEvent);
1170
+ });
1171
+
1172
+ filtersButton?.addEventListener('click', () => {
1173
+ const customEvent = new CustomEvent('open-filters');
1174
+ this.dispatchEvent(customEvent);
1175
+ });
1176
+
1177
+ // HTML Observer
1178
+ const htmlUpdated = (mutationList: any, observer: any): void => {
1179
+ observer.disconnect();
1180
+
1181
+ console.log(this.pauseObserver);
1182
+
1183
+ if (this.pauseObserver == false) {
1184
+ for (const mutation of mutationList) {
1185
+ if (
1186
+ mutation.type == 'characterData' ||
1187
+ (mutation.type == 'childList' && mutation.addedNodes.length) ||
1188
+ mutation.type === 'attributes'
1189
+ ) {
1190
+ //resetCalendar(this);
1191
+ this.addEvents();
1192
+ }
1193
+ }
1194
+ }
1195
+
1196
+ observer.observe(this, { childList: true, characterData: true, subtree: true, attributes: true });
1197
+ };
1198
+
1199
+ const observer = new MutationObserver(htmlUpdated);
1200
+ observer.observe(this, { childList: true, characterData: true, subtree: true, attributes: true });
1201
+
1202
+ todayButton?.addEventListener('click', () => {
1203
+ datePicker.value = strToday;
1204
+ title?.innerHTML = this.getTitle(datePicker.value, viewPicker.value);
1205
+
1206
+ if (this.shadowRoot.querySelector(`td:has(time[datetime="${datePicker.value}"]):not(.prev-month, .next-month)`))
1207
+ updateCalendar(this);
1208
+ else resetCalendar(this);
1209
+
1210
+ const customEvent = new CustomEvent('change-date-today', {
1211
+ detail: {
1212
+ view: viewPicker.value,
1213
+ date: datePicker.value,
1214
+ },
1215
+ });
1216
+
1217
+ this.dispatchEvent(customEvent);
1218
+ });
1219
+
1220
+ prevButton?.addEventListener('click', () => {
1221
+ datePicker.value = this.paginateDate('prev', viewPicker.value, datePicker.value);
1222
+ title?.innerHTML = this.getTitle(datePicker.value, viewPicker.value);
1223
+
1224
+ if (this.shadowRoot.querySelector(`td:has(time[datetime="${datePicker.value}"]):not(.prev-month, .next-month)`))
1225
+ updateCalendar(this);
1226
+ else resetCalendar(this);
1227
+
1228
+ const customEvent = new CustomEvent('change-date-previous', {
1229
+ detail: {
1230
+ view: viewPicker.value,
1231
+ date: datePicker.value,
1232
+ },
1233
+ });
1234
+
1235
+ this.dispatchEvent(customEvent);
1236
+ });
1237
+
1238
+ nextButton?.addEventListener('click', () => {
1239
+ datePicker.value = this.paginateDate('next', viewPicker.value, datePicker.value);
1240
+ title?.innerHTML = this.getTitle(datePicker.value, viewPicker.value);
1241
+
1242
+ console.log(datePicker.value);
1243
+
1244
+ if (this.shadowRoot.querySelector(`td:has(time[datetime="${datePicker.value}"]):not(.prev-month, .next-month)`))
1245
+ updateCalendar(this);
1246
+ else resetCalendar(this);
1247
+
1248
+ const customEvent = new CustomEvent('change-date-next', {
1249
+ detail: {
1250
+ view: viewPicker.value,
1251
+ date: datePicker.value,
1252
+ },
1253
+ });
1254
+
1255
+ this.dispatchEvent(customEvent);
1256
+ });
1257
+ // #endregion
1258
+
1259
+ // TODO
1260
+ trackComponent(this, 'iam-calendar', [
1261
+ 'open-filters',
1262
+ 'change-view',
1263
+ 'change-date',
1264
+ 'change-date-today',
1265
+ 'change-date-previous',
1266
+ 'change-date-next',
1267
+ 'open-settings',
1268
+ 'close-settings',
1269
+ 'save-settings',
1270
+ ]);
1271
+ }
1272
+
1273
+ static get observedAttributes(): any {
1274
+ return ['data-calendars', 'data-view'];
1275
+ }
1276
+
1277
+ attributeChangedCallback(attrName, oldVal, newVal): void {
1278
+ this.pauseObserver = true;
1279
+
1280
+ switch (attrName) {
1281
+ case 'data-calendars': {
1282
+ if (oldVal != newVal) {
1283
+ const tbody = this.shadowRoot?.querySelector('#calendar > table > tbody');
1284
+ const weekViewHeader = this.shadowRoot?.querySelector('#week-view-header > table > tbody');
1285
+ const datePicker = this.shadowRoot?.querySelector(`#date`);
1286
+
1287
+ // Get a formatted version of todays date
1288
+ const today = new Date();
1289
+ const date = today.getDate();
1290
+ const month = today.getMonth();
1291
+ const year = today.getFullYear();
1292
+ const strToday = `${year}-${String(month + 1).padStart(2, '0')}-${String(date).padStart(2, '0')}`;
1293
+
1294
+ if (this.hasAttribute('data-calendars')) {
1295
+ this.calendars = this.getAttribute('data-calendars').split(',');
1296
+
1297
+ this.calendars.forEach((item, index) => {
1298
+ this.calendars[index] = item.trim();
1299
+ });
1300
+ }
1301
+
1302
+ const calendarHtml = this.createCalendar(datePicker.value, strToday);
1303
+ tbody?.innerHTML = calendarHtml;
1304
+ weekViewHeader?.innerHTML = calendarHtml;
1305
+
1306
+ this.addEvents();
1307
+ this.addJSEvents(this);
1308
+ this.setWeekDay();
1309
+ this.setTime();
1310
+ }
1311
+ break;
1312
+ }
1313
+ case 'data-view': {
1314
+ if (oldVal != newVal) {
1315
+ const viewPicker = this.shadowRoot?.querySelector(`#view`);
1316
+
1317
+ viewPicker.value = newVal;
1318
+ viewPicker.dispatchEvent(new Event('change'));
1319
+ }
1320
+ break;
1321
+ }
1322
+ }
1323
+
1324
+ setTimeout(() => {
1325
+ this.pauseObserver = false;
1326
+ }, '500');
1327
+ }
1328
+ }
1329
+
1330
+ export default iamCalendar;