Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion core/block_svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,58 @@ export class BlockSvg
* @internal
*/
recomputeAriaLabel() {
if (this.initialized) {
const childElemIds: string[] = [];
for (const input of this.inputList) {
if (input.isVisible() && input.connection) {
if (input.connection.type === ConnectionType.NEXT_STATEMENT) {
let currentBlock: BlockSvg | null =
input.connection.targetBlock() as BlockSvg | null;
while (currentBlock) {
if (currentBlock.canBeFocused()) {
childElemIds.push(currentBlock.getBlockSvgFocusElem().id);
}
currentBlock = currentBlock.getNextBlock();
}
} else if (input.connection.type === ConnectionType.INPUT_VALUE) {
const inpBlock = input.connection.targetBlock() as BlockSvg | null;
if (inpBlock && inpBlock.canBeFocused()) {
childElemIds.push(inpBlock.getBlockSvgFocusElem().id);
}
}
}
for (const field of input.fieldRow) {
if (field.getSvgRoot() && field.canBeFocused()) {
// Only track the field if it's been initialized.
childElemIds.push(field.getFocusableElement().id);
}
}
for (const icon of this.icons) {
if (icon.canBeFocused()) {
childElemIds.push(icon.getFocusableElement().id);
}
}
for (const connection of this.getConnections_(true)) {
// TODO: Somehow it's possible for a connection to be highlighted but
// have no focusable element. This might be some sort of race
// condition or perhaps dispose-esque situation happening.
if (
connection.canBeFocused() &&
connection.isHighlighted() &&
connection.findHighlightSvg() !== null
) {
childElemIds.push(connection.getFocusableElement().id);
}
}
}
aria.setState(this.getBlockSvgFocusElem(), aria.State.OWNS, childElemIds);
}

if (this.isSimpleReporter()) {
const field = Array.from(this.getFields())[0];
if (field.isFullBlockField() && field.isCurrentlyEditable()) return;
if (field && field.isFullBlockField() && field.isCurrentlyEditable()) {
return;
}
}

aria.setState(
Expand All @@ -244,6 +293,12 @@ export class BlockSvg
);
}

private getBlockSvgFocusElem(): Element {
// Note that this deviates from getFocusableElement() to ensure that
// single field blocks are properly set up in the hierarchy.
return this.pathObject.svgPath;
}

private computeAriaLabel(): string {
const {blockSummary, inputCount} = buildBlockSummary(this);
const inputSummary = inputCount
Expand Down Expand Up @@ -352,6 +407,7 @@ export class BlockSvg
this.workspace.getCanvas().appendChild(svg);
}
this.initialized = true;
this.recomputeAriaLabel();
}

/**
Expand Down Expand Up @@ -456,6 +512,12 @@ export class BlockSvg
this.applyColour();

this.workspace.recomputeAriaTree();
this.recomputeAriaLabelRecursive();
}

private recomputeAriaLabelRecursive() {
this.recomputeAriaLabel();
this.parentBlock_?.recomputeAriaLabelRecursive();
}

/**
Expand Down
7 changes: 6 additions & 1 deletion core/rendered_connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ export class RenderedConnection
aria.setState(highlightSvg, aria.State.LABEL, 'Open connection');
}
}

this.sourceBlock_.recomputeAriaLabel();
}

/** Remove the highlighting around this connection. */
Expand All @@ -373,6 +375,8 @@ export class RenderedConnection
if (highlightSvg) {
highlightSvg.style.display = 'none';
}

this.sourceBlock_.recomputeAriaLabel();
}

/** Returns true if this connection is highlighted, false otherwise. */
Expand Down Expand Up @@ -688,7 +692,8 @@ export class RenderedConnection
return true;
}

private findHighlightSvg(): SVGPathElement | null {
// TODO: Figure out how to make this private again.
findHighlightSvg(): SVGPathElement | null {
// This cast is valid as TypeScript's definition is wrong. See:
// https://github.com/microsoft/TypeScript/issues/60996.
return document.getElementById(this.id) as
Expand Down
Loading