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.
author jbe/bsw
date Fri Feb 12 18:40:22 2010 +0100 (2010-02-12)
parents e017c47d43b5
children f3d3203cd2e4
files doc/autodoc-header.htmlpart framework/cgi-bin/webmcp.lua framework/env/encode/url.lua framework/env/ui/__init.lua framework/env/ui/_partial_load_js.lua framework/env/ui/add_partial_param_names.lua framework/env/ui/enable_partial_loading.lua framework/env/ui/form.lua framework/env/ui/is_partial_loading_enabled.lua framework/env/ui/link.lua framework/env/ui/paginate.lua framework/env/ui/partial.lua framework/env/ui/script.lua framework/js/partialload.js libraries/rocketcgi/rocketcgi.lua
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(

Impressum / About Us