Add IBubble interface (#4104)

* Add IBubble interface and make use of it for WorkspaceCommentSvgs
This commit is contained in:
Sam El-Husseini
2020-08-04 17:28:12 -04:00
committed by GitHub
parent b7305c1eed
commit f3fdab11fb
6 changed files with 277 additions and 143 deletions

View File

@@ -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_);
};

View File

@@ -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

View File

@@ -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_;
};

View 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;

View 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;

View File

@@ -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
]);