1 OSM.Router = function(map, rts) {
2 var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
3 var optionalParam = /\((.*?)\)/g;
4 var namedParam = /(\(\?)?:\w+/g;
5 var splatParam = /\*\w+/g;
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 : '([^\/]+)';
14 .replace(splatParam, '(.*?)') + '(?:\\?.*)?$');
18 route.match = function(path) {
19 return regexp.test(path);
22 route.run = function(action, path) {
26 params = regexp.exec(path).map(function(param, i) {
27 return (i > 0 && param) ? decodeURIComponent(param) : param;
31 return (controller[action] || $.noop).apply(controller, params);
39 routes.push(Route(r, rts[r]));
41 routes.recognize = function(path) {
42 for (var i = 0; i < this.length; i++) {
43 if (this[i].match(path)) return this[i];
47 var currentPath = window.location.pathname + window.location.search,
48 currentRoute = routes.recognize(currentPath),
49 currentHash = location.hash || OSM.formatHash(map);
51 var router, stateChange;
53 if (window.history && window.history.pushState) {
54 $(window).on('popstate', function(e) {
55 if (!e.originalEvent.state) return; // Is it a real popstate event or just a hash change?
56 var path = window.location.pathname + window.location.search;
57 if (path === currentPath) return;
58 currentRoute.run('unload');
60 currentRoute = routes.recognize(currentPath);
61 currentRoute.run('popstate', currentPath);
62 var state = e.originalEvent.state;
64 map.setView(state.center, state.zoom, {animate: false});
65 map.updateLayers(state.layers);
69 router = function (url) {
70 var path = url.replace(/#.*/, ''),
71 route = routes.recognize(path);
72 if (!route) return false;
73 window.history.pushState(OSM.parseHash(url) || {}, document.title, url);
74 currentRoute.run('unload');
77 currentRoute.run('pushstate', currentPath);
81 router.stateChange = function(state) {
83 window.history.replaceState(state, document.title, OSM.formatHash(state));
85 window.history.replaceState(state, document.title, window.location);
89 router = function (url) {
90 window.location.assign(url);
93 router.stateChange = function(state) {
94 if (state.center) window.location.replace(OSM.formatHash(state));
98 router.updateHash = function() {
99 var hash = OSM.formatHash(map);
100 if (hash === currentHash) return;
102 router.stateChange(OSM.parseHash(hash));
105 router.hashUpdated = function() {
106 var hash = location.hash;
107 if (hash === currentHash) return;
109 var state = OSM.parseHash(hash);
111 map.setView(state.center, state.zoom);
112 map.updateLayers(state.layers);
113 router.stateChange(state, hash);
116 router.moveListenerOn = function() {
117 map.on('moveend', router.updateHash);
120 router.moveListenerOff = function() {
121 map.off('moveend', router.updateHash);
124 router.load = function() {
125 var loadState = currentRoute.run('load', currentPath);
126 router.stateChange(loadState || {});
129 map.on('moveend baselayerchange overlaylayerchange', router.updateHash);
130 $(window).on('hashchange', router.hashUpdated);