UNPKG

@blockly/workspace-backpack

Version:
264 lines (253 loc) 8.52 kB
/** * @license * Copyright 2021 Google LLC * SPDX-License-Identifier: Apache-2.0 */ /** * @fileoverview Helper and utility methods for the backpack plugin. * @author kozbial@google.com (Monica Kozbial) */ import './msg'; import * as Blockly from 'blockly/core'; import {Backpack} from './backpack'; import {BackpackContextMenuOptions} from './options'; /** * Registers a context menu option to empty the backpack when right-clicked. * * @param workspace The workspace to register the context menu option on. */ function registerEmptyBackpack(workspace: Blockly.WorkspaceSvg) { const prevConfigureContextMenu = workspace.configureContextMenu; workspace.configureContextMenu = (menuOptions, e: Event) => { const backpack = workspace .getComponentManager() .getComponent('backpack') as Backpack; const backpackClientRect = backpack && backpack.getClientRect(); if (e instanceof PointerEvent && backpackClientRect) { if (!backpack || !backpackClientRect.contains(e.clientX, e.clientY)) { prevConfigureContextMenu && prevConfigureContextMenu.call(null, menuOptions, e); return; } } menuOptions.length = 0; const backpackOptions = { text: Blockly.Msg['EMPTY_BACKPACK'], enabled: !!backpack.getCount(), callback: function () { backpack.empty(); }, scope: { workspace, }, weight: 0, }; menuOptions.push(backpackOptions); }; } /** * Registers a context menu option to remove a block from a backpack flyout. */ function registerRemoveFromBackpack() { if (Blockly.ContextMenuRegistry.registry.getItem('remove_from_backpack')) { return; } const removeFromBackpack = { displayText: Blockly.Msg['REMOVE_FROM_BACKPACK'], preconditionFn: function (scope: Blockly.ContextMenuRegistry.Scope) { if (!scope.block) return 'hidden'; const ws = scope.block.workspace; if (ws.isFlyout && ws.targetWorkspace) { const backpack = ws.targetWorkspace .getComponentManager() .getComponent('backpack') as Backpack; const backpackFlyout = backpack && backpack.getFlyout(); if ( backpack && backpackFlyout && backpackFlyout.getWorkspace().id === ws.id ) { return 'enabled'; } } return 'hidden'; }, callback: function (scope: Blockly.ContextMenuRegistry.Scope) { if (!scope.block || !scope.block.workspace.targetWorkspace) return; const backpack = scope.block.workspace.targetWorkspace .getComponentManager() .getComponent('backpack') as Backpack; backpack.removeBlock(scope.block); }, scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, id: 'remove_from_backpack', // Use a larger weight to push the option lower on the context menu. weight: 200, }; Blockly.ContextMenuRegistry.registry.register(removeFromBackpack); } /** * Registers context menu options for adding a block to the backpack. * * @param disablePreconditionContainsCheck Whether to disable the * precondition check for whether the backpack contains the block. */ function registerCopyToBackpack(disablePreconditionContainsCheck: boolean) { if (Blockly.ContextMenuRegistry.registry.getItem('copy_to_backpack')) { return; } const copyToBackpack = { displayText: function (scope: Blockly.ContextMenuRegistry.Scope) { if (!scope.block) { return ''; } const backpack = scope.block.workspace .getComponentManager() .getComponent('backpack') as Backpack; const backpackCount = backpack.getCount(); return `${Blockly.Msg['COPY_TO_BACKPACK']} (${backpackCount})`; }, preconditionFn: function (scope: Blockly.ContextMenuRegistry.Scope) { if (!scope.block) return 'hidden'; const ws = scope.block.workspace; if (!ws.isFlyout) { const backpack = ws .getComponentManager() .getComponent('backpack') as Backpack; if (backpack) { if (disablePreconditionContainsCheck) { return 'enabled'; } return backpack.containsBlock(scope.block) ? 'disabled' : 'enabled'; } } return 'hidden'; }, callback: function (scope: Blockly.ContextMenuRegistry.Scope) { if (!scope.block) return; const backpack = scope.block.workspace .getComponentManager() .getComponent('backpack') as Backpack; backpack.addBlock(scope.block); }, scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK, id: 'copy_to_backpack', // Use a larger weight to push the option lower on the context menu. weight: 200, }; Blockly.ContextMenuRegistry.registry.register(copyToBackpack); } /** * Registers context menu options for copying all blocks from the workspace to * the backpack. */ function registerCopyAllBackpack() { if (Blockly.ContextMenuRegistry.registry.getItem('copy_all_to_backpack')) { return; } const copyAllToBackpack = { displayText: Blockly.Msg['COPY_ALL_TO_BACKPACK'], preconditionFn: function (scope: Blockly.ContextMenuRegistry.Scope) { const ws = scope.workspace; if (ws && !ws.isFlyout) { const backpack = ws.getComponentManager().getComponent('backpack'); if (backpack) { return 'enabled'; } } return 'hidden'; }, callback: function (scope: Blockly.ContextMenuRegistry.Scope) { const ws = scope.workspace; if (!ws) return; const backpack = ws .getComponentManager() .getComponent('backpack') as Backpack; backpack.addBlocks(ws.getTopBlocks(true)); }, scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, id: 'copy_all_to_backpack', // Use a larger weight to push the option lower on the context menu. weight: 200, }; Blockly.ContextMenuRegistry.registry.register(copyAllToBackpack); } /** * Registers context menu options for pasting all blocks from the backpack to * the workspace. */ function registerPasteAllBackpack() { if (Blockly.ContextMenuRegistry.registry.getItem('paste_all_from_backpack')) { return; } const pasteAllFromBackpack = { displayText: function (scope: Blockly.ContextMenuRegistry.Scope) { if (!scope.workspace) { return ''; } const backpack = scope.workspace .getComponentManager() .getComponent('backpack') as Backpack; const backpackCount = backpack.getCount(); return `${Blockly.Msg['PASTE_ALL_FROM_BACKPACK']} (${backpackCount})`; }, preconditionFn: function (scope: Blockly.ContextMenuRegistry.Scope) { const ws = scope.workspace; if (ws && !ws.isFlyout) { const backpack = ws.getComponentManager().getComponent('backpack'); if (backpack) { return 'enabled'; } } return 'hidden'; }, callback: function (scope: Blockly.ContextMenuRegistry.Scope) { const ws = scope.workspace; if (!ws) return; const backpack = ws .getComponentManager() .getComponent('backpack') as Backpack; const contents = backpack.getContents(); contents.forEach((blockText) => { const block = Blockly.serialization.blocks.append( JSON.parse(blockText), ws, ) as Blockly.BlockSvg; block.scheduleSnapAndBump(); }); }, scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE, id: 'paste_all_from_backpack', // Use a larger weight to push the option lower on the context menu. weight: 200, }; Blockly.ContextMenuRegistry.registry.register(pasteAllFromBackpack); } /** * Register all context menu options. * * @param contextMenuOptions The backpack context menu options. * @param workspace The workspace to register the context menu options. */ export function registerContextMenus( contextMenuOptions: BackpackContextMenuOptions, workspace: Blockly.WorkspaceSvg, ) { if (contextMenuOptions.emptyBackpack) { registerEmptyBackpack(workspace); } if (contextMenuOptions.removeFromBackpack) { registerRemoveFromBackpack(); } if (contextMenuOptions.copyToBackpack) { registerCopyToBackpack( contextMenuOptions.disablePreconditionChecks ?? false, ); } if (contextMenuOptions.copyAllToBackpack) { registerCopyAllBackpack(); } if (contextMenuOptions.pasteAllToBackpack) { registerPasteAllBackpack(); } }