From 28bf07a443169ddaec21c86d96361f72abde59dd Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sat, 4 Apr 2026 11:21:22 -0500 Subject: [PATCH] Add accessibility toolbar with 6 toggleable options Adds a floating accessibility toolbar to the template with individually enable/disable options: text resize, color inversion, high contrast, highlight links, readable font, and pause animations. Each option has an admin toggle in the Theme tab and persists visitor preferences in localStorage. Also fixes count() on null in mod_login override. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/html/mod_login/default.php | 2 +- src/index.php | 20 +- src/language/en-GB/tpl_mokocassiopeia.ini | 23 +++ src/language/en-US/tpl_mokocassiopeia.ini | 23 +++ src/media/css/template.css | 184 +++++++++++++++++ src/media/js/template.js | 234 ++++++++++++++++++++++ src/templateDetails.xml | 59 ++++++ 7 files changed, 543 insertions(+), 2 deletions(-) diff --git a/src/html/mod_login/default.php b/src/html/mod_login/default.php index 09883e8..7071b4f 100644 --- a/src/html/mod_login/default.php +++ b/src/html/mod_login/default.php @@ -71,7 +71,7 @@ $headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'U - 1) : ?> + 1) : ?>
diff --git a/src/index.php b/src/index.php index 977c4ff..c6ffb4b 100644 --- a/src/index.php +++ b/src/index.php @@ -43,6 +43,16 @@ $params_theme_control_type = (string) $this->params->get('theme_control_type', ' $params_theme_fab_enabled = $this->params->get('theme_fab_enabled', 1); $params_theme_fab_pos = $this->params->get('theme_fab_pos', 'br'); +// Accessibility params +$params_a11y_toolbar = $this->params->get('a11y_toolbar_enabled', 1); +$params_a11y_resize = $this->params->get('a11y_text_resize', 1); +$params_a11y_invert = $this->params->get('a11y_color_inversion', 1); +$params_a11y_contrast = $this->params->get('a11y_high_contrast', 1); +$params_a11y_links = $this->params->get('a11y_highlight_links', 1); +$params_a11y_font = $this->params->get('a11y_readable_font', 1); +$params_a11y_animations = $this->params->get('a11y_pause_animations', 1); +$params_a11y_pos = (string) $this->params->get('a11y_toolbar_pos', 'tl'); + // Detecting Active Variables $option = $input->getCmd('option', ''); $view = $input->getCmd('view', ''); @@ -277,8 +287,16 @@ $wa->useScript('user.js'); // js/user.js 0) { + prefs.fontStep--; + applyFontSize(prefs.fontStep); + sizeDisplay.textContent = fontSizeSteps[prefs.fontStep] + "%"; + saveA11yPrefs(prefs); + } + }); + + btnPlus.addEventListener("click", function () { + if (prefs.fontStep < fontSizeSteps.length - 1) { + prefs.fontStep++; + applyFontSize(prefs.fontStep); + sizeDisplay.textContent = fontSizeSteps[prefs.fontStep] + "%"; + saveA11yPrefs(prefs); + } + }); + + btnReset.addEventListener("click", function () { + prefs.fontStep = defaultStep; + applyFontSize(prefs.fontStep); + sizeDisplay.textContent = fontSizeSteps[prefs.fontStep] + "%"; + saveA11yPrefs(prefs); + }); + + btnRow.appendChild(btnMinus); + btnRow.appendChild(sizeDisplay); + btnRow.appendChild(btnPlus); + btnRow.appendChild(btnReset); + resizeGroup.appendChild(btnRow); + panel.appendChild(resizeGroup); + } + + // --- Helper: build a switch-style toggle button --- + function addSwitchOption(show, prefKey, icon, label, applyFn) { + if (!show) return; + var group = doc.createElement("div"); + group.className = "a11y-group"; + + var btn = doc.createElement("button"); + btn.type = "button"; + btn.className = "a11y-btn a11y-btn-wide"; + btn.setAttribute("role", "switch"); + btn.setAttribute("aria-checked", prefs[prefKey] ? "true" : "false"); + btn.setAttribute("aria-label", label); + btn.appendChild(faIcon(icon)); + btn.appendChild(doc.createTextNode(" " + label)); + + if (prefs[prefKey]) btn.classList.add("active"); + + btn.addEventListener("click", function () { + prefs[prefKey] = !prefs[prefKey]; + applyFn(prefs[prefKey]); + btn.setAttribute("aria-checked", prefs[prefKey] ? "true" : "false"); + btn.classList.toggle("active", prefs[prefKey]); + saveA11yPrefs(prefs); + }); + + group.appendChild(btn); + panel.appendChild(group); + } + + // --- Toggle options --- + addSwitchOption(showInvert, "inverted", "fa-solid fa-circle-half-stroke", "Invert colors", applyInversion); + addSwitchOption(showContrast, "contrast", "fa-solid fa-adjust", "High contrast", applyContrast); + addSwitchOption(showLinks, "links", "fa-solid fa-link", "Highlight links", applyLinks); + addSwitchOption(showFont, "font", "fa-solid fa-font", "Readable font", applyFont); + addSwitchOption(showAnimations, "paused", "fa-solid fa-pause", "Pause animations", applyPaused); + + // Toggle panel open/close + toggle.addEventListener("click", function () { + var isOpen = !panel.hidden; + panel.hidden = isOpen; + toggle.setAttribute("aria-expanded", isOpen ? "false" : "true"); + toggle.classList.toggle("active", !isOpen); + }); + + // Close on outside click + doc.addEventListener("click", function (e) { + if (!toolbar.contains(e.target) && !panel.hidden) { + panel.hidden = true; + toggle.setAttribute("aria-expanded", "false"); + toggle.classList.remove("active"); + } + }); + + // Apply saved preferences on load + if (prefs.fontStep !== defaultStep) applyFontSize(prefs.fontStep); + if (prefs.inverted) applyInversion(true); + if (prefs.contrast) applyContrast(true); + if (prefs.links) applyLinks(true); + if (prefs.font) applyFont(true); + if (prefs.paused) applyPaused(true); + + toolbar.appendChild(toggle); + toolbar.appendChild(panel); + body.appendChild(toolbar); + } + // ======================================================================== // TEMPLATE UTILITIES // ======================================================================== @@ -271,6 +500,11 @@ buildThemeToggle(); } + // Build accessibility toolbar if enabled + if (doc.body.getAttribute("data-a11y-toolbar") === "1") { + buildA11yToolbar(); + } + // Sticky header behavior handleScroll(); win.addEventListener("scroll", handleScroll); diff --git a/src/templateDetails.xml b/src/templateDetails.xml index 0b0d4a4..2e37862 100644 --- a/src/templateDetails.xml +++ b/src/templateDetails.xml @@ -241,6 +241,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +