PageSourceSearch

https://www.schlagerradio.de/wp-content/themes/ella-radio-theme/assets/js/accessibility.js?ver=1.6.6

js schlagerradio.de collected 2026-10-02 14:31:59 UTC 15,765 bytes, 408 lines download raw bytes

1/**
2 * Accessibility Widget
3 * Ella Radio Theme
4 */
5
6(function() {
7    'use strict';
8    
9    // Initialize flag to prevent multiple initializations
10    let isInitialized = false;
11    
12    // State
13    const state = {
14        fontSize: 100,
15        highContrast: false,
16        readingMode: false,
17        highlightLinks: false,
18        reduceMotion: false
19    };
20    
21    // Load saved settings
22    function loadSettings() {
23        const saved = localStorage.getItem('ella_accessibility_settings');
24        if (saved) {
25            Object.assign(state, JSON.parse(saved));
26            applySettings();
27        }
28    }
29    
30    // Save settings
31    function saveSettings() {
32        localStorage.setItem('ella_accessibility_settings', JSON.stringify(state));
33    }
34    
35    // Apply all settings
36    function applySettings() {
37        applyFontSize();
38        applyHighContrast();
39        applyReadingMode();
40        applyLinkHighlight();
41        applyReduceMotion();
42    }
43    
44    // Font Size
45    function applyFontSize() {
46        document.documentElement.style.fontSize = state.fontSize + '%';
47        const display = document.querySelector('.font-size-display');
48        if (display) display.textContent = state.fontSize + '%';
49    }
50    
51    function changeFontSize(delta) {
52        state.fontSize = Math.max(80, Math.min(150, state.fontSize + delta));
53        applyFontSize();
54        saveSettings();
55    }
56    
57    // High Contrast
58    function applyHighContrast() {
59        document.body.classList.toggle('high-contrast', state.highContrast);
60        updateToggle('high-contrast-toggle', state.highContrast);
61    }
62    
63    // Reading Mode
64    function applyReadingMode() {
65        document.body.classList.toggle('reading-mode', state.readingMode);
66        updateToggle('reading-mode-toggle', state.readingMode);
67    }
68    
69    // Link Highlight
70    function applyLinkHighlight() {
71        document.body.classList.toggle('highlight-links', state.highlightLinks);
72        updateToggle('highlight-links-toggle', state.highlightLinks);
73    }
74    
75    // Reduce Motion
76    function applyReduceMotion() {
77        document.body.classList.toggle('reduce-motion', state.reduceMotion);
78        updateToggle('reduce-motion-toggle', state.reduceMotion);
79    }
80    
81    // Update toggle button state
82    function updateToggle(id, active) {
83        const toggle = document.getElementById(id);
84        if (toggle) {
85            toggle.classList.toggle('active', active);
86            toggle.setAttribute('aria-checked', active);
87        }
88    }
89    
90    // Create Widget HTML
91    function createWidget() {
92        
93        // Check if widget already exists
94        const existing = document.getElementById('accessibility-widget');
95        if (existing) {
96            return;
97        }
98        
99        const widget = document.createElement('div');
100        widget.id = 'accessibility-widget';
101        widget.className = 'accessibility-widget';
102        widget.setAttribute('role', 'dialog');
103        widget.setAttribute('aria-label', 'Barrierefreiheit-Einstellungen');
104        widget.style.display = 'none';
105        
106        widget.innerHTML = `
107            <div class="accessibility-header">
108                <div class="accessibility-title">
109                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
110                        <circle cx="12" cy="12" r="10"/>
111                        <circle cx="12" cy="8" r="2"/>
112                        <path d="M12 14v6M8 18h8"/>
113                    </svg>
114                    <span>Barrierefreiheit</span>
115                </div>
116                <button class="accessibility-reset" id="accessibility-reset" aria-label="Zurücksetzen">
117                    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
118                        <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/>
119                        <path d="M21 3v5h-5"/>
120                    </svg>
121                    Zurücksetzen
122                </button>
123                <button class="accessibility-close" id="accessibility-close" aria-label="Schließen">
124                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
125                        <path d="M18 6L6 18M6 6l12 12"/>
126                    </svg>
127                </button>
128            </div>
129            
130            <div class="accessibility-content">
131                <!-- Font Size -->
132                <div class="accessibility-option">
133                    <div class="accessibility-option-header">
134                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
135                            <path d="M9 4v3h5v12h3V7h5V4H9zm-6 8h3v7h3v-7h3V9H3v3z"/>
136                        </svg>
137                        <span>Schriftgröße</span>
138                    </div>
139                    <div class="font-size-controls">
140                        <button id="font-size-decrease" aria-label="Schrift verkleinern">
141                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
142                                <path d="M5 12h14"/>
143                            </svg>
144                        </button>
145                        <span class="font-size-display">100%</span>
146                        <button id="font-size-increase" aria-label="Schrift vergrößern">
147                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
148                                <path d="M12 5v14M5 12h14"/>
149                            </svg>
150                        </button>
151                    </div>
152                </div>
153                
154                <!-- High Contrast -->
155                <div class="accessibility-option">
156                    <div class="accessibility-option-header">
157                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
158                            <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8v16z"/>
159                        </svg>
160                        <span>Hoher Kontrast</span>
161                    </div>
162                    <button class="accessibility-toggle" id="high-contrast-toggle" role="switch" aria-checked="false">
163                        <span class="toggle-track">
164                            <span class="toggle-thumb"></span>
165                        </span>
166                    </button>
167                </div>
168                
169                <!-- Reading Mode -->
170                <div class="accessibility-option">
171                    <div class="accessibility-option-header">
172                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
173                            <path d="M21 5c-1.11-.35-2.33-.5-3.5-.5-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5S2.45 4.9 1 6v14.65c0 .25.25.5.5.5.1 0 .15-.05.25-.05C3.1 20.45 5.05 20 6.5 20c1.95 0 4.05.4 5.5 1.5 1.35-.85 3.8-1.5 5.5-1.5 1.65 0 3.35.3 4.75 1.05.1.05.15.05.25.05.25 0 .5-.25.5-.5V6c-.6-.45-1.25-.75-2-1zm0 13.5c-1.1-.35-2.3-.5-3.5-.5-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5 1.2 0 2.4.15 3.5.5v11.5z"/>
174                        </svg>
175                        <span>Lesemodus</span>
176                    </div>
177                    <button class="accessibility-toggle" id="reading-mode-toggle" role="switch" aria-checked="false">
178                        <span class="toggle-track">
179                            <span class="toggle-thumb"></span>
180                        </span>
181                    </button>
182                </div>
183                
184                <!-- Highlight Links -->
185                <div class="accessibility-option">
186                    <div class="accessibility-option-header">
187                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
188                            <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/>
189                        </svg>
190                        <span>Links hervorheben</span>
191                    </div>
192                    <button class="accessibility-toggle" id="highlight-links-toggle" role="switch" aria-checked="false">
193                        <span class="toggle-track">
194                            <span class="toggle-thumb"></span>
195                        </span>
196                    </button>
197                </div>
198                
199                <!-- Reduce Motion -->
200                <div class="accessibility-option">
201                    <div class="accessibility-option-header">
202                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
203                            <path d="M18 8h2V6h-2v2zm0 4h2v-2h-2v2zm-2-8v2h2V4h-2zM8 20h2v-2H8v2zm0-4h2v-2H8v2zm8 4h2v-2h-2v2zm-4 0h2v-2h-2v2zm-8 0h2v-2H4v2zm0-4h2v-2H4v2zM2 8h2V6H2v2zm0 4h2v-2H2v2zm8-12v2h2V0h-2zM8 4v2h2V4H8zm-4 0v2h2V4H4z"/>
204                        </svg>
205                        <span>Animationen stoppen</span>
206                    </div>
207                    <button class="accessibility-toggle" id="reduce-motion-toggle" role="switch" aria-checked="false">
208                        <span class="toggle-track">
209                            <span class="toggle-thumb"></span>
210                        </span>
211                    </button>
212                </div>
213            </div>
214            
215            <div class="accessibility-footer">
216                <p>Tastenkürzel: Alt + A (Widget öffnen), Esc (schließen)</p>
217            </div>
218        `;
219        
220        document.body.appendChild(widget);
221    }
222    
223    // Toggle Widget
224    function toggleWidget(e) {
225        
226        if (e) {
227            e.preventDefault();
228            e.stopPropagation();
229        }
230        
231        const widget = document.getElementById('accessibility-widget');
232        
233        if (!widget) {
234            console.error('❌ Widget not found!');
235            return;
236        }
237        
238        if (widget.style.display === 'none') {
239            widget.style.display = 'block';
240            // Don't focus immediately to prevent scroll
241            setTimeout(() => {
242                const firstButton = document.getElementById('font-size-decrease');
243                if (firstButton) firstButton.focus({ preventScroll: true });
244            }, 100);
245        } else {
246            widget.style.display = 'none';
247        }
248    }
249    
250    // Reset all settings
251    function resetSettings() {
252        state.fontSize = 100;
253        state.highContrast = false;
254        state.readingMode = false;
255        state.highlightLinks = false;
256        state.reduceMotion = false;
257        applySettings();
258        saveSettings();
259    }
260    
261    // Event Listeners
262    function initEventListeners() {
263        
264        // Open button in footer - EVENT DELEGATION (funktioniert auch nach AJAX-Navigation)
265        document.addEventListener('click', (e) => {
266            const target = e.target.closest('.footer-column .accessibility-toggle');
267            if (target) {
268                e.preventDefault();
269                e.stopPropagation();
270                toggleWidget(e);
271            }
272        }, true);
273        
274        // Widget buttons - EVENT DELEGATION
275        document.addEventListener('click', (e) => {
276            // Close button
277            if (e.target.closest('#accessibility-close')) {
278                e.preventDefault();
279                toggleWidget(e);
280                return;
281            }
282            
283            // Reset button
284            if (e.target.closest('#accessibility-reset')) {
285                e.preventDefault();
286                resetSettings();
287                return;
288            }
289            
290            // Font size decrease
291            if (e.target.closest('#font-size-decrease')) {
292                e.preventDefault();
293                changeFontSize(-10);
294                return;
295            }
296            
297            // Font size increase
298            if (e.target.closest('#font-size-increase')) {
299                e.preventDefault();
300                changeFontSize(10);
301                return;
302            }
303            
304            // High contrast toggle
305            if (e.target.closest('#high-contrast-toggle')) {
306                e.preventDefault();
307                state.highContrast = !state.highContrast;
308                applyHighContrast();
309                saveSettings();
310                return;
311            }
312            
313            // Reading mode toggle
314            if (e.target.closest('#reading-mode-toggle')) {
315                e.preventDefault();
316                state.readingMode = !state.readingMode;
317                applyReadingMode();
318                saveSettings();
319                return;
320            }
321            
322            // Highlight links toggle
323            if (e.target.closest('#highlight-links-toggle')) {
324                e.preventDefault();
325                state.highlightLinks = !state.highlightLinks;
326                applyLinkHighlight();
327                saveSettings();
328                return;
329            }
330            
331            // Reduce motion toggle
332            if (e.target.closest('#reduce-motion-toggle')) {
333                e.preventDefault();
334                state.reduceMotion = !state.reduceMotion;
335                applyReduceMotion();
336                saveSettings();
337                return;
338            }
339        });
340        
341        // Keyboard shortcut: Alt + A
342        document.addEventListener('keydown', (e) => {
343            if (e.altKey && e.key === 'a') {
344                e.preventDefault();
345                e.stopPropagation();
346                toggleWidget(e);
347            }
348            
349            // Close with Escape
350            if (e.key === 'Escape') {
351                const widget = document.getElementById('accessibility-widget');
352                if (widget && widget.style.display !== 'none') {
353                    e.preventDefault();
354                    toggleWidget(e);
355                }
356            }
357        });
358        
359        // Close when clicking outside - EVENT DELEGATION
360        document.addEventListener('click', (e) => {
361            const widget = document.getElementById('accessibility-widget');
362            const isOpenBtn = e.target.closest('.footer-column .accessibility-toggle');
363            
364            if (widget && widget.style.display !== 'none' && 
365                !widget.contains(e.target) && 
366                !isOpenBtn) {
367                toggleWidget(e);
368            }
369        });
370    }
371    
372    // Initialize
373    function init() {
374        
375        // Prevent multiple initializations
376        if (isInitialized) {
377            return;
378        }
379        
380        try {
381            createWidget();
382            loadSettings();
383            initEventListeners();
384            isInitialized = true;
385            
386            // Check if footer button exists
387            const footerBtn = document.querySelector('.footer-column .accessibility-toggle');
388        } catch (error) {
389            console.error('❌ Error initializing Accessibility Widget:', error);
390        }
391    }
392    
393    // Close widget on Swup navigation
394    document.addEventListener('swup:willReplaceContent', () => {
395        const widget = document.getElementById('accessibility-widget');
396        if (widget) {
397            widget.style.display = 'none';
398        }
399    });
400    
401    // Run on DOM ready
402    if (document.readyState === 'loading') {
403        document.addEventListener('DOMContentLoaded', init);
404    } else {
405        init();
406    }
407    
408})();

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.