diff --git a/shared/static/wasm/sx-platform-2.js b/shared/static/wasm/sx-platform-2.js index 4a48d667..9cf89bdb 100644 --- a/shared/static/wasm/sx-platform-2.js +++ b/shared/static/wasm/sx-platform-2.js @@ -399,6 +399,52 @@ } console.log("[sx] boot done"); + // sx-on: inline event handlers — bind from JS because the WASM + // CSS selector [sx-on\:] doesn't match. Uses MutationObserver to + // also catch elements added after boot (e.g. from swaps). + function _bindSxOn(root) { + var all = (root || document).querySelectorAll('*'); + for (var k = 0; k < all.length; k++) { + var el = all[k]; + if (el._sxOnBound) continue; + var attrs = el.attributes; + var hasSxOn = false; + for (var a = 0; a < attrs.length; a++) { + var aname = attrs[a].name; + if (aname.indexOf('sx-on:') === 0) { + hasSxOn = true; + var evtName = aname.slice(6); + // HTML lowercases attrs: afterSwap → afterswap. + // Engine dispatches camelCase: sx:afterSwap. + // Listen for both forms. + var evtName2 = null; + if (evtName.indexOf('after') === 0 || evtName.indexOf('before') === 0) { + evtName2 = 'sx:' + evtName; // lowercase form + // Also try camelCase form + var camel = evtName.replace(/swap|request|settle/gi, function(m) { + return m.charAt(0).toUpperCase() + m.slice(1); + }); + evtName = 'sx:' + camel; + } + (function(el2, evt, evt2, code) { + var handler = function(e) { + try { new Function('event', code).call(el2, e); } + catch(err) { console.warn('[sx] sx-on:' + evt + ' error:', err); } + }; + el2.addEventListener(evt, handler); + if (evt2) el2.addEventListener(evt2, handler); + })(el, evtName, evtName2, attrs[a].value); + } + } + if (hasSxOn) el._sxOnBound = true; + } + } + _bindSxOn(document); + // Re-bind after swaps + document.addEventListener('sx:afterSwap', function(e) { + if (e.target) _bindSxOn(e.target); + }); + // Global keyboard shortcut dispatch — WASM host-callbacks on // document/body don't fire, so handle from:body keyboard // triggers in JS and call execute-request via the SX engine.