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.