1/* ========================================================= 2 * Bespoke Bike Builder â Notices & WhatsApp Layer 3 * Additive script. Reads settings localized from PHP via 4 * bbbNotices (wp_localize_script) â disclaimer text, checkbox 5 * text, WhatsApp number and messages all come from the new 6 * "BBB Notices" admin settings page, not hardcoded here. 7 * 8 * v4: 9 * - Fixed duplicate disclaimer bug on the confirmation step. 10 * Priority is now: success message banner > review banner > 11 * lead-form banner, checked in that order and stopping at 12 * the first match, since a submitted step can still have 13 * leftover (hidden) lead-form fields in the DOM alongside 14 * its now-visible success message. 15 * - Added a WhatsApp icon (inline SVG) to the Frame Size 16 * "Chat with us" link. 17 * ========================================================= */ 18 19(function () { 20 "use strict"; 21 22 var settings = window.bbbNotices || {}; 23 var whatsappNumber = (settings.whatsappNumber || "").replace(/[^\d+]/g, ""); 24 var disclaimerText = 25 settings.disclaimerText || 26 "Your selected configuration is subject to availability, technical review and final confirmation by The Cycle Hub team. Submitting this request does not reserve any component or confirm an order."; 27 var checkboxText = 28 settings.checkboxText || 29 "I understand that this configuration is subject to availability and confirmation by The Cycle Hub team. Deposit terms apply."; 30 var sizeMessage = settings.whatsappSizeMessage || "Hi, I need help choosing the right frame size for my Dogma F build."; 31 32 var WHATSAPP_ICON_SVG = 33 '<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" style="flex-shrink:0;">' + 34 '<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.149-.15.298-.347.446-.52.15-.174.199-.298.298-.497.099-.198.05-.372-.05-.52-.099-.148-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.076 4.487.709.306 1.262.489 1.694.626.712.226 1.36.194 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347z"/>' + 35 '<path d="M12.012 2C6.486 2 2 6.486 2 12.012c0 1.987.582 3.833 1.586 5.386L2 22l4.706-1.552a9.94 9.94 0 0 0 5.306 1.516c5.526 0 10.012-4.486 10.012-10.012C22.024 6.486 17.538 2 12.012 2zm0 18.062a8.02 8.02 0 0 1-4.319-1.267l-.31-.192-3.06 1.01 1.02-2.98-.202-.32a8.01 8.01 0 0 1-1.24-4.29c0-4.436 3.612-8.048 8.05-8.048 4.436 0 8.048 3.612 8.048 8.048 0 4.437-3.612 8.04-8.048 8.04z"/>' + 36 '</svg>'; 37 38 function getRoot() {
39 return document.querySelector(".bbb-builder-placeholder"); 40 } 41 42 function buildWhatsappLink(message) { 43 if (!whatsappNumber) return null; 44 var encoded = encodeURIComponent(message); 45 return "https://wa.me/" + whatsappNumber.replace("+", "") + "?text=" + encoded; 46 } 47 48 function removeLegacyBanners(root) { 49 if (!root) return; 50 var legacyTop = root.querySelector(".bbb-notice-banner--top"); 51 if (legacyTop) legacyTop.parentNode.removeChild(legacyTop); 52 var legacyFloating = document.querySelector(".bbb-whatsapp-floating"); 53 if (legacyFloating) legacyFloating.parentNode.removeChild(legacyFloating); 54 } 55 56 function insertBanner(container) { 57 var banner = document.createElement("div"); 58 banner.className = "bbb-notice-banner"; 59 banner.textContent = disclaimerText; 60 container.appendChild(banner); 61 return banner; 62 } 63 64 function tagAndBannerSteps(root) { 65 if (!root) return; 66 root.querySelectorAll(".bbb-step").forEach(function (step) { 67 var successMsg = step.querySelector(".bbb-success-message"); 68 var reviewContent = step.querySelector(".bbb-review-content"); 69 var leadFields = step.querySelectorAll(".bbb-lead-field:not(.bbb-lead-field--agreement)"); 70 71 if (successMsg) { 72 step.querySelectorAll(".bbb-notice-banner").forEach(function (b) { 73 if (b.parentNode !== successMsg) { 74 b.parentNode.removeChild(b); 75 } 76 }); 77 if (!successMsg.querySelector(".bbb-notice-banner")) { 78 insertBanner(successMsg); 79 } 80 return; 81 } 82 83 if (reviewContent) { 84 if (!step.querySelector(".bbb-notice-banner")) { 85 insertBanner(step); 86 } 87 return; 88 } 89 90 if (leadFields && leadFields.length > 0) { 91 if (!step.querySelector(".bbb-notice-banner")) { 92 insertBanner(step); 93 } 94 } 95 }); 96 } 97 98 function ensureFrameSizeHelp(root) { 99 if (!root || !whatsappNumber) return; 100 root.querySelectorAll(".bbb-dropdown").forEach(function (select) { 101 if (select.dataset.bbbSizeHelpAdded) return; 102 var heading = select.previousElementSibling; 103 var headingText = heading && heading.textContent ? heading.textContent.trim().toLowerCase() : ""; 104 if (headingText.indexOf("frame size") === -1 && headingText.indexOf("size") === -1) return; 105 106 select.dataset.bbbSizeHelpAdded = "true"; 107 var link = document.createElement("a"); 108 link.className = "bbb-whatsapp-inline"; 109 link.href = buildWhatsappLink(sizeMessage); 110 link.target = "_blank"; 111 link.rel = "noopener noreferrer"; 112 link.innerHTML = WHATSAPP_ICON_SVG + '<span>Not sure which size is right? Chat with us</span>'; 113 select.parentNode.insertBefore(link, select.nextSibling); 114 }); 115 } 116 117 function ensureAgreementCheckbox(root) { 118 if (!root) return; 119 root.querySelectorAll(".bbb-step").forEach(function (step) { 120 if (step.dataset.bbbAgreementAdded) return; 121 var textarea = step.querySelector("textarea"); 122 if (!textarea) return; 123 124 step.dataset.bbbAgreementAdded = "true"; 125 126 var wrap = document.createElement("div"); 127 wrap.className = "bbb-lead-field bbb-lead-field--agreement"; 128 wrap.style.marginTop = "16px"; 129 wrap.innerHTML = 130 '<label style="display:flex;align-items:flex-start;gap:10px;font-weight:normal;">' + 131 '<input type="checkbox" class="bbb-agreement-checkbox" style="margin-top:4px;min-width:20px;min-height:20px;" />' + 132 "<span>" + checkboxText + "</span>" + 133 "</label>"; 134 135 textarea.parentNode.insertBefore(wrap, textarea.nextSibling); 136 137 var checkbox = wrap.querySelector(".bbb-agreement-checkbox"); 138 var nav = step.parentNode ? step.parentNode.querySelector(".bbb-nav") : null; 139 140 function syncButtonState() { 141 var nextBtn = document.querySelector(".bbb-step-active .bbb-next-button") || 142 (nav ? nav.querySelector(".bbb-next-button") : null); 143 if (!nextBtn) return; 144 if (checkbox.checked) { 145 nextBtn.removeAttribute("data-bbb-agreement-blocked"); 146 } else { 147 nextBtn.setAttribute("data-bbb-agreement-blocked", "true"); 148 } 149 } 150 151 checkbox.addEventListener("change", syncButtonState); 152 153 document.addEventListener( 154 "click", 155 function (e) { 156 if (!step.classList.contains("bbb-step-active")) return; 157 var target = e.target; 158 if (target && target.classList && target.classList.contains("bbb-next-button")) { 159 if (!checkbox.checked) { 160 e.preventDefault(); 161 e.stopImmediatePropagation(); 162 checkbox.parentNode.style.color = "#ff6b6b";
163 } 164 } 165 }, 166 true 167 ); 168 }); 169 } 170 171 function runEnhancements() { 172 var root = getRoot(); 173 if (!root) return; 174 removeLegacyBanners(root); 175 tagAndBannerSteps(root); 176 ensureFrameSizeHelp(root); 177 ensureAgreementCheckbox(root); 178 } 179 180 document.addEventListener("DOMContentLoaded", function () { 181 runEnhancements(); 182 var root = getRoot(); 183 if (root) { 184 var observer = new MutationObserver(function () { 185 runEnhancements(); 186 }); 187 observer.observe(root, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"] }); 188 } 189 }); 190})();
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.