X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;f=libs%2Fweb%2Fluasrc%2Fdispatcher.lua;h=9e5b78d5e9f93b3bf6737f53fdebe65924697798;hb=848e43a5b47c0467b90e7d9a029e59ec53461da3;hp=0162407cd54bc3d936d2002f80bf0b2009417756;hpb=b3861e0ec70ad94f925f196564e6a20e509ab9c4;p=project%2Fluci.git diff --git a/libs/web/luasrc/dispatcher.lua b/libs/web/luasrc/dispatcher.lua index 0162407cd..9e5b78d5e 100644 --- a/libs/web/luasrc/dispatcher.lua +++ b/libs/web/luasrc/dispatcher.lua @@ -73,6 +73,43 @@ function build_url(...) return table.concat(url, "") end +--- Check whether a dispatch node shall be visible +-- @param node Dispatch node +-- @return Boolean indicating whether the node should be visible +function node_visible(node) + if node then + return not ( + (not node.title or #node.title == 0) or + (not node.target or node.hidden == true) or + (type(node.target) == "table" and node.target.type == "firstchild" and + (type(node.nodes) ~= "table" or not next(node.nodes))) + ) + end + return false +end + +--- Return a sorted table of visible childs within a given node +-- @param node Dispatch node +-- @return Ordered table of child node names +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 + end + end + end + return rv +end + + --- Send a 404 error code and render the "error404" template if available. -- @param message Custom error message (optional) -- @return false @@ -130,6 +167,8 @@ function httpdispatch(request, prefix) local r = {} context.request = r + context.urltoken = {} + local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true) if prefix then @@ -138,8 +177,18 @@ function httpdispatch(request, prefix) end end + local tokensok = true for node in pathinfo:gmatch("[^/]+") do - r[#r+1] = node + local tkey, tval + if tokensok then + tkey, tval = node:match(";(%w+)=([a-fA-F0-9]*)") + end + if tkey then + context.urltoken[tkey] = tval + else + tokensok = false + r[#r+1] = node + end end local stat, err = util.coxpcall(function() @@ -157,7 +206,6 @@ function dispatch(request) --context._disable_memtrace = require "luci.debug".trap_memtrace("l") local ctx = context ctx.path = request - ctx.urltoken = ctx.urltoken or {} local conf = require "luci.config" assert(conf.main, @@ -187,34 +235,23 @@ function dispatch(request) ctx.args = args ctx.requestargs = ctx.requestargs or args local n - local t = true local token = ctx.urltoken local preq = {} local freq = {} for i, s in ipairs(request) do - local tkey, tval - if t then - tkey, tval = s:match(";(%w+)=([a-fA-F0-9]*)") + preq[#preq+1] = s + freq[#freq+1] = s + c = c.nodes[s] + n = i + if not c then + break end - if tkey then - token[tkey] = tval - else - t = false - preq[#preq+1] = s - freq[#freq+1] = s - c = c.nodes[s] - n = i - if not c then - break - end - - util.update(track, c) + util.update(track, c) - if c.leaf then - break - end + if c.leaf then + break end end @@ -229,7 +266,7 @@ function dispatch(request) ctx.path = preq if track.i18n then - require("luci.i18n").loadc(track.i18n) + i18n.loadc(track.i18n) end -- Init template engine @@ -247,16 +284,35 @@ function dispatch(request) assert(media, "No valid theme found") end + local function _ifattr(cond, key, val) + if cond then + local env = getfenv(3) + local scope = (type(env.self) == "table") and env.self + return string.format( + ' %s="%s"', tostring(key), + luci.util.pcdata(tostring( val + or (type(env[key]) ~= "function" and env[key]) + or (scope and type(scope[key]) ~= "function" and scope[key]) + or "" )) + ) + else + return '' + end + end + tpl.context.viewns = setmetatable({ write = luci.http.write; include = function(name) tpl.Template(name):render(getfenv(2)) end; - translate = function(...) return require("luci.i18n").translate(...) end; + translate = i18n.translate; + translatef = i18n.translatef; export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end; striptags = util.striptags; pcdata = util.pcdata; media = media; theme = fs.basename(media); - resource = luci.config.main.resourcebase + resource = luci.config.main.resourcebase; + ifattr = function(...) return _ifattr(...) end; + attr = function(...) return _ifattr(true, ...) end; }, {__index=function(table, key) if key == "controller" then return build_url() @@ -297,9 +353,6 @@ function dispatch(request) local user if sdat then - sdat = loadstring(sdat) - setfenv(sdat, {}) - sdat = sdat() if not verifytoken or ctx.urltoken.stok == sdat.token then user = sdat.user end @@ -321,11 +374,12 @@ function dispatch(request) local sid = sess or luci.sys.uniqueid(16) if not sess then local token = luci.sys.uniqueid(16) - sauth.write(sid, util.get_bytecode({ + sauth.reap() + sauth.write(sid, { user=user, token=token, secret=luci.sys.uniqueid(16) - })) + }) ctx.urltoken.stok = token end luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path="..build_url()) @@ -399,7 +453,7 @@ function dispatch(request) local root = node() if not root or not root.target then error404("No root node was registered, this usually happens if no module was installed.\n" .. - "Install luci-admin-full and retry. " .. + "Install luci-mod-admin-full and retry. " .. "If the module is already installed, try removing the /tmp/luci-indexcache file.") else error404("No page is registered at '/" .. table.concat(request, "/") .. "'.\n" .. @@ -487,7 +541,7 @@ function createindex_plain(path, suffixes) "The file '" .. c .. "' contains an invalid module line.\n" .. "Please verify whether the module name is set to '" .. modname .. "' - It must correspond to the file path!") - + local idx = mod.index assert(type(idx) == "function", "Invalid controller file found\n" .. @@ -513,7 +567,7 @@ function createtree() end local ctx = context - local tree = {nodes={}} + local tree = {nodes={}, inreq=true} local modi = {} ctx.treecache = setmetatable({}, {__mode="v"}) @@ -625,6 +679,11 @@ function _create_node(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 + end parent.nodes[last] = c context.treecache[name] = c end @@ -633,6 +692,35 @@ 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 + + assert(lowest ~= nil, + "The requested node contains no childs, unable to redispatch") + + path[#path+1] = lowest + dispatch(path) +end + +--- Alias the first (lowest order) page automatically +function firstchild() + return { type = "firstchild", target = _firstchild } +end + --- Create a redirect to another dispatching node. -- @param ... Virtual path destination function alias(...) @@ -672,10 +760,18 @@ end local function _call(self, ...) + local func = getfenv()[self.name] + assert(func ~= nil, + 'Cannot resolve function "' .. self.name .. '". Is it misspelled or local?') + + assert(type(func) == "function", + 'The symbol "' .. self.name .. '" does not refer to a function but data ' .. + 'of type "' .. type(func) .. '".') + if #self.argv > 0 then - return getfenv()[self.name](unpack(self.argv), ...) + return func(unpack(self.argv), ...) else - return getfenv()[self.name](...) + return func(...) end end @@ -848,3 +944,16 @@ end function form(model) return {type = "cbi", model = model, target = _form} end + +--- Access the luci.i18n translate() api. +-- @class function +-- @name translate +-- @param text Text to translate +translate = i18n.translate + +--- No-op function used to mark translation entries for menu labels. +-- This function does not actually translate the given argument but +-- is used by build/i18n-scan.pl to find translatable entries. +function _(text) + return text +end