diff --git a/core/block_svg.js b/core/block_svg.js index 5938e597e..83af1db30 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -32,6 +32,7 @@ goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.object'); goog.require('Blockly.utils.Rect'); +goog.requireType('Blockly.ICopyable'); /** * Class for a block's SVG representation. @@ -42,6 +43,7 @@ goog.require('Blockly.utils.Rect'); * @param {string=} opt_id Optional ID. Use this ID if provided, otherwise * create a new ID. * @extends {Blockly.Block} + * @implements {Blockly.ICopyable} * @constructor */ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { @@ -991,6 +993,26 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { Blockly.utils.dom.stopTextWidthCache(); }; +/** + * Encode a block for copying. + * @return {!Blockly.ICopyable.CopyData} Copy metadata. + * @package + */ +Blockly.BlockSvg.prototype.toCopyData = function() { + var xml = 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, + source: this.workspace, + typeCounts: Blockly.utils.getBlockTypeCounts(this, true) + }; +}; + /** * Change the colour of a block. * @package diff --git a/core/blockly.js b/core/blockly.js index 209c22e96..ceeae2ae8 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -51,7 +51,7 @@ Blockly.mainWorkspace = null; /** * Currently selected block. - * @type {Blockly.Block} + * @type {?Blockly.ICopyable} */ Blockly.selected = null; @@ -264,32 +264,20 @@ Blockly.onKeyDown = function(e) { /** * Copy a block or workspace comment onto the local clipboard. - * @param {!Blockly.Block | !Blockly.WorkspaceComment} toCopy Block or - * Workspace Comment to be copied. + * @param {!Blockly.ICopyable} toCopy Block or Workspace Comment to be copied. * @private */ Blockly.copy_ = function(toCopy) { - if (toCopy.isComment) { - var xml = toCopy.toXmlWithXY(); - } else { - var xml = Blockly.Xml.blockToDom(toCopy, true); - // Copy only the selected block and internal blocks. - Blockly.Xml.deleteNext(xml); - // Encode start position in XML. - var xy = toCopy.getRelativeToSurfaceXY(); - xml.setAttribute('x', toCopy.RTL ? -xy.x : xy.x); - xml.setAttribute('y', xy.y); - } - Blockly.clipboardXml_ = xml; - Blockly.clipboardSource_ = toCopy.workspace; - Blockly.clipboardTypeCounts_ = toCopy.isComment ? null : - Blockly.utils.getBlockTypeCounts(toCopy, true); + var data = toCopy.toCopyData(); + Blockly.clipboardXml_ = data.xml; + Blockly.clipboardSource_ = data.source; + Blockly.clipboardTypeCounts_ = data.typeCounts; }; /** * Duplicate this block and its children, or a workspace comment. - * @param {!Blockly.Block | !Blockly.WorkspaceComment} toDuplicate Block or - * Workspace Comment to be copied. + * @param {!Blockly.ICopyable} toDuplicate Block or Workspace Comment to be + * copied. * @package */ Blockly.duplicate = function(toDuplicate) { diff --git a/core/interfaces/i_copyable.js b/core/interfaces/i_copyable.js new file mode 100644 index 000000000..807911ef9 --- /dev/null +++ b/core/interfaces/i_copyable.js @@ -0,0 +1,41 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview The interface for an object that is copyable. + * @author samelh@google.com (Sam El-Husseini) + */ + +'use strict'; + +goog.provide('Blockly.ICopyable'); + +goog.require('Blockly.ISelectable'); + +goog.requireType('Blockly.WorkspaceSvg'); + + +/** + * @extends {Blockly.ISelectable} + * @interface + */ +Blockly.ICopyable = function() {}; + +/** + * Encode for copying. + * @return {!Blockly.ICopyable.CopyData} Copy metadata. + */ +Blockly.ICopyable.prototype.toCopyData; + +/** + * Copy Metadata. + * @typedef {{ + * xml:!Element, + * source:Blockly.WorkspaceSvg, + * typeCounts:?Object + * }} + */ +Blockly.ICopyable.CopyData; diff --git a/core/interfaces/i_deletable.js b/core/interfaces/i_deletable.js new file mode 100644 index 000000000..ee3058666 --- /dev/null +++ b/core/interfaces/i_deletable.js @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview The interface for an object that is deletable. + * @author samelh@google.com (Sam El-Husseini) + */ + +'use strict'; + +goog.provide('Blockly.IDeletable'); + + +/** @interface */ +Blockly.IDeletable = function() {}; + +/** + * Get whether this object is deletable or not. + * @return {boolean} True if deletable. + */ +Blockly.IDeletable.prototype.isDeletable; diff --git a/core/interfaces/i_movable.js b/core/interfaces/i_movable.js new file mode 100644 index 000000000..f183cd196 --- /dev/null +++ b/core/interfaces/i_movable.js @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview The interface for an object that is movable. + * @author samelh@google.com (Sam El-Husseini) + */ + +'use strict'; + +goog.provide('Blockly.IMovable'); + + +/** @interface */ +Blockly.IMovable = function() {}; + +/** + * Get whether this is movable or not. + * @return {boolean} True if movable. + */ +Blockly.IMovable.prototype.isMovable; diff --git a/core/interfaces/i_selectable.js b/core/interfaces/i_selectable.js new file mode 100644 index 000000000..8db8a63f5 --- /dev/null +++ b/core/interfaces/i_selectable.js @@ -0,0 +1,42 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview The interface for an object that is selectable. + * @author samelh@google.com (Sam El-Husseini) + */ + +'use strict'; + +goog.provide('Blockly.ISelectable'); + +goog.require('Blockly.IDeletable'); +goog.require('Blockly.IMovable'); + + +/** + * @extends {Blockly.IDeletable} + * @extends {Blockly.IMovable} + * @interface + */ +Blockly.ISelectable = function() {}; + +/** + * @type {string} + */ +Blockly.ISelectable.prototype.id; + +/** + * Select this. Highlight it visually. + * @return {void} + */ +Blockly.ISelectable.prototype.select; + +/** + * Unselect this. Unhighlight it visually. + * @return {void} + */ +Blockly.ISelectable.prototype.unselect; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index f4b97a136..5301018cf 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -25,6 +25,7 @@ goog.require('Blockly.utils.object'); goog.require('Blockly.utils.Rect'); goog.require('Blockly.WorkspaceComment'); +goog.requireType('Blockly.ICopyable'); /** * Class for a workspace comment's SVG representation. @@ -35,6 +36,7 @@ goog.require('Blockly.WorkspaceComment'); * @param {string=} opt_id Optional ID. Use this ID if provided, otherwise * create a new ID. * @extends {Blockly.WorkspaceComment} + * @implements {Blockly.ICopyable} * @constructor */ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width, @@ -612,6 +614,19 @@ Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) { return element; }; +/** + * Encode a comment for copying. + * @return {!Blockly.ICopyable.CopyData} Copy metadata. + * @package + */ +Blockly.WorkspaceCommentSvg.prototype.toCopyData = function() { + return { + xml: this.toXmlWithXY(), + source: this.workspace, + typeCounts: null + }; +}; + /** * CSS for workspace comment. See css.js for use. */ diff --git a/scripts/gulpfiles/typings.js b/scripts/gulpfiles/typings.js index 81dbe7ea6..0822dea3b 100644 --- a/scripts/gulpfiles/typings.js +++ b/scripts/gulpfiles/typings.js @@ -33,6 +33,7 @@ function typings() { "core/renderers/common", "core/renderers/measurables", "core/theme", + "core/interfaces", "core/utils", "msg/" ];