Skip to content

Commit

Permalink
remove hidden div wrapper for hidden_tag
Browse files Browse the repository at this point in the history
only render hidden fields that exist with hidden_tag
closes #217, closes #193
  • Loading branch information
davidism committed Jul 2, 2016
1 parent d867ada commit 4422227
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 54 deletions.
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']

intersphinx_mapping = {
'wtforms': ('https://wtforms.readthedocs.io/en/latest', None)
}

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down
4 changes: 0 additions & 4 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ WTF_CSRF_SSL_STRICT Strictly protection on SSL. This will check
origin. Default is True.
WTF_CSRF_METHODS CSRF protection on these request methods.
Default is **['POST', 'PUT', 'PATCH']**
WTF_HIDDEN_TAG HTML tag name of the hidden tag wrapper.
Default is **div**
WTF_HIDDEN_TAG_ATTRS HTML tag attributes of the hidden tag wrapper.
Default is **{'style': 'display:none;'}**
======================= ==============================================


Expand Down
16 changes: 8 additions & 8 deletions docs/form.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,14 @@ Flask-WTF also provides Recaptcha support through a :class:`RecaptchaField`::
This comes together with a number of configuration, which you have to
implement them.

===================== =========================================================
RECAPTCHA_PUBLIC_KEY **required** A public key.
RECAPTCHA_PRIVATE_KEY **required** A private key.
RECAPTCHA_API_SERVER **optional** Specify your Recaptcha API server.
RECAPTCHA_PARAMETERS **optional** A dict of JavaScript (api.js) parameters.
RECAPTCHA_DATA_ATTRS **optional** A dict of data attributes options.
https://developers.google.com/recaptcha/docs/display
===================== ==========================================================
======================= ==============================================
RECAPTCHA_PUBLIC_KEY **required** A public key.
RECAPTCHA_PRIVATE_KEY **required** A private key.
RECAPTCHA_API_SERVER **optional** Specify your Recaptcha API server.
RECAPTCHA_PARAMETERS **optional** A dict of JavaScript (api.js) parameters.
RECAPTCHA_DATA_ATTRS **optional** A dict of data attributes options.
https://developers.google.com/recaptcha/docs/display
======================= ==============================================

Example of RECAPTCHA_PARAMETERS, and RECAPTCHA_DATA_ATTRS::

Expand Down
5 changes: 2 additions & 3 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ render this in your template:
<input type="submit" value="Go">
</form>

However, in order to create valid XHTML/HTML the Form class has a method
hidden_tag which renders any hidden fields, including the CSRF field,
inside a hidden DIV tag:
If your form has multiple hidden fields, you can render them in one
block using :meth:`~flask_wtf.FlaskForm.hidden_tag`.

.. sourcecode:: html+jinja

Expand Down
61 changes: 26 additions & 35 deletions flask_wtf/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@

import werkzeug.datastructures
from flask import request, session, current_app
from jinja2 import Markup, escape
from jinja2 import Markup
from wtforms.compat import with_metaclass
from wtforms.ext.csrf.form import SecureForm
from wtforms.fields import HiddenField
from wtforms.form import FormMeta
from wtforms.validators import ValidationError
from wtforms.widgets import HiddenInput
from wtforms.widgets import HiddenInput, SubmitInput

from ._compat import text_type, string_types, FlaskWTFDeprecationWarning
from .csrf import generate_csrf, validate_csrf
Expand All @@ -30,15 +29,6 @@ class _Auto(object):
pass


def _is_hidden(field):
"""Detect if the field is hidden."""
if isinstance(field, HiddenField):
return True
if isinstance(field.widget, HiddenInput):
return True
return False


class FlaskForm(SecureForm):
"""Flask-specific subclass of WTForms :class:`~wtforms.ext.csrf.form.SecureForm` class.
Expand Down Expand Up @@ -132,36 +122,37 @@ def is_submitted(self):
return request and request.method in SUBMIT_METHODS

def hidden_tag(self, *fields):
"""
Wraps hidden fields in a hidden DIV tag, in order to keep XHTML
compliance.
"""Render the form's hidden fields in one call.
.. versionadded:: 0.3
A field is considered hidden if it uses the
:class:`~wtforms.widgets.HiddenInput` widget.
:param fields: list of hidden field names. If not provided will render
all hidden fields, including the CSRF field.
"""
If ``fields`` are given, only render the given fields that
are hidden. If a string is passed, render the field with that
name if it exists.
if not fields:
fields = [f for f in self if _is_hidden(f)]
.. versionchanged:: 0.13
No longer wraps inputs in hidden div.
This is valid HTML 5.
.. versionchanged:: 0.13
Skip passed fields that aren't hidden.
Skip passed names that don't exist.
"""

name = current_app.config.get('WTF_HIDDEN_TAG', 'div')
attrs = current_app.config.get(
'WTF_HIDDEN_TAG_ATTRS', {'style': 'display:none;'})
def hidden_fields(fields):
for f in fields:
if isinstance(f, string_types):
f = getattr(self, f, None)

tag_attrs = u' '.join(
u'%s="%s"' % (escape(k), escape(v)) for k, v in attrs.items())
tag_start = u'<%s %s>' % (escape(name), tag_attrs)
tag_end = u'</%s>' % escape(name)
if f is None or not isinstance(f.widget, HiddenInput):
continue

rv = [tag_start]
for field in fields:
if isinstance(field, string_types):
field = getattr(self, field)
rv.append(text_type(field))
rv.append(tag_end)
yield f

return Markup(u"".join(rv))
return Markup(u'\n'.join(text_type(f) for f in hidden_fields(fields or self)))

def validate_on_submit(self):
"""Call :meth:`validate` only if the form is submitted.
Expand Down
5 changes: 1 addition & 4 deletions tests/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ class TestCSRF(TestCase):
def test_csrf_token(self):

response = self.client.get("/")
snippet = (
'<div style="display:none;">'
'<input id="csrf_token" name="csrf_token" type="hidden" value'
)
snippet = '<input id="csrf_token" name="csrf_token" type="hidden" value'
assert snippet in to_unicode(response.data)

def test_invalid_csrf(self):
Expand Down

0 comments on commit 4422227

Please sign in to comment.