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