- From: Jonas Sicking <jonas@sicking.cc>
- Date: Fri, 29 Jul 2011 17:08:37 -0700
On Tue, Jul 26, 2011 at 11:34 PM, Ryosuke Niwa <rniwa at webkit.org> wrote: > Hi all, > In the last couple of weeks, I've been working with developers of CKEditor, > TinyMCE, and Google Docs to come up with new API for undo and redo. > Why? Because undo and redo are broken on the Web today. Whenever Web apps > try to add a custom editing operation without using execCommand or do a "fix > up" after browser executes a user editing action, user agents get confused > by DOM mutations made by the apps and won't be able to undo or redo user > editing actions and execCommand. This forces Web apps to re-implement undo > and redo themselves, and in fact, many rich text editors store innerHTML of > a contenteditable element as a string in their internal undo transaction > history (a.k.a undo stack). > Also, there's no way for Web apps to add new undo item and populate undo and > redo menus on user agent's native UI. ?In addition, if an editor app has a > widget with input/textarea, then the undo stack of the editor gets confused > when the widget goes away because the undo transaction history exists only > per document. > In order to solve above and numerous other problems, we've come to a > conclusion that we need to?add UndoManager and Transaction. > UndoManager is an interface for managing undo transaction history. ?It > exists on a document and an element with the undoscope content attribute. > ?UndoManager applies new transaction (i.e. make undoable DOM changes) and > manage them. ?The main purpose of UndoManager is to communicate the list of > undoable items with the user agent so that the user agent can provide a > native UI (e.g. populating menu items with them). > A transaction is a collection of DOM mutations that can be applied, > unapplied, or reapplied. UndoManager manages transactions and execute > unapply and reapply upon undo and redo respectively. > There are two types of DOM transactions: > > Managed transaction - the app supplies apply() and the user agent > automatically takes care of undo and redo. It is compatible with user > editing actions and editing commands, and allows Web apps to easily add new > editing operations or fix up DOM after user editing actions or editing > commands and still have the user agent manage the undo and redo. > Manual transaction - the app supplies apply(), unapply(), and reapply() > and?the app takes the full control of undo and redo. However, it is NOT > compatible with user editing actions, editing commands, or managed > transactions, meaning that, the user agents won't be able to undo or redo > them. This transaction is useful for apps such as a?collaborative editor > that implements domain-specific undo or redo. > > You can see more concrete definitions of UndoManager and Transaction at: > https://rniwa.com/editing/undomanager.html and see a list of uses cases > at?https://rniwa.com/editing/undomanager-usecases.html. ?The documents are > incomplete and I need your feedback in order to refine details. This is awesome and much more thought through than my proposal! I really do like the undoscope attribute, that is something that is definitely needed. But I think it should simply be a boolean attribute, a'la disabled for example. 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. It does however seem to me that the proposal is unnecessarily complex in a few areas: Why is there a need for a 'reapply' action? How is it different from the 'apply' action? 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? Why expose explicit Transaction objects. What value does that provide? Here is my updated proposal, which will surely need to be revised once I understand the questions above better: interface UndoManager { transaction(Function callback, optional in DOMString label, optional in Boolean merge); manualTransaction(Function apply, Function unapply, optional in DOMString label, optional in boolean merge); readonly attribute unsigned long position; readonly attribute unsigned long length; DOMString? labelAt(in unsigned long index); void undo(); void redo(); void clearUndo(); void clearRedo(); readonly Node host; }; / Jonas
Received on Friday, 29 July 2011 17:08:37 UTC