@@ -151,7 +151,7 @@ export function EnrichedMathItemMixin<N, T, D, B extends Constructor<AbstractMat
151151 public generatorPool = new GeneratorPool < N , T , D > ( ) ;
152152
153153 /**
154- * The MathML adaptor.
154+ * The MathML serializer
155155 */
156156 public toMathML = toMathML ;
157157
@@ -285,9 +285,11 @@ export function EnrichedMathItemMixin<N, T, D, B extends Constructor<AbstractMat
285285 const node = this . typesetRoot ;
286286 if ( speech && options . enableSpeech ) {
287287 adaptor . setAttribute ( node , 'aria-label' , speech as string ) ;
288+ this . root . attributes . set ( 'aria-label' , speech ) ;
288289 }
289290 if ( braille && options . enableBraille ) {
290291 adaptor . setAttribute ( node , 'aria-braillelabel' , braille as string ) ;
292+ this . root . attributes . set ( 'aria-braillelabel' , braille ) ;
291293 }
292294 for ( const child of adaptor . childNodes ( node ) as N [ ] ) {
293295 adaptor . setAttribute ( child , 'aria-hidden' , 'true' ) ;
@@ -379,6 +381,7 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
379381 attachSpeech : [ STATE . ATTACHSPEECH ]
380382 } ) ,
381383 speechTiming : {
384+ asynchronous : true , // true to allow screen updates while adding speech, false to not
382385 initial : 100 , // initial delay until starting to add speech
383386 threshold : 250 , // time (in milliseconds) to process speech before letting screen update
384387 intermediate : 10 // delay after processing speech reaches the threshold
@@ -406,6 +409,11 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
406409 */
407410 protected speechTimeout : number = 0 ;
408411
412+ /**
413+ * The function to resolve when the speech loop finishes
414+ */
415+ protected attachSpeechDone : ( ) => void ;
416+
409417 /**
410418 * Enrich the MathItem class used for this MathDocument, and create the
411419 * temporary MathItem used for enrchment
@@ -435,21 +443,46 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
435443 public attachSpeech ( ) {
436444 if ( ! this . processed . isSet ( 'attach-speech' ) ) {
437445 if ( this . options . enableSpeech || this . options . enableBraille ) {
438- if ( this . speechTimeout ) {
439- clearTimeout ( this . speechTimeout ) ;
440- this . speechTimeout = 0 ;
446+ if ( this . options . speechTiming . asynchronous ) {
447+ this . attachSpeechAsync ( ) ;
448+ } else {
449+ this . attachSpeechSync ( ) ;
441450 }
442- this . awaitingSpeech = Array . from ( this . math ) ;
443- this . speechTimeout = setTimeout (
444- ( ) => this . attachSpeechLoop ( ) ,
445- this . options . speechTiming . initial
446- ) ;
447451 }
448452 this . processed . set ( 'attach-speech' ) ;
449453 }
450454 return this ;
451455 }
452456
457+ /**
458+ * Add speech synchronously (e.g., for use in node applications on the server)
459+ */
460+ protected attachSpeechSync ( ) {
461+ for ( const math of this . math ) {
462+ ( math as EnrichedMathItem < N , T , D > ) . attachSpeech ( this ) ;
463+ }
464+ }
465+
466+ /**
467+ * Add speech in small chunks, allowing screen updates in between
468+ * (e.g., helpful with lazy typesetting)
469+ */
470+ protected attachSpeechAsync ( ) {
471+ if ( this . speechTimeout ) {
472+ clearTimeout ( this . speechTimeout ) ;
473+ this . speechTimeout = 0 ;
474+ this . attachSpeechDone ( ) ;
475+ }
476+ this . awaitingSpeech = Array . from ( this . math ) ;
477+ this . renderPromises . push ( new Promise < void > ( ( ok , _fail ) => {
478+ this . attachSpeechDone = ok ;
479+ } ) ) ;
480+ this . speechTimeout = setTimeout (
481+ ( ) => this . attachSpeechLoop ( ) ,
482+ this . options . speechTiming . initial
483+ ) ;
484+ }
485+
453486 /**
454487 * Loops through math items to attach speech until the timeout threshold is reached.
455488 */
@@ -462,8 +495,12 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
462495 const math = awaitingSpeech . shift ( ) ;
463496 ( math as EnrichedMathItem < N , T , D > ) . attachSpeech ( this ) ;
464497 } while ( awaitingSpeech . length && new Date ( ) . getTime ( ) < timeEnd ) ;
465- this . speechTimeout = awaitingSpeech . length ?
466- setTimeout ( ( ) => this . attachSpeechLoop ( ) , timing . intermediate ) : 0 ;
498+ if ( awaitingSpeech . length ) {
499+ this . speechTimeout = setTimeout ( ( ) => this . attachSpeechLoop ( ) , timing . intermediate ) ;
500+ } else {
501+ this . speechTimeout = 0 ;
502+ this . attachSpeechDone ( ) ;
503+ }
467504 }
468505
469506 /**
0 commit comments