Here's a quick overview of how to use the
opencore.nui.formhandler.octopus decorator to handle complex form
submissions as either synchronous or asynchronous (i.e. AJAX) HTTP
requests.


- your form should have a form action submit to a view that delegates
  directly to a view method (by using 'attribute=methodname' in your
  browser:page ZCML tag).

- the method that the form submits to should be decorated by the
  opencore.nui.formhandler.octopus function.

- octopus expects to find a form element named "task"; this tells the
  machinery what it's doing.  usually you would set name="task" on all
  of the form's submit buttons; the value of each button will then
  tell the octopus what to do.

- the task value depends on some magic formatting.  it should contain
  an underscore ("_"); the piece before the underscore specifies the
  'target', the piece after the underscore specifies the 'action'.
  the octopus decorator extracts this information and eventually
  passes it back to the decorated method.

- once it knows that the target of the action is, the octopus will
  look through the form for any form fields that start with the target
  name followed by an underscore.  so if the target ends up being
  'unicorn', then the octopus would also discover add'l form fields
  called 'unicorn_name', 'unicorn_color', and 'unicorn_saddlesize'.
  it extracts these values from the form and puts them into a 'fields'
  value, which also gets passed in to the decorated method.

- if you have a 'task' that has a value that starts with 'batch', this
  tells the octopus that it should be acting on a set of items, not
  just a single target.  'batch' should be immediately followed by a
  colon (':') and the name of the form field from which the list of
  targets can be retrieved.  the octopus will check through the form
  for any additional field values related to each separate target,
  passing these in as a list in the 'fields' argument of the decorated
  method.

  for example, consider the following two buttons:

  <button type="submit" name="task"
          value="batch:deletes_remove-members"
          class="oc-button" >remove members</button>
  
  <button type="submit" name="task"
          value="batch:roles_set-roles"
          class="oc-button" >set roles</button>

  the first button triggers the 'remove-members' action, and the list
  of members to remove is in the 'deletes' form field.

  the second button triggers the 'set-roles' action, and the list of
  members for which to set the roles is available from the request in
  the 'roles' form field.

- if you want to do something asynchronously, then you would construct
  a request with the form fields as described above, but you'd add a
  'mode' form field with the value 'async'.  this causes zope to
  return a data structure with info about the results, rather than
  rendering a full page for the browser.  it's up to the template to
  update itself based on the returned data, although i think there's
  already some JS infrastructure in place to help with this.

- When your task action is "update", you should return a JSON object
  that looks like the following.

{'id1': 
  {'html': '<div>thing</div>',
   'effects': 'highlight'
  },
'id2': 
  {'html': '<div>thing2</div>',
   'effects': 'highlight'
  }
}

  There is a (deprecated) short form of this; the example below is
  precisely equivalent to the above:

{'id1': '<div>thing</div>',
 'id2': '<div>thing2</div>'}

 * 'id' is the id of a DOM element to be replaced.
 * 'html' is a snippet of HTML to be inserted in place of 'id'.
 * 'effects' is a list of flashy javascript effects to apply. Right
    now it can be 'highlight' or nothing.
