add-to-calendar-button 2.12.7 → 2.12.9

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.
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Style: 3D
7
7
  *
8
- * Version: 2.12.7
8
+ * Version: 2.12.9
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.7
8
+ * Version: 2.12.9
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.7
8
+ * Version: 2.12.9
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.7
8
+ * Version: 2.12.9
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.7
8
+ * Version: 2.12.9
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.7
8
+ * Version: 2.12.9
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.7
8
+ * Version: 2.12.9
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.7
8
+ * Version: 2.12.9
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.7
226
+ * Version: 2.12.9
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.7';
233
+ const atcbVersion = '2.12.9';
234
234
  const atcbCssTemplate = {};
235
235
  const atcbIsBrowser = () => {
236
236
  if (typeof window === 'undefined') {
@@ -620,7 +620,7 @@ function atcb_decorate_data_recurring_events(data) {
620
620
  }
621
621
  const endDate = data.dates?.[0].endDate || data.endDate || startDate;
622
622
  const endTime = data.dates?.[0].endTime || data.endTime || '';
623
- const diff = new Date(endDate + (endTime && endTime !== '' ? 'T' + endTime : '')) - new Date(startDate + (startTime && startTime !== '' ? 'T' + startTime : ''));
623
+ const diff = new Date(endDate + (endTime && endTime !== '' ? 'T' + endTime : '')).getTime() - new Date(startDate + (startTime && startTime !== '' ? 'T' + startTime : '')).getTime();
624
624
  const newEndDateTime = new Date(occurenceData.nextOccurrence.getTime() + diff);
625
625
  const newEndDateTimeString =
626
626
  String(newEndDateTime.getFullYear()) +
@@ -2916,7 +2916,7 @@ function atcb_determine_ical_filename(data, subEvent) {
2916
2916
  return filenamePart + filenameSuffix;
2917
2917
  }
2918
2918
  }
2919
- return 'event-to-save-in-my-calendar' + filenameSuffix;
2919
+ return 'event' + filenameSuffix;
2920
2920
  }
2921
2921
  function atcb_ical_copy_note(host, dataUrl, data, keyboardTrigger) {
2922
2922
  atcb_copy_to_clipboard(dataUrl);
@@ -3505,6 +3505,65 @@ function atcb_apply_transformation(value, transform) {
3505
3505
  return value;
3506
3506
  }
3507
3507
  }
3508
+ function atcb_parseByWeekdayTokens(rawByDay) {
3509
+ const tokens = rawByDay ? rawByDay.toString().split(',') : [];
3510
+ const mapWeekdayCode = (wd) => {
3511
+ switch (wd) {
3512
+ case 'SU':
3513
+ return 0;
3514
+ case 'MO':
3515
+ return 1;
3516
+ case 'TU':
3517
+ return 2;
3518
+ case 'WE':
3519
+ return 3;
3520
+ case 'TH':
3521
+ return 4;
3522
+ case 'FR':
3523
+ return 5;
3524
+ case 'SA':
3525
+ return 6;
3526
+ default:
3527
+ return undefined;
3528
+ }
3529
+ };
3530
+ const plainWeekdays = [];
3531
+ const ordinals = [];
3532
+ for (const tok of tokens) {
3533
+ const t = tok.trim().toUpperCase();
3534
+ if (t.length < 2) continue;
3535
+ const wd = t.slice(-2);
3536
+ const day = mapWeekdayCode(wd);
3537
+ if (day === undefined) continue;
3538
+ const prefix = t.slice(0, t.length - 2);
3539
+ if (prefix) {
3540
+ let sign = 1;
3541
+ let digits = prefix;
3542
+ if (digits[0] === '+') {
3543
+ digits = digits.slice(1);
3544
+ } else if (digits[0] === '-') {
3545
+ sign = -1;
3546
+ digits = digits.slice(1);
3547
+ }
3548
+ if (!digits || digits.length > 2) continue;
3549
+ let validDigits = true;
3550
+ for (let i = 0; i < digits.length; i++) {
3551
+ const code = digits.charCodeAt(i);
3552
+ if (code < 48 || code > 57) {
3553
+ validDigits = false;
3554
+ break;
3555
+ }
3556
+ }
3557
+ if (!validDigits) continue;
3558
+ const abs = parseInt(digits, 10);
3559
+ if (abs < 1 || abs > 53) continue;
3560
+ ordinals.push({ n: sign * abs, day });
3561
+ } else {
3562
+ plainWeekdays.push(day);
3563
+ }
3564
+ }
3565
+ return { plainWeekdays, ordinals };
3566
+ }
3508
3567
  function atcb_parseRRule(rruleStr, deep = true) {
3509
3568
  const parts = rruleStr
3510
3569
  .replace('RRULE:', '')
@@ -3516,40 +3575,66 @@ function atcb_parseRRule(rruleStr, deep = true) {
3516
3575
  }, {});
3517
3576
  if (!parts.FREQ) throw new Error('RRULE must have FREQ');
3518
3577
  parts.FREQ = parts.FREQ.toUpperCase();
3519
- parts.INTERVAL = parseInt(parts.INTERVAL || 1, 10);
3520
- parts.COUNT = parts.COUNT ? parseInt(parts.COUNT, 10) : null;
3578
+ parts.INTERVAL = parts.INTERVAL ? parseInt(parts.INTERVAL.toString(), 10) : 1;
3579
+ parts.COUNT = parts.COUNT ? parseInt(parts.COUNT.toString(), 10) : null;
3521
3580
  if (parts.UNTIL) {
3522
- const untilStr = parts.UNTIL;
3523
- parts.UNTIL = deep ? new Date(Date.UTC(parseInt(untilStr.slice(0, 4), 10), parseInt(untilStr.slice(4, 6), 10) - 1, parseInt(untilStr.slice(6, 8), 10), parseInt(untilStr.slice(9, 11) || 0, 10), parseInt(untilStr.slice(11, 13) || 0, 10))) : untilStr;
3581
+ const untilStr = parts.UNTIL.toString();
3582
+ parts.UNTIL = deep ? new Date(Date.UTC(parseInt(untilStr.slice(0, 4), 10), parseInt(untilStr.slice(4, 6), 10) - 1, parseInt(untilStr.slice(6, 8), 10), parseInt(untilStr.slice(9, 11) || '0', 10), parseInt(untilStr.slice(11, 13) || '0', 10))) : untilStr;
3524
3583
  }
3525
3584
  if (parts.BYWEEKDAY || parts.BYDAY) {
3526
- const dayMap = { SU: 0, MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6 };
3527
- parts.BYWEEKDAY = deep
3528
- ? (parts.BYWEEKDAY || parts.BYDAY)
3585
+ const rawByDay = (parts.BYWEEKDAY || parts.BYDAY)?.toString();
3586
+ if (deep) {
3587
+ const { plainWeekdays, ordinals } = atcb_parseByWeekdayTokens(rawByDay);
3588
+ parts.BYWEEKDAY = plainWeekdays.length ? plainWeekdays : null;
3589
+ parts.BYDAY_ORDINALS = ordinals.length ? ordinals : null;
3590
+ } else {
3591
+ parts.BYWEEKDAY = parts.BYWEEKDAY || parts.BYDAY;
3592
+ }
3593
+ }
3594
+ parts.BYMONTH =
3595
+ deep && parts.BYMONTH
3596
+ ? parts.BYMONTH.toString()
3597
+ .split(',')
3598
+ .map((n) => parseInt(n, 10))
3599
+ : parts.BYMONTH;
3600
+ parts.BYYEARDAY =
3601
+ deep && parts.BYYEARDAY
3602
+ ? parts.BYYEARDAY.toString()
3603
+ .split(',')
3604
+ .map((n) => parseInt(n, 10))
3605
+ : parts.BYYEARDAY;
3606
+ parts.BYMONTHDAY =
3607
+ deep && parts.BYMONTHDAY
3608
+ ? parts.BYMONTHDAY.toString()
3609
+ .split(',')
3610
+ .map((n) => parseInt(n, 10))
3611
+ : parts.BYMONTHDAY;
3612
+ parts.BYWEEKNO =
3613
+ deep && parts.BYWEEKNO
3614
+ ? parts.BYWEEKNO.toString()
3529
3615
  .split(',')
3530
- .map((day) => dayMap[day.trim().toUpperCase()])
3531
- .filter((n) => n !== undefined)
3532
- : parts.BYWEEKDAY || parts.BYDAY;
3533
- }
3534
- parts.BYMONTH = deep && parts.BYMONTH ? parts.BYMONTH.split(',').map((n) => parseInt(n, 10)) : parts.BYMONTH;
3535
- parts.BYYEARDAY = deep && parts.BYYEARDAY ? parts.BYYEARDAY.split(',').map((n) => parseInt(n, 10)) : parts.BYYEARDAY;
3536
- parts.BYMONTHDAY = deep && parts.BYMONTHDAY ? parts.BYMONTHDAY.split(',').map((n) => parseInt(n, 10)) : parts.BYMONTHDAY;
3537
- parts.BYWEEKNO = deep && parts.BYWEEKNO ? parts.BYWEEKNO.split(',').map((n) => parseInt(n, 10)) : parts.BYWEEKNO;
3538
- parts.BYHOUR = deep && parts.BYHOUR ? parts.BYHOUR.split(',').map((n) => parseInt(n, 10)) : parts.BYHOUR;
3616
+ .map((n) => parseInt(n, 10))
3617
+ : parts.BYWEEKNO;
3618
+ parts.BYHOUR =
3619
+ deep && parts.BYHOUR
3620
+ ? parts.BYHOUR.toString()
3621
+ .split(',')
3622
+ .map((n) => parseInt(n, 10))
3623
+ : parts.BYHOUR;
3539
3624
  return parts;
3540
3625
  }
3541
3626
  function getDayOfYear(date) {
3542
3627
  const start = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
3543
- return Math.floor((date - start) / (1000 * 60 * 60 * 24)) + 1;
3628
+ return Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1;
3544
3629
  }
3545
3630
  function getWeekNumber(date) {
3546
3631
  const d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
3547
3632
  d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
3548
3633
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
3549
- return Math.ceil(((d - yearStart) / 86400000 + 1) / 7);
3634
+ return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
3550
3635
  }
3551
3636
  function matchesFreq(date, rrule, startDate) {
3552
- const interval = rrule.INTERVAL;
3637
+ const interval = parseInt(rrule.INTERVAL.toString(), 10) || 1;
3553
3638
  switch (rrule.FREQ) {
3554
3639
  case 'YEARLY':
3555
3640
  return (date.getUTCFullYear() - startDate.getUTCFullYear()) % interval === 0;
@@ -3558,12 +3643,12 @@ function matchesFreq(date, rrule, startDate) {
3558
3643
  return months % interval === 0;
3559
3644
  }
3560
3645
  case 'WEEKLY': {
3561
- const daysW = Math.floor((date - startDate) / 86400000);
3646
+ const daysW = Math.floor((date.getTime() - startDate.getTime()) / 86400000);
3562
3647
  const weeks = Math.floor(daysW / 7);
3563
3648
  return weeks % interval === 0;
3564
3649
  }
3565
3650
  case 'DAILY': {
3566
- const days = Math.floor((date - startDate) / 86400000);
3651
+ const days = Math.floor((date.getTime() - startDate.getTime()) / 86400000);
3567
3652
  return days % interval === 0;
3568
3653
  }
3569
3654
  default:
@@ -3580,16 +3665,73 @@ function matchesBYRules(date, rrule) {
3580
3665
  if (rrule.BYYEARDAY && !rrule.BYYEARDAY.includes(getDayOfYear(date))) return false;
3581
3666
  if (rrule.BYMONTHDAY && !rrule.BYMONTHDAY.includes(date.getUTCDate())) return false;
3582
3667
  if (rrule.BYWEEKNO && !rrule.BYWEEKNO.includes(getWeekNumber(date))) return false;
3583
- if (rrule.BYWEEKDAY && !rrule.BYWEEKDAY.includes(date.getUTCDay())) return false;
3668
+ const hasPlainWeekday = !!(rrule.BYWEEKDAY && rrule.BYWEEKDAY.length);
3669
+ const plainWeekdayOk = hasPlainWeekday ? rrule.BYWEEKDAY.includes(date.getUTCDay()) : null;
3670
+ let ordinalOk = null;
3671
+ if (rrule.BYDAY_ORDINALS && Array.isArray(rrule.BYDAY_ORDINALS) && rrule.BYDAY_ORDINALS.length > 0) {
3672
+ const dow = date.getUTCDay();
3673
+ const year = date.getUTCFullYear();
3674
+ const month = date.getUTCMonth();
3675
+ const dayOfYear = getDayOfYear(date);
3676
+ const daysInMonth = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
3677
+ const daysInYear = getDayOfYear(new Date(Date.UTC(year, 11, 31)));
3678
+ const isNthWeekdayOfMonth = (n, weekday) => {
3679
+ if (n === 0) return false;
3680
+ if (n > 0) {
3681
+ const firstOfMonth = new Date(Date.UTC(year, month, 1));
3682
+ const firstDow = firstOfMonth.getUTCDay();
3683
+ const offset = (weekday - firstDow + 7) % 7;
3684
+ const targetDay = 1 + offset + (n - 1) * 7;
3685
+ return targetDay >= 1 && targetDay <= daysInMonth && date.getUTCDate() === targetDay;
3686
+ } else {
3687
+ const lastOfMonth = new Date(Date.UTC(year, month + 1, 0));
3688
+ const lastDow = lastOfMonth.getUTCDay();
3689
+ const backOffset = (lastDow - weekday + 7) % 7;
3690
+ const targetDay = lastOfMonth.getUTCDate() - backOffset + (n + 1) * 7;
3691
+ return targetDay >= 1 && targetDay <= daysInMonth && date.getUTCDate() === targetDay;
3692
+ }
3693
+ };
3694
+ const isNthWeekdayOfYear = (n, weekday) => {
3695
+ if (n === 0) return false;
3696
+ if (n > 0) {
3697
+ const jan1 = new Date(Date.UTC(year, 0, 1));
3698
+ const jan1Dow = jan1.getUTCDay();
3699
+ const offset = (weekday - jan1Dow + 7) % 7;
3700
+ const targetDoy = 1 + offset + (n - 1) * 7;
3701
+ return targetDoy >= 1 && targetDoy <= daysInYear && dayOfYear === targetDoy;
3702
+ } else {
3703
+ const dec31 = new Date(Date.UTC(year, 11, 31));
3704
+ const dec31Dow = dec31.getUTCDay();
3705
+ const backOffset = (dec31Dow - weekday + 7) % 7;
3706
+ const targetDoy = daysInYear - backOffset + (n + 1) * 7;
3707
+ return targetDoy >= 1 && targetDoy <= daysInYear && dayOfYear === targetDoy;
3708
+ }
3709
+ };
3710
+ const anyOrdinalMatch = rrule.BYDAY_ORDINALS.some(({ n, day }) => {
3711
+ if (day !== dow) return false;
3712
+ if (rrule.FREQ === 'MONTHLY') return isNthWeekdayOfMonth(n, day);
3713
+ if (rrule.FREQ === 'YEARLY') {
3714
+ if (rrule.BYMONTH && rrule.BYMONTH.length > 0) return isNthWeekdayOfMonth(n, day);
3715
+ if (!rrule.BYWEEKNO) return isNthWeekdayOfYear(n, day);
3716
+ return false;
3717
+ }
3718
+ return false;
3719
+ });
3720
+ ordinalOk = anyOrdinalMatch;
3721
+ }
3722
+ if (plainWeekdayOk === false && ordinalOk === false) return false;
3723
+ if (plainWeekdayOk === false && ordinalOk === null) return false;
3724
+ if (ordinalOk === false && plainWeekdayOk === null) return false;
3584
3725
  if (rrule.BYHOUR && !rrule.BYHOUR.includes(date.getUTCHours())) return false;
3585
3726
  return true;
3586
3727
  }
3587
3728
  function matchesImplicitRules(date, rrule, startDate) {
3588
3729
  if (!rrule.BYHOUR && date.getUTCHours() !== startDate.getUTCHours()) return false;
3589
- if (rrule.FREQ === 'WEEKLY' && !rrule.BYWEEKDAY && date.getUTCDay() !== startDate.getUTCDay()) return false;
3590
- if (rrule.FREQ === 'MONTHLY' && !rrule.BYMONTHDAY && !rrule.BYWEEKDAY && date.getUTCDate() !== startDate.getUTCDate()) return false;
3730
+ const hasByWeekdayAny = !!(rrule.BYWEEKDAY && rrule.BYWEEKDAY.length) || !!(rrule.BYDAY_ORDINALS && rrule.BYDAY_ORDINALS.length);
3731
+ if (rrule.FREQ === 'WEEKLY' && !hasByWeekdayAny && date.getUTCDay() !== startDate.getUTCDay()) return false;
3732
+ if (rrule.FREQ === 'MONTHLY' && !rrule.BYMONTHDAY && !hasByWeekdayAny && date.getUTCDate() !== startDate.getUTCDate()) return false;
3591
3733
  if (rrule.FREQ === 'YEARLY' && !rrule.BYMONTH && date.getUTCMonth() !== startDate.getUTCMonth()) return false;
3592
- if (rrule.FREQ === 'YEARLY' && !rrule.BYMONTHDAY && !rrule.BYWEEKDAY && !rrule.BYYEARDAY && !rrule.BYWEEKNO && date.getUTCDate() !== startDate.getUTCDate()) return false;
3734
+ if (rrule.FREQ === 'YEARLY' && !rrule.BYMONTHDAY && !hasByWeekdayAny && !rrule.BYYEARDAY && !rrule.BYWEEKNO && date.getUTCDate() !== startDate.getUTCDate()) return false;
3593
3735
  return true;
3594
3736
  }
3595
3737
  function atcb_getNextOccurrence(rruleStr, startDateTime, allday) {
@@ -3608,16 +3750,17 @@ function atcb_getNextOccurrence(rruleStr, startDateTime, allday) {
3608
3750
  let maxIterations = 10000;
3609
3751
  while (true) {
3610
3752
  if (rrule.UNTIL && currentDate > rrule.UNTIL) break;
3611
- if (matchesFreq(currentDate, rrule, startDateTime) && matchesRRule(currentDate, rrule, startDateTime)) {
3753
+ const isMatch = matchesFreq(currentDate, rrule, startDateTime) && matchesRRule(currentDate, rrule, startDateTime);
3754
+ if (isMatch) {
3612
3755
  occurrences.push(currentDate);
3613
3756
  count++;
3614
3757
  if (rrule.COUNT && count >= rrule.COUNT) break;
3615
- if (!rrule.COUNT && !rrule.UNTIL && occurrences.length > 0 && (allday ? currentDate >= now : currentDate > now)) break;
3758
+ if (!rrule.COUNT && !rrule.UNTIL && (allday ? currentDate >= now : currentDate > now)) break;
3616
3759
  }
3617
- currentDate = new Date(currentDate.getTime() + stepMs);
3618
3760
  if (--maxIterations <= 0) {
3619
3761
  break;
3620
3762
  }
3763
+ currentDate = new Date(currentDate.getTime() + stepMs);
3621
3764
  }
3622
3765
  let nextDate = null;
3623
3766
  let countDate = 0;
@@ -3629,8 +3772,15 @@ function atcb_getNextOccurrence(rruleStr, startDateTime, allday) {
3629
3772
  countDate++;
3630
3773
  }
3631
3774
  if (!nextDate) {
3632
- nextDate = occurrences.length > 1 ? occurrences[occurrences.length - 1] : null;
3633
- countDate = countDate - 1;
3775
+ if (occurrences.length > 1) {
3776
+ nextDate = occurrences[occurrences.length - 1];
3777
+ countDate = countDate - 1;
3778
+ } else if (occurrences.length === 1) {
3779
+ nextDate = occurrences[0];
3780
+ } else {
3781
+ nextDate = startDateTime;
3782
+ countDate = 1;
3783
+ }
3634
3784
  }
3635
3785
  return {
3636
3786
  nextOccurrence: nextDate,