1(function () { 2 // Merge footerTotalConfig with defaults 3 const defaultConfig = { 4 currency: '$', 5 percentage: 0, 6 logicType: 'sum' 7 }; 8 9 const config = typeof footerTotalConfig !== 'undefined' 10 ? { ...defaultConfig, ...footerTotalConfig } 11 : defaultConfig; 12 13 // Now extract directly - no need for fallbacks since config is guaranteed to have valid values 14 const currency = config.currency; 15 const percentage = parseFloat(config.percentage) || 0; // Keep this for NaN protection 16 const logicType = String(config.logicType).toLowerCase(); 17 18 // Re-query on each calculate â drawer HTML can be re-injected after PLP AJAX 19 function getTotalEl() { 20 return document.getElementById('footer-total-price'); 21 } 22 function getQtyEl() { 23 return document.getElementById('footer-quantity'); 24 } 25 26 if (!getTotalEl() || !getQtyEl()) return; 27 28 function parsePrice(str) { 29 if (!str) return 0; 30 const cleaned = String(str).replace(/[^0-9.\-]/g, '').replace(/,/g, ''); 31 const n = parseFloat(cleaned); 32 return isNaN(n) ? 0 : n; 33 } 34 35 function getBasePrice() { 36 // Volume tier pricing via shared getVolumeTierPrice 37 if (window.__productDetailsData && window.__productDetailsData.pricing 38 && typeof window.getVolumeTierPrice === 'function') { 39 var pricing = window.__productDetailsData.pricing; 40 if (Array.isArray(pricing.volume_tiers) && pricing.volume_tiers.length > 0) { 41 var counterInput = document.getElementById('footer-counter-input'); 42 var quantity = counterInput ? Math.max(1, parseInt(counterInput.value, 10) || 1) : Math.max(1, counterMultiplier); 43 return window.getVolumeTierPrice(pricing, quantity); 44 } 45 } 46 47 // Flat price fallbacks 48 if (window.__productDetailsData) { 49 if (window.__productDetailsData.price != null) { 50 return parseFloat(window.__productDetailsData.price) || 0; 51 } 52 if (window.__productDetailsData.pricing && window.__productDetailsData.pricing.price != null) { 53 return parseFloat(window.__productDetailsData.pricing.price) || 0; 54 } 55 if (window.__productDetailsData.catalog_list && window.__productDetailsData.catalog_list[0] && window.__productDetailsData.catalog_list[0].price != null) { 56 return parseFloat(window.__productDetailsData.catalog_list[0].price) || 0; 57 } 58 } 59 60 if (typeof product_details_data !== 'undefined') { 61 if (product_details_data.price != null) { 62 return parseFloat(product_details_data.price) || 0; 63 } 64 if (product_details_data.pricing && product_details_data.pricing.price != null) { 65 return parseFloat(product_details_data.pricing.price) || 0; 66 } 67 } 68 69 // 2. Try DOM selectors (for PDP pages) 70 const selectors = [ 71 '.wiz-prodimgcmp-price span', 72 '.wiz-prodimgcmp-price', 73 '.product-price', 74 '.price', 75 '#product-price' 76 ]; 77 78 for (let sel of selectors) { 79 const el = document.querySelector(sel); 80 if (el && el.textContent.trim()) { 81 const price = parsePrice(el.textContent); 82 if (price > 0) return price; 83 } 84 } 85 86 return 0; 87 } 88 89 // Store counter multiplier 90 let counterMultiplier = 1; 91 92 function calculate() { 93 let totals = []; 94 95 document.querySelectorAll('.cart-customization-table tr, .customizations-applied tr') 96 .forEach(row => { 97 const text = row.textContent || ""; 98 const priceCell = row.querySelector('.cart-table-price, td:last-child'); 99 if (priceCell) totals.push(parsePrice(priceCell.textContent)); 100 }); 101 102 103 104 105 let result = 0; 106 if (totals.length) { 107 switch (logicType) { 108 case 'max': result = Math.max(...totals); break; 109 case 'min': result = Math.min(...totals); break; 110 case 'average': result = totals.reduce((a, b) => a + b, 0) / totals.length; break; 111 default: result = totals.reduce((a, b) => a + b, 0); 112 } 113 } 114 115 result += getBasePrice(); 116 if (percentage) result += (result * percentage) / 100; 117
118 const qtyEl = getQtyEl(); 119 const totalEl = getTotalEl(); 120 if (!totalEl) return; 121 122 const qty = Math.max(1, parseInt(qtyEl && qtyEl.value, 10) || 1); 123 result = result * qty; 124 125 // Apply counter multiplier to the final result 126 result = result * counterMultiplier; 127 128 totalEl.textContent = currency + (Number.isInteger(result) ? result : result.toFixed(2)); 129 130 131 } // calculate function end 132 133 //in case any delays fetching value 134 let pollAttempts = 0; 135 let pollHandle = null; 136 function ensureBasePriceAndCalc() { 137 const hasData = !!window.__productDetailsData || typeof product_details_data !== 'undefined'; 138 if (hasData) { 139 calculate(); 140 if (pollHandle) { clearInterval(pollHandle); pollHandle = null; } 141 } else { 142 pollAttempts++; 143 if (pollAttempts >= 20) { 144 calculate(); 145 if (pollHandle) { clearInterval(pollHandle); pollHandle = null; } 146 } 147 } 148 } 149 150 function attachObservers() { 151 const tableTarget = document.querySelector('.cart-customization-table, .customizations-applied table, #modifier-table .cart-customization-table'); 152 if (tableTarget && typeof MutationObserver !== 'undefined') { 153 const tableObs = new MutationObserver(function () { 154 clearTimeout(window.__footerTotalTimeout); 155 window.__footerTotalTimeout = setTimeout(calculate, 40); 156 }); 157 tableObs.observe(tableTarget, { childList: true, subtree: true, characterData: true }); 158 } 159 160 const baseEl = document.querySelector('.wiz-prodigmcmp-price, .wiz-prodigmcmp-price span'); 161 if (baseEl && typeof MutationObserver !== 'undefined') { 162 const baseObs = new MutationObserver(function () { 163 clearTimeout(window.__footerTotalTimeout); 164 window.__footerTotalTimeout = setTimeout(calculate, 40); 165 }); 166 baseObs.observe(baseEl, { childList: true, subtree: true, characterData: true }); 167 } 168 } 169 170 calculate(); 171 if (!pollHandle) pollHandle = setInterval(ensureBasePriceAndCalc, 200); 172 173 //automatically trigger calculate() whenever something changes in the DOM. 174 attachObservers(); 175 176 document.addEventListener('input', function (e) { 177 if (e.target && e.target.id === 'footer-quantity') calculate(); 178 }); 179 document.addEventListener('change', function (e) { 180 if (e.target && e.target.id === 'footer-quantity') calculate(); 181 }); 182 183 // Listen for footer counter changes 184 document.addEventListener('footerCounterChanged', function (e) { 185 counterMultiplier = e.detail.value; 186 clearTimeout(window.__footerTotalTimeout); 187 window.__footerTotalTimeout = setTimeout(calculate, 40); 188 }); 189 190 // Sync counterMultiplier from +/- on the live footer counter 191 document.addEventListener('input', function (e) { 192 if (!e.target || e.target.id !== 'footer-counter-input') return; 193 var val = parseInt(e.target.value, 10); 194 if (!isNaN(val) && val > 0) { 195 counterMultiplier = val; 196 clearTimeout(window.__footerTotalTimeout); 197 window.__footerTotalTimeout = setTimeout(calculate, 40); 198 } 199 }); 200 201 document.addEventListener('click', function (e) { 202 const mt = document.getElementById('modifier-table'); 203 if (mt && mt.contains(e.target)) { 204 clearTimeout(window.__footerTotalTimeout); 205 window.__footerTotalTimeout = setTimeout(calculate, 40); 206 } 207 }, true); 208 209 document.addEventListener('change', function (e) { 210 const mt = document.getElementById('modifier-table'); 211 if (mt && mt.contains(e.target)) { 212 clearTimeout(window.__footerTotalTimeout); 213 window.__footerTotalTimeout = setTimeout(calculate, 30); 214 } 215 }, true); 216 217 // Listen for product details loaded (PLP support) 218 document.addEventListener('productDetails:loaded', function (e) { 219 // Force recalculation when product details (including price) are loaded 220 clearTimeout(window.__footerTotalTimeout); 221 window.__footerTotalTimeout = setTimeout(calculate, 50); 222 }); 223 224 document.addEventListener('modifierRulesApplied', function () { 225 clearTimeout(window.__footerTotalTimeout); 226 window.__footerTotalTimeout = setTimeout(calculate, 50); 227 }); 228 229 window.footerTotalForceUpdate = function () { 230 clearTimeout(window.__footerTotalTimeout); 231 return calculate(); 232 }; 233})();
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.