-
Notifications
You must be signed in to change notification settings - Fork 7
/
gov_form_base.py
127 lines (91 loc) · 4.11 KB
/
gov_form_base.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from flask import render_template
from markupsafe import Markup
from govuk_frontend_wtf.main import merger
class GovFormBase(object):
"""Collection of helpers
These are mixed into the WTForms classes which we are subclassing
to provide extra functionality.
Some of our subclasses then extend these base utilities for their
specific use cases
"""
def __call__(self, field, **kwargs):
return self.render(self.map_gov_params(field, **kwargs))
def map_gov_params(self, field, **kwargs):
"""Map WTForms' html params to govuk macros
Taking WTForms' output, we need to map it to a params dict
which matches the structure that the govuk macros are expecting
"""
params = {
"id": kwargs["id"],
"name": field.name,
"label": {"text": field.label.text},
"attributes": {},
"hint": {"text": field.description},
}
if "value" in kwargs:
params["value"] = kwargs["value"]
del kwargs["value"]
# Not all form elements have a type so guard against it not existing
if "type" in kwargs:
params["type"] = kwargs["type"]
del kwargs["type"]
# Remove items that we've already used from the kwargs
del kwargs["id"]
if "items" in kwargs:
del kwargs["items"]
# Merge in any extra params passed in from the template layer
if "params" in kwargs:
params = self.merge_params(params, kwargs["params"])
# And then remove it, to make sure it doesn't make it's way into the attributes below
del kwargs["params"]
# Map error messages
if field.errors:
params["errorMessage"] = {"text": field.errors[0]}
# And then Merge any remaining attributes directly to the attributes param
# This catches anything set in the more traditional WTForms manner
# i.e. directly as kwargs passed into the field when it's rendered
params["attributes"] = self.merge_params(params["attributes"], kwargs)
# Map attributes such as required="True" to required="required"
for key, value in params["attributes"].items():
if value is True:
params["attributes"][key] = key
return params
def merge_params(self, a, b):
return merger.merge(a, b)
def render(self, params):
return Markup(render_template(self.template, params=params))
class GovIterableBase(GovFormBase):
def __call__(self, field, **kwargs):
kwargs.setdefault("id", field.id)
if "required" not in kwargs and "required" in getattr(field, "flags", []):
kwargs["required"] = True
kwargs["items"] = []
# This field is constructed as an iterable of subfields
for subfield in field:
item = {"text": subfield.label.text, "value": subfield._value()}
if getattr(subfield, "checked", subfield.data):
item["checked"] = True
kwargs["items"].append(item)
return super().__call__(field, **kwargs)
def map_gov_params(self, field, **kwargs):
"""Completely override the params mapping for this input type
It bears little resemblance to that of a normal field
because these fields are effectively collections of
fields wrapped in an iterable
"""
params = {
"name": field.name,
"items": kwargs["items"],
"hint": {"text": field.description},
}
# Merge in any extra params passed in from the template layer
if "params" in kwargs:
# Merge items individually as otherwise the merge will append new ones
if "items" in kwargs["params"]:
for index, item in enumerate(kwargs["params"]["items"]):
item = self.merge_params(params["items"][index], item)
del kwargs["params"]["items"]
params = self.merge_params(params, kwargs["params"])
if field.errors:
params["errorMessage"] = {"text": field.errors[0]}
return params