webmcp
view framework/env/ui/list.lua @ 2:72860d232f32
Version 1.0.2
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
| author | jbe/bsw | 
|---|---|
| date | Thu Dec 10 12:00:00 2009 +0100 (2009-12-10) | 
| parents | 9fdfb27f8e67 | 
| children | 10275e753a22 | 
 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
    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
