add-to-calendar-button 2.12.3 → 2.12.5

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/README.md CHANGED
@@ -290,6 +290,7 @@ In doubt, simply ask and we find a way. :)
290
290
  <a href="https://github.com/acm-will"><img src="https://avatars.githubusercontent.com/u/103984058?v=4" title="acm-will" width="60" height="60"></a>
291
291
  <a href="https://github.com/sukharenko"><img src="https://avatars.githubusercontent.com/u/2049036?v=4" title="Yevgen Sukharenko" width="60" height="60"></a>
292
292
  <a href="https://github.com/pbaumard"><img src="https://avatars.githubusercontent.com/u/6176006?v=4" title="Pierre Baumard" width="60" height="60"></a>
293
+ <a href="https://github.com/rocky-premise"><img src="https://avatars.githubusercontent.com/u/230592673?v=4" title="Rocky Assad" width="60" height="60"></a>
293
294
  <a href="https://github.com/brenjt"><img src="https://avatars.githubusercontent.com/u/1713885?v=4" title="Brennan" width="60" height="60"></a>
294
295
  <a href="https://github.com/chris-at-fabius-labs"><img src="https://avatars.githubusercontent.com/u/108754665?v=4" title="chris-at-fabius-labs" width="60" height="60"></a>
295
296
  <a href="https://github.com/ssaaiidd"><img src="https://avatars.githubusercontent.com/u/29234802?v=4" title="ssaaiidd" width="60" height="60"></a>
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: 3D
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: Date
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: Flat
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: Neumorphism
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: Round
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: Simple
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: Text
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: Default
7
7
  *
8
- * Version: 2.12.3
8
+ * Version: 2.12.5
9
9
  * Creator: Jens Kuerschner (https://jekuer.com)
10
10
  * Project: https://github.com/add2cal/add-to-calendar-button
11
11
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
@@ -223,14 +223,14 @@ function tzlib_get_timezones(jsonType = false) {
223
223
  * Add to Calendar Button
224
224
  * ++++++++++++++++++++++
225
225
  *
226
- * Version: 2.12.3
226
+ * Version: 2.12.5
227
227
  * Creator: Jens Kuerschner (https://jekuer.com)
228
228
  * Project: https://github.com/add2cal/add-to-calendar-button
229
229
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
230
230
  * Note: DO NOT REMOVE THE COPYRIGHT NOTICE ABOVE!
231
231
  *
232
232
  */
233
- const atcbVersion = '2.12.3';
233
+ const atcbVersion = '2.12.5';
234
234
  const atcbCssTemplate = {};
235
235
  const atcbIsBrowser = () => {
236
236
  if (typeof window === 'undefined') {
@@ -572,11 +572,11 @@ function atcb_decorate_data_rrule(data) {
572
572
  data.recurrence_frequency = data.recurrence;
573
573
  data.recurrence = 'RRULE:FREQ=' + data.recurrence + ';WKST=' + data.recurrence_weekstart + ';INTERVAL=' + data.recurrence_interval;
574
574
  if (data.recurrence_until && data.recurrence_until !== '') {
575
- if (data.endTime && data.endTime !== '') {
576
- data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until.replace(/-/g, '').slice(0, 8) + 'T' + data.endTime.replace(':', '') + '00';
577
- } else {
578
- data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until.replace(/-/g, '').slice(0, 8);
575
+ data.recurrence_until = data.recurrence_until.replace(/[-:]/g, '');
576
+ if (data.recurrence_until.length < 9) {
577
+ data.recurrence_until += 'T235959Z';
579
578
  }
579
+ data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until;
580
580
  }
581
581
  if (data.recurrence_count && data.recurrence_count !== '') {
582
582
  data.recurrence = data.recurrence + ';COUNT=' + data.recurrence_count;
@@ -597,13 +597,14 @@ function atcb_decorate_data_recurring_events(data) {
597
597
  const startDate = data.dates?.[0].startDate || data.startDate;
598
598
  const startTime = data.dates?.[0].startTime || data.startTime;
599
599
  const startDateTime = (function () {
600
- if (startTime) {
600
+ if (startTime && startTime !== '') {
601
601
  const offset = tzlib_get_offset(data.dates?.[0].timeZone || data.timeZone, startDate, startTime);
602
602
  return new Date(startDate + ' ' + startTime + ':00 GMT' + offset);
603
603
  }
604
604
  return new Date(startDate + 'T00:00:00Z');
605
605
  })();
606
- const occurenceData = atcb_getNextOccurrence(data.recurrence, startDateTime);
606
+ const isAllDay = !(startTime && startTime !== '');
607
+ const occurenceData = atcb_getNextOccurrence(data.recurrence, startDateTime, isAllDay);
607
608
  if (!occurenceData || !occurenceData.nextOccurrence) {
608
609
  return data;
609
610
  }
@@ -909,7 +910,7 @@ function atcb_set_online_event_flag(data, i) {
909
910
  if (dateEntry.location && dateEntry.location.startsWith('http')) {
910
911
  dateEntry.onlineEvent = true;
911
912
  } else {
912
- dateEntry.v = false;
913
+ dateEntry.onlineEvent = false;
913
914
  }
914
915
  return data;
915
916
  }
@@ -918,12 +919,12 @@ function atcb_replace_custom_variables(data, i) {
918
919
  const dateEntry = data.dates[`${i}`];
919
920
  for (const key in data.customVar) {
920
921
  const value = data.customVar[`${key}`];
921
- dateEntry.name = atcb_replace_placeholder(dateEntry.name, value);
922
- dateEntry.location = atcb_replace_placeholder(dateEntry.location, value);
922
+ dateEntry.name = atcb_replace_placeholder(dateEntry.name, key, value);
923
+ dateEntry.location = atcb_replace_placeholder(dateEntry.location, key, value);
923
924
  }
924
925
  return data;
925
926
  }
926
- function atcb_replace_placeholder(text, value) {
927
+ function atcb_replace_placeholder(text, key, value) {
927
928
  const placeholder = '%%' + key.replace(/[^\w\-.]/g, '') + '%%';
928
929
  if (!text) return text;
929
930
  // eslint-disable-next-line security/detect-non-literal-regexp
@@ -1335,8 +1336,8 @@ async function atcb_validate_rrule_simplyfied(data, msgPrefix) {
1335
1336
  if (data.recurrence_interval && (data.recurrence_interval < 1 || data.recurrence_interval % 1 !== 0)) {
1336
1337
  throw new Error(msgPrefix + ' failed: recurrence data (interval) misspelled');
1337
1338
  }
1338
- if (data.recurrence_until && data.recurrence_until !== '' && !/^[\d\-:]+$/.test(data.recurrence_until)) {
1339
- throw new Error(msgPrefix + ' failed: recurrence data (until) misspelled');
1339
+ if (data.recurrence_until && data.recurrence_until !== '' && !/^\d{8}T\d{6}Z$/.test(data.recurrence_until)) {
1340
+ throw new Error(msgPrefix + ' failed: recurrence data (until) misspelled - must be in format YYYYMMDDTHHMMSSZ');
1340
1341
  }
1341
1342
  if (data.recurrence_count && (data.recurrence_count < 1 || data.recurrence_count % 1 !== 0)) {
1342
1343
  throw new Error(msgPrefix + ' failed: recurrence data (count) misspelled');
@@ -3090,7 +3091,6 @@ function atcb_translate_via_time_zone(date, time, baseTimeZone, targetTimeZone)
3090
3091
  }
3091
3092
  function atcb_generate_timestring(dates, language = 'en', subEvent = 'all', decorate = false, browserTimeOverride = false, enforceYear = false, hideTimeZone = false) {
3092
3093
  if (decorate) {
3093
- dates = atcb_decorate_data_recurrence({ dates: dates }).dates;
3094
3094
  dates = atcb_decorate_data_dates({ dates: dates }).dates;
3095
3095
  }
3096
3096
  let startDateInfo, endDateInfo, timeZoneInfoStart, timeZoneInfoEnd;
@@ -3592,12 +3592,18 @@ function matchesImplicitRules(date, rrule, startDate) {
3592
3592
  if (rrule.FREQ === 'YEARLY' && !rrule.BYMONTHDAY && !rrule.BYWEEKDAY && !rrule.BYYEARDAY && !rrule.BYWEEKNO && date.getUTCDate() !== startDate.getUTCDate()) return false;
3593
3593
  return true;
3594
3594
  }
3595
- function atcb_getNextOccurrence(rruleStr, startDateTime) {
3595
+ function atcb_getNextOccurrence(rruleStr, startDateTime, allday) {
3596
3596
  const rrule = atcb_parseRRule(rruleStr);
3597
+ if (allday && rrule.UNTIL instanceof Date) {
3598
+ const untilEod = new Date(rrule.UNTIL);
3599
+ untilEod.setUTCHours(23, 59, 59, 999);
3600
+ rrule.UNTIL = untilEod;
3601
+ }
3597
3602
  const now = new Date();
3603
+ now.setUTCHours(0, 0, 0, 0);
3598
3604
  const stepMs = rrule.BYHOUR ? 60 * 60 * 1000 : 24 * 60 * 60 * 1000;
3599
3605
  let currentDate = startDateTime;
3600
- let occurrences = [];
3606
+ const occurrences = [];
3601
3607
  let count = 0;
3602
3608
  let maxIterations = 10000;
3603
3609
  while (true) {
@@ -3605,19 +3611,18 @@ function atcb_getNextOccurrence(rruleStr, startDateTime) {
3605
3611
  occurrences.push(currentDate);
3606
3612
  count++;
3607
3613
  if (rrule.COUNT && count >= rrule.COUNT) break;
3608
- if (!rrule.COUNT && !rrule.UNTIL && occurrences.length > 0 && currentDate > now) break;
3614
+ if (!rrule.COUNT && !rrule.UNTIL && occurrences.length > 0 && (allday ? currentDate >= now : currentDate > now)) break;
3609
3615
  }
3610
3616
  if (rrule.UNTIL && currentDate > rrule.UNTIL) break;
3611
3617
  currentDate = new Date(currentDate.getTime() + stepMs);
3612
3618
  if (--maxIterations <= 0) {
3613
- console.log('Max iterations reached. Using what got calculated so far.');
3614
3619
  break;
3615
3620
  }
3616
3621
  }
3617
3622
  let nextDate = null;
3618
3623
  let countDate = 0;
3619
- for (let d of occurrences) {
3620
- if (d > now) {
3624
+ for (const d of occurrences) {
3625
+ if (allday ? d >= now : d > now) {
3621
3626
  nextDate = d;
3622
3627
  break;
3623
3628
  }
@@ -5373,10 +5378,18 @@ function atcb_global_listener_keydown(event) {
5373
5378
  if (event.key === 'ArrowDown' && currFocusOption.dataset.optionNumber < optionListCount) {
5374
5379
  targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
5375
5380
  } else if (event.key === 'Tab') {
5376
- if (currFocusOption.dataset.optionNumber < optionListCount) {
5377
- targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
5381
+ if (event.shiftKey) {
5382
+ if (currFocusOption.dataset.optionNumber > 1) {
5383
+ targetFocus = parseInt(currFocusOption.dataset.optionNumber) - 1;
5384
+ } else {
5385
+ targetFocus = optionListCount;
5386
+ }
5378
5387
  } else {
5379
- targetFocus = 1;
5388
+ if (currFocusOption.dataset.optionNumber < optionListCount) {
5389
+ targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
5390
+ } else {
5391
+ targetFocus = 1;
5392
+ }
5380
5393
  }
5381
5394
  } else if (event.key === 'ArrowUp' && currFocusOption.dataset.optionNumber >= 1) {
5382
5395
  targetFocus = parseInt(currFocusOption.dataset.optionNumber) - 1;
@@ -223,14 +223,14 @@ function tzlib_get_timezones(jsonType = false) {
223
223
  * Add to Calendar Button
224
224
  * ++++++++++++++++++++++
225
225
  *
226
- * Version: 2.12.3
226
+ * Version: 2.12.5
227
227
  * Creator: Jens Kuerschner (https://jekuer.com)
228
228
  * Project: https://github.com/add2cal/add-to-calendar-button
229
229
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
230
230
  * Note: DO NOT REMOVE THE COPYRIGHT NOTICE ABOVE!
231
231
  *
232
232
  */
233
- const atcbVersion = '2.12.3';
233
+ const atcbVersion = '2.12.5';
234
234
  const atcbCssTemplate = {
235
235
  if (typeof window === 'undefined') {
236
236
  return false;
@@ -571,11 +571,11 @@ function atcb_decorate_data_rrule(data) {
571
571
  data.recurrence_frequency = data.recurrence;
572
572
  data.recurrence = 'RRULE:FREQ=' + data.recurrence + ';WKST=' + data.recurrence_weekstart + ';INTERVAL=' + data.recurrence_interval;
573
573
  if (data.recurrence_until && data.recurrence_until !== '') {
574
- if (data.endTime && data.endTime !== '') {
575
- data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until.replace(/-/g, '').slice(0, 8) + 'T' + data.endTime.replace(':', '') + '00';
576
- } else {
577
- data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until.replace(/-/g, '').slice(0, 8);
574
+ data.recurrence_until = data.recurrence_until.replace(/[-:]/g, '');
575
+ if (data.recurrence_until.length < 9) {
576
+ data.recurrence_until += 'T235959Z';
578
577
  }
578
+ data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until;
579
579
  }
580
580
  if (data.recurrence_count && data.recurrence_count !== '') {
581
581
  data.recurrence = data.recurrence + ';COUNT=' + data.recurrence_count;
@@ -596,13 +596,14 @@ function atcb_decorate_data_recurring_events(data) {
596
596
  const startDate = data.dates?.[0].startDate || data.startDate;
597
597
  const startTime = data.dates?.[0].startTime || data.startTime;
598
598
  const startDateTime = (function () {
599
- if (startTime) {
599
+ if (startTime && startTime !== '') {
600
600
  const offset = tzlib_get_offset(data.dates?.[0].timeZone || data.timeZone, startDate, startTime);
601
601
  return new Date(startDate + ' ' + startTime + ':00 GMT' + offset);
602
602
  }
603
603
  return new Date(startDate + 'T00:00:00Z');
604
604
  })();
605
- const occurenceData = atcb_getNextOccurrence(data.recurrence, startDateTime);
605
+ const isAllDay = !(startTime && startTime !== '');
606
+ const occurenceData = atcb_getNextOccurrence(data.recurrence, startDateTime, isAllDay);
606
607
  if (!occurenceData || !occurenceData.nextOccurrence) {
607
608
  return data;
608
609
  }
@@ -908,7 +909,7 @@ function atcb_set_online_event_flag(data, i) {
908
909
  if (dateEntry.location && dateEntry.location.startsWith('http')) {
909
910
  dateEntry.onlineEvent = true;
910
911
  } else {
911
- dateEntry.v = false;
912
+ dateEntry.onlineEvent = false;
912
913
  }
913
914
  return data;
914
915
  }
@@ -917,12 +918,12 @@ function atcb_replace_custom_variables(data, i) {
917
918
  const dateEntry = data.dates[`${i}`];
918
919
  for (const key in data.customVar) {
919
920
  const value = data.customVar[`${key}`];
920
- dateEntry.name = atcb_replace_placeholder(dateEntry.name, value);
921
- dateEntry.location = atcb_replace_placeholder(dateEntry.location, value);
921
+ dateEntry.name = atcb_replace_placeholder(dateEntry.name, key, value);
922
+ dateEntry.location = atcb_replace_placeholder(dateEntry.location, key, value);
922
923
  }
923
924
  return data;
924
925
  }
925
- function atcb_replace_placeholder(text, value) {
926
+ function atcb_replace_placeholder(text, key, value) {
926
927
  const placeholder = '%%' + key.replace(/[^\w\-.]/g, '') + '%%';
927
928
  if (!text) return text;
928
929
  // eslint-disable-next-line security/detect-non-literal-regexp
@@ -1334,8 +1335,8 @@ async function atcb_validate_rrule_simplyfied(data, msgPrefix) {
1334
1335
  if (data.recurrence_interval && (data.recurrence_interval < 1 || data.recurrence_interval % 1 !== 0)) {
1335
1336
  throw new Error(msgPrefix + ' failed: recurrence data (interval) misspelled');
1336
1337
  }
1337
- if (data.recurrence_until && data.recurrence_until !== '' && !/^[\d\-:]+$/.test(data.recurrence_until)) {
1338
- throw new Error(msgPrefix + ' failed: recurrence data (until) misspelled');
1338
+ if (data.recurrence_until && data.recurrence_until !== '' && !/^\d{8}T\d{6}Z$/.test(data.recurrence_until)) {
1339
+ throw new Error(msgPrefix + ' failed: recurrence data (until) misspelled - must be in format YYYYMMDDTHHMMSSZ');
1339
1340
  }
1340
1341
  if (data.recurrence_count && (data.recurrence_count < 1 || data.recurrence_count % 1 !== 0)) {
1341
1342
  throw new Error(msgPrefix + ' failed: recurrence data (count) misspelled');
@@ -3089,7 +3090,6 @@ function atcb_translate_via_time_zone(date, time, baseTimeZone, targetTimeZone)
3089
3090
  }
3090
3091
  function atcb_generate_timestring(dates, language = 'en', subEvent = 'all', decorate = false, browserTimeOverride = false, enforceYear = false, hideTimeZone = false) {
3091
3092
  if (decorate) {
3092
- dates = atcb_decorate_data_recurrence({ dates: dates }).dates;
3093
3093
  dates = atcb_decorate_data_dates({ dates: dates }).dates;
3094
3094
  }
3095
3095
  let startDateInfo, endDateInfo, timeZoneInfoStart, timeZoneInfoEnd;
@@ -3591,12 +3591,18 @@ function matchesImplicitRules(date, rrule, startDate) {
3591
3591
  if (rrule.FREQ === 'YEARLY' && !rrule.BYMONTHDAY && !rrule.BYWEEKDAY && !rrule.BYYEARDAY && !rrule.BYWEEKNO && date.getUTCDate() !== startDate.getUTCDate()) return false;
3592
3592
  return true;
3593
3593
  }
3594
- function atcb_getNextOccurrence(rruleStr, startDateTime) {
3594
+ function atcb_getNextOccurrence(rruleStr, startDateTime, allday) {
3595
3595
  const rrule = atcb_parseRRule(rruleStr);
3596
+ if (allday && rrule.UNTIL instanceof Date) {
3597
+ const untilEod = new Date(rrule.UNTIL);
3598
+ untilEod.setUTCHours(23, 59, 59, 999);
3599
+ rrule.UNTIL = untilEod;
3600
+ }
3596
3601
  const now = new Date();
3602
+ now.setUTCHours(0, 0, 0, 0);
3597
3603
  const stepMs = rrule.BYHOUR ? 60 * 60 * 1000 : 24 * 60 * 60 * 1000;
3598
3604
  let currentDate = startDateTime;
3599
- let occurrences = [];
3605
+ const occurrences = [];
3600
3606
  let count = 0;
3601
3607
  let maxIterations = 10000;
3602
3608
  while (true) {
@@ -3604,19 +3610,18 @@ function atcb_getNextOccurrence(rruleStr, startDateTime) {
3604
3610
  occurrences.push(currentDate);
3605
3611
  count++;
3606
3612
  if (rrule.COUNT && count >= rrule.COUNT) break;
3607
- if (!rrule.COUNT && !rrule.UNTIL && occurrences.length > 0 && currentDate > now) break;
3613
+ if (!rrule.COUNT && !rrule.UNTIL && occurrences.length > 0 && (allday ? currentDate >= now : currentDate > now)) break;
3608
3614
  }
3609
3615
  if (rrule.UNTIL && currentDate > rrule.UNTIL) break;
3610
3616
  currentDate = new Date(currentDate.getTime() + stepMs);
3611
3617
  if (--maxIterations <= 0) {
3612
- console.log('Max iterations reached. Using what got calculated so far.');
3613
3618
  break;
3614
3619
  }
3615
3620
  }
3616
3621
  let nextDate = null;
3617
3622
  let countDate = 0;
3618
- for (let d of occurrences) {
3619
- if (d > now) {
3623
+ for (const d of occurrences) {
3624
+ if (allday ? d >= now : d > now) {
3620
3625
  nextDate = d;
3621
3626
  break;
3622
3627
  }
@@ -5372,10 +5377,18 @@ function atcb_global_listener_keydown(event) {
5372
5377
  if (event.key === 'ArrowDown' && currFocusOption.dataset.optionNumber < optionListCount) {
5373
5378
  targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
5374
5379
  } else if (event.key === 'Tab') {
5375
- if (currFocusOption.dataset.optionNumber < optionListCount) {
5376
- targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
5380
+ if (event.shiftKey) {
5381
+ if (currFocusOption.dataset.optionNumber > 1) {
5382
+ targetFocus = parseInt(currFocusOption.dataset.optionNumber) - 1;
5383
+ } else {
5384
+ targetFocus = optionListCount;
5385
+ }
5377
5386
  } else {
5378
- targetFocus = 1;
5387
+ if (currFocusOption.dataset.optionNumber < optionListCount) {
5388
+ targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
5389
+ } else {
5390
+ targetFocus = 1;
5391
+ }
5379
5392
  }
5380
5393
  } else if (event.key === 'ArrowUp' && currFocusOption.dataset.optionNumber >= 1) {
5381
5394
  targetFocus = parseInt(currFocusOption.dataset.optionNumber) - 1;
@@ -223,14 +223,14 @@ function tzlib_get_timezones(jsonType = false) {
223
223
  * Add to Calendar Button
224
224
  * ++++++++++++++++++++++
225
225
  *
226
- * Version: 2.12.3
226
+ * Version: 2.12.5
227
227
  * Creator: Jens Kuerschner (https://jekuer.com)
228
228
  * Project: https://github.com/add2cal/add-to-calendar-button
229
229
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
230
230
  * Note: DO NOT REMOVE THE COPYRIGHT NOTICE ABOVE!
231
231
  *
232
232
  */
233
- const atcbVersion = '2.12.3';
233
+ const atcbVersion = '2.12.5';
234
234
  const atcbCssTemplate = {};
235
235
  const atcbIsBrowser = () => {
236
236
  if (typeof window === 'undefined') {
@@ -572,11 +572,11 @@ function atcb_decorate_data_rrule(data) {
572
572
  data.recurrence_frequency = data.recurrence;
573
573
  data.recurrence = 'RRULE:FREQ=' + data.recurrence + ';WKST=' + data.recurrence_weekstart + ';INTERVAL=' + data.recurrence_interval;
574
574
  if (data.recurrence_until && data.recurrence_until !== '') {
575
- if (data.endTime && data.endTime !== '') {
576
- data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until.replace(/-/g, '').slice(0, 8) + 'T' + data.endTime.replace(':', '') + '00';
577
- } else {
578
- data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until.replace(/-/g, '').slice(0, 8);
575
+ data.recurrence_until = data.recurrence_until.replace(/[-:]/g, '');
576
+ if (data.recurrence_until.length < 9) {
577
+ data.recurrence_until += 'T235959Z';
579
578
  }
579
+ data.recurrence = data.recurrence + ';UNTIL=' + data.recurrence_until;
580
580
  }
581
581
  if (data.recurrence_count && data.recurrence_count !== '') {
582
582
  data.recurrence = data.recurrence + ';COUNT=' + data.recurrence_count;
@@ -597,13 +597,14 @@ function atcb_decorate_data_recurring_events(data) {
597
597
  const startDate = data.dates?.[0].startDate || data.startDate;
598
598
  const startTime = data.dates?.[0].startTime || data.startTime;
599
599
  const startDateTime = (function () {
600
- if (startTime) {
600
+ if (startTime && startTime !== '') {
601
601
  const offset = tzlib_get_offset(data.dates?.[0].timeZone || data.timeZone, startDate, startTime);
602
602
  return new Date(startDate + ' ' + startTime + ':00 GMT' + offset);
603
603
  }
604
604
  return new Date(startDate + 'T00:00:00Z');
605
605
  })();
606
- const occurenceData = atcb_getNextOccurrence(data.recurrence, startDateTime);
606
+ const isAllDay = !(startTime && startTime !== '');
607
+ const occurenceData = atcb_getNextOccurrence(data.recurrence, startDateTime, isAllDay);
607
608
  if (!occurenceData || !occurenceData.nextOccurrence) {
608
609
  return data;
609
610
  }
@@ -909,7 +910,7 @@ function atcb_set_online_event_flag(data, i) {
909
910
  if (dateEntry.location && dateEntry.location.startsWith('http')) {
910
911
  dateEntry.onlineEvent = true;
911
912
  } else {
912
- dateEntry.v = false;
913
+ dateEntry.onlineEvent = false;
913
914
  }
914
915
  return data;
915
916
  }
@@ -918,12 +919,12 @@ function atcb_replace_custom_variables(data, i) {
918
919
  const dateEntry = data.dates[`${i}`];
919
920
  for (const key in data.customVar) {
920
921
  const value = data.customVar[`${key}`];
921
- dateEntry.name = atcb_replace_placeholder(dateEntry.name, value);
922
- dateEntry.location = atcb_replace_placeholder(dateEntry.location, value);
922
+ dateEntry.name = atcb_replace_placeholder(dateEntry.name, key, value);
923
+ dateEntry.location = atcb_replace_placeholder(dateEntry.location, key, value);
923
924
  }
924
925
  return data;
925
926
  }
926
- function atcb_replace_placeholder(text, value) {
927
+ function atcb_replace_placeholder(text, key, value) {
927
928
  const placeholder = '%%' + key.replace(/[^\w\-.]/g, '') + '%%';
928
929
  if (!text) return text;
929
930
  // eslint-disable-next-line security/detect-non-literal-regexp
@@ -1335,8 +1336,8 @@ async function atcb_validate_rrule_simplyfied(data, msgPrefix) {
1335
1336
  if (data.recurrence_interval && (data.recurrence_interval < 1 || data.recurrence_interval % 1 !== 0)) {
1336
1337
  throw new Error(msgPrefix + ' failed: recurrence data (interval) misspelled');
1337
1338
  }
1338
- if (data.recurrence_until && data.recurrence_until !== '' && !/^[\d\-:]+$/.test(data.recurrence_until)) {
1339
- throw new Error(msgPrefix + ' failed: recurrence data (until) misspelled');
1339
+ if (data.recurrence_until && data.recurrence_until !== '' && !/^\d{8}T\d{6}Z$/.test(data.recurrence_until)) {
1340
+ throw new Error(msgPrefix + ' failed: recurrence data (until) misspelled - must be in format YYYYMMDDTHHMMSSZ');
1340
1341
  }
1341
1342
  if (data.recurrence_count && (data.recurrence_count < 1 || data.recurrence_count % 1 !== 0)) {
1342
1343
  throw new Error(msgPrefix + ' failed: recurrence data (count) misspelled');
@@ -3810,7 +3811,6 @@ function atcb_translate_via_time_zone(date, time, baseTimeZone, targetTimeZone)
3810
3811
  }
3811
3812
  function atcb_generate_timestring(dates, language = 'en', subEvent = 'all', decorate = false, browserTimeOverride = false, enforceYear = false, hideTimeZone = false) {
3812
3813
  if (decorate) {
3813
- dates = atcb_decorate_data_recurrence({ dates: dates }).dates;
3814
3814
  dates = atcb_decorate_data_dates({ dates: dates }).dates;
3815
3815
  }
3816
3816
  let startDateInfo, endDateInfo, timeZoneInfoStart, timeZoneInfoEnd;
@@ -4312,12 +4312,18 @@ function matchesImplicitRules(date, rrule, startDate) {
4312
4312
  if (rrule.FREQ === 'YEARLY' && !rrule.BYMONTHDAY && !rrule.BYWEEKDAY && !rrule.BYYEARDAY && !rrule.BYWEEKNO && date.getUTCDate() !== startDate.getUTCDate()) return false;
4313
4313
  return true;
4314
4314
  }
4315
- function atcb_getNextOccurrence(rruleStr, startDateTime) {
4315
+ function atcb_getNextOccurrence(rruleStr, startDateTime, allday) {
4316
4316
  const rrule = atcb_parseRRule(rruleStr);
4317
+ if (allday && rrule.UNTIL instanceof Date) {
4318
+ const untilEod = new Date(rrule.UNTIL);
4319
+ untilEod.setUTCHours(23, 59, 59, 999);
4320
+ rrule.UNTIL = untilEod;
4321
+ }
4317
4322
  const now = new Date();
4323
+ now.setUTCHours(0, 0, 0, 0);
4318
4324
  const stepMs = rrule.BYHOUR ? 60 * 60 * 1000 : 24 * 60 * 60 * 1000;
4319
4325
  let currentDate = startDateTime;
4320
- let occurrences = [];
4326
+ const occurrences = [];
4321
4327
  let count = 0;
4322
4328
  let maxIterations = 10000;
4323
4329
  while (true) {
@@ -4325,19 +4331,18 @@ function atcb_getNextOccurrence(rruleStr, startDateTime) {
4325
4331
  occurrences.push(currentDate);
4326
4332
  count++;
4327
4333
  if (rrule.COUNT && count >= rrule.COUNT) break;
4328
- if (!rrule.COUNT && !rrule.UNTIL && occurrences.length > 0 && currentDate > now) break;
4334
+ if (!rrule.COUNT && !rrule.UNTIL && occurrences.length > 0 && (allday ? currentDate >= now : currentDate > now)) break;
4329
4335
  }
4330
4336
  if (rrule.UNTIL && currentDate > rrule.UNTIL) break;
4331
4337
  currentDate = new Date(currentDate.getTime() + stepMs);
4332
4338
  if (--maxIterations <= 0) {
4333
- console.log('Max iterations reached. Using what got calculated so far.');
4334
4339
  break;
4335
4340
  }
4336
4341
  }
4337
4342
  let nextDate = null;
4338
4343
  let countDate = 0;
4339
- for (let d of occurrences) {
4340
- if (d > now) {
4344
+ for (const d of occurrences) {
4345
+ if (allday ? d >= now : d > now) {
4341
4346
  nextDate = d;
4342
4347
  break;
4343
4348
  }
@@ -6093,10 +6098,18 @@ function atcb_global_listener_keydown(event) {
6093
6098
  if (event.key === 'ArrowDown' && currFocusOption.dataset.optionNumber < optionListCount) {
6094
6099
  targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
6095
6100
  } else if (event.key === 'Tab') {
6096
- if (currFocusOption.dataset.optionNumber < optionListCount) {
6097
- targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
6101
+ if (event.shiftKey) {
6102
+ if (currFocusOption.dataset.optionNumber > 1) {
6103
+ targetFocus = parseInt(currFocusOption.dataset.optionNumber) - 1;
6104
+ } else {
6105
+ targetFocus = optionListCount;
6106
+ }
6098
6107
  } else {
6099
- targetFocus = 1;
6108
+ if (currFocusOption.dataset.optionNumber < optionListCount) {
6109
+ targetFocus = parseInt(currFocusOption.dataset.optionNumber) + 1;
6110
+ } else {
6111
+ targetFocus = 1;
6112
+ }
6100
6113
  }
6101
6114
  } else if (event.key === 'ArrowUp' && currFocusOption.dataset.optionNumber >= 1) {
6102
6115
  targetFocus = parseInt(currFocusOption.dataset.optionNumber) - 1;