| rev | line source | 
| jbe/bsw@0 | 1 --[[-- | 
| jbe/bsw@0 | 2 ui.form{ | 
| jbe/bsw@0 | 3   record    = record,     -- optional record to be used | 
| jbe/bsw@0 | 4   read_only = read_only,  -- set to true, if form should be read-only (no submit button) | 
| jbe/bsw@0 | 5   external  = external,   -- external URL to be used as HTML form action | 
| jbe/bsw@0 | 6   module    = module,     -- module name to be used for HTML form action | 
| jbe/bsw@0 | 7   view      = view,       -- view name   to be used for HTML form action | 
| jbe/bsw@0 | 8   action    = action,     -- action name to be used for HTML form action | 
| jbe/bsw@0 | 9   routing = { | 
| jbe/bsw@0 | 10     default = {           -- default routing for called action | 
| jbe/bsw@0 | 11       mode   = mode,      -- "forward" or "redirect" | 
| jbe/bsw@0 | 12       module = module,    -- optional module name, defaults to current module | 
| jbe/bsw@0 | 13       view   = view,      -- view name | 
| jbe/bsw@0 | 14       id     = id,        -- optional id to be passed to the view | 
| jbe/bsw@0 | 15       params = params     -- optional params to be passed to the view | 
| jbe/bsw@0 | 16     }, | 
| jbe/bsw@0 | 17     ok    = { ... },      -- routing when "ok"    is returned by the called action | 
| jbe/bsw@0 | 18     error = { ... },      -- routing when "error" is returned by the called action | 
| jbe/bsw@0 | 19     ...   = { ... }       -- routing when "..."   is returned by the called action | 
| jbe@12 | 20   }, | 
| jbe@12 | 21   partial   = {           -- parameters for partial loading, see below | 
| jbe@12 | 22     module = module, | 
| jbe@12 | 23     view   = view, | 
| jbe@12 | 24     id     = id, | 
| jbe@12 | 25     params = params, | 
| jbe@12 | 26     target = target | 
| jbe@12 | 27   }, | 
| jbe/bsw@0 | 28   content = function() | 
| jbe/bsw@0 | 29     ...                   -- code creating the contents of the form | 
| jbe/bsw@0 | 30   end | 
| jbe/bsw@0 | 31 } | 
| jbe/bsw@0 | 32 | 
| jbe/bsw@0 | 33 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. | 
| jbe/bsw@0 | 34 | 
| jbe@12 | 35 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 | 
| jbe@12 | 36 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 | 
| jbe@12 | 37 further documentation. | 
| jbe@12 | 38 | 
| jbe/bsw@0 | 39 --]]-- | 
| jbe/bsw@0 | 40 | 
| jbe/bsw@11 | 41 local function prepare_routing_params(params, routing, default_module) | 
| jbe/bsw@11 | 42   local routing_default_given = false | 
| jbe/bsw@11 | 43   if routing then | 
| jbe/bsw@11 | 44     for status, settings in pairs(routing) do | 
| jbe/bsw@11 | 45       if status == "default" then | 
| jbe/bsw@11 | 46         routing_default_given = true | 
| jbe/bsw@11 | 47       end | 
| jbe/bsw@11 | 48       local module = settings.module or default_module or request.get_module() | 
| jbe/bsw@11 | 49       assert(settings.mode, "No mode specified in routing entry.") | 
| jbe/bsw@11 | 50       assert(settings.view, "No view specified in routing entry.") | 
| jbe/bsw@11 | 51       params["_webmcp_routing." .. status .. ".mode"]   = settings.mode | 
| jbe/bsw@11 | 52       params["_webmcp_routing." .. status .. ".module"] = module | 
| jbe/bsw@11 | 53       params["_webmcp_routing." .. status .. ".view"]   = settings.view | 
| jbe/bsw@11 | 54       params["_webmcp_routing." .. status .. ".id"]     = settings.id | 
| jbe/bsw@11 | 55       if settings.params then | 
| jbe/bsw@11 | 56         for key, value in pairs(settings.params) do | 
| jbe/bsw@11 | 57           params["_webmcp_routing." .. status .. ".params." .. key] = value | 
| jbe/bsw@11 | 58         end | 
| jbe/bsw@11 | 59       end | 
| jbe/bsw@11 | 60     end | 
| jbe/bsw@11 | 61   end | 
| jbe/bsw@11 | 62   if not routing_default_given then | 
| jbe/bsw@11 | 63     params["_webmcp_routing.default.mode"]   = "forward" | 
| jbe/bsw@11 | 64     params["_webmcp_routing.default.module"] = request.get_module() | 
| jbe/bsw@11 | 65     params["_webmcp_routing.default.view"]   = request.get_view() | 
| jbe/bsw@11 | 66   end | 
| jbe/bsw@11 | 67   return params | 
| jbe/bsw@11 | 68 end | 
| jbe/bsw@11 | 69 | 
| jbe/bsw@0 | 70 function ui.form(args) | 
| jbe/bsw@0 | 71   local args = args or {} | 
| jbe/bsw@0 | 72   local slot_state = slot.get_state_table() | 
| jbe/bsw@0 | 73   local old_record   = slot_state.form_record | 
| jbe/bsw@0 | 74   local old_readonly = slot_state.form_readonly | 
| jbe/bsw@0 | 75   slot_state.form_record = args.record | 
| jbe/bsw@0 | 76   if args.readonly then | 
| jbe/bsw@0 | 77     slot_state.form_readonly = true | 
| jbe/bsw@0 | 78     ui.container{ attr = args.attr, content = args.content } | 
| jbe/bsw@0 | 79   else | 
| jbe/bsw@0 | 80     slot_state.form_readonly = false | 
| jbe/bsw@0 | 81     local params = table.new(args.params) | 
| jbe/bsw@11 | 82     prepare_routing_params(params, args.routing, args.module) | 
| jbe/bsw@0 | 83     params._webmcp_csrf_secret = request.get_csrf_secret() | 
| jbe/bsw@0 | 84     local attr = table.new(args.attr) | 
| jbe/bsw@0 | 85     attr.action = encode.url{ | 
| jbe/bsw@0 | 86       external  = args.external, | 
| jbe/bsw@0 | 87       module    = args.module or request.get_module(), | 
| jbe/bsw@0 | 88       view      = args.view, | 
| jbe/bsw@0 | 89       action    = args.action, | 
| jbe/bsw@0 | 90     } | 
| jbe/bsw@0 | 91     attr.method = args.method and string.upper(args.method) or "POST" | 
| jbe/bsw@11 | 92     if ui.is_partial_loading_enabled() and args.partial then | 
| jbe/bsw@11 | 93       attr.onsubmit = slot.use_temporary(function() | 
| jbe/bsw@11 | 94         local partial_mode = "form_normal" | 
| jbe/bsw@11 | 95         if args.action then | 
| jbe/bsw@11 | 96           partial_mode = "form_action" | 
| jbe/bsw@11 | 97           slot.put( | 
| jbe/bsw@11 | 98             'var element; ', | 
| jbe/bsw@11 | 99             'var formElements = []; ', | 
| jbe/bsw@11 | 100             'for (var i=0; i<this.elements.length; i++) { ', | 
| jbe/bsw@11 | 101               'formElements[formElements.length] = this.elements[i]; ', | 
| jbe/bsw@11 | 102             '} ', | 
| jbe/bsw@11 | 103             'for (i=0; i<formElements.length; i++) { ', | 
| jbe/bsw@11 | 104               'element = formElements[i]; ', | 
| jbe/bsw@11 | 105               'if (element.name.search(/^_webmcp_routing\\./) >= 0) { ', | 
| jbe/bsw@11 | 106                 'element.parentNode.removeChild(element); ', | 
| jbe/bsw@11 | 107               '} ', | 
| jbe/bsw@11 | 108             '}' | 
| jbe/bsw@11 | 109           ) | 
| jbe/bsw@11 | 110           local routing_params = {} | 
| jbe/bsw@11 | 111           prepare_routing_params( | 
| jbe/bsw@11 | 112             routing_params, | 
| jbe/bsw@11 | 113             args.partial.routing, | 
| jbe/bsw@11 | 114             args.partial.module | 
| jbe/bsw@11 | 115           ) | 
| jbe/bsw@11 | 116           for key, value in pairs(routing_params) do | 
| jbe/bsw@11 | 117             slot.put( | 
| jbe/bsw@11 | 118               ' ', | 
| jbe/bsw@11 | 119               'element = document.createElement("input"); ', | 
| jbe/bsw@11 | 120               'element.setAttribute("type", "hidden"); ', | 
| jbe/bsw@11 | 121               'element.setAttribute("name", ', encode.json(key), '); ', | 
| jbe/bsw@11 | 122               'element.setAttribute("value", ', encode.json(value), '); ', | 
| jbe/bsw@11 | 123               'this.appendChild(element);' | 
| jbe/bsw@11 | 124             ) | 
| jbe/bsw@11 | 125           end | 
| jbe/bsw@11 | 126           slot.put(' ') | 
| jbe/bsw@11 | 127         end | 
| jbe/bsw@11 | 128         slot.put(ui._partial_load_js(args.partial, partial_mode)) | 
| jbe/bsw@11 | 129       end) | 
| jbe/bsw@11 | 130     end | 
| jbe/bsw@0 | 131     if slot_state.form_opened then | 
| jbe/bsw@0 | 132       error("Cannot open a non-readonly form inside a non-readonly form.") | 
| jbe/bsw@0 | 133     end | 
| jbe/bsw@0 | 134     slot_state.form_opened = true | 
| jbe/bsw@0 | 135     ui.tag { | 
| jbe/bsw@0 | 136       tag     = "form", | 
| jbe/bsw@0 | 137       attr    = attr, | 
| jbe/bsw@0 | 138       content = function() | 
| jbe/bsw@0 | 139         if args.id then | 
| jbe/bsw@0 | 140           ui.hidden_field{ name = "_webmcp_id", value = args.id } | 
| jbe/bsw@0 | 141         end | 
| jbe/bsw@0 | 142         for key, value in pairs(params) do | 
| jbe/bsw@0 | 143           ui.hidden_field{ name = key, value = value } | 
| jbe/bsw@0 | 144         end | 
| jbe/bsw@0 | 145         if args.content then | 
| jbe/bsw@0 | 146           args.content() | 
| jbe/bsw@0 | 147         end | 
| jbe/bsw@0 | 148       end | 
| jbe/bsw@0 | 149     } | 
| jbe/bsw@0 | 150     slot_state.form_opened = false | 
| jbe/bsw@0 | 151   end | 
| jbe/bsw@0 | 152   slot_state.form_readonly = old_readonly | 
| jbe/bsw@0 | 153   slot_state.form_record   = old_record | 
| jbe/bsw@0 | 154 end |