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