local tostring, pairs, loadstring = tostring, pairs, loadstring
local setmetatable, loadfile = setmetatable, loadfile
-local getfenv, setfenv = getfenv, setfenv
+local getfenv, setfenv, rawget = getfenv, setfenv, rawget
local assert, type, error = assert, type, error
--- LuCI template library.
-- Define the namespace for template modules
context = util.threadlocal()
-viewns = {
- include = function(name) Template(name):render(getfenv(2)) end,
-}
-
--- Manually compile a given template into an executable Lua function
-- @param template LuCI template
-- @return Lua template function
-- Search all <% %> expressions
local function expr_add(ws1, skip1, command, skip2, ws2)
- table.insert(expr, command)
+ expr[#expr+1] = command
return ( #skip1 > 0 and "" or ws1 ) ..
"<%" .. tostring(#expr) .. "%>" ..
( #skip2 > 0 and "" or ws2 )
self.name = name
-- Create a new namespace for this template
- self.viewns = {sink=self.sink}
-
- -- Copy over from general namespace
- util.update(self.viewns, viewns)
- if context.viewns then
- util.update(self.viewns, context.viewns)
- end
+ self.viewns = context.viewns
-- If we have a cached template, skip compiling and loading
if self.template then
local cdir = compiledir .. "/" .. sys.process.info("uid")
-- Compile and build
- local sourcefile = viewdir .. "/" .. name .. ".htm"
+ local sourcefile = viewdir .. "/" .. name
local compiledfile = cdir .. "/" .. _encode_filename(name) .. ".lua"
local err
if compiler_mode == "file" then
- local tplmt = fs.mtime(sourcefile)
+ local tplmt = fs.mtime(sourcefile) or fs.mtime(sourcefile .. ".htm")
local commt = fs.mtime(compiledfile)
if not fs.mtime(cdir) then
fs.mkdir(cdir, true)
fs.chmod(fs.dirname(cdir), "a+rxw")
end
+
+ assert(tplmt or commt, "No such template: " .. name)
-- Build if there is no compiled file or if compiled file is outdated
- if ((commt == nil) and not (tplmt == nil))
- or (not (commt == nil) and not (tplmt == nil) and commt < tplmt) then
+ if not commt or (commt and tplmt and commt < tplmt) then
local source
- source, err = fs.readfile(sourcefile)
+ source, err = fs.readfile(sourcefile) or fs.readfile(sourcefile .. ".htm")
if source then
local compiled, err = compile(source)
elseif compiler_mode == "memory" then
local source
- source, err = fs.readfile(sourcefile)
+ source, err = fs.readfile(sourcefile) or fs.readfile(sourcefile .. ".htm")
if source then
self.template, err = compile(source)
end
function Template.render(self, scope)
scope = scope or getfenv(2)
- -- Save old environment
- local oldfenv = getfenv(self.template)
-
-- Put our predefined objects in the scope of the template
- util.resfenv(self.template)
- util.updfenv(self.template, scope)
- util.updfenv(self.template, self.viewns)
+ setfenv(self.template, setmetatable({}, {__index =
+ function(tbl, key)
+ return rawget(tbl, key) or self.viewns[key] or scope[key]
+ end}))
-- Now finally render the thing
local stat, err = util.copcall(self.template)
if not stat then
- setfenv(self.template, oldfenv)
- error("Error in template %s: %s" % {self.name, chunk})
+ error("Error in template %s: %s" % {self.name, err})
end
-
- -- Reset environment
- setfenv(self.template, oldfenv)
end