refactor!: Move responsibility for block creation out of flyouts#9610
refactor!: Move responsibility for block creation out of flyouts#9610
Conversation
| * from any parent blocks. | ||
| */ | ||
| startDrag(e?: PointerEvent | KeyboardEvent) { | ||
| const alterateTarget = this.swapTargetBlock(); |
There was a problem hiding this comment.
typo: alternate (if this stays)
| * Returns a block to use for the current drag operation in place of the | ||
| * current block, or undefined if the current block should be used. | ||
| */ | ||
| protected swapTargetBlock() { |
There was a problem hiding this comment.
we discussed offline why this is the way it is:
startDrag on the dragger returns the thing being dragged, to allow for cases just like this. since the block drag strategy is the thing that ultimately decides which thing is being dragged, it has to have a method for doing that logic.
we decided to call it getTargetBlock (or something similar) which feels a little simpler and more generic. It might be a little unexpected that a get method can create a new block (as it does in the flyout case) so should be explained in the tsdoc.
| getFocusManager().focusNode(newBlock); | ||
| } | ||
|
|
||
| // Perform a zero-length drag to copy the block out of the flyout. |
There was a problem hiding this comment.
It's really weird that Gesture does this I think. A couple of thoughts:
- I know some people were doing custom block creation shenanigans where they would have a block look different in the flyout than it did in the main workspace, to make the flyout look simpler. I don't know how this works, are they doing it with fancy block definitions (that change based on whether the block is in a flyout) or were they doing it with fancy flyouts that override
flyout.createBlock? If the latter, now they'll have to override the drag strategy instead which is maybe unexpected. Is there a place, maybe on the block class which can be customized with a mixin, where we can have the logic for "create a new block of this type from the flyout"? - If we did have that, it could also be called from the keyboard shortcut that handles pressing "enter" on a block in the flyout (which currently calls
flyout.createBlockas well) - otherwise, the Enter shortcut is also going to have to create one of these fake drags which is also undesirable.
- Then, as to the fact that gesture is for some reason handling creating a block on click, maybe blocks should just do this themselves in response to a block click? if they're on a flyout and get a click event, then they could clone themselves onto the main workspace without involving the dragger at all? I know you're just recreating the logic that was here but the old logic was weird too.
Let me know your thoughts here!
| test('Clicking on shadow block does not select it', function () { | ||
| const flyout = this.workspace.getFlyout(true); | ||
| flyout.createBlock( | ||
| Blockly.KeyboardMover.mover.startMove( |
There was a problem hiding this comment.
Is this just a convoluted way to get a block with a shadow block onto the workspace? why not do that via serializing a block instead?
The basics
The details
Proposed Changes
This PR moves block creation out of the flyout and into the
BlockDragStrategy. This simplifies the code overall and results in a better separation of concerns: flyouts are capable of holding arbitrary kinds of objects now, so having them tightly coupled to blocks is suboptimal. Now, duplicating blocks when dragged out of the flyout is handled by theBlockDragStrategy, and the flyout is concerned only with the display and layout of its contents, whatever they may be. As a result of this change, it's now possible to copy blocks out of the flyout using the keyboard alone by selecting a block in the flyout and hittingmto enter move mode, which copies the block to the main workspace and puts it in move mode, exactly the same as a mouse-driven drag would.Breaking Changes
createBlock(),isDragTowardWorkspace(), andisBlockCreatable()have been removed fromIFlyout. While this is not breaking from a building standpoint, it is behaviorally breaking if you have an alternate flyout implementation that customized those methods.isDragTowardWorkspace()was already a no-op, so no action needs to be taken other than removing it. Customizations that were made tocreateBlock()andisBlockCreatable()can be achieved by creating aBlockDragStrategysubclass that overridesisMovable()and/orswapTargetBlock()and using a mixin or extension to apply that drag strategy to your blocks.