1// Shared cart-banner pricing engine. Every cart-banner surface (classic cart, 2// classic checkout, block cart/checkout, drag-drop block, shortcode) renders a 3// bare <iwocapay-price-calculator-cart-banner> marker and defers ALL pricing to 4// this one module, so the surfaces can't drift apart (the lesson from Magento's 5// shared cart-pricing module). 6// 7// The marker carries NO price server-side â this fetches the live basket figures 8// client-side, so it's correct under full-page caching and re-renders on cart 9// change. Amounts come back pre-formatted (e.g. "£137.50") from PHP; the 10// component does no maths, it just displays what it's given. 11(function () { 12 var TAG = "iwocapay-price-calculator-cart-banner"; 13 var MARKER_ATTR = "data-iwocapay-cart-banner"; 14 15 // Fire the view event only once the banner actually intersects the viewport. 16 // A cart banner can sit below the fold or in a collapsed panel â present and 17 // eligible in the DOM long before the customer sees it. The dedup (in-memory 18 // + 24h localStorage) lives in fireIwocapayBannerEvent, so this only gates on 19 // visibility. Falls back to firing immediately where IO is unavailable. 20 var viewObserver = 21 typeof window.IntersectionObserver !== "undefined" 22 ? new window.IntersectionObserver(function (entries, observer) { 23 entries.forEach(function (entry) { 24 if (entry.isIntersecting) { 25 observer.unobserve(entry.target); 26 fireView(); 27 } 28 }); 29 }) 30 : null; 31 32 function fireView() { 33 if (window.fireIwocapayBannerEvent) { 34 window.fireIwocapayBannerEvent("CUSTOMER_VIEWED_CART_BANNER", { 35 isDeprecated: false, 36 }); 37 } 38 } 39 40 function observeForView(el) { 41 if (viewObserver) { 42 viewObserver.observe(el); 43 } else { 44 fireView(); 45 } 46 } 47 48 // Ensure the marker holds exactly one banner element to feed attributes into. 49 function ensureBanner(marker) { 50 var banner = marker.querySelector(TAG); 51 if (!banner) { 52 banner = document.createElement(TAG); 53 marker.appendChild(banner); 54 } 55 return banner; 56 } 57 58 function applyPricing(marker, data) { 59 // Ineligible (out of the £150â£30k band, no enabled terms, or an 60 // unavailable cart) â hide the whole marker, leave nothing half-rendered. 61 if (!data || !data.eligible || !data.terms || !data.terms.length) { 62 marker.style.display = "none"; 63 return; 64 } 65 66 var banner = ensureBanner(marker); 67 banner.setAttribute("theme", data.theme || "dark"); 68 banner.setAttribute("includes-vat", data.includes_vat ? "true" : "false"); 69 70 data.terms.forEach(function (term) { 71 // "3_months" -> "3-months" for the paired amount/interest attributes. 72 var suffix = term.duration.replace(/_/g, "-"); 73 banner.setAttribute("amount-" + suffix, term.amount); 74 banner.setAttribute("interest-" + suffix, term.interest); 75 }); 76 77 marker.style.display = ""; 78 observeForView(banner); 79 } 80 81 function render(marker) { 82 if (!marker || !window.iwocapayCartBanner || !window.jQuery) { 83 return; 84 } 85 86 window.jQuery.ajax({ 87 url: window.iwocapayCartBanner.ajaxUrl, 88 type: "POST", 89 data: { action: "get_cart_banner_pricing" }, 90 dataType: "json", 91 success: function (data) { 92 applyPricing(marker, data); 93 }, 94 error: function () { 95 marker.style.display = "none"; 96 }, 97 }); 98 } 99 100 function renderAll() { 101 var markers = document.querySelectorAll("[" + MARKER_ATTR + "]"); 102 Array.prototype.forEach.call(markers, render); 103 } 104 105 // Exposed so the block SlotFill can render a marker it inserts into the React 106 // tree, and re-render it on the block cart store's totals changes. 107 window.iwocapayCartBannerRender = render; 108 window.iwocapayCartBannerRenderAll = renderAll; 109 110 // updated_checkout fires on many classic-checkout interactions (address, 111 // shipping method, payment-method select), not just total changes â debounce 112 // so a burst collapses into a single re-fetch instead of one roundtrip each. 113 function debounce(fn, wait) { 114 var timer; 115 return function () { 116 clearTimeout(timer); 117 timer = setTimeout(fn, wait); 118 }; 119 } 120
121 function init() { 122 renderAll(); 123 if (window.jQuery) { 124 // Classic cart/checkout re-render on the standard WooCommerce cart events. 125 window 126 .jQuery(document.body) 127 .on("updated_cart_totals wc_cart_emptied updated_checkout", debounce(renderAll, 300)); 128 } 129 } 130 131 if (document.readyState === "loading") { 132 document.addEventListener("DOMContentLoaded", init); 133 } else { 134 init(); 135 } 136})();
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.