Skip to content

Commit

Permalink
feat!: use new connection previewer in block-dynamic-connection (#2204)
Browse files Browse the repository at this point in the history
* fix: change the block-dynamic-connections plugin to use a connection previewer instead of monkey patching (#2190)

* feat: add pass through previewer

* fix: don't remove valid connections on saveExtraState

* fix: have connection previewer handle pending connections

* fix: have onPendingConnection ignore insertion markers

* chore: delete insertion marker monkey patch

* fixup

* chore: bump versions

* chore: fixup naming and docs

* chore: format

* chore: fix build

* chore: fixup type

* feat: make BasePreviewerConstructor optional

* chore: fix readme

* chore: PR nits

* feat!: update block-dynamic-connection to use blockly v10.4.1

---------

Co-authored-by: Beka Westberg <[email protected]>
  • Loading branch information
maribethb and BeksOmega authored Feb 16, 2024
1 parent 7954a8f commit fb17b94
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 116 deletions.
12 changes: 12 additions & 0 deletions plugins/block-dynamic-connection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ npm install @blockly/block-dynamic-connection --save
```js
import * as Blockly from 'blockly';
import * as BlockDynamicConnection from '@blockly/block-dynamic-connection';

const ws = Blockly.inject({
// options...
plugins: {
connectionPreviewer:
BlockDynamicConnection.decoratePreviewerWithDynamicConnections(
// Replace with a custom connection previewer, or remove to decorate
// the default one.
Blockly.InsertionMarkerPreviewer,
),
},
};
```
## API
Expand Down
16 changes: 8 additions & 8 deletions plugins/block-dynamic-connection/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions plugins/block-dynamic-connection/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@
"devDependencies": {
"@blockly/dev-scripts": "^3.1.1",
"@blockly/dev-tools": "^7.1.6",
"blockly": "^10.2.0",
"blockly": "^10.4.1",
"chai": "^4.2.0",
"mocha": "^10.2.0",
"typescript": "^5.2.2"
},
"peerDependencies": {
"blockly": "^10.2.0"
"blockly": "^10.4.1"
},
"publishConfig": {
"access": "public",
Expand Down
96 changes: 96 additions & 0 deletions plugins/block-dynamic-connection/src/connection_previewer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from 'blockly/core';

interface ConnectionPreviewerConstructor {
new (draggedBlock: Blockly.BlockSvg): Blockly.IConnectionPreviewer;
}

interface DynamicBlock extends Blockly.BlockSvg {
onPendingConnection(connection: Blockly.RenderedConnection): void;
finalizeConnections(): void;
}

function blockIsDynamic(block: Blockly.BlockSvg): block is DynamicBlock {
return (
(block as DynamicBlock)['onPendingConnection'] !== undefined &&
(block as DynamicBlock)['finalizeConnections'] !== undefined
);
}

/**
* Returns a connection previewer constructor that decorates the passed
* constructor to add connection previewing.
*
* @param BasePreviewerConstructor The constructor for the base connection
* previewer class being decorated. If not provided, the default
* InsertionMarkerPreviewer will be used.
* @return A decorated connection previewer constructor.
*/
export function decoratePreviewer(
BasePreviewerConstructor?: ConnectionPreviewerConstructor,
): ConnectionPreviewerConstructor {
return class implements Blockly.IConnectionPreviewer {
private basePreviewer: Blockly.IConnectionPreviewer;

private pendingBlocks: Set<DynamicBlock> = new Set();

constructor(draggedBlock: Blockly.BlockSvg) {
const BaseConstructor =
BasePreviewerConstructor ?? Blockly.InsertionMarkerPreviewer;
this.basePreviewer = new BaseConstructor(draggedBlock);
}

previewReplacement(
draggedConn: Blockly.RenderedConnection,
staticConn: Blockly.RenderedConnection,
replacedBlock: Blockly.BlockSvg,
): void {
this.previewDynamism(staticConn);
this.basePreviewer.previewReplacement(
draggedConn,
staticConn,
replacedBlock,
);
}

previewConnection(
draggedConn: Blockly.RenderedConnection,
staticConn: Blockly.RenderedConnection,
): void {
this.previewDynamism(staticConn);
this.basePreviewer.previewConnection(draggedConn, staticConn);
}

hidePreview(): void {
this.basePreviewer.hidePreview();
}

dispose(): void {
for (const block of this.pendingBlocks) {
if (block.isDeadOrDying()) return;
block.finalizeConnections();
}
this.pendingBlocks.clear();
this.basePreviewer.dispose();
}

/**
* If the block is a dynamic block, calls onPendingConnection and
* stores the block to be finalized later.
*
* @param conn The block to trigger onPendingConnection on.
*/
private previewDynamism(conn: Blockly.RenderedConnection) {
const block = conn.getSourceBlock();
if (blockIsDynamic(block)) {
block.onPendingConnection(conn);
this.pendingBlocks.add(block);
}
}
};
}
35 changes: 28 additions & 7 deletions plugins/block-dynamic-connection/src/dynamic_if.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,14 @@ const DYNAMIC_IF_MIXIN = {
* @returns The state of this block, ie the else if count and else state.
*/
saveExtraState: function (this: DynamicIfBlock): IfExtraState | null {
// If we call finalizeConnections here without disabling events, we get into
// an event loop.
Blockly.Events.disable();
this.finalizeConnections();
if (this instanceof Blockly.BlockSvg) this.initSvg();
Blockly.Events.enable();
if (!this.isCorrectlyFormatted()) {
// If we call finalizeConnections here without disabling events, we get into
// an event loop.
Blockly.Events.disable();
this.finalizeConnections();
if (this instanceof Blockly.BlockSvg) this.initSvg();
Blockly.Events.enable();
}

if (!this.elseifCount && !this.elseCount) {
return null;
Expand Down Expand Up @@ -218,6 +220,13 @@ const DYNAMIC_IF_MIXIN = {
this: DynamicIfBlock,
connection: Blockly.Connection,
): number | null {
if (
!connection.targetConnection ||
connection.targetBlock()?.isInsertionMarker()
) {
// This connection is available.
return null;
}
for (let i = 0; i < this.inputList.length; i++) {
const input = this.inputList[i];
if (input.connection == connection) {
Expand Down Expand Up @@ -270,7 +279,7 @@ const DYNAMIC_IF_MIXIN = {
return;
}
const input = this.inputList[inputIndex];
if (connection.targetConnection && input.name.includes('IF')) {
if (input.name.includes('IF')) {
const nextIfInput = this.inputList[inputIndex + 2];
if (!nextIfInput || nextIfInput.name == 'ELSE') {
this.insertElseIf(inputIndex + 2, Blockly.utils.idGenerator.genUid());
Expand Down Expand Up @@ -381,6 +390,18 @@ const DYNAMIC_IF_MIXIN = {
Blockly.Msg['CONTROLS_IF_MSG_THEN'],
);
},

/**
* Returns true if all of the inputs on this block are in order.
* False otherwise.
*/
isCorrectlyFormatted(this: DynamicIfBlock): boolean {
for (let i = 0; i < this.inputList.length - 1; i += 2) {
if (this.inputList[i].name !== `IF${i}`) return false;
if (this.inputList[i + 1].name !== `DO${i}`) return false;
}
return true;
},
};

Blockly.Blocks['dynamic_if'] = DYNAMIC_IF_MIXIN;
36 changes: 26 additions & 10 deletions plugins/block-dynamic-connection/src/dynamic_list_create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,14 @@ const DYNAMIC_LIST_CREATE_MIXIN = {
* @returns The state of this block, ie the item count.
*/
saveExtraState: function (this: DynamicListCreateBlock): {itemCount: number} {
// If we call finalizeConnections here without disabling events, we get into
// an event loop.
Blockly.Events.disable();
this.finalizeConnections();
if (this instanceof Blockly.BlockSvg) this.initSvg();
Blockly.Events.enable();
if (!this.isCorrectlyFormatted()) {
// If we call finalizeConnections here without disabling events, we get
// into an event loop.
Blockly.Events.disable();
this.finalizeConnections();
if (this instanceof Blockly.BlockSvg) this.initSvg();
Blockly.Events.enable();
}

return {
itemCount: this.itemCount,
Expand Down Expand Up @@ -156,8 +158,11 @@ const DYNAMIC_LIST_CREATE_MIXIN = {
this: DynamicListCreateBlock,
connection: Blockly.Connection,
): number | null {
if (!connection.targetConnection) {
// this connection is available
if (
!connection.targetConnection ||
connection.targetBlock()?.isInsertionMarker()
) {
// This connection is available.
return null;
}

Expand All @@ -169,7 +174,7 @@ const DYNAMIC_LIST_CREATE_MIXIN = {
}

if (connectionIndex == this.inputList.length - 1) {
// this connection is the last one and already has a block in it, so
// This connection is the last one and already has a block in it, so
// we should add a new connection at the end.
return this.inputList.length + 1;
}
Expand All @@ -183,7 +188,7 @@ const DYNAMIC_LIST_CREATE_MIXIN = {
return connectionIndex + 1;
}

// Don't add new connection
// Don't add new connection.
return null;
},

Expand Down Expand Up @@ -281,6 +286,17 @@ const DYNAMIC_LIST_CREATE_MIXIN = {
Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH'],
);
},

/**
* Returns true if all of the inputs on this block are in order.
* False otherwise.
*/
isCorrectlyFormatted(this: DynamicListCreateBlock): boolean {
for (let i = 0; i < this.inputList.length; i++) {
if (this.inputList[i].name !== `ADD${i}`) return false;
}
return true;
},
};

Blockly.Blocks['dynamic_list_create'] = DYNAMIC_LIST_CREATE_MIXIN;
36 changes: 26 additions & 10 deletions plugins/block-dynamic-connection/src/dynamic_text_join.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,14 @@ const DYNAMIC_TEXT_JOIN_MIXIN = {
* @returns The state of this block, ie the item count.
*/
saveExtraState: function (this: DynamicTextJoinBlock): {itemCount: number} {
// If we call finalizeConnections here without disabling events, we get into
// an event loop.
Blockly.Events.disable();
this.finalizeConnections();
if (this instanceof Blockly.BlockSvg) this.initSvg();
Blockly.Events.enable();
if (!this.isCorrectlyFormatted()) {
// If we call finalizeConnections here without disabling events, we get into
// an event loop.
Blockly.Events.disable();
this.finalizeConnections();
if (this instanceof Blockly.BlockSvg) this.initSvg();
Blockly.Events.enable();
}

return {
itemCount: this.itemCount,
Expand Down Expand Up @@ -152,8 +154,11 @@ const DYNAMIC_TEXT_JOIN_MIXIN = {
this: DynamicTextJoinBlock,
connection: Blockly.Connection,
): number | null {
if (!connection.targetConnection) {
// this connection is available
if (
!connection.targetConnection ||
connection.targetBlock()?.isInsertionMarker()
) {
// This connection is available.
return null;
}

Expand All @@ -165,7 +170,7 @@ const DYNAMIC_TEXT_JOIN_MIXIN = {
}

if (connectionIndex == this.inputList.length - 1) {
// this connection is the last one and already has a block in it, so
// This connection is the last one and already has a block in it, so
// we should add a new connection at the end.
return this.inputList.length + 1;
}
Expand All @@ -179,7 +184,7 @@ const DYNAMIC_TEXT_JOIN_MIXIN = {
return connectionIndex + 1;
}

// Don't add new connection
// Don't add new connection.
return null;
},

Expand Down Expand Up @@ -278,6 +283,17 @@ const DYNAMIC_TEXT_JOIN_MIXIN = {
Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH'],
);
},

/**
* Returns true if all of the inputs on this block are in order.
* False otherwise.
*/
isCorrectlyFormatted(this: DynamicTextJoinBlock): boolean {
for (let i = 0; i < this.inputList.length; i++) {
if (this.inputList[i].name !== `ADD${i}`) return false;
}
return true;
},
};

Blockly.Blocks['dynamic_text_join'] = DYNAMIC_TEXT_JOIN_MIXIN;
4 changes: 3 additions & 1 deletion plugins/block-dynamic-connection/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
*/

import * as Blockly from 'blockly/core';
import './insertion_marker_manager_monkey_patch';
import './dynamic_if';
import './dynamic_text_join';
import './dynamic_list_create';
import {decoratePreviewer} from './connection_previewer';

export {decoratePreviewer};

export const overrideOldBlockDefinitions = function (): void {
Blockly.Blocks['lists_create_with'] = Blockly.Blocks['dynamic_list_create'];
Expand Down
Loading

0 comments on commit fb17b94

Please sign in to comment.