mirror of
https://github.com/google/blockly.git
synced 2026-01-04 23:50:12 +01:00
chore: merge develop into v11
This commit is contained in:
@@ -20,6 +20,7 @@ import type {BlockDefinition} from '../core/blocks.js';
|
||||
export {
|
||||
colour,
|
||||
lists,
|
||||
logic,
|
||||
loops,
|
||||
math,
|
||||
procedures,
|
||||
@@ -40,6 +41,7 @@ export const blocks: {[key: string]: BlockDefinition} = Object.assign(
|
||||
loops.blocks,
|
||||
math.blocks,
|
||||
procedures.blocks,
|
||||
texts.blocks,
|
||||
variables.blocks,
|
||||
variablesDynamic.blocks,
|
||||
);
|
||||
|
||||
@@ -69,8 +69,18 @@ export class BlockDragger implements IBlockDragger {
|
||||
|
||||
/** Whether the block would be deleted if dropped immediately. */
|
||||
protected wouldDeleteBlock_ = false;
|
||||
|
||||
protected startXY_: Coordinate;
|
||||
|
||||
/** The parent block at the start of the drag. */
|
||||
private startParentConn: RenderedConnection | null = null;
|
||||
|
||||
/**
|
||||
* The child block at the start of the drag. Only gets set if
|
||||
* `healStack` is true.
|
||||
*/
|
||||
private startChildConn: RenderedConnection | null = null;
|
||||
|
||||
/**
|
||||
* @param block The block to drag.
|
||||
* @param workspace The workspace to drag on.
|
||||
@@ -126,6 +136,13 @@ export class BlockDragger implements IBlockDragger {
|
||||
blockAnimation.disconnectUiStop();
|
||||
|
||||
if (this.shouldDisconnect_(healStack)) {
|
||||
this.startParentConn =
|
||||
this.draggingBlock_.outputConnection?.targetConnection ??
|
||||
this.draggingBlock_.previousConnection?.targetConnection;
|
||||
if (healStack) {
|
||||
this.startChildConn =
|
||||
this.draggingBlock_.nextConnection?.targetConnection;
|
||||
}
|
||||
this.disconnectBlock_(healStack, currentDragDeltaXY);
|
||||
}
|
||||
this.draggingBlock_.setDragging(true);
|
||||
@@ -413,17 +430,10 @@ export class BlockDragger implements IBlockDragger {
|
||||
.getLayerManager()
|
||||
?.moveOffDragLayer(this.draggingBlock_, layers.BLOCK);
|
||||
this.draggingBlock_.setDragging(false);
|
||||
if (delta) {
|
||||
// !preventMove
|
||||
if (preventMove) {
|
||||
this.moveToOriginalPosition();
|
||||
} else if (delta) {
|
||||
this.updateBlockAfterMove_();
|
||||
} else {
|
||||
// Blocks dragged directly from a flyout may need to be bumped into
|
||||
// bounds.
|
||||
bumpObjects.bumpIntoBounds(
|
||||
this.draggingBlock_.workspace,
|
||||
this.workspace_.getMetricsManager().getScrollMetrics(true),
|
||||
this.draggingBlock_,
|
||||
);
|
||||
}
|
||||
}
|
||||
// Must dispose after `updateBlockAfterMove_` is called to not break the
|
||||
@@ -434,6 +444,32 @@ export class BlockDragger implements IBlockDragger {
|
||||
eventUtils.setGroup(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the dragged block back to its original position before the start of
|
||||
* the drag. Reconnects any parent and child blocks.
|
||||
*/
|
||||
private moveToOriginalPosition() {
|
||||
this.startChildConn?.connect(this.draggingBlock_.nextConnection);
|
||||
if (this.startParentConn) {
|
||||
switch (this.startParentConn.type) {
|
||||
case ConnectionType.INPUT_VALUE:
|
||||
this.startParentConn.connect(this.draggingBlock_.outputConnection);
|
||||
break;
|
||||
case ConnectionType.NEXT_STATEMENT:
|
||||
this.startParentConn.connect(this.draggingBlock_.previousConnection);
|
||||
}
|
||||
} else {
|
||||
this.draggingBlock_.moveTo(this.startXY_, ['drag']);
|
||||
// Blocks dragged directly from a flyout may need to be bumped into
|
||||
// bounds.
|
||||
bumpObjects.bumpIntoBounds(
|
||||
this.draggingBlock_.workspace,
|
||||
this.workspace_.getMetricsManager().getScrollMetrics(true),
|
||||
this.draggingBlock_,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the drag delta and new location values after a block is dragged.
|
||||
*
|
||||
|
||||
@@ -282,7 +282,9 @@ export function defineBlocks(blocks: {[key: string]: BlockDefinition}) {
|
||||
for (const type of Object.keys(blocks)) {
|
||||
const definition = blocks[type];
|
||||
if (type in Blocks) {
|
||||
console.warn(`Block definiton "${type}" overwrites previous definition.`);
|
||||
console.warn(
|
||||
`Block definition "${type}" overwrites previous definition.`,
|
||||
);
|
||||
}
|
||||
Blocks[type] = definition;
|
||||
}
|
||||
|
||||
27
core/grid.ts
27
core/grid.ts
@@ -66,12 +66,26 @@ export class Grid {
|
||||
this.update(this.scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the spacing of the grid points (in px).
|
||||
*
|
||||
* @returns The spacing of the grid points.
|
||||
*/
|
||||
getSpacing(): number {
|
||||
return this.spacing;
|
||||
}
|
||||
|
||||
/** Sets the length of the grid lines. */
|
||||
setLength(length: number) {
|
||||
this.length = length;
|
||||
this.update(this.scale);
|
||||
}
|
||||
|
||||
/** Get the length of the grid lines (in px). */
|
||||
getLength(): number {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether blocks should snap to the grid or not.
|
||||
*
|
||||
@@ -85,25 +99,14 @@ export class Grid {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether blocks should snap to the grid, based on the initial configuration.
|
||||
* Whether blocks should snap to the grid.
|
||||
*
|
||||
* @returns True if blocks should snap, false otherwise.
|
||||
* @internal
|
||||
*/
|
||||
shouldSnap(): boolean {
|
||||
return this.snapToGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the spacing of the grid points (in px).
|
||||
*
|
||||
* @returns The spacing of the grid points.
|
||||
* @internal
|
||||
*/
|
||||
getSpacing(): number {
|
||||
return this.spacing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the pattern element, which should be randomized to avoid
|
||||
* conflicts with other Blockly instances on the page.
|
||||
|
||||
@@ -12,6 +12,8 @@ import * as blocks from './serialization/blocks.js';
|
||||
import * as eventUtils from './events/utils.js';
|
||||
import * as renderManagement from './render_management.js';
|
||||
import * as registry from './registry.js';
|
||||
import {Renderer as ZelosRenderer} from './renderers/zelos/renderer.js';
|
||||
import {ConnectionType} from './connection_type.js';
|
||||
|
||||
/**
|
||||
* An error message to throw if the block created by createMarkerBlock_ is
|
||||
@@ -97,34 +99,18 @@ export class InsertionMarkerPreviewer implements IConnectionPreviewer {
|
||||
throw Error(DUPLICATE_BLOCK_ERROR);
|
||||
}
|
||||
|
||||
// Render disconnected from everything else so that we have a valid
|
||||
// connection location.
|
||||
marker.queueRender();
|
||||
renderManagement.triggerQueuedRenders();
|
||||
|
||||
// Connect() also renders the insertion marker.
|
||||
markerConn.connect(staticConn);
|
||||
|
||||
const originalOffsetToTarget = {
|
||||
x: staticConn.x - markerConn.x,
|
||||
y: staticConn.y - markerConn.y,
|
||||
};
|
||||
const originalOffsetInBlock = markerConn.getOffsetInBlock().clone();
|
||||
renderManagement.finishQueuedRenders().then(() => {
|
||||
// Position so that the existing block doesn't move.
|
||||
marker?.positionNearConnection(
|
||||
markerConn,
|
||||
originalOffsetToTarget,
|
||||
originalOffsetInBlock,
|
||||
);
|
||||
marker?.getSvgRoot().setAttribute('visibility', 'visible');
|
||||
});
|
||||
// TODO(7898): Instead of special casing, we should change the dragger to
|
||||
// track the change in distance between the dragged connection and the
|
||||
// static connection, so that it doesn't disconnect unless that
|
||||
// (+ a bit) has been exceeded.
|
||||
if (this.shouldUseMarkerPreview(draggedConn, staticConn)) {
|
||||
this.markerConn = this.previewMarker(draggedConn, staticConn);
|
||||
}
|
||||
|
||||
if (this.workspace.getRenderer().shouldHighlightConnection(staticConn)) {
|
||||
staticConn.highlight();
|
||||
}
|
||||
|
||||
this.markerConn = markerConn;
|
||||
this.draggedConn = draggedConn;
|
||||
this.staticConn = staticConn;
|
||||
} finally {
|
||||
@@ -132,6 +118,53 @@ export class InsertionMarkerPreviewer implements IConnectionPreviewer {
|
||||
}
|
||||
}
|
||||
|
||||
private shouldUseMarkerPreview(
|
||||
_draggedConn: RenderedConnection,
|
||||
staticConn: RenderedConnection,
|
||||
): boolean {
|
||||
return (
|
||||
staticConn.type === ConnectionType.PREVIOUS_STATEMENT ||
|
||||
staticConn.type === ConnectionType.NEXT_STATEMENT ||
|
||||
!(this.workspace.getRenderer() instanceof ZelosRenderer)
|
||||
);
|
||||
}
|
||||
|
||||
private previewMarker(
|
||||
draggedConn: RenderedConnection,
|
||||
staticConn: RenderedConnection,
|
||||
): RenderedConnection {
|
||||
const dragged = draggedConn.getSourceBlock();
|
||||
const marker = this.createInsertionMarker(dragged);
|
||||
const markerConn = this.getMatchingConnection(dragged, marker, draggedConn);
|
||||
if (!markerConn) {
|
||||
throw Error('Could not create insertion marker to preview connection');
|
||||
}
|
||||
|
||||
// Render disconnected from everything else so that we have a valid
|
||||
// connection location.
|
||||
marker.queueRender();
|
||||
renderManagement.triggerQueuedRenders();
|
||||
|
||||
// Connect() also renders the insertion marker.
|
||||
markerConn.connect(staticConn);
|
||||
|
||||
const originalOffsetToTarget = {
|
||||
x: staticConn.x - markerConn.x,
|
||||
y: staticConn.y - markerConn.y,
|
||||
};
|
||||
const originalOffsetInBlock = markerConn.getOffsetInBlock().clone();
|
||||
renderManagement.finishQueuedRenders().then(() => {
|
||||
// Position so that the existing block doesn't move.
|
||||
marker?.positionNearConnection(
|
||||
markerConn,
|
||||
originalOffsetToTarget,
|
||||
originalOffsetInBlock,
|
||||
);
|
||||
marker?.getSvgRoot().setAttribute('visibility', 'visible');
|
||||
});
|
||||
return markerConn;
|
||||
}
|
||||
|
||||
private createInsertionMarker(origBlock: BlockSvg) {
|
||||
const blockJson = blocks.save(origBlock, {
|
||||
addCoordinates: false,
|
||||
|
||||
32
package-lock.json
generated
32
package-lock.json
generated
@@ -236,9 +236,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz",
|
||||
"integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
|
||||
"version": "8.57.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
|
||||
"integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -351,13 +351,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.13",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
|
||||
"integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^2.0.1",
|
||||
"debug": "^4.1.1",
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -378,9 +378,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
|
||||
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@hyperjump/json-pointer": {
|
||||
@@ -3951,16 +3951,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
|
||||
"integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
|
||||
"version": "8.57.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
|
||||
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.4",
|
||||
"@eslint/js": "8.56.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@eslint/js": "8.57.0",
|
||||
"@humanwhocodes/config-array": "^0.11.14",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
|
||||
Reference in New Issue
Block a user