@@ -577,7 +577,7 @@ export class SpeechExplorer
577577 this . FocusOut ( null ) ;
578578 } else {
579579 this . stopEvent ( event ) ;
580- this . refocus = this . node . querySelector ( nav ) ;
580+ this . refocus = this . firstNode ( this . node ) ;
581581 this . Start ( ) ;
582582 }
583583 }
@@ -644,7 +644,7 @@ export class SpeechExplorer
644644 * Select top-level of expression
645645 */
646646 protected homeKey ( ) {
647- this . setCurrent ( this . node . querySelector ( nav ) ) ;
647+ this . setCurrent ( this . firstNode ( this . node ) ) ;
648648 }
649649
650650 /**
@@ -656,7 +656,7 @@ export class SpeechExplorer
656656 protected moveDown ( shift : boolean ) : boolean | void {
657657 return shift
658658 ? this . moveToNeighborCell ( 1 , 0 )
659- : this . moveTo ( this . current . querySelector ( nav ) ) ;
659+ : this . moveTo ( this . firstNode ( this . current ) ) ;
660660 }
661661
662662 /**
@@ -755,7 +755,7 @@ export class SpeechExplorer
755755 protected prevMark ( ) {
756756 if ( this . currentMark < 0 ) {
757757 if ( this . marks . length === 0 ) {
758- this . setCurrent ( this . lastMark || this . node . querySelector ( nav ) ) ;
758+ this . setCurrent ( this . lastMark || this . firstNode ( this . node ) ) ;
759759 return ;
760760 }
761761 this . currentMark = this . marks . length - 1 ;
@@ -991,7 +991,9 @@ export class SpeechExplorer
991991 // (i.e., we are focusing out)
992992 //
993993 if ( this . current ) {
994- this . current . classList . remove ( 'mjx-selected' ) ;
994+ for ( const part of this . getSplitNodes ( this . current ) ) {
995+ part . classList . remove ( 'mjx-selected' ) ;
996+ }
995997 this . pool . unhighlight ( ) ;
996998 if ( this . document . options . a11y . tabSelects === 'last' ) {
997999 this . refocus = this . current ;
@@ -1009,8 +1011,11 @@ export class SpeechExplorer
10091011 this . current = node ;
10101012 this . currentMark = - 1 ;
10111013 if ( this . current ) {
1012- this . current . classList . add ( 'mjx-selected' ) ;
1013- this . pool . highlight ( [ this . current ] ) ;
1014+ const parts = this . getSplitNodes ( this . current ) ;
1015+ for ( const part of parts ) {
1016+ part . classList . add ( 'mjx-selected' ) ;
1017+ }
1018+ this . pool . highlight ( parts ) ;
10141019 this . addSpeech ( node , addDescription ) ;
10151020 }
10161021 //
@@ -1019,6 +1024,20 @@ export class SpeechExplorer
10191024 this . node . removeAttribute ( 'aria-busy' ) ;
10201025 }
10211026
1027+ /**
1028+ * Get all nodes with the same semantic id (multiple nodes if there are line breaks).
1029+ *
1030+ * @param {HTMLElement } node The node to check if it is split
1031+ * @returns {HTMLElement[] } All the nodes for the given id
1032+ */
1033+ protected getSplitNodes ( node : HTMLElement ) : HTMLElement [ ] {
1034+ const id = this . nodeId ( node ) ;
1035+ if ( ! id ) {
1036+ return [ node ] ;
1037+ }
1038+ return Array . from ( this . node . querySelectorAll ( `[data-semantic-id="${ id } "]` ) ) ;
1039+ }
1040+
10221041 /**
10231042 * Remove the top-level speech node and create
10241043 * a temporary one for the given node.
@@ -1241,52 +1260,44 @@ export class SpeechExplorer
12411260 return cell ;
12421261 }
12431262
1263+ /**
1264+ * Get an element's first speech child.
1265+ *
1266+ * @param {HTMLElement } node The parent element to get a child from
1267+ * @returns {HTMLElement } The first speech child of the node
1268+ */
1269+ protected firstNode ( node : HTMLElement ) : HTMLElement {
1270+ return node . querySelector ( nav ) as HTMLElement ;
1271+ }
1272+
12441273 /**
12451274 * Navigate one step to the right on the same level.
12461275 *
1247- * @param {HTMLElement } el The current element.
1248- * @returns {HTMLElement } The next element.
1276+ * @param {HTMLElement } node The current element.
1277+ * @returns {HTMLElement } The next element.
12491278 */
1250- protected nextSibling ( el : HTMLElement ) : HTMLElement {
1251- if ( ! this . current . getAttribute ( 'data-semantic-parent' ) ) {
1252- return null ;
1253- }
1254- const sib = el . nextElementSibling as HTMLElement ;
1255- if ( sib ) {
1256- if ( sib . matches ( nav ) ) {
1257- return sib ;
1258- }
1259- const sibChild = sib . querySelector ( nav ) as HTMLElement ;
1260- return sibChild ?? this . nextSibling ( sib ) ;
1261- }
1262- if ( ! isContainer ( el ) && ! el . parentElement . matches ( nav ) ) {
1263- return this . nextSibling ( el . parentElement ) ;
1264- }
1265- return null ;
1279+ protected nextSibling ( node : HTMLElement ) : HTMLElement {
1280+ const id = this . parentId ( node ) ;
1281+ if ( ! id ) return null ;
1282+ const owns = this . getNode ( id ) . getAttribute ( 'data-semantic-owns' ) ?. split ( / / ) ;
1283+ if ( ! owns ) return null ;
1284+ const i = owns . indexOf ( this . nodeId ( node ) ) ;
1285+ return this . getNode ( owns [ i + 1 ] ) ;
12661286 }
12671287
12681288 /**
12691289 * Navigate one step to the left on the same level.
12701290 *
1271- * @param {HTMLElement } el The current element.
1272- * @returns {HTMLElement } The next element.
1291+ * @param {HTMLElement } node The current element.
1292+ * @returns {HTMLElement } The next element.
12731293 */
1274- protected prevSibling ( el : HTMLElement ) : HTMLElement {
1275- if ( ! this . current . getAttribute ( 'data-semantic-parent' ) ) {
1276- return null ;
1277- }
1278- const sib = el . previousElementSibling as HTMLElement ;
1279- if ( sib ) {
1280- if ( sib . matches ( nav ) ) {
1281- return sib ;
1282- }
1283- const sibChild = sib . querySelector ( nav ) as HTMLElement ;
1284- return sibChild ?? this . prevSibling ( sib ) ;
1285- }
1286- if ( ! isContainer ( el ) && ! el . parentElement . matches ( nav ) ) {
1287- return this . prevSibling ( el . parentElement ) ;
1288- }
1289- return null ;
1294+ protected prevSibling ( node : HTMLElement ) : HTMLElement {
1295+ const id = this . parentId ( node ) ;
1296+ if ( ! id ) return null ;
1297+ const owns = this . getNode ( id ) . getAttribute ( 'data-semantic-owns' ) ?. split ( / / ) ;
1298+ if ( ! owns ) return null ;
1299+ const i = owns . indexOf ( this . nodeId ( node ) ) ;
1300+ return this . getNode ( owns [ i - 1 ] ) ;
12901301 }
12911302
12921303 /**
@@ -1455,7 +1466,7 @@ export class SpeechExplorer
14551466 // current node (which creates the speech) and start the explorer.
14561467 //
14571468 const node = this . findStartNode ( ) ;
1458- this . setCurrent ( node || this . node . querySelector ( nav ) , ! node ) ;
1469+ this . setCurrent ( node || this . firstNode ( this . node ) , ! node ) ;
14591470 super . Start ( ) ;
14601471 //
14611472 // Show any needed regions
0 commit comments