Fix sx-browser.js navigation bugs: CSS tracking meta tag and stale verb info
Two fixes for sx-browser.js (spec-compiled) vs sx.js (hand-written): 1. CSS meta tag mismatch: initCssTracking read meta[name="sx-css-hash"] but the page template uses meta[name="sx-css-classes"]. This left _cssHash empty, causing the server to send ALL CSS as "new" on every navigation, appending duplicate rules that broke Tailwind responsive ordering (e.g. menu bar layout). 2. Stale verb info after morph: execute-request used captured verbInfo from bind time. After morph updated element attributes (e.g. during OOB nav swap), click handlers still fired with old URLs. Now re-reads verb info from the element first, matching sx.js behavior. Also includes: render-expression dispatch in eval.sx, NIL guard for preload cache in bootstrap_js.py, and helpers.py switched to sx-browser.js. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,7 @@
|
|||||||
if (x._macro) return "macro";
|
if (x._macro) return "macro";
|
||||||
if (x._raw) return "raw-html";
|
if (x._raw) return "raw-html";
|
||||||
if (x._styleValue) return "style-value";
|
if (x._styleValue) return "style-value";
|
||||||
|
if (typeof Node !== "undefined" && x instanceof Node) return "dom-node";
|
||||||
if (Array.isArray(x)) return "list";
|
if (Array.isArray(x)) return "list";
|
||||||
if (typeof x === "object") return "dict";
|
if (typeof x === "object") return "dict";
|
||||||
return "unknown";
|
return "unknown";
|
||||||
@@ -178,6 +179,29 @@
|
|||||||
function dictSet(d, k, v) { d[k] = v; }
|
function dictSet(d, k, v) { d[k] = v; }
|
||||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||||
|
|
||||||
|
// Render-expression detection — lets the evaluator delegate to the active adapter.
|
||||||
|
// Matches HTML tags, SVG tags, <>, raw!, ~components, html: prefix, custom elements.
|
||||||
|
function isRenderExpr(expr) {
|
||||||
|
if (!Array.isArray(expr) || !expr.length) return false;
|
||||||
|
var h = expr[0];
|
||||||
|
if (!h || !h._sym) return false;
|
||||||
|
var n = h.name;
|
||||||
|
return !!(n === "<>" || n === "raw!" ||
|
||||||
|
n.charAt(0) === "~" || n.indexOf("html:") === 0 ||
|
||||||
|
(typeof HTML_TAGS !== "undefined" && HTML_TAGS.indexOf(n) >= 0) ||
|
||||||
|
(typeof SVG_TAGS !== "undefined" && SVG_TAGS.indexOf(n) >= 0) ||
|
||||||
|
(n.indexOf("-") > 0 && expr.length > 1 && expr[1] && expr[1]._kw));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render dispatch — call the active adapter's render function.
|
||||||
|
// Set by each adapter when loaded; defaults to identity (no rendering).
|
||||||
|
var _renderExprFn = null;
|
||||||
|
function renderExpr(expr, env) {
|
||||||
|
if (_renderExprFn) return _renderExprFn(expr, env);
|
||||||
|
// No adapter loaded — just return the expression as-is
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
function stripPrefix(s, prefix) {
|
function stripPrefix(s, prefix) {
|
||||||
return s.indexOf(prefix) === 0 ? s.slice(prefix.length) : s;
|
return s.indexOf(prefix) === 0 ? s.slice(prefix.length) : s;
|
||||||
}
|
}
|
||||||
@@ -507,7 +531,7 @@
|
|||||||
return (isSxTruthy((name == "if")) ? sfIf(args, env) : (isSxTruthy((name == "when")) ? sfWhen(args, env) : (isSxTruthy((name == "cond")) ? sfCond(args, env) : (isSxTruthy((name == "case")) ? sfCase(args, env) : (isSxTruthy((name == "and")) ? sfAnd(args, env) : (isSxTruthy((name == "or")) ? sfOr(args, env) : (isSxTruthy((name == "let")) ? sfLet(args, env) : (isSxTruthy((name == "let*")) ? sfLet(args, env) : (isSxTruthy((name == "lambda")) ? sfLambda(args, env) : (isSxTruthy((name == "fn")) ? sfLambda(args, env) : (isSxTruthy((name == "define")) ? sfDefine(args, env) : (isSxTruthy((name == "defcomp")) ? sfDefcomp(args, env) : (isSxTruthy((name == "defmacro")) ? sfDefmacro(args, env) : (isSxTruthy((name == "defstyle")) ? sfDefstyle(args, env) : (isSxTruthy((name == "defkeyframes")) ? sfDefkeyframes(args, env) : (isSxTruthy((name == "defhandler")) ? sfDefine(args, env) : (isSxTruthy((name == "begin")) ? sfBegin(args, env) : (isSxTruthy((name == "do")) ? sfBegin(args, env) : (isSxTruthy((name == "quote")) ? sfQuote(args, env) : (isSxTruthy((name == "quasiquote")) ? sfQuasiquote(args, env) : (isSxTruthy((name == "->")) ? sfThreadFirst(args, env) : (isSxTruthy((name == "set!")) ? sfSetBang(args, env) : (isSxTruthy((name == "map")) ? hoMap(args, env) : (isSxTruthy((name == "map-indexed")) ? hoMapIndexed(args, env) : (isSxTruthy((name == "filter")) ? hoFilter(args, env) : (isSxTruthy((name == "reduce")) ? hoReduce(args, env) : (isSxTruthy((name == "some")) ? hoSome(args, env) : (isSxTruthy((name == "every?")) ? hoEvery(args, env) : (isSxTruthy((name == "for-each")) ? hoForEach(args, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
|
return (isSxTruthy((name == "if")) ? sfIf(args, env) : (isSxTruthy((name == "when")) ? sfWhen(args, env) : (isSxTruthy((name == "cond")) ? sfCond(args, env) : (isSxTruthy((name == "case")) ? sfCase(args, env) : (isSxTruthy((name == "and")) ? sfAnd(args, env) : (isSxTruthy((name == "or")) ? sfOr(args, env) : (isSxTruthy((name == "let")) ? sfLet(args, env) : (isSxTruthy((name == "let*")) ? sfLet(args, env) : (isSxTruthy((name == "lambda")) ? sfLambda(args, env) : (isSxTruthy((name == "fn")) ? sfLambda(args, env) : (isSxTruthy((name == "define")) ? sfDefine(args, env) : (isSxTruthy((name == "defcomp")) ? sfDefcomp(args, env) : (isSxTruthy((name == "defmacro")) ? sfDefmacro(args, env) : (isSxTruthy((name == "defstyle")) ? sfDefstyle(args, env) : (isSxTruthy((name == "defkeyframes")) ? sfDefkeyframes(args, env) : (isSxTruthy((name == "defhandler")) ? sfDefine(args, env) : (isSxTruthy((name == "begin")) ? sfBegin(args, env) : (isSxTruthy((name == "do")) ? sfBegin(args, env) : (isSxTruthy((name == "quote")) ? sfQuote(args, env) : (isSxTruthy((name == "quasiquote")) ? sfQuasiquote(args, env) : (isSxTruthy((name == "->")) ? sfThreadFirst(args, env) : (isSxTruthy((name == "set!")) ? sfSetBang(args, env) : (isSxTruthy((name == "map")) ? hoMap(args, env) : (isSxTruthy((name == "map-indexed")) ? hoMapIndexed(args, env) : (isSxTruthy((name == "filter")) ? hoFilter(args, env) : (isSxTruthy((name == "reduce")) ? hoReduce(args, env) : (isSxTruthy((name == "some")) ? hoSome(args, env) : (isSxTruthy((name == "every?")) ? hoEvery(args, env) : (isSxTruthy((name == "for-each")) ? hoForEach(args, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
|
||||||
var mac = envGet(env, name);
|
var mac = envGet(env, name);
|
||||||
return makeThunk(expandMacro(mac, args, env), env);
|
return makeThunk(expandMacro(mac, args, env), env);
|
||||||
})() : evalCall(head, args, env)))))))))))))))))))))))))))))));
|
})() : (isSxTruthy(isRenderExpr(expr)) ? renderExpr(expr, env) : evalCall(head, args, env))))))))))))))))))))))))))))))));
|
||||||
})() : evalCall(head, args, env)));
|
})() : evalCall(head, args, env)));
|
||||||
})(); };
|
})(); };
|
||||||
|
|
||||||
@@ -1149,11 +1173,12 @@
|
|||||||
var morphNode = function(oldNode, newNode) { return (isSxTruthy(sxOr(domHasAttr(oldNode, "sx-preserve"), domHasAttr(oldNode, "sx-ignore"))) ? NIL : (isSxTruthy(sxOr(!(domNodeType(oldNode) == domNodeType(newNode)), !(domNodeName(oldNode) == domNodeName(newNode)))) ? domReplaceChild(domParent(oldNode), domClone(newNode), oldNode) : (isSxTruthy(sxOr((domNodeType(oldNode) == 3), (domNodeType(oldNode) == 8))) ? (isSxTruthy(!(domTextContent(oldNode) == domTextContent(newNode))) ? domSetTextContent(oldNode, domTextContent(newNode)) : NIL) : (isSxTruthy((domNodeType(oldNode) == 1)) ? (syncAttrs(oldNode, newNode), (isSxTruthy(!(isSxTruthy(domIsActiveElement(oldNode)) && domIsInputElement(oldNode))) ? morphChildren(oldNode, newNode) : NIL)) : NIL)))); };
|
var morphNode = function(oldNode, newNode) { return (isSxTruthy(sxOr(domHasAttr(oldNode, "sx-preserve"), domHasAttr(oldNode, "sx-ignore"))) ? NIL : (isSxTruthy(sxOr(!(domNodeType(oldNode) == domNodeType(newNode)), !(domNodeName(oldNode) == domNodeName(newNode)))) ? domReplaceChild(domParent(oldNode), domClone(newNode), oldNode) : (isSxTruthy(sxOr((domNodeType(oldNode) == 3), (domNodeType(oldNode) == 8))) ? (isSxTruthy(!(domTextContent(oldNode) == domTextContent(newNode))) ? domSetTextContent(oldNode, domTextContent(newNode)) : NIL) : (isSxTruthy((domNodeType(oldNode) == 1)) ? (syncAttrs(oldNode, newNode), (isSxTruthy(!(isSxTruthy(domIsActiveElement(oldNode)) && domIsInputElement(oldNode))) ? morphChildren(oldNode, newNode) : NIL)) : NIL)))); };
|
||||||
|
|
||||||
// sync-attrs
|
// sync-attrs
|
||||||
var syncAttrs = function(oldEl, newEl) { return forEach(function(attr) { return (function() {
|
var syncAttrs = function(oldEl, newEl) { { var _c = domAttrList(newEl); for (var _i = 0; _i < _c.length; _i++) { var attr = _c[_i]; (function() {
|
||||||
var name = first(attr);
|
var name = first(attr);
|
||||||
var val = nth(attr, 1);
|
var val = nth(attr, 1);
|
||||||
return (isSxTruthy(!(domGetAttr(oldEl, name) == val)) ? domSetAttr(oldEl, name, val) : NIL);
|
return (isSxTruthy(!(domGetAttr(oldEl, name) == val)) ? domSetAttr(oldEl, name, val) : NIL);
|
||||||
})(); }, domAttrList(newEl)); };
|
})(); } }
|
||||||
|
return forEach(function(attr) { return (isSxTruthy(!domHasAttr(newEl, first(attr))) ? domRemoveAttr(oldEl, first(attr)) : NIL); }, domAttrList(oldEl)); };
|
||||||
|
|
||||||
// morph-children
|
// morph-children
|
||||||
var morphChildren = function(oldParent, newParent) { return (function() {
|
var morphChildren = function(oldParent, newParent) { return (function() {
|
||||||
@@ -1272,7 +1297,7 @@
|
|||||||
|
|
||||||
// init-css-tracking
|
// init-css-tracking
|
||||||
var initCssTracking = function() { return (function() {
|
var initCssTracking = function() { return (function() {
|
||||||
var meta = domQuery("meta[name=\"sx-css-hash\"]");
|
var meta = domQuery("meta[name=\"sx-css-classes\"]");
|
||||||
return (isSxTruthy(meta) ? (function() {
|
return (isSxTruthy(meta) ? (function() {
|
||||||
var content = domGetAttr(meta, "content");
|
var content = domGetAttr(meta, "content");
|
||||||
return (isSxTruthy(content) ? (_cssHash = content) : NIL);
|
return (isSxTruthy(content) ? (_cssHash = content) : NIL);
|
||||||
@@ -1281,7 +1306,7 @@
|
|||||||
|
|
||||||
// execute-request
|
// execute-request
|
||||||
var executeRequest = function(el, verbInfo, extraParams) { return (function() {
|
var executeRequest = function(el, verbInfo, extraParams) { return (function() {
|
||||||
var info = sxOr(verbInfo, getVerbInfo(el));
|
var info = sxOr(getVerbInfo(el), verbInfo);
|
||||||
return (isSxTruthy(isNil(info)) ? promiseResolve(NIL) : (function() {
|
return (isSxTruthy(isNil(info)) ? promiseResolve(NIL) : (function() {
|
||||||
var verb = get(info, "method");
|
var verb = get(info, "method");
|
||||||
var url = get(info, "url");
|
var url = get(info, "url");
|
||||||
@@ -1373,11 +1398,14 @@
|
|||||||
var rendered = sxRender(trimmed);
|
var rendered = sxRender(trimmed);
|
||||||
var container = domCreateElement("div", NIL);
|
var container = domCreateElement("div", NIL);
|
||||||
domAppend(container, rendered);
|
domAppend(container, rendered);
|
||||||
processOobSwaps(container, function(t, oob, s) { return swapDomNodes(t, oob, s); });
|
processOobSwaps(container, function(t, oob, s) { swapDomNodes(t, oob, s);
|
||||||
|
sxHydrate(t);
|
||||||
|
return processElements(t); });
|
||||||
return (function() {
|
return (function() {
|
||||||
var selectSel = domGetAttr(el, "sx-select");
|
var selectSel = domGetAttr(el, "sx-select");
|
||||||
var content = (isSxTruthy(selectSel) ? selectFromContainer(container, selectSel) : childrenToFragment(container));
|
var content = (isSxTruthy(selectSel) ? selectFromContainer(container, selectSel) : childrenToFragment(container));
|
||||||
return withTransition(useTransition, function() { return swapDomNodes(target, content, swapStyle); });
|
return withTransition(useTransition, function() { swapDomNodes(target, content, swapStyle);
|
||||||
|
return postSwap(target); });
|
||||||
})();
|
})();
|
||||||
})() : NIL);
|
})() : NIL);
|
||||||
})();
|
})();
|
||||||
@@ -1391,13 +1419,16 @@
|
|||||||
var selectSel = domGetAttr(el, "sx-select");
|
var selectSel = domGetAttr(el, "sx-select");
|
||||||
return (isSxTruthy(selectSel) ? (function() {
|
return (isSxTruthy(selectSel) ? (function() {
|
||||||
var html = selectHtmlFromDoc(doc, selectSel);
|
var html = selectHtmlFromDoc(doc, selectSel);
|
||||||
return withTransition(useTransition, function() { return swapHtmlString(target, html, swapStyle); });
|
return withTransition(useTransition, function() { swapHtmlString(target, html, swapStyle);
|
||||||
|
return postSwap(target); });
|
||||||
})() : (function() {
|
})() : (function() {
|
||||||
var container = domCreateElement("div", NIL);
|
var container = domCreateElement("div", NIL);
|
||||||
domSetInnerHtml(container, domBodyInnerHtml(doc));
|
domSetInnerHtml(container, domBodyInnerHtml(doc));
|
||||||
processOobSwaps(container, function(t, oob, s) { return swapDomNodes(t, oob, s); });
|
processOobSwaps(container, function(t, oob, s) { swapDomNodes(t, oob, s);
|
||||||
|
return postSwap(t); });
|
||||||
hoistHeadElements(container);
|
hoistHeadElements(container);
|
||||||
return withTransition(useTransition, function() { return swapDomNodes(target, childrenToFragment(container), swapStyle); });
|
return withTransition(useTransition, function() { swapDomNodes(target, childrenToFragment(container), swapStyle);
|
||||||
|
return postSwap(target); });
|
||||||
})());
|
})());
|
||||||
})() : NIL);
|
})() : NIL);
|
||||||
})(); };
|
})(); };
|
||||||
@@ -1444,7 +1475,10 @@
|
|||||||
})(); };
|
})(); };
|
||||||
|
|
||||||
// post-swap
|
// post-swap
|
||||||
var postSwap = function(root) { return activateScripts(root); };
|
var postSwap = function(root) { activateScripts(root);
|
||||||
|
sxProcessScripts(root);
|
||||||
|
sxHydrate(root);
|
||||||
|
return processElements(root); };
|
||||||
|
|
||||||
// activate-scripts
|
// activate-scripts
|
||||||
var activateScripts = function(root) { return (isSxTruthy(root) ? (function() {
|
var activateScripts = function(root) { return (isSxTruthy(root) ? (function() {
|
||||||
@@ -1472,13 +1506,43 @@
|
|||||||
})(); };
|
})(); };
|
||||||
|
|
||||||
// hoist-head-elements
|
// hoist-head-elements
|
||||||
var hoistHeadElements = function(container) { return forEach(function(style) { return (isSxTruthy(domParent(style)) ? domRemoveChild(domParent(style), style) : NIL); }, domQueryAll(container, "style[data-sx-css]")); };
|
var hoistHeadElements = function(container) { { var _c = domQueryAll(container, "style[data-sx-css]"); for (var _i = 0; _i < _c.length; _i++) { var style = _c[_i]; if (isSxTruthy(domParent(style))) {
|
||||||
|
domRemoveChild(domParent(style), style);
|
||||||
|
}
|
||||||
|
domAppendToHead(style); } }
|
||||||
|
return forEach(function(link) { if (isSxTruthy(domParent(link))) {
|
||||||
|
domRemoveChild(domParent(link), link);
|
||||||
|
}
|
||||||
|
return domAppendToHead(link); }, domQueryAll(container, "link[rel=\"stylesheet\"]")); };
|
||||||
|
|
||||||
// process-boosted
|
// process-boosted
|
||||||
var processBoosted = function(root) { return forEach(function(container) { return boostDescendants(container); }, domQueryAll(sxOr(root, domBody()), "[sx-boost]")); };
|
var processBoosted = function(root) { return forEach(function(container) { return boostDescendants(container); }, domQueryAll(sxOr(root, domBody()), "[sx-boost]")); };
|
||||||
|
|
||||||
// boost-descendants
|
// boost-descendants
|
||||||
var boostDescendants = function(container) { return forEach(function(link) { return (isSxTruthy((isSxTruthy(!isProcessed(link, "boost")) && shouldBoostLink(link))) ? (markProcessed(link, "boost"), (isSxTruthy(!domHasAttr(link, "sx-target")) ? domSetAttr(link, "sx-target", "#main-panel") : NIL), (isSxTruthy(!domHasAttr(link, "sx-swap")) ? domSetAttr(link, "sx-swap", "innerHTML") : NIL), (isSxTruthy(!domHasAttr(link, "sx-push-url")) ? domSetAttr(link, "sx-push-url", "true") : NIL), bindBoostLink(link, domGetAttr(link, "href"))) : NIL); }, domQueryAll(container, "a[href]")); };
|
var boostDescendants = function(container) { { var _c = domQueryAll(container, "a[href]"); for (var _i = 0; _i < _c.length; _i++) { var link = _c[_i]; if (isSxTruthy((isSxTruthy(!isProcessed(link, "boost")) && shouldBoostLink(link)))) {
|
||||||
|
markProcessed(link, "boost");
|
||||||
|
if (isSxTruthy(!domHasAttr(link, "sx-target"))) {
|
||||||
|
domSetAttr(link, "sx-target", "#main-panel");
|
||||||
|
}
|
||||||
|
if (isSxTruthy(!domHasAttr(link, "sx-swap"))) {
|
||||||
|
domSetAttr(link, "sx-swap", "innerHTML");
|
||||||
|
}
|
||||||
|
if (isSxTruthy(!domHasAttr(link, "sx-push-url"))) {
|
||||||
|
domSetAttr(link, "sx-push-url", "true");
|
||||||
|
}
|
||||||
|
bindBoostLink(link, domGetAttr(link, "href"));
|
||||||
|
} } }
|
||||||
|
return forEach(function(form) { return (isSxTruthy((isSxTruthy(!isProcessed(form, "boost")) && shouldBoostForm(form))) ? (markProcessed(form, "boost"), (function() {
|
||||||
|
var method = upper(sxOr(domGetAttr(form, "method"), "GET"));
|
||||||
|
var action = sxOr(domGetAttr(form, "action"), browserLocationHref());
|
||||||
|
if (isSxTruthy(!domHasAttr(form, "sx-target"))) {
|
||||||
|
domSetAttr(form, "sx-target", "#main-panel");
|
||||||
|
}
|
||||||
|
if (isSxTruthy(!domHasAttr(form, "sx-swap"))) {
|
||||||
|
domSetAttr(form, "sx-swap", "innerHTML");
|
||||||
|
}
|
||||||
|
return bindBoostForm(form, method, action);
|
||||||
|
})()) : NIL); }, domQueryAll(container, "form")); };
|
||||||
|
|
||||||
// process-sse
|
// process-sse
|
||||||
var processSse = function(root) { return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "sse")) ? (markProcessed(el, "sse"), bindSse(el)) : NIL); }, domQueryAll(sxOr(root, domBody()), "[sx-sse]")); };
|
var processSse = function(root) { return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "sse")) ? (markProcessed(el, "sse"), bindSse(el)) : NIL); }, domQueryAll(sxOr(root, domBody()), "[sx-sse]")); };
|
||||||
@@ -1504,8 +1568,10 @@
|
|||||||
var rendered = sxRender(trimmed);
|
var rendered = sxRender(trimmed);
|
||||||
var container = domCreateElement("div", NIL);
|
var container = domCreateElement("div", NIL);
|
||||||
domAppend(container, rendered);
|
domAppend(container, rendered);
|
||||||
return withTransition(useTransition, function() { return swapDomNodes(target, childrenToFragment(container), swapStyle); });
|
return withTransition(useTransition, function() { swapDomNodes(target, childrenToFragment(container), swapStyle);
|
||||||
})() : withTransition(useTransition, function() { return swapHtmlString(target, trimmed, swapStyle); })) : NIL);
|
return postSwap(target); });
|
||||||
|
})() : withTransition(useTransition, function() { swapHtmlString(target, trimmed, swapStyle);
|
||||||
|
return postSwap(target); })) : NIL);
|
||||||
})(); };
|
})(); };
|
||||||
|
|
||||||
// bind-inline-handlers
|
// bind-inline-handlers
|
||||||
@@ -1540,10 +1606,13 @@
|
|||||||
var VERB_SELECTOR = (String("[sx-get],[sx-post],[sx-put],[sx-delete],[sx-patch]"));
|
var VERB_SELECTOR = (String("[sx-get],[sx-post],[sx-put],[sx-delete],[sx-patch]"));
|
||||||
|
|
||||||
// process-elements
|
// process-elements
|
||||||
var processElements = function(root) { return (function() {
|
var processElements = function(root) { (function() {
|
||||||
var els = domQueryAll(sxOr(root, domBody()), VERB_SELECTOR);
|
var els = domQueryAll(sxOr(root, domBody()), VERB_SELECTOR);
|
||||||
return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "verb")) ? (markProcessed(el, "verb"), processOne(el)) : NIL); }, els);
|
return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "verb")) ? (markProcessed(el, "verb"), processOne(el)) : NIL); }, els);
|
||||||
})(); };
|
})();
|
||||||
|
processBoosted(root);
|
||||||
|
processSse(root);
|
||||||
|
return bindInlineHandlers(root); };
|
||||||
|
|
||||||
// process-one
|
// process-one
|
||||||
var processOne = function(el) { return (function() {
|
var processOne = function(el) { return (function() {
|
||||||
@@ -1592,7 +1661,13 @@
|
|||||||
var _injectedStyles = {};
|
var _injectedStyles = {};
|
||||||
|
|
||||||
// load-style-dict
|
// load-style-dict
|
||||||
var loadStyleDict = function(data) { return (_styleAtoms = sxOr(get(data, "a"), {})); };
|
var loadStyleDict = function(data) { _styleAtoms = sxOr(get(data, "a"), {});
|
||||||
|
_pseudoVariants = sxOr(get(data, "v"), {});
|
||||||
|
_responsiveBreakpoints = sxOr(get(data, "b"), {});
|
||||||
|
_styleKeyframes = sxOr(get(data, "k"), {});
|
||||||
|
_childSelectorPrefixes = sxOr(get(data, "c"), []);
|
||||||
|
_arbitraryPatterns = map(function(pair) { return {["re"]: compileRegex((String("^") + String(first(pair)) + String("$"))), ["tmpl"]: nth(pair, 1)}; }, sxOr(get(data, "p"), []));
|
||||||
|
return (_styleCache = {}); };
|
||||||
|
|
||||||
// split-variant
|
// split-variant
|
||||||
var splitVariant = function(atom) { return (function() {
|
var splitVariant = function(atom) { return (function() {
|
||||||
@@ -1714,7 +1789,10 @@
|
|||||||
var allKf = [];
|
var allKf = [];
|
||||||
{ var _c = styles; for (var _i = 0; _i < _c.length; _i++) { var sv = _c[_i]; if (isSxTruthy(styleValueDeclarations(sv))) {
|
{ var _c = styles; for (var _i = 0; _i < _c.length; _i++) { var sv = _c[_i]; if (isSxTruthy(styleValueDeclarations(sv))) {
|
||||||
allDecls.push(styleValueDeclarations(sv));
|
allDecls.push(styleValueDeclarations(sv));
|
||||||
} } }
|
}
|
||||||
|
allMedia = concat(allMedia, styleValueMediaRules(sv));
|
||||||
|
allPseudo = concat(allPseudo, styleValuePseudoRules(sv));
|
||||||
|
allKf = concat(allKf, styleValueKeyframes_(sv)); } }
|
||||||
return (function() {
|
return (function() {
|
||||||
var hashInput = join(";", allDecls);
|
var hashInput = join(";", allDecls);
|
||||||
{ var _c = allMedia; for (var _i = 0; _i < _c.length; _i++) { var mr = _c[_i]; hashInput = (String(hashInput) + String("@") + String(first(mr)) + String("{") + String(nth(mr, 1)) + String("}")); } }
|
{ var _c = allMedia; for (var _i = 0; _i < _c.length; _i++) { var mr = _c[_i]; hashInput = (String(hashInput) + String("@") + String(first(mr)) + String("{") + String(nth(mr, 1)) + String("}")); } }
|
||||||
@@ -1796,7 +1874,8 @@
|
|||||||
var comp = envGet(env, fullName);
|
var comp = envGet(env, fullName);
|
||||||
return (isSxTruthy(!isComponent(comp)) ? error((String("Unknown component: ") + String(fullName))) : (function() {
|
return (isSxTruthy(!isComponent(comp)) ? error((String("Unknown component: ") + String(fullName))) : (function() {
|
||||||
var callExpr = [makeSymbol(fullName)];
|
var callExpr = [makeSymbol(fullName)];
|
||||||
{ var _c = keys(kwargs); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; callExpr.push(makeKeyword(toKebab(k))); } }
|
{ var _c = keys(kwargs); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; callExpr.push(makeKeyword(toKebab(k)));
|
||||||
|
callExpr.push(dictGet(kwargs, k)); } }
|
||||||
return renderToDom(callExpr, env, NIL);
|
return renderToDom(callExpr, env, NIL);
|
||||||
})());
|
})());
|
||||||
})();
|
})();
|
||||||
@@ -1861,6 +1940,9 @@
|
|||||||
|
|
||||||
var _hasDom = typeof document !== "undefined";
|
var _hasDom = typeof document !== "undefined";
|
||||||
|
|
||||||
|
// Register DOM adapter as the render dispatch target for the evaluator.
|
||||||
|
_renderExprFn = function(expr, env) { return renderToDom(expr, env, null); };
|
||||||
|
|
||||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||||
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
|
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
|
||||||
|
|
||||||
@@ -2142,7 +2224,7 @@
|
|||||||
if (config.body && config.method !== "GET") opts.body = config.body;
|
if (config.body && config.method !== "GET") opts.body = config.body;
|
||||||
if (config["cross-origin"]) opts.credentials = "include";
|
if (config["cross-origin"]) opts.credentials = "include";
|
||||||
|
|
||||||
var p = config.preloaded
|
var p = (config.preloaded && config.preloaded !== NIL)
|
||||||
? Promise.resolve({
|
? Promise.resolve({
|
||||||
ok: true, status: 200,
|
ok: true, status: 200,
|
||||||
headers: new Headers({ "Content-Type": config.preloaded["content-type"] || "" }),
|
headers: new Headers({ "Content-Type": config.preloaded["content-type"] || "" }),
|
||||||
@@ -2538,23 +2620,25 @@
|
|||||||
// --- SX API references ---
|
// --- SX API references ---
|
||||||
|
|
||||||
function sxRender(source) {
|
function sxRender(source) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (SxObj && SxObj.render) return SxObj.render(source);
|
if (SxObj && SxObj.render) return SxObj.render(source);
|
||||||
throw new Error("No SX renderer available");
|
throw new Error("No SX renderer available");
|
||||||
}
|
}
|
||||||
|
|
||||||
function sxProcessScripts(root) {
|
function sxProcessScripts(root) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (SxObj && SxObj.processScripts) SxObj.processScripts(root || undefined);
|
var r = (root && root !== NIL) ? root : undefined;
|
||||||
|
if (SxObj && SxObj.processScripts) SxObj.processScripts(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sxHydrate(root) {
|
function sxHydrate(root) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (SxObj && SxObj.hydrate) SxObj.hydrate(root || undefined);
|
var r = (root && root !== NIL) ? root : undefined;
|
||||||
|
if (SxObj && SxObj.hydrate) SxObj.hydrate(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadedComponentNames() {
|
function loadedComponentNames() {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (!SxObj) return [];
|
if (!SxObj) return [];
|
||||||
var env = SxObj.componentEnv || (SxObj.getEnv ? SxObj.getEnv() : {});
|
var env = SxObj.componentEnv || (SxObj.getEnv ? SxObj.getEnv() : {});
|
||||||
return Object.keys(env).filter(function(k) { return k.charAt(0) === "~"; });
|
return Object.keys(env).filter(function(k) { return k.charAt(0) === "~"; });
|
||||||
@@ -2563,7 +2647,7 @@
|
|||||||
// --- Response processing ---
|
// --- Response processing ---
|
||||||
|
|
||||||
function stripComponentScripts(text) {
|
function stripComponentScripts(text) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
return text.replace(/<script[^>]*type="text\/sx"[^>]*data-components[^>]*>([\s\S]*?)<\/script>/gi,
|
return text.replace(/<script[^>]*type="text\/sx"[^>]*data-components[^>]*>([\s\S]*?)<\/script>/gi,
|
||||||
function(_, defs) { if (SxObj && SxObj.loadComponents) SxObj.loadComponents(defs); return ""; });
|
function(_, defs) { if (SxObj && SxObj.loadComponents) SxObj.loadComponents(defs); return ""; });
|
||||||
}
|
}
|
||||||
@@ -2760,8 +2844,9 @@
|
|||||||
|
|
||||||
function querySxScripts(root) {
|
function querySxScripts(root) {
|
||||||
if (!_hasDom) return [];
|
if (!_hasDom) return [];
|
||||||
|
var r = (root && root !== NIL) ? root : document;
|
||||||
return Array.prototype.slice.call(
|
return Array.prototype.slice.call(
|
||||||
(root || document).querySelectorAll('script[type="text/sx"]'));
|
r.querySelectorAll('script[type="text/sx"]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryStyleScripts() {
|
function queryStyleScripts() {
|
||||||
@@ -2989,8 +3074,10 @@
|
|||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
var SxRef = {
|
var Sx = {
|
||||||
|
VERSION: "ref-2.0",
|
||||||
parse: parse,
|
parse: parse,
|
||||||
|
parseAll: parse,
|
||||||
eval: function(expr, env) { return trampoline(evalExpr(expr, env || merge(componentEnv))); },
|
eval: function(expr, env) { return trampoline(evalExpr(expr, env || merge(componentEnv))); },
|
||||||
loadComponents: loadComponents,
|
loadComponents: loadComponents,
|
||||||
render: render,
|
render: render,
|
||||||
@@ -2999,6 +3086,8 @@
|
|||||||
NIL: NIL,
|
NIL: NIL,
|
||||||
Symbol: Symbol,
|
Symbol: Symbol,
|
||||||
Keyword: Keyword,
|
Keyword: Keyword,
|
||||||
|
isTruthy: isSxTruthy,
|
||||||
|
isNil: isNil,
|
||||||
componentEnv: componentEnv,
|
componentEnv: componentEnv,
|
||||||
renderToDom: _hasDom ? function(expr, env, ns) { return renderToDom(expr, env || merge(componentEnv), ns || null); } : null,
|
renderToDom: _hasDom ? function(expr, env, ns) { return renderToDom(expr, env || merge(componentEnv), ns || null); } : null,
|
||||||
parseTriggerSpec: typeof parseTriggerSpec === "function" ? parseTriggerSpec : null,
|
parseTriggerSpec: typeof parseTriggerSpec === "function" ? parseTriggerSpec : null,
|
||||||
@@ -3028,14 +3117,14 @@
|
|||||||
|
|
||||||
// --- Auto-init ---
|
// --- Auto-init ---
|
||||||
if (typeof document !== "undefined") {
|
if (typeof document !== "undefined") {
|
||||||
var _sxRefInit = function() { bootInit(); };
|
var _sxInit = function() { bootInit(); };
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
document.addEventListener("DOMContentLoaded", _sxRefInit);
|
document.addEventListener("DOMContentLoaded", _sxInit);
|
||||||
} else {
|
} else {
|
||||||
_sxRefInit();
|
_sxInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof module !== "undefined" && module.exports) module.exports = SxRef;
|
if (typeof module !== "undefined" && module.exports) module.exports = Sx;
|
||||||
else global.SxRef = SxRef;
|
else global.Sx = Sx;
|
||||||
|
|
||||||
})(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : this);
|
})(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : this);
|
||||||
@@ -606,7 +606,7 @@ details.group{{overflow:hidden}}details.group>summary{{list-style:none}}details.
|
|||||||
<script type="text/sx-styles" data-hash="{styles_hash}">{styles_json}</script>
|
<script type="text/sx-styles" data-hash="{styles_hash}">{styles_json}</script>
|
||||||
<script type="text/sx" data-components data-hash="{component_hash}">{component_defs}</script>
|
<script type="text/sx" data-components data-hash="{component_hash}">{component_defs}</script>
|
||||||
<script type="text/sx" data-mount="body">{page_sx}</script>
|
<script type="text/sx" data-mount="body">{page_sx}</script>
|
||||||
<script src="{asset_url}/scripts/sx.js?v={sx_js_hash}"></script>
|
<script src="{asset_url}/scripts/sx-browser.js?v={sx_js_hash}"></script>
|
||||||
<script src="{asset_url}/scripts/body.js?v={body_js_hash}"></script>
|
<script src="{asset_url}/scripts/body.js?v={body_js_hash}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>"""
|
</html>"""
|
||||||
@@ -693,7 +693,7 @@ def sx_page(ctx: dict, page_sx: str, *,
|
|||||||
page_sx=page_sx,
|
page_sx=page_sx,
|
||||||
sx_css=sx_css,
|
sx_css=sx_css,
|
||||||
sx_css_classes=sx_css_classes,
|
sx_css_classes=sx_css_classes,
|
||||||
sx_js_hash=_script_hash("sx.js"),
|
sx_js_hash=_script_hash("sx-browser.js"),
|
||||||
body_js_hash=_script_hash("body.js"),
|
body_js_hash=_script_hash("body.js"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ class JSEmitter:
|
|||||||
"eval-expr": "evalExpr",
|
"eval-expr": "evalExpr",
|
||||||
"eval-list": "evalList",
|
"eval-list": "evalList",
|
||||||
"eval-call": "evalCall",
|
"eval-call": "evalCall",
|
||||||
|
"is-render-expr?": "isRenderExpr",
|
||||||
|
"render-expr": "renderExpr",
|
||||||
"call-lambda": "callLambda",
|
"call-lambda": "callLambda",
|
||||||
"call-component": "callComponent",
|
"call-component": "callComponent",
|
||||||
"parse-keyword-args": "parseKeywordArgs",
|
"parse-keyword-args": "parseKeywordArgs",
|
||||||
@@ -559,7 +561,7 @@ class JSEmitter:
|
|||||||
|
|
||||||
def _emit_fn(self, expr) -> str:
|
def _emit_fn(self, expr) -> str:
|
||||||
params = expr[1]
|
params = expr[1]
|
||||||
body = expr[2]
|
body = expr[2:]
|
||||||
param_names = []
|
param_names = []
|
||||||
for p in params:
|
for p in params:
|
||||||
if isinstance(p, Symbol):
|
if isinstance(p, Symbol):
|
||||||
@@ -567,8 +569,16 @@ class JSEmitter:
|
|||||||
else:
|
else:
|
||||||
param_names.append(str(p))
|
param_names.append(str(p))
|
||||||
params_str = ", ".join(param_names)
|
params_str = ", ".join(param_names)
|
||||||
body_js = self.emit(body)
|
if len(body) == 1:
|
||||||
return f"function({params_str}) {{ return {body_js}; }}"
|
body_js = self.emit(body[0])
|
||||||
|
return f"function({params_str}) {{ return {body_js}; }}"
|
||||||
|
# Multi-expression body: statements then return last
|
||||||
|
parts = []
|
||||||
|
for b in body[:-1]:
|
||||||
|
parts.append(self.emit_statement(b))
|
||||||
|
parts.append(f"return {self.emit(body[-1])};")
|
||||||
|
inner = "\n".join(parts)
|
||||||
|
return f"function({params_str}) {{ {inner} }}"
|
||||||
|
|
||||||
def _emit_let(self, expr) -> str:
|
def _emit_let(self, expr) -> str:
|
||||||
bindings = expr[1]
|
bindings = expr[1]
|
||||||
@@ -717,10 +727,10 @@ class JSEmitter:
|
|||||||
# If fn is an inline lambda, emit a for loop
|
# If fn is an inline lambda, emit a for loop
|
||||||
if isinstance(fn_expr, list) and fn_expr[0] == Symbol("fn"):
|
if isinstance(fn_expr, list) and fn_expr[0] == Symbol("fn"):
|
||||||
params = fn_expr[1]
|
params = fn_expr[1]
|
||||||
body = fn_expr[2]
|
body = fn_expr[2:]
|
||||||
p = params[0].name if isinstance(params[0], Symbol) else str(params[0])
|
p = params[0].name if isinstance(params[0], Symbol) else str(params[0])
|
||||||
p_js = self._mangle(p)
|
p_js = self._mangle(p)
|
||||||
body_js = self.emit_statement(body)
|
body_js = "\n".join(self.emit_statement(b) for b in body)
|
||||||
return f"{{ var _c = {coll}; for (var _i = 0; _i < _c.length; _i++) {{ var {p_js} = _c[_i]; {body_js} }} }}"
|
return f"{{ var _c = {coll}; for (var _i = 0; _i < _c.length; _i++) {{ var {p_js} = _c[_i]; {body_js} }} }}"
|
||||||
fn = self.emit(fn_expr)
|
fn = self.emit(fn_expr)
|
||||||
return f"{{ var _c = {coll}; for (var _i = 0; _i < _c.length; _i++) {{ {fn}(_c[_i]); }} }}"
|
return f"{{ var _c = {coll}; for (var _i = 0; _i < _c.length; _i++) {{ {fn}(_c[_i]); }} }}"
|
||||||
@@ -978,6 +988,7 @@ PLATFORM_JS = '''
|
|||||||
if (x._macro) return "macro";
|
if (x._macro) return "macro";
|
||||||
if (x._raw) return "raw-html";
|
if (x._raw) return "raw-html";
|
||||||
if (x._styleValue) return "style-value";
|
if (x._styleValue) return "style-value";
|
||||||
|
if (typeof Node !== "undefined" && x instanceof Node) return "dom-node";
|
||||||
if (Array.isArray(x)) return "list";
|
if (Array.isArray(x)) return "list";
|
||||||
if (typeof x === "object") return "dict";
|
if (typeof x === "object") return "dict";
|
||||||
return "unknown";
|
return "unknown";
|
||||||
@@ -1053,6 +1064,29 @@ PLATFORM_JS = '''
|
|||||||
function dictSet(d, k, v) { d[k] = v; }
|
function dictSet(d, k, v) { d[k] = v; }
|
||||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||||
|
|
||||||
|
// Render-expression detection — lets the evaluator delegate to the active adapter.
|
||||||
|
// Matches HTML tags, SVG tags, <>, raw!, ~components, html: prefix, custom elements.
|
||||||
|
function isRenderExpr(expr) {
|
||||||
|
if (!Array.isArray(expr) || !expr.length) return false;
|
||||||
|
var h = expr[0];
|
||||||
|
if (!h || !h._sym) return false;
|
||||||
|
var n = h.name;
|
||||||
|
return !!(n === "<>" || n === "raw!" ||
|
||||||
|
n.charAt(0) === "~" || n.indexOf("html:") === 0 ||
|
||||||
|
(typeof HTML_TAGS !== "undefined" && HTML_TAGS.indexOf(n) >= 0) ||
|
||||||
|
(typeof SVG_TAGS !== "undefined" && SVG_TAGS.indexOf(n) >= 0) ||
|
||||||
|
(n.indexOf("-") > 0 && expr.length > 1 && expr[1] && expr[1]._kw));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render dispatch — call the active adapter's render function.
|
||||||
|
// Set by each adapter when loaded; defaults to identity (no rendering).
|
||||||
|
var _renderExprFn = null;
|
||||||
|
function renderExpr(expr, env) {
|
||||||
|
if (_renderExprFn) return _renderExprFn(expr, env);
|
||||||
|
// No adapter loaded — just return the expression as-is
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
function stripPrefix(s, prefix) {
|
function stripPrefix(s, prefix) {
|
||||||
return s.indexOf(prefix) === 0 ? s.slice(prefix.length) : s;
|
return s.indexOf(prefix) === 0 ? s.slice(prefix.length) : s;
|
||||||
}
|
}
|
||||||
@@ -1366,6 +1400,9 @@ PLATFORM_DOM_JS = """
|
|||||||
|
|
||||||
var _hasDom = typeof document !== "undefined";
|
var _hasDom = typeof document !== "undefined";
|
||||||
|
|
||||||
|
// Register DOM adapter as the render dispatch target for the evaluator.
|
||||||
|
_renderExprFn = function(expr, env) { return renderToDom(expr, env, null); };
|
||||||
|
|
||||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||||
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
|
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
|
||||||
|
|
||||||
@@ -1649,7 +1686,7 @@ PLATFORM_ORCHESTRATION_JS = """
|
|||||||
if (config.body && config.method !== "GET") opts.body = config.body;
|
if (config.body && config.method !== "GET") opts.body = config.body;
|
||||||
if (config["cross-origin"]) opts.credentials = "include";
|
if (config["cross-origin"]) opts.credentials = "include";
|
||||||
|
|
||||||
var p = config.preloaded
|
var p = (config.preloaded && config.preloaded !== NIL)
|
||||||
? Promise.resolve({
|
? Promise.resolve({
|
||||||
ok: true, status: 200,
|
ok: true, status: 200,
|
||||||
headers: new Headers({ "Content-Type": config.preloaded["content-type"] || "" }),
|
headers: new Headers({ "Content-Type": config.preloaded["content-type"] || "" }),
|
||||||
@@ -2045,23 +2082,25 @@ PLATFORM_ORCHESTRATION_JS = """
|
|||||||
// --- SX API references ---
|
// --- SX API references ---
|
||||||
|
|
||||||
function sxRender(source) {
|
function sxRender(source) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (SxObj && SxObj.render) return SxObj.render(source);
|
if (SxObj && SxObj.render) return SxObj.render(source);
|
||||||
throw new Error("No SX renderer available");
|
throw new Error("No SX renderer available");
|
||||||
}
|
}
|
||||||
|
|
||||||
function sxProcessScripts(root) {
|
function sxProcessScripts(root) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (SxObj && SxObj.processScripts) SxObj.processScripts(root || undefined);
|
var r = (root && root !== NIL) ? root : undefined;
|
||||||
|
if (SxObj && SxObj.processScripts) SxObj.processScripts(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sxHydrate(root) {
|
function sxHydrate(root) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (SxObj && SxObj.hydrate) SxObj.hydrate(root || undefined);
|
var r = (root && root !== NIL) ? root : undefined;
|
||||||
|
if (SxObj && SxObj.hydrate) SxObj.hydrate(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadedComponentNames() {
|
function loadedComponentNames() {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
if (!SxObj) return [];
|
if (!SxObj) return [];
|
||||||
var env = SxObj.componentEnv || (SxObj.getEnv ? SxObj.getEnv() : {});
|
var env = SxObj.componentEnv || (SxObj.getEnv ? SxObj.getEnv() : {});
|
||||||
return Object.keys(env).filter(function(k) { return k.charAt(0) === "~"; });
|
return Object.keys(env).filter(function(k) { return k.charAt(0) === "~"; });
|
||||||
@@ -2070,7 +2109,7 @@ PLATFORM_ORCHESTRATION_JS = """
|
|||||||
// --- Response processing ---
|
// --- Response processing ---
|
||||||
|
|
||||||
function stripComponentScripts(text) {
|
function stripComponentScripts(text) {
|
||||||
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||||||
return text.replace(/<script[^>]*type="text\\/sx"[^>]*data-components[^>]*>([\\s\\S]*?)<\\/script>/gi,
|
return text.replace(/<script[^>]*type="text\\/sx"[^>]*data-components[^>]*>([\\s\\S]*?)<\\/script>/gi,
|
||||||
function(_, defs) { if (SxObj && SxObj.loadComponents) SxObj.loadComponents(defs); return ""; });
|
function(_, defs) { if (SxObj && SxObj.loadComponents) SxObj.loadComponents(defs); return ""; });
|
||||||
}
|
}
|
||||||
@@ -2269,8 +2308,9 @@ PLATFORM_BOOT_JS = """
|
|||||||
|
|
||||||
function querySxScripts(root) {
|
function querySxScripts(root) {
|
||||||
if (!_hasDom) return [];
|
if (!_hasDom) return [];
|
||||||
|
var r = (root && root !== NIL) ? root : document;
|
||||||
return Array.prototype.slice.call(
|
return Array.prototype.slice.call(
|
||||||
(root || document).querySelectorAll('script[type="text/sx"]'));
|
r.querySelectorAll('script[type="text/sx"]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryStyleScripts() {
|
function queryStyleScripts() {
|
||||||
@@ -2556,11 +2596,13 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has
|
|||||||
return parts.join("");
|
return parts.join("");
|
||||||
}''')
|
}''')
|
||||||
|
|
||||||
# Build SxRef object
|
# Build Sx object
|
||||||
version = f"ref-2.0 ({adapter_label}, bootstrap-compiled)"
|
version = f"ref-2.0 ({adapter_label}, bootstrap-compiled)"
|
||||||
api_lines.append(f'''
|
api_lines.append(f'''
|
||||||
var SxRef = {{
|
var Sx = {{
|
||||||
|
VERSION: "ref-2.0",
|
||||||
parse: parse,
|
parse: parse,
|
||||||
|
parseAll: parse,
|
||||||
eval: function(expr, env) {{ return trampoline(evalExpr(expr, env || merge(componentEnv))); }},
|
eval: function(expr, env) {{ return trampoline(evalExpr(expr, env || merge(componentEnv))); }},
|
||||||
loadComponents: loadComponents,
|
loadComponents: loadComponents,
|
||||||
render: render,{"" if has_html else ""}
|
render: render,{"" if has_html else ""}
|
||||||
@@ -2569,6 +2611,8 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has
|
|||||||
NIL: NIL,
|
NIL: NIL,
|
||||||
Symbol: Symbol,
|
Symbol: Symbol,
|
||||||
Keyword: Keyword,
|
Keyword: Keyword,
|
||||||
|
isTruthy: isSxTruthy,
|
||||||
|
isNil: isNil,
|
||||||
componentEnv: componentEnv,''')
|
componentEnv: componentEnv,''')
|
||||||
|
|
||||||
if has_html:
|
if has_html:
|
||||||
@@ -2612,27 +2656,27 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has
|
|||||||
api_lines.append('''
|
api_lines.append('''
|
||||||
// --- Auto-init ---
|
// --- Auto-init ---
|
||||||
if (typeof document !== "undefined") {
|
if (typeof document !== "undefined") {
|
||||||
var _sxRefInit = function() { bootInit(); };
|
var _sxInit = function() { bootInit(); };
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
document.addEventListener("DOMContentLoaded", _sxRefInit);
|
document.addEventListener("DOMContentLoaded", _sxInit);
|
||||||
} else {
|
} else {
|
||||||
_sxRefInit();
|
_sxInit();
|
||||||
}
|
}
|
||||||
}''')
|
}''')
|
||||||
elif has_orch:
|
elif has_orch:
|
||||||
api_lines.append('''
|
api_lines.append('''
|
||||||
// --- Auto-init ---
|
// --- Auto-init ---
|
||||||
if (typeof document !== "undefined") {
|
if (typeof document !== "undefined") {
|
||||||
var _sxRefInit = function() { engineInit(); };
|
var _sxInit = function() { engineInit(); };
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
document.addEventListener("DOMContentLoaded", _sxRefInit);
|
document.addEventListener("DOMContentLoaded", _sxInit);
|
||||||
} else {
|
} else {
|
||||||
_sxRefInit();
|
_sxInit();
|
||||||
}
|
}
|
||||||
}''')
|
}''')
|
||||||
|
|
||||||
api_lines.append(' if (typeof module !== "undefined" && module.exports) module.exports = SxRef;')
|
api_lines.append(' if (typeof module !== "undefined" && module.exports) module.exports = Sx;')
|
||||||
api_lines.append(' else global.SxRef = SxRef;')
|
api_lines.append(' else global.Sx = Sx;')
|
||||||
|
|
||||||
return "\n".join(api_lines)
|
return "\n".join(api_lines)
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,10 @@
|
|||||||
(let ((mac (env-get env name)))
|
(let ((mac (env-get env name)))
|
||||||
(make-thunk (expand-macro mac args env) env))
|
(make-thunk (expand-macro mac args env) env))
|
||||||
|
|
||||||
|
;; Render expression — delegate to active adapter
|
||||||
|
(is-render-expr? expr)
|
||||||
|
(render-expr expr env)
|
||||||
|
|
||||||
;; Fall through to function call
|
;; Fall through to function call
|
||||||
:else (eval-call head args env)))
|
:else (eval-call head args env)))
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
(define init-css-tracking
|
(define init-css-tracking
|
||||||
(fn ()
|
(fn ()
|
||||||
;; Read initial CSS hash from meta tag
|
;; Read initial CSS hash from meta tag
|
||||||
(let ((meta (dom-query "meta[name=\"sx-css-hash\"]")))
|
(let ((meta (dom-query "meta[name=\"sx-css-classes\"]")))
|
||||||
(when meta
|
(when meta
|
||||||
(let ((content (dom-get-attr meta "content")))
|
(let ((content (dom-get-attr meta "content")))
|
||||||
(when content
|
(when content
|
||||||
@@ -76,8 +76,9 @@
|
|||||||
(fn (el verbInfo extraParams)
|
(fn (el verbInfo extraParams)
|
||||||
;; Gate checks then delegate to do-fetch.
|
;; Gate checks then delegate to do-fetch.
|
||||||
;; verbInfo: dict with "method" and "url" (or nil to read from element).
|
;; verbInfo: dict with "method" and "url" (or nil to read from element).
|
||||||
|
;; Re-read from element in case attributes were morphed since binding.
|
||||||
;; Returns a promise.
|
;; Returns a promise.
|
||||||
(let ((info (or verbInfo (get-verb-info el))))
|
(let ((info (or (get-verb-info el) verbInfo)))
|
||||||
(if (nil? info)
|
(if (nil? info)
|
||||||
(promise-resolve nil)
|
(promise-resolve nil)
|
||||||
(let ((verb (get info "method"))
|
(let ((verb (get info "method"))
|
||||||
|
|||||||
Reference in New Issue
Block a user