From d879104bfdf5a77105f1049d38a5d2912c73deaa Mon Sep 17 00:00:00 2001 From: Laura Sach <5183697+lawsie@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:44:05 +0100 Subject: [PATCH 1/2] Don't show separators --- ui/contextmenu.js | 71 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/ui/contextmenu.js b/ui/contextmenu.js index 8b30d539..308973aa 100644 --- a/ui/contextmenu.js +++ b/ui/contextmenu.js @@ -27,6 +27,18 @@ function renderShortcut(label, shortcut) { return wrapper; } +// Hide separators with no items between them +function collapseSeparators(options) { + if (!Array.isArray(options)) return options; + const out = []; + for (const option of options) { + if (!option?.separator) out.push(option); + else if (out.length && !out[out.length - 1].separator) out.push(option); + } + while (out.length && out[out.length - 1].separator) out.pop(); + return out; +} + export function initContextMenus(workspace) { // ------- Pointer tracking for "paste at pointer" ------- let lastCM = { x: 0, y: 0 }; @@ -192,8 +204,7 @@ export function initContextMenus(workspace) { const origDisplayText = item.displayText; item.displayText = (scope) => { - const text = - typeof origDisplayText === 'function' ? origDisplayText(scope) : origDisplayText; + const text = typeof origDisplayText === 'function' ? origDisplayText(scope) : origDisplayText; const hasComment = scope?.block?.getCommentText?.() != null; return renderShortcut(text, hasComment ? 'Shift+K' : 'K'); }; @@ -423,6 +434,26 @@ export function initContextMenus(workspace) { } })(); + // Drop separators left stranded + (function filterStrandedSeparators() { + const proto = Blockly.BlockSvg.prototype; + if (!proto.__flockSeparatorFilter) { + const origGenerate = proto.generateContextMenu; + proto.generateContextMenu = function (...args) { + return collapseSeparators(origGenerate.apply(this, args)); + }; + proto.__flockSeparatorFilter = true; + } + + // Workspace scope has no equivalent method; configureContextMenu is the + // documented hook and mutates the array in place. + const origConfigure = workspace.configureContextMenu; + workspace.configureContextMenu = function (options, e) { + origConfigure?.call(this, options, e); + options.splice(0, options.length, ...collapseSeparators(options)); + }; + })(); + // ===== OVERRIDE CLIPBOARD METHODS ===== const origCopy = Blockly.clipboard.copy; const origToastShow = Blockly.Toast?.show; @@ -493,38 +524,6 @@ export function initContextMenus(workspace) { } const host = workspace.getInjectionDiv() || document; - let __fcLastPointer = { x: 0, y: 0 }; - let __fcLastPointerType = 'mouse'; // 'mouse' | 'touch' | 'pen' - let __fcMenuPoint = null; - let __fcMenuPointerType = 'mouse'; - - host.addEventListener( - 'pointerdown', - (e) => { - if (!e.isPrimary) return; - __fcLastPointer = { x: e.clientX, y: e.clientY }; - __fcLastPointerType = e.pointerType || 'mouse'; - }, - { capture: true } - ); - - host.addEventListener( - 'pointermove', - (e) => { - if (!e.isPrimary) return; - __fcLastPointer = { x: e.clientX, y: e.clientY }; - __fcLastPointerType = e.pointerType || __fcLastPointerType; - }, - { capture: true } - ); - - // Capture the *actual* coordinates that opened the context menu (works for long-press) - const __origShow = Blockly.ContextMenu.show; - Blockly.ContextMenu.show = function (e, options, rtl) { - __fcMenuPoint = { x: e.clientX, y: e.clientY }; - __fcMenuPointerType = e.pointerType || __fcLastPointerType || 'mouse'; - return __origShow.call(Blockly.ContextMenu, e, options, rtl); - }; host.addEventListener( 'contextmenu', (e) => { @@ -988,7 +987,9 @@ export function initContextMenus(workspace) { } let meshRoot = mesh; while (meshRoot?.parent) meshRoot = meshRoot.parent; - const exitMode = !!window.orbitViewActive && (window.orbitBlock === block || (meshRoot && window.orbitMesh === meshRoot)); + const exitMode = + !!window.orbitViewActive && + (window.orbitBlock === block || (meshRoot && window.orbitMesh === meshRoot)); viewBtn.innerHTML = exitMode ? viewExitSvg : viewEnterSvg; viewBtn.setAttribute( 'aria-label', From 2572af43f514c3cdc0a52b8bc3bff82ae3709cca Mon Sep 17 00:00:00 2001 From: Laura Sach <5183697+lawsie@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:35:57 +0100 Subject: [PATCH 2/2] Rabbit complaint --- ui/contextmenu.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/contextmenu.js b/ui/contextmenu.js index 308973aa..dbc3d434 100644 --- a/ui/contextmenu.js +++ b/ui/contextmenu.js @@ -33,9 +33,9 @@ function collapseSeparators(options) { const out = []; for (const option of options) { if (!option?.separator) out.push(option); - else if (out.length && !out[out.length - 1].separator) out.push(option); + else if (out.length && !out[out.length - 1]?.separator) out.push(option); } - while (out.length && out[out.length - 1].separator) out.pop(); + while (out.length && out[out.length - 1]?.separator) out.pop(); return out; }