Skip to content

Instantly share code, notes, and snippets.

@yoko
Created October 27, 2010 12:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save yoko/648950 to your computer and use it in GitHub Desktop.
Save yoko/648950 to your computer and use it in GitHub Desktop.
a URL dispatcher.
var dispatcher = {
location: window.location,
stash : [],
connect: function(paths, action) {
if (paths || paths === 0) {
paths = paths.valueOf();
if (!(typeof paths == 'object' && !(paths instanceof RegExp))) // webkit: typeof RegExp == 'function'
paths = { pathname: paths };
dispatcher.stash.push([paths, action]);
}
return dispatcher;
},
and: function() {
var stash = dispatcher.stash,
length = stash.length;
length && (stash[length - 1][2] = true);
return dispatcher;
},
dispatch: function(location) {
location = location || dispatcher.location;
var stash = dispatcher.stash,
params = {};
for (var i = 0, c; c = stash[i]; ++i) {
var paths = c[0], action = c[1], chain = c[2];
var matched = false;
for (var k in paths) {
var v = paths[k];
var path = location[k];
if (!path) continue;
var m = dispatcher.match(v, path);
matched = !!m;
if (matched)
params[k] = m;
else
break;
}
if (matched) {
if (action)
action(params);
if (!chain) break;
}
}
dispatcher.clear();
return dispatcher;
},
match: function(value, path) {
var ret;
if (value instanceof RegExp)
ret = value.exec(path) || false;
else {
value = value.toString();
ret = (path.indexOf(value) != -1) && value;
}
return ret;
},
clear: function() {
dispatcher.stash = [];
return dispatcher;
}
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>dispatcher test</title>
<link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script src="https://github.com/jquery/qunit/raw/2b3e049a2aca11c03ed245d2c01db525a1e2b149/qunit/qunit.js"></script>
</head>
<body>
<h1 id="qunit-header">dispatcher test</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<script src="dispatcher.js"></script>
<script>
new function() {
module('dispatcher', {
setup: function() {
dispatcher.location = {
hash : '#hash',
host : 'example.com:1234',
hostname: 'example.com',
href : 'http://example.com:1234/foo/bar/0',
pathname: '/foo/bar/0',
port : '1234',
protocol: 'http:',
search : '?search'
};
},
teardown: function() {
dispatcher.location = window.location;
dispatcher.clear();
}
});
test('connect, and, dispatch #1', 13, function() {
var ret;
var patterns = {
hash : /^#(hash)/,
pathname: /^\/(foo)\/(bar)/,
hostname: /example\.com/,
search : /^\?search/
};
strictEqual(dispatcher.connect(), dispatcher, 'connect returns dispatcher');
ret = dispatcher.connect('/foo', function(params) {
equal(arguments.length, 1, 'an argument');
deepEqual(params, {
pathname: '/foo'
}, 'string pattern');
}).dispatch();
strictEqual(dispatcher.stash.length, 0, 'cleared');
strictEqual(ret, dispatcher, 'dispatch returns dispatcher');
dispatcher.connect(/^\/(foo)/, function(params) {
deepEqual(params, {
pathname: ['/foo', 'foo']
}, 'regexp pattern');
}).dispatch();
dispatcher.connect(new String('/foo'), function(params) {
deepEqual(params, {
pathname: '/foo'
}, 'string object pattern');
}).dispatch();
dispatcher.connect({ port: 1234 }, function(params) {
deepEqual(params, {
port: '1234'
}, 'number pattern');
}).dispatch();
dispatcher.connect(0, function(params) {
deepEqual(params, {
pathname: '0'
}, '0 pattern #1');
}).dispatch();
dispatcher.connect({ port: 0 }, function(params) {
deepEqual(params, {
port: '0'
}, '0 pattern #2');
}).dispatch({
port: '0'
});
dispatcher.connect(patterns, function(params) {
deepEqual(params, {
hash : ['#hash', 'hash'],
pathname: ['/foo/bar', 'foo', 'bar'],
hostname: ['example.com'],
search : ['?search']
});
}).dispatch();
dispatcher.connect('baz', function(params) {
deepEqual(params, {
pathname: 'baz'
}, 'custom location');
}).dispatch({
pathname: '/baz'
});
dispatcher
.connect('foo').and()
.connect('bar', function(params) {
deepEqual(params, {
pathname: 'bar'
});
})
.dispatch();
dispatcher
.connect('no-match').and()
.connect('bar', function(params) {
deepEqual(params, {
pathname: 'bar'
});
})
.dispatch();
});
test('connect, and, dispatch #2', 1, function() {
dispatcher
.connect(/^\/no-match/, function() {
ok(false, 'must not run');
})
.connect(/^\/foo/, function() {
ok(true, 'must run');
})
.connect(/^\/no-match/, function() {
ok(false, 'must not run');
})
.dispatch();
});
test('connect, and, dispatch #3', 1, function() {
dispatcher
.connect({ invalid: 123 }, function(params) {
ok(false, 'must not run');
})
.connect(/^\/foo/, function() {
ok(true, 'must run');
})
.dispatch();
});
test('connect, and, dispatch #4', 1, function() {
dispatcher
.connect({}, function(params) {
ok(false, 'must not run');
})
.connect(/^\/foo/, function() {
ok(true, 'must run');
})
.dispatch();
});
test('connect, and, dispatch #5', 4, function() {
var ret = dispatcher.and();
strictEqual(dispatcher.stash.length, 0, 'do nothing');
strictEqual(ret, dispatcher, 'and returns dispatcher');
dispatcher
.connect(/^\/.*/, function() {
ok(true, 'match all');
}).and()
.connect(/^\/no-match/, function() {
ok(false, 'must not run');
})
.connect(/^\/foo/, function() {
ok(true, 'must run');
})
.connect(/^\/foo/, function() {
ok(false, 'must not run because closed');
})
.dispatch();
});
test('clear', function() {
var ret;
dispatcher.connect(/^\/foo/);
equal(dispatcher.stash.length, 1, 'registered');
ret = dispatcher.clear();
strictEqual(dispatcher.stash.length, 0, 'cleared');
strictEqual(ret, dispatcher, 'clear returns dispatcher');
});
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment