| 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
 |