Skip to content

Commit

Permalink
Added base code
Browse files Browse the repository at this point in the history
  • Loading branch information
m3talsmith committed Dec 28, 2015
1 parent 9454fee commit 64ddb54
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ build/Release
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules

# Bower directory
bower_components
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# porter-router
# Porter Router

A router for the Porter framework
62 changes: 62 additions & 0 deletions RoutePath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

class RoutePath {

static forwardSlash = /\//;
static startsWithColon = /^\:/;
static validChars = '([a-zA-Z0-9-_~\\.%@]+)';
static matchForwardSlash = "\\/";


constructor(pattern, action) {
this.action = action;
this.rawPattern = pattern;
this.fragments = [];
this.tokens = [];
this.setPattern(pattern);
}

setPattern(pattern){
if (pattern instanceof RegExp) {
this.pattern = pattern;
} else {
this.pattern = this.compile(pattern);
}
}

compile(pattern) {
let parts = pattern.split(RoutePath.forwardSlash);

parts.forEach((part, index) => {
if (part.match(RoutePath.startsWithColon)) {
this.tokens.push(part.replace(RoutePath.startsWithColon, ''));
this.fragments.push(RoutePath.validChars);
} else {
this.fragments.push(part);
}
});

return this.compileRegexp();
}

compileRegexp() {
return new RegExp(this.fragments.join(RoutePath.matchForwardSlash) + "$");
}

parseTokens(path) {
// unsure why +1
let tokenLength = this.tokens.length + 1;
let matches = path.match(this.pattern);
if (!matches) {
return [];
}
let values = matches.slice(1, tokenLength);
return this.tokens.reduce((finalValues, token, index, tokens) => {
finalValues[token] = values[index];
return finalValues;
},
{} // initial finalValues
);
}
}

export default RoutePath;
87 changes: 87 additions & 0 deletions Router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

import {Channel} from "porter-client";

import {queryStringToObject} from "../utilities/helpers";
import RoutePath from "./RoutePath";


class Router {
// Broadcasts {path, search, hash, error, query, tokens}
constructor(channel) {
if (!(channel instanceof Channel)) throw "Router: a valid channel is required.";
this.channel = channel;
this.routes = [];
this.changeRoute = "changeRoute";
this.defaultRoute = null;
window.onload = e => this.connect();
}

addDefaultRoute(action) {
this.defaultRoute = new RoutePath(/([\s\S])+/, action); // matches anything
}

addRoute(pattern, action) {
this.routes.push(new RoutePath(pattern, action));
}

parseHash(hash) {
let parts = hash.split("?");
return {
path: parts[0],
search: parts[1] || null,
hash: hash,
};
}

firstMatchingRoute(parts) {
let matchingRoutes = this.routes.filter(route => {
return parts.path.match(route.pattern);
});
return matchingRoutes[0];
}

match(hash) {
let parts = this.parseHash(hash);
let route = this.firstMatchingRoute(parts)
let error = null;
if (!route) {
error = "NotFound";
route = this.defaultRoute;
}
return this.parseMessage(route, parts, error);
}

parseMessage(route, parts, error) {
if (!route) {
console.warn("Router: unmatched route and no default", hash);
return null;
}
return {
...parts,
error: error,
query: queryStringToObject(parts.search),
tokens: route.parseTokens(parts.path),
action: route.action,
};
}

updateRoute() {
console.log("updating route");
let match = this.match(window.location.hash);
console.log("match is", match);
if (match) {
console.log("route Matched", match);
this.channel.publish(this.changeRoute, match);
}
}

connect(){
window.addEventListener("hashchange", event => {
console.info("hashchange", event);
this.updateRoute();
});
this.updateRoute();
}
}

export default Router;
29 changes: 29 additions & 0 deletions bower.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "porter-router",
"homepage": "https://github.com/agrarianlabs/porter-router#readme",
"authors": [
"Jason Goldberger <[email protected]>",
"Michael Christenson II <[email protected]>"
],
"description": "A contract for a new form of communication between front and backend tech.",
"main": "index.js",
"moduleType": [],
"keywords": [
"porter",
"connector",
"channel",
"plugin",
"router"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"porter": "~0.8.0"
}
}
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Router } from './Router';
export { default as RoutePath } from './RoutePath';
32 changes: 32 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "porter-router",
"version": "0.1.0",
"homepage": "https://github.com/agrarianlabs/porter-router#readme",
"description": "A router for porter that acts as a channel to window hash changes and links hash paths to callbacks.",
"keywords": [
"porter",
"connector",
"channel",
"plugin",
"router"
],
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/agrarianlabs/porter-router.git"
},
"contributors": [
"Jason Goldberger <[email protected]>",
"Michael Christenson II <[email protected]>"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/agrarianlabs/porter-router/issues"
},
"dependencies": {
"porter-client": "^0.11.0"
}
}

0 comments on commit 64ddb54

Please sign in to comment.