Expanding the transaction class


#1

This post is aimed at @marijn but I wanted to forum it because I think it merits discussion.

A while ago (as I mentioned on this forum) I had to hijack one of the “Enter” commands so that I could have nodes inherit classes from their predecessors (such that text would continue to be aligned left/right/center based on the previous line of text). At the time, we weren’t sure how client developers could get around this kind of problem (the nature of a WYSIWYM library makes life tough on that front). I speculated event-hook callbacks that you feed into commands; but maybe that’s over-complicating things. I think I have a solution because I’m kind of in the same boat once again (I have some very specific behaviour involving splitting lists that I just can’t get right without essentially rewriting splitListItem).

I think the library really needs some more complex transaction structures. because of how transactions currently work (if I’ve read your code correctly and based on various chain experiments), once I’ve called dispatch the window of opportunity to perform actions is shut.

The solution, as I see it, would be to have a series of prototypically inherited transaction methods that behave like commands.

This would greatly increase the power and modularity of the library in my eyes and make for a much more versatile platform from which to develop frameworks and so on.

I’ll give a more detailed example once I’ve got a working demo of my design.

for my part I’d be happy to fork ProseMirror once I’ve got a few useful things together!


#2

These don’t necessary need to be methods — they can just be functions that take and return transactions. I’ve said before that I’d be open to breaking out parts of the commands package into separately exported utility functions, but doing so will require care (and good taste) since this functionality tends to be rather subtle and writing things that work for all schemata is tricky.


#3

The trouble is, if they were stand-alone functions, you wouldn’t be able to chain prior tr calls

one option would be to have transaction “upgrade” methods. you pass your transaction to, for example, upgradeToSplitList(tr) and then you can do stuff like:

tr.split(…) .splitList(…) .delete(…) .etc


#4

I’d say doing normal function pipelining (f(g(tr))) isn’t that much of a problem.


#5

Ok, after a lot of experimentation, I’m struggling to get this code working

so my example would be the following:

  1. create a new item in a list.
  2. lift the new item out of the list so it’s at the previous level.
  3. insert a new inline node into the lifted node.
  4. create a brand new list immediately after.

the problem I always seem to stumble on is: inconsistent open depths

i want to go from (for example, where the pipe represents the cursor)

<ul><li><p>con|tent</p></li></ul>

to

<ul><li><p>con</p></li></ul>
<p><p class="my-inline-node"><hr></p></p>
<ul><li><p>tent</p></li></ul>

#6

the problem with function pipelining is that all the existing transaction calls would have to be wrapped in event methods as well (ie. you’d be reinventing your wheel :slight_smile:) . I’m assuming that sometimes clients will prefer to use the simple transaction calls like split and so on. Is there a reason you think prototyping transactions is problematic? It feels like the natural way to go to me.

(I figured out a workaround using a modified paragraph node schema for my previous problem, however, I’ve also decided I’d like to make bullet points work more like they do in MS word when you delete them as well so that might add some complexity again)


#7

thank God for your autoJoin helper! In the end I had to write a special variant of joinBackward/deleteBarrier and have them feed through autoJoin to get the behaviour I was after:

msWordStyle

I’d be tempted to open source it, but it’d require a bunch of schema specific stuff to work for other people.