Re: Mutation events replacement

On 7/2/2011 12:36 PM, Ryosuke Niwa wrote:
> On Sat, Jul 2, 2011 at 10:46 AM, John J. Barton
> <johnjbarton@johnjbarton.com>  wrote:
>> 1) break on mutation. In Firebug we add DOM mutation listeners to
>> implement graphical breakpoints. The replacement would work fine for
>> local, element observation breakpoints like add/remove attribute.
>> If my goal is to break on addition of elements with class="foo", then
>> I guess I have to listen for addChildlistChanged on all elements, and
>> add an additional addChildlistChanged listener for each new element?
>> So in general one would implement document observation by walking
>> the DOM and covering it with listeners?
> I don't think we can support this use case in general.  We're trying
> to avoid invoking scripts synchronously and your use case requires
> exactly that.
Are you talking about the algorithm described by Olli and Jonas:
http://www.mail-archive.com/public-webapps@w3.org/msg14008.html
? If I set a breakpoint in a listener in their algorithm I would expect 
to halt the browser before the algorithm completed and especially before 
another DOM change can occur. (An entirely separate issue is how the 
debugger mutates the document).

The only part that is async in the Mutation Event replacement is further 
DOM events.
>> 2) element transformation. The replacement fires "after" a mutation.
>> Library or tools that want to transform the application dynamically want
>> to get notification "before" the mutation.
> Why do you need to get notified before the mutation?
Because developers want to take actions before the mutation.  Removing 
mutations after they are committed is a kludge we should try to avoid.
> Again, this is
> exactly the sort of usage that causes us headaches and what we want to
> avoid because scripts can then modify DOM before we make mutations.
>> A common solution then is to bracket changes:
>> "beforeChange" or "onModelChanging"
>> "afterChange" or "onModelChanged"
>> Of course element transformation may want to prevent the current
>> change and replace it. Some changes are reversible so the observed
>> change can be countered with a remove (at unknown cost to performance
>> and user experience).
> I don't think we can address your use case here.  Scripts'
> intercepting and preventing mutations browser is about to make or
> mutating DOM in the way browser doesn't expect is exactly what we want
> to avoid.
The stated properties (goals)  of the replacement are (rephased):
   1. No script operation in the middle of mutation,
   2. Callback in order of mutation,
   3. No propagation chain,
Importantly the current proposal has an undesirable feature:
   4. DOM modification in listeners is asynchronous.
Preventing mutation in a 'before' listener still allows all of the 
properties as far as I know.

A "two-phase-commit" like solution can have all of these properties.  
Copy Jonas' AttributeChanged algorithm from the page cited above. 
Replace "...ed" with "...ing". Add a flag 'cancelChange' initially 
false.  Add step
     8b. If cancelChange is true, abort these steps and the DOM 
mutation.  Fire event DOMMutationCanceled

The 'before' version would be more powerful.

The Mutation events replacement gains its advantages from property 3 and 
especially 4.  Whether you enter the callback algorithm before or after 
the mutation does not change this. In fact I think from the API point of 
view the 'before' version is clearer.  If the developer knows that the 
callback is 'before' the mutation, they are naturally set up to think 
about the meaning of additional DOM mutations.  The arguments in the 
callback are known to be in flight.

In fact we could go one step further and eliminate the undesirable 
feature #4: if notifyingCallbacks is true, all DOM write operations 
fail.  That way developers are never surprised by DOM functions that 
fail as in the current version. Instead developers will explicitly have 
to cascade modifications via separate events. This would be a much less 
mysterious solution.  In some places Firefox already works in the 
mystery way and speaking from experience it is not fun to figure out why 
your function calls have no effect.

If you have both a before and and after event and both events prevent 
DOM write, then the programming paradigm could be clear:
    before handlers cancel mutations and signal 'after' handlers to 
stage alternatives
    after handlers stage responses to mutation or alternatives to 
canceled mutations.

jjb

Received on Sunday, 3 July 2011 17:04:47 UTC