Commits

Mike Orr committed 1416a38

Add field() helper and NL, BR constants.

Comments (0)

Files changed (1)

webhelpers/html/tags.py

 import urllib
 import urlparse
 
+from webhelpers import containers
 from webhelpers.html import escape, HTML, literal, url_escape
 
 __all__ = [
            "text", "textarea", "hidden", "file", "password", 
            "checkbox", "radio", "submit",
            "select", "Options", "Option",
-           "ModelTags",
+           "ModelTags", "field",
            # hyperlinks
            "link_to", "link_to_if", "link_to_unless",
            # Table tags
            "th_sortable",
            # Other non-form tags
-           "ol", "ul", "image",
+           "ol", "ul", "image", "BR",
            # Head tags
            "stylesheet_link", "javascript_link", "auto_discovery_link",
            # Utility functions
            "convert_boolean_attrs",
            ]
 
+NL = literal("\n")
+BR = literal("<br />\n")
 
 def form(url, method="post", multipart=False, **attrs):
     """An open tag for a form that will submit to ``url``.
        else:
            opt = HTML.option(opt.label, value=opt.value)
        html_options.append(opt)
-    return HTML.select(
-        "\n", 
-        literal("\n").join(html_options),
-        "\n",
-        **attrs)
+    return HTML.select(NL, NL.join(html_options), NL, **attrs)
 
 
 class ModelTags(object):
         """Iterate the label element of each pair."""
         return (x.label for x in self)
 
+def field(label, required, widget, hint=None, error=None, **attrs):
+    """A simple formatter for form fields.
+
+    >>> field("LABEL", True, "WIDGET")
+    literal(u'<div class="field">\\n<label><span class="required">LABEL&nbsp;*</span>\\n<div class="field-body">WIDGET</div></label>\\n</div>')
+    >>> field("LABEL", False, text("notes"))
+    literal(u'<div class="field">\\n<label><span class="not-required">LABEL</span>\\n<div class="field-body"><input name="notes" type="text" /></div></label>\\n</div>')
+    >>> field("LABEL", True, text("notes"), "HINT", "ERROR", id="my-id")
+    literal(u'<div class="field" id="my-id">\\n<label><span class="required">LABEL&nbsp;*</span>\\n<div class="field-body"><span class="error-message">ERROR</span><br />\\n<input name="notes" type="text" /><br />\\n<div class="hint">HINT</div></div></label>\\n</div>')
+
+    Here's a sample stylesheet to accompany the fields:
+
+    =====
+    .field {
+        margin-top: 1em;
+        }
+    .required {
+        color: red;
+        font-weight: bold;
+        }
+    .field-body {
+        margin-left: 1em;
+        }
+    .error-message {
+        color: #cc0000;
+        background-color: #ffeeee;
+        font-size: large;
+        font-weight: bold;
+        font-style: italic;
+        padding: 4px;
+        }
+    .hint {
+        color: #006400;
+        font-style: italic;
+        }
+    =====
+    """
+    if required:
+        label_span = HTML.span(label, literal("&nbsp;*"), class_="required")
+    else:
+        label_span = HTML.span(label, class_="not-required")
+    body = []
+    if error:
+        body.append(HTML.span(error, class_="error-message"))
+        body.append(BR)
+    body.append(widget)
+    if hint:
+        body.append(BR)
+        body.append(HTML.div(hint, class_="hint"))
+    return HTML.div(
+        "\n",
+        HTML.label(label_span,
+            "\n",
+            HTML.div(c=body, class_="field-body"),
+            ),
+        "\n",
+        class_="field", **attrs)
+
+def form_legend(**attrs):
+    """Return a span containing standard form instructions.
+
+    Currently it just explains that "*" means the field is required.
+
+    >>> form_legend()
+    literal(u'<span><span class="required">*</span> = required</span>')
+    >>> form_legend(style="font-size: x-small")
+    literal(u'<span style="font-size: x-small"><span class="required">*</span> = required</span>')
+    """
+    return HTML.span(
+        HTML.span("*", class_="required"),
+        " = required",
+        **attrs)
+
+
 #### Hyperlink tags
 
 def link_to(label, url='', **attrs):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.