webmcp
changeset 11:d76a8857ba62
Added ui.partial and other functions, which allow partial content replacement using XMLHttpRequests; Image support for ui.link
Also includes following changes:
- Fix for rocketcgi library to accept POST data content-types, which contain additional charset information.
- Support arrays passed as params to encode.url (only for keys ending with "[]")
- Version information changed to "1.0.7"
Documentation for added functions is not yet complete.
Also includes following changes:
- Fix for rocketcgi library to accept POST data content-types, which contain additional charset information.
- Support arrays passed as params to encode.url (only for keys ending with "[]")
- Version information changed to "1.0.7"
Documentation for added functions is not yet complete.
line diff
1.1 --- a/doc/autodoc-header.htmlpart Wed Feb 03 00:57:18 2010 +0100 1.2 +++ b/doc/autodoc-header.htmlpart Fri Feb 12 18:40:22 2010 +0100 1.3 @@ -55,10 +55,10 @@ 1.4 color: #505050; 1.5 } 1.6 </style> 1.7 - <title>WebMCP 1.0.6 Documentation</title> 1.8 + <title>WebMCP 1.0.7 Documentation</title> 1.9 </head> 1.10 <body> 1.11 - <h1>WebMCP 1.0.6 Documentation</h1> 1.12 + <h1>WebMCP 1.0.7 Documentation</h1> 1.13 <p> 1.14 WebMCP is a completely new web development framework, and has not been extensively tested yet. The API might change at any time, but in future releases there will be a list of all changes, which break downward compatibility. 1.15 </p>
2.1 --- a/framework/cgi-bin/webmcp.lua Wed Feb 03 00:57:18 2010 +0100 2.2 +++ b/framework/cgi-bin/webmcp.lua Fri Feb 12 18:40:22 2010 +0100 2.3 @@ -1,6 +1,6 @@ 2.4 #!/usr/bin/env lua 2.5 2.6 -_WEBMCP_VERSION = "1.0.6" 2.7 +_WEBMCP_VERSION = "1.0.7" 2.8 2.9 -- include "../lib/" in search path for libraries 2.10 do 2.11 @@ -388,7 +388,7 @@ 2.12 if not success then 2.13 local errobj = error_info.errobj 2.14 local stacktrace = error_info.stacktrace 2.15 - if not request.get_status() then 2.16 + if not request.get_status() and not request.get_json_request_slots() then 2.17 request.set_status("500 Internal Server Error") 2.18 end 2.19 slot.set_layout('system_error') 2.20 @@ -417,6 +417,10 @@ 2.21 if slot_dump ~= "" then 2.22 redirect_params.tempstore = tempstore.save(slot_dump) 2.23 end 2.24 + local json_request_slots = request.get_json_request_slots() 2.25 + if json_request_slots then 2.26 + redirect_params["_webmcp_json_slots[]"] = json_request_slots 2.27 + end 2.28 cgi.redirect( 2.29 encode.url{ 2.30 base = request.get_absolute_baseurl(),
3.1 --- a/framework/env/encode/url.lua Wed Feb 03 00:57:18 2010 +0100 3.2 +++ b/framework/env/encode/url.lua Fri Feb 12 18:40:22 2010 +0100 3.3 @@ -81,7 +81,14 @@ 3.4 add("_webmcp_id=", encode.url_part(id), "&") 3.5 end 3.6 for key, value in pairs(params) do 3.7 - add(encode.url_part(key), "=", encode.url_part(value), "&") 3.8 + -- TODO: better way to detect arrays? 3.9 + if string.match(key, "%[%]$") then 3.10 + for idx, entry in ipairs(value) do 3.11 + add(encode.url_part(key), "=", encode.url_part(entry), "&") 3.12 + end 3.13 + else 3.14 + add(encode.url_part(key), "=", encode.url_part(value), "&") 3.15 + end 3.16 end 3.17 result[#result] = nil -- remove last '&' or '?' 3.18 end
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/framework/env/ui/__init.lua Fri Feb 12 18:40:22 2010 +0100 4.3 @@ -0,0 +1,2 @@ 4.4 +ui._partial_loading_enabled = false 4.5 +ui._partial_state = nil
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/framework/env/ui/_partial_load_js.lua Fri Feb 12 18:40:22 2010 +0100 5.3 @@ -0,0 +1,93 @@ 5.4 +--[[-- 5.5 +ui._partial_load_js{ 5.6 +} 5.7 + 5.8 +TODO: documentation 5.9 + 5.10 +NOTE: may return nil 5.11 + 5.12 +--]]-- 5.13 + 5.14 +function ui._partial_load_js(args, mode) 5.15 + local args = args or {} 5.16 + local module 5.17 + local view 5.18 + local id 5.19 + local params = {} 5.20 + local target 5.21 + if args.view and args.target then 5.22 + module = args.module 5.23 + view = args.view 5.24 + id = args.id 5.25 + target = args.target 5.26 + elseif not args.view and not args.target then 5.27 + if not ui._partial_state then 5.28 + return nil 5.29 + end 5.30 + module = ui._partial_state.module 5.31 + view = ui._partial_state.view 5.32 + id = ui._partial_state.id 5.33 + target = ui._partial_state.target 5.34 + else 5.35 + error("Unexpected arguments passed to ui._partial_load_js{...}") 5.36 + end 5.37 + 5.38 + if ui._partial_state then 5.39 + if ui._partial_state.params then 5.40 + for key, value in pairs(ui._partial_state.params) do 5.41 + params[key] = value 5.42 + end 5.43 + end 5.44 + for param_name, dummy in pairs(ui._partial_state.param_name_hash) do 5.45 + params[param_name] = cgi.params[param_name] 5.46 + end 5.47 + end 5.48 + if args.params then 5.49 + for key, value in pairs(args.params) do 5.50 + params[key] = value 5.51 + end 5.52 + end 5.53 + local encoded_url = encode.json( 5.54 + encode.url{ 5.55 + module = module, 5.56 + view = view, 5.57 + id = id, 5.58 + params = params 5.59 + } 5.60 + ) 5.61 + 5.62 + if mode == "form_normal" then 5.63 + -- NOTE: action in "action_mode" refers to WebMCP actions, while action 5.64 + -- in "this.action" refers to the action attribute of HTML forms 5.65 + slot.put('this.action = ', encoded_url, '; ') 5.66 + end 5.67 + 5.68 + return slot.use_temporary(function() 5.69 + slot.put( 5.70 + 'partialMultiLoad({', 5.71 + -- mapping: 5.72 + '"trace": "trace", "system_error": "system_error", ', 5.73 + encode.json(target), ': "default" }, ', 5.74 + -- tempLoadingContents: 5.75 + '{}, ', 5.76 + -- failureContents: 5.77 + '"error", ', 5.78 + -- url: 5.79 + (mode == "form_normal" or mode == "form_action") and ( 5.80 + 'this' 5.81 + ) or ( 5.82 + encoded_url 5.83 + ), ', ', 5.84 + -- urlParams: 5.85 + '"_webmcp_json_slots[]=default&_webmcp_json_slots[]=trace&_webmcp_json_slots[]=system_error", ', 5.86 + -- postParams: 5.87 + '{}, ', 5.88 + -- successHandler: 5.89 + 'function() {}, ', 5.90 + -- failureHandler: 5.91 + 'function() {} ', 5.92 + '); ', 5.93 + 'return false;' 5.94 + ) 5.95 + end) 5.96 +end
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/framework/env/ui/add_partial_param_names.lua Fri Feb 12 18:40:22 2010 +0100 6.3 @@ -0,0 +1,16 @@ 6.4 +--[[-- 6.5 +ui.add_partial_param_names( 6.6 + name_list 6.7 +) 6.8 + 6.9 +TODO: documentation 6.10 + 6.11 +--]]-- 6.12 + 6.13 +function ui.add_partial_param_names(name_list) 6.14 + if ui._partial_state then 6.15 + for idx, param_name in ipairs(name_list) do 6.16 + ui._partial_state.param_name_hash[param_name] = true 6.17 + end 6.18 + end 6.19 +end
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/framework/env/ui/enable_partial_loading.lua Fri Feb 12 18:40:22 2010 +0100 7.3 @@ -0,0 +1,11 @@ 7.4 +--[[-- 7.5 +ui.enable_partial_loading() 7.6 + 7.7 +TODO: documentation 7.8 + 7.9 +--]]-- 7.10 + 7.11 +function ui.enable_partial_loading() 7.12 + ui._partial_loading_enabled = true 7.13 + request.force_absolute_baseurl() 7.14 +end
8.1 --- a/framework/env/ui/form.lua Wed Feb 03 00:57:18 2010 +0100 8.2 +++ b/framework/env/ui/form.lua Fri Feb 12 18:40:22 2010 +0100 8.3 @@ -27,6 +27,35 @@ 8.4 8.5 --]]-- 8.6 8.7 +local function prepare_routing_params(params, routing, default_module) 8.8 + local routing_default_given = false 8.9 + if routing then 8.10 + for status, settings in pairs(routing) do 8.11 + if status == "default" then 8.12 + routing_default_given = true 8.13 + end 8.14 + local module = settings.module or default_module or request.get_module() 8.15 + assert(settings.mode, "No mode specified in routing entry.") 8.16 + assert(settings.view, "No view specified in routing entry.") 8.17 + params["_webmcp_routing." .. status .. ".mode"] = settings.mode 8.18 + params["_webmcp_routing." .. status .. ".module"] = module 8.19 + params["_webmcp_routing." .. status .. ".view"] = settings.view 8.20 + params["_webmcp_routing." .. status .. ".id"] = settings.id 8.21 + if settings.params then 8.22 + for key, value in pairs(settings.params) do 8.23 + params["_webmcp_routing." .. status .. ".params." .. key] = value 8.24 + end 8.25 + end 8.26 + end 8.27 + end 8.28 + if not routing_default_given then 8.29 + params["_webmcp_routing.default.mode"] = "forward" 8.30 + params["_webmcp_routing.default.module"] = request.get_module() 8.31 + params["_webmcp_routing.default.view"] = request.get_view() 8.32 + end 8.33 + return params 8.34 +end 8.35 + 8.36 function ui.form(args) 8.37 local args = args or {} 8.38 local slot_state = slot.get_state_table() 8.39 @@ -39,31 +68,7 @@ 8.40 else 8.41 slot_state.form_readonly = false 8.42 local params = table.new(args.params) 8.43 - local routing_default_given = false 8.44 - if args.routing then 8.45 - for status, settings in pairs(args.routing) do 8.46 - if status == "default" then 8.47 - routing_default_given = true 8.48 - end 8.49 - local module = settings.module or args.module or request.get_module() 8.50 - assert(settings.mode, "No mode specified in routing entry.") 8.51 - assert(settings.view, "No view specified in routing entry.") 8.52 - params["_webmcp_routing." .. status .. ".mode"] = settings.mode 8.53 - params["_webmcp_routing." .. status .. ".module"] = module 8.54 - params["_webmcp_routing." .. status .. ".view"] = settings.view 8.55 - params["_webmcp_routing." .. status .. ".id"] = settings.id 8.56 - if settings.params then 8.57 - for key, value in pairs(settings.params) do 8.58 - params["_webmcp_routing." .. status .. ".params." .. key] = value 8.59 - end 8.60 - end 8.61 - end 8.62 - end 8.63 - if not routing_default_given then 8.64 - params["_webmcp_routing.default.mode"] = "forward" 8.65 - params["_webmcp_routing.default.module"] = request.get_module() 8.66 - params["_webmcp_routing.default.view"] = request.get_view() 8.67 - end 8.68 + prepare_routing_params(params, args.routing, args.module) 8.69 params._webmcp_csrf_secret = request.get_csrf_secret() 8.70 local attr = table.new(args.attr) 8.71 attr.action = encode.url{ 8.72 @@ -73,6 +78,45 @@ 8.73 action = args.action, 8.74 } 8.75 attr.method = args.method and string.upper(args.method) or "POST" 8.76 + if ui.is_partial_loading_enabled() and args.partial then 8.77 + attr.onsubmit = slot.use_temporary(function() 8.78 + local partial_mode = "form_normal" 8.79 + if args.action then 8.80 + partial_mode = "form_action" 8.81 + slot.put( 8.82 + 'var element; ', 8.83 + 'var formElements = []; ', 8.84 + 'for (var i=0; i<this.elements.length; i++) { ', 8.85 + 'formElements[formElements.length] = this.elements[i]; ', 8.86 + '} ', 8.87 + 'for (i=0; i<formElements.length; i++) { ', 8.88 + 'element = formElements[i]; ', 8.89 + 'if (element.name.search(/^_webmcp_routing\\./) >= 0) { ', 8.90 + 'element.parentNode.removeChild(element); ', 8.91 + '} ', 8.92 + '}' 8.93 + ) 8.94 + local routing_params = {} 8.95 + prepare_routing_params( 8.96 + routing_params, 8.97 + args.partial.routing, 8.98 + args.partial.module 8.99 + ) 8.100 + for key, value in pairs(routing_params) do 8.101 + slot.put( 8.102 + ' ', 8.103 + 'element = document.createElement("input"); ', 8.104 + 'element.setAttribute("type", "hidden"); ', 8.105 + 'element.setAttribute("name", ', encode.json(key), '); ', 8.106 + 'element.setAttribute("value", ', encode.json(value), '); ', 8.107 + 'this.appendChild(element);' 8.108 + ) 8.109 + end 8.110 + slot.put(' ') 8.111 + end 8.112 + slot.put(ui._partial_load_js(args.partial, partial_mode)) 8.113 + end) 8.114 + end 8.115 if slot_state.form_opened then 8.116 error("Cannot open a non-readonly form inside a non-readonly form.") 8.117 end
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/framework/env/ui/is_partial_loading_enabled.lua Fri Feb 12 18:40:22 2010 +0100 9.3 @@ -0,0 +1,11 @@ 9.4 +--[[-- 9.5 +result = 9.6 +ui.is_partial_loading_enabled() 9.7 + 9.8 +TODO: documentation 9.9 + 9.10 +--]]-- 9.11 + 9.12 +function ui.is_partial_loading_enabled() 9.13 + return ui._partial_loading_enabled 9.14 +end
10.1 --- a/framework/env/ui/link.lua Wed Feb 03 00:57:18 2010 +0100 10.2 +++ b/framework/env/ui/link.lua Fri Feb 12 18:40:22 2010 +0100 10.3 @@ -9,7 +9,13 @@ 10.4 params = params, -- optional parameters to be passed to the view or action 10.5 routing = routing, -- optional routing information for action links, as described for ui.form{...} 10.6 text = text, -- link text 10.7 - content = content -- link content (overrides link text, except for submit buttons for action calls without JavaScript) 10.8 + content = content, -- link content (overrides link text, except for submit buttons for action calls without JavaScript) 10.9 + partial = { -- TODO: documentation 10.10 + module = module, 10.11 + view = view, 10.12 + id = id, 10.13 + params = params 10.14 + } 10.15 } 10.16 10.17 This function inserts a link into the active slot. It may be either an internal application link ('module' given and 'view' or 'action' given), or a link to an external web page ('external' given), or a link to a file in the static file directory of the application ('static' given). 10.18 @@ -21,7 +27,9 @@ 10.19 local content = args.content or args.text 10.20 assert(content, "ui.link{...} needs a text.") 10.21 local function wrapped_content() 10.22 - -- TODO: icon/image 10.23 + if args.image then 10.24 + ui.image(args.image) 10.25 + end 10.26 if type(content) == "function" then 10.27 content() 10.28 else 10.29 @@ -49,6 +57,7 @@ 10.30 id = args.id, 10.31 params = args.params, 10.32 routing = args.routing, 10.33 + partial = args.partial, 10.34 attr = form_attr, 10.35 content = function() 10.36 ui.submit{ text = args.text, attr = args.submit_attr } 10.37 @@ -85,6 +94,9 @@ 10.38 id = args.id, 10.39 params = args.params, 10.40 } 10.41 + if ui.is_partial_loading_enabled() and args.partial then 10.42 + a_attr.onclick = ui._partial_load_js(args.partial) 10.43 + end 10.44 return ui.tag{ tag = "a", attr = a_attr, content = wrapped_content } 10.45 end 10.46 end
11.1 --- a/framework/env/ui/paginate.lua Wed Feb 03 00:57:18 2010 +0100 11.2 +++ b/framework/env/ui/paginate.lua Fri Feb 12 18:40:22 2010 +0100 11.3 @@ -46,13 +46,22 @@ 11.4 if current_page == page then 11.5 attr.class = "active" 11.6 end 11.7 + local partial 11.8 + if ui.is_partial_loading_enabled() then 11.9 + partial = { 11.10 + params = { 11.11 + [name] = tostring(page) 11.12 + } 11.13 + } 11.14 + end 11.15 ui.link{ 11.16 - attr = attr, 11.17 + attr = attr, 11.18 module = request.get_module(), 11.19 view = request.get_view(), 11.20 id = id, 11.21 params = params, 11.22 - text = tostring(page) 11.23 + text = tostring(page), 11.24 + partial = partial 11.25 } 11.26 end 11.27 end
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/framework/env/ui/partial.lua Fri Feb 12 18:40:22 2010 +0100 12.3 @@ -0,0 +1,26 @@ 12.4 +--[[-- 12.5 +ui.partial{ 12.6 + module = 12.7 + view = 12.8 + id = 12.9 + params = 12.10 + target = 12.11 + content = function() 12.12 + ... -- 12.13 + end 12.14 +} 12.15 + 12.16 +TODO: documentation 12.17 + 12.18 +--]]-- 12.19 + 12.20 +function ui.partial(args) 12.21 + local old_state = ui._partial_state 12.22 + ui._partial_state = table.new(args) 12.23 + ui._partial_state.param_name_hash = {} 12.24 + if args.param_names then 12.25 + ui.add_partial_param_names(args.param_names) 12.26 + end 12.27 + args.content() 12.28 + ui._partial_state = old_state 12.29 +end
13.1 --- a/framework/env/ui/script.lua Wed Feb 03 00:57:18 2010 +0100 13.2 +++ b/framework/env/ui/script.lua Fri Feb 12 18:40:22 2010 +0100 13.3 @@ -9,7 +9,7 @@ 13.4 13.5 This function is used to insert a script into the active slot. 13.6 13.7 -WARNING: The given script MUST NOT include two closing square brackets directly followed by a greater-than sign, unless the output is interpreted strictly as XHTML. For string literals this is ensured automatically, if being encoded with encode.json{...}. 13.8 +WARNING: If the script contains two closing square brackets directly followed by a greater-than sign, it will be rejected to avoid ambiguity related to HTML vs. XML parsing. Additional space characters can be added within the program code to avoid occurrence of the character sequence. The function encode.json{...} encodes all string literals in a way that the sequence is not contained. 13.9 13.10 --]]-- 13.11 13.12 @@ -31,19 +31,21 @@ 13.13 if attr.src then 13.14 ui.tag{ tag = "script", attr = attr, content = "" } 13.15 elseif script then 13.16 + local script_string 13.17 + if type(script) == "function" then 13.18 + script_string = slot.use_temporary(script) 13.19 + else 13.20 + script_string = script 13.21 + end 13.22 + if string.find(script_string, "]]>") then 13.23 + error('Script contains character sequence "]]>" and is thus rejected to avoid ambiguity. If this sequence occurs as part of program code, please add additional space characters. If this sequence occurs inside a string literal, please encode one of this characters using the \\uNNNN unicode escape sequence.') 13.24 + end 13.25 ui.tag{ 13.26 tag = "script", 13.27 attr = attr, 13.28 content = function() 13.29 slot.put("/* <![CDATA[ */") 13.30 - local script_string 13.31 - if type(script) == "function" then 13.32 - script_string = slot.use_temporary(script) 13.33 - else 13.34 - script_string = script 13.35 - end 13.36 - -- Using double parenthesis in following command is important 13.37 - slot.put((string.gsub(script_string, "]]>", "]]]]><![CDATA[>"))) 13.38 + slot.put(script_string) 13.39 slot.put("/* ]]> */") 13.40 end 13.41 }
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/framework/js/partialload.js Fri Feb 12 18:40:22 2010 +0100 14.3 @@ -0,0 +1,271 @@ 14.4 + 14.5 +partialload_queue = []; 14.6 +partialload_queueRPos = 0; 14.7 +partialload_queueWPos = 0; 14.8 + 14.9 +function partialload_getFormKeyValuePairs(form) { 14.10 + var result = {}; 14.11 + for (var i=0; i<form.elements.length; i++) { 14.12 + var inputElement = form.elements[i]; 14.13 + var key = inputElement.name; 14.14 + var value = inputElement.value; 14.15 + if (result[key] == null) result[key] = value; 14.16 + else if (typeof(result[key]) == "object") { 14.17 + result[key][result[key].length] = value; 14.18 + } else { 14.19 + result[key] = [result[key], value]; 14.20 + } 14.21 + } 14.22 + return result; 14.23 +} 14.24 + 14.25 +function partialload_encodeFormData(params) { 14.26 + var result = ""; 14.27 + for (var key in params) { 14.28 + var value = params[key]; 14.29 + if (typeof(value) == "string") { 14.30 + if (result != "") result += "&"; 14.31 + result += encodeURIComponent(key) + "=" + encodeURIComponent(value); 14.32 + } else if (typeof(value) == "object") { 14.33 + var i; 14.34 + for (i=0; i<value.length; i++) { 14.35 + if (result != "") result += "&"; 14.36 + result += encodeURIComponent(key) + "=" + encodeURIComponent(value[i]); 14.37 + } 14.38 + } 14.39 + } 14.40 + return result; 14.41 +} 14.42 + 14.43 +function partialload_addFormDataToUrl(url, params) { 14.44 + if (params != null && typeof(params) != "string") { 14.45 + params = partialload_encodeFormData(params); 14.46 + } 14.47 + if (params != null) { 14.48 + if (url.search(/\?/) >= 0) { 14.49 + if (url.search(/&$/) >= 0) { 14.50 + url = url + params; 14.51 + } else { 14.52 + url = url + "&" + params; 14.53 + } 14.54 + } else { 14.55 + url = url + "?" + params; 14.56 + } 14.57 + } 14.58 + return url; 14.59 +} 14.60 + 14.61 +function partialload_mergeEncodedFormData(data1, data2) { 14.62 + if (data2 == null || data2 == "") return data1; 14.63 + if (data1 == null || data1 == "") return data2; 14.64 + return data1 + "&" + data2; 14.65 +} 14.66 + 14.67 +function partialload_startNextRequest() { 14.68 + var entry = partialload_queue[partialload_queueRPos++]; 14.69 + var req = new XMLHttpRequest(); 14.70 + req.open(entry.method, entry.url, true); 14.71 + req.onreadystatechange = function() { 14.72 + if (req.readyState == 4) { 14.73 + if (req.status == 200) { 14.74 + if (entry.successHandler != null) entry.successHandler(req.responseText); 14.75 + } else { 14.76 + if (entry.failureHandler != null) entry.failureHandler(); 14.77 + } 14.78 + if (partialload_queue[partialload_queueRPos]) { 14.79 + partialload_startNextRequest(); 14.80 + } else { 14.81 + partialload_queue = []; 14.82 + partialload_queueRPos = 0; 14.83 + partialload_queueWPos = 0; 14.84 + } 14.85 + } 14.86 + } 14.87 + if (entry.data) { 14.88 + req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 14.89 + } 14.90 + req.send(entry.data); 14.91 +} 14.92 + 14.93 +function queuedHttpRequest( 14.94 + url_or_form, 14.95 + urlParams, 14.96 + postParams, 14.97 + successHandler, 14.98 + failureHandler 14.99 +) { 14.100 + var method; 14.101 + var data = null; 14.102 + if (typeof(postParams) == "string") { 14.103 + data = postParams; 14.104 + } else if (postParams != null) { 14.105 + data = partialload_encodeFormData(postParams); 14.106 + } 14.107 + var url; 14.108 + if (typeof(url_or_form) == "object") { 14.109 + // form element given 14.110 + var form = url_or_form; 14.111 + url = partialload_addFormDataToUrl(form.action, urlParams); 14.112 + var dataFromForm = partialload_encodeFormData( 14.113 + partialload_getFormKeyValuePairs(form) 14.114 + ); 14.115 + if (form.method != null && form.method.search(/^POST$/i) >= 0) { 14.116 + method = "POST"; 14.117 + data = partialload_mergeEncodedFormData(data, dataFromForm); 14.118 + } else { 14.119 + method = (postParams == NULL) ? "GET" : "POST"; 14.120 + url = partialload_addFormDataToUrl(url, dataFromForm); 14.121 + } 14.122 + } else { 14.123 + // URL given 14.124 + url = partialload_addFormDataToUrl(url_or_form, urlParams); 14.125 + if (postParams == null) { 14.126 + method = "GET"; 14.127 + } else { 14.128 + method = "POST"; 14.129 + if (typeof(postParams) == "string") { 14.130 + data = postParams; 14.131 + } else { 14.132 + data = partialload_encodeFormData(postParams); 14.133 + } 14.134 + } 14.135 + } 14.136 + partialload_queue[partialload_queueWPos++] = { 14.137 + method: method, 14.138 + url: url, 14.139 + data: data, 14.140 + successHandler: successHandler, 14.141 + failureHandler: failureHandler 14.142 + }; 14.143 + if (partialload_queueRPos == 0) { 14.144 + partialload_startNextRequest(); 14.145 + } 14.146 +} 14.147 + 14.148 +function setHtmlContent(node, htmlWithScripts) { 14.149 + var uniquePrefix = "placeholder" + Math.floor(Math.random()*10e16) + "_"; 14.150 + var i = 0; 14.151 + var scripts = []; 14.152 + var htmlWithPlaceholders = ""; 14.153 + // NOTE: This function can not handle CDATA blocks at random positions. 14.154 + htmlWithPlaceholders = htmlWithScripts.replace( 14.155 + /<script[^>]*>(.*?)<\/script>/ig, 14.156 + function(all, inside) { 14.157 + scripts[i] = inside; 14.158 + var placeholder = '<span id="' + uniquePrefix + i + '"></span>'; 14.159 + i++; 14.160 + return placeholder; 14.161 + } 14.162 + ) 14.163 + node.innerHTML = htmlWithPlaceholders; 14.164 + var documentWriteBackup = document.write; 14.165 + var documentWritelnBackup = document.writeln; 14.166 + var output; 14.167 + document.write = function(str) { output += str; } 14.168 + document.writeln = function(str) { output += str + "\n"; } 14.169 + for (i=0; i<scripts.length; i++) { 14.170 + var placeholderNode = document.getElementById(uniquePrefix + i); 14.171 + output = ""; 14.172 + eval(scripts[i]); 14.173 + if (output != "") { 14.174 + placeholderNode.innerHTML = output; 14.175 + while (placeholderNode.childNodes.length > 0) { 14.176 + var childNode = placeholderNode.childNodes[0]; 14.177 + placeholderNode.removeChild(childNode); 14.178 + placeholderNode.parentNode.insertBefore(childNode, placeholderNode); 14.179 + } 14.180 + } 14.181 + placeholderNode.parentNode.removeChild(placeholderNode); 14.182 + } 14.183 + document.write = documentWriteBackup; 14.184 + document.writeln = documentWritelnBackup; 14.185 +} 14.186 + 14.187 +function partialLoad( 14.188 + node, 14.189 + tempLoadingContent, 14.190 + failureContent, 14.191 + url_or_form, 14.192 + urlParams, 14.193 + postParams, 14.194 + successHandler, 14.195 + failureHandler 14.196 +) { 14.197 + if (typeof(node) == "string") node = document.getElementById(node); 14.198 + if (tempLoadingContent != null) setHtmlContent(node, tempLoadingContent); 14.199 + queuedHttpRequest( 14.200 + url_or_form, 14.201 + urlParams, 14.202 + postParams, 14.203 + function(response) { 14.204 + setHtmlContent(node, response); 14.205 + if (successHandler != null) successHandler(); 14.206 + }, 14.207 + function() { 14.208 + if (failureContent != null) setHtmlContent(node, failureContent); 14.209 + if (failureHandler != null) failureHandler(); 14.210 + } 14.211 + ); 14.212 +} 14.213 + 14.214 +function partialMultiLoad( 14.215 + mapping, 14.216 + tempLoadingContents, 14.217 + failureContents, 14.218 + url_or_form, 14.219 + urlParams, 14.220 + postParams, 14.221 + successHandler, 14.222 + failureHandler 14.223 +) { 14.224 + if (mapping instanceof Array) { 14.225 + var mappingHash = {} 14.226 + for (var i=0; i<mapping.length; i++) { 14.227 + mappingHash[mapping[i]] = mapping[i]; 14.228 + } 14.229 + mapping = mappingHash; 14.230 + } 14.231 + if (typeof(tempLoadingContents) == "string") { 14.232 + for (var key in mapping) { 14.233 + var node = key; 14.234 + if (typeof(node) == "string") node = document.getElementById(node); 14.235 + setHtmlContent(node, tempLoadingContents); 14.236 + } 14.237 + } else if (tempLoadingContents != null) { 14.238 + for (var key in tempLoadingContents) { 14.239 + var node = key; 14.240 + if (typeof(node) == "string") node = document.getElementById(node); 14.241 + setHtmlContent(node, tempLoadingContents[key]); 14.242 + } 14.243 + } 14.244 + queuedHttpRequest( 14.245 + url_or_form, 14.246 + urlParams, 14.247 + postParams, 14.248 + function(response) { 14.249 + var data = eval("(" + response + ")"); 14.250 + for (var key in mapping) { 14.251 + var node = key; 14.252 + if (typeof(node) == "string") node = document.getElementById(node); 14.253 + setHtmlContent(node, data[mapping[key]]); 14.254 + } 14.255 + if (successHandler != null) successHandler(); 14.256 + }, 14.257 + function() { 14.258 + if (typeof(failureContents) == "string") { 14.259 + for (var key in mapping) { 14.260 + var node = key; 14.261 + if (typeof(node) == "string") node = document.getElementById(node); 14.262 + setHtmlContent(node, failureContents); 14.263 + } 14.264 + } else if (failureContents != null) { 14.265 + for (var key in failureContents) { 14.266 + var node = key; 14.267 + if (typeof(node) == "string") node = document.getElementById(node); 14.268 + setHtmlContent(node, failureContents[key]); 14.269 + } 14.270 + } 14.271 + if (failureHandler != null) failureHandler(); 14.272 + } 14.273 + ); 14.274 +}
15.1 --- a/libraries/rocketcgi/rocketcgi.lua Wed Feb 03 00:57:18 2010 +0100 15.2 +++ b/libraries/rocketcgi/rocketcgi.lua Fri Feb 12 18:40:22 2010 +0100 15.3 @@ -134,7 +134,10 @@ 15.4 end 15.5 end 15.6 15.7 -if post_contenttype == "application/x-www-form-urlencoded" then 15.8 +if post_contenttype and ( 15.9 + post_contenttype == "application/x-www-form-urlencoded" or 15.10 + string.match(post_contenttype, "^application/x%-www%-form%-urlencoded[ ;]") 15.11 +) then 15.12 read_urlencoded_form(post_params, post_data) 15.13 elseif post_contenttype then 15.14 local boundary = string.match(