@teddy-dev/frontend 1.0.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.
- package/algolia/algolia-loader.js +56 -0
- package/algolia/algolia-search.js +222 -0
- package/auth/teddy-auth-login.js +29 -0
- package/auth/teddy-auth-profile.js +58 -0
- package/auth/teddy-auth-register.js +52 -0
- package/auth/teddy-auth-reset.js +39 -0
- package/auth/teddy-auth.js +92 -0
- package/bantoa/bantoa-product.js +64 -0
- package/bantoa/bantoa-search.js +46 -0
- package/bantoa/bantoa-stylemix.js +43 -0
- package/bantoa/bantoa.js +21 -0
- package/cart/teddy-cart-controller.js +163 -0
- package/cart/teddy-cart-customer.js +86 -0
- package/cart/teddy-cart-discounts.js +55 -0
- package/cart/teddy-cart-promo-apply.js +24 -0
- package/cart/teddy-cart-promo-error.js +38 -0
- package/cart/teddy-cart-promo-loading.js +20 -0
- package/cart/teddy-cart-promo.js +96 -0
- package/components/mc-btn.js +38 -0
- package/components/mc-card-render.js +33 -0
- package/components/mc-cart-counter.js +14 -0
- package/components/mc-cart-error.js +35 -0
- package/components/mc-cart-quantity.js +43 -0
- package/components/mc-cart-remove.js +32 -0
- package/components/mc-copy.js +33 -0
- package/components/mc-element.js +84 -0
- package/components/mc-form-errors.js +35 -0
- package/components/mc-form-success.js +31 -0
- package/components/mc-form.js +223 -0
- package/components/mc-input-area.js +13 -0
- package/components/mc-input-checkbox-group.js +52 -0
- package/components/mc-input-checkbox.js +12 -0
- package/components/mc-input-password.js +39 -0
- package/components/mc-input-places.js +43 -0
- package/components/mc-input-quantity.js +43 -0
- package/components/mc-input-select.js +14 -0
- package/components/mc-input-text.js +12 -0
- package/components/mc-input.js +137 -0
- package/components/mc-loader.js +21 -0
- package/components/mc-modal.js +69 -0
- package/components/mc-password-eye.js +24 -0
- package/components/mc-password-tips.js +60 -0
- package/components/mc-qrcode.js +41 -0
- package/components/mc-range.js +108 -0
- package/components/mc-read-more.js +56 -0
- package/components/mc-recommended.js +50 -0
- package/components/mc-referrer.js +20 -0
- package/components/mc-splash-controller.js +32 -0
- package/components/mc-splash-link.js +65 -0
- package/components/mc-stoq.js +30 -0
- package/components/mc-swiper.js +333 -0
- package/components/mc-video.js +61 -0
- package/css/bootstrap-lg.css +2762 -0
- package/css/bootstrap-lg.min.css +1 -0
- package/css/bootstrap-md.css +2762 -0
- package/css/bootstrap-md.min.css +1 -0
- package/css/bootstrap-sm.css +2762 -0
- package/css/bootstrap-sm.min.css +1 -0
- package/css/bootstrap-xl.css +2790 -0
- package/css/bootstrap-xl.min.css +1 -0
- package/css/bootstrap-xxl.css +2762 -0
- package/css/bootstrap-xxl.min.css +1 -0
- package/css/bootstrap.css +9824 -0
- package/css/bootstrap.min.css +5 -0
- package/css/mc-form-errors.css +3 -0
- package/css/mc-loader.css +6 -0
- package/css/mc-password-eye.css +6 -0
- package/css/mc-password-tips.css +6 -0
- package/css/mc-read-more.css +14 -0
- package/css/mc-video.css +4 -0
- package/css/mc-wishlist-hero-btn.css +7 -0
- package/loader.js +110 -0
- package/loyalty/teddy-loyalty-create.js +40 -0
- package/loyalty/teddy-loyalty-redeem.js +38 -0
- package/loyalty/teddy-loyalty.js +214 -0
- package/package.json +20 -0
- package/res/mc-events.js +43 -0
- package/res/mc-shopify.js +439 -0
- package/res/mc-utils.js +119 -0
- package/res/mc-vue.js +9350 -0
- package/returns/teddy-return-iban.js +115 -0
- package/returns/teddy-return-list.js +165 -0
- package/returns/teddy-return-request.js +353 -0
- package/scripts/publish-store.js +62 -0
- package/test/auth-login-error.json +4 -0
- package/test/auth-login-success.json +13 -0
- package/test/auth-password-change-error.json +4 -0
- package/test/auth-password-change-success.json +3 -0
- package/test/auth-register-error.json +4 -0
- package/test/auth-register-success.json +12 -0
- package/test/auth-reset-error.json +4 -0
- package/test/auth-reset-success.json +3 -0
- package/test/loyalty-error.json +4 -0
- package/test/loyalty-noinfo.json +18 -0
- package/test/loyalty-redeem-error.json +4 -0
- package/test/loyalty-redeem-success.json +11 -0
- package/test/loyalty-success.json +143 -0
- package/test/returns-create-success.json +1 -0
- package/test/returns-get-success.json +35 -0
- package/test/returns-get-tracking.json +30 -0
- package/test/returns-list-empty.json +4 -0
- package/test/returns-list-success.json +59 -0
- package/test/returns-search-manual.json +67 -0
- package/test/returns-search-success.json +76 -0
- package/test/wishlist-error.json +4 -0
- package/test/wishlist-success.json +3 -0
- package/wishlist/teddy-wishlist-btn.js +55 -0
- package/wishlist/teddy-wishlist-clear.js +18 -0
- package/wishlist/teddy-wishlist-counter.js +35 -0
- package/wishlist/teddy-wishlist-item.js +46 -0
- package/wishlist/teddy-wishlist-page.js +59 -0
- package/wishlist/teddy-wishlist.js +131 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import '../res/mc-events.js';
|
|
2
|
+
await loadComponent('./components/mc-element.js', false);
|
|
3
|
+
await loadComponent('./components/mc-input-quantity.js', false);
|
|
4
|
+
await loadComponent('./res/mc-shopify.js', false);
|
|
5
|
+
|
|
6
|
+
class McCartQuantity extends McElement {
|
|
7
|
+
|
|
8
|
+
connectedCallback() {
|
|
9
|
+
if(!this.hasAttribute('data-key')) {
|
|
10
|
+
console.error('McCartQuantity component requires a data-key attribute.');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
const input = this.querySelector('mc-input-quantity');
|
|
16
|
+
if(!input) {
|
|
17
|
+
console.error('McCartQuantity component requires an mc-input-quantity element inside.');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
input.addEventListener(MCEVENTS.QUANTITY_CHANGED, this.changeItem.bind(this));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
changeItem = (e) => {
|
|
25
|
+
console.log('McCartQuantity changeItem', e.detail);
|
|
26
|
+
const key = this.getAttribute('data-key');
|
|
27
|
+
if (!key) return;
|
|
28
|
+
|
|
29
|
+
const quantity = parseInt(e.detail.value);
|
|
30
|
+
if (!quantity || isNaN(quantity)) return;
|
|
31
|
+
|
|
32
|
+
McShopify.updateCartLine({
|
|
33
|
+
id: key,
|
|
34
|
+
quantity: quantity
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!customElements.get('mc-cart-quantity')) {
|
|
40
|
+
customElements.define('mc-cart-quantity', McCartQuantity);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
window.McCartQuantity = McCartQuantity;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
await loadComponent('./components/mc-element.js', false);
|
|
2
|
+
await loadComponent('./res/mc-shopify.js', false);
|
|
3
|
+
|
|
4
|
+
class McCartRemove extends McElement {
|
|
5
|
+
|
|
6
|
+
connectedCallback() {
|
|
7
|
+
if(!this.hasAttribute('data-key')) {
|
|
8
|
+
console.error('McCartRemove component requires a data-key attribute.');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
this.addEventListener('click', () => {
|
|
12
|
+
this.removeItem();
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
removeItem = () => {
|
|
17
|
+
const key = this.getAttribute('data-key');
|
|
18
|
+
if (!key) return;
|
|
19
|
+
|
|
20
|
+
McShopify.updateCartLine({
|
|
21
|
+
id: key,
|
|
22
|
+
quantity: 0
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!customElements.get('mc-cart-remove')) {
|
|
29
|
+
customElements.define('mc-cart-remove', McCartRemove);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
window.McCartRemove = McCartRemove;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
await loadComponent('./components/mc-element.js', false);
|
|
2
|
+
|
|
3
|
+
class McCopy extends McElement {
|
|
4
|
+
text; toast;
|
|
5
|
+
|
|
6
|
+
connectedCallback() {
|
|
7
|
+
this.text = this.dataset.text || this.textContent;
|
|
8
|
+
if(!this.text) { console.error('McCopy: No text to copy'); return; }
|
|
9
|
+
|
|
10
|
+
this.addEventListener('click', () => this.copy());
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
copy = () => {
|
|
14
|
+
navigator.clipboard.writeText(this.text);
|
|
15
|
+
const toastElement = document.querySelector(this.dataset.toast);
|
|
16
|
+
const popoverElement = document.querySelector(this.dataset.popover);
|
|
17
|
+
console.log(toastElement);
|
|
18
|
+
if (toastElement) {
|
|
19
|
+
const toast = bootstrap.Toast.getOrCreateInstance(toastElement);
|
|
20
|
+
toast.show();
|
|
21
|
+
}
|
|
22
|
+
if (popoverElement) {
|
|
23
|
+
const popover = bootstrap.Popover.getOrCreateInstance(popoverElement);
|
|
24
|
+
popover.show();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
if (!window.customElements.get("mc-copy")) {
|
|
30
|
+
window.customElements.define("mc-copy", McCopy);
|
|
31
|
+
}
|
|
32
|
+
window.McCopy = McCopy;
|
|
33
|
+
export default McCopy;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Questa classe base `McElement` estende HTMLElement e fornisce funzionalità comuni per web component personalizzati.
|
|
2
|
+
// Lo scopo principale è essere estesa da altri componenti custom che necessitano di ricaricare dinamicamente il proprio contenuto tramite chiamate HTTP.
|
|
3
|
+
// Non richiede data attributes o elementi HTML specifici: i metodi sono pensati per essere usati dalle sottoclassi.
|
|
4
|
+
|
|
5
|
+
import '../res/mc-events.js';
|
|
6
|
+
await loadComponent('./res/mc-utils.js', false);
|
|
7
|
+
await loadComponent('./res/mc-shopify.js', false);
|
|
8
|
+
|
|
9
|
+
class McElement extends HTMLElement {
|
|
10
|
+
|
|
11
|
+
// Metodo per ricaricare dinamicamente il contenuto dell'elemento tramite una richiesta GET.
|
|
12
|
+
// Parametri:
|
|
13
|
+
// - url: URL da cui caricare il nuovo contenuto (default: pagina corrente)
|
|
14
|
+
// - onSuccess: funzione callback chiamata in caso di successo
|
|
15
|
+
// - onError: funzione callback chiamata in caso di errore
|
|
16
|
+
// - onComplete: funzione callback chiamata al termine della richiesta
|
|
17
|
+
reload = ({
|
|
18
|
+
url=location.href, // URL da cui caricare il nuovo contenuto (default: pagina corrente)
|
|
19
|
+
onSuccess, // Funzione da chiamare in caso di successo
|
|
20
|
+
onError, // Funzione da chiamare in caso di errore
|
|
21
|
+
onComplete // Funzione da chiamare al termine della richiesta
|
|
22
|
+
}) => {
|
|
23
|
+
if(!url || typeof url !== 'string') { console.error('McElement.reload: Il parametro "url" deve essere una stringa valida.'); return; }
|
|
24
|
+
|
|
25
|
+
axios({
|
|
26
|
+
url: url,
|
|
27
|
+
method: 'GET',
|
|
28
|
+
}).then(response => {
|
|
29
|
+
// Aggiorna il contenuto dell'elemento usando la funzione utility McUtils.reloadElement
|
|
30
|
+
McUtils.reloadElement(response.data, this, this.getSelector());
|
|
31
|
+
if(typeof onSuccess === 'function') { onSuccess(response.data); }
|
|
32
|
+
}).catch(error => {
|
|
33
|
+
if(typeof onError === 'function') { onError(error); }
|
|
34
|
+
}).finally(() => {
|
|
35
|
+
if(typeof onComplete === 'function') { onComplete(); }
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Restituisce un selettore CSS univoco per questo elemento (id, classi e attributi)
|
|
40
|
+
getSelector = () => {
|
|
41
|
+
if(this.id) {
|
|
42
|
+
return `#${this.id}`;
|
|
43
|
+
}
|
|
44
|
+
let selector = this.tagName.toLowerCase();
|
|
45
|
+
if(this.classList.length > 0) {
|
|
46
|
+
selector += this.classList.map(c => `.${c}`).join('');
|
|
47
|
+
}
|
|
48
|
+
if(this.attributes.length > 0) {
|
|
49
|
+
selector += Array.from(this.attributes).map(attr => `[${attr.name}="${attr.value}"]`).join('');
|
|
50
|
+
}
|
|
51
|
+
return selector;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
activate = () => {
|
|
55
|
+
this.classList.add('active'); // Aggiunge la classe 'active' per lo stile
|
|
56
|
+
McShopify.customEvent(MCEVENTS.EL_ACTIVATED, null, this);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
deactivate = () => {
|
|
60
|
+
this.classList.remove('active'); // Rimuove la classe 'active' per lo stile
|
|
61
|
+
McShopify.customEvent(MCEVENTS.EL_DEACTIVATED, null, this);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
toggle = () => {
|
|
65
|
+
this.isActive() ? this.deactivate() : this.activate();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
isActive = () => {
|
|
69
|
+
return this.classList.contains('active');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
constructor() {
|
|
73
|
+
super(); // Chiama il costruttore della classe base HTMLElement
|
|
74
|
+
if(this.dataset.active != undefined)
|
|
75
|
+
this.activate(); // Attiva l'elemento se il data attribute "active" è presente
|
|
76
|
+
else
|
|
77
|
+
this.deactivate(); // Altrimenti lo disattiva
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Espone la classe McElement come globale e come modulo, pronta per essere estesa da altri web component
|
|
83
|
+
window.McElement = McElement;
|
|
84
|
+
export default McElement;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
await loadComponent('./components/mc-element.js', false);
|
|
2
|
+
await loadComponent('./res/mc-utils.js', false);
|
|
3
|
+
|
|
4
|
+
class McFormErrors extends McElement {
|
|
5
|
+
|
|
6
|
+
connectedCallback() {
|
|
7
|
+
this.checkErrors();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
checkErrors = () => {
|
|
11
|
+
if (this.innerHTML.length > 0) {
|
|
12
|
+
this.activate();
|
|
13
|
+
} else {
|
|
14
|
+
this.deactivate();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
clear = () => {
|
|
19
|
+
this.innerHTML = '';
|
|
20
|
+
this.deactivate();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
showError = (content) => {
|
|
24
|
+
this.innerHTML = content;
|
|
25
|
+
this.activate();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!customElements.get('mc-form-errors')) {
|
|
30
|
+
customElements.define('mc-form-errors', McFormErrors);
|
|
31
|
+
McUtils.addCss(`https://cdn.jsdelivr.net/npm/teddy-frontend@${theme.version}/css/mc-form-errors.css`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
window.McFormErrors = McFormErrors;
|
|
35
|
+
export default McFormErrors;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
await loadComponent('./components/mc-element.js', false);
|
|
2
|
+
|
|
3
|
+
class McFormSuccess extends McElement {
|
|
4
|
+
|
|
5
|
+
connectedCallback() {
|
|
6
|
+
this.checkMessages();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
checkMessages = () => {
|
|
10
|
+
if (this.innerHTML.length > 0) {
|
|
11
|
+
this.activate();
|
|
12
|
+
} else {
|
|
13
|
+
this.deactivate();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
clear = () => {
|
|
18
|
+
this.innerHTML = '';
|
|
19
|
+
this.deactivate();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
showMessage = (content) => {
|
|
23
|
+
this.innerHTML = content;
|
|
24
|
+
this.activate();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!customElements.get('mc-form-success')) {
|
|
29
|
+
customElements.define('mc-form-success', McFormSuccess);
|
|
30
|
+
}
|
|
31
|
+
window.McFormSuccess = McFormSuccess;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import '../res/mc-events.js';
|
|
2
|
+
await loadComponent('./components/mc-element.js', false);
|
|
3
|
+
await loadComponent('./res/mc-utils.js', false);
|
|
4
|
+
await loadComponent('./res/mc-shopify.js', false);
|
|
5
|
+
await loadComponent('./components/mc-form-errors.js', false); // Carica il componente Input
|
|
6
|
+
await loadComponent('./components/mc-input.js', false); // Carica il componente Input
|
|
7
|
+
|
|
8
|
+
class McForm extends McElement {
|
|
9
|
+
form; inputs; isValid; buttons; data; options; errors;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
// Metodo chiamato automaticamente quando l'elemento viene aggiunto al DOM
|
|
13
|
+
connectedCallback() {
|
|
14
|
+
this.init(); // Inizializza il form
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Inizializza il form e i suoi elementi
|
|
18
|
+
init = () => {
|
|
19
|
+
this.form = this.querySelector('form'); // Seleziona il form
|
|
20
|
+
if (!this.form) { console.error('McForm: No form element found'); return; }
|
|
21
|
+
|
|
22
|
+
this.inputs = this.querySelectorAll('mc-input-text, mc-input-checkbox, mc-input-select, mc-input-area, mc-input-checkbox-group, mc-input-password'); // Seleziona gli input
|
|
23
|
+
this.inputs = [...this.inputs, ...this.form.querySelectorAll(`mc-input-text[form="${this.form.id}"], mc-input-checkbox[form="${this.form.id}"], mc-input-select[form="${this.form.id}"], mc-input-area[form="${this.form.id}"], mc-input-checkbox-group[form="${this.form.id}"], mc-input-password[form="${this.form.id}"]`)]; // Aggiunge gli input del form
|
|
24
|
+
if (this.inputs.length === 0) { console.error('McForm: No input elements found'); return; }
|
|
25
|
+
|
|
26
|
+
this.buttons = this.querySelectorAll(`[data-submit]`); // Seleziona i pulsanti di submit
|
|
27
|
+
this.buttons = [...this.buttons, ...document.querySelectorAll(`[data-submit][form="${this.form.id}"]`)];
|
|
28
|
+
|
|
29
|
+
this.errors = this.querySelector('mc-form-errors'); // Seleziona il container degli errori
|
|
30
|
+
if (!this.errors) { console.error('McForm: No mc-form-errors element found'); return; }
|
|
31
|
+
|
|
32
|
+
this.form.addEventListener(MCEVENTS.FORM_AUTOSUBMIT, this.submit.bind(this));
|
|
33
|
+
this.handleButtons(); // Gestisce i pulsanti
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Gestisce i pulsanti di submit
|
|
37
|
+
handleButtons = () => {
|
|
38
|
+
this.buttons.forEach(button => {
|
|
39
|
+
button.addEventListener('click', this.submit.bind(this)); // Aggiunge un listener per il click
|
|
40
|
+
});
|
|
41
|
+
if (this.dataset.ajax) {
|
|
42
|
+
// Se il form è configurato per l'invio in AJAX, previene il comportamento predefinito
|
|
43
|
+
this.form.addEventListener('submit', (e) => {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Valida tutti gli input del form
|
|
50
|
+
validate = () => {
|
|
51
|
+
this.isValid = true; // Assume che il form sia valido
|
|
52
|
+
this.inputs.forEach(input => {
|
|
53
|
+
input.validate(); // Valida ogni input
|
|
54
|
+
this.isValid = this.isValid && input.isValid; // Aggiorna lo stato di validità
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// se non qualcosa non è valido metto il focus sul primo input non valido
|
|
58
|
+
if (!this.isValid) {
|
|
59
|
+
const firstInvalid = this.inputs.find(input => !input.isValid);
|
|
60
|
+
if (firstInvalid && firstInvalid.input) {
|
|
61
|
+
firstInvalid.input.focus(); // Imposta il focus sul primo input non valido
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
McShopify.customEvent(MCEVENTS.FORM_VALIDATE, {valid: this.isValid}, this); // Emette un evento di validazione
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Gestisce l'invio del form
|
|
68
|
+
submit = () => {
|
|
69
|
+
this.validate(); // Valida il form
|
|
70
|
+
if (this.isValid) {
|
|
71
|
+
// Se il form è valido
|
|
72
|
+
McShopify.customEvent(MCEVENTS.FORM_SUBMIT, null, this); // Emette un evento di submit
|
|
73
|
+
if (this.dataset.ajax != undefined) {
|
|
74
|
+
// Se configurato per AJAX, prepara i dati e invia la richiesta
|
|
75
|
+
this.getData();
|
|
76
|
+
this.getOptions();
|
|
77
|
+
this.ajaxSubmit();
|
|
78
|
+
} else {
|
|
79
|
+
// Altrimenti invia il form normalmente
|
|
80
|
+
this.form.submit();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Invia il form in AJAX
|
|
86
|
+
ajaxSubmit = () => {
|
|
87
|
+
axios(this.options).then(this.success.bind(this)).catch(this.error.bind(this)).finally(this.complete.bind(this));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Ottiene i dati del form in base al content-type
|
|
91
|
+
getData = () => {
|
|
92
|
+
const formData = new FormData(this.form);
|
|
93
|
+
|
|
94
|
+
if (this.dataset.contentType?.includes('json')) {
|
|
95
|
+
// Se il content-type è JSON, converte i dati in JSON
|
|
96
|
+
this.data = JSON.stringify(McForm.formDataToObject(formData));
|
|
97
|
+
} else if (this.dataset.contentType?.includes('form')) {
|
|
98
|
+
// Se il content-type è form-urlencoded, usa FormData
|
|
99
|
+
this.data = formData;
|
|
100
|
+
} else {
|
|
101
|
+
// Altrimenti usa URLSearchParams
|
|
102
|
+
this.data = new URLSearchParams(formData);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Ottiene le opzioni della richiesta AJAX
|
|
107
|
+
getOptions = () => {
|
|
108
|
+
const headers = {};
|
|
109
|
+
const method = this.form.getAttribute('method') || 'POST'; // Metodo HTTP
|
|
110
|
+
if (this.dataset.contentType != undefined) {
|
|
111
|
+
headers['Content-Type'] = this.dataset.contentType; // Imposta il content-type
|
|
112
|
+
}
|
|
113
|
+
if (this.dataset.authUser != undefined && this.dataset.authToken != undefined) {
|
|
114
|
+
// Aggiunge l'autenticazione se configurata
|
|
115
|
+
headers['Authorization'] = 'Basic ' + btoa(this.dataset.authUser + ':' + this.dataset.authToken);
|
|
116
|
+
}
|
|
117
|
+
if(this.dataset.headers){
|
|
118
|
+
const customHeaders = JSON.parse(this.dataset.headers);
|
|
119
|
+
Object.keys(customHeaders).forEach(key => {
|
|
120
|
+
headers[key] = customHeaders[key];
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
this.options = {
|
|
124
|
+
url: this.form.action, // URL del form
|
|
125
|
+
method: method, // Metodo HTTP
|
|
126
|
+
headers: headers // Headers della richiesta
|
|
127
|
+
};
|
|
128
|
+
if (method.toUpperCase() != 'GET') {
|
|
129
|
+
this.options.data = this.data; // Aggiunge il corpo della richiesta
|
|
130
|
+
} else {
|
|
131
|
+
this.options.params = this.data; // Aggiunge i parametri per GET
|
|
132
|
+
}
|
|
133
|
+
console.log('McForm.getOptions', this.options, this.form, this.form.getAttribute('method'), method);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Gestisce gli errori della richiesta
|
|
137
|
+
error = (e) => {
|
|
138
|
+
McShopify.customEvent(MCEVENTS.FORM_ERROR, e, this); // Emette un evento di errore
|
|
139
|
+
console.error(e); // Logga l'errore
|
|
140
|
+
this.errors.showError(e.message || theme.t.errors.generic); // Mostra l'errore
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Gestisce il successo della richiesta
|
|
144
|
+
success = (response) => {
|
|
145
|
+
McShopify.customEvent(MCEVENTS.FORM_SUCCESS, response, this); // Emette un evento di successo
|
|
146
|
+
this.errors.clear(); // Pulisce gli errori
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Gestisce il completamento della richiesta
|
|
150
|
+
complete = () => {
|
|
151
|
+
McShopify.customEvent(MCEVENTS.FORM_COMPLETED, null, this); // Emette un evento di completamento
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Trasforma i dati del form in un oggetto
|
|
155
|
+
static formDataToObject = (formData) => {
|
|
156
|
+
const object = {};
|
|
157
|
+
formData.forEach((value, key) => {
|
|
158
|
+
// Converte valori come 'true', 'false' e 'null'
|
|
159
|
+
if (value === 'true') {
|
|
160
|
+
value = true;
|
|
161
|
+
} else if (value === 'false') {
|
|
162
|
+
value = false;
|
|
163
|
+
} else if (value === 'null') {
|
|
164
|
+
value = null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Gestisce chiavi che indicano array con oggetti annidati
|
|
168
|
+
const arrayKeyMatch = key.match(/(\w+)\[(\d*)\]\[(\w+)\]/);
|
|
169
|
+
|
|
170
|
+
if (arrayKeyMatch) {
|
|
171
|
+
const arrayKey = arrayKeyMatch[1];
|
|
172
|
+
const index = arrayKeyMatch[2];
|
|
173
|
+
const subKey = arrayKeyMatch[3];
|
|
174
|
+
|
|
175
|
+
if (!object[arrayKey]) {
|
|
176
|
+
object[arrayKey] = [];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (index) {
|
|
180
|
+
if (!object[arrayKey][index]) {
|
|
181
|
+
object[arrayKey][index] = {};
|
|
182
|
+
}
|
|
183
|
+
object[arrayKey][index][subKey] = value;
|
|
184
|
+
} else {
|
|
185
|
+
const newItem = {};
|
|
186
|
+
newItem[subKey] = value;
|
|
187
|
+
object[arrayKey].push(newItem);
|
|
188
|
+
}
|
|
189
|
+
} else if (key.endsWith('[]')) {
|
|
190
|
+
const keyName = key.slice(0, -2);
|
|
191
|
+
if (!Array.isArray(object[keyName])) {
|
|
192
|
+
object[keyName] = [];
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
object[keyName].push(JSON.parse(value));
|
|
196
|
+
} catch (e) {
|
|
197
|
+
object[keyName].push(value);
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
const keys = key.split('.');
|
|
201
|
+
keys.reduce((acc, k, i) => {
|
|
202
|
+
if (i === keys.length - 1) {
|
|
203
|
+
acc[k] = value;
|
|
204
|
+
} else {
|
|
205
|
+
if (!acc[k]) acc[k] = {};
|
|
206
|
+
return acc[k];
|
|
207
|
+
}
|
|
208
|
+
}, object);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
return object;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Registra il componente personalizzato se non è già stato definito
|
|
217
|
+
if (!customElements.get('mc-form')) {
|
|
218
|
+
customElements.define('mc-form', McForm);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Esporta la classe nel contesto globale e come modulo
|
|
222
|
+
window.McForm = McForm;
|
|
223
|
+
export default McForm;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
await loadComponent('./components/mc-input.js', false);
|
|
2
|
+
|
|
3
|
+
class McInputArea extends McInput {
|
|
4
|
+
connectedCallback() {
|
|
5
|
+
this.input = this.querySelector('textarea');
|
|
6
|
+
this.init();
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
if(!customElements.get('mc-input-area')) {
|
|
10
|
+
customElements.define('mc-input-area', McInputArea);
|
|
11
|
+
}
|
|
12
|
+
window.McInputArea = McInputArea;
|
|
13
|
+
export default McInputArea;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import '../res/mc-events.js';
|
|
2
|
+
await loadComponent('./components/mc-input.js', false);
|
|
3
|
+
|
|
4
|
+
// Definizione della classe custom element McInputCheckboxGroup
|
|
5
|
+
class McInputCheckboxGroup extends McInput {
|
|
6
|
+
inputs; // Collezione di input checkbox nel gruppo
|
|
7
|
+
|
|
8
|
+
connectedCallback() {
|
|
9
|
+
this.init();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Inizializza il gruppo: collega inputs, error e listener
|
|
13
|
+
init = () => {
|
|
14
|
+
this.inputs = this.querySelectorAll('input');
|
|
15
|
+
this.error = this.querySelector('[data-error]');
|
|
16
|
+
if(!this.inputs || this.inputs.length === 0) { console.error('McInputCheckboxGroup: No input elements found'); return; }
|
|
17
|
+
if(!this.error){ console.error('McInput: No error container found'); return; }
|
|
18
|
+
if(!window.theme?.t) { console.error('McInput: Translations not available'); return; }
|
|
19
|
+
if(!window.theme.t.errors) { console.error('McInput: Translations for errors not available'); return; }
|
|
20
|
+
|
|
21
|
+
// Listener per validazione su change di ogni checkbox
|
|
22
|
+
this.inputs.forEach(input => {
|
|
23
|
+
input.addEventListener('change', this.validate.bind(this));
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Valida che almeno una checkbox sia selezionata
|
|
28
|
+
validate = () => {
|
|
29
|
+
this.isValid = false;
|
|
30
|
+
this.inputs.forEach(input => {
|
|
31
|
+
this.isValid = this.isValid || input.validity.valid;
|
|
32
|
+
});
|
|
33
|
+
if(!this.isValid) {
|
|
34
|
+
this.errorText = theme.t.errors.required;
|
|
35
|
+
}
|
|
36
|
+
// Emissione eventi custom in base alla validità
|
|
37
|
+
if (this.isValid) {
|
|
38
|
+
McShopify.customEvent(MCEVENTS.INPUT_VALID, this.input?.value, this);
|
|
39
|
+
} else {
|
|
40
|
+
McShopify.customEvent(MCEVENTS.INPUT_ERROR, this.errorText, this);
|
|
41
|
+
}
|
|
42
|
+
this.showError();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Definizione custom element e esportazione globale/modulo
|
|
48
|
+
if(!customElements.get('mc-input-checkbox-group')) {
|
|
49
|
+
customElements.define('mc-input-checkbox-group', McInputCheckboxGroup);
|
|
50
|
+
}
|
|
51
|
+
window.McInputCheckboxGroup = McInputCheckboxGroup;
|
|
52
|
+
export default McInputCheckboxGroup;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
await loadComponent('./components/mc-input.js', false);
|
|
2
|
+
|
|
3
|
+
class McInputCheckbox extends McInput {
|
|
4
|
+
connectedCallback() {
|
|
5
|
+
this.init();
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
if(!customElements.get('mc-input-checkbox')) {
|
|
9
|
+
customElements.define('mc-input-checkbox', McInputCheckbox);
|
|
10
|
+
}
|
|
11
|
+
window.McInputCheckbox = McInputCheckbox;
|
|
12
|
+
export default McInputCheckbox;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import '../res/mc-events.js';
|
|
2
|
+
await loadComponent('./components/mc-input.js', false);
|
|
3
|
+
|
|
4
|
+
class McInputPassword extends McInput {
|
|
5
|
+
tips; eye;
|
|
6
|
+
|
|
7
|
+
connectedCallback() {
|
|
8
|
+
this.init();
|
|
9
|
+
|
|
10
|
+
this.addEventListener(MCEVENTS.EL_ACTIVATED, this.showPassword.bind(this));
|
|
11
|
+
this.addEventListener(MCEVENTS.EL_DEACTIVATED, this.hidePassword.bind(this));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
showPassword = () => {
|
|
15
|
+
this.input.type = "text";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
hidePassword = () => {
|
|
19
|
+
this.input.type = "password";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
hideTips = () => {
|
|
23
|
+
this.tips?.hide();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
showTips = () => {
|
|
27
|
+
this.tips?.show();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
checkTips = () => {
|
|
31
|
+
this.tips?.checkPoints(this.input.value);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
if (!window.customElements.get("mc-input-password")) {
|
|
36
|
+
window.customElements.define("mc-input-password", McInputPassword);
|
|
37
|
+
}
|
|
38
|
+
window.McInputPassword = McInputPassword;
|
|
39
|
+
export default McInputPassword;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import '../res/mc-events.js';
|
|
2
|
+
await loadComponent('./components/mc-input.js', false);
|
|
3
|
+
|
|
4
|
+
class McInputPlaces extends McInput {
|
|
5
|
+
target; search;
|
|
6
|
+
|
|
7
|
+
connectedCallback() {
|
|
8
|
+
this.target = this.querySelector("[data-geolocate]");
|
|
9
|
+
if(!google?.maps?.places) { console.error("McInputPlaces: Google Maps Places API is not loaded. Please ensure you have included the Google Maps JavaScript API with Places library."); return; }
|
|
10
|
+
|
|
11
|
+
this.init();
|
|
12
|
+
this.search = new google.maps.places.SearchBox(this.input);
|
|
13
|
+
this.search.addListener('place_changed', this.onChange.bind(this));
|
|
14
|
+
this.target?.addEventListener("click", this.locate.bind(this));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
locate = () => {
|
|
18
|
+
if (navigator.geolocation) {
|
|
19
|
+
navigator.geolocation.getCurrentPosition((position) => {
|
|
20
|
+
McShopify.customEvent(MCEVENTS.PLACES_LOCATED, position, this);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onChange = () => {
|
|
26
|
+
const places = this.search.getPlaces();
|
|
27
|
+
McShopify.customEvent(MCEVENTS.PLACES_CHANGE, places, this);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getPlaces = () => {
|
|
31
|
+
return this.search.getPlaces();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
setBounds = (bounds) => {
|
|
35
|
+
this.search.setBounds(bounds);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
if (!window.customElements.get("mc-input-places")) {
|
|
40
|
+
window.customElements.define("mc-input-places", McInputPlaces);
|
|
41
|
+
}
|
|
42
|
+
window.McInputPlaces = McInputPlaces;
|
|
43
|
+
export default McInputPlaces;
|