(function() { /** * Edmond * * @constructor */ var edmond = (function() { // This is where all the routes live this.routes = []; /** * List of event listeners * * @private */ var listeners = {}; /** * DispatchEvent * * @param {string} type */ var dispatchEvent = function(type, message) { var eventListeners = listeners[type] || []; for (var i = 0, len = eventListeners.length; i < len; i++) { eventListeners[i](message); } }; return { /** * AddRoute * * @param {string} route */ addRoute: function(route) { var fns = Array.prototype.slice.call(arguments, 1), tokenRe = /:([A-Za-z0-9_]+)/g; // Look for tokens var tokenMatches = route.match(tokenRe) || []; // Remove ‘:’ at the beginning var tokens = tokenMatches.map(function(token) { return token.slice(1); }); var routeRe = '^'; routeRe += route.replace(tokenRe, '([^/?#]+)'); routeRe += '\/?'; // Optional back slash routeRe += '(?:\\?([^#]+))?'; // Querystring routeRe += '(?:\\#(.+))?'; // Hash routeRe += '$'; // End // Save routes.push({ tokens: tokens, fns: fns, re: new RegExp(routeRe), route: route }); }, /** * DispatchRoute * * @param {string} location */ dispatchRoute: function(path) { // Fire all event listeners dispatchEvent('dispatch', { path: path }); // The choosen route var route = null; // Match the route for (var i = 0, len = routes.length; i < len; i++) { if ( path.match( routes[i].re ) ) { route = routes[i]; break; } } // If route was not found if ( !route ) { return dispatchEvent('error', { path: path, error: 404 }); } /** * Request */ var request = { params: {}, query: {}, path: path, route: route.route }; var matches = path.match(route.re); var tokensValues = matches.slice(1, route.tokens.length + 1), queryString = matches.slice(-2, -1)[0], hashString = matches.slice(-1)[0]; // Request.params tokensValues.forEach(function(tokenValue, index) { var tokenName = route.tokens[index]; request.params[tokenName] = tokenValue; }); // QueryString if (queryString) { queryString = queryString.split('&'); queryString.forEach(function(chunk) { chunk = chunk.split('='); request.query[chunk[0]] = chunk[1] || true; }); } request.hash = hashString; // Vygenerujeme frontu var queue = route.fns.map(function(fn, index) { return function() { var next = function(error) { var fn = queue[index++]; if ( error ) { return dispatchEvent('error', error); } if (fn) { return fn; } }; return fn(request, next); }; }); // And goo! queue[0](); }, /** * On * * @param {string} event * @param {function} listener */ on: function(event, listener) { if (!listeners[event]) { listeners[event] = []; } return listeners[event].push(listener); } }; }()); // Export if ( typeof module !== 'undefined' && module.exports ) { module.exports = edmond; } else if ( typeof define !== 'undefined' ) { define(function() { return edmond; }); } else { this.edmond = edmond; } }());