add-to-calendar-button 2.6.21 → 2.7.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.
@@ -6,15 +6,15 @@ import { tzlib_get_ical_block, tzlib_get_offset, tzlib_get_timezones } from 'tim
6
6
  * Add to Calendar Button
7
7
  * ++++++++++++++++++++++
8
8
  *
9
- * Version: 2.6.21
9
+ * Version: 2.7.1
10
10
  * Creator: Jens Kuerschner (https://jekuer.com)
11
11
  * Project: https://github.com/add2cal/add-to-calendar-button
12
12
  * License: Elastic License 2.0 (ELv2) (https://github.com/add2cal/add-to-calendar-button/blob/main/LICENSE.txt)
13
13
  * Note: DO NOT REMOVE THE COPYRIGHT NOTICE ABOVE!
14
14
  *
15
15
  */
16
- const atcbVersion = '2.6.21';
17
- const atcbCssTemplate = {
16
+ const atcbVersion = '2.7.1';
17
+ const atcbCssTemplate = {
18
18
  if (typeof window === 'undefined') {
19
19
  return false;
20
20
  } else {
@@ -547,8 +547,9 @@ function atcb_decorate_data_description(data, i) {
547
547
  description = cleanDescription(description);
548
548
  if (data.customVar) {
549
549
  for (const key in data.customVar) {
550
- const sanitizedKey = key.replace(/[^\w\-.]/g, '');
551
- description = description.replace(new RegExp(`%%${sanitizedKey}%%`, 'g'), data.customVar[`${key}`]);
550
+ const sanitizedKey = '%%' + key.replace(/[^\w\-.]/g, '') + '%%';
551
+ // eslint-disable-next-line security/detect-non-literal-regexp
552
+ description = description.replace(new RegExp(sanitizedKey, 'gi'), data.customVar[`${key}`]);
552
553
  }
553
554
  }
554
555
  const descriptionHtmlFree = atcb_rewrite_html_elements(description, true);
@@ -606,9 +607,11 @@ function atcb_decorate_data_extend(data) {
606
607
  }
607
608
  if (data.customVar) {
608
609
  for (const key in data.customVar) {
609
- const sanitizedKey = key.replace(/[^\w\-.]/g, '');
610
- data.dates[`${i}`].name = data.dates[`${i}`].name.replace(new RegExp(`%%${sanitizedKey}%%`, 'g'), data.customVar[`${key}`]);
611
- data.dates[`${i}`].location = data.dates[`${i}`].location.replace(new RegExp(`%%${sanitizedKey}%%`, 'g'), data.customVar[`${key}`]);
610
+ const sanitizedKey = '%%' + key.replace(/[^\w\-.]/g, '') + '%%';
611
+ // eslint-disable-next-line security/detect-non-literal-regexp
612
+ data.dates[`${i}`].name = data.dates[`${i}`].name.replace(new RegExp(sanitizedKey, 'gi'), data.customVar[`${key}`]);
613
+ // eslint-disable-next-line security/detect-non-literal-regexp
614
+ data.dates[`${i}`].location = data.dates[`${i}`].location.replace(new RegExp(sanitizedKey, 'gi'), data.customVar[`${key}`]);
612
615
  }
613
616
  }
614
617
  }
@@ -621,26 +624,31 @@ function atcb_decorate_data_extend(data) {
621
624
  return data;
622
625
  }
623
626
  function atcb_date_cleanup(dateTimeData) {
627
+ function isValidDateFormat(dateStr) {
628
+ return /^\d\d\d\d-\d\d-\d\d(?:T\d\d:\d\d)?(?::\d\d)?(?:.\d\d\d)?Z?$/i.test(dateStr);
629
+ }
630
+ function isValidTodayFormat(dateStr) {
631
+ return /^today(?:\+(?:\d|\d\d|\d\d\d|\d\d\d\d))?$/i.test(dateStr);
632
+ }
624
633
  if (!dateTimeData.endDate || dateTimeData.endDate === '') {
625
634
  dateTimeData.endDate = dateTimeData.startDate;
626
635
  }
627
636
  const endpoints = ['start', 'end'];
628
637
  endpoints.forEach(function (point) {
629
- if (!/^(?:\d{4}-\d{2}-\d{2}T?(?:\d{2}:\d{2})?Z?|today(?:\+\d{1,4})?)$/i.test(dateTimeData[point + 'Date'])) {
638
+ const dateStr = dateTimeData[point + 'Date'];
639
+ if (!isValidDateFormat(dateStr) && !isValidTodayFormat(dateStr)) {
630
640
  dateTimeData[point + 'Date'] = 'badly-formed';
631
641
  } else {
632
- dateTimeData[point + 'Date'] = atcb_date_calculation(dateTimeData[point + 'Date']);
642
+ if (isValidTodayFormat(dateStr)) dateTimeData[point + 'Date'] = atcb_date_calculation(dateStr);
633
643
  if (dateTimeData[point + 'Date']) {
634
- dateTimeData[point + 'Date'] = dateTimeData[point + 'Date'].replace(/\.\d{3}/, '').replace('Z', '');
635
644
  const tmpSplitStartDate = dateTimeData[point + 'Date'].split('T');
636
645
  if (tmpSplitStartDate[1]) {
637
646
  dateTimeData[point + 'Date'] = tmpSplitStartDate[0];
638
647
  dateTimeData[point + 'Time'] = tmpSplitStartDate[1];
639
648
  }
640
649
  }
641
- if (dateTimeData[point + 'Time'] && dateTimeData[point + 'Time'].length === 8) {
642
- const timeStr = dateTimeData[point + 'Time'];
643
- dateTimeData[point + 'Time'] = timeStr.substring(0, timeStr.length - 3);
650
+ if (dateTimeData[point + 'Time'] && dateTimeData[point + 'Time'].length > 5) {
651
+ dateTimeData[point + 'Time'] = dateTimeData[point + 'Time'].substring(0, 5);
644
652
  }
645
653
  }
646
654
  });
@@ -685,12 +693,7 @@ function atcb_date_calculation(dateString) {
685
693
  dateString = dateString.replace(/today/gi, todayString);
686
694
  const dateStringParts = dateString.split('+');
687
695
  const dateParts = dateStringParts[0].split('-');
688
- let newDate = (function () {
689
- if (dateParts[0].length < 4) {
690
- return new Date(Date.UTC(dateParts[2], dateParts[0] - 1, dateParts[1]));
691
- }
692
- return new Date(Date.UTC(dateParts[0], dateParts[1] - 1, dateParts[2]));
693
- })();
696
+ const newDate = new Date(Date.UTC(dateParts[0], dateParts[1] - 1, dateParts[2].substring(0, 2)));
694
697
  if (dateStringParts[1] && dateStringParts[1] > 0) {
695
698
  newDate.setDate(newDate.getDate() + parseInt(dateStringParts[1]));
696
699
  }
@@ -733,19 +736,25 @@ function atcb_decorate_data_button_status_handling(data) {
733
736
  return data;
734
737
  }
735
738
  async function atcb_decorate_data_rsvp(data) {
736
- if (typeof atcb_check_booked_out !== 'function' || !data.rsvp || Object.keys(data.rsvp).length === 0) return data;
739
+ if (typeof atcb_check_bookings !== 'function' || !data.rsvp || !data.proKey || Object.keys(data.rsvp).length === 0) return data;
737
740
  data.rsvp.expired = (function () {
738
741
  if (data.rsvp && data.rsvp.expires && new Date(data.rsvp.expires) < new Date()) {
739
742
  return true;
740
743
  }
741
744
  return false;
742
745
  })();
743
- data.rsvp.bookedOut = await atcb_check_booked_out(data);
744
- if (data.rsvp.expired || data.rsvp.bookedOut) {
745
- data.blockInteraction = true;
746
- }
747
- if (data.blockInteraction) {
748
- data.disabled = true;
746
+ if (data.rsvp.max) {
747
+ const bookings = await atcb_check_bookings(data.proKey, data.dev);
748
+ data.rsvp.seatsLeft = data.rsvp.max - bookings;
749
+ if (data.rsvp.seatsLeft < 1) {
750
+ data.rsvp.bookedOut = true;
751
+ }
752
+ if (data.rsvp.expired || data.rsvp.bookedOut) {
753
+ data.blockInteraction = true;
754
+ }
755
+ if (data.blockInteraction) {
756
+ data.disabled = true;
757
+ }
749
758
  }
750
759
  return data;
751
760
  }
@@ -1484,6 +1493,9 @@ async function atcb_generate_rsvp_form(host, data, hostEl, keyboardTrigger = fal
1484
1493
  ' class="atcb-modal-btn atcb-modal-btn-primary atcb-modal-btn-border">' +
1485
1494
  atcb_translate_hook('submit', data) +
1486
1495
  '</button><span id="pro-form-submitting" class="pro-waiting"><span>.</span><span>.</span><span>.</span></span></p>';
1496
+ if (rsvpData.seatsLeft && rsvpData.seatsLeft > 0) {
1497
+ rsvpContent += '<p class="pro-form-fine">' + atcb_translate_hook('form.seatsleft', data) + ': <b>' + rsvpData.seatsLeft + '</b></p>';
1498
+ }
1487
1499
  rsvpContent += '</form>';
1488
1500
  rsvpContent += '</div></div>';
1489
1501
  let rsvpHost = null;
@@ -1723,24 +1735,20 @@ async function atcb_generate_rsvp_button(host, data) {
1723
1735
  }
1724
1736
  return true;
1725
1737
  }
1726
- async function atcb_check_booked_out(data) {
1727
- if (data.rsvp && data.rsvp.max && data.proKey && data.proKey !== '') {
1728
- try {
1729
- const response = await fetch('https://api.add-to-calendar-pro.com/dffb8bbd-ee5e-4a4f-a7ea-503af98ca468?prokey=' + data.proKey + (data.dev ? '&dev=true' : ''), {
1730
- method: 'GET',
1731
- });
1732
- if (!response.ok) {
1733
- throw new Error('Network response was not ok');
1734
- }
1735
- const responseJson = await response.json();
1736
- if (parseInt(responseJson.total) >= data.rsvp.max) {
1737
- return true;
1738
- }
1739
- } catch (error) {
1740
- console.error('Error:', error);
1738
+ async function atcb_check_bookings(proKey, dev = false) {
1739
+ try {
1740
+ const response = await fetch('https://api.add-to-calendar-pro.com/dffb8bbd-ee5e-4a4f-a7ea-503af98ca468?prokey=' + proKey + (dev ? '&dev=true' : ''), {
1741
+ method: 'GET',
1742
+ });
1743
+ if (!response.ok) {
1744
+ throw new Error('Network response was not ok');
1741
1745
  }
1746
+ const responseJson = await response.json();
1747
+ return parseInt(responseJson.total);
1748
+ } catch (error) {
1749
+ console.error('Error:', error);
1742
1750
  }
1743
- return false;
1751
+ return 0;
1744
1752
  }
1745
1753
  function atcb_build_form(fields, identifier = '', disabled = false) {
1746
1754
  /*!
@@ -2860,7 +2868,7 @@ function atcb_generate_subscribe_links(host, linkType, data, keyboardTrigger) {
2860
2868
  atcb_subscribe_ical(data, data.icsFile);
2861
2869
  break;
2862
2870
  }
2863
- atcb_subscribe_ical(data, adjustedFileUrl);
2871
+ atcb_subscribe_ical(data, adjustedFileUrl, host, keyboardTrigger);
2864
2872
  break;
2865
2873
  case 'google':
2866
2874
  atcb_subscribe_google(data, adjustedFileUrl);
@@ -2929,7 +2937,11 @@ function atcb_set_fully_successful(host, data, multiDateModal = false) {
2929
2937
  atcb_toggle(host, 'close');
2930
2938
  }
2931
2939
  }
2932
- function atcb_subscribe_ical(data, fileUrl) {
2940
+ function atcb_subscribe_ical(data, fileUrl, host = null, keyboardTrigger = false) {
2941
+ if ((atcbIsiOS() || data.fakeIOS) && !atcbIsSafari()) {
2942
+ atcb_ical_copy_note(host, fileUrl, data, keyboardTrigger);
2943
+ return;
2944
+ }
2933
2945
  atcb_open_cal_url(data, 'ical', fileUrl, true);
2934
2946
  }
2935
2947
  function atcb_subscribe_google(data, fileUrl) {
@@ -3254,7 +3266,7 @@ function atcb_generate_ical(host, data, subEvent = 'all', keyboardTrigger = fals
3254
3266
  }
3255
3267
  return 'data:text/calendar;charset=utf-8,' + encodeURIComponent(ics_lines.join('\r\n'));
3256
3268
  })();
3257
- if ((atcbIsiOS() && !atcbIsSafari()) || (atcbIsWebView() && (atcbIsiOS() || (atcbIsAndroid() && atcbIsProblematicWebView())))) {
3269
+ if (((atcbIsiOS() || data.fakeIOS) && !atcbIsSafari()) || (atcbIsWebView() && (atcbIsiOS() || data.fakeIOS || ((atcbIsAndroid() || data.fakeAndroid) && atcbIsProblematicWebView())))) {
3258
3270
  atcb_ical_copy_note(host, dataUrl, data, keyboardTrigger);
3259
3271
  return;
3260
3272
  }
@@ -3280,7 +3292,7 @@ function atcb_determine_ical_filename(data, subEvent) {
3280
3292
  }
3281
3293
  function atcb_ical_copy_note(host, dataUrl, data, keyboardTrigger) {
3282
3294
  atcb_copy_to_clipboard(dataUrl);
3283
- if (atcbIsiOS() && !atcbIsSafari()) {
3295
+ if ((atcbIsiOS() || data.fakeIOS) && !atcbIsSafari()) {
3284
3296
  atcb_create_modal(
3285
3297
  host,
3286
3298
  data,
@@ -4797,27 +4809,26 @@ if (atcbIsBrowser()) {
4797
4809
  }
4798
4810
  this.proOverride = !proOverrideVal || proOverrideVal === 'true' || proOverrideVal === '' ? true : false;
4799
4811
  }
4800
- if ((this.hasAttribute('proKey') && this.getAttribute('proKey') !== '') || (this.hasAttribute('prokey') && this.getAttribute('prokey') !== '')) {
4801
- if (this.hasAttribute('proKey') && this.getAttribute('proKey') !== '') {
4802
- this.data = await atcb_get_pro_data(this.getAttribute('proKey'), this);
4812
+ try {
4813
+ if ((this.hasAttribute('proKey') && this.getAttribute('proKey') !== '') || (this.hasAttribute('prokey') && this.getAttribute('prokey') !== '')) {
4814
+ if (this.hasAttribute('proKey') && this.getAttribute('proKey') !== '') {
4815
+ this.data = await atcb_get_pro_data(this.getAttribute('proKey'), this);
4816
+ } else {
4817
+ this.data = await atcb_get_pro_data(this.getAttribute('prokey'), this);
4818
+ }
4819
+ if (this.data.proKey) this.proKey = this.data.proKey;
4803
4820
  } else {
4804
- this.data = await atcb_get_pro_data(this.getAttribute('prokey'), this);
4805
- }
4806
- if (this.data.proKey) this.proKey = this.data.proKey;
4807
- }
4808
- if (!this.data.name || this.data.name === '') {
4809
- this.data.proKey = '';
4810
- try {
4821
+ this.data.proKey = '';
4811
4822
  this.data = await atcb_process_inline_data(this, this.debug);
4812
- } catch (e) {
4813
- if (this.debug) {
4814
- console.error(e);
4815
- atcb_render_debug_msg(this.shadowRoot, e);
4816
- }
4817
- this.state.initializing = false;
4818
- this.state.ready = true;
4819
- return;
4820
4823
  }
4824
+ } catch (e) {
4825
+ if (this.debug) {
4826
+ console.error(e);
4827
+ atcb_render_debug_msg(this.shadowRoot, e);
4828
+ }
4829
+ this.state.initializing = false;
4830
+ this.state.ready = true;
4831
+ return;
4821
4832
  }
4822
4833
  await this.initButton();
4823
4834
  this.state.initializing = false;
@@ -4872,24 +4883,23 @@ if (atcbIsBrowser()) {
4872
4883
  const elem = document.createElement('template');
4873
4884
  elem.innerHTML = template;
4874
4885
  this.shadowRoot.append(elem.content.cloneNode(true));
4875
- if (this.hasAttribute('proKey') && this.getAttribute('proKey') !== '') {
4876
- this.data = await atcb_get_pro_data(this.getAttribute('proKey'), this);
4877
- if (this.data.proKey) this.proKey = this.data.proKey;
4878
- } else if (this.hasAttribute('prokey') && this.getAttribute('prokey') !== '') {
4879
- this.data = await atcb_get_pro_data(this.getAttribute('prokey'), this);
4880
- if (this.data.proKey) this.proKey = this.data.proKey;
4881
- }
4882
- if (!this.data.name || this.data.name === '') {
4883
- try {
4886
+ try {
4887
+ if (this.hasAttribute('proKey') && this.getAttribute('proKey') !== '') {
4888
+ this.data = await atcb_get_pro_data(this.getAttribute('proKey'), this);
4889
+ if (this.data.proKey) this.proKey = this.data.proKey;
4890
+ } else if (this.hasAttribute('prokey') && this.getAttribute('prokey') !== '') {
4891
+ this.data = await atcb_get_pro_data(this.getAttribute('prokey'), this);
4892
+ if (this.data.proKey) this.proKey = this.data.proKey;
4893
+ } else {
4884
4894
  this.data = await atcb_process_inline_data(this, this.debug);
4885
- } catch (e) {
4886
- if (this.debug) {
4887
- console.error(e);
4888
- atcb_render_debug_msg(this.shadowRoot, e);
4889
- }
4890
- this.updatePending = false;
4891
- return;
4892
4895
  }
4896
+ } catch (e) {
4897
+ if (this.debug) {
4898
+ console.error(e);
4899
+ atcb_render_debug_msg(this.shadowRoot, e);
4900
+ }
4901
+ this.updatePending = false;
4902
+ return;
4893
4903
  }
4894
4904
  atcb_cleanup(this.shadowRoot, this.identifier);
4895
4905
  await this.initButton();
@@ -5220,19 +5230,28 @@ async function atcb_action(inputData, triggerElement, keyboardTrigger = false) {
5220
5230
  if (!atcbIsBrowser()) {
5221
5231
  return;
5222
5232
  }
5223
- let data = await (async function () {
5224
- const cleanedInput = atcb_secure_content(inputData);
5225
- if (cleanedInput.prokey && cleanedInput.prokey !== '') {
5226
- cleanedInput.proKey = cleanedInput.prokey;
5227
- }
5228
- if (cleanedInput.proKey && cleanedInput.proKey !== '') {
5229
- const proData = await atcb_get_pro_data(cleanedInput.proKey, null, cleanedInput);
5230
- if (proData.name && proData.name != '') {
5231
- return proData;
5233
+ let data;
5234
+ try {
5235
+ data = await (async function () {
5236
+ const cleanedInput = atcb_secure_content(inputData);
5237
+ if (cleanedInput.prokey && cleanedInput.prokey !== '') {
5238
+ cleanedInput.proKey = cleanedInput.prokey;
5232
5239
  }
5233
- }
5234
- return cleanedInput;
5235
- })();
5240
+ if (cleanedInput.proKey && cleanedInput.proKey !== '') {
5241
+ try {
5242
+ const proData = await atcb_get_pro_data(cleanedInput.proKey, null, cleanedInput);
5243
+ return proData;
5244
+ } catch (e) {
5245
+ throw new Error(e.message);
5246
+ }
5247
+ } else {
5248
+ return cleanedInput;
5249
+ }
5250
+ })();
5251
+ } catch (e) {
5252
+ console.error(e);
5253
+ return;
5254
+ }
5236
5255
  data.debug = data.debug === 'true';
5237
5256
  try {
5238
5257
  await atcb_check_required(data);
@@ -5370,9 +5389,6 @@ async function atcb_get_pro_data(licenseKey, el = null, directData = {}) {
5370
5389
  const response = await fetch((dataOverrides.dev ? 'https://event-dev.caldn.net/' : 'https://event.caldn.net/') + licenseKey + '/config.json');
5371
5390
  if (response.ok) {
5372
5391
  const data = await response.json();
5373
- if (!data.name || data.name === '') {
5374
- throw new Error('Not possible to read proKey config from server...');
5375
- }
5376
5392
  if (proOverride) {
5377
5393
  atcbWcParams.forEach((key) => {
5378
5394
  if (Object.prototype.hasOwnProperty.call(dataOverrides, key) && ['hideBranding', 'hidebranding', 'rsvp', 'ty'].indexOf(key) === -1) {
@@ -5386,13 +5402,16 @@ async function atcb_get_pro_data(licenseKey, el = null, directData = {}) {
5386
5402
  }
5387
5403
  });
5388
5404
  }
5405
+ if (!data.name || data.name === '') {
5406
+ throw new Error('Not possible to read proKey config from server...');
5407
+ }
5389
5408
  data.proKey = licenseKey;
5390
5409
  data.identifier = licenseKey;
5391
5410
  return data;
5392
5411
  }
5393
5412
  throw new Error('Not possible to read proKey config from server...');
5394
5413
  } catch {
5395
- console.error('Add to Calendar Button proKey invalid or server not responding! Falling back to local data...');
5414
+ throw new Error('Add to Calendar Button proKey invalid or server not responding!');
5396
5415
  }
5397
5416
  }
5398
5417
  return {};