X-Git-Url: http://git.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=modules%2Fluci-base%2Fluasrc%2Fdispatcher.lua;h=d85cb58243082e007a3144ca2ee03bbc50e2aca0;hp=2c58b0ab3d9220d76f7b0a1e7196b0da622949f6;hb=2509b5984d026f285e5768fec5933ef72f37fbd8;hpb=7acacf2cf806c5d74fc60f8a2de95628ba52bb7d diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index 2c58b0ab3d..d85cb58243 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -40,6 +40,28 @@ function build_url(...) return table.concat(url, "") end +function _ordered_children(node) + local name, child, children = nil, nil, {} + + for name, child in pairs(node.nodes) do + children[#children+1] = { + name = name, + node = child, + order = child.order or 100 + } + end + + table.sort(children, function(a, b) + if a.order == b.order then + return a.name < b.name + else + return a.order < b.order + end + end) + + return children +end + function node_visible(node) if node then return not ( @@ -55,15 +77,10 @@ end function node_childs(node) local rv = { } if node then - local k, v - for k, v in util.spairs(node.nodes, - function(a, b) - return (node.nodes[a].order or 100) - < (node.nodes[b].order or 100) - end) - do - if node_visible(v) then - rv[#rv+1] = k + local _, child + for _, child in ipairs(_ordered_children(node)) do + if node_visible(child.node) then + rv[#rv+1] = child.name end end end @@ -296,10 +313,6 @@ function dispatch(request) ctx.requestpath = ctx.requestpath or freq ctx.path = preq - if track.i18n then - i18n.loadc(track.i18n) - end - -- Init template engine if (c and c.index) or not track.notemplate then local tpl = require("luci.template") @@ -358,7 +371,7 @@ function dispatch(request) elseif key == "REQUEST_URI" then return build_url(unpack(ctx.requestpath)) elseif key == "FULL_REQUEST_URI" then - local url = { http.getenv("SCRIPT_NAME") or "" , http.getenv("PATH_INFO") } + local url = { http.getenv("SCRIPT_NAME") or "", http.getenv("PATH_INFO") } local query = http.getenv("QUERY_STRING") if query and #query > 0 then url[#url+1] = "?" @@ -421,6 +434,7 @@ function dispatch(request) context.path = {} http.status(403, "Forbidden") + http.header("X-LuCI-Login-Required", "yes") tmpl.render(track.sysauth_template or "sysauth", { duser = default_user, fuser = user @@ -437,6 +451,7 @@ function dispatch(request) if not sid or not sdat then http.status(403, "Forbidden") + http.header("X-LuCI-Login-Required", "yes") return end @@ -507,10 +522,11 @@ function dispatch(request) else ok, err = util.copcall(target, unpack(args)) end - assert(ok, - "Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") .. - " dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" .. - "The called action terminated with an exception:\n" .. tostring(err or "(unknown)")) + if not ok then + error500("Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") .. + " dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" .. + "The called action terminated with an exception:\n" .. tostring(err or "(unknown)")) + end else local root = node() if not root or not root.target then @@ -596,14 +612,9 @@ function createtree() local ctx = context local tree = {nodes={}, inreq=true} - local modi = {} ctx.treecache = setmetatable({}, {__mode="v"}) ctx.tree = tree - ctx.modifiers = modi - - -- Load default translation - require "luci.i18n".loadc("base") local scope = setmetatable({}, {__index = luci.dispatcher}) @@ -613,28 +624,9 @@ function createtree() v() end - local function modisort(a,b) - return modi[a].order < modi[b].order - end - - for _, v in util.spairs(modi, modisort) do - scope._NAME = v.module - setfenv(v.func, scope) - v.func() - end - return tree end -function modifier(func, order) - context.modifiers[#context.modifiers+1] = { - func = func, - order = order or 0, - module - = getfenv(2)._NAME - } -end - function assign(path, clone, title, order) local obj = node(unpack(path)) obj.nodes = nil @@ -702,46 +694,87 @@ function _create_node(path) local last = table.remove(path) local parent = _create_node(path) - c = {nodes={}, auto=true} - -- the node is "in request" if the request path matches - -- at least up to the length of the node path - if parent.inreq and context.path[#path+1] == last then - c.inreq = true + c = {nodes={}, auto=true, inreq=true} + + local _, n + for _, n in ipairs(path) do + if context.path[_] ~= n then + c.inreq = false + break + end end + + c.inreq = c.inreq and (context.path[#path + 1] == last) + parent.nodes[last] = c context.treecache[name] = c end + return c end -- Subdispatchers -- -function _firstchild() - local path = { unpack(context.path) } - local name = table.concat(path, ".") - local node = context.treecache[name] - - local lowest - if node and node.nodes and next(node.nodes) then - local k, v - for k, v in pairs(node.nodes) do - if not lowest or - (v.order or 100) < (node.nodes[lowest].order or 100) - then - lowest = k - end - end - end +function _find_eligible_node(root, prefix, deep, types, descend) + local children = _ordered_children(root) - assert(lowest ~= nil, - "The requested node contains no childs, unable to redispatch") + if not root.leaf and deep ~= nil then + local sub_path = { unpack(prefix) } - path[#path+1] = lowest - dispatch(path) + if deep == false then + deep = nil + end + + local _, child + for _, child in ipairs(children) do + sub_path[#prefix+1] = child.name + + local res_path = _find_eligible_node(child.node, sub_path, + deep, types, true) + + if res_path then + return res_path + end + end + end + + if descend and + (not types or + (type(root.target) == "table" and + util.contains(types, root.target.type))) + then + return prefix + end +end + +function _find_node(recurse, types) + local path = { unpack(context.path) } + local name = table.concat(path, ".") + local node = context.treecache[name] + + path = _find_eligible_node(node, path, recurse, types) + + if path then + dispatch(path) + else + require "luci.template".render("empty_node_placeholder") + end +end + +function _firstchild() + return _find_node(false, nil) end function firstchild() - return { type = "firstchild", target = _firstchild } + return { type = "firstchild", target = _firstchild } +end + +function _firstnode() + return _find_node(true, { "cbi", "form", "template", "arcombine" }) +end + +function firstnode() + return { type = "firstnode", target = _firstnode } end function alias(...) @@ -885,8 +918,6 @@ local function _cbi(self, ...) local pageaction = true local parsechain = { } - local is_rollback, time_remaining = uci:rollback_pending() - for i, res in ipairs(maps) do if res.apply_needed and res.parsechain then local c @@ -913,8 +944,6 @@ local function _cbi(self, ...) for i, res in ipairs(maps) do res:render({ firstmap = (i == 1), - applymap = applymap, - confirmmap = (is_rollback and time_remaining or nil), redirect = redirect, messages = messages, pageaction = pageaction, @@ -924,11 +953,12 @@ local function _cbi(self, ...) if not config.nofooter then tpl.render("cbi/footer", { - flow = config, - pageaction = pageaction, - redirect = redirect, - state = state, - autoapply = config.autoapply + flow = config, + pageaction = pageaction, + redirect = redirect, + state = state, + autoapply = config.autoapply, + trigger_apply = applymap }) end end