mirror of
https://github.com/google/blockly.git
synced 2026-03-06 21:30:11 +01:00
Add IBubble interface (#4104)
* Add IBubble interface and make use of it for WorkspaceCommentSvgs
This commit is contained in:
136
core/bubble.js
136
core/bubble.js
@@ -21,6 +21,7 @@ goog.require('Blockly.utils.math');
|
||||
goog.require('Blockly.utils.userAgent');
|
||||
goog.require('Blockly.Workspace');
|
||||
|
||||
goog.requireType('Blockly.IBubble');
|
||||
goog.requireType('Blockly.utils.Metrics');
|
||||
|
||||
|
||||
@@ -34,10 +35,11 @@ goog.requireType('Blockly.utils.Metrics');
|
||||
* anchor point.
|
||||
* @param {?number} bubbleWidth Width of bubble, or null if not resizable.
|
||||
* @param {?number} bubbleHeight Height of bubble, or null if not resizable.
|
||||
* @implements {Blockly.IBubble}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Bubble = function(workspace, content, shape, anchorXY,
|
||||
bubbleWidth, bubbleHeight) {
|
||||
Blockly.Bubble = function(
|
||||
workspace, content, shape, anchorXY, bubbleWidth, bubbleHeight) {
|
||||
this.workspace_ = workspace;
|
||||
this.content_ = content;
|
||||
this.shape_ = shape;
|
||||
@@ -236,23 +238,21 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
*/
|
||||
this.bubbleGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.G, {}, null);
|
||||
var filter =
|
||||
{'filter': 'url(#' +
|
||||
this.workspace_.getRenderer().getConstants().embossFilterId + ')'};
|
||||
var filter = {
|
||||
'filter': 'url(#' +
|
||||
this.workspace_.getRenderer().getConstants().embossFilterId + ')'
|
||||
};
|
||||
if (Blockly.utils.userAgent.JAVA_FX) {
|
||||
// Multiple reports that JavaFX can't handle filters.
|
||||
// https://github.com/google/blockly/issues/99
|
||||
filter = {};
|
||||
}
|
||||
var bubbleEmboss = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.G,
|
||||
filter, this.bubbleGroup_);
|
||||
Blockly.utils.dom.SvgElementType.G, filter, this.bubbleGroup_);
|
||||
this.bubbleArrow_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.PATH, {},
|
||||
bubbleEmboss);
|
||||
Blockly.utils.dom.SvgElementType.PATH, {}, bubbleEmboss);
|
||||
this.bubbleBack_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.RECT,
|
||||
{
|
||||
Blockly.utils.dom.SvgElementType.RECT, {
|
||||
'class': 'blocklyDraggable',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
@@ -263,8 +263,7 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
if (hasResize) {
|
||||
this.resizeGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.G,
|
||||
{'class': this.workspace_.RTL ?
|
||||
'blocklyResizeSW' : 'blocklyResizeSE'},
|
||||
{'class': this.workspace_.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'},
|
||||
this.bubbleGroup_);
|
||||
var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
@@ -272,21 +271,23 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
{'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())},
|
||||
this.resizeGroup_);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.LINE,
|
||||
{
|
||||
Blockly.utils.dom.SvgElementType.LINE, {
|
||||
'class': 'blocklyResizeLine',
|
||||
'x1': resizeSize / 3, 'y1': resizeSize - 1,
|
||||
'x2': resizeSize - 1, 'y2': resizeSize / 3
|
||||
}, this.resizeGroup_);
|
||||
'x1': resizeSize / 3,
|
||||
'y1': resizeSize - 1,
|
||||
'x2': resizeSize - 1,
|
||||
'y2': resizeSize / 3
|
||||
},
|
||||
this.resizeGroup_);
|
||||
Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.LINE,
|
||||
{
|
||||
Blockly.utils.dom.SvgElementType.LINE, {
|
||||
'class': 'blocklyResizeLine',
|
||||
'x1': resizeSize * 2 / 3,
|
||||
'y1': resizeSize - 1,
|
||||
'x2': resizeSize - 1,
|
||||
'y2': resizeSize * 2 / 3
|
||||
}, this.resizeGroup_);
|
||||
},
|
||||
this.resizeGroup_);
|
||||
} else {
|
||||
this.resizeGroup_ = null;
|
||||
}
|
||||
@@ -305,7 +306,7 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
|
||||
|
||||
/**
|
||||
* Return the root node of the bubble's SVG group.
|
||||
* @return {SVGElement} The root SVG node of the bubble's group.
|
||||
* @return {!SVGElement} The root SVG node of the bubble's group.
|
||||
*/
|
||||
Blockly.Bubble.prototype.getSvgRoot = function() {
|
||||
return this.bubbleGroup_;
|
||||
@@ -352,6 +353,15 @@ Blockly.Bubble.prototype.isDeletable = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the style of this bubble when it is dragged over a delete area.
|
||||
* @param {boolean} _enable True if the bubble is about to be deleted, false
|
||||
* otherwise.
|
||||
*/
|
||||
Blockly.Bubble.prototype.setDeleteStyle = function(_enable) {
|
||||
// NOP if bubble is not deletable.
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a mouse-down on bubble's resize corner.
|
||||
* @param {!Event} e Mouse down event.
|
||||
@@ -366,13 +376,15 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) {
|
||||
return;
|
||||
}
|
||||
// Left-click (or middle click)
|
||||
this.workspace_.startDrag(e, new Blockly.utils.Coordinate(
|
||||
this.workspace_.RTL ? -this.width_ : this.width_, this.height_));
|
||||
this.workspace_.startDrag(
|
||||
e,
|
||||
new Blockly.utils.Coordinate(
|
||||
this.workspace_.RTL ? -this.width_ : this.width_, this.height_));
|
||||
|
||||
Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document,
|
||||
'mouseup', this, Blockly.Bubble.bubbleMouseUp_);
|
||||
Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(document,
|
||||
'mousemove', this, this.resizeMouseMove_);
|
||||
Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
|
||||
document, 'mouseup', this, Blockly.Bubble.bubbleMouseUp_);
|
||||
Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(
|
||||
document, 'mousemove', this, this.resizeMouseMove_);
|
||||
Blockly.hideChaff();
|
||||
// This event has been handled. No need to bubble up to the document.
|
||||
e.stopPropagation();
|
||||
@@ -470,8 +482,9 @@ Blockly.Bubble.prototype.layoutBubble_ = function() {
|
||||
|
||||
// Set the position to whichever position shows the most of the bubble,
|
||||
// with tiebreaks going in the order: top > start > close > far.
|
||||
var mostOverlap = Math.max(topPositionOverlap, startPositionOverlap,
|
||||
closerPositionOverlap, fartherPositionOverlap);
|
||||
var mostOverlap = Math.max(
|
||||
topPositionOverlap, startPositionOverlap, closerPositionOverlap,
|
||||
fartherPositionOverlap);
|
||||
if (topPositionOverlap == mostOverlap) {
|
||||
this.relativeLeft_ = topPosition.x;
|
||||
this.relativeTop_ = topPosition.y;
|
||||
@@ -508,14 +521,11 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, metrics) {
|
||||
// The position of the top-left corner of the bubble in workspace units.
|
||||
var bubbleMin = {
|
||||
x: this.workspace_.RTL ? (this.anchorXY_.x - relativeMin.x - this.width_) :
|
||||
(relativeMin.x + this.anchorXY_.x),
|
||||
(relativeMin.x + this.anchorXY_.x),
|
||||
y: relativeMin.y + this.anchorXY_.y
|
||||
};
|
||||
// The position of the bottom-right corner of the bubble in workspace units.
|
||||
var bubbleMax = {
|
||||
x: bubbleMin.x + this.width_,
|
||||
y: bubbleMin.y + this.height_
|
||||
};
|
||||
var bubbleMax = {x: bubbleMin.x + this.width_, y: bubbleMin.y + this.height_};
|
||||
|
||||
// We could adjust these values to account for the scrollbars, but the
|
||||
// bubbles should have been adjusted to not collide with them anyway, so
|
||||
@@ -523,10 +533,7 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, metrics) {
|
||||
// calculation.
|
||||
|
||||
// The position of the top-left corner of the workspace.
|
||||
var workspaceMin = {
|
||||
x: metrics.viewLeft,
|
||||
y: metrics.viewTop
|
||||
};
|
||||
var workspaceMin = {x: metrics.viewLeft, y: metrics.viewTop};
|
||||
// The position of the bottom-right corner of the workspace.
|
||||
var workspaceMax = {
|
||||
x: metrics.viewLeft + metrics.viewWidth,
|
||||
@@ -537,8 +544,10 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, metrics) {
|
||||
Math.max(bubbleMin.x, workspaceMin.x);
|
||||
var overlapHeight = Math.min(bubbleMax.y, workspaceMax.y) -
|
||||
Math.max(bubbleMin.y, workspaceMin.y);
|
||||
return Math.max(0, Math.min(1,
|
||||
(overlapWidth * overlapHeight) / (this.width_ * this.height_)));
|
||||
return Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
1, (overlapWidth * overlapHeight) / (this.width_ * this.height_)));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -574,8 +583,8 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(metrics) {
|
||||
|
||||
var workspaceLeft = metrics.viewLeft;
|
||||
var workspaceRight = metrics.viewLeft + metrics.viewWidth -
|
||||
// Thickness in workspace units.
|
||||
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
// Thickness in workspace units.
|
||||
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
|
||||
}
|
||||
|
||||
if (this.workspace_.RTL) {
|
||||
@@ -698,12 +707,15 @@ Blockly.Bubble.prototype.setBubbleSize = function(width, height) {
|
||||
if (this.workspace_.RTL) {
|
||||
// Mirror the resize group.
|
||||
var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH;
|
||||
this.resizeGroup_.setAttribute('transform', 'translate(' +
|
||||
resizeSize + ',' + (height - doubleBorderWidth) + ') scale(-1 1)');
|
||||
this.resizeGroup_.setAttribute(
|
||||
'transform',
|
||||
'translate(' + resizeSize + ',' + (height - doubleBorderWidth) +
|
||||
') scale(-1 1)');
|
||||
} else {
|
||||
this.resizeGroup_.setAttribute('transform', 'translate(' +
|
||||
(width - doubleBorderWidth) + ',' +
|
||||
(height - doubleBorderWidth) + ')');
|
||||
this.resizeGroup_.setAttribute(
|
||||
'transform',
|
||||
'translate(' + (width - doubleBorderWidth) + ',' +
|
||||
(height - doubleBorderWidth) + ')');
|
||||
}
|
||||
}
|
||||
if (this.autoLayout_) {
|
||||
@@ -756,8 +768,8 @@ Blockly.Bubble.prototype.renderArrow_ = function() {
|
||||
|
||||
// Calculate the thickness of the base of the arrow.
|
||||
var bubbleSize = this.getBubbleSize();
|
||||
var thickness = (bubbleSize.width + bubbleSize.height) /
|
||||
Blockly.Bubble.ARROW_THICKNESS;
|
||||
var thickness =
|
||||
(bubbleSize.width + bubbleSize.height) / Blockly.Bubble.ARROW_THICKNESS;
|
||||
thickness = Math.min(thickness, bubbleSize.width, bubbleSize.height) / 4;
|
||||
|
||||
// Back the tip of the arrow off of the anchor.
|
||||
@@ -776,18 +788,18 @@ Blockly.Bubble.prototype.renderArrow_ = function() {
|
||||
if (swirlAngle > Math.PI * 2) {
|
||||
swirlAngle -= Math.PI * 2;
|
||||
}
|
||||
var swirlRise = Math.sin(swirlAngle) *
|
||||
hypotenuse / Blockly.Bubble.ARROW_BEND;
|
||||
var swirlRun = Math.cos(swirlAngle) *
|
||||
hypotenuse / Blockly.Bubble.ARROW_BEND;
|
||||
var swirlRise =
|
||||
Math.sin(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND;
|
||||
var swirlRun =
|
||||
Math.cos(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND;
|
||||
|
||||
steps.push('M' + baseX1 + ',' + baseY1);
|
||||
steps.push('C' + (baseX1 + swirlRun) + ',' + (baseY1 + swirlRise) +
|
||||
' ' + relAnchorX + ',' + relAnchorY +
|
||||
' ' + relAnchorX + ',' + relAnchorY);
|
||||
steps.push('C' + relAnchorX + ',' + relAnchorY +
|
||||
' ' + (baseX2 + swirlRun) + ',' + (baseY2 + swirlRise) +
|
||||
' ' + baseX2 + ',' + baseY2);
|
||||
steps.push(
|
||||
'C' + (baseX1 + swirlRun) + ',' + (baseY1 + swirlRise) + ' ' +
|
||||
relAnchorX + ',' + relAnchorY + ' ' + relAnchorX + ',' + relAnchorY);
|
||||
steps.push(
|
||||
'C' + relAnchorX + ',' + relAnchorY + ' ' + (baseX2 + swirlRun) + ',' +
|
||||
(baseY2 + swirlRise) + ' ' + baseX2 + ',' + baseY2);
|
||||
}
|
||||
steps.push('z');
|
||||
this.bubbleArrow_.setAttribute('d', steps.join(' '));
|
||||
@@ -849,8 +861,8 @@ Blockly.Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) {
|
||||
Blockly.Bubble.prototype.getRelativeToSurfaceXY = function() {
|
||||
return new Blockly.utils.Coordinate(
|
||||
this.workspace_.RTL ?
|
||||
-this.relativeLeft_ + this.anchorXY_.x - this.width_ :
|
||||
this.anchorXY_.x + this.relativeLeft_,
|
||||
-this.relativeLeft_ + this.anchorXY_.x - this.width_ :
|
||||
this.anchorXY_.x + this.relativeLeft_,
|
||||
this.anchorXY_.y + this.relativeTop_);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,20 +18,21 @@ goog.require('Blockly.Events.CommentMove');
|
||||
goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
|
||||
goog.requireType('Blockly.IBubble');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a bubble dragger. It moves things on the bubble canvas around the
|
||||
* workspace when they are being dragged by a mouse or touch. These can be
|
||||
* block comments, mutators, warnings, or workspace comments.
|
||||
* @param {!Blockly.Bubble|!Blockly.WorkspaceCommentSvg} bubble The item on the
|
||||
* bubble canvas to drag.
|
||||
* @param {!Blockly.IBubble} bubble The item on the bubble canvas to drag.
|
||||
* @param {!Blockly.WorkspaceSvg} workspace The workspace to drag on.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.BubbleDragger = function(bubble, workspace) {
|
||||
/**
|
||||
* The item on the bubble canvas that is being dragged.
|
||||
* @type {!Blockly.Bubble|!Blockly.WorkspaceCommentSvg}
|
||||
* @type {!Blockly.IBubble}
|
||||
* @private
|
||||
*/
|
||||
this.draggingBubble_ = bubble;
|
||||
@@ -75,7 +76,8 @@ Blockly.BubbleDragger = function(bubble, workspace) {
|
||||
*/
|
||||
this.dragSurface_ =
|
||||
Blockly.utils.is3dSupported() && !!workspace.getBlockDragSurface() ?
|
||||
workspace.getBlockDragSurface() : null;
|
||||
workspace.getBlockDragSurface() :
|
||||
null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -109,7 +111,7 @@ Blockly.BubbleDragger.prototype.startBubbleDrag = function() {
|
||||
var toolbox = this.workspace_.getToolbox();
|
||||
if (toolbox && typeof toolbox.addStyle == 'function') {
|
||||
var style = this.draggingBubble_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
'blocklyToolboxGrab';
|
||||
toolbox.addStyle(style);
|
||||
}
|
||||
};
|
||||
@@ -211,7 +213,7 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function(
|
||||
var toolbox = this.workspace_.getToolbox();
|
||||
if (toolbox && typeof toolbox.removeStyle == 'function') {
|
||||
var style = this.draggingBubble_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
'blocklyToolboxGrab';
|
||||
toolbox.removeStyle(style);
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
@@ -238,14 +240,15 @@ Blockly.BubbleDragger.prototype.fireMoveEvent_ = function() {
|
||||
* correction for mutator workspaces.
|
||||
* This function does not consider differing origins. It simply scales the
|
||||
* input's x and y values.
|
||||
* @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y values
|
||||
* in CSS pixel units.
|
||||
* @return {!Blockly.utils.Coordinate} The input coordinate divided by the workspace
|
||||
* scale.
|
||||
* @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y
|
||||
* values in CSS pixel units.
|
||||
* @return {!Blockly.utils.Coordinate} The input coordinate divided by the
|
||||
* workspace scale.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
|
||||
var result = new Blockly.utils.Coordinate(pixelCoord.x / this.workspace_.scale,
|
||||
var result = new Blockly.utils.Coordinate(
|
||||
pixelCoord.x / this.workspace_.scale,
|
||||
pixelCoord.y / this.workspace_.scale);
|
||||
if (this.workspace_.isMutator) {
|
||||
// If we're in a mutator, its scale is always 1, purely because of some
|
||||
|
||||
@@ -28,6 +28,7 @@ goog.require('Blockly.utils');
|
||||
goog.require('Blockly.utils.Coordinate');
|
||||
goog.require('Blockly.WorkspaceDragger');
|
||||
|
||||
goog.requireType('Blockly.IBubble');
|
||||
goog.requireType('Blockly.IFlyout');
|
||||
|
||||
|
||||
@@ -45,7 +46,6 @@ goog.requireType('Blockly.IFlyout');
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
|
||||
/**
|
||||
* The position of the mouse when the gesture started. Units are CSS pixels,
|
||||
* with (0, 0) at the top left of the browser window (mouseEvent clientX/Y).
|
||||
@@ -65,7 +65,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
|
||||
/**
|
||||
* The bubble that the gesture started on, or null if it did not start on a
|
||||
* bubble.
|
||||
* @type {Blockly.Bubble}
|
||||
* @type {Blockly.IBubble}
|
||||
* @private
|
||||
*/
|
||||
this.startBubble_ = null;
|
||||
@@ -280,16 +280,17 @@ Blockly.Gesture.prototype.updateFromEvent_ = function(e) {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateDragDelta_ = function(currentXY) {
|
||||
this.currentDragDeltaXY_ = Blockly.utils.Coordinate.difference(currentXY,
|
||||
this.currentDragDeltaXY_ = Blockly.utils.Coordinate.difference(
|
||||
currentXY,
|
||||
/** @type {!Blockly.utils.Coordinate} */ (this.mouseDownXY_));
|
||||
|
||||
if (!this.hasExceededDragRadius_) {
|
||||
var currentDragDelta = Blockly.utils.Coordinate.magnitude(
|
||||
this.currentDragDeltaXY_);
|
||||
var currentDragDelta =
|
||||
Blockly.utils.Coordinate.magnitude(this.currentDragDeltaXY_);
|
||||
|
||||
// The flyout has a different drag radius from the rest of Blockly.
|
||||
var limitRadius = this.flyout_ ? Blockly.FLYOUT_DRAG_RADIUS :
|
||||
Blockly.DRAG_RADIUS;
|
||||
var limitRadius =
|
||||
this.flyout_ ? Blockly.FLYOUT_DRAG_RADIUS : Blockly.DRAG_RADIUS;
|
||||
|
||||
this.hasExceededDragRadius_ = currentDragDelta > limitRadius;
|
||||
return this.hasExceededDragRadius_;
|
||||
@@ -387,7 +388,8 @@ Blockly.Gesture.prototype.updateIsDraggingBlock_ = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.updateIsDraggingWorkspace_ = function() {
|
||||
var wsMovable = this.flyout_ ? this.flyout_.isScrollable() :
|
||||
var wsMovable = this.flyout_ ?
|
||||
this.flyout_.isScrollable() :
|
||||
this.startWorkspace_ && this.startWorkspace_.isDraggable();
|
||||
|
||||
if (!wsMovable) {
|
||||
@@ -439,8 +441,7 @@ Blockly.Gesture.prototype.startDraggingBlock_ = function() {
|
||||
/** @type {!Blockly.BlockSvg} */ (this.targetBlock_),
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_));
|
||||
this.blockDragger_.startBlockDrag(this.currentDragDeltaXY_, this.healStack_);
|
||||
this.blockDragger_.dragBlock(this.mostRecentEvent_,
|
||||
this.currentDragDeltaXY_);
|
||||
this.blockDragger_.dragBlock(this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -450,11 +451,11 @@ Blockly.Gesture.prototype.startDraggingBlock_ = function() {
|
||||
// TODO (fenichel): Possibly combine this and startDraggingBlock_.
|
||||
Blockly.Gesture.prototype.startDraggingBubble_ = function() {
|
||||
this.bubbleDragger_ = new Blockly.BubbleDragger(
|
||||
/** @type {!Blockly.Bubble} */ (this.startBubble_),
|
||||
/** @type {!Blockly.IBubble} */ (this.startBubble_),
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_));
|
||||
this.bubbleDragger_.startBubbleDrag();
|
||||
this.bubbleDragger_.dragBubble(this.mostRecentEvent_,
|
||||
this.currentDragDeltaXY_);
|
||||
this.bubbleDragger_.dragBubble(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
};
|
||||
/**
|
||||
* Start a gesture: update the workspace to indicate that a gesture is in
|
||||
@@ -487,8 +488,7 @@ Blockly.Gesture.prototype.doStart = function(e) {
|
||||
Blockly.Tooltip.block();
|
||||
|
||||
if (this.targetBlock_) {
|
||||
if (!this.targetBlock_.isInFlyout &&
|
||||
e.shiftKey &&
|
||||
if (!this.targetBlock_.isInFlyout && e.shiftKey &&
|
||||
this.targetBlock_.workspace.keyboardAccessibilityMode) {
|
||||
this.creatorWorkspace_.getCursor().setCurNode(
|
||||
Blockly.ASTNode.createTopNode(this.targetBlock_));
|
||||
@@ -503,8 +503,8 @@ Blockly.Gesture.prototype.doStart = function(e) {
|
||||
}
|
||||
|
||||
if ((e.type.toLowerCase() == 'touchstart' ||
|
||||
e.type.toLowerCase() == 'pointerdown') &&
|
||||
e.pointerType != 'mouse') {
|
||||
e.type.toLowerCase() == 'pointerdown') &&
|
||||
e.pointerType != 'mouse') {
|
||||
Blockly.longStart(e, this);
|
||||
}
|
||||
|
||||
@@ -539,11 +539,11 @@ Blockly.Gesture.prototype.handleMove = function(e) {
|
||||
if (this.isDraggingWorkspace_) {
|
||||
this.workspaceDragger_.drag(this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingBlock_) {
|
||||
this.blockDragger_.dragBlock(this.mostRecentEvent_,
|
||||
this.currentDragDeltaXY_);
|
||||
this.blockDragger_.dragBlock(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingBubble_) {
|
||||
this.bubbleDragger_.dragBubble(this.mostRecentEvent_,
|
||||
this.currentDragDeltaXY_);
|
||||
this.bubbleDragger_.dragBubble(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -604,11 +604,11 @@ Blockly.Gesture.prototype.cancel = function() {
|
||||
}
|
||||
Blockly.longStop_();
|
||||
if (this.isDraggingBubble_) {
|
||||
this.bubbleDragger_.endBubbleDrag(this.mostRecentEvent_,
|
||||
this.currentDragDeltaXY_);
|
||||
this.bubbleDragger_.endBubbleDrag(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingBlock_) {
|
||||
this.blockDragger_.endBlockDrag(this.mostRecentEvent_,
|
||||
this.currentDragDeltaXY_);
|
||||
this.blockDragger_.endBlockDrag(
|
||||
this.mostRecentEvent_, this.currentDragDeltaXY_);
|
||||
} else if (this.isDraggingWorkspace_) {
|
||||
this.workspaceDragger_.endDrag(this.currentDragDeltaXY_);
|
||||
}
|
||||
@@ -647,7 +647,8 @@ Blockly.Gesture.prototype.handleRightClick = function(e) {
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleWsStart = function(e, ws) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error('Tried to call gesture.handleWsStart, ' +
|
||||
throw Error(
|
||||
'Tried to call gesture.handleWsStart, ' +
|
||||
'but the gesture had already been started.');
|
||||
}
|
||||
this.setStartWorkspace_(ws);
|
||||
@@ -677,7 +678,8 @@ Blockly.Gesture.prototype.fireWorkspaceClick_ = function(ws) {
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleFlyoutStart = function(e, flyout) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error('Tried to call gesture.handleFlyoutStart, ' +
|
||||
throw Error(
|
||||
'Tried to call gesture.handleFlyoutStart, ' +
|
||||
'but the gesture had already been started.');
|
||||
}
|
||||
this.setStartFlyout_(flyout);
|
||||
@@ -692,7 +694,8 @@ Blockly.Gesture.prototype.handleFlyoutStart = function(e, flyout) {
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleBlockStart = function(e, block) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error('Tried to call gesture.handleBlockStart, ' +
|
||||
throw Error(
|
||||
'Tried to call gesture.handleBlockStart, ' +
|
||||
'but the gesture had already been started.');
|
||||
}
|
||||
this.setStartBlock(block);
|
||||
@@ -702,12 +705,13 @@ Blockly.Gesture.prototype.handleBlockStart = function(e, block) {
|
||||
/**
|
||||
* Handle a mousedown/touchstart event on a bubble.
|
||||
* @param {!Event} e A mouse down or touch start event.
|
||||
* @param {!Blockly.Bubble} bubble The bubble the event hit.
|
||||
* @param {!Blockly.IBubble} bubble The bubble the event hit.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.handleBubbleStart = function(e, bubble) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error('Tried to call gesture.handleBubbleStart, ' +
|
||||
throw Error(
|
||||
'Tried to call gesture.handleBubbleStart, ' +
|
||||
'but the gesture had already been started.');
|
||||
}
|
||||
this.setStartBubble(bubble);
|
||||
@@ -804,7 +808,8 @@ Blockly.Gesture.prototype.bringBlockToFront_ = function() {
|
||||
*/
|
||||
Blockly.Gesture.prototype.setStartField = function(field) {
|
||||
if (this.hasStarted_) {
|
||||
throw Error('Tried to call gesture.setStartField, ' +
|
||||
throw Error(
|
||||
'Tried to call gesture.setStartField, ' +
|
||||
'but the gesture had already been started.');
|
||||
}
|
||||
if (!this.startField_) {
|
||||
@@ -814,7 +819,7 @@ Blockly.Gesture.prototype.setStartField = function(field) {
|
||||
|
||||
/**
|
||||
* Record the bubble that a gesture started on
|
||||
* @param {Blockly.Bubble} bubble The bubble the gesture started on.
|
||||
* @param {Blockly.IBubble} bubble The bubble the gesture started on.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Gesture.prototype.setStartBubble = function(bubble) {
|
||||
@@ -916,8 +921,8 @@ Blockly.Gesture.prototype.isBlockClick_ = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.isFieldClick_ = function() {
|
||||
var fieldClickable = this.startField_ ?
|
||||
this.startField_.isClickable() : false;
|
||||
var fieldClickable =
|
||||
this.startField_ ? this.startField_.isClickable() : false;
|
||||
return fieldClickable && !this.hasExceededDragRadius_ &&
|
||||
(!this.flyout_ || !this.flyout_.autoClose);
|
||||
};
|
||||
@@ -929,8 +934,8 @@ Blockly.Gesture.prototype.isFieldClick_ = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Gesture.prototype.isWorkspaceClick_ = function() {
|
||||
var onlyTouchedWorkspace = !this.startBlock_ && !this.startBubble_ &&
|
||||
!this.startField_;
|
||||
var onlyTouchedWorkspace =
|
||||
!this.startBlock_ && !this.startBubble_ && !this.startField_;
|
||||
return onlyTouchedWorkspace && !this.hasExceededDragRadius_;
|
||||
};
|
||||
|
||||
|
||||
83
core/interfaces/i_bubble.js
Normal file
83
core/interfaces/i_bubble.js
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for a bubble.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IBubble');
|
||||
|
||||
goog.requireType('Blockly.IContextMenu');
|
||||
goog.requireType('Blockly.IDeletable');
|
||||
|
||||
|
||||
/**
|
||||
* A bubble interface.
|
||||
* @interface
|
||||
* @extends {Blockly.IDeletable}
|
||||
* @extends {Blockly.IContextMenu}
|
||||
*/
|
||||
Blockly.IBubble = function() {};
|
||||
|
||||
/**
|
||||
* Return the coordinates of the top-left corner of this bubble's body relative
|
||||
* to the drawing surface's origin (0,0), in workspace units.
|
||||
* @return {!Blockly.utils.Coordinate} Object with .x and .y properties.
|
||||
*/
|
||||
Blockly.IBubble.prototype.getRelativeToSurfaceXY;
|
||||
|
||||
/**
|
||||
* Return the root node of the bubble's SVG group.
|
||||
* @return {!SVGElement} The root SVG node of the bubble's group.
|
||||
*/
|
||||
Blockly.IBubble.prototype.getSvgRoot;
|
||||
|
||||
/**
|
||||
* Set whether auto-layout of this bubble is enabled. The first time a bubble
|
||||
* is shown it positions itself to not cover any blocks. Once a user has
|
||||
* dragged it to reposition, it renders where the user put it.
|
||||
* @param {boolean} enable True if auto-layout should be enabled, false
|
||||
* otherwise.
|
||||
*/
|
||||
Blockly.IBubble.prototype.setAutoLayout;
|
||||
|
||||
/**
|
||||
* Triggers a move callback if one exists at the end of a drag.
|
||||
* @param {boolean} adding True if adding, false if removing.
|
||||
*/
|
||||
Blockly.IBubble.prototype.setDragging;
|
||||
|
||||
/**
|
||||
* Move this bubble during a drag, taking into account whether or not there is
|
||||
* a drag surface.
|
||||
* @param {Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries
|
||||
* rendered items during a drag, or null if no drag surface is in use.
|
||||
* @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in
|
||||
* workspace coordinates.
|
||||
*/
|
||||
Blockly.IBubble.prototype.moveDuringDrag;
|
||||
|
||||
/**
|
||||
* Move the bubble to the specified location in workspace coordinates.
|
||||
* @param {number} x The x position to move to.
|
||||
* @param {number} y The y position to move to.
|
||||
*/
|
||||
Blockly.IBubble.prototype.moveTo;
|
||||
|
||||
/**
|
||||
* Update the style of this bubble when it is dragged over a delete area.
|
||||
* @param {boolean} enable True if the bubble is about to be deleted, false
|
||||
* otherwise.
|
||||
*/
|
||||
Blockly.IBubble.prototype.setDeleteStyle;
|
||||
|
||||
/**
|
||||
* Dispose of this bubble.
|
||||
*/
|
||||
Blockly.IBubble.prototype.dispose;
|
||||
26
core/interfaces/i_contextmenu.js
Normal file
26
core/interfaces/i_contextmenu.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The interface for an object that supports a right-click.
|
||||
* @author samelh@google.com (Sam El-Husseini)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.IContextMenu');
|
||||
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
Blockly.IContextMenu = function() {};
|
||||
|
||||
/**
|
||||
* Show the context menu for this object.
|
||||
* @param {!Event} e Mouse event.
|
||||
*/
|
||||
Blockly.IContextMenu.prototype.showContextMenu;
|
||||
@@ -26,6 +26,7 @@ goog.require('Blockly.utils.Rect');
|
||||
goog.require('Blockly.WorkspaceComment');
|
||||
|
||||
goog.requireType('Blockly.IBoundedElement');
|
||||
goog.requireType('Blockly.IBubble');
|
||||
goog.requireType('Blockly.ICopyable');
|
||||
|
||||
/**
|
||||
@@ -38,12 +39,12 @@ goog.requireType('Blockly.ICopyable');
|
||||
* create a new ID.
|
||||
* @extends {Blockly.WorkspaceComment}
|
||||
* @implements {Blockly.IBoundedElement}
|
||||
* @implements {Blockly.IBubble}
|
||||
* @implements {Blockly.ICopyable}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg = function(workspace, content, height, width,
|
||||
opt_id) {
|
||||
|
||||
Blockly.WorkspaceCommentSvg = function(
|
||||
workspace, content, height, width, opt_id) {
|
||||
/**
|
||||
* Mouse up event data.
|
||||
* @type {?Blockly.EventData}
|
||||
@@ -60,7 +61,7 @@ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width,
|
||||
|
||||
// Create core elements for the block.
|
||||
/**
|
||||
* @type {SVGElement}
|
||||
* @type {!SVGElement}
|
||||
* @private
|
||||
*/
|
||||
this.svgGroup_ = Blockly.utils.dom.createSvgElement(
|
||||
@@ -68,8 +69,7 @@ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width,
|
||||
this.svgGroup_.translate_ = '';
|
||||
|
||||
this.svgRect_ = Blockly.utils.dom.createSvgElement(
|
||||
Blockly.utils.dom.SvgElementType.RECT,
|
||||
{
|
||||
Blockly.utils.dom.SvgElementType.RECT, {
|
||||
'class': 'blocklyCommentRect',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
@@ -94,13 +94,13 @@ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width,
|
||||
this.useDragSurface_ =
|
||||
Blockly.utils.is3dSupported() && !!workspace.blockDragSurface_;
|
||||
|
||||
Blockly.WorkspaceCommentSvg.superClass_.constructor.call(this,
|
||||
workspace, content, height, width, opt_id);
|
||||
Blockly.WorkspaceCommentSvg.superClass_.constructor.call(
|
||||
this, workspace, content, height, width, opt_id);
|
||||
|
||||
this.render();
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.WorkspaceCommentSvg,
|
||||
Blockly.WorkspaceComment);
|
||||
Blockly.utils.object.inherits(
|
||||
Blockly.WorkspaceCommentSvg, Blockly.WorkspaceComment);
|
||||
|
||||
/**
|
||||
* The width and height to use to size a workspace comment when it is first
|
||||
@@ -291,8 +291,8 @@ Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() {
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
|
||||
var dragSurfaceGroup = this.useDragSurface_ ?
|
||||
this.workspace.blockDragSurface_.getGroup() : null;
|
||||
var dragSurfaceGroup =
|
||||
this.useDragSurface_ ? this.workspace.blockDragSurface_.getGroup() : null;
|
||||
|
||||
var element = this.getSvgRoot();
|
||||
if (element) {
|
||||
@@ -312,7 +312,7 @@ Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() {
|
||||
}
|
||||
element = element.parentNode;
|
||||
} while (element && element != this.workspace.getBubbleCanvas() &&
|
||||
element != dragSurfaceGroup);
|
||||
element != dragSurfaceGroup);
|
||||
}
|
||||
this.xy_ = new Blockly.utils.Coordinate(x, y);
|
||||
return this.xy_;
|
||||
@@ -344,8 +344,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) {
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg.prototype.translate = function(x, y) {
|
||||
this.xy_ = new Blockly.utils.Coordinate(x, y);
|
||||
this.getSvgRoot().setAttribute('transform',
|
||||
'translate(' + x + ',' + y + ')');
|
||||
this.getSvgRoot().setAttribute('transform', 'translate(' + x + ',' + y + ')');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -373,8 +372,8 @@ Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface = function() {
|
||||
* Move this comment back to the workspace block canvas.
|
||||
* Generally should be called at the same time as setDragging(false).
|
||||
* Does nothing if useDragSurface_ is false.
|
||||
* @param {!Blockly.utils.Coordinate} newXY The position the comment should take on
|
||||
* on the workspace canvas, in workspace coordinates.
|
||||
* @param {!Blockly.utils.Coordinate} newXY The position the comment should take
|
||||
* on on the workspace canvas, in workspace coordinates.
|
||||
* @private
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface = function(newXY) {
|
||||
@@ -395,14 +394,14 @@ Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface = function(newXY) {
|
||||
* workspace coordinates.
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg.prototype.moveDuringDrag = function(dragSurface,
|
||||
newLoc) {
|
||||
Blockly.WorkspaceCommentSvg.prototype.moveDuringDrag = function(
|
||||
dragSurface, newLoc) {
|
||||
if (dragSurface) {
|
||||
dragSurface.translateSurface(newLoc.x, newLoc.y);
|
||||
} else {
|
||||
this.svgGroup_.translate_ = 'translate(' + newLoc.x + ',' + newLoc.y + ')';
|
||||
this.svgGroup_.setAttribute('transform',
|
||||
this.svgGroup_.translate_ + this.svgGroup_.skew_);
|
||||
this.svgGroup_.setAttribute(
|
||||
'transform', this.svgGroup_.translate_ + this.svgGroup_.skew_);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -507,7 +506,7 @@ Blockly.WorkspaceCommentSvg.prototype.setDragging = function(adding) {
|
||||
|
||||
/**
|
||||
* Return the root node of the SVG or null if none exists.
|
||||
* @return {SVGElement} The root SVG node (probably a group).
|
||||
* @return {!SVGElement} The root SVG node (probably a group).
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg.prototype.getSvgRoot = function() {
|
||||
@@ -551,7 +550,15 @@ Blockly.WorkspaceCommentSvg.prototype.setDeleteStyle = function(enable) {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.WorkspaceCommentSvg.prototype.setAutoLayout = function() {
|
||||
/**
|
||||
* Set whether auto-layout of this bubble is enabled. The first time a bubble
|
||||
* is shown it positions itself to not cover any blocks. Once a user has
|
||||
* dragged it to reposition, it renders where the user put it.
|
||||
* @param {boolean} _enable True if auto-layout should be enabled, false
|
||||
* otherwise.
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg.prototype.setAutoLayout = function(_enable) {
|
||||
// NOP for compatibility with the bubble dragger.
|
||||
};
|
||||
|
||||
@@ -564,14 +571,14 @@ Blockly.WorkspaceCommentSvg.prototype.setAutoLayout = function() {
|
||||
* @return {!Blockly.WorkspaceCommentSvg} The created workspace comment.
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg.fromXml = function(xmlComment, workspace,
|
||||
opt_wsWidth) {
|
||||
Blockly.WorkspaceCommentSvg.fromXml = function(
|
||||
xmlComment, workspace, opt_wsWidth) {
|
||||
Blockly.Events.disable();
|
||||
try {
|
||||
var info = Blockly.WorkspaceComment.parseAttributes(xmlComment);
|
||||
|
||||
var comment = new Blockly.WorkspaceCommentSvg(workspace,
|
||||
info.content, info.h, info.w, info.id);
|
||||
var comment = new Blockly.WorkspaceCommentSvg(
|
||||
workspace, info.content, info.h, info.w, info.id);
|
||||
if (workspace.rendered) {
|
||||
comment.initSvg();
|
||||
comment.render(false);
|
||||
@@ -608,8 +615,8 @@ Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) {
|
||||
}
|
||||
var element = this.toXml(opt_noId);
|
||||
var xy = this.getRelativeToSurfaceXY();
|
||||
element.setAttribute('x',
|
||||
Math.round(this.workspace.RTL ? width - xy.x : xy.x));
|
||||
element.setAttribute(
|
||||
'x', Math.round(this.workspace.RTL ? width - xy.x : xy.x));
|
||||
element.setAttribute('y', Math.round(xy.y));
|
||||
element.setAttribute('h', this.getHeight());
|
||||
element.setAttribute('w', this.getWidth());
|
||||
@@ -622,17 +629,14 @@ Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) {
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceCommentSvg.prototype.toCopyData = function() {
|
||||
return {
|
||||
xml: this.toXmlWithXY(),
|
||||
source: this.workspace,
|
||||
typeCounts: null
|
||||
};
|
||||
return {xml: this.toXmlWithXY(), source: this.workspace, typeCounts: null};
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS for workspace comment. See css.js for use.
|
||||
*/
|
||||
Blockly.Css.register([
|
||||
// clang-format off
|
||||
/* eslint-disable indent */
|
||||
'.blocklyCommentForeignObject {',
|
||||
'position: relative;',
|
||||
@@ -692,4 +696,5 @@ Blockly.Css.register([
|
||||
'stroke: #fc3;',
|
||||
'}'
|
||||
/* eslint-enable indent */
|
||||
// clang-format on
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user