Merge branch 'develop'

This commit is contained in:
Neil Fraser
2016-04-21 06:05:55 -07:00
17 changed files with 749 additions and 658 deletions
+369 -365
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -43,14 +43,14 @@ goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.Bl
goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.ContextMenu', 'goog.Timer', 'goog.asserts', 'goog.dom', 'goog.math.Coordinate', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'goog.color', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []);
goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Workspace', 'goog.dom', 'goog.math', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Workspace', 'goog.dom', 'goog.math', 'goog.math.Coordinate', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Icon', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['goog.asserts', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']);
goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []);
goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['goog.dom', 'goog.events', 'goog.style', 'goog.ui.Menu', 'goog.ui.MenuItem']);
goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []);
goog.addDependency("../../../" + dir + "/core/events.js", ['Blockly.Events'], []);
goog.addDependency("../../../" + dir + "/core/events.js", ['Blockly.Events'], ['goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['goog.asserts', 'goog.dom', 'goog.math.Size', 'goog.style', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.FieldTextInput', 'goog.math', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/field_checkbox.js", ['Blockly.FieldCheckbox'], ['Blockly.Field']);
@@ -61,9 +61,9 @@ goog.addDependency("../../../" + dir + "/core/field_image.js", ['Blockly.FieldIm
goog.addDependency("../../../" + dir + "/core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.Tooltip', 'goog.dom', 'goog.math.Size']);
goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.Field', 'Blockly.Msg', 'goog.asserts', 'goog.dom', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.Variables', 'goog.string']);
goog.addDependency("../../../" + dir + "/core/flyout.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Comment', 'Blockly.WorkspaceSvg', 'goog.dom', 'goog.events', 'goog.math.Rect', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/flyout.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Comment', 'Blockly.Events', 'Blockly.WorkspaceSvg', 'goog.dom', 'goog.events', 'goog.math.Rect', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['goog.dom']);
goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.Css', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'goog.dom', 'goog.ui.Component', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/msg.js", ['Blockly.Msg'], []);
+15 -4
View File
@@ -76,11 +76,18 @@ Blockly.BlockSvg.CORNER_RADIUS = 8;
* @const
*/
Blockly.BlockSvg.START_HAT = false;
/**
* Height of the top hat.
* @const
*/
Blockly.BlockSvg.START_HAT_HEIGHT = 15;
/**
* Path of the top hat's curve.
* @const
*/
Blockly.BlockSvg.START_HAT_PATH = 'c 30,-15 70,-15 100,0';
Blockly.BlockSvg.START_HAT_PATH = 'c 30,-' +
Blockly.BlockSvg.START_HAT_HEIGHT + ' 70,-' +
Blockly.BlockSvg.START_HAT_HEIGHT + ' 100,0';
/**
* Path of the top hat's curve's highlight in LTR.
* @const
@@ -99,14 +106,14 @@ Blockly.BlockSvg.START_HAT_HIGHLIGHT_RTL =
* @const
*/
Blockly.BlockSvg.DISTANCE_45_INSIDE = (1 - Math.SQRT1_2) *
(Blockly.BlockSvg.CORNER_RADIUS - 0.5) + 0.5;
(Blockly.BlockSvg.CORNER_RADIUS - 0.5) + 0.5;
/**
* Distance from shape edge to intersect with a curved corner at 45 degrees.
* Applies to highlighting on around the outside of a curve.
* @const
*/
Blockly.BlockSvg.DISTANCE_45_OUTSIDE = (1 - Math.SQRT1_2) *
(Blockly.BlockSvg.CORNER_RADIUS + 0.5) - 0.5;
(Blockly.BlockSvg.CORNER_RADIUS + 0.5) - 0.5;
/**
* SVG path for drawing next/previous notch from left to right.
* @const
@@ -480,6 +487,9 @@ Blockly.BlockSvg.prototype.renderCompute_ = function(iconWidth) {
*/
Blockly.BlockSvg.prototype.renderDraw_ = function(iconWidth, inputRows) {
this.startHat_ = false;
// Reset the height to zero and let the rendering process add in
// portions of the block height as it goes. (e.g. hats, inputs, etc.)
this.height = 0;
// Should the top and bottom left corners be rounded or square?
if (this.outputConnection) {
this.squareTopLeftCorner_ = true;
@@ -497,6 +507,7 @@ Blockly.BlockSvg.prototype.renderDraw_ = function(iconWidth, inputRows) {
// No output or previous connection.
this.squareTopLeftCorner_ = true;
this.startHat_ = true;
this.height += Blockly.BlockSvg.START_HAT_HEIGHT;
inputRows.rightEdge = Math.max(inputRows.rightEdge, 100);
}
var nextBlock = this.getNextBlock();
@@ -860,7 +871,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps,
*/
Blockly.BlockSvg.prototype.renderDrawBottom_ =
function(steps, highlightSteps, connectionsXY, cursorY) {
this.height = cursorY + 1; // Add one for the shadow.
this.height += cursorY + 1; // Add one for the shadow.
if (this.nextConnection) {
steps.push('H', (Blockly.BlockSvg.NOTCH_WIDTH + (this.RTL ? 0.5 : - 0.5)) +
' ' + Blockly.BlockSvg.NOTCH_PATH_RIGHT);
+12 -7
View File
@@ -127,6 +127,11 @@ Blockly.BlockSvg.prototype.initSvg = function() {
* Select this block. Highlight it visually.
*/
Blockly.BlockSvg.prototype.select = function() {
if (this.isShadow() && this.getParent()) {
// Shadow blocks should not be selected.
this.getParent().select();
return;
}
if (Blockly.selected == this) {
return;
}
@@ -532,7 +537,7 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) {
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
this.dragStartXY_ = this.getRelativeToSurfaceXY();
this.workspace.startDrag(e, this.dragStartXY_.x, this.dragStartXY_.y);
this.workspace.startDrag(e, this.dragStartXY_);
Blockly.dragMode_ = Blockly.DRAG_STICKY;
Blockly.BlockSvg.onMouseUpWrapper_ = Blockly.bindEvent_(document,
@@ -563,7 +568,8 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) {
* @private
*/
Blockly.BlockSvg.prototype.onMouseUp_ = function(e) {
if (Blockly.dragMode_ != Blockly.DRAG_FREE) {
if (Blockly.dragMode_ != Blockly.DRAG_FREE &&
!Blockly.WidgetDiv.isVisible()) {
Blockly.Events.fire(
new Blockly.Events.Ui(this, 'click', undefined, undefined));
}
@@ -839,16 +845,15 @@ Blockly.BlockSvg.prototype.onMouseMove_ = function(e) {
}
if (Blockly.dragMode_ == Blockly.DRAG_FREE) {
// Unrestricted dragging.
var dx = oldXY.x - this.dragStartXY_.x;
var dy = oldXY.y - this.dragStartXY_.y;
var dxy = goog.math.Coordinate.difference(oldXY, this.dragStartXY_);
var group = this.getSvgRoot();
group.translate_ = 'translate(' + newXY.x + ',' + newXY.y + ')';
group.setAttribute('transform', group.translate_ + group.skew_);
// Drag all the nested bubbles.
for (var i = 0; i < this.draggedBubbles_.length; i++) {
var commentData = this.draggedBubbles_[i];
commentData.bubble.setIconLocation(commentData.x + dx,
commentData.y + dy);
commentData.bubble.setIconLocation(
goog.math.Coordinate.sum(commentData, dxy));
}
// Check to see if any of this block's connections are within range of
@@ -859,7 +864,7 @@ Blockly.BlockSvg.prototype.onMouseMove_ = function(e) {
var radiusConnection = Blockly.SNAP_RADIUS;
for (var i = 0; i < myConnections.length; i++) {
var myConnection = myConnections[i];
var neighbour = myConnection.closest(radiusConnection, dx, dy);
var neighbour = myConnection.closest(radiusConnection, dxy);
if (neighbour.connection) {
closestConnection = neighbour.connection;
localConnection = myConnection;
+6 -9
View File
@@ -233,15 +233,12 @@ Blockly.onKeyDown_ = function(e) {
Blockly.hideChaff();
} else if (e.keyCode == 8 || e.keyCode == 46) {
// Delete or backspace.
try {
if (Blockly.selected && Blockly.selected.isDeletable()) {
deleteBlock = true;
}
} finally {
// Stop the browser from going back to the previous page.
// Use a finally so that any error in delete code above doesn't disappear
// from the console when the page rolls back.
e.preventDefault();
// Stop the browser from going back to the previous page.
// Do this first to prevent an error in the delete code from resulting in
// data loss.
e.preventDefault();
if (Blockly.selected && Blockly.selected.isDeletable()) {
deleteBlock = true;
}
} else if (e.altKey || e.ctrlKey || e.metaKey) {
if (Blockly.selected &&
+30 -36
View File
@@ -29,23 +29,23 @@ goog.provide('Blockly.Bubble');
goog.require('Blockly.Workspace');
goog.require('goog.dom');
goog.require('goog.math');
goog.require('goog.math.Coordinate');
goog.require('goog.userAgent');
/**
* Class for UI bubble.
* @param {!Blockly.Workspace} workspace The workspace on which to draw the
* @param {!Blockly.WorkspaceSvg} workspace The workspace on which to draw the
* bubble.
* @param {!Element} content SVG content for the bubble.
* @param {Element} shape SVG element to avoid eclipsing.
* @param {number} anchorX Absolute horizontal position of bubbles anchor point.
* @param {number} anchorY Absolute vertical position of bubbles anchor point.
* @param {!goog.math.Coodinate} anchorXY Absolute position of bubble's anchor
* point.
* @param {?number} bubbleWidth Width of bubble, or null if not resizable.
* @param {?number} bubbleHeight Height of bubble, or null if not resizable.
* @constructor
*/
Blockly.Bubble = function(workspace, content, shape,
anchorX, anchorY,
Blockly.Bubble = function(workspace, content, shape, anchorXY,
bubbleWidth, bubbleHeight) {
this.workspace_ = workspace;
this.content_ = content;
@@ -60,7 +60,7 @@ Blockly.Bubble = function(workspace, content, shape,
var canvas = workspace.getBubbleCanvas();
canvas.appendChild(this.createDom_(content, !!(bubbleWidth && bubbleHeight)));
this.setAnchorLocation(anchorX, anchorY);
this.setAnchorLocation(anchorXY);
if (!bubbleWidth || !bubbleHeight) {
var bBox = /** @type {SVGLocatable} */ (this.content_).getBBox();
bubbleWidth = bBox.width + 2 * Blockly.Bubble.BORDER_WIDTH;
@@ -145,16 +145,11 @@ Blockly.Bubble.unbindDragEvents_ = function() {
Blockly.Bubble.prototype.rendered_ = false;
/**
* Absolute X coordinate of anchor point.
* Absolute coordinate of anchor point.
* @type {goog.math.Coordinate}
* @private
*/
Blockly.Bubble.prototype.anchorX_ = 0;
/**
* Absolute Y coordinate of anchor point.
* @private
*/
Blockly.Bubble.prototype.anchorY_ = 0;
Blockly.Bubble.prototype.anchorXY_ = null;
/**
* Relative X coordinate of bubble with respect to the anchor's centre.
@@ -269,9 +264,9 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) {
// Left-click (or middle click)
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
this.workspace_.startDrag(e,
this.workspace_.startDrag(e, new goog.math.Coordinate(
this.workspace_.RTL ? -this.relativeLeft_ : this.relativeLeft_,
this.relativeTop_);
this.relativeTop_));
Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEvent_(document,
'mouseup', this, Blockly.Bubble.unbindDragEvents_);
@@ -312,8 +307,8 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) {
// Left-click (or middle click)
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
this.workspace_.startDrag(e,
this.workspace_.RTL ? -this.width_ : this.width_, this.height_);
this.workspace_.startDrag(e, new goog.math.Coordinate(
this.workspace_.RTL ? -this.width_ : this.width_, this.height_));
Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEvent_(document,
'mouseup', this, Blockly.Bubble.unbindDragEvents_);
@@ -360,12 +355,10 @@ Blockly.Bubble.prototype.promote_ = function() {
/**
* Notification that the anchor has moved.
* Update the arrow and bubble accordingly.
* @param {number} x Absolute horizontal location.
* @param {number} y Absolute vertical location.
* @param {!goog.math.Coordinate} xy Absolute location.
*/
Blockly.Bubble.prototype.setAnchorLocation = function(x, y) {
this.anchorX_ = x;
this.anchorY_ = y;
Blockly.Bubble.prototype.setAnchorLocation = function(xy) {
this.anchorXY_ = xy;
if (this.rendered_) {
this.positionBubble_();
}
@@ -383,31 +376,32 @@ Blockly.Bubble.prototype.layoutBubble_ = function() {
var metrics = this.workspace_.getMetrics();
metrics.viewWidth /= this.workspace_.scale;
metrics.viewLeft /= this.workspace_.scale;
var anchorX = this.anchorXY_.x;
if (this.workspace_.RTL) {
if (this.anchorX_ - metrics.viewLeft - relativeLeft - this.width_ <
if (anchorX - metrics.viewLeft - relativeLeft - this.width_ <
Blockly.Scrollbar.scrollbarThickness) {
// Slide the bubble right until it is onscreen.
relativeLeft = this.anchorX_ - metrics.viewLeft - this.width_ -
relativeLeft = anchorX - metrics.viewLeft - this.width_ -
Blockly.Scrollbar.scrollbarThickness;
} else if (this.anchorX_ - metrics.viewLeft - relativeLeft >
} else if (anchorX - metrics.viewLeft - relativeLeft >
metrics.viewWidth) {
// Slide the bubble left until it is onscreen.
relativeLeft = this.anchorX_ - metrics.viewLeft - metrics.viewWidth;
relativeLeft = anchorX - metrics.viewLeft - metrics.viewWidth;
}
} else {
if (this.anchorX_ + relativeLeft < metrics.viewLeft) {
if (anchorX + relativeLeft < metrics.viewLeft) {
// Slide the bubble right until it is onscreen.
relativeLeft = metrics.viewLeft - this.anchorX_;
relativeLeft = metrics.viewLeft - anchorX;
} else if (metrics.viewLeft + metrics.viewWidth <
this.anchorX_ + relativeLeft + this.width_ +
anchorX + relativeLeft + this.width_ +
Blockly.BlockSvg.SEP_SPACE_X +
Blockly.Scrollbar.scrollbarThickness) {
// Slide the bubble left until it is onscreen.
relativeLeft = metrics.viewLeft + metrics.viewWidth - this.anchorX_ -
relativeLeft = metrics.viewLeft + metrics.viewWidth - anchorX -
this.width_ - Blockly.Scrollbar.scrollbarThickness;
}
}
if (this.anchorY_ + relativeTop < metrics.viewTop) {
if (this.anchorXY_.y + relativeTop < metrics.viewTop) {
// Slide the bubble below the block.
var bBox = /** @type {SVGLocatable} */ (this.shape_).getBBox();
relativeTop = bBox.height;
@@ -421,13 +415,13 @@ Blockly.Bubble.prototype.layoutBubble_ = function() {
* @private
*/
Blockly.Bubble.prototype.positionBubble_ = function() {
var left;
var left = this.anchorXY_.x;
if (this.workspace_.RTL) {
left = this.anchorX_ - this.relativeLeft_ - this.width_;
left -= this.relativeLeft_ + this.width_;
} else {
left = this.anchorX_ + this.relativeLeft_;
left += this.relativeLeft_;
}
var top = this.relativeTop_ + this.anchorY_;
var top = this.relativeTop_ + this.anchorXY_.y;
this.bubbleGroup_.setAttribute('transform',
'translate(' + left + ',' + top + ')');
};
+2 -3
View File
@@ -180,10 +180,9 @@ Blockly.Comment.prototype.setVisible = function(visible) {
if (visible) {
// Create the bubble.
this.bubble_ = new Blockly.Bubble(
/** @type {!Blockly.Workspace} */ (this.block_.workspace),
/** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace),
this.createEditor_(), this.block_.svgPath_,
this.iconX_, this.iconY_,
this.width_, this.height_);
this.iconXY_, this.width_, this.height_);
this.bubble_.registerResizeEvent(this, this.resizeBubble_);
this.updateColour();
} else {
+3 -5
View File
@@ -664,16 +664,14 @@ Blockly.Connection.prototype.tighten_ = function() {
/**
* Find the closest compatible connection to this connection.
* @param {number} maxLimit The maximum radius to another connection.
* @param {number} dx Horizontal offset between this connection's location
* in the database and the current location (as a result of dragging).
* @param {number} dy Vertical offset between this connection's location
* @param {!goog.math.Coordinate} dxy Offset between this connection's location
* in the database and the current location (as a result of dragging).
* @return {!{connection: ?Blockly.Connection, radius: number}} Contains two
* properties:' connection' which is either another connection or null,
* and 'radius' which is the distance.
*/
Blockly.Connection.prototype.closest = function(maxLimit, dx, dy) {
return this.dbOpposite_.searchForClosest(this, maxLimit, dx, dy);
Blockly.Connection.prototype.closest = function(maxLimit, dxy) {
return this.dbOpposite_.searchForClosest(this, maxLimit, dxy);
};
/**
+5 -7
View File
@@ -226,16 +226,14 @@ Blockly.ConnectionDB.prototype.isInYRange_ = function(index, baseY, maxRadius) {
* @param {!Blockly.Connection} conn The connection searching for a compatible
* mate.
* @param {number} maxRadius The maximum radius to another connection.
* @param {number} dx Horizontal offset between this connection's location
* in the database and the current location (as a result of dragging).
* @param {number} dy Vertical offset between this connection's location
* @param {!goog.math.Coordinate} dxy Offset between this connection's location
* in the database and the current location (as a result of dragging).
* @return {!{connection: ?Blockly.Connection, radius: number}} Contains two
* properties:' connection' which is either another connection or null,
* and 'radius' which is the distance.
*/
Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dx,
dy) {
Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
dxy) {
// Don't bother.
if (!this.length) {
return {connection: null, radius: maxRadius};
@@ -245,8 +243,8 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dx,
var baseY = conn.y_;
var baseX = conn.x_;
conn.x_ = baseX + dx;
conn.y_ = baseY + dy;
conn.x_ = baseX + dxy.x;
conn.y_ = baseY + dxy.y;
// findPositionForConnection finds an index for insertion, which is always
// after any block with the same y index. We want to search both forward
+2
View File
@@ -26,6 +26,8 @@
goog.provide('Blockly.Events');
goog.require('goog.math.Coordinate');
/**
* Group ID for new events. Grouped events are indivisible.
+182 -93
View File
@@ -28,6 +28,7 @@ goog.provide('Blockly.Flyout');
goog.require('Blockly.Block');
goog.require('Blockly.Comment');
goog.require('Blockly.Events');
goog.require('Blockly.WorkspaceSvg');
goog.require('goog.dom');
goog.require('goog.events');
@@ -263,20 +264,8 @@ Blockly.Flyout.prototype.position = function() {
if (this.RTL) {
edgeWidth *= -1;
}
var path = ['M ' + (this.RTL ? this.width_ : 0) + ',0'];
path.push('h', edgeWidth);
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
this.RTL ? 0 : 1,
this.RTL ? -this.CORNER_RADIUS : this.CORNER_RADIUS,
this.CORNER_RADIUS);
path.push('v', Math.max(0, metrics.viewHeight - this.CORNER_RADIUS * 2));
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
this.RTL ? 0 : 1,
this.RTL ? this.CORNER_RADIUS : -this.CORNER_RADIUS,
this.CORNER_RADIUS);
path.push('h', -edgeWidth);
path.push('z');
this.svgBackground_.setAttribute('d', path.join(' '));
this.setBackgroundPath_(edgeWidth, metrics.viewHeight);
var x = metrics.absoluteLeft;
if (this.RTL) {
@@ -295,6 +284,37 @@ Blockly.Flyout.prototype.position = function() {
}
};
/**
* Create and set the path for the visible boundaries of the flyout.
* @param {number} width The width of the flyout, not including the
* rounded corners.
* @param {number} height The height of the flyout, not including
* rounded corners.
* @private
*/
Blockly.Flyout.prototype.setBackgroundPath_ = function(width, height) {
var path = ['M ' + (this.RTL ? this.width_ : 0) + ',0'];
// Top.
path.push('h', width);
// Rounded corner.
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
this.RTL ? 0 : 1,
this.RTL ? -this.CORNER_RADIUS : this.CORNER_RADIUS,
this.CORNER_RADIUS);
// Side closest to the workspace.
path.push('v', Math.max(0, height - this.CORNER_RADIUS * 2));
// Rounded corner.
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
this.RTL ? 0 : 1,
this.RTL ? this.CORNER_RADIUS : -this.CORNER_RADIUS,
this.CORNER_RADIUS);
// Bottom.
path.push('h', -width);
// Side away from the workspace.
path.push('z');
this.svgBackground_.setAttribute('d', path.join(' '));
};
/**
* Scroll the flyout to the top.
*/
@@ -362,18 +382,7 @@ Blockly.Flyout.prototype.hide = function() {
*/
Blockly.Flyout.prototype.show = function(xmlList) {
this.hide();
// Delete any blocks from a previous showing.
var blocks = this.workspace_.getTopBlocks(false);
for (var i = 0, block; block = blocks[i]; i++) {
if (block.workspace == this.workspace_) {
block.dispose(false, false);
}
}
// Delete any background buttons from a previous showing.
for (var i = 0, rect; rect = this.buttons_[i]; i++) {
goog.dom.removeNode(rect);
}
this.buttons_.length = 0;
this.clearOldBlocks_();
if (xmlList == Blockly.Variables.NAME_TYPE) {
// Special category for variables.
@@ -405,6 +414,38 @@ Blockly.Flyout.prototype.show = function(xmlList) {
}
}
this.layoutBlocks_(blocks, gaps, margin);
// IE 11 is an incompetant browser that fails to fire mouseout events.
// When the mouse is over the background, deselect all blocks.
var deselectAll = function(e) {
var blocks = this.workspace_.getTopBlocks(false);
for (var i = 0, block; block = blocks[i]; i++) {
block.removeSelect();
}
};
this.listeners_.push(Blockly.bindEvent_(this.svgBackground_, 'mouseover',
this, deselectAll));
this.width_ = 0;
this.reflow();
this.filterForCapacity_();
// Fire a resize event to update the flyout's scrollbar.
Blockly.fireUiEventNow(window, 'resize');
this.reflowWrapper_ = this.reflow.bind(this);
this.workspace_.addChangeListener(this.reflowWrapper_);
};
/**
* Lay out the blocks in the flyout.
* @param {!Array.<!Blockly.BlockSvg>} blocks The blocks to lay out.
* @param {!Array.<number>} gaps The visible gaps between blocks.
* @param {number} margin The margin around the edges of the flyout.
* @private
*/
Blockly.Flyout.prototype.layoutBlocks_ = function(blocks, gaps, margin) {
// Lay out the blocks vertically.
var cursorY = margin;
for (var i = 0, block; block = blocks[i]; i++) {
@@ -433,45 +474,57 @@ Blockly.Flyout.prototype.show = function(xmlList) {
block.flyoutRect_ = rect;
this.buttons_[i] = rect;
if (this.autoClose) {
this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null,
this.createBlockFunc_(block)));
} else {
this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null,
this.blockMouseDown_(block)));
this.addBlockListeners_(root, block, rect);
}
};
/**
* Delete blocks and background buttons from a previous showing of the flyout.
* @private
*/
Blockly.Flyout.prototype.clearOldBlocks_ = function() {
// Delete any blocks from a previous showing.
var blocks = this.workspace_.getTopBlocks(false);
for (var i = 0, block; block = blocks[i]; i++) {
if (block.workspace == this.workspace_) {
block.dispose(false, false);
}
this.listeners_.push(Blockly.bindEvent_(root, 'mouseover', block,
block.addSelect));
this.listeners_.push(Blockly.bindEvent_(root, 'mouseout', block,
block.removeSelect));
}
// Delete any background buttons from a previous showing.
for (var j = 0, rect; rect = this.buttons_[j]; j++) {
goog.dom.removeNode(rect);
}
this.buttons_.length = 0;
};
/**
* Add listeners to a block that has been added to the flyout.
* @param {!Element} root The root node of the SVG group the block is in.
* @param {!Blockly.Block} block The block to add listeners for.
* @param {!Element} rect The invisible rectangle under the block that acts as
* a button for that block.
* @private
*/
Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) {
if (this.autoClose) {
this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null,
this.createBlockFunc_(block)));
this.listeners_.push(Blockly.bindEvent_(rect, 'mousedown', null,
this.createBlockFunc_(block)));
this.listeners_.push(Blockly.bindEvent_(rect, 'mouseover', block,
block.addSelect));
this.listeners_.push(Blockly.bindEvent_(rect, 'mouseout', block,
block.removeSelect));
} else {
this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null,
this.blockMouseDown_(block)));
this.listeners_.push(Blockly.bindEvent_(rect, 'mousedown', null,
this.blockMouseDown_(block)));
}
// IE 11 is an incompetant browser that fails to fire mouseout events.
// When the mouse is over the background, deselect all blocks.
var deselectAll = function(e) {
var blocks = this.workspace_.getTopBlocks(false);
for (var i = 0, block; block = blocks[i]; i++) {
block.removeSelect();
}
};
this.listeners_.push(Blockly.bindEvent_(this.svgBackground_, 'mouseover',
this, deselectAll));
this.width_ = 0;
this.reflow();
this.filterForCapacity_();
// Fire a resize event to update the flyout's scrollbar.
Blockly.fireUiEventNow(window, 'resize');
this.reflowWrapper_ = this.reflow.bind(this);
this.workspace_.addChangeListener(this.reflowWrapper_);
this.listeners_.push(Blockly.bindEvent_(root, 'mouseover', block,
block.addSelect));
this.listeners_.push(Blockly.bindEvent_(root, 'mouseout', block,
block.removeSelect));
this.listeners_.push(Blockly.bindEvent_(rect, 'mouseover', block,
block.addSelect));
this.listeners_.push(Blockly.bindEvent_(rect, 'mouseout', block,
block.removeSelect));
};
/**
@@ -512,6 +565,13 @@ Blockly.Flyout.prototype.reflow = function() {
var blockXY = block.getRelativeToSurfaceXY();
block.flyoutRect_.setAttribute('x',
this.RTL ? blockXY.x - blockHW.width + tab : blockXY.x - tab);
// For hat blocks we want to shift them down by the hat height
// since the y coordinate is the corner, not the top of the hat.
var hatOffset =
block.startHat_ ? Blockly.BlockSvg.START_HAT_HEIGHT : 0;
if (hatOffset) {
block.moveBy(0, hatOffset);
}
block.flyoutRect_.setAttribute('y', blockXY.y);
}
}
@@ -544,7 +604,7 @@ Blockly.Flyout.prototype.blockMouseDown_ = function(block) {
Blockly.Flyout.startBlock_ = block;
Blockly.Flyout.startFlyout_ = flyout;
Blockly.Flyout.onMouseUpWrapper_ = Blockly.bindEvent_(document,
'mouseup', this, Blockly.terminateDrag_);
'mouseup', this, flyout.onMouseUp_);
Blockly.Flyout.onMouseMoveBlockWrapper_ = Blockly.bindEvent_(document,
'mousemove', this, flyout.onMouseMoveBlock_);
}
@@ -574,6 +634,23 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) {
e.stopPropagation();
};
/**
* Handle a mouse-up anywhere in the SVG pane. Is only registered when a
* block is clicked. We can't use mouseUp on the block since a fast-moving
* cursor can briefly escape the block before it catches up.
* @param {!Event} e Mouse up event.
* @private
*/
Blockly.Flyout.prototype.onMouseUp_ = function(e) {
if (Blockly.dragMode_ != Blockly.DRAG_FREE &&
!Blockly.WidgetDiv.isVisible()) {
Blockly.Events.fire(
new Blockly.Events.Ui(Blockly.Flyout.startBlock_, 'click',
undefined, undefined));
}
Blockly.terminateDrag_();
};
/**
* Handle a mouse-move to vertically drag the flyout.
* @param {!Event} e Mouse move event.
@@ -636,37 +713,7 @@ Blockly.Flyout.prototype.createBlockFunc_ = function(originBlock) {
return;
}
Blockly.Events.disable();
// Create the new block by cloning the block in the flyout (via XML).
var xml = Blockly.Xml.blockToDom(originBlock);
var block = Blockly.Xml.domToBlock(xml, workspace);
// Place it in the same spot as the flyout copy.
var svgRootOld = originBlock.getSvgRoot();
if (!svgRootOld) {
throw 'originBlock is not rendered.';
}
var xyOld = Blockly.getSvgXY_(svgRootOld, workspace);
// Scale the scroll (getSvgXY_ did not do this).
if (flyout.RTL) {
var width = workspace.getMetrics().viewWidth - flyout.width_;
xyOld.x += width / workspace.scale - width;
} else {
xyOld.x += flyout.workspace_.scrollX / flyout.workspace_.scale -
flyout.workspace_.scrollX;
}
xyOld.y += flyout.workspace_.scrollY / flyout.workspace_.scale -
flyout.workspace_.scrollY;
var svgRootNew = block.getSvgRoot();
if (!svgRootNew) {
throw 'block is not rendered.';
}
var xyNew = Blockly.getSvgXY_(svgRootNew, workspace);
// Scale the scroll (getSvgXY_ did not do this).
xyNew.x += workspace.scrollX / workspace.scale - workspace.scrollX;
xyNew.y += workspace.scrollY / workspace.scale - workspace.scrollY;
if (workspace.toolbox_ && !workspace.scrollbar) {
xyNew.x += workspace.toolbox_.width / workspace.scale;
}
block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y);
var block = flyout.placeNewBlock_(originBlock, workspace);
Blockly.Events.enable();
if (Blockly.Events.isEnabled()) {
Blockly.Events.setGroup(true);
@@ -684,6 +731,48 @@ Blockly.Flyout.prototype.createBlockFunc_ = function(originBlock) {
};
};
/**
* Copy a block from the flyout to the workspace and position it correctly.
* @param {!Blockly.Block} originBlock The flyout block to copy.
* @param {!Blockly.Workspace} workspace The main workspace.
* @return {!Blockly.Block} The new block in the main workspace.
* @private
*/
Blockly.Flyout.prototype.placeNewBlock_ = function(originBlock, workspace) {
// Create the new block by cloning the block in the flyout (via XML).
var xml = Blockly.Xml.blockToDom(originBlock);
var block = Blockly.Xml.domToBlock(xml, workspace);
// Place it in the same spot as the flyout copy.
var svgRootOld = originBlock.getSvgRoot();
if (!svgRootOld) {
throw 'originBlock is not rendered.';
}
var xyOld = Blockly.getSvgXY_(svgRootOld, workspace);
// Scale the scroll (getSvgXY_ did not do this).
if (this.RTL) {
var width = workspace.getMetrics().viewWidth - this.width_;
xyOld.x += width / workspace.scale - width;
} else {
xyOld.x += this.workspace_.scrollX / this.workspace_.scale -
this.workspace_.scrollX;
}
xyOld.y += this.workspace_.scrollY / this.workspace_.scale -
this.workspace_.scrollY;
var svgRootNew = block.getSvgRoot();
if (!svgRootNew) {
throw 'block is not rendered.';
}
var xyNew = Blockly.getSvgXY_(svgRootNew, workspace);
// Scale the scroll (getSvgXY_ did not do this).
xyNew.x += workspace.scrollX / workspace.scale - workspace.scrollX;
xyNew.y += workspace.scrollY / workspace.scale - workspace.scrollY;
if (workspace.toolbox_ && !workspace.scrollbar) {
xyNew.x += workspace.toolbox_.width / workspace.scale;
}
block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y);
return block;
};
/**
* Filter the blocks on the flyout to disable the ones that are above the
* capacity limit.
+15 -20
View File
@@ -27,6 +27,7 @@
goog.provide('Blockly.Icon');
goog.require('goog.dom');
goog.require('goog.math.Coordinate');
/**
@@ -56,16 +57,11 @@ Blockly.Icon.prototype.SIZE = 17;
Blockly.Icon.prototype.bubble_ = null;
/**
* Absolute X coordinate of icon's center.
* Absolute coordinate of icon's center.
* @type {goog.math.Coordinate}
* @private
*/
Blockly.Icon.prototype.iconX_ = 0;
/**
* Absolute Y coordinate of icon's centre.
* @private
*/
Blockly.Icon.prototype.iconY_ = 0;
Blockly.Icon.prototype.iconXY_ = null;
/**
* Create the icon on the block.
@@ -176,14 +172,12 @@ Blockly.Icon.prototype.renderIcon = function(cursorX) {
/**
* Notification that the icon has moved. Update the arrow accordingly.
* @param {number} x Absolute horizontal location.
* @param {number} y Absolute vertical location.
* @param {!goog.math.Coordinate} xy Absolute location.
*/
Blockly.Icon.prototype.setIconLocation = function(x, y) {
this.iconX_ = x;
this.iconY_ = y;
Blockly.Icon.prototype.setIconLocation = function(xy) {
this.iconXY_ = xy;
if (this.isVisible()) {
this.bubble_.setAnchorLocation(x, y);
this.bubble_.setAnchorLocation(xy);
}
};
@@ -195,17 +189,18 @@ Blockly.Icon.prototype.computeIconLocation = function() {
// Find coordinates for the centre of the icon and update the arrow.
var blockXY = this.block_.getRelativeToSurfaceXY();
var iconXY = Blockly.getRelativeXY_(this.iconGroup_);
var newX = blockXY.x + iconXY.x + this.SIZE / 2;
var newY = blockXY.y + iconXY.y + this.SIZE / 2;
if (newX !== this.iconX_ || newY !== this.iconY_) {
this.setIconLocation(newX, newY);
var newXY = new goog.math.Coordinate(
blockXY.x + iconXY.x + this.SIZE / 2,
blockXY.y + iconXY.y + this.SIZE / 2);
if (!goog.math.Coordinate.equals(this.getIconLocation(), newXY)) {
this.setIconLocation(newXY);
}
};
/**
* Returns the center of the block's icon relative to the surface.
* @return {!Object} Object with x and y properties.
* @return {!goog.math.Coordinate} Object with x and y properties.
*/
Blockly.Icon.prototype.getIconLocation = function() {
return {x: this.iconX_, y: this.iconY_};
return this.iconXY_;
};
+3 -3
View File
@@ -202,9 +202,9 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
new Blockly.Events.Ui(this.block_, 'mutatorOpen', !visible, visible));
if (visible) {
// Create the bubble.
this.bubble_ = new Blockly.Bubble(this.block_.workspace,
this.createEditor_(), this.block_.svgPath_,
this.iconX_, this.iconY_, null, null);
this.bubble_ = new Blockly.Bubble(
/** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace),
this.createEditor_(), this.block_.svgPath_, this.iconXY_, null, null);
var tree = this.workspace_.options.languageTree;
if (tree) {
this.workspace_.flyout_.init(this.workspace_);
+80 -59
View File
@@ -270,69 +270,89 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) {
* .absoluteLeft: Left-edge of view.
*/
if (this.horizontal_) {
var outerLength = hostMetrics.viewWidth - 1;
if (this.pair_) {
// Shorten the scrollbar to make room for the corner square.
outerLength -= Blockly.Scrollbar.scrollbarThickness;
} else {
// Only show the scrollbar if needed.
// Ideally this would also apply to scrollbar pairs, but that's a bigger
// headache (due to interactions with the corner square).
this.setVisible(outerLength < hostMetrics.contentWidth);
}
this.ratio_ = outerLength / hostMetrics.contentWidth;
if (this.ratio_ === -Infinity || this.ratio_ === Infinity ||
isNaN(this.ratio_)) {
this.ratio_ = 0;
}
var innerLength = hostMetrics.viewWidth * this.ratio_;
var innerOffset = (hostMetrics.viewLeft - hostMetrics.contentLeft) *
this.ratio_;
this.svgKnob_.setAttribute('width', Math.max(0, innerLength));
this.xCoordinate = hostMetrics.absoluteLeft + 0.5;
if (this.pair_ && this.workspace_.RTL) {
this.xCoordinate += hostMetrics.absoluteLeft +
Blockly.Scrollbar.scrollbarThickness;
}
this.yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight -
Blockly.Scrollbar.scrollbarThickness - 0.5;
this.svgGroup_.setAttribute('transform',
'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')');
this.svgBackground_.setAttribute('width', Math.max(0, outerLength));
this.svgKnob_.setAttribute('x', this.constrainKnob_(innerOffset));
this.resizeHorizontal_(hostMetrics);
} else {
var outerLength = hostMetrics.viewHeight - 1;
if (this.pair_) {
// Shorten the scrollbar to make room for the corner square.
outerLength -= Blockly.Scrollbar.scrollbarThickness;
} else {
// Only show the scrollbar if needed.
this.setVisible(outerLength < hostMetrics.contentHeight);
}
this.ratio_ = outerLength / hostMetrics.contentHeight;
if (this.ratio_ === -Infinity || this.ratio_ === Infinity ||
isNaN(this.ratio_)) {
this.ratio_ = 0;
}
var innerLength = hostMetrics.viewHeight * this.ratio_;
var innerOffset = (hostMetrics.viewTop - hostMetrics.contentTop) *
this.ratio_;
this.svgKnob_.setAttribute('height', Math.max(0, innerLength));
this.xCoordinate = hostMetrics.absoluteLeft + 0.5;
if (!this.workspace_.RTL) {
this.xCoordinate += hostMetrics.viewWidth -
Blockly.Scrollbar.scrollbarThickness - 1;
}
this.yCoordinate = hostMetrics.absoluteTop + 0.5;
this.svgGroup_.setAttribute('transform',
'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')');
this.svgBackground_.setAttribute('height', Math.max(0, outerLength));
this.svgKnob_.setAttribute('y', this.constrainKnob_(innerOffset));
this.resizeVertical_(hostMetrics);
}
// Resizing may have caused some scrolling.
this.onScroll_();
};
/**
* Recalculate a horizontal scrollbar's location and length.
* @param {!Object} hostMetrics A data structure describing all the
* required dimensions, possibly fetched from the host object.
* @private
*/
Blockly.Scrollbar.prototype.resizeHorizontal_ = function(hostMetrics) {
var outerLength = hostMetrics.viewWidth - 1;
if (this.pair_) {
// Shorten the scrollbar to make room for the corner square.
outerLength -= Blockly.Scrollbar.scrollbarThickness;
} else {
// Only show the scrollbar if needed.
// Ideally this would also apply to scrollbar pairs, but that's a bigger
// headache (due to interactions with the corner square).
this.setVisible(outerLength < hostMetrics.contentWidth);
}
this.ratio_ = outerLength / hostMetrics.contentWidth;
if (this.ratio_ === -Infinity || this.ratio_ === Infinity ||
isNaN(this.ratio_)) {
this.ratio_ = 0;
}
var innerLength = hostMetrics.viewWidth * this.ratio_;
var innerOffset = (hostMetrics.viewLeft - hostMetrics.contentLeft) *
this.ratio_;
this.svgKnob_.setAttribute('width', Math.max(0, innerLength));
this.xCoordinate = hostMetrics.absoluteLeft + 0.5;
if (this.pair_ && this.workspace_.RTL) {
this.xCoordinate += hostMetrics.absoluteLeft +
Blockly.Scrollbar.scrollbarThickness;
}
this.yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight -
Blockly.Scrollbar.scrollbarThickness - 0.5;
this.svgGroup_.setAttribute('transform',
'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')');
this.svgBackground_.setAttribute('width', Math.max(0, outerLength));
this.svgKnob_.setAttribute('x', this.constrainKnob_(innerOffset));
};
/**
* Recalculate a vertical scrollbar's location and length.
* @param {!Object} hostMetrics A data structure describing all the
* required dimensions, possibly fetched from the host object.
* @private
*/
Blockly.Scrollbar.prototype.resizeVertical_ = function(hostMetrics) {
var outerLength = hostMetrics.viewHeight - 1;
if (this.pair_) {
// Shorten the scrollbar to make room for the corner square.
outerLength -= Blockly.Scrollbar.scrollbarThickness;
} else {
// Only show the scrollbar if needed.
this.setVisible(outerLength < hostMetrics.contentHeight);
}
this.ratio_ = outerLength / hostMetrics.contentHeight;
if (this.ratio_ === -Infinity || this.ratio_ === Infinity ||
isNaN(this.ratio_)) {
this.ratio_ = 0;
}
var innerLength = hostMetrics.viewHeight * this.ratio_;
var innerOffset = (hostMetrics.viewTop - hostMetrics.contentTop) *
this.ratio_;
this.svgKnob_.setAttribute('height', Math.max(0, innerLength));
this.xCoordinate = hostMetrics.absoluteLeft + 0.5;
if (!this.workspace_.RTL) {
this.xCoordinate += hostMetrics.viewWidth -
Blockly.Scrollbar.scrollbarThickness - 1;
}
this.yCoordinate = hostMetrics.absoluteTop + 0.5;
this.svgGroup_.setAttribute('transform',
'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')');
this.svgBackground_.setAttribute('height', Math.max(0, outerLength));
this.svgKnob_.setAttribute('y', this.constrainKnob_(innerOffset));
};
/**
* Create all the DOM elements required for a scrollbar.
* The resulting widget is not sized.
@@ -516,7 +536,7 @@ Blockly.Scrollbar.prototype.onScroll_ = function() {
var barLength = parseFloat(
this.svgBackground_.getAttribute(this.horizontal_ ? 'width' : 'height'));
var ratio = knobValue / barLength;
if (isNaN(ratio)) {
if (isNaN(ratio) || !barLength) {
ratio = 0;
}
var xyRatio = {};
@@ -533,8 +553,9 @@ Blockly.Scrollbar.prototype.onScroll_ = function() {
* @param {number} value The distance from the top/left end of the bar.
*/
Blockly.Scrollbar.prototype.set = function(value) {
var constrainedValue = this.constrainKnob_(value * this.ratio_);
// Move the scrollbar slider.
this.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', value * this.ratio_);
this.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', constrainedValue);
this.onScroll_();
};
+2 -3
View File
@@ -111,9 +111,8 @@ Blockly.Warning.prototype.setVisible = function(visible) {
// Create the bubble to display all warnings.
var paragraph = Blockly.Warning.textToDom_(this.getText());
this.bubble_ = new Blockly.Bubble(
/** @type {!Blockly.Workspace} */ (this.block_.workspace),
paragraph, this.block_.svgPath_,
this.iconX_, this.iconY_, null, null);
/** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace),
paragraph, this.block_.svgPath_, this.iconXY_, null, null);
if (this.block_.RTL) {
// Right-align the paragraph.
// This cannot be done until the bubble is rendered on screen.
+11 -37
View File
@@ -107,18 +107,11 @@ Blockly.WorkspaceSvg.prototype.startScrollX = 0;
Blockly.WorkspaceSvg.prototype.startScrollY = 0;
/**
* Horizontal distance from mouse to object being dragged.
* @type {number}
* Distance from mouse to object being dragged.
* @type {goog.math.Coordinate}
* @private
*/
Blockly.WorkspaceSvg.prototype.dragDeltaX_ = 0;
/**
* Vertical distance from mouse to object being dragged.
* @type {number}
* @private
*/
Blockly.WorkspaceSvg.prototype.dragDeltaY_ = 0;
Blockly.WorkspaceSvg.prototype.dragDeltaXY_ = null;
/**
* Current scale.
@@ -494,8 +487,8 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) {
// Check for blocks in snap range to any of its connections.
var connections = block.getConnections_(false);
for (var i = 0, connection; connection = connections[i]; i++) {
var neighbour =
connection.closest(Blockly.SNAP_RADIUS, blockX, blockY);
var neighbour = connection.closest(Blockly.SNAP_RADIUS,
new goog.math.Coordinate(blockX, blockY));
if (neighbour.connection) {
collide = true;
break;
@@ -620,17 +613,15 @@ Blockly.WorkspaceSvg.prototype.onMouseDown_ = function(e) {
/**
* Start tracking a drag of an object on this workspace.
* @param {!Event} e Mouse down event.
* @param {number} x Starting horizontal location of object.
* @param {number} y Starting vertical location of object.
* @param {!goog.math.Coordinate} xy Starting location of object.
*/
Blockly.WorkspaceSvg.prototype.startDrag = function(e, x, y) {
Blockly.WorkspaceSvg.prototype.startDrag = function(e, xy) {
// Record the starting offset between the bubble's location and the mouse.
var point = Blockly.mouseToSvg(e, this.getParentSvg());
// Fix scale of mouse event.
point.x /= this.scale;
point.y /= this.scale;
this.dragDeltaX_ = x - point.x;
this.dragDeltaY_ = y - point.y;
this.dragDeltaXY_ = goog.math.Coordinate.difference(xy, point);
};
/**
@@ -643,9 +634,7 @@ Blockly.WorkspaceSvg.prototype.moveDrag = function(e) {
// Fix scale of mouse event.
point.x /= this.scale;
point.y /= this.scale;
var x = this.dragDeltaX_ + point.x;
var y = this.dragDeltaY_ + point.y;
return new goog.math.Coordinate(x, y);
return goog.math.Coordinate.sum(this.dragDeltaXY_, point);
};
/**
@@ -1049,25 +1038,13 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() {
var ratioX = workspaceWidth / blocksWidth;
var ratioY = workspaceHeight / blocksHeight;
this.setScale(Math.min(ratioX, ratioY));
this.scrollCenter_();
};
/**
* Reset zooming and dragging.
* @param {!Event} e Mouse down event.
*/
Blockly.WorkspaceSvg.prototype.zoomReset = function(e) {
this.setScale(1);
this.scrollCenter_();
// This event has been handled. Don't start a workspace drag.
e.stopPropagation();
this.scrollCenter();
};
/**
* Center the workspace.
* @private
*/
Blockly.WorkspaceSvg.prototype.scrollCenter_ = function() {
Blockly.WorkspaceSvg.prototype.scrollCenter = function() {
if (!this.scrollbar) {
// Can't center a non-scrolling workspace.
return;
@@ -1105,9 +1082,6 @@ Blockly.WorkspaceSvg.prototype.setScale = function(newScale) {
// No toolbox, resize flyout.
this.flyout_.reflow();
}
// This event has been handled. Don't start a workspace drag.
e.stopPropagation();
e.preventDefault();
};
/**
+8 -3
View File
@@ -162,16 +162,21 @@ Blockly.ZoomControls.prototype.createDom = function() {
workspace.options.pathToMedia + Blockly.SPRITE.url);
// Attach event listeners.
Blockly.bindEvent_(zoomresetSvg, 'mousedown', workspace, workspace.zoomReset);
Blockly.bindEvent_(zoomresetSvg, 'mousedown', null, function(e) {
workspace.setScale(1);
workspace.scrollCenter();
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault(); // Stop double-clicking from selecting text.
});
Blockly.bindEvent_(zoominSvg, 'mousedown', null, function(e) {
workspace.zoomCenter(1);
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault();
e.preventDefault(); // Stop double-clicking from selecting text.
});
Blockly.bindEvent_(zoomoutSvg, 'mousedown', null, function(e) {
workspace.zoomCenter(-1);
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault();
e.preventDefault(); // Stop double-clicking from selecting text.
});
return this.svgGroup_;