123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /**
- * @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;
- // Current route url (getting rid of "#" in hash as well):
- var matches = location.hash.match(/^#?([\w]*)(?:\?)?(.*)?/);
- path = matches[1] ? matches[1] : "/";
- path = path.toLowerCase();
- 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);
- window.location.assign("");
- }
- }
- // Bind router to browser events.
- window.addEventListener("hashchange", router);
- window.addEventListener("load", router);
- // ======== Route context functions ============================================
- function AboutContext() {
- console.log("About page");
- }
- function ClassContext(q) {
- var category = animals_data.category;
- var animals = null;
- var klass;
- this.class = q.class ? q.class : null;
- if (!this.class) {
- window.location.assign("");
- }
- console.log("Class page(" + this.class + ")");
- for (klass in category) {
- if (category.hasOwnProperty(klass)) {
- if (category[klass].name === this.class) {
- animals = category[klass].animals;
- break;
- }
- }
- }
- this.animals = animals;
- }
- /**
- * Home context.
- *
- * - category
- * - indicators
- *
- * @constructor
- */
- function HomeContext() {
- var i;
- console.log("Home page");
- // jQuery doesn't find the carousel without the 0 (or more) timeout.
- setTimeout(function () { $("#home-carousel").carousel(); }, 0);
- // Expose animals category to build the carousel.
- this.category = animals_data.category;
- // Carousel indicators count: JS doesn't have a range() function.
- this.indicators = [];
- for (i = 0; i < Object.keys(this.category).length; i++) {
- this.indicators.push(i);
- }
- }
- /**
- * Species context
- *
- * @param {Object} q
- * - class
- * - species
- * @constructor
- */
- function SpeciesContext(q) {
- var category = animals_data.category;
- var klass = null;
- var speciesArray = null;
- var species;
- var speciesIndex;
- var prop;
- if (!q.class || !q.species) {
- console.error("Missing class or species parameter.");
- window.location.assign("");
- return;
- }
- console.log("Species page(" + q.class + ", " + q.species + ")");
- this.class = q.class ? q.class : null;
- for (klass in category) {
- if (category.hasOwnProperty(klass)) {
- if (category[klass].name === this.class) {
- speciesArray = category[klass].animals;
- break;
- }
- }
- }
- // No species means class was not found.
- if (!speciesArray) {
- console.warn("No species found for class ", this.class);
- window.location.assign("");
- }
- for (speciesIndex in speciesArray) {
- if (speciesArray.hasOwnProperty(speciesIndex)) {
- species = speciesArray[speciesIndex];
- if (species.name === q.species) {
- for (prop in species) {
- if (species.hasOwnProperty(prop)) {
- this[prop] = species[prop];
- }
- }
- break;
- }
- }
- }
- }
- // ======== Route binding ======================================================
- /**
- * Route binding:
- *
- * - route context functions return a context instance.
- * - on invalid arguments, they redirect to the home page
- */
- route("/", HomeContext);
- route("class", ClassContext);
- route("species", SpeciesContext);
- route("about", AboutContext);
|