W3C home > Mailing lists > Public > whatwg@whatwg.org > October 2009

[whatwg] <a onlyreplace>

From: Tab Atkins Jr. <jackalmage@gmail.com>
Date: Fri, 16 Oct 2009 13:06:53 -0500
Message-ID: <dd0fbad0910161106r628fe6c5me6b3db686a3188b9@mail.gmail.com>
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.

Single-page apps are already becoming common for js-heavy sites.  The
obvious example is something like Gmail, but it's becoming more common
everywhere.  The main benefit of doing this is that you never dump the
script context, so you only have to parse/execute/apply scripting
*once* across the page, making really heavy libraries actually usable.
 In fact, writing a single-page app was explicitly given as a
suggestion in the "Global Script" thread.  Even in contexts with
lighter scripts, there can still be substantial run-time rewriting of
the page which a single-page app can avoid doing multiple times (frex,
transforming a nested list into a tree control).

The problem, though, is that single-page apps are currently a bit
clunky to write.  They require javascript to function, and the
necessary code is relatively large and clunky, even in libraries like
jQuery which make the process much simpler.  It requires you to
architect your site around the design, either producing a bunch of
single-widget files that you query for and slap into place, or some
relatively complex client-side logic to parse data structures into
HTML.  It's also very hard to get accessibility and graceful
degradation right, requiring you to basically completely duplicate
everything in a static form.  Finally, preserving
bookmarkability/general deeplinking (such as from a search engine)
requires significant effort with history management and url hacking.

Aryeh's suggestion, though, solves *all* of these problems with a
single trivial attribute.  You first design a static multi-page site
like normal, with the only change being this attribute on your
navigation links specifying the dynamic/replaceable portions of the
page.  In a legacy client, then, you have a perfectly serviceable
multipage site, with the only problems being the reloading of js and
such on each pageload.

In a supporting client, though, clicking a link causes the browser to
perform an ordinary request for the target page (requiring *no*
special treatment from the author), parse/treebuild the new page, and
then yank out the relevant fragments and replace bits in the current
page with them.  The url/history automatically updates properly;
bookmarking the page and visiting it later will take you to
appropriate static page that already exists.  Script context is
maintained, listeners stay around, overall page state remains stable
across 'pageloads'.

It's a declarative, accessible, automatic, and EASY way of creating
the commonest form of single-page apps.

This brings benefits to more than just the traditional js-heavy apps.
My company's web site utilizes jQuery for a lot of small upgrades in
the page template (like a hover-expand accordion for the main nav),
and for certain things on specific pages.  I know that loading the
library, and applying the template-affecting code, slows down my page
loads, but it's not significant enough to be worth the enormous effort
to create an accessible, search-engine friendly single-page app.  This
would solve my problem trivially, though, providing a better overall
UI to my visitors (snappier page loads) without any real effort on my
part, and without harming accessibility or SEO.

This also trivially replaces most/all uses of bad mechanisms like
<frameset> used to address similar problems (such as maintaining state
on a complex nav).

The only addition I'd make to this is to allow a tag in the <head>
that specifies default replaceability for all same-origin links.
Perhaps just an attribute on <base>?  It would accept a
space-separated list of ids, just like the @onlyreplace attribute on
<a>s.  An @onlyreplace attribute on a link would completely override
this default (this would allow me to, frex, have the mainnav only
replace the subnav, while all other links replace the content
instead).

I believe that the single-page app pattern solves a lot of problems
that exist today and will persist into the future, and that it's
worthy of being made into a declarative, html-supported mechanism.  I
also believe that Aryeh's suggestion is the correct way to go about
this.

The only problem I can see with this is that it's possible for authors
to believe that they only need to actually write a single full page,
and can just link to fragments containing only the chunk of content to
be replaced.  This would mostly break bookmarking and deeplinking, as
visitors would just receive a chunk of unstyled content separated from
the overall page template.  However, because it breaks so *visibly*
and reliably (unlike, say, framesets, which just break bookmarking by
sending you to the 'main page'), I think there would be sufficient
pressure for authors to get this right, especially since it's so
*easy* to get it right.

Thoughts?

~TJ
Received on Friday, 16 October 2009 11:06:53 UTC

This archive was generated by hypermail 2.4.0 : Wednesday, 22 January 2020 16:59:18 UTC