[object Object]

← back to Robet Site

round3 item (1): real WebKit+Firefox verify FOUND+FIXED a bug — /embed/appointments.js returns text/html (not JS), script-injection threw uncaught SyntaxError; switched to iframe of /book?embed=1 (no X-Frame-Options) + permanent 'open in new tab' escape link; verified 0 syntax errors across chromium/webkit/firefox

dc71cfa1b6fdb73da5366d06ae005eacb2e34de7 · 2026-06-30 01:32:01 -0700 · Steve

Files touched

Diff

commit dc71cfa1b6fdb73da5366d06ae005eacb2e34de7
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jun 30 01:32:01 2026 -0700

    round3 item (1): real WebKit+Firefox verify FOUND+FIXED a bug — /embed/appointments.js returns text/html (not JS), script-injection threw uncaught SyntaxError; switched to iframe of /book?embed=1 (no X-Frame-Options) + permanent 'open in new tab' escape link; verified 0 syntax errors across chromium/webkit/firefox
---
 public/app.js     | 36 ++++++++++++++++++++----------------
 public/index.html |  9 ++++-----
 2 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/public/app.js b/public/app.js
index 2cf2ede..154275f 100644
--- a/public/app.js
+++ b/public/app.js
@@ -51,34 +51,38 @@
     }
   });
 
-  // ── Smart Scheduling embed: skeleton → real widget OR fallback (never a perpetual spinner) ──
+  // ── Smart Scheduling embed: iframe the chromeless booking page directly ──
+  //   The /embed/appointments.js loader returns text/html (not JS), so injecting it as a
+  //   <script> throws an uncaught SyntaxError (caught cross-browser, loudest in WebKit) and never
+  //   renders. /book?embed=1 returns the chromeless widget with no X-Frame-Options, so it frames
+  //   cleanly; CSP already allows frame-src venturacorridor.com. Skeleton → iframe OR fallback link.
   const sched = cfg.scheduling || {};
   const embedBox = $('#embedBox');
+  const bookAlt = $('#bookAlt');
+  if (bookAlt && sched.bookUrl) bookAlt.href = sched.bookUrl;   // permanent escape hatch
   const fallbackHTML = () =>
     `<div class="fallback mono">Booking opens in a new tab — <a class="cta" href="${sched.bookUrl || '#'}" target="_blank" rel="noopener noreferrer">Open booking page →</a></div>`;
   if (embedBox) {
-    if (!sched.embedLoader) {
+    if (!sched.bookUrl) {
       embedBox.innerHTML = fallbackHTML();
     } else {
-      // brutalist loading skeleton, shown immediately
       embedBox.innerHTML = '<div class="embed-skeleton" aria-hidden="true"><span></span><span></span><span></span><span></span></div>';
       let settled = false;
       const settle = (mode) => {
-        if (settled) return; settled = true;
-        clearTimeout(timer); obs.disconnect();
+        if (settled) return; settled = true; clearTimeout(timer);
         const sk = embedBox.querySelector('.embed-skeleton'); if (sk) sk.remove();
-        if (mode === 'fallback' && !embedBox.querySelector('iframe')) embedBox.innerHTML = fallbackHTML();
+        if (mode === 'fallback') embedBox.innerHTML = fallbackHTML();
       };
-      // a rendered booking widget = an injected <iframe>; that's our "it worked" signal
-      const obs = new MutationObserver(() => { if (embedBox.querySelector('iframe')) settle('embed'); });
-      obs.observe(embedBox, { childList: true, subtree: true });
-      const timer = setTimeout(() => settle('fallback'), 7000);  // no widget in 7s → fallback link
-      const s = document.createElement('script');
-      s.src = sched.embedLoader;
-      if (sched.owner) s.setAttribute('data-owner', sched.owner);
-      s.async = true;
-      s.onerror = () => settle('fallback');
-      embedBox.appendChild(s);
+      const sep = sched.bookUrl.includes('?') ? '&' : '?';
+      const frame = document.createElement('iframe');
+      frame.src = sched.bookUrl + sep + 'embed=1';
+      frame.title = 'Book a meeting — Smart Scheduling';
+      frame.loading = 'lazy';
+      frame.style.cssText = 'width:100%;min-height:560px;border:0;display:block;background:#fff';
+      frame.addEventListener('load', () => settle('embed'));      // booking page rendered
+      frame.addEventListener('error', () => settle('fallback'));
+      const timer = setTimeout(() => settle('fallback'), 8000);    // never loaded → fallback link
+      embedBox.appendChild(frame);
     }
   }
 
diff --git a/public/index.html b/public/index.html
index 1789a89..816c304 100644
--- a/public/index.html
+++ b/public/index.html
@@ -104,11 +104,10 @@ MEETING.</h1>
     <section id="booking">
       <span class="kicker">/ smart scheduling</span>
       <h2 class="sec-h">Pick a time.</h2>
-      <div class="embed-box" id="embedBox">
-        <div class="fallback" id="bookFallback" class="mono">
-          Loading available slots… &nbsp; <a class="cta" id="bookLink" href="#">Open booking →</a>
-        </div>
-      </div>
+      <div class="embed-box" id="embedBox"></div>
+      <p class="mono" style="margin-top:14px">
+        Trouble with the scheduler? <a id="bookAlt" href="#" target="_blank" rel="noopener noreferrer">Open booking in a new tab →</a>
+      </p>
     </section>
 
     <!-- contact -->

← 19cdcaa round 2 closed (7/8, #17 deferred-gated); round-3 DTD backlo  ·  back to Robet Site  ·  loop ledger: round3 item (1) done + deployed 10dd446 →