|
| 1 | +// Collapsible navigation sidebar for the API docs (issue #7867). |
| 2 | +(() => { |
| 3 | + const KEY = "bn_api_sidebar_collapsed"; |
| 4 | + const CLS = "bn-sidebar-collapsed"; |
| 5 | + const root = document.documentElement; |
| 6 | + // Collapse is desktop only; on mobile the theme's hamburger owns the nav. |
| 7 | + const desktop = window.matchMedia("(min-width: 769px)"); |
| 8 | + |
| 9 | + const save = (v) => { try { localStorage.setItem(KEY, v); } catch (e) {} }; |
| 10 | + const load = () => { try { return localStorage.getItem(KEY); } catch (e) { return null; } }; |
| 11 | + |
| 12 | + let collapsed = load() === "1"; |
| 13 | + |
| 14 | + // Apply saved state before first paint to avoid a layout flash. |
| 15 | + root.classList.toggle(CLS, collapsed); |
| 16 | + |
| 17 | + const sync = () => { |
| 18 | + const btn = document.getElementById("bn-sidebar-toggle"); |
| 19 | + const nav = document.querySelector(".wy-nav-side"); |
| 20 | + // Only hide the nav from AT when it is actually offscreen. |
| 21 | + const hidden = collapsed && desktop.matches; |
| 22 | + if (btn) { |
| 23 | + btn.setAttribute("aria-pressed", collapsed ? "true" : "false"); |
| 24 | + btn.title = collapsed ? "Show navigation" : "Hide navigation"; |
| 25 | + } |
| 26 | + if (nav) { |
| 27 | + if (hidden) { |
| 28 | + nav.setAttribute("aria-hidden", "true"); |
| 29 | + nav.setAttribute("inert", ""); |
| 30 | + } else { |
| 31 | + nav.removeAttribute("aria-hidden"); |
| 32 | + nav.removeAttribute("inert"); |
| 33 | + } |
| 34 | + } |
| 35 | + }; |
| 36 | + |
| 37 | + const setCollapsed = (v) => { |
| 38 | + collapsed = v; |
| 39 | + root.classList.toggle(CLS, collapsed); |
| 40 | + save(collapsed ? "1" : "0"); |
| 41 | + sync(); |
| 42 | + }; |
| 43 | + |
| 44 | + const addButton = () => { |
| 45 | + const nav = document.querySelector(".wy-nav-side"); |
| 46 | + if (nav && !nav.id) nav.id = "bn-nav-side"; |
| 47 | + |
| 48 | + const btn = document.createElement("button"); |
| 49 | + btn.id = "bn-sidebar-toggle"; |
| 50 | + btn.type = "button"; |
| 51 | + btn.setAttribute("aria-label", "Toggle navigation"); |
| 52 | + if (nav) btn.setAttribute("aria-controls", nav.id); |
| 53 | + btn.textContent = "☰"; |
| 54 | + btn.addEventListener("click", () => setCollapsed(!collapsed)); |
| 55 | + document.body.appendChild(btn); |
| 56 | + sync(); |
| 57 | + }; |
| 58 | + |
| 59 | + // addListener fallback for older Safari/WebKit without addEventListener. |
| 60 | + if (desktop.addEventListener) desktop.addEventListener("change", sync); |
| 61 | + else desktop.addListener(sync); |
| 62 | + |
| 63 | + if (document.readyState === "loading") { |
| 64 | + document.addEventListener("DOMContentLoaded", addButton); |
| 65 | + } else { |
| 66 | + addButton(); |
| 67 | + } |
| 68 | +})(); |
0 commit comments