@@ -20,6 +20,7 @@ $(function () {
2020 am4core . options . autoDispose = true ;
2121
2222 let a11yScheduled = false ;
23+ let transcriptChartA11yObserver = null ;
2324
2425 function scheduleTranscriptChartA11yFix ( ) {
2526 if ( a11yScheduled ) return ;
@@ -31,6 +32,20 @@ $(function () {
3132 } ) ;
3233 }
3334
35+ function makeNodeUnfocusable ( node ) {
36+ node . removeAttribute ( 'tabindex' ) ;
37+ node . removeAttribute ( 'focusable' ) ;
38+ node . removeAttribute ( 'role' ) ;
39+ node . removeAttribute ( 'aria-label' ) ;
40+ node . removeAttribute ( 'aria-labelledby' ) ;
41+ node . removeAttribute ( 'aria-controls' ) ;
42+ node . removeAttribute ( 'aria-checked' ) ;
43+ node . removeAttribute ( 'aria-hidden' ) ;
44+ node . setAttribute ( 'tabindex' , '-1' ) ;
45+ node . setAttribute ( 'focusable' , 'false' ) ;
46+ node . setAttribute ( 'aria-hidden' , 'true' ) ;
47+ }
48+
3449 function fixTranscriptChartSvgA11y ( ) {
3550 try {
3651 const container = document . getElementById ( 'transcripts' ) ;
@@ -39,30 +54,76 @@ $(function () {
3954 const svg = container . querySelector ( 'svg' ) ;
4055 if ( ! svg ) return ;
4156
42- // We expose the accessible name/description on #transcripts (HTML),
43- // so hide the amCharts SVG internals from screen readers/scanners.
4457 svg . setAttribute ( 'aria-hidden' , 'true' ) ;
4558 svg . setAttribute ( 'focusable' , 'false' ) ;
4659
47- // Remove amCharts-generated landmark-ish nodes that Silktide flags as "g field label".
48- svg . querySelectorAll ( 'g[role], g[aria-label], g[aria-labelledby]' ) . forEach ( function ( node ) {
60+ svg . querySelectorAll (
61+ '[role], [aria-label], [aria-labelledby], [aria-controls], [aria-checked]'
62+ ) . forEach ( function ( node ) {
4963 node . removeAttribute ( 'role' ) ;
5064 node . removeAttribute ( 'aria-label' ) ;
5165 node . removeAttribute ( 'aria-labelledby' ) ;
66+ node . removeAttribute ( 'aria-controls' ) ;
67+ node . removeAttribute ( 'aria-checked' ) ;
5268 } ) ;
5369
54- // Also strip focus hooks if any appear.
55- svg . querySelectorAll ( '[tabindex]' ) . forEach ( function ( node ) {
56- node . removeAttribute ( 'tabindex' ) ;
70+ svg . querySelectorAll (
71+ '[tabindex], [focusable], [role="switch"], [aria-controls], [aria-checked]'
72+ ) . forEach ( function ( node ) {
73+ makeNodeUnfocusable ( node ) ;
5774 } ) ;
58- svg . querySelectorAll ( '[focusable]' ) . forEach ( function ( node ) {
59- node . removeAttribute ( 'focusable' ) ;
75+
76+ svg . querySelectorAll (
77+ '[aria-hidden="true"], [display="none"], [visibility="hidden"], [opacity="0"]'
78+ ) . forEach ( function ( node ) {
79+ makeNodeUnfocusable ( node ) ;
80+
81+ node . querySelectorAll (
82+ 'a, button, [tabindex], [focusable], [role], [aria-controls], [aria-checked]'
83+ ) . forEach ( function ( child ) {
84+ makeNodeUnfocusable ( child ) ;
85+ } ) ;
6086 } ) ;
6187 } catch ( e ) {
6288 // swallow
6389 }
6490 }
6591
92+ function observeTranscriptChartA11y ( ) {
93+ const container = document . getElementById ( 'transcripts' ) ;
94+ if ( ! container ) return ;
95+
96+ if ( transcriptChartA11yObserver ) {
97+ transcriptChartA11yObserver . disconnect ( ) ;
98+ }
99+
100+ transcriptChartA11yObserver = new MutationObserver ( function ( mutations ) {
101+ for ( const mutation of mutations ) {
102+ if ( mutation . type === 'childList' || mutation . type === 'attributes' ) {
103+ scheduleTranscriptChartA11yFix ( ) ;
104+ return ;
105+ }
106+ }
107+ } ) ;
108+
109+ transcriptChartA11yObserver . observe ( container , {
110+ childList : true ,
111+ subtree : true ,
112+ attributes : true ,
113+ attributeFilter : [
114+ 'tabindex' ,
115+ 'focusable' ,
116+ 'role' ,
117+ 'aria-hidden' ,
118+ 'aria-label' ,
119+ 'aria-labelledby' ,
120+ 'display' ,
121+ 'visibility' ,
122+ 'opacity' ,
123+ ] ,
124+ } ) ;
125+ }
126+
66127 let buildChart = function ( data ) {
67128 let transcripts = am4core . createFromConfig ( data , "transcripts" , am4charts . XYChart ) ;
68129
@@ -91,6 +152,7 @@ $(function () {
91152
92153 transcripts . events . on ( 'ready' , function ( ) {
93154 $ ( "#script-modal" ) . modal ( "hide" ) ;
155+ observeTranscriptChartA11y ( ) ;
94156 scheduleTranscriptChartA11yFix ( ) ;
95157 } ) ;
96158 } ,
0 commit comments