编写 ACF 视图
最基本的形式,视图仅仅是一种显示操作结果的方式。在实践中,视图可以用于显示结果、处理 HTML 表单、启动其他操作、在同一页面上组合多个操作、提供动态交互,或以上所有功能的组合。
视图基础
视图是由 haserl 加载的 Lua 服务器页面 (.lsp) 文件。该文件可以包含 HTML 和 LUA 的组合(以及任何其他可以在网页上的内容,即 javascript)。lsp 文件必须存储在特定的文件位置,才能被 acf_www-controller.lua 模块加载。
根据 haserl 文档,lsp 文件被解析以查找和执行任何 Lua 代码。Lua 代码必须用 <% %> 或较旧的 <? ?> 标记括起来。在解析 lsp 文件并执行 Lua 代码时,生成的文本通过套接字输出到 Web 浏览器。
视图输入
由于视图仅仅是向用户显示数据的一种手段,因此它不应直接访问任何控制器、模型或全局变量。视图的输入分为两类
参数
每个 html 视图页面都传递四个参数。它们通常按如下方式访问
<? local data, viewlibrary, page_info, session = ... ?>
- form - 这是执行的操作返回的表。
- viewlibrary - 如下所述
- page_info - 包含有关当前页面信息的表,例如控制器和操作的名称。
- session - 用户会话表。此表包含有关当前用户、权限和命令结果的信息。
库
视图可以访问所有常用的 Lua 库,尽管有些库并非设计为供视图使用。有两个库专门设计用于视图中
- viewlibrary - 此库作为参数传递给视图。此库中的函数是视图被允许与 MVC self 变量交互的唯一方式。目前,该库仅包含一个函数 - dispatch_component
- viewfunctions - 此库包含许多视图使用的常用函数。应尽可能使用它来显示 cfe 项目和表单,以保持兼容性。
模板
ACF 使用模板在所有视图上显示常见的应用程序信息。 acf_www-controller 模块在显示视图之前搜索合适的模板文件。如果找到模板,则会显示该模板,并且它将使用 haserl 加载和显示视图。标准模板将显示页眉、菜单、页脚等。如果您不希望将标准模板用于您的视图,则必须定义一个将要加载的模板。要从模板中启动您的视图
<? local viewtable, viewlibrary, page_info, session = ... local func = haserl.loadfile(pageinfo.viewfile) func (viewtable, viewlibrary, page_info, session) ?>
常用视图
为了简化开发,有几个常用的视图可用于任何控制器。
- debug-html.lsp - 在开发期间用于显示视图参数。
- filedetails-html.lsp - 显示一个表单,允许用户直接编辑文件。
- form-html.lsp - 显示一个基本表单,不带字段排序。
- startstop-html.lsp - 显示“启动”、“停止”和“重启”按钮以及先前操作的结果。按钮根据进程状态禁用。
- status-html.lsp - 显示进程的基本状态。
- expert-html.lsp - 显示状态和启动停止组件,并使用 filedetails-html.lsp 编辑配置文件。
常用视图可以通过两种方式使用。第一种是使用指向常用视图的符号链接,而不是 lsp 文件。常用视图将处理整个显示。请记住,相对路径是基于安装位置,而不是工作目录。
ln -s ../filedetails-html.lsp logfiles-view-html.lsp
另一种方法是从您的视图中使用 haserl 加载常用视图。这允许视图显示常用视图以及其他材料。请记住,绝对路径是基于安装位置,而不是工作目录。
<? local form, viewlibrary, page_info, session = ... local pattern = string.gsub(page_info.prefix..page_info.controller, "[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1") local func = haserl.loadfile(page_info.viewfile:gsub(pattern..".*$", "/") .. "filedetails-html.lsp") func(form, viewlibrary, page_info, session) ?>
链接和命令
视图可能包含指向其他操作的链接。例如,列表视图可以包含指向可以对该列表元素执行的各种操作的链接。当链接指向具有自己视图的操作时,不需要特殊处理。当链接到命令操作时,即重定向到引用页而不是具有自己的视图的操作,视图必须考虑如何显示命令结果。命令的结果存储在 session.actionresult 中。引用视图应处理并清除此会话数据,否则它将保留在会话中,可能显示在另一个页面上。viewfunctions displaycommandresults 函数可用于显示和清除这些结果。
高级
在视图开发中还有一些高级概念。
Javascript
ACF 应用程序主要设计用于服务器端生成静态 HTML 页面。为了允许客户端交互,某些页面使用 Javascript。Javascript 代码包含在 lsp 文件的开头附近,可能包含 Lua 代码(将在将页面传输到浏览器之前在服务器上运行)。由于使用了模板,因此很难在页面标头中包含 Javascript 代码。但是,Javascript 初始化代码可以放置在页面上的任何位置,并且在浏览器遇到它时将运行。因此,在大多数情况下,将代码包含在 lsp 文件中不是问题。有关示例,请参见 openssl-html.lsp、tinydns-edit-html.lsp 和 tinydns-view-html.lsp。
组件
组件是 ACF 的一项高级功能,允许视图启动另一个操作并显示结果。该功能基于 Ruby 的 render_component 和 render_component_as_string 函数,但仅允许从视图内部使用。要启动组件,请使用 viewlibrary 中的 dispatch_component 函数。
local dispatch_component = function(str, clientdata, suppress_view)
- str - 包含前缀、控制器和/或操作的字符串。该字符串从右到左解析,任何缺失的元素都假定与当前操作相同。例如,“expert”指的是与此操作相同的控制器中的 expert 操作。
- clientdata - 要传递给操作的 clientdata 表。
- suppress_view - 一个标志,指示 dispatch 函数调用操作但不显示其视图。
- 返回 viewtable - 操作返回的表。
视图可以简单地调度一个 suppress_view 为 false 或未定义的组件,并允许组件操作在视图中显示自身。在显示组件时,dispatch 函数不会显示模板,否则您会看到嵌套模板。或者,视图可以调度一个 suppress_view 为 true 的组件。由于 dispatch_component 函数返回 viewtable,因此视图可以随后显示或按其认为合适的方式使用组件结果。
组件表单
当视图包含显示表单的组件时,可能需要特殊处理。如果组件包含表单提交按钮,则该按钮应指向组件的操作,而不是当前操作。此外,当表单被处理时,浏览器应重定向到原始操作,以便表单再次显示为组件。最后,表单处理的结果必须存储在某处(在会话中),以便在表单作为组件重新加载时显示。此功能在 form-html.lsp 文件(以及许多其他文件)和控制器 redirect_to_referrer 函数中实现。父视图中不需要特殊代码,但组件视图必须正确设置其表单操作。
无操作的视图
dispatch 函数将允许用户启动一个操作,即使没有匹配的操作函数,甚至没有控制器,只要该操作有特定的视图文件即可。这允许创建仅启动组件的视图,以及为同一操作创建多个视图。视图将接收 clientdata 作为其第一个参数,而不是操作结果。
tinydns-edit-html.lsp 就是一个例子,其中控制器中没有 edit 函数。此视图仅调用 editfile 操作作为具有抑制视图的组件,并使用 javascript 显示结果。如果用户按下“保存”按钮,则再次启动 edit 视图,并将其 clientdata 传递给 editfile 操作。结果是一个新操作,而无需修改控制器。另一种选择是将表单操作指向 editfile 操作。editfile 中的 redirect_to_referrer 函数将导致再次启动 edit 视图,然后 editfile 的调度将从会话中读取结果。此方法看起来相同,但由于重定向而稍慢。