1/* book2look master-page chrome: theme (dark/light), accessibility toolbar, 2 GDPR consent banner, language select. 3 4 Vanilla-JS port of the React/dc-runtime "Component" that used to render 5 this cluster of UI in MasterWall.master's <x-dc> block. Ported 1:1 from 6 that component's state/renderVals()/gdprText()/componentDidMount so the 7 markup, colors, copy and behavior stay identical â only the rendering 8 mechanism (direct DOM updates instead of React) changed. */ 9(function () { 10 'use strict'; 11 12 var state = { 13 bDark: false, 14 textStep: 0, 15 contrast: false, 16 reduceMotion: false, 17 spacing: false, 18 plain: false, 19 consent: true, 20 prefsOpen: false, 21 lang: 'en' 22 }; 23 24 var zooms = [1, 1.15, 1.3]; 25 var tSizes = ['13px', '15px', '17px']; 26 27 function syncDarkFlag() { 28 try { document.documentElement.setAttribute('data-b2l-dark', state.bDark ? '1' : '0'); } catch (e) {} 29 try { document.documentElement.setAttribute('data-motion', state.reduceMotion ? 'off' : 'on'); } catch (e) {} 30 } 31 32 function log(name, data) { 33 try { if (window.LogThis) window.LogThis.track(name, data || {}); } catch (e) {} 34 } 35 36 function themeColors() { 37 return state.bDark 38 ? { bg: '#221A12', sf: '#2C231A', sf2: '#352A1F', tx: '#F3E9D8', mut: '#C0AE94', ln: '#463829', ac: '#E8823D', wood: '#5E4227', wood2: '#42301C', modeLabel: 'âï¸ Light', dark: true } 39 : { bg: '#F7F1E5', sf: '#FFFDF8', sf2: '#F1E7D2', tx: '#33261A', mut: '#6B5B48', ln: '#E8DCC4', ac: '#B0490F', wood: '#9C6B3C', wood2: '#7A4E28', modeLabel: 'ð Dark', dark: false }; 40 } 41 42 function onOff(B, on) { 43 return { bg: on ? B.tx : B.sf, fg: on ? B.bg : B.tx }; 44 } 45 46 function setBtnColors(btn, bg, fg, pressed) { 47 if (!btn) return; 48 btn.style.background = bg; 49 btn.style.color = fg; 50 btn.setAttribute('aria-pressed', pressed ? 'true' : 'false'); 51 } 52 53 function applyTheme() { 54 syncDarkFlag(); 55 56 var B = themeColors(); 57 var root = document.getElementById('b2lThemeRoot'); 58 if (root) { 59 root.style.setProperty('--bg', B.bg); 60 root.style.setProperty('--sf', B.sf); 61 root.style.setProperty('--sf2', B.sf2); 62 root.style.setProperty('--tx', B.tx); 63 root.style.setProperty('--mut', B.mut); 64 root.style.setProperty('--ln', B.ln); 65 root.style.setProperty('--ac', B.ac); 66 root.style.setProperty('--wood', B.wood); 67 root.style.setProperty('--wood2', B.wood2); 68 root.style.zoom = String(zooms[state.textStep]); 69 root.style.filter = state.contrast ? 'contrast(1.28) saturate(1.15)' : 'none'; 70 root.style.letterSpacing = state.spacing ? '0.035em' : 'normal'; 71 root.style.wordSpacing = state.spacing ? '0.12em' : 'normal'; 72 } 73 74 for (var i = 0; i < 3; i++) { 75 var tabBtn = document.querySelector('[data-mw-text-step="' + i + '"]'); 76 var active = state.textStep === i; 77 setBtnColors(tabBtn, active ? B.tx : B.sf, active ? B.bg : B.tx, active); 78 if (tabBtn) tabBtn.style.font = "700 " + tSizes[i] + " 'Source Sans 3',sans-serif"; 79 } 80 81 var cS = onOff(B, state.contrast); 82 var mS = onOff(B, state.reduceMotion); 83 var spS = onOff(B, state.spacing); 84 var pS = onOff(B, state.plain); 85 setBtnColors(document.querySelector('[data-mw-a11y-contrast]'), cS.bg, cS.fg, state.contrast); 86 setBtnColors(document.querySelector('[data-mw-a11y-motion]'), mS.bg, mS.fg, state.reduceMotion); 87 setBtnColors(document.querySelector('[data-mw-a11y-spacing]'), spS.bg, spS.fg, state.spacing); 88 setBtnColors(document.querySelector('[data-mw-a11y-plain]'), pS.bg, pS.fg, state.plain); 89 90 var darkBtn = document.querySelector('[data-mw-dark-toggle]'); 91 if (darkBtn) { 92 darkBtn.setAttribute('aria-pressed', B.dark ? 'true' : 'false'); 93 darkBtn.textContent = B.modeLabel; 94 } 95 } 96 97 function applyPlainBlock() { 98 var block = document.getElementById('b2lPlainBlock'); 99 if (block) block.hidden = !state.plain; 100 } 101 102 function gdprText(lang) { 103 if (lang === 'de') return { 104 lang: 'de', aria: 'Cookie-Einwilligung', 105 title: 'Datenschutz, Ihre Einwilligung', 106 body: 'Wir verwenden notwendige Cookies für den Betrieb dieser Website. Optionale Analyse-Cookies setzen wir ausschlieÃlich mit Ihrer ausdrücklichen Einwilligung nach Art. 6 Abs. 1 lit. a DSGVO. Sie können Ihre Einwilligung jederzeit mit Wirkung für die Zukunft widerrufen.', 107 privacy: 'Datenschutzerklärung', imprint: 'Impressum', 108 settings: 'Einstellungen', reject: 'Alle ablehnen', accept: 'Alle akzeptieren', 109 c1t: 'Notwendig (immer aktiv)', c1b: 'Sitzung, Spracheinstellung und Barrierefreiheits-Einstellungen. Ohne diese funktioniert die Website nicht.', 110 c2t: 'Analyse (optional)', c2b: 'Seitenaufrufe, Referrer, Gerätetyp und Verweildauer, um das Angebot zu verbessern. Nur nac
110h Ihrer Zustimmung.', 111 c3t: 'Ihre Rechte', c3b: 'Auskunft, Berichtigung, Löschung, Widerspruch und Beschwerde bei der Aufsichtsbehörde. Kontakt: [email protected]' 112 }; 113 return { 114 lang: 'en', aria: 'Cookie consent', 115 title: 'Your privacy, your choice', 116 body: 'We use essential cookies to run this website. Optional analytics cookies are set only with your explicit consent under Art. 6(1)(a) GDPR. You can withdraw consent at any time with effect for the future.', 117 privacy: 'Privacy Policy', imprint: 'Imprint', 118 settings: 'Settings', reject: 'Reject all', accept: 'Accept all', 119 c1t: 'Essential (always on)', c1b: 'Session, language choice and accessibility preferences. The site cannot work without these.', 120 c2t: 'Analytics (optional)', c2b: 'Page views, referrer, device type and time on page, so we can improve the service. Only after you agree.', 121 c3t: 'Your rights', c3b: 'Access, rectification, erasure, objection and complaint to a supervisory authority. Contact: [email protected]' 122 }; 123 } 124 125 function setText(id, text) { 126 var el = document.getElementById(id); 127 if (el) el.textContent = text; 128 } 129 130 /*function renderGdpr() { 131 var banner = document.getElementById('b2lGdprBanner'); 132 if (!banner) return; 133 consentChoice 134 if (!state.consent) { 135 banner.hidden = true; 136 return; 137 } 138 banner.hidden = false; 139 140 var gdpr = gdprText(state.lang === 'de' ? 'de' : 'en'); 141 banner.setAttribute('aria-label', gdpr.aria); 142 banner.setAttribute('lang', gdpr.lang); 143 setText('b2lGdprTitle', gdpr.title); 144 setText('b2lGdprBody', gdpr.body); 145 setText('b2lGdprPrivacyLink', gdpr.privacy); 146 setText('b2lGdprImprintLink', gdpr.imprint); 147 setText('b2lGdprSettingsBtn', gdpr.settings); 148 setText('b2lGdprRejectBtn', gdpr.reject); 149 setText('b2lGdprAcceptBtn', gdpr.accept); 150 setText('b2lGdprC1t', gdpr.c1t); 151 setText('b2lGdprC1b', gdpr.c1b); 152 setText('b2lGdprC2t', gdpr.c2t); 153 setText('b2lGdprC2b', gdpr.c2b); 154 setText('b2lGdprC3t', gdpr.c3t); 155 setText('b2lGdprC3b', gdpr.c3b); 156 157 var settingsBtn = document.getElementById('b2lGdprSettingsBtn'); 158 if (settingsBtn) settingsBtn.setAttribute('aria-expanded', state.prefsOpen ? 'true' : 'false'); 159 160 var prefs = document.getElementById('b2lGdprPrefs'); 161 if (prefs) prefs.hidden = !state.prefsOpen; 162 }*/ 163 164 /*function consentChoice(choice) { 165 state.consent = false; 166 state.prefsOpen = false; 167 try { localStorage.setItem('b2l_consent', choice); } catch (e) {} 168 try { if (window.LogThis && window.LogThis.trackConsent) window.LogThis.trackConsent(choice); } catch (e) {} 169 renderGdpr(); 170 }*/ 171 172 /*function bindEvents() { 173 for (var i = 0; i < 3; i++) { 174 (function (step) { 175 var btn = document.querySelector('[data-mw-text-step="' + step + '"]'); 176 if (btn) btn.addEventListener('click', function () { 177 state.textStep = step; 178 applyTheme(); 179 log('a11y_text_size', { step: step + 1 }); 180 }); 181 })(i); 182 } 183 184 var contrastBtn = document.querySelector('[data-mw-a11y-contrast]'); 185 if (contrastBtn) contrastBtn.addEventListener('click', function () { 186 state.contrast = !state.contrast; 187 applyTheme(); 188 log('a11y_contrast', { on: state.contrast }); 189 }); 190 191 var motionBtn = document.querySelector('[data-mw-a11y-motion]'); 192 if (motionBtn) motionBtn.addEventListener('click', function () { 193 state.reduceMotion = !state.reduceMotion; 194 applyTheme(); 195 log('a11y_reduce_motion', { on: state.reduceMotion }); 196 }); 197 198 var spacingBtn = document.querySelector('[data-mw-a11y-spacing]'); 199 if (spacingBtn) spacingBtn.addEventListener('click', function () { 200 state.spacing = !state.spacing; 201 applyTheme(); 202 log('a11y_spacing', { on: state.spacing }); 203 }); 204 205 var plainBtn = document.querySelector('[data-mw-a11y-plain]'); 206 if (plainBtn) plainBtn.addEventListener('click', function () { 207 state.plain = !state.plain; 208 applyTheme(); 209 applyPlainBlock(); 210 log('a11y_plain_language', { on: state.plain }); 211 }); 212 213 var darkBtn = document.querySelector('[data-mw-dark-toggle]'); 214 if (darkBtn) darkBtn.addEventListener('click', function () { 215 state.bDark = !state.bDark; 216 applyTheme(); 217 log('theme_toggle', { dark: state.bDark }); 218 }); 219 220 var langSel = document.getElementById('lang-sel'); 221 if (langSel) langSel.addEventListener('change', function (e) { 222 var v = e.target.value; 223 state.lang = v;
224 try { localStorage.setItem('b2l_lang', v); } catch (err) {} 225 renderGdpr(); 226 log('language_change', { language: v }); 227 }); 228 229 var settingsBtn = document.getElementById('b2lGdprSettingsBtn'); 230 if (settingsBtn) settingsBtn.addEventListener('click', function () { 231 state.prefsOpen = !state.prefsOpen; 232 renderGdpr(); 233 }); 234 235 var rejectBtn = document.getElementById('b2lGdprRejectBtn'); 236 if (rejectBtn) rejectBtn.addEventListener('click', function () { consentChoice('rejected'); }); 237 238 var acceptBtn = document.getElementById('b2lGdprAcceptBtn'); 239 if (acceptBtn) acceptBtn.addEventListener('click', function () { consentChoice('accepted'); }); 240 }*/ 241 242 function renderGdpr() { 243 var banner = document.getElementById('b2lGdprBanner'); 244 if (!banner) return; 245 246 if (!state.consent) { 247 $('#b2lGdprBanner').prop('hidden', true).hide(); 248 return; 249 } 250 251 $('#b2lGdprBanner').prop('hidden', false).show(); 252 253 var gdpr = gdprText(state.lang === 'de' ? 'de' : 'en'); 254 255 banner.setAttribute('aria-label', gdpr.aria); 256 banner.setAttribute('lang', gdpr.lang); 257 258 setText('b2lGdprTitle', gdpr.title); 259 setText('b2lGdprBody', gdpr.body); 260 setText('b2lGdprPrivacyLink', gdpr.privacy); 261 setText('b2lGdprImprintLink', gdpr.imprint); 262 setText('b2lGdprSettingsBtn', gdpr.settings); 263 setText('b2lGdprRejectBtn', gdpr.reject); 264 setText('b2lGdprAcceptBtn', gdpr.accept); 265 266 setText('b2lGdprC1t', gdpr.c1t); 267 setText('b2lGdprC1b', gdpr.c1b); 268 setText('b2lGdprC2t', gdpr.c2t); 269 setText('b2lGdprC2b', gdpr.c2b); 270 setText('b2lGdprC3t', gdpr.c3t); 271 setText('b2lGdprC3b', gdpr.c3b); 272 273 var settingsBtn = document.getElementById('b2lGdprSettingsBtn'); 274 if (settingsBtn) { 275 settingsBtn.setAttribute( 276 'aria-expanded', 277 state.prefsOpen ? 'true' : 'false' 278 ); 279 } 280 281 var prefs = document.getElementById('b2lGdprPrefs'); 282 if (prefs) { 283 prefs.hidden = !state.prefsOpen; 284 } 285 } 286 287 function consentChoice(choice) { 288 state.consent = false; 289 state.prefsOpen = false; 290 291 try { 292 localStorage.setItem('b2l_consent', choice); 293 } catch (e) { } 294 295 try { 296 if (window.LogThis && window.LogThis.trackConsent) { 297 window.LogThis.trackConsent(choice); 298 } 299 } catch (e) { } 300 301 $('#b2lGdprBanner').prop('hidden', true).hide(); 302 } 303 function bindEvents() { 304 $(document).on('click', '[data-mw-text-step]', function () { 305 var step = parseInt($(this).attr('data-mw-text-step'), 10); 306 if (isNaN(step)) return; 307 308 state.textStep = step; 309 applyTheme(); 310 log('a11y_text_size', { step: step + 1 }); 311 }); 312 313 $(document).on('click', '[data-mw-a11y-contrast]', function () { 314 state.contrast = !state.contrast; 315 applyTheme(); 316 log('a11y_contrast', { on: state.contrast }); 317 }); 318 319 $(document).on('click', '[data-mw-a11y-motion]', function () { 320 state.reduceMotion = !state.reduceMotion; 321 applyTheme(); 322 log('a11y_reduce_motion', { on: state.reduceMotion }); 323 }); 324 325 $(document).on('click', '[data-mw-a11y-spacing]', function () { 326 state.spacing = !state.spacing; 327 applyTheme(); 328 log('a11y_spacing', { on: state.spacing }); 329 }); 330 331 $(document).on('click', '[data-mw-a11y-plain]', function () { 332 state.plain = !state.plain; 333 applyTheme(); 334 applyPlainBlock(); 335 log('a11y_plain_language', { on: state.plain }); 336 }); 337 338 $(document).on('click', '[data-mw-dark-toggle]', function () { 339 state.bDark = !state.bDark; 340 applyTheme(); 341 log('theme_toggle', { dark: state.bDark }); 342 }); 343 344 $(document).on('change', '#lang-sel', function () { 345 var v = $(this).val(); 346 state.lang = v; 347 348 try { 349 localStorage.setItem('b2l_lang', v); 350 } catch (err) { } 351
352 renderGdpr(); 353 log('language_change', { language: v }); 354 }); 355 356 $(document).on('click', '#b2lGdprSettingsBtn', function (e) { 357 e.preventDefault(); 358 359 state.prefsOpen = !state.prefsOpen; 360 361 renderGdpr(); 362 }); 363 364 $(document).on('click', '#b2lGdprRejectBtn', function (e) { 365 e.preventDefault(); 366 367 consentChoice('rejected'); 368 }); 369 370 $(document).on('click', '#b2lGdprAcceptBtn', function (e) { 371 e.preventDefault(); 372 373 consentChoice('accepted'); 374 }); 375 } 376 377 function init() { 378 document.title = 'Home · book2look'; 379 380 syncDarkFlag(); 381 382 try { 383 var stored = localStorage.getItem('b2l_consent'); 384 if (stored === 'accepted' || stored === 'rejected') state.consent = false; 385 var pref = localStorage.getItem('b2l_lang'); 386 var nav = (navigator.language || 'en').toLowerCase(); 387 state.lang = pref || (nav.indexOf('de') === 0 ? 'de' : nav.slice(0, 2)); 388 } catch (e) {} 389 390 try { 391 if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) state.reduceMotion = true; 392 } catch (e) {} 393 394 bindEvents(); 395 applyTheme(); 396 applyPlainBlock(); 397 renderGdpr(); 398 } 399 400 if (document.readyState === 'loading') { 401 document.addEventListener('DOMContentLoaded', init); 402 } else { 403 init(); 404 } 405})();
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.