X-Git-Url: http://git.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fcbi%2Fluasrc%2Fcbi.lua;h=d5be48edba96c9133c0584175226b5b19b0701c0;hp=31fa8bffb4353d08d9907f00b5b6d9a6438f49d2;hb=76982655fa433edd885bbb80bbe74e82fca527e2;hpb=47b62843fc944e8bfafa78348715bac0b948eb08 diff --git a/libs/cbi/luasrc/cbi.lua b/libs/cbi/luasrc/cbi.lua index 31fa8bffb4..d5be48edba 100644 --- a/libs/cbi/luasrc/cbi.lua +++ b/libs/cbi/luasrc/cbi.lua @@ -31,9 +31,11 @@ require("luci.util") require("luci.http") require("luci.model.uci") +local uci = luci.model.uci local class = luci.util.class local instanceof = luci.util.instanceof + -- Loads a CBI map from given file, creating an environment and returns it function load(cbimap) require("luci.fs") @@ -55,14 +57,16 @@ function load(cbimap) luci.util.extfenv(func, "translate", luci.i18n.translate) luci.util.extfenv(func, "translatef", luci.i18n.translatef) - 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, Map) then + error("CBI map returns no valid map object!") + return nil + end end - return map + return maps end -- Node pseudo abstract class @@ -140,28 +144,50 @@ function Map.__init__(self, config, ...) Node._i18n(self, config, nil, nil, ...) self.config = config + self.parsechain = {self.config} self.template = "cbi/map" - self.uci = luci.model.uci.Session() - self.ucidata, self.uciorder = self.uci:sections(self.config) - if not self.ucidata or not self.uciorder then + 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, ...) - self.uci:t_load(self.config) Node.parse(self, ...) - self.uci:t_save(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 -function Map.section(self, class, section, ...) +function Map.section(self, class, ...) if instanceof(class, AbstractSection) then - local obj = class(self, section, ...) - - Node._i18n(obj, self.config, section, nil, ...) - + local obj = class(self, ...) self:append(obj) return obj else @@ -171,59 +197,35 @@ end -- UCI add function Map.add(self, sectiontype) - local name = self.uci:t_add(self.config, sectiontype) - if name then - self.ucidata[name] = {} - self.ucidata[name][".type"] = sectiontype - table.insert(self.uciorder, name) - end - return name + return uci.add(self.config, sectiontype) end -- UCI set function Map.set(self, section, option, value) - local stat = self.uci:t_set(self.config, section, option, value) - if stat then - local val = self.uci:t_get(self.config, section, option) - if option then - self.ucidata[section][option] = val - else - if not self.ucidata[section] then - self.ucidata[section] = {} - end - self.ucidata[section][".type"] = val - table.insert(self.uciorder, section) - end + if option then + return uci.set(self.config, section, option, value) + else + return uci.set(self.config, section, value) end - return stat end -- UCI del function Map.del(self, section, option) - local stat = self.uci:t_del(self.config, section, option) - if stat then - if option then - self.ucidata[section][option] = nil - else - self.ucidata[section] = nil - for i, k in ipairs(self.uciorder) do - if section == k then - table.remove(self.uciorder, i) - end - end - end + if option then + return uci.delete(self.config, section, option) + else + return uci.delete(self.config, section) end - return stat end --- UCI get (cached) +-- UCI get function Map.get(self, section, option) if not section then - return self.ucidata, self.uciorder - elseif option and self.ucidata[section] then - return self.ucidata[section][option] + return uci.get_all(self.config) + elseif option then + return uci.get(self.config, section, option) else - return self.ucidata[section] + return uci.get_all(self.config, section) end end @@ -239,6 +241,7 @@ function AbstractSection.__init__(self, map, sectiontype, ...) self.map = map self.config = map.config self.optionals = {} + self.defaults = {} self.optional = true self.addremove = false @@ -250,7 +253,7 @@ function AbstractSection.option(self, class, option, ...) if instanceof(class, AbstractValue) then local obj = class(self.map, option, ...) - Node._i18n(obj, self.config, self.section, option, ...) + Node._i18n(obj, self.config, self.section or self.sectiontype, option, ...) self:append(obj) return obj @@ -328,7 +331,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 @@ -338,10 +362,11 @@ NamedSection - A fixed configuration section defined by its name ]]-- NamedSection = class(AbstractSection) -function NamedSection.__init__(self, map, section, ...) - AbstractSection.__init__(self, map, ...) - self.template = "cbi/nsection" +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 end @@ -358,10 +383,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 @@ -384,8 +408,10 @@ TypedSection - A (set of) configuration section(s) defined by the type ]]-- TypedSection = class(AbstractSection) -function TypedSection.__init__(self, ...) - AbstractSection.__init__(self, ...) +function TypedSection.__init__(self, map, type, ...) + AbstractSection.__init__(self, map, type, ...) + Node._i18n(self, map.config, type, nil, ...) + self.template = "cbi/tsection" self.deps = {} self.excludes = {} @@ -396,34 +422,16 @@ end -- Return all matching UCI sections for this TypedSection function TypedSection.cfgsections(self) local sections = {} - local map, order = self.map:get() - - for i, k in ipairs(order) do - if map[k][".type"] == self.sectiontype then - if self:checkscope(k) then - table.insert(sections, k) + uci.foreach(self.map.config, self.sectiontype, + function (section) + if self:checkscope(section[".name"]) then + table.insert(sections, section[".name"]) end - 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}) @@ -579,6 +587,28 @@ 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 @@ -609,28 +639,20 @@ end --[[ Value - A one-line value maxlength: The maximum length - isnumber: The value must be a valid (floating point) number - isinteger: The value must be a valid integer - ispositive: The value must be positive (and a number) ]]-- Value = class(AbstractValue) function Value.__init__(self, ...) AbstractValue.__init__(self, ...) self.template = "cbi/value" - - self.maxlength = nil - self.isnumber = false - self.isinteger = false + 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 luci.util.validate(val, self.isnumber, self.isinteger) +function Value.value(self, key, val) + val = val or key + table.insert(self.keylist, tostring(key)) + table.insert(self.vallist, tostring(val)) end @@ -647,10 +669,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 @@ -735,6 +753,14 @@ function MultiValue.__init__(self, ...) self.delimiter = " " end +function MultiValue.render(self, ...) + if self.widget == "select" and not self.size then + self.size = #self.vallist + end + + AbstractValue.render(self, ...) +end + function MultiValue.value(self, key, val) val = val or key table.insert(self.keylist, tostring(key)) @@ -752,21 +778,15 @@ function MultiValue.valuelist(self, section) end function MultiValue.validate(self, val) - if not(type(val) == "string") then - return nil - end + val = (type(val) == "table") and val or {val} - local result = "" + local result - for value in val:gmatch("[^\n]+") do + for i, value in ipairs(val) do if luci.util.contains(self.keylist, value) then - result = result .. self.delimiter .. value + result = result and (result .. self.delimiter .. value) or value end end - if result:len() > 0 then - return result:sub(self.delimiter:len() + 1) - else - return nil - end + return result end