PageSourceSearch

https://thecyclehub.com/wp-content/plugins/bespoke-bike-builder/assets/js/builder-notices.js?ver=1788008794

js thecyclehub.com collected 2026-10-06 19:17:03 UTC 8,133 bytes, 190 lines download raw bytes

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.