Files
llmgw/internal/web/static/pages.js
T
Ilker ManapandClaude Opus 5.5 e78075876b A form being filled in is not refreshed away
The cluster and node pages swap their live part every few seconds, and the
forms inside it went with it: what was typed, an open choice, the focus.
Filling one in raced the clock. The swap now waits while a field in the
live part has the focus or a form in it has been typed into and not sent;
sending it, or leaving the page, ends that. The mirror page's reload
during a download goes through the same check instead of http-equiv.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 08:13:08 +02:00

68 lines
2.8 KiB
JavaScript

// What the pages did in inline handlers, which the Content-Security-Policy
// does not run: a form sent when a choice changes, a confirmation before a
// removal, a field filled from the option chosen, and the live parts of the
// cluster and node pages refreshed only while the tab is in view.
(function () {
document.addEventListener('change', function (e) {
var t = e.target;
if (t.matches && t.matches('[data-autosubmit]') && t.form) {
t.form.submit();
}
if (t.matches && t.matches('[data-suggest-into]') && t.form) {
var f = t.form.elements[t.getAttribute('data-suggest-into')];
var o = t.selectedOptions[0];
if (f && o) { f.value = o.dataset.suggest || ''; }
}
});
document.addEventListener('submit', function (e) {
var msg = e.target.getAttribute && e.target.getAttribute('data-confirm');
if (msg && !window.confirm(msg)) { e.preventDefault(); }
});
// A form being filled in is not refreshed away. The live parts of the
// cluster and node pages are swapped whole every few seconds, and a form
// inside one lost what was typed into it, its open choice, its focus:
// filling one in raced the clock. While a field in the refreshing part
// has the focus, or a form in it has been typed into and not sent, it
// waits; sending the form, or leaving the page, ends that.
var edited = [];
document.addEventListener('input', function (e) {
var f = e.target.form || (e.target.closest && e.target.closest('form'));
if (f && edited.indexOf(f) < 0) { edited.push(f); }
});
document.addEventListener('submit', function (e) {
if (!e.defaultPrevented) { edited = []; }
});
function busy(root) {
var a = document.activeElement;
if (a && a !== document.body && root.contains(a) &&
a.matches('input, select, textarea, [contenteditable]')) {
return true;
}
for (var i = 0; i < edited.length; i++) {
if (root.contains(edited[i]) && document.contains(edited[i])) { return true; }
}
return false;
}
// htmx's trigger filters are evaluated JavaScript; this is the same
// "only while visible" without them, and "not while being filled in".
document.addEventListener('htmx:beforeRequest', function (e) {
var elt = e.detail.elt;
if (elt.hasAttribute('data-visible-only') &&
(document.visibilityState !== 'visible' || busy(elt))) {
e.preventDefault();
}
});
// A page that reloads itself (<meta name="llmgw-refresh" content="N">)
// does it on the same terms, rather than by http-equiv, which nothing
// can hold off.
var r = document.querySelector('meta[name="llmgw-refresh"]');
var every = r ? parseInt(r.getAttribute('content'), 10) : 0;
if (every > 0) {
setInterval(function () {
if (document.visibilityState === 'visible' && !busy(document.body)) {
window.location.reload();
}
}, every * 1000);
}
})();