1(() => { 2 function initAccessibility() { 3 const toggle = document.getElementById('accessibility-toggle'); 4 const menu = document.getElementById('accessibility-menu'); 5 const contrast = document.getElementById('contrast-select'); 6 const font = document.getElementById('font-select'); 7 const lineheight = document.getElementById('lineheight-select'); 8 const colorblind = document.getElementById('colorblindMode'); 9 const resetBtn = document.getElementById('reset-accessibility'); 10 11 const announcer = document.getElementById('accessibility-announcer'); 12 function announce(msg) { 13 if (announcer) announcer.textContent = msg; 14 } 15 16 if (!toggle || !menu) { 17 setTimeout(initAccessibility, 100); 18 return; 19 } 20 if (toggle.dataset.accessibilityInit) return; 21 toggle.dataset.accessibilityInit = true; 22 23 const WIDGET_SELECTOR = '#accessibility-widget'; 24 let rotation = 0; 25 26 toggle.addEventListener('click', (e) => { 27 e.stopPropagation(); 28 const isOpen = menu.classList.toggle('visible'); 29 rotation += isOpen ? 360 : -360; 30 toggle.style.transform = `rotate(${rotation}deg) scale(1.1)`; 31 toggle.setAttribute('aria-expanded', isOpen); 32 }); 33 34 document.addEventListener('click', (e) => { 35 if (!menu.contains(e.target) && !toggle.contains(e.target)) { 36 menu.classList.remove('visible'); 37 toggle.setAttribute('aria-expanded', 'false'); 38 } 39 }); 40 41 document.addEventListener('keydown', (e) => { 42 if (e.key === 'Escape' && menu.classList.contains('visible')) { 43 menu.classList.remove('visible'); 44 toggle.setAttribute('aria-expanded', 'false'); 45 } 46 }); 47 48 function loadState() { 49 try { 50 const saved = JSON.parse(localStorage.getItem('acc_prefs') || '{}'); 51 return { 52 contrast: saved.contrast || 'default', 53 font: saved.font || 'default', 54 lineheight: saved.lineheight || 'default', 55 brightness: saved.brightness || 0, 56 colorblind: saved.colorblind || 'none' 57 }; 58 } catch (e) { 59 return { contrast: 'default', font: 'default', lineheight: 'default', brightness: 0, colorblind: 'none' }; 60 } 61 } 62 63 function saveState(state) { 64 try { localStorage.setItem('acc_prefs', JSON.stringify(state)); } catch(e){} 65 } 66 67 function applyState(state) { 68 document.body.classList.remove( 69 'contrast-high','contrast-invert', 70 'font-dyslexic','lineheight-large', 71 'assist-protanopia','assist-deuteranopia', 72 'assist-tritanopia','assist-achromatopsia' 73 ); 74 75 if (state.contrast === 'high') document.body.classList.add('contrast-high'); 76 if (state.contrast === 'invert') document.body.classList.add('contrast-invert'); 77 if (state.font === 'dyslexic') document.body.classList.add('font-dyslexic'); 78 if (state.lineheight === 'large') document.body.classList.add('lineheight-large'); 79 if (state.colorblind && state.colorblind !== 'none') { 80 document.body.classList.add('assist-' + state.colorblind); 81 } 82 83 applyBrightness(state.brightness); 84 } 85 86 function parseRgbString(str) { 87 if (!str) return null; 88 const m = str.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([0-9.]+))?\)/); 89 if (!m) return null; 90 return { r: +m[1], g: +m[2], b: +m[3], a: m[4] !== undefined ? +m[4] : 1 }; 91 } 92 93 function rgbObjToString(o) { 94 if (o.a !== undefined && o.a < 1) return `rgba(${o.r}, ${o.g}, ${o.b}, ${o.a})`; 95 return `rgb(${o.r}, ${o.g}, ${o.b})`; 96 } 97 98 function rgbToHsl(r,g,b){ 99 r/=255; g/=255; b/=255; 100 const max=Math.max(r,g,b), min=Math.min(r,g,b); 101 let h=0,s=0,l=(max+min)/2; 102 if(max!==min){ 103 const d=max-min; 104 s=l>0.5 ? d/(2-max-min) : d/(max+min); 105 switch(max){ 106 case r: h=(g-b)/d + (g<b?6:0); break; 107 case g: h=(b-r)/d + 2; break; 108 case b: h=(r-g)/d + 4; break; 109 } 110 h/=6; 111 } 112 return [h,s,l]; 113 } 114 115 function hslToRgb(h,s,l){ 116 let r,g,b; 117 if(s===0) r=g=b=l; 118 else{
119 const hue2rgb=(p,q,t)=>{ 120 if(t<0) t+=1; 121 if(t>1) t-=1; 122 if(t<1/6) return p+(q-p)*6*t; 123 if(t<1/2) return q; 124 if(t<2/3) return p+(q-p)*(2/3-t)*6; 125 return p; 126 }; 127 const q=l<0.5?l*(1+s):l+s-l*s; 128 const p=2*l-q; 129 r=hue2rgb(p,q,h+1/3); 130 g=hue2rgb(p,q,h); 131 b=hue2rgb(p,q,h-1/3); 132 } 133 return [Math.round(r*255),Math.round(g*255),Math.round(b*255)]; 134 } 135 136 function adjustLightness(rgbString, amount){ 137 const p=parseRgbString(rgbString); 138 if(!p) return rgbString; 139 140 let [h,s,l]=rgbToHsl(p.r,p.g,p.b); 141 142 if(l <= 0.15 || l >= 0.85) return rgbString; 143 144 const DARK_SCALE=0.3,LIGHT_SCALE=0.9; 145 l += amount<0 ? (amount/100)*DARK_SCALE : (amount/100)*LIGHT_SCALE; 146 l=Math.max(0,Math.min(1,l)); 147 const [nr,ng,nb]=hslToRgb(h,s,l); 148 return `rgb(${nr}, ${ng}, ${nb})`; 149 } 150 151 /* ======================================================= 152 ð¥ CORRECTION ICI : on ignore les éléments interactifs 153 ======================================================= */ 154 155 function applyBrightness(amount){ 156 document.querySelectorAll('*').forEach(el=>{ 157 if(el.closest && el.closest(WIDGET_SELECTOR)) return; 158 159 // â NE PAS toucher aux éléments interactifs 160 if ( 161 el.matches('button, a, input, select, textarea') || 162 el.closest('button, a, input, select, textarea') || 163 el.classList.contains('btn') || 164 el.classList.contains('sppb-btn') || 165 el.getAttribute('role') === 'button' 166 ) { 167 return; 168 } 169 170 const style = getComputedStyle(el); 171 172 if(!el.dataset.originalColor && style.color) 173 el.dataset.originalColor = style.color; 174 175 if(!el.dataset.originalBg && style.backgroundColor) 176 el.dataset.originalBg = style.backgroundColor; 177 178 if(el.dataset.originalBg) 179 el.style.backgroundColor = adjustLightness(el.dataset.originalBg, amount); 180 181 if(el.dataset.originalColor) 182 el.style.color = adjustLightness(el.dataset.originalColor, amount); 183 }); 184 } 185 186 const state=loadState(); 187 applyState(state); 188 189 contrast?.addEventListener('change',()=>{state.contrast=contrast.value; applyState(state); saveState(state);}); 190 font?.addEventListener('change',()=>{state.font=font.value; applyState(state); saveState(state);}); 191 lineheight?.addEventListener('change',()=>{state.lineheight=lineheight.value; applyState(state); saveState(state);}); 192 colorblind?.addEventListener('change',()=>{state.colorblind=colorblind.value; applyState(state); saveState(state);}); 193 194 resetBtn?.addEventListener('click',()=> { 195 state.contrast='default'; 196 state.font='default'; 197 state.lineheight='default'; 198 state.brightness=0; 199 state.colorblind='none'; 200 applyState(state); 201 saveState(state); 202 applyBrightness(0); 203 announce('Préférences réinitialisées'); 204 }); 205 } 206 207 if(document.readyState==='loading') 208 document.addEventListener('DOMContentLoaded',initAccessibility); 209 else initAccessibility(); 210})();
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.