PageSourceSearch

https://drglenntoby.com/assets/enhance/btt-band.js?v=f1bd6253

js drglenntoby.com collected 2026-10-02 11:32:28 UTC 11,124 bytes, 278 lines download raw bytes

1/* A Bridge to the Throne — Black Friday band (enhancement layer).
2   Inserts one section on the homepage after the Rhythm of Revenue book
3   band. Rules honoured, each learned the hard way on this ecosystem:
4   never reuse builder class names (find the anchor by its text), insert
5   only after hydration settles, and if the framework drops the node on a
6   re-render, put it back rather than assume it stays. */
7(function () {
8  "use strict";
9
10  // The Bridge to the Throne site. Swap this one line when the custom
11  // domain is acquired, re-hash the ?v= in index.html, re-zip.
12  var BTT_URL = "https://abridgetothethrone.com";
13
14  var path = location.pathname.replace(/\/+$/, "") || "/";
15  if (path !== "/" && !/\/index(\.html)?$/.test(path)) return;
16
17  var BAND_ID = "gtbtt-band";
18  var attempts = 0;
19
20  function ownText(el) {
21    var t = "";
22    for (var i = 0; i < el.childNodes.length; i++) {
23      if (el.childNodes[i].nodeType === 3) t += el.childNodes[i].textContent;
24    }
25    return t;
26  }
27
28  function findAnchor() {
29    // The ROR purple band: the ancestor of its copy whose parent is the
30    // page's section list (13 children on this page). Structural, no
31    // geometry, so viewport width cannot break it.
32    var probe = null;
33    var ps = document.querySelectorAll("p");
34    for (var i = 0; i < ps.length; i++) {
35      if (/turned survival into strategy/.test(ps[i].textContent || "")) { probe = ps[i]; break; }
36    }
37    if (!probe) return null;
38    var el = probe;
39    while (el && el !== document.body) {
40      var pr = el.parentElement;
41      if (pr && pr.children.length >= 8) {
42        // confirm this really is the section list: testimonials lives here too
43        for (var k = 0; k < pr.children.length; k++) {
44          if (pr.children[k] !== el && /WHAT LEADERS AND COLLABORATORS SAY/i.test(pr.children[k].innerText || "")) {
45            return { host: el, parent: pr };
46          }
47        }
48      }
49      el = pr;
50    }
51    return null;
52  }
53
54  function buildBand() {
55    var section = document.createElement("section");
56    section.id = BAND_ID;
57    section.className = "gtbtt";
58    section.innerHTML =
59      '<div class="gtbtt__inner">' +
60        '<div class="gtbtt__copy">' +
61          '<p class="gtbtt__eyebrow">The New Book · A Bridge to the Throne</p>' +
62          '<h3 class="gtbtt__headline gtbtt__headline--announce">Coming Soon on Black&nbsp;Friday.</h3>' +
63          '<p class="gtbtt__date">November 27, 2026</p>' +
64          '<p class="gtbtt__pullline">You have been crossing the bridge your entire life.</p>' +
65          '<p class="gtbtt__body">How to cross from purpose to legacy. A transformational journey through healing, discipline, character, courage, financial wisdom, service, and consciousness, built one decision at a time.</p>' +
66          '<form class="gtbtt__form" method="post" action="/api/notify" novalidate>' +
67            '<input class="gtbtt__email" type="email" name="email" placeholder="Your email" required autocomplete="email" aria-label="Your email">' +
68            '<input type="text" name="company" tabindex="-1" autocomplete="off" aria-hidden="true" style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0">' +
69            '<button class="gtbtt__btn" type="submit">Notify Me First</button>' +
70          "</form>" +
71          '<p class="gtbtt__note">Release list only. One email when the book goes live.</p>' +
72          '<a class="gtbtt__link" href="' + BTT_URL + '" target="_blank" rel="noopener">Visit the Book Site →</a>' +
73        "</div>" +
74        '<div class="gtbtt__coverwrap">' +
75          '<a href="' + BTT_URL + '" target="_blank" rel="noopener" aria-label="Visit the A Bridge to the Throne site">' +
76            '<img class="gtbtt__cover" src="/assets/enhance/btt-cover.jpg" alt="A Bridge to the Throne by Dr. Glenn Toby, book cover" loading="lazy">' +
77          "</a>" +
78        "</div>" +
79      "</div>";
80
81    // staggered entrance on the house grid (625ms beat, quarter offsets)
82    var stagger = 0;
83    [].slice.call(section.querySelectorAll(".gtbtt__eyebrow, .gtbtt__headline, .gtbtt__date, .gtbtt__pullline, .gtbtt__body, .gtbtt__form, .gtbtt__note, .gtbtt__link, .gtbtt__coverwrap")).forEac
83h(function (el) {
84      el.setAttribute("data-gtrv", "");
85      el.style.transitionDelay = (stagger * 0.08).toFixed(2) + "s";
86      stagger++;
87    });
88
89    var form = section.querySelector("form");
90    form.addEventListener("submit", function (ev) {
91      ev.preventDefault();
92      var btn = form.querySelector("button");
93      var msg = section.querySelector(".gtbtt__msg");
94      if (!msg) {
95        msg = document.createElement("p");
96        msg.className = "gtbtt__msg";
97        form.insertAdjacentElement("afterend", msg);
98      }
99      msg.textContent = "";
100      msg.className = "gtbtt__msg";
101      var email = (form.elements.email.value || "").trim();
102      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
103        msg.textContent = "Enter a valid email address.";
104        msg.className = "gtbtt__msg gtbtt__msg--err";
105        return;
106      }
107      var original = btn.textContent;
108      btn.textContent = "Sending…";
109      btn.disabled = true;
110      fetch("/api/notify", {
111        method: "POST",
112        headers: { "Content-Type": "application/json" },
113        body: JSON.stringify({ email: email, company: form.elements.company.value || "" })
114      }).then(function (res) {
115        return res.json().catch(function () { return { ok: false }; }).then(function (body) {
116          if (res.ok && body.ok) {
117            btn.textContent = "You are on the list.";
118            form.elements.email.value = "";
119            setTimeout(function () { btn.textContent = original; btn.disabled = false; }, 6000);
120          } else { throw new Error("failed"); }
121        });
122      }).catch(function () {
123        btn.textContent = original;
124        btn.disabled = false;
125        msg.textContent = "Could not send right now. Please try again shortly.";
126        msg.className = "gtbtt__msg gtbtt__msg--err";
127      });
128    });
129    return section;
130  }
131
132  var band = null;
133
134  function bandPlacedRight() {
135    var b = document.getElementById(BAND_ID);
136    if (!b || !b.previousElementSibling) return false;
137    return /FROM BROOKLYN TO THE BOARDROOM/i.test(
138      (b.previousElementSibling.innerText || "").slice(0, 800));
139  }
140
141  function ensureInserted() {
142    if (bandPlacedRight()) return true;
143    var anchor = findAnchor();
144    if (!anchor) return false;
145    if (!band) band = buildBand();
146    // insertAdjacentElement re-homes the node if it landed somewhere wrong
147    anchor.host.insertAdjacentElement("afterend", band);
148    return bandPlacedRight();
149  }
150
151  function fallbackInsert() {
152    if (document.getElementById(BAND_ID)) return true;
153    var els = document.querySelectorAll("p, h2, h3, div");
154    for (var i = 0; i < els.length; i++) {
155      if (/WHAT LEADERS AND COLLABORATORS SAY/i.test(els[i].innerText || "")) {
156        var el = els[i];
157        while (el && el !== document.body) {
158          var pr = el.parentElement;
159          if (pr && pr.children.length >= 8) {
160            if (!band) band = buildBand();
161            el.insertAdjacentElement("beforebegin", band);
162            return true;
163          }
164          el = pr;
165        }
166      }
167    }
168    return false;
169  }
170
171  function start() {
172    if (ensureInserted()) {
173      armReveals();
174      armProgress();
175      repairGalleryLinks();
176      watch();
177      return;
178    }
179    attempts++;
180    if (attempts < 30) { setTimeout(start, 400); return; } // hydration can be slow; keep probing
181    // primary anchor never resolved: presence beats perfection
182    if (fallbackInsert()) {
183      armReveals();
184      armProgress();
185      repairGalleryLinks();
186      watch();
187    }
188  }
189
190  var reduceMotion = false;
191  try { reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; } catch (e) {}
192
193  function armReveals() {
194    // fail-open: nothing is ever hidden unless the observer is live and the
195    // element is safely below the viewport; a missed callback can only mean
196    // "no animation", never "invisible content"
197    var els = [].slice.call(document.querySelectorAll("[data-gtrv]"));
198    if (!els.length) return;
199    if (reduceMotion || !("IntersectionObserver" in window)) return;
200    var io = new IntersectionObserver(function (entries) {
201      entries.forEach(function (entry) {
202        if (entry.isIntersecting) {
203          entry.target.classList.remove("gtrv-pre");
204          entry.target.classList.add("gtrv-in");
205          io.unobserve(entry.target);
206        }
207      });
208    }, { threshold: 0.2 });
209    els.forEach(function (el) {
210      var r = el.getBoundingClientRect();
211      if (r.top > window.innerHeight * 1.05) {
212        el.classList.add("gtrv-pre");
213        io.observe(el);
214      }
215    });
216    // safety net: whatever is still pre-hidden after 8s becomes visible
217    setTimeout(function () {
218      els.forEach(function (el) { el.classList.remove("gtrv-pre"); el.classList.add("gtrv-in"); });
219    }, 8000);
220  }
221
222  function armProgress() {
223    if (document.getElementById("gtbtt-progress")) return;
224    var bar = document.createElement("div");
225    bar.id = "gtbtt-progress";
226    bar.setAttribute("aria-hidden", "true");
227    document.body.appendChild(bar);
228    var ticking = false;
229    function frame() {
230      ticking = false;
231      var doc = document.documentElement;
232      var max = (doc.scrollHeight - window.innerHeight) || 1;
233      var f = Math.min(1, Math.max(0, (window.scrollY || doc.scrollTop) / max));
234      bar.style.transform = "scaleX(" + f.toFixed(4) + ")";
235    }
236    window.addEventListener("scroll", function () {
237      if (!ticking) { ticking = true; requestAnimationFrame(frame); }
238    }, { passive: true });
239    window.addEventListener("resize", frame);
240    frame();
241  }
242
243  // --- gallery-door repair ---------------------------------------------
244  // The Arrangement's ART-room card (and three other spots) still point at
245  // the interim Adobe Express page. The King's Exhibition now lives at its
246  // own domain, so those anchors are repointed at runtime. Attribute-only
247  // mutation; the observer re-applies it if a re-render restores the old
248  // href.
249  var OLD_KE = "new.express.adobe.com";
250  var NEW_KE = "https://thekingsexhibition.com";
251  function repairGalleryLinks() {
252    var as = document.querySelectorAll('a[href*="' + OLD_KE + '"]');
253    for (var i = 0; i < as.length; i++) as[i].setAttribute("href", NEW_KE);
254    return as.length;
255  }
256
257  function watch() {
258    // If a framework re-render drops the band, re-insert. Union semantics:
259    // never remove on our own.
260    var queued = false;
261    var mo = new MutationObserver(function () {
262      if (queued) return;
263      queued = true;
264      setTimeout(function () {
265        queued = false;
266        if (!bandPlacedRight()) ensureInserted();
267        repairGalleryLinks();
268      }, 250);
269    });
270    mo.observe(document.body, { childList: true, subtree: true });
271  }
272
273  if (document.readyState === "loading") {
274    document.addEventListener("DOMContentLoaded", function () { setTimeout(start, 250); });
275  } else {
276    setTimeout(start, 250);
277  }
278})();

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.