diff --git a/core/block_svg.js b/core/block_svg.js index ed93fc845..8b1429bd4 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -390,6 +390,28 @@ Blockly.BlockSvg.prototype.moveToDragSurface_ = function() { this.workspace.blockDragSurface_.setBlocksAndShow(this.getSvgRoot()); }; +/** + * Move a block to a position. + * @param {goog.math.Coordinate} xy The position to move to in workspace units. + */ +Blockly.BlockSvg.prototype.moveTo = function(xy) { + if (this.parentBlock_) { + throw Error('Block has parent.'); + } + var eventsEnabled = Blockly.Events.isEnabled(); + if (eventsEnabled) { + var event = new Blockly.Events.BlockMove(this); + } + var curXY = this.getRelativeToSurfaceXY(); + this.translate(xy.x, xy.y); + this.moveConnections_(xy.x - curXY.x, xy.y - curXY.y); + if (eventsEnabled) { + event.recordNew(); + Blockly.Events.fire(event); + } + this.workspace.resizeContents(); +}; + /** * Move this block back to the workspace block canvas. * Generally should be called at the same time as setDragging_(false). @@ -1499,3 +1521,25 @@ Blockly.BlockSvg.prototype.scheduleSnapAndBump = function() { Blockly.Events.setGroup(false); }, Blockly.BUMP_DELAY); }; + +/** + * Position a block so that it doesn't move the target block when connected. + * The block to position is usually either the first block in a dragged stack or + * an insertion marker. + * @param {!Blockly.Connection} sourceConnection The connection on the moving + * block's stack. + * @param {!Blockly.Connection} targetConnection The connection that should stay + * stationary as this block is positioned. + */ +Blockly.BlockSvg.prototype.positionNearConnection = function(sourceConnection, + targetConnection) { + // We only need to position the new block if it's before the existing one, + // otherwise its position is set by the previous block. + if (sourceConnection.type == Blockly.NEXT_STATEMENT || + sourceConnection.type == Blockly.INPUT_VALUE) { + var dx = targetConnection.x_ - sourceConnection.x_; + var dy = targetConnection.y_ - sourceConnection.y_; + + this.moveBy(dx, dy); + } +}; diff --git a/core/connection.js b/core/connection.js index 082cfc441..52e5f9f11 100644 --- a/core/connection.js +++ b/core/connection.js @@ -710,6 +710,25 @@ Blockly.Connection.prototype.neighbours_ = function(_maxLimit) { return []; }; +/** + * Get the parent input of a connection. + * @return {Blockly.Input} The input that the connection belongs to or null if + * no parent exists. + * @package + */ +Blockly.Connection.prototype.getParentInput = function() { + var parentInput = null; + var block = this.sourceBlock_; + var inputs = block.inputList; + for (var idx = 0; idx < block.inputList.length; idx++) { + if (inputs[idx].connection === this) { + parentInput = inputs[idx]; + break; + } + } + return parentInput; +}; + /** * This method returns a string describing this Connection in developer terms * (English only). Intended to on be used in console logs and errors. diff --git a/core/css.js b/core/css.js index 1fa075011..775f9d4f1 100644 --- a/core/css.js +++ b/core/css.js @@ -647,6 +647,11 @@ Blockly.Css.CONTENT = [ 'padding: 0 !important;', '}', + '.blocklyVerticalCursor {', + 'stroke-width: 3px;', + 'fill: rgba(255,255,255,0.5);', + '}', + '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,', '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {', 'background: url(<<>>/sprites.png) no-repeat -48px -16px;', diff --git a/core/field.js b/core/field.js index 1ff332c76..42cb66646 100644 --- a/core/field.js +++ b/core/field.js @@ -936,3 +936,27 @@ Blockly.Field.prototype.getAbsoluteXY_ = function() { Blockly.Field.prototype.referencesVariables = function() { return false; }; + +/** + * Search through the list of inputs and their fields in order to find the + * parent input of a field. + * @return {Blockly.Input} The input that the field belongs to. + * @package + */ +Blockly.Field.prototype.getParentInput = function() { + var parentInput = null; + var block = this.sourceBlock_; + var inputs = block.inputList; + + for (var idx = 0; idx < block.inputList.length; idx++) { + var input = inputs[idx]; + var fieldRows = input.fieldRow; + for (var j = 0; j < fieldRows.length; j++) { + if (fieldRows[j] === this) { + parentInput = input; + break; + } + } + } + return parentInput; +}; diff --git a/core/input.js b/core/input.js index 5b9c8b170..ddfa1d772 100644 --- a/core/input.js +++ b/core/input.js @@ -71,6 +71,14 @@ Blockly.Input.prototype.align = Blockly.ALIGN_LEFT; */ Blockly.Input.prototype.visible_ = true; +/** + * Get the source block for this input. + * @return {Blockly.Block} The source block, or null if there is none. + */ +Blockly.Input.prototype.getSourceBlock = function() { + return this.sourceBlock_; +}; + /** * Add a field (or label from string), and all prefix and suffix fields, to the * end of the input's field row. diff --git a/core/rendered_connection.js b/core/rendered_connection.js index b9ab29a16..610881f9d 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -162,6 +162,15 @@ Blockly.RenderedConnection.prototype.setOffsetInBlock = function(x, y) { this.offsetInBlock_.y = y; }; +/** + * Get the offset of this connection relative to the top left of its block. + * @return {!goog.math.Coordinate} The offset of the connection. + * @package + */ +Blockly.RenderedConnection.prototype.getOffsetInBlock = function() { + return this.offsetInBlock_; +}; + /** * Move the blocks on either side of this connection right next to each other. * @private diff --git a/core/utils.js b/core/utils.js index 160696d76..fe29242c5 100644 --- a/core/utils.js +++ b/core/utils.js @@ -586,6 +586,42 @@ Blockly.utils.getBlockTypeCounts = function(block, opt_stripFollowing) { return typeCountsMap; }; +/** + * Converts screen coordinates to workspace coordinates. + * @param {Blockly.Workspace_Svg} ws The workspace to find the coordinates on. + * @param {goog.math.Coordinate} screenCoordinates The screen coordinates to be + * converted to workspace coordintaes + * @return {goog.math.Coorindate} The workspace coordinates. + * @package + */ +Blockly.utils.screenToWsCoordinates = function(ws, screenCoordinates) { + var screenX = screenCoordinates.x; + var screenY = screenCoordinates.y; + + var injectionDiv = ws.getInjectionDiv(); + // Bounding rect coordinates are in client coordinates, meaning that they + // are in pixels relative to the upper left corner of the visible browser + // window. These coordinates change when you scroll the browser window. + var boundingRect = injectionDiv.getBoundingClientRect(); + + // The client coordinates offset by the injection div's upper left corner. + var clientOffsetPixels = new goog.math.Coordinate( + screenX - boundingRect.left, screenY - boundingRect.top); + + // The offset in pixels between the main workspace's origin and the upper + // left corner of the injection div. + var mainOffsetPixels = ws.getOriginOffsetInPixels(); + + // The position of the new comment in pixels relative to the origin of the + // main workspace. + var finalOffsetPixels = goog.math.Coordinate.difference(clientOffsetPixels, + mainOffsetPixels); + + // The position in main workspace coordinates. + var finalOffsetMainWs = finalOffsetPixels.scale(1 / ws.scale); + return finalOffsetMainWs; +}; + /** * Reference to the global object. */