fix: Ensure selection stays when dragging blocks (#9034)

## The basics

- [x] I [validated my changes](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change)

## The details
### Resolves

Fixes #9027

### Proposed Changes

Ensure that a block being dragged is properly focused mid-drag.

### Reason for Changes

Focus seems to be lost due to the block being moved to the drag layer, so re-focusing the block ensures that it remains both actively focused and selected while dragging.

The regression was likely caused when block selection was moved to be fully synced based on active focus.

### Test Coverage

This has been manually verified in Core's simple playground. At the time of the PR being opened, this couldn't be tested in the test environment for the experimental keyboard navigation plugin since there's a navigation connection issue there that needs to be resolved to test movement.

It would be helpful to add a new test case for the underlying problem (i.e. ensuring that the block holds focus mid-drag) as part of resolving #8915.

### Documentation

No new documentation should need to be added.

### Additional Information

This was found during the development of https://github.com/google/blockly-keyboard-experimentation/pull/511.
This commit is contained in:
Ben Henning
2025-05-13 14:37:58 -07:00
committed by GitHub
parent 556ee39f6f
commit e34a9690ed
3 changed files with 33 additions and 2 deletions

View File

@@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import {getFocusManager} from './focus_manager.js';
import type {IFocusableNode} from './interfaces/i_focusable_node.js';
import {IRenderedElement} from './interfaces/i_rendered_element.js';
import * as layerNums from './layers.js';
import {Coordinate} from './utils/coordinate.js';
@@ -99,8 +101,12 @@ export class LayerManager {
*
* @internal
*/
moveToDragLayer(elem: IRenderedElement) {
moveToDragLayer(elem: IRenderedElement & IFocusableNode) {
this.dragLayer?.appendChild(elem.getSvgRoot());
// Since moving the element to the drag layer will cause it to lose focus,
// ensure it regains focus (to ensure proper highlights & sent events).
getFocusManager().focusNode(elem);
}
/**
@@ -108,8 +114,12 @@ export class LayerManager {
*
* @internal
*/
moveOffDragLayer(elem: IRenderedElement, layerNum: number) {
moveOffDragLayer(elem: IRenderedElement & IFocusableNode, layerNum: number) {
this.append(elem, layerNum);
// Since moving the element off the drag layer will cause it to lose focus,
// ensure it regains focus (to ensure proper highlights & sent events).
getFocusManager().focusNode(elem);
}
/**

View File

@@ -8,6 +8,7 @@
import type {BlockSvg} from '../../block_svg.js';
import type {Connection} from '../../connection.js';
import {FocusManager} from '../../focus_manager.js';
import type {BlockStyle} from '../../theme.js';
import * as dom from '../../utils/dom.js';
import {Svg} from '../../utils/svg.js';
@@ -91,6 +92,17 @@ export class PathObject extends BasePathObject {
if (!this.svgPathSelected) {
this.svgPathSelected = this.svgPath.cloneNode(true) as SVGElement;
this.svgPathSelected.classList.add('blocklyPathSelected');
// Ensure focus-specific properties don't overlap with the block's path.
dom.removeClass(
this.svgPathSelected,
FocusManager.ACTIVE_FOCUS_NODE_CSS_CLASS_NAME,
);
dom.removeClass(
this.svgPathSelected,
FocusManager.PASSIVE_FOCUS_NODE_CSS_CLASS_NAME,
);
this.svgPathSelected.removeAttribute('tabindex');
this.svgPathSelected.removeAttribute('id');
this.svgRoot.appendChild(this.svgPathSelected);
}
} else {

View File

@@ -24,6 +24,15 @@ suite('Layering', function () {
const g = Blockly.utils.dom.createSvgElement('g', {});
return {
getSvgRoot: () => g,
getFocusableElement: () => {
throw new Error('Unsupported.');
},
getFocusableTree: () => {
throw new Error('Unsupported.');
},
onNodeFocus: () => {},
onNodeBlur: () => {},
canBeFocused: () => false,
};
}