Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/foxbunny/fragrouter

Hash-based routing for modern web browsers
https://github.com/foxbunny/fragrouter

Last synced: 28 days ago
JSON representation

Hash-based routing for modern web browsers

Awesome Lists containing this project

README

        

# FragRouter

FragRouter is a hash-based routing for web browsers, similar to normal URL
routing found in server-side MVC frameworks like Django or Ruby on Rails
(and most others). It is 'hash-based' because it uses the fragment
identifier (commonly called 'hash') to determine the path.

## Installing

FragRouter can be used either as stand-alone script using the conventional
`` tag, or as an AMD module with loaders like
[RequireJS](http://requirejs.org/).

To install it standalone, you don't need to worry about dependencies, since
FragRouter has none to speak of. However, if your target browser does not
support ES5 features, you may want to load the
[es5-shim](https://github.com/kriskowal/es5-shim) before it.

## Getting started (short tutorial)

Suppose your web application knows three routes:

+ http://example.com/#pages
+ http://example.com/#pages/PAGE_ID
+ http://example.com/#about

On top of that, you also need the root route, which is simply
http://example.com/ (without the fragment identifier).

To set these up, you first need to define five handler functions. Yes, you
read that right. You need one for each route, plus a 404 handler which will
inform the user that the route did not match. You don't really need the last
one, but then users won't know why nothing happens on the page. Here is what
the handler functions might look like:

function page(id) {
if (!id) {
// load Home page
$('#content').load('/homepage');
} else {
// load a specific page
$('#content').load('/pages/' + id);
}
}

function about() {
$('#content').load('/about');
}

function missing() {
alert('Page you are looking for is not there');
}

Now define which hash will trigger which handler:

var routes = {
_: page,
pages: page,
about: about,
'404': missing
};

We are almost there. Now we just need to start the router:

frag.start(routes);

What the above routing setup will do is:

+ for the root path (URL with no fragment identifier), `page` function will
be called with no arguments (root handlers never get any arguments).
+ for the pages path (fragment identifier that starts with #pages), the
part after the slash (e.g., '45' in '#pages/45') will be passed in as ID
+ if #pages fragment has more than one slash (e.g., '#pages/45/foo'), the
part after the second slash is passed in as second argument, but is
ignored by the handler function
+ for about path, (fragment '#about'), about function is called
+ for any other path, missing is called.

## Request object

In any handler function, `this` is a Request object. You should not rely on
`this` being anything else.

The Request object has some (arguably) useful properties that you can read
to get more information about the 'request':

+ `time`: Gives you the exact time hash was accessed
+ `path`: Gives you an array of path components that have been used for the
request (read notes about the `path` property in "Multi-level routes"
below).
+ `route`: Name of the route
+ `parameters`: Array of positional parameters passed to handler (same as
`arguments`, but a real Array object)
+ `history`: A read-only copy of internal history (Array of fragment
identifiers without the leading pound character `#`)
+ `frag`: The FragRouter module (same as `frag` global)

The Request object also has a few handy methods:

+ `this.back()`: Go back in internal history (not same as browser history)
+ `this.forward()`: Go forward in internal history
+ `this.go()`: Go to a specific location (see API documentation)

## Multi-level routes

If you have a few routes that you want to nest under a common prefix, you
can add nested route handlers:

var routes = {
_: page,
pages: page,
about: about,
clients: {
_: clientsDefault,
list: clientsList,
modify: clientsModify
}
'404': missing
}

For the above, setup, if the fragment looks like '#clients',
`clientsDefault` is called. For '#clients/list', `clientsList` is called.
And finally, for '#clients/modify', the `clientsModify` is called.
Naturally, the two non-root routes can also accept arguments (e.g.,
'#clients/modify/CLIENT_ID').

The `path` property on the Request object in the case of multi-level routes
looks like a `path` property for non-multi-level route. In other words, the
`clients` subpath is a world of its own, and you cannot tell whether it has
been nested under `clients` path or not. FragRouter may provide mechanisms
for finding this out in future, but for now, you can manually parse the
`window.location.hash`.

## Nested routes

Note that it is currently not possible to do nested routes like
'#clients/CLIENT_ID/modify'. In other words, any variables in the routes
must come last, no matter how deeply your route is nested.

In future FragRouter will provide mechanisms for calling other handlers from
within handlers, which will enable you to manually write nested routes.

## Middleware

FragRouter supports rudimentary middlewares. These are functions that are
called right before a handler. They can be used to perform tasks that are
common for all routes in preparation for route handling.

Let's implement a simple middleware that allows handlers to change the page
title so you can get an idea about how it works:

var titleSuffix = " - My awesome site";
function pageTitleMiddleware(next) {
var request = this;
request.setTitle = function(title) {
document.title = title + titleSuffix;
};
next();
}
frag.addMiddleware(pageTitleMiddleware);

Now, in your request handler, you can set the title like so:

function myHandler() {
var request = this;
request.setTitle('Home');
}

# API Documentation

## frag.start(handlers)

Start routing handlers found in `handlers` object.

## frag.isRouting (boolean)

Boolean flag telling the router if routing is being done.

## frag.setNotFoundHandler(handler)

Missing routes handler is called when no route matches. You can override
it by using this method to set your own function. The handler function
must accept a single argument, which is a string containing the route that
failed to mach.

## frag.addMiddleware(func)

Push a middleware function to the last possition o the middleware stack. The
middleware will be executed once per each hashchange event, before any handler
can handle the reuqest. It will accept a single callback function, which allows
the stack to continue.

Passing a truthy value to the continuation callback will halt the stack and
prevent the handling of the route. This can be useful during debugging, to
prevent the code from doing unexpected or unforeseen things.

Within the middleware function, `this` is a Request object.

## Request([path, route, parameters])

Constructor for creating a request object. Within handlers `this` is a Request
object.

### Request.prototype.back()

Go back one step in internal history (not browser history)

### Request.prototype.forward()

Go forward one step in internal history (not browser history)

### Request.prototype.go(location, [params, hide])

Go to specified location with specified parameters and optionally hide the
new location from browser history.