PRs and issues resolved during GSoC 2022:
- PR #1
- PR #2
- Issue #3
- PR #4
- PR #5
- google/blockly-samples PR #1202
- ThibaultJanBeyer/DragSelect PR #128
Hi there! If you prefer watching videos, check this out for an episode demoing the plugin: https://www.youtube.com/watch?v=FZyvvPZhIRs
For you guys who prefer reading, in this blog post I will introduce you to my work on the plugin for selecting, dragging, and doing actions on multiple blocks. The project is sponsored by Google Summer of Code (GSoC) 2022, under MIT App inventor.
The project aims to enable the selection of multiple blocks at the same time and allow moving and doing actions on multiple blocks on Blockly.
This behavior is the same as when you try to manage your files on your Operating System. You can click on the files while pressing the control key, drag a rectangle to select multiple files. Then move them around, copying and deleting.
It sounds a little bit easy, but actually, I would say that it's not. Multiple selections can become a crazy-complex feature when you start thinking about the details.
This feature request has remained open on GitHub Issues for six years. However, it was still in the discussion phase and far from the beginning of Implementation before my project began.
Since the Blockly community long wants this feature, we base our plugin on the latest Blockly so that it can be applied to everyone's project. The App Inventor uses a Blockly version that is much older, so it's a pity that we can't see it work on App Inventor now. Let's hope that the App Inventor can upgrade the Blockly version to the latest soon.
In addition, I disable the drag surface feature in Blockly, which stops us from moving multiple blocks simultaneously. Also, there's evidence suggesting that we can perform better without a drag surface.
So, how does the plugin work? Well, generally, the plugin acts like an adapter. It maintains its own multiple selection set, which keeps currently selected blocks and make sure we always have one of the selected blocks as the selected one in Blockly core. When users do some actions, the plugin also passes all the actions to the other blocks in our set besides the selected one in Blockly core.
Let's check out what the plugin can do!
- Additional blocks can be selected by holding the SHIFT key while clicking the new block. You can also deselect the block by clicking the already selected block.
- Clicking on the button above the trashcan is equivalent to holding or releasing the SHIFT key for switching between the multiple selection mode and the normal mode.
- We can clear the selection by clicking on the workspace background.
- Clicking a new block without holding SHIFT key can clear the multiple selections and change the selection to only that block.
- Holding SHIFT key to drag a rectangle area to select can reverse their selection state for the blocks touched by the rectangle.
- In multiple selection mode, workspace dragging and block dragging will all be disabled. You can only drag to draw a rectangle for selection.
- When some of the selected blocks are in one block stack, for example, some top blocks and some of their children blocks are in the selection simultaneously. If applicable, the plugin only disconnects the selected most top block in that stack with its parent block. Move along with all the children's blocks of that most top block as a whole.
- You can also drag all the blocks to the trash can.
- When you edit the fields while selecting multiple blocks, we will automatically apply that to all the blocks with the same type.
- There's also an MIT App Inventor-only feature that has been migrated into this plugin, that you can double click to collapse or expand currently selected blocks.
- For the context menu, the
Duplicatewill duplicate the selected most top block in the block stack and all the children blocks of that most top block. The selection will be changed to all newly created duplicate blocks' most top blocks. For all the other items, The actions to show are determined by the state of the block which the user right-clicks on, and the same action will be applied to all the blocks no matter their individual state. We will append the currently applicable number of user-selected state-changing blocks, and the number will only be shown when it is greater than 1.
Remove Commentoption will add / remove comment buttons to all the selected blocks.
External Inputsoption will convert the input format with all the selected blocks.
Expand Blockoption will only apply to the selected most top block in the block stack.
Enable Blockoption will only apply to the selected most top block in the block stack. All the children blocks of that most top block will also get disabled.
- The number in
Delete [X] Blocksis the count of the selected most top block in the block stack as well as all children of those selected most top block. Clicking on that option will delete the blocks mentioned.
Helpoption displays just the helping information of the block the user just right-clicked on.
- We add
Select all Blocksin the workspace context menu.
- For the shortcut keys, These actions will only apply to the selected most top block in the block stack. when you press
Ctrl A, you can select all the blocks in the current workspace.
Ctrl Cto copy the selected blocks,
Ctrl Xto cut the selected blocks to the clipboard, and
Ctrl Vto paste all the blocks currently in the clipboard and get all the newly pasted blocks selected.
- Bumping neighbors after dragging to avoid overlapping is disabled in this plugin by default, since I find it disturbing sometimes for multiple selections.
- Click on a block will bring that block to the front in case Bumping neighbours is disabled.
If you want to integrate the plugin into your project, you can add the dependency into your
package.json. In the source code, pass the workspace to the plugin, and initialize the plugin, and then it's done! You can choose to disable double-click the blocks to collapse or expand and enable bumping neighbors after dragging to avoid overlapping. For the multi-select controls, you can also choose to hide the icon and customize the icons of each state. More details can be found in the README.
You can also choose to integrate the plugin with other ones, like the scroll options, which enable the edge scroll and wheel scroll for Blockly. The only thing you have to pay attention for the scroll options plugin to work is to assign the original
blockDragger value required for scroll options to
baseBlockDragger in our plugin. During the project period I also submitted a PR for fixing the a bug that makes scroll options unable to work without the drag surface, and it has already got merged.
That's all for this blog post. Before it ends, I would like to say thank you to my mentors, Evan Patton and Li Li, as well as the MIT App Inventor Team for guiding me throughout the project. They are really supportive. Also, special Thanks to Beka Westberg. She devoted a lot of time to giving suggestions and helping review the code. We can't have this plugin without her! Finally, thanks for reading this blog post! If you have any questions, please comment, and I'll reply. Cheers!