Skip to content

Instantly share code, notes, and snippets.

@marrs
Last active August 29, 2015 14:18
Show Gist options
  • Save marrs/2c4946df7d7d03fc9451 to your computer and use it in GitHub Desktop.
Save marrs/2c4946df7d7d03fc9451 to your computer and use it in GitHub Desktop.
Suggested native routing

Native Routing in the Browser

It is often the case a website's pages are made up of standard content, such as a site logo, navigation, breadcrumb, footer, etc, and then the content that is specific to the page itself. I shall refer to these as "template" and "content" from now on. These are concepts only, they have no concrete representation below.

The content makes up the meat of the resource and will be unique for each page.

The template, in contrast, will change a little from page to page. For example, the highlighted item in the navigation menu will change, as will the contents of the breadcrumb, but most parts of the template will remain static.

The following proposal explores the possible ways of using XML-HTTP-Requests natively to allow users to navigate between site resources without having to download the entire page every time.

The term native implies that the browser would be able to navigate the site in this way without the aid of Javascript.

Here is a simple example:

<head>
  <routes>
    <!-- Any element implementing this route will update
    its contents with the resource at dst if the user
    navigates to src through an href -->
    <route src="/articles/:id" dst="/_partials/articles/:id" />
  </routes>
</head>
<body>
  <!-- User navigates to a URL through an anchor -->
  <a href="/articles/foo">Foo</a>
  <a href="/articles/bar">Bar</a>
  <!-- Any elements resolving that url get updated with
  the contents of a mapped partial if it exists. -->
  <div class="content" route="/articles/:id"></div>
</body>

Notice that the styling of the navigation is unaffected by the routing. Implementing something like this would be a bad idea:

<a class="active" href="/articles/foo">Foo</a>
<a href="/articles/bar">Bar</a>

The menu item for "Foo" would remain highlighted regardless of what page we were actually on.

To get around this we could progressively enhance with Javascript, but the default user experience would still be poor.

To work without Javascript, we could implement a pseudo-selector for anchor tags to match any tag whose href matches the current URL.

a:current-location {
  color: darkblue;
}

An alternative approach is to have a separate resource for navigation that also matches the route. This might be useful if the CSS alone isn't enough. For this we need to add the ability to have one route mapping to many resources, which we achieve with named routes.

<routes>
  <!-- This example uses a named route so that one src
  can resolve to multiple destinations. The bound element
  decides which to use. -->
  <route name="route1" src="/articles/:id" dst="/_partials/articles/:id" />
  <route name="route2" src="/articles/:id" dst="/_partials/articles/:id/nav" />
</routes>

Now we can assign a route to an element by its name, rather than its source. This time the entire contents of <nav> will be replaced.

<nav route="route2">
 <a class="active" href="/articles/foo">Foo</a>
 <a href="/articles/bar">Bar</a>
</nav>
<div class="content" route="route1"></div>

If we carried on and added more routes, we might find that we want to refactor the route definition a little bit. Some data could be refactored to the <routes> tag.

<routes>
  <route name="article.body" src="/articles/:id" dst="/_partials/articles/:id/content" />
  <route name="article.summary" src="/articles/:id" dst="/_partials/articles/:id/summary" />
  <route name="article.title" src="/articles/:id" dst="/_partials/articles/:id/title" />
</routes>

<!-- with simple concatenation rules, could become -->
<routes name="article." src="/articles/:id" dst="/_partials/articles/:id/">
  <route name="body" dst="content" />
  <route name="summary" dst="summary" />
  <route name="title" dst="title" />
</routes>

At this point we have the beginings of a templating engine. Indeed, with more partials we can template more and more of the page. Taken to its logical extreme you could replace large parts of an MVC framework with this, although this isn't something I'm advocating at this point.

<a href="/articles/foo">Foo</a>
<a class="active" href="/articles/bar">Bar</a>
<a class="active" href="/articles/foo">Foo</a>
<a href="/articles/bar">Bar</a>
<head>
<routes>
<!-- Not that this is the intention, but you could use this as the basis
of an MV* framework, where the routes map to view models(? Maybe more like
partials actually). Realistically, this would require an engine on the server
to transform the object tree into a set of resources. Not necessarily the
fastest implementation, although it would enable you to download only the
parts of a model the document needs. -->
<route name="article.body" src="/articles/:id" dst="/_partials/articles/:id/content" />
<route name="article.summary" src="/articles/:id" dst="/_partials/articles/:id/summary" />
<route name="article.title" src="/articles/:id" dst="/_partials/articles/:id/title" />
</routes>
<!-- Alternative version where routes are grouped -->
<routes name="article." src="/articles/:id" dst="/_model/articles/:id/">
<route name="body" dst="content" />
<route name="summary" dst="summary" />
<route name="title" dst="title" />
</routes>
</head>
<body>
<!-- User navigates to a URL through an anchor -->
<a href="/articles/foo">Foo</a>
<a href="/articles/bar">Bar</a>
<!-- Any elements resolving that url get updated with
the contents of a mapped partial if it exists. -->
<h3 route="article.title">Default Header</h3>
<div route="article.summary"></div>
<div route="article.content"></div>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment