Skip to content

Commit 44e0ba8

Browse files
committed
release: Merge branch 'develop' into rc/v11.0.0
2 parents 2f261ea + 3ac2fb9 commit 44e0ba8

42 files changed

Lines changed: 654 additions & 357 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/block.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,17 @@ export class Block implements IASTNodeLocation {
675675
return block;
676676
}
677677

678+
/**
679+
* Returns this block if it is a shadow block, or the first non-shadow parent.
680+
*
681+
* @internal
682+
*/
683+
getFirstNonShadowBlock(): this {
684+
if (!this.isShadow()) return this;
685+
// We can assert the parent is non-null because shadows must have parents.
686+
return this.getParent()!.getFirstNonShadowBlock();
687+
}
688+
678689
/**
679690
* Find all the blocks that are directly nested inside this one.
680691
* Includes value and statement inputs, as well as any following statement.

core/block_animations.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,11 @@ export function disposeUiEffect(block: BlockSvg) {
4242
// Deeply clone the current block.
4343
const clone: SVGGElement = svgGroup.cloneNode(true) as SVGGElement;
4444
clone.setAttribute('transform', 'translate(' + xy.x + ',' + xy.y + ')');
45-
if (workspace.isDragging()) {
46-
workspace.getLayerManager()?.moveToDragLayer({
47-
getSvgRoot: () => {
48-
return clone;
49-
},
50-
});
51-
} else {
52-
workspace.getLayerManager()?.getBlockLayer().appendChild(clone);
53-
}
45+
workspace.getLayerManager()?.appendToAnimationLayer({
46+
getSvgRoot: () => {
47+
return clone;
48+
},
49+
});
5450
const cloneRect = {
5551
'x': xy.x,
5652
'y': xy.y,

core/block_svg.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export class BlockSvg
208208
icon.updateEditable();
209209
}
210210
this.applyColour();
211-
this.pathObject.updateMovable(this.isMovable());
211+
this.pathObject.updateMovable(this.isMovable() || this.isInFlyout);
212212
const svg = this.getSvgRoot();
213213
if (!this.workspace.options.readOnly && svg) {
214214
browserEvents.conditionalBind(

core/bubbles/textinput_bubble.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export class TextInputBubble extends Bubble {
143143

144144
/** Binds events to the text area element. */
145145
private bindTextAreaEvents(textArea: HTMLTextAreaElement) {
146-
// Don't zoom with mousewheel.
146+
// Don't zoom with mousewheel; let it scroll instead.
147147
browserEvents.conditionalBind(textArea, 'wheel', this, (e: Event) => {
148148
e.stopPropagation();
149149
});
@@ -198,19 +198,12 @@ export class TextInputBubble extends Bubble {
198198
const heightMinusBorder = size.height - Bubble.DOUBLE_BORDER;
199199
this.inputRoot.setAttribute('width', `${widthMinusBorder}`);
200200
this.inputRoot.setAttribute('height', `${heightMinusBorder}`);
201-
this.textArea.style.width = `${widthMinusBorder - 4}px`;
202-
this.textArea.style.height = `${heightMinusBorder - 4}px`;
203201

202+
this.resizeGroup.setAttribute('y', `${heightMinusBorder}`);
204203
if (this.workspace.RTL) {
205-
this.resizeGroup.setAttribute(
206-
'transform',
207-
`translate(${Bubble.DOUBLE_BORDER}, ${heightMinusBorder}) scale(-1 1)`,
208-
);
204+
this.resizeGroup.setAttribute('x', `${-Bubble.DOUBLE_BORDER}`);
209205
} else {
210-
this.resizeGroup.setAttribute(
211-
'transform',
212-
`translate(${widthMinusBorder}, ${heightMinusBorder})`,
213-
);
206+
this.resizeGroup.setAttribute('x', `${widthMinusBorder}`);
214207
}
215208

216209
super.setSize(size, relayout);
@@ -310,11 +303,12 @@ Css.register(`
310303
.blocklyTextInputBubble .blocklyTextarea {
311304
background-color: var(--commentFillColour);
312305
border: 0;
306+
box-sizing: border-box;
313307
display: block;
314-
margin: 0;
315308
outline: 0;
316-
padding: 3px;
309+
padding: 5px;
317310
resize: none;
318-
text-overflow: hidden;
311+
width: 100%;
312+
height: 100%;
319313
}
320314
`);

core/clipboard/block_paster.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,21 @@ export class BlockPaster implements IPaster<BlockCopyData, BlockSvg> {
3030
copyData.blockState['y'] = coordinate.y;
3131
}
3232

33+
// After appending the block to the workspace, it will be bumped from its neighbors
34+
// However, the algorithm for deciding where to paste a block depends on
35+
// the starting position of the copied block, so we'll pass those coordinates along
36+
const initialCoordinates =
37+
coordinate ||
38+
new Coordinate(
39+
copyData.blockState['x'] || 0,
40+
copyData.blockState['y'] || 0,
41+
);
42+
3343
eventUtils.disable();
3444
let block;
3545
try {
3646
block = append(copyData.blockState, workspace) as BlockSvg;
37-
moveBlockToNotConflict(block);
47+
moveBlockToNotConflict(block, initialCoordinates);
3848
} finally {
3949
eventUtils.enable();
4050
}
@@ -56,12 +66,20 @@ export class BlockPaster implements IPaster<BlockCopyData, BlockSvg> {
5666
* Exported for testing.
5767
*
5868
* @param block The block to move to an unambiguous location.
69+
* @param originalPosition The initial coordinate to start searching from,
70+
* likely the position of the copied block.
5971
* @internal
6072
*/
61-
export function moveBlockToNotConflict(block: BlockSvg) {
73+
export function moveBlockToNotConflict(
74+
block: BlockSvg,
75+
originalPosition: Coordinate,
76+
) {
6277
const workspace = block.workspace;
6378
const snapRadius = config.snapRadius;
64-
const coord = block.getRelativeToSurfaceXY();
79+
const bumpOffset = Coordinate.difference(
80+
originalPosition,
81+
block.getRelativeToSurfaceXY(),
82+
);
6583
const offset = new Coordinate(0, 0);
6684
// getRelativeToSurfaceXY is really expensive, so we want to cache this.
6785
const otherCoords = workspace
@@ -70,8 +88,11 @@ export function moveBlockToNotConflict(block: BlockSvg) {
7088
.map((b) => b.getRelativeToSurfaceXY());
7189

7290
while (
73-
blockOverlapsOtherExactly(Coordinate.sum(coord, offset), otherCoords) ||
74-
blockIsInSnapRadius(block, offset, snapRadius)
91+
blockOverlapsOtherExactly(
92+
Coordinate.sum(originalPosition, offset),
93+
otherCoords,
94+
) ||
95+
blockIsInSnapRadius(block, Coordinate.sum(bumpOffset, offset), snapRadius)
7596
) {
7697
if (workspace.RTL) {
7798
offset.translate(-snapRadius, snapRadius * 2);
@@ -80,7 +101,7 @@ export function moveBlockToNotConflict(block: BlockSvg) {
80101
}
81102
}
82103

83-
block!.moveTo(Coordinate.sum(coord, offset));
104+
block!.moveTo(Coordinate.sum(originalPosition, offset));
84105
}
85106

86107
/**

core/comments/comment_view.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,12 @@ export class CommentView implements IRenderedElement {
286286
return this.svgRoot;
287287
}
288288

289-
/** Returns the current size of the comment in workspace units. */
289+
/**
290+
* Returns the current size of the comment in workspace units.
291+
* Respects collapsing.
292+
*/
290293
getSize(): Size {
291-
return this.size;
294+
return this.collapsed ? this.topBarBackground.getBBox() : this.size;
292295
}
293296

294297
/**
@@ -401,8 +404,6 @@ export class CommentView implements IRenderedElement {
401404
if (this.workspace.RTL) {
402405
this.foreignObject.setAttribute('x', `${-size.width}`);
403406
}
404-
this.textArea.style.width = `${size.width}px`;
405-
this.textArea.style.height = `${size.height}px`;
406407
}
407408

408409
/**
@@ -773,14 +774,13 @@ css.register(`
773774
.blocklyComment .blocklyTextarea {
774775
background-color: var(--commentFillColour);
775776
border: 1px solid var(--commentBorderColour);
777+
box-sizing: border-box;
778+
display: block;
776779
outline: 0;
780+
padding: 5px;
777781
resize: none;
778-
overflow: hidden;
779-
box-sizing: border-box;
780-
padding: 8px;
781782
width: 100%;
782783
height: 100%;
783-
display: block;
784784
}
785785
786786
.blocklyReadonly.blocklyComment .blocklyTextarea {
@@ -810,6 +810,7 @@ css.register(`
810810
}
811811
812812
.blocklyCommentTopbarBackground {
813+
cursor: grab;
813814
fill: var(--commentBorderColour);
814815
height: 24px;
815816
}

core/comments/rendered_workspace_comment.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ export class RenderedWorkspaceComment
6666
this,
6767
this.startGesture,
6868
);
69+
// Don't zoom with mousewheel; let it scroll instead.
70+
browserEvents.conditionalBind(
71+
this.view.getSvgRoot(),
72+
'wheel',
73+
this,
74+
(e: Event) => {
75+
e.stopPropagation();
76+
},
77+
);
6978
}
7079

7180
/**
@@ -120,11 +129,31 @@ export class RenderedWorkspaceComment
120129
return this.view.getSvgRoot();
121130
}
122131

123-
/** Returns the bounding rectangle of this comment in workspace coordinates. */
132+
/**
133+
* Returns the comment's size in workspace units.
134+
* Does not respect collapsing.
135+
*/
136+
getSize(): Size {
137+
return super.getSize();
138+
}
139+
140+
/**
141+
* Returns the bounding rectangle of this comment in workspace coordinates.
142+
* Respects collapsing.
143+
*/
124144
getBoundingRectangle(): Rect {
125145
const loc = this.getRelativeToSurfaceXY();
126-
const size = this.getSize();
127-
return new Rect(loc.y, loc.y + size.height, loc.x, loc.x + size.width);
146+
const size = this.view?.getSize() ?? this.getSize();
147+
let left;
148+
let right;
149+
if (this.workspace.RTL) {
150+
left = loc.x - size.width;
151+
right = loc.x;
152+
} else {
153+
left = loc.x;
154+
right = loc.x + size.width;
155+
}
156+
return new Rect(loc.y, loc.y + size.height, left, right);
128157
}
129158

130159
/** Move the comment by the given amounts in workspace coordinates. */
@@ -138,7 +167,6 @@ export class RenderedWorkspaceComment
138167
override moveTo(location: Coordinate, reason?: string[] | undefined): void {
139168
super.moveTo(location, reason);
140169
this.view.moveTo(location);
141-
this.snapToGrid();
142170
}
143171

144172
/**
@@ -209,7 +237,6 @@ export class RenderedWorkspaceComment
209237

210238
/** Ends the drag on the comment. */
211239
endDrag(): void {
212-
this.snapToGrid();
213240
this.dragStrategy.endDrag();
214241
}
215242

core/css.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ input[type=number] {
500500
margin-right: -24px;
501501
}
502502
503-
.blocklyBlockDragSurface {
503+
.blocklyBlockDragSurface, .blocklyAnimationLayer {
504504
position: absolute;
505505
top: 0;
506506
left: 0;

core/dragging/block_drag_strategy.ts

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,15 @@ export class BlockDragStrategy implements IDragStrategy {
5555

5656
private dragging = false;
5757

58-
/**
59-
* If this is a shadow block, the offset between this block and the parent
60-
* block, to add to the drag location. In workspace units.
61-
*/
62-
private dragOffset = new Coordinate(0, 0);
63-
6458
constructor(private block: BlockSvg) {
6559
this.workspace = block.workspace;
6660
}
6761

6862
/** Returns true if the block is currently movable. False otherwise. */
6963
isMovable(): boolean {
70-
if (this.block.isShadow()) {
71-
return this.block.getParent()?.isMovable() ?? false;
72-
}
73-
7464
return (
7565
this.block.isOwnMovable() &&
66+
!this.block.isShadow() &&
7667
!this.block.isDeadOrDying() &&
7768
!this.workspace.options.readOnly &&
7869
// We never drag blocks in the flyout, only create new blocks that are
@@ -86,11 +77,6 @@ export class BlockDragStrategy implements IDragStrategy {
8677
* from any parent blocks.
8778
*/
8879
startDrag(e?: PointerEvent): void {
89-
if (this.block.isShadow()) {
90-
this.startDraggingShadow(e);
91-
return;
92-
}
93-
9480
this.dragging = true;
9581
if (!eventUtils.getGroup()) {
9682
eventUtils.setGroup(true);
@@ -120,22 +106,6 @@ export class BlockDragStrategy implements IDragStrategy {
120106
this.workspace.getLayerManager()?.moveToDragLayer(this.block);
121107
}
122108

123-
/** Starts a drag on a shadow, recording the drag offset. */
124-
private startDraggingShadow(e?: PointerEvent) {
125-
const parent = this.block.getParent();
126-
if (!parent) {
127-
throw new Error(
128-
'Tried to drag a shadow block with no parent. ' +
129-
'Shadow blocks should always have parents.',
130-
);
131-
}
132-
this.dragOffset = Coordinate.difference(
133-
parent.getRelativeToSurfaceXY(),
134-
this.block.getRelativeToSurfaceXY(),
135-
);
136-
parent.startDrag(e);
137-
}
138-
139109
/**
140110
* Whether or not we should disconnect the block when a drag is started.
141111
*
@@ -204,11 +174,6 @@ export class BlockDragStrategy implements IDragStrategy {
204174

205175
/** Moves the block and updates any connection previews. */
206176
drag(newLoc: Coordinate): void {
207-
if (this.block.isShadow()) {
208-
this.block.getParent()?.drag(Coordinate.sum(newLoc, this.dragOffset));
209-
return;
210-
}
211-
212177
this.block.moveDuringDrag(newLoc);
213178
this.updateConnectionPreview(
214179
this.block,
@@ -352,12 +317,7 @@ export class BlockDragStrategy implements IDragStrategy {
352317
* Cleans up any state at the end of the drag. Applies any pending
353318
* connections.
354319
*/
355-
endDrag(e?: PointerEvent): void {
356-
if (this.block.isShadow()) {
357-
this.block.getParent()?.endDrag(e);
358-
return;
359-
}
360-
320+
endDrag(): void {
361321
this.fireDragEndEvent();
362322
this.fireMoveEvent();
363323

@@ -413,11 +373,6 @@ export class BlockDragStrategy implements IDragStrategy {
413373
* including reconnecting connections.
414374
*/
415375
revertDrag(): void {
416-
if (this.block.isShadow()) {
417-
this.block.getParent()?.revertDrag();
418-
return;
419-
}
420-
421376
this.startChildConn?.connect(this.block.nextConnection);
422377
if (this.startParentConn) {
423378
switch (this.startParentConn.type) {

0 commit comments

Comments
 (0)