X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;f=libs%2Fcbi%2Fluasrc%2Fcbi.lua;h=024687c6fb236bf27825fc5bfc77dad0a4600851;hb=355ac6b1a27598499d64c793817877755e166f88;hp=6e08455655f12e09f6c79dc100985775c083f6bd;hpb=d12dfa5186f83fdb25ddbadfe2077f40115ce820;p=project%2Fluci.git diff --git a/libs/cbi/luasrc/cbi.lua b/libs/cbi/luasrc/cbi.lua index 6e0845565..024687c6f 100644 --- a/libs/cbi/luasrc/cbi.lua +++ b/libs/cbi/luasrc/cbi.lua @@ -35,15 +35,21 @@ local uci = luci.model.uci local class = luci.util.class local instanceof = luci.util.instanceof +FORM_NODATA = 0 +FORM_VALID = 1 +FORM_INVALID = -1 + +CREATE_PREFIX = "cbi.cts." +REMOVE_PREFIX = "cbi.rts." -- Loads a CBI map from given file, creating an environment and returns it -function load(cbimap) +function load(cbimap, ...) require("luci.fs") require("luci.i18n") require("luci.config") - require("luci.sys") + require("luci.util") - local cbidir = luci.sys.libpath() .. "/model/cbi/" + local cbidir = luci.util.libpath() .. "/model/cbi/" local func, err = loadfile(cbidir..cbimap..".lua") if not func then @@ -56,15 +62,18 @@ function load(cbimap) luci.util.updfenv(func, luci.cbi) luci.util.extfenv(func, "translate", luci.i18n.translate) luci.util.extfenv(func, "translatef", luci.i18n.translatef) + luci.util.extfenv(func, "arg", {...}) - local map = func() + local maps = {func()} - if not instanceof(map, Map) then - error("CBI map returns no valid map object!") - return nil + for i, map in ipairs(maps) do + if not instanceof(map, Node) then + error("CBI map returns no valid map object!") + return nil + end end - return map + return maps end -- Node pseudo abstract class @@ -142,17 +151,44 @@ function Map.__init__(self, config, ...) Node._i18n(self, config, nil, nil, ...) self.config = config + self.parsechain = {self.config} self.template = "cbi/map" if not uci.load(self.config) then error("Unable to read UCI data: " .. self.config) end end + +-- Chain foreign config +function Map.chain(self, config) + table.insert(self.parsechain, config) +end + -- Use optimized UCI writing function Map.parse(self, ...) Node.parse(self, ...) - uci.save(self.config) - uci.unload(self.config) + for i, config in ipairs(self.parsechain) do + uci.save(config) + end + if luci.http.formvalue("cbi.apply") then + for i, config in ipairs(self.parsechain) do + uci.commit(config) + if luci.config.uci_oncommit and luci.config.uci_oncommit[config] then + luci.util.exec(luci.config.uci_oncommit[config]) + end + + -- Refresh data because commit changes section names + uci.unload(config) + uci.load(config) + end + + -- Reparse sections + Node.parse(self, ...) + + end + for i, config in ipairs(self.parsechain) do + uci.unload(config) + end end -- Creates a child section @@ -200,6 +236,73 @@ function Map.get(self, section, option) end end +-- UCI stateget +function Map.stateget(self, section, option) + return uci.get_statevalue(self.config, section, option) +end + + +--[[ +SimpleForm - A Simple non-UCI form +]]-- +SimpleForm = class(Node) + +function SimpleForm.__init__(self, config, title, description, data) + Node.__init__(self, title, description) + self.config = config + self.data = data or {} + self.template = "cbi/simpleform" + self.dorender = true +end + +function SimpleForm.parse(self, ...) + Node.parse(self, 1, ...) + + local valid = true + for i, v in ipairs(self.children) do + valid = valid and not v.tag_missing[1] and not v.tag_invalid[1] + end + + local state = + not luci.http.formvalue("cbi.submit") and 0 + or valid and 1 + or -1 + + self.dorender = self:handle(state) +end + +function SimpleForm.render(self, ...) + if self.dorender then + Node.render(self, ...) + end +end + +-- Creates a child section +function SimpleForm.field(self, class, ...) + if instanceof(class, AbstractValue) then + local obj = class(self, ...) + self:append(obj) + return obj + else + error("class must be a descendent of AbstractValue") + end +end + +function SimpleForm.set(self, section, option, value) + self.data[option] = value +end + + +function SimpleForm.del(self, section, option) + self.data[option] = nil +end + + +function SimpleForm.get(self, section, option) + return self.data[option] +end + + --[[ AbstractSection @@ -212,6 +315,7 @@ function AbstractSection.__init__(self, map, sectiontype, ...) self.map = map self.config = map.config self.optionals = {} + self.defaults = {} self.optional = true self.addremove = false @@ -301,7 +405,28 @@ end -- Creates the section function AbstractSection.create(self, section) - return self.map:set(section, nil, self.sectiontype) + local stat + + if section then + stat = self.map:set(section, nil, self.sectiontype) + else + section = self.map:add(self.sectiontype) + stat = section + end + + if stat then + for k,v in pairs(self.children) do + if v.default then + self.map:set(section, v.option, v.default) + end + end + + for k,v in pairs(self.defaults) do + self.map:set(section, k, v) + end + end + + return stat end @@ -314,7 +439,7 @@ NamedSection = class(AbstractSection) function NamedSection.__init__(self, map, section, type, ...) AbstractSection.__init__(self, map, type, ...) Node._i18n(self, map.config, section, nil, ...) - + self.template = "cbi/nsection" self.section = section self.addremove = false @@ -332,10 +457,9 @@ function NamedSection.parse(self) return end else -- Create and apply default values - if luci.http.formvalue("cbi.cns."..path) and self:create(s) then - for k,v in pairs(self.children) do - v:write(s, v.default) - end + if luci.http.formvalue("cbi.cns."..path) then + self:create(s) + return end end end @@ -364,7 +488,6 @@ function TypedSection.__init__(self, map, type, ...) self.template = "cbi/tsection" self.deps = {} - self.excludes = {} self.anonymous = false end @@ -376,41 +499,21 @@ function TypedSection.cfgsections(self) function (section) if self:checkscope(section[".name"]) then table.insert(sections, section[".name"]) - end + end end) return sections end --- Creates a new section of this type with the given name (or anonymous) -function TypedSection.create(self, name) - if name then - self.map:set(name, nil, self.sectiontype) - else - name = self.map:add(self.sectiontype) - end - - for k,v in pairs(self.children) do - if v.default then - self.map:set(name, v.option, v.default) - end - end -end - -- Limits scope to sections that have certain option => value pairs function TypedSection.depends(self, option, value) table.insert(self.deps, {option=option, value=value}) end --- Excludes several sections by name -function TypedSection.exclude(self, field) - self.excludes[field] = true -end - function TypedSection.parse(self) if self.addremove then -- Create - local crval = "cbi.cts." .. self.config .. "." .. self.sectiontype + local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype local name = luci.http.formvalue(crval) if self.anonymous then if name then @@ -436,7 +539,7 @@ function TypedSection.parse(self) end -- Remove - crval = "cbi.rts." .. self.config + crval = REMOVE_PREFIX .. self.config name = luci.http.formvaluetable(crval) for k,v in pairs(name) do if self:cfgvalue(k) and self:checkscope(k) then @@ -457,7 +560,7 @@ end -- Verifies scope of sections function TypedSection.checkscope(self, section) -- Check if we are not excluded - if self.excludes[section] then + if self.filter and not self:filter(section) then return nil end @@ -504,12 +607,14 @@ function AbstractValue.__init__(self, map, option, ...) self.map = map self.config = map.config self.tag_invalid = {} + self.tag_missing = {} self.deps = {} - self.rmempty = false - self.default = nil - self.size = nil - self.optional = false + self.rmempty = false + self.default = nil + self.size = nil + self.optional = false + self.stateful = false end -- Add a dependencie to another section field @@ -529,11 +634,20 @@ function AbstractValue.formvalue(self, section) return luci.http.formvalue(key) end +function AbstractValue.additional(self, value) + self.optional = value +end + +function AbstractValue.mandatory(self, value) + self.rmempty = not value +end + function AbstractValue.parse(self, section) local fvalue = self:formvalue(section) + local cvalue = self:cfgvalue(section) if fvalue and fvalue ~= "" then -- If we have a form value, write it to UCI - fvalue = self:validate(fvalue) + fvalue = self:transform(self:validate(fvalue)) if not fvalue then self.tag_invalid[section] = true end @@ -543,6 +657,8 @@ function AbstractValue.parse(self, section) else -- Unset the UCI or error if self.rmempty or self.optional then self:remove(section) + elseif not fvalue or fvalue ~= cvalue then + --self.tag_missing[section] = true end end end @@ -552,14 +668,37 @@ function AbstractValue.render(self, s, scope) if not self.optional or self:cfgvalue(s) or self:formcreated(s) then scope = scope or {} scope.section = s - + scope.cbid = "cbid." .. self.config .. + "." .. s .. + "." .. self.option + + scope.ifattr = function(cond,key,val) + if cond then + return string.format( + ' %s="%s"', tostring(key), + tostring( val + or scope[key] + or (type(self[key]) ~= "function" and self[key]) + or "" ) + ) + else + return '' + end + end + + scope.attr = function(...) + return scope.ifattr( true, ... ) + end + Node.render(self, scope) end end -- Return the UCI value of this object function AbstractValue.cfgvalue(self, section) - return self.map:get(section, self.option) + return self.stateful + and self.map:stateget(section, self.option) + or self.map:get(section, self.option) end -- Validate the form value @@ -567,6 +706,9 @@ function AbstractValue.validate(self, value) return value end +AbstractValue.transform = AbstractValue.validate + + -- Write to UCI function AbstractValue.write(self, section, value) return self.map:set(section, self.option, value) @@ -589,17 +731,14 @@ Value = class(AbstractValue) function Value.__init__(self, ...) AbstractValue.__init__(self, ...) self.template = "cbi/value" - - self.maxlength = nil + self.keylist = {} + self.vallist = {} end --- This validation is a bit more complex -function Value.validate(self, val) - if self.maxlength and tostring(val):len() > self.maxlength then - val = nil - end - - return val +function Value.value(self, key, val) + val = val or key + table.insert(self.keylist, tostring(key)) + table.insert(self.vallist, tostring(val)) end @@ -616,10 +755,6 @@ function DummyValue.parse(self) end -function DummyValue.render(self, s) - luci.template.render(self.template, {self=self, section=s}) -end - --[[ Flag - A flag being enabled or disabled @@ -729,7 +864,7 @@ function MultiValue.valuelist(self, section) end function MultiValue.validate(self, val) - val = (type(val) == "table") and val or {val} + val = (type(val) == "table") and val or {val} local result