89 lines
2.6 KiB
JavaScript
89 lines
2.6 KiB
JavaScript
(function (scope) {
|
|
'use strict';
|
|
|
|
function parse(pattern) {
|
|
return pattern.split('/').map(function (part) {
|
|
return part.charAt(0) === ':' ? { name: part.slice(1) } : { part: part };
|
|
});
|
|
}
|
|
|
|
function Call(event, url, params) {
|
|
this.event = event;
|
|
this.request = event.request;
|
|
this.url = url;
|
|
this.params = params;
|
|
this.htmx = this.request.headers.get('HX-Request') === 'true';
|
|
this.navigate = this.request.mode === 'navigate';
|
|
this.restore =
|
|
this.request.headers.get('HX-History-Restore-Request') === 'true';
|
|
this.current = this.request.headers.get('HX-Current-URL');
|
|
}
|
|
|
|
Call.prototype.currentUrl = function () {
|
|
return this.current ? new URL(this.current, this.url) : null;
|
|
};
|
|
|
|
Call.prototype.form = function () {
|
|
return this.request.formData();
|
|
};
|
|
|
|
function Router(base) {
|
|
this.base = base;
|
|
this.routes = [];
|
|
}
|
|
|
|
Router.prototype.route = function (method, pattern, handler) {
|
|
this.routes.push({ method: method, path: parse(pattern), handler: handler });
|
|
return this;
|
|
};
|
|
|
|
Router.prototype.get = function (pattern, handler) {
|
|
return this.route('GET', pattern, handler);
|
|
};
|
|
|
|
Router.prototype.post = function (pattern, handler) {
|
|
return this.route('POST', pattern, handler);
|
|
};
|
|
|
|
Router.prototype.relative = function (url) {
|
|
var path = url.pathname;
|
|
return path.indexOf(this.base) === 0 ? '/' + path.slice(this.base.length) : path;
|
|
};
|
|
|
|
Router.prototype.find = function (method, path) {
|
|
var segments = path.split('/');
|
|
for (var i = 0; i < this.routes.length; i++) {
|
|
var route = this.routes[i];
|
|
if (route.method !== method || route.path.length !== segments.length) continue;
|
|
var params = {};
|
|
var ok = route.path.every(function (segment, n) {
|
|
if (!segment.name) return segment.part === segments[n];
|
|
params[segment.name] = decodeURIComponent(segments[n]);
|
|
return true;
|
|
});
|
|
if (ok) return { handler: route.handler, params: params };
|
|
}
|
|
return null;
|
|
};
|
|
|
|
Router.prototype.handle = function (event, url) {
|
|
var found = this.find(event.request.method, this.relative(url));
|
|
if (!found) return null;
|
|
|
|
return Promise.resolve(found.handler(new Call(event, url, found.params)))
|
|
.then(function (result) {
|
|
if (result instanceof Response) return result;
|
|
if (typeof result !== 'string') return null;
|
|
return new Response(result, {
|
|
status: 200,
|
|
headers: {
|
|
'Content-Type': 'text/html; charset=utf-8',
|
|
'Cache-Control': 'no-store'
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
scope.Router = Router;
|
|
})(self);
|