diff --git a/src/engine/blocks.js b/src/engine/blocks.js index e73f4b27..85ef3b20 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -247,7 +247,7 @@ class Blocks { // --------------------------------------------------------------------- /** - * Create event listener for blocks and variables. Handles validation and + * Create event listener for blocks, variables, and comments. Handles validation and * serves as a generic adapter between the blocks, variables, and the * runtime interface. * @param {object} e Blockly "block" or "variable" event @@ -256,7 +256,8 @@ class Blocks { blocklyListen (e, optRuntime) { // Validate event if (typeof e !== 'object') return; - if (typeof e.blockId !== 'string' && typeof e.varId !== 'string') { + if (typeof e.blockId !== 'string' && typeof e.varId !== 'string' && + typeof e.commentId !== 'string') { return; } const stage = optRuntime.getTargetForStage(); @@ -294,8 +295,9 @@ class Blocks { oldInput: e.oldInputName, newParent: e.newParentId, newInput: e.newInputName, - newCoordinate: e.newCoordinate - }); + newCoordinate: e.newCoordinate, + oldCoordinate: e.oldCoordinate + }, optRuntime); break; case 'dragOutside': if (optRuntime) { @@ -356,6 +358,74 @@ class Blocks { case 'var_delete': stage.deleteVariable(e.varId); break; + case 'comment_create': + if (optRuntime && optRuntime.getEditingTarget()) { + const currTarget = optRuntime.getEditingTarget(); + currTarget.createComment(e.commentId, e.blockId, e.text, + e.xy.x, e.xy.y, e.width, e.height, e.minimized); + } + break; + case 'comment_change': + if (optRuntime && optRuntime.getEditingTarget()) { + const currTarget = optRuntime.getEditingTarget(); + if (!currTarget.comments.hasOwnProperty(e.commentId)) { + log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); + return; + } + const comment = currTarget.comments[e.commentId]; + const change = e.newContents_; + if (typeof change === 'object') { + if (change.hasOwnProperty('minimized')) { + comment.minimized = change.minimized; + break; + } else if (change.hasOwnProperty('width') && change.hasOwnProperty('height')){ + comment.width = change.width; + comment.height = change.height; + break; + } + } else if (typeof change === 'string') { + comment.text = change; + break; + } + log.warn(`Unrecognized comment change: ${ + JSON.stringify(change)} for comment with id: ${e.commentId}.`); + return; + } + break; + case 'comment_move': + if (optRuntime && optRuntime.getEditingTarget()) { + const currTarget = optRuntime.getEditingTarget(); + if (currTarget && !currTarget.comments.hasOwnProperty(e.commentId)) { + log.warn(`Cannot change comment with id ${e.commentId} because it does not exist.`); + return; + } + const comment = currTarget.comments[e.commentId]; + const newCoord = e.newCoordinate_; + comment.x = newCoord.x; + comment.y = newCoord.y; + } + break; + case 'comment_delete': + if (optRuntime && optRuntime.getEditingTarget()) { + const currTarget = optRuntime.getEditingTarget(); + if (!currTarget.comments.hasOwnProperty(e.commentId)) { + // If we're in this state, we have probably received + // a delete event from a workspace that we switched from + // (e.g. a delete event for a comment on sprite a's workspace + // when switching from sprite a to sprite b) + return; + } + delete currTarget.comments[e.commentId]; + if (e.blockId) { + const block = currTarget.blocks.getBlock(e.blockId); + if (!block) { + log.warn(`Could not find block referenced by comment with id: ${e.commentId}`); + return; + } + delete block.comment; + } + } + break; } } @@ -482,8 +552,10 @@ class Blocks { /** * Block management: move blocks from parent to parent * @param {!object} e Blockly move event to be processed + * @param {?Runtime} optRuntime Optional runtime for updating the position + * of a comment on the block that moved. */ - moveBlock (e) { + moveBlock (e, optRuntime) { if (!this._blocks.hasOwnProperty(e.id)) { return; } @@ -492,6 +564,19 @@ class Blocks { if (e.newCoordinate) { this._blocks[e.id].x = e.newCoordinate.x; this._blocks[e.id].y = e.newCoordinate.y; + + // If the moved block has a comment, update the position of the comment. + if (typeof this._blocks[e.id].comment === 'string' && optRuntime && + e.oldCoordinate) { + const commentId = this._blocks[e.id].comment; + const currTarget = optRuntime.getEditingTarget(); + if (currTarget && currTarget.comments.hasOwnProperty(commentId)) { + const deltaX = e.newCoordinate.x - e.oldCoordinate.x; + const deltaY = e.newCoordinate.y - e.oldCoordinate.y; + currTarget.comments[commentId].x += deltaX; + currTarget.comments[commentId].y += deltaY; + } + } } // Remove from any old parent. diff --git a/src/engine/target.js b/src/engine/target.js index 5e4d2e08..a8c6828e 100644 --- a/src/engine/target.js +++ b/src/engine/target.js @@ -2,6 +2,7 @@ const EventEmitter = require('events'); const Blocks = require('./blocks'); const Variable = require('../engine/variable'); +const Comment = require('../engine/comment'); const uid = require('../util/uid'); const {Map} = require('immutable'); const log = require('../util/log'); @@ -190,6 +191,36 @@ class Target extends EventEmitter { } } + /** + * Creates a comment with the given properties. + * @param {string} id Id of the comment. + * @param {string} blockId Optional id of the block the comment is attached + * to if it is a block comment. + * @param {string} text The text the comment contains. + * @param {number} x The x coordinate of the comment on the workspace. + * @param {number} y The y coordinate of the comment on the workspace. + * @param {number} width The width of the comment when it is full size + * @param {number} height The height of the comment when it is full size + * @param {boolean} minimized Whether the comment is minimized. + */ + createComment (id, blockId, text, x, y, width, height, minimized) { + if (!this.comments.hasOwnProperty(id)) { + const newComment = new Comment(id, text, x, y, + width, height, minimized); + if (blockId) { + newComment.blockId = blockId; + const blockWithComment = this.blocks.getBlock(blockId); + if (blockWithComment) { + blockWithComment.comment = id; + } else { + log.warn(`Could not find block with id ${blockId + } associated with commentId: ${id}`); + } + } + this.comments[id] = newComment; + } + } + /** * Renames the variable with the given id to newName. * @param {string} id Id of renamed variable.