From 9ffe272d13ded9bedc8c0f90de9e8792ec957043 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 3 Sep 2021 22:19:52 +0000 Subject: [PATCH] fix: copy paste with json system (#5423) * fix: copy paste w/ json system * fix: pr comments --- core/block_svg.js | 14 +++------- core/blockly.js | 48 ++++++++------------------------ core/interfaces/i_copyable.js | 3 +- core/workspace_comment_svg.js | 6 +++- core/workspace_svg.js | 52 +++++++++++++++++++++++------------ 5 files changed, 57 insertions(+), 66 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 08e5addcb..772b37f41 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -45,7 +45,6 @@ goog.require('Blockly.utils.object'); goog.require('Blockly.utils.Rect'); goog.require('Blockly.utils.Svg'); goog.require('Blockly.utils.userAgent'); -goog.require('Blockly.Xml'); goog.requireType('Blockly.blockRendering.Debug'); goog.requireType('Blockly.Comment'); @@ -963,17 +962,12 @@ Blockly.BlockSvg.prototype.toCopyData = function() { if (this.isInsertionMarker_) { return null; } - var xml = /** @type {!Element} */ (Blockly.Xml.blockToDom(this, true)); - // Copy only the selected block and internal blocks. - Blockly.Xml.deleteNext(xml); - // Encode start position in XML. - var xy = this.getRelativeToSurfaceXY(); - xml.setAttribute('x', this.RTL ? -xy.x : xy.x); - xml.setAttribute('y', xy.y); return { - xml: xml, + saveInfo: /** @type {!Blockly.serialization.blocks.State} */ + (Blockly.serialization.blocks.save( + this, {addCoordinates: true, addNextBlocks: false})), source: this.workspace, - typeCounts: Blockly.utils.getBlockTypeCounts(this, true) + typeCounts: Blockly.utils.getBlockTypeCounts(this, true), }; }; diff --git a/core/blockly.js b/core/blockly.js index 92716e4d1..fd604d8f4 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -92,24 +92,10 @@ Blockly.draggingConnections = []; /** * Contents of the local clipboard. - * @type {Element} + * @type {?Blockly.ICopyable.CopyData} * @private */ -Blockly.clipboardXml_ = null; - -/** - * Source of the local clipboard. - * @type {Blockly.WorkspaceSvg} - * @private - */ -Blockly.clipboardSource_ = null; - -/** - * Map of types to type counts for the clipboard object and descendants. - * @type {Object} - * @private - */ -Blockly.clipboardTypeCounts_ = null; +Blockly.clipboardData_ = null; /** * Cached value for whether 3D is supported. @@ -234,12 +220,7 @@ Blockly.deleteBlock = function(selected) { * @package */ Blockly.copy = function(toCopy) { - var data = toCopy.toCopyData(); - if (data) { - Blockly.clipboardXml_ = data.xml; - Blockly.clipboardSource_ = data.source; - Blockly.clipboardTypeCounts_ = data.typeCounts; - } + Blockly.clipboardData_ = toCopy.toCopyData(); }; /** @@ -248,19 +229,19 @@ Blockly.copy = function(toCopy) { * @package */ Blockly.paste = function() { - if (!Blockly.clipboardXml_) { + if (!Blockly.clipboardData_) { return false; } // Pasting always pastes to the main workspace, even if the copy // started in a flyout workspace. - var workspace = Blockly.clipboardSource_; + var workspace = Blockly.clipboardData_.source; if (workspace.isFlyout) { workspace = workspace.targetWorkspace; } - if (Blockly.clipboardTypeCounts_ && - workspace.isCapacityAvailable(Blockly.clipboardTypeCounts_)) { + if (Blockly.clipboardData_.typeCounts && + workspace.isCapacityAvailable(Blockly.clipboardData_.typeCounts)) { Blockly.Events.setGroup(true); - workspace.paste(Blockly.clipboardXml_); + workspace.paste(Blockly.clipboardData_.saveInfo); Blockly.Events.setGroup(false); return true; } @@ -274,17 +255,10 @@ Blockly.paste = function() { * @package */ Blockly.duplicate = function(toDuplicate) { - // Save the clipboard. - var clipboardXml = Blockly.clipboardXml_; - var clipboardSource = Blockly.clipboardSource_; - - // Create a duplicate via a copy/paste operation. + var data = Blockly.clipboardData_; Blockly.copy(toDuplicate); - toDuplicate.workspace.paste(Blockly.clipboardXml_); - - // Restore the clipboard. - Blockly.clipboardXml_ = clipboardXml; - Blockly.clipboardSource_ = clipboardSource; + toDuplicate.workspace.paste(Blockly.clipboardData_.saveInfo); + Blockly.clipboardData_ = data; }; /** diff --git a/core/interfaces/i_copyable.js b/core/interfaces/i_copyable.js index 4aeac9776..c01bbc9c2 100644 --- a/core/interfaces/i_copyable.js +++ b/core/interfaces/i_copyable.js @@ -26,13 +26,14 @@ Blockly.ICopyable = function() {}; /** * Encode for copying. * @return {?Blockly.ICopyable.CopyData} Copy metadata. + * @package */ Blockly.ICopyable.prototype.toCopyData; /** * Copy Metadata. * @typedef {{ - * xml:!Element, + * saveInfo:(!Object|!Element), * source:Blockly.WorkspaceSvg, * typeCounts:?Object * }} diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 401b840e1..2a3dea3be 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -643,7 +643,11 @@ Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) { * @package */ Blockly.WorkspaceCommentSvg.prototype.toCopyData = function() { - return {xml: this.toXmlWithXY(), source: this.workspace, typeCounts: null}; + return { + saveInfo: this.toXmlWithXY(), + source: this.workspace, + typeCounts: null + }; }; /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 6721722bb..d97550c4a 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1467,40 +1467,58 @@ Blockly.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. */ -Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { - if (!this.rendered || !xmlBlock.tagName || xmlBlock.getElementsByTagName('block').length >= - this.remainingCapacity()) { +Blockly.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 {!Blockly.serialization.blocks.State} */ (state)); } else { - this.pasteBlock_(xmlBlock); + var 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 {?Blockly.serialization.blocks.State} jsonBlock JSON block + * representation. * @private */ -Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { +Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock, jsonBlock) { Blockly.Events.disable(); try { - var block = Blockly.Xml.domToBlock(xmlBlock, this); + var block; + var blockX; + var blockY; + if (xmlBlock) { + block = Blockly.Xml.domToBlock(xmlBlock, this); + blockX = parseInt(xmlBlock.getAttribute('x'), 10); + blockY = parseInt(xmlBlock.getAttribute('y'), 10); + } else if (jsonBlock) { + block = Blockly.serialization.blocks.load(jsonBlock, this); + blockX = jsonBlock['x'] || 10; + blockY = jsonBlock['y'] || 10; + } // Move the duplicate to original position. - var blockX = parseInt(xmlBlock.getAttribute('x'), 10); - var blockY = parseInt(xmlBlock.getAttribute('y'), 10); if (!isNaN(blockX) && !isNaN(blockY)) { if (this.RTL) { blockX = -blockX; @@ -1539,7 +1557,7 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { blockY += Blockly.SNAP_RADIUS * 2; } } while (collide); - block.moveBy(blockX, blockY); + block.moveTo(new Blockly.utils.Coordinate(blockX, blockY)); } } finally { Blockly.Events.enable();