[whatwg] Fixing undo on the Web - UndoManager and Transaction

Ryosuke Niwa rniwa at webkit.org
Fri Jul 29 17:40:05 PDT 2011


On Fri, Jul 29, 2011 at 5:08 PM, Jonas Sicking <jonas at sicking.cc> wrote:

> I really do like the undoscope attribute, that is something that is
> definitely needed.


Yes. I've considered other possibilities such as letting scripts to manually
instantiate UndoManager objects, etc... but that turned out to require too
much work just to separate undo transaction histories of two editable
regions.


> It does seem undefined how it
> interacts with the contenteditable attribute? I was thinking that
> contenteditable would create a undoscope, unless there's an element
> higher up in the tree which has an explicit undoscope attribute.
>

I've thought this approach as well but this would break the backward
compatibility as the major browsers currently provide one undo transaction
history per document.  My proposal tries to decouple contenteditable and
undoscope so that if the apps were so desired, they can share the same undo
transaction history between multiple contenteditable regions.

My proposal, however, mentions the editing host when I define a "proper
sequence of managed transactions" in order to support co-existance of
managed and manual transactions.

 Why is there a need for a 'reapply' action? How is it different from
> the 'apply' action?
>

In the case of collaborative editing apps, reapply is different from apply
because the backend server may have a tree of transaction history and may
need to consult on demand in order to determine exactly what mutations have
to happen.

What is the purpose of the UndoManager.replace function and it's
> replaceGroup argument? In general I'm not sure I fully understand
> "transaction groups". Are they different from simply a set of
> transactions which have been merged together such that they are
> done/undone together?
>

Yeah, sorry about that.  I should clarify that part of the design.

*UndoManager.replace*
The key observation is that ManagedTransaction is constrained to work only
with a "proper sequence of managed transactions".  Whenever an app inserts a
manual transaction or directly mutates the DOM under the same editing host,
the UA won't be able to unapply/reapply the existing ManagedTransaction
created by user editing actions; i.e. inserting a manual transaction breaks
the existing managed transactions.  Without this constraint, however, the UA
is required to keep track of all DOM mutations happening in the undo scope
:(

Given this constraint, the apps that do use managed transactions such as
collaborative editing apps need to replace the managed transactions inserted
by the UA by the corresponding manual transaction when user types text.

*Transaction Group*
When a user types "hello", he isn't really typing all of "hello" at once but
rather inserting character "h", "e", "l", "l", and "o", letting the UA
insert each letter as a separate managed transaction in the order.  However,
when the user undoes or redoes this typing command, the entire "hello" needs
to removed.  This is accomplished as grouping 5 managed transactions for
inserting "h", "e", "l", "l", and "o" as a transaction group.

Why expose explicit Transaction objects. What value does that provide?
>

I admit this is more of stylistic issue rather than the technical limitation
but given a transaction already has label and apply "properties", it seemed
more natural for it to be an object.  That'll allow us to add more
properties in the future.

In particular, I really wanted to provide a mutation list as discussed on
the mutation events replacement thread on public-webapps.  This allows apps
to determine which transaction did what without having to listening to each
mutation event, and makes it easier to replace managed transactions by
manual transactions as described above.

- Ryosuke



More information about the whatwg mailing list