1// gtm.js 2function getStoreNumber() { 3 var query = window.location.search.substring(1); 4 var vars = query.split("&"); 5 6 for (var i = 0; i < vars.length; i++) { 7 var pair = vars[i].split("="); 8 if (pair[0] === "number") { 9 var num = parseInt(pair[1], 10); 10 return isNaN(num) ? null : num; 11 } 12 } 13 return null; 14} 15 16function matches(el, selector) { 17 var fn = 18 el.matches || 19 el.matchesSelector || 20 el.webkitMatchesSelector || 21 el.mozMatchesSelector || 22 el.msMatchesSelector; 23 24 return fn ? fn.call(el, selector) : false; 25} 26 27function closest(el, selector) { 28 while (el) { 29 if (matches(el, selector)) { 30 return el; 31 } 32 el = el.parentElement; 33 } 34 return null; 35} 36 37 38 39 40(function () { 41 window.dataLayer = window.dataLayer || []; 42 43 var DEBUG = true; 44 var TEST_MODE = false; // ð turn on to restrict again 45 var TEST_STORE_NUMBER = 999; // ð only allow GTM events for this store 46 47 function pushEvent(payload) { 48 var storeNumber = getStoreNumber(); 49 50 // ð« Block events for non-test stores 51 if (TEST_MODE && storeNumber !== TEST_STORE_NUMBER) { 52 if (DEBUG && console.debug) { 53 console.debug( 54 "GTM event blocked (non-test store):", 55 storeNumber, 56 payload.event 57 ); 58 } 59 return; 60 } 61 62 // Attach store number consistently 63 payload.store_number = storeNumber; 64 65 // Clear previous ecommerce object (GA4 requirement) 66 window.dataLayer.push({ ecommerce: null }); 67 window.dataLayer.push(payload); 68 69 if (DEBUG && window.console && console.debug) { 70 console.debug("GTM event pushed:", payload); 71 } 72 } 73 74 window.GTM = { 75 pushEvent: pushEvent 76 }; 77})(); 78 79 80 81(function () { 82 83 function handleViewItem(e) { 84 var btn = closest(e.target,'[data-item-id]'); 85 if (!btn) return; 86 87 if (btn.__gtmViewed) return; 88 btn.__gtmViewed = true; 89 90 var price = parseFloat(btn.dataset.itemPrice || "0"); 91 var storeNumber = getStoreNumber(); 92 93 window.GTM.pushEvent({ 94 event: "view_item", 95 96 // â Store-level metadata 97 store_number: storeNumber, 98 99 ecommerce: { 100 currency: "USD", 101 value: price, 102 items: [{ 103 item_id: btn.dataset.itemId, 104 item_name: btn.dataset.itemName, 105 item_category: btn.dataset.sectionName || "", 106 price: price, 107 quantity: 1 108 }] 109 } 110 }); 111 } 112 113 document.addEventListener("click", handleViewItem, true); 114 115})(); 116 117(function () { 118 119 function handleViewCart(e) { 120 var trigger = closest(e.target,'#cartIcon, #checkoutButtonConfirmation'); 121 if (!trigger) return; 122 123 if (!cart || cart.length === 0) return; 124 125 var ga4Items = buildGA4ItemsFromCart(cart); 126 127 var totalValue = ga4Items.reduce(function (sum, i) { 128 return sum + (i.price * i.quantity); 129 }, 0); 130 131 132 window.GTM.pushEvent({ 133 event: "view_cart", 134 store_number: getStoreNumber(), 135 ecommerce: { 136 currency: "USD", 137 value: +totalValue.toFixed(2), 138 items: ga4Items 139 } 140 }); 141 } 142 143 document.addEventListener("click", handleViewCart, true); 144 145})(); 146 147(function () { 148 149 function handleBeginCheckout(e) { 150 var btn = closest(e.target,'#checkoutButton'); 151 if (!btn) return; 152 153 if (!cart || cart.length === 0) return; 154 155 var ga4Items = buildGA4ItemsFromCart(cart); 156 157 var totalValue = ga4Items.reduce(function (sum, i) { 158 return sum + (i.price * i.quantity); 159 }, 0); 160 161 162 // Optional coupon (only include if you have it) 163 var coupon = ""; 164 var couponEl = document.getElementById("discountCode"); 165 166 if (couponEl && couponEl.value) { 167 coupon = couponEl.value.trim(); 168 } 169 170 if (coupon === "") coupon = null; 171 172 173 var payload = { 174 event: "begin_checkout", 175 store_number: getStoreNumber(), 176 ecommerce: { 177 currency: "USD", 178 value: +totalValue.toFixed(2), 179 items: ga4Items 180 } 181 }; 182 183 // GA4 supports coupon at ecommerce level for begin_checkout 184 if (coupon) { 185 payload.ecommerce.coupon = coupon; 186 } 187 188 window.GTM.pushEvent(payload); 189 } 190 191 document.addEventListener("click", handleBeginCheckout, true); 192 193})(); 194 195
196function fireAddPaymentInfo(paymentType) { 197 var order = getOrderFromHiddenField(); 198 if (!order || order.length === 0) return; 199 200 var ga4Items = buildGA4ItemsFromOrder(order); 201 202 var totalValue = ga4Items.reduce(function (sum, i) { 203 return sum + (i.price * i.quantity); 204 }, 0); 205 206 207 var coupon = null; 208 209 if (order[0].discountcode) { 210 coupon = String(order[0].discountcode).trim(); 211 if (coupon === "") coupon = null; 212 } 213 214 215 var payload = { 216 event: "add_payment_info", 217 store_number: getStoreNumber(), 218 ecommerce: { 219 currency: "USD", 220 value: +totalValue.toFixed(2), 221 payment_type: paymentType, 222 items: ga4Items 223 } 224 }; 225 226 if (coupon) { 227 payload.ecommerce.coupon = coupon; 228 } 229 230 window.GTM.pushEvent(payload); 231} 232 233(function () { 234 235 function handlePaymentClick(e) { 236 // Credit Card 237 if (closest(e.target, "#sq-creditcard")) { 238 fireAddPaymentInfo("Credit Card"); 239 return; 240 } 241 242 // Google Pay 243 if (closest(e.target, "#gpay-button-online-api-id")) { 244 fireAddPaymentInfo("Google Pay"); 245 return; 246 } 247 248 // Apple Pay 249 if (closest(e.target, "#sq-apple-pay")) { 250 fireAddPaymentInfo("Apple Pay"); 251 return; 252 } 253 } 254 255 document.addEventListener("click", handlePaymentClick, true); 256 257})(); 258 259
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.