More use-cases for mutation events replacement

When discussing mutation events use-cases, mostly so far people have
been talking about editors.  However, I think mutation event
replacements would have a much more general appeal if they were easily
usable in certain cases with little performance impact.  Specifically,
one use-case I've run into a lot is "I want to modify some class of
node soon after it gets added to the DOM, but before it's actually
painted".  Examples of where this has come up for me in practice:

1) Some images in Wikipedia articles are offensive to some users, who
may want to block them by default.  However, we want to serve the same
page content to different users for caching reasons, only varying the
HTML used for the interface.  One way to solve this would be to add
classes to potentially offensive images, then have a script run that
replaces the image with a placeholder before it's visible to the user.
 Currently, as far as I can tell, the only way to do this is to put a
<script> immediately after the <img>.  This could theoretically fail
if the <script> winds up getting parsed too long after the <img>, like
if it winds up in a different TCP segment that then gets dropped and
takes a few seconds to resend while the image loads from cache.  More
practically, it's incompatible with CSP, which prohibits inline
script.  It also can't be used in situations like Wikipedia, where
administrators can add scripts to the <head> but cannot add inline
script.  It's also excessively verbose if there are lots of places per
page you need to do it.  (Actual writeup of requirements, albeit
abandoned: <http://www.mediawiki.org/wiki/User:Simetrical/Censorship>)

2) Some pages have content that should be collapsed by default with a
way for the user to un-collapse it, but they should be uncollapsed if
the user has script disabled, since otherwise the user won't be able
to access the contents.  This is true for some Wikipedia infoboxes,
for instance.  <details> might solve this use-case without the need
for script, but it might not (e.g., styling might not be flexible
enough).  Supposing it doesn't, the way you'd currently have to do
this is add a <script> right after the opening tag that collapses it
and adds the uncollapse button.  But again, inline script is
incompatible with CSP, and incompatible with setups like Wikipedia
where you might not be allowed to add inline script, and excessively
verbose if there are many occurrences per page.

3) In current HTML drafts, <details> auto-closes <p>.  I just filed a
bug asking that it be made an inline element that doesn't auto-close
<p>: <http://www.w3.org/Bugs/Public/show_bug.cgi?id=13345>.  I want
this because smaug complained that my specs didn't contain rationale,
and when I pointed out that I had detailed rationale in comments, he
said I should make it visible to the reader.  So I want to have inline
<details> at the end of some <li>'s or <p>'s.  If the change I request
is made, <details> will still auto-close <p> in current browsers, so
I'd want to work around that with a shim for browsers using the
current HTML parser.  The obvious thing to do would be to run some
script after every <details> is added that's the next sibling of a
<p>, and move it inside the <p>.  Again, this would require a lot of
repetitive use of <script>.

4) Prior to the invention of the autofocus attribute, just like in all
the cases above, the only way to reliably autofocus inputs was to add
a <script> immediately after the <input>.  This case is moot now that
autofocus exists, but it illustrates that there are more use-cases in
the same vein.

What would solve all of these use-cases is a way to register a handler
that would get notified every time an element is added to the DOM that
matches a particular CSS selector, which is guaranteed to run at some
point before the element is actually painted.  Thus it could be a
special type of event that runs when the event loop spins *before*
there's any opportunity to paint, or it could be semi-synchronous, or
whatever, as long as it runs before paint.  Then I could easily solve
all the use-cases:

1) Register a handler for "img" that changes the .src of the
newly-added Element.

2) Register a handler for ".collapsed" or whatever that sets the
appropriate part to display: none and adds the uncollapse button.

3) Register a handler for "p + details" that moves the <details>
inside the <p>.  (This would be trickier if I sometimes put <details>
in the middle of <p>, but still doable, and anyway I don't plan to.)

4) Register a handler for ".autofocus" or whatever that calls focus().

It seems to me this dovetails pretty nicely with some of the proposed
mutation events replacement APIs.  Specifically, people have been
talking about allowing filtering of events, so this use-case should be
solved easily enough if you can use CSS selectors as filters.  In that
case, the perf hit from using such events should be negligible, right?
 I think there are lots of cases like the four I gave above where this
sort of API would be handy for very general-purpose websites, not just
special cases like editors.  I know there are more times than this
that I've wished I had such an API.  This will be especially true once
CSP becomes more mature and we want to encourage authors to move away
from using inline script -- in these use-cases, there's no existing
replacement for inline script.

Received on Sunday, 24 July 2011 16:19:13 UTC