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