Remove all inline JS from admin templates

script-src 'self' blocks inline onclick handlers and <script> blocks.
Migrate all interactive behavior to data-* attributes wired by mcias.js:

- data-toggle-form: accounts, policies, pgcreds create-form buttons
- data-href: audit clickable table rows
- data-tab: policy form tab switching (moved showTab from inline script)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 08:26:29 -07:00
parent e082671f53
commit 15e7eb5bd1
6 changed files with 68 additions and 39 deletions

View File

@@ -1,4 +1,8 @@
// mcias.js — HTMX event wiring for the MCIAS web UI.
// mcias.js — HTMX event wiring and CSP-safe UI helpers for the MCIAS web UI.
//
// All interactive behavior that would otherwise require inline onclick/onchange
// handlers is wired here via data-* attributes so that script-src 'self'
// (without 'unsafe-inline') is sufficient.
// Show server error responses in the global #htmx-error-banner.
//
@@ -15,9 +19,17 @@ document.body.addEventListener('htmx:responseError', function (evt) {
banner.scrollIntoView({ behavior: 'instant', block: 'nearest' });
});
// Toggle visibility of a create-form panel. The button text alternates
// between the given labels. Used by admin pages (accounts, policies,
// pgcreds, SSO clients) to show/hide the inline create form.
// Clear the error banner whenever a successful HTMX swap completes so
// stale errors do not persist after the user corrects their input.
document.body.addEventListener('htmx:afterSwap', function () {
var banner = document.getElementById('htmx-error-banner');
if (banner) {
banner.style.display = 'none';
banner.innerHTML = '';
}
});
// --- Toggle-form buttons ---
//
// Usage: <button data-toggle-form="create-form"
// data-label-show="Add Item" data-label-hide="Cancel">
@@ -33,19 +45,43 @@ function toggleForm(btn) {
btn.textContent = show ? labelHide : labelShow;
}
// Auto-wire all toggle-form buttons on page load.
// --- Clickable rows ---
//
// Usage: <tr class="clickable-row" data-href="/audit/123">
function handleClickableRow(row) {
var href = row.getAttribute('data-href');
if (href) { window.location = href; }
}
// --- Policy form tab switching ---
//
// Usage: <button data-tab="form"> / <button data-tab="json">
function showTab(tab) {
var formMode = document.getElementById('pf-form-mode');
var jsonMode = document.getElementById('pf-json-mode');
var formBtn = document.getElementById('tab-form');
var jsonBtn = document.getElementById('tab-json');
if (!formMode || !jsonMode) { return; }
formMode.style.display = tab === 'form' ? '' : 'none';
jsonMode.style.display = tab === 'json' ? '' : 'none';
if (formBtn) { formBtn.className = tab === 'form' ? 'btn btn-sm btn-secondary' : 'btn btn-sm'; }
if (jsonBtn) { jsonBtn.className = tab === 'json' ? 'btn btn-sm btn-secondary' : 'btn btn-sm'; }
}
// --- Auto-wire on DOMContentLoaded ---
document.addEventListener('DOMContentLoaded', function () {
// Toggle-form buttons.
document.querySelectorAll('[data-toggle-form]').forEach(function (btn) {
btn.addEventListener('click', function () { toggleForm(btn); });
});
});
// Clear the error banner whenever a successful HTMX swap completes so
// stale errors do not persist after the user corrects their input.
document.body.addEventListener('htmx:afterSwap', function () {
var banner = document.getElementById('htmx-error-banner');
if (banner) {
banner.style.display = 'none';
banner.innerHTML = '';
}
// Clickable table rows.
document.querySelectorAll('[data-href]').forEach(function (row) {
row.addEventListener('click', function () { handleClickableRow(row); });
});
// Tab buttons.
document.querySelectorAll('[data-tab]').forEach(function (btn) {
btn.addEventListener('click', function () { showTab(btn.getAttribute('data-tab')); });
});
});