mirror of
https://github.com/google/blockly.git
synced 2026-01-30 12:10:12 +01:00
refactor(shortcuts): Factor copy-eligibility out of cut/copy preconditionFn (#9102)
* refactor(shortcuts): Rename import isDeletable -> isIDeletable etc. Some of the existing code is confusing to read because e.g. isDeletable doesn't check if an item .isDeletable(), but only whether it is an IDeletable. By renaming these imports the shortcut precondition functions are easier to understand, and allows a subsequent to commit to add an isCopyable function that actually checks copyability. * refactor(shortcuts): Introduce isCopyable Create a function, isCopyable, that encapsulates the criteria we currently use to determine whether an item can be copied. This facilitate future modification of the copyability criteria (but is not intended to modify them at all at the present time). * chore(shortcuts): Add TODO re: copying shadow blocks
This commit is contained in:
committed by
GitHub
parent
d5a4522dd2
commit
b0b685a739
@@ -10,9 +10,17 @@ import {BlockSvg} from './block_svg.js';
|
||||
import * as clipboard from './clipboard.js';
|
||||
import * as eventUtils from './events/utils.js';
|
||||
import {Gesture} from './gesture.js';
|
||||
import {ICopyData, isCopyable} from './interfaces/i_copyable.js';
|
||||
import {isDeletable} from './interfaces/i_deletable.js';
|
||||
import {isDraggable} from './interfaces/i_draggable.js';
|
||||
import {
|
||||
ICopyable,
|
||||
ICopyData,
|
||||
isCopyable as isICopyable,
|
||||
} from './interfaces/i_copyable.js';
|
||||
import {
|
||||
IDeletable,
|
||||
isDeletable as isIDeletable,
|
||||
} from './interfaces/i_deletable.js';
|
||||
import {IDraggable, isDraggable} from './interfaces/i_draggable.js';
|
||||
import {IFocusableNode} from './interfaces/i_focusable_node.js';
|
||||
import {KeyboardShortcut, ShortcutRegistry} from './shortcut_registry.js';
|
||||
import {Coordinate} from './utils/coordinate.js';
|
||||
import {KeyCodes} from './utils/keycodes.js';
|
||||
@@ -62,7 +70,7 @@ export function registerDelete() {
|
||||
return (
|
||||
!workspace.isReadOnly() &&
|
||||
focused != null &&
|
||||
isDeletable(focused) &&
|
||||
isIDeletable(focused) &&
|
||||
focused.isDeletable() &&
|
||||
!Gesture.inProgress()
|
||||
);
|
||||
@@ -76,7 +84,7 @@ export function registerDelete() {
|
||||
const focused = scope.focusedNode;
|
||||
if (focused instanceof BlockSvg) {
|
||||
focused.checkAndDelete();
|
||||
} else if (isDeletable(focused) && focused.isDeletable()) {
|
||||
} else if (isIDeletable(focused) && focused.isDeletable()) {
|
||||
eventUtils.setGroup(true);
|
||||
focused.dispose();
|
||||
eventUtils.setGroup(false);
|
||||
@@ -92,6 +100,39 @@ let copyData: ICopyData | null = null;
|
||||
let copyWorkspace: WorkspaceSvg | null = null;
|
||||
let copyCoords: Coordinate | null = null;
|
||||
|
||||
/**
|
||||
* Determine if a focusable node can be copied using cut or copy.
|
||||
*
|
||||
* Unfortunately the ICopyable interface doesn't include an isCopyable
|
||||
* method, so we must use some other criteria to make the decision.
|
||||
* Specifically,
|
||||
*
|
||||
* - It must be an ICopyable.
|
||||
* - So that a pasted copy can be manipluated and/or disposed of, it
|
||||
* must be both an IDraggable and an IDeletable.
|
||||
* - Additionally, both .isMovable() and .isDeletable() must return
|
||||
* true (i.e., can currently be moved and deleted).
|
||||
*
|
||||
* TODO(#9098): Revise these criteria. The latter criteria prevents
|
||||
* shadow blocks from being copied; additionally, there are likely to
|
||||
* be other circumstances were it is desirable to allow movable /
|
||||
* copyable copies of a currently-unmovable / -copyable block to be
|
||||
* made.
|
||||
*
|
||||
* @param focused The focused object.
|
||||
*/
|
||||
function isCopyable(
|
||||
focused: IFocusableNode,
|
||||
): focused is ICopyable<ICopyData> & IDeletable & IDraggable {
|
||||
return (
|
||||
isICopyable(focused) &&
|
||||
isIDeletable(focused) &&
|
||||
focused.isDeletable() &&
|
||||
isDraggable(focused) &&
|
||||
focused.isMovable()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyboard shortcut to copy a block on ctrl+c, cmd+c, or alt+c.
|
||||
*/
|
||||
@@ -110,11 +151,7 @@ export function registerCopy() {
|
||||
return (
|
||||
!workspace.isReadOnly() &&
|
||||
!Gesture.inProgress() &&
|
||||
focused != null &&
|
||||
isDeletable(focused) &&
|
||||
focused.isDeletable() &&
|
||||
isDraggable(focused) &&
|
||||
focused.isMovable() &&
|
||||
!!focused &&
|
||||
isCopyable(focused)
|
||||
);
|
||||
},
|
||||
@@ -124,7 +161,7 @@ export function registerCopy() {
|
||||
e.preventDefault();
|
||||
workspace.hideChaff();
|
||||
const focused = scope.focusedNode;
|
||||
if (!focused || !isCopyable(focused)) return false;
|
||||
if (!focused || !isICopyable(focused)) return false;
|
||||
copyData = focused.toCopyData();
|
||||
copyWorkspace =
|
||||
focused.workspace instanceof WorkspaceSvg
|
||||
@@ -158,13 +195,11 @@ export function registerCut() {
|
||||
return (
|
||||
!workspace.isReadOnly() &&
|
||||
!Gesture.inProgress() &&
|
||||
focused != null &&
|
||||
isDeletable(focused) &&
|
||||
focused.isDeletable() &&
|
||||
isDraggable(focused) &&
|
||||
focused.isMovable() &&
|
||||
!!focused &&
|
||||
isCopyable(focused) &&
|
||||
!focused.workspace.isFlyout
|
||||
// Extra criteria for cut (not just copy):
|
||||
!focused.workspace.isFlyout &&
|
||||
focused.isDeletable()
|
||||
);
|
||||
},
|
||||
callback(workspace, e, shortcut, scope) {
|
||||
@@ -177,9 +212,9 @@ export function registerCut() {
|
||||
focused.checkAndDelete();
|
||||
return true;
|
||||
} else if (
|
||||
isDeletable(focused) &&
|
||||
isIDeletable(focused) &&
|
||||
focused.isDeletable() &&
|
||||
isCopyable(focused)
|
||||
isICopyable(focused)
|
||||
) {
|
||||
copyData = focused.toCopyData();
|
||||
copyWorkspace = workspace;
|
||||
|
||||
Reference in New Issue
Block a user