1class AHAccessibility { 2 3 constructor({ holder, baseUrl, primaryColor = "#161616", textColor = "#FFFFFF", left = "20px", bottom = "20px" }) { 4 this.name = "AHAccessibility"; 5 this.version = "1.0.0"; 6 this.description = "Accessibility features for the application."; 7 this.author = "AD HOC"; 8 this.authorHtml = "AD <span class=\"adhoc-color\">HOC</span>"; 9 this.license = "MIT"; 10 this.homepage = "https://www.adhocweb.it"; 11 this.websiteAccessibility = baseUrl; 12 this.primaryColor = primaryColor; 13 this.textColor = textColor; 14 this.left = left; 15 this.bottom = bottom; 16 17 if (typeof holder === 'undefined') { 18 console.error(`${this.name}: Holder is undefined.`); 19 return; 20 } 21 22 if (typeof holder === 'string') { 23 holder = document.querySelector(holder); 24 if (!holder) { 25 console.error(`${this.name}: No element found for the provided selector.`); 26 return; 27 } 28 } 29 30 this.holder = holder; 31 this.init(); 32 } 33 34 init() { 35 const hideInterface = this.getCookie('hideAccessibilityInterface') || 'false'; 36 if (hideInterface !== 'true') { 37 this.injectStyles(); 38 } 39 40 console.log(`${this.name} v${this.version} initialized.`); 41 } 42 43 createAccessibilityFloatingButton() { 44 const div = document.createElement('div'); 45 div.classList.add('accessibility-floating-button-container'); 46 div.innerHTML = this.getHtmlFloatingButton(); 47 48 const button = div.querySelector('.floating-button'); 49 button.addEventListener('click', () => { 50 const menu = this.holder.querySelector('.accessibility-menu-container'); 51 if (menu) { 52 menu.classList.toggle('show'); 53 54 const isHidden = menu.getAttribute('aria-hidden') === 'true'; 55 menu.setAttribute('aria-hidden', isHidden ? 'false' : 'true'); 56
57 if (!isHidden) document.querySelector('.accessibility-floating-button').focus(); 58 else menu.focus(); 59 } 60 }); 61 62 this.holder.appendChild(div); 63 } 64 65 createAccessibilityMenu() { 66 const div = document.createElement('div'); 67 div.classList.add('accessibility-menu-container'); 68 div.setAttribute('aria-hidden', 'true'); 69 div.setAttribute('tabindex', '-1'); 70 div.innerHTML = this.getHtmlMenu(); 71 72 const closeButton = div.querySelector('.accessibility-menu-close'); 73 closeButton.addEventListener('click', () => { 74 const menu = this.holder.querySelector('.accessibility-menu-container'); 75 if (menu) { 76 document.querySelector('.floating-button').focus(); 77 78 menu.classList.remove('show'); 79 menu.setAttribute('aria-hidden', 'true'); 80 } 81 }); 82 83 const menuBackdrop = div.querySelector('.accessibility-menu-backdrop'); 84 menuBackdrop.addEventListener('click', () => { 85 const menu = this.holder.querySelector('.accessibility-menu-container'); 86 if (menu) { 87 document.querySelector('.floating-button').focus(); 88 menu.classList.remove('show'); 89 menu.setAttribute('aria-hidden', 'true'); 90 } 91 }); 92 93 const settingsButtons = div.querySelectorAll('.accessibility-setting[data-action]'); 94 settingsButtons.forEach(button => { 95 button.addEventListener('click', (event) => { 96 const action = event.currentTarget.getAttribute('data-action'); 97 this.handleSettingAction(action); 98 }); 99 }); 100 101 const modalBackdrop = div.querySelector('.accessibility-modal-backdrop'); 102 modalBackdrop.addEventListener('click', () => { 103 const modal = this.holder.querySelector(this.selectorModal); 104 if (modal) { 105 modal.setAttribute('aria-hidden', 'true'); 106 modal.classList.remove('show'); 107 this.selectorModal = null; 108 } 109 }); 110 111 const cancelButtonModal = div.querySelectorAll('.accessibility-button-cancel'); 112 cancelButtonModal.forEach(button => { 113 button.addEventListener('click', () => { 114 const modal = this.holder.querySelector(this.selectorModal); 115 if (modal) { 116 modal.setAttribute('aria-hidden', 'true'); 117 modal.classList.remove('show'); 118 this.selectorModal = null; 119 } 120 }); 121 }); 122 123 const confirmButtonModal = div.querySelectorAll('.accessibility-button-confirm'); 124 confirmButtonModal.forEach(button => { 125 button.addEventListener('click', (event) => { 126 const action = event.currentTarget.getAttribute('data-modal-action'); 127 this.handleModalAction(action); 128 }); 129 }); 130 131 this.holder.appendChild(div); 132 } 133 134 initDefaultParameters() { 135 this.defaultZoomMultiplier = 0.16; 136 this.minZoomLevel = 0.5; 137 this.maxZoomLevel = 2.0; 138 139 this.defaultFontSizeMultiplier = 0.5; 140 // this.minFontSize = 10; 141 // this.maxFontSize = 52; 142 143 // Setto le variabili css per i colori dell'interfaccia 144 document.documentElement.style.setProperty('--accessibility-primary-color', this.primaryColor); 145 document.documentElement.style.setProperty('--accessibility-text-color', this.textColor); 146 147 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 148 const filtered = Array.from(elements).filter(el => !el.closest('.accessibility-menu-container') && !el.closest('.accessibility-floating-button-container')); 149 150 filtered.forEach(el => { 151 const style = window.getComputedStyle(el); 152 const fontSizeStr = style.fontSize; 153 const fontSize = parseFloat(fontSizeStr); 154 el.dataset.originalFontSize = fontSize; // Store original font size in a data attribute 155 }); 156 157 const landmarks = [ 158 { role: "banner", label: "Intestazione", target: this.holder.querySelector('header') }, 159 { role: "main", label: "Contenuto principale", target: this.holder.querySelector('main') }, 160 { role: "contentinfo", label: "Piè di pagina", target: this.holder.querySelector('footer') } 161 ]; 162
163 // Crea il container dei link di salto 164 const skipNav = document.createElement("nav"); 165 skipNav.setAttribute("aria-label", "Link rapidi"); 166 skipNav.classList.add("accessibility-skip-nav"); 167 168 // Genera i link verso i landmark 169 landmarks.forEach(lm => { 170 if (lm.target) { 171 const link = document.createElement("a"); 172 link.classList.add("accessibility-skip-link"); 173 link.setAttribute("role", "link"); 174 link.setAttribute("aria-label", `Vai a ${lm.label}`); 175 link.href = "#"; 176 link.textContent = `Vai a ${lm.label}`; 177 178 link.addEventListener("click", e => { 179 e.preventDefault(); 180 lm.target.setAttribute("tabindex", "-1"); // focusabile temporaneamente 181 lm.target.focus(); 182 }); 183 184 // Mostra i link quando ricevono focus 185 link.addEventListener("focusin", () => { 186 link.style.top = "0"; 187 }); 188 link.addEventListener("focusout", () => { 189 link.style.top = "-9999px"; 190 }); 191 192 skipNav.appendChild(link); 193 } 194 }); 195 196 document.body.prepend(skipNav); 197 198 // Mostra i link quando ricevono focus 199 skipNav.addEventListener("focusin", () => { 200 skipNav.style.left = "0"; 201 }); 202 skipNav.addEventListener("focusout", () => { 203 skipNav.style.left = "-9999px"; 204 }); 205 206 window.addEventListener('scroll', () => { 207 const floatingButton = this.holder.querySelector('.accessibility-floating-button'); 208 if (!floatingButton) return; 209 210 const isMenuOpen = this.holder.querySelector('.accessibility-menu-container.show'); 211 if (isMenuOpen) return; // Non fare nulla se il menu è aperto 212 213 const currentScrollTop = window.pageYOffset || document.documentElement.scrollTop; 214 if (currentScrollTop > 100) { 215 // Scrolling down 216 floatingButton.style.display = 'none'; // Nascondi il bottone 217 floatingButton.querySelector('.floating-button').setAttribute('tabindex', '-1'); // Rendi il bottone non focusabile 218 } else { 219 // Scrolling up 220 floatingButton.style.display = 'block'; // Mostra il bottone 221 floatingButton.querySelector('.floating-button').setAttribute('tabindex', '0'); // Rendi il bottone focusabile 222 } 223 }); 224 } 225 226 applySavedPreferences() { 227 const savedZoom = this.getCookie('zoomLevel'); 228 if (savedZoom) { 229 document.body.style.zoom = savedZoom; 230 const zoomPercentage = Math.round((parseFloat(savedZoom) - 1) * 100 / this.defaultZoomMultiplier); 231 this.holder.querySelector('#zoom-level').textContent = zoomPercentage === 0 ? 'Predefinito' : `${zoomPercentage}%`; 232 } 233 234 const savedFontSize = this.getCookie('fontSize'); 235 if (savedFontSize) { 236 const fontSizePercentage = parseInt(savedFontSize); 237 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 238 const filtered = Array.from(elements).filter(el => !el.closest('.accessibility-menu-container') && !el.closest('.accessibility-floating-button-container')); 239 240 filtered.forEach(el => { 241 const baseFontSize = parseFloat(el.dataset.originalFontSize) || 16; // Fallback to 16px if not set 242 const newFontSize = Math.round(baseFontSize + (this.defaultFontSizeMultiplier * (fontSizePercentage / 100) * baseFontSize)); 243 el.style.fontSize = `${newFontSize}px`; 244 }); 245 this.holder.querySelector('#font-size-level').textContent = fontSizePercentage === 0 ? 'Predefinito' : `${fontSizePercentage}%`; 246 } 247 248 const readableFont = this.getCookie('readableFont'); 249 if (readableFont === 'true') { 250 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 251
252 elements.forEach(el => { 253 el.style.fontFamily = 'Arial, sans-serif'; 254 }); 255 this.holder.querySelector('.accessibility-setting[data-action="readable-font"]').classList.add('active'); 256 } 257 258 const textAlignment = this.getCookie('textAlignment'); 259 if (textAlignment) { 260 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 261 262 elements.forEach(el => { 263 el.style.textAlign = textAlignment; 264 el.style.justifyContent = textAlignment === 'left' ? 'start' : textAlignment === 'right' ? 'end' : 'center'; 265 }); 266 this.holder.querySelectorAll('.accessibility-setting[data-action^="alterate-alignment-"]').forEach(btn => { 267 btn.classList.remove('active'); 268 if (btn.getAttribute('data-action') === `alterate-alignment-${textAlignment}`) { 269 btn.classList.add('active'); 270 } 271 }); 272 } 273 274 const filterColor = this.getCookie('filterColor'); 275 if (filterColor) { 276 const html = document.documentElement; 277 switch (filterColor) { 278 case 'high-contrast': 279 html.style.filter = 'contrast(1.5)'; 280 break; 281 case 'high-saturation': 282 html.style.filter = 'saturate(2)'; 283 break; 284 case 'monocromatic': 285 html.style.filter = 'grayscale(1)'; 286 break; 287 case 'low-saturation': 288 html.style.filter = 'saturate(0.5)'; 289 break; 290 default: 291 html.style.filter = ''; 292 } 293 this.holder.querySelectorAll('.accessibility-setting[data-action^="filter-"]').forEach(btn => { 294 btn.classList.remove('active'); 295 if (btn.getAttribute('data-action') === `filter-${filterColor}`) { 296 btn.classList.add('active'); 297 } 298 }); 299 } 300 } 301 302 handleSettingAction(action) { 303 switch (action) { 304 case 'reset-settings': 305 this.resetSettings(); 306 break; 307 case 'read-accessibility-statement': 308 // this.selectorModal = '#accessibility-modal-read-accessibility-statement'; 309 // this.showAccessibilityModal(); 310 window.open('/dichiarazione-di-accessibilita', '_blank'); 311 break; 312 case 'hide-accessibility': 313 this.selectorModal = '#accessibility-modal-hide-accessibility'; 314 this.showAccessibilityModal(); 315 break; 316 case 'increase-zoom': 317 this.increaseZoom(); 318 break; 319 case 'decrease-zoom': 320 this.decreaseZoom(); 321 break; 322 case 'increase-font-size': 323 this.increaseFontSize(); 324 break; 325 case 'decrease-font-size': 326 this.decreaseFontSize(); 327 break; 328 case 'readable-font': 329 this.toggleReadableFont(); 330 break; 331 case 'alterate-alignment-center': 332 this.toggleAlignment('center'); 333 break; 334 case 'alterate-alignment-left': 335 this.toggleAlignment('left'); 336 break; 337 case 'alterate-alignment-right': 338 this.toggleAlignment('right'); 339 break; 340 case 'filter-high-contrast': 341 this.filterColor('high-contrast'); 342 break; 343 case 'filter-high-saturation': 344 this.filterColor('high-saturation'); 345 break; 346 case 'filter-monocromatic': 347 this.filterColor('monocromatic'); 348 break; 349 case 'filter-low-saturation': 350 this.filterColor('low-saturation'); 351 break; 352 default: 353 console.warn(`${this.name}: Unknown action "${action}".`); 354 } 355 } 356 357 handleModalAction(action) { 358 switch (action) { 359 case 'hide-accessibility': 360 this.hideAccessibilityInterface(); 361 const modal = this.holder.querySelector(this.selectorModal); 362 if (modal) { 363 modal.setAttribute('aria-hidden', 'true'); 364 modal.classList.remove('show'); 365 this.selectorModal = null; 366 } 367 break; 368 default: 369 console.warn(`${this.name}: Unknown modal action "${action}".`); 370 } 371 } 372 373 resetSettings() { 374 this.setCookie('zoomLevel', '', -1); 375 this.setCookie('fontSize', '', -1); 376 this.setCookie('readableFont', '', -1); 377 this.setCookie('textAlignment', '', -1); 378 this.setCookie('filterColor', '', -1); 379 380 window.location.reload(); 381 } 382 383 hideAccessibilityInterface() { 384 this.setCookie('hideAccessibilityInterface', 'true', 365); 385 386 const floatingButton = this.holder.querySelector('.accessibility-floating-button'); 387 if (floatingButton) floatingButton.remove(); 388 const menu = this.holder.querySelector('.accessibility-menu'); 389 if (menu) menu.remove(); 390 391 this.resetSettings(); 392 } 393 394 showAccessibilityModal() { 395 const modal = this.holder.querySelector(this.selectorModal); 396 if (!modal) return; 397 398 modal.setAttribute('aria-hidden', 'false'); 399 modal.classList.add('show'); 400 modal.focus(); 401 } 402 403 increaseZoom() { 404 const currentZoom = document.body.style.zoom ? parseFloat(document.body.style.zoom) : 1;
405 const newZoom = Math.min(currentZoom + (0.1 * this.defaultZoomMultiplier), 1 + (this.defaultZoomMultiplier * this.maxZoomLevel)); // Limit max zoom to 200% 406 const newZoomPercentage = Math.round((newZoom - 1) * 100 / this.defaultZoomMultiplier); 407 document.body.style.zoom = newZoom; 408 this.holder.querySelector('#zoom-level').textContent = `${newZoomPercentage}%`; 409 if (newZoom === 1) this.holder.querySelector('#zoom-level').textContent = 'Predefinito'; 410 411 this.setCookie('zoomLevel', newZoom, 365); 412 } 413 414 decreaseZoom() { 415 const currentZoom = document.body.style.zoom ? parseFloat(document.body.style.zoom) : 1; 416 const newZoom = Math.max(currentZoom - (0.1 * this.defaultZoomMultiplier), 1 - (this.defaultZoomMultiplier * this.minZoomLevel)); // Limit min zoom -50% 417 const newZoomPercentage = Math.round((newZoom - 1) * 100 / this.defaultZoomMultiplier); 418 document.body.style.zoom = newZoom; 419 this.holder.querySelector('#zoom-level').textContent = `${newZoomPercentage}%`; 420 if (newZoom === 1) this.holder.querySelector('#zoom-level').textContent = 'Predefinito'; 421 422 this.setCookie('zoomLevel', newZoom, 365); 423 } 424 425 increaseFontSize() { 426 let fontSizePercentage = parseInt(this.getCookie('fontSize')); 427 if (isNaN(fontSizePercentage)) fontSizePercentage = 0; // Default font size 428 429 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 430 const filtered = Array.from(elements).filter(el => !el.closest('.accessibility-menu-container') && !el.closest('.accessibility-floating-button-container')); 431 432 filtered.forEach(el => { 433 const style = window.getComputedStyle(el); 434 const currentFontSize = style.fontSize ? parseFloat(style.fontSize) : 16; 435 const baseFontSize = parseFloat(el.dataset.originalFontSize) || 16; // Fallback to 16px if not set 436 const newFontSize = Math.round(currentFontSize + (this.defaultFontSizeMultiplier * 0.1 * baseFontSize)); 437 el.style.fontSize = `${newFontSize}px`; 438 }); 439 440 fontSizePercentage += 10; 441 this.setCookie('fontSize', fontSizePercentage, 365); 442 this.holder.querySelector('#font-size-level').textContent = `${fontSizePercentage}%`; 443 if (fontSizePercentage === 0) this.holder.querySelector('#font-size-level').textContent = 'Predefinito'; 444 } 445 446 decreaseFontSize() { 447 let fontSizePercentage = parseInt(this.getCookie('fontSize')); 448 if (isNaN(fontSizePercentage)) fontSizePercentage = 0; // Default font size 449 450 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 451 const filtered = Array.from(elements).filter(el => !el.closest('.accessibility-menu-container') && !el.closest('.accessibility-floating-button-container')); 452 453 filtered.forEach(el => { 454 const style = window.getComputedStyle(el); 455 const currentFontSize = style.fontSize ? parseFloat(style.fontSize) : 16; 456 const baseFontSize = parseFloat(el.dataset.originalFontSize) || 16; // Fallback to 16px if not set 457 const newFontSize = Math.round(currentFontSize - (this.defaultFontSizeMultiplier * 0.1 * baseFontSize)); 458 el.style.fontSize = `${newFontSize}px`; 459 }); 460 461 fontSizePercentage -= 10; 462 this.setCookie('fontSize', fontSizePercentage, 365); 463 this.holder.querySelector('#font-size-level').textContent = `${fontSizePercentage}%`; 464 if (fontSizePercentage === 0) this.holder.querySelector('#font-size-level').textContent = 'Predefinito'; 465 } 466 467 toggleReadableFont() { 468 const readableFont = this.getCookie('readableFont') || 'false'; 469 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 470 471 elements.forEach(el => { 472 if (readableFont !== 'true') { 473 el.style.fontFamily = 'Arial, sans-serif'; 474 } else { 475 el.style.fontFamily = ''; 476 } 477 }); 478 479 this.holder.querySelector('.accessibility-setting[data-action="readable-font"]').classList.toggle('active', readableFont !== 'true'); 480
481 setCookie('readableFont', readableFont === 'true' ? 'false' : 'true', 365); 482 } 483 484 toggleAlignment(alignment) { 485 const currentAlignment = this.getCookie('textAlignment'); 486 const elements = this.holder.querySelectorAll('h1, h2, h3, h4, h5, h6, p, a, li, span, div, input, textarea, button, select, label, legend'); 487 488 elements.forEach(el => { 489 if (currentAlignment === alignment) { 490 el.style.textAlign = ''; 491 el.style.justifyContent = ''; 492 } else { 493 el.style.textAlign = alignment; 494 el.style.justifyContent = alignment === 'left' ? 'start' : alignment === 'right' ? 'end' : 'center'; 495 } 496 }); 497 this.holder.querySelectorAll('.accessibility-setting[data-action^="alterate-alignment-"]').forEach(btn => { 498 btn.classList.remove('active'); 499 if (btn.getAttribute('data-action') === `alterate-alignment-${alignment}` && currentAlignment !== alignment) { 500 btn.classList.add('active'); 501 } 502 }); 503 504 this.setCookie('textAlignment', currentAlignment !== alignment ? alignment : '', 365); 505 } 506 507 filterColor(filter) { 508 const currentFilter = this.getCookie('filterColor'); 509 const html = document.documentElement; 510 html.style.filter = ''; 511 512 if (currentFilter === filter) { 513 this.setCookie('filterColor', '', -1); 514 this.holder.querySelectorAll('.accessibility-setting[data-action^="filter-"]').forEach(btn => btn.classList.remove('active')); 515 } else { 516 switch (filter) { 517 case 'high-contrast': 518 html.style.filter = 'contrast(1.5)'; 519 break; 520 case 'high-saturation': 521 html.style.filter = 'saturate(2)'; 522 break; 523 case 'monocromatic': 524 html.style.filter = 'grayscale(1)'; 525 break; 526 case 'low-saturation': 527 html.style.filter = 'saturate(0.5)'; 528 break; 529 default: 530 html.style.filter = ''; 531 } 532 this.setCookie('filterColor', filter, 365); 533 this.holder.querySelectorAll('.accessibility-setting[data-action^="filter-"]').forEach(btn => { 534 btn.classList.remove('active'); 535 if (btn.getAttribute('data-action') === `filter-${filter}`) { 536 btn.classList.add('active'); 537 } 538 }); 539 } 540 } 541 542 injectStyles() { 543 const linkElement = document.createElement('link'); 544 linkElement.rel = 'stylesheet'; 545 linkElement.href = `${this.websiteAccessibility}/assets/accessibility/accessibility.css?v=${new Date().getTime()}&ver=${this.version}`; 546 linkElement.onload = () => { 547 this.createAccessibilityFloatingButton(); 548 this.createAccessibilityMenu(); 549 this.initDefaultParameters(); 550 this.applySavedPreferences(); 551 }; 552 this.holder.appendChild(linkElement); 553 } 554 555 getHtmlFloatingButton() { 556 return ` 557 <div class="accessibility-floating-button" style="--accessibility-bottom: ${this.bottom}; --accessibility-left: ${this.left};"> 558 <button class="floating-button" aria-label="Apri/Chiudi Menu"> 559 <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="${this.primaryColor}"> 560 <path d="M480-723.85q-30.69 0-52.27-21.57-21.58-21.58-21.58-52.27 0-30.69 21.58-52.27 21.58-21.58 52.27-21.58 30.69 0 52.27 21.58 21.58 21.58 21.58 52.27 0 30.69-21.58 52.27-21.58 21.57-52.27 21.57ZM376.16-90v-521.54q-61.16-5-121.62-14.42-60.46-9.43-114.54-23.27l14.62-60q76.84 19.85 159.27 28.77 82.42 8.92 166.11 8.92 83.69 0 166.11-8.92 82.43-8.92 159.27-28.77l14.62 60q-54.08 13.84-114.54 23.27-60.46 9.42-121.62 14.42V-90h-59.99v-244.62h-87.7V-90h-59.99Z"/> 561 </svg> 562 </button> 563 </div> 564 `; 565 // <svg viewBox="0 0 20 24" width="20" height="24" fill="none"> 566 // <g fill="${this.primaryColor}" stroke="${this.primaryColor}" stroke-width=".318"> 567 // <path d="M17.887 5.683c-2.627.664-4.907 1.144-7.886 1.144-2.985 0-5.269-.483-7.904-1.149C1.3 5.476.477 5.91.23 6.67a1.436 1.436 0 0 0 .877 1.792c1.21.45
5675 2.43.855 3.668 1.26l1.094.36c.594.197.946.785.833 1.382L4.699 22.008c-.15.788.357 1.556 1.153 1.774.867.237 1.78-.256 2.007-1.1l1.698-6.32a.456.456 0 0 1 .444-.332c.21 0 .392.136.445.332l1.698 6.32c.227.844 1.14 1.337 2.007 1.1.796-.218 1.302-.986 1.153-1.774l-1.995-10.507c-.116-.61.256-1.21.87-1.405 1.59-.503 3.148-1.02 4.687-1.59a1.461 1.461 0 0 0 .907-1.816c-.246-.77-1.08-1.211-1.886-1.007Z"/> 568 // <path d="M10 5.657c.756 0 1.481-.29 2.016-.806a2.703 2.703 0 0 0 .836-1.943 2.68 2.68 0 0 0-.481-1.527 2.832 2.832 0 0 0-1.28-1.013A2.95 2.95 0 0 0 9.444.212a2.886 2.886 0 0 0-1.46.752 2.72 2.72 0 0 0-.78 1.408 2.658 2.658 0 0 0 .161 1.588c.216.502.582.932 1.05 1.234.47.302 1.021.463 1.585.463z"/> 569 // </g> 570 // </svg> 571 } 572 573 getHtmlMenu() { 574 return ` 575 <div class="accessibility-menu"> 576 <button class="accessibility-menu-close" aria-label="Chiudi Menu"> 577 <img src="${this.websiteAccessibility}/assets/accessibility/media/close-icon.png" alt="Icona chiudi" width="28" height="28"> 578 </button> 579 <div class="accessibility-menu-header"> 580 <p class="accessibility-title">Regolazione Accessibilità</p> 581 </div> 582 <div class="accessibility-menu-content"> 583 <button class="accessibility-button accessibility-setting" data-action="reset-settings" aria-label="Reset Impostazioni"> 584 <img src="${this.websiteAccessibility}/assets/accessibility/media/reset-icon.png" alt="Icona reset" width="21" height="21"> Reset impostazioni 585 </button> 586 <button class="accessibility-button accessibility-setting" data-action="read-accessibility-statement" aria-label="Leggi Dichiarazione di Accessibilità"> 587 <img src="${this.websiteAccessibility}/assets/accessibility/media/document-icon.png" alt="Icona documento" width="21" height="21"> Dichiarazione 588 </button> 589 <button class="accessibility-button accessibility-setting" data-action="hide-accessibility" aria-label="Nascondi Interfaccia Accessibilità"> 590 <img src="${this.websiteAccessibility}/assets/accessibility/media/hide-icon.png" alt="Icona nascondi" width="21" height="21"> Nascondi interfaccia 591 </button> 592 <div class="accessibility-menu-separator" role="separator" aria-orientation="horizontal"></div> 593 <p class="accessibility-title">Regolazione dei contenuti</p> 594 <div class="accessibility-settings-group"> 595 <div class="accessibility-col-12"> 596 <div class="accessibility-setting-item"> 597 <p id="alterate-zoom-label" class="accessibility-setting-label"> 598 <img src="${this.websiteAccessibility}/assets/accessibility/media/scale-icon.png" alt="Icona scala contenuto" width="21" height="21"> Scala i contenuti 599 </p> 600 <div class="accessibility-setting-controls"> 601 <button class="accessibility-button accessibility-setting" aria-label="Riduci Scala Contenuti" data-action="decrease-zoom"> 602 <img src="${this.websiteAccessibility}/assets/accessibility/media/remove-icon.png" alt="Icona diminuisci" width="21" height="21"> 603 </button> 604 <span id="zoom-level" class="accessibility-setting-value" aria-live="polite" aria-atomic="true">Predefinito</span> 605 <button class="accessibility-button accessibility-setting" aria-label="Aumenta Scala Contenuti" data-action="increase-zoom"> 606 <img src="${this.websiteAccessibility}/assets/accessibility/media/add-icon.png" alt="Icona incrementa" width="21" height="21"> 607 </button> 608 </div> 609 </div> 610 </div> 611 <div class="accessibility-col-12"> 612 <div class="accessibility-setting-item"> 613 <p id="alterate-font-size-label" class="accessibility-setting-label"> 614 <img src="${this.websiteAccessibility}/assets/accessibility/media/font-icon.png" alt="Icona dimensione caratteri" width="21" height="21"> Regola la dimensione dei caratteri 615 </p> 616 <div class="accessibility-setting-control
616s"> 617 <button class="accessibility-button accessibility-setting" aria-label="Riduci Dimensione Caratteri" data-action="decrease-font-size"> 618 <img src="${this.websiteAccessibility}/assets/accessibility/media/remove-icon.png" alt="Icona diminuisci" width="21" height="21"> 619 </button> 620 <span id="font-size-level" class="accessibility-setting-value" aria-live="polite" aria-atomic="true">Predefinito</span> 621 <button class="accessibility-button accessibility-setting" aria-label="Aumenta Dimensione Caratteri" data-action="increase-font-size"> 622 <img src="${this.websiteAccessibility}/assets/accessibility/media/add-icon.png" alt="Icona incrementa" width="21" height="21"> 623 </button> 624 </div> 625 </div> 626 </div> 627 </div> 628 <div class="accessibility-settings-group"> 629 <div class="accessibility-col-6"> 630 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#readable-font-label" data-action="readable-font"> 631 <img src="${this.websiteAccessibility}/assets/accessibility/media/text-icon.png" alt="Icona carattere" width="28" height="28"> 632 <p id="readable-font-label" class="accessibility-setting-label">
632Carattere leggibile</p> 633 </button> 634 </div> 635 <div class="accessibility-col-6"> 636 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#alterate-alignment-center-label" data-action="alterate-alignment-center"> 637 <img src="${this.websiteAccessibility}/assets/accessibility/media/align-center-icon.png" alt="Icona allinea centro" width="28" height="28"> 638 <p id="alterate-alignment-center-label" class="accessibility-setting-label">Allinea al centro</p> 639 </button> 640 </div> 641 <div class="accessibility-col-6"> 642 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#alterate-alignment-left-label" data-action="alterate-alignment-left"> 643 <img src="${this.websiteAccessibility}/assets/accessibility/media/align-left-icon.png" alt="Icona allinea sinistra" width="28" height="28"> 644 <p id="alterate-alignment-left-label" class="accessibility-setting-label">Allinea a sinistra</p> 645 </button> 646 </div> 647 <div class="accessibility-col-6"> 648 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#alterate-alignment-right-label" data-action="alterate-alignment-right"> 649 <img src="${this.websiteAccessibility}/assets/accessibility/media/align-right-icon.png" alt="Icona allinea destra" width="28" height="28"> 650 <p id="alterate-alignment-right-label" class="accessibility-setting-label">Allinea a destra</p> 651 </button> 652 </div> 653 </div> 654 <div class="accessibility-menu-separator" role="separator" aria-orientation="horizontal"></div> 655 <p class="accessibility-title">Regolazione del colore</p> 656 <div class="accessibility-settings-group"> 657 <div class="accessibility-col-6 accessibility-col-lg-4"> 658 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#high-contrast-label" data-action="filter-high-contrast"> 659 <img src="${this.websiteAccessibility}/assets/accessibility/media/contrast-icon.png" alt="Icona contrasto" width="28" height="28"> 660 <p id="high-contrast-label" class="accessibility-setting-label">Contrasto elevato</p> 661 </button> 662 </div> 663 <div class="accessibility-col-6 accessibility-col-lg-4"> 664 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#high-saturation-label" data-action="filter-high-saturation"> 665 <img src="${this.websiteAccessibility}/assets/accessibility/media/saturation-high-icon.png" alt="Icona saturazione alta" width="28" height="28"> 666 <p id="high-saturation-label" class="accessibility-setting-label">Saturazione elevata</p> 667 </button> 668 </div> 669 <div class="accessibility-col-6 accessibility-col-lg-4"> 670 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#monocromatic-label" data-action="filter-monocromatic"> 671 <img src="${this.websiteAccessibility}/assets/accessibility/media/mono-icon.png" alt="Icona monocromatico" width="28" height="28"> 672 <p id="monocromatic-label" class="accessibility-setting-label">Monocromatico</p> 673 </button> 674 </div> 675 <div class="accessibility-col-6"> 676 <button type="button" class="accessibility-setting-item accessibility-setting" aria-labelledby="#low-saturation-label" data-action="filter-low-saturation"> 677 <img src="${this.websiteAccessibility}/assets/accessibility/media/saturation-low-icon.png" alt="Icona saturaziona bassa" width="28" height="28"> 678 <p id="low-saturation-label" class="accessibility-setting-label">Saturazione bassa</p> 679 </button> 680 </div> 681 </div> 682 </div> 683 <div id="accessibility-modal-hide-accessibility" role="dialog" class="accessibility-modal" aria-hidden="true" tabindex="-1"> 684 <p class="accessibility-title">Vuoi nascondere l'interfaccia di accessibilità?</p> 685 <p>Attenzione: se scegli di nascondere l'interfaccia di accessibilità, non potrai più vederla, a meno che non cancelli la cronologia e i dati di navigazione. Sei sicuro di voler nascondere l'interfaccia?</p> 686 <div class="accessibility-modal-actions"> 687 <button class="accessibility-button accessibility-button-confirm" aria-label="Conferma Nascondi Interfaccia" data-modal-action="hide-accessibility">Conferma</button> 688 <button class="accessibility-button accessibility-button-cancel" aria-label="Annulla Nascondi Interfaccia">Annulla</button> 689 </div> 690 </div> 691 <div id="accessibility-modal-read-accessibility-statement" role="dialog" class="accessibility-modal" aria-hidden="true" tabindex="-1"> 692 <p class="accessibility-title">Dichiarazione di Accessibilità</p> 693 <div class="accessibility-section"> 694 <p class="accessibility-title-section">Stato di conformità</p> 695 <p class="accessibility-text">Crediamo fermamente che Internet debba essere disponibile e accessibile a chiunque e ci impegniamo a fornire un sito web accessibile al pubblico più ampio possibile, indipendentemente dalle abilità.</p> 696 <p class="accessibility-text">Per realizzare questo obiettivo, puntiamo ad aderire nel modo più rigoroso possibile alle Linee guida per l'accessibilità dei contenuti web 2.1 (WCAG 2.1) del World Wide Web Consortium (W3C), a livello AA. Queste linee guida spiegano come rendere i contenuti web accessibili a persone con una vasta gamma di disabilità. Rispettarle ci aiuta a garantire che il sito web sia accessibile a persone non vedenti, con disabilità motorie, problemi di vista, disabilità
696 cognitive e molto altro.</p> 697 <p class="accessibility-text">Questo sito web utilizza diverse tecnologie pensate per renderlo il più accessibile possibile in ogni momento. Utilizziamo un'interfaccia di accessibilità che consente alle persone con disabilità specifiche di modificare l'interfaccia utente (UI) del sito web e di adattarla alle proprie esigenze personali.</p> 698 <p class="accessibility-text">Inoltre, il sito web utilizza un'applicazione basata sull'intelligenza artificiale che opera in background e ottimizza costantemente il livello di accessibilità. Questa applicazione corregge il codice HTML del sito, adatta le sue funzionalità e il suo comportamento per i lettori di schermo utilizzati dagli utenti non vedenti e per le funzioni da tastiera impiegate da persone con disabilità motorie.</p> 699 <p class="accessibility-text">Nonostante i nostri sforzi, alcune parti del sito web potrebbero non essere ancora completamente conformi alle linee guida WCAG 2.1. Stiamo lavorando costantemente per migliorare l'accessibilità del sito e accogliamo con favore qualsiasi feedback o suggerimento che possa aiutarci in questo processo.</p> 700 <p class="accessibility-text">Se desideri contattare il proprietario del sito web, utilizza il modulo presente sul sito.</p> 701 </div> 702 <div class="accessibility-section"> 703 <p class="accessibility-title-section">Navigazione tramite lettore di schermo e tastiera</p> 704 <p class="accessibility-text">Il nostro sito web implementa la tecnica degli attributi ARIA (Accessible Rich Internet Applications), insieme a diverse modifiche comportamentali, per garantire che gli utenti non vedenti che utilizzano lettori di schermo possano leggere, comprendere e utilizzare pienamente le funzioni del sito. Non appena un utente con un lettore di schermo accede al sito, riceve immediatamente un prompt per inserire il Profilo del Lettore di Schermo, così da poter navigare e operare sul sito in modo efficace.<br/>Ecco come il nostro sito soddisfa alcuni dei requisiti più importanti per i lettori di schermo:</p> 705 <p class="accessibility-text"> 706 <ul> 707 <li> 708 <span class="accessibility-fw-500">Ottimizzazione per lettori di schermo:</span> 709 <br/> 710 Eseguiamo un processo che analizza i componenti del sito dall'alto verso il basso, per garantire la conformità continua anche durante gli aggiornamenti del sito. In questo processo forniamo ai lettori di schermo dati significativi tramite l'insieme di attributi ARIA. Ad esempio, forniamo etichette accurate per i moduli; descrizioni per le icone interattive (icone dei social media, icone di ricerca, icone del carrello, ecc.); indicazioni di convalida per i campi dei moduli; ruoli degli elementi come pulsanti, menu, finestre modali (popup) e altri. 711 <br/> 712 <br/> 713 Inoltre, il processo in background analizza tutte le immagini del sito web. Fornisce una descrizione accurata e significativa basata sul riconoscimento degli oggetti presenti nelle immagini, utilizzata come tag ALT (testo alternativo) per le immagini non descritte. Estrarre anche i testi incorporati nelle immagini tramite la tecnologia OCR (riconoscimento ottico dei caratteri). Per attivare le regolazioni per il lettore di schermo in qualsiasi momento, agli utenti basta premere la combinazione di tasti Alt+1. Gli utenti che utilizzano lettori di schermo ricevono anche annunci automatici che li invitano ad attivare la modalità Lettore di Schermo non appena accedono al sito. 714 <br/> 715 <br/> 716 Queste regolazioni sono compatibili con i principali lettori di schermo, come JAWS, NVDA, VoiceOver e TalkBack. 717 </li> 718 <li>
719 <span class="accessibility-fw-500">Ottimizzazione della navigazione tramite tastiera:</span> 720 </li> 721 </ul> 722 </p> 723 </div> 724 <div class="accessibility-modal-actions"> 725 <button class="accessibility-button accessibility-button-cancel" aria-label="Chiudi Dichiarazione">Chiudi</button> 726 </div> 727 </div> 728 <div class="accessibility-modal-backdrop"></div> 729 </div> 730 <div class="accessibility-menu-backdrop"></div> 731 `; 732 // <div class="accessibility-menu-footer"> 733 // <p class="accessibility-text-footer">Realizzato da <a href="${this.homepage}" target="_blank" rel="noopener">${this.authorHtml}</a></p> 734 // </div> 735 } 736 737 setCookie(name, value, days) { 738 const date = new Date(); 739 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 740 const expires = "expires=" + date.toUTCString(); 741 document.cookie = name + "=" + value + ";" + expires + ";path=/"; 742 } 743 744 getCookie(name) { 745 const nameEQ = name + "="; 746 const ca = document.cookie.split(';'); 747 for (let i = 0; i < ca.length; i++) { 748 let c = ca[i]; 749 while (c.charAt(0) === ' ') c = c.substring(1, c.length); 750 if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); 751 } 752 return null; 753 } 754}
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.