cbi: Increare responsiveness of "Save & Apply"
[project/luci.git] / libs / cbi / luasrc / cbi.lua
index fb0355e..09ba553 100644 (file)
@@ -47,7 +47,7 @@ REMOVE_PREFIX = "cbi.rts."
 -- Loads a CBI map from given file, creating an environment and returns it
 function load(cbimap, ...)
        require("luci.fs")
-       require("luci.i18n")
+       local i18n = require "luci.i18n"
        require("luci.config")
        require("luci.util")
 
@@ -56,12 +56,18 @@ function load(cbimap, ...)
        assert(func, err)
 
        luci.i18n.loadc("cbi")
+       luci.i18n.loadc("uvl")
 
-       luci.util.resfenv(func)
-       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 env = {
+               translate=i18n.translate,
+               translatef=i18n.translatef,
+               arg={...}
+       }
+
+       setfenv(func, setmetatable(env, {__index =
+               function(tbl, key)
+                       return rawget(tbl, key) or _M[key] or _G[key]
+               end}))
 
        local maps = {func()}
 
@@ -81,26 +87,31 @@ local function _uvl_validate_section(node, name)
        luci.uvl.STRICT_UNKNOWN_OPTIONS = false
        luci.uvl.STRICT_UNKNOWN_SECTIONS = false
 
-       local stat, err = node.map.validator:validate_section(node.config, name, co)
-       if err then
-               node.map.save = false
-               if err:is(luci.uvl.errors.ERR_DEPENDENCY) then
-                       node.tag_deperror[name] = true
-               else
-                       node.tag_invalid[name] = true
+       local function tag_fields(e)
+               if e.option and node.fields[e.option] then
+                       node.fields[e.option].error = e
+               elseif e.childs then
+                       for _, c in ipairs(e.childs) do tag_fields(c) end
                end
-               for i, v in ipairs(err.childs) do
-                       if v.option and node.fields[v.option] then
-                               if v:is(luci.uvl.errors.ERR_DEPENDENCY) then
-                                       node.fields[v.option].tag_reqerror[name] = true
-                               elseif v:is(luci.uvl.errors.ERR_OPT_REQUIRED) then
-                                       node.fields[v.option].tag_missing[name] = true
-                                       node.tag_deperror[name] = true
-                               elseif v:is(luci.uvl.errors.ERR_OPTION) then
-                                       node.fields[v.option].tag_invalid[name] = true
-                               end
+       end
+
+       local function tag_section(e)
+               local s = { }
+               for _, c in ipairs(e.childs) do
+                       if c.childs and not c:is(luci.uvl.errors.ERR_DEPENDENCY) then
+                               table.insert( s, c.childs[1]:string() )
+                       else
+                               table.insert( s, c:string() )
                        end
                end
+               if #s > 0 then node.error = s end
+       end
+
+       local stat, err = node.map.validator:validate_section(node.config, name, co)
+       if err then
+               node.map.save = false
+               tag_fields(err)
+               tag_section(err)
        end
 
 end
@@ -200,6 +211,7 @@ function Map.__init__(self, config, ...)
        self.config = config
        self.parsechain = {self.config}
        self.template = "cbi/map"
+       self.apply_on_parse = nil
        self.uci = uci.cursor()
        self.save = true
        if not self.uci:load(self.config) then
@@ -208,7 +220,7 @@ function Map.__init__(self, config, ...)
 
        self.validator = luci.uvl.UVL()
        self.scheme = self.validator:get_scheme(self.config)
-       
+
 end
 
 function Map.get_scheme(self, sectiontype, option)
@@ -237,15 +249,22 @@ function Map.parse(self, ...)
                if luci.http.formvalue("cbi.apply") then
                        for i, config in ipairs(self.parsechain) do
                                self.uci:commit(config)
-                               self.uci:apply(config)
-       
+
                                -- Refresh data because commit changes section names
                                self.uci:load(config)
                        end
-       
+                       if self.apply_on_parse then
+                               self.uci:apply(self.parsechain)
+                       else
+                               self._apply = function()
+                                       local cmd = self.uci:apply(self.parsechain, true)
+                                       return io.popen(cmd)
+                               end
+                       end
+
                        -- Reparse sections
                        Node.parse(self, ...)
-       
+
                end
                for i, config in ipairs(self.parsechain) do
                        self.uci:unload(config)
@@ -253,6 +272,15 @@ function Map.parse(self, ...)
        end
 end
 
+function Map.render(self, ...)
+       Node.render(self, ...)
+       if self._apply then
+               local fp = self._apply()
+               fp:read("*a")
+               fp:close()
+       end
+end
+
 -- Creates a child section
 function Map.section(self, class, ...)
        if instanceof(class, AbstractSection) then
@@ -611,7 +639,7 @@ NamedSection = class(AbstractSection)
 function NamedSection.__init__(self, map, section, stype, ...)
        AbstractSection.__init__(self, map, stype, ...)
        Node._i18n(self, map.config, section, nil, ...)
-       
+
        -- Defaults
        self.addremove = false
 
@@ -650,7 +678,7 @@ function NamedSection.parse(self)
                AbstractSection.parse_dynamic(self, s)
                if luci.http.formvalue("cbi.submit") then
                        Node.parse(self, s)
-                       
+
                        if not self.override_scheme and self.map.scheme then
                                _uvl_validate_section(self, s)
                        end
@@ -725,7 +753,7 @@ function TypedSection.parse(self)
                AbstractSection.parse_dynamic(self, k)
                if luci.http.formvalue("cbi.submit") then
                        Node.parse(self, k)
-                       
+
                        if not self.override_scheme and self.map.scheme then
                                _uvl_validate_section(self, k)
                        end
@@ -838,6 +866,7 @@ function AbstractValue.__init__(self, map, section, option, ...)
                self.cast        = (vs.type == "list") and "list" or "string"
                self.title       = self.title or vs.title
                self.description = self.description or vs.descr
+               self.default     = vs.default
 
                if vs.depends and not self.override_dependencies then
                        for i, deps in ipairs(vs.depends) do