nodebb-plugin-calendar-onekite 11.2.19 → 11.2.21
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.
- package/package.json +1 -1
- package/public/client.js +68 -15
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -95,11 +95,15 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
95
95
|
|
|
96
96
|
async function openSpecialEventDialog(selectionInfo) {
|
|
97
97
|
const start = selectionInfo.start;
|
|
98
|
+
// FullCalendar can omit `end` for certain interactions. Also, for all-day
|
|
99
|
+
// selections, `end` is exclusive (next day at 00:00). We normalise below
|
|
100
|
+
// so a single-day click always defaults to a single-day range.
|
|
98
101
|
const end = selectionInfo.end;
|
|
99
102
|
|
|
100
103
|
// Prefer event times starting at 07:00 for day-clicks (all-day selections).
|
|
101
104
|
let seStart = new Date(start);
|
|
102
|
-
|
|
105
|
+
// If `end` is missing, start with the same day.
|
|
106
|
+
let seEnd = end ? new Date(end) : new Date(seStart);
|
|
103
107
|
|
|
104
108
|
const msSpan = seEnd.getTime() - seStart.getTime();
|
|
105
109
|
const isAllDaySelection = selectionInfo && (selectionInfo.allDay || (
|
|
@@ -107,19 +111,25 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
107
111
|
seEnd.getHours() === 0 && seEnd.getMinutes() === 0
|
|
108
112
|
));
|
|
109
113
|
|
|
110
|
-
|
|
114
|
+
// For all-day selections, the simplest robust check is:
|
|
115
|
+
// does (end - 1ms) fall on the same calendar day as start?
|
|
116
|
+
const endMinus1 = isAllDaySelection ? new Date(seEnd.getTime() - 1) : null;
|
|
117
|
+
const isSingleDayAllDay = isAllDaySelection && (!end || (endMinus1 && toDateInputValue(seStart) === toDateInputValue(endMinus1)));
|
|
111
118
|
|
|
112
119
|
if (isSingleDayAllDay) {
|
|
113
|
-
// Keep same day; default
|
|
120
|
+
// Keep same day; default to a "one day" block (07:00 → 07:00).
|
|
121
|
+
// We keep end date equal to start date in the modal. On submit,
|
|
122
|
+
// if end <= start we automatically roll end by +1 day.
|
|
114
123
|
seStart.setHours(7, 0, 0, 0);
|
|
115
124
|
seEnd = new Date(seStart);
|
|
116
|
-
seEnd.setHours(
|
|
125
|
+
seEnd.setHours(7, 0, 0, 0);
|
|
117
126
|
} else if (isAllDaySelection) {
|
|
118
|
-
// Multi-day all-day selection: start at 07:00 on first day, end at
|
|
127
|
+
// Multi-day all-day selection: start at 07:00 on first day, end at 07:00 on last day
|
|
128
|
+
// (end date shown is the last selected day; submit logic will roll if needed).
|
|
119
129
|
seStart.setHours(7, 0, 0, 0);
|
|
120
|
-
const lastDay = new Date(
|
|
130
|
+
const lastDay = endMinus1 ? new Date(endMinus1) : new Date(seEnd);
|
|
121
131
|
seEnd = new Date(lastDay);
|
|
122
|
-
seEnd.setHours(
|
|
132
|
+
seEnd.setHours(7, 0, 0, 0);
|
|
123
133
|
} else {
|
|
124
134
|
seStart = roundTo5Minutes(seStart);
|
|
125
135
|
seEnd = roundTo5Minutes(seEnd);
|
|
@@ -180,6 +190,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
180
190
|
`;
|
|
181
191
|
|
|
182
192
|
return await new Promise((resolve) => {
|
|
193
|
+
let resolved = false;
|
|
183
194
|
const dialog = bootbox.dialog({
|
|
184
195
|
title: 'Créer un évènement',
|
|
185
196
|
message: html,
|
|
@@ -187,7 +198,10 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
187
198
|
cancel: {
|
|
188
199
|
label: 'Annuler',
|
|
189
200
|
className: 'btn-secondary',
|
|
190
|
-
callback: () =>
|
|
201
|
+
callback: () => {
|
|
202
|
+
resolved = true;
|
|
203
|
+
resolve(null);
|
|
204
|
+
},
|
|
191
205
|
},
|
|
192
206
|
ok: {
|
|
193
207
|
label: 'Créer',
|
|
@@ -198,12 +212,35 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
198
212
|
const st = (document.getElementById('onekite-se-start-time')?.value || '').trim();
|
|
199
213
|
const ed = (document.getElementById('onekite-se-end-date')?.value || '').trim();
|
|
200
214
|
const et = (document.getElementById('onekite-se-end-time')?.value || '').trim();
|
|
201
|
-
|
|
202
|
-
|
|
215
|
+
// If the user keeps the same day but chooses an end time earlier than
|
|
216
|
+
// (or equal to) the start time (default 07:00 → 07:00), interpret
|
|
217
|
+
// it as an overnight/24h range and roll the end date by +1 day.
|
|
218
|
+
let startVal = '';
|
|
219
|
+
let endVal = '';
|
|
220
|
+
try {
|
|
221
|
+
if (sd && st) {
|
|
222
|
+
const startDt = new Date(`${sd}T${st}`);
|
|
223
|
+
startVal = startDt.toISOString();
|
|
224
|
+
if (ed && et) {
|
|
225
|
+
let endDt = new Date(`${ed}T${et}`);
|
|
226
|
+
if (!isNaN(startDt) && !isNaN(endDt) && endDt.getTime() <= startDt.getTime()) {
|
|
227
|
+
// Only auto-roll when user kept the same end date.
|
|
228
|
+
if (ed === sd) {
|
|
229
|
+
endDt = new Date(endDt.getTime() + 24 * 60 * 60 * 1000);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
endVal = endDt.toISOString();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
} catch (e) {
|
|
236
|
+
startVal = (sd && st) ? buildLocalIso(sd, st) : '';
|
|
237
|
+
endVal = (ed && et) ? buildLocalIso(ed, et) : '';
|
|
238
|
+
}
|
|
203
239
|
const address = (document.getElementById('onekite-se-address')?.value || '').trim();
|
|
204
240
|
const notes = (document.getElementById('onekite-se-notes')?.value || '').trim();
|
|
205
241
|
const lat = (document.getElementById('onekite-se-lat')?.value || '').trim();
|
|
206
242
|
const lon = (document.getElementById('onekite-se-lon')?.value || '').trim();
|
|
243
|
+
resolved = true;
|
|
207
244
|
resolve({ title, start: startVal, end: endVal, address, notes, lat, lon });
|
|
208
245
|
return true;
|
|
209
246
|
},
|
|
@@ -211,6 +248,19 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
211
248
|
},
|
|
212
249
|
});
|
|
213
250
|
|
|
251
|
+
// If the modal is closed via ESC, backdrop click, or the "X" button,
|
|
252
|
+
// Bootbox does not trigger our cancel callback. Ensure we always resolve
|
|
253
|
+
// and release the global lock.
|
|
254
|
+
try {
|
|
255
|
+
dialog.on('hidden.bs.modal', () => {
|
|
256
|
+
if (resolved) return;
|
|
257
|
+
resolved = true;
|
|
258
|
+
resolve(null);
|
|
259
|
+
});
|
|
260
|
+
} catch (e) {
|
|
261
|
+
// ignore
|
|
262
|
+
}
|
|
263
|
+
|
|
214
264
|
// init leaflet
|
|
215
265
|
dialog.on('shown.bs.modal', () => {
|
|
216
266
|
setTimeout(async () => {
|
|
@@ -222,7 +272,6 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
222
272
|
const map = L.map(mapEl).setView([46.5, 2.5], 5);
|
|
223
273
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map);
|
|
224
274
|
setTimeout(() => { try { map.invalidateSize(); } catch (e) {} }, 100);
|
|
225
|
-
setTimeout(() => { try { map.invalidateSize(); } catch (e) {} }, 100);
|
|
226
275
|
let marker = null;
|
|
227
276
|
function setMarker(lat, lon) {
|
|
228
277
|
if (marker) map.removeLayer(marker);
|
|
@@ -937,6 +986,10 @@ function toDatetimeLocalValue(date) {
|
|
|
937
986
|
const mapped = (Array.isArray(data) ? data : []).map((ev) => {
|
|
938
987
|
try {
|
|
939
988
|
if (ev && ev.extendedProps && ev.extendedProps.type === 'special' && ev.start && ev.end) {
|
|
989
|
+
// Force the same visual layout as reservations in month view
|
|
990
|
+
// (avoid the "dot" layout which introduces a leading gap).
|
|
991
|
+
ev.display = 'block';
|
|
992
|
+
|
|
940
993
|
const s = new Date(ev.start);
|
|
941
994
|
const e = new Date(ev.end);
|
|
942
995
|
const ts = `${pad2(s.getHours())}:${pad2(s.getMinutes())}`;
|
|
@@ -980,7 +1033,6 @@ function toDatetimeLocalValue(date) {
|
|
|
980
1033
|
try {
|
|
981
1034
|
if (mode === 'special' && canCreateSpecial) {
|
|
982
1035
|
const payload = await openSpecialEventDialog(info);
|
|
983
|
-
setMode('reservation');
|
|
984
1036
|
if (!payload) {
|
|
985
1037
|
calendar.unselect();
|
|
986
1038
|
isDialogOpen = false;
|
|
@@ -996,6 +1048,7 @@ function toDatetimeLocalValue(date) {
|
|
|
996
1048
|
});
|
|
997
1049
|
});
|
|
998
1050
|
showAlert('success', 'Évènement créé.');
|
|
1051
|
+
setMode('reservation');
|
|
999
1052
|
calendar.refetchEvents();
|
|
1000
1053
|
calendar.unselect();
|
|
1001
1054
|
isDialogOpen = false;
|
|
@@ -1070,13 +1123,12 @@ function toDatetimeLocalValue(date) {
|
|
|
1070
1123
|
}
|
|
1071
1124
|
isDialogOpen = true;
|
|
1072
1125
|
try {
|
|
1073
|
-
// Default to a
|
|
1126
|
+
// Default to a one-day block: 07:00 -> 07:00 (end rolled to +1 day on submit).
|
|
1074
1127
|
const start2 = new Date(start);
|
|
1075
1128
|
start2.setHours(7, 0, 0, 0);
|
|
1076
1129
|
const end2 = new Date(start);
|
|
1077
|
-
end2.setHours(
|
|
1130
|
+
end2.setHours(7, 0, 0, 0);
|
|
1078
1131
|
const payload = await openSpecialEventDialog({ start: start2, end: end2, allDay: false });
|
|
1079
|
-
setMode('reservation');
|
|
1080
1132
|
if (!payload) {
|
|
1081
1133
|
isDialogOpen = false;
|
|
1082
1134
|
return;
|
|
@@ -1090,6 +1142,7 @@ function toDatetimeLocalValue(date) {
|
|
|
1090
1142
|
body: JSON.stringify(payload),
|
|
1091
1143
|
});
|
|
1092
1144
|
});
|
|
1145
|
+
setMode('reservation');
|
|
1093
1146
|
showAlert('success', 'Évènement créé.');
|
|
1094
1147
|
calendar.refetchEvents();
|
|
1095
1148
|
} finally {
|