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