Skip to content
Merged
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
1 change: 1 addition & 0 deletions main/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ export function togglePlayMode() {
window.flockShortcutsPanel?.panel?.classList.contains('hidden') ?? true
);
window.flockShortcutsPanel?.hide();
window.flockBlockToolbar?.hide();
blocklyArea.style.display = 'none';
gizmoButtons.style.display = 'none';
bottomBar.style.display = 'none';
Expand Down
33 changes: 33 additions & 0 deletions tests/contextmenu.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function runContextMenuTests(_flock) {
let container;
let createdBlocks;
let previousMainWorkspace;
let blockToolbar;

before(function () {
// The full app registers block types during its Blockly-init sequence,
Expand All @@ -30,6 +31,8 @@ export function runContextMenuTests(_flock) {
document.body.appendChild(container);
workspace = Blockly.inject(container, { collapse: true });
initContextMenus(workspace);
// initContextMenus appends its toolbar to <body>; ours is the newest.
blockToolbar = [...document.querySelectorAll('.fc-block-toolbar')].pop();
});

after(function () {
Expand Down Expand Up @@ -272,5 +275,35 @@ export function runContextMenuTests(_flock) {
expect(target.nextConnection.isConnected()).to.equal(true);
});
});

describe('floating block toolbar', function () {
// Blockly fires its change events asynchronously.
const flush = () => new Promise((resolve) => setTimeout(resolve, 50));

it('dismisses itself when repositioned against a collapsed workspace', async function () {
const block = makeBlock();
// Keyboard modality shows the toolbar at once; pointer waits for a hover.
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
block.select();
await flush();
expect(blockToolbar.classList.contains('visible')).to.equal(true);

// Collapse rather than display:none — the toolbar survives this, so the
// dismissal below is the visibility guard rather than a Blockly deselect.
container.style.width = '0px';
container.style.height = '0px';
try {
await flush();
expect(blockToolbar.classList.contains('visible')).to.equal(true);

block.moveBy(1, 1); // any event that repositions the toolbar
await flush();
expect(blockToolbar.classList.contains('visible')).to.equal(false);
} finally {
container.style.width = '300px';
container.style.height = '200px';
}
});
});
});
}
12 changes: 12 additions & 0 deletions ui/contextmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -884,10 +884,20 @@ export function initContextMenus(workspace) {
};
}

// Play mode hides #codePanel without deselecting the block (main/view.js).
const workspaceIsVisible = () => {
const div = workspace.getInjectionDiv?.();
return !!div && div.clientWidth > 0 && div.clientHeight > 0;
};

function positionBlockToolbar() {
if (!toolbarBlock) return;
const svgRoot = toolbarBlock.getSvgRoot?.();
if (!svgRoot) return;
if (!workspaceIsVisible()) {
hideBlockToolbar();
return;
}
const rect = getOwnBlockScreenRect(toolbarBlock) ?? svgRoot.getBoundingClientRect();
const blockCenterX = Math.round(rect.left + rect.width / 2);
blockToolbar.style.left = `${blockCenterX}px`;
Expand Down Expand Up @@ -1006,6 +1016,8 @@ export function initContextMenus(workspace) {
clearBadges();
}

window.flockBlockToolbar = { hide: hideBlockToolbar };

const isToolbarBlock = (block) => block && !block.isInFlyout && !block.isShadow();

workspace.addChangeListener((e) => {
Expand Down
Loading