From 6dbb38f84d109fbd4caef748da271979e5363bc9 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Jan 2024 20:16:58 +0000 Subject: [PATCH 01/14] feat: add pass through previewer --- .../src/connection_previewer.ts | 51 +++++++++++++++++++ plugins/block-dynamic-connection/src/index.ts | 3 ++ .../block-dynamic-connection/test/index.ts | 5 ++ 3 files changed, 59 insertions(+) create mode 100644 plugins/block-dynamic-connection/src/connection_previewer.ts diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts new file mode 100644 index 0000000000..9d6f30d868 --- /dev/null +++ b/plugins/block-dynamic-connection/src/connection_previewer.ts @@ -0,0 +1,51 @@ +/** + * @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; +} + +export function DynamicConnectionPreviewer( + // TODO: Make this optional before merging. + basePreviewerConstructor: ConnectionPreviewerConstructor, +): ConnectionPreviewerConstructor { + return class implements Blockly.IConnectionPreviewer { + private basePreviewer: Blockly.IConnectionPreviewer; + + constructor(draggedBlock: Blockly.BlockSvg) { + this.basePreviewer = new basePreviewerConstructor(draggedBlock); + } + + previewReplacement( + draggedConn: Blockly.RenderedConnection, + staticConn: Blockly.RenderedConnection, + replacedBlock: Blockly.BlockSvg, + ): void { + this.basePreviewer.previewReplacement( + draggedConn, + staticConn, + replacedBlock, + ); + } + + previewConnection( + draggedConn: Blockly.RenderedConnection, + staticConn: Blockly.RenderedConnection, + ): void { + this.basePreviewer.previewConnection(draggedConn, staticConn); + } + + hidePreview(): void { + this.basePreviewer.hidePreview(); + } + + dispose(): void { + this.basePreviewer.dispose(); + } + }; +} diff --git a/plugins/block-dynamic-connection/src/index.ts b/plugins/block-dynamic-connection/src/index.ts index 7c1c1733f6..08db9f98b4 100644 --- a/plugins/block-dynamic-connection/src/index.ts +++ b/plugins/block-dynamic-connection/src/index.ts @@ -14,6 +14,9 @@ import './insertion_marker_manager_monkey_patch'; import './dynamic_if'; import './dynamic_text_join'; import './dynamic_list_create'; +import {DynamicConnectionPreviewer} from './connection_previewer'; + +export {DynamicConnectionPreviewer}; export const overrideOldBlockDefinitions = function (): void { Blockly.Blocks['lists_create_with'] = Blockly.Blocks['dynamic_list_create']; diff --git a/plugins/block-dynamic-connection/test/index.ts b/plugins/block-dynamic-connection/test/index.ts index 006c6aa61b..dbad6e1b2d 100644 --- a/plugins/block-dynamic-connection/test/index.ts +++ b/plugins/block-dynamic-connection/test/index.ts @@ -85,6 +85,11 @@ document.addEventListener('DOMContentLoaded', function () { const defaultOptions: Blockly.BlocklyOptions = { toolbox, + plugins: { + connectionPreviewer: BlockDynamicConnection.DynamicConnectionPreviewer( + Blockly.InsertionMarkerPreviewer, + ), + }, }; const rootElement = document.getElementById('root'); if (rootElement) { From e40ba41eaf88824a426f41235d2c25e65b068d9d Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Jan 2024 20:17:35 +0000 Subject: [PATCH 02/14] fix: don't remove valid connections on saveExtraState --- .../src/dynamic_if.ts | 26 ++++++++++++++----- .../src/dynamic_list_create.ts | 25 +++++++++++++----- .../src/dynamic_text_join.ts | 25 +++++++++++++----- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/plugins/block-dynamic-connection/src/dynamic_if.ts b/plugins/block-dynamic-connection/src/dynamic_if.ts index ee77b0b684..6753fcccc6 100644 --- a/plugins/block-dynamic-connection/src/dynamic_if.ts +++ b/plugins/block-dynamic-connection/src/dynamic_if.ts @@ -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; @@ -381,6 +383,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; diff --git a/plugins/block-dynamic-connection/src/dynamic_list_create.ts b/plugins/block-dynamic-connection/src/dynamic_list_create.ts index c911abb87f..c297daa3c8 100644 --- a/plugins/block-dynamic-connection/src/dynamic_list_create.ts +++ b/plugins/block-dynamic-connection/src/dynamic_list_create.ts @@ -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, @@ -281,6 +283,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; diff --git a/plugins/block-dynamic-connection/src/dynamic_text_join.ts b/plugins/block-dynamic-connection/src/dynamic_text_join.ts index eece63b023..2289f01cb5 100644 --- a/plugins/block-dynamic-connection/src/dynamic_text_join.ts +++ b/plugins/block-dynamic-connection/src/dynamic_text_join.ts @@ -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, @@ -278,6 +280,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; From 89e4c7ddabadec3f9ea456b58356ce343ae4c2e6 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Jan 2024 22:20:13 +0000 Subject: [PATCH 03/14] fix: have connection previewer handle pending connections --- .../src/connection_previewer.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts index 9d6f30d868..7406174640 100644 --- a/plugins/block-dynamic-connection/src/connection_previewer.ts +++ b/plugins/block-dynamic-connection/src/connection_previewer.ts @@ -10,6 +10,18 @@ interface ConnectionPreviewerConstructor { new (draggedBlock: Blockly.BlockSvg): Blockly.IConnectionPreviewer; } +interface DynamicBlock extends Blockly.BlockSvg { + onPendingConnection(connection: Blockly.Connection): void; + finalizeConnections(): void; +} + +function blockIsDynamic(block: Blockly.BlockSvg): block is DynamicBlock { + return ( + (block as any)['onPendingConnection'] !== undefined && + (block as any)['finalizeConnections'] !== undefined + ); +} + export function DynamicConnectionPreviewer( // TODO: Make this optional before merging. basePreviewerConstructor: ConnectionPreviewerConstructor, @@ -17,6 +29,8 @@ export function DynamicConnectionPreviewer( return class implements Blockly.IConnectionPreviewer { private basePreviewer: Blockly.IConnectionPreviewer; + private pendingBlocks: Set = new Set(); + constructor(draggedBlock: Blockly.BlockSvg) { this.basePreviewer = new basePreviewerConstructor(draggedBlock); } @@ -26,6 +40,7 @@ export function DynamicConnectionPreviewer( staticConn: Blockly.RenderedConnection, replacedBlock: Blockly.BlockSvg, ): void { + this.previewDynamism(staticConn); this.basePreviewer.previewReplacement( draggedConn, staticConn, @@ -37,6 +52,7 @@ export function DynamicConnectionPreviewer( draggedConn: Blockly.RenderedConnection, staticConn: Blockly.RenderedConnection, ): void { + this.previewDynamism(staticConn); this.basePreviewer.previewConnection(draggedConn, staticConn); } @@ -45,7 +61,24 @@ export function DynamicConnectionPreviewer( } 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. + */ + private previewDynamism(conn: Blockly.RenderedConnection) { + const block = conn.getSourceBlock(); + if (blockIsDynamic(block)) { + block.onPendingConnection(conn); + this.pendingBlocks.add(block); + } + } }; } From 23b5ba4ff8521e5b9a2a7773371ac5db239d9002 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Jan 2024 22:28:39 +0000 Subject: [PATCH 04/14] fix: have onPendingConnection ignore insertion markers --- plugins/block-dynamic-connection/src/dynamic_if.ts | 9 ++++++++- .../src/dynamic_list_create.ts | 11 +++++++---- .../block-dynamic-connection/src/dynamic_text_join.ts | 11 +++++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/block-dynamic-connection/src/dynamic_if.ts b/plugins/block-dynamic-connection/src/dynamic_if.ts index 6753fcccc6..5090ada2d6 100644 --- a/plugins/block-dynamic-connection/src/dynamic_if.ts +++ b/plugins/block-dynamic-connection/src/dynamic_if.ts @@ -220,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) { @@ -272,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()); diff --git a/plugins/block-dynamic-connection/src/dynamic_list_create.ts b/plugins/block-dynamic-connection/src/dynamic_list_create.ts index c297daa3c8..dc48ce792e 100644 --- a/plugins/block-dynamic-connection/src/dynamic_list_create.ts +++ b/plugins/block-dynamic-connection/src/dynamic_list_create.ts @@ -158,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; } @@ -171,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; } @@ -185,7 +188,7 @@ const DYNAMIC_LIST_CREATE_MIXIN = { return connectionIndex + 1; } - // Don't add new connection + // Don't add new connection. return null; }, diff --git a/plugins/block-dynamic-connection/src/dynamic_text_join.ts b/plugins/block-dynamic-connection/src/dynamic_text_join.ts index 2289f01cb5..d5beec8901 100644 --- a/plugins/block-dynamic-connection/src/dynamic_text_join.ts +++ b/plugins/block-dynamic-connection/src/dynamic_text_join.ts @@ -154,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; } @@ -167,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; } @@ -181,7 +184,7 @@ const DYNAMIC_TEXT_JOIN_MIXIN = { return connectionIndex + 1; } - // Don't add new connection + // Don't add new connection. return null; }, From c6c8c76c68214e517c56e7595ed05776f67fba2e Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Jan 2024 22:29:26 +0000 Subject: [PATCH 05/14] chore: delete insertion marker monkey patch --- plugins/block-dynamic-connection/package.json | 2 +- .../insertion_marker_manager_monkey_patch.ts | 78 ------------------- 2 files changed, 1 insertion(+), 79 deletions(-) delete mode 100644 plugins/block-dynamic-connection/src/insertion_marker_manager_monkey_patch.ts diff --git a/plugins/block-dynamic-connection/package.json b/plugins/block-dynamic-connection/package.json index 8c3e588c32..6ebb80db51 100644 --- a/plugins/block-dynamic-connection/package.json +++ b/plugins/block-dynamic-connection/package.json @@ -1,6 +1,6 @@ { "name": "@blockly/block-dynamic-connection", - "version": "0.5.6", + "version": "1.0.0", "description": "A group of blocks that add connections dynamically.", "scripts": { "audit:fix": "blockly-scripts auditFix", diff --git a/plugins/block-dynamic-connection/src/insertion_marker_manager_monkey_patch.ts b/plugins/block-dynamic-connection/src/insertion_marker_manager_monkey_patch.ts deleted file mode 100644 index d1a3eb9334..0000000000 --- a/plugins/block-dynamic-connection/src/insertion_marker_manager_monkey_patch.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Overrides methods on Blockly.InsertionMarkerManager to - * allow blocks to hook in dynamic functionality when they have pending - * connections. - * @author anjali@code.org (Anjali Pal) - */ - -import * as Blockly from 'blockly/core'; - -// MonkeyPatchedInsertionMarkerManager overrides the update and dispose methods, -// and adds a new property called pendingBlocks. -interface MonkeyPatchedInsertionMarkerManager - extends Blockly.InsertionMarkerManager { - pendingBlocks: Set; -} - -// MonkeyPatchedInsertionMarkerManager relies on the dynamic blocks adding new -// methods called onPendingConnection and finalizeConnections. -interface DynamicBlock extends Blockly.Block { - onPendingConnection(connection: Blockly.Connection): void; - finalizeConnections(): void; -} - -// Override the update method, possibly adding the candidate to pendingBlocks. -// Hack: Private methods of InsertionMarkerManager are called using the array -// index syntax, bypassing access checking. The private methods are also missing -// type information in the d.ts files and are considered to return any here. -Blockly.InsertionMarkerManager.prototype.update = function ( - this: MonkeyPatchedInsertionMarkerManager, - dxy: Blockly.utils.Coordinate, - dragTarget: Blockly.IDragTarget | null, -): void { - const newCandidate = this['getCandidate'](dxy); - - this.wouldDeleteBlock = this['shouldDelete'](!!newCandidate, dragTarget); - - const shouldUpdate: boolean = - this.wouldDeleteBlock || this['shouldUpdatePreviews'](newCandidate, dxy); - - if (shouldUpdate) { - // Begin monkey patch - if (newCandidate?.closest?.sourceBlock_.onPendingConnection) { - newCandidate.closest.sourceBlock_.onPendingConnection( - newCandidate.closest, - ); - if (!this.pendingBlocks) { - this.pendingBlocks = new Set(); - } - this.pendingBlocks.add(newCandidate.closest.sourceBlock_); - } - // End monkey patch - // Don't fire events for insertion marker creation or movement. - Blockly.Events.disable(); - this['maybeHidePreview'](newCandidate); - this['maybeShowPreview'](newCandidate); - Blockly.Events.enable(); - } -}; - -const oldDispose = Blockly.InsertionMarkerManager.prototype.dispose; -Blockly.InsertionMarkerManager.prototype.dispose = function ( - this: MonkeyPatchedInsertionMarkerManager, -) { - if (this.pendingBlocks) { - this.pendingBlocks.forEach((block) => { - if ((block as DynamicBlock).finalizeConnections) { - (block as DynamicBlock).finalizeConnections(); - } - }); - } - oldDispose.call(this); -}; From 0d06cb3786bc4b9f0f95b0596b99044a8bd1ab5d Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Jan 2024 22:50:18 +0000 Subject: [PATCH 06/14] fixup --- plugins/block-dynamic-connection/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/block-dynamic-connection/src/index.ts b/plugins/block-dynamic-connection/src/index.ts index 08db9f98b4..9ed5626333 100644 --- a/plugins/block-dynamic-connection/src/index.ts +++ b/plugins/block-dynamic-connection/src/index.ts @@ -10,7 +10,6 @@ */ import * as Blockly from 'blockly/core'; -import './insertion_marker_manager_monkey_patch'; import './dynamic_if'; import './dynamic_text_join'; import './dynamic_list_create'; From 36fa7b46f39e4731ee31fba465be5819f218b648 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 2 Feb 2024 23:09:40 +0000 Subject: [PATCH 07/14] chore: bump versions --- .../package-lock.json | 20 +++++++++---------- plugins/block-dynamic-connection/package.json | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/block-dynamic-connection/package-lock.json b/plugins/block-dynamic-connection/package-lock.json index aa6a72abee..8d7edb11a8 100644 --- a/plugins/block-dynamic-connection/package-lock.json +++ b/plugins/block-dynamic-connection/package-lock.json @@ -1,15 +1,15 @@ { "name": "@blockly/block-dynamic-connection", - "version": "0.5.6", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@blockly/block-dynamic-connection", - "version": "0.5.6", + "version": "1.0.0", "license": "Apache-2.0", "devDependencies": { - "blockly": "^10.2.0", + "blockly": "^10.4.0-beta.1", "chai": "^4.2.0", "mocha": "^10.2.0", "typescript": "^5.2.2" @@ -18,7 +18,7 @@ "node": ">=8.17.0" }, "peerDependencies": { - "blockly": "^10.2.0" + "blockly": "^10.4.0-beta.1" } }, "node_modules/@tootallnate/once": { @@ -116,9 +116,9 @@ } }, "node_modules/blockly": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.2.0.tgz", - "integrity": "sha512-9jPGdiU3/pzyc2abyqoWcG+ddQwLBixb8HHr5QH2oSn+HialbaR94hS0hqgKXptMr7eD5/ZwEqVK+ptq8Gxe0A==", + "version": "10.4.0-beta.1", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.4.0-beta.1.tgz", + "integrity": "sha512-+/9IO6ugkTJ4VY0Vp2Zbk0cbFEdZ5fPcDE9CMztjJng0Oe5NU9o4e4iRAC/tmpo/R7QRSARPbSW49/JR8uepgg==", "dev": true, "dependencies": { "jsdom": "22.1.0" @@ -1556,9 +1556,9 @@ "dev": true }, "blockly": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.2.0.tgz", - "integrity": "sha512-9jPGdiU3/pzyc2abyqoWcG+ddQwLBixb8HHr5QH2oSn+HialbaR94hS0hqgKXptMr7eD5/ZwEqVK+ptq8Gxe0A==", + "version": "10.4.0-beta.1", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.4.0-beta.1.tgz", + "integrity": "sha512-+/9IO6ugkTJ4VY0Vp2Zbk0cbFEdZ5fPcDE9CMztjJng0Oe5NU9o4e4iRAC/tmpo/R7QRSARPbSW49/JR8uepgg==", "dev": true, "requires": { "jsdom": "22.1.0" diff --git a/plugins/block-dynamic-connection/package.json b/plugins/block-dynamic-connection/package.json index 6ebb80db51..a4753975f8 100644 --- a/plugins/block-dynamic-connection/package.json +++ b/plugins/block-dynamic-connection/package.json @@ -42,13 +42,13 @@ "devDependencies": { "@blockly/dev-scripts": "^3.1.1", "@blockly/dev-tools": "^7.1.5", - "blockly": "^10.2.0", + "blockly": "^10.4.0-beta.1", "chai": "^4.2.0", "mocha": "^10.2.0", "typescript": "^5.2.2" }, "peerDependencies": { - "blockly": "^10.2.0" + "blockly": "^10.4.0-beta.1" }, "publishConfig": { "access": "public", From f65ac42f33c994550a17508cae311c95aa874c9a Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 3 Feb 2024 00:10:32 +0000 Subject: [PATCH 08/14] chore: fixup naming and docs --- .../src/connection_previewer.ts | 20 ++++++++++++++----- .../block-dynamic-connection/test/index.ts | 7 ++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts index 7406174640..5ff61e588f 100644 --- a/plugins/block-dynamic-connection/src/connection_previewer.ts +++ b/plugins/block-dynamic-connection/src/connection_previewer.ts @@ -17,14 +17,22 @@ interface DynamicBlock extends Blockly.BlockSvg { function blockIsDynamic(block: Blockly.BlockSvg): block is DynamicBlock { return ( - (block as any)['onPendingConnection'] !== undefined && - (block as any)['finalizeConnections'] !== undefined + (block as DynamicBlock)['onPendingConnection'] !== undefined && + (block as DynamicBlock)['finalizeConnections'] !== undefined ); } -export function DynamicConnectionPreviewer( +/** + * 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. + * @return A decofrated connection previewer constructor. + */ +export function decoratePreviewerWithDynamicConnections( // TODO: Make this optional before merging. - basePreviewerConstructor: ConnectionPreviewerConstructor, + BasePreviewerConstructor: ConnectionPreviewerConstructor, ): ConnectionPreviewerConstructor { return class implements Blockly.IConnectionPreviewer { private basePreviewer: Blockly.IConnectionPreviewer; @@ -32,7 +40,7 @@ export function DynamicConnectionPreviewer( private pendingBlocks: Set = new Set(); constructor(draggedBlock: Blockly.BlockSvg) { - this.basePreviewer = new basePreviewerConstructor(draggedBlock); + this.basePreviewer = new BasePreviewerConstructor(draggedBlock); } previewReplacement( @@ -72,6 +80,8 @@ export function DynamicConnectionPreviewer( /** * If the block is a dynamic block, calls onPendingConnection and * stores the block to be finalized later. + * + * @param conn The block to rtrigger onPendingConnection on. */ private previewDynamism(conn: Blockly.RenderedConnection) { const block = conn.getSourceBlock(); diff --git a/plugins/block-dynamic-connection/test/index.ts b/plugins/block-dynamic-connection/test/index.ts index dbad6e1b2d..6d21dc950f 100644 --- a/plugins/block-dynamic-connection/test/index.ts +++ b/plugins/block-dynamic-connection/test/index.ts @@ -86,9 +86,10 @@ document.addEventListener('DOMContentLoaded', function () { const defaultOptions: Blockly.BlocklyOptions = { toolbox, plugins: { - connectionPreviewer: BlockDynamicConnection.DynamicConnectionPreviewer( - Blockly.InsertionMarkerPreviewer, - ), + connectionPreviewer: + BlockDynamicConnection.decoratePreviewerWithDynamicConnections( + Blockly.InsertionMarkerPreviewer, + ), }, }; const rootElement = document.getElementById('root'); From f3e9f9ee10fc0be926c5335e79c2faa3de1dca6b Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 3 Feb 2024 00:12:43 +0000 Subject: [PATCH 09/14] chore: format --- plugins/block-dynamic-connection/src/connection_previewer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts index 5ff61e588f..0cbaf824b5 100644 --- a/plugins/block-dynamic-connection/src/connection_previewer.ts +++ b/plugins/block-dynamic-connection/src/connection_previewer.ts @@ -25,7 +25,7 @@ function blockIsDynamic(block: Blockly.BlockSvg): block is DynamicBlock { /** * 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. * @return A decofrated connection previewer constructor. @@ -80,7 +80,7 @@ export function decoratePreviewerWithDynamicConnections( /** * If the block is a dynamic block, calls onPendingConnection and * stores the block to be finalized later. - * + * * @param conn The block to rtrigger onPendingConnection on. */ private previewDynamism(conn: Blockly.RenderedConnection) { From fa6545469275632153d33fb3c5fe42f9b254a8d6 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 5 Feb 2024 17:08:28 +0000 Subject: [PATCH 10/14] chore: fix build --- plugins/block-dynamic-connection/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/block-dynamic-connection/src/index.ts b/plugins/block-dynamic-connection/src/index.ts index 9ed5626333..7b4fd5a027 100644 --- a/plugins/block-dynamic-connection/src/index.ts +++ b/plugins/block-dynamic-connection/src/index.ts @@ -13,9 +13,9 @@ import * as Blockly from 'blockly/core'; import './dynamic_if'; import './dynamic_text_join'; import './dynamic_list_create'; -import {DynamicConnectionPreviewer} from './connection_previewer'; +import {decoratePreviewerWithDynamicConnections} from './connection_previewer'; -export {DynamicConnectionPreviewer}; +export {decoratePreviewerWithDynamicConnections}; export const overrideOldBlockDefinitions = function (): void { Blockly.Blocks['lists_create_with'] = Blockly.Blocks['dynamic_list_create']; From b90a927cea24d51939549ac7776aac54417faafd Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 5 Feb 2024 17:10:07 +0000 Subject: [PATCH 11/14] chore: fixup type --- plugins/block-dynamic-connection/src/connection_previewer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts index 0cbaf824b5..75bf319fb1 100644 --- a/plugins/block-dynamic-connection/src/connection_previewer.ts +++ b/plugins/block-dynamic-connection/src/connection_previewer.ts @@ -11,7 +11,7 @@ interface ConnectionPreviewerConstructor { } interface DynamicBlock extends Blockly.BlockSvg { - onPendingConnection(connection: Blockly.Connection): void; + onPendingConnection(connection: Blockly.RenderedConnection): void; finalizeConnections(): void; } From 97b7c02f393bbd212a42b88b123d8f522bddd585 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 5 Feb 2024 18:25:33 +0000 Subject: [PATCH 12/14] feat: make BasePreviewerConstructor optional --- .../src/connection_previewer.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts index 75bf319fb1..4563f2a7f2 100644 --- a/plugins/block-dynamic-connection/src/connection_previewer.ts +++ b/plugins/block-dynamic-connection/src/connection_previewer.ts @@ -27,12 +27,12 @@ function blockIsDynamic(block: Blockly.BlockSvg): block is DynamicBlock { * constructor to add connection previewing. * * @param BasePreviewerConstructor The constructor for the base connection - * previewer class being decorated. + * previewer class being decorated. If not provided, the default + * InsertionMarkerPreviewer will be used. * @return A decofrated connection previewer constructor. */ export function decoratePreviewerWithDynamicConnections( - // TODO: Make this optional before merging. - BasePreviewerConstructor: ConnectionPreviewerConstructor, + BasePreviewerConstructor?: ConnectionPreviewerConstructor, ): ConnectionPreviewerConstructor { return class implements Blockly.IConnectionPreviewer { private basePreviewer: Blockly.IConnectionPreviewer; @@ -40,7 +40,9 @@ export function decoratePreviewerWithDynamicConnections( private pendingBlocks: Set = new Set(); constructor(draggedBlock: Blockly.BlockSvg) { - this.basePreviewer = new BasePreviewerConstructor(draggedBlock); + const BaseConstructor = + BasePreviewerConstructor ?? Blockly.InsertionMarkerPreviewer; + this.basePreviewer = new BaseConstructor(draggedBlock); } previewReplacement( From b7f5cfb56a14930b488cfde1c5da8a953fbed7ec Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 5 Feb 2024 19:09:39 +0000 Subject: [PATCH 13/14] chore: fix readme --- plugins/block-dynamic-connection/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/block-dynamic-connection/README.md b/plugins/block-dynamic-connection/README.md index 6fb7f62d7b..50a7d69d47 100644 --- a/plugins/block-dynamic-connection/README.md +++ b/plugins/block-dynamic-connection/README.md @@ -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 From 0f70c6e331f12dae3e5be97f8c1a4636e24a9485 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 5 Feb 2024 20:54:09 +0000 Subject: [PATCH 14/14] chore: PR nits --- .../block-dynamic-connection/src/connection_previewer.ts | 6 +++--- plugins/block-dynamic-connection/src/index.ts | 4 ++-- plugins/block-dynamic-connection/test/index.ts | 7 +++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts index 4563f2a7f2..ec7e0612fa 100644 --- a/plugins/block-dynamic-connection/src/connection_previewer.ts +++ b/plugins/block-dynamic-connection/src/connection_previewer.ts @@ -29,9 +29,9 @@ function blockIsDynamic(block: Blockly.BlockSvg): block is DynamicBlock { * @param BasePreviewerConstructor The constructor for the base connection * previewer class being decorated. If not provided, the default * InsertionMarkerPreviewer will be used. - * @return A decofrated connection previewer constructor. + * @return A decorated connection previewer constructor. */ -export function decoratePreviewerWithDynamicConnections( +export function decoratePreviewer( BasePreviewerConstructor?: ConnectionPreviewerConstructor, ): ConnectionPreviewerConstructor { return class implements Blockly.IConnectionPreviewer { @@ -83,7 +83,7 @@ export function decoratePreviewerWithDynamicConnections( * If the block is a dynamic block, calls onPendingConnection and * stores the block to be finalized later. * - * @param conn The block to rtrigger onPendingConnection on. + * @param conn The block to trigger onPendingConnection on. */ private previewDynamism(conn: Blockly.RenderedConnection) { const block = conn.getSourceBlock(); diff --git a/plugins/block-dynamic-connection/src/index.ts b/plugins/block-dynamic-connection/src/index.ts index 7b4fd5a027..bc581d2b4e 100644 --- a/plugins/block-dynamic-connection/src/index.ts +++ b/plugins/block-dynamic-connection/src/index.ts @@ -13,9 +13,9 @@ import * as Blockly from 'blockly/core'; import './dynamic_if'; import './dynamic_text_join'; import './dynamic_list_create'; -import {decoratePreviewerWithDynamicConnections} from './connection_previewer'; +import {decoratePreviewer} from './connection_previewer'; -export {decoratePreviewerWithDynamicConnections}; +export {decoratePreviewer}; export const overrideOldBlockDefinitions = function (): void { Blockly.Blocks['lists_create_with'] = Blockly.Blocks['dynamic_list_create']; diff --git a/plugins/block-dynamic-connection/test/index.ts b/plugins/block-dynamic-connection/test/index.ts index 6d21dc950f..b057355055 100644 --- a/plugins/block-dynamic-connection/test/index.ts +++ b/plugins/block-dynamic-connection/test/index.ts @@ -86,10 +86,9 @@ document.addEventListener('DOMContentLoaded', function () { const defaultOptions: Blockly.BlocklyOptions = { toolbox, plugins: { - connectionPreviewer: - BlockDynamicConnection.decoratePreviewerWithDynamicConnections( - Blockly.InsertionMarkerPreviewer, - ), + connectionPreviewer: BlockDynamicConnection.decoratePreviewer( + Blockly.InsertionMarkerPreviewer, + ), }, }; const rootElement = document.getElementById('root');