@@ -294,8 +294,32 @@ export class SpeechExplorer extends AbstractExplorer<string> implements KeyExplo
294294 [ '>' , this . nextRules . bind ( this ) ] ,
295295 [ '<' , this . nextStyle . bind ( this ) ] ,
296296 [ 'x' , this . summary . bind ( this ) ] ,
297+ [ '-' , this . expand . bind ( this ) ] ,
297298 ] ) ;
298299
300+ /**
301+ * Checks if a node is actionable, i.e., corresponds to an maction.
302+ *
303+ * @param {HTMLElement } node The (rendered) node under consideration.
304+ * @returns {HTMLElement } The node corresponding to an maction element.
305+ */
306+ private actionable ( node : HTMLElement ) : HTMLElement {
307+ const parent = node ?. parentNode as HTMLElement ;
308+ return parent && this . highlighter . isMactionNode ( parent ) ? parent : null ;
309+ }
310+
311+ /**
312+ * Expands or collapses the currently focused node.
313+ *
314+ * @param {HTMLElement } node The focused node.
315+ */
316+ public expand ( node : HTMLElement ) {
317+ const expandable = this . actionable ( node ) ;
318+ if ( expandable ) {
319+ expandable . dispatchEvent ( new Event ( 'click' ) ) ;
320+ }
321+ }
322+
299323 /**
300324 * Computes the summary for this expression. This is temporary and will be
301325 * replaced by the full speech on focus out.
@@ -408,9 +432,22 @@ export class SpeechExplorer extends AbstractExplorer<string> implements KeyExplo
408432 // Here we refocus after a restart: We either find the previously focused
409433 // node or we assume that it is inside the collapsed expression tree and
410434 // focus on the collapsed element.
411- this . current =
412- this . node . querySelector ( `[data-semantic-id="${ this . restarted } "]` ) ||
413- this . node . querySelector ( `[data-semantic-type="dummy"]` ) ;
435+ this . current = this . node . querySelector ( `[data-semantic-id="${ this . restarted } "]` )
436+ if ( ! this . current ) {
437+ const dummies = Array . from (
438+ this . node . querySelectorAll ( `[data-semantic-type="dummy"]` ) )
439+ . map ( x => x . getAttribute ( 'data-semantic-id' ) )
440+ let internal = this . generators . element . querySelector (
441+ `[data-semantic-id="${ this . restarted } "]` ) ;
442+ while ( internal && internal !== this . generators . element ) {
443+ let sid = internal . getAttribute ( 'data-semantic-id' ) ;
444+ if ( dummies . indexOf ( sid ) !== - 1 ) {
445+ this . current = this . node . querySelector ( `[data-semantic-id="${ sid } "]` ) ;
446+ break ;
447+ } ;
448+ internal = internal . parentNode as Element ;
449+ }
450+ }
414451 this . restarted = null ;
415452 }
416453 if ( ! this . current ) {
0 commit comments