Browse Source

Working client-side routing, but without onhashchange handling.

Frederic G. MARAND 8 years ago
parent
commit
cabbaeb5a9
8 changed files with 227 additions and 32 deletions
  1. 3 1
      assignment.css
  2. 7 0
      assignment.css.map
  3. 23 28
      assignment.js
  4. 0 0
      assignment.scss
  5. 3 2
      index.html
  6. 121 0
      routed.html
  7. 69 0
      routing.js
  8. 1 1
      templates/class.hbs

+ 3 - 1
assignment.css

@@ -1 +1,3 @@
-/* put your css code here */
+
+
+/*# sourceMappingURL=assignment.css.map */

+ 7 - 0
assignment.css.map

@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "",
+"sources": [],
+"names": [],
+"file": "assignment.css"
+}

+ 23 - 28
assignment.js

@@ -10,37 +10,32 @@ const partialNames = [
   "nav"
 ];
 
+const loadCount = templateNames.length + partialNames.length;
+
 var templates = {};
-var $content = null;
+var contentElement = document.getElementById("content");
 
-function checkLoad($target) {
-  if (Object.keys(templates).length === templateNames.length + partialNames.length) {
-    $target.trigger(EVENT_TEMPLATES_LOADED);
+function checkLoad(target) {
+  if (Object.keys(templates).length === loadCount) {
+    target.dispatchEvent(new Event(EVENT_TEMPLATES_LOADED));
   }
 }
 
-$(document).ready(function () {
-  $content = $("#content");
-
-  templateNames.forEach(function (name) {
-    const path = "templates/" + name + ".hbs";
-
-    $.get(path, function (data) {
-      templates[name] = Handlebars.compile(data);
-      checkLoad($content);
-    }, "html");
-  });
-
-  partialNames.forEach(function (name) {
-    const path = "templates/" + name + ".hbs";
-    $.get(path, function (data) {
-      templates[name] = Handlebars.compile(data);
-      Handlebars.registerPartial(name, templates[name]);
-      checkLoad($content);
-    }, "html");
-  });
-
-  $content.on(EVENT_TEMPLATES_LOADED, {}, function () {
-    $(this).html(templates.home());
-  });
+
+templateNames.forEach(function (name) {
+  const path = "templates/" + name + ".hbs";
+
+  $.get(path, function (data) {
+    templates[name] = Handlebars.compile(data);
+    checkLoad(contentElement);
+  }, "html");
+});
+
+partialNames.forEach(function (name) {
+  const path = "templates/" + name + ".hbs";
+  $.get(path, function (data) {
+    templates[name] = Handlebars.compile(data);
+    Handlebars.registerPartial(name, templates[name]);
+    checkLoad(contentElement);
+  }, "html");
 });

+ 0 - 0
assignment.scss


+ 3 - 2
index.html

@@ -17,8 +17,7 @@
   <script id="tpl-species" type="text/x-handlebars-template" src="templates/species.hbs"></script>
 
   <!-- Custom code -->
-  <script type="text/javascript" src="AnimalsData.js"></script>
-  <script type="text/javascript" src="assignment.js"></script>
+  <script type="text/ecmascript" src="AnimalsData.js"></script>
 
   <link rel="stylesheet" type="text/css" href="assignment.css" />
 </head>
@@ -27,4 +26,6 @@
 
   <div id="content"></div>
 
+  <script type="text/ecmascript" src="assignment.js"></script>
+  <script type="text/ecmascript" src="routing.js"></script>
 </body>

+ 121 - 0
routed.html

@@ -0,0 +1,121 @@
+<!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>

+ 69 - 0
routing.js

@@ -0,0 +1,69 @@
+/**
+ * @file
+ *   Contains the router code and route definitions
+ *
+ * Inspired by Joakim Beng's example.
+ *
+ * @see http://joakim.beng.se/blog/posts/a-javascript-router-in-20-lines.html
+ */
+
+
+// The routes object.
+var routes = {};
+
+// The route registering function:
+function route(path, controller) {
+  routes[path] = controller;
+}
+
+// The router.
+function router() {
+  // Current route url (getting rid of "#" in hash as well):
+  var url = location.hash.slice(1) || "/";
+
+  // Get route by url:
+  var currentRoute = routes[url];
+
+  var context = null;
+  var templateName = null;
+
+  // Do we have both a view and a route ?
+  if (contentElement) {
+    if (currentRoute) {
+      // Render route template with Handlebars:
+      context = new currentRoute();
+      templateName = (url === "/") ? "home" : url;
+
+      contentElement.addEventListener(EVENT_TEMPLATES_LOADED, function () {
+        console.log('templates', templates, 'name', url, templateName);
+        contentElement.innerHTML = templates[templateName](context);
+      });
+    }
+    else {
+      console.warn("Content found but no route matching", url);
+    }
+  }
+  else {
+    console.warn("Content not found.");
+  }
+}
+
+// Bind router to browser events.
+// window.addEventListener("hashchange", router);
+window.addEventListener("load", router);
+
+// Route declarations.
+route("/", function () {
+  console.log('Home controller');
+});
+
+route("class", function () {
+  console.log('Class controller');
+  this.greeting = "Hello world!";
+  this.moreText = "Bacon ipsum...";
+});
+
+route("species", function () {
+  console.log('Species controller');
+  this.heading = "I\"m page two!";
+});

+ 1 - 1
templates/class.hbs

@@ -1,3 +1,3 @@
 <div class="class">
-  CLASS
+  CLASS {{ greeting }} {{ moreText }}
 </div>