libs/cbi: Fix option initialisation errors
[project/luci.git] / libs / cbi / luasrc / cbi.lua
1 --[[
2 LuCI - Configuration Bind Interface
3
4 Description:
5 Offers an interface for binding configuration 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("luci.cbi", package.seeall)
28
29 require("luci.template")
30 require("luci.util")
31 require("luci.http")
32 require("luci.uvl")
33
34 local uci        = require("luci.model.uci")
35 local class      = luci.util.class
36 local instanceof = luci.util.instanceof
37
38 FORM_NODATA  =  0
39 FORM_VALID   =  1
40 FORM_INVALID = -1
41
42 AUTO = true
43
44 CREATE_PREFIX = "cbi.cts."
45 REMOVE_PREFIX = "cbi.rts."
46
47 -- Loads a CBI map from given file, creating an environment and returns it
48 function load(cbimap, ...)
49         require("luci.fs")
50         local i18n = require "luci.i18n"
51         require("luci.config")
52         require("luci.util")
53
54         local cbidir = luci.util.libpath() .. "/model/cbi/"
55         local func, err = loadfile(cbimap) or loadfile(cbidir..cbimap..".lua")
56         assert(func, err)
57
58         luci.i18n.loadc("cbi")
59         luci.i18n.loadc("uvl")
60
61         local env = {
62                 translate=i18n.translate,
63                 translatef=i18n.translatef,
64                 arg={...}
65         }
66
67         setfenv(func, setmetatable(env, {__index =
68                 function(tbl, key)
69                         return rawget(tbl, key) or _M[key] or _G[key]
70                 end}))
71
72         local maps = {func()}
73
74         for i, map in ipairs(maps) do
75                 if not instanceof(map, Node) then
76                         error("CBI map returns no valid map object!")
77                         return nil
78                 else
79                         map:prepare()
80                 end
81         end
82
83         return maps
84 end
85
86 local function _uvl_validate_section(node, name)
87         local co = node.map:get()
88
89         luci.uvl.STRICT_UNKNOWN_OPTIONS = false
90         luci.uvl.STRICT_UNKNOWN_SECTIONS = false
91
92         local function tag_fields(e)
93                 if e.option and node.fields[e.option] then
94                         if node.fields[e.option].error then
95                                 node.fields[e.option].error[name] = e
96                         else
97                                 node.fields[e.option].error = { [name] = e }
98                         end
99                 elseif e.childs then
100                         for _, c in ipairs(e.childs) do tag_fields(c) end
101                 end
102         end
103
104         local function tag_section(e)
105                 local s = { }
106                 for _, c in ipairs(e.childs) do
107                         if c.childs and not c:is(luci.uvl.errors.ERR_DEPENDENCY) then
108                                 table.insert( s, c.childs[1]:string() )
109                         else
110                                 table.insert( s, c:string() )
111                         end
112                 end
113                 if #s > 0 then
114                         if node.error then
115                                 node.error[name] = s
116                         else
117                                 node.error = { [name] = s }
118                         end
119                 end
120         end
121
122         local stat, err = node.map.validator:validate_section(node.config, name, co)
123         if err then
124                 node.map.save = false
125                 tag_fields(err)
126                 tag_section(err)
127         end
128
129 end
130
131 local function _uvl_strip_remote_dependencies(deps)
132         local clean = {}
133
134         for k, v in pairs(deps) do
135                 k = k:gsub("%$config%.%$section%.", "")
136                 if k:match("^[%w_]+$") and type(v) == "string" then
137                         clean[k] = v
138                 end
139         end
140
141         return clean
142 end
143
144
145 -- Node pseudo abstract class
146 Node = class()
147
148 function Node.__init__(self, title, description)
149         self.children = {}
150         self.title = title or ""
151         self.description = description or ""
152         self.template = "cbi/node"
153 end
154
155 -- i18n helper
156 function Node._i18n(self, config, section, option, title, description)
157
158         -- i18n loaded?
159         if type(luci.i18n) == "table" then
160
161                 local key = config and config:gsub("[^%w]+", "") or ""
162
163                 if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end
164                 if option  then key = key .. "_" .. tostring(option):lower():gsub("[^%w]+", "")  end
165
166                 self.title = title or luci.i18n.translate( key, option or section or config )
167                 self.description = description or luci.i18n.translate( key .. "_desc", "" )
168         end
169 end
170
171 -- Prepare nodes
172 function Node.prepare(self, ...)
173         for k, child in ipairs(self.children) do
174                 child:prepare(...)
175         end
176 end
177
178 -- Append child nodes
179 function Node.append(self, obj)
180         table.insert(self.children, obj)
181 end
182
183 -- Parse this node and its children
184 function Node.parse(self, ...)
185         for k, child in ipairs(self.children) do
186                 child:parse(...)
187         end
188 end
189
190 -- Render this node
191 function Node.render(self, scope)
192         scope = scope or {}
193         scope.self = self
194
195         luci.template.render(self.template, scope)
196 end
197
198 -- Render the children
199 function Node.render_children(self, ...)
200         for k, node in ipairs(self.children) do
201                 node:render(...)
202         end
203 end
204
205
206 --[[
207 A simple template element
208 ]]--
209 Template = class(Node)
210
211 function Template.__init__(self, template)
212         Node.__init__(self)
213         self.template = template
214 end
215
216 function Template.render(self)
217         luci.template.render(self.template, {self=self})
218 end
219
220
221 --[[
222 Map - A map describing a configuration file
223 ]]--
224 Map = class(Node)
225
226 function Map.__init__(self, config, ...)
227         Node.__init__(self, ...)
228         Node._i18n(self, config, nil, nil, ...)
229
230         self.config = config
231         self.parsechain = {self.config}
232         self.template = "cbi/map"
233         self.apply_on_parse = nil
234         self.uci = uci.cursor()
235         self.save = true
236         if not self.uci:load(self.config) then
237                 error("Unable to read UCI data: " .. self.config)
238         end
239
240         self.validator = luci.uvl.UVL()
241         self.scheme = self.validator:get_scheme(self.config)
242
243 end
244
245 function Map.get_scheme(self, sectiontype, option)
246         if not option then
247                 return self.scheme and self.scheme.sections[sectiontype]
248         else
249                 return self.scheme and self.scheme.variables[sectiontype]
250                  and self.scheme.variables[sectiontype][option]
251         end
252 end
253
254
255 -- Chain foreign config
256 function Map.chain(self, config)
257         table.insert(self.parsechain, config)
258 end
259
260 -- Use optimized UCI writing
261 function Map.parse(self)
262         Node.parse(self)
263
264         if self.save then
265                 for i, config in ipairs(self.parsechain) do
266                         self.uci:save(config)
267                 end
268                 if luci.http.formvalue("cbi.apply") then
269                         for i, config in ipairs(self.parsechain) do
270                                 self.uci:commit(config)
271
272                                 -- Refresh data because commit changes section names
273                                 self.uci:load(config)
274                         end
275                         if self.apply_on_parse then
276                                 self.uci:apply(self.parsechain)
277                         else
278                                 self._apply = function()
279                                         local cmd = self.uci:apply(self.parsechain, true)
280                                         return io.popen(cmd)
281                                 end
282                         end
283
284                         -- Reparse sections
285                         Node.parse(self, true)
286
287                 end
288                 for i, config in ipairs(self.parsechain) do
289                         self.uci:unload(config)
290                 end
291         end
292 end
293
294 function Map.render(self, ...)
295         Node.render(self, ...)
296         if self._apply then
297                 local fp = self._apply()
298                 fp:read("*a")
299                 fp:close()
300         end
301 end
302
303 -- Creates a child section
304 function Map.section(self, class, ...)
305         if instanceof(class, AbstractSection) then
306                 local obj  = class(self, ...)
307                 self:append(obj)
308                 return obj
309         else
310                 error("class must be a descendent of AbstractSection")
311         end
312 end
313
314 -- UCI add
315 function Map.add(self, sectiontype)
316         return self.uci:add(self.config, sectiontype)
317 end
318
319 -- UCI set
320 function Map.set(self, section, option, value)
321         if option then
322                 return self.uci:set(self.config, section, option, value)
323         else
324                 return self.uci:set(self.config, section, value)
325         end
326 end
327
328 -- UCI del
329 function Map.del(self, section, option)
330         if option then
331                 return self.uci:delete(self.config, section, option)
332         else
333                 return self.uci:delete(self.config, section)
334         end
335 end
336
337 -- UCI get
338 function Map.get(self, section, option)
339         if not section then
340                 return self.uci:get_all(self.config)
341         elseif option then
342                 return self.uci:get(self.config, section, option)
343         else
344                 return self.uci:get_all(self.config, section)
345         end
346 end
347
348
349 --[[
350 Page - A simple node
351 ]]--
352
353 Page = class(Node)
354 Page.__init__ = Node.__init__
355 Page.parse    = function() end
356
357
358 --[[
359 SimpleForm - A Simple non-UCI form
360 ]]--
361 SimpleForm = class(Node)
362
363 function SimpleForm.__init__(self, config, title, description, data)
364         Node.__init__(self, title, description)
365         self.config = config
366         self.data = data or {}
367         self.template = "cbi/simpleform"
368         self.dorender = true
369 end
370
371 function SimpleForm.parse(self, ...)
372         if luci.http.formvalue("cbi.submit") then
373                 Node.parse(self, 1, ...)
374         end
375
376         local valid = true
377         for k, j in ipairs(self.children) do
378                 for i, v in ipairs(j.children) do
379                         valid = valid
380                          and (not v.tag_missing or not v.tag_missing[1])
381                          and (not v.tag_invalid or not v.tag_invalid[1])
382                 end
383         end
384
385         local state =
386                 not luci.http.formvalue("cbi.submit") and 0
387                 or valid and 1
388                 or -1
389
390         self.dorender = not self.handle or self:handle(state, self.data) ~= false
391 end
392
393 function SimpleForm.render(self, ...)
394         if self.dorender then
395                 Node.render(self, ...)
396         end
397 end
398
399 function SimpleForm.section(self, class, ...)
400         if instanceof(class, AbstractSection) then
401                 local obj  = class(self, ...)
402                 self:append(obj)
403                 return obj
404         else
405                 error("class must be a descendent of AbstractSection")
406         end
407 end
408
409 -- Creates a child field
410 function SimpleForm.field(self, class, ...)
411         local section
412         for k, v in ipairs(self.children) do
413                 if instanceof(v, SimpleSection) then
414                         section = v
415                         break
416                 end
417         end
418         if not section then
419                 section = self:section(SimpleSection)
420         end
421
422         if instanceof(class, AbstractValue) then
423                 local obj  = class(self, section, ...)
424                 obj.track_missing = true
425                 section:append(obj)
426                 return obj
427         else
428                 error("class must be a descendent of AbstractValue")
429         end
430 end
431
432 function SimpleForm.set(self, section, option, value)
433         self.data[option] = value
434 end
435
436
437 function SimpleForm.del(self, section, option)
438         self.data[option] = nil
439 end
440
441
442 function SimpleForm.get(self, section, option)
443         return self.data[option]
444 end
445
446
447 function SimpleForm.get_scheme()
448         return nil
449 end
450
451
452
453 --[[
454 AbstractSection
455 ]]--
456 AbstractSection = class(Node)
457
458 function AbstractSection.__init__(self, map, sectiontype, ...)
459         Node.__init__(self, ...)
460         self.sectiontype = sectiontype
461         self.map = map
462         self.config = map.config
463         self.optionals = {}
464         self.defaults = {}
465         self.fields = {}
466         self.tag_error = {}
467         self.tag_invalid = {}
468         self.tag_deperror = {}
469
470         self.optional = true
471         self.addremove = false
472         self.dynamic = false
473 end
474
475 -- Appends a new option
476 function AbstractSection.option(self, class, option, ...)
477         -- Autodetect from UVL
478         if class == true and self.map:get_scheme(self.sectiontype, option) then
479                 local vs = self.map:get_scheme(self.sectiontype, option)
480                 if vs.type == "boolean" then
481                         class = Flag
482                 elseif vs.type == "list" then
483                         class = DynamicList
484                 elseif vs.type == "enum" or vs.type == "reference" then
485                         class = ListValue
486                 else
487                         class = Value
488                 end
489         end
490
491         if instanceof(class, AbstractValue) then
492                 local obj  = class(self.map, self, option, ...)
493
494                 Node._i18n(obj, self.config, self.section or self.sectiontype, option, ...)
495
496                 self:append(obj)
497                 self.fields[option] = obj
498                 return obj
499         elseif class == true then
500                 error("No valid class was given and autodetection failed.")
501         else
502                 error("class must be a descendant of AbstractValue")
503         end
504 end
505
506 -- Parse optional options
507 function AbstractSection.parse_optionals(self, section)
508         if not self.optional then
509                 return
510         end
511
512         self.optionals[section] = {}
513
514         local field = luci.http.formvalue("cbi.opt."..self.config.."."..section)
515         for k,v in ipairs(self.children) do
516                 if v.optional and not v:cfgvalue(section) then
517                         if field == v.option then
518                                 field = nil
519                         else
520                                 table.insert(self.optionals[section], v)
521                         end
522                 end
523         end
524
525         if field and #field > 0 and self.dynamic then
526                 self:add_dynamic(field)
527         end
528 end
529
530 -- Add a dynamic option
531 function AbstractSection.add_dynamic(self, field, optional)
532         local o = self:option(Value, field, field)
533         o.optional = optional
534 end
535
536 -- Parse all dynamic options
537 function AbstractSection.parse_dynamic(self, section)
538         if not self.dynamic then
539                 return
540         end
541
542         local arr  = luci.util.clone(self:cfgvalue(section))
543         local form = luci.http.formvaluetable("cbid."..self.config.."."..section)
544         for k, v in pairs(form) do
545                 arr[k] = v
546         end
547
548         for key,val in pairs(arr) do
549                 local create = true
550
551                 for i,c in ipairs(self.children) do
552                         if c.option == key then
553                                 create = false
554                         end
555                 end
556
557                 if create and key:sub(1, 1) ~= "." then
558                         self:add_dynamic(key, true)
559                 end
560         end
561 end
562
563 -- Returns the section's UCI table
564 function AbstractSection.cfgvalue(self, section)
565         return self.map:get(section)
566 end
567
568 -- Removes the section
569 function AbstractSection.remove(self, section)
570         return self.map:del(section)
571 end
572
573 -- Creates the section
574 function AbstractSection.create(self, section)
575         local stat
576
577         if section then
578                 stat = section:match("^%w+$") and self.map:set(section, nil, self.sectiontype)
579         else
580                 section = self.map:add(self.sectiontype)
581                 stat = section
582         end
583
584         if stat then
585                 for k,v in pairs(self.children) do
586                         if v.default then
587                                 self.map:set(section, v.option, v.default)
588                         end
589                 end
590
591                 for k,v in pairs(self.defaults) do
592                         self.map:set(section, k, v)
593                 end
594         end
595
596         return stat
597 end
598
599
600 SimpleSection = class(AbstractSection)
601
602 function SimpleSection.__init__(self, form, ...)
603         AbstractSection.__init__(self, form, nil, ...)
604         self.template = "cbi/nullsection"
605 end
606
607
608 Table = class(AbstractSection)
609
610 function Table.__init__(self, form, data, ...)
611         local datasource = {}
612         datasource.config = "table"
613         self.data = data
614
615         function datasource.get(self, section, option)
616                 return data[section] and data[section][option]
617         end
618
619         function datasource.del(...)
620                 return true
621         end
622
623         function datasource.get_scheme()
624                 return nil
625         end
626
627         AbstractSection.__init__(self, datasource, "table", ...)
628         self.template = "cbi/tblsection"
629         self.rowcolors = true
630         self.anonymous = true
631 end
632
633 function Table.parse(self)
634         for i, k in ipairs(self:cfgsections()) do
635                 if luci.http.formvalue("cbi.submit") then
636                         Node.parse(self, k)
637                 end
638         end
639 end
640
641 function Table.cfgsections(self)
642         local sections = {}
643
644         for i, v in luci.util.kspairs(self.data) do
645                 table.insert(sections, i)
646         end
647
648         return sections
649 end
650
651
652
653 --[[
654 NamedSection - A fixed configuration section defined by its name
655 ]]--
656 NamedSection = class(AbstractSection)
657
658 function NamedSection.__init__(self, map, section, stype, ...)
659         AbstractSection.__init__(self, map, stype, ...)
660         Node._i18n(self, map.config, section, nil, ...)
661
662         -- Defaults
663         self.addremove = false
664
665         -- Use defaults from UVL
666         if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
667                 local vs = self.map:get_scheme(self.sectiontype)
668                 self.addremove = not vs.unique and not vs.required
669                 self.dynamic   = vs.dynamic
670                 self.title       = self.title or vs.title
671                 self.description = self.description or vs.descr
672         end
673
674         self.template = "cbi/nsection"
675         self.section = section
676 end
677
678 function NamedSection.parse(self, novld)
679         local s = self.section
680         local active = self:cfgvalue(s)
681
682         if self.addremove then
683                 local path = self.config.."."..s
684                 if active then -- Remove the section
685                         if luci.http.formvalue("cbi.rns."..path) and self:remove(s) then
686                                 return
687                         end
688                 else           -- Create and apply default values
689                         if luci.http.formvalue("cbi.cns."..path) then
690                                 self:create(s)
691                                 return
692                         end
693                 end
694         end
695
696         if active then
697                 AbstractSection.parse_dynamic(self, s)
698                 if luci.http.formvalue("cbi.submit") then
699                         Node.parse(self, s)
700
701                         if not novld and not self.override_scheme and self.map.scheme then
702                                 _uvl_validate_section(self, s)
703                         end
704                 end
705                 AbstractSection.parse_optionals(self, s)
706         end
707 end
708
709
710 --[[
711 TypedSection - A (set of) configuration section(s) defined by the type
712         addremove:      Defines whether the user can add/remove sections of this type
713         anonymous:  Allow creating anonymous sections
714         validate:       a validation function returning nil if the section is invalid
715 ]]--
716 TypedSection = class(AbstractSection)
717
718 function TypedSection.__init__(self, map, type, ...)
719         AbstractSection.__init__(self, map, type, ...)
720         Node._i18n(self, map.config, type, nil, ...)
721
722         self.template  = "cbi/tsection"
723         self.deps = {}
724         self.anonymous = false
725
726         -- Use defaults from UVL
727         if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
728                 local vs = self.map:get_scheme(self.sectiontype)
729                 self.addremove = not vs.unique and not vs.required
730                 self.dynamic   = vs.dynamic
731                 self.anonymous = not vs.named
732                 self.title       = self.title or vs.title
733                 self.description = self.description or vs.descr
734         end
735 end
736
737 -- Return all matching UCI sections for this TypedSection
738 function TypedSection.cfgsections(self)
739         local sections = {}
740         self.map.uci:foreach(self.map.config, self.sectiontype,
741                 function (section)
742                         if self:checkscope(section[".name"]) then
743                                 table.insert(sections, section[".name"])
744                         end
745                 end)
746
747         return sections
748 end
749
750 -- Limits scope to sections that have certain option => value pairs
751 function TypedSection.depends(self, option, value)
752         table.insert(self.deps, {option=option, value=value})
753 end
754
755 function TypedSection.parse(self, novld)
756         if self.addremove then
757                 -- Remove
758                 local crval = REMOVE_PREFIX .. self.config
759                 local name = luci.http.formvaluetable(crval)
760                 for k,v in pairs(name) do
761                         if k:sub(-2) == ".x" then
762                                 k = k:sub(1, #k - 2)
763                         end
764                         if self:cfgvalue(k) and self:checkscope(k) then
765                                 self:remove(k)
766                         end
767                 end
768         end
769
770         local co
771         for i, k in ipairs(self:cfgsections()) do
772                 AbstractSection.parse_dynamic(self, k)
773                 if luci.http.formvalue("cbi.submit") then
774                         Node.parse(self, k)
775
776                         if not novld and not self.override_scheme and self.map.scheme then
777                                 _uvl_validate_section(self, k)
778                         end
779                 end
780                 AbstractSection.parse_optionals(self, k)
781         end
782
783         if self.addremove then
784                 -- Create
785                 local created
786                 local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype
787                 local name  = luci.http.formvalue(crval)
788                 if self.anonymous then
789                         if name then
790                                 created = self:create()
791                         end
792                 else
793                         if name then
794                                 -- Ignore if it already exists
795                                 if self:cfgvalue(name) then
796                                         name = nil;
797                                 end
798
799                                 name = self:checkscope(name)
800
801                                 if not name then
802                                         self.err_invalid = true
803                                 end
804
805                                 if name and #name > 0 then
806                                         created = self:create(name) and name
807                                         if not created then
808                                                 self.invalid_cts = true
809                                         end
810                                 end
811                         end
812                 end
813
814                 if created then
815                         AbstractSection.parse_optionals(self, created)
816                 end
817         end
818 end
819
820 -- Verifies scope of sections
821 function TypedSection.checkscope(self, section)
822         -- Check if we are not excluded
823         if self.filter and not self:filter(section) then
824                 return nil
825         end
826
827         -- Check if at least one dependency is met
828         if #self.deps > 0 and self:cfgvalue(section) then
829                 local stat = false
830
831                 for k, v in ipairs(self.deps) do
832                         if self:cfgvalue(section)[v.option] == v.value then
833                                 stat = true
834                         end
835                 end
836
837                 if not stat then
838                         return nil
839                 end
840         end
841
842         return self:validate(section)
843 end
844
845
846 -- Dummy validate function
847 function TypedSection.validate(self, section)
848         return section
849 end
850
851
852 --[[
853 AbstractValue - An abstract Value Type
854         null:           Value can be empty
855         valid:          A function returning the value if it is valid otherwise nil
856         depends:        A table of option => value pairs of which one must be true
857         default:        The default value
858         size:           The size of the input fields
859         rmempty:        Unset value if empty
860         optional:       This value is optional (see AbstractSection.optionals)
861 ]]--
862 AbstractValue = class(Node)
863
864 function AbstractValue.__init__(self, map, section, option, ...)
865         Node.__init__(self, ...)
866         self.section = section
867         self.option  = option
868         self.map     = map
869         self.config  = map.config
870         self.tag_invalid = {}
871         self.tag_missing = {}
872         self.tag_reqerror = {}
873         self.tag_error = {}
874         self.deps = {}
875         --self.cast = "string"
876
877         self.track_missing = false
878         --self.rmempty   = false
879         self.default   = nil
880         self.size      = nil
881         self.optional  = false
882 end
883
884 function AbstractValue.prepare(self)
885         -- Use defaults from UVL
886         if not self.override_scheme
887          and self.map:get_scheme(self.section.sectiontype, self.option) then
888                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
889                 if self.rmempty == nil then
890                         self.rmempty = not vs.required
891                 end
892                 if self.cast == nil then
893                         self.cast = (vs.type == "list") and "list" or "string"
894                 end
895                 self.title       = self.title or vs.title
896                 self.description = self.description or vs.descr
897                 if self.default == nil then
898                         self.default = vs.default
899                 end
900
901                 if vs.depends and not self.override_dependencies then
902                         for i, deps in ipairs(vs.depends) do
903                                 deps = _uvl_strip_remote_dependencies(deps)
904                                 if next(deps) then
905                                         self:depends(deps)
906                                 end
907                         end
908                 end
909         end
910
911         self.cast = self.cast or "string"
912 end
913
914 -- Add a dependencie to another section field
915 function AbstractValue.depends(self, field, value)
916         local deps
917         if type(field) == "string" then
918                 deps = {}
919                 deps[field] = value
920         else
921                 deps = field
922         end
923
924         table.insert(self.deps, {deps=deps, add=""})
925 end
926
927 -- Generates the unique CBID
928 function AbstractValue.cbid(self, section)
929         return "cbid."..self.map.config.."."..section.."."..self.option
930 end
931
932 -- Return whether this object should be created
933 function AbstractValue.formcreated(self, section)
934         local key = "cbi.opt."..self.config.."."..section
935         return (luci.http.formvalue(key) == self.option)
936 end
937
938 -- Returns the formvalue for this object
939 function AbstractValue.formvalue(self, section)
940         return luci.http.formvalue(self:cbid(section))
941 end
942
943 function AbstractValue.additional(self, value)
944         self.optional = value
945 end
946
947 function AbstractValue.mandatory(self, value)
948         self.rmempty = not value
949 end
950
951 function AbstractValue.parse(self, section)
952         local fvalue = self:formvalue(section)
953         local cvalue = self:cfgvalue(section)
954
955         if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI
956                 fvalue = self:transform(self:validate(fvalue, section))
957                 if not fvalue then
958                         self.tag_invalid[section] = true
959                 end
960                 if fvalue and not (fvalue == cvalue) then
961                         self:write(section, fvalue)
962                 end
963         else                                                    -- Unset the UCI or error
964                 if self.rmempty or self.optional then
965                         self:remove(section)
966                 elseif self.track_missing and (not fvalue or fvalue ~= cvalue) then
967                         self.tag_missing[section] = true
968                 end
969         end
970 end
971
972 -- Render if this value exists or if it is mandatory
973 function AbstractValue.render(self, s, scope)
974         if not self.optional or self:cfgvalue(s) or self:formcreated(s) then
975                 scope = scope or {}
976                 scope.section   = s
977                 scope.cbid      = self:cbid(s)
978                 scope.striptags = luci.util.striptags
979
980                 scope.ifattr = function(cond,key,val)
981                         if cond then
982                                 return string.format(
983                                         ' %s="%s"', tostring(key),
984                                         luci.util.pcdata(tostring( val
985                                          or scope[key]
986                                          or (type(self[key]) ~= "function" and self[key])
987                                          or "" ))
988                                 )
989                         else
990                                 return ''
991                         end
992                 end
993
994                 scope.attr = function(...)
995                         return scope.ifattr( true, ... )
996                 end
997
998                 Node.render(self, scope)
999         end
1000 end
1001
1002 -- Return the UCI value of this object
1003 function AbstractValue.cfgvalue(self, section)
1004         local value = self.map:get(section, self.option)
1005         if not value then
1006                 return nil
1007         elseif not self.cast or self.cast == type(value) then
1008                 return value
1009         elseif self.cast == "string" then
1010                 if type(value) == "table" then
1011                         return value[1]
1012                 end
1013         elseif self.cast == "table" then
1014                 return {value}
1015         end
1016 end
1017
1018 -- Validate the form value
1019 function AbstractValue.validate(self, value)
1020         return value
1021 end
1022
1023 AbstractValue.transform = AbstractValue.validate
1024
1025
1026 -- Write to UCI
1027 function AbstractValue.write(self, section, value)
1028         return self.map:set(section, self.option, value)
1029 end
1030
1031 -- Remove from UCI
1032 function AbstractValue.remove(self, section)
1033         return self.map:del(section, self.option)
1034 end
1035
1036
1037
1038
1039 --[[
1040 Value - A one-line value
1041         maxlength:      The maximum length
1042 ]]--
1043 Value = class(AbstractValue)
1044
1045 function Value.__init__(self, ...)
1046         AbstractValue.__init__(self, ...)
1047         self.template  = "cbi/value"
1048         self.keylist = {}
1049         self.vallist = {}
1050 end
1051
1052 function Value.value(self, key, val)
1053         val = val or key
1054         table.insert(self.keylist, tostring(key))
1055         table.insert(self.vallist, tostring(val))
1056 end
1057
1058
1059 -- DummyValue - This does nothing except being there
1060 DummyValue = class(AbstractValue)
1061
1062 function DummyValue.__init__(self, ...)
1063         AbstractValue.__init__(self, ...)
1064         self.template = "cbi/dvalue"
1065         self.value = nil
1066 end
1067
1068 function DummyValue.parse(self)
1069
1070 end
1071
1072
1073 --[[
1074 Flag - A flag being enabled or disabled
1075 ]]--
1076 Flag = class(AbstractValue)
1077
1078 function Flag.__init__(self, ...)
1079         AbstractValue.__init__(self, ...)
1080         self.template  = "cbi/fvalue"
1081
1082         self.enabled = "1"
1083         self.disabled = "0"
1084 end
1085
1086 -- A flag can only have two states: set or unset
1087 function Flag.parse(self, section)
1088         local fvalue = self:formvalue(section)
1089
1090         if fvalue then
1091                 fvalue = self.enabled
1092         else
1093                 fvalue = self.disabled
1094         end
1095
1096         if fvalue == self.enabled or (not self.optional and not self.rmempty) then
1097                 if not(fvalue == self:cfgvalue(section)) then
1098                         self:write(section, fvalue)
1099                 end
1100         else
1101                 self:remove(section)
1102         end
1103 end
1104
1105
1106
1107 --[[
1108 ListValue - A one-line value predefined in a list
1109         widget: The widget that will be used (select, radio)
1110 ]]--
1111 ListValue = class(AbstractValue)
1112
1113 function ListValue.__init__(self, ...)
1114         AbstractValue.__init__(self, ...)
1115         self.template  = "cbi/lvalue"
1116
1117         self.keylist = {}
1118         self.vallist = {}
1119         self.size   = 1
1120         self.widget = "select"
1121 end
1122
1123 function ListValue.prepare(self, ...)
1124         AbstractValue.prepare(self, ...)
1125         if not self.override_scheme
1126          and self.map:get_scheme(self.section.sectiontype, self.option) then
1127                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1128                 if self.value and vs.valuelist and not self.override_values then
1129                         for k, v in ipairs(vs.valuelist) do
1130                                 local deps = {}
1131                                 if not self.override_dependencies
1132                                  and vs.enum_depends and vs.enum_depends[v.value] then
1133                                         for i, dep in ipairs(vs.enum_depends[v.value]) do
1134                                                 table.insert(deps, _uvl_strip_remote_dependencies(dep))
1135                                         end
1136                                 end
1137                                 self:value(v.value, v.title or v.value, unpack(deps))
1138                         end
1139                 end
1140         end
1141 end
1142
1143 function ListValue.value(self, key, val, ...)
1144         if luci.util.contains(self.keylist, key) then
1145                 return
1146         end
1147
1148         val = val or key
1149         table.insert(self.keylist, tostring(key))
1150         table.insert(self.vallist, tostring(val))
1151
1152         for i, deps in ipairs({...}) do
1153                 table.insert(self.deps, {add = "-"..key, deps=deps})
1154         end
1155 end
1156
1157 function ListValue.validate(self, val)
1158         if luci.util.contains(self.keylist, val) then
1159                 return val
1160         else
1161                 return nil
1162         end
1163 end
1164
1165
1166
1167 --[[
1168 MultiValue - Multiple delimited values
1169         widget: The widget that will be used (select, checkbox)
1170         delimiter: The delimiter that will separate the values (default: " ")
1171 ]]--
1172 MultiValue = class(AbstractValue)
1173
1174 function MultiValue.__init__(self, ...)
1175         AbstractValue.__init__(self, ...)
1176         self.template = "cbi/mvalue"
1177
1178         self.keylist = {}
1179         self.vallist = {}
1180
1181         self.widget = "checkbox"
1182         self.delimiter = " "
1183 end
1184
1185 function MultiValue.render(self, ...)
1186         if self.widget == "select" and not self.size then
1187                 self.size = #self.vallist
1188         end
1189
1190         AbstractValue.render(self, ...)
1191 end
1192
1193 function MultiValue.value(self, key, val)
1194         if luci.util.contains(self.keylist, key) then
1195                 return
1196         end
1197
1198         val = val or key
1199         table.insert(self.keylist, tostring(key))
1200         table.insert(self.vallist, tostring(val))
1201 end
1202
1203 function MultiValue.valuelist(self, section)
1204         local val = self:cfgvalue(section)
1205
1206         if not(type(val) == "string") then
1207                 return {}
1208         end
1209
1210         return luci.util.split(val, self.delimiter)
1211 end
1212
1213 function MultiValue.validate(self, val)
1214         val = (type(val) == "table") and val or {val}
1215
1216         local result
1217
1218         for i, value in ipairs(val) do
1219                 if luci.util.contains(self.keylist, value) then
1220                         result = result and (result .. self.delimiter .. value) or value
1221                 end
1222         end
1223
1224         return result
1225 end
1226
1227
1228 StaticList = class(MultiValue)
1229
1230 function StaticList.__init__(self, ...)
1231         MultiValue.__init__(self, ...)
1232         self.cast = "table"
1233         self.valuelist = self.cfgvalue
1234
1235         if not self.override_scheme
1236          and self.map:get_scheme(self.section.sectiontype, self.option) then
1237                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1238                 if self.value and vs.values and not self.override_values then
1239                         for k, v in pairs(vs.values) do
1240                                 self:value(k, v)
1241                         end
1242                 end
1243         end
1244 end
1245
1246 function StaticList.validate(self, value)
1247         value = (type(value) == "table") and value or {value}
1248
1249         local valid = {}
1250         for i, v in ipairs(value) do
1251                 if luci.util.contains(self.vallist, v) then
1252                         table.insert(valid, v)
1253                 end
1254         end
1255         return valid
1256 end
1257
1258
1259 DynamicList = class(AbstractValue)
1260
1261 function DynamicList.__init__(self, ...)
1262         AbstractValue.__init__(self, ...)
1263         self.template  = "cbi/dynlist"
1264         self.cast = "table"
1265         self.keylist = {}
1266         self.vallist = {}
1267 end
1268
1269 function DynamicList.value(self, key, val)
1270         val = val or key
1271         table.insert(self.keylist, tostring(key))
1272         table.insert(self.vallist, tostring(val))
1273 end
1274
1275 function DynamicList.formvalue(self, section)
1276         local value = AbstractValue.formvalue(self, section)
1277         value = (type(value) == "table") and value or {value}
1278
1279         local valid = {}
1280         for i, v in ipairs(value) do
1281                 if v and #v > 0
1282                  and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i)
1283                  and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then
1284                         table.insert(valid, v)
1285                 end
1286         end
1287
1288         return valid
1289 end
1290
1291
1292 --[[
1293 TextValue - A multi-line value
1294         rows:   Rows
1295 ]]--
1296 TextValue = class(AbstractValue)
1297
1298 function TextValue.__init__(self, ...)
1299         AbstractValue.__init__(self, ...)
1300         self.template  = "cbi/tvalue"
1301 end
1302
1303 --[[
1304 Button
1305 ]]--
1306 Button = class(AbstractValue)
1307
1308 function Button.__init__(self, ...)
1309         AbstractValue.__init__(self, ...)
1310         self.template  = "cbi/button"
1311         self.inputstyle = nil
1312         self.rmempty = true
1313 end