1// Global floating cart FAB â CI3 #cart_icon parity. 2// 3// Reveals a circular cart button (with an item-count badge) on every page once: 4// 1. the user is logged in (localStorage `userdata`), AND 5// 2. an outlet is selected and its cart (localStorage `v4_cart`) has items. 6// 7// The cart is outlet-scoped â `v4_cart.bId` is the selected outlet â so a cart 8// with items inherently means an outlet was chosen. Click proceeds to checkout 9// for that outlet, mirroring menu.js `goToCheckout()`. 10// 11// Stays hidden on pages that already carry their own cart entry point: the 12// menu/grocery page (#floatingCartBar) and the cart/checkout funnel. 13(function () { 14 const fab = document.getElementById('cartFab'); 15 if (!fab) return; 16 17 // Pages with their own cart entry point â never show the global (menu) FAB 18 // there, or it overlaps and links to the wrong cart. The menu/order pages use 19 // one of two bar ids; subscription & prepaid-pack pages carry their own FAB 20 // (#subCartFab / #pkgCartFab) driven by their own server cart. The v2 header 21 // carries a cart button on every page ([data-hdr2-cart], count kept by 22 // headerV2.js), so brands on that header never need the FAB â and would 23 // otherwise show two cart entry points at once. No effect on v1 brands: the 24 // attribute only exists in templates/header_v2.php. 25 const hasOwnCartUi = !!(document.getElementById('floatingCartBar') 26 || document.getElementById('floatingCart') 27 || document.getElementById('subCartFab') 28 || document.getElementById('pkgCartFab') 29 || document.querySelector('[data-hdr2-cart]')); 30 // Cart funnel + the whole subscription/prepaid-pack section (list, VIEW, and 31 // checkout) â those run their own server cart, so the menu FAB must never show. 32 const onOwnRoute = /^\/(cart|checkout|payments-page|order-polling|subscriptions?|package|store-locator)\b/.test(location.pathname); 33 if (hasOwnCartUi || onOwnRoute) return; 34 35 function isLoggedIn() { 36 const ud = localStorage.getItem('userdata'); 37 if (!ud || ud === 'null' || ud === '') return false; 38 try { return !!JSON.parse(ud); } catch { return false; } 39 } 40 41 function readCart() { 42 try { 43 const c = JSON.parse(localStorage.getItem('v4_cart') || 'null'); 44 if (c && c.bId && Array.isArray(c.items)) return c; 45 } catch {} 46 return null; 47 } 48 49 function refresh() { 50 const cart = readCart(); 51 const count = isLoggedIn() && cart 52 ? cart.items.reduce((s, i) => s + (i.qty || 0), 0) 53 : 0; 54 if (count > 0) { 55 const badge = document.getElementById('cartFabCount'); 56 if (badge) badge.textContent = count > 99 ? '99+' : String(count); 57 fab.dataset.bid = String(cart.bId); 58 fab.hidden = false; 59 } else { 60 fab.hidden = true; 61 } 62 } 63 64 // Proceed to checkout for the cart's outlet (mirrors menu.js goToCheckout). 65 fab.addEventListener('click', function () { 66 const bId = fab.dataset.bid; 67 if (!bId) return; 68 if (!isLoggedIn()) { if (window.showLogin) window.showLogin(); return; } 69 const ot = localStorage.getItem('orderType') || '1'; 70 const tid = localStorage.getItem('tableId'); 71 if (ot === '3' && tid && tid !== 'null' && Number(tid) > 0) { 72 location.href = '/checkout/' + bId + '/' + ot + '/' + tid; 73 } else { 74 location.href = '/checkout/' + bId + '/' + ot; 75 } 76 }); 77 78 // Re-evaluate on cross-tab changes, cart.js's event, and bfcache restores. 79 window.addEventListener('storage', function (e) { 80 if (!e.key || e.key === 'v4_cart' || e.key === 'userdata') refresh(); 81 }); 82 window.addEventListener('cart:updated', refresh); 83 window.addEventListener('pageshow', refresh); 84 window.addEventListener('focus', refresh); 85 86 // Allow same-page updaters to force a refresh after writing v4_cart. 87 window.refreshCartFab = refresh; 88 89 refresh(); 90})();
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.