1const textColorPicker = document.getElementById('text-color-picker') 2const backgroundColorPicker = document.getElementById('background-color-picker') 3const fontSizeIncreaseBtn = document.getElementById('font-size-increase') 4const fontSizeDecreaseBtn = document.getElementById('font-size-decrease') 5const hideImagesEnable = document.querySelector( 6 '#settings-hide-images input[value="enable"]', 7) 8const hideImagesDisable = document.querySelector( 9 '#settings-hide-images input[value="disable"]', 10) 11const resetHideImagesBtn = document.getElementById('reset-hide-images') 12const wordSpacingIncreaseBtn = document.getElementById('word-spacing-increase') 13const wordSpacingDecreaseBtn = document.getElementById('word-spacing-decrease') 14const lineHeightIncreaseBtn = document.getElementById('line-height-increase') 15const highlightLinksEnable = document.querySelector( 16 '#settings-highlight-links input[value="enable"]', 17) 18const readingModeEnable = document.getElementById('reading-mode-enable') 19const readingModeDisable = document.getElementById('reading-mode-disable') 20const resetReadingModeBtn = document.getElementById('reset-reading-mode') 21const readingFontIncrease = document.getElementById('reading-font-increase') 22const readingFontDecrease = document.getElementById('reading-font-decrease') 23const readingFontSizeValue = document.getElementById('reading-font-size-value') 24const readingBgSwatches = document.querySelectorAll('.reading-bg-swatch') 25 26let readingFontSize = 27 parseFloat(localStorage.getItem('a11yReadingFontSize')) || 1.125 28const highlightLinksDisable = document.querySelector( 29 '#settings-highlight-links input[value="disable"]', 30) 31const resetHighlightLinksBtn = document.getElementById('reset-highlight-links') 32const lineHeightDecreaseBtn = document.getElementById('line-height-decrease') 33const fontFamilySelect = document.getElementById('font-family-select') 34const colorBlindnessSelect = document.getElementById('color-blindness-select') 35// const cursorSizeSmallBtn = document.getElementById('cursor-size-small') 36// const cursorSizeMediumBtn = document.getElementById('cursor-size-medium') 37// const cursorSizeLargeBtn = document.getElementById('cursor-size-large') 38const accessibilityToggle = document.getElementById('accessibility-toggle') 39const accessibilityWidget = document.getElementById('accessibility-widget') 40const accessibilityClose = document.getElementById('accessibility-close') 41const resetButton = document.getElementById('reset-button') 42 43const resetTextColorBtn = document.getElementById('reset-text-color') 44const resetBackgroundColorBtn = document.getElementById( 45 'reset-background-color', 46) 47const resetFontSizeBtn = document.getElementById('reset-font-size') 48const resetWordSpacingBtn = document.getElementById('reset-word-spacing') 49const resetLineHeightBtn = document.getElementById('reset-line-height') 50// const resetCursorSizeBtn = document.getElementById('reset-cursor-size') 51const resetFontFamilyBtn = document.getElementById('reset-font-family') 52const resetColorBlindnessBtn = document.getElementById('reset-color-blindness') 53const resetContrastBtn = document.getElementById('reset-contrast') 54const resetReduceMotionBtn = document.getElementById('reset-reduce-motion') 55 56const menuButtons = document.querySelectorAll('.menu-button') 57const backButtons = document.querySelectorAll('.back-button') 58const mainMenu = document.getElementById('main-menu') 59 60const contrastButtons = { 61 normal: document.getElementById('contrast-normal'), 62 high: document.getElementById('contrast-high'), 63 inverse: document.getElementById('contrast-inverse'), 64} 65const reduceMotionEnable = document.getElementById('reduce-motion-enable') 66const reduceMotionDisable = document.getElementById('reduce-motion-disable') 67 68// Display spans for "current value" 69const textColorValue = document.getElementById('text-color-value') 70const backgroundColorValue = document.getElementById('background-color-value') 71const fontSizeValue = document.getElementById('font-size-value') 72const wordSpacingValue = document.getElementById('word-spacing-value') 73const lineHeightValue = document.getElementById('line-height-value') 74// const cursorSizeValue = document.getElementById('cursor-size-value') 75const fontFamilyValue = document.getElementById('font-family-value') 76const colorBlindnessValue = document.getElementById('color-blindness-value') 77const contrastValue = document.getElementById('contrast-value') 78const reduceMotionValue = document.getElementById('reduce-motion-value') 79 80// Initial empty values (will keep the site as-is unless changed) 81let fontSize = isNaN(parseInt(getSettings('a11yFontSize'))) 82 ? null 83 : parseInt(getSettings('a11yFontSize')) 84let wordSpacing = isNaN(parseInt(getSettings('a11yWordSpacing'))) 85 ? null 86 : parseInt(getSettings('a11yWordSpacing')) 87let lineHeight = isNaN(parseFloat(getSettings('a11yLineHeight'))) 88 ? null 89 : parseFloat(getSettings('a11yLineHeight')) 90// let cursorSize = null 91 92// Cache all elements except those inside the widget and toggle button 93const allElements = document.querySelectorAll( 94 'body *:not(#accessibility-widget):not(#accessibility-widget *):not(#accessibility-toggle):not(#accessibility-toggle *)', 95) 96const allLinks = document.querySelectorAll( 97 'body a:not(#accessibility-widget a):not(#accessibility-widget * a):not(#accessibility-toggle):not(#accessibility-toggle *)', 98) 99 100function resetHighlightLinks() { 101 localStorage.removeItem('a11yHighlightLinks') 102 document.body.classList.remove('a11y-highlight-links') 103 // Reset radio buttons 104 if (highlightLinksEnable) highlightLinksEnable.checked = false 105 if (highlightLinksDisable) highlightLinksDisable.checked = false 106} 107 108// Get elements with background colors
109function getAllElementsWithBackgroundColor() { 110 const elements = document.querySelectorAll( 111 'body *:not(#accessibility-widget):not(#accessibility-widget *):not(#accessibility-toggle):not(#accessibility-toggle *):not(header):not(header *):not(footer):not(footer *)', 112 ) 113 const elementsWithBackground = [] 114 for (let el of elements) { 115 const bgColor = window 116 .getComputedStyle(el) 117 .getPropertyValue('background-color') 118 if ( 119 bgColor && 120 bgColor !== 'rgba(0, 0, 0, 0)' && 121 bgColor !== 'transparent' 122 ) { 123 elementsWithBackground.push(el) 124 } 125 } 126 return elementsWithBackground 127} 128 129let elementsWithBackground = getAllElementsWithBackgroundColor() 130 131function saveSettings(key, value) { 132 localStorage.setItem(key, value) 133} 134 135function getSettings(key) { 136 return localStorage.getItem(key) 137} 138 139function resetTextColor() { 140 localStorage.removeItem('a11yTextColor') 141 for (let el of allElements) { 142 el.style.removeProperty('color') 143 } 144 updateTextColorValue() 145} 146 147function resetBackgroundColor() { 148 localStorage.removeItem('a11yBackgroundColor') 149 document.body.style.removeProperty('background-color') 150 for (let el of elementsWithBackground) { 151 el.style.removeProperty('background-color') 152 } 153 // Re-scan possible background elements in case user changed them 154 elementsWithBackground = getAllElementsWithBackgroundColor()
155 updateBackgroundColorValue() 156} 157 158function resetFontSize() { 159 localStorage.removeItem('a11yFontSize') 160 for (let el of allElements) { 161 el.style.removeProperty('font-size') 162 } 163 fontSize = null 164 updateFontSizeValue() 165} 166 167function resetWordSpacing() { 168 localStorage.removeItem('a11yWordSpacing') 169 for (let el of allElements) { 170 el.style.removeProperty('word-spacing') 171 } 172 wordSpacing = null 173 updateWordSpacingValue() 174} 175 176function resetLineHeight() { 177 localStorage.removeItem('a11yLineHeight') 178 for (let el of allElements) { 179 el.style.removeProperty('line-height') 180 } 181 lineHeight = null 182 updateLineHeightValue() 183} 184 185// function resetCursorSize() { 186// localStorage.removeItem('a11yCursorSize') 187// document.documentElement.style.removeProperty('--custom-cursor') 188// document.documentElement.style.removeProperty('--custom-pointer-cursor') 189// document.documentElement.style.removeProperty('--custom-text-cursor') 190// cursorSize = null 191// updateCursorSizeValue() 192// } 193 194function resetFontFamily() { 195 localStorage.removeItem('a11yFontFamily') 196 for (let el of allElements) { 197 el.style.removeProperty('font-family') 198 } 199 fontFamilySelect.value = '' 200 // updateFontFamilyValue() 201} 202 203function resetColorBlindness() { 204 localStorage.removeItem('a11yColorBlindness') 205 // remove filter from content-wrapper / footer 206 const cw = document.getElementById('content-wrapper') 207 if (cw) cw.style.removeProperty('filter') 208 const ft = document.querySelector('footer') 209 if (ft) ft.style.removeProperty('filter') 210 211 colorBlindnessSelect.value = '' 212 // updateColorBlindnessValue() 213} 214 215function resetContrast() { 216 localStorage.removeItem('a11yContrast') 217 const cw = document.getElementById('content-wrapper') 218 if (cw) cw.style.removeProperty('filter') 219 const ft = document.querySelector('footer') 220 if (ft) ft.style.removeProperty('filter') 221 222 // updateContrastValue() 223} 224 225function resetReduceMotion() { 226 localStorage.removeItem('a11yReduceMotion') 227 reduceMotionEnable.checked = false 228 reduceMotionDisable.checked = false 229 applyReduceMotion(false) 230 // updateReduceMotionValue() 231} 232 233function updateTextColorValue() { 234 const saved = getSettings('a11yTextColor') 235 textColorValue.textContent = saved || 'Default' 236}
237function updateBackgroundColorValue() { 238 const saved = getSettings('a11yBackgroundColor') 239 backgroundColorValue.textContent = saved || 'Default' 240} 241function updateFontSizeValue() { 242 const saved = getSettings('a11yFontSize') 243 fontSizeValue.textContent = saved ? saved + 'px' : 'Default (16px)' 244} 245function updateWordSpacingValue() { 246 const saved = getSettings('a11yWordSpacing') 247 wordSpacingValue.textContent = saved ? saved + 'px' : 'Default (0px)' 248} 249function updateLineHeightValue() { 250 const saved = getSettings('a11yLineHeight') 251 lineHeightValue.textContent = saved || 'Default (1.5)' 252} 253// function updateCursorSizeValue() { 254// const saved = getSettings('a11yCursorSize') 255// if (!saved) cursorSizeValue.textContent = 'Default' 256// else cursorSizeValue.textContent = saved 257// } 258function updateFontFamilyValue() { 259 const saved = getSettings('a11yFontFamily') 260 fontFamilyValue.textContent = saved || 'Default' 261} 262function updateColorBlindnessValue() { 263 const saved = getSettings('a11yColorBlindness') 264 colorBlindnessValue.textContent = saved || 'None' 265} 266function updateContrastValue() { 267 const saved = getSettings('a11yContrast') 268 if (!saved || saved === 'none') contrastValue.textContent = 'عادÛ' 269 else if (saved.includes('contrast')) contrastValue.textContent = 'ØªØ´Ø¯ÛØ¯' 270 else if (saved.includes('invert')) contrastValue.textContent = 'Ù Ø¹Ú©ÙØ³' 271 else contrastValue.textContent = 'Unknown' 272} 273function updateReduceMotionValue() { 274 const saved = getSettings('a11yReduceMotion') 275 if (saved === 'true') reduceMotionValue.textContent = 'ØºÛØ±ÙعاÙ' 276 else if (saved === 'false') reduceMotionValue.textContent = 'ÙØ¹Ø§Ù' 277 else reduceMotionValue.textContent = 'Default' 278} 279 280function applyHighlightLinks(enable) { 281 if (enable) { 282 document.body.classList.add('a11y-highlight-links') 283 } else { 284 document.body.classList.remove('a11y-highlight-links') 285 } 286} 287 288function ensureBubble() { 289 var existing = document.getElementById('rm-bubble') 290 if (existing) return existing 291 292 var bubble = document.createElement('div') 293 bubble.id = 'rm-bubble' 294 bubble.setAttribute('role', 'status') 295 bubble.setAttribute('aria-live', 'polite') 296 bubble.innerHTML = 297 '<span class="rm-bubble-icon d-none" aria-hidden="true"><i class="fa fa-book"></i></span>' + 298 '<span class="rm-bubble-text d-none">ØØ§Ùت Ù Ø·Ø§ÙØ¹Ù ÙØ¹Ø§Ù است</span>' + 299 '<button type="button" class="rm-bubble-close d-none" aria-label="Ø®Ø±ÙØ¬ از ØØ§Ùت Ù Ø·Ø§ÙØ¹Ù">' + 300 '<i class="fa fa-times d-none" aria-hidden="true"></i>' + 301 '</button>' 302 303 document.body.appendChild(bubble) 304 305 bubble 306 .querySelector('.rm-bubble-close') 307 .addEventListener('click', function () { 308 applyReadingMode(false) 309 saveSettings('a11yReadingMode', 'false') 310 if (readingModeDisable) readingModeDisable.checked = true 311 if (readingModeEnable) readingModeEnable.checked = false 312 }) 313 314 return bubble 315} 316 317function rmNormHref(href) { 318 try { 319 var u = new URL(href, location.href) 320 u.hash = '' 321 return u.origin + u.pathname 322 } catch (e) { 323 return (href || '').trim() 324 } 325} 326function rmClean(t) { 327 return (t || '').replace(/\s+/g, ' ').trim() 328} 329 330function rmSectionOf(a) { 331 return ( 332 a.closest( 333 'section, .news-ticker, .multipurpose-news, .multi-purpos, ' + 334 '.multi-purpos-list, .main-news, .album-news, .album-carousel', 335 ) || 336 document.getElementById('content-wrapper') || 337 document.body 338 ) 339} 340 341function rmSectionHeading(section) { 342 if (!section) return '' 343 var t = section.querySelector('.title') 344 if (t && !t.closest('.news-list') && !t.closest('li')) { 345 var txt = rmClean(t.textContent) 346 if (txt) return txt 347 } 348 var hs = section.querySelectorAll('h1,h2,h3,h4,h5') 349 for (var i = 0; i < hs.length; i++) { 350 var h = hs[i] 351 if ( 352 h.closest('.news-list') || 353 h.closest('.item-title') || 354 h.closest('.media-heading') || 355 h.closest('li') 356 ) 357 continue 358 var ht = rmClean(h.textContent) 359 if (ht) return ht 360 } 361 return '' 362} 363 364function rmExtractTitle(a) { 365 var h = a.querySelector('h1,h2,h3,h4,h5,h6') 366 if (h) { 367 var ht = rmClean(h.textContent) 368 if (ht) return { text: ht, pr: 4 } 369 } 370 371 var item = a.closest('li, .item, .album-main-item, .services-banner-item') 372 if (item) { 373 var it = item.querySelector('.item-title, .media-heading') 374 if (it) { 375 var itt = rmClean(it.textContent) 376 if (itt) return { text: itt, pr: 3 } 377 } 378 } 379 var own = rmClean(a.textContent) 380 if (own) return { text: own, pr: own.length > 120 ? 1 : 2 } 381 382 var img = a.querySelector('img') 383 if (img && img.alt) return { text: rmClean(img.alt), pr: 2 } 384 385 return { text: '', pr: 0 } 386} 387 388function rmImgOf(a) { 389 var img = a.querySelector('img') 390 if (img) return img.getAttribute('src') 391 var item = a.closest('li, .item, .album-main-item, div') 392 if (item) { 393 var im = item.querySelector('img') 394 if (im) return im.getAttribute('src') 395 } 396 return '' 397} 398 399function rmDateOf(a) { 400 var item = a.closest('li, .item, div') 401 if (!item) return '' 402 var d = item.querySelector('.published-date, time') 403 return d ? rmClean(d.textContent) : '' 404} 405 406function rmDetectArticle() { 407 return document.querySelector( 408 '.news-view, article, .article-view, .single-content, .post-content', 409 ) 410} 411 412/* ---- builds the clean article view for detail pages ---- */ 413function rmBuildArticle(container, articleEl) { 414 // Title 415 var h1 = 416 articleEl.querySelector('h1') || 417 document.querySelector('#content-wrapper h1, h1') 418 var titleText = (h1 && rmClean(h1.textContent)) || rmClean(document.title) 419 if (titleText) { 420 var pt = document.createElement('h1') 421 pt.className = 'rm-page-title' 422 pt.textContent = titleText 423 container.appendChild(pt) 424 } 425 426 // Date / meta (optional, single line) 427 var dateEl = articleEl.querySelector('.date-info, .published-date, time') 428 if (dateEl) { 429 var d = document.createElement('p') 430 d.className = 'rm-article-meta' 431 d.textContent = rmClean(dateEl.textContent) 432 container.appendChild(d) 433 } 434 435 var summary = articleEl.querySelector('.summary, .lead, .excerpt') 436 if (summary) { 437 var s = document.createElement('p') 438 s.className = 'rm-article-summary' 439 s.textContent = rmClean(summary.textContent) 440 container.appendChild(s) 441 } 442 443 var body = articleEl.querySelector( 444 '.content, .news-content, .article-body, .post-body', 445 ) 446 var art = document.createElement('div') 447 art.className = 'rm-article-body' 448 449 if (body) { 450 var clone = body.cloneNode(true) 451 452 clone 453 .querySelectorAll( 454 'script, style, iframe, .video, #tts-wrapper, #tts-player-icon, ' + 455 'input, button, .share-links, .rate-widget, audio, video', 456 ) 457 .forEach(function (n) { 458 n.remove() 459 }) 460 461 clone 462 .querySelectorAll('p, h2, h3, h4, h5, li, blockquote') 463 .forEach(function (n) { 464 var txt = rmClean(n.textContent) 465 if (!txt) { 466 return 467 } 468 }) 469 470 clone.querySelectorAll('img').forEach(function (img) { 471 img.removeAttribute('width') 472 img.removeAttribute('height') 473 img.removeAttribute('style') 474 img.classList.add('rm-article-img') 475 img.loading = 'lazy' 476 if (!img.alt) img.alt = '' 477 }) 478 479 clone.querySelectorAll('[style]').forEach(function (n) { 480 if (n.tagName !== 'IMG') n.removeAttribute('style') 481 }) 482 483 art.innerHTML = clone.innerHTML 484 } else { 485 var ps = articleEl.querySelectorAll('p') 486 ps.forEach(function (p) { 487 var txt = rmClean(p.textContent) 488 if (!txt) return 489 var np = document.createElement('p') 490 np.textContent = txt 491 art.appendChild(np) 492 }) 493 } 494 495 container.appendChild(art) 496 497 var relWrap = document.querySelector( 498 '.relative-news-wrapper, .related-news, .relative-news-carousel', 499 ) 500 if (relWrap) { 501 var links = relWrap.querySelectorAll('a[href]') 502 var seen = {}, 503 items = [] 504 links.forEach(function (a) { 505 var href = a.getAttribute('href') 506 if (!href || href === '#') return 507 var key = rmNormHref(href) 508 if (seen[key]) return 509 var titleNode = a.querySelector( 510 '.relative-news-title, h5, h4, .item-title', 511 ) 512 var t = titleNode 513 ? rmClean(titleNode.textContent) 514 : rmClean(a.textContent) 515 if (!t) return 516 seen[key] = true 517 var img = a.querySelector('img') 518 items.push({ 519 href: href, 520 title: t, 521 img: img ? img.getAttribute('src') : '', 522 }) 523 }) 524 525 if (items.length) { 526 var sec = document.createElement('section') 527 sec.className = 'rm-section' 528 var h = document.createElement('h2') 529 h.className = 'rm-section-title' 530 h.textContent = 'اخبار ٠رتبط' 531 sec.appendChild(h) 532 533 var ul = document.createElement('ul') 534 ul.className = 'rm-list'
535 items.forEach(function (it) { 536 ul.appendChild(rmBuildListItem(it)) 537 }) 538 sec.appendChild(ul) 539 container.appendChild(sec) 540 } 541 } 542} 543 544function rmBuildListItem(it) { 545 var li = document.createElement('li') 546 li.className = 'rm-item' 547 548 var a = document.createElement('a') 549 a.className = 'rm-item-link' 550 a.href = it.href 551 552 if (it.img) { 553 var im = document.createElement('img') 554 im.className = 'rm-item-img' 555 im.src = it.img 556 im.alt = '' 557 im.loading = 'lazy' 558 a.appendChild(im) 559 } 560 var body = document.createElement('div') 561 body.className = 'rm-item-body' 562 var tt = document.createElement('span') 563 tt.className = 'rm-item-title' 564 tt.textContent = it.title || it.href 565 body.appendChild(tt) 566 if (it.date) { 567 var dd = document.createElement('span') 568 dd.className = 'rm-item-date' 569 dd.textContent = it.date 570 body.appendChild(dd) 571 } 572 a.appendChild(body) 573 li.appendChild(a) 574 return li 575} 576 577function rmBuildListing(container) { 578 var scope = document.getElementById('content-wrapper') || document.body 579 var anchors = scope.querySelectorAll( 580 'a[href*="/news/"], a[href*="/article/"], a[href*="/post/"]', 581 ) 582 583 var map = {}, 584 order = [], 585 groups = {} 586 587 anchors.forEach(function (a) { 588 var href = a.getAttribute('href') 589 if (!href || href === '#') return 590 var key = rmNormHref(href) 591 if (!key) return 592 593 var t = rmExtractTitle(a) 594 var img = rmImgOf(a) 595 if (!t.text && !img) return 596 597 var ex = map[key] 598 if (ex) { 599 if (t.pr > ex.tpr) { 600 ex.title = t.text 601 ex.tpr = t.pr 602 } 603 if (!ex.img && img) ex.img = img 604 if (!ex.date) { 605 var dd = rmDateOf(a) 606 if (dd) ex.date = dd 607 } 608 return 609 } 610 611 var heading = rmSectionHeading(rmSectionOf(a)) 612 var gkey = heading || '__default__' 613 var item = { 614 href: href, 615 title: t.text, 616 tpr: t.pr, 617 img: img, 618 date: rmDateOf(a), 619 } 620 map[key] = item 621 622 if (!groups[gkey]) { 623 groups[gkey] = { heading: heading, items: [] } 624 order.push(gkey) 625 } 626 groups[gkey].items.push(item) 627 }) 628 629 var h1 = document.querySelector('#content-wrapper h1, h1') 630 var titleText = (h1 && rmClean(h1.textContent)) || rmClean(document.title) 631 if (titleText) { 632 var pt = document.createElement('h1') 633 pt.className = 'rm-page-title' 634 pt.textContent = titleText 635 container.appendChild(pt) 636 } 637 638 var total = 0 639 order.forEach(function (gkey) { 640 var g = groups[gkey] 641 if (!g.items.length) return 642 643 var sec = document.createElement('section') 644 sec.className = 'rm-section' 645 if (g.heading) { 646 var h = document.createElement('h2') 647 h.className = 'rm-section-title' 648 h.textContent = g.heading 649 sec.appendChild(h) 650 } 651 var ul = document.createElement('ul') 652 ul.className = 'rm-list' 653 g.items.forEach(function (it) { 654 total++ 655 ul.appendChild(rmBuildListItem(it)) 656 }) 657 sec.appendChild(ul) 658 container.appendChild(sec) 659 }) 660 661 return total 662} 663 664function buildReadingContent() { 665 if (document.getElementById('rm-root')) return 666 667 var root = document.createElement('div') 668 root.id = 'rm-root' 669 root.setAttribute('role', 'region') 670 root.setAttribute('aria-label', 'ÙØ³Ø®Ù سادÙâØ´Ø¯Ù Ø¨Ø±Ø§Û Ù Ø·Ø§ÙØ¹Ù') 671 672 var container = document.createElement('div') 673 container.className = 'rm-container' 674 root.appendChild(container) 675 676 var articleEl = rmDetectArticle() 677 var empty = false 678 679 if (articleEl) { 680 rmBuildArticle(container, articleEl) 681 } else { 682 var total = rmBuildListing(container) 683 if (!total) empty = true 684 } 685 686 if (empty) { 687 var p = document.createElement('p') 688 p.className = 'rm-empty' 689 p.textContent = 'Ù ØØªÙØ§Û ÙØ§Ø¨Ù ÙÙ Ø§ÛØ´Û Ø¨Ø±Ø§Û ØØ§Ùت Ù Ø·Ø§ÙØ¹Ù ÛØ§Ùت ÙØ´Ø¯.' 690 container.appendChild(p) 691 } 692 693 document.body.appendChild(root) 694} 695 696function destroyReadingContent() { 697 var r = document.getElementById('rm-root') 698 if (r) r.remove() 699} 700 701function applyReadingMode(enable) { 702 document.body.classList.toggle('a11y-reading-mode', enable) 703 704 if (readingModeEnable) readingModeEnable.checked = enable 705 if (readingModeDisable) readingModeDisable.checked = !enable 706 707 if (enable) { 708 buildReadingContent() 709 window.scrollTo(0, 0) 710 void document.body.offsetHeight // force immediate repaint 711 } else { 712 destroyReadingContent() 713 window.dispatchEvent(new Event('resize')) // let owl carousels recalc 714 } 715 716 var bubble = ensureBubble() 717 if (enable) { 718 requestAnimationFrame(function () { 719 bubble.classList.add('rm-bubble-visible') 720 }) 721 } else { 722 bubble.classList.remove('rm-bubble-visible') 723 } 724} 725 726function applyReadingFontSize(size) { 727 document.documentElement.style.setProperty('--rm-font-size', size + 'rem') 728 if (readingFontSizeValue) { 729 readingFontSizeValue.textContent = 730 size.toFixed(3).replace(/\.?0+$/, '') + 'rem' 731 } 732} 733 734function applyReadingBg(bg, text) { 735 document.documentElement.style.setProperty('--rm-bg', bg) 736 document.documentElement.style.setProperty('--rm-text', text) 737 738 var isDark = bg === '#1c1c1e' 739 document.body.classList.toggle('reading-mode-dark', isDark) 740
741 readingBgSwatches.forEach(function (s) { 742 s.classList.toggle('active', s.dataset.bg === bg) 743 }) 744} 745 746function resetReadingMode() { 747 localStorage.removeItem('a11yReadingMode') 748 localStorage.removeItem('a11yReadingFontSize') 749 localStorage.removeItem('a11yReadingBg') 750 localStorage.removeItem('a11yReadingText') 751 readingFontSize = 1.125 752 applyReadingMode(false) 753 applyReadingFontSize(readingFontSize) 754 applyReadingBg('#fafaf8', '#1a1a1a') 755} 756 757function applySavedSettings() { 758 const savedFontSize = getSettings('a11yFontSize') 759 if (savedFontSize !== null) { 760 applyFontSize(parseInt(savedFontSize)) 761 } 762 763 const savedBackgroundColor = getSettings('a11yBackgroundColor') 764 if (savedBackgroundColor !== null) { 765 applyBackgroundColor(savedBackgroundColor) 766 } 767 768 const savedWordSpacing = getSettings('a11yWordSpacing') 769 if (savedWordSpacing !== null) { 770 applyWordSpacing(parseInt(savedWordSpacing)) 771 } 772 773 const savedHideImages = getSettings('a11yHideImages') 774 if (savedHideImages === 'true') { 775 applyHideImages(true) 776 if (hideImagesEnable) hideImagesEnable.checked = true 777 } else if (savedHideImages === 'false') { 778 applyHideImages(false) 779 if (hideImagesDisable) hideImagesDisable.checked = true 780 } 781 782 const savedLineHeight = getSettings('a11yLineHeight') 783 if (savedLineHeight !== null) { 784 applyLineHeight(parseFloat(savedLineHeight)) 785 } 786 787 const savedFontFamily = getSettings('a11yFontFamily') 788 if (savedFontFamily !== null) { 789 applyFontFamily(savedFontFamily) 790 } 791 const savedHighlightLinks = getSettings('a11yHighlightLinks') 792 if (savedHighlightLinks === 'true') { 793 applyHighlightLinks(true) 794 if (highlightLinksEnable) highlightLinksEnable.checked = true 795 } else if (savedHighlightLinks === 'false') { 796 applyHighlightLinks(false) 797 if (highlightLinksDisable) highlightLinksDisable.checked = true 798 } 799 const savedColorBlindness = getSettings('a11yColorBlindness') 800 if (savedColorBlindness !== null) { 801 applyColorBlindnessFilter(savedColorBlindness) 802 } 803 804 const savedContrastSetting = getSettings('a11yContrast') 805 if (savedContrastSetting !== null) { 806 applyContrastFilter(savedContrastSetting) 807 } 808 809 // const savedCursorSize = getSettings('a11yCursorSize') 810 // if (savedCursorSize !== null) { 811 // applyCursorSize(savedCursorSize) 812 // } 813 814 const savedTextColor = getSettings('a11yTextColor') 815 if (savedTextColor !== null) { 816 applyTextColor(savedTextColor) 817 } 818 819 const savedLinkColor = getSettings('a11yLinkColor') 820 if (savedLinkColor !== null) { 821 applyLinkColor(savedLinkColor) 822 } 823 824 const savedReduceMotion = getSettings('a11yReduceMotion') 825 if (savedReduceMotion === 'true') { 826 reduceMotionEnable.checked = true 827 applyReduceMotion(true) 828 } else if (savedReduceMotion === 'false') { 829 reduceMotionDisable.checked = true 830 applyReduceMotion(false) 831 } 832 const savedReadingMode = getSettings('a11yReadingMode') 833 if (savedReadingMode === 'true') { 834 applyReadingMode(true) 835 } else if (savedReadingMode === 'false') { 836 applyReadingMode(false) 837 } 838 839 const savedReadingFontSize = parseFloat(getSettings('a11yReadingFontSize')) 840 if (!isNaN(savedReadingFontSize)) { 841 readingFontSize = savedReadingFontSize 842 } 843 applyReadingFontSize(readingFontSize) 844 845 const savedReadingBg = getSettings('a11yReadingBg') 846 const savedReadingText = getSettings('a11yReadingText') 847 if (savedReadingBg && savedReadingText) { 848 applyReadingBg(savedReadingBg, savedReadingText) 849 } else { 850 applyReadingBg('#fafaf8', '#1a1a1a') 851 } 852 // updateTextColorValue()
853 // updateBackgroundColorValue() 854 updateFontSizeValue() 855 updateWordSpacingValue() 856 updateLineHeightValue() 857 // updateCursorSizeValue() 858 // updateFontFamilyValue() 859 // updateColorBlindnessValue() 860 // updateContrastValue() 861 // updateReduceMotionValue() 862} 863 864function applyReduceMotion(reduceMotion) { 865 if (reduceMotion) { 866 document.documentElement.setAttribute('data-reduce-motion', 'true') 867 pauseAllSliders() 868 } else { 869 document.documentElement.removeAttribute('data-reduce-motion') 870 resumeAllSliders() 871 } 872} 873 874function pauseAllSliders() { 875 if ( 876 typeof jQuery !== 'undefined' && 877 typeof jQuery.fn.owlCarousel !== 'undefined' 878 ) { 879 $('.owl-carousel').trigger('stop.owl.autoplay') 880 } 881} 882function resumeAllSliders() { 883 if ( 884 typeof jQuery !== 'undefined' && 885 typeof jQuery.fn.owlCarousel !== 'undefined' 886 ) { 887 $('.owl-carousel').trigger('play.owl.autoplay', [1000]) 888 } 889} 890 891// Apply styles with !important to override existing 892function applyTextColor(color) { 893 for (let el of allElements) { 894 el.style.setProperty('color', color, 'important') 895 } 896} 897function applyLinkColor(color) { 898 for (let el of allLinks) { 899 el.style.setProperty('color', color, 'important') 900 } 901} 902function applyBackgroundColor(color) { 903 document.body.style.setProperty('background-color', color, 'important') 904 for (let el of elementsWithBackground) { 905 el.style.setProperty('background-color', color, 'important') 906 } 907} 908function applyFontSize(size) { 909 for (let el of allElements) { 910 el.style.setProperty('font-size', size + 'px', 'important') 911 } 912} 913function applyWordSpacing(spacing) { 914 for (let el of allElements) { 915 el.style.setProperty('word-spacing', spacing + 'px', 'important') 916 } 917} 918function applyLineHeight(lineHeight) { 919 for (let el of allElements) { 920 el.style.setProperty('line-height', lineHeight, 'important') 921 } 922} 923function applyFontFamily(fontFamily) { 924 for (let el of allElements) { 925 el.style.setProperty('font-family', fontFamily, 'important') 926 } 927} 928function applyColorBlindnessFilter(filterType) { 929 let filterValue = '' 930 switch (filterType) { 931 case 'protanopia': 932 filterValue = 933 'grayscale(100%) sepia(100%) hue-rotate(-50deg) saturate(50%)' 934 break 935 case 'deuteranopia': 936 filterValue = 937 'grayscale(100%) sepia(100%) hue-rotate(-20deg) saturate(50%)' 938 break 939 case 'tritanopia': 940 filterValue = 941 'grayscale(100%) sepia(100%) hue-rotate(80deg) saturate(50%)' 942 break 943 case 'protanomaly': 944 filterValue = 945 'grayscale(50%) sepia(100%) hue-rotate(-30deg) saturate(70%)' 946 break 947 case 'deuteranomaly': 948 filterValue = 949 'grayscale(50%) sepia(100%) hue-rotate(-20deg) saturate(70%)' 950 break 951 case 'tritanomaly': 952 filterValue = 'grayscale(50%) sepia(100%) hue-rotate(60deg) saturate(70%)' 953 break 954 case 'achromatopsia': 955 filterValue = 'grayscale(100%)' 956 break 957 case 'achromatomaly': 958 filterValue = 'grayscale(80%)' 959 break 960 default: 961 filterValue = 'none' 962 } 963 const cw = document.getElementById('content-wrapper') 964 if (cw) cw.style.setProperty('filter', filterValue, 'important') 965 const ft = document.querySelector('footer') 966 if (ft) ft.style.setProperty('filter', filterValue, 'important') 967} 968// function applyCursorSize(size) { 969// cursorSize = size 970// } 971function applyContrastFilter(filterValue) { 972 const cw = document.getElementById('content-wrapper') 973 if (cw) cw.style.setProperty('filter', filterValue, 'important') 974 const ft = document.querySelector('footer') 975 if (ft) ft.style.setProperty('filter', filterValue, 'important') 976} 977 978function applyHideImages(enable) { 979 if (enable) { 980 document.body.classList.add('a11y-hide-images') 981 } else { 982 document.body.classList.remove('a11y-hide-images') 983 } 984} 985 986function resetHideImages() { 987 localStorage.removeItem('a11yHideImages') 988 document.body.classList.remove('a11y-hide-images') 989 if (hideImagesEnable) hideImagesEnable.checked = false 990 if (hideImagesDisable) hideImagesDisable.checked = false 991} 992 993function resetAccessibilitySettings() { 994 localStorage.removeItem('a11ySettings') 995 localStorage.removeItem('a11yColorBlindness') 996 // localStorage.removeItem('a11yCursorSize') 997 localStorage.removeItem('a11yFontSize') 998 localStorage.removeItem('a11yLineHeight') 999 localStorage.removeItem('a11yTextColor')
1000 localStorage.removeItem('a11yBackgroundColor') 1001 localStorage.removeItem('a11yWordSpacing') 1002 localStorage.removeItem('a11yFontFamily') 1003 localStorage.removeItem('a11yHighlightLinks') 1004 localStorage.removeItem('a11yReduceMotion') 1005 localStorage.removeItem('a11yContrast') 1006 localStorage.removeItem('a11yReadingMode') 1007 localStorage.removeItem('a11yReadingFontSize') 1008 localStorage.removeItem('a11yReadingBg') 1009 localStorage.removeItem('a11yReadingText') 1010 readingFontSize = 1.125 1011 applyReadingMode(false) 1012 applyReadingFontSize(readingFontSize) 1013 applyReadingBg('#fafaf8', '#1a1a1a') 1014 1015 document.body.classList.remove('a11y-highlight-links') 1016 if (highlightLinksEnable) highlightLinksEnable.checked = false 1017 if (highlightLinksDisable) highlightLinksDisable.checked = false 1018 1019 localStorage.removeItem('a11yHideImages') 1020 document.body.classList.remove('a11y-hide-images') 1021 if (hideImagesEnable) hideImagesEnable.checked = false 1022 if (hideImagesDisable) hideImagesDisable.checked = false 1023 1024 for (let el of allElements) { 1025 el.style.removeProperty('font-size') 1026 el.style.removeProperty('word-spacing') 1027 el.style.removeProperty('line-height') 1028 el.style.removeProperty('font-family') 1029 el.style.removeProperty('color') 1030 el.style.removeProperty('background-color') 1031 // el.style.removeProperty('cursor') 1032 } 1033 1034 document.body.style.removeProperty('background-color') 1035 const cw = document.getElementById('content-wrapper') 1036 if (cw) cw.style.removeProperty('filter') 1037 const ft = document.querySelector('footer') 1038 if (ft) ft.style.removeProperty('filter') 1039 1040 // document.documentElement.style.removeProperty('--custom-cursor') 1041 // document.documentElement.style.removeProperty('--custom-pointer-cursor') 1042 // document.documentElement.style.removeProperty('--custom-text-cursor') 1043 1044 reduceMotionEnable.checked = false 1045 reduceMotionDisable.checked = false 1046 applyReduceMotion(false) 1047 1048 // Re-scan any background changes 1049 elementsWithBackground = getAllElementsWithBackgroundColor() 1050 1051 // Update all dynamic values to defaults 1052 // updateTextColorValue()
1053 // updateBackgroundColorValue() 1054 updateFontSizeValue() 1055 updateWordSpacingValue() 1056 updateLineHeightValue() 1057 // updateCursorSizeValue() 1058 // updateFontFamilyValue() 1059 // updateColorBlindnessValue() 1060 // updateContrastValue() 1061 // updateReduceMotionValue() 1062} 1063 1064resetButton.addEventListener('click', function () { 1065 resetAccessibilitySettings() 1066}) 1067 1068// Single-feature reset 1069resetTextColorBtn.addEventListener('click', resetTextColor) 1070resetBackgroundColorBtn.addEventListener('click', resetBackgroundColor) 1071resetFontSizeBtn.addEventListener('click', resetFontSize) 1072resetWordSpacingBtn.addEventListener('click', resetWordSpacing) 1073resetLineHeightBtn.addEventListener('click', resetLineHeight) 1074// resetCursorSizeBtn.addEventListener('click', resetCursorSize) 1075resetFontFamilyBtn.addEventListener('click', resetFontFamily) 1076resetColorBlindnessBtn.addEventListener('click', resetColorBlindness) 1077resetContrastBtn.addEventListener('click', resetContrast) 1078resetReduceMotionBtn.addEventListener('click', resetReduceMotion) 1079 1080// Contrast settings 1081contrastButtons.normal.addEventListener('click', function () { 1082 applyContrastFilter('none') 1083 saveSettings('a11yContrast', 'none') 1084 updateContrastValue() 1085}) 1086contrastButtons.high.addEventListener('click', function () { 1087 applyContrastFilter('contrast(150%)') 1088 saveSettings('a11yContrast', 'contrast(150%)') 1089 updateContrastValue() 1090}) 1091contrastButtons.inverse.addEventListener('click', function () { 1092 applyContrastFilter('invert(100%)') 1093 saveSettings('a11yContrast', 'invert(100%)') 1094 updateContrastValue() 1095}) 1096 1097// Widget open/close 1098accessibilityToggle.addEventListener('click', function (event) { 1099 event.stopPropagation() 1100 accessibilityWidget.classList.add('active') 1101}) 1102accessibilityClose.addEventListener('click', function (event) { 1103 event.stopPropagation() 1104 accessibilityWidget.classList.remove('active') 1105}) 1106 1107// Close the widget when clicking outside 1108document.addEventListener('click', function (event) { 1109 if ( 1110 !accessibilityWidget.contains(event.target) && 1111 !accessibilityToggle.contains(event.target) 1112 ) { 1113 accessibilityWidget.classList.remove('active') 1114 } 1115}) 1116accessibilityWidget.addEventListener('click', function (event) { 1117 event.stopPropagation() 1118}) 1119document.addEventListener('keydown', function (event) { 1120 if ( 1121 event.ctrlKey && 1122 (event.key === 'm' || event.key === 'M' || event.key === 'Ù¾') 1123 ) { 1124 accessibilityWidget.classList.toggle('active') 1125 } 1126}) 1127 1128// Navigate between menu and setting pages 1129menuButtons.forEach((button) => { 1130 button.addEventListener('click', function () { 1131 const settingsPageId = 'settings-' + button.dataset.settings 1132 const settingsPage = document.getElementById(settingsPageId) 1133 if (settingsPage) { 1134 mainMenu.classList.remove('active') 1135 settingsPage.classList.add('active') 1136 } 1137 }) 1138}) 1139backButtons.forEach((button) => { 1140 button.addEventListener('click', function () { 1141 const parentSettingsPage = button.closest('.widget-page') 1142 if (parentSettingsPage) { 1143 parentSettingsPage.classList.remove('active') 1144 mainMenu.classList.add('active') 1145 } 1146 }) 1147}) 1148 1149// WOW instance (optional) 1150if (typeof WOW !== 'undefined') { 1151 const wowInstance = new WOW() 1152 wowInstance.start = () => { 1153 const elements = document.querySelectorAll('.wow') 1154 elements.forEach((el) => { 1155 el.style.visibility = '' 1156 el.classList.add('wow', 'animated') 1157 }) 1158 wowInstance.sync() 1159 } 1160 wowInstance.stop = () => { 1161 const elements = document.querySelectorAll('.wow') 1162 elements.forEach((el) => { 1163 el.classList.remove('wow', 'animated') 1164 el.style.visibility = 'visible' 1165 }) 1166 } 1167 wowInstance.init() 1168} 1169 1170if (hideImagesEnable) { 1171 hideImagesEnable.addEventListener('change', function () { 1172 if (this.checked) { 1173 applyHideImages(true) 1174 saveSettings('a11yHideImages', 'true') 1175 } 1176 }) 1177} 1178if (hideImagesDisable) { 1179 hideImagesDisable.addEventListener('change', function () { 1180 if (this.checked) { 1181 applyHideImages(false) 1182 saveSettings('a11yHideImages', 'false') 1183 } 1184 }) 1185} 1186resetHideImagesBtn.addEventListener('click', resetHideImages) 1187 1188if (readingModeEnable) { 1189 readingModeEnable.addEventListener('change', function () { 1190 if (this.checked) { 1191 applyReadingMode(true) 1192 saveSettings('a11yReadingMode', 'true') 1193 } 1194 }) 1195} 1196 1197if (readingModeDisable) { 1198 readingModeDisable.addEventListener('change', function () { 1199 if (this.checked) { 1200 applyReadingMode(false) 1201 saveSettings('a11yReadingMode', 'false') 1202 } 1203 }) 1204} 1205 1206if (resetReadingModeBtn) { 1207 resetReadingModeBtn.addEventListener('click', function () { 1208 resetReadingMode() 1209 }) 1210} 1211 1212if (readingFontIncrease) { 1213 readingFontIncrease.addEventListener('click', function () { 1214 readingFontSize = Math.min(readingFontSize + 0.125, 2.0) 1215 applyReadingFontSize(readingFontSize) 1216 saveSettings('a11yReadingFontSize', readingFontSize) 1217 }) 1218} 1219 1220if (readingFontDecrease) { 1221 readingFontDecrease.addEventListener('click', function () { 1222 readingFontSize = Math.max(readingFontSize - 0.125, 0.75) 1223 applyReadingFontSize(readingFontSize) 1224 saveSettings('a11yReadingFontSize', readingFontSize) 1225 }) 1226} 1227
1228readingBgSwatches.forEach(function (swatch) { 1229 swatch.addEventListener('click', function () { 1230 var bg = this.dataset.bg 1231 var text = this.dataset.text 1232 applyReadingBg(bg, text) 1233 saveSettings('a11yReadingBg', bg) 1234 saveSettings('a11yReadingText', text) 1235 }) 1236}) 1237 1238reduceMotionEnable.addEventListener('change', function () { 1239 if (reduceMotionEnable.checked) { 1240 applyReduceMotion(true) 1241 saveSettings('a11yReduceMotion', 'true') 1242 // updateReduceMotionValue() 1243 } 1244}) 1245reduceMotionDisable.addEventListener('change', function () { 1246 if (reduceMotionDisable.checked) { 1247 applyReduceMotion(false) 1248 saveSettings('a11yReduceMotion', 'false') 1249 // updateReduceMotionValue() 1250 } 1251}) 1252 1253if (highlightLinksEnable) { 1254 highlightLinksEnable.addEventListener('change', function () { 1255 if (this.checked) { 1256 applyHighlightLinks(true) 1257 saveSettings('a11yHighlightLinks', 'true') 1258 } 1259 }) 1260} 1261if (highlightLinksDisable) { 1262 highlightLinksDisable.addEventListener('change', function () { 1263 if (this.checked) { 1264 applyHighlightLinks(false) 1265 saveSettings('a11yHighlightLinks', 'false') 1266 } 1267 }) 1268} 1269resetHighlightLinksBtn.addEventListener('click', resetHighlightLinks) 1270 1271// cursorSizeSmallBtn.addEventListener('click', function () { 1272// applyCursorSize('small') 1273// saveSettings('a11yCursorSize', 'small') 1274// updateCursorSizeValue() 1275// }) 1276// cursorSizeMediumBtn.addEventListener('click', function () { 1277// applyCursorSize('medium') 1278// saveSettings('a11yCursorSize', 'medium') 1279// updateCursorSizeValue() 1280// }) 1281// cursorSizeLargeBtn.addEventListener('click', function () { 1282// applyCursorSize('large') 1283// saveSettings('a11yCursorSize', 'large') 1284// updateCursorSizeValue() 1285// }) 1286 1287// Color pickers 1288textColorPicker.addEventListener('change', function () { 1289 applyTextColor(this.value) 1290 saveSettings('a11yTextColor', this.value) 1291 // updateTextColorValue() 1292}) 1293backgroundColorPicker.addEventListener('change', function () { 1294 applyBackgroundColor(this.value) 1295 saveSettings('a11yBackgroundColor', this.value)
1296 // updateBackgroundColorValue() 1297}) 1298 1299// Font Size 1300fontSizeIncreaseBtn.addEventListener('click', function () { 1301 fontSize = fontSize === null ? 16 : fontSize + 1 1302 applyFontSize(fontSize) 1303 saveSettings('a11yFontSize', fontSize) 1304 updateFontSizeValue() 1305}) 1306fontSizeDecreaseBtn.addEventListener('click', function () { 1307 if (fontSize === null) { 1308 fontSize = 16 1309 } 1310 if (fontSize > 1) { 1311 fontSize -= 1 1312 applyFontSize(fontSize) 1313 saveSettings('a11yFontSize', fontSize) 1314 updateFontSizeValue() 1315 } 1316}) 1317 1318// Word Spacing 1319wordSpacingIncreaseBtn.addEventListener('click', function () { 1320 wordSpacing = wordSpacing === null ? 0 : wordSpacing + 1 1321 applyWordSpacing(wordSpacing) 1322 saveSettings('a11yWordSpacing', wordSpacing) 1323 updateWordSpacingValue() 1324}) 1325wordSpacingDecreaseBtn.addEventListener('click', function () { 1326 if (wordSpacing === null) { 1327 wordSpacing = 0 1328 } 1329 if (wordSpacing > 0) { 1330 wordSpacing -= 1 1331 applyWordSpacing(wordSpacing) 1332 saveSettings('a11yWordSpacing', wordSpacing) 1333 updateWordSpacingValue() 1334 } 1335}) 1336 1337// Line Height 1338lineHeightIncreaseBtn.addEventListener('click', function () { 1339 lineHeight = lineHeight === null ? 1.5 : lineHeight + 0.1 1340 applyLineHeight(lineHeight.toFixed(1)) 1341 saveSettings('a11yLineHeight', lineHeight) 1342 updateLineHeightValue() 1343}) 1344lineHeightDecreaseBtn.addEventListener('click', function () { 1345 if (lineHeight === null) { 1346 lineHeight = 1.5 1347 } 1348 if (lineHeight > 0.1) { 1349 lineHeight -= 0.1 1350 applyLineHeight(lineHeight.toFixed(1)) 1351 saveSettings('a11yLineHeight', lineHeight) 1352 updateLineHeightValue() 1353 } 1354}) 1355 1356// Font Family 1357fontFamilySelect.addEventListener('change', function () { 1358 applyFontFamily(this.value) 1359 saveSettings('a11yFontFamily', this.value) 1360 // updateFontFamilyValue() 1361}) 1362 1363// Color Blindness 1364colorBlindnessSelect.addEventListener('change', function () { 1365 applyColorBlindnessFilter(this.value) 1366 saveSettings('a11yColorBlindness', this.value) 1367 // updateColorBlindnessValue() 1368}) 1369 1370document.addEventListener('DOMContentLoaded', function () { 1371 applySavedSettings() 1372})
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.