libs/cbi: Major Improvements
[project/luci.git] / libs / cbi / luasrc / cbi.lua
index d5be48e..0ec2ff8 100644 (file)
@@ -35,15 +35,18 @@ local uci        = luci.model.uci
 local class      = luci.util.class
 local instanceof = luci.util.instanceof
 
+FORM_NODATA  =  0
+FORM_VALID   =  1
+FORM_INVALID = -1
 
 -- 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,11 +59,12 @@ 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 maps = {func()}
 
        for i, map in ipairs(maps) do
-               if not instanceof(map, Map) then
+               if not instanceof(map, Node) then
                        error("CBI map returns no valid map object!")
                        return nil
                end
@@ -231,6 +235,68 @@ 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
 ]]--
 AbstractSection = class(Node)
@@ -414,7 +480,6 @@ function TypedSection.__init__(self, map, type, ...)
 
        self.template  = "cbi/tsection"
        self.deps = {}
-       self.excludes = {}
 
        self.anonymous = false
 end
@@ -437,11 +502,6 @@ 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
@@ -492,7 +552,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
 
@@ -539,12 +599,13 @@ 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
 end
 
 -- Add a dependencie to another section field
@@ -564,11 +625,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
@@ -578,6 +648,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
@@ -623,6 +695,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)