Customising how a slice gets pasted depending on where the cursor is


#1

Hey there!

I’m currently investigating how to override the way a slice gets pasted depending on where the paste/drop ‘selection target’ is.


Current Behaviour

As an example, when pasting content into a table - rather than splitting the node in half when pasting content like:


Wanted

I’d rather override the pasting behaviour to unwrap the table-cell contents and show the content in a list like:


To get this behaviour, I can’t use transformPasted as there’s way no to access the state / selection so I’m forced to override both handlePaste and handleDrop and reimplement all of the logic prosemirror-view already does for these handlers to iterate through the slice and unwrap the table/tableCell.

I’m wondering what people think is the best course of action, either:

  1. Do nothing, and just copy across the handlePaste/handleDrop handlers from prosemirror-view (at the risk of not getting bug fixes / incurring the maintenance cost of owning this code)
  2. Try and get the logic to paste / drop a slice (like https://github.com/ProseMirror/prosemirror-view/blob/8363b38d52a08035feae71459b49895916fd84f6/src/input.js#L512) to their own commands in PM-View
  3. Try and change transformPasted to have the signature: transformPasted:: ?(slice: Slice, view: EditorView, event: dom.Event) → Slice but the argument ordering is strange when compared to handlePaste & handleDrop
  4. A better idea?

#2

Have you seen the context property for parse rules? Does it help with your use case?


#3

I don’t believe so, though that is an interesting suggestion :slight_smile:

You’re right that using context property for parse rules would allow me to get the behaviour I’m looking for (creating/transforming the slice so it only has the cell content). However, I’m wanting to only do this only when the selection/paste will occur inside a table. At all other times, I want to be able to paste the table elsewhere in the document as per normal. Hence why the logic that would otherwise be suited for transformPasted has to end up in handlePaste and handleDrop since it has access to state.selection to determine if the cursor is in a table.

The psuedocode for what I’d have to do today is basically:

{
  handlePaste(view, event, slice) {
    slice = unwrapContentFromTableCellsIfSelectionIsInTable(slice, view.state);
    ....
    dispatch(state.tr.replaceSelection(slice));
    return true;
  },
  handleDrop(view, event, slice, moved) {
    slice = unwrapContentFromTableCellsIfSelectionIsInTable(slice, view.state);
    ....
    // work out where the dropPos is and whether to
    // replace or insert slice based off `moved` 
    ....
    dispatch(state.tr.doSomethingWith(slice));
    return true;
  },

but I’d rather not have to copy dropPos & all that logic since it’s fairly non-trivial


#4

However, I’m wanting to only do this only when the selection/paste will occur inside a table

Doesn’t the context tell you whether you are pasting into a table?

Anyway, you can return false from handleDrop to defer to the default behavior, so if your custom behavior is relatively simple, only handling that case might work.


#5

(Failing that, you could create an RFC to pass the default drop position to handleDrop, to reduce the amount of code needed in your custom handler.)