Skip to content

Commit

Permalink
Fix some widget param mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
ahosgood committed Aug 20, 2024
1 parent 44273cd commit af930cd
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 155 deletions.
2 changes: 1 addition & 1 deletion test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from flask import Flask
from jinja2 import ChoiceLoader, PackageLoader
from tna_frontend_jinja.wtforms.widgets import WTFormsHelpers
from tna_frontend_jinja.wtforms.helpers import WTFormsHelpers

from .components import bp as components_bp
from .forms import bp as forms_bp
Expand Down
30 changes: 23 additions & 7 deletions test/forms/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,26 @@
SubmitField,
TextAreaField,
)
from wtforms.validators import Email, InputRequired, Length
from wtforms.validators import InputRequired, Length


class ExampleForm(FlaskForm):
email_address = StringField(
"Email address",
username = StringField(
"Username",
widget=TnaTextInput(),
validators=[
InputRequired(message="Enter an email address"),
Length(
max=256, message="Email address must be 256 characters or fewer"
),
Email(
message="Enter an email address in the correct format, like [email protected]"
),
],
description="We’ll only use this to send you a receipt",
)
password = StringField(
"Password",
validators=[
InputRequired(message="Enter a password"),
],
widget=TnaPasswordInput(),
)
remember = BooleanField(
Expand All @@ -51,29 +51,45 @@ class ExampleForm(FlaskForm):
)
shopping = SelectMultipleField(
"Shopping list",
validators=[
InputRequired(message="Select an item"),
],
choices=[("cpp", "C++"), ("py", "Python"), ("text", "Plain Text")],
widget=TnaCheckboxesInput(),
)
day = RadioField(
"Day",
choices=[("mon", "Monday"), ("tue", "Tuesday"), ("wed", "Wednesday")],
validators=[
InputRequired(message="Select a day"),
],
widget=TnaRadioInput(),
)
birthday = DateField(
"Birthday",
validators=[
InputRequired(message="Enter a date"),
],
widget=TnaDateInput(),
)
message = TextAreaField(
"Message",
validators=[
InputRequired(message="Enter a message"),
],
widget=TnaTextArea(),
)
order = SelectField(
"Order",
choices=[
("", "None"),
("date", "Date"),
("relevance", "Relevance"),
("popularity", "Popularity"),
],
validators=[
InputRequired(message="Select an order"),
],
widget=TnaSelect(),
)

Expand All @@ -84,5 +100,5 @@ class ExampleForm(FlaskForm):
def index():
form = ExampleForm()
if form.validate_on_submit():
return redirect(url_for("forms.index"))
return redirect(url_for("forms.index", status="Success"))
return render_template("example-form.html", form=form)
4 changes: 1 addition & 3 deletions test/forms/test-templates/example-form.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ <h1 class="tna-heading-xl">Example form</h1>
<form action="" method="post" novalidate>
{{ form.csrf_token }}

{{ form.email_address(params={
{{ form.username(params={
'headingLevel': 2,
'type': 'email',
'autofill': 'email',
'spellcheck': False
}) }}

Expand Down
6 changes: 3 additions & 3 deletions test/templates/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

@bp.route("/base")
def base():
params = request.args.get("params")
context = json.loads(params) if params else {}
return render_template("layouts/base.html", context=context)
params_str = request.args.get("params")
params = json.loads(params_str) if params_str else {}
return render_template("layouts/base.html", context=params)
71 changes: 71 additions & 0 deletions tna_frontend_jinja/wtforms/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from deepmerge import Merger

merger = Merger(
# pass in a list of tuple, with the
# strategies you are looking to apply
# to each type.
[(list, ["append"]), (dict, ["merge"])],
# next, choose the fallback strategies,
# applied to all other types:
["override"],
# finally, choose the strategies in
# the case where the types conflict:
["override"],
)


def flatten_errors(errors, prefix="", id_map={}):
"""Return list of errors from form errors."""
error_list = []
if isinstance(errors, dict):
for key, value in errors.items():
# Recurse to handle subforms.
if key in id_map:
key = id_map[key]
error_list += flatten_errors(
value, prefix=f"{prefix}{key}-", id_map=id_map
)
elif isinstance(errors, list) and isinstance(errors[0], dict):
for idx, error in enumerate(errors):
error_list += flatten_errors(
error, prefix=f"{prefix}{idx}-", id_map=id_map
)
elif isinstance(errors, list):
error_list.append(
{"text": errors[0], "href": "#{}".format(prefix.rstrip("-"))}
)
else:
error_list.append(
{"text": errors, "href": "#{}".format(prefix.rstrip("-"))}
)
return error_list


def wtforms_errors(form, params={}):
wtforms_params = {"title": "There is a problem", "items": []}

id_map = {}
for field_name in form._fields.keys():
field = getattr(form, field_name, None)
if field and hasattr(field, "id"):
id_map[field_name] = field.id

wtforms_params["items"] = flatten_errors(form.errors, id_map=id_map)

return merger.merge(wtforms_params, params)


class WTFormsHelpers(object):
"""WTForms helpers
Register some template helpers to allow developers to
map WTForms elements to the GOV.UK jinja macros
"""

def __init__(self, app=None):
self.app = app
if app is not None:
self.init_app(app)

def init_app(self, app):
app.add_template_global(wtforms_errors)
Loading

0 comments on commit af930cd

Please sign in to comment.