Skip to content

Commit 0363d67

Browse files
committed
fix: Ensure widget divs restore focus correctly.
This avoids reintroducing #9203.
1 parent 3aa3238 commit 0363d67

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

core/widgetdiv.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ export function hide() {
146146

147147
const div = containerDiv;
148148
if (!div) return;
149+
150+
(common.getMainWorkspace() as WorkspaceSvg).markFocused();
151+
152+
if (returnEphemeralFocus) {
153+
returnEphemeralFocus();
154+
returnEphemeralFocus = null;
155+
}
156+
157+
// Content must be cleared after returning ephemeral focus since otherwise it
158+
// may force focus changes which could desynchronize the focus manager and
159+
// make it think the user directed focus away from the widget div (which will
160+
// then notify it to not restore focus back to any previously focused node).
149161
div.style.display = 'none';
150162
div.style.left = '';
151163
div.style.top = '';
@@ -163,12 +175,6 @@ export function hide() {
163175
dom.removeClass(div, themeClassName);
164176
themeClassName = '';
165177
}
166-
(common.getMainWorkspace() as WorkspaceSvg).markFocused();
167-
168-
if (returnEphemeralFocus) {
169-
returnEphemeralFocus();
170-
returnEphemeralFocus = null;
171-
}
172178
}
173179

174180
/**

tests/mocha/widget_div_test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,5 +423,26 @@ suite('WidgetDiv', function () {
423423
assert.strictEqual(Blockly.getFocusManager().getFocusedNode(), block);
424424
assert.strictEqual(document.activeElement, blockFocusableElem);
425425
});
426+
427+
test('for showing nested div with ephemeral focus restores DOM focus', function () {
428+
const block = this.setUpBlockWithField();
429+
const field = Array.from(block.getFields())[0];
430+
Blockly.getFocusManager().focusNode(block);
431+
const nestedDiv = document.createElement('div');
432+
nestedDiv.tabIndex = -1;
433+
Blockly.WidgetDiv.getDiv().appendChild(nestedDiv);
434+
Blockly.WidgetDiv.show(field, false, () => {}, null, true);
435+
nestedDiv.focus(); // It's valid to focus this during ephemeral focus.
436+
437+
// Hiding will cause the now focused child div to be removed, leading to
438+
// ephemeral focus being lost if the implementation doesn't handle
439+
// returning ephemeral focus correctly.
440+
Blockly.WidgetDiv.hide();
441+
442+
// Hiding the div should restore focus back to the block.
443+
const blockFocusableElem = block.getFocusableElement();
444+
assert.strictEqual(Blockly.getFocusManager().getFocusedNode(), block);
445+
assert.strictEqual(document.activeElement, blockFocusableElem);
446+
});
426447
});
427448
});

0 commit comments

Comments
 (0)