mirror of
https://github.com/openwrt/luci.git
synced 2026-02-04 12:06:01 +08:00
luci-base: dispatcher; improve wildcard routing
When a menu JSON describes an endpoint like
"admin/app/edit/*" : { ...
and the user navigates to
admin/app/edit/
instead of the URI which supplies an ID to edit, like
admin/app/edit/myfoobarthing
we now can use 'alias' and 'rewrite' to redirect
transparently for more generic endpoints.
Without this, it's possible to navigate to
admin/app/edit/
and the corresponding view does not receive a suitable
path/ID to derive data from, when views use anything
derived via L.env.requestpath.
This menu JSON
"admin/app/entry/*": {
"action": {
"type": "view",
"path": "app/entry"
}
},
"admin/app/entries": {
"title": "entries",
"order": 5,
"action": {
"type": "view",
"path": "app/entries"
}
},
"admin/app/entry": {
"action": {
"type": "alias",
"path": "admin/app/entries"
}
},
Produces JSON with a wildcardaction element
"entry":
{
"satisfied": true,
"wildcard": true,
"action":
{
"type": "alias",
"path": "admin/app/entries"
},
"wildcardaction":
{
"type": "view",
"path": "app/entry"
}
},
"entries":
{
"satisfied": true,
"action":
{
"type": "view",
"path": "app/entries"
},
"order": 5,
"title": "entries"
},
Signed-off-by: Paul Donald <newtwen+github@gmail.com>
This commit is contained in:
@@ -388,10 +388,12 @@ function build_pagetree() {
|
||||
for (let path, spec in data) {
|
||||
if (type(spec) == 'object') {
|
||||
let node = tree;
|
||||
let has_wildcard = false;
|
||||
|
||||
for (let s in match(path, /[^\/]+/g)) {
|
||||
if (s[0] == '*') {
|
||||
node.wildcard = true;
|
||||
has_wildcard = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -405,6 +407,12 @@ function build_pagetree() {
|
||||
if (type(spec[k]) == t)
|
||||
node[k] = spec[k];
|
||||
|
||||
/* Preserve distinct actions for wildcard vs. base path */
|
||||
if (has_wildcard && type(spec.action) == 'object')
|
||||
node.wildcardaction = spec.action;
|
||||
else if (type(spec.action) == 'object')
|
||||
node.action = spec.action;
|
||||
|
||||
node.satisfied = check_depends(spec);
|
||||
}
|
||||
}
|
||||
@@ -635,16 +643,27 @@ function resolve_page(tree, request_path) {
|
||||
if (!login && node.auth?.login)
|
||||
login = true;
|
||||
|
||||
/* If this node is marked as wildcard, check if the next segment
|
||||
* matches a child node. Only apply wildcard behaviour (capturing
|
||||
* remaining segments as args) if no child matches, allowing
|
||||
* deeper routes like foo/bar/* to work alongside
|
||||
* foo/*
|
||||
*/
|
||||
if (node.wildcard) {
|
||||
ctx.request_args = [];
|
||||
ctx.request_path = ctx.path ? [ ...ctx.path ] : [];
|
||||
let next_segment = request_path[i + 1];
|
||||
let has_matching_child = next_segment && node.children?.[next_segment]?.satisfied;
|
||||
|
||||
while (++i < length(request_path)) {
|
||||
push(ctx.request_path, request_path[i]);
|
||||
push(ctx.request_args, request_path[i]);
|
||||
if (!has_matching_child) {
|
||||
ctx.request_args = [];
|
||||
ctx.request_path = ctx.path ? [ ...ctx.path ] : [];
|
||||
|
||||
while (++i < length(request_path)) {
|
||||
push(ctx.request_path, request_path[i]);
|
||||
push(ctx.request_args, request_path[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -986,6 +1005,11 @@ dispatch = function(_http, path) {
|
||||
|
||||
let action = resolved.node.action;
|
||||
|
||||
/* If this node matched a wildcard and we have request args,
|
||||
* prefer the wildcard-specific action when defined. */
|
||||
if (length(resolved.ctx.request_args) && type(resolved.node.wildcardaction) == 'object')
|
||||
action = resolved.node.wildcardaction;
|
||||
|
||||
if (action?.type == 'arcombine')
|
||||
action = length(resolved.ctx.request_args) ? action.targets?.[1] : action.targets?.[0];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user