libs/cbi: Major Improvements

Added initial support for non-UCI-based forms (luci.cbi.SimpleForm)
	Minor API improvements
	Now correctly tagging "empty mandatory field" errors
This commit is contained in:
Steven Barth 2008-08-09 14:14:04 +00:00
parent b71825db91
commit bdb4bbde13
8 changed files with 169 additions and 7 deletions

View file

@ -1,6 +1,7 @@
cbi_add = "Add entry"
cbi_del = "Remove entry"
cbi_invalid = "Error: Invalid input value"
cbi_missing = "Error: This field is mandatory"
cbi_addopt = "-- Additional Field --"
cbi_optional = " (optional)"
cbi_sectempty = "This section contains no values yet"

View file

@ -89,6 +89,7 @@ settings = "Settings"
start = "Start"
static = "static"
statistics = "Statistics"
submit = "Submit"
syslog = "System Log"
system = "System"

View file

@ -1,6 +1,7 @@
cbi_add = "Eintrag hinzufügen"
cbi_del = "Eintrag entfernen"
cbi_invalid = "Error: Ungültige Eingabe"
cbi_invalid = "Fehler: Ungültige Eingabe"
cbi_missing = "Fehler: Dieses Feld muss ausgefüllt werden"
cbi_addopt = "-- Zusätzliches Feld --"
cbi_sectempty = "Diese Sektion enthält noch keine Einträge"
cbi_manual = "-- benutzerdefiniert --"

View file

@ -90,6 +90,7 @@ settings = "Einstellungen"
start = "Start"
static = "statisch"
statistics = "Statistiken"
submit = "Absenden"
syslog = "Systemprotokoll"
system = "System"

View file

@ -35,6 +35,9 @@ 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, ...)
@ -61,7 +64,7 @@ function load(cbimap, ...)
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 +234,68 @@ function Map.get(self, section, option)
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
]]--
@ -534,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
@ -559,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
@ -573,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
@ -618,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)

View file

@ -21,6 +21,9 @@ $Id$
<% if self.tag_invalid[section] then -%>
<div class="cbi-error"><%:cbi_invalid%></div>
<%- end %>
<% if self.tag_missing[section] then -%>
<div class="cbi-error"><%:cbi_missing%></div>
<%- end %>
</div>
<% if #self.deps > 0 then -%>

View file

@ -0,0 +1,46 @@
<%#
LuCI - Lua Configuration Interface
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
-%>
<form method="post" action="<%=luci.http.getenv("REQUEST_URI")%>">
<div>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<input type="hidden" name="cbi.submit" value="1" />
<input type="submit" value="<%:save%>" class="hidden" />
</div>
<div class="cbi-map" id="cbi-<%=self.config%>">
<h1><%=self.title%></h1>
<div class="cbi-map-descr"><%=self.description%></div>
<fieldset class="cbi-section">
<div class="cbi-section-node">
<% self:render_children(1, scope or {}) %>
</div>
<br />
</fieldset>
<br />
</div>
<div>
<%- if self.submit ~= false then %>
<input type="submit" value="
<%- if not self.submit then -%><%-:submit-%><%-else-%><%=self.submit%><%end%>
" />
<% end %>
<%- if self.reset ~= false then %>
<input type="reset" value="
<%- if not self.reset then -%><%-:reset-%><%-else-%><%=self.reset%><%end%>
" />
<% end %>
<script type="text/javascript">cbi_d_init();</script>
</div>
</form>

View file

@ -461,3 +461,32 @@ function cbi(model)
luci.template.render("cbi/footer")
end
end
--- Create a CBI form model dispatching target.
-- @param model CBI form model tpo be rendered
function form(model)
require("luci.cbi")
require("luci.template")
return function(...)
local stat, maps = luci.util.copcall(luci.cbi.load, model, ...)
if not stat then
error500(maps)
return true
end
for i, res in ipairs(maps) do
local stat, err = luci.util.copcall(res.parse, res)
if not stat then
error500(err)
return true
end
end
luci.template.render("header")
for i, res in ipairs(maps) do
res:render()
end
luci.template.render("footer")
end
end