luci/modules/luci-base/luasrc/template.lua

101 lines
2.8 KiB
Lua
Raw Normal View History

-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
2008-09-01 16:05:40 +00:00
local util = require "luci.util"
local config = require "luci.config"
local tparser = require "luci.template.parser"
2008-09-01 16:05:40 +00:00
local tostring, pairs, loadstring = tostring, pairs, loadstring
local setmetatable, loadfile = setmetatable, loadfile
local getfenv, setfenv, rawget = getfenv, setfenv, rawget
2008-09-01 16:05:40 +00:00
local assert, type, error = assert, type, error
2008-09-01 16:05:40 +00:00
--- LuCI template library.
module "luci.template"
2008-09-01 16:05:40 +00:00
config.template = config.template or {}
viewdir = config.template.viewdir or util.libpath() .. "/view"
-- Define the namespace for template modules
2008-09-01 16:05:40 +00:00
context = util.threadlocal()
--- Render a certain template.
-- @param name Template name
2008-09-01 16:05:40 +00:00
-- @param scope Scope to assign to template (optional)
function render(name, scope)
return Template(name):render(scope or getfenv(2))
end
--- Render a template from a string.
-- @param template Template string
-- @param scope Scope to assign to template (optional)
function render_string(template, scope)
return Template(nil, template):render(scope or getfenv(2))
end
-- Template class
2008-09-01 16:05:40 +00:00
Template = util.class()
-- Shared template cache to store templates in to avoid unnecessary reloading
2008-09-01 16:05:40 +00:00
Template.cache = setmetatable({}, {__mode = "v"})
-- Constructor - Reads and compiles the template on-demand
function Template.__init__(self, name, template)
if name then
self.template = self.cache[name]
self.name = name
else
self.name = "[string]"
end
2008-09-01 16:05:40 +00:00
-- Create a new namespace for this template
self.viewns = context.viewns
-- If we have a cached template, skip compiling and loading
if not self.template then
-- Compile template
local err
local sourcefile
if name then
sourcefile = viewdir .. "/" .. name .. ".htm"
self.template, _, err = tparser.parse(sourcefile)
else
sourcefile = "[string]"
self.template, _, err = tparser.parse_string(template)
end
-- If we have no valid template throw error, otherwise cache the template
if not self.template then
2011-07-21 01:04:53 +00:00
error("Failed to load template '" .. name .. "'.\n" ..
"Error while parsing template '" .. sourcefile .. "':\n" ..
(err or "Unknown syntax error"))
elseif name then
self.cache[name] = self.template
end
end
end
-- Renders a template
function Template.render(self, scope)
scope = scope or getfenv(2)
-- Put our predefined objects in the scope of the template
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
2008-09-01 16:05:40 +00:00
local stat, err = util.copcall(self.template)
if not stat then
2011-07-21 01:04:53 +00:00
error("Failed to execute template '" .. self.name .. "'.\n" ..
"A runtime error occurred: " .. tostring(err or "(nil)"))
end
end