Skip to content

Instantly share code, notes, and snippets.

@beyond-code-github
Created April 5, 2013 08:54
Show Gist options
  • Save beyond-code-github/5317736 to your computer and use it in GitHub Desktop.
Save beyond-code-github/5317736 to your computer and use it in GitHub Desktop.
State machine routing Javascript prototype
<html>
<head>
<title>State machine routing prototype</title>
</head>
<body>
<h3>State machine routing concept</h3>
<p>Extremely flexible mechanism for defining routes for web applications</p>
<ul>
<li>Hierarchical
</li>
<li>Efficient
</li>
<li>Easy to configure
</li>
</ul>
<h3>Try it out with the following routes:</h3>
<p>
/Products/<br />
/Products/{id}<br />
/Categories/<br />
/Categories/id}<br />
/Products/{id}/Categories<br />
/Products/{id}/Categories/{id}<br />
</p>
<p><strong>View the source to see configuration</strong></p>
<label for="route">Enter route here: http://localhost</label>
<input type="text" id="route" value="/Api/Products/1" style="width: 600px">
<input type="button" id="go" value="Go" onclick="execute(route.value);">
<h3>Output:</h3>
<div id="output"></div>
<script type="text/javascript">
function execute(route) {
var target;
var params = {};
var categoryId = {
matcher: /[0-9]/,
action: function (value) { params.categoryId = value; }
};
var categories = {
matcher: /Categories/,
action: function (value) { target = "Categories controller"; },
transitions: [categoryId]
};
var productId = {
matcher: /[0-9]/,
action: function (value) { params.productId = value; },
transitions: [categories]
};
var products = {
matcher: /Products/,
action: function (value) { target = "Products controller"; },
transitions: [productId]
};
var apiRoot = {
matcher: /Api/,
transitions: [products, categories]
};
success = processRoute(route, [apiRoot]);
var output = document.getElementById("output");
output.innerHTML = "";
if (success) {
output.innerHTML = output.innerHTML + "<p><strong>Target:</strong> " + target + "</p>";
output.innerHTML = output.innerHTML + "<p><strong>Parameters:</strong>";
output.innerHTML = output.innerHTML + "<ul>";
for (prop in params) {
if (params.hasOwnProperty(prop)) {
output.innerHTML = output.innerHTML + "<li>" + prop + ": " + params[prop] + "</li>";
}
}
output.innerHtml = output.innerHtml + "</ul></p>";
}
else {
output.innerHTML = "<p><strong>404</strong></p>";
}
}
function processRoute(route, availableTransitions) {
if (!route || !availableTransitions || availableTransitions.length == 0) {
return false;
}
var remainingRoute = route;
var segment = null;
// Identify the next valid segment of the route, and remove this from the remaining route
while (!segment || segment == "") {
var slashIndex = remainingRoute.indexOf("/");
if (slashIndex >= 0) {
segment = remainingRoute.substring(0, slashIndex);
remainingRoute = remainingRoute.substring(slashIndex + 1, remainingRoute.length);
} else {
segment = remainingRoute;
remainingRoute = null;
break;
}
}
// Check for transitions that match the segment
var matchedTransition;
for (index in availableTransitions) {
if (availableTransitions[index].matcher.test(segment)) {
matchedTransition = availableTransitions[index];
break;
}
}
if (!matchedTransition) {
return false;
}
// Perform any actions
if (matchedTransition.action) {
matchedTransition.action(segment);
}
// Recurse for remainder of the route
if (remainingRoute) {
if (matchedTransition.transitions && matchedTransition.transitions.length > 0) {
return processRoute(remainingRoute, matchedTransition.transitions);
} else {
return false;
}
}
return true;
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment