PageSourceSearch

https://www.cdslindia.com/eservices/lib/ux4g/ux4g.js

js cdslindia.com collected 2026-10-01 12:03:42 UTC 74,530 bytes, 1,586 lines download raw bytes

1/*!
2* UX4G Accessibility v2.22.0 (https://doc.ux4g.gov.in/)
3* Copyright 2025 The UX4G Authors(Vipul Agarwal, Ershad Alam)
4* Copyright 2025 NeGD, MeitY.
5* Licensed under MIT. 
6*/
7
8(function () {
9    const SETTINGS_KEY = "accessibilitySettings";
10    const prefix = "ux4g-accessibility-";
11
12    // Function to get cookie domain dynamically
13    function getCookieDomain() {
14        const hostname = location.hostname;
15
16        // For localhost or IP addresses, return empty string
17        if (hostname === 'localhost' || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
18            return '';
19        }
20
21        // For regular domains, prepend with dot for cross-subdomain access
22        const parts = hostname.split('.');
23
24        if (parts.length > 1) {
25            return '.' + parts.slice(1).join('.'); // ".example.co.in"
26        }
27    }
28
29    const widgetHTML = `
30    <button tabindex="0"  aria-label="Accessibility Options" aria-haspopup="dialog" aria-controls="uw-main" aria-expanded="false" id="uw-widget-custom-trigger" class="uw-widget-custom-trigger">
31    <div style="background-color:var(--color-dark-blue-1) !important;">
32        <img alt="accessibility icon" loading="lazy"
33            src="data:image/svg+xml,%0A%3Csvg width='32' height='32' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0_1_1506)' fill='%23fff'%3E%3Cpath d='M16 7a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7z'/%3E%3Cpath d='M27 7.05l-.028.008-.026.008a7.112 7.112 0 0 0-.188.055c-1.163.341-6.808 1.933-10.785 1.933-3.696 0-8.83-1.375-10.472-1.842A4.61 4.61 0 0 0 5 7.05c-1.188-.313-2 .893-2 1.996 0 1.092.98 1.612 1.972 1.985v.017l5.95 1.86c.609.232.771.47.85.677.259.662.053 1.972-.02 2.43l-.363 2.812L9.378 29.84l-.017.092-.014.08c-.145 1.009.596 1.988 2 1.988 1.225 0 1.766-.846 2-1.996.234-1.15 1.75-9.848 2.625-9.848s2.677 9.848 2.677 9.848c.235 1.15.775 1.996 2 1.996 1.408 0 2.15-.984 2-1.996a3.591 3.591 0 0 0-.047-.254l-2.04-10.92-.361-2.813c-.262-1.638-.052-2.18.02-2.306a.07.07 0 0 0 .005-.01c.067-.125.375-.405 1.092-.674l5.58-1.95c.034-.01.068-.02.101-.033 1-.375 2-.894 2-1.996 0-1.102-.811-2.31-1.999-1.998z'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0_1_1506'%3E%3Cpath fill='%23fff' d='M0 0h32v32H0z'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E"
34        />
35        <label class="short-key">Ctrl+F2</label>    
36    </div>
37    <span>Accessibility Options</span> 
38</button>
39
40<div class="uwaw uw-light-theme gradient-head uwaw-initial paid_widget" id="uw-main" role="dialog" aria-modal="true" aria-labelledby="uw-heading">
41    <div class="relative second-panel">
42        <h2 id="uw-heading">Accessibility options <span class="inner-short-key">Ctrl+F2</span></h2>
43        <button type="button" aria-label="Close main navigation panel" class="uwaw-close" tabindex="0"></button>
44    </div>
45    <div class="uwaw-body">
46        <div class="h-scroll">
47            <div class="uwaw-features">
48            <div class="uwaw-features__item reset-feature" id="featureItem">
49                    <button aria-label="Bigger Text" tabindex="0" id="btn-s9" class="uwaw-features__item__i">
50                        <span class="uwaw-features__item__icon">
51                            <span class="ux4g-icon icon-bigger-text" role="img" aria-label="Bigger text icon" aria-hidden="true" aria-pressed="false"></span>
52                        </span>
53                        <span class="uwaw-features__item__name">Bigger Text</span>
54                        <div class="uwaw-features__item__steps reset-steps" id="featureSteps">
55                            <span class="step uwaw-features__step"></span>
56                            <span class="step uwaw-features__step"></span>
57                            <span class="step uwaw-features__step"></span>
58                            <span class="step uwaw-features__step"></span>
59                        </div>
60                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon"  aria-live="polite" role="status"></span>
61                    </button>
62                </div>
63                <div class="uwaw-features__item reset-feature" id="featureItem-st">
64                    <button aria-label="Smaller Text" tabindex="0" id="btn-s17" class="uwaw-features__item__i" disabled>
65                        <span class="uwaw-features__item__icon">
66                            <span class="ux4g-icon icon-smaller-text" role="img" aria-label="Smaller text icon" aria-hidden="true" aria-pressed="false"></span>
67                        </span>
68                        <span class="uwaw-features__item__name">Smaller Text</span>
69                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIconSt"  aria-live="polite" role="status"></span>
70                    </button>
71                </div>
72
73                 <div class="uwaw-features__item reset-feature" id="featureItem-ts">
74                    <button aria-label="Text Spacing" tabindex="0" id="btn-s13" class="uwaw-features__item__i">
75                        <span class="uwaw-features__item__icon">
76                            <span class="ux4g-icon icon-text-spacing"  role="img" aria-label="Text spacing icon" aria-hidden="true" aria-pressed="false"></span>
77                        </span>
78                        <span class="uwaw-features__item__name">Text Spacing</span>
79                        <div class="uwaw-features__item__steps reset-steps" id="featureSteps-ts">
80                            <span class="step uwaw-features__step"></span>
81                            <span class="step uwaw-features__step"></span>
82                            <span class="step uwaw-features__step"></span>
83                        </div>
84                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-ts"  aria-live="polite" role="status"></span>
85                    </button>
86                </div>
87
88                 <div class="uwaw-features__item reset-feature" id="featureItem-lh">
89                    <button aria-label="Line Height" tabindex="0" id="btn-s12" class="uwaw-features__item__i">
90                        <span class="uwaw-features__item__icon">
91                            <span class="ux4g-icon icon-line-hight" role="img" aria-label="Line height icon" aria-hidden="true" aria-pressed="false"></span>
92                        </span>
93                        <span class="uwaw-features__item__name">Line Height</span>
94                        <div class="uwaw-features__item__steps reset-steps" id="featureSteps-lh">
95                            <span class="step uwaw-features__step"></span>
96                            <span class="step uwaw-features__step"></span>
97                            <span class="step uwaw-features__step"></span>
98                            <span class="step uwaw-features__step"></span>
99                        </div>
100                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-lh"  aria-live="polite" role="status"></span>
101                    </button>
102                </div>
103
104                 <div class="uwaw-features__item reset-feature" id="featureItem-df">
105                    <button aria-label="Dyslexia Friendly disabled" aria-pressed="false" tabindex="0" id="btn-df" class="uwaw-features__item__i">
106                        <span class="uwaw-features__item__icon">
107                            <span class="ux4g-icon icon-dyslexia-font" role="img" aria-label="Dyslexia friendly font icon" aria-hidden="true"></span>
108                        </span>
109                        <span class="uwaw-features__item__name">Dyslexia Friendly</span>
110                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-df"  aria-live="polite" role="status"></span>
111                    </button>
112                </div>
113                <div class="uwaw-features__item reset-feature" id="featureItem-adhd">                    
114                    <button aria-label="ADHD Mode" aria-pressed="false" tabindex="0" id="btn-adhd" class="uwaw-features__item__i">
115                        <span class="uwaw-features__item__icon">
116                            <span class="ux4g-icon icon-adhd-friendly" role="img" aria-label="Icon ADHD Friendly icon" aria-hidden="true"></span>
117                        </span>
118                        <span class="uwaw-features__item__name">ADHD Mode</span>
119                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-adhd" aria-live="polite" role="status"></span>
120                    </button>
121                </div>
122                <!-- Saturate Widget -->
123                <div class="uwaw-features__item reset-feature" id="featureItem-saturate">
124                    <button aria-label="Saturate Colors" aria-pressed="false" tabindex="0" id="btn-saturate" class="uwaw-features__item__i">
125                        <span class="uwaw-features__item__icon">
126                            <span class="ux4g-icon icon-saturate" role="img" aria-label="Saturate icon" aria-hidden="true" id="saturate-text-0"></span>
127                            <span class="ux4g-icon icon-lowsaturate" role="img" aria-label="Low Saturate icon" aria-hidden="true" id="saturate-text-1" style="display: none;"></span>
128                            <span class="ux4g-icon icon-highsaturate" role="img" aria-label="High Saturate colors icon" aria-hidden="true" id="saturate-text-2" style="display: none;"></span>
129                            <span class="ux4g-icon icon-desaturate" role="img" aria-label="Desaturate icon" aria-hidden="true" id="saturate-text-3" style="display: none;"></span>
130
131                        </span>
132                        <div id="feature-container">
133                            <span class="uwaw-features__item__name saturate-text" id="saturate-detail-text-0">Saturation</span>
134                            <span class="uwaw-features__item__name saturate-text" id="saturate-detail-text-1" style="display: none;">Low Saturation</span>
135                            <span class="uwaw-features__item__name saturate-text" id="saturate-detail-text-2" style="display: none;">High Saturation</span>
136                            <span class="uwaw-features__item__name saturate-text" id="saturate-detail-text-3" style="display: none;">Desaturate</span>
137                        </div>
138                        <div class="uwaw-features__item__steps reset-steps" id="featureStepsSaturate">
139                            <span class="step uwaw-features__step"></span>
140                            <span class="step uwaw-features__step"></span>
141                            <span class="step uwaw-features__step"></span>
142                        </div>
143                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-saturate"  aria-live="polite" role="status"></span>
144                    </button>
145                </div>
146                <!-- Invert Colors Widget -->
147                <div class="uwaw-features__item reset-feature" id="featureItem-ic">
148                    <button aria-label="Invert Colors" aria-pressed="false" tabindex="0" id="btn-invert" class="uwaw-features__item__i">
149                        <span class="uwaw-features__item__icon">
150                            <span class="ux4g-icon icon-invert" role="img" aria-label="Invert colors icon" aria-hidden="true"></span>
151                        </span>
152                        <span class="uwaw-features__item__name">Invert Colors</span>
153                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-ic"  aria-live="polite" role="status"></span>
154                    </button>
155                </div>
156                <div class="uwaw-features__item reset-feature" id="featureItem-ht">
157                    <button aria-pressed="false" aria-label="Highlight Links" tabindex="0" id="btn-s10" class="uwaw-features__item__i">
158                        <span class="uwaw-features__item__icon">
159                            <span class="ux4g-icon icon-highlight-links" role="img" aria-label="Highlight links icon" aria-hidden="true"></span>
160                        </span>
161                        <span class="uwaw-features__item__name">Highlight Links</span>
162                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-ht"  aria-live="polite" role="status"></span>
163                    </button>
164                </div>
165                
166                <div class="uwaw-features__item reset-feature" id="featureItem_sp">
167                    <button aria-pressed="false" aria-label="Text To Speech" tabindex="0" id="speak" class="uwaw-features__item__i">
168                        <span class="uwaw-features__item__icon">
169                            <span class="ux4g-icon icon-speaker" role="img" aria-label="Text to speech icon" aria-hidden="true" aria-pressed="false"></span>
170                        </span>
171                        <span class="uwaw-features__item__name">Text To Speech</span>
172                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon_sp"  aria-live="polite" role="status"></span>
173                    </button>
174                </div>
175               
176                <div class="uwaw-features__item reset-feature" id="featureItem-Cursor">
177                    <button aria-label="Cursor Bigger" aria-pressed="false" tabindex="0" id="btn-cursor" class="uwaw-features__item__i">
178                        <span class="uwaw-features__item__icon">
179                            <span class="ux4g-icon icon-cursor" role="img" aria-label="Cursor bigger icon" aria-hidden="true"></span>
180                        </span>
181                        <span class="uwaw-features__item__name">Cursor</span>
182                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-cursor"  aria-live="polite" role="status"></span>
183                    </button>
184                </div>
185                
186                <div class="uwaw-features__item reset-feature" id="featureItem-animate">
187                    <button aria-label="Pause Animation" aria-pressed="false" tabindex="0" id="btn-animation" class="uwaw-features__item__i">
188                        <span class="uwaw-features__item__icon">
189                            <span class="ux4g-icon icon-animation-pause" role="img" aria-label="Pause Animation icon" aria-hidden="true"></span>
190                        </span>
191                        <span class="uwaw-features__item__name">Pause Animation</span>
192                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-animate"  aria-live="polite" role="status"></span>
193                    </button>
194                </div>
195                 <div class="uwaw-features__item reset-feature" id="featureItem-hi">
196                    <button aria-label="Hide Images" aria-pressed="false" tabindex="0" id="btn-s11" class="uwaw-features__item__i">
197                        <span class="uwaw-features__item__icon">
198                            <span class="ux4g-icon icon-hide-images" role="img" aria-label="Hide images icon" aria-hidden="true"></span>
199                        </span>
200                        <span class="uwaw-features__item__name">Hide Images</span>
201                        <span class="tick-active uwaw-features__item__enabled reset-tick" id="tickIcon-hi"  aria-live="polite" role="status"></span>
202                    </button>
203                </div>
204
205
206               
207            </div>
208        </div>
209        
210        <!-- Reset Button -->
211    </div>
212    <div class="reset-panel">
213        <!-- copyright accessibility bar -->
214        <div class="copyrights-accessibility">
215            <button aria-label="Reset All Settings" tabindex="0" class="btn-reset-all" id="reset-all">
216                <div class="reset-icon"></div>
217                <div class="reset-btn-text">Reset All Settings</div>
218            </button>
219        </div>
220    </div>
221</div>`;
222    document.body.insertAdjacentHTML('beforeend', widgetHTML);
223    document.addEventListener("DOMContentLoaded", loadSettings);
224    document.addEventListener("scroll", function () {
225        detectRouteChange()
226    })
227    document.addEventListener('DOMContentLoaded', function () {
228        const menu = document.getElementById('uw-main');
229        menu.inert = true;
230    });
231    document.getElementById('uw-widget-custom-trigger')
232        .addEventListener('click', function () {
233            const menu = document.getElementById('uw-main');
234            menu.inert = false;
235            menu.style.left = '0';
236            menu.focus();
237        });
238
239    document.getElementById('open-the-accessibility-menu')
240        .addEventListener('click', function () {
241            const menu = document.getElementById('uw-main');
242            const btn = document.getElementById('open-the-accessibility-menu');
243
244            if (menu) {
245                menu.inert = false;
246                menu.style.left = '0';
247                menu.focus();
248            }
249
250            if (btn) {
251                btn.style.display = 'none';
252            }
253        });
254
255    function closeMain() {
256        document.getElementById('uw-main').style.left = '-530px'
257        const btn = document.getElementById('open-the-accessibility-menu');
258        btn.style.display = 'flex';
259    }
260    document.addEventListener('DOMContentLoaded', function () {
261        const closeButtons = document.querySelectorAll('.uwaw-close');
262        closeButtons.forEach(function (button) {
263            button.addEventListener('click', closeMain)
264        })
265    });
266    let fontSizeCount = 0;
267    let lineHeightCount = 0;
268    let textSpacingCount = 0;
269    let saturateCount = 0;
270    let lastPath = window.location.pathname;
271    let screenReader = !1;
272    const fontSizeSpans = document.querySelectorAll('#featureSteps span');
273    const lineHeightSpans = document.querySelectorAll('#featureSteps-lh span');
274    const textSpacingSpans = document.querySelectorAll('#featureSteps-ts span');
275    const saturateSpans = document.querySelectorAll('#featureStepsSaturate span');
276    let speechSynthesisInstance = window.speechSynthesis;
277    let tabPressCount = 0;
278    let adhdActive = false;
279
280    // Create the reading mask
281    const readingMask = document.createElement('div');
282    readingMask.className = 'reading-mask-horizontal';
283
284    document.body.appendChild(readingMask);
285
286    // Track cursor Y position
287    let cursorPositionY = 0;
288
289    document.addEventListener('mousemove', (e) => {
290        cursorPositionY = e.clientY;
291        updateHighlightBarPosition();
292        readingMask.style.setProperty('--y', `${e.clientY}px`);
293    });
294
295    window.addEventListener('wheel', () => {
296        updateHighlightBarPosition();
297    });
298
299    function updateHighlightBarPosition() {
300        if (adhdActive) {
301            readingMask.style.top = '0';
302        }
303    }
304
305    function speakText(text) {
306        if (!text.trim()) return;
307        const utterance = new SpeechSynthesisUtterance(text);
308        utterance.lang = "en-US";
309        utterance.rate = 1;
310        speechSynthesisInstance.cancel();
311        speechSynthesisInstance.speak(utterance)
312    }
313    // document.addEventListener("keydown", (event) => {
314    //     if (event.key === "Tab") {
315    //         tabPressCount++;
316    //         if (tabPressCount === 2) {
317    //             speakText("Press Enter to open accessibility menu.")
318    //         }
319    //     } else if (event.key === "Enter" && tabPressCount === 2) {
320    //         speakText("Opening accessibility menu.");
321    //         tabPressCount = 0
322    //     }
323    // });
324
325    // new this is for open panel on tab 
326
327
328
329
330    document.addEventListener("DOMContentLoaded", () => {
331        const accessibilityBtn = document.getElementById("open-the-accessibility-menu");
332        const accessibilityMenu = document.getElementById("uw-main");
333        const overlay = document.getElementById("accessibility-overlay");
334        const closeBtn = document.getElementById("close-uw-main");
335
336        if (!accessibilityBtn || !accessibilityMenu || !overlay) {
337            // console.warn("Missing required elements.");
338            return;
339        }
340
341        let hasSpoken = false;
342        let menuOpened = false;
343        let lastFocusedElement = null;
344        let tabPressCount = 0;
345        let menuClosedByEscape = false; // NEW FLAG
346
347        function speakText(text) {
348            speechSynthesis.cancel();
349            const utterance = new SpeechSynthesisUtterance(text);
350            speechSynthesis.speak(utterance);
351        }
352
353        // ============= Menu Control =============
354        function openMenu() {
355            lastFocusedElement = document.activeElement;
356
357            accessibilityMenu.style.left = "0";
358            menuOpened = true;
359            menuClosedByEscape = false; // Reset when menu is opened
360
361            const focusableElements = accessibilityMenu.querySelectorAll(
362                'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
363            );
364            const firstFocusable =
365                focusableElements.length > 0 ? focusableElements[0] : accessibilityMenu;
366
367            if (firstFocusable === accessibilityMenu) {
368                accessibilityMenu.setAttribute("tabindex", "-1");
369            }
370            firstFocusable.focus();
371            tabPressCount = 0;
372        }
373
374        function closeMenu() {
375            accessibilityMenu.style.left = "-530px";
376            accessibilityBtn.style.display = 'flex';
377            tabPressCount = 0;
378            menuOpened = false;
379            menuClosedByEscape = true; // Mark as closed by Escape or manual close
380
381            if (lastFocusedElement) {
382                lastFocusedElement.focus();
383            }
384        }
385
386        accessibilityBtn.addEventListener("keydown", (e) => {
387            if (e.key === "Enter" || e.key === " ") {
388                e.preventDefault();
389                openMenu();
390            }
391        });
392
393        accessibilityBtn.addEventListener("click", openMenu);
394
395        if (closeBtn) {
396            closeBtn.addEventListener("click", closeMenu);
397        }
398
399        document.addEventListener("keydown", (e) => {
400            if (e.key === "Escape") {
401                closeMenu();
402            }
403        });
404
405        overlay.addEventListener("click", (e) => {
406            if (e.target === overlay) {
407                closeMenu();
408            }
409        });
410
411        // == Ctrl + F2 (toggle) ==
412        document.addEventListener("keydown", (e) => {
413            if (e.ctrlKey && e.key === "F2") {
414                e.preventDefault();
415                if (menuOpened) {
416                    closeMenu();
417                } else {
418                    openMenu();
419                }
420            }
421        });
422    });
423
424
425
426
427
428    // this is for open the accessibility menu  end here
429
430    document.addEventListener("click", (event) => {
431        tabPressCount = 0;
432        let element = event.target;
433        let clickedText = "";
434        if (element.tagName === "IMG") {
435            clickedText = element.getAttribute("alt") || element.getAttribute("aria-label") || element.getAttribute("title") || "Clickable image"
436        } else {
437            clickedText = element.innerText.trim()
438        }
439        if (clickedText && screenReader) {
440            speakText(clickedText)
441        }
442    });
443    document.addEventListener("mouseup", () => {
444        let selectedText = window.getSelection().toString();
445        if (selectedText && screenReader) {
446            speakText(selectedText)
447        }
448    });
449    document.addEventListener("mouseover", (event) => {
450        let element = event.target;
451        let textToSpeak = "";
452        if (element.tagName === "IMG" && element.closest("A, BUTTON")) {
453            textToSpeak = element.getAttribute("alt") || element.getAttribute("aria-label") || element.getAttribute("title") || "Clickable image"
454        } else if (element.tagName === "A" || element.tagName === "BUTTON" || element.tagName === "INPUT" || element.tagName === "TEXTAREA" || element.hasAttribute("role")) {
455            textToSpeak = element.innerText || element.getAttribute("aria-label") || element.getAttribute("alt") || element.value || "Interactive element"
456        }
457        if (textToSpeak && screenReader) {
458            speechSynthesisInstance.cancel();
459            speakText(textToSpeak)
460        }
461    });
462
463    function toggleTextToSpeech() {
464        const tickIcon = document.getElementById('tickIcon_sp');
465        const button = document.getElementById('featureItem_sp');
466        button.classList.toggle(prefix + 'feature-active');
467        tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex';
468        const speakButton = document.getElementById('speak');
469        speakButton.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
470        screenReader = !screenReader;
471        saveSettings();
472        if (speechSynthesis.speaking) {
473            speechSynthesis.cancel()
474        }
475    }
476    document.addEventListener('DOMContentLoaded', function () {
477        const speakButton = document.getElementById('speak');
478        if (speakButton) {
479            speakButton.addEventListener('click', toggleTextToSpeech)
480        }
481    });
482
483    function applyTextSettings(direction = '+') {
484        let elements = document.querySelectorAll('body > div > *:not(.uwaw)');
485        elements.forEach(el => {
486            let currentZoom = parseFloat(el.style.zoom) || 1;
487            let newZoom;
488
489            if (direction === '+') {
490                newZoom = (currentZoom + 0.1).toFixed(2);
491            } else {
492                newZoom = Math.max(0.1, currentZoom - 0.1).toFixed(2); // Prevent zoom from going below 0.1
493            }
494
495            el.style.setProperty('zoom', newZoom, 'important');
496        });
497    }
498    function announceFontSizeLevel(level) {
499        const increaseBtn = document.getElementById('btn-s9');
500        if (!increaseBtn) return;
501
502        if (level === 0) {
503            increaseBtn.setAttribute('aria-pressed', 'false');
504            increaseBtn.setAttribute('aria-label', 'Bigger Text');
505        } else {
506            increaseBtn.setAttribute('aria-pressed', 'true');
507            increaseBtn.setAttribute(
508                'aria-label',
509                `Bigger Text, level ${level} of 4`
510            );
511        }
512    }
513
514    function announceTextSpacingLevel(level) {
515        const btn = document.getElementById('btn-s13');
516
517        if (!btn) return;
518
519        if (level === 0) {
520            btn.setAttribute('aria-pressed', 'false');
521            btn.setAttribute('aria-label', 'Text Spacing');
522        } else {
523            btn.setAttribute('aria-pressed', 'true');
524            btn.setAttribute(
525                'aria-label',
526                `Text Spacing, level ${level} of 3`
527            );
528        }
529    }
530
531    function announceLineHeightLevel(level) {
532        const btn = document.getElementById('btn-s12');
533
534        if (!btn) return;
535
536        if (level === 0) {
537            btn.setAttribute('aria-pressed', 'false');
538            btn.setAttribute('aria-label', 'Line Height');
539        } else {
540            btn.setAttribute('aria-pressed', 'true');
541            btn.setAttribute(
542                'aria-label',
543                `Line Height, level ${level} of 4`
544            );
545        }
546    }
547
548    function announceSaturationState(stateIndex) {
549        const btn = document.getElementById('btn-saturate');
550
551        if (!btn) return;
552
553        const states = [
554            'Normal saturation',
555            'Low saturation',
556            'High saturation',
557            'Desaturated'
558        ];
559
560        btn.setAttribute('aria-pressed', stateIndex !== 0 ? 'true' : 'false');
561        btn.setAttribute(
562            'aria-label',
563            `Saturation, ${states[stateIndex]}`
564        );
565    }
566
567    function adjustFontSize(data) {
568        if (data === '+1') {
569            fontSizeCount = (fontSizeCount + 1) % 5;
570            applyTextSettings('+');
571        } else {
572            fontSizeCount = (fontSizeCount - 1 + 5) % 5; // ensures no negative values
573            if (fontSizeCount > 0) {
574                applyTextSettings('-');
575            }
576        }
577
578        const button = document.getElementById('featureItem');
579        const tickIcon = document.getElementById('tickIcon');
580        const fontCheck = document.getElementById('featureSteps');
581        const smallerTextBtn = document.getElementById('btn-s17');
582
583        button.classList.add(prefix + 'feature-active');
584
585        saveSettings();
586
587        // Enable or disable Smaller Text button based on fontSizeCount
588        if (fontSizeCount > 0) {
589            smallerTextBtn.disabled = false;
590            smallerTextBtn.setAttribute(
591                'aria-label',
592                'Smaller Text. Decrease text size'
593            )
594        } else {
595            smallerTextBtn.disabled = true;
596            smallerTextBtn.setAttribute(
597                'aria-label',
598                'Smaller Text disabled. Text size is at default'
599            );
600        }
601
602        if (fontSizeCount === 0) {
603            button.classList.toggle(prefix + 'feature-active');
604            tickIcon.style.display = 'none';
605            fontCheck.classList.remove(prefix + 'featureSteps-visible');
606            let elements = document.querySelectorAll('body > div > *:not(.uwaw)');
607            elements.forEach(el => el.style.zoom = 1);
608            fontSizeSpans.forEach(span => span.classList.remove(prefix + 'active'))
609        } else {
610            tickIcon.style.display = 'inline-flex';
611            fontCheck.classList.add(prefix + 'featureSteps-visible');
612            fontSizeSpans.forEach(span => span.classList.remove(prefix + 'active'));
613            fontSizeSpans.forEach((span, index) => {
614                if (index <= fontSizeCount - 1) {
615                    span.classList.add(prefix + 'active')
616                }
617            });
618        }
619        announceFontSizeLevel(fontSizeCount);
620    }
621
622    document.addEventListener('DOMContentLoaded', function () {
623        const btnIncrease = document.getElementById('btn-s9');
624        const btnDecrease = document.getElementById('btn-s17');
625
626        if (btnIncrease) {
627            btnIncrease.addEventListener('click', () => adjustFontSize('+1'));
628        }
629        if (btnDecrease) {
630            btnDecrease.addEventListener('click', () => adjustFontSize('-1'));
631        }
632    });
633
634    function createLineHeightStyles() {
635        // Remove existing line height styles if they exist
636        const existingStyle = document.getElementById('ux4g-line-height-styles');
637        if (existingStyle) {
638            existingStyle.remove();
639        }
640
641        // Create new style element
642        const style = document.createElement('style');
643        style.id = 'ux4g-line-height-styles';
644
645        // Create dynamic CSS class based on current lineHeightCount
646        if (lineHeightCount > 0) {
647            const lineHeightValue = 1.2 + (lineHeightCount * 0.3); // Base 1.2 + incremental increase
648            style.textContent = `
649                .ux4g-line-height {
650                    line-height: ${lineHeightValue} !important;
651                }
652            `;
653        }
654
655        document.head.appendChild(style);
656    }
657
658    // Updated updateLineHeight function to use CSS classes
659    function updateLineHeight() {
660        // Remove existing line height classes from all elements
661        document.querySelectorAll('.ux4g-line-height').forEach((el) => {
662            el.classList.remove('ux4g-line-height');
663        });
664
665        if (lineHeightCount > 0) {
666            // Create/update CSS class
667            createLineHeightStyles();
668
669            // Add class to text elements
670            const textElements = document.querySelectorAll(`
671                p:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
672                h1:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
673                h2:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
674                h3:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
675                h4:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
676                h5:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
677                h6:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
678                div:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
679                span:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
680                li:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
681                td:not(.uwaw *):not(.uwaw):not(.wsmenucontainer),
682                th:not(.uwaw *):not(.uwaw):not(.wsmenucontainer)
683            `);
684
685            // Use requestAnimationFrame for better performance
686            requestAnimationFrame(() => {
687                textElements.forEach((el) => {
688                    // Skip elements that are hidden or have no content
689                    if (el.offsetHeight === 0 || !el.textContent.trim()) return;
690
691                    el.classList.add('ux4g-line-height');
692                });
693            });
694        } else {
695            // Remove the style element if lineHeightCount is 0
696            const existingStyle = document.getElementById('ux4g-line-height-styles');
697            if (existingStyle) {
698                existingStyle.remove();
699            }
700        }
701    }
702
703    function adjustLineHeight() {
704        const button = document.getElementById('featureItem-lh');
705
706        button.classList.add(prefix + 'feature-active');
707        lineHeightCount = (lineHeightCount + 1) % 5;
708
709        if (lineHeightCount !== 0) {
710            updateLineHeight();
711        }
712
713        saveSettings();
714
715        const tickIcon = document.getElementById('tickIcon-lh');
716        const lineHeightCheck = document.getElementById('featureSteps-lh');
717
718        if (lineHeightCount === 0) {
719            button.classList.remove(prefix + 'feature-active');
720            tickIcon.style.display = 'none';
721            lineHeightCheck.classList.remove(prefix + 'featureSteps-visible');
722
723            // Remove classes instead of inline styles
724            document.querySelectorAll('.ux4g-line-height').forEach((el) => {
725                el.classList.remove('ux4g-line-height');
726            });
727
728            // Remove the style element
729            const existingStyle = document.getElementById('ux4g-line-height-styles');
730            if (existingStyle) {
731                existingStyle.remove();
732            }
733
734            lineHeightSpans.forEach(span => span.classList.remove(prefix + 'active'));
735        } else {
736            tickIcon.style.display = 'inline-flex';
737            lineHeightSpans.forEach(span => span.classList.remove(prefix + 'active'));
738            lineHeightSpans.forEach((span, index) => {
739                if (index <= lineHeightCount - 1) {
740                    span.classList.add(prefix + 'active');
741                }
742            });
743            lineHeightCheck.classList.add(prefix + 'featureSteps-visible');
744        }
745        announceLineHeightLevel(lineHeightCount);
746    }
747
748    document.addEventListener('DOMContentLoaded', function () {
749        const lineHeightBtn = document.getElementById('btn-s12');
750        if (lineHeightBtn) {
751            lineHeightBtn.addEventListener('click', adjustLineHeight)
752        }
753    });
754
755    // Add this function to create/update CSS classes dynamically for text spacing
756    function createTextSpacingStyles() {
757        // Remove existing text spacing styles if they exist
758        const existingStyle = document.getElementById('ux4g-text-spacing-styles');
759        if (existingStyle) {
760            existingStyle.remove();
761        }
762
763        // Create new style element
764        const style = document.createElement('style');
765        style.id = 'ux4g-text-spacing-styles';
766
767        // Create dynamic CSS class based on current textSpacingCount
768        if (textSpacingCount > 0) {
769            style.textContent = `
770                .ux4g-text-spacing {
771                    letter-spacing: ${textSpacingCount * 0.12}em !important;
772                    word-spacing: ${textSpacingCount * 0.16}em !important;
773                }
774            `;
775        }
776
777        document.head.appendChild(style);
778    }
779
780    // Updated updateLetterSpacing function to use CSS classes
781    function updateLetterSpacing() {
782        // Remove existing text spacing classes from all elements
783        document.querySelectorAll('.ux4g-text-spacing').forEach((el) => {
784            el.classList.remove('ux4g-text-spacing');
785        });
786
787        if (textSpacingCount > 0) {
788            // Create/update CSS class
789            createTextSpacingStyles();
790
791            // Add class to elements
792            document.querySelectorAll('body > div *:not(.uwaw *):not(.uwaw)').forEach((el) => {
793                el.classList.add('ux4g-text-spacing');
794            });
795        } else {
796            // Remove the style element if textSpacingCount is 0
797            const existingStyle = document.getElementById('ux4g-text-spacing-styles');
798            if (existingStyle) {
799                existingStyle.remove();
800            }
801        }
802    }
803
804    function adjustTextSpacing() {
805        const button = document.getElementById('featureItem-ts');
806        button.classList.add(prefix + 'feature-active');
807        textSpacingCount = (textSpacingCount + 1) % 4;
808
809        if (textSpacingCount > 0) {
810            updateLetterSpacing();
811        }
812
813        saveSettings();
814        const tickIcon = document.getElementById('tickIcon-ts');
815        const textSpacingCheck = document.getElementById('featureSteps-ts');
816
817        if (textSpacingCount <= 0) {
818            button.classList.remove(prefix + 'feature-active');
819            tickIcon.style.display = 'none';
820            textSpacingCheck.classList.remove(prefix + 'featureSteps-visible');
821
822            // Remove classes instead of inline styles
823            document.querySelectorAll('.ux4g-text-spacing').forEach(el => {
824                el.classList.remove('ux4g-text-spacing');
825            });
826
827            // Remove the style element
828            const existingStyle = document.getElementById('ux4g-text-spacing-styles');
829            if (existingStyle) {
830                existingStyle.remove();
831            }
832
833            textSpacingSpans.forEach(span => span.classList.remove(prefix + 'active'))
834        } else {
835            tickIcon.style.display = 'inline-flex';
836            textSpacingSpans.forEach(span => span.classList.remove(prefix + 'active'));
837            textSpacingSpans.forEach((span, index) => {
838                if (index <= textSpacingCount - 1) {
839                    span.classList.add(prefix + 'active')
840                }
841            });
842            textSpacingCheck.classList.add(prefix + 'featureSteps-visible')
843        }
844        announceTextSpacingLevel(textSpacingCount);
845    }
846
847    document.addEventListener('DOMContentLoaded', function () {
848        const spacingBtn = document.getElementById('btn-s13');
849        if (spacingBtn) {
850            spacingBtn.addEventListener('click', adjustTextSpacing)
851        }
852    });
853
854    function toggleHighlightLinks() {
855        const button = document.getElementById('featureItem-ht');
856        const tickIcon = document.getElementById('tickIcon-ht');
857        button.classList.toggle(prefix + 'feature-active');
858        tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex';
859        const highlightBtn = document.getElementById('btn-s10');
860        highlightBtn.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
861        document.body.classList.toggle(prefix + 'highlight-links');
862        let tool = document.querySelector('.uwaw');
863        if (tool) {
864            tool.classList.remove(prefix + 'highlight-links')
865        }
866        saveSettings()
867    }
868    document.addEventListener('DOMContentLoaded', function () {
869        const highlightBtn = document.getElementById('btn-s10');
870        if (highlightBtn) {
871            highlightBtn.addEventListener('click', toggleHighlightLinks)
872        }
873    });
874
875    function toggleDyslexiaMode() {
876        const button = document.getElementById('featureItem-df');
877        const tickIcon = document.getElementById('tickIcon-df');
878        button.classList.toggle(prefix + 'feature-active');
879        tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex';
880        document.body.classList.toggle(prefix + 'dyslexia-mode');
881        const dfButton = document.getElementById('btn-df');
882        dfButton.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
883        saveSettings()
884    }
885    document.addEventListener('DOMContentLoaded', function () {
886        const dyslexiaBtn = document.getElementById('btn-df');
887        if (dyslexiaBtn) {
888            dyslexiaBtn.addEventListener('click', toggleDyslexiaMode)
889        }
890    });
891
892    function hideImages() {
893        const button = document.getElementById('featureItem-hi');
894        const tickIcon = document.getElementById('tickIcon-hi');
895        button.classList.toggle(prefix + 'feature-active');
896        tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex';
897        document.body.classList.toggle(prefix + 'hide-images');
898        const hideImagesBtn = document.getElementById('btn-s11');
899        hideImagesBtn.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
900        saveSettings()
901    }
902    document.addEventListener('DOMContentLoaded', function () {
903        const hideImagesBtn = document.getElementById('btn-s11');
904        if (hideImagesBtn) {
905            hideImagesBtn.addEventListener('click', hideImages)
906        }
907    });
908
909    function changeCursor() {
910        const button = document.getElementById('featureItem-Cursor');
911        const tickIcon = document.getElementById('tickIcon-cursor');
912        button.classList.toggle(prefix + 'feature-active');
913        tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex';
914        document.body.classList.toggle(prefix + 'custom-cursor');
915        const cursorBtn = document.getElementById('btn-cursor');
916        cursorBtn.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
917        saveSettings()
918    }
919    document.addEventListener('DOMContentLoaded', function () {
920        const cursorBtn = document.getElementById('btn-cursor');
921        if (cursorBtn) {
922            cursorBtn.addEventListener('click', changeCursor)
923        }
924    });
925
926    // on scape key press, close the panel
927    document.addEventListener('keydown', function (event) {
928        if (event.key === 'Escape') {
929            const uwMain = document.getElementById('uw-main');
930            if (uwMain) {
931                uwMain.style.left = '-530px';
932            }
933        }
934    });
935
936    function invertColor() {
937        const button = document.getElementById('featureItem-ic');
938        const tickIcon = document.getElementById('tickIcon-ic');
939        button.classList.toggle(prefix + 'feature-active');
940        tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex';
941        document.documentElement.classList.toggle(prefix + "invert-colors");
942        const invertBtn = document.getElementById('btn-invert');
943        invertBtn.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
944        saveSettings()
945    }
946    document.addEventListener('DOMContentLoaded', function () {
947        const invertBtn = document.getElementById('btn-invert');
948        if (invertBtn) {
949            invertBtn.addEventListener('click', invertColor)
950        }
951    });
952
953    function saturateColor() {
954        const button = document.getElementById('featureItem-saturate');
955        const tickIcon = document.getElementById('tickIcon-saturate');
956        const saturateCheck = document.getElementById('featureStepsSaturate');
957
958        // Remove existing saturate classes
959        document.documentElement.classList.remove(prefix + 'saturate-low', prefix + 'saturate-high', prefix + 'saturate-desaturate');
960
961        // Increment saturate count and cycle through options (0-3)
962        saturateCount = (saturateCount + 1) % 4;
963
964        // Hide all saturate text labels
965        for (let i = 0; i <= 3; i++) {
966            const textElement = document.getElementById(`saturate-text-${i}`);
967            const textElement1 = document.getElementById(`saturate-detail-text-${i}`);
968            if (textElement) {
969                textElement.style.display = 'none';
970            }
971            if (textElement1) {
972                textElement1.style.display = 'none';
973            }
974        }
975
976        // Show current saturate text and apply corresponding class
977        const currentTextElement = document.getElementById(`saturate-text-${saturateCount}`);
978        if (currentTextElement) {
979            currentTextElement.style.display = 'inline';
980        }
981
982        const currentTextElement1 = document.getElementById(`saturate-detail-text-${saturateCount}`);
983        if (currentTextElement1) {
984            currentTextElement1.style.display = 'inline';
985        }
986
987        if (saturateCount === 0) {
988            // Reset state - no saturate applied
989            button.classList.remove(prefix + 'feature-active');
990            tickIcon.style.display = 'none';
991            saturateCheck.classList.remove(prefix + 'featureSteps-visible');
992            saturateSpans.forEach(span => span.classList.remove(prefix + 'active'));
993        } else {
994            // Apply saturate based on count
995            button.classList.add(prefix + 'feature-active');
996            tickIcon.style.display = 'inline-flex';
997            saturateCheck.classList.add(prefix + 'featureSteps-visible');
998
999            // Apply the appropriate saturate class
1000            if (saturateCount === 1) {
1001                document.documentElement.classList.add(prefix + 'saturate-low');
1002            } else if (saturateCount === 2) {
1003                document.documentElement.classList.add(prefix + 'saturate-high');
1004            } else if (saturateCount === 3) {
1005                document.documentElement.classList.add(prefix + 'saturate-desaturate');
1006            }
1007
1008            // Update step indicators
1009            saturateSpans.forEach(span => span.classList.remove(prefix + 'active'));
1010            saturateSpans.forEach((span, index) => {
1011                if (index <= saturateCount - 1) {
1012                    span.classList.add(prefix + 'active');
1013                }
1014            });
1015        }
1016
1017        saveSettings();
1018        announceSaturationState(saturateCount);
1019    }
1020
1021    document.addEventListener('DOMContentLoaded', function () {
1022        const saturateBtn = document.getElementById('btn-saturate');
1023        if (saturateBtn) {
1024            saturateBtn.addEventListener('click', saturateColor)
1025        }
1026    });
1027
1028    function pauseAnimation() {
1029        const button = document.getElementById('featureItem-animate');
1030        const tickIcon = document.getElementById('tickIcon-animate');
1031        button.classList.toggle(prefix + 'feature-active');
1032        tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex';
1033
1034        // Toggle pause animation class on body
1035        document.body.classList.toggle(prefix + 'animation-pause');
1036        const pauseAnimationBtn = document.getElementById('btn-animation');
1037        pauseAnimationBtn.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
1038        // Pause/resume videos and audio elements
1039        const isAnimationPaused = document.body.classList.contains(prefix + 'animation-pause');
1040
1041        if (isAnimationPaused) {
1042            // Pause all videos
1043            document.querySelectorAll('video:not(.uwaw video):not(.uwaw)').forEach(video => {
1044                if (!video.paused) {
1045                    video.setAttribute('data-was-playing', 'true');
1046                    video.pause();
1047                }
1048            });
1049
1050            // Pause all audio elements
1051            document.querySelectorAll('audio:not(.uwaw audio):not(.uwaw)').forEach(audio => {
1052                if (!audio.paused) {
1053                    audio.setAttribute('data-was-playing', 'true');
1054                    audio.pause();
1055                }
1056            });
1057        } else {
1058            // Resume all videos that were playing
1059            document.querySelectorAll('video[data-was-playing="true"]:not(.uwaw video):not(.uwaw)').forEach(video => {
1060                video.play();
1061                video.removeAttribute('data-was-playing');
1062            });
1063
1064            // Resume all audio elements that were playing
1065            document.querySelectorAll('audio[data-was-playing="true"]:not(.uwaw audio):not(.uwaw)').forEach(audio => {
1066                audio.play();
1067                audio.removeAttribute('data-was-playing');
1068            });
1069        }
1070
1071        saveSettings();
1072    }
1073
1074    document.addEventListener('DOMContentLoaded', function () {
1075        const pauseAnimationBtn = document.getElementById('btn-animation');
1076        if (pauseAnimationBtn) {
1077            pauseAnimationBtn.addEventListener('click', pauseAnimation);
1078        }
1079    });
1080
1081    function toggleADHDFriendlyMode() {
1082        const button = document.getElementById('featureItem-adhd');
1083        const tickIcon = document.getElementById('tickIcon-adhd');
1084
1085        if (adhdActive) {
1086            // Remove active state
1087            button.classList.remove(prefix + 'feature-active');
1088            tickIcon.style.display = 'none';
1089
1090            readingMask.classList.add('mask-hidden');
1091            readingMask.classList.remove('mask-visible');
1092            document.body.classList.remove(prefix + 'adhd-saturate');
1093            adhdActive = false;
1094        } else {
1095            // Add active state
1096            button.classList.add(prefix + 'feature-active');
1097            tickIcon.style.display = 'inline-flex';
1098            readingMask.classList.remove('mask-hidden');
1099            readingMask.classList.add('mask-visible');
1100            document.body.classList.add(prefix + 'adhd-saturate');
1101            adhdActive = true;
1102        }
1103        const adhdBtn = document.getElementById('btn-adhd');
1104        adhdBtn.setAttribute('aria-pressed', tickIcon.style.display === 'inline-flex' ? 'true' : 'false');
1105        saveSettings();
1106    }
1107
1108    document.addEventListener('DOMContentLoaded', function () {
1109        const adhdBtn = document.getElementById('btn-adhd');
1110        if (adhdBtn) {
1111            adhdBtn.addEventListener('click', toggleADHDFriendlyMode)
1112        }
1113    });
1114
1115    function resetSettings() {
1116        const cookieDomain = getCookieDomain();
1117
1118        if (cookieDomain) {
1119            document.cookie = `${SETTINGS_KEY}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${cookieDomain}`;
1120        } else {
1121            document.cookie = `${SETTINGS_KEY}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
1122        }
1123        speechSynthesisInstance.cancel();
1124        const allTextNodes = document.body.querySelectorAll('p:not(.uwaw *), h1:not(.uwaw *), h2:not(.uwaw *), h3:not(.uwaw *), h4:not(.uwaw *), h5:not(.uwaw *), h6:not(.uwaw *), span:not(.uwaw *), li:not(.uwaw *), a:not(.uwaw *)');
1125        allTextNodes.forEach(node => {
1126            node.innerHTML = node.innerHTML.replace(/<span style="font-weight: bold !important;?[^"']*["']>(.*?)<\/span>/g, '$1')
1127        });
1128
1129
1130        // Remove line height classes and styles
1131        document.querySelectorAll('.ux4g-line-height').forEach((el) => {
1132            el.classList.remove('ux4g-line-height');
1133        });
1134
1135        const lineHeightStyle = document.getElementById('ux4g-line-height-styles');
1136        if (lineHeightStyle) {
1137            lineHeightStyle.remove();
1138        }
1139
1140        // Remove text spacing classes and styles
1141        document.querySelectorAll('.ux4g-text-spacing').forEach((el) => {
1142            el.classList.remove('ux4g-text-spacing');
1143        });
1144
1145        const textSpacingStyle = document.getElementById('ux4g-text-spacing-styles');
1146        if (textSpacingStyle) {
1147            textSpacingStyle.remove();
1148        }
1149
1150        document.querySelectorAll('body *:not(.uwaw *):not(.uwaw)').forEach((el) => {
1151            el.style.fontSize = "";
1152            el.style.lineHeight = "";
1153            el.style.cursor = "";
1154            el.style.zoom = "1";
1155            el.classList.remove(prefix + "active");
1156            el.classList.remove(prefix + 'animation-pause');
1157        });
1158
1159        adhdActive = false;
1160        document.body.classList.remove(prefix + "dark-mode", prefix + "custom-cursor", prefix + "dyslexia-mode", prefix + "highlight-links", prefix + "hide-images", prefix + "animation-pause", prefix + 'saturate-low', prefix + 'saturate-high', prefix + 'saturate-desaturate', prefix + 'adhd-saturate');
1161        // Resume any paused media
1162        document.querySelectorAll('video[data-was-playing="true"]:not(.uwaw video):not(.uwaw)').forEach(video => {
1163            video.play();
1164            video.removeAttribute('data-was-playing');
1165        });
1166
1167        document.querySelectorAll('audio[data-was-playing="true"]:not(.uwaw audio):not(.uwaw)').forEach(audio => {
1168            audio.play();
1169            audio.removeAttribute('data-was-playing');
1170        });
1171        document.documentElement.classList.remove(prefix + "invert-colors");
1172        fontSizeCount = 0;
1173        lineHeightCount = 0;
1174        textSpacingCount = 0;
1175        saturateCount = 0;
1176        screenReader = !1;
1177        saveSettings();
1178        loadSettings();
1179        const checkboxes = document.querySelectorAll('.uwaw input[type="checkbox"]');
1180        checkboxes.forEach(checkbox => checkbox.checked = !1);
1181        document.querySelectorAll('.font-size-visible, .line-height-visible, .text-spacing-visible').forEach(el => el.classList.remove(prefix + 'span-visible'))
1182        readingMask.classList.add('mask-hidden');
1183        readingMask.classList.remove('mask-visible');
1184    }
1185
1186    document.addEventListener('DOMContentLoaded', function () {
1187        const resetBtn = document.getElementById('reset-all');
1188        if (resetBtn) {
1189            resetBtn.addEventListener('click', resetSettings)
1190        }
1191    });
1192
1193    function getCookie(name) {
1194        const value = "; " + document.cookie;
1195        const parts = value.split("; " + name + "=");
1196        if (parts.length === 2) return decodeURIComponent(parts.pop().split(";").shift());
1197    }
1198
1199    function saveSettings() {
1200        const settings = {
1201            screenReader: screenReader,
1202            fontSizeCount: fontSizeCount - 1,
1203            lineHeightCount: lineHeightCount - 1,
1204            textSpacingCount: textSpacingCount - 1,
1205            saturateCount: saturateCount,
1206            highlightLinks: document.body.classList.contains(prefix + 'highlight-links'),
1207            dyslexiaMode: document.body.classList.contains(prefix + 'dyslexia-mode'),
1208            hideImages: document.body.classList.contains(prefix + 'hide-images'),
1209            cursorChanged: document.body.classList.contains(prefix + 'custom-cursor'),
1210            invert: document.documentElement.classList.contains(prefix + 'invert-colors'),
1211            adhdFriendly: document.body.classList.contains(prefix + 'adhd-saturate'),
1212            pauseAnimation: document.body.classList.contains(prefix + 'animation-pause'),
1213        };
1214
1215        const jsonStr = JSON.stringify(settings);
1216        const expiryDate = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toUTCString(); // 30 days
1217
1218        const cookieDomain = getCookieDomain();
1219        // console.log(cookieDomain);
1220
1221        // Check if running on HTTPS
1222        if (location.protocol === 'https:') {
1223            if (cookieDomain) {
1224                // For production domains with HTTPS
1225                document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/; domain=${cookieDomain}; SameSite=Strict; Secure`;
1226            } else {
1227                // For localhost/IP with HTTPS
1228                document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/; SameSite=Strict; Secure`;
1229            }
1230        } else {
1231            // Fallback for HTTP (development)
1232            if (cookieDomain) {
1233                document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/; domain=${cookieDomain}`;
1234            } else {
1235                document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/`;
1236            }
1237            // console.warn("⚠️ Secure cookie attribute skipped (not HTTPS)");
1238        }
1239
1240        // console.log("✅ Cookie saved for domain:", cookieDomain || 'current domain');
1241
1242    }
1243
1244    function updateWidgetToggles(settings) {
1245        const speakOn = document.getElementById('tickIcon_sp');
1246        if (speakOn) {
1247            speakOn.style.display = settings.screenReader ? 'inline-flex' : 'none'
1248        }
1249        const highlightToggle = document.getElementById('tickIcon-ht');
1250        if (highlightToggle) {
1251            highlightToggle.style.display = settings.highlightLinks ? 'inline-flex' : 'none'
1252        }
1253        const invertToggle = document.getElementById('tickIcon-ic');
1254        if (invertToggle) {
1255            invertToggle.style.display = settings.invert ? 'inline-flex' : 'none'
1256        }
1257        const dyslexiaToggle = document.getElementById('tickIcon-df');
1258        if (dyslexiaToggle) {
1259            dyslexiaToggle.style.display = settings.dyslexiaMode ? 'inline-flex' : 'none'
1260        }
1261        const adhdToggle = document.getElementById('tickIcon-adhd');
1262        if (adhdToggle) {
1263            adhdToggle.style.display = settings.adhdFriendly ? 'inline-flex' : 'none'
1264        }
1265        const hideImagesToggle = document.getElementById('tickIcon-hi');
1266        if (hideImagesToggle) {
1267            hideImagesToggle.style.display = settings.hideImages ? 'inline-flex' : 'none'
1268        }
1269        const cursorToggle = document.getElementById('tickIcon-cursor');
1270        if (cursorToggle) {
1271            cursorToggle.style.display = settings.cursorChanged ? 'inline-flex' : 'none'
1272        }
1273        const saturateToggle = document.getElementById('tickIcon-saturate');
1274        if (saturateToggle) {
1275            saturateToggle.style.display = settings.saturateCount > 0 ? 'inline-flex' : 'none'
1276        }
1277
1278        const animationToggle = document.getElementById('tickIcon-animate');
1279        if (animationToggle) {
1280            animationToggle.style.display = settings.pauseAnimation ? 'inline-flex' : 'none'
1281        }
1282
1283        adjustFontSize('+1');
1284        adjustLineHeight();
1285        adjustTextSpacing()
1286    }
1287
1288    function loadSettings() {
1289        let settings = getCookie(SETTINGS_KEY);
1290        if (!settings) {
1291            settings = getCookie(SETTINGS_KEY);
1292        }
1293        // console.log(settings);
1294        if (settings) {
1295            settings = JSON.parse(settings);
1296            fontSizeCount = settings.fontSizeCount || 0;
1297            lineHeightCount = settings.lineHeightCount || 0;
1298            textSpacingCount = settings.textSpacingCount || 0;
1299            saturateCount = settings.saturateCount || 0;
1300
1301            announceFontSizeLevel(fontSizeCount);
1302            announceLineHeightLevel(lineHeightCount);
1303            announceTextSpacingLevel(textSpacingCount);
1304            announceSaturationState(saturateCount);
1305
1306            if (settings.screenReader) {
1307                screenReader = settings.screenReader;
1308                const button = document.getElementById('featureItem_sp');
1309                button.classList.add(prefix + 'feature-active');
1310                const speakButton = document.getElementById('speak');
1311                speakButton.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1312            } else {
1313                const button = document.getElementById('featureItem_sp');
1314                button.classList.remove(prefix + 'feature-active');
1315                const speakButton = document.getElementById('speak');
1316                speakButton.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1317            }
1318            if (settings.highlightLinks) {
1319                document.body.classList.add(prefix + 'highlight-links');
1320                const button = document.getElementById('featureItem-ht');
1321                button.classList.add(prefix + 'feature-active');
1322                const highlightBtn = document.getElementById('btn-s10');
1323                highlightBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1324            } else {
1325                const button = document.getElementById('featureItem-ht');
1326                button.classList.remove(prefix + 'feature-active');
1327                const highlightBtn = document.getElementById('btn-s10');
1328                highlightBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1329            }
1330            if (settings.dyslexiaMode) {
1331                document.body.classList.add(prefix + 'dyslexia-mode');
1332                const button = document.getElementById('featureItem-df');
1333                button.classList.add(prefix + 'feature-active');
1334                const dfBtn = document.getElementById('btn-df');
1335                dfBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1336            } else {
1337                const button = document.getElementById('featureItem-df');
1338                button.classList.remove(prefix + 'feature-active');
1339                const dfBtn = document.getElementById('btn-df');
1340                dfBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1341            }
1342            if (settings.hideImages) {
1343                document.body.classList.add(prefix + 'hide-images');
1344                const button = document.getElementById('featureItem-hi');
1345                button.classList.add(prefix + 'feature-active');
1346                const hideImagesBtn = document.getElementById('btn-s11');
1347                hideImagesBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1348            } else {
1349                const button = document.getElementById('featureItem-hi');
1350                button.classList.remove(prefix + 'feature-active');
1351                const hideImagesBtn = document.getElementById('btn-s11');
1352                hideImagesBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1353            }
1354            if (settings.invert) {
1355                document.documentElement.classList.toggle(prefix + "invert-colors");
1356                const button = document.getElementById('featureItem-ic');
1357                button.classList.add(prefix + 'feature-active');
1358                const invertBtn = document.getElementById('btn-invert');
1359                invertBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1360            } else {
1361                const button = document.getElementById('featureItem-ic');
1362                button.classList.remove(prefix + 'feature-active');
1363                const invertBtn = document.getElementById('btn-invert');
1364                invertBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1365            }
1366            if (settings.cursorChanged) {
1367                document.body.classList.add(prefix + 'custom-cursor');
1368                const button = document.getElementById('featureItem-Cursor');
1369                button.classList.add(prefix + 'feature-active');
1370                const cursorBtn = document.getElementById('btn-cursor');
1371                cursorBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1372            } else {
1373                const button = document.getElementById('featureItem-Cursor');
1374                button.classList.remove(prefix + 'feature-active');
1375                const cursorBtn = document.getElementById('btn-cursor');
1376                cursorBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1377            }
1378            if (settings.adhdFriendly) {
1379                toggleADHDFriendlyMode();
1380                readingMask.classList.remove('mask-hidden');
1381                const button = document.getElementById('featureItem-adhd');
1382                button.classList.add(prefix + 'feature-active');
1383                const adhdBtn = document.getElementById('btn-adhd');
1384                adhdBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1385            }
1386            else {
1387                readingMask.classList.add('mask-hidden');
1388                const button = document.getElementById('featureItem-adhd');
1389                button.classList.remove(prefix + 'feature-active');
1390                const adhdBtn = document.getElementById('btn-adhd');
1391                adhdBtn.setAttribute('aria-pressed', button.classList.contains(`${prefix}feature-active`) ? 'true' : 'false');
1392            }
1393
1394            applyTextSettings()
1395
1396            // Apply line height settings using classes
1397            if (lineHeightCount > 0) {
1398                updateLineHeight();
1399            }
1400
1401            // Apply text spacing settings using classes  
1402            if (textSpacingCount > 0) {
1403                updateLetterSpacing();
1404            }
1405
1406            // Load saturate settings
1407            if (saturateCount > 0) {
1408                const button = document.getElementById('featureItem-saturate');
1409                button.classList.add(prefix + 'feature-active');
1410
1411                // Apply saved saturate class
1412                if (saturateCount === 1) {
1413                    document.documentElement.classList.add(prefix + 'saturate-low');
1414                } else if (saturateCount === 2) {
1415                    document.documentElement.classList.add(prefix + 'saturate-high');
1416                } else if (saturateCount === 3) {
1417                    document.documentElement.classList.add(prefix + 'saturate-desaturate');
1418                }
1419
1420                // Show correct text and icons
1421                for (let i = 0; i <= 3; i++) {
1422                    const textElement = document.getElementById(`saturate-text-${i}`);
1423                    const detailTextElement = document.getElementById(`saturate-detail-text-${i}`);
1424                    if (textElement) {
1425                        textElement.style.display = i === saturateCount ? 'inline' : 'none';
1426                    }
1427                    if (detailTextElement) {
1428                        detailTextElement.style.display = i === saturateCount ? 'inline' : 'none';
1429                    }
1430                }
1431
1432                const saturateCheck = document.getElementById('featureStepsSaturate');
1433                saturateCheck.classList.add(prefix + 'featureSteps-visible');
1434                saturateSpans.forEach((span, index) => {
1435                    if (index <= saturateCount - 1) {
1436                        span.classList.add(prefix + 'active');
1437                    }
1438                });
1439            }
1440            else {
1441                const button = document.getElementById('featureItem-saturate');
1442                button.classList.remove(prefix + 'feature-active');
1443                document.documentElement.classList.remove(prefix + 'saturate-low');
1444                document.documentElement.classList.remove(prefix + 'saturate-high');
1445                document.documentElement.classList.remove(prefix + 'saturate-desaturate');
1446                const saturateCheck = document.getElementById('featureStepsSaturate');
1447                saturateCheck.classList.remove(prefix + 'featureSteps-visible');
1448                saturateSpans.forEach((span, index) => {
1449                    if (index <= saturateCount - 1) {
1450                        span.classList.remove(prefix + 'active');
1451                    }
1452                });
1453
1454            }
1455
1456            if (settings.pauseAnimation) {
1457                // console.log('Animation pause is enabled');
1458
1459                const button = document.getElementById('featureItem-animate');
1460                const tickIcon = document.getElementById('tickIcon-animate');
1461
1462                if (button) button.classList.add(prefix + 'feature-active');
1463                if (tickIcon) tickIcon.style.display = 'inline-flex';
1464
1465                document.body.classList.add(prefix + 'animation-pause');
1466
1467                // 🔁 Delay pausing slightly to allow media to finish initializing
1468                setTimeout(() => {
1469                    document.querySelectorAll('video:not(.uwaw video):not(.uwaw)').forEach(video => {
1470                        video.setAttribute('data-was-playing', 'true');
1471                        video.pause();
1472                    });
1473
1474                    document.querySelectorAll('audio:not(.uwaw audio):not(.uwaw)').forEach(audio => {
1475                        audio.setAttribute('data-was-playing', 'true');
1476                        audio.pause();
1477                    });
1478                }, 300); // Adjust delay if needed
1479            } else {
1480                const button = document.getElementById('featureItem-animate');
1481                const tickIcon = document.getElementById('tickIcon-animate');
1482
1483                if (button) button.classList.remove(prefix + 'feature-active');
1484                if (tickIcon) tickIcon.style.display = 'none';
1485            }
1486            updateWidgetToggles(settings)
1487        }
1488    }
1489
1490    const modal = document.getElementById("uw-main");
1491
1492    // Toggle modal on Ctrl + F2
1493    document.addEventListener("keydown", function (e) {
1494        if (e.ctrlKey && e.key === "F2") {
1495            e.preventDefault();
1496            // Toggle based on current right style
1497            const currentRight = window.getComputedStyle(modal).left;
1498            if (currentRight === "0px") {
1499                // Close
1500                modal.style.left = "-530px";
1500 // adjust width as needed
1501            } else {
1502                // Open
1503                modal.style.left = "0";
1504            }
1505        }
1506    });
1507
1508    function detectRouteChange() {
1509        setInterval(() => {
1510            let currentPath = window.location.pathname;
1511            if (currentPath !== lastPath) {
1512                // console.log('Route changed from', lastPath, 'to', currentPath);
1513                speechSynthesisInstance.cancel();
1514                lastPath = currentPath;
1515
1516                // Get settings from cookie (not localStorage)
1517                const settingsStr = getCookie(SETTINGS_KEY);
1518                if (settingsStr) {
1519                    const settings = JSON.parse(settingsStr);
1520
1521                    // Re-apply ADHD mode if it was active
1522                    if (settings.adhdFriendly && !adhdActive) {
1523                        toggleADHDFriendlyMode()
1524                    }
1525
1526                    // Apply line height changes using classes
1527                    if (settings.lineHeightCount && settings.lineHeightCount > 0) {
1528                        lineHeightCount = settings.lineHeightCount + 1;
1529                        updateLineHeight();
1530                    }
1531
1532                    // Apply text spacing changes using classes
1533                    if (settings.textSpacingCount && settings.textSpacingCount > 0) {
1534                        textSpacingCount = settings.textSpacingCount + 1;
1535                        updateLetterSpacing();
1536                    }
1537                }
1538            }
1539        }, 1000);
1540    }
1541})()
1542
1543
1544//this code for page loading showing accessibility code issue fixed 
1545window.addEventListener("load", function () {
1546    document.body.classList.remove("accessibility-loading");
1547});
1548
1549// // start here hide image and background hide
1550function hideBackgroundImages() {
1551    if (!document.body.classList.contains('ux4g-accessibility-hide-images')) return;
1552
1553    document.querySelectorAll('*:not(#uw-main):not(#uw-main *):not(.reading-mask-horizontal)')
1554        .forEach(el => {
1555            const bgImage = getComputedStyle(el).backgroundImage;
1556            if (bgImage.includes('url(')) {
1557                el.dataset.origBgImage = bgImage; // Store original
1558                el.style.setProperty('background-image', 'none', 'important');
1559            }
1560        });
1561}
1562
1563function restoreBackgroundImages() {
1564    document.querySelectorAll('[data-orig-bg-image]').forEach(el => {
1565        el.style.backgroundImage = el.dataset.origBgImage;
1566        delete el.dataset.origBgImage;
1567    });
1568}
1569
1570function toggleBackgroundImageHiding() {
1571    if (document.body.classList.contains('ux4g-accessibility-hide-images')) {
1572        hideBackgroundImages();
1573    } else {
1574        restoreBackgroundImages();
1575    }
1576}
1577
1578document.addEventListener('DOMContentLoaded', hideBackgroundImages);
1579
1580new MutationObserver(mutations => {
1581    if (mutations.some(m => m.attributeName === 'class')) {
1582        toggleBackgroundImageHiding();
1583    }
1584}).observe(document.body, { attributes: true });
1585
1586// end here hide image and background hide

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.