@@ -582,7 +582,7 @@ export class SpeechExplorer
582582 this . FocusOut ( null ) ;
583583 } else {
584584 this . stopEvent ( event ) ;
585- this . refocus = this . node . querySelector ( nav ) ;
585+ this . refocus = this . firstNode ( this . node ) ;
586586 this . Start ( ) ;
587587 }
588588 }
@@ -649,7 +649,7 @@ export class SpeechExplorer
649649 * Select top-level of expression
650650 */
651651 protected homeKey ( ) {
652- this . setCurrent ( this . node . querySelector ( nav ) ) ;
652+ this . setCurrent ( this . firstNode ( this . node ) ) ;
653653 }
654654
655655 /**
@@ -661,7 +661,7 @@ export class SpeechExplorer
661661 protected moveDown ( shift : boolean ) : boolean | void {
662662 return shift
663663 ? this . moveToNeighborCell ( 1 , 0 )
664- : this . moveTo ( this . current . querySelector ( nav ) ) ;
664+ : this . moveTo ( this . firstNode ( this . current ) ) ;
665665 }
666666
667667 /**
@@ -760,7 +760,7 @@ export class SpeechExplorer
760760 protected prevMark ( ) {
761761 if ( this . currentMark < 0 ) {
762762 if ( this . marks . length === 0 ) {
763- this . setCurrent ( this . lastMark || this . node . querySelector ( nav ) ) ;
763+ this . setCurrent ( this . lastMark || this . firstNode ( this . node ) ) ;
764764 return ;
765765 }
766766 this . currentMark = this . marks . length - 1 ;
@@ -996,7 +996,9 @@ export class SpeechExplorer
996996 // (i.e., we are focusing out)
997997 //
998998 if ( this . current ) {
999- this . current . classList . remove ( 'mjx-selected' ) ;
999+ for ( const part of this . getSplitNodes ( this . current ) ) {
1000+ part . classList . remove ( 'mjx-selected' ) ;
1001+ }
10001002 this . pool . unhighlight ( ) ;
10011003 if ( this . document . options . a11y . tabSelects === 'last' ) {
10021004 this . refocus = this . current ;
@@ -1014,8 +1016,11 @@ export class SpeechExplorer
10141016 this . current = node ;
10151017 this . currentMark = - 1 ;
10161018 if ( this . current ) {
1017- this . current . classList . add ( 'mjx-selected' ) ;
1018- this . pool . highlight ( [ this . current ] ) ;
1019+ const parts = this . getSplitNodes ( this . current ) ;
1020+ for ( const part of parts ) {
1021+ part . classList . add ( 'mjx-selected' ) ;
1022+ }
1023+ this . pool . highlight ( parts ) ;
10191024 this . addSpeech ( node , addDescription ) ;
10201025 }
10211026 //
@@ -1024,6 +1029,20 @@ export class SpeechExplorer
10241029 this . node . removeAttribute ( 'aria-busy' ) ;
10251030 }
10261031
1032+ /**
1033+ * Get all nodes with the same semantic id (multiple nodes if there are line breaks).
1034+ *
1035+ * @param {HTMLElement } node The node to check if it is split
1036+ * @returns {HTMLElement[] } All the nodes for the given id
1037+ */
1038+ protected getSplitNodes ( node : HTMLElement ) : HTMLElement [ ] {
1039+ const id = this . nodeId ( node ) ;
1040+ if ( ! id ) {
1041+ return [ node ] ;
1042+ }
1043+ return Array . from ( this . node . querySelectorAll ( `[data-semantic-id="${ id } "]` ) ) ;
1044+ }
1045+
10271046 /**
10281047 * Remove the top-level speech node and create
10291048 * a temporary one for the given node.
@@ -1273,52 +1292,44 @@ export class SpeechExplorer
12731292 return cell ;
12741293 }
12751294
1295+ /**
1296+ * Get an element's first speech child.
1297+ *
1298+ * @param {HTMLElement } node The parent element to get a child from
1299+ * @returns {HTMLElement } The first speech child of the node
1300+ */
1301+ protected firstNode ( node : HTMLElement ) : HTMLElement {
1302+ return node . querySelector ( nav ) as HTMLElement ;
1303+ }
1304+
12761305 /**
12771306 * Navigate one step to the right on the same level.
12781307 *
1279- * @param {HTMLElement } el The current element.
1280- * @returns {HTMLElement } The next element.
1308+ * @param {HTMLElement } node The current element.
1309+ * @returns {HTMLElement } The next element.
12811310 */
1282- protected nextSibling ( el : HTMLElement ) : HTMLElement {
1283- if ( ! this . current . getAttribute ( 'data-semantic-parent' ) ) {
1284- return null ;
1285- }
1286- const sib = el . nextElementSibling as HTMLElement ;
1287- if ( sib ) {
1288- if ( sib . matches ( nav ) ) {
1289- return sib ;
1290- }
1291- const sibChild = sib . querySelector ( nav ) as HTMLElement ;
1292- return sibChild ?? this . nextSibling ( sib ) ;
1293- }
1294- if ( ! isContainer ( el ) && ! el . parentElement . matches ( nav ) ) {
1295- return this . nextSibling ( el . parentElement ) ;
1296- }
1297- return null ;
1311+ protected nextSibling ( node : HTMLElement ) : HTMLElement {
1312+ const id = this . parentId ( node ) ;
1313+ if ( ! id ) return null ;
1314+ const owns = this . getNode ( id ) . getAttribute ( 'data-semantic-owns' ) ?. split ( / / ) ;
1315+ if ( ! owns ) return null ;
1316+ const i = owns . indexOf ( this . nodeId ( node ) ) ;
1317+ return this . getNode ( owns [ i + 1 ] ) ;
12981318 }
12991319
13001320 /**
13011321 * Navigate one step to the left on the same level.
13021322 *
1303- * @param {HTMLElement } el The current element.
1304- * @returns {HTMLElement } The next element.
1323+ * @param {HTMLElement } node The current element.
1324+ * @returns {HTMLElement } The next element.
13051325 */
1306- protected prevSibling ( el : HTMLElement ) : HTMLElement {
1307- if ( ! this . current . getAttribute ( 'data-semantic-parent' ) ) {
1308- return null ;
1309- }
1310- const sib = el . previousElementSibling as HTMLElement ;
1311- if ( sib ) {
1312- if ( sib . matches ( nav ) ) {
1313- return sib ;
1314- }
1315- const sibChild = sib . querySelector ( nav ) as HTMLElement ;
1316- return sibChild ?? this . prevSibling ( sib ) ;
1317- }
1318- if ( ! isContainer ( el ) && ! el . parentElement . matches ( nav ) ) {
1319- return this . prevSibling ( el . parentElement ) ;
1320- }
1321- return null ;
1326+ protected prevSibling ( node : HTMLElement ) : HTMLElement {
1327+ const id = this . parentId ( node ) ;
1328+ if ( ! id ) return null ;
1329+ const owns = this . getNode ( id ) . getAttribute ( 'data-semantic-owns' ) ?. split ( / / ) ;
1330+ if ( ! owns ) return null ;
1331+ const i = owns . indexOf ( this . nodeId ( node ) ) ;
1332+ return this . getNode ( owns [ i - 1 ] ) ;
13221333 }
13231334
13241335 /**
@@ -1487,7 +1498,7 @@ export class SpeechExplorer
14871498 // current node (which creates the speech) and start the explorer.
14881499 //
14891500 const node = this . findStartNode ( ) ;
1490- this . setCurrent ( node || this . node . querySelector ( nav ) , ! node ) ;
1501+ this . setCurrent ( node || this . firstNode ( this . node ) , ! node ) ;
14911502 super . Start ( ) ;
14921503 //
14931504 // Show any needed regions
0 commit comments