webmcp
view framework/env/ui/list.lua @ 3:795b764629ca
Version 1.0.3
Important bugfix related to internal forwards (Bug was introduced by the restriction of views with underscore prefix in Version 1.0.2)
Important bugfix related to internal forwards (Bug was introduced by the restriction of views with underscore prefix in Version 1.0.2)
author | jbe |
---|---|
date | Thu Dec 10 12:00:00 2009 +0100 (2009-12-10) |
parents | 9fdfb27f8e67 |
children | 10275e753a22 |
line source
1 --[[--
2 ui.list{
3 label = list_label, -- optional label for the whole list
4 style = style, -- "table", "ulli" or "div"
5 prefix = prefix, -- prefix for HTML field names
6 records = records, -- array of records to be displayed as rows in the list
7 columns = {
8 {
9 label = column_label, -- label for the column
10 label_attr = label_attr, -- table with HTML attributes for the heading cell or div
11 field_attr = field_attr, -- table with HTML attributes for the data cell or div
12 name = name, -- name of the field in each record
13 html_name = html_name, -- optional html-name for writable fields (defaults to name)
14 ui_field_type = ui_field_type, -- name of the ui.field.* function to use
15 ...., -- other options for the given ui.field.* functions
16 format = format, -- name of the format function to be used (if not using ui_field_type)
17 format_options = format_options, -- options to be passed to the format function
18 content = content -- function to output field data per record (ignoring name, format, ...)
19 },
20 { ... },
21 ...
22 }
23 }
25 This function takes an array of records to be displayed in a list. The whole list may have a label. The style's "table" (for <table>), "ulli" (for <ul><li>) and "div" (just using <div> tags) are supported. For each column several options must be specified.
27 --]]--
29 -- TODO: documentation of the prefix option
30 -- TODO: check short descriptions of fields in documentation
31 -- TODO: field_attr is used for the OUTER html tag's attributes, while attr is used for the INNER html tag's attributes (produced by ui.field.*), is that okay?
32 -- TODO: use field information of record class, if no columns are given
33 -- TODO: callback to set row attr's for a specific row
35 function ui.list(args)
36 local args = args or {}
37 local label = args.label
38 local list_type = args.style or "table"
39 local prefix = args.prefix
40 local records = assert(args.records, "ui.list{...} needs records.")
41 local columns = assert(args.columns, "ui.list{...} needs column definitions.")
42 local outer_attr = table.new(args.attr)
43 local header_existent = false
44 for idx, column in ipairs(columns) do
45 if column.label then
46 header_existent = true
47 break
48 end
49 end
50 local slot_state = slot.get_state_table()
51 local outer_tag, head_tag, head_tag2, label_tag, body_tag, row_tag
52 if list_type == "table" then
53 outer_tag = "table"
54 head_tag = "thead"
55 head_tag2 = "tr"
56 label_tag = "th"
57 body_tag = "tbody"
58 row_tag = "tr"
59 field_tag = "td"
60 elseif list_type == "ulli" then
61 outer_tag = "div"
62 head_tag = "div"
63 label_tag = "div"
64 body_tag = "ul"
65 row_tag = "li"
66 field_tag = "td"
67 elseif list_type == "div" then
68 outer_tag = "div"
69 head_tag = "div"
70 label_tag = "div"
71 body_tag = "div"
72 row_tag = "div"
73 field_tag = "div"
74 else
75 error("Unknown list type specified for ui.list{...}.")
76 end
77 outer_attr.class = outer_attr.class or "ui_list"
78 ui.container{
79 auto_args = args,
80 content = function()
81 ui.tag{
82 tag = outer_tag,
83 attr = outer_attr,
84 content = function()
85 if header_existent then
86 ui.tag{
87 tag = head_tag,
88 attr = { class = "ui_list_head" },
89 content = function()
90 local function header_content()
91 for idx, column in ipairs(columns) do
92 if column.ui_field_type ~= "hidden" then
93 local label_attr = table.new(column.label_attr)
94 label_attr.class =
95 label_attr.class or { class = "ui_list_label" }
96 ui.tag{
97 tag = label_tag,
98 attr = label_attr,
99 content = column.label or ""
100 }
101 end
102 end
103 end
104 if head_tag2 then
105 ui.tag{ tag = head_tag2, content = header_content }
106 else
107 header_content()
108 end
109 end
110 }
111 end
112 ui.tag{
113 tag = body_tag,
114 attr = { class = "ui_list_body" },
115 content = function()
116 for record_idx, record in ipairs(records) do
117 local row_class
118 if record_idx % 2 == 0 then
119 row_class = "ui_list_row ui_list_even"
120 else
121 row_class = "ui_list_row ui_list_odd"
122 end
123 ui.tag{
124 tag = row_tag,
125 attr = { class = row_class },
126 content = function()
127 local old_html_name_prefix, old_form_record
128 if prefix then
129 old_html_name_prefix = slot_state.html_name_prefix
130 old_form_record = slot_state.form_record
131 slot_state.html_name_prefix = prefix .. "[" .. record_idx .. "]"
132 slot_state.form_record = record
133 end
134 local first_column = true
135 for column_idx, column in ipairs(columns) do
136 if column.ui_field_type ~= "hidden" then
137 local field_attr = table.new(column.field_attr)
138 field_attr.class =
139 field_attr.class or { class = "ui_list_field" }
140 local field_content
141 if column.content then
142 field_content = function()
143 return column.content(record)
144 end
145 elseif column.name then
146 if column.ui_field_type then
147 local ui_field_func = ui.field[column.ui_field_type]
148 if not ui_field_func then
149 error('Unknown ui_field_type "' .. column.ui_field_type .. '".')
150 end
151 local ui_field_options = table.new(column)
152 ui_field_options.record = record
153 ui_field_options.label = nil
154 if not prefix and ui_field_options.readonly == nil then
155 ui_field_options.readonly = true
156 end
157 field_content = function()
158 return ui.field[column.ui_field_type](ui_field_options)
159 end
160 elseif column.format then
161 local formatter = format[column.format]
162 if not formatter then
163 error('Unknown format "' .. column.format .. '".')
164 end
165 field_content = formatter(
166 record[column.name], column.format_options
167 )
168 else
169 field_content = function()
170 return ui.autofield{
171 record = record,
172 name = column.name,
173 html_name = column.html_name
174 }
175 end
176 end
177 else
178 error("Each column needs either a 'content' or a 'name'.")
179 end
180 local extended_field_content
181 if first_column then
182 first_column = false
183 extended_field_content = function()
184 for column_idx, column in ipairs(columns) do
185 if column.ui_field_type == "hidden" then
186 local ui_field_options = table.new(column)
187 ui_field_options.record = record
188 ui_field_options.label = nil
189 if not prefix and ui_field_options.readonly == nil then
190 ui_field_options.readonly = true
191 end
192 ui.field.hidden(ui_field_options)
193 end
194 end
195 field_content()
196 end
197 else
198 extended_field_content = field_content
199 end
200 ui.tag{
201 tag = field_tag,
202 attr = field_attr,
203 content = extended_field_content
204 }
205 end
206 end
207 if prefix then
208 slot_state.html_name_prefix = old_html_name_prefix
209 slot_state.form_record = old_form_record
210 end
211 end
212 }
213 end
214 end
215 }
216 end
217 }
218 end
219 }
220 if prefix then
221 -- ui.field.hidden is used instead of ui.hidden_field to suppress output in case of read-only mode.
222 ui.field.hidden{
223 html_name = prefix .. "[len]",
224 value = #records
225 }
226 end
227 end