=====================
Ordered-Select Widget
=====================

The ordered select widget allows you to select one or more values from a set
of given options and sort those options. Unfortunately, HTML does not provide
such a widget as part of its specification, so that the system has to use a
combnation of "option" elements, buttons and Javascript.

As for all widgets, the select widget must provide the new ``IWidget``
interface:

  >>> from zope.interface import verify
  >>> from z3c.form import interfaces
  >>> from z3c.form.browser import orderedselect

  >>> verify.verifyClass(interfaces.IWidget, orderedselect.OrderedSelectWidget)
  True

The widget can be instantiated only using the request:

  >>> from z3c.form.testing import TestRequest
  >>> request = TestRequest()

  >>> widget = orderedselect.OrderedSelectWidget(request)

Before rendering the widget, one has to set the name and id of the widget:

  >>> widget.id = 'widget-id'
  >>> widget.name = 'widget.name'

We also need to register the template for at least the widget and request:

  >>> import zope.component
  >>> from zope.pagetemplate.interfaces import IPageTemplate
  >>> from z3c.form.testing import getPath
  >>> from z3c.form.widget import WidgetTemplateFactory

  >>> zope.component.provideAdapter(
  ...     WidgetTemplateFactory(getPath('orderedselect_input.pt'), 'text/html'),
  ...     (None, None, None, None, interfaces.IOrderedSelectWidget),
  ...     IPageTemplate, name=interfaces.INPUT_MODE)

If we render the widget we get an emtpy widget:

  >>> print widget.render()
  <script type="text/javascript">
  ...
  </script>
  <table border="0" class="ordered-selection-field">
    <tr>
      <td>
        <select id="widget-id-from" name="widget.name.from"
                size="5" multiple="multiple">
        </select>
      </td>
      <td>
        <button name="from2toButton" type="button"
                value=" -&gt;"
                onclick="javascript:from2to('widget-id')">&nbsp;-&gt;</button>
        <br />
        <button name="to2fromButton" type="button"
                value="&lt;- "
                onclick="javascript:to2from('widget-id')">&lt;-&nbsp;</button>
      </td>
      <td>
        <select id="widget-id-to" name="widget.name.to"
                size="5" multiple="multiple">
        </select>
        <input name="widget.name-empty-marker" type="hidden" />
        <span id="widget-id-toDataContainer">
          <script type="text/javascript">
            copyDataForSubmit('widget-id');</script>
        </span>
      </td>
      <td>
        <button name="upButton" type="button" value="^"
                onclick="javascript:moveUp('widget-id')">^</button>
        <br />
        <button name="downButton" type="button" value="v"
                onclick="javascript:moveDown('widget-id')">v</button>
      </td>
    </tr>
  </table>

Let's provide some values for this widget. We can do this by defining a source
providing ``ITerms``. This source uses descriminators wich will fit our setup.

  >>> import zope.schema.interfaces
  >>> from zope.schema.vocabulary import SimpleVocabulary
  >>> import z3c.form.term

  >>> class SelectionTerms(z3c.form.term.Terms):
  ...     def __init__(self, context, request, form, field, widget):
  ...         self.terms = SimpleVocabulary([
  ...              SimpleVocabulary.createTerm(1, 'a', u'A'),
  ...              SimpleVocabulary.createTerm(2, 'b', u'B'),
  ...              SimpleVocabulary.createTerm(3, 'c', u'C')
  ...              ])

  >>> zope.component.provideAdapter(SelectionTerms,
  ...     (None, interfaces.IFormLayer, None, None,
  ...      interfaces.IOrderedSelectWidget) )

Now let's try if we get widget values:

  >>> widget.update()
  >>> print widget.render()
  <script type="text/javascript">
  ...
  </script>
  <table border="0" class="ordered-selection-field">
    <tr>
      <td>
        <select id="widget-id-from" name="widget.name.from"
                size="5" multiple="multiple">
          <option value="a">A</option>
          <option value="b">B</option>
          <option value="c">C</option>
        </select>
      </td>
      ...
    </tr>
  </table>

If we select item "b", then it should be selected:

  >>> widget.value = ['b']
  >>> widget.update()
  >>> print widget.render()
  <script type="text/javascript">
  ...
  </script>
  <table border="0" class="ordered-selection-field">
    <tr>
      <td>
        <select id="widget-id-from" name="widget.name.from"
                size="5" multiple="multiple">
          <option value="a">A</option>
          <option value="b">B</option>
          <option value="c">C</option>
        </select>
      </td>
      ...
      <td>
        <select id="widget-id-to" name="widget.name.to"
                size="5" multiple="multiple">
          <option value="b">B</option>
        </select>
        <input name="widget.name-empty-marker" type="hidden" />
        <span id="widget-id-toDataContainer">
          <script type="text/javascript">
            copyDataForSubmit('widget-id');</script>
        </span>
      </td>
      ...
    </tr>
  </table>

Let's now make sure that we can extract user entered data from a widget:

  >>> widget.request = TestRequest(form={'widget.name': ['c']})
  >>> widget.update()
  >>> widget.extract()
  ['c']

Unfortunately, when nothing is selected, we do not get an empty list sent into
the request, but simply no entry at all. For this we have the empty marker, so
that:

  >>> widget.request = TestRequest(form={'widget.name-empty-marker': '1'})
  >>> widget.update()
  >>> widget.extract()
  []

If nothing is found in the request, the default is returned:

  >>> widget.request = TestRequest()
  >>> widget.update()
  >>> widget.extract()
  <NOVALUE>

Let's now make sure that a bogus value causes extract to return the default as
described by the interface:

  >>> widget.request = TestRequest(form={'widget.name': ['x']})
  >>> widget.update()
  >>> widget.extract()
  <NOVALUE>
