@mintplayer/ng-bootstrap 21.0.0 → 21.1.1

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 (155) hide show
  1. package/fesm2022/mintplayer-ng-bootstrap-accordion.mjs +33 -46
  2. package/fesm2022/mintplayer-ng-bootstrap-accordion.mjs.map +1 -1
  3. package/fesm2022/mintplayer-ng-bootstrap-alert.mjs +12 -30
  4. package/fesm2022/mintplayer-ng-bootstrap-alert.mjs.map +1 -1
  5. package/fesm2022/mintplayer-ng-bootstrap-badge.mjs +6 -18
  6. package/fesm2022/mintplayer-ng-bootstrap-badge.mjs.map +1 -1
  7. package/fesm2022/mintplayer-ng-bootstrap-calendar.mjs +31 -65
  8. package/fesm2022/mintplayer-ng-bootstrap-calendar.mjs.map +1 -1
  9. package/fesm2022/mintplayer-ng-bootstrap-carousel.mjs +200 -132
  10. package/fesm2022/mintplayer-ng-bootstrap-carousel.mjs.map +1 -1
  11. package/fesm2022/mintplayer-ng-bootstrap-close.mjs +5 -7
  12. package/fesm2022/mintplayer-ng-bootstrap-close.mjs.map +1 -1
  13. package/fesm2022/mintplayer-ng-bootstrap-code-snippet.mjs +14 -17
  14. package/fesm2022/mintplayer-ng-bootstrap-code-snippet.mjs.map +1 -1
  15. package/fesm2022/mintplayer-ng-bootstrap-color-picker.mjs +231 -347
  16. package/fesm2022/mintplayer-ng-bootstrap-color-picker.mjs.map +1 -1
  17. package/fesm2022/mintplayer-ng-bootstrap-datatable.mjs +43 -39
  18. package/fesm2022/mintplayer-ng-bootstrap-datatable.mjs.map +1 -1
  19. package/fesm2022/mintplayer-ng-bootstrap-datepicker.mjs +7 -35
  20. package/fesm2022/mintplayer-ng-bootstrap-datepicker.mjs.map +1 -1
  21. package/fesm2022/mintplayer-ng-bootstrap-dock.mjs +1 -0
  22. package/fesm2022/mintplayer-ng-bootstrap-dock.mjs.map +1 -1
  23. package/fesm2022/mintplayer-ng-bootstrap-dropdown-menu.mjs +1 -1
  24. package/fesm2022/mintplayer-ng-bootstrap-dropdown-menu.mjs.map +1 -1
  25. package/fesm2022/mintplayer-ng-bootstrap-dropdown.mjs +46 -86
  26. package/fesm2022/mintplayer-ng-bootstrap-dropdown.mjs.map +1 -1
  27. package/fesm2022/mintplayer-ng-bootstrap-enhanced-paste.mjs +7 -7
  28. package/fesm2022/mintplayer-ng-bootstrap-enhanced-paste.mjs.map +1 -1
  29. package/fesm2022/mintplayer-ng-bootstrap-file-upload.mjs +7 -6
  30. package/fesm2022/mintplayer-ng-bootstrap-file-upload.mjs.map +1 -1
  31. package/fesm2022/mintplayer-ng-bootstrap-grid.mjs +32 -74
  32. package/fesm2022/mintplayer-ng-bootstrap-grid.mjs.map +1 -1
  33. package/fesm2022/mintplayer-ng-bootstrap-let.mjs +6 -7
  34. package/fesm2022/mintplayer-ng-bootstrap-let.mjs.map +1 -1
  35. package/fesm2022/mintplayer-ng-bootstrap-markdown.mjs +18 -18
  36. package/fesm2022/mintplayer-ng-bootstrap-markdown.mjs.map +1 -1
  37. package/fesm2022/mintplayer-ng-bootstrap-modal.mjs +20 -22
  38. package/fesm2022/mintplayer-ng-bootstrap-modal.mjs.map +1 -1
  39. package/fesm2022/mintplayer-ng-bootstrap-multiselect.mjs +16 -10
  40. package/fesm2022/mintplayer-ng-bootstrap-multiselect.mjs.map +1 -1
  41. package/fesm2022/mintplayer-ng-bootstrap-navbar-toggler.mjs +8 -28
  42. package/fesm2022/mintplayer-ng-bootstrap-navbar-toggler.mjs.map +1 -1
  43. package/fesm2022/mintplayer-ng-bootstrap-navbar.mjs +208 -265
  44. package/fesm2022/mintplayer-ng-bootstrap-navbar.mjs.map +1 -1
  45. package/fesm2022/mintplayer-ng-bootstrap-navigation-lock.mjs +8 -21
  46. package/fesm2022/mintplayer-ng-bootstrap-navigation-lock.mjs.map +1 -1
  47. package/fesm2022/mintplayer-ng-bootstrap-offcanvas.mjs +43 -38
  48. package/fesm2022/mintplayer-ng-bootstrap-offcanvas.mjs.map +1 -1
  49. package/fesm2022/mintplayer-ng-bootstrap-ordinal-number.mjs +6 -6
  50. package/fesm2022/mintplayer-ng-bootstrap-ordinal-number.mjs.map +1 -1
  51. package/fesm2022/mintplayer-ng-bootstrap-pagination.mjs +59 -120
  52. package/fesm2022/mintplayer-ng-bootstrap-pagination.mjs.map +1 -1
  53. package/fesm2022/mintplayer-ng-bootstrap-placeholder.mjs +11 -25
  54. package/fesm2022/mintplayer-ng-bootstrap-placeholder.mjs.map +1 -1
  55. package/fesm2022/mintplayer-ng-bootstrap-playlist-toggler.mjs +8 -28
  56. package/fesm2022/mintplayer-ng-bootstrap-playlist-toggler.mjs.map +1 -1
  57. package/fesm2022/mintplayer-ng-bootstrap-popover.mjs +67 -103
  58. package/fesm2022/mintplayer-ng-bootstrap-popover.mjs.map +1 -1
  59. package/fesm2022/mintplayer-ng-bootstrap-progress-bar.mjs +34 -63
  60. package/fesm2022/mintplayer-ng-bootstrap-progress-bar.mjs.map +1 -1
  61. package/fesm2022/mintplayer-ng-bootstrap-range.mjs +6 -6
  62. package/fesm2022/mintplayer-ng-bootstrap-range.mjs.map +1 -1
  63. package/fesm2022/mintplayer-ng-bootstrap-rating.mjs +19 -47
  64. package/fesm2022/mintplayer-ng-bootstrap-rating.mjs.map +1 -1
  65. package/fesm2022/mintplayer-ng-bootstrap-resizable.mjs +35 -41
  66. package/fesm2022/mintplayer-ng-bootstrap-resizable.mjs.map +1 -1
  67. package/fesm2022/mintplayer-ng-bootstrap-scheduler.mjs +205 -779
  68. package/fesm2022/mintplayer-ng-bootstrap-scheduler.mjs.map +1 -1
  69. package/fesm2022/mintplayer-ng-bootstrap-scrollspy.mjs +34 -39
  70. package/fesm2022/mintplayer-ng-bootstrap-scrollspy.mjs.map +1 -1
  71. package/fesm2022/mintplayer-ng-bootstrap-searchbox.mjs +74 -100
  72. package/fesm2022/mintplayer-ng-bootstrap-searchbox.mjs.map +1 -1
  73. package/fesm2022/mintplayer-ng-bootstrap-select.mjs +37 -79
  74. package/fesm2022/mintplayer-ng-bootstrap-select.mjs.map +1 -1
  75. package/fesm2022/mintplayer-ng-bootstrap-select2.mjs +78 -45
  76. package/fesm2022/mintplayer-ng-bootstrap-select2.mjs.map +1 -1
  77. package/fesm2022/mintplayer-ng-bootstrap-shell.mjs +16 -26
  78. package/fesm2022/mintplayer-ng-bootstrap-shell.mjs.map +1 -1
  79. package/fesm2022/mintplayer-ng-bootstrap-signature-pad.mjs +14 -40
  80. package/fesm2022/mintplayer-ng-bootstrap-signature-pad.mjs.map +1 -1
  81. package/fesm2022/mintplayer-ng-bootstrap-spinner.mjs +8 -32
  82. package/fesm2022/mintplayer-ng-bootstrap-spinner.mjs.map +1 -1
  83. package/fesm2022/mintplayer-ng-bootstrap-splitter.mjs +70 -76
  84. package/fesm2022/mintplayer-ng-bootstrap-splitter.mjs.map +1 -1
  85. package/fesm2022/mintplayer-ng-bootstrap-sticky-footer.mjs +11 -11
  86. package/fesm2022/mintplayer-ng-bootstrap-sticky-footer.mjs.map +1 -1
  87. package/fesm2022/mintplayer-ng-bootstrap-tab-control.mjs +53 -99
  88. package/fesm2022/mintplayer-ng-bootstrap-tab-control.mjs.map +1 -1
  89. package/fesm2022/mintplayer-ng-bootstrap-table.mjs +7 -38
  90. package/fesm2022/mintplayer-ng-bootstrap-table.mjs.map +1 -1
  91. package/fesm2022/mintplayer-ng-bootstrap-timepicker.mjs +23 -49
  92. package/fesm2022/mintplayer-ng-bootstrap-timepicker.mjs.map +1 -1
  93. package/fesm2022/mintplayer-ng-bootstrap-toast.mjs +33 -38
  94. package/fesm2022/mintplayer-ng-bootstrap-toast.mjs.map +1 -1
  95. package/fesm2022/mintplayer-ng-bootstrap-toggle-button.mjs +45 -98
  96. package/fesm2022/mintplayer-ng-bootstrap-toggle-button.mjs.map +1 -1
  97. package/fesm2022/mintplayer-ng-bootstrap-tooltip.mjs +12 -24
  98. package/fesm2022/mintplayer-ng-bootstrap-tooltip.mjs.map +1 -1
  99. package/fesm2022/mintplayer-ng-bootstrap-treeview.mjs +21 -43
  100. package/fesm2022/mintplayer-ng-bootstrap-treeview.mjs.map +1 -1
  101. package/fesm2022/mintplayer-ng-bootstrap-trust-html.mjs +6 -6
  102. package/fesm2022/mintplayer-ng-bootstrap-trust-html.mjs.map +1 -1
  103. package/fesm2022/mintplayer-ng-bootstrap-typeahead.mjs +29 -49
  104. package/fesm2022/mintplayer-ng-bootstrap-typeahead.mjs.map +1 -1
  105. package/package.json +5 -5
  106. package/types/mintplayer-ng-bootstrap-accordion.d.ts +11 -15
  107. package/types/mintplayer-ng-bootstrap-alert.d.ts +4 -9
  108. package/types/mintplayer-ng-bootstrap-badge.d.ts +5 -9
  109. package/types/mintplayer-ng-bootstrap-calendar.d.ts +14 -22
  110. package/types/mintplayer-ng-bootstrap-carousel.d.ts +41 -35
  111. package/types/mintplayer-ng-bootstrap-close.d.ts +1 -2
  112. package/types/mintplayer-ng-bootstrap-code-snippet.d.ts +4 -5
  113. package/types/mintplayer-ng-bootstrap-color-picker.d.ts +70 -97
  114. package/types/mintplayer-ng-bootstrap-datatable.d.ts +11 -11
  115. package/types/mintplayer-ng-bootstrap-datepicker.d.ts +6 -13
  116. package/types/mintplayer-ng-bootstrap-dropdown.d.ts +14 -20
  117. package/types/mintplayer-ng-bootstrap-enhanced-paste.d.ts +1 -3
  118. package/types/mintplayer-ng-bootstrap-file-upload.d.ts +1 -1
  119. package/types/mintplayer-ng-bootstrap-grid.d.ts +14 -26
  120. package/types/mintplayer-ng-bootstrap-let.d.ts +0 -2
  121. package/types/mintplayer-ng-bootstrap-markdown.d.ts +1 -5
  122. package/types/mintplayer-ng-bootstrap-modal.d.ts +3 -6
  123. package/types/mintplayer-ng-bootstrap-multiselect.d.ts +6 -6
  124. package/types/mintplayer-ng-bootstrap-navbar-toggler.d.ts +5 -11
  125. package/types/mintplayer-ng-bootstrap-navbar.d.ts +75 -80
  126. package/types/mintplayer-ng-bootstrap-navigation-lock.d.ts +2 -4
  127. package/types/mintplayer-ng-bootstrap-offcanvas.d.ts +12 -14
  128. package/types/mintplayer-ng-bootstrap-ordinal-number.d.ts +1 -2
  129. package/types/mintplayer-ng-bootstrap-pagination.d.ts +17 -31
  130. package/types/mintplayer-ng-bootstrap-placeholder.d.ts +3 -8
  131. package/types/mintplayer-ng-bootstrap-playlist-toggler.d.ts +5 -11
  132. package/types/mintplayer-ng-bootstrap-popover.d.ts +15 -23
  133. package/types/mintplayer-ng-bootstrap-progress-bar.d.ts +19 -22
  134. package/types/mintplayer-ng-bootstrap-range.d.ts +1 -2
  135. package/types/mintplayer-ng-bootstrap-rating.d.ts +8 -14
  136. package/types/mintplayer-ng-bootstrap-resizable.d.ts +7 -11
  137. package/types/mintplayer-ng-bootstrap-scheduler.d.ts +132 -220
  138. package/types/mintplayer-ng-bootstrap-scrollspy.d.ts +14 -15
  139. package/types/mintplayer-ng-bootstrap-searchbox.d.ts +20 -27
  140. package/types/mintplayer-ng-bootstrap-select.d.ts +13 -23
  141. package/types/mintplayer-ng-bootstrap-select2.d.ts +16 -14
  142. package/types/mintplayer-ng-bootstrap-shell.d.ts +6 -12
  143. package/types/mintplayer-ng-bootstrap-signature-pad.d.ts +7 -12
  144. package/types/mintplayer-ng-bootstrap-spinner.d.ts +8 -16
  145. package/types/mintplayer-ng-bootstrap-splitter.d.ts +21 -27
  146. package/types/mintplayer-ng-bootstrap-sticky-footer.d.ts +3 -3
  147. package/types/mintplayer-ng-bootstrap-tab-control.d.ts +29 -37
  148. package/types/mintplayer-ng-bootstrap-table.d.ts +6 -13
  149. package/types/mintplayer-ng-bootstrap-timepicker.d.ts +7 -14
  150. package/types/mintplayer-ng-bootstrap-toast.d.ts +5 -10
  151. package/types/mintplayer-ng-bootstrap-toggle-button.d.ts +22 -36
  152. package/types/mintplayer-ng-bootstrap-tooltip.d.ts +4 -7
  153. package/types/mintplayer-ng-bootstrap-treeview.d.ts +10 -15
  154. package/types/mintplayer-ng-bootstrap-trust-html.d.ts +0 -2
  155. package/types/mintplayer-ng-bootstrap-typeahead.d.ts +14 -17
@@ -1,809 +1,235 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, Input, Component, Pipe, EventEmitter, HostListener, Output, ViewChildren, NgModule } from '@angular/core';
3
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
- import { BehaviorSubject, map, filter, combineLatest, take } from 'rxjs';
5
- import * as i1 from '@angular/platform-browser';
6
- import * as i2 from '@mintplayer/ng-bootstrap/calendar-month';
7
- import * as i5 from '@angular/common';
8
- import { CommonModule } from '@angular/common';
2
+ import { inject, Injector, input, model, output, computed, signal, runInInjectionContext, effect, ViewChild, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
3
+ import '@mintplayer/scheduler-wc';
4
+ export { generateEventId, generateGroupId, generateResourceId } from '@mintplayer/scheduler-core';
9
5
 
10
- var ESchedulerMode;
11
- (function (ESchedulerMode) {
12
- ESchedulerMode[ESchedulerMode["week"] = 0] = "week";
13
- ESchedulerMode[ESchedulerMode["timeline"] = 1] = "timeline";
14
- })(ESchedulerMode || (ESchedulerMode = {}));
15
-
16
- var EDragOperation;
17
- (function (EDragOperation) {
18
- EDragOperation[EDragOperation["none"] = 0] = "none";
19
- EDragOperation[EDragOperation["createEvent"] = 1] = "createEvent";
20
- EDragOperation[EDragOperation["resizeEvent"] = 2] = "resizeEvent";
21
- EDragOperation[EDragOperation["moveEvent"] = 3] = "moveEvent";
22
- })(EDragOperation || (EDragOperation = {}));
23
-
24
- class BsTimelineService {
25
- splitInParts(event) {
26
- let startTime = event.start;
27
- const result = [];
28
- const eventOrNull = 'color' in event ? event : null;
29
- while (!this.dateEquals(startTime, event.end)) {
30
- const end = new Date(startTime.getFullYear(), startTime.getMonth(), startTime.getDate() + 1, 0, 0, 0);
31
- result.push({ start: startTime, end: end, event: eventOrNull });
32
- startTime = end;
33
- }
34
- if (startTime != event.end) {
35
- result.push({ start: startTime, end: event.end, event: eventOrNull });
36
- }
37
- return { event: event, parts: result };
38
- }
39
- dateEquals(date1, date2) {
40
- return (date1.getFullYear() === date2.getFullYear() &&
41
- date1.getMonth() === date2.getMonth() &&
42
- date1.getDate() === date2.getDate());
43
- }
44
- getTimeline(events) {
45
- const timestamps = this.getTimestamps(events);
46
- const tracks = [];
47
- timestamps.forEach((timestamp, tIndex) => {
48
- const starting = events.filter((e) => e.start === timestamp);
49
- // const ending = events.filter((e) => e.end === timestamp);
50
- starting.forEach((startedEvent, eIndex) => {
51
- const freeTracks = tracks.filter(t => this.trackIsFreeAt(t, startedEvent));
52
- if (freeTracks.length === 0) {
53
- tracks.push({ index: tracks.length, events: [startedEvent] });
54
- }
55
- else {
56
- freeTracks[0].events.push(startedEvent);
6
+ /**
7
+ * Angular wrapper for the mp-scheduler web component using signals
8
+ */
9
+ class BsSchedulerComponent {
10
+ constructor() {
11
+ this.injector = inject(Injector);
12
+ // Input signals
13
+ this.view = input('week', ...(ngDevMode ? [{ debugName: "view" }] : []));
14
+ this.date = input(new Date(), ...(ngDevMode ? [{ debugName: "date" }] : []));
15
+ this.events = input([], ...(ngDevMode ? [{ debugName: "events" }] : []));
16
+ this.resources = input([], ...(ngDevMode ? [{ debugName: "resources" }] : []));
17
+ this.options = input({}, ...(ngDevMode ? [{ debugName: "options" }] : []));
18
+ // Two-way binding model signals
19
+ this.selectedEvent = model(null, ...(ngDevMode ? [{ debugName: "selectedEvent" }] : []));
20
+ this.selectedRange = model(null, ...(ngDevMode ? [{ debugName: "selectedRange" }] : []));
21
+ // Output signals (events)
22
+ this.eventClick = output();
23
+ this.eventDblClick = output();
24
+ this.eventCreate = output();
25
+ this.eventUpdate = output();
26
+ this.eventDelete = output();
27
+ this.dateClick = output();
28
+ this.dateSelect = output();
29
+ this.viewChange = output();
30
+ // Computed signals
31
+ this.currentWeekStart = computed(() => {
32
+ const d = new Date(this.date());
33
+ const day = d.getDay();
34
+ const diff = (day === 0 ? 6 : day - 1); // Adjust for Monday start
35
+ d.setDate(d.getDate() - diff);
36
+ d.setHours(0, 0, 0, 0);
37
+ return d;
38
+ }, ...(ngDevMode ? [{ debugName: "currentWeekStart" }] : []));
39
+ this.currentWeekEnd = computed(() => {
40
+ const start = this.currentWeekStart();
41
+ const end = new Date(start);
42
+ end.setDate(end.getDate() + 6);
43
+ end.setHours(23, 59, 59, 999);
44
+ return end;
45
+ }, ...(ngDevMode ? [{ debugName: "currentWeekEnd" }] : []));
46
+ this.visibleEvents = computed(() => {
47
+ const start = this.currentWeekStart();
48
+ const end = this.currentWeekEnd();
49
+ return this.events().filter((e) => e.start < end && e.end > start);
50
+ }, ...(ngDevMode ? [{ debugName: "visibleEvents" }] : []));
51
+ // Internal state
52
+ this.initialized = signal(false, ...(ngDevMode ? [{ debugName: "initialized" }] : []));
53
+ this.eventListeners = [];
54
+ }
55
+ ngAfterViewInit() {
56
+ runInInjectionContext(this.injector, () => {
57
+ // Set up effects to sync inputs to web component
58
+ effect(() => {
59
+ const el = this.schedulerRef?.nativeElement;
60
+ if (el) {
61
+ el.view = this.view();
57
62
  }
58
63
  });
59
- });
60
- return tracks;
61
- }
62
- getTimestamps(events) {
63
- const allTimestamps = events.map(e => [e.start, e.end])
64
- .reduce((flat, toFlatten) => flat.concat(toFlatten), []);
65
- return allTimestamps
66
- .filter((t, i) => allTimestamps.indexOf(t) === i)
67
- .sort((t1, t2) => t1 - t2);
68
- }
69
- trackIsFreeAt(track, event) {
70
- if (track.events.every((ev) => (ev.end <= event.start) || (event.end <= ev.start))) {
71
- return true;
72
- }
73
- else {
74
- return false;
75
- }
76
- }
77
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsTimelineService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
78
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsTimelineService, providedIn: 'root' }); }
79
- }
80
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsTimelineService, decorators: [{
81
- type: Injectable,
82
- args: [{
83
- providedIn: 'root'
84
- }]
85
- }] });
86
-
87
- class ResourceGroupPresenterComponent {
88
- constructor(sanitizer) {
89
- this.sanitizer = sanitizer;
90
- this.level = 0;
91
- this.resourceOrGroup$ = new BehaviorSubject(null);
92
- this.timeSlots$ = new BehaviorSubject([]);
93
- this.isExpanded$ = new BehaviorSubject(false);
94
- this.data$ = this.resourceOrGroup$
95
- .pipe(map((resourceOrGroup) => {
96
- if (!resourceOrGroup) {
97
- return null;
98
- }
99
- else if ('children' in resourceOrGroup) {
100
- return {
101
- resource: null,
102
- resourceGroup: resourceOrGroup
103
- };
104
- }
105
- else {
106
- return {
107
- resource: resourceOrGroup,
108
- resourceGroup: null
109
- };
110
- }
111
- }))
112
- .pipe(filter((resourceOrGroup) => !!resourceOrGroup))
113
- .pipe(map((resourceOrGroup) => resourceOrGroup));
114
- this.colSpan$ = this.timeSlots$
115
- .pipe(map(timeSlots => timeSlots
116
- .map(timeslot => timeslot.slots.length)
117
- .reduce((sum, current) => sum + current, 0)));
118
- import('bootstrap-icons/icons/chevron-down.svg').then((icon) => {
119
- this.chevronDown = sanitizer.bypassSecurityTrustHtml(icon.default);
120
- });
121
- import('bootstrap-icons/icons/chevron-right.svg').then((icon) => {
122
- this.chevronRight = sanitizer.bypassSecurityTrustHtml(icon.default);
123
- });
124
- }
125
- //#region resourceOrGroup
126
- get resourceOrGroup() {
127
- return this.resourceOrGroup$.value;
128
- }
129
- set resourceGroup(value) {
130
- this.resourceOrGroup$.next(value);
131
- }
132
- //#endregion
133
- //#region timeSlots
134
- get timeSlots() {
135
- return this.timeSlots$.value;
136
- }
137
- set timeSlots(value) {
138
- this.timeSlots$.next(value);
139
- }
140
- //#endregion
141
- //#region isExpanded
142
- get isExpanded() {
143
- return this.isExpanded$.value;
144
- }
145
- set isExpanded(value) {
146
- this.isExpanded$.next(value);
147
- }
148
- //#endregion
149
- toggleExpanded() {
150
- this.isExpanded$.next(!this.isExpanded$.value);
151
- }
152
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ResourceGroupPresenterComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
153
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ResourceGroupPresenterComponent, isStandalone: false, selector: "bs-resource-group-presenter", inputs: { level: "level", resourceGroup: "resourceGroup", timeSlots: "timeSlots", isExpanded: "isExpanded" }, ngImport: i0, template: "@if (data$ | async; as data) {\n\n <!-- Data is a resource group -->\n @if (data.resourceGroup) {\n <!-- Header -->\n @if (timeSlots$ | async; as timeSlots) {\n <tr class=\"p-0 cursor-pointer\" [title]=\"data.resourceGroup.description\">\n @if (colSpan$ | async; as colspan) {\n <td class=\"p-2 cursor-pointer\" [colSpan]=\"colspan + 1\" (click)=\"toggleExpanded()\">\n <span class=\"p-2 align-middle position-sticky\">\n @if (isExpanded$ | async) {\n <span [innerHTML]=\"chevronDown\" [style.padding-left.px]=\"level * 20\"></span>\n } @else {\n <span [innerHTML]=\"chevronRight\" [style.padding-left.px]=\"level * 20\"></span>\n }\n {{ data.resourceGroup.description }}\n </span>\n </td>\n }\n </tr>\n }\n\n <!-- Subgroups or resources -->\n @if (isExpanded$ | async) {\n @if (timeSlots$ | async; as timeSlots) {\n @for (child of data.resourceGroup.children; track child) {\n <bs-resource-group-presenter [resourceGroup]=\"child\" [timeSlots]=\"timeSlots\" [level]=\"level + 1\"></bs-resource-group-presenter>\n }\n }\n }\n }\n\n <!-- Data is a resource -->\n @if (data.resource) {\n <tr class=\"p-0 bordered\" [title]=\"data.resource.description\">\n <td class=\"p-0 bg-white\">\n <div class=\"p-2\">{{ data.resource.description }}</div>\n </td>\n @for (slots of (timeSlots$ | async); track $index) {\n @for (slot of slots.slots; track slot) {\n <td class=\"bg-white border-1\">\n <!-- {{ slot.start | date: 'dd/MM/yyyy HH:mm:ss' }} -->\n </td>\n }\n }\n </tr>\n }\n}", styles: [":host{display:contents}tr{border-bottom-width:1px}tr:not(.bordered) td span.position-sticky{left:0;right:0}\n"], dependencies: [{ kind: "component", type: ResourceGroupPresenterComponent, selector: "bs-resource-group-presenter", inputs: ["level", "resourceGroup", "timeSlots", "isExpanded"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }] }); }
154
- }
155
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ResourceGroupPresenterComponent, decorators: [{
156
- type: Component,
157
- args: [{ selector: 'bs-resource-group-presenter', standalone: false, template: "@if (data$ | async; as data) {\n\n <!-- Data is a resource group -->\n @if (data.resourceGroup) {\n <!-- Header -->\n @if (timeSlots$ | async; as timeSlots) {\n <tr class=\"p-0 cursor-pointer\" [title]=\"data.resourceGroup.description\">\n @if (colSpan$ | async; as colspan) {\n <td class=\"p-2 cursor-pointer\" [colSpan]=\"colspan + 1\" (click)=\"toggleExpanded()\">\n <span class=\"p-2 align-middle position-sticky\">\n @if (isExpanded$ | async) {\n <span [innerHTML]=\"chevronDown\" [style.padding-left.px]=\"level * 20\"></span>\n } @else {\n <span [innerHTML]=\"chevronRight\" [style.padding-left.px]=\"level * 20\"></span>\n }\n {{ data.resourceGroup.description }}\n </span>\n </td>\n }\n </tr>\n }\n\n <!-- Subgroups or resources -->\n @if (isExpanded$ | async) {\n @if (timeSlots$ | async; as timeSlots) {\n @for (child of data.resourceGroup.children; track child) {\n <bs-resource-group-presenter [resourceGroup]=\"child\" [timeSlots]=\"timeSlots\" [level]=\"level + 1\"></bs-resource-group-presenter>\n }\n }\n }\n }\n\n <!-- Data is a resource -->\n @if (data.resource) {\n <tr class=\"p-0 bordered\" [title]=\"data.resource.description\">\n <td class=\"p-0 bg-white\">\n <div class=\"p-2\">{{ data.resource.description }}</div>\n </td>\n @for (slots of (timeSlots$ | async); track $index) {\n @for (slot of slots.slots; track slot) {\n <td class=\"bg-white border-1\">\n <!-- {{ slot.start | date: 'dd/MM/yyyy HH:mm:ss' }} -->\n </td>\n }\n }\n </tr>\n }\n}", styles: [":host{display:contents}tr{border-bottom-width:1px}tr:not(.bordered) td span.position-sticky{left:0;right:0}\n"] }]
158
- }], ctorParameters: () => [{ type: i1.DomSanitizer }], propDecorators: { level: [{
159
- type: Input
160
- }], resourceGroup: [{
161
- type: Input
162
- }], timeSlots: [{
163
- type: Input
164
- }], isExpanded: [{
165
- type: Input
166
- }] } });
167
-
168
- class BsSecondsTimespanPipe {
169
- transform(value) {
170
- return (value.end.getTime() - value.start.getTime()) / 1000;
171
- }
172
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSecondsTimespanPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
173
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: BsSecondsTimespanPipe, isStandalone: false, name: "bsSecondsTimespan" }); }
174
- }
175
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSecondsTimespanPipe, decorators: [{
176
- type: Pipe,
177
- args: [{
178
- name: 'bsSecondsTimespan',
179
- standalone: false,
180
- }]
181
- }] });
182
-
183
- class BsSecondsTodayOffsetPipe {
184
- transform(value) {
185
- const today = new Date(value.start);
186
- today.setHours(0);
187
- today.setMinutes(0);
188
- today.setSeconds(0);
189
- return (value.start.getTime() - today.getTime()) / 1000;
190
- }
191
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSecondsTodayOffsetPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
192
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: BsSecondsTodayOffsetPipe, isStandalone: false, name: "bsSecondsTodayOffset" }); }
193
- }
194
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSecondsTodayOffsetPipe, decorators: [{
195
- type: Pipe,
196
- args: [{
197
- name: 'bsSecondsTodayOffset',
198
- standalone: false,
199
- }]
200
- }] });
201
-
202
- class DayOfWeekPipe {
203
- transform(value) {
204
- const dayOfWeek = value.start.getDay();
205
- if (dayOfWeek === 0) {
206
- return 7;
207
- }
208
- else {
209
- return dayOfWeek;
210
- }
211
- }
212
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DayOfWeekPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
213
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: DayOfWeekPipe, isStandalone: false, name: "dayOfWeek" }); }
214
- }
215
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DayOfWeekPipe, decorators: [{
216
- type: Pipe,
217
- args: [{
218
- name: 'dayOfWeek',
219
- standalone: false,
220
- }]
221
- }] });
222
-
223
- /// <reference types="../../types" />
224
- class BsSchedulerComponent {
225
- constructor(sanitizer, calendarMonthService, timelineService, destroy) {
226
- this.sanitizer = sanitizer;
227
- this.calendarMonthService = calendarMonthService;
228
- this.timelineService = timelineService;
229
- this.destroy = destroy;
230
- this.resources$ = new BehaviorSubject([]);
231
- this.weekOptions$ = new BehaviorSubject({ unitHeight: 30 });
232
- this.timelineOptions$ = new BehaviorSubject({ unitWidth: 50 });
233
- this.previewEvent$ = new BehaviorSubject(null);
234
- this.timeSlotDuration$ = new BehaviorSubject(1800);
235
- this.timeSlots$ = new BehaviorSubject([]);
236
- this.mouseState$ = new BehaviorSubject(false);
237
- this.hoveredTimeSlot$ = new BehaviorSubject(null);
238
- this.hoveredEvent$ = new BehaviorSubject(null);
239
- this.resourceGroupPresenterCounter = 1;
240
- //#region Mode
241
- this.modes = ESchedulerMode;
242
- this.mode$ = new BehaviorSubject(ESchedulerMode.week);
243
- this.modeChange = new EventEmitter();
244
- //#endregion
245
- // //#region Scale
246
- // scale$ = new BehaviorSubject<SchedulerScale>(availableScales[4]);
247
- // @Output() public scaleChange = new EventEmitter<SchedulerScale>();
248
- // public get scale() {
249
- // return this.scale$.value;
250
- // }
251
- // @Input() public set scale(value: SchedulerScale) {
252
- // this.scale$.next(value);
253
- // }
254
- // //#endregion
255
- //#region WeekOptions
256
- this.weekOptionsChange = new EventEmitter();
257
- //#endregion
258
- //#region TimelineOptions
259
- this.timelineOptionsChange = new EventEmitter();
260
- //#endregion
261
- //#region maxInnerHeight
262
- this.maxInnerHeight = null;
263
- this.operation = null;
264
- this.dragStartTimeslot = null;
265
- const monday = this.calendarMonthService.getMondayBefore(new Date());
266
- this.currentWeekOrMonth$ = new BehaviorSubject(monday);
267
- this.shownDays$ = combineLatest([this.currentWeekOrMonth$, this.mode$])
268
- .pipe(map(([currentDay, mode]) => {
269
- currentDay.setHours(0);
270
- currentDay.setMinutes(0);
271
- currentDay.setSeconds(0);
272
- currentDay.setMilliseconds(0);
273
- switch (mode) {
274
- case ESchedulerMode.week: {
275
- return Array.from(Array(7).keys()).map((x) => this.addDays(currentDay, x));
64
+ effect(() => {
65
+ const el = this.schedulerRef?.nativeElement;
66
+ if (el) {
67
+ el.date = this.date();
276
68
  }
277
- case ESchedulerMode.timeline: {
278
- const firstDay = new Date(currentDay.getFullYear(), currentDay.getMonth(), 1);
279
- const daysOfMonth = new Date(currentDay.getFullYear(), currentDay.getMonth() + 1, 0).getDate();
280
- return Array.from(Array(daysOfMonth).keys()).map((x) => this.addDays(firstDay, x));
69
+ });
70
+ effect(() => {
71
+ const el = this.schedulerRef?.nativeElement;
72
+ if (el) {
73
+ el.events = this.events();
281
74
  }
282
- }
283
- }));
284
- this.daysOfWeekWithTimestamps$ = this.shownDays$
285
- .pipe(map((shownDays) => ({ start: shownDays[0].getTime(), end: shownDays[shownDays.length - 1].getTime() + 24 * 60 * 60 * 1000 })));
286
- this.events$ = this.resources$
287
- .pipe(map((resourcesOrGroups) => resourcesOrGroups.map(resOrGroup => this.getResourcesForGroup(resOrGroup))))
288
- .pipe(map(jaggedResources => jaggedResources.reduce((flat, toFlatten) => flat.concat(toFlatten), [])))
289
- .pipe(map(resources => resources.map(res => res.events)))
290
- .pipe(map(jaggedEvents => jaggedEvents.reduce((flat, toFlatten) => flat.concat(toFlatten), [])));
291
- // groups.reduce((flat, toFlatten) => flat.concat(toFlatten.children), [])
292
- this.eventParts$ = this.events$.pipe(map((events) => events.map((ev) => this.timelineService.splitInParts(ev))));
293
- this.eventPartsForThisWeek$ = combineLatest([
294
- this.daysOfWeekWithTimestamps$,
295
- this.eventParts$
296
- .pipe(map(eventParts => eventParts.map(evp => evp.parts)))
297
- .pipe(map(jaggedParts => jaggedParts.reduce((flat, toFlatten) => flat.concat(toFlatten), [])))
298
- ])
299
- .pipe(map(([startAndEnd, eventParts]) => {
300
- return eventParts.filter(eventPart => {
301
- return !((eventPart.end.getTime() <= startAndEnd.start) || (eventPart.start.getTime() >= startAndEnd.end));
302
75
  });
303
- }));
304
- this.previewEventParts$ = this.previewEvent$.pipe(map((event) => {
305
- if (event) {
306
- return this.timelineService.splitInParts(event);
307
- }
308
- else {
309
- return null;
310
- }
311
- }));
312
- this.previewEventPartsForThisWeek$ = combineLatest([this.daysOfWeekWithTimestamps$, this.previewEventParts$])
313
- .pipe(map(([startAndEnd, previewEventParts]) => {
314
- if (previewEventParts) {
315
- return previewEventParts.parts.filter(eventPart => {
316
- return !((eventPart.end.getTime() <= startAndEnd.start) || (eventPart.start.getTime() >= startAndEnd.end));
317
- });
318
- }
319
- else {
320
- return [];
321
- }
322
- }));
323
- this.timelinedEventPartsForThisWeek$ = this.eventPartsForThisWeek$
324
- .pipe(map(eventParts => {
325
- // We'll only use the events for this week
326
- const events = eventParts.map(ep => ep.event)
327
- .filter((e, i, list) => list.indexOf(e) === i)
328
- .filter((e) => !!e)
329
- .map((e) => e);
330
- const timeline = this.timelineService.getTimeline(events);
331
- const result = timeline.map(track => track.events.map(ev => ({ event: ev, index: track.index })))
332
- .reduce((flat, toFlatten) => flat.concat(toFlatten), [])
333
- .map((evi) => eventParts.filter(p => p.event === evi.event).map(p => ({ part: p, index: evi.index })))
334
- .reduce((flat, toFlatten) => flat.concat(toFlatten), []);
335
- return {
336
- total: timeline.length,
337
- parts: result
338
- };
339
- }));
340
- combineLatest([this.mode$, this.shownDays$, this.timeSlotDuration$])
341
- .pipe(filter(([mode, shownDays, duration]) => mode !== null))
342
- .pipe(map(([mode, shownDays, duration]) => {
343
- switch (mode) {
344
- case ESchedulerMode.week: {
345
- const timeSlotsPerDay = Math.floor((60 * 60 * 24) / duration);
346
- return Array.from(Array(timeSlotsPerDay).keys()).map((index) => {
347
- const timeslotForMonday = this.createTimeslot(shownDays[0], index, duration);
348
- return {
349
- slots: shownDays.map((day) => {
350
- const start = new Date(day);
351
- start.setHours(timeslotForMonday.start.getHours());
352
- start.setMinutes(timeslotForMonday.start.getMinutes());
353
- start.setSeconds(timeslotForMonday.start.getSeconds());
354
- start.setMilliseconds(timeslotForMonday.start.getMilliseconds());
355
- const end = new Date(day);
356
- end.setHours(timeslotForMonday.end.getHours());
357
- end.setMinutes(timeslotForMonday.end.getMinutes());
358
- end.setSeconds(timeslotForMonday.end.getSeconds());
359
- end.setMilliseconds(timeslotForMonday.end.getMilliseconds());
360
- end.setDate(end.getDate() + timeslotForMonday.end.getDate() - timeslotForMonday.start.getDate());
361
- return { start, end };
362
- }),
363
- stamp: timeslotForMonday.start
364
- };
365
- });
76
+ effect(() => {
77
+ const el = this.schedulerRef?.nativeElement;
78
+ if (el) {
79
+ el.resources = this.resources();
366
80
  }
367
- case ESchedulerMode.timeline: {
368
- const totalTimeslots = (24 * 60 * 60) / duration;
369
- return shownDays.map((day) => {
370
- return {
371
- slots: Array.from(Array(totalTimeslots).keys())
372
- .map((index) => {
373
- return this.createTimeslot(day, index, duration);
374
- }),
375
- stamp: day
376
- };
377
- });
81
+ });
82
+ effect(() => {
83
+ const el = this.schedulerRef?.nativeElement;
84
+ if (el) {
85
+ el.options = this.options();
378
86
  }
379
- default: {
380
- throw 'Unknown value for Mode: ' + mode;
87
+ });
88
+ // Sync selectedEvent to web component
89
+ effect(() => {
90
+ const el = this.schedulerRef?.nativeElement;
91
+ if (el) {
92
+ el.selectedEvent = this.selectedEvent();
381
93
  }
382
- }
383
- }))
384
- .pipe(takeUntilDestroyed(this.destroy))
385
- .subscribe((timeslots) => {
386
- // For performance reasons, we're not using an observable here, but persist the timeslots in a BehaviorSubject.
387
- this.timeSlots$.next(timeslots);
94
+ });
388
95
  });
389
- this.weekOptions$.pipe(takeUntilDestroyed())
390
- .subscribe(weekOptions => this.weekOptionsChange.emit(weekOptions));
391
- this.timelineOptions$.pipe(takeUntilDestroyed())
392
- .subscribe(timelineOptions => this.timelineOptionsChange.emit(timelineOptions));
393
- // combineLatest([this.mode$, this.scale$])
394
- // .pipe(filter(([mode, scale]) => mode === ESchedulerMode.timeline))
395
- import('bootstrap-icons/icons/chevron-left.svg').then((icon) => {
396
- this.chevronLeft = sanitizer.bypassSecurityTrustHtml(icon.default);
96
+ // Set up event listeners
97
+ this.setupEventListeners();
98
+ this.initialized.set(true);
99
+ }
100
+ ngOnDestroy() {
101
+ this.removeEventListeners();
102
+ }
103
+ setupEventListeners() {
104
+ const el = this.schedulerRef?.nativeElement;
105
+ if (!el)
106
+ return;
107
+ const addListener = (type, handler) => {
108
+ const listener = (e) => handler(e);
109
+ el.addEventListener(type, listener);
110
+ this.eventListeners.push({ type, listener });
111
+ };
112
+ addListener('event-click', (e) => {
113
+ this.eventClick.emit(e.detail);
114
+ this.selectedEvent.set(e.detail.event);
397
115
  });
398
- import('bootstrap-icons/icons/chevron-right.svg').then((icon) => {
399
- this.chevronRight = sanitizer.bypassSecurityTrustHtml(icon.default);
116
+ addListener('event-dblclick', (e) => {
117
+ this.eventDblClick.emit(e.detail);
400
118
  });
401
- }
402
- createTimeslot(date, index, duration) {
403
- const timeSlotStart = new Date(date);
404
- timeSlotStart.setTime(+timeSlotStart.getTime() + index * duration * 1000);
405
- const timeSlotEnd = new Date(timeSlotStart);
406
- timeSlotEnd.setTime(+timeSlotEnd.getTime() + duration * 1000);
407
- return { start: timeSlotStart, end: timeSlotEnd };
408
- }
409
- getResourcesForGroup(resourceOrGroup) {
410
- if ('children' in resourceOrGroup) {
411
- return resourceOrGroup.children
412
- .map((child) => this.getResourcesForGroup(child))
413
- .reduce((flat, toFlatten) => flat.concat(toFlatten), []);
414
- }
415
- else {
416
- return [resourceOrGroup];
417
- }
418
- }
419
- get mode() {
420
- return this.mode$.value;
421
- }
422
- set mode(value) {
423
- this.mode$.next(value);
424
- }
425
- get weekOptions() {
426
- return this.weekOptions$.value;
427
- }
428
- set weekOptions(value) {
429
- this.weekOptions$.next(value);
430
- }
431
- get timelineOptions() {
432
- return this.timelineOptions$.value;
433
- }
434
- set timelineOptions(value) {
435
- this.timelineOptions$.next(value);
436
- }
437
- //#endregion
438
- //#region Resources
439
- get resources() {
440
- return this.resources$.value;
441
- }
442
- set resources(value) {
443
- this.resources$.next(value);
444
- }
445
- //#endregion
446
- addDays(date, days) {
447
- const result = new Date(date);
448
- result.setDate(result.getDate() + days);
449
- return result;
450
- }
451
- onPreviousWeekOrMonth() {
452
- this.onChangeWeekOrMonth(false);
453
- }
454
- onNextWeekOrMonth() {
455
- this.onChangeWeekOrMonth(true);
456
- }
457
- onChangeWeekOrMonth(next) {
458
- combineLatest([this.currentWeekOrMonth$, this.mode$])
459
- .pipe(map(([currentWeekOrMonth, mode]) => {
460
- switch (mode) {
461
- case ESchedulerMode.week: {
462
- return this.addDays(currentWeekOrMonth, (next ? 7 : -7));
463
- }
464
- case ESchedulerMode.timeline: {
465
- return new Date(currentWeekOrMonth.getFullYear(), currentWeekOrMonth.getMonth() + (next ? 1 : -1), 1);
466
- }
467
- }
468
- }), take(1), takeUntilDestroyed(this.destroy))
469
- .subscribe((w) => this.currentWeekOrMonth$.next(w));
470
- }
471
- onHoverEvent(ev) {
472
- this.hoveredEvent$.next(ev);
473
- }
474
- onLeaveEvent(ev) {
475
- this.hoveredEvent$.next(null);
476
- }
477
- onCreateEvent(ev, slot) {
478
- ev.preventDefault();
479
- this.mouseState$.next(true);
480
- this.dragStartTimeslot = slot;
481
- this.operation = {
482
- operation: EDragOperation.createEvent,
483
- event: {
484
- start: slot.start,
485
- end: slot.end,
486
- color: '#F00',
487
- description: 'Test event',
488
- },
489
- meta: null,
490
- };
491
- this.previewEvent$.next({ start: slot.start, end: slot.end });
492
- }
493
- randomColor() {
494
- const brightness = 128;
495
- return '#' + this.randomChannel(brightness) + this.randomChannel(brightness) + this.randomChannel(brightness);
496
- }
497
- randomChannel(brightness) {
498
- const r = 255 - brightness;
499
- const n = 0 | ((Math.random() * r) + brightness);
500
- const s = n.toString(16);
501
- return (s.length == 1) ? '0' + s : s;
502
- }
503
- onStartDragEvent(eventPart, ev) {
504
- ev.preventDefault();
505
- this.hoveredTimeSlot$.pipe(take(1), takeUntilDestroyed(this.destroy)).subscribe((hoveredTimeSlot) => {
506
- if (eventPart.event) {
507
- this.dragStartTimeslot = hoveredTimeSlot;
508
- this.operation = {
509
- operation: EDragOperation.moveEvent,
510
- event: eventPart.event,
511
- meta: null,
512
- };
513
- this.previewEvent$.next({ start: eventPart.event.start, end: eventPart.event.end });
514
- }
119
+ addListener('event-create', (e) => {
120
+ this.eventCreate.emit(e.detail);
515
121
  });
516
- }
517
- onStartResizeEvent(event, position) {
518
- if (event) {
519
- switch (position) {
520
- case 'top':
521
- {
522
- this.operation = {
523
- operation: EDragOperation.resizeEvent,
524
- event: event,
525
- meta: { position },
526
- };
527
- this.previewEvent$.next({ start: event.start, end: event.end });
528
- }
529
- break;
530
- case 'bottom':
531
- {
532
- this.operation = {
533
- operation: EDragOperation.resizeEvent,
534
- event: event,
535
- meta: { position },
536
- };
537
- this.previewEvent$.next({ start: event.start, end: event.end });
538
- }
539
- break;
540
- }
541
- }
542
- }
543
- //#region hoveredTimeslot$
544
- getHoveredTimeslot(ev, timeSlots) {
545
- const hoveredSlots = this.timeSlotElements.filter((el) => {
546
- const rct = el.nativeElement.getBoundingClientRect();
547
- if (rct.left <= ev.x && ev.x <= rct.right && rct.top <= ev.y && ev.y <= rct.bottom) {
548
- return true;
549
- }
550
- else {
551
- return false;
552
- }
122
+ addListener('event-update', (e) => {
123
+ this.eventUpdate.emit(e.detail);
553
124
  });
554
- if (!hoveredSlots || hoveredSlots.length === 0) {
555
- return null;
556
- }
557
- const slotElement = hoveredSlots[0].nativeElement;
558
- const strRow = slotElement.getAttribute('data-row');
559
- if (!strRow) {
560
- return null;
561
- }
562
- const row = parseInt(strRow);
563
- const strColumn = slotElement.getAttribute('data-column');
564
- if (!strColumn) {
565
- return null;
566
- }
567
- const column = parseInt(strColumn);
568
- const slot = timeSlots[row].slots[column];
569
- return slot;
570
- }
571
- onMousemove(ev) {
572
- this.timeSlots$.pipe(take(1), takeUntilDestroyed(this.destroy)).subscribe((timeSlots) => {
573
- const hovered = this.getHoveredTimeslot(ev, timeSlots);
574
- this.hoveredTimeSlot$.next(hovered);
575
- if (this.operation) {
576
- switch (this.operation.operation) {
577
- case EDragOperation.createEvent:
578
- {
579
- if (this.operation.event && this.dragStartTimeslot && hovered && (this.operation.event.end.getTime() != hovered.end.getTime())) {
580
- if (this.dragStartTimeslot.start.getTime() === hovered.start.getTime()) {
581
- // 1 slot
582
- }
583
- else if (this.dragStartTimeslot.start.getTime() < hovered.start.getTime()) {
584
- // Drag down
585
- this.previewEvent$
586
- .pipe(filter((ev) => !!ev && !!this.dragStartTimeslot))
587
- .pipe(map((ev) => {
588
- if (ev && this.dragStartTimeslot) {
589
- ev.start = this.dragStartTimeslot.start;
590
- ev.end = hovered.end;
591
- }
592
- return ev;
593
- }))
594
- .pipe(take(1), takeUntilDestroyed(this.destroy))
595
- .subscribe((ev) => this.previewEvent$.next(ev));
596
- }
597
- else if (this.dragStartTimeslot.start.getTime() > hovered.start.getTime()) {
598
- // Drag up
599
- this.previewEvent$
600
- .pipe(filter((ev) => !!ev && !!this.dragStartTimeslot))
601
- .pipe(map((ev) => {
602
- if (ev && this.dragStartTimeslot) {
603
- ev.start = hovered.start;
604
- ev.end = this.dragStartTimeslot.end;
605
- }
606
- return ev;
607
- }))
608
- .pipe(take(1), takeUntilDestroyed(this.destroy))
609
- .subscribe((ev) => this.previewEvent$.next(ev));
610
- }
611
- }
612
- }
613
- break;
614
- case EDragOperation.moveEvent:
615
- {
616
- if (hovered && this.dragStartTimeslot) {
617
- this.previewEvent$
618
- .pipe(filter((ev) => !!ev && !!this.dragStartTimeslot))
619
- .pipe(map((ev) => {
620
- if (ev && this.dragStartTimeslot) {
621
- const result = {
622
- start: new Date(ev.start.getTime() + hovered.start.getTime() - this.dragStartTimeslot.start.getTime()),
623
- end: new Date(ev.end.getTime() + hovered.start.getTime() - this.dragStartTimeslot.start.getTime())
624
- };
625
- this.dragStartTimeslot = hovered;
626
- return result;
627
- }
628
- else {
629
- return ev;
630
- }
631
- }))
632
- .pipe(take(1), takeUntilDestroyed(this.destroy))
633
- .subscribe(ev => this.previewEvent$.next(ev));
634
- }
635
- }
636
- break;
637
- case EDragOperation.resizeEvent:
638
- {
639
- if (hovered) {
640
- this.previewEvent$
641
- .pipe(filter((ev) => !!ev))
642
- .pipe(map((ev) => {
643
- if (ev && this.operation && this.operation.event) {
644
- if (this.operation.meta.position === 'top') {
645
- ev.start = hovered.start;
646
- ev.end = this.operation.event.end;
647
- }
648
- else if (this.operation.meta.position === 'bottom') {
649
- ev.start = this.operation.event.start;
650
- ev.end = hovered.end;
651
- }
652
- }
653
- return ev;
654
- }))
655
- .pipe(take(1), takeUntilDestroyed(this.destroy))
656
- .subscribe((ev) => this.previewEvent$.next(ev));
657
- }
658
- }
659
- break;
660
- }
661
- }
125
+ addListener('event-delete', (e) => {
126
+ this.eventDelete.emit(e.detail);
127
+ });
128
+ addListener('date-click', (e) => {
129
+ this.dateClick.emit(e.detail);
130
+ });
131
+ addListener('date-select', (e) => {
132
+ this.dateSelect.emit(e.detail);
133
+ this.selectedRange.set({ start: e.detail.start, end: e.detail.end });
134
+ });
135
+ addListener('view-change', (e) => {
136
+ this.viewChange.emit(e.detail);
137
+ });
138
+ addListener('selection-change', (e) => {
139
+ this.selectedEvent.set(e.detail.selectedEvent);
662
140
  });
663
141
  }
664
- //#endregion
665
- onMouseUp(ev) {
666
- if (this.operation) {
667
- switch (this.operation.operation) {
668
- case EDragOperation.createEvent:
669
- {
670
- combineLatest([this.previewEvent$])
671
- .pipe(take(1), takeUntilDestroyed(this.destroy))
672
- .subscribe(([previewEvent]) => {
673
- if (previewEvent) {
674
- this.operation = null;
675
- this.dragStartTimeslot = null;
676
- this.resources$.next([
677
- ...this.resources$.value,
678
- {
679
- description: 'New resource group',
680
- events: [{
681
- start: previewEvent.start,
682
- end: previewEvent.end,
683
- color: this.randomColor(),
684
- description: 'New event'
685
- }]
686
- }
687
- ]);
688
- this.previewEvent$.next(null);
689
- }
690
- });
691
- }
692
- break;
693
- case EDragOperation.moveEvent:
694
- case EDragOperation.resizeEvent:
695
- {
696
- this.previewEvent$
697
- .pipe(filter((ev) => !!ev))
698
- .pipe(take(1), takeUntilDestroyed(this.destroy))
699
- .subscribe((previewEvent) => {
700
- if (this.operation && this.operation.event && previewEvent) {
701
- this.operation.event.start = previewEvent.start;
702
- this.operation.event.end = previewEvent.end;
703
- this.operation = null;
704
- this.dragStartTimeslot = null;
705
- this.resources$.next(this.resources$.value);
706
- this.previewEvent$.next(null);
707
- }
708
- });
709
- }
710
- break;
711
- }
142
+ removeEventListeners() {
143
+ const el = this.schedulerRef?.nativeElement;
144
+ if (!el)
145
+ return;
146
+ for (const { type, listener } of this.eventListeners) {
147
+ el.removeEventListener(type, listener);
712
148
  }
713
- }
714
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerComponent, deps: [{ token: i1.DomSanitizer }, { token: i2.BsCalendarMonthService }, { token: BsTimelineService }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
715
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: BsSchedulerComponent, isStandalone: false, selector: "bs-scheduler", inputs: { mode: "mode", weekOptions: "weekOptions", timelineOptions: "timelineOptions", maxInnerHeight: "maxInnerHeight", resources: "resources" }, outputs: { modeChange: "modeChange", weekOptionsChange: "weekOptionsChange", timelineOptionsChange: "timelineOptionsChange" }, host: { listeners: { "document:mousemove": "onMousemove($event)", "document:mouseup": "onMouseUp($event)" } }, viewQueries: [{ propertyName: "timeSlotElements", predicate: ["slot"], descendants: true }], ngImport: i0, template: "@switch (mode$ | async) {\n @case (modes.week) {\n <div class=\"d-flex flex-column w-100 overflow-y-auto mb-0 week-schedule\" [style.max-height.px]=\"null\">\n <div class=\"calendar-head\">\n <div class=\"w-100 d-flex flex-row\">\n <div class=\"d-flex calendar-left justify-content-between\">\n <button class=\"btn btn-default flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n <span [innerHTML]=\"chevronLeft\" class=\"px-0\"></span>\n </button>\n <button class=\"btn btn-default flex-end\" (click)=\"onNextWeekOrMonth()\">\n <span [innerHTML]=\"chevronRight\" class=\"px-0\"></span>\n </button>\n </div>\n @for (day of (shownDays$ | async); track day) {\n <div class=\"flex-grow-1 calendar-head-cell\">\n <span class=\"d-block col-form-label text-center text-nowrap\">\n <span>{{ day | date: 'dd-MM' }}</span><span class=\"d-none d-lg-inline-block\">-{{ day | date: 'yyyy' }}</span>\n </span>\n </div>\n }\n </div>\n </div>\n <div class=\"calendar-body\" [style.height.px]=\"maxInnerHeight\">\n @if (timeSlots$ | async; as row) {\n <div class=\"position-relative\">\n @if (weekOptions$ | async; as weekOptions) {\n <!-- Timeslots -->\n @for (timeslots of row; track timeslots; let i = $index) {\n <div class=\"d-flex flex-row p-0 timeslot\" [style.height.px]=\"weekOptions.unitHeight\">\n <div class=\"calendar-cell calendar-left align-top px-2 py-0\">{{ timeslots.slots[0].start | date: 'HH:mm:ss' }}</div>\n @for (slot of timeslots.slots; track slot.start; let j = $index) {\n <div class=\"calendar-cell flex-grow-1\" #slot (mousedown)=\"onCreateEvent($event, slot)\" [attr.data-row]=\"i\" [attr.data-column]=\"j\"></div>\n }\n </div>\n }\n \n <!-- Events -->\n @if (timeSlotDuration$ | async; as timeSlotDuration) {\n @if (timelinedEventPartsForThisWeek$ | async; as partData) {\n @for (eventPart of partData.parts; track eventPart) {\n <div class=\"event p-0\"\n [style.top.px]=\"(eventPart.part | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart.part | dayOfWeek) - 1) + '))'\">\n <div class=\"event-inner\" [class.hover]=\"(hoveredEvent$ | async) === eventPart.part.event\"\n [style.width]=\"'calc(100% / ' + partData.total + ')'\"\n [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n [style.margin-left]=\"'calc(100% / ' + partData.total + ' * ' + eventPart.index + ')'\">\n \n @if (eventPart.part.start === eventPart.part.event?.start) {\n <div class=\"event-resize top\" (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'top')\"></div>\n }\n <div class=\"event-border\"></div>\n @if (eventPart.part.event) {\n <div class=\"event-wrapper\"\n (mousedown)=\"onStartDragEvent(eventPart.part, $event)\"\n (mouseenter)=\"onHoverEvent(eventPart.part.event)\"\n (mouseleave)=\"onLeaveEvent(eventPart.part.event)\">\n <div class=\"event-bg\" [style.background-color]=\"eventPart.part.event.color\"></div>\n <div class=\"event-label\">{{ eventPart.part.event.description }}</div>\n </div>\n }\n @if (eventPart.part.end === eventPart.part.event?.end) {\n <div class=\"event-resize bottom\" (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'bottom')\"></div>\n }\n </div>\n </div>\n }\n }\n @if (previewEventPartsForThisWeek$ | async; as previewPartData) {\n @for (eventPart of previewPartData; track eventPart) {\n <div class=\"event preview p-0\"\n [style.top.px]=\"(eventPart | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart | dayOfWeek) - 1) + '))'\">\n <div class=\"event-inner w-100\"\n [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\">\n </div>\n </div>\n }\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @case (modes.timeline) {\n <div class=\"d-flex flex-column-100 overflow-y-auto mb-0 bg-white timeline\">\n <div class=\"calendar-head d-flex\">\n <button class=\"btn flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n <span [innerHTML]=\"chevronLeft\" class=\"px-0\"></span>\n </button>\n <div class=\"flex-grow-1 h3 py-2 mb-0 text-center\">{{ currentWeekOrMonth$ | async | date: 'MMMM yyyy' }}</div>\n <button class=\"btn flex-start\" (click)=\"onNextWeekOrMonth()\">\n <span [innerHTML]=\"chevronRight\" class=\"px-0\"></span>\n </button>\n </div>\n \n <div class=\"calendar-body table-responsive overflow-x-auto\">\n <table class=\"table mb-0\">\n @if (timeSlots$ | async; as timeSlots) {\n <tr>\n <td></td>\n @for (day of timeSlots; track day) {\n <td [attr.colspan]=\"day.slots.length\" class=\"text-center px-2\">\n <span class=\"position-sticky day-label\">{{ day.stamp | date: 'd EE' }}</span>\n </td>\n }\n </tr>\n <tr>\n <td></td>\n @if (timelineOptions$ | async; as timelineOptions) {\n @for (day of timeSlots; track day) {\n @for (slot of day.slots; track slot) {\n <td>\n <span class=\"d-block p-0 text-center\" [style.width.px]=\"timelineOptions.unitWidth\">\n {{ slot.start | date: 'HH:mm' }}\n </span>\n </td>\n }\n }\n }\n </tr>\n @for (group of (resources$ | async); track group) {\n <bs-resource-group-presenter [resourceGroup]=\"group\" [timeSlots]=\"timeSlots\"></bs-resource-group-presenter>\n }\n }\n </table>\n </div>\n </div>\n }\n}", styles: [":host{display:block;border:1px solid #333;border-top-right-radius:10px;border-top-left-radius:10px;overflow:hidden}.calendar-head{background:#f7f7f7;color:#007aff}.tabel .calendar-head{flex:0 0 auto}.tabel .calendar-body{display:block;flex:1 1 auto}.week-schedule .calendar-head>div{padding-right:18px}.week-schedule .calendar-body{overflow-y:scroll;overflow-x:hidden}.week-schedule .calendar-body .calendar-cell{border-right:1px solid #DEE2E6;border-bottom:1px solid #DEE2E6;cursor:default}.week-schedule .calendar-body .calendar-cell.hover{border-top-width:3px}.week-schedule .calendar-left{width:90px}.week-schedule .event{z-index:5;width:calc((100% - 90px) / 7);height:100px;overflow:hidden;position:absolute;-webkit-user-select:none;user-select:none;pointer-events:none}.week-schedule .event.preview{background:#666;opacity:.6}.week-schedule .event .event-border{background:#000;top:0;left:0;bottom:3px;width:3px;position:absolute;z-index:10;opacity:.3}.week-schedule .event .event-inner{position:relative;inset:0 5px 5px 0;cursor:move;pointer-events:all;overflow:hidden}.week-schedule .event .event-inner .event-wrapper{width:calc(100% - 2px);margin:1px auto 1px 0;height:calc(100% - 3px)}.week-schedule .event .event-inner .event-wrapper .event-bg{opacity:.5;height:100%;transition:opacity .15s ease-in-out}.week-schedule .event .event-inner .event-wrapper .event-label{position:absolute;top:0;font-size:12px;font-weight:600;padding:4px}.week-schedule .event .event-inner .event-resize{position:absolute;cursor:ns-resize;height:4px;left:0;right:0;z-index:400}.week-schedule .event .event-inner .event-resize.top{top:0}.week-schedule .event .event-inner .event-resize.bottom{bottom:0}.week-schedule .event .event-inner .event-resize:hover{background:#ddd}.week-schedule .event .event-inner.hover .event-bg{opacity:.7!important}@media(max-width:767px){.week-schedule.tabel .calendar-head .calendar-head-cell{text-orientation:sideways;writing-mode:vertical-rl}}.timeline.tabel{flex-flow:column}.timeline .calendar-body .tabel{background-color:#f7f7f7}.timeline .calendar-body .tabel tr:first-child td{background-color:#fff;border:1px solid #000}.timeline .calendar-body .tabel tr:first-child td:first-child{min-width:10rem}.timeline .calendar-body .tabel tr:first-child span.day-label{left:0;right:0}.timeline .calendar-body .tabel tr:nth-child(2) td{border-width:1px;border-color:inherit}.timeline .calendar-body .tabel>:not(:first-child){border-top:none!important}\n"], dependencies: [{ kind: "component", type: ResourceGroupPresenterComponent, selector: "bs-resource-group-presenter", inputs: ["level", "resourceGroup", "timeSlots", "isExpanded"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.DatePipe, name: "date" }, { kind: "pipe", type: BsSecondsTimespanPipe, name: "bsSecondsTimespan" }, { kind: "pipe", type: BsSecondsTodayOffsetPipe, name: "bsSecondsTodayOffset" }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }] }); }
149
+ this.eventListeners = [];
150
+ }
151
+ // Public API methods (delegate to web component)
152
+ /**
153
+ * Navigate to next period
154
+ */
155
+ next() {
156
+ this.schedulerRef?.nativeElement?.next();
157
+ }
158
+ /**
159
+ * Navigate to previous period
160
+ */
161
+ prev() {
162
+ this.schedulerRef?.nativeElement?.prev();
163
+ }
164
+ /**
165
+ * Navigate to today
166
+ */
167
+ today() {
168
+ this.schedulerRef?.nativeElement?.today();
169
+ }
170
+ /**
171
+ * Navigate to a specific date
172
+ */
173
+ gotoDate(date) {
174
+ this.schedulerRef?.nativeElement?.gotoDate(date);
175
+ }
176
+ /**
177
+ * Change the current view
178
+ */
179
+ changeView(view) {
180
+ this.schedulerRef?.nativeElement?.changeView(view);
181
+ }
182
+ /**
183
+ * Add an event
184
+ */
185
+ addEvent(event) {
186
+ this.schedulerRef?.nativeElement?.addEvent(event);
187
+ }
188
+ /**
189
+ * Update an event
190
+ */
191
+ updateEvent(event) {
192
+ this.schedulerRef?.nativeElement?.updateEvent(event);
193
+ }
194
+ /**
195
+ * Remove an event
196
+ */
197
+ removeEvent(eventId) {
198
+ this.schedulerRef?.nativeElement?.removeEvent(eventId);
199
+ }
200
+ /**
201
+ * Get an event by ID
202
+ */
203
+ getEventById(eventId) {
204
+ return this.schedulerRef?.nativeElement?.getEventById(eventId) ?? null;
205
+ }
206
+ /**
207
+ * Refetch/refresh events
208
+ */
209
+ refetchEvents() {
210
+ this.schedulerRef?.nativeElement?.refetchEvents();
211
+ }
212
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
213
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: BsSchedulerComponent, isStandalone: true, selector: "bs-scheduler", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, date: { classPropertyName: "date", publicName: "date", isSignal: true, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, resources: { classPropertyName: "resources", publicName: "resources", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, selectedEvent: { classPropertyName: "selectedEvent", publicName: "selectedEvent", isSignal: true, isRequired: false, transformFunction: null }, selectedRange: { classPropertyName: "selectedRange", publicName: "selectedRange", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedEvent: "selectedEventChange", selectedRange: "selectedRangeChange", eventClick: "eventClick", eventDblClick: "eventDblClick", eventCreate: "eventCreate", eventUpdate: "eventUpdate", eventDelete: "eventDelete", dateClick: "dateClick", dateSelect: "dateSelect", viewChange: "viewChange" }, viewQueries: [{ propertyName: "schedulerRef", first: true, predicate: ["scheduler"], descendants: true, static: true }], ngImport: i0, template: `<mp-scheduler #scheduler></mp-scheduler>`, isInline: true, styles: [":host{display:block;height:100%}mp-scheduler{display:block;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
716
214
  }
717
215
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerComponent, decorators: [{
718
216
  type: Component,
719
- args: [{ selector: 'bs-scheduler', standalone: false, template: "@switch (mode$ | async) {\n @case (modes.week) {\n <div class=\"d-flex flex-column w-100 overflow-y-auto mb-0 week-schedule\" [style.max-height.px]=\"null\">\n <div class=\"calendar-head\">\n <div class=\"w-100 d-flex flex-row\">\n <div class=\"d-flex calendar-left justify-content-between\">\n <button class=\"btn btn-default flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n <span [innerHTML]=\"chevronLeft\" class=\"px-0\"></span>\n </button>\n <button class=\"btn btn-default flex-end\" (click)=\"onNextWeekOrMonth()\">\n <span [innerHTML]=\"chevronRight\" class=\"px-0\"></span>\n </button>\n </div>\n @for (day of (shownDays$ | async); track day) {\n <div class=\"flex-grow-1 calendar-head-cell\">\n <span class=\"d-block col-form-label text-center text-nowrap\">\n <span>{{ day | date: 'dd-MM' }}</span><span class=\"d-none d-lg-inline-block\">-{{ day | date: 'yyyy' }}</span>\n </span>\n </div>\n }\n </div>\n </div>\n <div class=\"calendar-body\" [style.height.px]=\"maxInnerHeight\">\n @if (timeSlots$ | async; as row) {\n <div class=\"position-relative\">\n @if (weekOptions$ | async; as weekOptions) {\n <!-- Timeslots -->\n @for (timeslots of row; track timeslots; let i = $index) {\n <div class=\"d-flex flex-row p-0 timeslot\" [style.height.px]=\"weekOptions.unitHeight\">\n <div class=\"calendar-cell calendar-left align-top px-2 py-0\">{{ timeslots.slots[0].start | date: 'HH:mm:ss' }}</div>\n @for (slot of timeslots.slots; track slot.start; let j = $index) {\n <div class=\"calendar-cell flex-grow-1\" #slot (mousedown)=\"onCreateEvent($event, slot)\" [attr.data-row]=\"i\" [attr.data-column]=\"j\"></div>\n }\n </div>\n }\n \n <!-- Events -->\n @if (timeSlotDuration$ | async; as timeSlotDuration) {\n @if (timelinedEventPartsForThisWeek$ | async; as partData) {\n @for (eventPart of partData.parts; track eventPart) {\n <div class=\"event p-0\"\n [style.top.px]=\"(eventPart.part | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart.part | dayOfWeek) - 1) + '))'\">\n <div class=\"event-inner\" [class.hover]=\"(hoveredEvent$ | async) === eventPart.part.event\"\n [style.width]=\"'calc(100% / ' + partData.total + ')'\"\n [style.height.px]=\"(eventPart.part | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n [style.margin-left]=\"'calc(100% / ' + partData.total + ' * ' + eventPart.index + ')'\">\n \n @if (eventPart.part.start === eventPart.part.event?.start) {\n <div class=\"event-resize top\" (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'top')\"></div>\n }\n <div class=\"event-border\"></div>\n @if (eventPart.part.event) {\n <div class=\"event-wrapper\"\n (mousedown)=\"onStartDragEvent(eventPart.part, $event)\"\n (mouseenter)=\"onHoverEvent(eventPart.part.event)\"\n (mouseleave)=\"onLeaveEvent(eventPart.part.event)\">\n <div class=\"event-bg\" [style.background-color]=\"eventPart.part.event.color\"></div>\n <div class=\"event-label\">{{ eventPart.part.event.description }}</div>\n </div>\n }\n @if (eventPart.part.end === eventPart.part.event?.end) {\n <div class=\"event-resize bottom\" (mousedown)=\"onStartResizeEvent(eventPart.part.event, 'bottom')\"></div>\n }\n </div>\n </div>\n }\n }\n @if (previewEventPartsForThisWeek$ | async; as previewPartData) {\n @for (eventPart of previewPartData; track eventPart) {\n <div class=\"event preview p-0\"\n [style.top.px]=\"(eventPart | bsSecondsTodayOffset) / timeSlotDuration * weekOptions.unitHeight\"\n [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\"\n [style.left]=\"'calc(90px + ((100% - 90px) / 7 * ' + ((eventPart | dayOfWeek) - 1) + '))'\">\n <div class=\"event-inner w-100\"\n [style.height.px]=\"(eventPart | bsSecondsTimespan) / timeSlotDuration * weekOptions.unitHeight\">\n </div>\n </div>\n }\n }\n }\n }\n </div>\n }\n </div>\n </div>\n }\n @case (modes.timeline) {\n <div class=\"d-flex flex-column-100 overflow-y-auto mb-0 bg-white timeline\">\n <div class=\"calendar-head d-flex\">\n <button class=\"btn flex-start\" (click)=\"onPreviousWeekOrMonth()\">\n <span [innerHTML]=\"chevronLeft\" class=\"px-0\"></span>\n </button>\n <div class=\"flex-grow-1 h3 py-2 mb-0 text-center\">{{ currentWeekOrMonth$ | async | date: 'MMMM yyyy' }}</div>\n <button class=\"btn flex-start\" (click)=\"onNextWeekOrMonth()\">\n <span [innerHTML]=\"chevronRight\" class=\"px-0\"></span>\n </button>\n </div>\n \n <div class=\"calendar-body table-responsive overflow-x-auto\">\n <table class=\"table mb-0\">\n @if (timeSlots$ | async; as timeSlots) {\n <tr>\n <td></td>\n @for (day of timeSlots; track day) {\n <td [attr.colspan]=\"day.slots.length\" class=\"text-center px-2\">\n <span class=\"position-sticky day-label\">{{ day.stamp | date: 'd EE' }}</span>\n </td>\n }\n </tr>\n <tr>\n <td></td>\n @if (timelineOptions$ | async; as timelineOptions) {\n @for (day of timeSlots; track day) {\n @for (slot of day.slots; track slot) {\n <td>\n <span class=\"d-block p-0 text-center\" [style.width.px]=\"timelineOptions.unitWidth\">\n {{ slot.start | date: 'HH:mm' }}\n </span>\n </td>\n }\n }\n }\n </tr>\n @for (group of (resources$ | async); track group) {\n <bs-resource-group-presenter [resourceGroup]=\"group\" [timeSlots]=\"timeSlots\"></bs-resource-group-presenter>\n }\n }\n </table>\n </div>\n </div>\n }\n}", styles: [":host{display:block;border:1px solid #333;border-top-right-radius:10px;border-top-left-radius:10px;overflow:hidden}.calendar-head{background:#f7f7f7;color:#007aff}.tabel .calendar-head{flex:0 0 auto}.tabel .calendar-body{display:block;flex:1 1 auto}.week-schedule .calendar-head>div{padding-right:18px}.week-schedule .calendar-body{overflow-y:scroll;overflow-x:hidden}.week-schedule .calendar-body .calendar-cell{border-right:1px solid #DEE2E6;border-bottom:1px solid #DEE2E6;cursor:default}.week-schedule .calendar-body .calendar-cell.hover{border-top-width:3px}.week-schedule .calendar-left{width:90px}.week-schedule .event{z-index:5;width:calc((100% - 90px) / 7);height:100px;overflow:hidden;position:absolute;-webkit-user-select:none;user-select:none;pointer-events:none}.week-schedule .event.preview{background:#666;opacity:.6}.week-schedule .event .event-border{background:#000;top:0;left:0;bottom:3px;width:3px;position:absolute;z-index:10;opacity:.3}.week-schedule .event .event-inner{position:relative;inset:0 5px 5px 0;cursor:move;pointer-events:all;overflow:hidden}.week-schedule .event .event-inner .event-wrapper{width:calc(100% - 2px);margin:1px auto 1px 0;height:calc(100% - 3px)}.week-schedule .event .event-inner .event-wrapper .event-bg{opacity:.5;height:100%;transition:opacity .15s ease-in-out}.week-schedule .event .event-inner .event-wrapper .event-label{position:absolute;top:0;font-size:12px;font-weight:600;padding:4px}.week-schedule .event .event-inner .event-resize{position:absolute;cursor:ns-resize;height:4px;left:0;right:0;z-index:400}.week-schedule .event .event-inner .event-resize.top{top:0}.week-schedule .event .event-inner .event-resize.bottom{bottom:0}.week-schedule .event .event-inner .event-resize:hover{background:#ddd}.week-schedule .event .event-inner.hover .event-bg{opacity:.7!important}@media(max-width:767px){.week-schedule.tabel .calendar-head .calendar-head-cell{text-orientation:sideways;writing-mode:vertical-rl}}.timeline.tabel{flex-flow:column}.timeline .calendar-body .tabel{background-color:#f7f7f7}.timeline .calendar-body .tabel tr:first-child td{background-color:#fff;border:1px solid #000}.timeline .calendar-body .tabel tr:first-child td:first-child{min-width:10rem}.timeline .calendar-body .tabel tr:first-child span.day-label{left:0;right:0}.timeline .calendar-body .tabel tr:nth-child(2) td{border-width:1px;border-color:inherit}.timeline .calendar-body .tabel>:not(:first-child){border-top:none!important}\n"] }]
720
- }], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i2.BsCalendarMonthService }, { type: BsTimelineService }, { type: i0.DestroyRef }], propDecorators: { timeSlotElements: [{
721
- type: ViewChildren,
722
- args: ['slot']
723
- }], modeChange: [{
724
- type: Output
725
- }], mode: [{
726
- type: Input
727
- }], weekOptionsChange: [{
728
- type: Output
729
- }], weekOptions: [{
730
- type: Input
731
- }], timelineOptionsChange: [{
732
- type: Output
733
- }], timelineOptions: [{
734
- type: Input
735
- }], maxInnerHeight: [{
736
- type: Input
737
- }], resources: [{
738
- type: Input
739
- }], onMousemove: [{
740
- type: HostListener,
741
- args: ['document:mousemove', ['$event']]
742
- }], onMouseUp: [{
743
- type: HostListener,
744
- args: ['document:mouseup', ['$event']]
745
- }] } });
746
-
747
- const availableScales = [
748
- { time: 60, pixels: 60, markerSize: 900 }, // 60s / 60px = 1 s/px = 1 min / 60 px
749
- { time: 120, pixels: 60, markerSize: 900 }, // 120s / 60px = 2 s/px = 2 min / 60 px
750
- { time: 300, pixels: 60, markerSize: 900 }, // 180s / 60px = 3 s/px = 5 min / 60 px
751
- { time: 900, pixels: 60, markerSize: 900 }, // 360s / 60px = 6 s/px = 15 min / 60 px
752
- { time: 3600, pixels: 60, markerSize: 21600 }, // 600s / 60px = 10 s/px = 1 u / 60 px
753
- { time: 7200, pixels: 60, markerSize: 21600 }, // 1200s / 60px = 20 s/px
754
- { time: 10800, pixels: 60, markerSize: 21600 }, // 1800s / 60px = 30 s/px
755
- { time: 21600, pixels: 60, markerSize: 21600 }, // 3600s / 60px = 60 s/px
756
- { time: 86400, pixels: 60, markerSize: 604800 }, // 6000s / 60px = 100 s/px
757
- ];
758
-
759
- class DateOffsetPipe {
760
- transform(value) {
761
- const today = new Date(value.start);
762
- today.setHours(0);
763
- today.setMinutes(0);
764
- today.setSeconds(0);
765
- return (value.start.getTime() - today.getTime()) / 1000;
766
- }
767
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DateOffsetPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
768
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: DateOffsetPipe, isStandalone: false, name: "dateOffset" }); }
769
- }
770
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DateOffsetPipe, decorators: [{
771
- type: Pipe,
772
- args: [{
773
- name: 'dateOffset',
774
- standalone: false,
775
- }]
776
- }] });
217
+ args: [{ selector: 'bs-scheduler', standalone: true, template: `<mp-scheduler #scheduler></mp-scheduler>`, changeDetection: ChangeDetectionStrategy.OnPush, schemas: [CUSTOM_ELEMENTS_SCHEMA], styles: [":host{display:block;height:100%}mp-scheduler{display:block;height:100%}\n"] }]
218
+ }], propDecorators: { schedulerRef: [{
219
+ type: ViewChild,
220
+ args: ['scheduler', { static: true }]
221
+ }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }], date: [{ type: i0.Input, args: [{ isSignal: true, alias: "date", required: false }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], resources: [{ type: i0.Input, args: [{ isSignal: true, alias: "resources", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], selectedEvent: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedEvent", required: false }] }, { type: i0.Output, args: ["selectedEventChange"] }], selectedRange: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedRange", required: false }] }, { type: i0.Output, args: ["selectedRangeChange"] }], eventClick: [{ type: i0.Output, args: ["eventClick"] }], eventDblClick: [{ type: i0.Output, args: ["eventDblClick"] }], eventCreate: [{ type: i0.Output, args: ["eventCreate"] }], eventUpdate: [{ type: i0.Output, args: ["eventUpdate"] }], eventDelete: [{ type: i0.Output, args: ["eventDelete"] }], dateClick: [{ type: i0.Output, args: ["dateClick"] }], dateSelect: [{ type: i0.Output, args: ["dateSelect"] }], viewChange: [{ type: i0.Output, args: ["viewChange"] }] } });
777
222
 
778
223
  class BsSchedulerModule {
779
224
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
780
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerModule, declarations: [BsSchedulerComponent,
781
- BsSecondsTimespanPipe,
782
- BsSecondsTodayOffsetPipe,
783
- DateOffsetPipe,
784
- DayOfWeekPipe,
785
- ResourceGroupPresenterComponent], imports: [CommonModule], exports: [BsSchedulerComponent,
786
- ResourceGroupPresenterComponent] }); }
787
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerModule, imports: [CommonModule] }); }
225
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerModule, imports: [BsSchedulerComponent], exports: [BsSchedulerComponent] }); }
226
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerModule }); }
788
227
  }
789
228
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BsSchedulerModule, decorators: [{
790
229
  type: NgModule,
791
230
  args: [{
792
- declarations: [
793
- BsSchedulerComponent,
794
- BsSecondsTimespanPipe,
795
- BsSecondsTodayOffsetPipe,
796
- DateOffsetPipe,
797
- DayOfWeekPipe,
798
- ResourceGroupPresenterComponent
799
- ],
800
- imports: [
801
- CommonModule,
802
- ],
803
- exports: [
804
- BsSchedulerComponent,
805
- ResourceGroupPresenterComponent
806
- ]
231
+ imports: [BsSchedulerComponent],
232
+ exports: [BsSchedulerComponent],
807
233
  }]
808
234
  }] });
809
235
 
@@ -811,5 +237,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
811
237
  * Generated bundle index. Do not edit.
812
238
  */
813
239
 
814
- export { BsSchedulerComponent, BsSchedulerModule, ESchedulerMode, ResourceGroupPresenterComponent, availableScales };
240
+ export { BsSchedulerComponent, BsSchedulerModule };
815
241
  //# sourceMappingURL=mintplayer-ng-bootstrap-scheduler.mjs.map