Skip to content
Open
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
64 changes: 22 additions & 42 deletions main/blocklyinit.js
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,27 @@ export function initializeWorkspace() {
}

export function createBlocklyWorkspace() {
class OverlayMetricsManager extends Blockly.MetricsManager {
getAbsoluteMetrics() {
const absolute = super.getAbsoluteMetrics();
const flyout = this.workspace_.getFlyout?.();
if (!flyout || flyout.autoClose) return absolute;

const flyoutMetrics = this.getFlyoutMetrics();
const toolboxPosition = this.getToolboxMetrics().position;
const Position = Blockly.utils.toolbox.Position;
Comment on lines +615 to +617
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential null access if toolbox is absent.

If getToolboxMetrics() returns null (e.g., workspace without a toolbox), accessing .position will throw. Consider guarding:

 const flyoutMetrics = this.getFlyoutMetrics();
 const toolboxPosition = this.getToolboxMetrics().position;
+const toolboxMetrics = this.getToolboxMetrics();
+if (!toolboxMetrics) return absolute;
+const toolboxPosition = toolboxMetrics.position;

This is a minor edge case but worth defensive handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main/blocklyinit.js` around lines 615 - 617, The code assumes
getToolboxMetrics() always returns an object and immediately accesses .position,
which can throw if there's no toolbox; modify the logic around the
toolboxPosition assignment in blocklyinit.js to first call const toolboxMetrics
= this.getToolboxMetrics() and check for null/undefined before reading
toolboxMetrics.position (e.g., set toolboxPosition to null or a sensible default
when toolboxMetrics is falsy), and ensure subsequent use of toolboxPosition and
Blockly.utils.toolbox.Position handles the missing-toolbox case.


const adjusted = { ...absolute };
if (toolboxPosition === Position.LEFT) {
adjusted.left = Math.max(0, adjusted.left - flyoutMetrics.width);
} else if (toolboxPosition === Position.TOP) {
adjusted.top = Math.max(0, adjusted.top - flyoutMetrics.height);
}

return adjusted;
}
}

// Register the custom renderer
Blockly.registry.register(
Blockly.registry.Type.RENDERER,
Expand Down Expand Up @@ -636,6 +657,7 @@ export function createBlocklyWorkspace() {
);

workspace = Blockly.inject("blocklyDiv", options);
workspace.setMetricsManager(new OverlayMetricsManager(workspace));

// Initialize keyboard navigation.

Expand Down Expand Up @@ -951,48 +973,6 @@ export function createBlocklyWorkspace() {
shortcutRegistry.register(wrappedShortcut, true);
})();

// Keep scrolling; remove only the obvious flyout-width bump.
(function simpleNoBumpTranslate() {
const ws = Blockly.getMainWorkspace();
const original = ws.translate.bind(ws);

ws.translate = function (requestedX, newY) {
const tb = this.getToolbox?.();
const fo = this.getFlyout?.();
const mm = this.getMetricsManager?.();

// Toolbox edge on the left. Prefer toolbox.getWidth(); fallback to absolute metrics.
const tbW =
(tb && tb.getWidth?.()) ??
(mm && mm.getAbsoluteMetrics ? mm.getAbsoluteMetrics().left : 0) ??
0;

let x = requestedX;

// Only adjust when the flyout is actually visible.
if (fo && fo.isVisible?.()) {
const foW = fo.getWidth?.() || 0;
const EPS = 1; // small float tolerance

if (foW > 0) {
// Case 1: absolute shove to ≈ toolbox + flyout
if (x >= tbW + foW - EPS) {
x -= foW;
}
// Case 2: relative shove by ≈ flyout from current position
else if (x - this.scrollX >= foW - EPS) {
x -= foW;
}
}
}

// Never allow the origin to go left of the toolbox edge.
if (x < tbW) x = tbW;

return original(x, newY);
};
})();

// ------- Pointer tracking for "paste at pointer" -------
const mainWs = Blockly.getMainWorkspace();
let lastCM = { x: 0, y: 0 };
Expand Down
Loading