@foxy.io/elements 1.45.0-beta.2 → 1.45.0-beta.3

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.
@@ -1,16 +1,16 @@
1
1
  {
2
- "allunits_price_amount_discount_summary": "{{adjustment}}[currency] each after {{from}}",
2
+ "allunits_price_amount_discount_summary": "{{adjustment}}¤ amount each after {{from}}",
3
3
  "allunits_price_percentage_discount_summary": "{{adjustment, percent}} after {{from}}",
4
- "allunits_quantity_amount_discount_summary": "{{adjustment}}[currency] each on orders of {{from}}+",
4
+ "allunits_quantity_amount_discount_summary": "{{adjustment}}¤ amount each on orders of {{from}}+",
5
5
  "allunits_quantity_percentage_discount_summary": "{{adjustment, percent}} on orders of {{from}}+",
6
6
  "date_range_any": "Ongoing",
7
7
  "date_range_complete": "{{start, date}} – {{end, date}}",
8
8
  "date_range_from": "From {{start, date}}",
9
9
  "date_range_until": "Until {{end, date}}",
10
10
  "discount_summary": "{{params, discount}}",
11
- "incremental_price_amount_discount_summary": "{{adjustment}}[currency] each on orders of {{from}}+",
11
+ "incremental_price_amount_discount_summary": "{{adjustment}}¤ amount each on orders of {{from}}+",
12
12
  "incremental_price_percentage_discount_summary": "{{adjustment, percent}} on orders of {{from}}+",
13
- "incremental_quantity_amount_discount_summary": "{{adjustment}}[currency] each on items {{from}}+",
13
+ "incremental_quantity_amount_discount_summary": "{{adjustment}}¤ amount each on items {{from}}+",
14
14
  "incremental_quantity_percentage_discount_summary": "{{adjustment, percent}} on items {{from}}+",
15
15
  "ordinal_few": "rd",
16
16
  "ordinal_many": "th",
@@ -18,13 +18,13 @@
18
18
  "ordinal_other": "th",
19
19
  "ordinal_two": "nd",
20
20
  "ordinal_zero": "th",
21
- "repeat_price_amount_discount_summary": "for each {{from}}, {{adjustment}}[currency] on the next item",
21
+ "repeat_price_amount_discount_summary": "for each {{from}}, {{adjustment}}¤ amount on the next item",
22
22
  "repeat_price_percentage_discount_summary": "for each {{from}}, {{adjustment, percent}} on the next item",
23
- "repeat_quantity_amount_discount_summary": "{{adjustment}}[currency] on each {{from, ordinal}} item",
23
+ "repeat_quantity_amount_discount_summary": "{{adjustment}}¤ amount on each {{from, ordinal}} item",
24
24
  "repeat_quantity_percentage_discount_summary": "{{adjustment, percent}} on each {{from, ordinal}} item",
25
- "single_price_amount_discount_summary": "{{adjustment}}[currency] after {{from}}",
25
+ "single_price_amount_discount_summary": "{{adjustment}}¤ amount after {{from}}",
26
26
  "single_price_percentage_discount_summary": "{{adjustment, percent}} after {{from}}",
27
- "single_quantity_amount_discount_summary": "{{adjustment}}[currency] after {{from}} item(s)",
27
+ "single_quantity_amount_discount_summary": "{{adjustment}}¤ amount after {{from}} item(s)",
28
28
  "single_quantity_percentage_discount_summary": "{{adjustment, percent}} after {{from}} item(s)",
29
29
  "uses_count": "{{count}} uses",
30
30
  "uses_to_total_count": "{{count}}/{{total}} uses",
@@ -145,27 +145,27 @@
145
145
  "tier_repeat": "price of next item",
146
146
  "tier_single": "order total",
147
147
  "tier_then": "then",
148
- "units_amount": "currency",
149
- "units_percentage": "percent",
148
+ "units_amount": "¤ amount",
149
+ "units_percentage": "% percentage",
150
150
  "quantity": "quantity",
151
151
  "total": "total",
152
152
  "reduce": "reduce",
153
153
  "increase": "increase"
154
154
  },
155
- "allunits_price_amount_discount_summary": "{{adjustment}}[currency] each after {{from}}",
155
+ "allunits_price_amount_discount_summary": "{{adjustment}}¤ amount each after {{from}}",
156
156
  "allunits_price_percentage_discount_summary": "{{adjustment, percent}} after {{from}}",
157
- "allunits_quantity_amount_discount_summary": "{{adjustment}}[currency] each on orders of {{from}}+",
157
+ "allunits_quantity_amount_discount_summary": "{{adjustment}}¤ amount each on orders of {{from}}+",
158
158
  "allunits_quantity_percentage_discount_summary": "{{adjustment, percent}} on orders of {{from}}+",
159
- "incremental_price_amount_discount_summary": "{{adjustment}}[currency] each on orders of {{from}}+",
159
+ "incremental_price_amount_discount_summary": "{{adjustment}}¤ amount each on orders of {{from}}+",
160
160
  "incremental_price_percentage_discount_summary": "{{adjustment, percent}} on orders of {{from}}+",
161
- "incremental_quantity_amount_discount_summary": "{{adjustment}}[currency] each on items {{from}}+",
161
+ "incremental_quantity_amount_discount_summary": "{{adjustment}}¤ amount each on items {{from}}+",
162
162
  "incremental_quantity_percentage_discount_summary": "{{adjustment, percent}} on items {{from}}+",
163
- "repeat_price_amount_discount_summary": "for each {{from}}, {{adjustment}}[currency] on the next item",
163
+ "repeat_price_amount_discount_summary": "for each {{from}}, {{adjustment}}¤ amount on the next item",
164
164
  "repeat_price_percentage_discount_summary": "for each {{from}}, {{adjustment, percent}} on the next item",
165
- "repeat_quantity_amount_discount_summary": "{{adjustment}}[currency] on each {{from, ordinal}} item",
166
- "single_price_amount_discount_summary": "{{adjustment}}[currency] after {{from}}",
165
+ "repeat_quantity_amount_discount_summary": "{{adjustment}}¤ amount on each {{from, ordinal}} item",
166
+ "single_price_amount_discount_summary": "{{adjustment}}¤ amount after {{from}}",
167
167
  "single_price_percentage_discount_summary": "{{adjustment, percent}} after {{from}}",
168
- "single_quantity_amount_discount_summary": "{{adjustment}}[currency] after {{from}} items",
168
+ "single_quantity_amount_discount_summary": "{{adjustment}}¤ amount after {{from}} items",
169
169
  "single_quantity_percentage_discount_summary": "{{adjustment, percent}} after {{from}} items",
170
170
  "repeat_quantity_percentage_discount_summary": "{{adjustment, percent}} on each {{from, ordinal}} item",
171
171
  "discount_summary": "Applied discount: {{params, discount}}.",
@@ -7,8 +7,8 @@
7
7
  "tier_repeat": "price of next item",
8
8
  "tier_single": "order total",
9
9
  "tier_then": "then",
10
- "units_amount": "currency",
11
- "units_percentage": "percent",
10
+ "units_amount": "¤ amount",
11
+ "units_percentage": "% percentage",
12
12
  "quantity": "quantity",
13
13
  "total": "total",
14
14
  "reduce": "reduce",
@@ -230,8 +230,8 @@
230
230
  "tier_repeat": "price of next item",
231
231
  "tier_single": "order total",
232
232
  "tier_then": "then",
233
- "units_amount": "currency",
234
- "units_percentage": "percent",
233
+ "units_amount": "¤ amount",
234
+ "units_percentage": "% percentage",
235
235
  "quantity": "quantity",
236
236
  "total": "total",
237
237
  "reduce": "reduce",
@@ -544,7 +544,7 @@
544
544
  "empty": "Modify the item parameters to see the add-to-cart link.",
545
545
  "unavailable": {
546
546
  "loading_extra_data_needed": "Creating direct link...",
547
- "error_special_characters_present": "At the moment we don't support signed direct links with item parameters that contain the following characters: #, &, %, =.",
547
+ "error_special_characters_present": "At the moment we don't support signed direct links with custom option names that contain the following characters: #, &, %, =.",
548
548
  "error_price_configurable": "Direct link is not available when one or more items have configurable price.",
549
549
  "error_duplicate_custom_option_names": "Direct link is not available when one or more items have configurable custom options.",
550
550
  "paused_code_required": "Direct link will be available once you provide an SKU for each item.",
@@ -186,8 +186,8 @@
186
186
  "tier_repeat": "price of next item",
187
187
  "tier_single": "order total",
188
188
  "tier_then": "then",
189
- "units_amount": "currency",
190
- "units_percentage": "percent",
189
+ "units_amount": "¤ amount",
190
+ "units_percentage": "% percentage",
191
191
  "quantity": "quantity",
192
192
  "total": "total",
193
193
  "reduce": "reduce",
@@ -198,8 +198,8 @@
198
198
  "tier_repeat": "price of next item",
199
199
  "tier_single": "order total",
200
200
  "tier_then": "then",
201
- "units_amount": "currency",
202
- "units_percentage": "percent",
201
+ "units_amount": "¤ amount",
202
+ "units_percentage": "% percentage",
203
203
  "quantity": "quantity",
204
204
  "total": "total",
205
205
  "reduce": "reduce",
@@ -301,8 +301,8 @@
301
301
  "tier_repeat": "price of next item",
302
302
  "tier_single": "order total",
303
303
  "tier_then": "then",
304
- "units_amount": "currency",
305
- "units_percentage": "percent",
304
+ "units_amount": "¤ amount",
305
+ "units_percentage": "% percentage",
306
306
  "quantity": "quantity",
307
307
  "total": "total",
308
308
  "reduce": "reduce",
@@ -14,16 +14,23 @@ import hljs from 'highlight.js/lib/core.js';
14
14
  const NS = 'experimental-add-to-cart-builder';
15
15
  const Base = ResponsiveMixin(TranslatableMixin(InternalForm, NS));
16
16
  hljs.registerLanguage('xml', hljsxml);
17
- // TODO use proper encoding when encoding API supports HTML entities
18
- const weakEncode = (value, checkHmacCompatibility) => {
19
- if (checkHmacCompatibility) {
17
+ // Notes about encoding for HMAC signing:
18
+ //
19
+ // API does not support HTML entities in attribute values. Good thing is that
20
+ // encoding is optional for HTML attributes, except for the quote character.
21
+ // Since we use double quotes for attributes, they can't appear in the attribute values.
22
+ //
23
+ // API supports % encoding for URLs, but only in the query parameter values. Query parameter
24
+ // names must never be encoded. This is why we limit the allowed characters in the custom field names.
25
+ function encodeAttributeValue(value, isCartSigningOn) {
26
+ if (isCartSigningOn) {
20
27
  if (decode(value) !== value)
21
28
  throw new Error('error_html_entities_present');
22
29
  if (value.includes('"'))
23
30
  throw new Error('error_double_quotes_present');
24
31
  }
25
32
  return value.replace(/"/g, '"');
26
- };
33
+ }
27
34
  /**
28
35
  * WARNING: this element is marked as experimental and is subject to change in future releases.
29
36
  * We will not be maintaining backwards compatibility for elements in the experimental namespace.
@@ -513,13 +520,14 @@ export class ExperimentalAddToCartBuilder extends Base {
513
520
  throw new Error('loading_extra_data_needed');
514
521
  }
515
522
  const isHmacOn = store.use_cart_validation;
523
+ const encodedAction = encodeAttributeValue(cartUrl, isHmacOn);
516
524
  let hasAtLeastOneFieldset = false;
517
- let output = `<form action="${weakEncode(cartUrl, isHmacOn)}" method="post" target="_blank">`;
525
+ let output = `<form action="${encodedAction}" method="post" target="_blank">`;
518
526
  let level = 1;
519
527
  const newline = () => `\n${' '.repeat(level * 2)}`;
520
528
  const addHiddenInput = (name, value) => {
521
- const encodedValue = weakEncode(value, isHmacOn);
522
- const encodedName = weakEncode(name, isHmacOn);
529
+ const encodedValue = encodeAttributeValue(value, isHmacOn);
530
+ const encodedName = encodeAttributeValue(name, isHmacOn);
523
531
  output += `${newline()}<input type="hidden" name="${encodedName}" value="${encodedValue}">`;
524
532
  };
525
533
  if (templateSet.code !== 'DEFAULT')
@@ -559,7 +567,7 @@ export class ExperimentalAddToCartBuilder extends Base {
559
567
  addHiddenInput(`${prefix}name`, resolvedName);
560
568
  const price = `${product.price}${currencyCode}`;
561
569
  if (product.price_configurable) {
562
- const encodedNoCurrencyPrice = weakEncode(product.price.toFixed(2), isHmacOn);
570
+ const encodedNoCurrencyPrice = encodeAttributeValue(product.price.toFixed(2), isHmacOn);
563
571
  output += `${newline()}<label>`;
564
572
  level++;
565
573
  output += `${newline()}<span>${encode(this.t('preview.price_label'))}</span>`;
@@ -635,17 +643,17 @@ export class ExperimentalAddToCartBuilder extends Base {
635
643
  output += `${newline()}<label>`;
636
644
  level++;
637
645
  output += `${newline()}<span>${encode(this.t('preview.quantity_label'))}</span>`;
638
- const encodedName = weakEncode(`${prefix}quantity`, isHmacOn);
646
+ const encodedName = encodeAttributeValue(`${prefix}quantity`, isHmacOn);
639
647
  output += `${newline()}<input type="number" name="${encodedName}"`;
640
- output += ` min="${weakEncode(String(resolvedMinQty), isHmacOn)}"`;
648
+ output += ` min="${encodeAttributeValue(String(resolvedMinQty), isHmacOn)}"`;
641
649
  if (resolvedMaxQty !== Infinity)
642
- output += ` max="${weakEncode(String(resolvedMaxQty), isHmacOn)}"`;
650
+ output += ` max="${encodeAttributeValue(String(resolvedMaxQty), isHmacOn)}"`;
643
651
  if (store.use_cart_validation) {
644
- const encodedQuantity = weakEncode(String((_e = product.quantity) !== null && _e !== void 0 ? _e : 1), isHmacOn);
652
+ const encodedQuantity = encodeAttributeValue(String((_e = product.quantity) !== null && _e !== void 0 ? _e : 1), isHmacOn);
645
653
  output += ` value="--OPEN--" data-replace="${encodedQuantity}">`;
646
654
  }
647
655
  else {
648
- output += ` value="${weakEncode(String((_f = product.quantity) !== null && _f !== void 0 ? _f : 1), isHmacOn)}">`;
656
+ output += ` value="${encodeAttributeValue(String((_f = product.quantity) !== null && _f !== void 0 ? _f : 1), isHmacOn)}">`;
649
657
  }
650
658
  level--;
651
659
  output += `${newline()}</label>`;
@@ -700,12 +708,12 @@ export class ExperimentalAddToCartBuilder extends Base {
700
708
  output += `${newline()}<label>`;
701
709
  level++;
702
710
  output += `${newline()}<span>${encode(optionName)}:</span>`;
703
- output += `${newline()}<input name="${weakEncode(name, isHmacOn)}" `;
711
+ output += `${newline()}<input name="${encodeAttributeValue(name, isHmacOn)}" `;
704
712
  if (store.use_cart_validation) {
705
- output += `value="--OPEN--" data-replace="${weakEncode(value, isHmacOn)}">`;
713
+ output += `value="--OPEN--" data-replace="${encodeAttributeValue(value, isHmacOn)}">`;
706
714
  }
707
715
  else {
708
- output += `value="${weakEncode(value, isHmacOn)}">`;
716
+ output += `value="${encodeAttributeValue(value, isHmacOn)}">`;
709
717
  }
710
718
  level--;
711
719
  output += `${newline()}</label>`;
@@ -725,7 +733,7 @@ export class ExperimentalAddToCartBuilder extends Base {
725
733
  const optionIndex = product.custom_options.indexOf(option);
726
734
  const itemCategory = (_a = this.__getItemCategoryLoader(productIndex, optionIndex)) === null || _a === void 0 ? void 0 : _a.data;
727
735
  const modifiers = this.__getOptionModifiers(option, itemCategory !== null && itemCategory !== void 0 ? itemCategory : null, currencyCode);
728
- const encodedValue = weakEncode(`${option.value}${modifiers}`, isHmacOn);
736
+ const encodedValue = encodeAttributeValue(`${option.value}${modifiers}`, isHmacOn);
729
737
  const encodedCaption = encode((_b = option.value) !== null && _b !== void 0 ? _b : '');
730
738
  output += `${newline()}<option value="${encodedValue}">${encodedCaption}</option>`;
731
739
  });
@@ -756,21 +764,18 @@ export class ExperimentalAddToCartBuilder extends Base {
756
764
  if (!this.defaultDomain || !templateSet || !store || !currencyCode || !cartUrl) {
757
765
  throw new Error('loading_extra_data_needed');
758
766
  }
759
- const signedUrlParams = new Map();
760
- const unsignedUrlParams = new URLSearchParams();
767
+ const query = new Map();
761
768
  const setOrThrow = (name, value) => {
762
769
  if (store.use_cart_validation) {
763
- if (name.includes('&') ||
764
- value.includes('&') ||
765
- name.includes('%') ||
766
- value.includes('%') ||
767
- name.includes('=') ||
768
- value.includes('='))
770
+ if (['&', '%', '=', '#'].some(c => name.includes(c))) {
769
771
  throw new Error('error_special_characters_present');
770
- signedUrlParams.set(name, value);
772
+ }
773
+ else {
774
+ query.set(name, encodeURIComponent(value));
775
+ }
771
776
  }
772
777
  else {
773
- unsignedUrlParams.set(name, value);
778
+ query.set(encodeURIComponent(name), encodeURIComponent(value));
774
779
  }
775
780
  };
776
781
  if (templateSet.code !== 'DEFAULT')
@@ -883,11 +888,9 @@ export class ExperimentalAddToCartBuilder extends Base {
883
888
  setOrThrow(`${prefix}${option.name}`, `${(_h = option.value) !== null && _h !== void 0 ? _h : ''}${modifiers}`);
884
889
  }
885
890
  }
886
- return store.use_cart_validation
887
- ? `${cartUrl}?${Array.from(signedUrlParams.entries())
888
- .map(([key, value]) => `${key}=${value}`)
889
- .join('&')}`
890
- : `${cartUrl}?${unsignedUrlParams.toString()}`;
891
+ return `${cartUrl}?${Array.from(query.entries())
892
+ .map(([key, value]) => `${key}=${value}`)
893
+ .join('&')}`;
891
894
  }
892
895
  __getAddToCartCode() {
893
896
  var _a;
@@ -915,7 +918,7 @@ export class ExperimentalAddToCartBuilder extends Base {
915
918
  try {
916
919
  linkHref = this.__getAddToCartLinkHref();
917
920
  if (linkHref) {
918
- const linkHTML = `<a href="${weakEncode(linkHref, checkEquality)}">Add to cart</a>`;
921
+ const linkHTML = `<a href="${encodeAttributeValue(linkHref, checkEquality)}">Add to cart</a>`;
919
922
  unsignedCode = `${formHTML}${this.__signingSeparator}${linkHTML}`;
920
923
  }
921
924
  }