PageSourceSearch

https://www.sergiobonelli.it/wp-content/themes/bonelli/assets/js/cart-toast-messages.js?ver=1790063029

js sergiobonelli.it collected 2026-10-02 02:36:57 UTC 10,230 bytes, 276 lines download raw bytes

1/**
2 * Messaggi toast carrello: mappa errori WC/generici in testi chiari (IT).
3 */
4(function (window) {
5    'use strict';
6
7    function getI18n() {
8        if (typeof bonelli_ajax !== 'undefined' && bonelli_ajax.i18n) {
9            return bonelli_ajax.i18n;
10        }
11        if (typeof cart_ajax !== 'undefined' && cart_ajax.i18n) {
12            return cart_ajax.i18n;
13        }
14        return {};
15    }
16
17    function bonelliI18n(key) {
18        var args = Array.prototype.slice.call(arguments, 1);
19        var i18n = getI18n();
20        var str = i18n[key] || '';
21        args.forEach(function (arg) {
22            str = str.replace(/%[sd]/, String(arg));
23        });
24        return str;
25    }
26
27    function getDefaults() {
28        if (typeof bonelli_ajax !== 'undefined' && bonelli_ajax.cart_messages) {
29            return bonelli_ajax.cart_messages;
30        }
31        if (typeof cart_ajax !== 'undefined' && cart_ajax.cart_messages) {
32            return cart_ajax.cart_messages;
33        }
34        return {};
35    }
36
37    function normalize(raw) {
38        return String(raw || '')
39            .replace(/<[^>]+>/g, ' ')
40            .replace(/\s+/g, ' ')
41            .replace(/\s*(?:congedo|dismiss|chiudi|close)\s*$/gi, '')
42            .trim();
43    }
44
45    /**
46     * Testo notice WC senza link/pulsante "Chiudi" (es. "Congedo" = dismiss mal tradotto).
47     * @param {Element} node
48     * @returns {string}
49     */
50    function bonelliExtractNoticeText(node) {
51        if (!node) {
52            return '';
53        }
54        var li = node.querySelector && node.querySelector('li');
55        if (li) {
56            return normalize(li.textContent);
57        }
58        if (node.cloneNode) {
59            var clone = node.cloneNode(true);
60            var chrome = clone.querySelectorAll(
61                'a, button, .woocommerce-message-close, .notice-dismiss, [role="button"]'
62            );
63            chrome.forEach(function (el) {
64                el.remove();
65            });
66            return normalize(clone.textContent);
67        }
68        return normalize(node.textContent);
69    }
70
71    /**
72     * Estrae l'importo dal messaggio WC (es. "… è 50,00 €").
73     * @param {string} text
74     * @returns {string|null}
75     */
76    function extractPriceFromWcMessage(text) {
77        var m = text.match(/(?:is|è)\s*(.+)$/i);
78        if (m && m[1] && /[\d€$]/.test(m[1])) {
79            return m[1].trim();
80        }
81        m = text.match(/([\d.,]+\s*(?:€|EUR)|(?:€|EUR)\s*[\d.,]+)/i);
82        return m ? m[1].trim() : null;
83    }
84
85    /**
86     * @param {string} raw
87     * @param {string} [context] coupon | quantity | remove_item | generic
88     * @returns {string}
89     */
90    function bonelliFriendlyCartMessage(raw, context) {
91        context = context || 'generic';
92        const defaults = getDefaults();
93        const text = normalize(raw);
94
95        if (!text) {
96            if (context === 'coupon') {
97                return defaults.coupon_apply_failed || '';
98            }
99            if (context === 'quantity') {
100                return defaults.qty_update_failed || '';
101            }
102            if (context === 'remove_item') {
103                return defaults.item_remove_failed || '';
104            }
105            return defaults.request_failed || '';
106        }
107
108        const rules = [
109            [/does not exist|non esiste|coupon.*not found|codice.*non trovato|cannot be applied because it does not exist/i,
110                defaults.coupon_not_exist],
111            [/usage limit.*reached|limite.*utilizz|limite d'uso.*raggiung|già stato utilizzato|already been used/i,
112                defaults.coupon_usage_limit],
113            [/cannot be used in conjunction|in conjunction with other|non può essere utilizzato insieme|insieme ad altri coupon|già presente un altro codice/i,
114                defaults.coupon_individual_use],
115            [/already been applied|already applied|già stato applicato|già applicato|già presente nel carrello|already applied!/i,
116                defaults.coupon_already_applied],
117            [/has expired|è scadut|scadut/i,
118                defaults.coupon_expired],
119            [/not valid for your cart|not applicable|non valido per il carrello|non si applica agli articoli/i,
120                defaults.coupon_not_applicable],
121            [/please enter a coupon|inserisci un codice/i,
122                defaults.coupon_empty],
123            [/removed from your cart|rimosso dal carrello/i,
124                defaults.coupon_removed],
125            [/successfully applied|applicato con successo|coupon has been applied/i,
126                defaults.coupon_applied],
127            [/item non trovato|not found in your cart|non è più nel carrello/i,
128                defaults.item_not_in_cart],
129            [/raggiunto la quantità massima|limite massimo|limite prevendita|puoi aggiungere al massimo|puoi impostare al massimo/i,
130                text],
131            [/out of stock|non disponibile.*pezzi/i,
132                defaults.qty_unavailable_item],
133            [/sessione|session expired|nonce|richiesta non valida/i,
134                defaults.session_expired],
135            [/failed to fetch|network|connessione interrotta/i,
136                defaults.network_error],
137            [/parametri.*non disponibili|ajax.*non disponibili/i,
138                defaults.ajax_unavailable],
139        ];
140
141        for (let i = 0; i < rules.length; i++) {
142            if (rules[i][0].test(text)) {
143                return rules[i][1];
144            }
145        }
146
147        if (/minimum spend|spesa minima|importo minimo|minimum spend for coupon|spesa minima per/i.test(text)) {
148            var minAmount = extractPriceFromWcMessage(text);
149            if (minAmount) {
150                return (defaults.coupon_min_spend_amount || '').replace('%s', minAmount);
151            }
152            return defaults.coupon_min_spend_generic || '';
153        }
154
155        if (/maximum spend|spesa massima|maximum spend for coupon/i.test(text)) {
156            var maxAmount = extractPriceFromWcMessage(text);
157            if (maxAmount) {
158                return (defaults.coupon_max_spend_amount || '').replace('%s', maxAmount);
159            }
160            return defaults.coupon_max_spend_generic || '';
161        }
162
163        if (/errore|error|failed|non riuscit|impossibile|operazione.*non riuscita/i.test(text)) {
164            if (context === 'coupon') {
165                return defaults.coupon_apply_failed || text;
166            }
167            if (context === 'quantity') {
168                return defaults.qty_update_failed || text;
169            }
170            if (context === 'remove_item') {
171                return defaults.item_remove_failed || text;
172            }
173        }
174
175        return text;
176    }
177
178    /**
179     * @param {string} html
180     * @returns {{ type: 'error'|'success'|'info', message: string }|null}
181     */
182    function bonelliParseWcNoticeHtml(html) {
183        if (!html || typeof html !== 'string') {
184            return null;
185        }
186        const doc = new DOMParser().parseFromString(html, 'text/html');
187        const errLi = doc.querySelector('.woocommerce-error li');
188        if (errLi) {
189            return { type: 'error', message: normalize(errLi.textContent) };
190        }
191        const err = doc.querySelector('.woocommerce-error');
192        if (err) {
193            return { type: 'error', message: normalize(err.textContent) };
194        }
195        const okLi = doc.querySelector('.woocommerce-message li');
196        if (okLi) {
197            return { type: 'success', message: normalize(okLi.textContent) };
198        }
199        const ok = doc.querySelector('.woocommerce-message');
200        if (ok) {
201            return { type: 'success', message: normalize(ok.textContent) };
202        }
203        return null;
204    }
205
206    function bonelliIsCheckoutPage() {
207        return document.body.classList.contains('woocommerce-checkout')
208            || !!document.querySelector('form.checkout.woocommerce-checkout');
209    }
210
211    function bonelliNoticeContext(el, text) {
212        if (/coupon|codice sconto|sconto|discount/i.test(text)) {
213            return 'coupon';
214        }
215        if (el && el.closest && el.closest('[class*="coupon"], .checkout_coupon, .fc-coupon-code')) {
216            return 'coupon';
217        }
218        return 'generic';
219    }
220
221    /**
222     * Rimuove notice WC dal DOM; sul checkout le converte in toast.
223     * @param {Element} node
224     */
225    function bonelliHandleWcNoticeElement(node) {
226        if (!node || node.nodeType !== 1) {
227            return;
228        }
229        if (node.closest('.toast-notification')) {
230            return;
231        }
232
233        var isError = node.classList && node.classList.contains('woocommerce-error');
234        var isSuccess = node.classList && node.classList.contains('woocommerce-message');
235        var isInfo = node.classList && node.classList.contains('woocommerce-info');
236        if (!isError && !isSuccess && !isInfo) {
237            return;
238        }
239
240        var raw = bonelliExtractNoticeText(node);
241        if (bonelliIsCheckoutPage() && typeof window.showToast === 'function' && raw) {
242            var context = bonelliNoticeContext(node, raw);
243            var toastType = isError ? 'error' : (isSuccess ? 'success' : 'info');
244            var msg = bonelliFriendlyCartMessage(raw, context);
245            if (msg) {
246                window.showToast(msg, toastType);
247            }
248        }
249
250        node.remove();
251    }
252
253    function bonelliFlushCheckoutWcNotices() {
254        if (!bonelliIsCheckoutPage()) {
255            return;
256        }
257        document.querySelectorAll('.woocommerce-error, .woocommerce-message, .woocommerce-info').forEach(function (el) {
258            if (!el.closest('.toast-notification')) {
259                bonelliHandleWcNoticeElement(el);
260            }
261        });
262    }
263
264    window.bonelliFriendlyCartMessage = bonelliFriendlyCartMessage;
265    window.bonelliParseWcNoticeHtml = bonelliParseWcNoticeHtml;
266    window.bonelliHandleWcNoticeElement = bonelliHandleWcNoticeElement;
267    window.bonelliI18n = bonelliI18n;
268
269    if (typeof jQuery !== 'undefined') {
270        jQuery(function ($) {
271            $(document.body).on('updated_checkout', function () {
272                setTimeout(bonelliFlushCheckoutWcNotices, 80);
273            });
274        });
275    }
276})(window);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.