1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Licensed to the public under the Apache License 2.0.
4 local util = require "luci.util"
5 local config = require "luci.config"
6 local tparser = require "luci.template.parser"
8 local tostring, pairs, loadstring = tostring, pairs, loadstring
9 local setmetatable, loadfile = setmetatable, loadfile
10 local getfenv, setfenv, rawget = getfenv, setfenv, rawget
11 local assert, type, error = assert, type, error
13 --- LuCI template library.
14 module "luci.template"
16 config.template = config.template or {}
17 viewdir = config.template.viewdir or util.libpath() .. "/view"
20 -- Define the namespace for template modules
21 context = util.threadlocal()
23 --- Render a certain template.
24 -- @param name Template name
25 -- @param scope Scope to assign to template (optional)
26 function render(name, scope)
27 return Template(name):render(scope or getfenv(2))
30 --- Render a template from a string.
31 -- @param template Template string
32 -- @param scope Scope to assign to template (optional)
33 function render_string(template, scope)
34 return Template(nil, template):render(scope or getfenv(2))
39 Template = util.class()
41 -- Shared template cache to store templates in to avoid unnecessary reloading
42 Template.cache = setmetatable({}, {__mode = "v"})
45 -- Constructor - Reads and compiles the template on-demand
46 function Template.__init__(self, name, template)
48 self.template = self.cache[name]
51 self.name = "[string]"
54 -- Create a new namespace for this template
55 self.viewns = context.viewns
57 -- If we have a cached template, skip compiling and loading
58 if not self.template then
65 sourcefile = viewdir .. "/" .. name .. ".htm"
66 self.template, _, err = tparser.parse(sourcefile)
68 sourcefile = "[string]"
69 self.template, _, err = tparser.parse_string(template)
72 -- If we have no valid template throw error, otherwise cache the template
73 if not self.template then
74 error("Failed to load template '" .. name .. "'.\n" ..
75 "Error while parsing template '" .. sourcefile .. "':\n" ..
76 (err or "Unknown syntax error"))
78 self.cache[name] = self.template
85 function Template.render(self, scope)
86 scope = scope or getfenv(2)
88 -- Put our predefined objects in the scope of the template
89 setfenv(self.template, setmetatable({}, {__index =
91 return rawget(tbl, key) or self.viewns[key] or scope[key]
94 -- Now finally render the thing
95 local stat, err = util.copcall(self.template)
97 error("Failed to execute template '" .. self.name .. "'.\n" ..
98 "A runtime error occurred: " .. tostring(err or "(nil)"))