function?index()??
19??????luci.i18n.loadc("admin-core")??
20??????local?i18n?=?luci.i18n.translate??
21????
22??????entry({"mini",?"system"},?"system",?i18n("system"),?40).index?=?true??
23??????entry({"mini",?cbi("mini/system",?{autoapply=true}),?1)??
24??????entry({"mini",?"passwd"},?form("mini/passwd"),?i18n("a_s_changepw"),?10)??
25??????entry({"mini",?"backup"},?call("action_backup"),?i18n("a_s_backup"),?80)??
26??????entry({"mini",?"upgrade"},?call("action_upgrade"),?i18n("a_s_flash"),?90)??
27??????entry({"mini",?"reboot"},?call("action_reboot"),?i18n("reboot"),?100)??
28??end??
mudel是对应文件的,?function?index?定义了菜单,比如这一句entry({"mini",?"system",?"reboot"},?call("action_reboot"),?i18n("reboot"),?100)
第1?项为菜单入口:
{"mini",?"reboot"},?mini?是最上层的菜单,即为用户项,?system?为一个具体的菜单,?reboot?为这个菜单的子菜单,如果?reboot?还需要加上子菜单的话,可以这样写:
entry({"mini",?"reboot",?"chreboot"},?call("action_chreboot"),?i18n("chreboot"),?1),?这样就会在reboot?上产生一个新的子菜单,以此类推,可以产生?N?层菜单。
第二项为菜单对应的页面,可以是lua?的源代码文件,也可以是?html?页面。
alias?cgi?form?call?等定义了此菜单相应的处理方式,?form?和?cgi?对应到?model/cbi?相应的目录下面,那里面是对应的定制好的?html?和?lua?业务处理。
alias是等同于别的链接,?call?调用了相应的?action_function?。还有一种调用,是?template?,是直接链接到view?相应目录下面的?htm?页面。(说明:?luci?框架下面的?htm?都是可以嵌入?lua?语句的,做业务处理,相当于?jsp?页面的内部的?Java?语句)。
问价查找对应简介:
action_reboot?function
*/model/cbi/mini/system.lua??{autoapply=true}???这个失传的参数。
。。。。。
第三项为i18n?显示,比如entry({"mini",?100),菜单的名字为admin-core?文件内的对应显示。此处也可以这样写,??i18n("reboot","?重启?")?,即直接做了国际化。菜单上显示的就是“重启”。
第四项为现实的顺序,这个数字越小,显示越靠前,靠上。
?
现在说一下这些文件的解析是怎么解析的呢?你当然是说dispatch.lua中,你说对了,但是真正解析成菜单的递归算法确实在header.htm中 ?位置:*/view/themes/openwrt/
代码如下:
<%??
- require("luci.sys")??
- local?load1,?load5,?load15?=?luci.sys.loadavg()??
- local?request??=?require("luci.dispatcher").context.path??
- local?category?=?request[1]??
- local?tree?????=?luci.dispatcher.node()??
- local?cattree??=?category?and?luci.dispatcher.node(category)??
- local?node?????=?luci.dispatcher.context.dispatched??
- local?hostname?=?luci.sys.hostname()??
- local?c?=?tree??
- for?i,r?in?ipairs(request)?do??
- ?????if?c.nodes?and?c.nodes[r]?then??
- ??????????c?=?c.nodes[r]??
- ??????????c._menu_selected?=?true??
- ?????end??
- end??
- require("luci.i18n").loadc("default")??
- require("luci.http").prepare_content("application/xhtml+xml")??
- -%>??
- <?xml?version="1.0"?encoding="utf-8"?>??
- <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Strict//EN"?"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">??
- <html?xmlns="http://www.w3.org/1999/xhtml"?xml:lang="<%=luci.i18n.context.lang%>"?lang="<%=luci.i18n.context.lang%>">??
- <head>??
- <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>??
- <meta?http-equiv="Content-Script-Type"?content="text/javascript"?/>??
- <link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=media%>/cascade.css"?/>??
- <!--[if?lt?IE?7]><link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=media%>/ie6.css"?/><![endif]-->??
- <!--[if?IE?7]><link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=media%>/ie7.css"?/><![endif]-->??
- <%?if?node?and?node.css?then?%><link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=resource%>/<%=node.css%>"?/>??
- <%?end?-%>??
- <mce:script?type="text/javascript"?src="<%=resource%><!--??
- /VarType.js">??
- ??
- <mce:script?type="text/javascript"?src="<%=resource%><!--??
- /XHTML1.js">??
- ??
- /Dropdowns.js">??
- <title><%=striptags(?hostname?..?(?(node?and?node.title)?and?'?-?'?..?node.title?or?''))?%>?-?LuCI</title>??
- </head>??
- <body?class="lang_<%=luci.i18n.context.lang%>">??
- <p?class="skiplink">??
- <span?id="skiplink1"><a?href="#navigation"?mce_href="#navigation"><%:skiplink1?Skip?to?navigation%></a></span>??
- <span?id="skiplink2"><a?href="#content"?mce_href="#content"><%:skiplink2?Skip?to?content%></a></span>??
- </p>??
- <div?id="header">??
- <h1><%=luci.version.distname%></h1>??
- <p>??
- <%=luci.version.distversion%><br?/>??
- <%:load%>:?<%="%.2f"?%?load1%>?<%="%.2f"?%?load5%>?<%="%.2f"?%?load15%><br?/>??
- <%:hostname%>:?<%=hostname%>??
- </p>??
- </div>??
- <div?id="menubar">??
- <h2?class="navigation"><a?id="navigation"?name="navigation"><%:navigation?Navigation%></a></h2>??
- <ul?id="mainmenu"?class="dropdowns">??
- <%-??
- local?function?submenu(prefix,?node)??
- if?not?node.nodes?or?node.hidden?then??
- ??????????return?false??
- ?????end??
- ?????local?index?=?{}??
- ?????local?count?=?0??
- ?????for?k,?n?in?pairs(node.nodes)? ??????????if?n.title?and?n.target?then??
- ???????????????table.insert(index,?{name=k,?order=n.order?or?100})??
- ???????????????count?=?count?+?1??
- ??????????end??
- ?????table.sort(index,?function(a,?b)?return?a.order?<?b.order?end)??
- if?count?>?0?then??
- %>??
- <ul?id="submenu_<%=string.gsub(string.gsub(prefix,?"/",?"_"),?"^_(.-)_$",?"%1")%>">??
- <%-??
- for?j,?v?in?pairs(index)?do??
- ???????????????if?#v.name?>?0?then??
- ????????????????????local?nnode?=?node.nodes[v.name]??
- ????????????????????local?href?=?controller?..?prefix?..?v.name?..?"/"??
- ????????????????????href?=?(nnode.query)?and?href?..?luci.http.build_querystring(nnode.query)?or?href??
- ??????????????????????
- ????????????????????if?nnode.nodes?then??
- ?????????????????????????for?k1,?n1?in?pairs(nnode.nodes)? ??????????????????????????????href?=?"#"??
- ???????????????????????????
- ?????????????????????????end??
- ????????????????????end???????
- %>??
- <li><a<%?if?nnode._menu_selected?then?%>?class="active"<%end%>?href="<%=luci.util.pcdata(href)%>"><%=nnode.title%></a><%-??
- submenu(prefix?..?v.name?..?"/",?nnode)??
- %></li>??
- ???????????????end??
- ??????????end??
- </ul>??
- <%??
- end??
- if?cattree?and?cattree.nodes?then??
- ??????????table.insert(index,?order=node.order? ??????????node?=?cattree.nodes[k.name]??
- if?node.title?and?node.target?and?not?node.hidden?then??
- ???????????????local?href?=?controller.."/"..category.."/"..k.name.."/"??
- ???????????????href?=?(k.query)?and?href?..?luci.http.build_querystring(k.query)? ?????????????????
- ??????????????? ????????????????????if?n1.title?and?n1.target?then??
- ?????????????????????????href?=?"?#"??
- ????????????????????end??
- ???????????????end???????
- if?node._menu_selected?then?%>?class="preactive"<%end%>?href="<%=href%>"><%=node.title%></a><%??
- submenu("/"?..?category?..?"/"?..?k.name?..?"/",?node)??
- %></li><%?end??
- </ul>??
- <ul?id="modemenu"><%??
- and?not?node.hidden?then?%>??
- if?request[1]?==?k?then?%>?class="active"<%end%>?href="<%=controller%>/<%=k%>/"><%=node.title%></a></li><%??
- <%??
- if?tree.nodes[category]?and?tree.nodes[category].ucidata?then??
- ?????local?ucic?=?0??
- require("luci.model.uci").cursor():changes())?for?m,?n?in?pairs(l)? ????????????????????ucic?=?ucic?+?1;??
- -%>??
- <ul?id="savemenu"? <li><%?if?ucic?>?0?then?%><a?class="warning"?href="<%=controller%>/<%=category%>/uci/changes/"><%:unsavedchanges%>:?<%=ucic%></a><%??
- submenu("/"?..?category?..?"/uci/",?tree.nodes[category].nodes["uci"])??
- else?-%>??
- <a?href="#"?mce_href="#"><%:changes%>:?0</a><%?end?-%>??
- </li>??
- </ul><%?end?%>??
- <div?class="clear"></div>??
- </div>??
- <div?id="maincontent">??
3:?model?业务处理和页面生成简介
????我认为model?的业务处理和?html?生成,是?luci?框架的精华,但是想用好它,最终扩展定义自己的页面也是最难的,但是一旦定义好了,后面的工作就会轻松高效简介统一,不失为一种好的解决方案。但是它又有缺点,就是写页面虽然统一,但是不够灵活。
下面以?SimpleForm为例,讲解一下。
具体文件?*/luci/model/cbi/passwd.lua
f?=?SimpleForm("password",?translate("a_s_changepw"),?translate("a_s_changepw1"))??--调用SimpleForm?页面??当然还是?I18N?从中捣乱,看上去没那么直观,不理他?
pw1=f:field(Value,"pw1",translate("password"))?--??SimpleForm?里面加一个?field???至于?SimpleForm??和?fiemd?是什么,一会去看?SimpleForm?页面去?
pw1.rmempty=false?--?把?SimpleForm的?rmempty?为不显示??后面就不做注释了?应该看得懂了?
pw2?=?f:field(Value,?"pw2",?translate("confirmation"))?
pw2.rmempty?=?false?
function?pw2.validate(self,?value,?section)?
?????return?pw1:formvalue(section)?==?value?and?value?
end?
function?f.handle(self,?state,?data)?
?????if???state?==?FORM_VALID???then?????--这个就是业务处理了??你懂得??呵呵?
??????????local?stat?=?luci.sys.user.setpasswd("admin",?data.pw1)?==?0??--?root?-->?admin?????
??????????if?stat?then?
???????????????f.message?=?translate("a_s_changepw_changed")?
??????????else?
???????????????f.errmessage?=?translate("unknownerror")?
??????????end?
??????????
??????????data.pw1?=?nil?
??????????data.pw2?=?nil?
?????end?
?????return?true?
end?
return?f
说明:(?simpleForm??位于?view/cbi???下面,可以研究一下,各个元素是如何定义的?)
现在在给一个小例子:
以.*/luci/model?/cbi/admin_system/version_manage.lua?为例,介绍一下?luci?中?web?页面?lua?代码?
??6?local?h?=?loadfile("/usr/local/luci/help.lua")?
??7?if?h?then?
??8?????h()?
??9?end?
10?local?help_txt?=?help_info?and??help_info.version?
加载帮助帮助文件help.lua,?关于?loadfile()?的用法可以查看?lua?的手册?(?我还没完全弄明白,先用了?)?
help_txt?是一个全局变量?
12?appadmin_path?=?"/usr/local/appadmin/bin/"?
定义一个全局变量,其实跟功能跟宏一样,定义appadmin?的绝对路径?
14?versionlist?=?{}?
15?
16?function?getline?(s)?
.........?
32?end?
33?
34?function?get_versionlist()?
.........?
68?end?
69?
70?versionlist?=?get_versionlist()?
定义一个全局变量和两个函数,并初始化此变量?
接下来就是和最终展现的Web?页面直接相关的代码了,大部分都是对?luci?封装好的一些?html?控件(代码)的使用和扩展。?luci??封装好的?html?控件?
类可以在以下文件查看:./host/usr/lib/lua/luci/cbi.lua?
71?m?=?SimpleForm("version",?translate("版本管理?"))?
72?m.submit?=?false?
73?m.reset?=?false?
74?m.help?=?help_txt?and?true?or?false?
75?m.helptxt?=?help_txt?or?""?
使用了一个SimpleForm?的控件,?SimpleForm?实际上对应一个?html?表单,是整个页面最大的?"?容器?"?,本页面内的绝大部分控件都处于?SimpleForm?内?
,是它的子控件?。我知道的可以做>?页面最大?"?容器?"?的控件还有一个?Map,?但它需要?./host/etc/config/?目录下的一个配置文件,我没有使用。?
submit?reset是?luci?默认就封装好的一个属性,分别控制?html?表单的?"?提交?""?重置?"?按钮?;help?helptxt?是我扩充的表单属性,分别控制?web?页面的?
"帮助?"?功能和帮助内容。关于控件属?
性的意义、实现和扩充可以按以下步骤进行:?
????在文件./host/usr/lib/lua/luci/cbi.lua?中查找控件名?SimpleForm,??然后可以找到以下行?664?????self.template?=?"cbi/simpleform"?这?
表明SimpleForm?的?html?模版文件为?./host/usr/lib/lua/luci/view/cbi?/simpleform.htm?,通过研究?simpleform.htm?文件内容可以知道各属性的?
功能以及模版中使用lua?代码的方法,然后可以按类似的方法添加自定义的?
属性。?
77?s?=?m:section(Table,?versionlist)?
新建了一个section,section?内定义了一个表格类,?versionlist?是与其相关的变量(?lua?的所有变量都可归类于?table?类型?)?
与Table?关联的?table?变量应该是这种结构的:?
t?=?{?
????row1?=?{column1?=?"xxx",?column2?=?"xxx",?....?},?
????row2?=?{column1?=?"xxx",?
????row3?=?{column1?=?"xxx",?
????row4?=?{column1?=?"xxx",?
}?
然后定义Table?的列控件?
79?enable?=?s:option(DummyValue,?"_enabled",?translate("软件状态?"))?
83?appid??=?s:option(DummyValue,?"_appid",?translate("软件版本?"))?
84?appname?=?s:option(DummyValue,?"_appname",?translate("软件名称?"))?
DummyValue是只读的文本框,只输出不输入。?Value?是单行文本框,可输出也可输入。?Flag?是一个?checkbox,值为?"1"?时被选中,为?"0"?时未选中。?
ListValue是列表框?...?具体的用法可?
以看./host/usr/lib/lua/luci?/model/cbi/?下的文件(?find?./host/usr/lib/lua/luci/model/cbi/?-name?"*.lua"?|xargs?grep?
"ListValue")?
对于table?内普通的字符串类的值,只需要把列控件的?id?(括号内第二个值,如?"_appid"?)定义为?table?内对应的变量名(比如?column1?)?
对于非变通字符串类的值,或者为字符串但需要进行一定的处理然后再显示的值,可以按以下方法显示:定义该控件的cfgvalue?函数属性?
127?????newinfo?=?up_s:option(TextValue,?"_newifo",?translate("新版本信息?"))?
128?????newinfo.readonly?=?true?
129?????newinfo.rows?=?11?
130?????newinfo.cfgvalue?=?function(self,?section)?
131?????????local?t?=?string.gsub(info,?"Archive:[^/n]*",?"")?
132?????????return?t?
133?????end?
定义cfgvalue?后,?luci?的处理函数会调用此函数为此控件赋值,(传入的?section?参数值为?row1/row2/row3等,当处理到?row?几时值就为?row?几?)?
对于DummyValue?等只输出不输入的类,还有一种赋值方法:?控件实例名(如?enable).value?=?xxx?
对于有输入的控件Value?等,??.value?方法赋值在处理输入里会有一些问题,有什么问题以及如何解决可以做实验试试??,?也许是我使用方法不对造?
成的?
对有输入控件的处理有两种方法:?
1?定义控件的?.write?属性?
????这种方法对处理比较独立的输入(与其它控件输入关系不大)比较适用?
88?up_s?=?m:section(SimpleSection)?
89?up_version?=?up_s:option(Button,?"_up_version",?translate("上传新版本?"))?
90?up_version.onlybutton?=?true?
91?up_version.align?=?"right"?
92?up_version.inputstyle?=?"save"?
93?up_version.write?=?function(self,?section)?
94?????luci.http.redirect(luci.dispatcher.build_url("admin",?"version_manage",?"upload"))
95?end?
ps:只有当?Value?的?rmempty?==?false?时,?Value?输入为空也会触发?write?函数?,??需要对?rmemtpy?显示赋值为false?(?xx.rmempty?=?false)?
4:?view?下面的?html?简介
这个是最好理解的??例:passwd.htm
<%+header%>
<h2><a?id="content"?name="content"><%:system%></a></h2>
<h3><%:reboot%></h3>
<p><%:a_s_reboot1%></p>
<%-
local?c?=?require("luci.model.uci").cursor():changes()
if?c?and?next(c)?then
-%>
???????<p?class="warning"><%:a_s_reboot_u%></p>
end
if?not?reboot?then
<p><a?href="<%=controller%>/admin/system/reboot?reboot=1"><%:a_s_reboot_do%></a></p>
<%-?else?-%>
<p><%:a_s_reboot_running%></p>
<script?type="text/javascript">setTimeout("location='<%=controller%>/admin'",?60000)</script>
<%-?end?-%>
<%+footer%>
<%+header%>?<%+footer%>??加载公用的头部和尾部
<%?lua?code%>
<%:i18n%>
<%lua?code%>
<%=lua?变量?%>