<!DOCTYPE html>
<!--
 Joakim Beng's simple client-side routing example, with John Resig's simple router

 @see http://joakim.beng.se/blog/posts/a-javascript-router-in-20-lines.html

 @see http://ejohn.org/blog/javascript-micro-templating/
-->
<html>
  <head>
    <meta charset="utf-8">
    <title>Building a router</title>
    <script type="text/ecmascript">
      // Simple JavaScript Templating
      // John Resig - http://ejohn.org/ - MIT Licensed
      (function () {
        var cache = {};

        this.tmpl = function tmpl(str, data) {
          // Figure out if we're getting a template, or if we need to
          // load the template - and be sure to cache the result.
          var fn = !/\W/.test(str) ?
            cache[str] = cache[str] ||
              tmpl(document.getElementById(str).innerHTML) :

            // Generate a reusable function that will serve as a template
            // generator (and which will be cached).
            new Function("obj",
              "var p=[],print=function(){p.push.apply(p,arguments);};" +

              // Introduce the data as local variables using with(){}
              "with(obj){p.push('" +

              // Convert the template into pure JavaScript
              str
                .replace(/[\r\t\n]/g, " ")
                .split("<%").join("\t")
                .replace(/((^|%>)[^\t]*)'/g, "$1\r")
                .replace(/\t=(.*?)%>/g, "',$1,'")
                .split("\t").join("');")
                .split("%>").join("p.push('")
                .split("\r").join("\\'")
              + "');}return p.join('');");

          // Provide some basic currying to the user
          return data ? fn(data) : fn;
        };
      })();
    </script>

    <script type="text/html" id="home">
      <h1>Router FTW!</h1>
    </script>

    <script type="text/html" id="template1">
      <h1>Page 1: <%= greeting %></h1>
      <p><%= moreText %></p>
    </script>

    <script type="text/html" id="template2">
      <h1>Page 2: <%= heading %></h1>
      <p>Lorem ipsum...</p>
    </script>

    <script type="text/ecmascript" id="routing">
      // A hash to store our routes:
      var routes = {};
      // The route registering function:
      function route(path, templateId, controller) {
        routes[path] = {
          templateId: templateId,
          controller: controller
        };
      }

      // Now declare the routes.
      route('/', 'home', function () {
      });

      route('/page1', 'template1', function () {
        this.greeting = 'Hello world!';
        this.moreText = 'Bacon ipsum...';
      });

      route('/page2', 'template2', function () {
        this.heading = 'I\'m page two!';
      });

      // The router.
      var el = null;
      function router () {
        // Lazy load view element:
        el = el || document.getElementById('view');
        // Current route url (getting rid of '#' in hash as well):
        var url = location.hash.slice(1) || '/';
        // Get route by url:
        var route = routes[url];
        // Do we have both a view and a route?
        if (el && route && route.controller) {
          // Render route template with John Resig's template engine:
          el.innerHTML = tmpl(route.templateId, new route.controller());
        }
      }

      // Listen on hash change:
      window.addEventListener('hashchange', router);
      // Listen on page load:
      window.addEventListener('load', router);
    </script>
  </head>

  <body>
    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#/page1">Page 1</a></li>
      <li><a href="#/page2">Page 2</a></li>
    </ul>

    <div id="view"></div>
  </body>
</html>