@syncfusion/ej2-schedule 30.2.7 → 31.1.17

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 (304) hide show
  1. package/dist/ej2-schedule.min.js +2 -2
  2. package/dist/ej2-schedule.umd.min.js +2 -2
  3. package/dist/ej2-schedule.umd.min.js.map +1 -1
  4. package/dist/es6/ej2-schedule.es2015.js +110 -36
  5. package/dist/es6/ej2-schedule.es2015.js.map +1 -1
  6. package/dist/es6/ej2-schedule.es5.js +110 -36
  7. package/dist/es6/ej2-schedule.es5.js.map +1 -1
  8. package/dist/global/ej2-schedule.min.js +2 -2
  9. package/dist/global/ej2-schedule.min.js.map +1 -1
  10. package/dist/global/index.d.ts +1 -1
  11. package/dist/ts/common/calendar-util.d.ts +92 -0
  12. package/dist/ts/common/calendar-util.ts +261 -0
  13. package/dist/ts/common/index.d.ts +4 -0
  14. package/dist/ts/common/index.ts +4 -0
  15. package/dist/ts/components.d.ts +5 -0
  16. package/dist/ts/components.ts +5 -0
  17. package/dist/ts/index.d.ts +6 -0
  18. package/dist/ts/index.ts +7 -0
  19. package/dist/ts/recurrence-editor/date-generator.d.ts +76 -0
  20. package/dist/ts/recurrence-editor/date-generator.ts +1699 -0
  21. package/dist/ts/recurrence-editor/index.d.ts +6 -0
  22. package/dist/ts/recurrence-editor/index.ts +6 -0
  23. package/dist/ts/recurrence-editor/recurrence-editor-model.d.ts +112 -0
  24. package/dist/ts/recurrence-editor/recurrence-editor.d.ts +245 -0
  25. package/dist/ts/recurrence-editor/recurrence-editor.ts +1257 -0
  26. package/dist/ts/schedule/actions/action-base.d.ts +44 -0
  27. package/dist/ts/schedule/actions/action-base.ts +493 -0
  28. package/dist/ts/schedule/actions/crud.d.ts +41 -0
  29. package/dist/ts/schedule/actions/crud.ts +784 -0
  30. package/dist/ts/schedule/actions/data.d.ts +63 -0
  31. package/dist/ts/schedule/actions/data.ts +128 -0
  32. package/dist/ts/schedule/actions/drag.d.ts +75 -0
  33. package/dist/ts/schedule/actions/drag.ts +1401 -0
  34. package/dist/ts/schedule/actions/keyboard.d.ts +100 -0
  35. package/dist/ts/schedule/actions/keyboard.ts +1435 -0
  36. package/dist/ts/schedule/actions/resize.d.ts +27 -0
  37. package/dist/ts/schedule/actions/resize.ts +602 -0
  38. package/dist/ts/schedule/actions/scroll.d.ts +69 -0
  39. package/dist/ts/schedule/actions/scroll.ts +105 -0
  40. package/dist/ts/schedule/actions/touch.d.ts +32 -0
  41. package/dist/ts/schedule/actions/touch.ts +314 -0
  42. package/dist/ts/schedule/actions/virtual-scroll.d.ts +55 -0
  43. package/dist/ts/schedule/actions/virtual-scroll.ts +596 -0
  44. package/dist/ts/schedule/actions/work-cells.d.ts +14 -0
  45. package/dist/ts/schedule/actions/work-cells.ts +151 -0
  46. package/dist/ts/schedule/base/constant.d.ts +102 -0
  47. package/dist/ts/schedule/base/constant.ts +103 -0
  48. package/dist/ts/schedule/base/css-constant.d.ts +475 -0
  49. package/dist/ts/schedule/base/css-constant.ts +475 -0
  50. package/dist/ts/schedule/base/interface.d.ts +673 -0
  51. package/dist/ts/schedule/base/interface.ts +738 -0
  52. package/dist/ts/schedule/base/resource.d.ts +59 -0
  53. package/dist/ts/schedule/base/resource.ts +1091 -0
  54. package/dist/ts/schedule/base/schedule-model.d.ts +930 -0
  55. package/dist/ts/schedule/base/schedule.d.ts +1967 -0
  56. package/dist/ts/schedule/base/schedule.ts +4221 -0
  57. package/dist/ts/schedule/base/type.d.ts +134 -0
  58. package/dist/ts/schedule/base/type.ts +142 -0
  59. package/dist/ts/schedule/base/util.d.ts +266 -0
  60. package/dist/ts/schedule/base/util.ts +492 -0
  61. package/dist/ts/schedule/event-renderer/agenda-base.d.ts +15 -0
  62. package/dist/ts/schedule/event-renderer/agenda-base.ts +423 -0
  63. package/dist/ts/schedule/event-renderer/event-base.d.ts +101 -0
  64. package/dist/ts/schedule/event-renderer/event-base.ts +1501 -0
  65. package/dist/ts/schedule/event-renderer/inline-edit.d.ts +23 -0
  66. package/dist/ts/schedule/event-renderer/inline-edit.ts +287 -0
  67. package/dist/ts/schedule/event-renderer/month.d.ts +60 -0
  68. package/dist/ts/schedule/event-renderer/month.ts +760 -0
  69. package/dist/ts/schedule/event-renderer/timeline-view.d.ts +51 -0
  70. package/dist/ts/schedule/event-renderer/timeline-view.ts +606 -0
  71. package/dist/ts/schedule/event-renderer/vertical-view.d.ts +57 -0
  72. package/dist/ts/schedule/event-renderer/vertical-view.ts +898 -0
  73. package/dist/ts/schedule/event-renderer/year.d.ts +27 -0
  74. package/dist/ts/schedule/event-renderer/year.ts +623 -0
  75. package/dist/ts/schedule/exports/calendar-export.d.ts +16 -0
  76. package/dist/ts/schedule/exports/calendar-export.ts +160 -0
  77. package/dist/ts/schedule/exports/calendar-import.d.ts +18 -0
  78. package/dist/ts/schedule/exports/calendar-import.ts +277 -0
  79. package/dist/ts/schedule/exports/excel-export.d.ts +14 -0
  80. package/dist/ts/schedule/exports/excel-export.ts +89 -0
  81. package/dist/ts/schedule/exports/index.d.ts +7 -0
  82. package/dist/ts/schedule/exports/index.ts +7 -0
  83. package/dist/ts/schedule/exports/print.d.ts +20 -0
  84. package/dist/ts/schedule/exports/print.ts +233 -0
  85. package/dist/ts/schedule/index.d.ts +26 -0
  86. package/dist/ts/schedule/index.ts +26 -0
  87. package/dist/ts/schedule/models/event-settings-model.d.ts +165 -0
  88. package/dist/ts/schedule/models/event-settings.d.ts +149 -0
  89. package/dist/ts/schedule/models/event-settings.ts +187 -0
  90. package/dist/ts/schedule/models/field-options-model.d.ts +37 -0
  91. package/dist/ts/schedule/models/field-options.d.ts +31 -0
  92. package/dist/ts/schedule/models/field-options.ts +41 -0
  93. package/dist/ts/schedule/models/fields-model.d.ts +129 -0
  94. package/dist/ts/schedule/models/fields.d.ts +117 -0
  95. package/dist/ts/schedule/models/fields.ts +149 -0
  96. package/dist/ts/schedule/models/group-model.d.ts +69 -0
  97. package/dist/ts/schedule/models/group.d.ts +60 -0
  98. package/dist/ts/schedule/models/group.ts +75 -0
  99. package/dist/ts/schedule/models/header-rows-model.d.ts +33 -0
  100. package/dist/ts/schedule/models/header-rows.d.ts +30 -0
  101. package/dist/ts/schedule/models/header-rows.ts +35 -0
  102. package/dist/ts/schedule/models/models.d.ts +14 -0
  103. package/dist/ts/schedule/models/models.ts +15 -0
  104. package/dist/ts/schedule/models/quick-info-templates-model.d.ts +52 -0
  105. package/dist/ts/schedule/models/quick-info-templates.d.ts +47 -0
  106. package/dist/ts/schedule/models/quick-info-templates.ts +56 -0
  107. package/dist/ts/schedule/models/resources-model.d.ts +122 -0
  108. package/dist/ts/schedule/models/resources.d.ts +106 -0
  109. package/dist/ts/schedule/models/resources.ts +138 -0
  110. package/dist/ts/schedule/models/time-scale-model.d.ts +57 -0
  111. package/dist/ts/schedule/models/time-scale.d.ts +50 -0
  112. package/dist/ts/schedule/models/time-scale.ts +61 -0
  113. package/dist/ts/schedule/models/toolbar-model.d.ts +196 -0
  114. package/dist/ts/schedule/models/toolbar.d.ts +176 -0
  115. package/dist/ts/schedule/models/toolbar.ts +196 -0
  116. package/dist/ts/schedule/models/views-model.d.ts +370 -0
  117. package/dist/ts/schedule/models/views.d.ts +335 -0
  118. package/dist/ts/schedule/models/views.ts +408 -0
  119. package/dist/ts/schedule/models/work-hours-model.d.ts +29 -0
  120. package/dist/ts/schedule/models/work-hours.d.ts +24 -0
  121. package/dist/ts/schedule/models/work-hours.ts +31 -0
  122. package/dist/ts/schedule/popups/event-tooltip.d.ts +16 -0
  123. package/dist/ts/schedule/popups/event-tooltip.ts +203 -0
  124. package/dist/ts/schedule/popups/event-window.d.ts +118 -0
  125. package/dist/ts/schedule/popups/event-window.ts +2055 -0
  126. package/dist/ts/schedule/popups/form-validator.d.ts +16 -0
  127. package/dist/ts/schedule/popups/form-validator.ts +110 -0
  128. package/dist/ts/schedule/popups/quick-popups.d.ts +78 -0
  129. package/dist/ts/schedule/popups/quick-popups.ts +1470 -0
  130. package/dist/ts/schedule/renderer/agenda.d.ts +45 -0
  131. package/dist/ts/schedule/renderer/agenda.ts +497 -0
  132. package/dist/ts/schedule/renderer/day.d.ts +20 -0
  133. package/dist/ts/schedule/renderer/day.ts +28 -0
  134. package/dist/ts/schedule/renderer/header-renderer.d.ts +48 -0
  135. package/dist/ts/schedule/renderer/header-renderer.ts +736 -0
  136. package/dist/ts/schedule/renderer/month-agenda.d.ts +29 -0
  137. package/dist/ts/schedule/renderer/month-agenda.ts +184 -0
  138. package/dist/ts/schedule/renderer/month.d.ts +61 -0
  139. package/dist/ts/schedule/renderer/month.ts +766 -0
  140. package/dist/ts/schedule/renderer/renderer.d.ts +13 -0
  141. package/dist/ts/schedule/renderer/renderer.ts +165 -0
  142. package/dist/ts/schedule/renderer/timeline-header-row.d.ts +15 -0
  143. package/dist/ts/schedule/renderer/timeline-header-row.ts +132 -0
  144. package/dist/ts/schedule/renderer/timeline-month.d.ts +29 -0
  145. package/dist/ts/schedule/renderer/timeline-month.ts +184 -0
  146. package/dist/ts/schedule/renderer/timeline-view.d.ts +31 -0
  147. package/dist/ts/schedule/renderer/timeline-view.ts +308 -0
  148. package/dist/ts/schedule/renderer/timeline-year.d.ts +22 -0
  149. package/dist/ts/schedule/renderer/timeline-year.ts +450 -0
  150. package/dist/ts/schedule/renderer/vertical-view.d.ts +63 -0
  151. package/dist/ts/schedule/renderer/vertical-view.ts +911 -0
  152. package/dist/ts/schedule/renderer/view-base.d.ts +83 -0
  153. package/dist/ts/schedule/renderer/view-base.ts +709 -0
  154. package/dist/ts/schedule/renderer/week.d.ts +22 -0
  155. package/dist/ts/schedule/renderer/week.ts +35 -0
  156. package/dist/ts/schedule/renderer/work-week.d.ts +22 -0
  157. package/dist/ts/schedule/renderer/work-week.ts +36 -0
  158. package/dist/ts/schedule/renderer/year.d.ts +46 -0
  159. package/dist/ts/schedule/renderer/year.ts +470 -0
  160. package/dist/ts/schedule/timezone/timezone.d.ts +16 -0
  161. package/dist/ts/schedule/timezone/timezone.ts +313 -0
  162. package/package.json +56 -21
  163. package/src/schedule/actions/action-base.js +3 -0
  164. package/src/schedule/actions/drag.js +11 -4
  165. package/src/schedule/actions/keyboard.js +1 -1
  166. package/src/schedule/actions/resize.js +8 -5
  167. package/src/schedule/base/css-constant.d.ts +2 -0
  168. package/src/schedule/base/css-constant.js +2 -0
  169. package/src/schedule/base/schedule.js +15 -1
  170. package/src/schedule/event-renderer/agenda-base.d.ts +1 -1
  171. package/src/schedule/event-renderer/agenda-base.js +5 -4
  172. package/src/schedule/event-renderer/inline-edit.js +11 -6
  173. package/src/schedule/event-renderer/month.js +5 -3
  174. package/src/schedule/event-renderer/vertical-view.js +3 -0
  175. package/src/schedule/event-renderer/year.d.ts +2 -0
  176. package/src/schedule/event-renderer/year.js +28 -4
  177. package/src/schedule/popups/event-tooltip.js +4 -0
  178. package/src/schedule/popups/event-window.js +2 -2
  179. package/src/schedule/popups/quick-popups.js +5 -1
  180. package/src/schedule/renderer/agenda.js +3 -2
  181. package/src/schedule/renderer/vertical-view.js +1 -1
  182. package/src/schedule/renderer/year.js +3 -2
  183. package/styles/bds-lite.css +11 -8
  184. package/styles/bds.css +11 -8
  185. package/styles/bootstrap-dark-lite.css +12 -9
  186. package/styles/bootstrap-dark.css +12 -9
  187. package/styles/bootstrap-lite.css +12 -9
  188. package/styles/bootstrap.css +12 -9
  189. package/styles/bootstrap4-lite.css +11 -8
  190. package/styles/bootstrap4.css +11 -8
  191. package/styles/bootstrap5-dark-lite.css +11 -8
  192. package/styles/bootstrap5-dark.css +11 -8
  193. package/styles/bootstrap5-lite.css +11 -8
  194. package/styles/bootstrap5.3-lite.css +11 -8
  195. package/styles/bootstrap5.3.css +11 -8
  196. package/styles/bootstrap5.css +11 -8
  197. package/styles/fabric-dark-lite.css +12 -9
  198. package/styles/fabric-dark.css +12 -9
  199. package/styles/fabric-lite.css +12 -9
  200. package/styles/fabric.css +12 -9
  201. package/styles/fluent-dark-lite.css +13 -10
  202. package/styles/fluent-dark.css +13 -10
  203. package/styles/fluent-lite.css +13 -10
  204. package/styles/fluent.css +13 -10
  205. package/styles/fluent2-lite.css +11 -8
  206. package/styles/fluent2.css +11 -8
  207. package/styles/highcontrast-light-lite.css +12 -9
  208. package/styles/highcontrast-light.css +12 -9
  209. package/styles/highcontrast-lite.css +12 -9
  210. package/styles/highcontrast.css +12 -9
  211. package/styles/material-dark-lite.css +12 -9
  212. package/styles/material-dark.css +12 -9
  213. package/styles/material-lite.css +12 -9
  214. package/styles/material.css +12 -9
  215. package/styles/material3-dark-lite.css +11 -8
  216. package/styles/material3-dark.css +11 -8
  217. package/styles/material3-lite.css +11 -8
  218. package/styles/material3.css +11 -8
  219. package/styles/recurrence-editor/_bds-definition.scss +1 -0
  220. package/styles/recurrence-editor/_bootstrap-dark-definition.scss +1 -0
  221. package/styles/recurrence-editor/_bootstrap-definition.scss +1 -0
  222. package/styles/recurrence-editor/_bootstrap4-definition.scss +1 -0
  223. package/styles/recurrence-editor/_bootstrap5-definition.scss +1 -0
  224. package/styles/recurrence-editor/_bootstrap5.3-definition.scss +1 -0
  225. package/styles/recurrence-editor/_fabric-dark-definition.scss +1 -0
  226. package/styles/recurrence-editor/_fabric-definition.scss +1 -0
  227. package/styles/recurrence-editor/_fluent-definition.scss +1 -0
  228. package/styles/recurrence-editor/_fluent2-definition.scss +1 -0
  229. package/styles/recurrence-editor/_fusionnew-definition.scss +1 -0
  230. package/styles/recurrence-editor/_highcontrast-definition.scss +1 -0
  231. package/styles/recurrence-editor/_highcontrast-light-definition.scss +1 -0
  232. package/styles/recurrence-editor/_layout.scss +5 -1
  233. package/styles/recurrence-editor/_material-dark-definition.scss +1 -0
  234. package/styles/recurrence-editor/_material-definition.scss +1 -0
  235. package/styles/recurrence-editor/_material3-definition.scss +1 -0
  236. package/styles/recurrence-editor/_tailwind-definition.scss +1 -0
  237. package/styles/recurrence-editor/_tailwind3-definition.scss +1 -0
  238. package/styles/recurrence-editor/bds.css +3 -0
  239. package/styles/recurrence-editor/bootstrap-dark.css +4 -1
  240. package/styles/recurrence-editor/bootstrap.css +4 -1
  241. package/styles/recurrence-editor/bootstrap4.css +3 -0
  242. package/styles/recurrence-editor/bootstrap5-dark.css +3 -0
  243. package/styles/recurrence-editor/bootstrap5.3.css +3 -0
  244. package/styles/recurrence-editor/bootstrap5.css +3 -0
  245. package/styles/recurrence-editor/fabric-dark.css +4 -1
  246. package/styles/recurrence-editor/fabric.css +4 -1
  247. package/styles/recurrence-editor/fluent-dark.css +4 -1
  248. package/styles/recurrence-editor/fluent.css +4 -1
  249. package/styles/recurrence-editor/fluent2.css +3 -0
  250. package/styles/recurrence-editor/highcontrast-light.css +4 -1
  251. package/styles/recurrence-editor/highcontrast.css +4 -1
  252. package/styles/recurrence-editor/material-dark.css +4 -1
  253. package/styles/recurrence-editor/material.css +4 -1
  254. package/styles/recurrence-editor/material3-dark.css +3 -0
  255. package/styles/recurrence-editor/material3.css +3 -0
  256. package/styles/recurrence-editor/tailwind-dark.css +3 -0
  257. package/styles/recurrence-editor/tailwind.css +3 -0
  258. package/styles/recurrence-editor/tailwind3.css +3 -0
  259. package/styles/schedule/_bds-definition.scss +2 -0
  260. package/styles/schedule/_bootstrap-dark-definition.scss +2 -0
  261. package/styles/schedule/_bootstrap-definition.scss +2 -0
  262. package/styles/schedule/_bootstrap4-definition.scss +2 -0
  263. package/styles/schedule/_bootstrap5-definition.scss +2 -0
  264. package/styles/schedule/_bootstrap5.3-definition.scss +2 -0
  265. package/styles/schedule/_fabric-dark-definition.scss +2 -0
  266. package/styles/schedule/_fabric-definition.scss +2 -0
  267. package/styles/schedule/_fluent-definition.scss +3 -1
  268. package/styles/schedule/_fluent2-definition.scss +2 -0
  269. package/styles/schedule/_fusionnew-definition.scss +2 -0
  270. package/styles/schedule/_highcontrast-definition.scss +2 -0
  271. package/styles/schedule/_highcontrast-light-definition.scss +2 -0
  272. package/styles/schedule/_layout.scss +12 -11
  273. package/styles/schedule/_material-dark-definition.scss +2 -0
  274. package/styles/schedule/_material-definition.scss +2 -0
  275. package/styles/schedule/_material3-definition.scss +2 -0
  276. package/styles/schedule/_tailwind-definition.scss +2 -0
  277. package/styles/schedule/_tailwind3-definition.scss +2 -0
  278. package/styles/schedule/bds.css +8 -8
  279. package/styles/schedule/bootstrap-dark.css +8 -8
  280. package/styles/schedule/bootstrap.css +8 -8
  281. package/styles/schedule/bootstrap4.css +8 -8
  282. package/styles/schedule/bootstrap5-dark.css +8 -8
  283. package/styles/schedule/bootstrap5.3.css +8 -8
  284. package/styles/schedule/bootstrap5.css +8 -8
  285. package/styles/schedule/fabric-dark.css +8 -8
  286. package/styles/schedule/fabric.css +8 -8
  287. package/styles/schedule/fluent-dark.css +9 -9
  288. package/styles/schedule/fluent.css +9 -9
  289. package/styles/schedule/fluent2.css +8 -8
  290. package/styles/schedule/highcontrast-light.css +8 -8
  291. package/styles/schedule/highcontrast.css +8 -8
  292. package/styles/schedule/material-dark.css +8 -8
  293. package/styles/schedule/material.css +8 -8
  294. package/styles/schedule/material3-dark.css +8 -8
  295. package/styles/schedule/material3.css +8 -8
  296. package/styles/schedule/tailwind-dark.css +8 -8
  297. package/styles/schedule/tailwind.css +8 -8
  298. package/styles/schedule/tailwind3.css +8 -8
  299. package/styles/tailwind-dark-lite.css +11 -8
  300. package/styles/tailwind-dark.css +11 -8
  301. package/styles/tailwind-lite.css +11 -8
  302. package/styles/tailwind.css +11 -8
  303. package/styles/tailwind3-lite.css +11 -8
  304. package/styles/tailwind3.css +11 -8
@@ -0,0 +1,1470 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { L10n, closest, EventHandler, isNullOrUndefined, formatUnit, append, AnimationModel, KeyboardEventArgs } from '@syncfusion/ej2-base';
3
+ import { addClass, removeClass, createElement, remove, extend } from '@syncfusion/ej2-base';
4
+ import { Dialog, Popup, isCollide, ButtonPropsModel, BeforeCloseEventArgs } from '@syncfusion/ej2-popups';
5
+ import { Button } from '@syncfusion/ej2-buttons';
6
+ import { Input, FormValidator } from '@syncfusion/ej2-inputs';
7
+ import { Schedule } from '../base/schedule';
8
+ import { ResourcesModel } from '../models/models';
9
+ import { RecurrenceEditor } from '../../recurrence-editor/index';
10
+ import {
11
+ CellClickEventArgs, EventClickArgs, EventFieldsMapping, PopupOpenEventArgs,
12
+ EventRenderedArgs, EJ2Instance, TdData, PopupCloseEventArgs, CallbackFunction
13
+ } from '../base/interface';
14
+ import { PopupType, TemplateType } from '../base/type';
15
+ import { FieldValidator } from './form-validator';
16
+ import * as event from '../base/constant';
17
+ import * as cls from '../base/css-constant';
18
+ import * as util from '../base/util';
19
+
20
+ const EVENT_FIELD: string = 'e-field';
21
+
22
+ /**
23
+ * Quick Popups interactions
24
+ */
25
+ export class QuickPopups {
26
+ private l10n: L10n;
27
+ private parent: Schedule;
28
+ private isMultipleEventSelect: boolean = false;
29
+ public quickDialog: Dialog;
30
+ public quickPopup: Popup;
31
+ public morePopup: Popup;
32
+ private fieldValidator: FieldValidator;
33
+ private isCrudAction: boolean = false;
34
+ public lastEvent: Record<string, any>;
35
+ private dialogEvent: Event;
36
+
37
+ constructor(parent: Schedule) {
38
+ this.parent = parent;
39
+ this.l10n = this.parent.localeObj;
40
+ this.fieldValidator = new FieldValidator();
41
+ this.render();
42
+ this.addEventListener();
43
+ }
44
+
45
+ private render(): void {
46
+ this.renderQuickPopup();
47
+ this.renderMorePopup();
48
+ this.renderQuickDialog();
49
+ }
50
+
51
+ private renderQuickPopup(): void {
52
+ const quickPopupWrapper: HTMLElement = createElement('div', { className: cls.POPUP_WRAPPER_CLASS + ' e-popup-close', attrs: { role: 'dialog' } });
53
+ if (this.parent.isAdaptive) {
54
+ document.body.appendChild(quickPopupWrapper);
55
+ addClass([quickPopupWrapper], cls.DEVICE_CLASS);
56
+ } else {
57
+ this.parent.element.appendChild(quickPopupWrapper);
58
+ }
59
+ this.quickPopup = new Popup(quickPopupWrapper, {
60
+ targetType: (this.parent.isAdaptive ? 'container' : 'relative'),
61
+ enableRtl: this.parent.enableRtl,
62
+ open: this.quickPopupOpen.bind(this),
63
+ close: this.quickPopupClose.bind(this),
64
+ hideAnimation: (this.parent.isAdaptive ? { name: 'ZoomOut' } : { name: 'FadeOut', duration: 150 }),
65
+ showAnimation: (this.parent.isAdaptive ? { name: 'ZoomIn' } : { name: 'FadeIn', duration: 150 }),
66
+ collision: (this.parent.isAdaptive ? { X: 'fit', Y: 'fit' } :
67
+ (this.parent.enableRtl ? { X: 'flip', Y: 'fit' } : { X: 'none', Y: 'fit' })),
68
+ position: (this.parent.isAdaptive || this.parent.enableRtl ? { X: 'left', Y: 'top' } : { X: 'right', Y: 'top' }),
69
+ viewPortElement: (this.parent.isAdaptive ? document.body : this.parent.element),
70
+ zIndex: (this.parent.isAdaptive ? 1004 : 3)
71
+ });
72
+ }
73
+
74
+ private renderMorePopup(): void {
75
+ const moreEventPopup: string = `<div class="${cls.MORE_EVENT_POPUP_CLASS}"><div class="${cls.MORE_EVENT_HEADER_CLASS}">` +
76
+ `<div class="${cls.MORE_EVENT_CLOSE_CLASS}" title="${this.l10n.getConstant('close')}" tabindex="0" role="button"></div>` +
77
+ `<div class="${cls.MORE_EVENT_DATE_HEADER_CLASS}"><div class="${cls.MORE_EVENT_HEADER_DAY_CLASS}" id="${this.parent.element.id}_more_popup"></div>` +
78
+ `<div class="${cls.MORE_EVENT_HEADER_DATE_CLASS} ${cls.NAVIGATE_CLASS}" tabindex="0" role="link"></div></div></div></div>`;
79
+ const moreEventWrapper: HTMLElement = createElement('div', {
80
+ className: cls.MORE_POPUP_WRAPPER_CLASS + ' e-popup-close',
81
+ innerHTML: moreEventPopup
82
+ });
83
+ if (this.parent.isAdaptive) {
84
+ document.body.appendChild(moreEventWrapper);
85
+ addClass([moreEventWrapper], cls.DEVICE_CLASS);
86
+ } else {
87
+ this.parent.element.appendChild(moreEventWrapper);
88
+ }
89
+ this.morePopup = new Popup(moreEventWrapper, {
90
+ targetType: (this.parent.isAdaptive ? 'container' : 'relative'),
91
+ enableRtl: this.parent.enableRtl,
92
+ hideAnimation: { name: 'ZoomOut', duration: 300 },
93
+ showAnimation: { name: 'ZoomIn', duration: 300 },
94
+ open: this.morePopupOpen.bind(this),
95
+ close: this.morePopupClose.bind(this),
96
+ collision: (this.parent.isAdaptive ? { X: 'fit', Y: 'fit' } :
97
+ (this.parent.enableRtl ? { X: 'flip', Y: 'fit' } : { X: 'flip', Y: 'flip' })),
98
+ viewPortElement: (this.parent.isAdaptive ? document.body : this.parent.element),
99
+ zIndex: (this.parent.isAdaptive ? 1002 : 2)
100
+ });
101
+ this.morePopup.element.setAttribute('role', 'dialog');
102
+ this.morePopup.element.setAttribute('aria-labelledby', this.parent.element.id + '_more_popup');
103
+ const closeButton: HTMLButtonElement = this.morePopup.element.querySelector('.' + cls.MORE_EVENT_CLOSE_CLASS) as HTMLButtonElement;
104
+ this.renderButton('e-round', cls.ICON + ' ' + cls.CLOSE_ICON_CLASS, false, closeButton, this.closeClick);
105
+ EventHandler.add(this.morePopup.element.querySelector('.' + cls.MORE_EVENT_HEADER_DATE_CLASS), 'click', this.navigationClick, this);
106
+ }
107
+
108
+ private renderQuickDialog(): void {
109
+ const buttonModel: ButtonPropsModel[] = [
110
+ { buttonModel: { cssClass: 'e-quick-alertok e-flat', isPrimary: true }, click: this.dialogButtonClick.bind(this) },
111
+ { buttonModel: { cssClass: 'e-quick-alertcancel e-flat', isPrimary: false }, click: this.dialogButtonClick.bind(this) },
112
+ {
113
+ buttonModel: { cssClass: 'e-quick-dialog-cancel e-disable e-flat', isPrimary: false },
114
+ click: this.dialogButtonClick.bind(this)
115
+ }];
116
+ if (this.parent.eventSettings.editFollowingEvents) {
117
+ const followingSeriesButton: ButtonPropsModel = {
118
+ buttonModel: { cssClass: 'e-quick-alertfollowing e-flat', isPrimary: false }, click: this.dialogButtonClick.bind(this)
119
+ };
120
+ buttonModel.splice(1, 0, followingSeriesButton);
121
+ }
122
+ this.quickDialog = new Dialog({
123
+ animationSettings: { effect: 'Zoom' },
124
+ buttons: buttonModel,
125
+ cssClass: cls.QUICK_DIALOG_CLASS,
126
+ closeOnEscape: true,
127
+ enableRtl: this.parent.enableRtl,
128
+ enableHtmlSanitizer: this.parent.enableHtmlSanitizer,
129
+ beforeClose: this.beforeQuickDialogClose.bind(this),
130
+ isModal: true,
131
+ position: { X: 'center', Y: 'center' },
132
+ showCloseIcon: true,
133
+ target: document.body,
134
+ visible: false,
135
+ width: 'auto'
136
+ });
137
+ const dialogElement: HTMLElement = createElement('div', { id: this.parent.element.id + 'QuickDialog' });
138
+ this.parent.element.appendChild(dialogElement);
139
+ this.quickDialog.appendTo(dialogElement);
140
+ const okButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_OK);
141
+ if (okButton) {
142
+ okButton.setAttribute('aria-label', this.l10n.getConstant('occurrence'));
143
+ okButton.setAttribute('aria-label', okButton.innerHTML);
144
+ }
145
+ const cancelButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_CANCEL);
146
+ if (cancelButton) {
147
+ cancelButton.setAttribute('aria-label', this.l10n.getConstant('series'));
148
+ cancelButton.setAttribute('aria-label', cancelButton.innerHTML);
149
+ }
150
+ if (this.quickDialog.element.querySelector('.e-dlg-closeicon-btn')) {
151
+ this.quickDialog.element.querySelector('.e-dlg-closeicon-btn').setAttribute('title', this.l10n.getConstant('close'));
152
+ }
153
+ }
154
+
155
+ // eslint-disable-next-line max-len
156
+ private renderButton(className: string, iconName: string, isDisabled: boolean, element: HTMLButtonElement, clickEvent: CallbackFunction): void {
157
+ const buttonObj: Button = new Button({
158
+ cssClass: className,
159
+ disabled: isDisabled,
160
+ enableRtl: this.parent.enableRtl,
161
+ enableHtmlSanitizer: this.parent.enableHtmlSanitizer,
162
+ iconCss: iconName
163
+ });
164
+ buttonObj.appendTo(element);
165
+ EventHandler.add(element, 'click', clickEvent, this);
166
+ removeClass([element], cls.ICON);
167
+ }
168
+
169
+ private quickDialogClass(action: string): void {
170
+ const classList: string[] = [
171
+ cls.QUICK_DIALOG_OCCURRENCE_CLASS, cls.QUICK_DIALOG_SERIES_CLASS, cls.QUICK_DIALOG_DELETE_CLASS,
172
+ cls.QUICK_DIALOG_CANCEL_CLASS, cls.QUICK_DIALOG_ALERT_BTN_CLASS, cls.DISABLE_CLASS
173
+ ];
174
+ const okButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_OK);
175
+ const cancelButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_CANCEL);
176
+ const followingEventButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_FOLLOWING);
177
+ removeClass([okButton, cancelButton], classList);
178
+ addClass([this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_CANCEL_CLASS)], cls.DISABLE_CLASS);
179
+ if (this.parent.eventSettings.editFollowingEvents) {
180
+ addClass([followingEventButton], cls.DISABLE_CLASS);
181
+ removeClass([this.quickDialog.element], cls.FOLLOWING_EVENTS_DIALOG);
182
+ }
183
+ switch (action) {
184
+ case 'Recurrence':
185
+ addClass([okButton], cls.QUICK_DIALOG_OCCURRENCE_CLASS);
186
+ addClass([cancelButton], cls.QUICK_DIALOG_SERIES_CLASS);
187
+ if (this.parent.eventSettings.editFollowingEvents) {
188
+ removeClass([followingEventButton], cls.DISABLE_CLASS);
189
+ addClass([this.quickDialog.element], cls.FOLLOWING_EVENTS_DIALOG);
190
+ addClass([followingEventButton], cls.QUICK_DIALOG_FOLLOWING_EVENTS_CLASS);
191
+ }
192
+ break;
193
+ case 'Delete':
194
+ addClass([okButton], cls.QUICK_DIALOG_DELETE_CLASS);
195
+ addClass([cancelButton], cls.QUICK_DIALOG_CANCEL_CLASS);
196
+ break;
197
+ case 'Alert':
198
+ addClass([okButton], [cls.QUICK_DIALOG_ALERT_OK, cls.QUICK_DIALOG_ALERT_BTN_CLASS]);
199
+ addClass([cancelButton], [cls.QUICK_DIALOG_ALERT_CANCEL, cls.DISABLE_CLASS]);
200
+ break;
201
+ }
202
+ }
203
+
204
+ private applyFormValidation(): void {
205
+ const form: HTMLFormElement = this.quickPopup.element.querySelector('.' + cls.FORM_CLASS) as HTMLFormElement;
206
+ const rules: Record<string, any> = {};
207
+ rules[this.parent.eventSettings.fields.subject.name] = this.parent.eventSettings.fields.subject.validation;
208
+ this.fieldValidator.renderFormValidator(form, rules, this.quickPopup.element, this.parent.locale);
209
+ }
210
+
211
+ public openRecurrenceAlert(): void {
212
+ const editDeleteOnly: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_OK);
213
+ if (editDeleteOnly) {
214
+ editDeleteOnly.innerHTML = this.l10n.getConstant(this.parent.currentAction === 'Delete' ? 'deleteEvent' : 'editEvent');
215
+ editDeleteOnly.setAttribute('aria-label', editDeleteOnly.innerHTML);
216
+ }
217
+ const editFollowingEventsOnly: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_FOLLOWING);
218
+ if (editFollowingEventsOnly) {
219
+ editFollowingEventsOnly.innerHTML = this.l10n.getConstant('editFollowingEvent');
220
+ editFollowingEventsOnly.setAttribute('aria-label', editFollowingEventsOnly.innerHTML);
221
+ }
222
+ const editDeleteSeries: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_CANCEL);
223
+ if (editDeleteSeries) {
224
+ editDeleteSeries.innerHTML = this.l10n.getConstant(this.parent.currentAction === 'Delete' ? 'deleteSeries' : 'editSeries');
225
+ editDeleteSeries.setAttribute('aria-label', editDeleteSeries.innerHTML);
226
+ }
227
+ this.quickDialog.content = this.l10n.getConstant('editContent');
228
+ this.quickDialog.header = this.l10n.getConstant(this.parent.currentAction === 'Delete' ? 'deleteTitle' : 'editTitle');
229
+ this.quickDialogClass('Recurrence');
230
+ this.showQuickDialog('RecurrenceAlert');
231
+ }
232
+
233
+ public openRecurrenceValidationAlert(type: string): void {
234
+ this.quickDialogClass('Alert');
235
+ const okButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_OK);
236
+ okButton.innerHTML = this.l10n.getConstant('ok');
237
+ okButton.setAttribute('aria-label', okButton.innerHTML);
238
+ const cancelButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_CANCEL);
239
+ cancelButton.innerHTML = this.l10n.getConstant('cancel');
240
+ cancelButton.setAttribute('aria-label', cancelButton.innerHTML);
241
+ this.quickDialog.header = this.l10n.getConstant('alert');
242
+ let dialogCancel: Element;
243
+ switch (type) {
244
+ case 'wrongPattern':
245
+ addClass([cancelButton], cls.DISABLE_CLASS);
246
+ this.quickDialog.content = this.l10n.getConstant('wrongPattern');
247
+ break;
248
+ case 'createError':
249
+ addClass([cancelButton], cls.DISABLE_CLASS);
250
+ this.quickDialog.content = this.l10n.getConstant('createError');
251
+ break;
252
+ case 'sameDayAlert':
253
+ addClass([cancelButton], cls.DISABLE_CLASS);
254
+ this.quickDialog.content = this.l10n.getConstant('sameDayAlert');
255
+ break;
256
+ case 'seriesChangeAlert':
257
+ dialogCancel = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_CANCEL_CLASS);
258
+ removeClass([cancelButton, dialogCancel], cls.DISABLE_CLASS);
259
+ this.quickDialog.content = this.l10n.getConstant('seriesChangeAlert');
260
+ okButton.innerHTML = this.l10n.getConstant('yes');
261
+ cancelButton.innerHTML = this.l10n.getConstant('no');
262
+ dialogCancel.innerHTML = this.l10n.getConstant('cancel');
263
+ break;
264
+ case 'occurrenceAlert':
265
+ addClass([cancelButton], cls.DISABLE_CLASS);
266
+ this.quickDialog.content = this.l10n.getConstant('occurenceAlert');
267
+ break;
268
+ }
269
+ if ((!this.parent.enableRecurrenceValidation && type === 'wrongPattern') || this.parent.enableRecurrenceValidation) {
270
+ this.showQuickDialog('RecurrenceValidationAlert');
271
+ }
272
+ }
273
+
274
+ public openDeleteAlert(): void {
275
+ if (this.parent.activeViewOptions.readonly) {
276
+ return;
277
+ }
278
+ const okButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_OK);
279
+ if (okButton) {
280
+ okButton.innerHTML = this.l10n.getConstant('delete');
281
+ okButton.setAttribute('aria-label', okButton.innerHTML);
282
+ }
283
+ const cancelButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_CANCEL);
284
+ if (cancelButton) {
285
+ cancelButton.innerHTML = this.l10n.getConstant('cancel');
286
+ cancelButton.setAttribute('aria-label', cancelButton.innerHTML);
287
+ }
288
+ this.quickDialog.content = ((<Record<string, any>[]>this.parent.activeEventData.event).length > 1) ?
289
+ this.l10n.getConstant('deleteMultipleContent') : this.l10n.getConstant('deleteContent');
290
+ this.quickDialog.header = ((<Record<string, any>[]>this.parent.activeEventData.event).length > 1) ?
291
+ this.l10n.getConstant('deleteMultipleEvent') : this.l10n.getConstant('deleteEvent');
292
+ this.quickDialogClass('Delete');
293
+ this.showQuickDialog('DeleteAlert');
294
+ }
295
+
296
+ public openValidationError(type: string, eventData?: Record<string, any> | Record<string, any>[]): void {
297
+ this.quickDialog.header = this.l10n.getConstant('alert');
298
+ this.quickDialog.content = this.l10n.getConstant(type);
299
+ const okButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_OK);
300
+ if (okButton) {
301
+ okButton.innerHTML = this.l10n.getConstant('ok');
302
+ okButton.setAttribute('aria-label', okButton.innerHTML);
303
+ }
304
+ const cancelButton: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_CANCEL);
305
+ if (cancelButton) {
306
+ cancelButton.innerHTML = this.l10n.getConstant('cancel');
307
+ okButton.setAttribute('aria-label', cancelButton.innerHTML);
308
+ }
309
+ this.quickDialogClass('Alert');
310
+ this.showQuickDialog(type === 'overlapAlert' ? 'OverlapAlert' : 'ValidationAlert', eventData);
311
+ }
312
+
313
+ private showQuickDialog(popupType: PopupType, eventData?: Record<string, any> | Record<string, any>[]): void {
314
+ this.quickDialog.dataBind();
315
+ const eventProp: PopupOpenEventArgs = {
316
+ type: popupType, cancel: false, element: this.quickDialog.element,
317
+ data: extend({}, (eventData || this.parent.activeEventData.event), null, true) as Record<string, any>
318
+ };
319
+ if (!this.parent.activeViewOptions.allowOverlap) {
320
+ eventProp.overlapEvents = this.parent.overlapAppointments;
321
+ }
322
+ this.parent.trigger(event.popupOpen, eventProp, (popupArgs: PopupOpenEventArgs) => {
323
+ if (!popupArgs.cancel) {
324
+ this.quickDialog.show();
325
+ }
326
+ });
327
+ }
328
+
329
+ private createMoreEventList(eventCollection: Record<string, any>[], groupOrder: string[], groupIndex: string): HTMLElement {
330
+ const fields: EventFieldsMapping = this.parent.eventFields;
331
+ const moreEventContentEle: HTMLElement = createElement('div', { className: cls.MORE_EVENT_CONTENT_CLASS });
332
+ let moreEventWrapperEle: HTMLElement = createElement('div', { className: cls.MORE_EVENT_WRAPPER_CLASS });
333
+ if (eventCollection.length === 0) {
334
+ moreEventWrapperEle = createElement('div', {
335
+ className: cls.MORE_EVENT_CONTENT_CLASS,
336
+ innerHTML: this.l10n.getConstant('emptyContainer')
337
+ });
338
+ } else {
339
+ for (const eventData of eventCollection) {
340
+ const eventText: string = (eventData[fields.subject] || this.parent.eventSettings.fields.subject.default
341
+ || this.parent.localeObj.getConstant('addTitle')) as string;
342
+ const appointmentElement: HTMLElement = createElement('div', {
343
+ className: cls.APPOINTMENT_CLASS,
344
+ attrs: {
345
+ 'data-id': '' + eventData[fields.id],
346
+ 'data-guid': eventData.Guid as string, 'role': 'button', 'tabindex': '0',
347
+ 'aria-disabled': this.parent.eventBase.getReadonlyAttribute(eventData),
348
+ 'aria-label': this.parent.getAnnouncementString(eventData)
349
+ }
350
+ });
351
+ if (eventData[fields.isReadonly]) {
352
+ addClass([appointmentElement], 'e-read-only');
353
+ }
354
+ let templateElement: HTMLElement[];
355
+ if (!isNullOrUndefined(this.parent.activeViewOptions.eventTemplate)) {
356
+ const tempId: string = this.parent.element.id + '_' + this.parent.activeViewOptions.eventTemplateName + 'eventTemplate';
357
+ templateElement = this.parent.getAppointmentTemplate()(eventData, this.parent, 'eventTemplate', tempId, false,
358
+ undefined, undefined, this.parent.root);
359
+ append(templateElement, appointmentElement);
360
+ } else {
361
+ appointmentElement.appendChild(createElement('div', { className: cls.SUBJECT_CLASS }));
362
+ this.parent.sanitize(eventText, appointmentElement.firstElementChild as HTMLElement);
363
+ }
364
+ if (!isNullOrUndefined(groupIndex)) {
365
+ appointmentElement.setAttribute('data-group-index', groupIndex);
366
+ }
367
+ if (!isNullOrUndefined(eventData[fields.recurrenceRule])) {
368
+ const iconClass: string = (eventData[fields.id] === eventData[fields.recurrenceID]) ?
369
+ cls.EVENT_RECURRENCE_ICON_CLASS : cls.EVENT_RECURRENCE_EDIT_ICON_CLASS;
370
+ appointmentElement.appendChild(createElement('div', { className: cls.ICON + ' ' + iconClass }));
371
+ }
372
+ const args: EventRenderedArgs = {
373
+ data: extend({}, eventData, null, true) as Record<string, any>,
374
+ element: appointmentElement, cancel: false
375
+ };
376
+ this.parent.trigger(event.eventRendered, args, (eventArgs: EventRenderedArgs) => {
377
+ if (!eventArgs.cancel) {
378
+ moreEventWrapperEle.appendChild(appointmentElement);
379
+ const isPreventCrud: boolean = this.parent.isAdaptive || this.parent.currentView === 'Year';
380
+ this.parent.eventBase.wireAppointmentEvents(appointmentElement, eventData, isPreventCrud);
381
+ this.parent.eventBase.applyResourceColor(appointmentElement, eventData, 'backgroundColor', groupOrder);
382
+ }
383
+ });
384
+ }
385
+ }
386
+ moreEventContentEle.appendChild(moreEventWrapperEle);
387
+ return moreEventContentEle;
388
+ }
389
+
390
+ public tapHoldEventPopup(e: Event): void {
391
+ const target: Element = closest(<HTMLElement>e.target, '.' + cls.APPOINTMENT_CLASS);
392
+ this.parent.selectedElements = [];
393
+ this.isMultipleEventSelect = true;
394
+ this.parent.eventBase.getSelectedEventElements(target);
395
+ this.parent.activeEventData = this.parent.eventBase.getSelectedEvents();
396
+ const guid: string = target.getAttribute('data-guid');
397
+ const eventObj: Record<string, any> = this.parent.eventBase.getEventByGuid(guid);
398
+ if (isNullOrUndefined(eventObj)) {
399
+ return;
400
+ }
401
+ const eventTitle: string = (eventObj[this.parent.eventFields.subject] || this.l10n.getConstant('noTitle')) as string;
402
+ const eventTemplate: string = `<div class="${cls.MULTIPLE_EVENT_POPUP_CLASS}"><div class="${cls.POPUP_HEADER_CLASS}">` +
403
+ `<button class="${cls.CLOSE_CLASS}" title="${this.l10n.getConstant('close')}"></button>` +
404
+ `<div class="${cls.SUBJECT_CLASS}">${eventTitle}</div>` +
405
+ `<button class="${cls.EDIT_CLASS}" title="${this.l10n.getConstant('edit')}"></button>` +
406
+ `<button class="${cls.DELETE_CLASS}" title="${this.l10n.getConstant('delete')}"></button></div></div>`;
407
+ this.quickPopup.element.innerHTML = eventTemplate;
408
+ const closeIcon: HTMLButtonElement = this.quickPopup.element.querySelector('.' + cls.CLOSE_CLASS) as HTMLButtonElement;
409
+ this.renderButton('e-flat e-round e-small', cls.ICON + ' ' + cls.CLOSE_ICON_CLASS, false, closeIcon, this.closeClick);
410
+ const readonly: boolean = this.parent.activeViewOptions.readonly || eventObj[this.parent.eventFields.isReadonly] as boolean;
411
+ const editAction: boolean = !this.parent.eventSettings.allowEditing || readonly;
412
+ const deleteAction: boolean = !this.parent.eventSettings.allowDeleting || readonly;
413
+ const editIcon: HTMLButtonElement = this.quickPopup.element.querySelector('.' + cls.EDIT_CLASS) as HTMLButtonElement;
414
+ if (editIcon) {
415
+ this.renderButton('e-flat e-round e-small', cls.ICON + ' ' + cls.EDIT_ICON_CLASS, editAction, editIcon, this.editClick);
416
+ }
417
+ const deleteIcon: HTMLButtonElement = this.quickPopup.element.querySelector('.' + cls.DELETE_CLASS) as HTMLButtonElement;
418
+ if (deleteIcon) {
419
+ this.renderButton('e-flat e-round e-small', cls.ICON + ' ' + cls.DELETE_ICON_CLASS, deleteAction, deleteIcon, this.deleteClick);
420
+ }
421
+ this.beforeQuickPopupOpen(target, this.parent.eventBase.getPageCoordinates(e as MouseEvent & TouchEvent));
422
+ }
423
+
424
+ private isCellBlocked(args: CellClickEventArgs): boolean {
425
+ const tempObj: Record<string, any> = {};
426
+ tempObj[this.parent.eventFields.startTime] = this.parent.activeCellsData.startTime;
427
+ tempObj[this.parent.eventFields.endTime] = this.parent.activeCellsData.endTime;
428
+ tempObj[this.parent.eventFields.isAllDay] = this.parent.activeCellsData.isAllDay;
429
+ if (this.parent.activeViewOptions.group.resources.length > 0) {
430
+ const targetCell: HTMLElement = args.element instanceof Array ? args.element[0] : args.element;
431
+ const groupIndex: number = parseInt(targetCell.getAttribute('data-group-index'), 10);
432
+ this.parent.resourceBase.setResourceValues(tempObj, isNaN(groupIndex) ? null : groupIndex);
433
+ }
434
+ return this.parent.eventBase.isBlockRange(tempObj);
435
+ }
436
+
437
+ private cellClick(args: CellClickEventArgs): void {
438
+ const date: Date = new Date(args.startTime.getTime());
439
+ if (!this.parent.showQuickInfo || !this.parent.eventSettings.allowAdding ||
440
+ this.parent.currentView === 'MonthAgenda' || this.isCellBlocked(args) ||
441
+ !this.parent.isMinMaxDate(new Date(date.setHours(0, 0, 0, 0)))) {
442
+ this.quickPopupHide();
443
+ return;
444
+ }
445
+ const targetEle: Element = !isNullOrUndefined(args.event) ? args.event.target as Element : args.element as Element;
446
+ if (this.parent.isAdaptive) {
447
+ this.quickPopupHide();
448
+ let newEventClone: HTMLElement = this.parent.element.querySelector('.' + cls.NEW_EVENT_CLASS) as HTMLElement;
449
+ if (isNullOrUndefined(newEventClone)) {
450
+ newEventClone = createElement('div', {
451
+ className: cls.NEW_EVENT_CLASS,
452
+ innerHTML: `<div class="e-title">+ ${this.l10n.getConstant('newEvent')}</div>`
453
+ });
454
+ }
455
+ const targetCell: Element = closest(targetEle, '.' + cls.WORK_CELLS_CLASS + ',.' + cls.ALLDAY_CELLS_CLASS);
456
+ if (targetCell) {
457
+ targetCell.appendChild(newEventClone);
458
+ }
459
+ return;
460
+ }
461
+ const target: Element = closest(targetEle, '.' + cls.WORK_CELLS_CLASS + ',.' + cls.ALLDAY_CELLS_CLASS + ',.' +
462
+ cls.HEADER_CELLS_CLASS);
463
+ if (isNullOrUndefined(target) || targetEle.classList.contains(cls.MORE_INDICATOR_CLASS)) {
464
+ return;
465
+ }
466
+ const isSameTarget: boolean = this.quickPopup.relateTo === target;
467
+ if (isSameTarget && this.quickPopup.element.classList.contains(cls.POPUP_OPEN)) {
468
+ const subjectElement: HTMLInputElement = this.quickPopup.element.querySelector('.' + cls.SUBJECT_CLASS) as HTMLInputElement;
469
+ if (subjectElement) {
470
+ subjectElement.focus();
471
+ }
472
+ return;
473
+ } else if (this.quickPopup.element) {
474
+ this.destroyPopupButtons('quickPopup');
475
+ }
476
+ const temp: Record<string, any> = {};
477
+ temp[this.parent.eventFields.startTime] = this.parent.activeCellsData.startTime;
478
+ temp[this.parent.eventFields.endTime] = this.parent.activeCellsData.endTime;
479
+ temp[this.parent.eventFields.isAllDay] = this.parent.activeCellsData.isAllDay;
480
+ const quickCellPopup: HTMLElement = createElement('div', { className: cls.CELL_POPUP_CLASS });
481
+ quickCellPopup.appendChild(this.getPopupHeader('Cell', temp));
482
+ quickCellPopup.appendChild(this.getPopupContent('Cell', args, temp));
483
+ quickCellPopup.appendChild(this.getPopupFooter('Cell', temp));
484
+ this.quickPopup.element.setAttribute('aria-label', this.l10n.getConstant('newEvent'));
485
+ const subjectElement: HTMLInputElement = quickCellPopup.querySelector('.' + cls.SUBJECT_CLASS) as HTMLInputElement;
486
+ if (subjectElement) {
487
+ Input.createInput({ element: subjectElement, properties: { placeholder: this.l10n.getConstant('addTitle') } });
488
+ }
489
+ if (!isNullOrUndefined(this.parent.eventSettings.fields.subject.default)) {
490
+ subjectElement.value = this.parent.eventSettings.fields.subject.default;
491
+ }
492
+ const closeIcon: HTMLButtonElement = quickCellPopup.querySelector('.' + cls.CLOSE_CLASS) as HTMLButtonElement;
493
+ if (closeIcon) {
494
+ this.renderButton('e-flat e-round e-small', cls.ICON + ' ' + cls.CLOSE_ICON_CLASS, false, closeIcon, this.popupClose);
495
+ }
496
+ const moreButton: HTMLButtonElement = quickCellPopup.querySelector('.' + cls.QUICK_POPUP_EVENT_DETAILS_CLASS) as HTMLButtonElement;
497
+ if (moreButton) {
498
+ this.renderButton('e-flat', '', false, moreButton, this.detailsClick);
499
+ }
500
+ const saveButton: HTMLButtonElement = quickCellPopup.querySelector('.' + cls.EVENT_CREATE_CLASS) as HTMLButtonElement;
501
+ if (saveButton) {
502
+ this.renderButton('e-flat e-primary', '', this.parent.activeViewOptions.readonly, saveButton, this.saveClick);
503
+ }
504
+ if (this.morePopup) { this.morePopup.hide(); }
505
+ this.quickPopup.content = quickCellPopup;
506
+ this.quickPopup.relateTo = target as HTMLElement;
507
+ this.quickPopup.dataBind();
508
+ this.beforeQuickPopupOpen(target, this.parent.eventBase.getPageCoordinates(args.event as MouseEvent & TouchEvent));
509
+ }
510
+
511
+ private isSameEventClick(events: EventClickArgs): boolean {
512
+ const isSameTarget: boolean = this.quickPopup.relateTo === closest(<HTMLElement>events.element, '.' + cls.APPOINTMENT_CLASS);
513
+ if (isSameTarget && this.quickPopup.element.classList.contains(cls.POPUP_OPEN)) {
514
+ const editIcon: HTMLButtonElement = this.quickPopup.element.querySelector('.' + cls.EDIT_CLASS) as HTMLButtonElement;
515
+ if (editIcon) {
516
+ editIcon.focus();
517
+ }
518
+ if (!this.parent.isAdaptive) {
519
+ const editButton: HTMLButtonElement = this.quickPopup.element.querySelector('.' + cls.EDIT_EVENT_CLASS) as HTMLButtonElement;
520
+ if (editButton) {
521
+ editButton.focus();
522
+ }
523
+ }
524
+ return true;
525
+ }
526
+ return false;
527
+ }
528
+
529
+ private isQuickTemplate(type: TemplateType): boolean {
530
+ return this.parent.quickInfoTemplates.templateType === 'Both' || this.parent.quickInfoTemplates.templateType === type;
531
+ }
532
+
533
+ private eventClick(events: EventClickArgs): void {
534
+ if (this.parent.eventTooltip) {
535
+ this.parent.eventTooltip.close();
536
+ }
537
+ if (!this.parent.showQuickInfo) { return; }
538
+ if (this.parent.isAdaptive && this.isMultipleEventSelect) {
539
+ this.updateTapHoldEventPopup(closest(<HTMLElement>events.element, '.' + cls.APPOINTMENT_CLASS));
540
+ } else {
541
+ const isSameTarget: boolean = this.isSameEventClick(events);
542
+ this.parent.selectedElements = [];
543
+ if (isSameTarget) {
544
+ return;
545
+ } else if (this.quickPopup.element) {
546
+ this.destroyPopupButtons('quickPopup');
547
+ }
548
+ const eventData: Record<string, any> = <Record<string, any>>events.event;
549
+ const quickEventPopup: HTMLElement = createElement('div', { className: cls.EVENT_POPUP_CLASS });
550
+ quickEventPopup.appendChild(this.getPopupHeader('Event', eventData));
551
+ quickEventPopup.appendChild(this.getPopupContent('Event', events, eventData));
552
+ quickEventPopup.appendChild(this.getPopupFooter('Event', eventData));
553
+ this.quickPopup.element.setAttribute('aria-label', this.l10n.getConstant('editEvent'));
554
+ const readonly: boolean = this.parent.activeViewOptions.readonly || eventData[this.parent.eventFields.isReadonly] as boolean;
555
+ const editAction: boolean = !this.parent.eventSettings.allowEditing || readonly;
556
+ const deleteAction: boolean = !this.parent.eventSettings.allowDeleting || readonly;
557
+ const editIcon: HTMLButtonElement = quickEventPopup.querySelector('.' + cls.EDIT_CLASS) as HTMLButtonElement;
558
+ const buttonClass: string = 'e-flat e-round e-small';
559
+ if (editIcon) {
560
+ this.renderButton(buttonClass, cls.ICON + ' ' + cls.EDIT_ICON_CLASS, editAction, editIcon, this.editClick);
561
+ }
562
+ const deleteIcon: HTMLButtonElement = quickEventPopup.querySelector('.' + cls.DELETE_CLASS) as HTMLButtonElement;
563
+ if (deleteIcon) {
564
+ this.renderButton(buttonClass, cls.ICON + ' ' + cls.DELETE_ICON_CLASS, deleteAction, deleteIcon, this.deleteClick);
565
+ }
566
+ const closeIcon: HTMLButtonElement = quickEventPopup.querySelector('.' + cls.CLOSE_CLASS) as HTMLButtonElement;
567
+ if (closeIcon) {
568
+ this.renderButton(buttonClass, cls.ICON + ' ' + cls.CLOSE_ICON_CLASS, false, closeIcon, this.popupClose);
569
+ }
570
+ const editButton: HTMLButtonElement = quickEventPopup.querySelector('.' + cls.EDIT_EVENT_CLASS) as HTMLButtonElement;
571
+ if (editButton) {
572
+ this.renderButton('e-flat e-primary', '', editAction, editButton, this.editClick);
573
+ }
574
+ const deleteButton: HTMLButtonElement = quickEventPopup.querySelector('.' + cls.DELETE_EVENT_CLASS) as HTMLButtonElement;
575
+ if (deleteButton) {
576
+ this.renderButton('e-flat', '', deleteAction, deleteButton, this.deleteClick);
577
+ }
578
+ if (this.morePopup && !closest(<Element>events.element, '.' + cls.MORE_EVENT_WRAPPER_CLASS)) { this.morePopup.hide(); }
579
+ this.quickPopup.content = quickEventPopup;
580
+ this.quickPopup.relateTo = this.parent.isAdaptive ? document.body :
581
+ closest(<HTMLElement>events.element, '.' + cls.APPOINTMENT_CLASS) as HTMLElement;
582
+ this.quickPopup.dataBind();
583
+ this.beforeQuickPopupOpen(events.element as Element, this.parent.eventBase.getPageCoordinates((events as any).originalEvent));
584
+ }
585
+ }
586
+
587
+ private getPopupHeader(headerType: TemplateType, headerData: Record<string, any>): HTMLElement {
588
+ const headerTemplate: HTMLElement = createElement('div', { className: cls.POPUP_HEADER_CLASS });
589
+ if (this.isQuickTemplate(headerType) && this.parent.quickInfoTemplates.header) {
590
+ const headerArgs: Record<string, any> =
591
+ extend({}, headerData, { elementType: headerType.toLowerCase() }, true) as Record<string, any>;
592
+ const templateId: string = this.parent.element.id;
593
+ const headerTemp: HTMLElement[] = [].slice.call(
594
+ this.parent.getQuickInfoTemplatesHeader()(headerArgs, this.parent, 'header', templateId + '_headerTemplate', false));
595
+ append([].slice.call(headerTemp), headerTemplate);
596
+ } else {
597
+ let header: string;
598
+ let args: Record<string, any>;
599
+ switch (headerType) {
600
+ case 'Cell':
601
+ header = `<div class="${cls.POPUP_HEADER_ICON_WRAPPER}"><button class="${cls.CLOSE_CLASS}" title=` +
602
+ `"${this.l10n.getConstant('close')}"></button></div>`;
603
+ break;
604
+ case 'Event':
605
+ args = this.getFormattedString(headerData);
606
+ header = `<div class="${cls.POPUP_HEADER_ICON_WRAPPER}">` +
607
+ `<button class="${cls.EDIT_CLASS + ' ' + cls.ICON}" title="${this.l10n.getConstant('edit')}"></button>` +
608
+ `<button class="${cls.DELETE_CLASS + ' ' + cls.ICON}" title="${this.l10n.getConstant('delete')}"></button>` +
609
+ `<button class="${cls.CLOSE_CLASS}" title="${this.l10n.getConstant('close')}"></button></div>` +
610
+ `<div class="${cls.SUBJECT_WRAP}"><div class="${cls.SUBJECT_CLASS} ${cls.TEXT_ELLIPSIS}" ` +
611
+ `title="${args.eventSubject ? args.eventSubject.replaceAll('"', '\'') : args.eventSubject}"></div></div >`;
612
+ break;
613
+ }
614
+ const templateWrapper: HTMLElement = createElement('div', { innerHTML: header });
615
+ if (headerType === 'Event') {
616
+ const subjectText: HTMLElement = templateWrapper.querySelector('.' + cls.SUBJECT_CLASS);
617
+ this.parent.sanitize(args.eventSubject, subjectText);
618
+ }
619
+ append([].slice.call(templateWrapper.childNodes), headerTemplate);
620
+ }
621
+ return headerTemplate;
622
+ }
623
+
624
+ private getPopupContent(type: TemplateType, args: CellClickEventArgs | EventClickArgs, data: Record<string, any>): HTMLElement {
625
+ const contentTemplate: HTMLElement = createElement('div', { className: cls.POPUP_CONTENT_CLASS });
626
+ if (this.isQuickTemplate(type) && this.parent.quickInfoTemplates.content) {
627
+ const contentArgs: Record<string, any> =
628
+ extend({}, data, { elementType: type.toLowerCase() }, true) as Record<string, any>;
629
+ const templateId: string = this.parent.element.id;
630
+ const contentTemp: HTMLElement[] = [].slice.call(
631
+ this.parent.getQuickInfoTemplatesContent()(contentArgs, this.parent, 'content', templateId + '_contentTemplate', false));
632
+ append([].slice.call(contentTemp), contentTemplate);
633
+ } else {
634
+ let content: string;
635
+ let cellDetails: Record<string, any>;
636
+ let argsData: Record<string, any>;
637
+ const resourceText: string = this.getResourceText(args, type.toLowerCase());
638
+ switch (type) {
639
+ case 'Cell':
640
+ cellDetails = this.getFormattedString(data);
641
+ content = `<table class="${cls.POPUP_TABLE_CLASS}"><tbody><tr><td><form class="${cls.FORM_CLASS}">
642
+ <input class="${cls.SUBJECT_CLASS} ${EVENT_FIELD}" type="text" name=` +
643
+ `"${this.parent.eventFields.subject}" /></form></td></tr><tr><td><div class="${cls.DATE_TIME_CLASS}">` +
644
+ `<div class="${cls.DATE_TIME_ICON_CLASS} ${cls.ICON}"></div><div class="${cls.DATE_TIME_DETAILS_CLASS} ` +
645
+ `${cls.TEXT_ELLIPSIS}">${cellDetails.details}</div></div>` +
646
+ `${this.parent.activeViewOptions.group.resources.length > 0 ? `<div class="${cls.RESOURCE_CLASS}">` +
647
+ `<div class="${cls.RESOURCE_ICON_CLASS} ${cls.ICON} "></div><div class="${cls.RESOURCE_DETAILS_CLASS} ` +
648
+ `${cls.TEXT_ELLIPSIS}"></div></div>` : ''}</td></tr></tbody></table>`;
649
+ break;
650
+ case 'Event':
651
+ argsData = this.getFormattedString(data);
652
+ content = '<div class="' + cls.DATE_TIME_CLASS + '"><div class="' + cls.DATE_TIME_ICON_CLASS + ' ' + cls.ICON +
653
+ '"></div><div class="' + cls.DATE_TIME_WRAPPER_CLASS + ' ' + cls.TEXT_ELLIPSIS + '"><div class="' +
654
+ cls.DATE_TIME_DETAILS_CLASS + ' ' + cls.TEXT_ELLIPSIS + '">' + argsData.details + '</div>';
655
+ if (data[this.parent.eventFields.recurrenceRule]) {
656
+ content += '<div class="' + cls.RECURRENCE_SUMMARY_CLASS + ' ' + cls.TEXT_ELLIPSIS + '">' +
657
+ this.getRecurrenceSummary(data) + '</div>';
658
+ }
659
+ content += '</div></div>';
660
+ if (data[this.parent.eventFields.location]) {
661
+ content += '<div class="' + cls.LOCATION_CLASS + '"><div class="' + cls.LOCATION_ICON_CLASS + ' ' +
662
+ cls.ICON + '"></div><div class="' + cls.LOCATION_DETAILS_CLASS + ' ' + cls.TEXT_ELLIPSIS + '"></div></div>';
663
+ }
664
+ if (data[this.parent.eventFields.startTimezone] || data[this.parent.eventFields.endTimezone]) {
665
+ content += '<div class="' + cls.TIME_ZONE_CLASS + '"><div class="' + cls.TIME_ZONE_ICON_CLASS + ' ' + cls.ICON +
666
+ '"></div><div class="' + cls.TIME_ZONE_DETAILS_CLASS + ' ' + cls.TEXT_ELLIPSIS + '">' +
667
+ this.getTimezone(data) + '</div></div>';
668
+ }
669
+ if (data[this.parent.eventFields.description]) {
670
+ content += '<div class="' + cls.DESCRIPTION_CLASS + '"><div class="' + cls.DESCRIPTION_ICON_CLASS + ' ' + cls.ICON +
671
+ '"></div><div class="' + cls.DESCRIPTION_DETAILS_CLASS + ' ' + cls.TEXT_ELLIPSIS + '"></div></div>';
672
+ }
673
+ if (this.parent.resourceCollection.length > 0) {
674
+ content += '<div class="' + cls.RESOURCE_CLASS + '"><div class="' + cls.RESOURCE_ICON_CLASS + ' ' + cls.ICON +
675
+ '"></div><div class="' + cls.RESOURCE_DETAILS_CLASS + ' ' + cls.TEXT_ELLIPSIS + '"></div></div>';
676
+ }
677
+ break;
678
+ }
679
+ const templateWrapper: HTMLElement = createElement('div', { innerHTML: content });
680
+ const form: HTMLElement = templateWrapper.querySelector('form');
681
+ if (form) {
682
+ form.onsubmit = () => { return false; };
683
+ }
684
+ if (data[this.parent.eventFields.location]) {
685
+ const locationDetails: HTMLElement = templateWrapper.querySelector('.' + cls.LOCATION_DETAILS_CLASS);
686
+ if (!isNullOrUndefined(locationDetails)) {
687
+ this.parent.sanitize(data[this.parent.eventFields.location], locationDetails);
688
+ }
689
+ }
690
+ if (data[this.parent.eventFields.description]) {
691
+ const descriptionDetails: HTMLElement = templateWrapper.querySelector('.' + cls.DESCRIPTION_DETAILS_CLASS);
692
+ if (!isNullOrUndefined(descriptionDetails)) {
693
+ this.parent.sanitize(data[this.parent.eventFields.description], descriptionDetails);
694
+ }
695
+ }
696
+ if (resourceText) {
697
+ const resourceDetails: HTMLElement = templateWrapper.querySelector('.' + cls.RESOURCE_DETAILS_CLASS);
698
+ if (!isNullOrUndefined(resourceDetails)) {
699
+ this.parent.sanitize(resourceText, resourceDetails);
700
+ }
701
+ }
702
+ append([].slice.call(templateWrapper.childNodes), contentTemplate);
703
+ }
704
+ return contentTemplate;
705
+ }
706
+
707
+ private getPopupFooter(footerType: TemplateType, footerData: Record<string, any>): HTMLElement {
708
+ const footerTemplate: HTMLElement = createElement('div', { className: cls.POPUP_FOOTER_CLASS });
709
+ if (this.isQuickTemplate(footerType) && this.parent.quickInfoTemplates.footer) {
710
+ const footerArgs: Record<string, any> =
711
+ extend({}, footerData, { elementType: footerType.toLowerCase() }, true) as Record<string, any>;
712
+ const templateId: string = this.parent.element.id;
713
+ const footerTemp: HTMLElement[] = [].slice.call(
714
+ this.parent.getQuickInfoTemplatesFooter()(footerArgs, this.parent, 'footer', templateId + '_footerTemplate', false));
715
+ append([].slice.call(footerTemp), footerTemplate);
716
+ } else {
717
+ let footer: string;
718
+ switch (footerType) {
719
+ case 'Cell':
720
+ footer = `<button class="${cls.QUICK_POPUP_EVENT_DETAILS_CLASS + ' ' + cls.TEXT_ELLIPSIS}" title=` +
721
+ `"${this.l10n.getConstant('moreDetails')}">${this.l10n.getConstant('moreDetails')}</button>` +
722
+ `<button class="${cls.EVENT_CREATE_CLASS} ${cls.TEXT_ELLIPSIS}" title="${this.l10n.getConstant('save')}">` +
723
+ `${this.l10n.getConstant('save')}</button>`;
724
+ break;
725
+ case 'Event':
726
+ footer = `${this.parent.isAdaptive ? '' : `<button class="${cls.EDIT_EVENT_CLASS} ` +
727
+ `${cls.TEXT_ELLIPSIS}" title="${this.l10n.getConstant('edit')}">${this.l10n.getConstant('edit')}</button>` +
728
+ `<button class="${cls.DELETE_EVENT_CLASS} ${cls.TEXT_ELLIPSIS}" title="${this.l10n.getConstant('delete')}">` +
729
+ `${this.l10n.getConstant('delete')}</button>`}`;
730
+ break;
731
+ }
732
+ const templateWrapper: HTMLElement = createElement('div', { innerHTML: footer });
733
+ append([].slice.call(templateWrapper.childNodes), footerTemplate);
734
+ }
735
+ return footerTemplate;
736
+ }
737
+
738
+ public getResourceText(args: CellClickEventArgs | EventClickArgs, type: string): string {
739
+ if (this.parent.resourceCollection.length === 0) {
740
+ return null;
741
+ }
742
+ let resourceValue: string = '';
743
+ if (this.parent.activeViewOptions.group.resources.length === 0) {
744
+ const resourceCollection: ResourcesModel = this.parent.resourceBase.resourceCollection.slice(-1)[0];
745
+ const resourceData: Record<string, number>[] = resourceCollection.dataSource as Record<string, number>[];
746
+ if (type === 'event') {
747
+ const eventData: Record<string, any> = args.event as Record<string, any>;
748
+ for (const data of resourceData) {
749
+ const resourceId: number | number[] = eventData[resourceCollection.field] as number | number[];
750
+ if (resourceId instanceof Array) {
751
+ if (resourceId.indexOf(data[resourceCollection.idField]) > -1) {
752
+ const id: number = resourceId[resourceId.indexOf(data[resourceCollection.idField])];
753
+ const resource: Record<string, number> = resourceData.filter((e: Record<string, number>) =>
754
+ e[resourceCollection.idField] === id)[0];
755
+ resourceValue += (resourceValue === '') ? resource[resourceCollection.textField] :
756
+ ', ' + resource[resourceCollection.textField];
757
+ }
758
+ } else if (data[resourceCollection.idField] === resourceId) {
759
+ resourceValue = data[resourceCollection.textField].toString();
760
+ }
761
+ }
762
+ } else {
763
+ resourceValue = resourceData[0][resourceCollection.textField].toString();
764
+ }
765
+ } else {
766
+ if (type === 'event') {
767
+ const eventData: Record<string, any> = args.event as Record<string, any>;
768
+ let resourceData: string[];
769
+ let lastResource: ResourcesModel;
770
+ for (let i: number = this.parent.resourceBase.resourceCollection.length - 1; i >= 0; i--) {
771
+ resourceData = eventData[this.parent.resourceBase.resourceCollection[parseInt(i.toString(), 10)].field] as string[];
772
+ if (!isNullOrUndefined(resourceData)) {
773
+ lastResource = this.parent.resourceBase.resourceCollection[parseInt(i.toString(), 10)];
774
+ break;
775
+ }
776
+ }
777
+ if (!Array.isArray(resourceData)) {
778
+ resourceData = [resourceData];
779
+ }
780
+ const resNames: string[] = [];
781
+ const lastResourceData: Record<string, any>[] = lastResource.dataSource as Record<string, any>[];
782
+ resourceData.forEach((value: string) => {
783
+ let text: string;
784
+ const i: number = util.findIndexInData(lastResourceData, lastResource.idField, value);
785
+ if (i > -1) {
786
+ text = lastResourceData[parseInt(i.toString(), 10)][lastResource.textField] as string;
787
+ }
788
+ if (text) { resNames.push(text); }
789
+ });
790
+ resourceValue = resNames.join(', ');
791
+ } else {
792
+ const argsData: CellClickEventArgs = args as CellClickEventArgs;
793
+ const groupIndex: number = !isNullOrUndefined(argsData.groupIndex) ? argsData.groupIndex : 0;
794
+ const resourceDetails: TdData = this.parent.resourceBase.lastResourceLevel[parseInt(groupIndex.toString(), 10)];
795
+ resourceValue = resourceDetails.resourceData[resourceDetails.resource.textField] as string;
796
+ }
797
+ }
798
+ return resourceValue;
799
+ }
800
+
801
+ private getFormattedString(eventData: Record<string, any>): Record<string, any> {
802
+ const fields: EventFieldsMapping = this.parent.eventFields;
803
+ const eventSubject: string = (eventData[fields.subject] || this.l10n.getConstant('noTitle')) as string;
804
+ const startDate: Date = eventData[fields.startTime] as Date;
805
+ const endDate: Date = eventData[fields.endTime] as Date;
806
+ const startDateDetails: string = this.getDateFormat(startDate, 'long');
807
+ const endDateDetails: string = (eventData[fields.isAllDay] && endDate.getHours() === 0 && endDate.getMinutes() === 0) ?
808
+ this.getDateFormat(util.addDays(new Date(endDate.getTime()), -1), 'long') :
809
+ this.getDateFormat(endDate, 'long');
810
+ const startTimeDetail: string = this.parent.getTimeString(startDate);
811
+ const endTimeDetail: string = this.parent.getTimeString(endDate);
812
+ let details: string = '';
813
+ const spanLength: number = endDate.getDate() !== startDate.getDate() &&
814
+ (endDate.getTime() - startDate.getTime()) / (60 * 60 * 1000) < 24 ? 1 : 0;
815
+ if (eventData[fields.isAllDay]) {
816
+ details = startDateDetails + ' (' + this.l10n.getConstant('allDay') + ')';
817
+ if (((util.getUniversalTime(endDate) - util.getUniversalTime(startDate)) / util.MS_PER_DAY) > 1) {
818
+ details += '&nbsp;-&nbsp;' + endDateDetails + ' (' + this.l10n.getConstant('allDay') + ')';
819
+ }
820
+ } else if ((((util.getUniversalTime(endDate) - util.getUniversalTime(startDate)) / util.MS_PER_DAY) >= 1) || spanLength > 0) {
821
+ details = startDateDetails + ' (' + startTimeDetail + ')' + '&nbsp;-&nbsp;' + endDateDetails + ' (' + endTimeDetail + ')';
822
+ } else {
823
+ details = startDateDetails + ' (' + (startTimeDetail + '&nbsp;-&nbsp;' + endTimeDetail) + ')';
824
+ }
825
+ return { eventSubject: eventSubject, details: details };
826
+ }
827
+
828
+ public moreEventClick(data: EventClickArgs, endDate: Date, groupIndex?: string): void {
829
+ this.quickPopupHide(true);
830
+ const moreEventContentEle: Element = this.morePopup.element.querySelector('.' + cls.MORE_EVENT_CONTENT_CLASS);
831
+ if (moreEventContentEle) {
832
+ remove(moreEventContentEle);
833
+ }
834
+ const selectedDate: string = ((data.date).getTime()).toString();
835
+ const target: Element = closest(<Element>data.element, '.' + cls.MORE_INDICATOR_CLASS + ',.' + cls.WORK_CELLS_CLASS);
836
+ const day: string = this.parent.globalize.formatDate(data.date, { format: 'E', calendar: this.parent.getCalendarMode() });
837
+ this.morePopup.element.querySelector('.' + cls.MORE_EVENT_HEADER_DAY_CLASS).innerHTML = util.capitalizeFirstWord(day, 'single');
838
+ const dateElement: Element = this.morePopup.element.querySelector('.' + cls.MORE_EVENT_HEADER_DATE_CLASS);
839
+ dateElement.innerHTML = this.getDateFormat(data.date, 'd');
840
+ dateElement.setAttribute('data-date', selectedDate);
841
+ dateElement.setAttribute('data-end-date', endDate.getTime().toString());
842
+ let groupOrder: string[];
843
+ if (!isNullOrUndefined(groupIndex)) {
844
+ dateElement.setAttribute('data-group-index', groupIndex);
845
+ groupOrder = this.parent.resourceBase.lastResourceLevel[parseInt(groupIndex, 10)].groupOrder;
846
+ }
847
+ const moreEventElements: HTMLElement = this.createMoreEventList(data.event as Record<string, any>[], groupOrder, groupIndex);
848
+ this.morePopup.element.querySelector('.' + cls.MORE_EVENT_POPUP_CLASS).appendChild(moreEventElements);
849
+ removeClass(this.morePopup.element.querySelector('.' + cls.MORE_EVENT_DATE_HEADER_CLASS).childNodes, cls.CURRENTDATE_CLASS);
850
+ if (util.resetTime(data.date).getTime() === util.resetTime(this.parent.getCurrentTime()).getTime()) {
851
+ addClass(this.morePopup.element.querySelector('.' + cls.MORE_EVENT_DATE_HEADER_CLASS).childNodes, cls.CURRENTDATE_CLASS);
852
+ }
853
+ if (!this.parent.isAdaptive) {
854
+ if (this.parent.currentView.indexOf('Timeline') !== -1) {
855
+ const gIndex: string = target.getAttribute('data-group-index');
856
+ const startDate: Date = new Date(parseInt(target.getAttribute('data-start-date'), 10));
857
+ startDate.setHours(startDate.getHours(), startDate.getMinutes(), 0);
858
+ const tdDate: string = startDate.getTime().toString();
859
+ if (isNullOrUndefined(gIndex)) {
860
+ this.morePopup.relateTo = this.parent.element.querySelector('.' + cls.CONTENT_WRAP_CLASS +
861
+ ' tbody tr td[data-date="' + tdDate + '"]') as HTMLElement;
862
+ } else {
863
+ this.morePopup.relateTo = this.parent.element.querySelector('.' + cls.CONTENT_WRAP_CLASS +
864
+ ' tbody tr td[data-group-index="' + gIndex + '"][data-date="' + tdDate + '"]') as HTMLElement;
865
+ if (isNullOrUndefined(this.morePopup.relateTo)) {
866
+ const workCells: HTMLElement[] = [].slice.call(this.parent.element.querySelectorAll('.' + cls.CONTENT_WRAP_CLASS +
867
+ ' tbody tr td[data-group-index="' + gIndex + '"]'));
868
+ for (let i: number = 0; i < workCells.length; i++) {
869
+ const date: string = workCells[parseInt(i.toString(), 10)].getAttribute('data-date');
870
+ if (date < tdDate) {
871
+ this.morePopup.relateTo = workCells[parseInt(i.toString(), 10)] as HTMLElement;
872
+ }
873
+ }
874
+ }
875
+ }
876
+ } else {
877
+ this.morePopup.relateTo = closest(<Element>target, '.' + cls.WORK_CELLS_CLASS) as HTMLElement;
878
+ }
879
+ }
880
+ this.parent.renderTemplates(() => {
881
+ const eventProp: PopupOpenEventArgs = {
882
+ type: 'EventContainer', cancel: false,
883
+ element: this.morePopup.element, data: data as unknown as Record<string, any>
884
+ };
885
+ this.parent.trigger(event.popupOpen, eventProp, (popupArgs: PopupOpenEventArgs) => {
886
+ if (!popupArgs.cancel) {
887
+ this.morePopup.show();
888
+ }
889
+ });
890
+ });
891
+ }
892
+
893
+ private saveClick(event: Event): void {
894
+ this.applyFormValidation();
895
+ this.dialogEvent = event;
896
+ this.isCrudAction = true;
897
+ this.quickPopupHide();
898
+ }
899
+
900
+ private detailsClick(event: Event): void {
901
+ const subjectEle: HTMLInputElement = this.quickPopup.element.querySelector('.' + cls.SUBJECT_CLASS) as HTMLInputElement;
902
+ if (subjectEle && subjectEle.value !== '') {
903
+ extend(this.parent.activeCellsData, { subject: subjectEle.value });
904
+ }
905
+ this.dialogEvent = event;
906
+ this.isCrudAction = false;
907
+ this.fieldValidator.destroyToolTip();
908
+ this.quickPopupHide();
909
+ this.parent.eventWindow.openEditor(this.parent.activeCellsData as unknown as Record<string, any>, 'Add');
910
+ }
911
+
912
+ private editClick(event: Event): void {
913
+ this.dialogEvent = event;
914
+ this.quickPopupHide(true);
915
+ const data: Record<string, any> = this.parent.activeEventData.event as Record<string, any>;
916
+ this.parent.currentAction = 'EditSeries';
917
+ if (!isNullOrUndefined(data[this.parent.eventFields.recurrenceRule])) {
918
+ this.parent.currentAction = 'EditOccurrence';
919
+ this.openRecurrenceAlert();
920
+ } else {
921
+ this.parent.eventWindow.openEditor(data, this.parent.currentAction);
922
+ }
923
+ }
924
+
925
+ public deleteClick(event: Event): void {
926
+ this.dialogEvent = event;
927
+ this.quickPopupHide(true);
928
+ this.parent.currentAction = 'Delete';
929
+ if ((<Record<string, any>>this.parent.activeEventData.event)[this.parent.eventFields.recurrenceRule]) {
930
+ this.openRecurrenceAlert();
931
+ } else {
932
+ this.openDeleteAlert();
933
+ }
934
+ }
935
+ private updateMoreEventContent(): void {
936
+ if (this.morePopup.element.classList.contains('e-popup-close')) {
937
+ return;
938
+ }
939
+ const moreEventContentEle: Element = this.morePopup.element.querySelector('.' + cls.MORE_EVENT_CONTENT_CLASS);
940
+ if (moreEventContentEle) {
941
+ remove(moreEventContentEle);
942
+ }
943
+ const dateElement: Element = this.morePopup.element.querySelector('.' + cls.MORE_EVENT_HEADER_DATE_CLASS);
944
+ const startDate: Date = new Date(parseInt(dateElement.getAttribute('data-date'), 10));
945
+ const endDate: Date = new Date(parseInt(dateElement.getAttribute('data-end-date'), 10));
946
+ const groupIndex: string = dateElement.getAttribute('data-group-index');
947
+ let data: TdData;
948
+ let groupOrder: string[];
949
+ if (!isNullOrUndefined(groupIndex)) {
950
+ data = this.parent.resourceBase.lastResourceLevel[parseInt(groupIndex, 10)];
951
+ groupOrder = data.groupOrder;
952
+ }
953
+ const events: Record<string, any>[] = this.parent.eventBase.filterEvents(startDate, endDate, this.parent.eventsProcessed, data);
954
+ const moreElement: HTMLElement = this.createMoreEventList(events, groupOrder, groupIndex);
955
+ this.morePopup.element.querySelector('.' + cls.MORE_EVENT_POPUP_CLASS).appendChild(moreElement);
956
+ }
957
+
958
+ private closeClick(event: Event): void {
959
+ this.dialogEvent = event;
960
+ if (this.parent.currentView === 'Year' && this.parent.activeCellsData && this.parent.activeCellsData.element) {
961
+ this.parent.selectCell(this.parent.activeCellsData.element as HTMLTableCellElement);
962
+ }
963
+ this.quickPopupHide();
964
+ this.morePopup.hide();
965
+ }
966
+
967
+ private dialogButtonClick(event: Event): void {
968
+ this.dialogEvent = event;
969
+ this.quickDialog.hide();
970
+ const target: HTMLElement = event.target as HTMLElement;
971
+ const cancelBtn: Element = this.quickDialog.element.querySelector('.' + cls.QUICK_DIALOG_ALERT_CANCEL);
972
+ const eventData: Record<string, any> = this.parent.activeEventData.event as Record<string, any>;
973
+ if (target.classList.contains(cls.QUICK_DIALOG_OCCURRENCE_CLASS)) {
974
+ this.parent.currentAction = (this.parent.currentAction === 'Delete') ? 'DeleteOccurrence' : 'EditOccurrence';
975
+ switch (this.parent.currentAction) {
976
+ case 'EditOccurrence':
977
+ this.parent.eventWindow.openEditor(eventData, this.parent.currentAction);
978
+ break;
979
+ case 'DeleteOccurrence':
980
+ this.parent.crudModule.deleteEvent(eventData, this.parent.currentAction);
981
+ break;
982
+ }
983
+ } else if (target.classList.contains(cls.QUICK_DIALOG_FOLLOWING_EVENTS_CLASS)) {
984
+ this.parent.currentAction = (this.parent.currentAction === 'Delete') ? 'DeleteFollowingEvents' : 'EditFollowingEvents';
985
+ switch (this.parent.currentAction) {
986
+ case 'EditFollowingEvents':
987
+ this.parent.eventWindow.openEditor(eventData, this.parent.currentAction);
988
+ break;
989
+ case 'DeleteFollowingEvents':
990
+ this.parent.crudModule.deleteEvent(eventData, this.parent.currentAction);
991
+ break;
992
+ }
993
+ } else if (target.classList.contains(cls.QUICK_DIALOG_SERIES_CLASS)) {
994
+ this.parent.currentAction = (this.parent.currentAction === 'Delete') ? 'DeleteSeries' : 'EditSeries';
995
+ switch (this.parent.currentAction) {
996
+ case 'EditSeries':
997
+ this.parent.eventWindow.openEditor(this.parent.eventBase.getParentEvent(eventData, true), this.parent.currentAction);
998
+ break;
999
+ case 'DeleteSeries':
1000
+ this.parent.crudModule.deleteEvent(eventData, this.parent.currentAction);
1001
+ break;
1002
+ }
1003
+ } else if (target.classList.contains(cls.QUICK_DIALOG_DELETE_CLASS)) {
1004
+ this.parent.crudModule.deleteEvent(eventData, this.parent.currentAction);
1005
+ } else if (!cancelBtn.classList.contains(cls.DISABLE_CLASS) && (target.classList.contains(cls.QUICK_DIALOG_ALERT_OK) ||
1006
+ (target.classList.contains(cls.QUICK_DIALOG_ALERT_CANCEL) && !cancelBtn.classList.contains(cls.QUICK_DIALOG_CANCEL_CLASS)))) {
1007
+ this.parent.uiStateValues.isIgnoreOccurrence = target.classList.contains(cls.QUICK_DIALOG_ALERT_CANCEL);
1008
+ this.parent.eventWindow.eventSave(event, this.l10n.getConstant('ok'));
1009
+ }
1010
+ }
1011
+
1012
+ private updateTapHoldEventPopup(target: Element): void {
1013
+ const selectedElements: Element[] = this.parent.eventBase.getSelectedEventElements(target);
1014
+ this.parent.activeEventData = this.parent.eventBase.getSelectedEvents();
1015
+ if (selectedElements.length > 0) {
1016
+ const eventObj: Record<string, any> = this.parent.eventBase.getEventByGuid(selectedElements[0].getAttribute('data-guid'));
1017
+ const titleContent: string = (selectedElements.length === 1) ?
1018
+ ((<Record<string, any>>eventObj)[this.parent.eventFields.subject] || this.l10n.getConstant('noTitle')) as string :
1019
+ '(' + selectedElements.length + ')' + '&nbsp;' + this.l10n.getConstant('selectedItems');
1020
+ this.quickPopup.element.querySelector('.' + cls.SUBJECT_CLASS).innerHTML = titleContent;
1021
+ if (selectedElements.length > 1) {
1022
+ addClass([this.quickPopup.element.querySelector('.' + cls.EDIT_ICON_CLASS)], cls.HIDDEN_CLASS);
1023
+ } else {
1024
+ removeClass([this.quickPopup.element.querySelector('.' + cls.EDIT_ICON_CLASS)], cls.HIDDEN_CLASS);
1025
+ }
1026
+ } else {
1027
+ this.parent.selectedElements = [];
1028
+ this.quickPopupHide();
1029
+ }
1030
+ }
1031
+
1032
+ private getTimezone(event: Record<string, any>): string {
1033
+ let zoneDetails: string = '';
1034
+ zoneDetails += event[this.parent.eventFields.startTimezone] as string || '';
1035
+ zoneDetails += zoneDetails === '' ? '' : ' - ';
1036
+ zoneDetails += event[this.parent.eventFields.endTimezone] as string || '';
1037
+ return zoneDetails;
1038
+ }
1039
+
1040
+ private getRecurrenceSummary(event: Record<string, any>): string {
1041
+ const recurrenceEditor: RecurrenceEditor = this.parent.eventWindow.getRecurrenceEditorInstance();
1042
+ if (recurrenceEditor) {
1043
+ const ruleSummary: string = recurrenceEditor.getRuleSummary(<string>event[this.parent.eventFields.recurrenceRule]);
1044
+ return ruleSummary.charAt(0).toUpperCase() + ruleSummary.slice(1);
1045
+ }
1046
+ return '';
1047
+ }
1048
+
1049
+ private getDateFormat(date: Date, skeletonString: string): string {
1050
+ return util.capitalizeFirstWord(
1051
+ this.parent.globalize.formatDate(date, { skeleton: skeletonString, calendar: this.parent.getCalendarMode() }),
1052
+ 'single'
1053
+ );
1054
+ }
1055
+
1056
+ private getDataFromTarget(target: Element): Record<string, any> {
1057
+ if (target.classList.contains(cls.APPOINTMENT_CLASS)) {
1058
+ return this.parent.activeEventData.event as Record<string, any>;
1059
+ }
1060
+ // Deprecated cells data in quick popups
1061
+ const eventObj: Record<string, any> = {
1062
+ startTime: this.parent.activeCellsData.startTime,
1063
+ endTime: this.parent.activeCellsData.endTime,
1064
+ isAllDay: this.parent.activeCellsData.isAllDay,
1065
+ groupIndex: this.parent.activeCellsData.groupIndex
1066
+ };
1067
+ const cellsData: Record<string, any> = this.parent.activeCellsData as unknown as Record<string, any>;
1068
+ this.parent.eventWindow.convertToEventData(cellsData, eventObj);
1069
+ return eventObj;
1070
+ }
1071
+
1072
+ private beforeQuickDialogClose(e: BeforeCloseEventArgs): void {
1073
+ const args: PopupCloseEventArgs = {
1074
+ event: e.event || this.dialogEvent,
1075
+ type: (isNullOrUndefined(this.parent.activeEventData.event)) ? 'ValidationAlert' :
1076
+ !isNullOrUndefined((<Record<string, any>>this.parent.activeEventData.event)[this.parent.eventFields.recurrenceRule])
1077
+ ? 'RecurrenceAlert' : 'DeleteAlert', cancel: false, data: this.parent.activeEventData.event as Record<string, any>,
1078
+ element: this.quickDialog.element
1079
+ };
1080
+ this.parent.trigger(event.popupClose, args, (popupCloseArgs: PopupCloseEventArgs) => {
1081
+ if (!popupCloseArgs.cancel) {
1082
+ this.parent.eventBase.focusElement(true);
1083
+ }
1084
+ });
1085
+ }
1086
+
1087
+ private beforeQuickPopupOpen(target: Element, originalEvent: (MouseEvent & TouchEvent) | Touch): void {
1088
+ this.parent.renderTemplates(() => {
1089
+ const isEventPopup: Element = this.quickPopup.element.querySelector('.' + cls.EVENT_POPUP_CLASS);
1090
+ const popupType: PopupType = this.parent.isAdaptive ? isEventPopup ? 'ViewEventInfo' : 'EditEventInfo' : 'QuickInfo';
1091
+ const eventProp: PopupOpenEventArgs = {
1092
+ type: popupType, cancel: false, data: extend({}, this.getDataFromTarget(target), null, true) as Record<string, any>,
1093
+ target: target, element: this.quickPopup.element
1094
+ };
1095
+ this.parent.trigger(event.popupOpen, eventProp, (popupArgs: PopupOpenEventArgs) => {
1096
+ if (popupArgs.cancel) {
1097
+ this.quickPopupHide();
1098
+ this.destroyPopupButtons('quickPopup');
1099
+ if (popupArgs.element.classList.contains(cls.POPUP_OPEN)) {
1100
+ this.quickPopupClose();
1101
+ }
1102
+ util.removeChildren(this.quickPopup.element);
1103
+ this.isMultipleEventSelect = false;
1104
+ } else {
1105
+ const display: string = this.quickPopup.element.style.display;
1106
+ this.quickPopup.element.style.display = 'block';
1107
+ if (this.parent.isAdaptive) {
1108
+ this.quickPopup.element.removeAttribute('style');
1109
+ this.quickPopup.element.style.display = 'block';
1110
+ this.quickPopup.element.style.height = formatUnit((popupType === 'EditEventInfo') ? 65 : window.innerHeight);
1111
+ } else {
1112
+ const isVirtualScroll: boolean =
1113
+ this.parent.virtualScrollModule && this.parent.virtualScrollModule.isHorizontalScroll
1114
+ && !isNullOrUndefined(closest(target, '.' + cls.CONTENT_TABLE_CLASS));
1115
+ const conTable: HTMLElement = this.parent.element.querySelector('.' + cls.CONTENT_WRAP_CLASS + ' table');
1116
+ this.quickPopup.offsetX = isVirtualScroll && !this.parent.enableRtl ? (util.getTranslateX(conTable) + 10) : 10;
1117
+ this.quickPopup.offsetY = this.parent.virtualScrollModule && !this.parent.virtualScrollModule.isHorizontalScroll ?
1118
+ this.quickPopup.offsetY : 0;
1119
+ this.quickPopup.collision = { X: this.parent.enableRtl ? 'flip' : 'none', Y: 'fit' };
1120
+ this.quickPopup.position = { X: this.parent.enableRtl ? 'left' : 'right', Y: this.parent.enableRtl ? 'bottom' : 'top' };
1121
+ this.quickPopup.dataBind();
1122
+ this.quickPopup.refreshPosition(null, true);
1123
+ const collide: string[] = isCollide(this.quickPopup.element, this.parent.element);
1124
+ if (collide.indexOf(this.parent.enableRtl ? 'left' : 'right') > -1) {
1125
+ this.quickPopup.offsetX = -(target as HTMLElement).offsetWidth - 10 - this.quickPopup.element.offsetWidth;
1126
+ if (isVirtualScroll && !this.parent.enableRtl) {
1127
+ this.quickPopup.offsetX = util.getTranslateX(conTable) + this.quickPopup.offsetX;
1128
+ }
1129
+ this.quickPopup.dataBind();
1130
+ this.quickPopup.refreshPosition(null, true);
1131
+ const leftCollide: string[] = isCollide(this.quickPopup.element, this.parent.element);
1132
+ if (leftCollide.indexOf('left') > -1) {
1133
+ this.quickPopup.position = { X: 'center', Y: 'center' };
1134
+ this.quickPopup.collision = { X: 'fit', Y: 'fit' };
1135
+ this.quickPopup.offsetX = -(this.quickPopup.element.offsetWidth / 2);
1136
+ this.quickPopup.dataBind();
1137
+ }
1138
+ }
1139
+ if (this.parent.virtualScrollModule && !this.parent.virtualScrollModule.isHorizontalScroll && (collide.indexOf('top') > -1 || collide.indexOf('bottom') > -1)) {
1140
+ const translateY: number = util.getTranslateY(conTable);
1141
+ this.quickPopup.offsetY = translateY;
1142
+ this.quickPopup.dataBind();
1143
+ this.quickPopup.refreshPosition(null, true);
1144
+ }
1145
+ if (this.quickPopup.position.X === 'center' && this.quickPopup.position.Y === 'center' && !isNullOrUndefined(originalEvent) &&
1146
+ (originalEvent as MouseEvent).clientX && (originalEvent as MouseEvent).clientY) {
1147
+ const clientX: number = (originalEvent as MouseEvent).clientX;
1148
+ const clientY: number = (originalEvent as MouseEvent).clientY;
1149
+ const targetRect: ClientRect | DOMRect = target.getBoundingClientRect();
1150
+ const offsetY: number = (originalEvent as MouseEvent).offsetY || Math.ceil(clientY - (targetRect as any).y);
1151
+ const previousOffset: number = this.quickPopup.offsetY;
1152
+ let collision: string[] = isCollide(this.quickPopup.element, target as HTMLElement);
1153
+ const popupRect: ClientRect | DOMRect = this.quickPopup.element.getBoundingClientRect();
1154
+ const targetEle: Element = document.elementFromPoint(clientX, clientY);
1155
+ if (collision.indexOf('top') > -1 || collision.indexOf('bottom') > -1 || closest(targetEle, '.' + cls.POPUP_WRAPPER_CLASS)) {
1156
+ if (popupRect.top <= clientY &&
1157
+ clientY <= popupRect.top + popupRect.height) {
1158
+ this.quickPopup.offsetY = previousOffset - popupRect.height - 10;
1159
+ this.quickPopup.dataBind();
1160
+ collision = isCollide(this.quickPopup.element, this.parent.element);
1161
+ if (collision.indexOf('top') > -1) {
1162
+ this.quickPopup.offsetY = previousOffset + offsetY + 10;
1163
+ this.quickPopup.dataBind();
1164
+ }
1165
+ } else if (isCollide(this.quickPopup.element, this.parent.element).indexOf('bottom') > -1) {
1166
+ this.quickPopup.offsetY =
1167
+ previousOffset - offsetY - Math.ceil(popupRect.height) - 10;
1168
+ this.quickPopup.dataBind();
1169
+ }
1170
+ }
1171
+ }
1172
+ }
1173
+ if (isEventPopup) {
1174
+ this.applyEventColor();
1175
+ }
1176
+ this.quickPopup.element.style.display = display;
1177
+ this.quickPopup.dataBind();
1178
+ this.quickPopup.show();
1179
+ }
1180
+ });
1181
+ });
1182
+ }
1183
+
1184
+ private applyEventColor(): void {
1185
+ let colorField: string = '';
1186
+ if (this.parent.currentView === 'Agenda' || this.parent.currentView === 'MonthAgenda') {
1187
+ colorField = this.parent.enableRtl ? 'border-right-color' : 'border-left-color';
1188
+ } else {
1189
+ colorField = 'background-color';
1190
+ }
1191
+ let color: string = (<HTMLElement>this.parent.activeEventData.element).style[<any>colorField];
1192
+ if (color === '') {
1193
+ return;
1194
+ }
1195
+ let colorEle: HTMLElement = this.quickPopup.element.querySelector('.' + cls.POPUP_HEADER_CLASS) as HTMLElement;
1196
+ const footerEle: HTMLElement = this.quickPopup.element.querySelector('.' + cls.POPUP_FOOTER_CLASS) as HTMLElement;
1197
+ if (footerEle && footerEle.offsetParent) {
1198
+ colorEle = this.quickPopup.element.querySelector('.' + cls.SUBJECT_CLASS) as HTMLElement;
1199
+ if (colorEle) {
1200
+ colorEle.style.borderLeftColor = color;
1201
+ color = `rgba(${color.match(/\d+/g).join()},0.3)`;
1202
+ }
1203
+ }
1204
+ if (colorEle) {
1205
+ colorEle.style.backgroundColor = color;
1206
+ }
1207
+ }
1208
+
1209
+ private quickPopupOpen(): void {
1210
+ if (this.parent.isAdaptive) {
1211
+ this.quickPopup.element.style.top = '0px';
1212
+ return;
1213
+ }
1214
+ if (this.quickPopup.element.querySelector('.' + cls.CELL_POPUP_CLASS)) {
1215
+ const subjectElement: HTMLInputElement = this.quickPopup.element.querySelector('.' + cls.SUBJECT_CLASS) as HTMLInputElement;
1216
+ if (subjectElement) {
1217
+ subjectElement.focus();
1218
+ }
1219
+ } else {
1220
+ const editElement: HTMLInputElement = this.quickPopup.element.querySelector('.' + cls.EDIT_EVENT_CLASS) as HTMLInputElement;
1221
+ if (editElement) {
1222
+ editElement.focus();
1223
+ }
1224
+ const editIcon: HTMLInputElement = this.quickPopup.element.querySelector('.' + cls.EDIT_CLASS) as HTMLInputElement;
1225
+ if (editIcon) {
1226
+ editIcon.focus();
1227
+ }
1228
+ }
1229
+ }
1230
+
1231
+ private quickPopupClose(): void {
1232
+ this.parent.eventBase.focusElement();
1233
+ this.quickPopup.relateTo = '.' + cls.WORK_CELLS_CLASS;
1234
+ this.fieldValidator.destroyToolTip();
1235
+ if (this.quickPopup.element.querySelectorAll('.e-formvalidator').length) {
1236
+ this.fieldValidator.destroy();
1237
+ }
1238
+ this.destroyPopupButtons('quickPopup');
1239
+ util.removeChildren(this.quickPopup.element);
1240
+ }
1241
+
1242
+ private morePopupOpen(): void {
1243
+ if (this.parent.isAdaptive) {
1244
+ this.morePopup.element.style.top = '0px';
1245
+ this.morePopup.element.style.left = '0px';
1246
+ this.morePopup.element.style.height = formatUnit(window.innerHeight);
1247
+ return;
1248
+ }
1249
+ (this.morePopup.element.querySelector('.' + cls.MORE_EVENT_HEADER_DATE_CLASS) as HTMLElement).focus();
1250
+ this.morePopup.refreshPosition();
1251
+ }
1252
+
1253
+ private morePopupClose(): void {
1254
+ const moreWrapper: Element = this.parent.element.querySelector('.' + cls.MORE_EVENT_WRAPPER_CLASS);
1255
+ if (moreWrapper) {
1256
+ remove(moreWrapper);
1257
+ }
1258
+ }
1259
+
1260
+ private popupClose(event: Event): void {
1261
+ this.dialogEvent = event;
1262
+ this.isCrudAction = false;
1263
+ this.quickPopupHide(true);
1264
+ }
1265
+
1266
+ public quickPopupHide(hideAnimation?: boolean): void {
1267
+ if (!this.quickPopup.element.classList.contains(cls.POPUP_OPEN)) {
1268
+ return;
1269
+ }
1270
+ const isCellPopup: Element = this.quickPopup.element.querySelector('.' + cls.CELL_POPUP_CLASS);
1271
+ let popupData: Record<string, any>;
1272
+ if (isCellPopup) {
1273
+ const formvalidator: Element = this.quickPopup.element.querySelector('.e-formvalidator');
1274
+ if (this.isCrudAction && formvalidator &&
1275
+ !((formvalidator as EJ2Instance).ej2_instances[0] as FormValidator).validate()) {
1276
+ return;
1277
+ }
1278
+ const fields: EventFieldsMapping = this.parent.eventFields;
1279
+ const saveObj: Record<string, any> = this.parent.eventWindow.getObjectFromFormData(cls.POPUP_WRAPPER_CLASS);
1280
+ this.parent.eventWindow.setDefaultValueToObject(saveObj);
1281
+ saveObj[fields.id] = this.parent.eventBase.getEventMaxID();
1282
+ saveObj[fields.startTime] = this.parent.activeCellsData.startTime;
1283
+ saveObj[fields.endTime] = this.parent.activeCellsData.endTime;
1284
+ saveObj[fields.isAllDay] = this.parent.activeCellsData.isAllDay;
1285
+ if (this.parent.resourceBase) {
1286
+ this.parent.resourceBase.setResourceValues(saveObj);
1287
+ }
1288
+ popupData = saveObj;
1289
+ } else {
1290
+ popupData = this.parent.activeEventData.event as Record<string, any>;
1291
+ }
1292
+ const isEventPopup: Element = this.quickPopup.element.querySelector('.' + cls.EVENT_POPUP_CLASS);
1293
+ const args: PopupCloseEventArgs = {
1294
+ event: this.dialogEvent,
1295
+ type: this.parent.isAdaptive ? isEventPopup ? 'ViewEventInfo' : 'EditEventInfo' : 'QuickInfo',
1296
+ cancel: false, data: popupData, element: this.quickPopup.element,
1297
+ target: (isCellPopup ? this.parent.activeCellsData.element : this.parent.activeEventData.element) as Element
1298
+ };
1299
+ this.parent.trigger(event.popupClose, args, (popupCloseArgs: PopupCloseEventArgs) => {
1300
+ if (!popupCloseArgs.cancel) {
1301
+ if (this.quickPopup.element.classList.contains('e-popup-open')) {
1302
+ if (isCellPopup && this.isCrudAction) {
1303
+ this.parent.currentAction = 'Add';
1304
+ this.parent.crudModule.addEvent(popupCloseArgs.data);
1305
+ }
1306
+ if (hideAnimation) {
1307
+ const animation: AnimationModel = this.quickPopup.hideAnimation;
1308
+ this.quickPopup.hideAnimation = null;
1309
+ this.quickPopup.hide();
1310
+ this.quickPopup.hideAnimation = animation;
1311
+ } else {
1312
+ this.quickPopup.hide();
1313
+ }
1314
+ this.isMultipleEventSelect = false;
1315
+ this.isCrudAction = false;
1316
+ }
1317
+ }
1318
+ });
1319
+ }
1320
+
1321
+ private navigationClick(e: Event): void {
1322
+ const navigateEle: Element = closest((e.target as Element), '.' + cls.NAVIGATE_CLASS);
1323
+ if (!isNullOrUndefined(navigateEle)) {
1324
+ const date: Date = this.parent.getDateFromElement(e.currentTarget as HTMLTableCellElement);
1325
+ if (!isNullOrUndefined(date)) {
1326
+ this.closeClick(e);
1327
+ this.parent.setProperties({ selectedDate: date }, true);
1328
+ this.parent.changeView(this.parent.getNavigateView(), e);
1329
+ }
1330
+ }
1331
+ }
1332
+
1333
+ private documentClick(e: { event: Event }): void {
1334
+ const target: Element = e.event.target as Element;
1335
+ const isInsideDialog: boolean = !!closest(target, '.e-dialog');
1336
+ let classNames: string = '.' + cls.POPUP_WRAPPER_CLASS + ',.' + cls.HEADER_CELLS_CLASS + ',.' + cls.ALLDAY_CELLS_CLASS +
1337
+ ',.' + cls.WORK_CELLS_CLASS + ',.' + cls.APPOINTMENT_CLASS;
1338
+ if (!isInsideDialog) {
1339
+ classNames += ',.e-popup';
1340
+ }
1341
+ const popupWrap: Element = this.parent.element.querySelector('.' + cls.POPUP_WRAPPER_CLASS);
1342
+ if ((popupWrap && popupWrap.childElementCount > 0 && !closest(target, classNames)) || !closest(target, classNames)) {
1343
+ this.quickPopupHide();
1344
+ this.parent.removeNewEventElement();
1345
+ }
1346
+ const tar: HTMLInputElement | null = this.parent.allowInline ? this.parent.inlineModule.getInlineElement() : null;
1347
+ if (tar && tar !== target) {
1348
+ this.parent.inlineModule.documentClick(tar);
1349
+ }
1350
+ if (closest(target, '.' + cls.APPOINTMENT_CLASS + ',.' + cls.HEADER_CELLS_CLASS)) {
1351
+ this.parent.removeNewEventElement();
1352
+ }
1353
+ const isQuickPopupClick: boolean | Element | null = closest(target, '.' + cls.POPUP_WRAPPER_CLASS) ||
1354
+ closest(target, '.' + cls.QUICK_DIALOG_CLASS);
1355
+ const isEditButton: boolean = target.classList.contains(cls.EDIT_EVENT_CLASS) ||
1356
+ target.classList.contains(cls.EDIT_CLASS) || target.classList.contains(cls.EDIT_ICON_CLASS);
1357
+ if (isEditButton || !isQuickPopupClick && !closest(target, '.' + cls.MORE_POPUP_WRAPPER_CLASS) && (target.classList &&
1358
+ !target.classList.contains(cls.MORE_INDICATOR_CLASS))
1359
+ && (!closest(target, '.' + cls.MORE_POPUP_WRAPPER_CLASS + '.' + cls.POPUP_OPEN))
1360
+ && !closest(target, '.' + cls.WORK_CELLS_CLASS)) {
1361
+ this.morePopup.hide();
1362
+ }
1363
+ }
1364
+
1365
+ public onClosePopup(event?: Event): void {
1366
+ if (!isNullOrUndefined(event)) {
1367
+ this.dialogEvent = event;
1368
+ }
1369
+ this.quickPopupHide();
1370
+ if (isNullOrUndefined(event) || (!isNullOrUndefined(event) && (event as KeyboardEventArgs).action !== 'escape') ||
1371
+ (this.parent.inlineModule && this.parent.element.querySelector('.' + cls.INLINE_APPOINTMENT_CLASS))) {
1372
+ this.parent.eventBase.focusElement();
1373
+ }
1374
+ }
1375
+
1376
+ private addEventListener(): void {
1377
+ this.parent.on(event.cellClick, this.cellClick, this);
1378
+ this.parent.on(event.eventClick, this.eventClick, this);
1379
+ this.parent.on(event.documentClick, this.documentClick, this);
1380
+ this.parent.on(event.dataReady, this.updateMoreEventContent, this);
1381
+ }
1382
+
1383
+ private removeEventListener(): void {
1384
+ this.parent.off(event.cellClick, this.cellClick);
1385
+ this.parent.off(event.eventClick, this.eventClick);
1386
+ this.parent.off(event.documentClick, this.documentClick);
1387
+ this.parent.off(event.dataReady, this.updateMoreEventContent);
1388
+ }
1389
+
1390
+ private destroyPopupButtons(popupName: string): void {
1391
+ const popup: Popup = popupName === 'quickPopup' ? this.quickPopup : this.morePopup;
1392
+ const buttonCollections: HTMLElement[] = [].slice.call(popup.element.querySelectorAll('.e-control.e-btn'));
1393
+ for (const button of buttonCollections) {
1394
+ const instance: Button = (button as EJ2Instance).ej2_instances ? (button as EJ2Instance).ej2_instances[0] as Button : null;
1395
+ if (instance) {
1396
+ instance.destroy();
1397
+ }
1398
+ }
1399
+ if (popupName === 'quickPopup') {
1400
+ const input: HTMLInputElement = popup.element.querySelector('input.' + cls.SUBJECT_CLASS);
1401
+ if (input) {
1402
+ input.remove();
1403
+ }
1404
+ const form: HTMLFormElement = this.quickPopup.element.querySelector('form.' + cls.FORM_CLASS);
1405
+ if (form) {
1406
+ util.removeChildren(form);
1407
+ form.remove();
1408
+ }
1409
+ this.parent.resetTemplates(['content', 'header', 'footer']);
1410
+ }
1411
+ }
1412
+
1413
+ public refreshQuickDialog(): void {
1414
+ this.destroyQuickDialog();
1415
+ this.renderQuickDialog();
1416
+ }
1417
+
1418
+ public refreshQuickPopup(): void {
1419
+ this.destroyQuickPopup();
1420
+ this.renderQuickPopup();
1421
+ }
1422
+
1423
+ public refreshMorePopup(): void {
1424
+ this.destroyMorePopup();
1425
+ this.renderMorePopup();
1426
+ }
1427
+
1428
+ private destroyQuickDialog(): void {
1429
+ if (this.quickDialog.element) {
1430
+ this.quickDialog.destroy();
1431
+ remove(this.quickDialog.element);
1432
+ this.quickDialog = null;
1433
+ }
1434
+ }
1435
+
1436
+ private destroyQuickPopup(): void {
1437
+ if (this.quickPopup.element) {
1438
+ this.destroyPopupButtons('quickPopup');
1439
+ this.quickPopup.destroy();
1440
+ remove(this.quickPopup.element);
1441
+ this.quickPopup = null;
1442
+ }
1443
+ }
1444
+
1445
+ private destroyMorePopup(): void {
1446
+ if (this.morePopup.element) {
1447
+ this.destroyPopupButtons('morePopup');
1448
+ this.morePopup.destroy();
1449
+ remove(this.morePopup.element);
1450
+ this.morePopup = null;
1451
+ }
1452
+ }
1453
+
1454
+ public destroy(): void {
1455
+ if (this.quickPopup.element.querySelectorAll('.e-formvalidator').length) {
1456
+ this.fieldValidator.destroy();
1457
+ }
1458
+ this.removeEventListener();
1459
+ this.destroyQuickPopup();
1460
+ this.destroyMorePopup();
1461
+ this.destroyQuickDialog();
1462
+ this.dialogEvent = null;
1463
+ this.parent = null;
1464
+ this.l10n = null;
1465
+ this.isCrudAction = null;
1466
+ this.fieldValidator = null;
1467
+ this.isMultipleEventSelect = null;
1468
+ }
1469
+
1470
+ }