PageSourceSearch

https://book2look.de/Content/js/masterwall-chrome.js

js book2look.de collected 2026-10-02 09:56:56 UTC 14,961 bytes, 405 lines download raw bytes

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.