Skip to content

Commit

Permalink
release: v11.1.0
Browse files Browse the repository at this point in the history
Merge pull request #8185 from google/rc/v11.1.0
  • Loading branch information
BeksOmega authored May 30, 2024
2 parents 9519333 + 4f596aa commit e03d526
Show file tree
Hide file tree
Showing 22 changed files with 247 additions and 95 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto
11 changes: 0 additions & 11 deletions core/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,17 +675,6 @@ export class Block implements IASTNodeLocation {
return block;
}

/**
* Returns this block if it is a shadow block, or the first non-shadow parent.
*
* @internal
*/
getFirstNonShadowBlock(): this {
if (!this.isShadow()) return this;
// We can assert the parent is non-null because shadows must have parents.
return this.getParent()!.getFirstNonShadowBlock();
}

/**
* Find all the blocks that are directly nested inside this one.
* Includes value and statement inputs, as well as any following statement.
Expand Down
2 changes: 1 addition & 1 deletion core/block_svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ export class BlockSvg
const menuOptions = this.generateContextMenu();

if (menuOptions && menuOptions.length) {
ContextMenu.show(e, menuOptions, this.RTL);
ContextMenu.show(e, menuOptions, this.RTL, this.workspace);
ContextMenu.setCurrentBlock(this);
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/comments/rendered_workspace_comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ export class RenderedWorkspaceComment
ContextMenuRegistry.ScopeType.COMMENT,
{comment: this},
);
contextMenu.show(e, menuOptions, this.workspace.RTL);
contextMenu.show(e, menuOptions, this.workspace.RTL, this.workspace);
}

/** Snap this comment to the nearest grid point. */
Expand Down
5 changes: 4 additions & 1 deletion core/contextmenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {Rect} from './utils/rect.js';
import * as serializationBlocks from './serialization/blocks.js';
import * as svgMath from './utils/svg_math.js';
import * as WidgetDiv from './widgetdiv.js';
import type {WorkspaceSvg} from './workspace_svg.js';
import * as Xml from './xml.js';
import * as common from './common.js';

Expand Down Expand Up @@ -62,13 +63,15 @@ let menu_: Menu | null = null;
* @param e Mouse event.
* @param options Array of menu options.
* @param rtl True if RTL, false if LTR.
* @param workspace The workspace associated with the context menu, if any.
*/
export function show(
e: PointerEvent,
options: (ContextMenuOption | LegacyContextMenuOption)[],
rtl: boolean,
workspace?: WorkspaceSvg,
) {
WidgetDiv.show(dummyOwner, rtl, dispose);
WidgetDiv.show(dummyOwner, rtl, dispose, workspace);
if (!options.length) {
hide();
return;
Expand Down
1 change: 1 addition & 0 deletions core/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ let content = `
.blocklyMinimalBody {
margin: 0;
padding: 0;
height: 100%;
}
.blocklyHtmlInput {
Expand Down
49 changes: 47 additions & 2 deletions core/dragging/block_drag_strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,24 @@ export class BlockDragStrategy implements IDragStrategy {

private dragging = false;

/**
* If this is a shadow block, the offset between this block and the parent
* block, to add to the drag location. In workspace units.
*/
private dragOffset = new Coordinate(0, 0);

constructor(private block: BlockSvg) {
this.workspace = block.workspace;
}

/** Returns true if the block is currently movable. False otherwise. */
isMovable(): boolean {
if (this.block.isShadow()) {
return this.block.getParent()?.isMovable() ?? false;
}

return (
this.block.isOwnMovable() &&
!this.block.isShadow() &&
!this.block.isDeadOrDying() &&
!this.workspace.options.readOnly &&
// We never drag blocks in the flyout, only create new blocks that are
Expand All @@ -77,6 +86,11 @@ export class BlockDragStrategy implements IDragStrategy {
* from any parent blocks.
*/
startDrag(e?: PointerEvent): void {
if (this.block.isShadow()) {
this.startDraggingShadow(e);
return;
}

this.dragging = true;
if (!eventUtils.getGroup()) {
eventUtils.setGroup(true);
Expand Down Expand Up @@ -106,6 +120,22 @@ export class BlockDragStrategy implements IDragStrategy {
this.workspace.getLayerManager()?.moveToDragLayer(this.block);
}

/** Starts a drag on a shadow, recording the drag offset. */
private startDraggingShadow(e?: PointerEvent) {
const parent = this.block.getParent();
if (!parent) {
throw new Error(
'Tried to drag a shadow block with no parent. ' +
'Shadow blocks should always have parents.',
);
}
this.dragOffset = Coordinate.difference(
parent.getRelativeToSurfaceXY(),
this.block.getRelativeToSurfaceXY(),
);
parent.startDrag(e);
}

/**
* Whether or not we should disconnect the block when a drag is started.
*
Expand Down Expand Up @@ -174,6 +204,11 @@ export class BlockDragStrategy implements IDragStrategy {

/** Moves the block and updates any connection previews. */
drag(newLoc: Coordinate): void {
if (this.block.isShadow()) {
this.block.getParent()?.drag(Coordinate.sum(newLoc, this.dragOffset));
return;
}

this.block.moveDuringDrag(newLoc);
this.updateConnectionPreview(
this.block,
Expand Down Expand Up @@ -317,7 +352,12 @@ export class BlockDragStrategy implements IDragStrategy {
* Cleans up any state at the end of the drag. Applies any pending
* connections.
*/
endDrag(): void {
endDrag(e?: PointerEvent): void {
if (this.block.isShadow()) {
this.block.getParent()?.endDrag(e);
return;
}

this.fireDragEndEvent();
this.fireMoveEvent();

Expand Down Expand Up @@ -373,6 +413,11 @@ export class BlockDragStrategy implements IDragStrategy {
* including reconnecting connections.
*/
revertDrag(): void {
if (this.block.isShadow()) {
this.block.getParent()?.revertDrag();
return;
}

this.startChildConn?.connect(this.block.nextConnection);
if (this.startParentConn) {
switch (this.startParentConn.type) {
Expand Down
44 changes: 25 additions & 19 deletions core/dragging/dragger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,25 @@ export class Dragger implements IDragger {
*/
onDrag(e: PointerEvent, totalDelta: Coordinate) {
this.moveDraggable(e, totalDelta);
const root = this.getRoot(this.draggable);

// Must check `wouldDelete` before calling other hooks on drag targets
// since we have documented that we would do so.
if (isDeletable(this.draggable)) {
this.draggable.setDeleteStyle(
this.wouldDeleteDraggable(e, this.draggable),
);
if (isDeletable(root)) {
root.setDeleteStyle(this.wouldDeleteDraggable(e, root));
}
this.updateDragTarget(e);
}

/** Updates the drag target under the pointer (if there is one). */
protected updateDragTarget(e: PointerEvent) {
const newDragTarget = this.workspace.getDragTarget(e);
const root = this.getRoot(this.draggable);
if (this.dragTarget !== newDragTarget) {
this.dragTarget?.onDragExit(this.draggable);
newDragTarget?.onDragEnter(this.draggable);
this.dragTarget?.onDragExit(root);
newDragTarget?.onDragEnter(root);
}
newDragTarget?.onDragOver(this.draggable);
newDragTarget?.onDragOver(root);
this.dragTarget = newDragTarget;
}

Expand All @@ -80,7 +80,7 @@ export class Dragger implements IDragger {
*/
protected wouldDeleteDraggable(
e: PointerEvent,
draggable: IDraggable & IDeletable,
rootDraggable: IDraggable & IDeletable,
) {
const dragTarget = this.workspace.getDragTarget(e);
if (!dragTarget) return false;
Expand All @@ -92,50 +92,56 @@ export class Dragger implements IDragger {
);
if (!isDeleteArea) return false;

return (dragTarget as IDeleteArea).wouldDelete(draggable);
return (dragTarget as IDeleteArea).wouldDelete(rootDraggable);
}

/** Handles any drag cleanup. */
onDragEnd(e: PointerEvent) {
const origGroup = eventUtils.getGroup();
const dragTarget = this.workspace.getDragTarget(e);
const root = this.getRoot(this.draggable);

if (dragTarget) {
this.dragTarget?.onDrop(this.draggable);
this.dragTarget?.onDrop(root);
}

if (this.shouldReturnToStart(e, this.draggable)) {
if (this.shouldReturnToStart(e, root)) {
this.draggable.revertDrag();
}

const wouldDelete =
isDeletable(this.draggable) &&
this.wouldDeleteDraggable(e, this.draggable);
const wouldDelete = isDeletable(root) && this.wouldDeleteDraggable(e, root);

// TODO(#8148): use a generalized API instead of an instanceof check.
if (wouldDelete && this.draggable instanceof BlockSvg) {
blockAnimations.disposeUiEffect(this.draggable);
blockAnimations.disposeUiEffect(this.draggable.getRootBlock());
}

this.draggable.endDrag(e);

if (wouldDelete && isDeletable(this.draggable)) {
if (wouldDelete && isDeletable(root)) {
// We want to make sure the delete gets grouped with any possible
// move event.
const newGroup = eventUtils.getGroup();
eventUtils.setGroup(origGroup);
this.draggable.dispose();
root.dispose();
eventUtils.setGroup(newGroup);
}
}

// We need to special case blocks for now so that we look at the root block
// instead of the one actually being dragged in most cases.
private getRoot(draggable: IDraggable): IDraggable {
return draggable instanceof BlockSvg ? draggable.getRootBlock() : draggable;
}

/**
* Returns true if we should return the draggable to its original location
* at the end of the drag.
*/
protected shouldReturnToStart(e: PointerEvent, draggable: IDraggable) {
protected shouldReturnToStart(e: PointerEvent, rootDraggable: IDraggable) {
const dragTarget = this.workspace.getDragTarget(e);
if (!dragTarget) return false;
return dragTarget.shouldPreventMove(draggable);
return dragTarget.shouldPreventMove(rootDraggable);
}

protected pixelsToWorkspaceUnits(pixelCoord: Coordinate): Coordinate {
Expand Down
15 changes: 10 additions & 5 deletions core/field_input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,12 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
if (!block) {
throw new UnattachedFieldError();
}
WidgetDiv.show(this, block.RTL, this.widgetDispose_.bind(this));
WidgetDiv.show(
this,
block.RTL,
this.widgetDispose_.bind(this),
this.workspace_,
);
this.htmlInput_ = this.widgetCreate_() as HTMLInputElement;
this.isBeingEdited_ = true;
this.valueWhenEditorWasOpened_ = this.value_;
Expand All @@ -390,7 +395,7 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
*
* @returns The newly created text input editor.
*/
protected widgetCreate_(): HTMLElement {
protected widgetCreate_(): HTMLInputElement | HTMLTextAreaElement {
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
Expand Down Expand Up @@ -546,17 +551,17 @@ export abstract class FieldInput<T extends InputTypes> extends Field<
*/
protected onHtmlInputKeyDown_(e: KeyboardEvent) {
if (e.key === 'Enter') {
WidgetDiv.hide();
WidgetDiv.hideIfOwner(this);
dropDownDiv.hideWithoutAnimation();
} else if (e.key === 'Escape') {
this.setValue(
this.htmlInput_!.getAttribute('data-untyped-default-value'),
false,
);
WidgetDiv.hide();
WidgetDiv.hideIfOwner(this);
dropDownDiv.hideWithoutAnimation();
} else if (e.key === 'Tab') {
WidgetDiv.hide();
WidgetDiv.hideIfOwner(this);
dropDownDiv.hideWithoutAnimation();
(this.sourceBlock_ as BlockSvg).tab(this, !e.shiftKey);
e.preventDefault();
Expand Down
9 changes: 9 additions & 0 deletions core/flyout_base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,15 @@ export abstract class Flyout
this.hide();
}

/**
* Get the target workspace inside the flyout.
*
* @returns The target workspace inside the flyout.
*/
getTargetWorkspace(): WorkspaceSvg {
return this.targetWorkspace;
}

/**
* Is the flyout visible?
*
Expand Down
Loading

0 comments on commit e03d526

Please sign in to comment.