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.