edmond
Version:
Simple JavaScript router for web applications.
190 lines (151 loc) • 4.07 kB
JavaScript
(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;
}
}());