/** * @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; } /** * Set the target content to the template result. * * Use only if global "ready" is true, otherwise global "templates" may not be * entirely initialized. * * @param {DOMElement} target * The element in which to inject the template output. * @param {string} name * The name of the template to render. * @param {Object} context * The template context. * * @returns {void} * * @globals templates */ function render(target, name, context) { var output = null; var template = templates[name]; if (!template) { console.error("Template not found", name); return; } output = template(context); target.innerHTML = output; } /** * The router. * * @returns {void} * * @globals contentElement, ready, EVENT_TEMPLATES_LOADED */ function router() { var context = null; var CurrentRoute = null; var listener = null; var path = null; var query; var templateName = null; var urlArray = null; // Current route url (getting rid of "#" in hash as well): var matches = location.hash.match(/^#?([\w]*)(?:\?)?(.*)?/); path = matches[1] ? matches[1] : "/"; query = matches[2] ? matches[2].split("&").reduce(function (accu, v) { var vArray = v.split("="); accu[vArray[0]] = vArray[1]; return accu; }, {}) : {}; // console.log("url", url, "path", path, "queryObject", queryObject); // Get route by path: CurrentRoute = routes[path]; // Do we have a route ? if (CurrentRoute) { // Obtain the template context by passing the query to the controller. context = new CurrentRoute(query); // Render template with Handlebars templateName = (path === "/") ? "home" : path; if (ready) { console.log("Immediate render"); render(contentElement, templateName, context); } else { console.log("Deferred render"); listener = contentElement.addEventListener(EVENT_TEMPLATES_LOADED, function () { render(contentElement, templateName, context); contentElement.removeEventListener(EVENT_TEMPLATES_LOADED, listener); }); } } else { console.warn("Content found but no route matching", path); } } // Bind router to browser events. window.addEventListener("hashchange", router); window.addEventListener("load", router); // Route declarations. route("/", function (q) { console.log("Home controller", q); }); route("class", function (q) { console.log("Class controller", q); this.greeting = "Hello world!"; this.moreText = "Bacon ipsum..."; }); route("species", function (q) { console.log("Species controller", q); this.heading = "I\"m page two!"; });