Skip to content

Commit

Permalink
fix: copy paste with json system (google#5423)
Browse files Browse the repository at this point in the history
* fix: copy paste w/ json system

* fix: pr comments
  • Loading branch information
BeksOmega authored and alschmiedt committed Sep 20, 2021
1 parent 96935c2 commit e7541cb
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 64 deletions.
12 changes: 3 additions & 9 deletions core/block_svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ const Tooltip = goog.require('Blockly.Tooltip');
const Warning = goog.requireType('Blockly.Warning');
/* eslint-disable-next-line no-unused-vars */
const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg');
const Xml = goog.require('Blockly.Xml');
const blockAnimations = goog.require('Blockly.blockAnimations');
const blocks = goog.require('Blockly.serialization.blocks');
const browserEvents = goog.require('Blockly.browserEvents');
const common = goog.require('Blockly.common');
const connectionTypes = goog.require('Blockly.connectionTypes');
Expand Down Expand Up @@ -996,15 +996,9 @@ BlockSvg.prototype.toCopyData = function() {
if (this.isInsertionMarker_) {
return null;
}
const xml = /** @type {!Element} */ (Xml.blockToDom(this, true));
// Copy only the selected block and internal blocks.
Xml.deleteNext(xml);
// Encode start position in XML.
const xy = this.getRelativeToSurfaceXY();
xml.setAttribute('x', this.RTL ? -xy.x : xy.x);
xml.setAttribute('y', xy.y);
return {
xml: xml,
saveInfo: /** @type {!blocks.State} */(blocks.save(
this, {addCoordinates: true, addNextBlocks: false})),
source: this.workspace,
typeCounts: utils.getBlockTypeCounts(this, true)
};
Expand Down
14 changes: 4 additions & 10 deletions core/clipboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ exports.copy = copy;
* @return {boolean} True if the paste was successful, false otherwise.
*/
const paste = function() {
if (!copyData.xml) {
if (!copyData) {
return false;
}
// Pasting always pastes to the main workspace, even if the copy
// started in a flyout workspace.
var workspace = copyData.source;
let workspace = copyData.source;
if (workspace.isFlyout) {
workspace = workspace.targetWorkspace;
}
if (copyData.typeCounts &&
workspace.isCapacityAvailable(copyData.typeCounts)) {
Events.setGroup(true);
workspace.paste(copyData.xml);
workspace.paste(copyData.saveInfo);
Events.setGroup(false);
return true;
}
Expand All @@ -65,15 +65,9 @@ exports.paste = paste;
* duplicated.
*/
const duplicate = function(toDuplicate) {
// Save the clipboard.
const oldCopyData = copyData;

// Create a duplicate via a copy/paste operation.
copy(toDuplicate);
// copy() replaced the value of copyData.
toDuplicate.workspace.paste(copyData.xml);

// Restore the clipboard.
toDuplicate.workspace.paste(copyData.saveInfo);
copyData = oldCopyData;
};
/** @package */
Expand Down
3 changes: 2 additions & 1 deletion core/interfaces/i_copyable.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ const ICopyable = function() {};
/**
* Encode for copying.
* @return {?ICopyable.CopyData} Copy metadata.
* @package
*/
ICopyable.prototype.toCopyData;

/**
* Copy Metadata.
* @typedef {{
* xml:!Element,
* saveInfo:(!Object|!Element),
* source:WorkspaceSvg,
* typeCounts:?Object
* }}
Expand Down
6 changes: 5 additions & 1 deletion core/workspace_comment_svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,11 @@ WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) {
* @package
*/
WorkspaceCommentSvg.prototype.toCopyData = function() {
return {xml: this.toXmlWithXY(), source: this.workspace, typeCounts: null};
return {
saveInfo: this.toXmlWithXY(),
source: this.workspace,
typeCounts: null
};
};

/**
Expand Down
53 changes: 34 additions & 19 deletions core/workspace_svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const Xml = goog.require('Blockly.Xml');
/* eslint-disable-next-line no-unused-vars */
const ZoomControls = goog.requireType('Blockly.ZoomControls');
const blockRendering = goog.require('Blockly.blockRendering');
const blocks = goog.require('Blockly.serialization.blocks');
const browserEvents = goog.require('Blockly.browserEvents');
const common = goog.require('Blockly.common');
const dom = goog.require('Blockly.utils.dom');
Expand Down Expand Up @@ -1504,43 +1505,57 @@ WorkspaceSvg.prototype.highlightBlock = function(id, opt_state) {
};

/**
* Paste the provided block onto the workspace.
* @param {!Element|!DocumentFragment} xmlBlock XML block element or an empty
* DocumentFragment if the block was an insertion marker.
* Pastes the provided block or workspace comment onto the workspace.
* Does not check whether there is remaining capacity for the object, that
* should be done before calling this method.
* @param {!Object|!Element|!DocumentFragment} state The representation of the
* thing to paste.
*/
WorkspaceSvg.prototype.paste = function(xmlBlock) {
if (!this.rendered || !xmlBlock.tagName ||
xmlBlock.getElementsByTagName('block').length >=
this.remainingCapacity()) {
WorkspaceSvg.prototype.paste = function(state) {
if (!this.rendered || !state['type'] && !state.tagName) {
return;
}
// The check above for tagName rules out the possibility of this being a
// DocumentFragment.
xmlBlock = /** @type {!Element} */ (xmlBlock);
if (this.currentGesture_) {
this.currentGesture_.cancel(); // Dragging while pasting? No.
}
if (xmlBlock.tagName.toLowerCase() == 'comment') {
this.pasteWorkspaceComment_(xmlBlock);

// Checks if this is JSON. JSON has a type property, while elements don't.
if (state['type']) {
this.pasteBlock_(null, /** @type {!blocks.State} */ (state));
} else {
this.pasteBlock_(xmlBlock);
const xmlBlock = /** @type {!Element} */ (state);
if (xmlBlock.tagName.toLowerCase() == 'comment') {
this.pasteWorkspaceComment_(xmlBlock);
} else {
this.pasteBlock_(xmlBlock, null);
}
}
};

/**
* Paste the provided block onto the workspace.
* @param {!Element} xmlBlock XML block element.
* @param {?Element} xmlBlock XML block element.
* @param {?blocks.State} jsonBlock JSON block
* representation.
* @private
*/
WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) {
WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock, jsonBlock) {
Events.disable();
let block;
try {
block = Xml.domToBlock(xmlBlock, this);
let blockX;
let blockY;
if (xmlBlock) {
block = Xml.domToBlock(xmlBlock, this);
blockX = parseInt(xmlBlock.getAttribute('x'), 10);
blockY = parseInt(xmlBlock.getAttribute('y'), 10);
} else if (jsonBlock) {
block = blocks.load(jsonBlock, this);
blockX = jsonBlock['x'] || 10;
blockY = jsonBlock['y'] || 10;
}

// Move the duplicate to original position.
let blockX = parseInt(xmlBlock.getAttribute('x'), 10);
let blockY = parseInt(xmlBlock.getAttribute('y'), 10);
if (!isNaN(blockX) && !isNaN(blockY)) {
if (this.RTL) {
blockX = -blockX;
Expand Down Expand Up @@ -1580,7 +1595,7 @@ WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) {
blockY += internalConstants.SNAP_RADIUS * 2;
}
} while (collide);
block.moveBy(blockX, blockY);
block.moveTo(new Coordinate(blockX, blockY));
}
} finally {
Events.enable();
Expand Down
Loading

0 comments on commit e7541cb

Please sign in to comment.