webmcp
view framework/env/ui/form.lua @ 117:82c1daccd7cf
Default to "lua" and "luac" binaries in Makefile.options
| author | jbe | 
|---|---|
| date | Thu Jul 10 00:27:22 2014 +0200 (2014-07-10) | 
| parents | ca88032cb37c | 
| children | 32ec28229bb5 | 
 line source
     1 --[[--
     2 ui.form{
     3   record      = record,       -- optional record to be used 
     4   read_only   = read_only,    -- set to true, if form should be read-only (no submit button)
     5   file_upload = file_upload,  -- must be set to true, if form contains file upload element
     6   external    = external,     -- external URL to be used as HTML form action
     7   module      = module,       -- module name to be used for HTML form action
     8   view        = view,         -- view name   to be used for HTML form action
     9   action      = action,       -- action name to be used for HTML form action
    10   routing = {
    11     default = {           -- default routing for called action
    12       mode   = mode,      -- "forward" or "redirect"
    13       module = module,    -- optional module name, defaults to current module
    14       view   = view,      -- view name
    15       id     = id,        -- optional id to be passed to the view
    16       params = params,    -- optional params to be passed to the view
    17       anchor = anchor     -- optional anchor for URL
    18     },
    19     ok    = { ... },      -- routing when "ok"    is returned by the called action
    20     error = { ... },      -- routing when "error" is returned by the called action
    21     ...   = { ... }       -- routing when "..."   is returned by the called action
    22   },
    23   partial = {             -- parameters for partial loading, see below
    24     module = module,
    25     view   = view,
    26     id     = id,
    27     params = params,
    28     target = target
    29   },
    30   content = function()
    31     ...                   -- code creating the contents of the form
    32   end
    33 }
    35 This functions creates a web form, which encloses the content created by the given 'content' function. When a 'record' is given, ui.field.* helper functions will be able to automatically determine field values by using the given record. If 'read_only' is set to true, then a call of ui.submit{...} will be ignored, and ui.field.* helper functions will behave differently.
    37 When passing a table as "partial" argument, AND if partial loading has been enabled by calling ui.enable_partial_loading(), then ui._partial_load_js is
    38 used to create an onsubmit event. The "partial" setting table is passed to ui._partial_load_js as first argument. See ui._partial_load_js(...) for
    39 further documentation.
    41 --]]--
    43 local function prepare_routing_params(params, routing, default_module)
    44   local routing_default_given = false
    45   if routing then
    46     for status, settings in pairs(routing) do
    47       if status == "default" then
    48         routing_default_given = true
    49       end
    50       local module = settings.module or default_module or request.get_module()
    51       assert(settings.mode, "No mode specified in routing entry.")
    52       assert(settings.view, "No view specified in routing entry.")
    53       params["_webmcp_routing." .. status .. ".mode"]   = settings.mode
    54       params["_webmcp_routing." .. status .. ".module"] = module
    55       params["_webmcp_routing." .. status .. ".view"]   = settings.view
    56       params["_webmcp_routing." .. status .. ".id"]     = settings.id
    57       params["_webmcp_routing." .. status .. ".anchor"] = settings.anchor
    58       if settings.params then
    59         for key, value in pairs(settings.params) do
    60           params["_webmcp_routing." .. status .. ".params." .. key] = value
    61         end
    62       end
    63     end
    64   end
    65   if not routing_default_given then
    66     params["_webmcp_routing.default.mode"]   = "forward"
    67     params["_webmcp_routing.default.module"] = request.get_module()
    68     params["_webmcp_routing.default.view"]   = request.get_view()
    69   end
    70   return params
    71 end
    73 function ui.form(args)
    74   local args = args or {}
    75   local slot_state = slot.get_state_table()
    76   local old_record      = slot_state.form_record
    77   local old_readonly    = slot_state.form_readonly
    78   local old_file_upload = slot_state.form_file_upload
    79   slot_state.form_record = args.record
    80   if args.readonly then
    81     slot_state.form_readonly = true
    82     ui.container{ attr = args.attr, content = args.content }
    83   else
    84     slot_state.form_readonly = false
    85     local params = table.new(args.params)
    86     prepare_routing_params(params, args.routing, args.module)
    87     params._webmcp_csrf_secret = request.get_csrf_secret()
    88     local attr = table.new(args.attr)
    89     if attr.enctype=="multipart/form-data" or args.file_upload then
    90       slot_state.form_file_upload = true
    91       if attr.enctype == nil then
    92         attr.enctype = "multipart/form-data"
    93       end
    94     end
    95     attr.action = encode.url{
    96       external  = args.external,
    97       module    = args.module or request.get_module(),
    98       view      = args.view,
    99       action    = args.action,
   100     }
   101     attr.method = args.method and string.upper(args.method) or "POST"
   102     if ui.is_partial_loading_enabled() and args.partial then
   103       attr.onsubmit = slot.use_temporary(function()
   104         local partial_mode = "form_normal"
   105         if args.action then
   106           partial_mode = "form_action"
   107           slot.put(
   108             'var element; ',
   109             'var formElements = []; ',
   110             'for (var i=0; i<this.elements.length; i++) { ',
   111               'formElements[formElements.length] = this.elements[i]; ',
   112             '} ',
   113             'for (i=0; i<formElements.length; i++) { ',
   114               'element = formElements[i]; ',
   115               'if (element.name.search(/^_webmcp_routing\\./) >= 0) { ',
   116                 'element.parentNode.removeChild(element); ',
   117               '} ',
   118             '}'
   119           )
   120           local routing_params = {}
   121           prepare_routing_params(
   122             routing_params,
   123             args.partial.routing,
   124             args.partial.module
   125           )
   126           for key, value in pairs(routing_params) do
   127             slot.put(
   128               ' ',
   129               'element = document.createElement("input"); ',
   130               'element.setAttribute("type", "hidden"); ',
   131               'element.setAttribute("name", ', encode.json(key), '); ',
   132               'element.setAttribute("value", ', encode.json(value), '); ',
   133               'this.appendChild(element);'
   134             )
   135           end
   136           slot.put(' ')
   137         end
   138         slot.put(ui._partial_load_js(args.partial, partial_mode))
   139       end)
   140     end
   141     if slot_state.form_opened then
   142       error("Cannot open a non-readonly form inside a non-readonly form.")
   143     end
   144     slot_state.form_opened = true
   145     ui.tag {
   146       tag     = "form",
   147       attr    = attr,
   148       content = function()
   149         if args.id then
   150           ui.hidden_field{ name = "_webmcp_id", value = args.id }
   151         end
   152         for key, value in pairs(params) do
   153           ui.hidden_field{ name = key, value = value }
   154         end
   155         if args.content then
   156           args.content()
   157         end
   158       end
   159     }
   160     slot_state.form_opened = false
   161   end
   162   slot_state.form_file_upload = old_file_upload
   163   slot_state.form_readonly    = old_readonly
   164   slot_state.form_record      = old_record
   165 end
