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