WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.52k stars 4.21k forks source link

Allow non-consecutive multi-selection of blocks #16797

Open swissspidy opened 5 years ago

swissspidy commented 5 years ago

Is your feature request related to a problem? Please describe.

We are currently facing a situation where we need to be able to select multiple non-consecutive blocks to then perform a bulk action on them (e.g. remove, copy, move up/down, etc.).

However, in Gutenberg multi-selection is really designed for selecting a range of blocks from start to end, not a loose list of blocks that could be all over the place.

Examples in the code:

https://github.com/WordPress/gutenberg/blob/1b5fc6a593581bfe1ee75128f0d05c154c4b8fdf/packages/block-editor/src/store/selectors.js#L538-L598

https://github.com/WordPress/gutenberg/blob/1b5fc6a593581bfe1ee75128f0d05c154c4b8fdf/packages/block-editor/src/store/selectors.js#L313-L337

https://github.com/WordPress/gutenberg/blob/1b5fc6a593581bfe1ee75128f0d05c154c4b8fdf/packages/block-editor/src/store/actions.js#L157-L193

Describe the solution you'd like

I think the resolvers under the hood could be re-written in a way that multi-selection would store the actual list of items in an array, and not start and end values. This would allow plugins to perform this non-consecutive multi-selection on their own.

I think this could be done in a backward-compatible way.

In a next step, we could think about how to expose this feature in the Gutenberg UI itself. For example, in our plugin we were thinking about allowing CMD+clicking on individual blocks to mark them as selected.

Describe alternatives you've considered

I looked into rolling our own implementation for this in our plugin, but it's not really doable. The multi-selection block toolbar and sidebar all rely on the built-in selectors like getMultiSelectedBlocks(), getMultiSelectedBlockClientIds(), and getSelectedBlockClientIds().

talldan commented 5 years ago

I've been thinking about a similar problem in the table block, where you also expect to be able to multi-select cells. At the moment individual cells can only be selected. Similar sort of problem here, except blocks already support ranges of selections.

The solution I had in mind is a fairly obvious one, using an array to build up a list of the different selections. The existing 'range' object becomes the data used in an individual element of the array, so it should be possible to reuse some of the logic:

const selections = [
  {
    start: { clientId, ... },
    end: { clientId, ... },
  },
  {
    start: { clientId, ... },
    end: { clientId, ... },
  }
]

The idea then is that you can reduce the array to work out whether something is selected.

There are some little edge cases though. For example, a user might select a range by shift-clicking and then deselect one of the blocks in the middle by command clicking.

As blocks are stored sequentially, some splitting and merging logic when adding selections would possibly be the way to go. Another option is to add an object that represents a 'deselection' to the array.

swissspidy commented 5 years ago

Could another option be to store a list of all the selected client IDs or would that take up too much space?

talldan commented 5 years ago

Yeah, that's also definitely an option. Could do an array slice on state.blocks.order to build up a list for range selections.

swissspidy commented 5 years ago

FYI there's now a work-in-progress PR at #16811 that uses one big array of client IDs. Seemed the easiest solution to implement as a proof-of-concept. There's only some edge cases to address.

swissspidy commented 5 years ago

There was a good question from today's #core-editor meeting (source):

How would it handle “moving” once you select a bunch of non-consecutive blocks?

One suggestion was:

I think they could collapse before the last selected element, so any non selected element between them will move up the selected list, it makes sense when refactoring sides of the articles to different sections

Also another good thing to keep in mind:

My main thoughs at the moment is around all these places where we just assumed a sequential list of blocks for multiselection. start/end in the state are the obvious one but I feel we have more hidden places with that assumption.

maheshwaghmare commented 4 years ago

I have something similar situation in which I want to manage the styling of similar blocks.

Instead of creating new issue added below comments.

The situation is described as below:

Now, If user want to change the colors & other settings then I'm thinning to provide such option in which user can bulk select the blocks and change selected block (similar selected blocks) to change the colors & other settings.

I think I need to do this by adding some custom solution. Or It is good to add SlotFills in <MultiSelectionInspector>

Screenshot for reference:

Bulk Select Hook

I'm still experimenting things in the Gutenberg. So, Instead of creating new task added above comments here.

lubieowoce commented 4 years ago

+1, it would be really great to have something like PluginMultiBlockControls and PluginMultiInspectorControls (perhaps behind an __experimental for now) . i'm working on a plugin to edit multiple blocks at once (see #8743) and i have to render my own popover toolbar and do all sorts of ugly stuff because right now the standard contextual toolbar hides all controls during a multiselection (except for the builtin "convert" button).

talldan commented 4 years ago

16895 has some proposals on how moving non-consecutive blocks might work.

Here are some of the images from that now closed issue: moving down: ezgif com-video-to-gif (1)

moving up (fixed version): moveup

porg commented 4 months ago

👆 my linked ticket was a duplicate.

swissspidy commented 4 months ago

IDK why I was still assigned here. This isn't a focus for me anymore.

Someone else might want to pick up the ideas from #16811 and attempt this again, but a lot has changed in the last few years, so... 🤷