Skip to content
Open
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
61 changes: 61 additions & 0 deletions core/block_svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,54 @@ export class BlockSvg
* @internal
*/
recomputeAriaLabel() {
if (this.initialized) {
const childElemIds: string[] = [];
for (const input of this.inputList) {
const connection = input.connection as RenderedConnection | null;
if (input.isVisible() && connection) {
if (connection.type === ConnectionType.NEXT_STATEMENT) {
let currentBlock: BlockSvg | null = connection.targetBlock();
while (currentBlock) {
if (currentBlock.canBeFocused()) {
childElemIds.push(currentBlock.getBlockSvgFocusElem().id);
}
currentBlock = currentBlock.getNextBlock();
}
} else if (connection.type === ConnectionType.INPUT_VALUE) {
const inpBlock = connection.targetBlock() as BlockSvg | null;
if (inpBlock && inpBlock.canBeFocused()) {
childElemIds.push(inpBlock.getBlockSvgFocusElem().id);
}
if (connection.canBeFocused()) {
childElemIds.push(connection.getFocusableElement().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);
}
}
}

const nextConnection = this.nextConnection as RenderedConnection | null;
if (
nextConnection &&
nextConnection.canBeFocused() &&
nextConnection.type === ConnectionType.NEXT_STATEMENT
) {
childElemIds.push(nextConnection.getFocusableElement().id);
}

aria.setState(this.getBlockSvgFocusElem(), aria.State.OWNS, childElemIds);
}

if (this.isSimpleReporter(true, true)) return;

aria.setState(
Expand All @@ -243,6 +291,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;
}

computeAriaLabel(
verbose: boolean = false,
minimal: boolean = false,
Expand Down Expand Up @@ -359,6 +413,7 @@ export class BlockSvg
this.workspace.getCanvas().appendChild(svg);
}
this.initialized = true;
this.recomputeAriaLabel();
}

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

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

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

/**
Expand Down
2 changes: 1 addition & 1 deletion core/rendered_connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ export class RenderedConnection

/** See IFocusableNode.canBeFocused. */
canBeFocused(): boolean {
return true;
return this.findHighlightSvg() !== null;
}

private findHighlightSvg(): SVGPathElement | null {
Expand Down
8 changes: 4 additions & 4 deletions tests/mocha/cursor_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ suite('Cursor', function () {
});
suite('one empty block', function () {
setup(function () {
this.blockA = this.workspace.newBlock('empty_block');
this.blockA = createRenderedBlock(this.workspace, 'empty_block');
});
teardown(function () {
this.workspace.clear();
Expand All @@ -359,7 +359,7 @@ suite('Cursor', function () {

suite('one stack block', function () {
setup(function () {
this.blockA = this.workspace.newBlock('stack_block');
this.blockA = createRenderedBlock(this.workspace, 'stack_block');
});
teardown(function () {
this.workspace.clear();
Expand All @@ -376,7 +376,7 @@ suite('Cursor', function () {

suite('one row block', function () {
setup(function () {
this.blockA = this.workspace.newBlock('row_block');
this.blockA = createRenderedBlock(this.workspace, 'row_block');
});
teardown(function () {
this.workspace.clear();
Expand All @@ -392,7 +392,7 @@ suite('Cursor', function () {
});
suite('one c-hat block', function () {
setup(function () {
this.blockA = this.workspace.newBlock('c_hat_block');
this.blockA = createRenderedBlock(this.workspace, 'c_hat_block');
});
teardown(function () {
this.workspace.clear();
Expand Down
123 changes: 75 additions & 48 deletions tests/mocha/navigation_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
*/

import {assert} from '../../node_modules/chai/index.js';
import {createRenderedBlock} from './test_helpers/block_definitions.js';
import {
sharedTestSetup,
sharedTestTeardown,
workspaceTeardown,
} from './test_helpers/setup_teardown.js';

suite('Navigation', function () {
Expand Down Expand Up @@ -89,13 +89,28 @@ suite('Navigation', function () {
]);
this.workspace = Blockly.inject('blocklyDiv', {});
this.navigator = this.workspace.getNavigator();
const statementInput1 = this.workspace.newBlock('input_statement');
const statementInput2 = this.workspace.newBlock('input_statement');
const statementInput3 = this.workspace.newBlock('input_statement');
const statementInput4 = this.workspace.newBlock('input_statement');
const fieldWithOutput = this.workspace.newBlock('field_input');
const doubleValueInput = this.workspace.newBlock('double_value_input');
const valueInput = this.workspace.newBlock('value_input');
const statementInput1 = createRenderedBlock(
this.workspace,
'input_statement',
);
const statementInput2 = createRenderedBlock(
this.workspace,
'input_statement',
);
const statementInput3 = createRenderedBlock(
this.workspace,
'input_statement',
);
const statementInput4 = createRenderedBlock(
this.workspace,
'input_statement',
);
const fieldWithOutput = createRenderedBlock(this.workspace, 'field_input');
const doubleValueInput = createRenderedBlock(
this.workspace,
'double_value_input',
);
const valueInput = createRenderedBlock(this.workspace, 'value_input');

statementInput1.nextConnection.connect(statementInput2.previousConnection);
statementInput1.inputList[0].connection.connect(
Expand Down Expand Up @@ -355,13 +370,25 @@ suite('Navigation', function () {
'helpUrl': '',
},
]);
const noNextConnection = this.workspace.newBlock('top_connection');
const fieldAndInputs = this.workspace.newBlock('fields_and_input');
const twoFields = this.workspace.newBlock('two_fields');
const fieldAndInputs2 = this.workspace.newBlock('fields_and_input2');
const noPrevConnection = this.workspace.newBlock('start_block');
const hiddenField = this.workspace.newBlock('hidden_field');
const hiddenInput = this.workspace.newBlock('hidden_input');
const noNextConnection = createRenderedBlock(
this.workspace,
'top_connection',
);
const fieldAndInputs = createRenderedBlock(
this.workspace,
'fields_and_input',
);
const twoFields = createRenderedBlock(this.workspace, 'two_fields');
const fieldAndInputs2 = createRenderedBlock(
this.workspace,
'fields_and_input2',
);
const noPrevConnection = createRenderedBlock(
this.workspace,
'start_block',
);
const hiddenField = createRenderedBlock(this.workspace, 'hidden_field');
const hiddenInput = createRenderedBlock(this.workspace, 'hidden_input');
this.blocks.noNextConnection = noNextConnection;
this.blocks.fieldAndInputs = fieldAndInputs;
this.blocks.twoFields = twoFields;
Expand All @@ -373,28 +400,47 @@ suite('Navigation', function () {
hiddenField.inputList[0].fieldRow[1].setVisible(false);
hiddenInput.inputList[1].setVisible(false);

const dummyInput = this.workspace.newBlock('dummy_input');
const dummyInputValue = this.workspace.newBlock('dummy_inputValue');
const fieldWithOutput2 = this.workspace.newBlock('field_input');
const dummyInput = createRenderedBlock(this.workspace, 'dummy_input');
const dummyInputValue = createRenderedBlock(
this.workspace,
'dummy_inputValue',
);
const fieldWithOutput2 = createRenderedBlock(
this.workspace,
'field_input',
);
this.blocks.dummyInput = dummyInput;
this.blocks.dummyInputValue = dummyInputValue;
this.blocks.fieldWithOutput2 = fieldWithOutput2;

const secondBlock = this.workspace.newBlock('input_statement');
const outputNextBlock = this.workspace.newBlock('output_next');
const secondBlock = createRenderedBlock(
this.workspace,
'input_statement',
);
const outputNextBlock = createRenderedBlock(
this.workspace,
'output_next',
);
this.blocks.secondBlock = secondBlock;
this.blocks.outputNextBlock = outputNextBlock;

const buttonBlock = this.workspace.newBlock('buttons', 'button_block');
const buttonInput1 = this.workspace.newBlock(
const buttonBlock = createRenderedBlock(
this.workspace,
'buttons',
'button_block',
);
const buttonInput1 = createRenderedBlock(
this.workspace,
'field_input',
'button_input1',
);
const buttonInput2 = this.workspace.newBlock(
const buttonInput2 = createRenderedBlock(
this.workspace,
'field_input',
'button_input2',
);
const buttonNext = this.workspace.newBlock(
const buttonNext = createRenderedBlock(
this.workspace,
'input_statement',
'button_next',
);
Expand All @@ -420,15 +466,6 @@ suite('Navigation', function () {
this.workspace.cleanUp();
});
suite('Next', function () {
setup(function () {
this.singleBlockWorkspace = new Blockly.Workspace();
const singleBlock = this.singleBlockWorkspace.newBlock('two_fields');
this.blocks.singleBlock = singleBlock;
});
teardown(function () {
workspaceTeardown.call(this, this.singleBlockWorkspace);
});

test('fromPreviousToBlock', function () {
const prevConnection = this.blocks.statementInput1.previousConnection;
const nextNode = this.navigator.getNextSibling(prevConnection);
Expand Down Expand Up @@ -471,8 +508,6 @@ suite('Navigation', function () {
});
test('fromFieldToNestedBlock', function () {
const field = this.blocks.statementInput1.inputList[0].fieldRow[1];
const inputConnection =
this.blocks.statementInput1.inputList[0].connection;
const nextNode = this.navigator.getNextSibling(field);
assert.equal(nextNode, this.blocks.fieldWithOutput);
});
Expand Down Expand Up @@ -576,7 +611,6 @@ suite('Navigation', function () {
const prevNode = this.navigator.getPreviousSibling(
this.blocks.fieldWithOutput,
);
const outputConnection = this.blocks.fieldWithOutput.outputConnection;
assert.equal(prevNode, [...this.blocks.statementInput1.getFields()][1]);
});
test('fromNextToBlock', function () {
Expand Down Expand Up @@ -617,14 +651,12 @@ suite('Navigation', function () {
assert.isNull(prevNode);
});
test('fromFieldToInput', function () {
const outputBlock = this.workspace.newBlock('field_input');
const outputBlock = createRenderedBlock(this.workspace, 'field_input');
this.blocks.fieldAndInputs2.inputList[0].connection.connect(
outputBlock.outputConnection,
);

const field = this.blocks.fieldAndInputs2.inputList[1].fieldRow[0];
const inputConnection =
this.blocks.fieldAndInputs2.inputList[0].connection;
const prevNode = this.navigator.getPreviousSibling(field);
assert.equal(prevNode, outputBlock);
});
Expand Down Expand Up @@ -701,18 +733,13 @@ suite('Navigation', function () {
});

suite('In', function () {
setup(function () {
this.emptyWorkspace = Blockly.inject(document.createElement('div'), {});
});
teardown(function () {
workspaceTeardown.call(this, this.emptyWorkspace);
});

test('fromInputToOutput', function () {
// The first child is the connected block since the connection itself
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gonfunko I changed this test because the new canBeFocused logic results in this connection never being navigable which seems...correct?

// cannot be navigated to directly.
const input = this.blocks.statementInput1.inputList[0];
const inNode = this.navigator.getFirstChild(input.connection);
const outputConnection = this.blocks.fieldWithOutput.outputConnection;
assert.equal(inNode, outputConnection);
const connectedBlock = this.blocks.fieldWithOutput;
assert.equal(inNode, connectedBlock);
});
test('fromInputToNull', function () {
const input = this.blocks.statementInput2.inputList[0];
Expand Down
4 changes: 2 additions & 2 deletions tests/mocha/test_helpers/block_definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ export function createTestBlock() {
};
}

export function createRenderedBlock(workspaceSvg, type) {
const block = workspaceSvg.newBlock(type);
export function createRenderedBlock(workspaceSvg, type, opt_id) {
const block = workspaceSvg.newBlock(type, opt_id);
block.initSvg();
block.render();
return block;
Expand Down
Loading