mirror of
https://github.com/google/blockly.git
synced 2026-06-17 00:25:14 +02:00
Merge branch 'develop'
This commit is contained in:
+369
-365
File diff suppressed because it is too large
Load Diff
@@ -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'], []);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
goog.provide('Blockly.Events');
|
||||
|
||||
goog.require('goog.math.Coordinate');
|
||||
|
||||
|
||||
/**
|
||||
* Group ID for new events. Grouped events are indivisible.
|
||||
|
||||
+182
-93
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user