![/sugarskull/](https://github.com/flatiron/SugarSkull/raw/master/img/sugarskull.png)
Website/Demo: http://flatiron.github.com/sugarskull
SugarSkull is a router. Sugarskull can handle location.hash
-based routing on the server, url.path
-based routing for HTTP requests, and optimist-based routing for cli applications. As a client side router, it's the smallest amount of glue needed for building dynamic single page applications.
On the client, SugarSkull has no dependencies---not even jquery.
Examples
Client-Side Hash Routing
<!-- body goes here -->
Server-Side HTTP Routing
var http = sugarskull = ; var router = ; var server = http; router; server;console;
Motivation
Sometimes you only need a wrench, not the toolbox with a hammer, screwdriver, etc. sugarskull is small. it does one job and does it well. It's not a framework, its a simple tool easy to add or remove. It promotes centralizing router logic so it's not intertwined throughout your code. Sugarskull was intended to replace backbone.js routes and provide a lighter weight, less sinatra-like alternative to sammy.js.
Storing some information about the state of an application within the URL allows the URL of the application to be emailed, bookmarked or copied and pasted. When the URL is visited it restores the state of the application. A client side router will also notify the browser about changes to the page, so even if the page does not reload, the back/forward buttons will give the illusion of navigation.
The HTML5 history API isn't a replacement for using the location hash. The HTML5 history API requires that a URL resolves to real assets on the server. It is also designed around the requirement that all pages should load without Javascript. SugarSkull targets script-rich applications whose audience is well-known.
Anatomy of a Route
In general, SugarSkull associates functions with routes. When routing occurs, if the route matches one defined in SugarSkull's routing table then the function(s) associated with that route are executed.
The url is divided into two parts, divided by a "#":
HTTP Routing
Server-Side
The part of the url before the "#" is considered a server-side path, and is routed server-side.
Client-Side
The part of the url after the "#" is not considered part of the document's path, and is routed client-side for single-page apps.
CLI
SugarSkull routes for cli options are based on command line input instead of url, based on the output of optimist.
Usage
Constructor
var router = ;
routes (required)
An object literal that contains nested route definitions. A potentially nested set of key/value pairs. The keys in the object literal represent each potential part of the URL. The values in the object literal contain references to the functions that should be associated with them. bark and meow are two functions that you have defined in your code.
var routes = // an object literal. '/dog': bark // a route which assigns the function `bark`. '/cat': meow scratch // a route which assigns the functions `meow` and `scratch`. ; var router = ; // Instantiate the router.
URL Matching
var router = ;
Routes can sometimes become very complex, simple/:tokens
don't always suffice. SugarSkull supports regular expressions inside the route names. The values captured from the regular expressions are passed to your listener function.
var router = ;
var router = ;
Special Events
In some cases a listener should only fire once or only after the user leaves the route. See the API section for more events and details about what events are available.
var router = ;
More Options
recurse
Can be assigned the value of forward
or backward
. The recurse option will determine the order in which to fire the listeners that are associated with your routes. If this option is NOT specified or set to null, then only the listeners associated with an exact match will be fired.
No recursion, with the URL /dog/angry
var routes = '/dog': '/angry': on: growl // this method will be fired. on: bark ; var router = ;
Recursion set to true, with the URL /dog/angry
var routes = '/dog': '/angry': on: growl // this method will be fired second. on: bark // this method will be fired first. ; var router = ;
Recursion set to false, with the URL /dog/angry
var routes = '/dog': '/angry': on: growl // this method will be fired first. on: bark // this method will be fired second. ; var router = ;
Breaking out of recursion, with the URL /dog/angry
var routes = '/dog': '/angry': { return false; } // this method will be fired first. on: bark // this method will not be fired. ; // this feature works in reverse with recursion set to true. var router = ;
resource
An object literal containing functions. If a host object is specified, your route definitions can provide string literals that represent the function names inside the host object. A host object can provide the means for better encapsulation and design.
var router = ; var container = { return 100; } { return 5; } ;
Maintaining State
It is possible to attach state to any segment of the router, so in our case above if /dog
is reached, the current state will be set to { needy: true, fetch: 'possibly' }
. Each nested section will merge into and overwrite the current state. So in the case where the router matches /cat/hungry
, the state will become { needy: true, fetch: 'unlikely', frantic: true }
.
var router = ;
API
config
{Object} - An object literal representing the router configuration.
Returns a new instance of the router.
Instance methods
use([on, after, recurse, resource])
on
{Function} or {Array} - A callback or list of callbacks that will fire on every route.
after
{Function} or {Array} - A callback or list of callbacks that will fire after every route.
recurse
{String} - Determines the order in which to fire the listeners that are associated with your routes. can be set to 'backward' or 'forward'.
resource
{Object} - An object literal of function declarations.
notfound
{Function} or {Array} - A callback or a list of callbacks to be called when there is no matching route.
Initialize the router, start listening for changes to the URL.
init()
Initialize the router, start listening for changes to the URL.
getState()
Returns the state object that is relative to the current route.
getRoute([index])
index
{Numner} - The hash value is divided by forward slashes, each section then has an index, if this is provided, only that section of the route will be returned.
Returns the entire route or just a section of it.
setRoute(route)
route
{String} - Supply a route value, such as home/stats
.
Set the current route.
setRoute(start, length)
start
{Number} - The position at which to start removing items.
length
{Number} - The number of items to remove from the route.
Remove a segment from the current route.
setRoute(index, value)
index
{Number} - The hash value is divided by forward slashes, each section then has an index.
value
{String} - The new value to assign the the position indicated by the first parameter.
Set a segment of the current route.
Events
on
- A function or array of functions to execute when the route is matched.
after
- A function or array of functions to execute when leaving a particular route.
once
- A function or array of functions to execute only once for a particular route.
on
- A function or array of functions to execute when any route is matched.
after
- A function or array of functions to execute when leaving any route.
Article 1. the constructor should allow the centralization of the routing table.
var router = '/foo': fooLogic;
Article 2. the constructor's routing table should allow definition nesting for terseness.
var router = '/foo': '/bar': barLogic '/bazz': bazzLogic ;
Article 3. the constructor's routing table should allow named events to be associated with routing segments
var router = '/foo': '/bar': barLogic '/bazz': on: bazzOn // any kind of VERB. after: bazzAfter ;
Article 4. the constructor's routing table should allow special attributes to be associated with routing segments
var router = '/foo': '/bar': barLogic '/bazz': accept: 'GET' 'POST' // limit the verbs that on will accept. on: bazzLogic after: bazzAfter ;
Article 5. the constructor's routing table should allow event types to be associated with routing segments
var router = '/foo': '/bar': barlogic // no event type specified, synonymous with GET '/bazz': GET: fooGetLogic // explicitly accept the GET verb POST: fooPostLogic // explicitly accept the POST verb ;
global
method.
Article 6. the instance should have a var router = '/foo': '/bar': barlogic // no event type specified, defaults to GET GET: fooLogic // explicitly accept the verb GET for `/foo` ; router;
Article 7. the constructor's routing table should allow filter definitions to be associated with routing segments, these are simple and resolve to true or false values which permit the execution of the logic associated with the route.
var router = '/foo': '/bar': barlogic // no event type specified, synonymous with GET '/bazz': GET: bazzGetLogic // explicit activity filter: 'POST' 'DELETE' on: bazzLogic // any other activity ; router;
Article 8. the instance should allow for ad-hoc routing.
var router = ; router; router;
Article 9. the instance should allow for ad-hoc routing with special events.
var router = ;router;
Frequently Asked Questions
What About SEO?
Is using a client side router a problem for SEO? Yes. If advertising is a requirement, you are probably building a "Web Page" and not a "Web Application". SugarSkull on the client is meant for script-heavy Web Applications.
Is SugarSkull compatible with X?
SugarSkull is known to be Ender.js compatible. However, the project still needs solid cross-browser testing.
Licence
(The MIT License)
Copyright (c) 2010 Nodejitsu Inc. http://www.twitter.com/nodejitsu
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.