Node.parse(self, ...)
if self.save then
+ self:_run_hooks("on_save", "on_before_save")
for i, config in ipairs(self.parsechain) do
self.uci:save(config)
end
+ self:_run_hooks("on_after_save")
if self:submitstate() and ((not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply")) then
self:_run_hooks("on_before_commit")
for i, config in ipairs(self.parsechain) do
self.rmempty = not value
end
+function AbstractValue.add_error(self, section, type, msg)
+ self.error = self.error or { }
+ self.error[section] = msg or type
+
+ self.section.error = self.section.error or { }
+ self.section.error[section] = self.section.error[section] or { }
+ table.insert(self.section.error[section], msg or type)
+
+ if type == "invalid" then
+ self.tag_invalid[section] = true
+ elseif type == "missing" then
+ self.tag_missing[section] = true
+ end
+
+ self.tag_error[section] = true
+ self.map.save = false
+end
+
function AbstractValue.parse(self, section, novld)
local fvalue = self:formvalue(section)
local cvalue = self:cfgvalue(section)
end
if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI
- fvalue = self:transform(self:validate(fvalue, section))
+ local val_err
+ fvalue, val_err = self:validate(fvalue, section)
+ fvalue = self:transform(fvalue)
+
if not fvalue and not novld then
- if self.error then
- self.error[section] = "invalid"
- else
- self.error = { [section] = "invalid" }
- end
- if self.section.error then
- table.insert(self.section.error[section], "invalid")
- else
- self.section.error = {[section] = {"invalid"}}
- end
- self.map.save = false
+ self:add_error(section, "invalid", val_err)
end
- if fvalue and not (fvalue == cvalue) then
+
+ if fvalue and (self.forcewrite or not (fvalue == cvalue)) then
if self:write(section, fvalue) then
-- Push events
self.section.changed = true
--luci.util.append(self.map.events, self.events)
end
elseif cvalue ~= fvalue and not novld then
- self:write(section, fvalue or "")
- if self.error then
- self.error[section] = "missing"
- else
- self.error = { [section] = "missing" }
- end
- self.map.save = false
+ -- trigger validator with nil value to get custom user error msg.
+ local _, val_err = self:validate(nil, section)
+ self:add_error(section, "missing", val_err)
end
end
end
-- Return the UCI value of this object
function AbstractValue.cfgvalue(self, section)
- local value = (self.error and self.error[section] == "invalid")
- and self:formvalue(section) or self.map:get(section, self.option)
+ local value
+ if self.tag_error[section] then
+ value = self:formvalue(section)
+ else
+ value = self.map:get(section, self.option)
+ end
+
if not value then
return nil
elseif not self.cast or self.cast == type(value) then
-- Validate the form value
function AbstractValue.validate(self, value)
- if self.datatype and value and datatypes[self.datatype] then
- if type(value) == "table" then
- local v
- for _, v in ipairs(value) do
- if v and #v > 0 and not datatypes[self.datatype](v) then
- return nil
- end
+ if self.datatype and value then
+ local args = { }
+ local dt, ar = self.datatype:match("^(%w+)%(([^%(%)]+)%)")
+
+ if dt and ar then
+ local a
+ for a in ar:gmatch("[^%s,]+") do
+ args[#args+1] = a
end
else
- if not datatypes[self.datatype](value) then
- return nil
+ dt = self.datatype
+ end
+
+ if dt and datatypes[dt] then
+ if type(value) == "table" then
+ local v
+ for _, v in ipairs(value) do
+ if v and #v > 0 and not datatypes[dt](v, unpack(args)) then
+ return nil
+ end
+ end
+ else
+ if not datatypes[dt](value, unpack(args)) then
+ return nil
+ end
end
end
end
+
return value
end
self.vallist = {}
end
+function Value.reset_values(self)
+ self.keylist = {}
+ self.vallist = {}
+end
+
function Value.value(self, key, val)
val = val or key
table.insert(self.keylist, tostring(key))
self.widget = "select"
end
+function ListValue.reset_values(self)
+ self.keylist = {}
+ self.vallist = {}
+end
+
function ListValue.value(self, key, val, ...)
if luci.util.contains(self.keylist, key) then
return
AbstractValue.render(self, ...)
end
+function MultiValue.reset_values(self)
+ self.keylist = {}
+ self.vallist = {}
+end
+
function MultiValue.value(self, key, val)
if luci.util.contains(self.keylist, key) then
return
self.vallist = {}
end
+function DynamicList.reset_values(self)
+ self.keylist = {}
+ self.vallist = {}
+end
+
function DynamicList.value(self, key, val)
val = val or key
table.insert(self.keylist, tostring(key))
table.insert(self.vallist, tostring(val))
end
-function DynamicList.write(self, ...)
- self.map.proceed = true
- return AbstractValue.write(self, ...)
+function DynamicList.write(self, section, value)
+ local t = { }
+
+ if type(value) == "table" then
+ local x
+ for _, x in ipairs(value) do
+ if x and #x > 0 then
+ t[#t+1] = x
+ end
+ end
+ elseif self.cast == "table" then
+ local x
+ for x in util.imatch(value) do
+ t[#t+1] = x
+ end
+ else
+ t = { value }
+ end
+
+ if self.cast == "string" then
+ value = table.concat(t, " ")
+ else
+ value = t
+ end
+
+ return AbstractValue.write(self, section, value)
+end
+
+function DynamicList.cfgvalue(self, section)
+ local value = AbstractValue.cfgvalue(self, section)
+
+ if type(value) == "string" then
+ local x
+ local t = { }
+ for x in value:gmatch("%S+") do
+ if #x > 0 then
+ t[#t+1] = x
+ end
+ end
+ value = t
+ end
+
+ return value
end
function DynamicList.formvalue(self, section)
local value = AbstractValue.formvalue(self, section)
- value = (type(value) == "table") and value or {value}
- local valid = {}
- for i, v in ipairs(value) do
- if v and #v > 0
- and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i)
- and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then
- table.insert(valid, v)
+ if type(value) == "string" then
+ local x
+ local t = { }
+ for x in value:gmatch("%S+") do
+ t[#t+1] = x
end
+ value = t
end
- return valid
+ return value
end