7a61af106df9696b36ebc4bb68a8cda13be12da7
[rails.git] / app / assets / javascripts / router.js
1 OSM.Router = function(rts) {
2   var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
3   var optionalParam = /\((.*?)\)/g;
4   var namedParam    = /(\(\?)?:\w+/g;
5   var splatParam    = /\*\w+/g;
6
7   function Route(path, controller) {
8     var regexp = new RegExp('^' +
9       path.replace(escapeRegExp, '\\$&')
10         .replace(optionalParam, '(?:$1)?')
11         .replace(namedParam, function(match, optional){
12           return optional ? match : '([^\/]+)';
13         })
14         .replace(splatParam, '(.*?)') + '(?:\\?.*)?$');
15
16     var route = {};
17
18     route.match = function(path) {
19       return regexp.test(path);
20     };
21
22     route.run = function(action, path) {
23       var params = [];
24
25       if (path) {
26         params = regexp.exec(path).map(function(param, i) {
27           return (i > 0 && param) ? decodeURIComponent(param) : param;
28         });
29       }
30
31       (controller[action] || $.noop).apply(controller, params);
32     };
33
34     return route;
35   }
36
37   var routes = [];
38   for (var r in rts)
39     routes.push(Route(r, rts[r]));
40
41   routes.recognize = function(path) {
42     for (var i = 0; i < this.length; i++) {
43       if (this[i].match(path)) return this[i];
44     }
45   };
46
47   var currentPath = window.location.pathname + window.location.search,
48     currentRoute = routes.recognize(currentPath);
49
50   currentRoute.run('load', currentPath);
51
52   if (window.history && window.history.pushState) {
53     // Set a non-null initial state, so that the e.originalEvent.state
54     // check below works correctly when going back to the initial page.
55     window.history.replaceState({}, document.title, window.location);
56
57     $(window).on('popstate', function(e) {
58       if (!e.originalEvent.state) return; // Is it a real popstate event or just a hash change?
59       var path = window.location.pathname + window.location.search;
60       if (path === currentPath) return;
61       currentRoute.run('unload');
62       currentPath = path;
63       currentRoute = routes.recognize(currentPath);
64       currentRoute.run('popstate', currentPath);
65     });
66
67     return function (url) {
68       var path = url.replace(/#.*/, ''),
69         route = routes.recognize(path);
70       if (!route) return false;
71       window.history.pushState({}, document.title, url);
72       currentRoute.run('unload');
73       currentPath = path;
74       currentRoute = route;
75       currentRoute.run('pushstate', currentPath);
76       return true;
77     }
78   } else {
79     return function (url) {
80       window.location.assign(url);
81     }
82   }
83 };