<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.bellingham-heritage.org.uk:443/index.php?action=history&amp;feed=atom&amp;title=EdiaWiki%3AGadget-bhc-accessibility.js</id>
	<title>EdiaWiki:Gadget-bhc-accessibility.js - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.bellingham-heritage.org.uk:443/index.php?action=history&amp;feed=atom&amp;title=EdiaWiki%3AGadget-bhc-accessibility.js"/>
	<link rel="alternate" type="text/html" href="https://wiki.bellingham-heritage.org.uk:443/index.php?title=EdiaWiki:Gadget-bhc-accessibility.js&amp;action=history"/>
	<updated>2026-08-25T00:51:23Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.1</generator>
	<entry>
		<id>https://wiki.bellingham-heritage.org.uk:443/index.php?title=EdiaWiki:Gadget-bhc-accessibility.js&amp;diff=1471&amp;oldid=prev</id>
		<title>Steve: Created page with &quot;(() =&gt; {   &quot;use strict&quot;;    // -------------------------------------------------------------------   // Cookie helpers   // -------------------------------------------------------------------   const COOKIE_PREFIX = &quot;a11y_&quot;;    function setCookie(name, value, days = 365) {     const exp = new Date();     exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);     document.cookie = `${encodeURIComponent(COOKIE_PREFIX + name)}=${encodeURIComponent(String(value))}; expires...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.bellingham-heritage.org.uk:443/index.php?title=EdiaWiki:Gadget-bhc-accessibility.js&amp;diff=1471&amp;oldid=prev"/>
		<updated>2026-01-25T18:03:18Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;(() =&amp;gt; {   &amp;quot;use strict&amp;quot;;    // -------------------------------------------------------------------   // Cookie helpers   // -------------------------------------------------------------------   const COOKIE_PREFIX = &amp;quot;a11y_&amp;quot;;    function setCookie(name, value, days = 365) {     const exp = new Date();     exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);     document.cookie = `${encodeURIComponent(COOKIE_PREFIX + name)}=${encodeURIComponent(String(value))}; expires...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;(() =&amp;gt; {&lt;br /&gt;
  &amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // Cookie helpers&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  const COOKIE_PREFIX = &amp;quot;a11y_&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  function setCookie(name, value, days = 365) {&lt;br /&gt;
    const exp = new Date();&lt;br /&gt;
    exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);&lt;br /&gt;
    document.cookie = `${encodeURIComponent(COOKIE_PREFIX + name)}=${encodeURIComponent(String(value))}; expires=${exp.toUTCString()}; path=/; SameSite=Lax`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function getCookie(name, fallback = &amp;quot;&amp;quot;) {&lt;br /&gt;
    const key = encodeURIComponent(COOKIE_PREFIX + name) + &amp;quot;=&amp;quot;;&lt;br /&gt;
    const parts = document.cookie.split(&amp;quot;;&amp;quot;).map(s =&amp;gt; s.trim());&lt;br /&gt;
    for (const p of parts) {&lt;br /&gt;
      if (p.startsWith(key)) return decodeURIComponent(p.substring(key.length));&lt;br /&gt;
    }&lt;br /&gt;
    return fallback;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function delCookie(name) {&lt;br /&gt;
    document.cookie = `${encodeURIComponent(COOKIE_PREFIX + name)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; SameSite=Lax`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // State + announcements&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  const STATE = {&lt;br /&gt;
    contrast: false,&lt;br /&gt;
    underline: false,&lt;br /&gt;
    spacing: &amp;quot;off&amp;quot;,          // off | plus | minus&lt;br /&gt;
    cursor: &amp;quot;off&amp;quot;,           // off | white | yellow&lt;br /&gt;
    ruler: false,&lt;br /&gt;
    fontPct: 100             // 90..140 in steps of 10&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  let liveEl = null;&lt;br /&gt;
  let rulerEl = null;&lt;br /&gt;
  let rulerY = 0;&lt;br /&gt;
&lt;br /&gt;
  function announce(msg) {&lt;br /&gt;
    if (!liveEl) return;&lt;br /&gt;
    liveEl.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
    setTimeout(() =&amp;gt; { liveEl.textContent = msg; }, 10);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function clamp(n, min, max) { return Math.max(min, Math.min(max, n)); }&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // Apply state to DOM&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  function applyState() {&lt;br /&gt;
    document.body.classList.toggle(&amp;quot;a11y-contrast&amp;quot;, !!STATE.contrast);&lt;br /&gt;
    document.body.classList.toggle(&amp;quot;a11y-underline-links&amp;quot;, !!STATE.underline);&lt;br /&gt;
&lt;br /&gt;
    document.body.classList.toggle(&amp;quot;a11y-spacing-plus&amp;quot;, STATE.spacing === &amp;quot;plus&amp;quot;);&lt;br /&gt;
    document.body.classList.toggle(&amp;quot;a11y-spacing-minus&amp;quot;, STATE.spacing === &amp;quot;minus&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    document.body.classList.toggle(&amp;quot;a11y-cursor-white&amp;quot;, STATE.cursor === &amp;quot;white&amp;quot;);&lt;br /&gt;
    document.body.classList.toggle(&amp;quot;a11y-cursor-yellow&amp;quot;, STATE.cursor === &amp;quot;yellow&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    document.documentElement.style.fontSize = `${STATE.fontPct}%`;&lt;br /&gt;
&lt;br /&gt;
    ensureRuler();&lt;br /&gt;
    if (STATE.ruler) {&lt;br /&gt;
      rulerEl.hidden = false;&lt;br /&gt;
      setRulerY(rulerY || Math.floor(window.innerHeight / 2));&lt;br /&gt;
      enableRulerListeners();&lt;br /&gt;
    } else {&lt;br /&gt;
      if (rulerEl) rulerEl.hidden = true;&lt;br /&gt;
      disableRulerListeners();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    updateUiButtons();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // Ruler support&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  function ensureRuler() {&lt;br /&gt;
    if (rulerEl) return;&lt;br /&gt;
    rulerEl = document.getElementById(&amp;quot;a11y-ruler&amp;quot;);&lt;br /&gt;
    if (!rulerEl) {&lt;br /&gt;
      rulerEl = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
      rulerEl.id = &amp;quot;a11y-ruler&amp;quot;;&lt;br /&gt;
      rulerEl.hidden = true;&lt;br /&gt;
      document.body.appendChild(rulerEl);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function setRulerY(y) {&lt;br /&gt;
    rulerY = clamp(y, 0, Math.max(0, window.innerHeight - 1));&lt;br /&gt;
    if (rulerEl) rulerEl.style.transform = `translateY(${rulerY}px)`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function onMouseMove(e) {&lt;br /&gt;
    if (!STATE.ruler) return;&lt;br /&gt;
    setRulerY(e.clientY - 11);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function onKeyDown(e) {&lt;br /&gt;
    if (!STATE.ruler) return;&lt;br /&gt;
&lt;br /&gt;
    if (e.key === &amp;quot;ArrowDown&amp;quot;) {&lt;br /&gt;
      e.preventDefault();&lt;br /&gt;
      setRulerY(rulerY + 10);&lt;br /&gt;
      announce(&amp;quot;Reading ruler moved down&amp;quot;);&lt;br /&gt;
    } else if (e.key === &amp;quot;ArrowUp&amp;quot;) {&lt;br /&gt;
      e.preventDefault();&lt;br /&gt;
      setRulerY(rulerY - 10);&lt;br /&gt;
      announce(&amp;quot;Reading ruler moved up&amp;quot;);&lt;br /&gt;
    } else if (e.key === &amp;quot;Escape&amp;quot;) {&lt;br /&gt;
      e.preventDefault();&lt;br /&gt;
      STATE.ruler = false;&lt;br /&gt;
      setCookie(&amp;quot;ruler&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
      applyState();&lt;br /&gt;
      announce(&amp;quot;Reading ruler off&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  let rulerListenersOn = false;&lt;br /&gt;
  function enableRulerListeners() {&lt;br /&gt;
    if (rulerListenersOn) return;&lt;br /&gt;
    rulerListenersOn = true;&lt;br /&gt;
    window.addEventListener(&amp;quot;mousemove&amp;quot;, onMouseMove, { passive: true });&lt;br /&gt;
    window.addEventListener(&amp;quot;keydown&amp;quot;, onKeyDown);&lt;br /&gt;
    window.addEventListener(&amp;quot;resize&amp;quot;, () =&amp;gt; setRulerY(rulerY), { passive: true });&lt;br /&gt;
  }&lt;br /&gt;
  function disableRulerListeners() {&lt;br /&gt;
    if (!rulerListenersOn) return;&lt;br /&gt;
    rulerListenersOn = false;&lt;br /&gt;
    window.removeEventListener(&amp;quot;mousemove&amp;quot;, onMouseMove);&lt;br /&gt;
    window.removeEventListener(&amp;quot;keydown&amp;quot;, onKeyDown);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // UI creation&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  function ensureUi() {&lt;br /&gt;
    if (document.getElementById(&amp;quot;a11y-toggle&amp;quot;)) return;&lt;br /&gt;
&lt;br /&gt;
    // Resolve base install path (e.g. &amp;quot;/churches&amp;quot;) from &amp;lt;body data-app-base&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
const appBase =&lt;br /&gt;
  document.body.dataset.appBase?.replace(/\/$/, &amp;#039;&amp;#039;) || &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
const helpHref = appBase + &amp;quot;/index.php/Accessibility&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    const toggle = document.createElement(&amp;quot;button&amp;quot;);&lt;br /&gt;
    toggle.type = &amp;quot;button&amp;quot;;&lt;br /&gt;
    toggle.id = &amp;quot;a11y-toggle&amp;quot;;&lt;br /&gt;
    toggle.className = &amp;quot;a11y-toggle&amp;quot;;&lt;br /&gt;
    toggle.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Accessibility options&amp;quot;);&lt;br /&gt;
    toggle.setAttribute(&amp;quot;aria-haspopup&amp;quot;, &amp;quot;dialog&amp;quot;);&lt;br /&gt;
    toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    toggle.innerHTML = `&lt;br /&gt;
      &amp;lt;svg viewBox=&amp;quot;0 0 24 24&amp;quot; aria-hidden=&amp;quot;true&amp;quot; focusable=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;path d=&amp;quot;M12 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 12 2zm9 7h-6.5c-.7 0-1.3.4-1.6 1L12 12l-.9-2c-.3-.6-.9-1-1.6-1H3a1 1 0 0 0 0 2h5.3l1.3 2.9-1.7 6.2a1 1 0 0 0 1.9.6l1.2-4.3 1.2 4.3a1 1 0 0 0 1.9-.6l-1.7-6.2 1.3-2.9H21a1 1 0 0 0 0-2z&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/svg&amp;gt;&lt;br /&gt;
    `;&lt;br /&gt;
    document.body.appendChild(toggle);&lt;br /&gt;
&lt;br /&gt;
    const panel = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    panel.id = &amp;quot;a11y-panel&amp;quot;;&lt;br /&gt;
    panel.className = &amp;quot;a11y-panel&amp;quot;;&lt;br /&gt;
    panel.setAttribute(&amp;quot;role&amp;quot;, &amp;quot;dialog&amp;quot;);&lt;br /&gt;
    panel.setAttribute(&amp;quot;aria-label&amp;quot;, &amp;quot;Accessibility options&amp;quot;);&lt;br /&gt;
    panel.hidden = true;&lt;br /&gt;
&lt;br /&gt;
    panel.innerHTML = `&lt;br /&gt;
      &amp;lt;div class=&amp;quot;a11y-head&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;h2&amp;gt;Accessibility&amp;lt;/h2&amp;gt;&lt;br /&gt;
        &amp;lt;a class=&amp;quot;a11y-help&amp;quot; href=&amp;quot;${helpHref}&amp;quot; aria-label=&amp;quot;Accessibility help&amp;quot;&amp;gt;?&amp;lt;/a&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;div class=&amp;quot;a11y-row&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Text size&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;font-minus&amp;quot; aria-pressed=&amp;quot;false&amp;quot; aria-label=&amp;quot;Decrease text size&amp;quot;&amp;gt;A−&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;font-plus&amp;quot; aria-pressed=&amp;quot;false&amp;quot; aria-label=&amp;quot;Increase text size&amp;quot;&amp;gt;A+&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;font-reset&amp;quot; aria-pressed=&amp;quot;false&amp;quot; aria-label=&amp;quot;Reset text size&amp;quot;&amp;gt;Reset&amp;lt;/button&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;div class=&amp;quot;a11y-row&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Contrast and links&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;contrast&amp;quot; aria-pressed=&amp;quot;false&amp;quot;&amp;gt;High contrast&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;underline&amp;quot; aria-pressed=&amp;quot;false&amp;quot;&amp;gt;Underline links&amp;lt;/button&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;div class=&amp;quot;a11y-row&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Text spacing&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;spacing-plus&amp;quot; aria-pressed=&amp;quot;false&amp;quot;&amp;gt;More spacing&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;spacing-minus&amp;quot; aria-pressed=&amp;quot;false&amp;quot;&amp;gt;Less spacing&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;spacing-reset&amp;quot; aria-pressed=&amp;quot;false&amp;quot;&amp;gt;Spacing reset&amp;lt;/button&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;div class=&amp;quot;a11y-row&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Cursor and reading aid&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;cursor&amp;quot; aria-pressed=&amp;quot;false&amp;quot; aria-label=&amp;quot;Large cursor setting&amp;quot;&amp;gt;Large cursor: Off&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;ruler&amp;quot; aria-pressed=&amp;quot;false&amp;quot; aria-label=&amp;quot;Toggle reading ruler&amp;quot;&amp;gt;Reading ruler&amp;lt;/button&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;      &amp;lt;div class=&amp;quot;a11y-row&amp;quot; role=&amp;quot;group&amp;quot; aria-label=&amp;quot;Reset all&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;a11y-btn&amp;quot; data-action=&amp;quot;reset&amp;quot; aria-pressed=&amp;quot;false&amp;quot;&amp;gt;Reset all&amp;lt;/button&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;div class=&amp;quot;a11y-hint&amp;quot;&amp;gt;&lt;br /&gt;
        Settings are saved on this device. Large cursor cycles &amp;lt;strong&amp;gt;Off → White → Yellow → Off&amp;lt;/strong&amp;gt;. When Reading ruler is on, use &amp;lt;strong&amp;gt;↑/↓&amp;lt;/strong&amp;gt; to move it and &amp;lt;strong&amp;gt;Esc&amp;lt;/strong&amp;gt; to turn it off.&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;div id=&amp;quot;a11y-live&amp;quot; class=&amp;quot;a11y-sr&amp;quot; aria-live=&amp;quot;polite&amp;quot; aria-atomic=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    `;&lt;br /&gt;
    document.body.appendChild(panel);&lt;br /&gt;
&lt;br /&gt;
    liveEl = panel.querySelector(&amp;quot;#a11y-live&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    function openPanel() {&lt;br /&gt;
      panel.hidden = false;&lt;br /&gt;
      toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;
      const firstBtn = panel.querySelector(&amp;quot;button.a11y-btn&amp;quot;);&lt;br /&gt;
      if (firstBtn) firstBtn.focus();&lt;br /&gt;
    }&lt;br /&gt;
    function closePanel() {&lt;br /&gt;
      panel.hidden = true;&lt;br /&gt;
      toggle.setAttribute(&amp;quot;aria-expanded&amp;quot;, &amp;quot;false&amp;quot;);&lt;br /&gt;
      toggle.focus();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    toggle.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {&lt;br /&gt;
      if (panel.hidden) openPanel(); else closePanel();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.addEventListener(&amp;quot;click&amp;quot;, (e) =&amp;gt; {&lt;br /&gt;
      if (panel.hidden) return;&lt;br /&gt;
      if (panel.contains(e.target) || toggle.contains(e.target)) return;&lt;br /&gt;
      closePanel();&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.addEventListener(&amp;quot;keydown&amp;quot;, (e) =&amp;gt; {&lt;br /&gt;
      if (panel.hidden) return;&lt;br /&gt;
      if (e.key === &amp;quot;Escape&amp;quot;) {&lt;br /&gt;
        e.preventDefault();&lt;br /&gt;
        closePanel();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    panel.addEventListener(&amp;quot;click&amp;quot;, (e) =&amp;gt; {&lt;br /&gt;
      const btn = e.target.closest(&amp;quot;button[data-action]&amp;quot;);&lt;br /&gt;
      if (!btn) return;&lt;br /&gt;
      const action = btn.getAttribute(&amp;quot;data-action&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
      handleAction(action);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function updateUiButtons() {&lt;br /&gt;
&lt;br /&gt;
    const panel = document.getElementById(&amp;quot;a11y-panel&amp;quot;);&lt;br /&gt;
    if (!panel) return;&lt;br /&gt;
&lt;br /&gt;
    const setPressed = (action, pressed) =&amp;gt; {&lt;br /&gt;
      const b = panel.querySelector(`button[data-action=&amp;quot;${action}&amp;quot;]`);&lt;br /&gt;
      if (b) b.setAttribute(&amp;quot;aria-pressed&amp;quot;, pressed ? &amp;quot;true&amp;quot; : &amp;quot;false&amp;quot;);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    setPressed(&amp;quot;contrast&amp;quot;, STATE.contrast);&lt;br /&gt;
    setPressed(&amp;quot;underline&amp;quot;, STATE.underline);&lt;br /&gt;
    setPressed(&amp;quot;ruler&amp;quot;, STATE.ruler);&lt;br /&gt;
    // Cursor button is a 3-state cycle: Off -&amp;gt; White -&amp;gt; Yellow -&amp;gt; Off.&lt;br /&gt;
    setPressed(&amp;quot;cursor&amp;quot;, STATE.cursor !== &amp;quot;off&amp;quot;);&lt;br /&gt;
    setPressed(&amp;quot;spacing-plus&amp;quot;, STATE.spacing === &amp;quot;plus&amp;quot;);&lt;br /&gt;
    setPressed(&amp;quot;spacing-minus&amp;quot;, STATE.spacing === &amp;quot;minus&amp;quot;);&lt;br /&gt;
    // Reset buttons are actions, not toggles: keep them un-pressed&lt;br /&gt;
    setPressed(&amp;quot;spacing-reset&amp;quot;, false);&lt;br /&gt;
    setPressed(&amp;quot;font-plus&amp;quot;, false);&lt;br /&gt;
    setPressed(&amp;quot;font-minus&amp;quot;, false);&lt;br /&gt;
    setPressed(&amp;quot;font-reset&amp;quot;, STATE.fontPct !== 100);&lt;br /&gt;
    setPressed(&amp;quot;reset&amp;quot;, false);&lt;br /&gt;
&lt;br /&gt;
    // Make the 3-state cursor behaviour obvious to sighted users.&lt;br /&gt;
    const cursorBtn = panel.querySelector(&amp;#039;button[data-action=&amp;quot;cursor&amp;quot;]&amp;#039;);&lt;br /&gt;
    if (cursorBtn) {&lt;br /&gt;
      const label = (STATE.cursor === &amp;quot;off&amp;quot;) ? &amp;quot;Off&amp;quot; : (STATE.cursor === &amp;quot;white&amp;quot;) ? &amp;quot;White&amp;quot; : &amp;quot;Yellow&amp;quot;;&lt;br /&gt;
      cursorBtn.textContent = `Large cursor: ${label}`;&lt;br /&gt;
      cursorBtn.setAttribute(&lt;br /&gt;
        &amp;quot;aria-label&amp;quot;,&lt;br /&gt;
        STATE.cursor === &amp;quot;off&amp;quot;&lt;br /&gt;
          ? &amp;quot;Large cursor off. Press to turn on&amp;quot;&lt;br /&gt;
          : `Large cursor ${label}. Press to change colour or turn off`&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // Actions&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  function handleAction(action) {&lt;br /&gt;
    switch (action) {&lt;br /&gt;
      case &amp;quot;contrast&amp;quot;:&lt;br /&gt;
        STATE.contrast = !STATE.contrast;&lt;br /&gt;
        setCookie(&amp;quot;contrast&amp;quot;, STATE.contrast ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(`High contrast ${STATE.contrast ? &amp;quot;on&amp;quot; : &amp;quot;off&amp;quot;}`);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;underline&amp;quot;:&lt;br /&gt;
        STATE.underline = !STATE.underline;&lt;br /&gt;
        setCookie(&amp;quot;underline&amp;quot;, STATE.underline ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(`Underline links ${STATE.underline ? &amp;quot;on&amp;quot; : &amp;quot;off&amp;quot;}`);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;spacing-plus&amp;quot;:&lt;br /&gt;
        STATE.spacing = (STATE.spacing === &amp;quot;plus&amp;quot;) ? &amp;quot;off&amp;quot; : &amp;quot;plus&amp;quot;;&lt;br /&gt;
        setCookie(&amp;quot;spacing&amp;quot;, STATE.spacing);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(STATE.spacing === &amp;quot;plus&amp;quot; ? &amp;quot;Text spacing increased&amp;quot; : &amp;quot;Text spacing normal&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;spacing-minus&amp;quot;:&lt;br /&gt;
        STATE.spacing = (STATE.spacing === &amp;quot;minus&amp;quot;) ? &amp;quot;off&amp;quot; : &amp;quot;minus&amp;quot;;&lt;br /&gt;
        setCookie(&amp;quot;spacing&amp;quot;, STATE.spacing);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(STATE.spacing === &amp;quot;minus&amp;quot; ? &amp;quot;Text spacing decreased&amp;quot; : &amp;quot;Text spacing normal&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;spacing-reset&amp;quot;:&lt;br /&gt;
        STATE.spacing = &amp;quot;off&amp;quot;;&lt;br /&gt;
        setCookie(&amp;quot;spacing&amp;quot;, &amp;quot;off&amp;quot;);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(&amp;quot;Text spacing reset&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;cursor&amp;quot;:&lt;br /&gt;
        STATE.cursor = (STATE.cursor === &amp;quot;off&amp;quot;) ? &amp;quot;white&amp;quot; : (STATE.cursor === &amp;quot;white&amp;quot;) ? &amp;quot;yellow&amp;quot; : &amp;quot;off&amp;quot;;&lt;br /&gt;
        setCookie(&amp;quot;cursor&amp;quot;, STATE.cursor);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(&lt;br /&gt;
          STATE.cursor === &amp;quot;off&amp;quot; ? &amp;quot;Large cursor off&amp;quot; :&lt;br /&gt;
          STATE.cursor === &amp;quot;white&amp;quot; ? &amp;quot;Large cursor white&amp;quot; :&lt;br /&gt;
          &amp;quot;Large cursor yellow&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;ruler&amp;quot;:&lt;br /&gt;
        STATE.ruler = !STATE.ruler;&lt;br /&gt;
        setCookie(&amp;quot;ruler&amp;quot;, STATE.ruler ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;);&lt;br /&gt;
        if (STATE.ruler &amp;amp;&amp;amp; !rulerY) rulerY = Math.floor(window.innerHeight / 2);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(`Reading ruler ${STATE.ruler ? &amp;quot;on&amp;quot; : &amp;quot;off&amp;quot;}`);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;font-plus&amp;quot;:&lt;br /&gt;
        STATE.fontPct = clamp(STATE.fontPct + 10, 90, 140);&lt;br /&gt;
        setCookie(&amp;quot;fontPct&amp;quot;, String(STATE.fontPct));&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(&amp;quot;Text size increased&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;font-minus&amp;quot;:&lt;br /&gt;
        STATE.fontPct = clamp(STATE.fontPct - 10, 90, 140);&lt;br /&gt;
        setCookie(&amp;quot;fontPct&amp;quot;, String(STATE.fontPct));&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(&amp;quot;Text size decreased&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;font-reset&amp;quot;:&lt;br /&gt;
        STATE.fontPct = 100;&lt;br /&gt;
        setCookie(&amp;quot;fontPct&amp;quot;, &amp;quot;100&amp;quot;);&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(&amp;quot;Text size reset&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;reset&amp;quot;:&lt;br /&gt;
        [&amp;quot;contrast&amp;quot;,&amp;quot;underline&amp;quot;,&amp;quot;spacing&amp;quot;,&amp;quot;cursor&amp;quot;,&amp;quot;ruler&amp;quot;,&amp;quot;fontPct&amp;quot;].forEach(delCookie);&lt;br /&gt;
        STATE.contrast = false;&lt;br /&gt;
        STATE.underline = false;&lt;br /&gt;
        STATE.spacing = &amp;quot;off&amp;quot;;&lt;br /&gt;
        STATE.cursor = &amp;quot;off&amp;quot;;&lt;br /&gt;
        STATE.ruler = false;&lt;br /&gt;
        STATE.fontPct = 100;&lt;br /&gt;
        rulerY = 0;&lt;br /&gt;
        applyState();&lt;br /&gt;
        announce(&amp;quot;Accessibility settings reset&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // Load saved settings&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  function loadState() {&lt;br /&gt;
    STATE.contrast = getCookie(&amp;quot;contrast&amp;quot;, &amp;quot;0&amp;quot;) === &amp;quot;1&amp;quot;;&lt;br /&gt;
    STATE.underline = getCookie(&amp;quot;underline&amp;quot;, &amp;quot;0&amp;quot;) === &amp;quot;1&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    const spacing = getCookie(&amp;quot;spacing&amp;quot;, &amp;quot;off&amp;quot;);&lt;br /&gt;
    STATE.spacing = (spacing === &amp;quot;plus&amp;quot; || spacing === &amp;quot;minus&amp;quot;) ? spacing : &amp;quot;off&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    const cursor = getCookie(&amp;quot;cursor&amp;quot;, &amp;quot;off&amp;quot;);&lt;br /&gt;
    STATE.cursor = (cursor === &amp;quot;white&amp;quot; || cursor === &amp;quot;yellow&amp;quot;) ? cursor : &amp;quot;off&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    STATE.ruler = getCookie(&amp;quot;ruler&amp;quot;, &amp;quot;0&amp;quot;) === &amp;quot;1&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    const fp = parseInt(getCookie(&amp;quot;fontPct&amp;quot;, &amp;quot;100&amp;quot;), 10);&lt;br /&gt;
    STATE.fontPct = clamp(isNaN(fp) ? 100 : fp, 90, 140);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  // Init&lt;br /&gt;
  // -------------------------------------------------------------------&lt;br /&gt;
  function init() {&lt;br /&gt;
    ensureUi();&lt;br /&gt;
    loadState();&lt;br /&gt;
    applyState();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (document.readyState === &amp;quot;loading&amp;quot;) {&lt;br /&gt;
    document.addEventListener(&amp;quot;DOMContentLoaded&amp;quot;, init);&lt;br /&gt;
  } else {&lt;br /&gt;
    init();&lt;br /&gt;
  }&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Steve</name></author>
	</entry>
</feed>