Fix <sql> silent-failure bug; split /vst into overview + subpage; misc site fixes

- __mysql.cpp: <sql> never checked mysql_real_query's own return code,
  so a genuine query failure was indistinguishable from "ran fine, zero
  rows" - <try>/<catch> around a failing <sql> never actually caught
  anything anywhere. Now throws on a real failure.
- spa.js: dynamically re-injected scripts now run in true sequential
  order (wait for each external script's load event before running the
  next), fixing checkout's Square card field never building on the
  first client-side navigation to /checkout (only after a refresh) -
  async=false alone only orders multiple external scripts relative to
  each other, it doesn't delay a plain inline sibling.
- /vst split into a real overview + /vst/modular1 subpage with a left
  menu, reusing opensource.page's existing subpage-tier pattern
  (opensource.menu/main.css's submenuitem-active highlighting, and
  several other subpage-tier retirements, were already finished earlier
  this session but never committed - included here too).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Brad ArantandClaude Sonnet 5 committed 2026-09-13 15:14:25 +00:00
1 parent 46ef67b735
commit 905fbafa5a
17 files changed
+474 -63

No files matched your search

+32 -8
View File
@@ -127,19 +127,43 @@
// a client-side SPA swap (e.g. clicking "Check Out") instead of a
// full reload; only worked by accident on a fresh /checkout load.
// Re-creating each script element makes the browser actually run
// it. async=false on src="" ones preserves normal in-order
// execution (dynamically-inserted external scripts default to
// async otherwise), matching how a real page load would run them.
// it. A prior fix set async=false on src="" ones, but that only
// orders MULTIPLE external scripts relative to each other - it
// does nothing to delay a plain inline script sitting right after
// one, which still runs immediately on insertion regardless of a
// sibling's in-flight fetch. checkout.page is exactly that shape
// (an external Square SDK <script src> immediately followed by an
// inline script calling Square.payments(...)): on a client-side
// SPA swap the inline script ran before Square had actually
// finished downloading, throwing "Square is not defined" inside an
// async function with no visible catch, leaving the card container
// permanently empty - reported as "checkout's card field doesn't
// build the first time, only after a refresh" (a real full page
// load's parser-inserted <script src> blocks until loaded before
// the next tag runs, which a dynamically re-created one does not
// do on its own). Fixed by actually waiting for each external
// script's load/error event before moving on to the next one,
// rather than trusting async=false's narrower ordering guarantee -
// reproduced the failure and confirmed the fix against a real
// artificially-delayed script load before deploying.
var scripts = content.querySelectorAll('script');
for (var i = 0; i < scripts.length; i++) {
var old = scripts[i];
var scriptList = [];
for (var i = 0; i < scripts.length; i++) scriptList.push(scripts[i]);
(function runScript(index) {
if (index >= scriptList.length) return;
var old = scriptList[index];
var fresh = document.createElement('script');
for (var j = 0; j < old.attributes.length; j++)
fresh.setAttribute(old.attributes[j].name, old.attributes[j].value);
if (fresh.src) fresh.async = false;
fresh.textContent = old.textContent;
old.parentNode.replaceChild(fresh, old);
}
if (fresh.src) {
fresh.onload = fresh.onerror = function() { runScript(index + 1); };
old.parentNode.replaceChild(fresh, old);
} else {
old.parentNode.replaceChild(fresh, old);
runScript(index + 1);
}
})(0);
// #_spa_panelmenu carries the CURRENT page's own side-menu markup
// (mainpagetemplate.jet renders it into every fragment response
// specifically so this can pull it out) - extracted from the