/* Usage: var r = require('routrly'); var module = { onCreate: function() { }, onPostCreate: function() { }, onDestroy: function() { }, onPreDestroy: function(onfinish) { onfinish(); // calls onDestroy when finished } }; // r.route("/place", InfoBox); r.route("/thing", [ r("div", "okay"), r(InfoBox, {name: "Test", msg: "okay"}) ]); // var InfoBox = {}; InfoBox.onCreate = function(props) { return r("div", "Info Box"); }; InfoBox.onPostCreate = function(node) { }; InfoBox.onPreDestroy = function(node, done) { window.setTimeout(1000, function() { done(); // calls onDestroy }); }; // these assume the current hashbang location r.manage(module); // basic object with handlers and whatnot r.manage(new Module(thing)); // created object with handler and whatnot // these specify hashbang locations r.manage(module, "/api/thing"); // basic object in /api/thing context // all amalgamations of r() r("div"); r("span", "test"); r(InfoBox, "test"); r("span", {onclick: function(e){ e.target.value = "pressed"; }, value: "click me"}); r("ul", [ r("li"), r("li") r("ul", { onclick: function(e) { }, value: [ r("li"), r("li") ] ]); */ var routrly = function(type, attr) { if (typeof attr == 'undefined') { } if (obj.constructor === Array) { } else if (obj.constructor === RouteNode) { } else if (obj.constructor === Object) { } // if RouteNode // else if string (div,etc.) // else if Object }; function getRouteParts(routename) { return routename.split(/(?=\/)/g); // "/1/2/3" -> ["/1", "/2", "/3"] } function getRouteFromHash(hash) { return getRouteParts(hash.replace('#!','')); } routrly.activateRoute = function(path) { var parts = getRouteParts(path); var ctx = routrly.mRoutes; var i = 0; do { ctx.activate(); ctx = ctx.parts[parts[i]]; i++; } while(i <= parts.length && ctx) } routrly.deactivateRoute = function(path) { var parts = getRouteParts(path); var ctx = routrly.mRoutes; var i = 0; for (var i = 0; i < parts.length; i++) { ctx = ctx.parts[parts[i]]; } if (ctx) { ctx.deactivate(); } } routrly.hashchange = function(e) { var old_path, new_path; var old_parts, new_parts; var ctx; // on hashchange, check if any of our routes have gone out of scope var hash = location.hash.replace('^#/', '').replace('#!', ''); routrly.mRoute = hash; old_parts = getRouteParts(routrly.mLastHash); new_parts = getRouteParts(hash); // traverse up to change ctx = routrly.mRoutes; for (var i = 0; i < old_parts.length; i++) { if (new_parts[i] != old_parts[i]) { // found our out of scope spot routrly.deactivateRoute(old_parts.slice(0,i+1).join('')); break; } } routrly.activateRoute(hash); routrly.mLastHash = hash; } function RouteGroup(parent) { this.parent = parent; this.parts = {}; this.procs = []; this.activate = function() { for (var i = 0; i < this.procs.length; i++) { this.procs[i].doActivate(); } } this.deactivate = function() { for (var i in this.parts) { this.parts[i].deactivate(); } var i = this.procs.length; while (i--) { this.procs[i].doDeactivate(); if (this.procs[i].proc.destroy) { this.procs.splice(i,1); } } } this.render = function() { } } function RouteProc(proc) { this.active = false; this.proc = proc; this.doActivate = function() { if (this.active) return; if (this.proc.activate) this.proc.activate(); this.active = true; } this.doDeactivate = function() { if (!this.active) return; if (this.proc.deactivate) this.proc.deactivate(); this.active = false; } this.doRender = function(attr) { if (this.proc.render) return this.proc.render(attr); } } /** Adds a process module to the given route path. */ routrly.manage = function(proc, routepath) { if (!routepath) routepath = routrly.route(); var rpaths, ctx; rparts = getRouteParts(routepath); ctx = routrly.mRoutes; for (var i = 0; i < rparts.length; i++) { if (!ctx.parts[rparts[i]]) { ctx.parts[rparts[i]] = new RouteGroup(ctx); } ctx = ctx.parts[rparts[i]]; } // at this point ctx should point to where we want the proc to reside if (ctx) { ctx.procs.push(new RouteProc(proc)); // TODO: check if our current location (window.hash?) matches our routepath and thereafter run the proc's onCreate if (routepath == location.hash.replace("#!", "")) { ctx.procs[ctx.procs.length-1].doActivate(); } } } /** Routes to the given path -- basically sets hash */ routrly.route = function(routepath) { if (!routepath) return routrly.mRoute; routrly.mRoute = routepath; location.hash = '!'+routepath; return routrly.mRoute; } /** Calls render for current route's procs */ routrly.render = function() { do { for (var j = 0; j < ctx.procs.length; j++) { ctx.procs[j].doRender(); } ctx = ctx.parts[parts[i]]; i++; } while(i <= parts.length && ctx) } routrly.mRoute = ""; routrly.mRoutes = new RouteGroup(); routrly.mLastHash = location.hash.replace('^#/', '').replace('#!',''); addEventListener('hashchange', routrly.hashchange); module.exports = routrly;