webmcp
diff framework/env/ui/list.lua @ 0:9fdfb27f8e67
Version 1.0.0
author | jbe/bsw |
---|---|
date | Sun Oct 25 12:00:00 2009 +0100 (2009-10-25) |
parents | |
children | 10275e753a22 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/framework/env/ui/list.lua Sun Oct 25 12:00:00 2009 +0100 1.3 @@ -0,0 +1,227 @@ 1.4 +--[[-- 1.5 +ui.list{ 1.6 + label = list_label, -- optional label for the whole list 1.7 + style = style, -- "table", "ulli" or "div" 1.8 + prefix = prefix, -- prefix for HTML field names 1.9 + records = records, -- array of records to be displayed as rows in the list 1.10 + columns = { 1.11 + { 1.12 + label = column_label, -- label for the column 1.13 + label_attr = label_attr, -- table with HTML attributes for the heading cell or div 1.14 + field_attr = field_attr, -- table with HTML attributes for the data cell or div 1.15 + name = name, -- name of the field in each record 1.16 + html_name = html_name, -- optional html-name for writable fields (defaults to name) 1.17 + ui_field_type = ui_field_type, -- name of the ui.field.* function to use 1.18 + ...., -- other options for the given ui.field.* functions 1.19 + format = format, -- name of the format function to be used (if not using ui_field_type) 1.20 + format_options = format_options, -- options to be passed to the format function 1.21 + content = content -- function to output field data per record (ignoring name, format, ...) 1.22 + }, 1.23 + { ... }, 1.24 + ... 1.25 + } 1.26 +} 1.27 + 1.28 +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. 1.29 + 1.30 +--]]-- 1.31 + 1.32 +-- TODO: documentation of the prefix option 1.33 +-- TODO: check short descriptions of fields in documentation 1.34 +-- 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? 1.35 +-- TODO: use field information of record class, if no columns are given 1.36 +-- TODO: callback to set row attr's for a specific row 1.37 + 1.38 +function ui.list(args) 1.39 + local args = args or {} 1.40 + local label = args.label 1.41 + local list_type = args.style or "table" 1.42 + local prefix = args.prefix 1.43 + local records = assert(args.records, "ui.list{...} needs records.") 1.44 + local columns = assert(args.columns, "ui.list{...} needs column definitions.") 1.45 + local outer_attr = table.new(args.attr) 1.46 + local header_existent = false 1.47 + for idx, column in ipairs(columns) do 1.48 + if column.label then 1.49 + header_existent = true 1.50 + break 1.51 + end 1.52 + end 1.53 + local slot_state = slot.get_state_table() 1.54 + local outer_tag, head_tag, head_tag2, label_tag, body_tag, row_tag 1.55 + if list_type == "table" then 1.56 + outer_tag = "table" 1.57 + head_tag = "thead" 1.58 + head_tag2 = "tr" 1.59 + label_tag = "th" 1.60 + body_tag = "tbody" 1.61 + row_tag = "tr" 1.62 + field_tag = "td" 1.63 + elseif list_type == "ulli" then 1.64 + outer_tag = "div" 1.65 + head_tag = "div" 1.66 + label_tag = "div" 1.67 + body_tag = "ul" 1.68 + row_tag = "li" 1.69 + field_tag = "td" 1.70 + elseif list_type == "div" then 1.71 + outer_tag = "div" 1.72 + head_tag = "div" 1.73 + label_tag = "div" 1.74 + body_tag = "div" 1.75 + row_tag = "div" 1.76 + field_tag = "div" 1.77 + else 1.78 + error("Unknown list type specified for ui.list{...}.") 1.79 + end 1.80 + outer_attr.class = outer_attr.class or "ui_list" 1.81 + ui.container{ 1.82 + auto_args = args, 1.83 + content = function() 1.84 + ui.tag{ 1.85 + tag = outer_tag, 1.86 + attr = outer_attr, 1.87 + content = function() 1.88 + if header_existent then 1.89 + ui.tag{ 1.90 + tag = head_tag, 1.91 + attr = { class = "ui_list_head" }, 1.92 + content = function() 1.93 + local function header_content() 1.94 + for idx, column in ipairs(columns) do 1.95 + if column.ui_field_type ~= "hidden" then 1.96 + local label_attr = table.new(column.label_attr) 1.97 + label_attr.class = 1.98 + label_attr.class or { class = "ui_list_label" } 1.99 + ui.tag{ 1.100 + tag = label_tag, 1.101 + attr = label_attr, 1.102 + content = column.label or "" 1.103 + } 1.104 + end 1.105 + end 1.106 + end 1.107 + if head_tag2 then 1.108 + ui.tag{ tag = head_tag2, content = header_content } 1.109 + else 1.110 + header_content() 1.111 + end 1.112 + end 1.113 + } 1.114 + end 1.115 + ui.tag{ 1.116 + tag = body_tag, 1.117 + attr = { class = "ui_list_body" }, 1.118 + content = function() 1.119 + for record_idx, record in ipairs(records) do 1.120 + local row_class 1.121 + if record_idx % 2 == 0 then 1.122 + row_class = "ui_list_row ui_list_even" 1.123 + else 1.124 + row_class = "ui_list_row ui_list_odd" 1.125 + end 1.126 + ui.tag{ 1.127 + tag = row_tag, 1.128 + attr = { class = row_class }, 1.129 + content = function() 1.130 + local old_html_name_prefix, old_form_record 1.131 + if prefix then 1.132 + old_html_name_prefix = slot_state.html_name_prefix 1.133 + old_form_record = slot_state.form_record 1.134 + slot_state.html_name_prefix = prefix .. "[" .. record_idx .. "]" 1.135 + slot_state.form_record = record 1.136 + end 1.137 + local first_column = true 1.138 + for column_idx, column in ipairs(columns) do 1.139 + if column.ui_field_type ~= "hidden" then 1.140 + local field_attr = table.new(column.field_attr) 1.141 + field_attr.class = 1.142 + field_attr.class or { class = "ui_list_field" } 1.143 + local field_content 1.144 + if column.content then 1.145 + field_content = function() 1.146 + return column.content(record) 1.147 + end 1.148 + elseif column.name then 1.149 + if column.ui_field_type then 1.150 + local ui_field_func = ui.field[column.ui_field_type] 1.151 + if not ui_field_func then 1.152 + error('Unknown ui_field_type "' .. column.ui_field_type .. '".') 1.153 + end 1.154 + local ui_field_options = table.new(column) 1.155 + ui_field_options.record = record 1.156 + ui_field_options.label = nil 1.157 + if not prefix and ui_field_options.readonly == nil then 1.158 + ui_field_options.readonly = true 1.159 + end 1.160 + field_content = function() 1.161 + return ui.field[column.ui_field_type](ui_field_options) 1.162 + end 1.163 + elseif column.format then 1.164 + local formatter = format[column.format] 1.165 + if not formatter then 1.166 + error('Unknown format "' .. column.format .. '".') 1.167 + end 1.168 + field_content = formatter( 1.169 + record[column.name], column.format_options 1.170 + ) 1.171 + else 1.172 + field_content = function() 1.173 + return ui.autofield{ 1.174 + record = record, 1.175 + name = column.name, 1.176 + html_name = column.html_name 1.177 + } 1.178 + end 1.179 + end 1.180 + else 1.181 + error("Each column needs either a 'content' or a 'name'.") 1.182 + end 1.183 + local extended_field_content 1.184 + if first_column then 1.185 + first_column = false 1.186 + extended_field_content = function() 1.187 + for column_idx, column in ipairs(columns) do 1.188 + if column.ui_field_type == "hidden" then 1.189 + local ui_field_options = table.new(column) 1.190 + ui_field_options.record = record 1.191 + ui_field_options.label = nil 1.192 + if not prefix and ui_field_options.readonly == nil then 1.193 + ui_field_options.readonly = true 1.194 + end 1.195 + ui.field.hidden(ui_field_options) 1.196 + end 1.197 + end 1.198 + field_content() 1.199 + end 1.200 + else 1.201 + extended_field_content = field_content 1.202 + end 1.203 + ui.tag{ 1.204 + tag = field_tag, 1.205 + attr = field_attr, 1.206 + content = extended_field_content 1.207 + } 1.208 + end 1.209 + end 1.210 + if prefix then 1.211 + slot_state.html_name_prefix = old_html_name_prefix 1.212 + slot_state.form_record = old_form_record 1.213 + end 1.214 + end 1.215 + } 1.216 + end 1.217 + end 1.218 + } 1.219 + end 1.220 + } 1.221 + end 1.222 + } 1.223 + if prefix then 1.224 + -- ui.field.hidden is used instead of ui.hidden_field to suppress output in case of read-only mode. 1.225 + ui.field.hidden{ 1.226 + html_name = prefix .. "[len]", 1.227 + value = #records 1.228 + } 1.229 + end 1.230 +end