/* appjet:version 0.1 */
/* appjet:library */
// Copyright (c) 2009, Herbert Vojčík
// Licensed by MIT license (http://www.opensource.org/licenses/mit-license.php)
/** Decoded segments of full path */
request.fullPathSegments = request.path.split('/').map(decodeURIComponent);
/** Decoded full path */
request.fullPath = request.fullPathSegments.join('/');
/**@ignore*/
request.fullPathSegments.of = request.fullPath;
/**
*
Enhanced dispatcher function. Dispatches according to request.fullPath. Allows for:
* - nonalphanumeric characters in path. Serve /robots.txt with
get_robots$txt
* - subpath matching:
* - Serve /foo/, /foo/bar and /foo/bar/baz from
get_foo_
* get_foo_main
serves only the /foo/ path, but not the /foo/bar, nor /foo
* - If there are more functions matching, the most specific (the longest one) wins
* request.pagePath
is set to path of your handler (/foo), request.pathTail
is set to the rest(/bar).
* request.fullPath
contains the full path in decoded form
* - request.fullPathSegments, request.pagePathSegments and request.pathTailSegments contain segments of these paths
*
* 404 handling is different: assign your 404 handler to dispatchPlus.f404
* If you pass arguments to dispatchPlus call, they are passed to handler function. No more need for globals to pass initial information to handler functions.
*
*/
function dispatchPlus(arg1, arg2, etc) {
_rejuvenateFullPathSegments();
var selectorSegments = request.fullPathSegments.map(function(x) {
return [x.replace(/[\W]/g,'$$'), "_"];
});
selectorSegments.push([selectorSegments.pop()[0] || "main"]);
var handler, handlerSegments, selector = arguments.callee[request.method] || request.method.toLowerCase();
selectorSegments.forEach(function(segment, index) {
selector += segment.join('');
var candidate = appjet._internal.global[selector];
if (typeof candidate === "function") {
handler = candidate;
handlerSegments = index + 1;
}
});
if (handler) {
request.pagePathSegments = request.fullPathSegments.slice(0, handlerSegments);
request.pathTailSegments = request.fullPathSegments.slice(handlerSegments);
request.pagePath = request.pagePathSegments.join('/');
request.pathTail = request.fullPath.substring(request.pagePath.length);
}
(handler || arguments.callee.f404).apply(null, arguments);
}
/** The 404 (page not found) handler. You can replace it with your own. */
dispatchPlus.f404 = function() {
response.setStatusCode(404);
printp("Path not found: ", request.fullPath);
print(request);
response.stop();
};
/** The prefix for GET method dispatcher functions. Default is "get", you can change it. */
dispatchPlus.GET = "get";
/** The prefix for HEAD method dispatcher functions. Default is "get", you can change it. */
dispatchPlus.HEAD = "get";
/** The prefix for POST method dispatcher functions. Default is "post", you can change it. */
dispatchPlus.POST = "post";
/** The prefix for CRON method dispatcher functions. Default is "cron", you can change it. */
dispatchPlus.CRON = "cron";
function _rejuvenateFullPathSegments() {
if (request.fullPathSegments.of === request.fullPath) return;
request.fullPathSegments = request.fullPath.split('/');
request.fullPathSegments.of = request.fullPath;
}
/* appjet:server */
import("lib-app/dispatch-plus");
/**@ignore*/
function printRequest() {
printp({
pagePath: request.pagePath,
pagePathSegments: request.pagePathSegments,
fullPath: request.fullPath,
fullPathSegments: request.fullPathSegments,
pathTail: request.pathTail,
pathTailSegments: request.pathTailSegments
});
};
/**@ignore*/
function get_(arg) {
printp("Serviced by ", CODE(arguments.callee));
printp("Try these links:");
print(UL(
LI(A({href:"/long/path/here.2"}, "/long/path/here.2")),
LI(A({href:"/papľuh/path-ing/"}, "/papľuh/path-ing/"))
));
printp("Hello, ", arg, "!");
printRequest();
}
/**@ignore*/
function get_papľuh_(arg) {
printp("Serviced by ", CODE(arguments.callee));
printp("Hello, ", arg, "!");
printRequest();
}
/**@ignore*/
var get_papľuh_path$ing = "This is not a function";
/**@ignore*/
function get_long_path_() {
throw new Error("This should not be called.");
}
/**@ignore*/
function get_long_path_here$2(arg) {
printp("Serviced by ", CODE(arguments.callee));
printp("Hello, ", arg, "!");
printRequest();
}
/**@ignore*/
function get_long_path_here$2_() {
throw new Error("This should not be called.");
}
/**@ignore*/
function get_long_path_here$2_main() {
throw new Error("This should not be called.");
}
printp("Features of extended dispatcher:");
print(UL(
LI("Any nonalphanumeric characters (except the slash, of course) are replaced by '$' (dollar sign). Now you can serve /robots.txt by get_robots$txt function."),
LI("You can put a handler only to a beginning part of the path, if you use name like get_beginning_. This serves all paths in the form /beginning/... The path is broken to request.pagePath (the first part) and request.pathTail (the rest)."),
LI("If you end function with _main, it will not serve subpaths (it only matches to full path ending with / (a slash)."),
LI("If there are more subpath handlers and full path handlers, the most specific (the one that matches the longest part of the path) is chosen. If case of get_path_ and get_path_main, the latter will be chosen to service /path/, but the former to service /path/some/more."),
LI("404 is handled other way: you specify your 404 handler by assigning it to dispatchPlus.f404 before placing a call."),
LI("Any arguments you put in dispatchPlus call, gets copied into your handler function.")
));
printp("The statments issued in this minitest is ", CODE('dispatchPlus("world")'));
dispatchPlus("world");