* CBI updates
[project/luci.git] / src / ffluci / cbi.lua
1 --[[
2 FFLuCI - Configuration Bind Interface
3
4 Description:
5 Offers an interface for binding confiugration values to certain
6 data types. Supports value and range validation and basic dependencies.
7
8 FileId:
9 $Id$
10
11 License:
12 Copyright 2008 Steven Barth <steven@midlink.org>
13
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
17
18 http://www.apache.org/licenses/LICENSE-2.0
19
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.
25
26 ]]--
27 module("ffluci.cbi", package.seeall)
28 require("ffluci.template")
29 require("ffluci.util")
30 require("ffluci.http")
31 require("ffluci.model.uci")
32 local Template = ffluci.template.Template
33 local class = ffluci.util.class
34 local instanceof = ffluci.util.instanceof
35
36
37 -- Node pseudo abstract class
38 Node = class()
39
40 function Node.__init__(self, title, description)
41 self.children = {}
42 self.title = title
43 self.description = description
44 self.template = "cbi/node"
45 end
46
47 function Node.append(self, obj)
48 table.insert(self.children, obj)
49 end
50
51 function Node.parse(self)
52 for k, child in ipairs(self.children) do
53 child:parse()
54 end
55 end
56
57 function Node.render(self)
58 ffluci.template.render(self.template)
59 end
60
61
62 --[[
63 Map - A map describing a configuration file
64 ]]--
65 Map = class(Node)
66
67 function Map.__init__(self, config, ...)
68 Node.__init__(self, ...)
69 self.config = config
70 self.template = "cbi/map"
71 end
72
73 function Map.section(self, class, ...)
74 if instanceof(class, AbstractSection) then
75 local obj = class(...)
76 obj.map = self
77 obj.config = self.config
78 self:append(obj)
79 return obj
80 else
81 error("class must be a descendent of AbstractSection")
82 end
83 end
84
85 function Map.read(self)
86 self.ucidata = self.ucidata or ffluci.model.uci.show(self.config)
87 return self.ucidata
88 end
89
90 --[[
91 AbstractSection
92 ]]--
93 AbstractSection = class(Node)
94
95 function AbstractSection.__init__(self, sectiontype, ...)
96 Node.__init__(self, ...)
97 self.sectiontype = sectiontype
98 end
99
100 function AbstractSection.option(self, class, ...)
101 if instanceof(class, AbstractValue) then
102 local obj = class(...)
103 obj.map = self.map
104 obj.config = self.config
105 self:append(obj)
106 return obj
107 else
108 error("class must be a descendent of AbstractValue")
109 end
110 end
111
112
113
114 --[[
115 NamedSection - A fixed configuration section defined by its name
116 ]]--
117 NamedSection = class(AbstractSection)
118
119 function NamedSection.__init__(self, section, ...)
120 AbstractSection.__init__(self, ...)
121 self.template = "cbi/nsection"
122
123 self.section = section
124 end
125
126 function NamedSection.option(self, ...)
127 local obj = AbstractSection.option(self, ...)
128 obj.section = self.section
129 return obj
130 end
131
132
133 --[[
134 TypedSection - A (set of) configuration section(s) defined by the type
135 addremove: Defines whether the user can add/remove sections of this type
136 anonymous: Allow creating anonymous sections
137 valid: a table with valid names or a function returning nil if invalid
138 ]]--
139 TypedSection = class(AbstractSection)
140
141 function TypedSection.__init__(self, ...)
142 AbstractSection.__init__(self, ...)
143 self.template = "cbi/tsection"
144
145 self.addremove = true
146 self.anonymous = false
147 self.valid = nil
148 end
149
150
151 --[[
152 AbstractValue - An abstract Value Type
153 null: Value can be empty
154 valid: A function returning the value if it is valid otherwise nil
155 depends: A table of option => value pairs of which one must be true
156 default: The default value
157 ]]--
158 AbstractValue = class(Node)
159
160 function AbstractValue.__init__(self, option, ...)
161 Node.__init__(self, ...)
162 self.option = option
163
164 self.valid = nil
165 self.depends = nil
166 self.default = nil
167 end
168
169
170 function AbstractValue.formvalue(self)
171 local key = "uci."..self.map.config.."."..self.section.."."..self.option
172 return ffluci.http.formvalue(key)
173 end
174
175 function AbstractValue.ucivalue(self)
176 return self.map.read()[self.section][self.option]
177 end
178
179 function AbstractValue.validate(self, value)
180 return ffluci.util.validate(value, nil, nil, self.valid)
181 end
182
183 function AbstractValue.write(self, value)
184 ffluci.model.uci.set(self.config, self.section, self.option, value)
185 end
186
187
188 --[[
189 Value - A one-line value
190 maxlength: The maximum length
191 isnumber: The value must be a valid (floating point) number
192 isinteger: The value must be a valid integer
193 ]]--
194 Value = class(AbstractValue)
195
196 function Value.__init__(self, ...)
197 AbstractValue.__init__(self, ...)
198 self.template = "cbi/value"
199
200 self.maxlength = nil
201 self.isnumber = false
202 self.isinteger = false
203 end
204
205
206 --[[
207 ListValue - A one-line value predefined in a list
208 ]]--
209 ListValue = class(AbstractValue)
210
211 function ListValue.__init__(self, ...)
212 AbstractValue.__init__(self, ...)
213 self.template = "cbi/lvalue"
214
215 self.list = {}
216 end
217
218 function ListValue.addValue(self, key, val)
219 val = val or key
220 self.list[key] = val
221 end