feat: add copy api and paste into correct workspace (#9215)

* feat: add copy api and paste into correct workspace

* fix: dont paste into unrendered workspaces

* fix: paste precondition and add test
This commit is contained in:
Maribeth Moffatt
2025-07-08 16:05:53 -07:00
committed by GitHub
parent 89af298918
commit c0489b41e0
4 changed files with 181 additions and 48 deletions

View File

@@ -76,7 +76,7 @@ suite('Clipboard', function () {
await mutatorIcon.setBubbleVisible(true);
const mutatorWorkspace = mutatorIcon.getWorkspace();
const elseIf = mutatorWorkspace.getBlocksByType('controls_if_elseif')[0];
assert.notEqual(elseIf, undefined);
assert.isDefined(elseIf);
assert.lengthOf(mutatorWorkspace.getAllBlocks(), 2);
assert.lengthOf(this.workspace.getAllBlocks(), 1);
const data = elseIf.toCopyData();
@@ -85,6 +85,34 @@ suite('Clipboard', function () {
assert.lengthOf(this.workspace.getAllBlocks(), 1);
});
test('pasting into a mutator flyout pastes into the mutator workspace', async function () {
const block = Blockly.serialization.blocks.append(
{
'type': 'controls_if',
'id': 'blockId',
'extraState': {
'elseIfCount': 1,
},
},
this.workspace,
);
const mutatorIcon = block.getIcon(Blockly.icons.IconType.MUTATOR);
await mutatorIcon.setBubbleVisible(true);
const mutatorWorkspace = mutatorIcon.getWorkspace();
const mutatorFlyoutWorkspace = mutatorWorkspace
.getFlyout()
.getWorkspace();
const elseIf =
mutatorFlyoutWorkspace.getBlocksByType('controls_if_elseif')[0];
assert.isDefined(elseIf);
assert.lengthOf(mutatorWorkspace.getAllBlocks(), 2);
assert.lengthOf(this.workspace.getAllBlocks(), 1);
const data = elseIf.toCopyData();
Blockly.clipboard.paste(data, mutatorFlyoutWorkspace);
assert.lengthOf(mutatorWorkspace.getAllBlocks(), 3);
assert.lengthOf(this.workspace.getAllBlocks(), 1);
});
suite('pasted blocks are placed in unambiguous locations', function () {
test('pasted blocks are bumped to not overlap', function () {
const block = Blockly.serialization.blocks.append(
@@ -139,8 +167,7 @@ suite('Clipboard', function () {
});
suite('pasting comments', function () {
// TODO: Reenable test when we readd copy-paste.
test.skip('pasted comments are bumped to not overlap', function () {
test('pasted comments are bumped to not overlap', function () {
Blockly.Xml.domToWorkspace(
Blockly.utils.xml.textToDom(
'<xml><comment id="test" x=10 y=10/></xml>',
@@ -153,7 +180,7 @@ suite('Clipboard', function () {
const newComment = Blockly.clipboard.paste(data, this.workspace);
assert.deepEqual(
newComment.getRelativeToSurfaceXY(),
new Blockly.utils.Coordinate(60, 60),
new Blockly.utils.Coordinate(40, 40),
);
});
});

View File

@@ -5,6 +5,7 @@
*/
import * as Blockly from '../../build/src/core/blockly.js';
import {assert} from '../../node_modules/chai/chai.js';
import {defineStackBlock} from './test_helpers/block_definitions.js';
import {
sharedTestSetup,
@@ -399,6 +400,19 @@ suite('Keyboard Shortcut Items', function () {
});
});
suite('Paste', function () {
test('Disabled when nothing has been copied', function () {
const pasteShortcut =
Blockly.ShortcutRegistry.registry.getRegistry()[
Blockly.ShortcutItems.names.PASTE
];
Blockly.clipboard.setLastCopiedData(undefined);
const isPasteEnabled = pasteShortcut.preconditionFn();
assert.isFalse(isPasteEnabled);
});
});
suite('Undo', function () {
setup(function () {
this.undoSpy = sinon.spy(this.workspace, 'undo');