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