2 LuCI - Configuration Bind Interface
5 Offers an interface for binding configuration 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("luci.cbi", package.seeall)
29 require("luci.template")
34 local uci = require("luci.model.uci")
35 local class = luci.util.class
36 local instanceof = luci.util.instanceof
44 CREATE_PREFIX = "cbi.cts."
45 REMOVE_PREFIX = "cbi.rts."
47 -- Loads a CBI map from given file, creating an environment and returns it
48 function load(cbimap, ...)
50 local i18n = require "luci.i18n"
51 require("luci.config")
54 local cbidir = luci.util.libpath() .. "/model/cbi/"
55 local func, err = loadfile(cbimap) or loadfile(cbidir..cbimap..".lua")
58 luci.i18n.loadc("cbi")
59 luci.i18n.loadc("uvl")
62 translate=i18n.translate,
63 translatef=i18n.translatef,
67 setfenv(func, setmetatable(env, {__index =
69 return rawget(tbl, key) or _M[key] or _G[key]
74 for i, map in ipairs(maps) do
75 if not instanceof(map, Node) then
76 error("CBI map returns no valid map object!")
86 local function _uvl_validate_section(node, name)
87 local co = node.map:get()
89 luci.uvl.STRICT_UNKNOWN_OPTIONS = false
90 luci.uvl.STRICT_UNKNOWN_SECTIONS = false
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
97 node.fields[e.option].error = { [name] = e }
100 for _, c in ipairs(e.childs) do tag_fields(c) end
104 local function tag_section(e)
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() )
110 table.insert( s, c:string() )
117 node.error = { [name] = s }
122 local stat, err = node.map.validator:validate_section(node.config, name, co)
124 node.map.save = false
131 local function _uvl_strip_remote_dependencies(deps)
134 for k, v in pairs(deps) do
135 k = k:gsub("%$config%.%$section%.", "")
136 if k:match("^[%w_]+$") and type(v) == "string" then
145 -- Node pseudo abstract class
148 function Node.__init__(self, title, description)
150 self.title = title or ""
151 self.description = description or ""
152 self.template = "cbi/node"
156 function Node._i18n(self, config, section, option, title, description)
159 if type(luci.i18n) == "table" then
161 local key = config and config:gsub("[^%w]+", "") or ""
163 if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end
164 if option then key = key .. "_" .. tostring(option):lower():gsub("[^%w]+", "") end
166 self.title = title or luci.i18n.translate( key, option or section or config )
167 self.description = description or luci.i18n.translate( key .. "_desc", "" )
172 function Node.prepare(self, ...)
173 for k, child in ipairs(self.children) do
178 -- Append child nodes
179 function Node.append(self, obj)
180 table.insert(self.children, obj)
183 -- Parse this node and its children
184 function Node.parse(self, ...)
185 for k, child in ipairs(self.children) do
191 function Node.render(self, scope)
195 luci.template.render(self.template, scope)
198 -- Render the children
199 function Node.render_children(self, ...)
200 for k, node in ipairs(self.children) do
207 A simple template element
209 Template = class(Node)
211 function Template.__init__(self, template)
213 self.template = template
216 function Template.render(self)
217 luci.template.render(self.template, {self=self})
222 Map - A map describing a configuration file
226 function Map.__init__(self, config, ...)
227 Node.__init__(self, ...)
228 Node._i18n(self, config, nil, nil, ...)
231 self.parsechain = {self.config}
232 self.template = "cbi/map"
233 self.apply_on_parse = nil
234 self.uci = uci.cursor()
236 if not self.uci:load(self.config) then
237 error("Unable to read UCI data: " .. self.config)
240 self.validator = luci.uvl.UVL()
241 self.scheme = self.validator:get_scheme(self.config)
245 function Map.get_scheme(self, sectiontype, option)
247 return self.scheme and self.scheme.sections[sectiontype]
249 return self.scheme and self.scheme.variables[sectiontype]
250 and self.scheme.variables[sectiontype][option]
255 -- Chain foreign config
256 function Map.chain(self, config)
257 table.insert(self.parsechain, config)
260 -- Use optimized UCI writing
261 function Map.parse(self)
265 for i, config in ipairs(self.parsechain) do
266 self.uci:save(config)
268 if luci.http.formvalue("cbi.apply") then
269 for i, config in ipairs(self.parsechain) do
270 self.uci:commit(config)
272 -- Refresh data because commit changes section names
273 self.uci:load(config)
275 if self.apply_on_parse then
276 self.uci:apply(self.parsechain)
278 self._apply = function()
279 local cmd = self.uci:apply(self.parsechain, true)
285 Node.parse(self, true)
288 for i, config in ipairs(self.parsechain) do
289 self.uci:unload(config)
294 function Map.render(self, ...)
295 Node.render(self, ...)
297 local fp = self._apply()
303 -- Creates a child section
304 function Map.section(self, class, ...)
305 if instanceof(class, AbstractSection) then
306 local obj = class(self, ...)
310 error("class must be a descendent of AbstractSection")
315 function Map.add(self, sectiontype)
316 return self.uci:add(self.config, sectiontype)
320 function Map.set(self, section, option, value)
322 return self.uci:set(self.config, section, option, value)
324 return self.uci:set(self.config, section, value)
329 function Map.del(self, section, option)
331 return self.uci:delete(self.config, section, option)
333 return self.uci:delete(self.config, section)
338 function Map.get(self, section, option)
340 return self.uci:get_all(self.config)
342 return self.uci:get(self.config, section, option)
344 return self.uci:get_all(self.config, section)
354 Page.__init__ = Node.__init__
355 Page.parse = function() end
359 SimpleForm - A Simple non-UCI form
361 SimpleForm = class(Node)
363 function SimpleForm.__init__(self, config, title, description, data)
364 Node.__init__(self, title, description)
366 self.data = data or {}
367 self.template = "cbi/simpleform"
371 function SimpleForm.parse(self, ...)
372 if luci.http.formvalue("cbi.submit") then
373 Node.parse(self, 1, ...)
377 for k, j in ipairs(self.children) do
378 for i, v in ipairs(j.children) do
380 and (not v.tag_missing or not v.tag_missing[1])
381 and (not v.tag_invalid or not v.tag_invalid[1])
386 not luci.http.formvalue("cbi.submit") and 0
390 self.dorender = not self.handle or self:handle(state, self.data) ~= false
393 function SimpleForm.render(self, ...)
394 if self.dorender then
395 Node.render(self, ...)
399 function SimpleForm.section(self, class, ...)
400 if instanceof(class, AbstractSection) then
401 local obj = class(self, ...)
405 error("class must be a descendent of AbstractSection")
409 -- Creates a child field
410 function SimpleForm.field(self, class, ...)
412 for k, v in ipairs(self.children) do
413 if instanceof(v, SimpleSection) then
419 section = self:section(SimpleSection)
422 if instanceof(class, AbstractValue) then
423 local obj = class(self, section, ...)
424 obj.track_missing = true
428 error("class must be a descendent of AbstractValue")
432 function SimpleForm.set(self, section, option, value)
433 self.data[option] = value
437 function SimpleForm.del(self, section, option)
438 self.data[option] = nil
442 function SimpleForm.get(self, section, option)
443 return self.data[option]
447 function SimpleForm.get_scheme()
456 AbstractSection = class(Node)
458 function AbstractSection.__init__(self, map, sectiontype, ...)
459 Node.__init__(self, ...)
460 self.sectiontype = sectiontype
462 self.config = map.config
467 self.tag_invalid = {}
468 self.tag_deperror = {}
471 self.addremove = false
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
482 elseif vs.type == "list" then
484 elseif vs.type == "enum" or vs.type == "reference" then
491 if instanceof(class, AbstractValue) then
492 local obj = class(self.map, self, option, ...)
494 Node._i18n(obj, self.config, self.section or self.sectiontype, option, ...)
497 self.fields[option] = obj
499 elseif class == true then
500 error("No valid class was given and autodetection failed.")
502 error("class must be a descendant of AbstractValue")
506 -- Parse optional options
507 function AbstractSection.parse_optionals(self, section)
508 if not self.optional then
512 self.optionals[section] = {}
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
520 table.insert(self.optionals[section], v)
525 if field and #field > 0 and self.dynamic then
526 self:add_dynamic(field)
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
536 -- Parse all dynamic options
537 function AbstractSection.parse_dynamic(self, section)
538 if not self.dynamic then
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
548 for key,val in pairs(arr) do
551 for i,c in ipairs(self.children) do
552 if c.option == key then
557 if create and key:sub(1, 1) ~= "." then
558 self:add_dynamic(key, true)
563 -- Returns the section's UCI table
564 function AbstractSection.cfgvalue(self, section)
565 return self.map:get(section)
568 -- Removes the section
569 function AbstractSection.remove(self, section)
570 return self.map:del(section)
573 -- Creates the section
574 function AbstractSection.create(self, section)
578 stat = section:match("^%w+$") and self.map:set(section, nil, self.sectiontype)
580 section = self.map:add(self.sectiontype)
585 for k,v in pairs(self.children) do
587 self.map:set(section, v.option, v.default)
591 for k,v in pairs(self.defaults) do
592 self.map:set(section, k, v)
600 SimpleSection = class(AbstractSection)
602 function SimpleSection.__init__(self, form, ...)
603 AbstractSection.__init__(self, form, nil, ...)
604 self.template = "cbi/nullsection"
608 Table = class(AbstractSection)
610 function Table.__init__(self, form, data, ...)
611 local datasource = {}
612 datasource.config = "table"
615 function datasource.get(self, section, option)
616 return data[section] and data[section][option]
619 function datasource.del(...)
623 function datasource.get_scheme()
627 AbstractSection.__init__(self, datasource, "table", ...)
628 self.template = "cbi/tblsection"
629 self.rowcolors = true
630 self.anonymous = true
633 function Table.parse(self)
634 for i, k in ipairs(self:cfgsections()) do
635 if luci.http.formvalue("cbi.submit") then
641 function Table.cfgsections(self)
644 for i, v in luci.util.kspairs(self.data) do
645 table.insert(sections, i)
654 NamedSection - A fixed configuration section defined by its name
656 NamedSection = class(AbstractSection)
658 function NamedSection.__init__(self, map, section, stype, ...)
659 AbstractSection.__init__(self, map, stype, ...)
660 Node._i18n(self, map.config, section, nil, ...)
663 self.addremove = false
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
674 self.template = "cbi/nsection"
675 self.section = section
678 function NamedSection.parse(self, novld)
679 local s = self.section
680 local active = self:cfgvalue(s)
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
688 else -- Create and apply default values
689 if luci.http.formvalue("cbi.cns."..path) then
697 AbstractSection.parse_dynamic(self, s)
698 if luci.http.formvalue("cbi.submit") then
701 if not novld and not self.override_scheme and self.map.scheme then
702 _uvl_validate_section(self, s)
705 AbstractSection.parse_optionals(self, s)
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
716 TypedSection = class(AbstractSection)
718 function TypedSection.__init__(self, map, type, ...)
719 AbstractSection.__init__(self, map, type, ...)
720 Node._i18n(self, map.config, type, nil, ...)
722 self.template = "cbi/tsection"
724 self.anonymous = false
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
737 -- Return all matching UCI sections for this TypedSection
738 function TypedSection.cfgsections(self)
740 self.map.uci:foreach(self.map.config, self.sectiontype,
742 if self:checkscope(section[".name"]) then
743 table.insert(sections, section[".name"])
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})
755 function TypedSection.parse(self, novld)
756 if self.addremove then
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
764 if self:cfgvalue(k) and self:checkscope(k) then
771 for i, k in ipairs(self:cfgsections()) do
772 AbstractSection.parse_dynamic(self, k)
773 if luci.http.formvalue("cbi.submit") then
776 if not novld and not self.override_scheme and self.map.scheme then
777 _uvl_validate_section(self, k)
780 AbstractSection.parse_optionals(self, k)
783 if self.addremove then
786 local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype
787 local name = luci.http.formvalue(crval)
788 if self.anonymous then
790 created = self:create()
794 -- Ignore if it already exists
795 if self:cfgvalue(name) then
799 name = self:checkscope(name)
802 self.err_invalid = true
805 if name and #name > 0 then
806 created = self:create(name) and name
808 self.invalid_cts = true
815 AbstractSection.parse_optionals(self, created)
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
827 -- Check if at least one dependency is met
828 if #self.deps > 0 and self:cfgvalue(section) then
831 for k, v in ipairs(self.deps) do
832 if self:cfgvalue(section)[v.option] == v.value then
842 return self:validate(section)
846 -- Dummy validate function
847 function TypedSection.validate(self, section)
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)
862 AbstractValue = class(Node)
864 function AbstractValue.__init__(self, map, section, option, ...)
865 Node.__init__(self, ...)
866 self.section = section
869 self.config = map.config
870 self.tag_invalid = {}
871 self.tag_missing = {}
872 self.tag_reqerror = {}
877 self.track_missing = false
881 self.optional = false
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 self.rmempty = not vs.required
890 self.cast = (vs.type == "list") and "list" or "string"
891 self.title = self.title or vs.title
892 self.description = self.description or vs.descr
893 self.default = vs.default
895 if vs.depends and not self.override_dependencies then
896 for i, deps in ipairs(vs.depends) do
897 deps = _uvl_strip_remote_dependencies(deps)
906 -- Add a dependencie to another section field
907 function AbstractValue.depends(self, field, value)
909 if type(field) == "string" then
916 table.insert(self.deps, {deps=deps, add=""})
919 -- Generates the unique CBID
920 function AbstractValue.cbid(self, section)
921 return "cbid."..self.map.config.."."..section.."."..self.option
924 -- Return whether this object should be created
925 function AbstractValue.formcreated(self, section)
926 local key = "cbi.opt."..self.config.."."..section
927 return (luci.http.formvalue(key) == self.option)
930 -- Returns the formvalue for this object
931 function AbstractValue.formvalue(self, section)
932 return luci.http.formvalue(self:cbid(section))
935 function AbstractValue.additional(self, value)
936 self.optional = value
939 function AbstractValue.mandatory(self, value)
940 self.rmempty = not value
943 function AbstractValue.parse(self, section)
944 local fvalue = self:formvalue(section)
945 local cvalue = self:cfgvalue(section)
947 if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI
948 fvalue = self:transform(self:validate(fvalue, section))
950 self.tag_invalid[section] = true
952 if fvalue and not (fvalue == cvalue) then
953 self:write(section, fvalue)
955 else -- Unset the UCI or error
956 if self.rmempty or self.optional then
958 elseif self.track_missing and (not fvalue or fvalue ~= cvalue) then
959 self.tag_missing[section] = true
964 -- Render if this value exists or if it is mandatory
965 function AbstractValue.render(self, s, scope)
966 if not self.optional or self:cfgvalue(s) or self:formcreated(s) then
969 scope.cbid = self:cbid(s)
970 scope.striptags = luci.util.striptags
972 scope.ifattr = function(cond,key,val)
974 return string.format(
975 ' %s="%s"', tostring(key),
976 luci.util.pcdata(tostring( val
978 or (type(self[key]) ~= "function" and self[key])
986 scope.attr = function(...)
987 return scope.ifattr( true, ... )
990 Node.render(self, scope)
994 -- Return the UCI value of this object
995 function AbstractValue.cfgvalue(self, section)
996 local value = self.map:get(section, self.option)
999 elseif not self.cast or self.cast == type(value) then
1001 elseif self.cast == "string" then
1002 if type(value) == "table" then
1005 elseif self.cast == "table" then
1010 -- Validate the form value
1011 function AbstractValue.validate(self, value)
1015 AbstractValue.transform = AbstractValue.validate
1019 function AbstractValue.write(self, section, value)
1020 return self.map:set(section, self.option, value)
1024 function AbstractValue.remove(self, section)
1025 return self.map:del(section, self.option)
1032 Value - A one-line value
1033 maxlength: The maximum length
1035 Value = class(AbstractValue)
1037 function Value.__init__(self, ...)
1038 AbstractValue.__init__(self, ...)
1039 self.template = "cbi/value"
1044 function Value.value(self, key, val)
1046 table.insert(self.keylist, tostring(key))
1047 table.insert(self.vallist, tostring(val))
1051 -- DummyValue - This does nothing except being there
1052 DummyValue = class(AbstractValue)
1054 function DummyValue.__init__(self, ...)
1055 AbstractValue.__init__(self, ...)
1056 self.template = "cbi/dvalue"
1060 function DummyValue.parse(self)
1066 Flag - A flag being enabled or disabled
1068 Flag = class(AbstractValue)
1070 function Flag.__init__(self, ...)
1071 AbstractValue.__init__(self, ...)
1072 self.template = "cbi/fvalue"
1078 -- A flag can only have two states: set or unset
1079 function Flag.parse(self, section)
1080 local fvalue = self:formvalue(section)
1083 fvalue = self.enabled
1085 fvalue = self.disabled
1088 if fvalue == self.enabled or (not self.optional and not self.rmempty) then
1089 if not(fvalue == self:cfgvalue(section)) then
1090 self:write(section, fvalue)
1093 self:remove(section)
1100 ListValue - A one-line value predefined in a list
1101 widget: The widget that will be used (select, radio)
1103 ListValue = class(AbstractValue)
1105 function ListValue.__init__(self, ...)
1106 AbstractValue.__init__(self, ...)
1107 self.template = "cbi/lvalue"
1112 self.widget = "select"
1115 function ListValue.prepare(self, ...)
1116 AbstractValue.prepare(self, ...)
1117 if not self.override_scheme
1118 and self.map:get_scheme(self.section.sectiontype, self.option) then
1119 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1120 if self.value and vs.valuelist and not self.override_values then
1121 for k, v in ipairs(vs.valuelist) do
1123 if not self.override_dependencies
1124 and vs.enum_depends and vs.enum_depends[v.value] then
1125 for i, dep in ipairs(vs.enum_depends[v.value]) do
1126 table.insert(deps, _uvl_strip_remote_dependencies(dep))
1129 self:value(v.value, v.title or v.value, unpack(deps))
1135 function ListValue.value(self, key, val, ...)
1136 if luci.util.contains(self.keylist, key) then
1141 table.insert(self.keylist, tostring(key))
1142 table.insert(self.vallist, tostring(val))
1144 for i, deps in ipairs({...}) do
1145 table.insert(self.deps, {add = "-"..key, deps=deps})
1149 function ListValue.validate(self, val)
1150 if luci.util.contains(self.keylist, val) then
1160 MultiValue - Multiple delimited values
1161 widget: The widget that will be used (select, checkbox)
1162 delimiter: The delimiter that will separate the values (default: " ")
1164 MultiValue = class(AbstractValue)
1166 function MultiValue.__init__(self, ...)
1167 AbstractValue.__init__(self, ...)
1168 self.template = "cbi/mvalue"
1173 self.widget = "checkbox"
1174 self.delimiter = " "
1177 function MultiValue.render(self, ...)
1178 if self.widget == "select" and not self.size then
1179 self.size = #self.vallist
1182 AbstractValue.render(self, ...)
1185 function MultiValue.value(self, key, val)
1186 if luci.util.contains(self.keylist, key) then
1191 table.insert(self.keylist, tostring(key))
1192 table.insert(self.vallist, tostring(val))
1195 function MultiValue.valuelist(self, section)
1196 local val = self:cfgvalue(section)
1198 if not(type(val) == "string") then
1202 return luci.util.split(val, self.delimiter)
1205 function MultiValue.validate(self, val)
1206 val = (type(val) == "table") and val or {val}
1210 for i, value in ipairs(val) do
1211 if luci.util.contains(self.keylist, value) then
1212 result = result and (result .. self.delimiter .. value) or value
1220 StaticList = class(MultiValue)
1222 function StaticList.__init__(self, ...)
1223 MultiValue.__init__(self, ...)
1225 self.valuelist = self.cfgvalue
1227 if not self.override_scheme
1228 and self.map:get_scheme(self.section.sectiontype, self.option) then
1229 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1230 if self.value and vs.values and not self.override_values then
1231 for k, v in pairs(vs.values) do
1238 function StaticList.validate(self, value)
1239 value = (type(value) == "table") and value or {value}
1242 for i, v in ipairs(value) do
1243 if luci.util.contains(self.vallist, v) then
1244 table.insert(valid, v)
1251 DynamicList = class(AbstractValue)
1253 function DynamicList.__init__(self, ...)
1254 AbstractValue.__init__(self, ...)
1255 self.template = "cbi/dynlist"
1261 function DynamicList.value(self, key, val)
1263 table.insert(self.keylist, tostring(key))
1264 table.insert(self.vallist, tostring(val))
1267 function DynamicList.formvalue(self, section)
1268 local value = AbstractValue.formvalue(self, section)
1269 value = (type(value) == "table") and value or {value}
1272 for i, v in ipairs(value) do
1274 and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i)
1275 and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then
1276 table.insert(valid, v)
1285 TextValue - A multi-line value
1288 TextValue = class(AbstractValue)
1290 function TextValue.__init__(self, ...)
1291 AbstractValue.__init__(self, ...)
1292 self.template = "cbi/tvalue"
1298 Button = class(AbstractValue)
1300 function Button.__init__(self, ...)
1301 AbstractValue.__init__(self, ...)
1302 self.template = "cbi/button"
1303 self.inputstyle = nil