1 2var cart = { 3 data: [], 4 shipping: 0.00, 5 giftCard: 0.00, 6 how: "", 7 lastAdd: null, 8 statusId: null, 9 init: function() { 10 cart.get(); 11 }, 12 events: function() { 13 $(".cart").click(function() { window.location = "/cart"; }); 14 }, 15 getAddy: function() { 16 service.call("addys", { }, cart.addy, "GET"); 17 }, 18 addy: function(e) { 19 20 }, 21 get: function() { 22 service.call("cart", { }, cart.getReturned, "GET"); 23 }, 24 getShippoRates: function(zip,callback) { 25 service.call("shipping/check-rates", {zipcode: zip}, callback); 26 }, 27 getCosts: function(zip,state,country) { 28 service.call("costs", {zip: zip, state: state, country, country}, cart.costsReturned); 29 }, 30 costsReturned: function(e) { 31 if (e.error) growler.error(e.error); 32 else { 33 context.set("cartCosts", e); 34 try { 35 page.updateTotals(); 36 } catch (e) { 37 38 } 39 } 40 }, 41 getReturned: function(e) { 42 cart.data = e; 43 context.set("cart", cart.data); 44 }, 45 canIncreaseItemQuantity: function(item) { 46 if (!item || item.type !== "product") return false; 47 const quantity = Number(item.quantity || 0); 48 // eslint-disable-next-line eqeqeq 49 if (item.lastKnownAvailableQty != null && item.lastKnownAvailableQty !== "") { 50 const lastKnownAvailableQty = Number(item.lastKnownAvailableQty); 51 if (Number.isFinite(lastKnownAvailableQty)) return lastKnownAvailableQty > quantity; 52 } 53 return item.canIncreaseQuantity !== false; 54 }, 55 add: function(product, quantity, pickup, options, store, address, external, relay, inventoryId, oPickup, details) { 56 if (product.isInStorePurchaseOnly) growler.error("This product is only available for in-store purchase."); 57 else { 58 $(".fullLoading").addClass("open"); 59 if (product.markdown!=null && product.markdown>0 && product.markdown<product.cost && product.isAuto) product.cost = product.markdown; 60 var column = ''; 61 var row = ''; 62 var opts = options.split('~'); 63 if (opts.length==2) { 64 column = opts[0]; 65 row = opts[1] 66 } else if (opts.length==1) { 67 column = opts[0]; 68 } 69 var total = 0; 70 if (quantity<=0) { 71 $(".fullLoading").removeClass("open"); 72 return; 73 } 74 cart.data.push({ 75 type: "product", 76 product: product, 77 sku: product.sku, 78 quantity: quantity, 79 options: options, 80 pickup: pickup, 81 store: store, 82 address: address, 83 external: external, 84 column: column, 85 row: row, 86 relay: relay, 87 inventoryId: inventoryId, 88 details: details 89 }); 90 var item = cart.data[cart.data.length - 1]; 91 trackEvent('add_to_cart', { 92 "items": [ 93 { 94 "id": item.product.productId, 95 "name": item.product.name, 96 "list_name": "Cart/Checkout", 97 "brand": item.product.brandName, 98 "category": item.product.categories && item.product.categories[0] ? item.product.categories[0].name : 'All Categories', 99 "variant": item.product.color, 100 "list_position": cart.data.indexOf(item), 101 "quantity": item.quantity, 102 "price": item.product.cost 103 } 104 ] 105 }); 106 try { 107 fbq('track', 'AddToCart', { 108 "id": item.product.productId, 109 "name": item.product.name, 110 "list_name": "Cart/Checkout", 111 "brand": item.product.brandName, 112 "category": item.product.categories && item.product.categories[0] ? item.product.categories[0].name : 'All Categories', 113 "variant": item.product.color, 114 "list_position": cart.data.indexOf(item), 115 "quantity": item.quantity, 116 "price": item.product.cost 117 }); 118 } catch (e) {} 119 try { 120 let names = []; 121 let items = []; 122 let cats = []; 123 for (let i=0; i<cart.data.length; i++) { 124 var product = cart.data[i].product; 125 if (cart.data[i].type=="giftcard") total += cart.data[i].quantity*cart.data[i].amount; 126 else total += cart.data[i].quantity*product.cost; 127 if (cart.data[i].type!="giftcard") { 128 names.push(product.name.trim()); 129 let itemCats = []; 130 for (let j=0; j<product.categories.length; j++) { 131 cats.push(product.categories[j].name.trim()); 132 itemCats.push(product.categories[j].name.trim()); 133 } 134 items.push({ 135 ProductID: product.productId, 136 SKU: product.sku, 137 ProductName: product.name.trim(), 138 Quantity: cart.data[i].quantity, 139 ItemPrice: product.cost, 140 RowTotal: cart.data[i].quantity*product.cost, 141 ProductURL: window.location.href, 142 ImageURL: window.location.protocol+"//"+window.location.host+product.imageUrl, 143 ProductCategories: itemCats 144 }); 145 } 146 } 147 if (_learnq!=null) { 148 // Build shareable cart URL for easy recovery 149 var recoverCartUrl = window.location.origin + "/cart?products="; 150 for (var k = 0; k < cart.data.length; k++) { 151 if (cart.data[k].type !== "giftcard" && cart.data[k].inventoryId) { 152 recoverCartUrl += (k > 0 ? "%2C" : "") + cart.data[k].inventoryId + "%3A" + cart.data[k].quantity; 153 } 154 } 155 156 var klaviyoData = { 157 $value: total.toFixed(2), 158 AddedItemProductName: item.product.name.trim(), 159 AddedItemProductID: item.product.productId, 160 AddedItemSKU: item.product.sku, 161 AddedItemCategories: cats, 162 AddedItemImageURL: window.location.protocol+"//"+window.location.host+product.imageUrl, 163 AddedItemURL: window.location.href, 164 AddedItemPrice: item.product.cost.toFixed(2), 165 AddedItemQuantity: quantity, 166 ItemNames: names, 167 CheckoutURL: "https://"+window.location.host+"/checkout", 168 RecoverCartURL: recoverCartUrl, 169 Items: items 170 }; 171 _learnq.push(["track", "Added to Cart", klaviyoData]); 172 } 173 if (window.blueshift!=null) { 174 blueshift.track("add_to_cart", {product_id: item.product.sku}); 175 } 176 } catch (e) { 177 console.error("Klaviyo Error", e); 178 } 179 service.call("cart", { items: cart.data, sku: product.sku, quantity: quantity, column: column, row: row, pickup: oPickup, id: product.productId, external: external, relay: relay }, cart.addComplete); 180 181 } 182 }, 183 addGiftCard: function(amount, to, email, message, senderName, phone, physical, award, dateToSend) { 184 service.call("cart/giftcard", { amount: amount, to: to, email: email, message: message, senderName: senderName, phone: phone, physical: physical, award: award, dateToSend: dateToSend }, cart.addComplete); 185 }, 186 addComplete: function(e) { 187 $(".fullLoading").removeClass("open"); 188 if (e.error) { 189 if (cart.data.length>0) cart.data.pop(); 190 growler.error(e.error); 191 } else { 192 if (window.location && window.location.pathname==="/cart") { 193 cart.getReturned(e); 194 } else window.location = "/cart"; 195 } 196 }, 197 getDiscount: function() { 198 service.call("appliedDiscount", {}, cart.discountApplied); 199 }, 200 applyDiscount: function(code) { 201 service.call("applyDiscount", {code: code}, cart.discountApplied); 202 }, 203 discountApplied: function(e) { 204 if (e.error) growler.error(e.error); 205 else { 206 if (e.type) context.set("cartDiscount", e); 207 } 208 }, 209 getGiftCard: function() { 210 service.call("appliedGiftCard", {}, cart.giftCardApplied); 211 }, 212 applyGiftCard: function(code) { 213 service.call("applygiftCard", {card: code}, cart.giftCardReturned); 214 }, 215 giftCardApplied: function(e) { 216 if (e.value>0) { 217 cart.giftCard = e.value; 218 context.set("giftCard", e.value); 219 if (e.cards) { 220 if (e.card?.value) { 221 cart.giftCard = e.card.value; 222 context.set("giftCard", e.card.value); 223 } 224 cart.multipleGiftCards = e.cards; 225 context.set("multipleGiftCards", e.cards);
226 } 227 if (page && page.updateTotals) page.updateTotals(); 228 } 229 }, 230 giftCardReturned: function(e) { 231 if (e.value>0) { 232 cart.giftCard = e.value; 233 context.set("giftCard", e.value); 234 if (e.cards) { 235 if (e.card?.value) { 236 cart.giftCard = e.card.value; 237 context.set("giftCard", e.card.value); 238 } 239 cart.multipleGiftCards = e.cards; 240 context.set("multipleGiftCards", e.cards); 241 } 242 if (page && page.updateTotals) page.updateTotals(); 243 } else { 244 growler.info("The Gift Card entered does not have a balance.") 245 } 246 }, 247 setAddress: function(e) { 248 cart.getAddy(); 249 service.call("cartAddress", { addresses: e }, cart.setAddressReturned); 250 }, 251 setAddressReturned: function(e) { 252 cart.getCosts(e.szipCode, e.sstate, e.scountry); 253 }, 254 change: function(product, quantity) { 255 256 }, 257 remove: function(index) { 258 var items = []; 259 for (var i=0; i<cart.data.length; i++) { 260 if (i!=index) { 261 items[items.length] = cart.data[i]; 262 } if (i === index) { 263 var item = cart.data[i]; 264 if (item.type!="giftcard") { 265 trackEvent('remove_from_cart', { 266 "items": [ 267 { 268 "id": item.product.productId, 269 "name": item.product.name, 270 "list_name": "Cart/Checkout", 271 "brand": item.product.brandName, 272 "category": item.product.categories && item.product.categories[0] ? item.product.categories[0].name : 'All Categories', 273 "variant": item.product.color, 274 "list_position": i, 275 "quantity": item.quantity, 276 "price": item.product.cost 277 } 278 ] 279 }); 280 if (window.blueshift!=null) { 281 blueshift.track("remove_from_cart", {product_id: item.product.sku}); 282 } 283 } 284 } 285 } 286 service.call("cart/remove", { items: items }, cart.getReturned); 287 }, 288 updateQuantity: function(index, newQuantity) { 289 var item = cart.data[index]; 290 if (!item || item.type=="giftcard") return; 291 if (!item.product) return; 292 if (newQuantity<0 || newQuantity===item.quantity) return; 293 if (newQuantity>item.quantity) { 294 var difference = newQuantity - item.quantity; 295 cart.add(item.product, difference, item.pickup, item.options, item.store, item.address, item.external, item.relay, item.inventoryId, item.pickup, item.details); 296 } else { 297 var updatedItems = []; 298 for (var i=0; i<cart.data.length; i++) { 299 if (i===index) { 300 var updatedItem = $.extend(true, {}, cart.data[i]); 301 updatedItem.quantity = newQuantity; 302 updatedItems.push(updatedItem); 303 } else updatedItems.push(cart.data[i]); 304 } 305 cart.data = updatedItems; 306 context.set("cart", cart.data); 307 service.call("cart/remove", { items: cart.data }, cart.getReturned); 308 } 309 }, 310 clear: function() { 311 cart.data = []; 312 context.set("cart", cart.data); 313 service.call("cart", { }
313, cart.getReturned, "DELETE"); 314 }, 315 process: function(how, params, confirm) { 316 cart.how = how; 317 if (params.afterpay || params.stripeCheckout) { 318 service.call("process", params, e => { 319 // Store purchase data in sessionStorage for GA4 tracking on ordersuccess page 320 try { 321 var gTagItems = []; 322 for (var i = 0; i < cart.data.length; i++) { 323 var item = cart.data[i]; 324 if (item.type === "giftcard") continue; 325 var storeDetails = item.store && typeof store !== 'undefined' ? store.detailsFromCode(item.store) : null; 326 gTagItems.push({ 327 id: item.product.productId, 328 name: item.product.name, 329 list_name: "Cart/Checkout", 330 brand: item.product.brandName, 331 category: item.product.categories && item.product.categories[0] ? item.product.categories[0].name : 'All Categories', 332 variant: item.product.color, 333 list_position: i, 334 quantity: item.quantity, 335 price: item.product.cost, 336 affiliation: storeDetails && storeDetails.name ? storeDetails.name : "" 337 }); 338 } 339 sessionStorage.setItem('_rfPurchaseEvent', JSON.stringify({ 340 order: e.order, 341 subtotal: e.subtotal, 342 currency: e.currency, 343 tax: e.tax, 344 shipping: e.shipping, 345 couponCode: e.couponCode, 346 items: gTagItems 347 })); 348 } catch (ex) {} 349 if (params.afterpay) { 350 confirm(e.intent); 351 } else { 352 confirm(e.session); 353 } 354 }); 355 } else { 356 service.log({isAt:"cart.process", data: params}); 357 service.call("process", params, cart.complete); 358 } 359 cart.pollStatus(); 360 if (cart.statusId) clearInterval(cart.statusId); 361 cart.statusId = setInterval(cart.pollStatus, 1000); 362 }, 363 pollStatus: function() { 364 service.call("checkout/status", {}, (e) => { 365 try { 366 $("#CheckoutStatus").html(e.data); 367 } catch (e) {} 368 }); 369 }, 370 complete: function(e) { 371 $(window).off('beforeunload'); 372 if (e.error) { 373 clearInterval(cart.statusId); 374 $(".fullLoadingOrders").removeClass("open"); 375 $(".fullLoading").removeClass("open"); 376 $("#ActionButton").prop("disabled", false); 377 if (cart.how=="heartland") $("#HeartButton").show(); 378 var error = "Card Declined"; 379 if (e.error.raw != null && e.error.message !=null && e.error.message.length>0) error = e.error.message; 380 else { 381 if (typeof e.error === "string") error = e.error; 382 } 383 growler.error(error); 384 } else { 385 cart.orderNumber = e.order; 386 try { 387 var gTagItems = []; 388 var bsProducts = []; 389 for (var i=0; i<cart.data.length; i++) { 390 var item = cart.data[i]; 391 var imageUrl = ''; 392 if (item.product.images && item.product.images.length>0) { 393 imageUrl = products.getSize(600, item.product.images[i].url); 394 } 395 var categoryList = []; 396 for (let g=0; g<item.product.categories.length; g++) categoryList.push(item.product.categories[g].name); 397 var storeDetails = item.store ? store.detailsFromCode(item.store) : null; 398 var gTagItem = { 399 "id": item.product.productId, 400 "name": item.product.name, 401 "list_name": "Cart/Checkout", 402 "brand": item.product.brandName, 403 "category": item.product.categories && item.product.categories[0] ? item.product.categories[0].name : 'All Categories', 404 "variant": item.product.color, 405 "list_position": i, 406 "quantity": item.quantity, 407 "price": item.product.cost, 408 "affiliation": storeDetails && storeDetails.name ? storeDetails.name : "" 409 } 410 gTagItems.push(gTagItem); 411 bsProducts.push({ 412 sku: item.product.sku, 413 price: item.product.cost, 414 quantity: item.quantity, 415 title: item.product.name.trim(), 416 brand: item.product.brandName, 417 store_id: item.store, 418 product_sku: item.product.sku, 419 image: imageUrl, 420 size: item.column, 421 width: item.row, 422 color: item.product.color, 423 web_link: "https://"+window.location.hostname+products.getCanonical( item.product ), 424 category: categoryList 425 }); 426 } 427 trackEvent('purchase', { 428 "transaction_id": '' + e.order, 429 "value": e.subtotal, 430 "currency": e.currency, 431 "tax": e.tax, 432 "shipping": e.shipping, 433 "coupon": e.couponCode || "", 434 "items": gTagItems 435 }); 436 437 if (window.blueshift!=null) { 438 blueshift.track("purchase", { 439 email: user.data.emailAddress, 440 order_id: e.order, 441 total: e.subtotal + e.shipping + e.tax, 442 revenue: e.subtotal, 443 shipping: e.shipping, 444 tax: e.tax, 445 discount: e.coupon, 446 coupon: e.couponCode, 447 products: bsProducts, 448 source: "Run Free"
449 }); 450 } 451 452 if (_learnq!=null) { 453 let names = []; 454 let items = []; 455 let cats = []; 456 for (let i=0; i<cart.data.length; i++) { 457 var product = cart.data[i].product; 458 names.push(product.name.trim()); 459 let itemCats = []; 460 for (let j=0; j<product.categories.length; j++) { 461 cats.push(product.categories[j].name.trim()); 462 itemCats.push(product.categories[j].name.trim()); 463 } 464 items.push({ 465 ProductID: product.productId, 466 SKU: product.sku, 467 ProductName: product.name.trim(), 468 Quantity: cart.data[i].quantity, 469 ItemPrice: product.cost, 470 RowTotal: cart.data[i].quantity*product.cost, 471 ProductURL: window.location.href, 472 ImageURL: window.location.protocol+"//"+window.location.host+product.imageUrl, 473 ProductCategories: itemCats 474 }); 475 } 476 var klaviyoData = { 477 $event_id: moment().unix(), 478 $value: e.subtotal + e.shipping + e.tax, 479 ItemNames: names, 480 Categories: cats, 481 Items: items, 482 DiscountCode: e.couponCode, 483 DiscountValue: e.coupon, 484 BillingAddress: { 485 FirstName: user.data.firstName, 486 LastName: user.data.lastNAme, 487 Address1: user.data.street, 488 City: user.data.city, 489 RegionCode: user.data.state, 490 CountryCode: user.data.country, 491 Zip: user.data.postalCode, 492 Phone: user.data.phone 493 }, 494 ShippingAddress: { 495 FirstName: user.data.firstName, 496 LastName: user.data.lastNAme, 497 Address1: user.data.sstreet, 498 City: user.data.scity, 499 RegionCode: user.data.sstate, 500 CountryCode: user.data.scountry, 501 Zip: user.data.spostalCode, 502 Phone: user.data.phone 503 } 504 }; 505 _learnq.push(["track", "Placed Order", klaviyoData]); 506 } 507 } catch (e) {} 508 window.location = "/success"; 509 } 510 }, 511 logCart(type) { 512 service.call("cart/log", {cartData: cart.data, type: type}, (e) => { }); 513 } 514}
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.