编写 ACF 视图

出自 Alpine Linux

最基本的形式,视图仅仅是一种显示操作结果的方式。在实践中,视图可以用于显示结果、处理 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.lsptinydns-edit-html.lsptinydns-view-html.lsp

组件

组件是 ACF 的一项高级功能,允许视图启动另一个操作并显示结果。该功能基于 Ruby 的 render_componentrender_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 的调度将从会话中读取结果。此方法看起来相同,但由于重定向而稍慢。