0001"""
0002Form Options Helpers
0003"""
0004# Last synced with Rails copy at Revision 6057 on Feb 7th, 2007.
0005# Purposely left out a few redundant options_for_collection stuff.
0006
0007from webhelpers.util import html_escape
0008
0009def options_for_select(container, selected=None):
0010    """
0011    Creates select options from a container (list, tuple, dict)
0012    
0013    Accepts a container (list, tuple, dict) and returns a string of option tags. Given a container where the 
0014    elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
0015    the "firsts" as option text. Dicts are turned into this form automatically, so the keys become "firsts" and values
0016    become lasts. If ``selected`` is specified, the matching "last" or element will get the selected option-tag.
0017    ``Selected`` may also be an array of values to be selected when using a multiple select.
0018    
0019    Examples (call, result)::
0020    
0021        >>> options_for_select([["Dollar", "$"], ["Kroner", "DKK"]])
0022        '<option value="$">Dollar</option>\\n<option value="DKK">Kroner</option>'
0023        >>> options_for_select([ "VISA", "MasterCard" ], "MasterCard")
0024        '<option value="VISA">VISA</option>\\n<option value="MasterCard" selected="selected">MasterCard</option>'
0025        >>> options_for_select(dict(Basic="$20", Plus="$40"), "$40")
0026        '<option value="$40" selected="selected">Plus</option>\\n<option value="$20">Basic</option>'
0027        >>> options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
0028        '<option value="VISA" selected="selected">VISA</option>\\n<option value="MasterCard">MasterCard</option>\\n<option value="Discover" selected="selected">Discover</option>'
0029
0030    Note: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
0031    """
0032    if hasattr(container, 'values'):
0033        container = container.items()
0034
0035    if not isinstance(selected, (list, tuple)):
0036        selected = (selected,)
0037
0038    options = []
0039
0040    for elem in container:
0041        if isinstance(elem, (list, tuple)):
0042            name, value = elem
0043            n = html_escape(name)
0044            v = html_escape(value)
0045        else :
0046            name = value = elem
0047            n = v = html_escape(elem)
0048
0049        #TODO: run timeit for this against content_tag('option', n, value=v, selected=value in selected)
0050        if value in selected:
0051            options.append('<option value="%s" selected="selected">%s</option>' % (v, n))
0052        else :
0053            options.append('<option value="%s">%s</option>' % (v, n))
0054    return "\n".join(options)
0055
0056def options_for_select_from_objects(container, name_attr, value_attr=None, selected=None):
0057    """
0058    Create select options from objects in a container
0059    
0060    Returns a string of option tags that have been compiled by iterating over the ``container`` and assigning the
0061    the result of a call to the ``value_attr`` as the option value and the ``name_attr`` as the option text.
0062    If ``selected`` is specified, the element returning a match on ``value_attr`` will get the selected option tag.
0063    
0064    NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
0065    """
0066    if value_attr:
0067        def make_elem(elem):
0068            return getattr(elem, name_attr), getattr(elem, value_attr)
0069    else :
0070        def make_elem(elem):
0071            return getattr(elem, name_attr)
0072
0073    return options_for_select([make_elem(x) for x in container], selected)
0074
0075def options_for_select_from_dicts(container, name_key, value_key=None, selected=None):
0076    """
0077    Create select options from dicts in a container
0078    
0079    Returns a string of option tags that have been compiled by iterating over the ``container`` and assigning the
0080    the result of a call to the ``value_key`` as the option value and the ``name_attr`` as the option text.
0081    If ``selected`` is specified, the element returning a match on ``value_key`` will get the selected option tag.
0082    
0083    NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
0084    """
0085    if value_key:
0086        def make_elem(elem):
0087            return elem[name_key], elem[value_key]
0088    else:
0089        def make_elem(elem):
0090            return elem[name_key]
0091
0092    return options_for_select([make_elem(x) for x in container], selected)
0093
0094__all__ = ['options_for_select', 'options_for_select_from_objects', 'options_for_select_from_dicts']