@syncfusion/ej2-schedule 22.2.11 → 23.1.36

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 (120) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/ej2-schedule.min.js +2 -2
  3. package/dist/ej2-schedule.umd.min.js +2 -2
  4. package/dist/ej2-schedule.umd.min.js.map +1 -1
  5. package/dist/es6/ej2-schedule.es2015.js +445 -172
  6. package/dist/es6/ej2-schedule.es2015.js.map +1 -1
  7. package/dist/es6/ej2-schedule.es5.js +445 -173
  8. package/dist/es6/ej2-schedule.es5.js.map +1 -1
  9. package/dist/global/ej2-schedule.min.js +2 -2
  10. package/dist/global/ej2-schedule.min.js.map +1 -1
  11. package/dist/global/index.d.ts +1 -1
  12. package/package.json +16 -16
  13. package/src/recurrence-editor/date-generator.d.ts +1 -2
  14. package/src/recurrence-editor/date-generator.js +3 -5
  15. package/src/recurrence-editor/recurrence-editor.d.ts +1 -1
  16. package/src/schedule/actions/crud.d.ts +1 -1
  17. package/src/schedule/actions/crud.js +19 -6
  18. package/src/schedule/actions/data.js +29 -8
  19. package/src/schedule/actions/keyboard.js +4 -1
  20. package/src/schedule/actions/virtual-scroll.d.ts +1 -0
  21. package/src/schedule/actions/virtual-scroll.js +37 -2
  22. package/src/schedule/base/constant.d.ts +4 -0
  23. package/src/schedule/base/constant.js +4 -0
  24. package/src/schedule/base/interface.d.ts +15 -0
  25. package/src/schedule/base/resource.js +1 -0
  26. package/src/schedule/base/schedule-model.d.ts +41 -35
  27. package/src/schedule/base/schedule.d.ts +54 -35
  28. package/src/schedule/base/schedule.js +71 -6
  29. package/src/schedule/base/util.d.ts +1 -0
  30. package/src/schedule/base/util.js +1 -0
  31. package/src/schedule/event-renderer/event-base.d.ts +1 -1
  32. package/src/schedule/event-renderer/event-base.js +4 -4
  33. package/src/schedule/exports/calendar-import.d.ts +2 -1
  34. package/src/schedule/exports/calendar-import.js +134 -106
  35. package/src/schedule/models/views-model.d.ts +10 -1
  36. package/src/schedule/models/views.d.ts +9 -1
  37. package/src/schedule/models/views.js +3 -0
  38. package/src/schedule/popups/event-tooltip.js +7 -3
  39. package/src/schedule/popups/event-window.d.ts +7 -0
  40. package/src/schedule/popups/event-window.js +123 -29
  41. package/src/schedule/popups/quick-popups.js +3 -0
  42. package/src/schedule/renderer/timeline-view.js +5 -2
  43. package/styles/bootstrap-dark.css +15 -0
  44. package/styles/bootstrap.css +15 -0
  45. package/styles/bootstrap4.css +15 -0
  46. package/styles/bootstrap5-dark.css +15 -0
  47. package/styles/bootstrap5.css +15 -0
  48. package/styles/fabric-dark.css +15 -0
  49. package/styles/fabric.css +15 -0
  50. package/styles/fluent-dark.css +15 -0
  51. package/styles/fluent.css +15 -0
  52. package/styles/highcontrast-light.css +15 -0
  53. package/styles/highcontrast.css +15 -0
  54. package/styles/material-dark.css +15 -1
  55. package/styles/material.css +15 -1
  56. package/styles/material3-dark.css +16 -2
  57. package/styles/material3-dark.scss +1 -1
  58. package/styles/material3.css +16 -2
  59. package/styles/material3.scss +1 -1
  60. package/styles/recurrence-editor/bootstrap-dark.scss +1 -1
  61. package/styles/recurrence-editor/bootstrap.scss +1 -1
  62. package/styles/recurrence-editor/bootstrap4.scss +1 -1
  63. package/styles/recurrence-editor/bootstrap5-dark.scss +1 -1
  64. package/styles/recurrence-editor/bootstrap5.scss +1 -1
  65. package/styles/recurrence-editor/fabric-dark.scss +1 -1
  66. package/styles/recurrence-editor/fabric.scss +1 -1
  67. package/styles/recurrence-editor/fluent-dark.scss +1 -1
  68. package/styles/recurrence-editor/fluent.scss +1 -1
  69. package/styles/recurrence-editor/highcontrast-light.scss +1 -1
  70. package/styles/recurrence-editor/highcontrast.scss +1 -1
  71. package/styles/recurrence-editor/material-dark.css +0 -1
  72. package/styles/recurrence-editor/material-dark.scss +1 -1
  73. package/styles/recurrence-editor/material.css +0 -1
  74. package/styles/recurrence-editor/material.scss +1 -1
  75. package/styles/recurrence-editor/material3-dark.css +0 -1
  76. package/styles/recurrence-editor/material3-dark.scss +1 -1
  77. package/styles/recurrence-editor/material3.css +0 -1
  78. package/styles/recurrence-editor/material3.scss +1 -1
  79. package/styles/recurrence-editor/tailwind-dark.css +0 -1
  80. package/styles/recurrence-editor/tailwind-dark.scss +1 -1
  81. package/styles/recurrence-editor/tailwind.css +0 -1
  82. package/styles/recurrence-editor/tailwind.scss +1 -1
  83. package/styles/schedule/_layout.scss +15 -0
  84. package/styles/schedule/_material3-definition.scss +1 -1
  85. package/styles/schedule/bootstrap-dark.css +15 -0
  86. package/styles/schedule/bootstrap-dark.scss +1 -1
  87. package/styles/schedule/bootstrap.css +15 -0
  88. package/styles/schedule/bootstrap.scss +1 -1
  89. package/styles/schedule/bootstrap4.css +15 -0
  90. package/styles/schedule/bootstrap4.scss +1 -1
  91. package/styles/schedule/bootstrap5-dark.css +15 -0
  92. package/styles/schedule/bootstrap5-dark.scss +1 -1
  93. package/styles/schedule/bootstrap5.css +15 -0
  94. package/styles/schedule/bootstrap5.scss +1 -1
  95. package/styles/schedule/fabric-dark.css +15 -0
  96. package/styles/schedule/fabric-dark.scss +1 -1
  97. package/styles/schedule/fabric.css +15 -0
  98. package/styles/schedule/fabric.scss +1 -1
  99. package/styles/schedule/fluent-dark.css +15 -0
  100. package/styles/schedule/fluent-dark.scss +1 -1
  101. package/styles/schedule/fluent.css +15 -0
  102. package/styles/schedule/fluent.scss +1 -1
  103. package/styles/schedule/highcontrast-light.css +15 -0
  104. package/styles/schedule/highcontrast-light.scss +1 -1
  105. package/styles/schedule/highcontrast.css +15 -0
  106. package/styles/schedule/highcontrast.scss +1 -1
  107. package/styles/schedule/material-dark.css +15 -1
  108. package/styles/schedule/material-dark.scss +1 -1
  109. package/styles/schedule/material.css +15 -1
  110. package/styles/schedule/material.scss +1 -1
  111. package/styles/schedule/material3-dark.css +16 -2
  112. package/styles/schedule/material3-dark.scss +1 -1
  113. package/styles/schedule/material3.css +16 -2
  114. package/styles/schedule/material3.scss +1 -1
  115. package/styles/schedule/tailwind-dark.css +15 -1
  116. package/styles/schedule/tailwind-dark.scss +1 -1
  117. package/styles/schedule/tailwind.css +15 -1
  118. package/styles/schedule/tailwind.scss +1 -1
  119. package/styles/tailwind-dark.css +15 -2
  120. package/styles/tailwind.css +15 -2
@@ -60,6 +60,10 @@ const resizeStop = 'resizeStop';
60
60
  const inlineClick = 'inlineClick';
61
61
  /** @private */
62
62
  const cellSelect = 'cellSelect';
63
+ /** @private */
64
+ const virtualScrollStart = 'virtualScrollStart';
65
+ /** @private */
66
+ const virtualScrollStop = 'virtualScrollStop';
63
67
  /**
64
68
  * Specifies schedule internal events
65
69
  */
@@ -389,6 +393,7 @@ function getScrollBarWidth() {
389
393
  * Method to reset scrollbar width
390
394
  *
391
395
  * @private
396
+ * @returns {void}
392
397
  */
393
398
  function resetScrollbarWidth() {
394
399
  const zoomPixelRatio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
@@ -551,7 +556,7 @@ const WORK_HOURS_CLASS = 'e-work-hours';
551
556
  /** @private */
552
557
  const POPUP_OPEN = 'e-popup-open';
553
558
  /** @private */
554
-
559
+ const POPUP_CLOSE = 'e-popup-close';
555
560
  /** @private */
556
561
  const DATE_HEADER_WRAP_CLASS = 'e-date-header-wrap';
557
562
  /** @private */
@@ -2063,7 +2068,11 @@ class KeyboardInteraction {
2063
2068
  return;
2064
2069
  }
2065
2070
  const queryStr = '.' + WORK_CELLS_CLASS + ',.' + ALLDAY_CELLS_CLASS + ',.' + HEADER_CELLS_CLASS;
2066
- const target = closest(e.target, queryStr);
2071
+ let target = closest(e.target, queryStr);
2072
+ const selectedCells = this.parent.getSelectedCells();
2073
+ if (selectedCells.length > 0 && selectedCells.indexOf(target) === -1) {
2074
+ target = selectedCells[selectedCells.length - 1];
2075
+ }
2067
2076
  if (this.parent.currentView === 'TimelineYear' && target.classList.contains(OTHERMONTH_CLASS)) {
2068
2077
  return;
2069
2078
  }
@@ -2072,7 +2081,6 @@ class KeyboardInteraction {
2072
2081
  if (this.parent.eventWindow) {
2073
2082
  this.parent.eventWindow.convertToEventData(this.parent.activeCellsData, cellData);
2074
2083
  }
2075
- const selectedCells = this.parent.getSelectedCells();
2076
2084
  const args = {
2077
2085
  data: cellData, element: this.parent.activeCellsData.element, event: e,
2078
2086
  requestType: cellSelect, showQuickPopup: false
@@ -3039,15 +3047,35 @@ class Data {
3039
3047
  */
3040
3048
  generateQuery(startDate, endDate) {
3041
3049
  const query = this.query.clone();
3042
- if (this.parent && this.parent.eventSettings.includeFiltersInQuery && startDate && endDate) {
3043
- const dateQuery = this.getStartEndQuery(startDate, endDate);
3044
- const recurrenceQuery = new Predicate(this.parent.eventFields.recurrenceRule, 'notequal', null).and(new Predicate(this.parent.eventFields.recurrenceRule, 'notequal', ''));
3045
- return query.where(dateQuery.or(recurrenceQuery));
3046
- }
3047
- if (startDate) {
3050
+ if (this.parent && startDate && endDate) {
3051
+ if (this.parent.activeViewOptions && this.parent.activeViewOptions.enableLazyLoading &&
3052
+ !isNullOrUndefined(this.parent.activeViewOptions.group.resources) &&
3053
+ this.parent.activeViewOptions.group.resources.length > 0 && this.parent.resourceBase &&
3054
+ this.parent.resourceBase.resourceCollection.length > 0 && this.parent.resourceBase.renderedResources.length > 0) {
3055
+ const resIdCollection = [];
3056
+ this.parent.resourceBase.resourceCollection.forEach(() => resIdCollection.push([]));
3057
+ this.parent.resourceBase.renderedResources.forEach((resource) => {
3058
+ resIdCollection.forEach((resId, index) => {
3059
+ const groupId = resource.groupOrder[parseInt(index.toString(), 10)];
3060
+ if (groupId && resId.indexOf(groupId) < 0) {
3061
+ resId.push(groupId);
3062
+ }
3063
+ });
3064
+ });
3065
+ this.parent.resourceBase.resourceCollection.forEach((resource, index) => {
3066
+ query.addParams(resource.field, resIdCollection[parseInt(index.toString(), 10)].toString());
3067
+ });
3068
+ }
3069
+ if (this.parent.timezone) {
3070
+ startDate = this.parent.tzModule.remove(new Date(+startDate.getTime()), this.parent.timezone);
3071
+ endDate = this.parent.tzModule.remove(new Date(+endDate.getTime()), this.parent.timezone);
3072
+ }
3073
+ if (this.parent.eventSettings.includeFiltersInQuery) {
3074
+ const dateQuery = this.getStartEndQuery(startDate, endDate);
3075
+ const recurrenceQuery = new Predicate(this.parent.eventFields.recurrenceRule, 'notequal', null).and(new Predicate(this.parent.eventFields.recurrenceRule, 'notequal', ''));
3076
+ return query.where(dateQuery.or(recurrenceQuery));
3077
+ }
3048
3078
  query.addParams('StartDate', startDate.toISOString());
3049
- }
3050
- if (endDate) {
3051
3079
  query.addParams('EndDate', endDate.toISOString());
3052
3080
  }
3053
3081
  return query;
@@ -3714,11 +3742,10 @@ function getMonthSummary(ruleObject, cldrObj, localeObj) {
3714
3742
  * @param {number} maximumCount Accepts the maximum number count to generate date collections
3715
3743
  * @param {Date} viewDate Accepts the current date instead of start date
3716
3744
  * @param {CalendarType} calendarMode Accepts the calendar type
3717
- * @param {string} oldTimezone Accepts the timezone name
3718
3745
  * @param {string} newTimezone Accepts the timezone name
3719
3746
  * @returns {number[]} Returns the collection of dates
3720
3747
  */
3721
- function generate(startDate, rule, excludeDate, startDayOfWeek, maximumCount = MAXOCCURRENCE, viewDate = null, calendarMode = 'Gregorian', oldTimezone = null, newTimezone = null) {
3748
+ function generate(startDate, rule, excludeDate, startDayOfWeek, maximumCount = MAXOCCURRENCE, viewDate = null, calendarMode = 'Gregorian', newTimezone = null) {
3722
3749
  const ruleObject = extractObjectFromRule(rule);
3723
3750
  let cacheDate;
3724
3751
  calendarUtil = getCalendarUtil(calendarMode);
@@ -3729,8 +3756,8 @@ function generate(startDate, rule, excludeDate, startDayOfWeek, maximumCount = M
3729
3756
  const tz = new Timezone();
3730
3757
  tempDate.forEach((content) => {
3731
3758
  let parsedDate = getDateFromRecurrenceDateString(content);
3732
- if (oldTimezone && newTimezone) {
3733
- parsedDate = tz.convert(new Date(parsedDate.getTime()), oldTimezone, newTimezone);
3759
+ if (newTimezone) {
3760
+ parsedDate = tz.add(new Date(parsedDate.getTime()), newTimezone);
3734
3761
  }
3735
3762
  tempExcludeDate.push(new Date(parsedDate.getTime()).setHours(0, 0, 0, 0));
3736
3763
  });
@@ -5287,12 +5314,12 @@ class EventBase {
5287
5314
  }
5288
5315
  if (!isNullOrUndefined(event[fields.recurrenceRule]) && isNullOrUndefined(event[fields.recurrenceID]) &&
5289
5316
  !(this.parent.crudModule && this.parent.crudModule.crudObj.isCrudAction)) {
5290
- processed = processed.concat(this.generateOccurrence(event, null, oldTimezone, true));
5317
+ processed = processed.concat(this.generateOccurrence(event, null, true));
5291
5318
  }
5292
5319
  else {
5293
5320
  if (this.parent.crudModule && this.parent.crudModule.crudObj.isCrudAction) {
5294
5321
  if (!isNullOrUndefined(event[fields.recurrenceRule]) && isNullOrUndefined(event[fields.recurrenceID])) {
5295
- const recurrenceEvent = this.generateOccurrence(event, null, oldTimezone, true);
5322
+ const recurrenceEvent = this.generateOccurrence(event, null, true);
5296
5323
  for (const occurrence of recurrenceEvent) {
5297
5324
  const app = this.parent.eventsProcessed.filter((data) => data[fields.startTime].getTime() - occurrence[fields.startTime].getTime() === 0 &&
5298
5325
  data[fields.id] === occurrence[fields.id]);
@@ -6067,7 +6094,7 @@ class EventBase {
6067
6094
  }
6068
6095
  this.parent.activeEventData = { event: eventObject, element: target };
6069
6096
  }
6070
- generateOccurrence(event, viewDate, oldTimezone, isMaxCount) {
6097
+ generateOccurrence(event, viewDate, isMaxCount) {
6071
6098
  const startDate = event[this.parent.eventFields.startTime];
6072
6099
  const endDate = event[this.parent.eventFields.endTime];
6073
6100
  const eventRule = event[this.parent.eventFields.recurrenceRule];
@@ -6082,7 +6109,7 @@ class EventBase {
6082
6109
  const newTimezone = this.parent.timezone || this.parent.tzModule.getLocalTimezoneName();
6083
6110
  const firstDay = this.parent.activeViewOptions.firstDayOfWeek;
6084
6111
  const calendarMode = this.parent.calendarMode;
6085
- const dates = generate(startDate, eventRule, exception, firstDay, maxCount, viewDate, calendarMode, oldTimezone, newTimezone);
6112
+ const dates = generate(startDate, eventRule, exception, firstDay, maxCount, viewDate, calendarMode, newTimezone);
6086
6113
  if (this.parent.currentView === 'Agenda' && eventRule.indexOf('COUNT') === -1 && eventRule.indexOf('UNTIL') === -1) {
6087
6114
  if (isNullOrUndefined(event.generatedDates)) {
6088
6115
  event.generatedDates = { start: new Date(dates[0]), end: new Date(dates[dates.length - 1]) };
@@ -9163,6 +9190,9 @@ class QuickPopups {
9163
9190
  'aria-label': this.parent.getAnnouncementString(eventData)
9164
9191
  }
9165
9192
  });
9193
+ if (eventData[fields.isReadonly]) {
9194
+ addClass([appointmentElement], 'e-read-only');
9195
+ }
9166
9196
  let templateElement;
9167
9197
  if (!isNullOrUndefined(this.parent.activeViewOptions.eventTemplate)) {
9168
9198
  const tempId = this.parent.element.id + '_' + this.parent.activeViewOptions.eventTemplateName + 'eventTemplate';
@@ -10254,7 +10284,7 @@ class EventTooltip {
10254
10284
  cssClass: this.parent.cssClass + ' ' + EVENT_TOOLTIP_ROOT_CLASS,
10255
10285
  target: this.getTargets(),
10256
10286
  beforeRender: this.onBeforeRender.bind(this),
10257
- afterClose: this.onTooltipClose.bind(this),
10287
+ beforeClose: this.onTooltipClose.bind(this),
10258
10288
  enableRtl: this.parent.enableRtl,
10259
10289
  enableHtmlSanitizer: this.parent.enableHtmlSanitizer
10260
10290
  });
@@ -10362,7 +10392,11 @@ class EventTooltip {
10362
10392
  }
10363
10393
  this.parent.renderTemplates();
10364
10394
  }
10365
- onTooltipClose() {
10395
+ onTooltipClose(args) {
10396
+ if (args.element) {
10397
+ removeClass([args.element], POPUP_OPEN);
10398
+ addClass([args.element], POPUP_CLOSE);
10399
+ }
10366
10400
  this.parent.resetTemplates(['tooltipTemplate', 'headerTooltipTemplate']);
10367
10401
  }
10368
10402
  setContent(content) {
@@ -11534,40 +11568,54 @@ class EventWindow {
11534
11568
  };
11535
11569
  if (this.parent.isAdaptive) {
11536
11570
  dialogModel.cssClass = EVENT_WINDOW_DIALOG_CLASS + ' ' + DEVICE_CLASS;
11537
- dialogModel.header = '<div class="e-title-header"><div class="e-back-icon e-icons"></div><div class="e-title-text">' +
11538
- this.l10n.getConstant('newEvent') + '</div><div class="e-save-icon e-icons"></div></div>';
11571
+ if (!this.parent.editorHeaderTemplate) {
11572
+ dialogModel.header = '<div class="e-title-header"><div class="e-back-icon e-icons"></div><div class="e-title-text">' +
11573
+ this.l10n.getConstant('newEvent') + '</div><div class="e-save-icon e-icons"></div></div>';
11574
+ }
11539
11575
  }
11540
11576
  else {
11541
- dialogModel.buttons = [{
11542
- buttonModel: {
11543
- content: this.l10n.getConstant('deleteButton'), cssClass: DELETE_EVENT_CLASS,
11544
- disabled: !this.parent.eventSettings.allowDeleting || this.parent.readonly
11545
- },
11546
- click: this.eventDelete.bind(this)
11547
- }, {
11548
- buttonModel: {
11549
- content: this.l10n.getConstant('saveButton'), cssClass: 'e-primary ' + EVENT_WINDOW_SAVE_BUTTON_CLASS,
11550
- isPrimary: true, disabled: !this.parent.eventSettings.allowAdding || this.parent.readonly
11551
- },
11552
- click: this.eventSave.bind(this)
11553
- }, {
11554
- buttonModel: { cssClass: EVENT_WINDOW_CANCEL_BUTTON_CLASS, content: this.l10n.getConstant('cancelButton') },
11555
- click: this.dialogClose.bind(this)
11556
- }];
11557
- dialogModel.header = '<div class="e-title-text">' + this.l10n.getConstant('newEvent') + '</div>';
11577
+ if (!this.parent.editorFooterTemplate) {
11578
+ this.renderDialogButtons(dialogModel);
11579
+ }
11580
+ if (!this.parent.editorHeaderTemplate) {
11581
+ dialogModel.header = '<div class="e-title-text">' + this.l10n.getConstant('newEvent') + '</div>';
11582
+ }
11558
11583
  }
11559
11584
  this.dialogObject = new Dialog(dialogModel, this.element);
11560
11585
  if (this.dialogObject.element.querySelector('.e-dlg-closeicon-btn')) {
11561
11586
  this.dialogObject.element.querySelector('.e-dlg-closeicon-btn').setAttribute('title', this.l10n.getConstant('close'));
11562
11587
  }
11588
+ this.addEventHandlers();
11563
11589
  addClass([this.element.parentElement], EVENT_WINDOW_DIALOG_CLASS + '-container');
11564
- if (this.parent.isAdaptive) {
11565
- EventHandler.add(this.element.querySelector('.' + EVENT_WINDOW_BACK_ICON_CLASS), 'click', this.dialogClose, this);
11566
- EventHandler.add(this.element.querySelector('.' + EVENT_WINDOW_SAVE_ICON_CLASS), 'click', this.eventSave, this);
11567
- }
11568
11590
  EventHandler.add(this.dialogObject.element, 'keydown', this.preventEventSave, this);
11569
11591
  this.applyFormValidation();
11570
11592
  }
11593
+ renderDialogButtons(dialogButton) {
11594
+ dialogButton.buttons = [{
11595
+ buttonModel: {
11596
+ content: this.l10n.getConstant('deleteButton'), cssClass: DELETE_EVENT_CLASS,
11597
+ disabled: !this.parent.eventSettings.allowDeleting || this.parent.readonly
11598
+ },
11599
+ click: this.eventDelete.bind(this)
11600
+ }, {
11601
+ buttonModel: {
11602
+ content: this.l10n.getConstant('saveButton'), cssClass: 'e-primary ' + EVENT_WINDOW_SAVE_BUTTON_CLASS,
11603
+ isPrimary: true, disabled: !this.parent.eventSettings.allowAdding || this.parent.readonly
11604
+ },
11605
+ click: this.eventSave.bind(this)
11606
+ }, {
11607
+ buttonModel: { cssClass: EVENT_WINDOW_CANCEL_BUTTON_CLASS, content: this.l10n.getConstant('cancelButton') },
11608
+ click: this.dialogClose.bind(this)
11609
+ }];
11610
+ }
11611
+ addEventHandlers() {
11612
+ const backIcon = this.element.querySelector('.' + EVENT_WINDOW_BACK_ICON_CLASS);
11613
+ const saveIcon = this.element.querySelector('.' + EVENT_WINDOW_SAVE_ICON_CLASS);
11614
+ if (this.parent.isAdaptive && !isNullOrUndefined(backIcon) && !isNullOrUndefined(saveIcon)) {
11615
+ EventHandler.add(backIcon, 'click', this.dialogClose, this);
11616
+ EventHandler.add(saveIcon, 'click', this.eventSave, this);
11617
+ }
11618
+ }
11571
11619
  refresh() {
11572
11620
  this.destroy(true);
11573
11621
  this.renderEventWindow();
@@ -11611,6 +11659,23 @@ class EventWindow {
11611
11659
  }
11612
11660
  data = eventObj;
11613
11661
  }
11662
+ if (!isNullOrUndefined(this.parent.editorHeaderTemplate)) {
11663
+ this.parent.resetTemplates(['editorHeaderTemplate']);
11664
+ if (this.parent.isAdaptive && !this.parent.editorFooterTemplate) {
11665
+ this.dialogObject.header = this.createAdaptiveHeaderElement(data);
11666
+ }
11667
+ else {
11668
+ this.dialogObject.header = this.getDialogHeader(data);
11669
+ }
11670
+ }
11671
+ if (!isNullOrUndefined(this.parent.editorFooterTemplate)) {
11672
+ this.parent.resetTemplates(['editorFooterTemplate']);
11673
+ this.dialogObject.footerTemplate = this.getDialogFooter(data);
11674
+ }
11675
+ if (!isNullOrUndefined(this.parent.editorHeaderTemplate) || !isNullOrUndefined(this.parent.editorFooterTemplate)) {
11676
+ this.dialogObject.dataBind();
11677
+ this.addEventHandlers();
11678
+ }
11614
11679
  if (!isNullOrUndefined(this.parent.editorTemplate)) {
11615
11680
  this.renderFormElements(this.element.querySelector('.e-schedule-form'), data);
11616
11681
  }
@@ -11641,6 +11706,65 @@ class EventWindow {
11641
11706
  this.dialogObject.dataBind();
11642
11707
  this.applyFormValidation();
11643
11708
  }
11709
+ setDialogHeader() {
11710
+ if (!isNullOrUndefined(this.parent.editorHeaderTemplate)) {
11711
+ this.parent.resetTemplates(['editorHeaderTemplate']);
11712
+ if (this.parent.isAdaptive && !this.parent.editorFooterTemplate) {
11713
+ this.dialogObject.header = this.createAdaptiveHeaderElement();
11714
+ }
11715
+ else {
11716
+ this.dialogObject.header = this.getDialogHeader();
11717
+ }
11718
+ }
11719
+ else if (this.parent.isAdaptive) {
11720
+ this.dialogObject.header = '<div class="e-title-header"><div class="e-back-icon e-icons"></div><div class="e-title-text">' +
11721
+ this.l10n.getConstant('newEvent') + '</div><div class="e-save-icon e-icons"></div></div>';
11722
+ }
11723
+ else {
11724
+ this.dialogObject.header = '<div class="e-title-text">' + this.l10n.getConstant('newEvent') + '</div>';
11725
+ }
11726
+ this.dialogObject.dataBind();
11727
+ this.addEventHandlers();
11728
+ }
11729
+ setDialogFooter() {
11730
+ if (!isNullOrUndefined(this.parent.editorFooterTemplate)) {
11731
+ this.parent.resetTemplates(['editorFooterTemplate']);
11732
+ this.dialogObject.footerTemplate = this.getDialogFooter();
11733
+ }
11734
+ else if (!this.parent.isAdaptive && isNullOrUndefined(this.parent.editorFooterTemplate)) {
11735
+ this.renderDialogButtons(this.dialogObject);
11736
+ }
11737
+ else if (this.parent.isAdaptive && isNullOrUndefined(this.parent.editorFooterTemplate)) {
11738
+ this.dialogObject.footerTemplate = null;
11739
+ }
11740
+ this.dialogObject.dataBind();
11741
+ }
11742
+ createAdaptiveHeaderElement(data) {
11743
+ const header = createElement('div', { className: 'e-title-header' });
11744
+ const headerBackIcon = createElement('div', { className: 'e-back-icon e-icons' });
11745
+ header.appendChild(headerBackIcon);
11746
+ const headerTemplate = this.getDialogHeader(data);
11747
+ header.appendChild(headerTemplate);
11748
+ const headerSaveIcon = createElement('div', { className: 'e-save-icon e-icons' });
11749
+ header.appendChild(headerSaveIcon);
11750
+ return header;
11751
+ }
11752
+ getDialogHeader(args) {
11753
+ let headerTemplate = [];
11754
+ const headerTemplateId = this.parent.element.id + '_editorHeaderTemplate';
11755
+ const temHeaderDiv = document.createElement('div');
11756
+ headerTemplate = [].slice.call(this.parent.getEditorHeaderTemplate()(args || {}, this.parent, 'editorHeaderTemplate', headerTemplateId, false));
11757
+ append(headerTemplate, temHeaderDiv);
11758
+ return temHeaderDiv;
11759
+ }
11760
+ getDialogFooter(args) {
11761
+ let footerTemplate = [];
11762
+ const footerTemplateId = this.parent.element.id + '_editorFooterTemplate';
11763
+ const temFooterDiv = document.createElement('div');
11764
+ footerTemplate = [].slice.call(this.parent.getEditorFooterTemplate()(args || {}, this.parent, 'editorFooterTemplate', footerTemplateId, false));
11765
+ append(footerTemplate, temFooterDiv);
11766
+ return temFooterDiv;
11767
+ }
11644
11768
  preventEventSave(e) {
11645
11769
  if (this.parent && !this.parent.allowKeyboardInteraction && e.code === 'Enter') {
11646
11770
  this.isEnterKey = true;
@@ -11908,9 +12032,9 @@ class EventWindow {
11908
12032
  const resourceDiv = this.createDivElement(value + '-container' + ' ' + 'e-resources');
11909
12033
  const resourceInput = this.createInputElement(value + ' ' + EVENT_FIELD$1, fieldName);
11910
12034
  resourceDiv.appendChild(resourceInput);
11911
- function resourceTemplate(data) {
12035
+ const resourceTemplate = function (data) {
11912
12036
  return `<div class="e-resource-template"><div class="e-resource-color" style="background-color:${data[resourceData.colorField]}"></div><div class="e-resource-text">${data[resourceData.textField]}</div></div>`;
11913
- }
12037
+ };
11914
12038
  initializeCSPTemplate(resourceTemplate, resourceData);
11915
12039
  if (resourceData.allowMultiple) {
11916
12040
  const listObj = new MultiSelect({
@@ -12254,7 +12378,9 @@ class EventWindow {
12254
12378
  this.renderRepeatDialog();
12255
12379
  }
12256
12380
  this.element.querySelector('.' + FORM_CLASS).removeAttribute('data-id');
12257
- this.element.querySelector('.' + EVENT_WINDOW_TITLE_TEXT_CLASS).innerHTML = this.l10n.getConstant('newEvent');
12381
+ if (isNullOrUndefined(this.parent.editorHeaderTemplate)) {
12382
+ this.element.querySelector('.' + EVENT_WINDOW_TITLE_TEXT_CLASS).innerHTML = this.l10n.getConstant('newEvent');
12383
+ }
12258
12384
  eventObj.Timezone = false;
12259
12385
  this.repeatStartDate = eventObj[this.fields.startTime];
12260
12386
  this.repeatRule = '';
@@ -12491,10 +12617,12 @@ class EventWindow {
12491
12617
  if (!this.parent.eventSettings.allowEditing) {
12492
12618
  return;
12493
12619
  }
12494
- if (!this.parent.isAdaptive) {
12620
+ if (!this.parent.isAdaptive && isNullOrUndefined(this.parent.editorFooterTemplate)) {
12495
12621
  removeClass([this.element.querySelector('.' + DELETE_EVENT_CLASS)], DISABLE_CLASS);
12496
12622
  }
12497
- this.element.querySelector('.' + EVENT_WINDOW_TITLE_TEXT_CLASS).innerHTML = this.l10n.getConstant('editEvent');
12623
+ if (isNullOrUndefined(this.parent.editorHeaderTemplate)) {
12624
+ this.element.querySelector('.' + EVENT_WINDOW_TITLE_TEXT_CLASS).innerHTML = this.l10n.getConstant('editEvent');
12625
+ }
12498
12626
  this.element.querySelector('.' + FORM_CLASS).setAttribute('data-id', eventObj[this.fields.id].toString());
12499
12627
  if (isNullOrUndefined(this.parent.editorTemplate)) {
12500
12628
  eventObj = extend({}, eventObj, null, true);
@@ -13296,7 +13424,7 @@ class EventWindow {
13296
13424
  }
13297
13425
  destroy(isIgnore) {
13298
13426
  if (this.parent && !this.parent.isDestroyed) {
13299
- this.parent.resetTemplates(['editorTemplate']);
13427
+ this.parent.resetTemplates(['editorTemplate', 'editorHeaderTemplate', 'editorFooterTemplate']);
13300
13428
  }
13301
13429
  this.destroyComponents();
13302
13430
  if (this.recurrenceEditor) {
@@ -13339,6 +13467,7 @@ class EventWindow {
13339
13467
  }
13340
13468
  }
13341
13469
 
13470
+ /* eslint-disable @typescript-eslint/no-explicit-any */
13342
13471
  /**
13343
13472
  * Virtual Scroll
13344
13473
  */
@@ -13426,6 +13555,16 @@ class VirtualScroll {
13426
13555
  }
13427
13556
  renderEvents() {
13428
13557
  this.setTabIndex();
13558
+ const dynamicData = this.triggerScrollEvent(virtualScrollStop);
13559
+ if (this.parent.activeViewOptions && this.parent.activeViewOptions.enableLazyLoading && this.parent.crudModule) {
13560
+ if (dynamicData.length > 0) {
13561
+ this.parent.crudModule.refreshProcessedData(true, dynamicData);
13562
+ this.parent.hideSpinner();
13563
+ return;
13564
+ }
13565
+ this.parent.crudModule.refreshDataManager();
13566
+ return;
13567
+ }
13429
13568
  if (this.parent.crudModule) {
13430
13569
  this.parent.crudModule.refreshProcessedData(true);
13431
13570
  }
@@ -13461,7 +13600,7 @@ class VirtualScroll {
13461
13600
  resCollection = this.downScroll(conWrap, firstTDIndex);
13462
13601
  }
13463
13602
  if (!isNullOrUndefined(resCollection) && resCollection.length > 0) {
13464
- this.parent.showSpinner();
13603
+ this.triggerScrollEvent(virtualScrollStart);
13465
13604
  const selectedEle = this.parent.getSelectedCells();
13466
13605
  this.focusedEle = selectedEle[selectedEle.length - 1] || this.focusedEle;
13467
13606
  this.updateContent(resWrap, conWrap, eventWrap, resCollection);
@@ -13488,7 +13627,7 @@ class VirtualScroll {
13488
13627
  this.parent.resourceBase.expandedResources[0] !== resCollection[0] ||
13489
13628
  this.parent.resourceBase.expandedResources[this.parent.resourceBase.expandedResources.length - 1] !==
13490
13629
  resCollection[resCollection.length - 1]) {
13491
- this.parent.showSpinner();
13630
+ this.triggerScrollEvent(virtualScrollStart);
13492
13631
  const colLevels = this.parent.activeView.colLevels.slice(0);
13493
13632
  this.updateHorizontalContent(conWrap, resCollection);
13494
13633
  setStyleAttribute(conWrap.querySelector('table'), { transform: `translateX(${this.translateY}px)` });
@@ -13501,6 +13640,29 @@ class VirtualScroll {
13501
13640
  this.timeValue = window.setTimeout(() => { this.renderEvents(); }, 250);
13502
13641
  }
13503
13642
  }
13643
+ triggerScrollEvent(action) {
13644
+ let dynamicData = [];
13645
+ if (!this.parent.activeView) {
13646
+ return dynamicData;
13647
+ }
13648
+ const eventArgs = {
13649
+ startDate: this.parent.activeView.startDate(),
13650
+ endDate: this.parent.activeView.endDate(),
13651
+ startIndex: this.parent.resourceBase.renderedResources[0].groupIndex,
13652
+ endIndex: this.parent.resourceBase.renderedResources[this.parent.resourceBase.renderedResources.length - 1].groupIndex,
13653
+ resourceData: this.parent.resourceBase.renderedResources.map((x) => x.resourceData),
13654
+ name: action
13655
+ };
13656
+ this.parent.trigger(action, eventArgs, (args) => {
13657
+ if (action === virtualScrollStart) {
13658
+ this.parent.showSpinner();
13659
+ }
13660
+ else if (action === virtualScrollStop && !isNullOrUndefined(args.eventData) && args.eventData.length > 0) {
13661
+ dynamicData = args.eventData;
13662
+ }
13663
+ });
13664
+ return dynamicData;
13665
+ }
13504
13666
  upScroll(conWrap, firstTDIndex) {
13505
13667
  let index = 0;
13506
13668
  index = (~~(conWrap.scrollTop / this.itemSize) + Math.ceil(conWrap.clientHeight / this.itemSize)) - this.renderedLength;
@@ -14015,7 +14177,7 @@ class Crud {
14015
14177
  }
14016
14178
  this.parent.trigger(actionFailure, { error: e }, () => this.parent.hideSpinner());
14017
14179
  }
14018
- refreshProcessedData(isVirtualScrollAction = false) {
14180
+ refreshProcessedData(isVirtualScrollAction = false, dynamicEvents) {
14019
14181
  if (this.parent.dragAndDropModule) {
14020
14182
  this.parent.dragAndDropModule.actionObj.action = '';
14021
14183
  removeClass([this.parent.element], 'e-event-action');
@@ -14038,7 +14200,7 @@ class Crud {
14038
14200
  }
14039
14201
  }
14040
14202
  if (isVirtualScrollAction) {
14041
- this.parent.notify(dataReady, { processedData: this.parent.eventsProcessed });
14203
+ this.parent.notify(dataReady, { processedData: dynamicEvents ? this.parent.eventBase.processData(dynamicEvents) : this.parent.eventsProcessed });
14042
14204
  return;
14043
14205
  }
14044
14206
  const eventsData = this.parent.eventsData || [];
@@ -14194,6 +14356,8 @@ class Crud {
14194
14356
  editParams.changedRecords.push(event);
14195
14357
  promise = this.parent.dataModule.dataManager.update(fields.id, event, this.getTable(), this.getQuery());
14196
14358
  }
14359
+ const cloneEvent = extend({}, saveArgs.changedRecords[saveArgs.changedRecords.length - 1], null, true);
14360
+ this.parent.eventBase.selectWorkCellByTime([this.parent.eventBase.processTimezone(cloneEvent)]);
14197
14361
  const crudArgs = {
14198
14362
  requestType: 'eventChanged', cancel: false,
14199
14363
  data: saveArgs.changedRecords, promise: promise, editParams: editParams
@@ -14275,7 +14439,8 @@ class Crud {
14275
14439
  }
14276
14440
  const updateEvents = (eventData instanceof Array) ? eventData : [eventData];
14277
14441
  const args = {
14278
- requestType: action === 'EditOccurrence' ? 'eventChange' : 'eventRemove', cancel: false,
14442
+ requestType: action === 'EditOccurrence' ? 'eventChange' : 'eventRemove',
14443
+ cancel: false,
14279
14444
  addedRecords: [], changedRecords: updateEvents, deletedRecords: []
14280
14445
  };
14281
14446
  args.data = occurrenceData;
@@ -14320,7 +14485,8 @@ class Crud {
14320
14485
  }
14321
14486
  }
14322
14487
  const promise = this.parent.dataModule.dataManager.saveChanges(editParams, fields.id, this.getTable(), this.getQuery());
14323
- this.parent.eventBase.selectWorkCellByTime(occurrenceArgs.changedRecords);
14488
+ const cloneEvent = extend({}, occurrenceArgs.changedRecords[occurrenceArgs.changedRecords.length - 1], null, true);
14489
+ this.parent.eventBase.selectWorkCellByTime(action === 'EditOccurrence' ? [this.parent.eventBase.processTimezone(cloneEvent)] : [cloneEvent]);
14324
14490
  const crudArgs = {
14325
14491
  requestType: action === 'EditOccurrence' ? 'eventChanged' : 'eventRemoved',
14326
14492
  cancel: false, data: isDeletedRecords ? occurrenceArgs.deletedRecords : occurrenceArgs.changedRecords,
@@ -14390,7 +14556,8 @@ class Crud {
14390
14556
  }
14391
14557
  }
14392
14558
  const promise = this.parent.dataModule.dataManager.saveChanges(editParams, fields.id, this.getTable(), this.getQuery());
14393
- this.parent.eventBase.selectWorkCellByTime(followArgs.changedRecords);
14559
+ const cloneEvent = extend({}, followArgs.changedRecords[followArgs.changedRecords.length - 1], null, true);
14560
+ this.parent.eventBase.selectWorkCellByTime(action === 'EditFollowingEvents' ? [this.parent.eventBase.processTimezone(cloneEvent)] : [cloneEvent]);
14394
14561
  const crudArgs = {
14395
14562
  requestType: action === 'EditFollowingEvents' ? 'eventChanged' : 'eventRemoved',
14396
14563
  cancel: false, data: followArgs.changedRecords, promise: promise, editParams: editParams
@@ -14451,7 +14618,8 @@ class Crud {
14451
14618
  }
14452
14619
  }
14453
14620
  const promise = this.parent.dataModule.dataManager.saveChanges(editParams, fields.id, this.getTable(), this.getQuery());
14454
- this.parent.eventBase.selectWorkCellByTime(seriesArgs.changedRecords);
14621
+ const cloneEvent = extend({}, seriesArgs.changedRecords[seriesArgs.changedRecords.length - 1], null, true);
14622
+ this.parent.eventBase.selectWorkCellByTime(action === 'EditSeries' ? [this.parent.eventBase.processTimezone(cloneEvent)] : [cloneEvent]);
14455
14623
  const crudArgs = {
14456
14624
  requestType: action === 'EditSeries' ? 'eventChanged' : 'eventRemoved',
14457
14625
  cancel: false, data: isDeletedRecords ? seriesArgs.deletedRecords : seriesArgs.changedRecords,
@@ -14505,6 +14673,7 @@ class Crud {
14505
14673
  }
14506
14674
  }
14507
14675
  const promise = this.parent.dataModule.dataManager.saveChanges(editParams, fields.id, this.getTable(), this.getQuery());
14676
+ this.parent.eventBase.selectWorkCellByTime(deleteArgs.deletedRecords);
14508
14677
  const crudArgs = {
14509
14678
  requestType: 'eventRemoved', cancel: false, data: deleteArgs.deletedRecords, promise: promise, editParams: editParams
14510
14679
  };
@@ -14545,6 +14714,8 @@ class Crud {
14545
14714
  }
14546
14715
  }
14547
14716
  const promise = this.parent.dataModule.dataManager.saveChanges(editParams, fields.id, this.getTable(), this.getQuery());
14717
+ const cloneEvent = extend({}, editArgs.changedRecords[editArgs.changedRecords.length - 1], null, true);
14718
+ this.parent.eventBase.selectWorkCellByTime([this.parent.eventBase.processTimezone(cloneEvent)]);
14548
14719
  const crudArgs = { requestType: 'eventChanged', cancel: false, data: editArgs.changedRecords, promise: promise, editParams: editParams };
14549
14720
  this.refreshData(crudArgs);
14550
14721
  }
@@ -14558,6 +14729,10 @@ class Crud {
14558
14729
  return parentEvent;
14559
14730
  }
14560
14731
  excludeDateCheck(eventStartTime, exceptionDateList) {
14732
+ const timezone = this.parent.timezone || this.parent.tzModule.getLocalTimezoneName();
14733
+ if (timezone) {
14734
+ eventStartTime = this.parent.tzModule.remove(new Date(+eventStartTime.getTime()), timezone);
14735
+ }
14561
14736
  const exDate = getRecurrenceStringFromDate(eventStartTime);
14562
14737
  if (!isNullOrUndefined(exceptionDateList)) {
14563
14738
  if (exceptionDateList.indexOf(exDate) === -1) {
@@ -15335,6 +15510,7 @@ class ResourceBase {
15335
15510
  nodeClicked: this.resourceClick.bind(this),
15336
15511
  created: this.resourceTreeCreated.bind(this)
15337
15512
  });
15513
+ this.treeViewObj.root = this.parent.root ? this.parent.root : this.parent;
15338
15514
  this.treeViewObj.appendTo(resourceTree);
15339
15515
  this.treeViewObj.expandAll();
15340
15516
  this.treePopup = new Popup(treeWrapper, {
@@ -16179,6 +16355,13 @@ let Schedule = class Schedule extends Component {
16179
16355
  this.renderElements(isSetModel);
16180
16356
  }
16181
16357
  }
16358
+ destroyEditorWindow() {
16359
+ if (this.eventWindow) {
16360
+ this.eventWindow.destroy();
16361
+ this.eventWindow = null;
16362
+ }
16363
+ this.eventWindow = new EventWindow(this);
16364
+ }
16182
16365
  /**
16183
16366
  * Method to render the layout elements
16184
16367
  *
@@ -16345,7 +16528,8 @@ let Schedule = class Schedule extends Component {
16345
16528
  headerRows: this.headerRows,
16346
16529
  orientation: 'Horizontal',
16347
16530
  numberOfWeeks: 0,
16348
- displayDate: null
16531
+ displayDate: null,
16532
+ enableLazyLoading: false
16349
16533
  };
16350
16534
  const viewOptions = this.viewCollections[this.viewIndex];
16351
16535
  const viewsData = extend(scheduleOptions, viewOptions, undefined, true);
@@ -16356,6 +16540,11 @@ let Schedule = class Schedule extends Component {
16356
16540
  viewsData.displayDate = viewsData.displayDate instanceof Date ? new Date(viewsData.displayDate.getTime()) :
16357
16541
  new Date(viewsData.displayDate);
16358
16542
  }
16543
+ if (viewsData.enableLazyLoading && !isNullOrUndefined(viewsData.group.resources) && viewsData.group.resources.length > 0 &&
16544
+ (['Agenda', 'MonthAgenda', 'Year', 'TimelineYear'].indexOf(viewsData.option) === -1 ||
16545
+ (viewsData.option === 'TimelineYear' && viewsData.orientation === 'Vertical'))) {
16546
+ viewsData.allowVirtualScrolling = true;
16547
+ }
16359
16548
  return viewsData;
16360
16549
  }
16361
16550
  initializeDataModule() {
@@ -16417,6 +16606,8 @@ let Schedule = class Schedule extends Component {
16417
16606
  this.headerTooltipTemplateFn = this.templateParser(this.activeViewOptions.group.headerTooltipTemplate);
16418
16607
  this.eventTooltipTemplateFn = this.templateParser(this.eventSettings.tooltipTemplate);
16419
16608
  this.editorTemplateFn = this.templateParser(this.editorTemplate);
16609
+ this.editorHeaderTemplateFn = this.templateParser(this.editorHeaderTemplate);
16610
+ this.editorFooterTemplateFn = this.templateParser(this.editorFooterTemplate);
16420
16611
  this.quickInfoTemplatesHeaderFn = this.templateParser(this.quickInfoTemplates.header);
16421
16612
  this.quickInfoTemplatesContentFn = this.templateParser(this.quickInfoTemplates.content);
16422
16613
  this.quickInfoTemplatesFooterFn = this.templateParser(this.quickInfoTemplates.footer);
@@ -17050,6 +17241,24 @@ let Schedule = class Schedule extends Component {
17050
17241
  getEditorTemplate() {
17051
17242
  return this.editorTemplateFn;
17052
17243
  }
17244
+ /**
17245
+ * Method to process editor header template
17246
+ *
17247
+ * @returns {CallbackFunction} Returns the callback function
17248
+ * @private
17249
+ */
17250
+ getEditorHeaderTemplate() {
17251
+ return this.editorHeaderTemplateFn;
17252
+ }
17253
+ /**
17254
+ * Method to process editor footer template
17255
+ *
17256
+ * @returns {CallbackFunction} Returns the callback function
17257
+ * @private
17258
+ */
17259
+ getEditorFooterTemplate() {
17260
+ return this.editorFooterTemplateFn;
17261
+ }
17053
17262
  /**
17054
17263
  * Method to process quick info header template
17055
17264
  *
@@ -17566,6 +17775,22 @@ let Schedule = class Schedule extends Component {
17566
17775
  this.eventWindow.setDialogContent();
17567
17776
  }
17568
17777
  break;
17778
+ case 'editorHeaderTemplate':
17779
+ if (!isNullOrUndefined(this.editorHeaderTemplate)) {
17780
+ this.editorHeaderTemplateFn = this.templateParser(this.editorHeaderTemplate);
17781
+ }
17782
+ if (this.eventWindow) {
17783
+ this.eventWindow.setDialogHeader();
17784
+ }
17785
+ break;
17786
+ case 'editorFooterTemplate':
17787
+ if (!isNullOrUndefined(this.editorFooterTemplate)) {
17788
+ this.editorFooterTemplateFn = this.templateParser(this.editorFooterTemplate);
17789
+ }
17790
+ if (this.eventWindow) {
17791
+ this.eventWindow.setDialogFooter();
17792
+ }
17793
+ break;
17569
17794
  case 'quickInfoTemplates':
17570
17795
  if (this.quickInfoTemplates.header) {
17571
17796
  this.quickInfoTemplatesHeaderFn = this.templateParser(this.quickInfoTemplates.header);
@@ -18331,13 +18556,17 @@ let Schedule = class Schedule extends Component {
18331
18556
  this.quickInfoTemplatesFooterFn = this.templateParser(this.quickInfoTemplates.footer);
18332
18557
  break;
18333
18558
  case 'editorTemplate':
18334
- if (this.eventWindow) {
18335
- this.eventWindow.destroy();
18336
- this.eventWindow = null;
18337
- }
18338
- this.eventWindow = new EventWindow(this);
18559
+ this.destroyEditorWindow();
18339
18560
  this.editorTemplateFn = this.templateParser(this.editorTemplate);
18340
18561
  break;
18562
+ case 'editorHeaderTemplate':
18563
+ this.destroyEditorWindow();
18564
+ this.editorHeaderTemplateFn = this.templateParser(this.editorHeaderTemplate);
18565
+ break;
18566
+ case 'editorFooterTemplate':
18567
+ this.destroyEditorWindow();
18568
+ this.editorFooterTemplateFn = this.templateParser(this.editorFooterTemplate);
18569
+ break;
18341
18570
  case 'tooltipTemplate':
18342
18571
  case 'headerTooltipTemplate':
18343
18572
  if (this.eventTooltip) {
@@ -18811,6 +19040,12 @@ __decorate([
18811
19040
  __decorate([
18812
19041
  Property()
18813
19042
  ], Schedule.prototype, "editorTemplate", void 0);
19043
+ __decorate([
19044
+ Property()
19045
+ ], Schedule.prototype, "editorHeaderTemplate", void 0);
19046
+ __decorate([
19047
+ Property()
19048
+ ], Schedule.prototype, "editorFooterTemplate", void 0);
18814
19049
  __decorate([
18815
19050
  Complex({}, QuickInfoTemplates)
18816
19051
  ], Schedule.prototype, "quickInfoTemplates", void 0);
@@ -18922,6 +19157,12 @@ __decorate([
18922
19157
  __decorate([
18923
19158
  Event()
18924
19159
  ], Schedule.prototype, "resizeStop", void 0);
19160
+ __decorate([
19161
+ Event()
19162
+ ], Schedule.prototype, "virtualScrollStart", void 0);
19163
+ __decorate([
19164
+ Event()
19165
+ ], Schedule.prototype, "virtualScrollStop", void 0);
18925
19166
  __decorate([
18926
19167
  Event()
18927
19168
  ], Schedule.prototype, "dataBound", void 0);
@@ -25584,8 +25825,11 @@ class TimelineViews extends VerticalView {
25584
25825
  let diffInMinutes = ((date.getHours() - startHour.getHours()) * 60) + (date.getMinutes() - startHour.getMinutes());
25585
25826
  if (!isNullOrUndefined(currentDateIndex)) {
25586
25827
  if (currentDateIndex[0] !== 0) {
25587
- if (this.parent.activeView.colLevels[0] && this.parent.activeView.colLevels[0][0].colSpan) {
25588
- diffInDates = currentDateIndex[0] * this.parent.activeView.colLevels[0][0].colSpan * this.getWorkCellWidth();
25828
+ const index = this.parent.activeView.colLevels.findIndex((level) => level[0].type === 'dateHeader');
25829
+ if (this.parent.activeView.colLevels[parseInt(index.toString(), 10)] &&
25830
+ this.parent.activeView.colLevels[parseInt(index.toString(), 10)][0].colSpan) {
25831
+ diffInDates = currentDateIndex[0] * this.parent.activeView.colLevels[parseInt(index.toString(), 10)][0].colSpan *
25832
+ this.getWorkCellWidth();
25589
25833
  }
25590
25834
  else {
25591
25835
  const endHour = this.getEndHour();
@@ -26486,115 +26730,144 @@ class ICalendarImport {
26486
26730
  }
26487
26731
  }
26488
26732
  iCalendarParser(iCalString) {
26489
- const fields = this.parent.eventFields;
26490
- const events = [];
26491
- const uId = 'UID';
26492
- const calArray = iCalString.replace(new RegExp('\\r', 'g'), '').split('\n');
26493
- const descriptionIndex = calArray.findIndex((line) => line.startsWith('DESCRIPTION:'));
26494
- if (descriptionIndex !== -1) {
26495
- let description = calArray[descriptionIndex].substring('DESCRIPTION:'.length);
26496
- for (let i = descriptionIndex + 1; i < calArray.length; i++) {
26497
- if (calArray[i].startsWith(' ') || !(/[A-Z]{3}:/.test(calArray[i]))) {
26498
- description += calArray[i];
26499
- }
26500
- else {
26501
- calArray[descriptionIndex] = 'DESCRIPTION:' + description;
26502
- break;
26733
+ let iCalData = {
26734
+ isEvent: false,
26735
+ curEvent: null,
26736
+ id: this.parent.eventBase.getEventMaxID(),
26737
+ count: 0,
26738
+ events: [],
26739
+ key: null
26740
+ };
26741
+ const iStringLength = iCalString.length;
26742
+ let lastPosition = iCalString.search(/[^ \t]/);
26743
+ let position = lastPosition;
26744
+ let iString;
26745
+ let newlineOffset;
26746
+ do {
26747
+ position = iCalString.indexOf('\n', lastPosition) + 1;
26748
+ if (position === 0) {
26749
+ position = iStringLength;
26750
+ newlineOffset = 0;
26751
+ }
26752
+ else if (position > 1 && iCalString[position - 2] === '\r') {
26753
+ newlineOffset = 2;
26754
+ }
26755
+ else {
26756
+ newlineOffset = 1;
26757
+ }
26758
+ // eslint-disable-next-line security/detect-object-injection
26759
+ const firstChar = iCalString[lastPosition];
26760
+ if (firstChar === ' ' || firstChar === '\n' || firstChar === '\t') {
26761
+ iString += iCalString.slice(lastPosition + 1, position - newlineOffset);
26762
+ }
26763
+ else {
26764
+ if (iString) {
26765
+ iCalData = this.updateEventData(iString, iCalData);
26503
26766
  }
26767
+ iString = iCalString.slice(lastPosition, position - newlineOffset);
26504
26768
  }
26769
+ lastPosition = position;
26770
+ } while (position !== iStringLength);
26771
+ iString = iString.trim();
26772
+ if (iString.length) {
26773
+ iCalData = this.updateEventData(iString, iCalData);
26505
26774
  }
26506
- let isEvent = false;
26507
- let curEvent;
26508
- // eslint-disable-next-line prefer-const
26509
- let id = this.parent.eventBase.getEventMaxID();
26510
- let count = 0;
26511
- calArray.forEach((element) => {
26512
- let index;
26513
- let type;
26514
- let value;
26515
- if (!isEvent && element === 'BEGIN:VEVENT') {
26516
- isEvent = true;
26517
- curEvent = {};
26518
- }
26519
- if (isEvent && element === 'END:VEVENT') {
26520
- isEvent = false;
26521
- events.push(curEvent);
26522
- curEvent = null;
26523
- }
26524
- if (isEvent) {
26525
- index = element.indexOf(':');
26526
- type = element.substr(0, index).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
26527
- value = element.substr(index + 1, element.length - (index + 1)).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
26528
- if (element.indexOf('SUMMARY') !== -1) {
26529
- type = 'SUMMARY';
26530
- }
26531
- if (element.indexOf('DTSTART') !== -1) {
26532
- curEvent[fields.startTime] = this.dateParsing(element);
26533
- curEvent[fields.isAllDay] = this.allDay;
26534
- this.allDay = false;
26535
- }
26536
- else if (element.indexOf('DTEND') !== -1) {
26537
- curEvent[fields.endTime] = this.dateParsing(element);
26538
- }
26539
- else if (element.indexOf('EXDATE') !== -1) {
26540
- value = getRecurrenceStringFromDate(this.dateParsing(element));
26541
- curEvent[fields.recurrenceException] = (isNullOrUndefined(curEvent[fields.recurrenceException])) ?
26542
- value : curEvent[fields.recurrenceException] + ',' + value;
26543
- }
26544
- else if (element.indexOf('RECURRENCE-ID') !== -1) {
26545
- value = getRecurrenceStringFromDate(this.dateParsing(element));
26546
- curEvent[fields.recurrenceException] = value;
26547
- curEvent[fields.recurrenceID] = value;
26548
- }
26549
- else {
26550
- switch (type) {
26551
- case 'BEGIN':
26552
- break;
26553
- case 'UID':
26554
- curEvent[`${uId}`] = value;
26555
- if (typeof (id) == 'number') {
26556
- curEvent[fields.id] = parseInt(value, 10);
26557
- if (isNaN(curEvent[fields.id])) {
26558
- curEvent[fields.id] = id + count;
26559
- count++;
26560
- }
26561
- }
26562
- else {
26563
- curEvent[fields.id] = value;
26564
- }
26565
- break;
26566
- case 'SUMMARY':
26567
- curEvent[fields.subject] = value;
26568
- break;
26569
- case 'LOCATION':
26570
- curEvent[fields.location] = value;
26571
- break;
26572
- case 'DESCRIPTION':
26573
- if (!(curEvent[fields.description])) {
26574
- curEvent[fields.description] = value.replace(/\\,/g, ',')
26575
- .replace(/\\n/g, '\n');
26576
- }
26577
- break;
26578
- case 'ISREADONLY':
26579
- curEvent[fields.isReadonly] = (value.indexOf('true') > -1);
26580
- break;
26581
- case 'RRULE':
26582
- curEvent[fields.recurrenceRule] = value;
26583
- break;
26584
- default:
26585
- if (this.parent.resourceCollection.length > 0) {
26586
- const resData = this.parent.resourceCollection.filter((data) => data.field === type);
26587
- curEvent[`${type}`] = (resData.length > 0 && (typeof (resData[0].dataSource[0][resData[0].idField]) == 'number')) ? parseInt(value, 10) : value;
26588
- }
26589
- else {
26590
- curEvent[`${type}`] = value;
26775
+ const app = extend([], iCalData.events, null, true);
26776
+ this.parent.addEvent(this.processOccurrence(app, iCalData.id));
26777
+ }
26778
+ updateEventData(iString, iCalData) {
26779
+ const fields = this.parent.eventFields;
26780
+ const SEPARATOR = '\r\n';
26781
+ const id = iCalData.id;
26782
+ const events = iCalData.events;
26783
+ let isEvent = iCalData.isEvent;
26784
+ let count = iCalData.count;
26785
+ let curEvent = iCalData.curEvent;
26786
+ let key = iCalData.key;
26787
+ if (!isEvent && iString === 'BEGIN:VEVENT') {
26788
+ isEvent = true;
26789
+ curEvent = {};
26790
+ }
26791
+ if (isEvent && iString === 'END:VEVENT') {
26792
+ isEvent = false;
26793
+ events.push(curEvent);
26794
+ curEvent = null;
26795
+ }
26796
+ if (isEvent) {
26797
+ const index = iString.indexOf(':');
26798
+ let type = iString.substring(0, index).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
26799
+ let value = iString.substring(index + 1, iString.length).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
26800
+ if (iString.indexOf('SUMMARY') !== -1) {
26801
+ type = 'SUMMARY';
26802
+ }
26803
+ if (iString.indexOf('DTSTART') !== -1) {
26804
+ curEvent[fields.startTime] = this.dateParsing(iString);
26805
+ curEvent[fields.isAllDay] = this.allDay;
26806
+ this.allDay = false;
26807
+ }
26808
+ else if (iString.indexOf('DTEND') !== -1) {
26809
+ curEvent[fields.endTime] = this.dateParsing(iString);
26810
+ }
26811
+ else if (iString.indexOf('EXDATE') !== -1) {
26812
+ value = getRecurrenceStringFromDate(this.dateParsing(iString));
26813
+ curEvent[fields.recurrenceException] = isNullOrUndefined(curEvent[fields.recurrenceException]) ?
26814
+ value : curEvent[fields.recurrenceException] + ',' + value;
26815
+ }
26816
+ else if (iString.indexOf('RECURRENCE-ID') !== -1) {
26817
+ value = getRecurrenceStringFromDate(this.dateParsing(iString));
26818
+ curEvent[fields.recurrenceException] = value;
26819
+ curEvent[fields.recurrenceID] = value;
26820
+ }
26821
+ else {
26822
+ key = type || key;
26823
+ switch (key) {
26824
+ case 'BEGIN':
26825
+ break;
26826
+ case 'UID':
26827
+ curEvent[`${type}`] = value;
26828
+ if (typeof (id) == 'number') {
26829
+ curEvent[fields.id] = parseInt(value, 10);
26830
+ if (isNaN(curEvent[fields.id])) {
26831
+ curEvent[fields.id] = id + count;
26832
+ count++;
26591
26833
  }
26592
- }
26834
+ }
26835
+ else {
26836
+ curEvent[fields.id] = value;
26837
+ }
26838
+ break;
26839
+ case 'SUMMARY':
26840
+ curEvent[fields.subject] = this.getFormattedString(value);
26841
+ break;
26842
+ case 'LOCATION':
26843
+ curEvent[fields.location] = this.getFormattedString(value);
26844
+ break;
26845
+ case 'DESCRIPTION':
26846
+ if (curEvent[fields.description]) {
26847
+ curEvent[fields.description] = this.getFormattedString(curEvent[fields.description] + SEPARATOR + value);
26848
+ }
26849
+ else {
26850
+ curEvent[fields.description] = this.getFormattedString(value);
26851
+ }
26852
+ break;
26853
+ case 'ISREADONLY':
26854
+ curEvent[fields.isReadonly] = (value.indexOf('true') > -1);
26855
+ break;
26856
+ case 'RRULE':
26857
+ curEvent[fields.recurrenceRule] = value;
26858
+ break;
26859
+ default:
26860
+ if (this.parent.resourceCollection.length > 0) {
26861
+ const resData = this.parent.resourceCollection.filter((data) => data.field === type);
26862
+ curEvent[`${type}`] = (resData.length > 0 && (typeof (resData[0].dataSource[0][resData[0].idField]) == 'number')) ? parseInt(value, 10) : value;
26863
+ }
26864
+ else {
26865
+ curEvent[`${type}`] = value;
26866
+ }
26593
26867
  }
26594
26868
  }
26595
- });
26596
- const app = extend([], events, null, true);
26597
- this.parent.addEvent(this.processOccurrence(app, id));
26869
+ }
26870
+ return { isEvent, curEvent, id, count, events, key };
26598
26871
  }
26599
26872
  processOccurrence(app, maxId) {
26600
26873
  const appoint = [];
@@ -26658,7 +26931,7 @@ class ICalendarImport {
26658
26931
  }
26659
26932
  return parentException + ',' + occurrenceException;
26660
26933
  }
26661
- getDateString(value) {
26934
+ getFormattedString(value) {
26662
26935
  value = value || '';
26663
26936
  // eslint-disable-next-line no-useless-escape
26664
26937
  return (value.replace(/\\\,/g, ',').replace(/\\\;/g, ';').replace(/\\[nN]/g, '\n').replace(/\\\\/g, '\\'));
@@ -26666,7 +26939,7 @@ class ICalendarImport {
26666
26939
  dateParsing(element) {
26667
26940
  const split = element.split(':');
26668
26941
  const value = split[split.length - 1];
26669
- let newDate = new Date(this.getDateString(value));
26942
+ let newDate = new Date(this.getFormattedString(value));
26670
26943
  if (element && (element.indexOf('VALUE=DATE') > -1 || element.indexOf('RECURRENCE-ID;TZID') > -1)) {
26671
26944
  const data = /^(\d{4})(\d{2})(\d{2})$/.exec(value);
26672
26945
  if (data !== null) {
@@ -26941,5 +27214,5 @@ class Print {
26941
27214
  * Export Schedule components
26942
27215
  */
26943
27216
 
26944
- export { Schedule, cellClick, cellDoubleClick, moreEventsClick, select, hover, actionBegin, actionComplete, actionFailure, navigating, renderCell, eventClick, eventRendered, dataBinding, dataBound, popupOpen, popupClose, dragStart, drag, dragStop, resizeStart, resizing, resizeStop, inlineClick, cellSelect, initialLoad, initialEnd, print$1 as print, dataReady, eventsLoaded, contentReady, scroll, virtualScroll, scrollUiUpdate, uiUpdate, documentClick, cellMouseDown, WEEK_LENGTH, DEFAULT_WEEKS, MS_PER_DAY, MS_PER_MINUTE, getElementHeightFromClass, getElementWidthFromClass, getTranslateY, getTranslateX, getWeekFirstDate, getWeekLastDate, firstDateOfMonth, lastDateOfMonth, getWeekNumber, getWeekMiddleDate, setTime, resetTime, getDateInMs, getDateCount, addDays, addMonths, addYears, getStartEndHours, getMaxDays, getDaysCount, getDateFromString, getScrollBarWidth, resetScrollbarWidth, findIndexInData, getOuterHeight, removeChildren, isDaylightSavingTime, getUniversalTime, isMobile, isIPadDevice, capitalizeFirstWord, Resize, DragAndDrop, HeaderRenderer, ViewBase, Day, Week, WorkWeek, Month, Year, Agenda, MonthAgenda, TimelineViews, TimelineMonth, TimelineYear, Timezone, timezoneData, ICalendarExport, ICalendarImport, ExcelExport, Print, RecurrenceEditor, generateSummary, generate, getDateFromRecurrenceDateString, extractObjectFromRule, getCalendarUtil, getRecurrenceStringFromDate, Gregorian, Islamic };
27217
+ export { Schedule, cellClick, cellDoubleClick, moreEventsClick, select, hover, actionBegin, actionComplete, actionFailure, navigating, renderCell, eventClick, eventRendered, dataBinding, dataBound, popupOpen, popupClose, dragStart, drag, dragStop, resizeStart, resizing, resizeStop, inlineClick, cellSelect, virtualScrollStart, virtualScrollStop, initialLoad, initialEnd, print$1 as print, dataReady, eventsLoaded, contentReady, scroll, virtualScroll, scrollUiUpdate, uiUpdate, documentClick, cellMouseDown, WEEK_LENGTH, DEFAULT_WEEKS, MS_PER_DAY, MS_PER_MINUTE, getElementHeightFromClass, getElementWidthFromClass, getTranslateY, getTranslateX, getWeekFirstDate, getWeekLastDate, firstDateOfMonth, lastDateOfMonth, getWeekNumber, getWeekMiddleDate, setTime, resetTime, getDateInMs, getDateCount, addDays, addMonths, addYears, getStartEndHours, getMaxDays, getDaysCount, getDateFromString, getScrollBarWidth, resetScrollbarWidth, findIndexInData, getOuterHeight, removeChildren, isDaylightSavingTime, getUniversalTime, isMobile, isIPadDevice, capitalizeFirstWord, Resize, DragAndDrop, HeaderRenderer, ViewBase, Day, Week, WorkWeek, Month, Year, Agenda, MonthAgenda, TimelineViews, TimelineMonth, TimelineYear, Timezone, timezoneData, ICalendarExport, ICalendarImport, ExcelExport, Print, RecurrenceEditor, generateSummary, generate, getDateFromRecurrenceDateString, extractObjectFromRule, getCalendarUtil, getRecurrenceStringFromDate, Gregorian, Islamic };
26945
27218
  //# sourceMappingURL=ej2-schedule.es2015.js.map