0001"""
0002Form Tag Helpers
0003"""
0004# Last synced with Rails copy at Revision 6057 on Feb 9th, 2007.
0005
0006import re
0007from urls import confirm_javascript_function
0008from tags import *
0009from webhelpers.util import html_escape
0010
0011def form(url, method="POST", multipart=False, **options):
0012    """
0013    Starts a form tag that points the action to an url. 
0014    
0015    The url options should be given either as a string, or as a ``url()``
0016    function. The method for the form defaults to POST.
0017    
0018    Options:
0019
0020    ``multipart``
0021        If set to True, the enctype is set to "multipart/form-data".
0022    ``method``
0023        The method to use when submitting the form, usually either "GET" or 
0024        "POST". If "PUT", "DELETE", or another verb is used, a hidden input
0025        with name _method is added to simulate the verb over POST.
0026    
0027    """
0028    if multipart:
0029        options["enctype"] = "multipart/form-data"
0030
0031    if callable(url):
0032        url = url()
0033    else:
0034        url = html_escape(url)
0035
0036    method_tag = ""
0037
0038    if method.upper() in ['POST', 'GET']:
0039        options['method'] = method
0040    else:
0041        options['method'] = "POST"
0042        method_tag = tag('input', type="hidden", id="_method", name_="_method",
0043                         value=method)
0044
0045    options["action"] = url
0046    return tag("form", True, **options) + method_tag
0047
0048start_form = form
0049
0050def end_form():
0051    """
0052    Outputs "</form>"
0053    
0054    Example::
0055
0056        >>> end_form()
0057        '</form>'
0058    """
0059    return "</form>"
0060
0061def select(name, option_tags='', **options):
0062    """
0063    Creates a dropdown selection box
0064    
0065    ``option_tags`` is a string containing the option tags for the select box::
0066
0067        >>> select("people", "<option>George</option>")
0068        '<select id="people" name="people"><option>George</option></select>'
0069    
0070    Options:
0071    
0072    * ``multiple`` - If set to true the selection will allow multiple choices.
0073    
0074    """
0075    o = { 'name_': name, 'id': name }
0076    o.update(options)
0077    return content_tag("select", option_tags, **o)
0078
0079def text_field(name, value=None, **options):
0080    """
0081    Creates a standard text field.
0082    
0083    ``value`` is a string, the content of the text field
0084    
0085    Options:
0086    
0087    * ``disabled`` - If set to True, the user will not be able to use this input.
0088    * ``size`` - The number of visible characters that will fit in the input.
0089    * ``maxlength`` - The maximum number of characters that the browser will allow the user to enter.
0090    
0091    Remaining keyword options will be standard HTML options for the tag.
0092    """
0093    o = {'type': 'text', 'name_': name, 'id': name, 'value': value}
0094    o.update(options)
0095    return tag("input", **o)
0096
0097def hidden_field(name, value=None, **options):
0098    """
0099    Creates a hidden field.
0100    
0101    Takes the same options as text_field
0102    """
0103    return text_field(name, value, type="hidden", **options)
0104
0105def file_field(name, value=None, **options):
0106    """
0107    Creates a file upload field.
0108    
0109    If you are using file uploads then you will also need to set the multipart option for the form.
0110
0111    Example::
0112
0113        >>> file_field('myfile')
0114        '<input id="myfile" name="myfile" type="file" />'
0115    """
0116    return text_field(name, value=value, type="file", **options)
0117
0118def password_field(name="password", value=None, **options):
0119    """
0120    Creates a password field
0121    
0122    Takes the same options as text_field
0123    """
0124    return text_field(name, value, type="password", **options)
0125
0126def text_area(name, content='', **options):
0127    """
0128    Creates a text input area.
0129    
0130    Options:
0131    
0132    * ``size`` - A string specifying the dimensions of the textarea.
0133    
0134    Example::
0135    
0136        >>> text_area("body", '', size="25x10")
0137        '<textarea cols="25" id="body" name="body" rows="10"></textarea>'
0138    """
0139    if 'size' in options:
0140        options["cols"], options["rows"] = options["size"].split("x")
0141        del options['size']
0142    o = {'name_': name, 'id': name}
0143    o.update(options)
0144    return content_tag("textarea", content, **o)
0145
0146def check_box(name, value="1", checked=False, **options):
0147    """
0148    Creates a check box.
0149    """
0150    o = {'type': 'checkbox', 'name_': name, 'id': name, 'value': value}
0151    o.update(options)
0152    if checked:
0153        o["checked"] = "checked"
0154    return tag("input", **o)
0155
0156def radio_button(name, value, checked=False, **options):
0157    """Creates a radio button.
0158    
0159    The id of the radio button will be set to the name + value with a _ in
0160    between to ensure its uniqueness.
0161    """
0162    pretty_tag_value = re.sub(r'\s', "_", '%s' % value)
0163    pretty_tag_value = re.sub(r'(?!-)\W', "", pretty_tag_value).lower()
0164    html_options = {'type': 'radio', 'name_': name, 'id': '%s_%s' % (name, pretty_tag_value), 'value': value}
0165    html_options.update(options)
0166    if checked:
0167        html_options["checked"] = "checked"
0168    return tag("input", **html_options)
0169
0170def submit(value="Save changes", name='commit', confirm=None, disable_with=None, **options):
0171    """Creates a submit button with the text ``value`` as the caption.
0172
0173    Options:
0174
0175    * ``confirm`` - A confirm message displayed when the button is clicked.
0176    * ``disable_with`` - The value to be used to rename a disabled version of the submit
0177      button.
0178    """
0179    if confirm:
0180        onclick = options.get('onclick', '')
0181        if onclick.strip() and not onclick.rstrip().endswith(';'):
0182            onclick += ';'
0183        options['onclick'] = "%sreturn %s;" % (onclick, confirm_javascript_function(confirm))
0184
0185    if disable_with:
0186        options["onclick"] = "this.disabled=true;this.value='%s';this.form.submit();%s" % (disable_with, options.get("onclick", ''))
0187    o = {'type': 'submit', 'name_': name, 'value': value }
0188    o.update(options)
0189    return tag("input", **o)
0190
0191#def image_submit(source, **options):
0192#    """Displays an image which when clicked will submit the form"""
0193#    o = {'type': 'image', 'src': image_path_source) }
0194#    o.update(options)
0195#    return tag("input", **o)
0196
0197__all__ = ['form', 'start_form', 'end_form', 'select', 'text_field', 'hidden_field', 'file_field',
0198           'password_field', 'text_area', 'check_box', 'radio_button', 'submit']