@foxy.io/elements 1.45.0-beta.1 → 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.
Files changed (157) hide show
  1. package/dist/cdn/foxy-access-recovery-form.js +1 -1
  2. package/dist/cdn/foxy-address-card.js +1 -1
  3. package/dist/cdn/foxy-address-form.js +1 -1
  4. package/dist/cdn/foxy-admin-subscription-card.js +1 -1
  5. package/dist/cdn/foxy-admin-subscription-form.js +1 -1
  6. package/dist/cdn/foxy-api-browser.js +1 -1
  7. package/dist/cdn/foxy-applied-coupon-code-card.js +1 -1
  8. package/dist/cdn/foxy-applied-coupon-code-form.js +1 -1
  9. package/dist/cdn/foxy-applied-tax-card.js +1 -1
  10. package/dist/cdn/foxy-attribute-card.js +1 -1
  11. package/dist/cdn/foxy-attribute-form.js +1 -1
  12. package/dist/cdn/foxy-billing-address-card.js +1 -1
  13. package/dist/cdn/foxy-cancellation-form.js +1 -1
  14. package/dist/cdn/foxy-cart-card.js +1 -1
  15. package/dist/cdn/foxy-cart-form.js +1 -1
  16. package/dist/cdn/foxy-client-card.js +1 -1
  17. package/dist/cdn/foxy-client-form.js +1 -1
  18. package/dist/cdn/foxy-collection-page.js +1 -1
  19. package/dist/cdn/foxy-collection-pages.js +1 -1
  20. package/dist/cdn/foxy-coupon-card.js +1 -1
  21. package/dist/cdn/foxy-coupon-code-card.js +1 -1
  22. package/dist/cdn/foxy-coupon-code-form.js +1 -1
  23. package/dist/cdn/foxy-coupon-codes-form.js +1 -1
  24. package/dist/cdn/foxy-coupon-detail-card.js +1 -1
  25. package/dist/cdn/foxy-coupon-form.js +1 -1
  26. package/dist/cdn/foxy-custom-field-card.js +1 -1
  27. package/dist/cdn/foxy-custom-field-form.js +1 -1
  28. package/dist/cdn/foxy-customer-card.js +1 -1
  29. package/dist/cdn/foxy-customer-form.js +1 -1
  30. package/dist/cdn/foxy-customer-portal-settings-form.js +1 -1
  31. package/dist/cdn/foxy-customer-portal.js +1 -1
  32. package/dist/cdn/foxy-customer.js +1 -1
  33. package/dist/cdn/foxy-customers-table.js +1 -1
  34. package/dist/cdn/foxy-discount-card.js +1 -1
  35. package/dist/cdn/foxy-discount-detail-card.js +1 -1
  36. package/dist/cdn/foxy-downloadable-card.js +1 -1
  37. package/dist/cdn/foxy-downloadable-form.js +1 -1
  38. package/dist/cdn/foxy-email-template-card.js +1 -1
  39. package/dist/cdn/foxy-email-template-form.js +1 -1
  40. package/dist/cdn/foxy-error-entry-card.js +1 -1
  41. package/dist/cdn/foxy-experimental-add-to-cart-builder.js +1 -1
  42. package/dist/cdn/foxy-filter-attribute-card.js +1 -1
  43. package/dist/cdn/foxy-filter-attribute-form.js +1 -1
  44. package/dist/cdn/foxy-generate-codes-form.js +1 -1
  45. package/dist/cdn/foxy-gift-card-card.js +1 -1
  46. package/dist/cdn/foxy-gift-card-code-card.js +1 -1
  47. package/dist/cdn/foxy-gift-card-code-form.js +1 -1
  48. package/dist/cdn/foxy-gift-card-code-log-card.js +1 -1
  49. package/dist/cdn/foxy-gift-card-codes-form.js +1 -1
  50. package/dist/cdn/foxy-gift-card-form.js +1 -1
  51. package/dist/cdn/foxy-i18n-editor.js +1 -1
  52. package/dist/cdn/foxy-integration-card.js +1 -1
  53. package/dist/cdn/foxy-integration-form.js +1 -1
  54. package/dist/cdn/foxy-item-card.js +1 -1
  55. package/dist/cdn/foxy-item-category-card.js +1 -1
  56. package/dist/cdn/foxy-item-category-form.js +1 -1
  57. package/dist/cdn/foxy-item-form.js +1 -1
  58. package/dist/cdn/foxy-item-option-card.js +1 -1
  59. package/dist/cdn/foxy-item-option-form.js +1 -1
  60. package/dist/cdn/foxy-native-integration-card.js +1 -1
  61. package/dist/cdn/foxy-native-integration-form.js +1 -1
  62. package/dist/cdn/foxy-nucleon-element.js +1 -1
  63. package/dist/cdn/foxy-pagination.js +1 -1
  64. package/dist/cdn/foxy-passkey-card.js +1 -1
  65. package/dist/cdn/foxy-passkey-form.js +1 -1
  66. package/dist/cdn/foxy-payment-card.js +1 -1
  67. package/dist/cdn/foxy-payment-method-card.js +1 -1
  68. package/dist/cdn/foxy-payments-api-fraud-protection-card.js +1 -1
  69. package/dist/cdn/foxy-payments-api-fraud-protection-form.js +1 -1
  70. package/dist/cdn/foxy-payments-api-payment-method-card.js +1 -1
  71. package/dist/cdn/foxy-payments-api-payment-method-form.js +1 -1
  72. package/dist/cdn/foxy-payments-api-payment-preset-card.js +1 -1
  73. package/dist/cdn/foxy-payments-api-payment-preset-form.js +1 -1
  74. package/dist/cdn/foxy-query-builder.js +1 -1
  75. package/dist/cdn/foxy-report-form.js +1 -1
  76. package/dist/cdn/foxy-reports-table.js +1 -1
  77. package/dist/cdn/foxy-shipment-card.js +1 -1
  78. package/dist/cdn/foxy-shipping-container-card.js +1 -1
  79. package/dist/cdn/foxy-shipping-drop-type-card.js +1 -1
  80. package/dist/cdn/foxy-shipping-method-card.js +1 -1
  81. package/dist/cdn/foxy-shipping-service-card.js +1 -1
  82. package/dist/cdn/foxy-sign-in-form.js +1 -1
  83. package/dist/cdn/foxy-store-card.js +1 -1
  84. package/dist/cdn/foxy-store-form.js +1 -1
  85. package/dist/cdn/foxy-store-shipping-method-form.js +1 -1
  86. package/dist/cdn/foxy-subscription-card.js +1 -1
  87. package/dist/cdn/foxy-subscription-form.js +1 -1
  88. package/dist/cdn/foxy-subscription-settings-form.js +1 -1
  89. package/dist/cdn/foxy-subscriptions-table.js +1 -1
  90. package/dist/cdn/foxy-table.js +1 -1
  91. package/dist/cdn/foxy-tax-card.js +1 -1
  92. package/dist/cdn/foxy-tax-form.js +1 -1
  93. package/dist/cdn/foxy-template-config-form.js +1 -1
  94. package/dist/cdn/foxy-template-form.js +1 -1
  95. package/dist/cdn/foxy-template-set-card.js +1 -1
  96. package/dist/cdn/foxy-template-set-form.js +1 -1
  97. package/dist/cdn/foxy-transaction-card.js +1 -1
  98. package/dist/cdn/foxy-transaction.js +1 -1
  99. package/dist/cdn/foxy-transactions-table.js +1 -1
  100. package/dist/cdn/foxy-update-payment-method-form.js +1 -1
  101. package/dist/cdn/foxy-user-card.js +1 -1
  102. package/dist/cdn/foxy-user-form.js +1 -1
  103. package/dist/cdn/foxy-user-invitation-card.js +1 -1
  104. package/dist/cdn/foxy-user-invitation-form.js +1 -1
  105. package/dist/cdn/foxy-users-table.js +1 -1
  106. package/dist/cdn/foxy-webhook-card.js +1 -1
  107. package/dist/cdn/foxy-webhook-form.js +1 -1
  108. package/dist/cdn/foxy-webhook-log-card.js +1 -1
  109. package/dist/cdn/foxy-webhook-status-card.js +1 -1
  110. package/dist/cdn/{shared-f00cd094.js → shared-05e997ae.js} +1 -1
  111. package/dist/cdn/{shared-d0c1664e.js → shared-0abec247.js} +1 -1
  112. package/dist/cdn/{shared-9b599205.js → shared-0b3dbac6.js} +1 -1
  113. package/dist/cdn/{shared-15a7e329.js → shared-1b04321a.js} +1 -1
  114. package/dist/cdn/{shared-8a83a6eb.js → shared-461a25ae.js} +1 -1
  115. package/dist/cdn/{shared-cee1c6f1.js → shared-4e279e77.js} +1 -1
  116. package/dist/cdn/{shared-e6559d84.js → shared-4e4766ee.js} +1 -1
  117. package/dist/cdn/{shared-d525b69b.js → shared-4f36f302.js} +1 -1
  118. package/dist/cdn/{shared-c4df3a2a.js → shared-52053d0d.js} +1 -1
  119. package/dist/cdn/{shared-57b7386e.js → shared-6783fe5e.js} +1 -1
  120. package/dist/cdn/{shared-da95bb48.js → shared-69074dae.js} +1 -1
  121. package/dist/cdn/{shared-da4f539a.js → shared-7933d898.js} +1 -1
  122. package/dist/cdn/{shared-8f2da12b.js → shared-7f4e3256.js} +1 -1
  123. package/dist/cdn/{shared-b56949d3.js → shared-8ba4b5bf.js} +1 -1
  124. package/dist/cdn/{shared-b4a3d776.js → shared-8bda01cf.js} +1 -1
  125. package/dist/cdn/{shared-6c2a7d2f.js → shared-92c211bd.js} +1 -1
  126. package/dist/cdn/shared-9585cf5b.js +1 -0
  127. package/dist/cdn/shared-96e4f603.js +1 -0
  128. package/dist/cdn/{shared-64c855e5.js → shared-ada2d315.js} +1 -1
  129. package/dist/cdn/{shared-5b93d193.js → shared-adfed461.js} +1 -1
  130. package/dist/cdn/{shared-438e41ab.js → shared-b148b310.js} +1 -1
  131. package/dist/cdn/{shared-090ee4eb.js → shared-b7401886.js} +1 -1
  132. package/dist/cdn/{shared-264fb8a2.js → shared-ba0d1f31.js} +1 -1
  133. package/dist/cdn/{shared-a1f181bf.js → shared-bc89d3fb.js} +1 -1
  134. package/dist/cdn/{shared-8ee6bff5.js → shared-c84bb30e.js} +1 -1
  135. package/dist/cdn/{shared-af39ffd8.js → shared-d674d2ce.js} +1 -1
  136. package/dist/cdn/{shared-597fffaa.js → shared-df92d411.js} +1 -1
  137. package/dist/cdn/{shared-73c199ae.js → shared-f58068b0.js} +1 -1
  138. package/dist/cdn/translations/admin-subscription-form/en.json +2 -2
  139. package/dist/cdn/translations/cart-form/en.json +2 -2
  140. package/dist/cdn/translations/coupon-card/en.json +8 -8
  141. package/dist/cdn/translations/coupon-form/en.json +10 -10
  142. package/dist/cdn/translations/discount-builder/en.json +2 -2
  143. package/dist/cdn/translations/experimental-add-to-cart-builder/en.json +15 -7
  144. package/dist/cdn/translations/item-category-form/en.json +2 -2
  145. package/dist/cdn/translations/item-form/en.json +2 -2
  146. package/dist/cdn/translations/transaction/en.json +2 -2
  147. package/dist/elements/public/ExperimentalAddToCartBuilder/ExperimentalAddToCartBuilder.js +195 -167
  148. package/dist/elements/public/ExperimentalAddToCartBuilder/ExperimentalAddToCartBuilder.js.map +1 -1
  149. package/dist/elements/public/NucleonElement/NucleonElement.js +11 -6
  150. package/dist/elements/public/NucleonElement/NucleonElement.js.map +1 -1
  151. package/dist/elements/public/UserInvitationForm/internal/InternalUserInvitationFormAsyncAction/InternalUserInvitationFormAsyncAction.js +0 -2
  152. package/dist/elements/public/UserInvitationForm/internal/InternalUserInvitationFormAsyncAction/InternalUserInvitationFormAsyncAction.js.map +1 -1
  153. package/dist/utils/get-subscription-status.js +1 -1
  154. package/dist/utils/get-subscription-status.js.map +1 -1
  155. package/package.json +1 -1
  156. package/dist/cdn/shared-02dd05dd.js +0 -1
  157. package/dist/cdn/shared-ada5e9f5.js +0 -1
@@ -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.
@@ -112,10 +119,11 @@ export class ExperimentalAddToCartBuilder extends Base {
112
119
  const addToCartCode = this.__getAddToCartCode();
113
120
  const storeUrl = (_c = (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links['fx:store'].href) !== null && _b !== void 0 ? _b : this.store) !== null && _c !== void 0 ? _c : void 0;
114
121
  const store = (_d = this.__storeLoader) === null || _d === void 0 ? void 0 : _d.data;
122
+ const formHtmlState = (_f = (_e = addToCartCode.formHTMLError) === null || _e === void 0 ? void 0 : _e.split('_')[0]) !== null && _f !== void 0 ? _f : 'paused';
115
123
  return html `
116
124
  <div class="grid gap-m items-start sm-grid-cols-2 md-grid-cols-3 h-full overflow-auto">
117
125
  <foxy-internal-summary-control layout="section" class="space-y-s" infer="items">
118
- ${(_e = this.form.items) === null || _e === void 0 ? void 0 : _e.map((product, index) => {
126
+ ${(_g = this.form.items) === null || _g === void 0 ? void 0 : _g.map((product, index) => {
119
127
  var _a;
120
128
  return html `
121
129
  <foxy-internal-summary-control
@@ -166,9 +174,21 @@ export class ExperimentalAddToCartBuilder extends Base {
166
174
  </foxy-internal-summary-control>
167
175
 
168
176
  <div class="space-y-m md-col-span-2 sticky top-0">
169
- ${addToCartCode && !addToCartCode.error
177
+ <foxy-internal-summary-control infer="preview">
178
+ ${addToCartCode.formHTMLError
170
179
  ? html `
171
- <foxy-internal-summary-control infer="preview">
180
+ <div class="flex flex-col gap-xs items-center justify-center p-xl">
181
+ <foxy-spinner layout="no-label" infer="unavailable" state=${formHtmlState}>
182
+ </foxy-spinner>
183
+ <foxy-i18n
184
+ class="${formHtmlState === 'error' ? 'text-error' : 'text-tertiary'} text-s"
185
+ infer="unavailable"
186
+ key=${addToCartCode.formHTMLError}
187
+ >
188
+ </foxy-i18n>
189
+ </div>
190
+ `
191
+ : html `
172
192
  <div class="flex">
173
193
  <iframe
174
194
  srcdoc="${previewCSS}${addToCartCode.formHTML}"
@@ -244,87 +264,66 @@ export class ExperimentalAddToCartBuilder extends Base {
244
264
  </a>
245
265
  </p>
246
266
  </div>
247
- </foxy-internal-summary-control>
267
+ `}
268
+ </foxy-internal-summary-control>
248
269
 
249
- <foxy-internal-summary-control infer="link">
250
- ${addToCartCode.linkHref
251
- ? html `
252
- <div
253
- class="flex items-center leading-s min-w-0 relative"
254
- style="gap: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px)"
255
- >
256
- <foxy-i18n infer="" key="direct_link"></foxy-i18n>
257
- <a
258
- target="_blank"
259
- style="max-width: 30rem"
260
- href=${addToCartCode.linkHref}
261
- class=${classMap({
262
- 'font-medium truncate ml-auto min-w-0 rounded-s': true,
263
- 'transition-all filter': true,
264
- 'hover-underline': true,
265
- 'focus-outline-none focus-ring-2 focus-ring-primary-50': true,
266
- 'blur-sm': this.__signingState !== 'idle',
267
- })}
268
- >
269
- ${addToCartCode.linkHref}
270
- </a>
271
- <div
272
- style="top: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px); right: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px)"
273
- class=${classMap({
274
- 'absolute right-0 bg-base rounded-s transition-opacity': true,
275
- 'opacity-0 pointer-events-none': this.__signingState !== 'busy',
276
- })}
277
- >
278
- <div class="bg-contrast-10 rounded-s">
279
- <foxy-spinner
280
- infer="spinner"
281
- state=${this.__signingState === 'fail' ? 'error' : 'busy'}
282
- class="-mx-xs"
283
- style="transform: scale(0.8)"
284
- >
285
- </foxy-spinner>
286
- </div>
287
- </div>
288
- <foxy-copy-to-clipboard
289
- infer="copy-to-clipboard"
290
- text=${addToCartCode.linkHref}
291
- class=${classMap({
292
- 'flex-shrink-0 text-m transition-opacity': true,
293
- 'opacity-0 pointer-events-none': this.__signingState === 'busy',
294
- })}
295
- >
296
- </foxy-copy-to-clipboard>
297
- </div>
298
- `
299
- : html `
300
- <p class="text-disabled">
301
- <foxy-i18n infer="" key="unavailable"></foxy-i18n>
302
- </p>
303
- `}
304
- </foxy-internal-summary-control>
305
- `
270
+ <foxy-internal-summary-control infer="link">
271
+ ${addToCartCode.linkHrefError
272
+ ? html `
273
+ <p class="text-tertiary">
274
+ <foxy-i18n infer="unavailable" key=${addToCartCode.linkHrefError}> </foxy-i18n>
275
+ </p>
276
+ `
306
277
  : html `
307
- <foxy-internal-summary-control infer="preview">
308
- <div class="flex flex-col gap-xs items-center justify-center p-xl">
309
- <foxy-spinner
310
- layout="no-label"
311
- infer="unavailable"
312
- state=${(_f = addToCartCode === null || addToCartCode === void 0 ? void 0 : addToCartCode.error.split('_')[0]) !== null && _f !== void 0 ? _f : 'busy'}
278
+ <div
279
+ class="flex items-center leading-s min-w-0 relative"
280
+ style="gap: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px)"
281
+ >
282
+ <foxy-i18n infer="" key="direct_link"></foxy-i18n>
283
+ <a
284
+ target="_blank"
285
+ style="max-width: 30rem"
286
+ href=${addToCartCode.linkHref}
287
+ class=${classMap({
288
+ 'font-medium truncate ml-auto min-w-0 rounded-s': true,
289
+ 'transition-all filter': true,
290
+ 'hover-underline': true,
291
+ 'focus-outline-none focus-ring-2 focus-ring-primary-50': true,
292
+ 'blur-sm': this.__signingState !== 'idle',
293
+ })}
313
294
  >
314
- </foxy-spinner>
315
- <foxy-i18n
295
+ ${addToCartCode.linkHref}
296
+ </a>
297
+ <div
298
+ style="top: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px); right: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px)"
316
299
  class=${classMap({
317
- 'text-tertiary': !(addToCartCode === null || addToCartCode === void 0 ? void 0 : addToCartCode.error.startsWith('error_')),
318
- 'text-error': !!(addToCartCode === null || addToCartCode === void 0 ? void 0 : addToCartCode.error.startsWith('error_')),
319
- 'text-s': true,
300
+ 'absolute right-0 bg-base rounded-s transition-opacity': true,
301
+ 'opacity-0 pointer-events-none': this.__signingState !== 'busy',
320
302
  })}
321
- infer="unavailable"
322
- key="${(_g = addToCartCode === null || addToCartCode === void 0 ? void 0 : addToCartCode.error) !== null && _g !== void 0 ? _g : 'loading_busy'}"
323
303
  >
324
- </foxy-i18n>
304
+ <div class="bg-contrast-10 rounded-s">
305
+ <foxy-spinner
306
+ infer="spinner"
307
+ state=${this.__signingState === 'fail' ? 'error' : 'busy'}
308
+ class="-mx-xs"
309
+ style="transform: scale(0.8)"
310
+ >
311
+ </foxy-spinner>
312
+ </div>
313
+ </div>
314
+ <foxy-copy-to-clipboard
315
+ infer="copy-to-clipboard"
316
+ text=${addToCartCode.linkHref}
317
+ class=${classMap({
318
+ 'flex-shrink-0 text-m transition-opacity': true,
319
+ 'opacity-0 pointer-events-none': this.__signingState === 'busy',
320
+ })}
321
+ >
322
+ </foxy-copy-to-clipboard>
325
323
  </div>
326
- </foxy-internal-summary-control>
327
- `}
324
+ `}
325
+ </foxy-internal-summary-control>
326
+
328
327
  ${this.renderTemplateOrSlot()}
329
328
 
330
329
  <foxy-internal-summary-control infer="cart-settings">
@@ -517,16 +516,18 @@ export class ExperimentalAddToCartBuilder extends Base {
517
516
  const templateSet = this.__resolvedTemplateSet;
518
517
  const cartUrl = this.__resolvedCartUrl;
519
518
  const store = (_a = this.__storeLoader) === null || _a === void 0 ? void 0 : _a.data;
520
- if (!this.defaultDomain || !templateSet || !store || !currencyCode || !cartUrl)
521
- return '';
519
+ if (!this.defaultDomain || !templateSet || !store || !currencyCode || !cartUrl) {
520
+ throw new Error('loading_extra_data_needed');
521
+ }
522
522
  const isHmacOn = store.use_cart_validation;
523
+ const encodedAction = encodeAttributeValue(cartUrl, isHmacOn);
523
524
  let hasAtLeastOneFieldset = false;
524
- let output = `<form action="${weakEncode(cartUrl, isHmacOn)}" method="post" target="_blank">`;
525
+ let output = `<form action="${encodedAction}" method="post" target="_blank">`;
525
526
  let level = 1;
526
527
  const newline = () => `\n${' '.repeat(level * 2)}`;
527
528
  const addHiddenInput = (name, value) => {
528
- const encodedValue = weakEncode(value, isHmacOn);
529
- const encodedName = weakEncode(name, isHmacOn);
529
+ const encodedValue = encodeAttributeValue(value, isHmacOn);
530
+ const encodedName = encodeAttributeValue(name, isHmacOn);
530
531
  output += `${newline()}<input type="hidden" name="${encodedName}" value="${encodedValue}">`;
531
532
  };
532
533
  if (templateSet.code !== 'DEFAULT')
@@ -546,7 +547,7 @@ export class ExperimentalAddToCartBuilder extends Base {
546
547
  const itemCategory = itemCategoryLoader === null || itemCategoryLoader === void 0 ? void 0 : itemCategoryLoader.data;
547
548
  const product = items[productIndex];
548
549
  if (product.item_category_uri && !itemCategory)
549
- return '';
550
+ throw new Error('loading_extra_data_needed');
550
551
  const resolvedMinQty = Math.max(1, (_c = product.quantity_min) !== null && _c !== void 0 ? _c : 1);
551
552
  const resolvedMaxQty = Math.max(resolvedMinQty, (_d = product.quantity_max) !== null && _d !== void 0 ? _d : Infinity);
552
553
  const varyQty = resolvedMinQty !== resolvedMaxQty &&
@@ -566,7 +567,7 @@ export class ExperimentalAddToCartBuilder extends Base {
566
567
  addHiddenInput(`${prefix}name`, resolvedName);
567
568
  const price = `${product.price}${currencyCode}`;
568
569
  if (product.price_configurable) {
569
- const encodedNoCurrencyPrice = weakEncode(product.price.toFixed(2), isHmacOn);
570
+ const encodedNoCurrencyPrice = encodeAttributeValue(product.price.toFixed(2), isHmacOn);
570
571
  output += `${newline()}<label>`;
571
572
  level++;
572
573
  output += `${newline()}<span>${encode(this.t('preview.price_label'))}</span>`;
@@ -589,7 +590,7 @@ export class ExperimentalAddToCartBuilder extends Base {
589
590
  addHiddenInput(`${prefix}code`, product.code);
590
591
  }
591
592
  else if (store.use_cart_validation) {
592
- return { error: 'paused_code_required' };
593
+ throw new Error('paused_code_required');
593
594
  }
594
595
  if (product.parent_code)
595
596
  addHiddenInput(`${prefix}parent_code`, product.parent_code);
@@ -642,17 +643,17 @@ export class ExperimentalAddToCartBuilder extends Base {
642
643
  output += `${newline()}<label>`;
643
644
  level++;
644
645
  output += `${newline()}<span>${encode(this.t('preview.quantity_label'))}</span>`;
645
- const encodedName = weakEncode(`${prefix}quantity`, isHmacOn);
646
+ const encodedName = encodeAttributeValue(`${prefix}quantity`, isHmacOn);
646
647
  output += `${newline()}<input type="number" name="${encodedName}"`;
647
- output += ` min="${weakEncode(String(resolvedMinQty), isHmacOn)}"`;
648
+ output += ` min="${encodeAttributeValue(String(resolvedMinQty), isHmacOn)}"`;
648
649
  if (resolvedMaxQty !== Infinity)
649
- output += ` max="${weakEncode(String(resolvedMaxQty), isHmacOn)}"`;
650
+ output += ` max="${encodeAttributeValue(String(resolvedMaxQty), isHmacOn)}"`;
650
651
  if (store.use_cart_validation) {
651
- 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);
652
653
  output += ` value="--OPEN--" data-replace="${encodedQuantity}">`;
653
654
  }
654
655
  else {
655
- 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)}">`;
656
657
  }
657
658
  level--;
658
659
  output += `${newline()}</label>`;
@@ -707,12 +708,12 @@ export class ExperimentalAddToCartBuilder extends Base {
707
708
  output += `${newline()}<label>`;
708
709
  level++;
709
710
  output += `${newline()}<span>${encode(optionName)}:</span>`;
710
- output += `${newline()}<input name="${weakEncode(name, isHmacOn)}" `;
711
+ output += `${newline()}<input name="${encodeAttributeValue(name, isHmacOn)}" `;
711
712
  if (store.use_cart_validation) {
712
- output += `value="--OPEN--" data-replace="${weakEncode(value, isHmacOn)}">`;
713
+ output += `value="--OPEN--" data-replace="${encodeAttributeValue(value, isHmacOn)}">`;
713
714
  }
714
715
  else {
715
- output += `value="${weakEncode(value, isHmacOn)}">`;
716
+ output += `value="${encodeAttributeValue(value, isHmacOn)}">`;
716
717
  }
717
718
  level--;
718
719
  output += `${newline()}</label>`;
@@ -732,7 +733,7 @@ export class ExperimentalAddToCartBuilder extends Base {
732
733
  const optionIndex = product.custom_options.indexOf(option);
733
734
  const itemCategory = (_a = this.__getItemCategoryLoader(productIndex, optionIndex)) === null || _a === void 0 ? void 0 : _a.data;
734
735
  const modifiers = this.__getOptionModifiers(option, itemCategory !== null && itemCategory !== void 0 ? itemCategory : null, currencyCode);
735
- const encodedValue = weakEncode(`${option.value}${modifiers}`, isHmacOn);
736
+ const encodedValue = encodeAttributeValue(`${option.value}${modifiers}`, isHmacOn);
736
737
  const encodedCaption = encode((_b = option.value) !== null && _b !== void 0 ? _b : '');
737
738
  output += `${newline()}<option value="${encodedValue}">${encodedCaption}</option>`;
738
739
  });
@@ -760,62 +761,78 @@ export class ExperimentalAddToCartBuilder extends Base {
760
761
  const templateSet = this.__resolvedTemplateSet;
761
762
  const cartUrl = this.__resolvedCartUrl;
762
763
  const store = (_a = this.__storeLoader) === null || _a === void 0 ? void 0 : _a.data;
763
- if (!this.defaultDomain || !templateSet || !store || !currencyCode || !cartUrl)
764
- return '';
765
- const url = new URL(cartUrl);
764
+ if (!this.defaultDomain || !templateSet || !store || !currencyCode || !cartUrl) {
765
+ throw new Error('loading_extra_data_needed');
766
+ }
767
+ const query = new Map();
768
+ const setOrThrow = (name, value) => {
769
+ if (store.use_cart_validation) {
770
+ if (['&', '%', '=', '#'].some(c => name.includes(c))) {
771
+ throw new Error('error_special_characters_present');
772
+ }
773
+ else {
774
+ query.set(name, encodeURIComponent(value));
775
+ }
776
+ }
777
+ else {
778
+ query.set(encodeURIComponent(name), encodeURIComponent(value));
779
+ }
780
+ };
766
781
  if (templateSet.code !== 'DEFAULT')
767
- url.searchParams.set('template_set', templateSet.code);
782
+ setOrThrow('template_set', templateSet.code);
768
783
  if (this.form.cart === 'checkout')
769
- url.searchParams.set('cart', 'checkout');
784
+ setOrThrow('cart', 'checkout');
770
785
  if (this.form.redirect)
771
- url.searchParams.set('redirect', this.form.redirect);
786
+ setOrThrow('redirect', this.form.redirect);
772
787
  if (this.form.coupon)
773
- url.searchParams.set('coupon', this.form.coupon);
788
+ setOrThrow('coupon', this.form.coupon);
774
789
  if (this.form.empty && this.form.empty !== 'false') {
775
- url.searchParams.set('empty', this.form.empty);
790
+ setOrThrow('empty', this.form.empty);
776
791
  }
777
792
  for (let index = 0; index < ((_c = (_b = this.form.items) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0); ++index) {
778
793
  const product = this.form.items[index];
779
794
  const prefix = index === 0 ? '' : `${index + 1}:`;
780
795
  const itemCategory = (_d = this.__getItemCategoryLoader(index)) === null || _d === void 0 ? void 0 : _d.data;
781
- if (product.item_category_uri && !itemCategory)
782
- return '';
783
- if (product.price_configurable)
784
- return '';
796
+ if (product.item_category_uri && !itemCategory) {
797
+ throw new Error('loading_extra_data_needed');
798
+ }
799
+ if (product.price_configurable) {
800
+ throw new Error('error_price_configurable');
801
+ }
785
802
  if (new Set(product.custom_options.map(v => v.name)).size < product.custom_options.length) {
786
- return '';
803
+ throw new Error('error_duplicate_custom_option_names');
787
804
  }
788
805
  if (itemCategory && itemCategory.code !== 'DEFAULT') {
789
- url.searchParams.set(`${prefix}category`, itemCategory.code);
806
+ setOrThrow(`${prefix}category`, itemCategory.code);
790
807
  }
791
- url.searchParams.set(`${prefix}name`, product.name);
792
- url.searchParams.set(`${prefix}price`, `${product.price}${currencyCode}`);
808
+ setOrThrow(`${prefix}name`, product.name);
809
+ setOrThrow(`${prefix}price`, `${product.price}${currencyCode}`);
793
810
  if (product.code) {
794
- url.searchParams.set(`${prefix}code`, product.code);
811
+ setOrThrow(`${prefix}code`, product.code);
795
812
  }
796
813
  else if (store.use_cart_validation) {
797
- return { error: 'paused_code_required' };
814
+ throw new Error('paused_code_required');
798
815
  }
799
816
  if (product.parent_code)
800
- url.searchParams.set(`${prefix}parent_code`, product.parent_code);
817
+ setOrThrow(`${prefix}parent_code`, product.parent_code);
801
818
  if (product.image) {
802
- url.searchParams.set(`${prefix}image`, product.image);
819
+ setOrThrow(`${prefix}image`, product.image);
803
820
  if (product.url)
804
- url.searchParams.set(`${prefix}url`, product.url);
821
+ setOrThrow(`${prefix}url`, product.url);
805
822
  }
806
823
  if (product.sub_enabled) {
807
824
  if (product.sub_frequency) {
808
- url.searchParams.set(`${prefix}sub_frequency`, product.sub_frequency);
825
+ setOrThrow(`${prefix}sub_frequency`, product.sub_frequency);
809
826
  if (product.sub_startdate) {
810
827
  if (product.sub_startdate_format === 'yyyymmdd') {
811
828
  const date = new Date(product.sub_startdate);
812
829
  const year = date.getFullYear();
813
830
  const month = (date.getMonth() + 1).toString().padStart(2, '0');
814
831
  const day = date.getDate().toString().padStart(2, '0');
815
- url.searchParams.set(`${prefix}sub_startdate`, `${year}${month}${day}`);
832
+ setOrThrow(`${prefix}sub_startdate`, `${year}${month}${day}`);
816
833
  }
817
834
  else {
818
- url.searchParams.set(`${prefix}sub_startdate`, String(product.sub_startdate));
835
+ setOrThrow(`${prefix}sub_startdate`, String(product.sub_startdate));
819
836
  }
820
837
  }
821
838
  if (product.sub_enddate) {
@@ -824,94 +841,105 @@ export class ExperimentalAddToCartBuilder extends Base {
824
841
  const year = date.getFullYear();
825
842
  const month = (date.getMonth() + 1).toString().padStart(2, '0');
826
843
  const day = date.getDate().toString().padStart(2, '0');
827
- url.searchParams.set(`${prefix}sub_enddate`, `${year}${month}${day}`);
844
+ setOrThrow(`${prefix}sub_enddate`, `${year}${month}${day}`);
828
845
  }
829
846
  else {
830
- url.searchParams.set(`${prefix}sub_enddate`, String(product.sub_enddate));
847
+ setOrThrow(`${prefix}sub_enddate`, String(product.sub_enddate));
831
848
  }
832
849
  }
833
850
  }
834
851
  }
835
852
  if (product.discount_name && product.discount_type && product.discount_details) {
836
- url.searchParams.set(`${prefix}discount_${product.discount_type}`, `${product.discount_name}{${product.discount_details}}`);
853
+ setOrThrow(`${prefix}discount_${product.discount_type}`, `${product.discount_name}{${product.discount_details}}`);
837
854
  }
838
855
  if (product.expires_value) {
839
856
  if (product.expires_format === 'timestamp') {
840
- url.searchParams.set(`${prefix}expires`, product.expires_value.toFixed(0));
857
+ setOrThrow(`${prefix}expires`, product.expires_value.toFixed(0));
841
858
  }
842
859
  else {
843
- url.searchParams.set(`${prefix}expires`, product.expires_value.toFixed(0));
860
+ setOrThrow(`${prefix}expires`, product.expires_value.toFixed(0));
844
861
  }
845
862
  }
846
863
  if (((_e = product.quantity) !== null && _e !== void 0 ? _e : 1) > 1) {
847
- url.searchParams.set(`${prefix}quantity`, ((_f = product.quantity) !== null && _f !== void 0 ? _f : 1).toFixed(0));
864
+ setOrThrow(`${prefix}quantity`, ((_f = product.quantity) !== null && _f !== void 0 ? _f : 1).toFixed(0));
848
865
  }
849
866
  if (product.expires_format !== 'minutes') {
850
867
  if (product.quantity_min) {
851
- url.searchParams.set(`${prefix}quantity_min`, product.quantity_min.toString());
868
+ setOrThrow(`${prefix}quantity_min`, product.quantity_min.toString());
852
869
  }
853
870
  if (product.quantity_max) {
854
- url.searchParams.set(`${prefix}quantity_max`, product.quantity_max.toString());
871
+ setOrThrow(`${prefix}quantity_max`, product.quantity_max.toString());
855
872
  }
856
873
  }
857
874
  if (product.weight)
858
- url.searchParams.set(`${prefix}weight`, product.weight.toFixed(3));
875
+ setOrThrow(`${prefix}weight`, product.weight.toFixed(3));
859
876
  if (product.length)
860
- url.searchParams.set(`${prefix}length`, product.length.toFixed(3));
877
+ setOrThrow(`${prefix}length`, product.length.toFixed(3));
861
878
  if (product.width)
862
- url.searchParams.set(`${prefix}width`, product.width.toFixed(3));
879
+ setOrThrow(`${prefix}width`, product.width.toFixed(3));
863
880
  if (product.height)
864
- url.searchParams.set(`${prefix}height`, product.height.toFixed(3));
881
+ setOrThrow(`${prefix}height`, product.height.toFixed(3));
865
882
  for (let optionIndex = 0; optionIndex < product.custom_options.length; ++optionIndex) {
866
883
  const option = product.custom_options[optionIndex];
867
884
  if (option.value_configurable)
868
- return '';
885
+ throw new Error('error_option_value_configurable');
869
886
  const itemCategory = (_g = this.__getItemCategoryLoader(index, optionIndex)) === null || _g === void 0 ? void 0 : _g.data;
870
887
  const modifiers = this.__getOptionModifiers(option, itemCategory !== null && itemCategory !== void 0 ? itemCategory : null, currencyCode);
871
- url.searchParams.set(`${prefix}${option.name}`, `${(_h = option.value) !== null && _h !== void 0 ? _h : ''}${modifiers}`);
888
+ setOrThrow(`${prefix}${option.name}`, `${(_h = option.value) !== null && _h !== void 0 ? _h : ''}${modifiers}`);
872
889
  }
873
890
  }
874
- return url.toString();
891
+ return `${cartUrl}?${Array.from(query.entries())
892
+ .map(([key, value]) => `${key}=${value}`)
893
+ .join('&')}`;
875
894
  }
876
895
  __getAddToCartCode() {
877
896
  var _a;
897
+ const store = (_a = this.__storeLoader) === null || _a === void 0 ? void 0 : _a.data;
898
+ if (!this.encodeHelper || !store) {
899
+ return {
900
+ linkHref: '',
901
+ linkHrefError: 'loading_extra_data_needed',
902
+ formHTML: '',
903
+ formHTMLError: 'loading_extra_data_needed',
904
+ };
905
+ }
906
+ const checkEquality = store.use_cart_validation;
907
+ let formHTMLError = null;
908
+ let linkHrefError = null;
909
+ let formHTML = '';
910
+ let linkHref = '';
911
+ try {
912
+ formHTML = this.__getAddToCartFormHTML();
913
+ }
914
+ catch (err) {
915
+ formHTMLError = err.message;
916
+ }
917
+ let unsignedCode = formHTML;
878
918
  try {
879
- const store = (_a = this.__storeLoader) === null || _a === void 0 ? void 0 : _a.data;
880
- if (!this.encodeHelper || !store)
881
- return null;
882
- const checkEquality = store.use_cart_validation;
883
- const formHTML = this.__getAddToCartFormHTML();
884
- const linkHref = this.__getAddToCartLinkHref();
885
- if (!formHTML && !linkHref)
886
- return null;
887
- if (typeof formHTML === 'object')
888
- return { error: formHTML.error };
889
- if (typeof linkHref === 'object')
890
- return { error: linkHref.error };
891
- let unsignedCode;
919
+ linkHref = this.__getAddToCartLinkHref();
892
920
  if (linkHref) {
893
- const linkHTML = `<a href="${weakEncode(linkHref, checkEquality)}">Add to cart</a>`;
921
+ const linkHTML = `<a href="${encodeAttributeValue(linkHref, checkEquality)}">Add to cart</a>`;
894
922
  unsignedCode = `${formHTML}${this.__signingSeparator}${linkHTML}`;
895
923
  }
896
- else {
897
- unsignedCode = formHTML;
898
- }
899
- if (unsignedCode === this.__previousUnsignedCode && this.__previousSignedCode) {
900
- const [formHTML, linkHTML] = this.__previousSignedCode.split(this.__signingSeparator);
901
- return {
902
- linkHref: linkHTML ? decode(linkHTML.substring(9, linkHTML.length - 17)) : '',
903
- formHTML,
904
- };
905
- }
906
- this.__previousUnsignedCode = unsignedCode;
907
- this.__previousSignedCode = '';
908
- if (store.use_cart_validation)
909
- this.__signAsync(unsignedCode, this.encodeHelper);
910
- return { formHTML, linkHref };
911
924
  }
912
925
  catch (err) {
913
- return { error: err.message };
926
+ linkHrefError = err.message;
927
+ linkHref = '';
914
928
  }
929
+ if (unsignedCode === this.__previousUnsignedCode && this.__previousSignedCode) {
930
+ const [formHTML, linkHTML] = this.__previousSignedCode.split(this.__signingSeparator);
931
+ return {
932
+ linkHref: linkHTML ? decode(linkHTML.substring(9, linkHTML.length - 17)) : '',
933
+ linkHrefError,
934
+ formHTML,
935
+ formHTMLError,
936
+ };
937
+ }
938
+ this.__previousUnsignedCode = unsignedCode;
939
+ this.__previousSignedCode = '';
940
+ if (store.use_cart_validation)
941
+ this.__signAsync(unsignedCode, this.encodeHelper);
942
+ return { formHTML, formHTMLError, linkHref, linkHrefError };
915
943
  }
916
944
  __getOptionModifiers(option, optionItemCategory, currencyCode) {
917
945
  if (option.value_configurable)