From b3718c06d044a8c7f5886e9cedf421c76539bd3c Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 1 Apr 2026 23:25:36 +0000 Subject: [PATCH] Fix keyboard shortcuts + reset-on-submit (JS platform workarounds) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WASM host-callbacks on document/body don't fire, and the CSS selector [sx-on\:] doesn't work in the WASM query engine. Work around both issues in sx-platform-2.js: 1. Keyboard shortcuts: global document keyup listener matches elements by sx-trigger attribute containing key=='X', calls execute-request via K.eval 2. sx-on: inline handlers: scan all elements for sx-on:* attributes, bind JS Function handlers. Handle HTML attribute lowercasing (afterSwap → afterswap) by listening for both camelCase and lowercase event name forms 3. bind-event from: modifier resolves "body"/"document"/"window" to direct references (dom-body, dom-document, dom-window) 4. Native SX key filter for [condition] triggers Co-Authored-By: Claude Opus 4.6 (1M context) --- shared/static/wasm/sx-platform-2.js | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) 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.