编写 LuCI CBI 模型
CBI模型是描述UCI配置文件结构的Lua文件,并且CBI解析器将lua文件转为HTML呈现给用户 。
所有 CBI 模型文件都必须返回类型为
luci.cbi.Map
的对象。CBI 模型文件的范围由 luci.cbi 模块的内容和 luci.i18n 的转换函数自动扩展。
CBI控件类型汇总
名称 | 描述 | 继承自 | 模板 |
---|---|---|---|
NamedSection | A fixed configuration section defined by its name | NamedSection = class(AbstractSection) | cbi/nsection |
TypedSection | A (set of) configuration section(s) defined by the type | TypedSection = class(AbstractSection) | cbi/tsection |
Node | Node pseudo abstract class | Node = class() | cbi/node |
Template | A simple template element | Template = class(Node) | |
Map | A map describing a configuration file | Map = class(Node) | cbi/map |
Compound | Container | Compound = class(Node) | cbi/compound |
Delegator | Node controller | Delegator = class(Node) | cbi/delegator |
SimpleForm | A Simple non-UCI form | SimpleForm = class(Node) | cbi/simpleform |
Form | Form = class(SimpleForm) | ||
AbstractSection | AbstractSection = class(Node) | ||
SimpleSection | SimpleSection = class(AbstractSection) | cbi/nullsection | |
Table | Table = class(AbstractSection) | cbi/tblsection | |
AbstractValue | An abstract Value Type | AbstractValue = class(Node) | |
Value | A one-line value | Value = class(AbstractValue) | cbi/value |
DummyValue | This does nothing except being there | DummyValue = class(AbstractValue) | cbi/dvalue |
Flag | A flag being enabled or disabled | Flag = class(AbstractValue) | cbi/fvalue |
ListValue | A one-line value predefined in a list | ListValue = class(AbstractValue) | cbi/lvalue |
MultiValue | Multiple delimited values | MultiValue = class(AbstractValue) | cbi/mvalue |
StaticList | StaticList = class(MultiValue) | ||
DynamicList | DynamicList = class(AbstractValue) | cbi/dynlist | |
TextValue | A multi-line value | TextValue = class(AbstractValue) | cbi/tvalue |
Button | Button = class(AbstractValue) | cbi/button | |
FileUpload | FileUpload = class(AbstractValue) | cbi/upload | |
FileBrowser | FileBrowser = class(AbstractValue) | cbi/browser | |
Page | A simple node | Page = class(Node) |
CBI常用控件用法详解
class Map (config, title, description)
这是模型的根对象。
config:
映射的配置文件名,请参阅UCI 文档和中的文件/etc/config
title:
UI中显示的标题description:
UI中显示的描述
function :section(sectionclass, …)
创建一个新的 section。
sectionclass
:section 对应的类对象- 传递给section类的构造函数的附加参数
section(TypedSection, type, title, description) section(NamedSection, name, type, title, description)
section 对象有一些属性如下:
template: html 模板, 默认为"cbi/tsection"
addremove: 是否可以增加和删除, 默认为 false
anonymous: 是否为匿名 section, 默认为 false
Hooks
可用于在Map的生命周期中触发其他操作
on_cancel
:用户在多步骤委托人或 SimpleForm 实例中按下取消on_init
: CBI 即将渲染 Map 对象on_parse
:CBI 即将读取接收到的 HTTP 表单值on_save
,on_before_save
: CBI即将保存修改后的UCI配置文件on_after_save
: 修改后的 UCI 配置文件刚刚得到 savon_before_commit
:CBI 即将提交更改on_commit
,on_after_commit
,on_before_apply
: 修改后的配置已提交,CBI 即将重启相关服务on_apply
,on_after_apply
: 完全应用的所有更改(仅适用于具有 apply_on_parse 属性集的 Map 实例)示例:
map = Map("config", "Title Text") function map.on_commit(self) -- do something if the UCI configuration got committed end
Sortable Tables
使用
cbi/tblsection
模板的 TypedSection 实例现在可以使用新属性sortable
来允许用户重新排序表行,列表中会有up,down按钮。sct = map:section(TypedSection, "name", "type", "Title Text") sct.template = "cbi/tblsection" sct.sortable = true
class NamedSection (name, type, title, description)
通过UCI section 的 name 选择 一个 section 对象。
实例化使用:Map:section(NamedSection, "name", "type", "title", "description")
name:
UCI section 名称type:
UCI section 类型: Value、 DynamicList、 Flag、 ListValue、TextValue、MultiValue、DummyValue、StaticList、Button …title:
UI 中显示的标题description:
UI中显示的描述
function :option(optionclass, …)
创建一个新option
optionclass
: section 对应的类对象- 传递给 option 类的构造函数的附加参数
function :tab(name, title, description)
将 CBI sections 分成多个tabs,以更好地组织更长的表格。
声明一个新选项卡并最多接受三个参数:
name:
tab 的内部名称,在该 section 内必须是唯一的title:
tab 的标题description:
tab 的描述
function :taboption(tabname, type, name, title, description)
将 CBI sections 分成多个tabs,以更好地组织更长的表格。
该
taboption()
函数包装option()
选项对象并将其分配给给定的选项卡。它最多需要五个参数:
tabname:
分配给option的tab的名称type:
option类型,例如 Value 或 DynamicListname:
option名称title:
option的标题description:
option的描述如果在特定section中使用tabs,则
option()
不得使用该功能,否则会导致未定义的行为。示例:
sct = map:section(TypedSection, "name", "type", "Title Text") sct:tab("general", "General Tab Title", "General Tab Description") sct:tab("advanced", "Advanced Tab Title", "Advanced Tab Description") opt = sct:taboption("general", Value, "optname", "Title Text")
property.addremove = false
允许用户删除和重新创建配置section。
property.dynamic = false
将此section标记为动态。动态section可以包含未定义数量的完全用户定义的option。
property.optional = true
解析可选option
class TypedSection (type, title, description)
描述一组按类型选择的 UCI sections 的对象。
实例化使用:Map:section(TypedSection, "type", "title", "description")
type:
UCI section类型: Value、 DynamicList、 Flag、 ListValue、TextValue、MultiValue、DummyValue、StaticList、Button …title:
UI 中显示的标题description:
UI中显示的描述
function :option(optionclass, …)
创建一个新option
optionclass:
section 对应的类对象- 传递给 option 类的构造函数的附加参数
function :depends(key, value)
只有在同一 section 中另一个option 的 key 设置为 value,才显示此 option 字段。 如果多次调用此函数,则这些依赖项为或的关系。
function.filter(self, section) -abstract-
可以重写此函数以过滤某些不需要被解析的sections。每个sections都会调用filter函数,要过滤掉不解析的section返回
nil
。其他sections需要返回第二个参数中给定的section name。例如:
s = m:section(TypedSection, "interface", "Interfaces") function s:filter(value) return value ~= "loopback" and value end
function :tab(name, title, description)
将 CBI sections 分成多个tabs,以更好地组织更长的表格。
声明一个新选项卡并最多接受三个参数:
name:
tab 的内部名称,在该 section 内必须是唯一的title:
tab 的标题description:
tab 的描述
function :taboption(tabname, type, name, title, description)
将 CBI sections 分成多个tabs,以更好地组织更长的表格。
该
taboption()
函数包装option()
选项对象并将其分配给给定的选项卡。它最多需要五个参数:
tabname:
分配给option的tab的名称type:
option类型,例如 Value 或 DynamicListname:
option名称title:
option的标题description:
option的描述如果在特定section中使用tabs,则
option()
不得使用该功能,否则会导致未定义的行为。示例:
sct = map:section(TypedSection, "name", "type", "Title Text") sct:tab("general", "General Tab Title", "General Tab Description") sct:tab("advanced", "Advanced Tab Title", "Advanced Tab Description") opt = sct:taboption("general", Value, "optname", "Title Text")
property.addremove = false
允许用户删除和重新创建配置section
property.dynamic = false
将此section标记为动态。动态section可以包含未定义数量的完全用户定义的option。
property.optional = true
解析可选option
property.anonymous = false
不显示 UCI section 名称
class Value (option, title, description)
描述 UCI 文件中某个section的 option 对象。在公式中创建标准文本字段(单行文本框)。
实例化使用:NamedSection:option(Value, "option", "title", "description")
或TypedSection:option(Value, "option", "title", "description")
option:
UCI option名称title:
UI 中显示的标题description:
UI中显示的描述
function :depends(key, value)
只有在同一 section 中另一个option 的 key 设置为 value,才显示此 option 字段。 如果多次调用此函数,则这些依赖项为或的关系。
function :value(key, value)
如果可能,将此文本字段转换为组合框并添加一个可选的option。
property.default = nil
默认值
property.maxlength = nil
值的最大输入长度(字符)
property.optional = false
将此option标记为可选,暗示
.rmempty = true
property.rmempty = true
当用户输入空值时从配置文件中删除此option
property.size = nil
表单域显示的最大字符数
property.password = false
密码输入框
class ListValue (option, title, description)
描述 UCI 文件中某个section的 option 对象
在公式中创建一个列表框或单选列表(用于选择多个option之一)。
实例化使用:NamedSection:option(ListValue, "option", "title", "description")
或TypedSection:option(ListValue, "option", "title", "description")
option:
UCI option名称title:
UI 中显示的标题description:
UI中显示的描述
function :depends(key, value)
只有在同一 section 中另一个option 的 key 设置为 value,才显示此 option 字段。 如果多次调用此函数,则这些依赖项为或的关系。
function :value(key, value)
将条目添加到选择列表
property .widget =“select”
select
显示选择列表,radio
显示表单内的单选按钮列表
property.default = nil
默认值
property.optional = false
将此option标记为可选,暗示
.rmempty = true
property.rmempty = true
当用户输入空值时从配置文件中删除此option
property.size = nil
表单域的大小
class Flag(option, title, description)
描述 UCI 文件section中具有两个可能值的option的对象。
在公式中创建一个复选框字段。
实例化使用:NamedSection:option(Flag, "option", "title", "description")
或TypedSection:option(Flag, "option", "title", "description")
option:
UCI option名称title:
UI 中显示的标题description:
UI中显示的描述
function :depends (key, value)
只有在同一 section 中另一个option 的 key 设置为 value,才显示此 option 字段。 如果多次调用此函数,则这些依赖项为或的关系。
property.default = nil
默认值
property.disabled = 0
如果未选中该复选框,则应设置的值
property.enabled = 1
复选框被选中时应设置的值
property.optional = false
将此option标记为可选,暗示
.rmempty = true
property.rmempty = true
当用户输入空值时从配置文件中删除此option
class MultiValue (option, title, description)
描述 UCI 文件中某个section的 option 对象。
创建一个复选框列表或一个多选列表作为表单字段。
实例化使用:NamedSection:option(MultiValue, "option", "title", "description")
或TypedSection:option(MultiValue, "option", "title", "description")
option:
UCI option名称title:
UI 中显示的标题description:
UI中显示的描述
function :depends (key, value)
只有在同一 section 中另一个option 的 key 设置为 value,才显示此 option 字段。 如果多次调用此函数,则这些依赖项为或的关系。
function :value(key, value)
向列表中添加条目。
property .widget =“checkbox”
select
显示选择列表,checkbox
显示表单内的复选框列表
property.delimiter = " "
将用于分隔存储option中的值的字符串
property.default = nil
默认值
property.optional = false
将此option标记为可选,暗示
.rmempty = true
property.rmempty = true
当用户输入空值时从配置文件中删除此option
property.size = nil
表单字段的大小(仅在 property 时使用
.widget = "select"
)
class StaticList (option, title, description)
类似于MultiValue
,但将选定的值存储到 UCI 列表中而不是字符分隔的option中。
config timeserver 'ntp'
list server '0.openwrt.pool.ntp.org'
list server '1.openwrt.pool.ntp.org'
list server '2.openwrt.pool.ntp.org'
list server '3.openwrt.pool.ntp.org'
option MultiValue '0 1 2 3'
class DynamicList (option, title, description)
用户定义值的可扩展列表。将值存储到 UCI 列表中。
UI页面点击添加可向对应list增加条目。
class DummyValue (option, title, description)
在表单中创建一个只读文本。注意它不会向 UCI 写入数据!
实例化使用:NamedSection:option(DummyValue, "option", "title", "description")
或TypedSection:option(DummyValue, "option", "title", "description")
option:
UCI option名称title:
UI 中显示的标题description:
UI中显示的描述
function :depends (key, value)
只有在同一 section 中另一个option 的 key 设置为 value,才显示此 option 字段。 如果多次调用此函数,则这些依赖项为或的关系。
class TextValue (option, title, description)
描述非 UCI 形式的section中的多行文本框的对象。
class Button (option, title, description)
继承自Value。在非 UCI 形式的section中描述 Button 的对象。
property.inputstyle = nil
按钮样式 apply, reset,button,remove,save,find,link,reload等。
定义在对应主题的 cascade.css中:
.cbi-button-positive, .cbi-button-fieldadd, .cbi-button-add, .cbi-button-save { border-color: #4a4; color: #4a4; } .cbi-button-neutral, .cbi-button-download, .cbi-button-find, .cbi-button-link, .cbi-button-up, .cbi-button-down { color: #444; } .cbi-button-action, .cbi-button-apply, .cbi-button-reload, .cbi-button-edit { border-color: #0069d6; color: #0069d6; } .cbi-button-negative, .cbi-button-reset, .cbi-button-remove { border-color: #c44; color: #c44; }
其他属性:
onclick
inputtitle
CBI控件汇总示例
lua 文件中CBI控件代码
m = Map("test_file","map title" ,translate("map descrption")) -- cbi_file is the config file in /etc/config
a = m:section(TypedSection, "typedsection1_title", "typedsection1 description") -- info is the section called info in cbi_file
a1 = a:option(Value, "Value_option_name","Value option title", translate("Value option description"));
a2 = a:option(TextValue, "TextValue_option_name","TextValue option title", "TextValue option description");
a3 = a:option(MultiValue , "MultiValue_option_name","MultiValue option title", "MultiValue option description");
a3:value("0", translate("value0"));
a3:value("1", translate("value1"));
a3:value("2", translate("value2"));
a3:value("3", translate("value3"));
a4 = a:option(DummyValue , "DummyValue_option_name","DummyValue option title", "DummyValue option description");
a5 = a:option(ListValue, "Listvalue_option_name","ListValue option title", "ListValue option description");
a5:value("0", translate("value0"));
a5:value("1", translate("value1"));
a5:value("2", translate("value2"));
a5:value("3", translate("value3"));
a6 = a:option(DynamicList, "DynamicList_option_name","Dynamiclist option title", "DynamicList option description");
a7 = a:option(StaticList, "StaticList_option_name","StaticList option title", "StaticList option description");
a7:value("0", translate("value0"));
a7:value("1", translate("value1"));
a7:value("2", translate("value2"));
a7:value("3", translate("value3"));
a8 = a:option(Flag, "Flag_option_name","Flag option title", "Flag option description");
a9 = a:option(Button, "Button_option_name","Button option title", "Button option description");
b = m:section(TypedSection, "typedsection2_title", "typedsection2 description")
b:tab("tab1", "Tab1");
b:tab("tab2", "Tab2");
b1=b:taboption("tab1", Value, "tab1_option1", "tab1 Option1");
b2=b:taboption("tab2", Value, "tab2_option2", "tab2 Option2");
return m
UCI配置文件
config typedsection1_title 'typedsection1'
option Value_option_name 'Value'
option TextValue_option_name 'TextValue'
option DummyValue_option_name 'DummyValue'
option Listvalue_option_name '1'
list DynamicList_option_name 'DynamicList'
list DynamicList_option_name '123123'
option Flag_option_name '1'
option MultiValue_option_name '0 1 2 3'
list StaticList_option_name '0'
list StaticList_option_name '1'
list StaticList_option_name '2'
list StaticList_option_name '3'
config typedsection2_title 'typedsection2'
option tab1_option1 '1'
option tab2_option2 '2'
显示效果
数据类型验证
Datatypes
验证
服务器端验证器函数现在可以返回自定义错误消息,以便对无效输入提供更好的反馈。
opt = section:option(Value, "optname", "Title Text")
function opt.validate(self, value, section)
if input_is_valid(value) then
return value
else
return nil, "The value is invalid because ..."
end
end
或者自定义不包含冒号的 maclist 验证
maclist = s:taboption("filter", DynamicList, "special_maclist", "MacList")
maclist.optional = true
maclist.rmempty = true
maclist.cast = "table"
maclist.placeholder = "eg. AABBCCDDEEFF"
maclist.validate = function (self, value)
for i, val in pairs(value) do
if val ~= "" then
if not val:match("^[%x]+$") or #val ~= 12 then
return nil, "The"..val.." format error!"
end
end
end
return value
end
JavaScript
LuCI 0.10 分支引入了一个新的 JavaScript 文件xhr.js
,它为操作提供支持例程XMLHttpRequest
。<head>
每个主题都必须在文档区域中包含此文件,以便表单正常工作。
它应该像这样包含:
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>