[whatwg] <a onlyreplace>

Tab Atkins Jr. jackalmage at gmail.com
Sat Oct 17 08:06:17 PDT 2009


On Sat, Oct 17, 2009 at 12:22 AM, Jonas Sicking <jonas at sicking.cc> wrote:
> On Fri, Oct 16, 2009 at 11:06 AM, Tab Atkins Jr. <jackalmage at gmail.com> wrote:
>> Promoting this reply to top-level because I think it's crazy good.
>>
>> On Fri, Oct 16, 2009 at 11:09 AM, Aryeh Gregor <Simetrical+w3c at gmail.com> wrote:
>>> On Fri, Oct 16, 2009 at 10:16 AM, Tab Atkins Jr. <jackalmage at gmail.com> wrote:
>>>> As well, this still doesn't answer the question of what to do with
>>>> script links between the static content and the original page, like
>>>> event listeners placed on content within the <static>.  Do they get
>>>> preserved?  How would that work?  If they don't, then some of the
>>>> benefit of 'static' content is lost, since it will be inoperable for a
>>>> moment after each pageload while the JS reinitializes.
>>>
>>> Script links should be preserved somehow, ideally.  I would like to
>>> see this be along the lines of "AJAX reload of some page content,
>>> without JavaScript and with automatically working URLs".
>> [snip]
>>> I'm drawn back to my original proposal.  The idea would be as follows:
>>> instead of loading the new page in place of the new one, just parse
>>> it, extract the bit you want, plug that into the existing DOM, and
>>> throw away the rest.  More specifically, suppose we mark the dynamic
>>> content instead of the static.
>>>
>>> Let's say we add a new attribute to <a>, like <a onlyreplace="foo">,
>>> where "foo" is the id of an element on the page.  Or better, a
>>> space-separated list of elements.  When the user clicks such a link,
>>> the browser should do something like this: change the URL in the
>>> navigation bar to the indicated URL, and retrieve the indicated
>>> resource and begin to parse it.  Every time an element is encountered
>>> that has an id in the onlyreplace list, if there is an element on the
>>> current page with that id, remove the existing element and then add
>>> the element from the new page.  I guess this should be done in the
>>> usual fashion, first appending the element itself and then its
>>> children recursively, leaf-first.
>>
>> This. Is. BRILLIANT.
>
> [snip]
>
>> Thoughts?
>
> We actually have a similar technology in XUL called "overlays" [1],
> though we use that for a wholly different purpose.

Interesting.  It does seem like nearly the same idea in practice.

> Anyhow, this is certainly an interesting suggestion. You can actually
> mostly implement it using the primitives in HTML5 already. By using
> pushState and XMLHttpRequest you can download the page and change the
> current page's URI, and then use the DOM to replace the needed parts.
> The only thing that you can't do is "stream" in the new content since
> mutations aren't dispatched during parsing.

Yup, it's basic AJAX (or AHAH if you want to be specific, I guess)
with some history hacking.  Doing this in JS is completely possible
(it's done today), it's just non-trivial and, duh, requires js.

(However, I'm still not sure what the accessibility/searchability
story is for AJAXy single-page apps that operate similarly.  I'm
concerned that it's suboptimal, but I'm pretty sure that @onlyreplace
solves those issues by allowing such clients to just perform ordinary
navigation if they don't want to/don't know how to deal with
@onlyreplace properly.  The fact that @onlyreplace is a simple
declarative mechanism, however, may allow such clients to finally
handle this sort of interaction properly, as they can predict in
advance which parts of the page will change; something that is
difficult/impossible to do in AJAX apps without actually running the
JS and watching for mutation.)

> For some reason I'm still a bit uneasy about this feature. It feels a
> bit fragile for some reason. One thing I can think of is what happens
> if the load stalls or fails halfway through the load. Then you could
> end up with a page that contains half of the old page and half the
> new.

I imagine a browser could stall on swapping in the new bits until it's
found all of them?  I'm not sure if that would give too much of a
penalty in common situations or not.

This same sort of situation can occur with an AJAX load too.  There
you have error callbacks, though.  Does it feel like something similar
might be necessary?  I'd prefer to keep this as transparent as
possible.

Heck, though, this situation can occur with an *ordinary* load.  When
that happens you just get a partial page.  We don't have special
handling for that; we just expect the user to hit Refresh and carry
on.  @onlyreplace is supposed to be robust against refreshing, so do
we expect partial-page loads to be any worse under it than under
ordinary navigation?

> Also, what should happen if the user presses the 'back' button?

If the browser can remember what the page state was previously, just
swap in the old parts.  If not, but it at least remembers what parts
were replaced, make a fresh request for the previous page and
substitute in just those bits.  If it can't remember anything, just do
an ordinary navigation with a full page swap.

It should act as exactly like current Back behavior as possible.
We're not really playing with the semantics of navigation, so that
shouldn't be difficult.

> Don't know how big of a problem these issues are, and they are quite
> possibly fixable. I'm definitely curious to hear what developers that
> would actually use this think of the idea.

As a reminder, I'm just a web developer.  ^_^  I'd use this in an
instant on my company's sites if I could.  Just run a regex over the
existing content in the db, update links in the templates, and I'm
done.  I can even be a little intelligent about things and only
replace content+breadcrumbs (leaving the section nav alone) on links
that I know will stay within the section.


On Sat, Oct 17, 2009 at 3:53 AM, Gregory Maxwell <gmaxwell at gmail.com> wrote:
> but a query parameter is not a good method: it'll
> break bookmarking ... and preserving bookmarking is one of the most
> attractive aspects of this proposal.

Yeah, I thought of that, but didn't want to further lengthen my email
with workarounds.  You could add a timestamp in the query params as
well, and return the full page if the timestamp is more than 10s old
regardless of what's requested.  Or you could use xState hacking to
remove the query params from the displayed url.

> I'm guessing that the rare case where you need to write into a
> replaced ID you can simply have a JS hook that fires on the load and
> fixes up the replaced sections as needed.

The functioning of load events here confuses me a bit, because I've
never done any hacking in that area and so don't understand the
mechanics well enough to know what's reasonable.  Should the new page
still fire a load event once its replaceable content has loaded?  I'm
guessing that the old page never fires an unload event?  I really
don't know what should happen in this area.

(After giving it a little thought, though, I think we shouldn't change
the semantics of load/unload/etc.  These are still useful, after all,
for when the page *is* completely unloaded or loaded, such as on first
visit or when the user hits Refresh.  We'd probably want a new set of
events that fire at the elements being swapped out, and then at the
new elements once they've been pushed in.)


On Sat, Oct 17, 2009 at 4:51 AM, Nelson Menezes
<flying.mushroom at gmail.com> wrote:
> You'd obviously
> also need a JS hook to be able to invoke this functionality
> programmatically (location.onlyreplace...?)

Ah, right, something was tickling my brain when I was suggesting
hooking the links and rewriting urls, but I didn't follow it through.
This is what it was.  Since @onlyreplace gives side-band information,
it can't be easily communicated purely through the url (without
query-param hacking that requires server-side handling, yuck).  So
yeah, location.onlyreplace or something similar would be necessary.


More information about the whatwg mailing list