Skip to content

Commit f92085b

Browse files
fix: scroll into view used the wrong position (#604)
* chore: test asserting broken scroll behaviour * fix: scroll into view used the wrong position It used the position from positionNewTopLevelBlock, not the initial insert position. Delay the setting of current node until the position is correct. * chore: comment typo
1 parent 9130145 commit f92085b

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

src/actions/enter.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,6 @@ export class EnterAction {
146146

147147
workspace.setResizesEnabled(true);
148148

149-
getFocusManager().focusTree(workspace);
150-
workspace.getCursor()?.setCurNode(newBlock);
151149
this.mover.startMove(workspace, newBlock, insertStartPoint);
152150

153151
const isStartBlock =

src/actions/mover.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ export class Mover {
143143
dragger.onDragStart(info.fakePointerEvent('pointerdown'));
144144
info.updateTotalDelta();
145145
// In case the block is detached, ensure that it still retains focus
146-
// (otherwise dragging will break).
147-
getFocusManager().focusNode(block);
146+
// (otherwise dragging will break). This is also the point a new block's
147+
// initial insert position is scrolled into view.
148+
workspace.getCursor()?.setCurNode(block);
148149
block.getFocusableElement().addEventListener('blur', blurListener);
149150

150151
// Register a keyboard shortcut under the key combos of all existing
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import * as Blockly from 'blockly';
8+
import * as chai from 'chai';
9+
import {Key} from 'webdriverio';
10+
import {
11+
keyDown,
12+
keyRight,
13+
PAUSE_TIME,
14+
tabNavigateToWorkspace,
15+
testFileLocations,
16+
testSetup,
17+
} from './test_setup.js';
18+
19+
suite('Scrolling into view', function () {
20+
// Setting timeout to unlimited as these tests take longer time to run
21+
this.timeout(0);
22+
23+
// Clear the workspace and load start blocks
24+
setup(async function () {
25+
this.browser = await testSetup(testFileLocations.BASE);
26+
// Predictable small window size for scrolling.
27+
this.browser.setWindowSize(800, 600);
28+
await this.browser.pause(PAUSE_TIME);
29+
});
30+
31+
test('Insert scrolls new block into view', async function () {
32+
await tabNavigateToWorkspace(this.browser);
33+
34+
// Separate the two top-level blocks by moving p5_draw_1 further down.
35+
await keyDown(this.browser, 3);
36+
await this.browser.keys('m');
37+
await this.browser.keys([Key.Alt, ...new Array(25).fill(Key.ArrowDown)]);
38+
await this.browser.keys(Key.Enter);
39+
// Scroll back up, leaving cursor on the draw block out of the viewport.
40+
await this.browser.execute(() => {
41+
const workspace = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
42+
workspace.scrollBoundsIntoView(
43+
(
44+
workspace.getTopBlocks(true)[0] as Blockly.BlockSvg
45+
).getBoundingRectangleWithoutChildren(),
46+
);
47+
});
48+
49+
// Insert and confirm the test block which should be scrolled into view.
50+
await this.browser.keys('t');
51+
await keyRight(this.browser);
52+
await this.browser.keys(Key.Enter);
53+
await this.browser.keys(Key.Enter);
54+
55+
// Assert new block has been scrolled into the viewport.
56+
await this.browser.pause(PAUSE_TIME);
57+
const inViewport = await this.browser.execute(() => {
58+
const workspace = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
59+
const block = workspace.getBlocksByType(
60+
'controls_if',
61+
)[0] as Blockly.BlockSvg;
62+
const blockBounds = block.getBoundingRectangleWithoutChildren();
63+
const rawViewport = workspace.getMetricsManager().getViewMetrics(true);
64+
const viewport = new Blockly.utils.Rect(
65+
rawViewport.top,
66+
rawViewport.top + rawViewport.height,
67+
rawViewport.left,
68+
rawViewport.left + rawViewport.width,
69+
);
70+
return viewport.contains(blockBounds.left, blockBounds.top);
71+
});
72+
chai.assert.isTrue(inViewport);
73+
});
74+
});

0 commit comments

Comments
 (0)