* luci/core: cbi.lua: automatic i18n capabilities; whitespace cleanup

This commit is contained in:
Jo-Philipp Wich 2008-06-01 16:42:33 +00:00
parent 6250394740
commit 47b62843fc

View file

@ -2,7 +2,7 @@
LuCI - Configuration Bind Interface LuCI - Configuration Bind Interface
Description: Description:
Offers an interface for binding confiugration values to certain Offers an interface for binding configuration values to certain
data types. Supports value and range validation and basic dependencies. data types. Supports value and range validation and basic dependencies.
FileId: FileId:
@ -13,9 +13,9 @@ Copyright 2008 Steven Barth <steven@midlink.org>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@ -40,28 +40,28 @@ function load(cbimap)
require("luci.i18n") require("luci.i18n")
require("luci.config") require("luci.config")
require("luci.sys") require("luci.sys")
local cbidir = luci.sys.libpath() .. "/model/cbi/" local cbidir = luci.sys.libpath() .. "/model/cbi/"
local func, err = loadfile(cbidir..cbimap..".lua") local func, err = loadfile(cbidir..cbimap..".lua")
if not func then if not func then
return nil return nil
end end
luci.i18n.loadc("cbi") luci.i18n.loadc("cbi")
luci.util.resfenv(func) luci.util.resfenv(func)
luci.util.updfenv(func, luci.cbi) luci.util.updfenv(func, luci.cbi)
luci.util.extfenv(func, "translate", luci.i18n.translate) luci.util.extfenv(func, "translate", luci.i18n.translate)
luci.util.extfenv(func, "translatef", luci.i18n.translatef) luci.util.extfenv(func, "translatef", luci.i18n.translatef)
local map = func() local map = func()
if not instanceof(map, Map) then if not instanceof(map, Map) then
error("CBI map returns no valid map object!") error("CBI map returns no valid map object!")
return nil return nil
end end
return map return map
end end
@ -75,6 +75,22 @@ function Node.__init__(self, title, description)
self.template = "cbi/node" self.template = "cbi/node"
end end
-- i18n helper
function Node._i18n(self, config, section, option, title, description)
-- i18n loaded?
if type(luci.i18n) == "table" then
local key = config:gsub("[^%w]+", "")
if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end
if option then key = key .. "_" .. option:lower():gsub("[^%w]+", "") end
self.title = title or luci.i18n.translate( key, option or section or config )
self.description = description or luci.i18n.translate( key .. "_desc", "" )
end
end
-- Append child nodes -- Append child nodes
function Node.append(self, obj) function Node.append(self, obj)
table.insert(self.children, obj) table.insert(self.children, obj)
@ -115,12 +131,14 @@ end
--[[ --[[
Map - A map describing a configuration file Map - A map describing a configuration file
]]-- ]]--
Map = class(Node) Map = class(Node)
function Map.__init__(self, config, ...) function Map.__init__(self, config, ...)
Node.__init__(self, ...) Node.__init__(self, ...)
Node._i18n(self, config, nil, nil, ...)
self.config = config self.config = config
self.template = "cbi/map" self.template = "cbi/map"
self.uci = luci.model.uci.Session() self.uci = luci.model.uci.Session()
@ -138,9 +156,12 @@ function Map.parse(self, ...)
end end
-- Creates a child section -- Creates a child section
function Map.section(self, class, ...) function Map.section(self, class, section, ...)
if instanceof(class, AbstractSection) then if instanceof(class, AbstractSection) then
local obj = class(self, ...) local obj = class(self, section, ...)
Node._i18n(obj, self.config, section, nil, ...)
self:append(obj) self:append(obj)
return obj return obj
else else
@ -218,21 +239,24 @@ function AbstractSection.__init__(self, map, sectiontype, ...)
self.map = map self.map = map
self.config = map.config self.config = map.config
self.optionals = {} self.optionals = {}
self.optional = true self.optional = true
self.addremove = false self.addremove = false
self.dynamic = false self.dynamic = false
end end
-- Appends a new option -- Appends a new option
function AbstractSection.option(self, class, ...) function AbstractSection.option(self, class, option, ...)
if instanceof(class, AbstractValue) then if instanceof(class, AbstractValue) then
local obj = class(self.map, ...) local obj = class(self.map, option, ...)
Node._i18n(obj, self.config, self.section, option, ...)
self:append(obj) self:append(obj)
return obj return obj
else else
error("class must be a descendent of AbstractValue") error("class must be a descendent of AbstractValue")
end end
end end
-- Parse optional options -- Parse optional options
@ -240,9 +264,9 @@ function AbstractSection.parse_optionals(self, section)
if not self.optional then if not self.optional then
return return
end end
self.optionals[section] = {} self.optionals[section] = {}
local field = luci.http.formvalue("cbi.opt."..self.config.."."..section) local field = luci.http.formvalue("cbi.opt."..self.config.."."..section)
for k,v in ipairs(self.children) do for k,v in ipairs(self.children) do
if v.optional and not v:cfgvalue(section) then if v.optional and not v:cfgvalue(section) then
@ -253,7 +277,7 @@ function AbstractSection.parse_optionals(self, section)
end end
end end
end end
if field and #field > 0 and self.dynamic then if field and #field > 0 and self.dynamic then
self:add_dynamic(field) self:add_dynamic(field)
end end
@ -270,27 +294,27 @@ function AbstractSection.parse_dynamic(self, section)
if not self.dynamic then if not self.dynamic then
return return
end end
local arr = luci.util.clone(self:cfgvalue(section)) local arr = luci.util.clone(self:cfgvalue(section))
local form = luci.http.formvaluetable("cbid."..self.config.."."..section) local form = luci.http.formvaluetable("cbid."..self.config.."."..section)
for k, v in pairs(form) do for k, v in pairs(form) do
arr[k] = v arr[k] = v
end end
for key,val in pairs(arr) do for key,val in pairs(arr) do
local create = true local create = true
for i,c in ipairs(self.children) do for i,c in ipairs(self.children) do
if c.option == key then if c.option == key then
create = false create = false
end end
end end
if create and key:sub(1, 1) ~= "." then if create and key:sub(1, 1) ~= "." then
self:add_dynamic(key, true) self:add_dynamic(key, true)
end end
end end
end end
-- Returns the section's UCI table -- Returns the section's UCI table
function AbstractSection.cfgvalue(self, section) function AbstractSection.cfgvalue(self, section)
@ -317,16 +341,16 @@ NamedSection = class(AbstractSection)
function NamedSection.__init__(self, map, section, ...) function NamedSection.__init__(self, map, section, ...)
AbstractSection.__init__(self, map, ...) AbstractSection.__init__(self, map, ...)
self.template = "cbi/nsection" self.template = "cbi/nsection"
self.section = section self.section = section
self.addremove = false self.addremove = false
end end
function NamedSection.parse(self) function NamedSection.parse(self)
local s = self.section local s = self.section
local active = self:cfgvalue(s) local active = self:cfgvalue(s)
if self.addremove then if self.addremove then
local path = self.config.."."..s local path = self.config.."."..s
if active then -- Remove the section if active then -- Remove the section
@ -341,14 +365,14 @@ function NamedSection.parse(self)
end end
end end
end end
if active then if active then
AbstractSection.parse_dynamic(self, s) AbstractSection.parse_dynamic(self, s)
if luci.http.formvalue("cbi.submit") then if luci.http.formvalue("cbi.submit") then
Node.parse(self, s) Node.parse(self, s)
end end
AbstractSection.parse_optionals(self, s) AbstractSection.parse_optionals(self, s)
end end
end end
@ -356,7 +380,7 @@ end
TypedSection - A (set of) configuration section(s) defined by the type TypedSection - A (set of) configuration section(s) defined by the type
addremove: Defines whether the user can add/remove sections of this type addremove: Defines whether the user can add/remove sections of this type
anonymous: Allow creating anonymous sections anonymous: Allow creating anonymous sections
validate: a validation function returning nil if the section is invalid validate: a validation function returning nil if the section is invalid
]]-- ]]--
TypedSection = class(AbstractSection) TypedSection = class(AbstractSection)
@ -365,7 +389,7 @@ function TypedSection.__init__(self, ...)
self.template = "cbi/tsection" self.template = "cbi/tsection"
self.deps = {} self.deps = {}
self.excludes = {} self.excludes = {}
self.anonymous = false self.anonymous = false
end end
@ -373,7 +397,7 @@ end
function TypedSection.cfgsections(self) function TypedSection.cfgsections(self)
local sections = {} local sections = {}
local map, order = self.map:get() local map, order = self.map:get()
for i, k in ipairs(order) do for i, k in ipairs(order) do
if map[k][".type"] == self.sectiontype then if map[k][".type"] == self.sectiontype then
if self:checkscope(k) then if self:checkscope(k) then
@ -381,18 +405,18 @@ function TypedSection.cfgsections(self)
end end
end end
end end
return sections return sections
end end
-- Creates a new section of this type with the given name (or anonymous) -- Creates a new section of this type with the given name (or anonymous)
function TypedSection.create(self, name) function TypedSection.create(self, name)
if name then if name then
self.map:set(name, nil, self.sectiontype) self.map:set(name, nil, self.sectiontype)
else else
name = self.map:add(self.sectiontype) name = self.map:add(self.sectiontype)
end end
for k,v in pairs(self.children) do for k,v in pairs(self.children) do
if v.default then if v.default then
self.map:set(name, v.option, v.default) self.map:set(name, v.option, v.default)
@ -419,25 +443,25 @@ function TypedSection.parse(self)
if name then if name then
self:create() self:create()
end end
else else
if name then if name then
-- Ignore if it already exists -- Ignore if it already exists
if self:cfgvalue(name) then if self:cfgvalue(name) then
name = nil; name = nil;
end end
name = self:checkscope(name) name = self:checkscope(name)
if not name then if not name then
self.err_invalid = true self.err_invalid = true
end end
if name and name:len() > 0 then if name and name:len() > 0 then
self:create(name) self:create(name)
end end
end end
end end
-- Remove -- Remove
crval = "cbi.rts." .. self.config crval = "cbi.rts." .. self.config
name = luci.http.formvaluetable(crval) name = luci.http.formvaluetable(crval)
@ -445,9 +469,9 @@ function TypedSection.parse(self)
if self:cfgvalue(k) and self:checkscope(k) then if self:cfgvalue(k) and self:checkscope(k) then
self:remove(k) self:remove(k)
end end
end end
end end
for i, k in ipairs(self:cfgsections()) do for i, k in ipairs(self:cfgsections()) do
AbstractSection.parse_dynamic(self, k) AbstractSection.parse_dynamic(self, k)
if luci.http.formvalue("cbi.submit") then if luci.http.formvalue("cbi.submit") then
@ -463,22 +487,22 @@ function TypedSection.checkscope(self, section)
if self.excludes[section] then if self.excludes[section] then
return nil return nil
end end
-- Check if at least one dependency is met -- Check if at least one dependency is met
if #self.deps > 0 and self:cfgvalue(section) then if #self.deps > 0 and self:cfgvalue(section) then
local stat = false local stat = false
for k, v in ipairs(self.deps) do for k, v in ipairs(self.deps) do
if self:cfgvalue(section)[v.option] == v.value then if self:cfgvalue(section)[v.option] == v.value then
stat = true stat = true
end end
end end
if not stat then if not stat then
return nil return nil
end end
end end
return self:validate(section) return self:validate(section)
end end
@ -492,7 +516,7 @@ end
--[[ --[[
AbstractValue - An abstract Value Type AbstractValue - An abstract Value Type
null: Value can be empty null: Value can be empty
valid: A function returning the value if it is valid otherwise nil valid: A function returning the value if it is valid otherwise nil
depends: A table of option => value pairs of which one must be true depends: A table of option => value pairs of which one must be true
default: The default value default: The default value
size: The size of the input fields size: The size of the input fields
@ -508,7 +532,7 @@ function AbstractValue.__init__(self, map, option, ...)
self.config = map.config self.config = map.config
self.tag_invalid = {} self.tag_invalid = {}
self.deps = {} self.deps = {}
self.rmempty = false self.rmempty = false
self.default = nil self.default = nil
self.size = nil self.size = nil
@ -534,7 +558,7 @@ end
function AbstractValue.parse(self, section) function AbstractValue.parse(self, section)
local fvalue = self:formvalue(section) local fvalue = self:formvalue(section)
if fvalue and fvalue ~= "" then -- If we have a form value, write it to UCI if fvalue and fvalue ~= "" then -- If we have a form value, write it to UCI
fvalue = self:validate(fvalue) fvalue = self:validate(fvalue)
if not fvalue then if not fvalue then
@ -542,7 +566,7 @@ function AbstractValue.parse(self, section)
end end
if fvalue and not (fvalue == self:cfgvalue(section)) then if fvalue and not (fvalue == self:cfgvalue(section)) then
self:write(section, fvalue) self:write(section, fvalue)
end end
else -- Unset the UCI or error else -- Unset the UCI or error
if self.rmempty or self.optional then if self.rmempty or self.optional then
self:remove(section) self:remove(section)
@ -594,7 +618,7 @@ Value = class(AbstractValue)
function Value.__init__(self, ...) function Value.__init__(self, ...)
AbstractValue.__init__(self, ...) AbstractValue.__init__(self, ...)
self.template = "cbi/value" self.template = "cbi/value"
self.maxlength = nil self.maxlength = nil
self.isnumber = false self.isnumber = false
self.isinteger = false self.isinteger = false
@ -605,7 +629,7 @@ function Value.validate(self, val)
if self.maxlength and tostring(val):len() > self.maxlength then if self.maxlength and tostring(val):len() > self.maxlength then
val = nil val = nil
end end
return luci.util.validate(val, self.isnumber, self.isinteger) return luci.util.validate(val, self.isnumber, self.isinteger)
end end
@ -620,7 +644,7 @@ function DummyValue.__init__(self, map, ...)
end end
function DummyValue.parse(self) function DummyValue.parse(self)
end end
function DummyValue.render(self, s) function DummyValue.render(self, s)
@ -636,7 +660,7 @@ Flag = class(AbstractValue)
function Flag.__init__(self, ...) function Flag.__init__(self, ...)
AbstractValue.__init__(self, ...) AbstractValue.__init__(self, ...)
self.template = "cbi/fvalue" self.template = "cbi/fvalue"
self.enabled = "1" self.enabled = "1"
self.disabled = "0" self.disabled = "0"
end end
@ -644,17 +668,17 @@ end
-- A flag can only have two states: set or unset -- A flag can only have two states: set or unset
function Flag.parse(self, section) function Flag.parse(self, section)
local fvalue = self:formvalue(section) local fvalue = self:formvalue(section)
if fvalue then if fvalue then
fvalue = self.enabled fvalue = self.enabled
else else
fvalue = self.disabled fvalue = self.disabled
end end
if fvalue == self.enabled or (not self.optional and not self.rmempty) then if fvalue == self.enabled or (not self.optional and not self.rmempty) then
if not(fvalue == self:cfgvalue(section)) then if not(fvalue == self:cfgvalue(section)) then
self:write(section, fvalue) self:write(section, fvalue)
end end
else else
self:remove(section) self:remove(section)
end end
@ -673,7 +697,7 @@ function ListValue.__init__(self, ...)
self.template = "cbi/lvalue" self.template = "cbi/lvalue"
self.keylist = {} self.keylist = {}
self.vallist = {} self.vallist = {}
self.size = 1 self.size = 1
self.widget = "select" self.widget = "select"
end end
@ -681,7 +705,7 @@ end
function ListValue.value(self, key, val) function ListValue.value(self, key, val)
val = val or key val = val or key
table.insert(self.keylist, tostring(key)) table.insert(self.keylist, tostring(key))
table.insert(self.vallist, tostring(val)) table.insert(self.vallist, tostring(val))
end end
function ListValue.validate(self, val) function ListValue.validate(self, val)
@ -705,8 +729,8 @@ function MultiValue.__init__(self, ...)
AbstractValue.__init__(self, ...) AbstractValue.__init__(self, ...)
self.template = "cbi/mvalue" self.template = "cbi/mvalue"
self.keylist = {} self.keylist = {}
self.vallist = {} self.vallist = {}
self.widget = "checkbox" self.widget = "checkbox"
self.delimiter = " " self.delimiter = " "
end end
@ -714,16 +738,16 @@ end
function MultiValue.value(self, key, val) function MultiValue.value(self, key, val)
val = val or key val = val or key
table.insert(self.keylist, tostring(key)) table.insert(self.keylist, tostring(key))
table.insert(self.vallist, tostring(val)) table.insert(self.vallist, tostring(val))
end end
function MultiValue.valuelist(self, section) function MultiValue.valuelist(self, section)
local val = self:cfgvalue(section) local val = self:cfgvalue(section)
if not(type(val) == "string") then if not(type(val) == "string") then
return {} return {}
end end
return luci.util.split(val, self.delimiter) return luci.util.split(val, self.delimiter)
end end
@ -731,18 +755,18 @@ function MultiValue.validate(self, val)
if not(type(val) == "string") then if not(type(val) == "string") then
return nil return nil
end end
local result = "" local result = ""
for value in val:gmatch("[^\n]+") do for value in val:gmatch("[^\n]+") do
if luci.util.contains(self.keylist, value) then if luci.util.contains(self.keylist, value) then
result = result .. self.delimiter .. value result = result .. self.delimiter .. value
end end
end end
if result:len() > 0 then if result:len() > 0 then
return result:sub(self.delimiter:len() + 1) return result:sub(self.delimiter:len() + 1)
else else
return nil return nil
end end
end end