2 FFLuCI - Configuration Bind Interface
5 Offers an interface for binding confiugration values to certain
6 data types. Supports value and range validation and basic dependencies.
12 Copyright 2008 Steven Barth <steven@midlink.org>
14 Licensed under the Apache License, Version 2.0 (the "License");
15 you may not use this file except in compliance with the License.
16 You may obtain a copy of the License at
18 http://www.apache.org/licenses/LICENSE-2.0
20 Unless required by applicable law or agreed to in writing, software
21 distributed under the License is distributed on an "AS IS" BASIS,
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 See the License for the specific language governing permissions and
24 limitations under the License.
27 module("ffluci.cbi", package.seeall)
29 require("ffluci.template")
30 require("ffluci.util")
31 require("ffluci.http")
32 require("ffluci.model.uci")
34 local Template = ffluci.template.Template
35 local class = ffluci.util.class
36 local instanceof = ffluci.util.instanceof
41 require("ffluci.i18n")
43 local cbidir = ffluci.fs.dirname(ffluci.util.__file__()) .. "model/cbi/"
44 local func = loadfile(cbidir..cbimap..".lua")
47 error("Unable to load CBI map: " .. cbimap)
51 ffluci.util.resfenv(func)
52 ffluci.util.updfenv(func, ffluci.cbi)
53 ffluci.util.extfenv(func, "translate", ffluci.i18n.translate)
57 if not instanceof(map, Map) then
58 error("CBI map returns no valid map object!")
65 -- Node pseudo abstract class
68 function Node.__init__(self, title, description)
70 self.title = title or ""
71 self.description = description or ""
72 self.template = "cbi/node"
75 function Node.append(self, obj)
76 table.insert(self.children, obj)
79 function Node.parse(self)
80 for k, child in ipairs(self.children) do
85 function Node.render(self)
86 ffluci.template.render(self.template, {self=self})
89 function Node.render_children(self)
90 for k, node in ipairs(self.children) do
97 Map - A map describing a configuration file
101 function Map.__init__(self, config, ...)
102 Node.__init__(self, ...)
104 self.template = "cbi/map"
107 function Map.section(self, class, ...)
108 if instanceof(class, AbstractSection) then
109 local obj = class(...)
111 obj.config = self.config
115 error("class must be a descendent of AbstractSection")
119 function Map.read(self)
120 self.ucidata = self.ucidata or ffluci.model.uci.show(self.config)[self.config]
127 AbstractSection = class(Node)
129 function AbstractSection.__init__(self, sectiontype, ...)
130 Node.__init__(self, ...)
131 self.sectiontype = sectiontype
134 function AbstractSection.option(self, class, ...)
135 if instanceof(class, AbstractValue) then
136 local obj = class(...)
138 obj.config = self.config
142 error("class must be a descendent of AbstractValue")
149 NamedSection - A fixed configuration section defined by its name
151 NamedSection = class(AbstractSection)
153 function NamedSection.__init__(self, section, ...)
154 AbstractSection.__init__(self, ...)
155 self.template = "cbi/nsection"
157 self.section = section
160 function NamedSection.option(self, ...)
161 local obj = AbstractSection.option(self, ...)
162 obj.section = self.section
168 TypedSection - A (set of) configuration section(s) defined by the type
169 addremove: Defines whether the user can add/remove sections of this type
170 anonymous: Allow creating anonymous sections
171 valid: a table with valid names or a function returning nil if invalid
173 TypedSection = class(AbstractSection)
175 function TypedSection.__init__(self, ...)
176 AbstractSection.__init__(self, ...)
177 self.template = "cbi/tsection"
179 self.addremove = true
180 self.anonymous = false
184 function TypedSection.render_children(self, section)
185 for k, node in ipairs(self.children) do
186 node.section = section
191 function TypedSection.ucisections(self)
193 for k, v in pairs(self.map:read()) do
194 if v[".type"] == self.sectiontype then
203 AbstractValue - An abstract Value Type
204 null: Value can be empty
205 valid: A function returning the value if it is valid otherwise nil
206 depends: A table of option => value pairs of which one must be true
207 default: The default value
209 AbstractValue = class(Node)
211 function AbstractValue.__init__(self, option, ...)
212 Node.__init__(self, ...)
221 function AbstractValue.formvalue(self)
222 local key = "uci."..self.map.config.."."..self.section.."."..self.option
223 return ffluci.http.formvalue(key)
226 function AbstractValue.ucivalue(self)
227 return self.map:read()[self.section][self.option]
230 function AbstractValue.validate(self, value)
231 return ffluci.util.validate(value, nil, nil, self.valid)
234 function AbstractValue.write(self, value)
235 ffluci.model.uci.set(self.config, self.section, self.option, value)
240 Value - A one-line value
241 maxlength: The maximum length
242 isnumber: The value must be a valid (floating point) number
243 isinteger: The value must be a valid integer
245 Value = class(AbstractValue)
247 function Value.__init__(self, ...)
248 AbstractValue.__init__(self, ...)
249 self.template = "cbi/value"
252 self.isnumber = false
253 self.isinteger = false
258 ListValue - A one-line value predefined in a list
260 ListValue = class(AbstractValue)
262 function ListValue.__init__(self, ...)
263 AbstractValue.__init__(self, ...)
264 self.template = "cbi/lvalue"
269 function ListValue.addValue(self, key, val)