1/** 2 * EnergyExperts Portal â Sidebar-Steuerung 3 * 4 * Zwei getrennte Zustaende, beide als Klasse auf <html>: 5 * ee-portal-collapsed Desktop: Sidebar schmal (nur Kurzzeichen). 6 * ee-portal-mobile-open Mobil: Off-canvas-Sidebar sichtbar. 7 * 8 * Der Desktop-Zustand wird in localStorage gehalten und GANZ OBEN â noch 9 * waehrend des <head>-Parsings, bevor der Body gezeichnet wird â angewandt. 10 * Deshalb wird dieses Script ohne defer im Head geladen: sonst blitzt bei 11 * jedem Seitenwechsel kurz das volle Menue auf. 12 * 13 * Zusaetzlich merkt sich das Script den zuletzt besuchten Bereich und loest 14 * damit den Einstieg ueber die Portal-Wurzel /portal auf (siehe unten). 15 * 16 * Vanilla-JS, kein Framework, keine globalen Namen ausser dem IIFE. 17 */ 18(function () { 19 'use strict'; 20 21 var STORAGE_KEY = 'eePortalSidebarCollapsed'; 22 var LAST_AREA_KEY = 'eePortalLastArea'; 23 var CLASS_COLLAPSED = 'ee-portal-collapsed'; 24 var CLASS_MOBILE_OPEN = 'ee-portal-mobile-open'; 25 var MOBILE_BREAKPOINT = 768; 26 27 var root = document.documentElement; 28 29 /** 30 * localStorage kann in Privat-Modi werfen â jeder Zugriff ist gekapselt, 31 * der Toggle funktioniert dann eben ohne Persistenz statt gar nicht. 32 */ 33 function readStored(key) { 34 try { 35 return window.localStorage.getItem(key); 36 } catch (e) { 37 return null; 38 } 39 } 40 41 function writeStored(key, value) { 42 try { 43 window.localStorage.setItem(key, value); 44 } catch (e) { 45 /* kein Speicher verfuegbar â Zustand gilt nur fuer diese Seite */ 46 } 47 } 48 49 function clearStored(key) { 50 try { 51 window.localStorage.removeItem(key); 52 } catch (e) { 53 /* nichts zu tun */ 54 } 55 } 56 57 // ------------------------------------------------------------------ 58 // Einstieg ueber die Portal-Wurzel /portal 59 // 60 // Der Server kennt den zuletzt besuchten Bereich nicht (er steht nur im 61 // localStorage), liefert aber am <html>-Element die Entscheidungsgrundlage: 62 // erlaubte Bereiche, Basis-URL und Rueckfall-Ziel. Weil dieses Script ohne 63 // defer im Head laeuft, ist das <html>-Tag bereits geparst â die Adresse 64 // wird ersetzt, bevor irgendetwas gezeichnet wird. Ist der gemerkte Bereich 65 // fuer die Rolle nicht (mehr) erlaubt, greift der Rueckfall. 66 // ------------------------------------------------------------------ 67 if (root.getAttribute('data-ee-portal-entry')) { 68 (function () { 69 var base = root.getAttribute('data-ee-portal-base') || ''; 70 var fallback = root.getAttribute('data-ee-portal-fallback') || ''; 71 var allowed = (root.getAttribute('data-ee-portal-areas') || '').split(','); 72 var last = readStored(LAST_AREA_KEY); 73 var target = ''; 74 75 if (last && base && allowed.indexOf(last) !== -1) { 76 target = base + last + '/'; 77 } else if (fallback) { 78 target = fallback; 79 } 80 81 if (target) { 82 window.location.replace(target); 83 } 84 })(); 85 86 return; 87 } 88 89 // ------------------------------------------------------------------ 90 // Letzten Bereich merken 91 // 92 // Nur erreichbare Bereiche werden gemerkt. Wird ein Bereich verweigert 93 // (403-Panel), fliegt genau dieser Eintrag raus, damit die Wurzel nicht 94 // dauerhaft in eine gesperrte Ansicht zeigt. 95 // ------------------------------------------------------------------ 96 (function () { 97 var area = root.getAttribute('data-ee-portal-area'); 98 99 if (!area) { 100 return; 101 } 102 103 if (root.getAttribute('data-ee-portal-denied')) { 104 if (readStored(LAST_AREA_KEY) === area) { 105 clearStored(LAST_AREA_KEY); 106 } 107 return; 108 } 109 110 writeStored(LAST_AREA_KEY, area); 111 })(); 112 113 function isCollapsed() { 114 return root.classList.contains(CLASS_COLLAPSED); 115 } 116 117 function isMobile() { 118 return window.matchMedia 119 ? window.matchMedia('(max-width: ' + MOBILE_BREAKPOINT + 'px)').matches 120 : window.innerWidth <= MOBILE_BREAKPOINT; 121 } 122 123 // --- Schritt 1: gespeicherten Zustand sofort anwenden (kein Flackern) --- 124 if (readStored(STORAGE_KEY) === '1') { 125 root.classList.add(CLASS_COLLAPSED); 126 } 127 128 // --- Schritt 2: Bedienelemente verdrahten, sobald das DOM steht --- 129 function syncAria(collapseBtn, burgerBtn) { 130 if (collapseBtn) { 131 collapseBtn.setAttribute('aria-expanded', isCollapsed() ? 'false' : 'true'); 132 } 133 if (burgerBtn) { 134 burgerBtn.setAttribute( 135 'aria-expanded', 136 root.classList.contains(CLASS_MOBILE_OPEN) ? 'true' : 'false' 137 ); 138 } 139 } 140
141 function init() { 142 var collapseBtn = document.querySelector('[data-ee-portal-collapse]'); 143 var burgerBtn = document.querySelector('[data-ee-portal-burger]'); 144 var scrim = document.querySelector('[data-ee-portal-close]'); 145 146 function closeMobile() { 147 root.classList.remove(CLASS_MOBILE_OPEN); 148 syncAria(collapseBtn, burgerBtn); 149 } 150 151 if (collapseBtn) { 152 collapseBtn.addEventListener('click', function () { 153 // Auf schmalen Viewports ist die Sidebar off-canvas; der 154 // Collapse-Knopf schliesst sie dort, statt sie zu verschmaelern. 155 if (isMobile()) { 156 closeMobile(); 157 return; 158 } 159 160 var next = !isCollapsed(); 161 root.classList.toggle(CLASS_COLLAPSED, next); 162 writeStored(STORAGE_KEY, next ? '1' : '0'); 163 syncAria(collapseBtn, burgerBtn); 164 }); 165 } 166 167 if (burgerBtn) { 168 burgerBtn.addEventListener('click', function () { 169 root.classList.toggle(CLASS_MOBILE_OPEN); 170 syncAria(collapseBtn, burgerBtn); 171 }); 172 } 173 174 if (scrim) { 175 scrim.addEventListener('click', closeMobile); 176 } 177 178 document.addEventListener('keydown', function (event) { 179 if (event.key === 'Escape' && root.classList.contains(CLASS_MOBILE_OPEN)) { 180 closeMobile(); 181 } 182 }); 183 184 syncAria(collapseBtn, burgerBtn); 185 } 186 187 if (document.readyState === 'loading') { 188 document.addEventListener('DOMContentLoaded', init); 189 } else { 190 init(); 191 } 192})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.