* 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 local Template = ffluci.template.Template
31 local class = ffluci.util.class
32 local instanceof = ffluci.util.instanceof
33
34
35 -- Node pseudo abstract class
36 Node = class()
37
38 function Node.__init__(self, title, description)
39 self.children = {}
40 self.title = title
41 self.description = description
42 self.template = "cbi/node"
43 end
44
45 function Node.append(self, obj)
46 table.insert(self.children, obj)
47 end
48
49 function Node.render(self)
50 ffluci.template.render(self.template, self)
51 end
52
53
54 --[[
55 Map - A map describing a configuration file
56 ]]--
57 Map = class(Node)
58
59 function Map.__init__(self, config, ...)
60 Node.__init__(self, ...)
61 self.config = config
62 self.template = "cbi/map"
63 end
64
65 function Map.section(self, class, ...)
66 if instanceof(class, AbstractSection) then
67 local obj = class(...)
68 obj.map = self.config
69 table.insert(self.children, obj)
70 return obj
71 else
72 error("class must be a descendent of AbstractSection")
73 end
74 end
75
76
77 --[[
78 AbstractSection
79 ]]--
80 AbstractSection = class(Node)
81
82 function AbstractSection.__init__(self, sectiontype, ...)
83 Node.__init__(self, ...)
84 self.sectiontype = sectiontype
85 end
86
87 function AbstractSection.option(self, class, ...)
88 if instanceof(class, AbstractValue) then
89 local obj = class(...)
90 obj.map = self.map
91 table.insert(self.children, obj)
92 return obj
93 else
94 error("class must be a descendent of AbstractValue")
95 end
96 end
97
98
99
100 --[[
101 NamedSection - A fixed configuration section defined by its name
102 ]]--
103 NamedSection = class(AbstractSection)
104
105 function NamedSection.__init__(self, section, ...)
106 AbstractSection.__init__(self, ...)
107 self.template = "cbi/nsection"
108
109 self.section = section
110 end
111
112 function NamedSection.option(self, ...)
113 local obj = AbstractSection.option(self, ...)
114 obj.section = self.section
115 return obj
116 end
117
118
119 --[[
120 TypedSection - A (set of) configuration section(s) defined by the type
121 addremove: Defines whether the user can add/remove sections of this type
122 anonymous: Allow creating anonymous sections
123 valid: a table with valid names or a function returning nil if invalid
124 ]]--
125 TypedSection = class(AbstractSection)
126
127 function TypedSection.__init__(self, ...)
128 AbstractSection.__init__(self, ...)
129 self.template = "cbi/tsection"
130
131 self.addremove = true
132 self.anonymous = false
133 self.valid = nil
134 end
135
136
137 --[[
138 AbstractValue - An abstract Value Type
139 null: Value can be empty
140 valid: A function returning nil if invalid
141 depends: A table of option => value pairs of which one must be true
142 default: The default value
143 ]]--
144 AbstractValue = class(Node)
145
146 function AbstractValue.__init__(self, option, ...)
147 Node.__init__(self, ...)
148 self.option = option
149
150 self.valid = nil
151 self.depends = nil
152 self.default = nil
153 end
154
155
156 --[[
157 Value - A one-line value
158 maxlength: The maximum length
159 isnumber: The value must be a valid (floating point) number
160 isinteger: The value must be a valid integer
161 ]]--
162 Value = class(AbstractValue)
163
164 function Value.__init__(self, ...)
165 AbstractValue.__init__(self, ...)
166 self.template = "cbi/value"
167
168 self.maxlength = nil
169 self.isnumber = false
170 self.isinteger = false
171 end
172
173
174 --[[
175 ListValue - A one-line value predefined in a list
176 ]]--
177 ListValue = class(AbstractValue)
178
179 function ListValue.__init__(self, ...)
180 AbstractValue.__init__(self, ...)
181 self.template = "cbi/value"
182
183 self.list = {}
184 end
185
186 function ListValue.addValue(self, key, val)
187 val = val or key
188 self.list[key] = val
189 end