mirror of
https://github.com/google/blockly.git
synced 2026-06-11 13:45:14 +02:00
fix: allow nav into collapsed block row via right arrow (#9958)
This supports e.g. expand/collapse icons added outside core Blockly.
MakeCode has an expand FieldImageNoText on collapsed blocks that wasn't
otherwise navigable (inserted into COLLAPSED_INPUT_NAME):
input.appendField(new FieldImageNoText(image, 24, 24, "Expand", () => {
this.setCollapsed(false)
}, false));
To support this:
1. the input that shares the block row id takes into account visibility
2. we drop the short circuit for collapsed blocks and rely on the filtering
already in place to filter out the collapsed content
Also filter icons whose updateCollapsed() hides them via display:none;
without this they remain in the candidate list and the navigator can
focus e.g. an invisible cog for a mutator workspace.
Add tests for icon visibility.
This commit is contained in:
@@ -375,7 +375,13 @@ export class Input {
|
||||
getRowId(): string {
|
||||
const inputs = this.getSourceBlock().inputList;
|
||||
|
||||
// The first input in a block has the same ID as its parent block.
|
||||
// The first visible input shares the block's row id; this also covers
|
||||
// the collapsed-input placeholder, since every other input is hidden.
|
||||
if (this === inputs.find((i) => i.isVisible())) {
|
||||
return (this.getSourceBlock() as BlockSvg).getRowId();
|
||||
}
|
||||
|
||||
// Fallback when inputs[0] itself is hidden.
|
||||
if (this === inputs[0]) {
|
||||
return (this.getSourceBlock() as BlockSvg).getRowId();
|
||||
}
|
||||
|
||||
@@ -119,13 +119,12 @@ export class BlockNavigationPolicy implements INavigationPolicy<BlockSvg> {
|
||||
* @returns A list of navigable/focusable children of the given block.
|
||||
*/
|
||||
function getBlockNavigationCandidates(block: BlockSvg): IFocusableNode[] {
|
||||
// Collapsed blocks have no navigable children.
|
||||
if (block.isCollapsed()) return [];
|
||||
|
||||
const candidates: IFocusableNode[] = [];
|
||||
|
||||
// Icons and open bubbles are navigable.
|
||||
for (const icon of block.getIcons()) {
|
||||
// Icons hidden when the block is collapsed shouldn't be navigable.
|
||||
if (block.isCollapsed() && !icon.isShownWhenCollapsed()) continue;
|
||||
candidates.push(icon);
|
||||
let bubble;
|
||||
if (
|
||||
@@ -162,7 +161,7 @@ function getBlockNavigationCandidates(block: BlockSvg): IFocusableNode[] {
|
||||
}
|
||||
|
||||
// The block's next connection is navigable.
|
||||
if (block.nextConnection) {
|
||||
if (block.nextConnection && !block.isCollapsed()) {
|
||||
candidates.push(block.nextConnection);
|
||||
}
|
||||
|
||||
|
||||
@@ -774,6 +774,43 @@ suite('Navigation', function () {
|
||||
const inNode = this.navigator.getFirstChild(this.blocks.buttonBlock);
|
||||
assert.isNull(inNode);
|
||||
});
|
||||
test('reachesClickableFieldOnCollapsedInput', function () {
|
||||
// Models a pattern where a clickable field is appended to
|
||||
// COLLAPSED_INPUT_NAME when the block collapses.
|
||||
const block = this.blocks.buttonBlock;
|
||||
block.setCollapsed(true);
|
||||
const input = block.getInput(Blockly.constants.COLLAPSED_INPUT_NAME);
|
||||
const expandButton = new Blockly.FieldImage(
|
||||
'https://www.gstatic.com/codesite/ph/images/star_on.gif',
|
||||
16,
|
||||
16,
|
||||
'expand',
|
||||
() => {},
|
||||
);
|
||||
input.appendField(expandButton);
|
||||
|
||||
const inNode = this.navigator.getInNode(block);
|
||||
assert.equal(inNode, expandButton);
|
||||
});
|
||||
test('skipsIconsHiddenWhenCollapsed', function () {
|
||||
// Comment icons are hidden when the block is collapsed, so they
|
||||
// should not be navigable.
|
||||
const block = this.blocks.statementInput1;
|
||||
block.setCommentText('comment');
|
||||
block.setCollapsed(true);
|
||||
assert.isNull(this.navigator.getInNode(block));
|
||||
});
|
||||
test('reachesIconsShownWhenCollapsed', function () {
|
||||
// Warning icons remain shown when the block is collapsed, so they
|
||||
// should still be navigable.
|
||||
const block = this.blocks.statementInput1;
|
||||
block.setWarningText('warning');
|
||||
block.setCollapsed(true);
|
||||
assert.equal(
|
||||
this.navigator.getInNode(block),
|
||||
block.getIcon(Blockly.icons.IconType.WARNING),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Out', function () {
|
||||
|
||||
Reference in New Issue
Block a user