ff0000/rosy — pull request #80 by timrwood (2013-02-07 22:46:04+00:00)
Title: Replace view groups with routers

This change replaces view groups with routers.

It's kinda hard to explain conceptually, so I'll use before and after examples.

```javascript
// with view groups
ViewManager.initialize({
viewGroups : [
{
"config" : {
"id" : "main",
"selector" : "#main",
"useHistory" : true,
"transition" : "sync"
},

"routes" : [
{
"viewClass" : "project/views/Home",
"route" : "/",
"config" : {
"bodyClass" : "home",
"title" : "Home"
}
},
{
"viewClass" : "project/views/About",
"route" : "/about/:subSection?",
"config" : {
"bodyClass" : "about",
"title" : "About"
}
}
]
},
{
"config" : {
"id" : "header",
"selector" : "#header",
"useHistory" : false,
"transition" : "async"
},

"routes" : [
{
"viewClass" : "project/header/Home",
"route" : "/",
"config" : {}
},
{
"viewClass" : "project/header/About",
"route" : "/about/:subSection?",
"config" : {}
}
]
}
]
});
```

```javascript
// with Routers
var mainRouter = new HistoryRouter([
{
view : "project/views/Home",
path : "/",
config : {
bodyClass : "home",
title : "Home"
}
},
{
view : "project/views/About",
path : "/about/:subSection?",
config : {
bodyClass : "about",
title : "About"
}
}
], {
usePushState: true,
transition: "sync"
});

var headerRouter = new Router([], {
transition: "async"
});
headerRouter.addRoute("/", "project/header/Home");
headerRouter.addRoute("/about/:subSection?", About);

mainRouter.link(headerRouter);
```

## Router types

There are 3 types of routers. HistoryRouter, HashRouter, and Router. HistoryRouter and HashRouter both inherit from Router.

The HistoryRouter will route to the current path on page load. If you pass `usePushState : true` to the router, it will use html5 history management. If your site uses full page refreshes, you can use a HistoryRouter with `usePushState : false` and it will create the correct View based on `location.pathname`.

As the name implies, the HashRouter uses hash routing.

Both the HashRouter and the HistoryRouter are two-way. External push/popstates will be picked up by the HistoryRouter, and calls to `router.route()` will be reflected with `history.pushstate`. External hash changes will be picked up by the HashRouter, and calls to `router.route()` will be reflected with `location.href = newPath`.

## Linking

Two or more routes can be linked together, and when one router changes routes, all other routers will change as well.

```javascript
var routerA = new Router();
routerA.addRoute('/home', Home);
var routerB = new Router();
routerB.addRoute('/home', Home);

routerA.link(routerB);

routerB.route('/home');
routerA.path === '/home';
```

## Routes

Each router has many `Routes`. Each route consists of a view class, path, and config as they previously did.

The view classes can be defined as a string to be required, or can be the actual view class.

```javascript
define(
["rosy/views/Router", "./views/About"],
function (Router, About) {
var router = new Router();
router.addRoute('/', "site/views/Home"); // will not be included in build
router.addRoute('/about', About); // will be included in build
}
);
```

This allows you to specify all the views that your site depends on and have them included in the requirejs grunt task without modifying the grunt task itself.

## Link Hijacking

Hijacking links to use routing is similar to before.

```javascript
var router = new Router();
router.hijack($('#main'), 'a[href^='/'], [data-route], a[href^='#']', 'click');
```

## Active classes

If you want active classes to be applied to links, use the following.

```javascript
var router = new Router();
router.activate($('#main'), 'a[href^='/'], [data-route], a[href^='#']', 'active');
```

Any time the route changes, all elements in `#main` that match the selector will have the active class added. Any routes that do not match will have the active class removed.

## Conclusion

This probably isn't ready to merge in yet, and is not backwards compatible, but I wanted to get the ball rolling...

Thoughts?