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