@planning-inspectorate/dynamic-forms 1.17.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.releaserc +14 -0
- package/README.md +68 -3
- package/package.json +2 -1
- package/src/components/address/index.njk +1 -18
- package/src/components/address/question.test.js +1 -1
- package/src/components/boolean/index.njk +1 -18
- package/src/components/checkbox/index.njk +1 -19
- package/src/components/date/index.njk +1 -18
- package/src/components/date-period/index.njk +1 -18
- package/src/components/date-time/index.njk +1 -18
- package/src/components/identifier/index.njk +1 -18
- package/src/components/multi-field-input/index.njk +1 -18
- package/src/components/multi-field-input/question.test.js +3 -3
- package/src/components/number-entry/index.njk +1 -18
- package/src/components/radio/index.njk +1 -18
- package/src/components/select/index.njk +1 -18
- package/src/components/single-line-input/index.njk +1 -18
- package/src/components/task-list/index.njk +2 -8
- package/src/components/text-entry/index.njk +1 -18
- package/src/components/text-entry-redact/index.njk +1 -18
- package/src/components/text-entry-redact/question.test.js +4 -4
- package/src/components/unit-option-entry/index.njk +1 -18
- package/src/controller.js +2 -2
- package/src/controller.test.js +5 -5
- package/src/journey/journey.js +7 -7
- package/src/journey/journey.test.js +10 -10
- package/src/middleware/redirect-to-unanswered-question.test.js +1 -1
- package/src/validator/address-validator.js +1 -1
- package/src/validator/address-validator.test.js +1 -5
- package/test/journey.js +2 -2
- package/test/snapshots/add-insurance.html +0 -6
- package/test/snapshots/check-your-answers-not-started.html +0 -3
- package/test/snapshots/check-your-answers-with-answers.html +0 -3
- package/test/snapshots/companions.html +0 -6
- package/test/snapshots/departure-date.html +0 -6
- package/test/snapshots/holiday-activities.html +0 -6
- package/test/snapshots/holiday-arrival.html +0 -6
- package/test/snapshots/holiday-description.html +0 -6
- package/test/snapshots/holiday-destination.html +0 -6
- package/test/snapshots/holiday-period.html +0 -6
- package/test/snapshots/holiday-snack.html +0 -6
- package/test/snapshots/hotel-address.html +0 -6
- package/test/snapshots/luggage-weight-units.html +0 -6
- package/test/snapshots/nights.html +0 -6
- package/test/snapshots/secret-wish.html +0 -6
- package/test/snapshots/travel-class.html +0 -6
- package/test/snapshots/travel-insurance-type.html +0 -6
- package/test/views/layout-check-your-answers.njk +1 -1
- package/test/views/layout-journey.njk +1 -0
- package/test/views/layout-question.njk +0 -2
package/.releaserc
ADDED
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ The functionality for 'check-your-answers' pages can also be useful for generati
|
|
|
21
21
|
|
|
22
22
|
## Requirements
|
|
23
23
|
|
|
24
|
-
To use this package nunjucks must be configured so that the component view files are available, and static assets must be made available for certain components and styling.
|
|
24
|
+
To use this package nunjucks must be configured so that the component view files are available, and static assets must be made available for certain components and styling. Some nunjucks templates are required to correctly render the question pages and task list views.
|
|
25
25
|
|
|
26
26
|
### Nunjucks
|
|
27
27
|
|
|
@@ -67,12 +67,77 @@ The select component can use the [accessible-autocomplete](https://www.npmjs.com
|
|
|
67
67
|
|
|
68
68
|
### Layouts
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
There are two layout files that need to be configured for dynamic-forms: journey and task list.
|
|
71
|
+
|
|
72
|
+
**Journey template**
|
|
73
|
+
|
|
74
|
+
The journey template is used for question pages. It must include a block called `dynQuestionContent`, and a block called `head` (which the default gov.uk template has).
|
|
75
|
+
It should also include the rendering of the errorSummary component. The path to this template is configured via the `journeyTemplate` property on a Journey.
|
|
76
|
+
|
|
77
|
+
e.g.
|
|
78
|
+
|
|
79
|
+
```nunjucks
|
|
80
|
+
{% extends "govuk/template.njk" %}
|
|
81
|
+
|
|
82
|
+
{% block beforeContent %}
|
|
83
|
+
{% if errorSummary %}
|
|
84
|
+
<div class="govuk-grid-row">
|
|
85
|
+
<div class="govuk-grid-column-two-thirds">
|
|
86
|
+
{{ govukErrorSummary({
|
|
87
|
+
titleText: "There is a problem",
|
|
88
|
+
errorList: errorSummary,
|
|
89
|
+
attributes: {"data-cy": "error-wrapper"}
|
|
90
|
+
}) }}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
{% endif %}
|
|
94
|
+
{% endblock %}
|
|
95
|
+
|
|
96
|
+
{% block content %}
|
|
97
|
+
<div class="govuk-grid-row">
|
|
98
|
+
<div class="govuk-grid-column-full">
|
|
99
|
+
<h1 class="govuk-heading-xl">
|
|
100
|
+
{% if pageCaption %}
|
|
101
|
+
<span class="govuk-caption-xl">{{ pageCaption }}</span>
|
|
102
|
+
{% endif %}
|
|
103
|
+
{{ pageHeading }}
|
|
104
|
+
</h1>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
{% block dynQuestionContent %}{% endblock %}
|
|
109
|
+
{% endblock %}
|
|
110
|
+
```
|
|
71
111
|
|
|
72
|
-
|
|
112
|
+
**Task list template**
|
|
113
|
+
|
|
114
|
+
The task list template is used for the task list or "check your answers" page. It must include a block called `dynTaskList`. The path to this template is configured via the `taskListTemplate` property on a Journey.
|
|
115
|
+
|
|
116
|
+
e.g.
|
|
117
|
+
|
|
118
|
+
```nunjucks
|
|
119
|
+
{% extends "govuk/template.njk" %}
|
|
120
|
+
|
|
121
|
+
{% block content %}
|
|
122
|
+
<div class="govuk-grid-row">
|
|
123
|
+
<div class="govuk-grid-column-full">
|
|
124
|
+
<h1 class="govuk-heading-xl">
|
|
125
|
+
{% if pageCaption %}
|
|
126
|
+
<span class="govuk-caption-xl">{{ pageCaption }}</span>
|
|
127
|
+
{% endif %}
|
|
128
|
+
{{ pageHeading }}
|
|
129
|
+
</h1>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
{% block dynTaskList %}{% endblock %}
|
|
134
|
+
{% endblock %}
|
|
135
|
+
```
|
|
73
136
|
|
|
74
137
|
## Usage
|
|
75
138
|
|
|
139
|
+
The test directory includes a very basic journey in `test/journey.js`. This may be a useful guide for setting up a journey and associated questions. Also in `test/questions.test.js` there is a function `createAppWithQuestions` which may be a useful guide for setting up the appropriate controllers and routes for a journey.
|
|
140
|
+
|
|
76
141
|
### Conditions
|
|
77
142
|
|
|
78
143
|
Conditions are used to show/hide questions based on the answers to other questions. There are fluent methods on a Section
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planning-inspectorate/dynamic-forms",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "This package is for building GDS forms using a configuration-based approach.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"@commitlint/cli": "^20.0.0",
|
|
33
33
|
"@commitlint/config-conventional": "^20.0.0",
|
|
34
34
|
"body-parser": "^2.2.0",
|
|
35
|
+
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
35
36
|
"cookie-parser": "^1.4.7",
|
|
36
37
|
"eslint": "^9.29.0",
|
|
37
38
|
"eslint-config-prettier": "^10.1.5",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/input/macro.njk" import govukInput %}
|
|
5
4
|
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
|
|
6
5
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
@@ -11,23 +10,7 @@
|
|
|
11
10
|
{% set county= question.fieldName + "_county" %}
|
|
12
11
|
{% set postcode= question.fieldName + "_postcode" %}
|
|
13
12
|
|
|
14
|
-
{% block
|
|
15
|
-
<div class="govuk-grid-row">
|
|
16
|
-
<div class="govuk-grid-column-two-thirds">
|
|
17
|
-
{% if errorSummary %}
|
|
18
|
-
{{ govukErrorSummary({
|
|
19
|
-
titleText: "There is a problem",
|
|
20
|
-
errorList: errorSummary,
|
|
21
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
22
|
-
}) }}
|
|
23
|
-
{% endif %}
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
{{ super() }}
|
|
28
|
-
{% endblock before_content %}
|
|
29
|
-
|
|
30
|
-
{% block content %}
|
|
13
|
+
{% block dynQuestionContent %}
|
|
31
14
|
<div class="govuk-grid-row">
|
|
32
15
|
<div class="govuk-grid-column-two-thirds">
|
|
33
16
|
<form action="" method="post" novalidate>
|
|
@@ -132,7 +132,7 @@ describe('AddressQuestion', () => {
|
|
|
132
132
|
const model = await question.prepQuestionForRendering(
|
|
133
133
|
{},
|
|
134
134
|
{ getBackLink: mock.fn(), response },
|
|
135
|
-
{ layoutTemplate: 'views/layout-
|
|
135
|
+
{ layoutTemplate: 'views/layout-journey.njk' }
|
|
136
136
|
);
|
|
137
137
|
|
|
138
138
|
assert.strictEqual(model.question.hint, hintText);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/radios/macro.njk" import govukRadios %}
|
|
5
4
|
{% from "govuk/components/checkboxes/macro.njk" import govukCheckboxes %}
|
|
6
5
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
@@ -11,23 +10,7 @@
|
|
|
11
10
|
{% endset %}
|
|
12
11
|
{% endif %}
|
|
13
12
|
|
|
14
|
-
{% block
|
|
15
|
-
<div class="govuk-grid-row">
|
|
16
|
-
<div class="govuk-grid-column-two-thirds">
|
|
17
|
-
{% if errorSummary %}
|
|
18
|
-
{{ govukErrorSummary({
|
|
19
|
-
titleText: "There is a problem",
|
|
20
|
-
errorList: errorSummary,
|
|
21
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
22
|
-
}) }}
|
|
23
|
-
{% endif %}
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
{{ super() }}
|
|
28
|
-
{% endblock before_content %}
|
|
29
|
-
|
|
30
|
-
{% block content %}
|
|
13
|
+
{% block dynQuestionContent %}
|
|
31
14
|
<div class="govuk-grid-row">
|
|
32
15
|
<div class="govuk-grid-column-two-thirds">
|
|
33
16
|
<form action="" method="post" novalidate>
|
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/checkboxes/macro.njk" import govukCheckboxes %}
|
|
5
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
{% block before_content %}
|
|
9
|
-
<div class="govuk-grid-row">
|
|
10
|
-
<div class="govuk-grid-column-two-thirds">
|
|
11
|
-
{% if errorSummary %}
|
|
12
|
-
{{ govukErrorSummary({
|
|
13
|
-
titleText: "There is a problem",
|
|
14
|
-
errorList: errorSummary,
|
|
15
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
16
|
-
}) }}
|
|
17
|
-
{% endif %}
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
{{ super() }}
|
|
22
|
-
{% endblock before_content %}
|
|
23
|
-
|
|
24
|
-
{% block content %}
|
|
6
|
+
{% block dynQuestionContent %}
|
|
25
7
|
<div class="govuk-grid-row">
|
|
26
8
|
<div class="govuk-grid-column-two-thirds">
|
|
27
9
|
<form action="" method="post" novalidate>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/date-input/macro.njk" import govukDateInput %}
|
|
5
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
6
5
|
|
|
@@ -14,23 +13,7 @@
|
|
|
14
13
|
{% endset %}
|
|
15
14
|
{% endif %}
|
|
16
15
|
|
|
17
|
-
{% block
|
|
18
|
-
<div class="govuk-grid-row">
|
|
19
|
-
<div class="govuk-grid-column-two-thirds">
|
|
20
|
-
{% if errorSummary %}
|
|
21
|
-
{{ govukErrorSummary({
|
|
22
|
-
titleText: "There is a problem",
|
|
23
|
-
errorList: errorSummary,
|
|
24
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
25
|
-
}) }}
|
|
26
|
-
{% endif %}
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
{{ super() }}
|
|
31
|
-
{% endblock before_content %}
|
|
32
|
-
|
|
33
|
-
{% block content %}
|
|
16
|
+
{% block dynQuestionContent %}
|
|
34
17
|
<div class="govuk-grid-row">
|
|
35
18
|
<div class="govuk-grid-column-two-thirds">
|
|
36
19
|
<form action="" method="post" novalidate>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/date-input/macro.njk" import govukDateInput %}
|
|
5
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
6
5
|
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
|
|
@@ -20,23 +19,7 @@
|
|
|
20
19
|
{% endset %}
|
|
21
20
|
{% endif %}
|
|
22
21
|
|
|
23
|
-
{% block
|
|
24
|
-
<div class="govuk-grid-row">
|
|
25
|
-
<div class="govuk-grid-column-two-thirds">
|
|
26
|
-
{% if errorSummary %}
|
|
27
|
-
{{ govukErrorSummary({
|
|
28
|
-
titleText: "There is a problem",
|
|
29
|
-
errorList: errorSummary,
|
|
30
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
31
|
-
}) }}
|
|
32
|
-
{% endif %}
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
{{ super() }}
|
|
37
|
-
{% endblock before_content %}
|
|
38
|
-
|
|
39
|
-
{% block content %}
|
|
22
|
+
{% block dynQuestionContent %}
|
|
40
23
|
<div class="govuk-grid-row">
|
|
41
24
|
<div class="govuk-grid-column-two-thirds">
|
|
42
25
|
<form action="" method="post" novalidate>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
5
4
|
{% from "govuk/components/date-input/macro.njk" import govukDateInput %}
|
|
6
5
|
{% from "govuk/components/input/macro.njk" import govukInput %}
|
|
@@ -19,23 +18,7 @@
|
|
|
19
18
|
{% endset %}
|
|
20
19
|
{% endif %}
|
|
21
20
|
|
|
22
|
-
{% block
|
|
23
|
-
<div class="govuk-grid-row">
|
|
24
|
-
<div class="govuk-grid-column-two-thirds">
|
|
25
|
-
{% if errorSummary %}
|
|
26
|
-
{{ govukErrorSummary({
|
|
27
|
-
titleText: "There is a problem",
|
|
28
|
-
errorList: errorSummary,
|
|
29
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
30
|
-
}) }}
|
|
31
|
-
{% endif %}
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
{{ super() }}
|
|
36
|
-
{% endblock before_content %}
|
|
37
|
-
|
|
38
|
-
{% block content %}
|
|
21
|
+
{% block dynQuestionContent %}
|
|
39
22
|
<style {% if cspNonce %}nonce={{ cspNonce }}{% endif %}>
|
|
40
23
|
.pins-select--width-4 {
|
|
41
24
|
min-width: 4.5em !important;
|
|
@@ -1,27 +1,10 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/input/macro.njk" import govukInput %}
|
|
5
4
|
{% from "govuk/components/label/macro.njk" import govukLabel %}
|
|
6
5
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
7
6
|
|
|
8
|
-
{% block
|
|
9
|
-
<div class="govuk-grid-row">
|
|
10
|
-
<div class="govuk-grid-column-two-thirds">
|
|
11
|
-
{% if errorSummary %}
|
|
12
|
-
{{ govukErrorSummary({
|
|
13
|
-
titleText: "There is a problem",
|
|
14
|
-
errorList: errorSummary,
|
|
15
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
16
|
-
}) }}
|
|
17
|
-
{% endif %}
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
{{ super() }}
|
|
22
|
-
{% endblock before_content %}
|
|
23
|
-
|
|
24
|
-
{% block content %}
|
|
7
|
+
{% block dynQuestionContent %}
|
|
25
8
|
<div class="govuk-grid-row">
|
|
26
9
|
<div class="govuk-grid-column-two-thirds">
|
|
27
10
|
<form action="" method="post" novalidate>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/input/macro.njk" import govukInput %}
|
|
5
4
|
{% from "govuk/components/label/macro.njk" import govukLabel %}
|
|
6
5
|
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
|
|
@@ -8,23 +7,7 @@
|
|
|
8
7
|
|
|
9
8
|
{% set inputFields = question.inputFields %}
|
|
10
9
|
|
|
11
|
-
{% block
|
|
12
|
-
<div class="govuk-grid-row">
|
|
13
|
-
<div class="govuk-grid-column-two-thirds">
|
|
14
|
-
{% if errorSummary %}
|
|
15
|
-
{{ govukErrorSummary({
|
|
16
|
-
titleText: "There is a problem",
|
|
17
|
-
errorList: errorSummary,
|
|
18
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
19
|
-
}) }}
|
|
20
|
-
{% endif %}
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
{{ super() }}
|
|
25
|
-
{% endblock before_content %}
|
|
26
|
-
|
|
27
|
-
{% block content %}
|
|
10
|
+
{% block dynQuestionContent %}
|
|
28
11
|
<div class="govuk-grid-row">
|
|
29
12
|
<div class="govuk-grid-column-two-thirds">
|
|
30
13
|
<form action="" method="post" novalidate>
|
|
@@ -231,7 +231,7 @@ describe('./src/dynamic-forms/components/single-line-input/question.js', () => {
|
|
|
231
231
|
}
|
|
232
232
|
},
|
|
233
233
|
journeyTemplate: 'mock template',
|
|
234
|
-
|
|
234
|
+
taskListTemplate: 'mock path',
|
|
235
235
|
journeyTitle: 'mock title',
|
|
236
236
|
sections: []
|
|
237
237
|
});
|
|
@@ -265,7 +265,7 @@ describe('./src/dynamic-forms/components/single-line-input/question.js', () => {
|
|
|
265
265
|
}
|
|
266
266
|
},
|
|
267
267
|
journeyTemplate: 'mock template',
|
|
268
|
-
|
|
268
|
+
taskListTemplate: 'mock path',
|
|
269
269
|
journeyTitle: 'mock title',
|
|
270
270
|
sections: []
|
|
271
271
|
});
|
|
@@ -299,7 +299,7 @@ describe('./src/dynamic-forms/components/single-line-input/question.js', () => {
|
|
|
299
299
|
}
|
|
300
300
|
},
|
|
301
301
|
journeyTemplate: 'mock template',
|
|
302
|
-
|
|
302
|
+
taskListTemplate: 'mock path',
|
|
303
303
|
journeyTitle: 'mock title',
|
|
304
304
|
sections: []
|
|
305
305
|
});
|
|
@@ -1,26 +1,9 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/input/macro.njk" import govukInput %}
|
|
5
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
6
5
|
|
|
7
|
-
{% block
|
|
8
|
-
<div class="govuk-grid-row">
|
|
9
|
-
<div class="govuk-grid-column-two-thirds">
|
|
10
|
-
{% if errorSummary %}
|
|
11
|
-
{{ govukErrorSummary({
|
|
12
|
-
titleText: "There is a problem",
|
|
13
|
-
errorList: errorSummary,
|
|
14
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
15
|
-
}) }}
|
|
16
|
-
{% endif %}
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
|
|
20
|
-
{{ super() }}
|
|
21
|
-
{% endblock before_content %}
|
|
22
|
-
|
|
23
|
-
{% block content %}
|
|
6
|
+
{% block dynQuestionContent %}
|
|
24
7
|
<div class="govuk-grid-row">
|
|
25
8
|
<div class="govuk-grid-column-two-thirds">
|
|
26
9
|
<h1 class="govuk-heading-l">{{ question.question }}</h1>
|
|
@@ -1,27 +1,10 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/radios/macro.njk" import govukRadios %}
|
|
5
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
6
5
|
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
|
|
7
6
|
|
|
8
|
-
{% block
|
|
9
|
-
<div class="govuk-grid-row">
|
|
10
|
-
<div class="govuk-grid-column-two-thirds">
|
|
11
|
-
{% if errorSummary %}
|
|
12
|
-
{{ govukErrorSummary({
|
|
13
|
-
titleText: "There is a problem",
|
|
14
|
-
errorList: errorSummary,
|
|
15
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
16
|
-
}) }}
|
|
17
|
-
{% endif %}
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
{{ super() }}
|
|
22
|
-
{% endblock before_content %}
|
|
23
|
-
|
|
24
|
-
{% block content %}
|
|
7
|
+
{% block dynQuestionContent %}
|
|
25
8
|
<div class="govuk-grid-row">
|
|
26
9
|
<div class="govuk-grid-column-two-thirds">
|
|
27
10
|
<form action="" method="post" novalidate>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/select/macro.njk" import govukSelect %}
|
|
5
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
6
5
|
|
|
@@ -10,23 +9,7 @@
|
|
|
10
9
|
{{ super() }}
|
|
11
10
|
{% endblock %}
|
|
12
11
|
|
|
13
|
-
{% block
|
|
14
|
-
<div class="govuk-grid-row">
|
|
15
|
-
<div class="govuk-grid-column-two-thirds">
|
|
16
|
-
{% if errorSummary %}
|
|
17
|
-
{{ govukErrorSummary({
|
|
18
|
-
titleText: "There is a problem",
|
|
19
|
-
errorList: errorSummary,
|
|
20
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
21
|
-
}) }}
|
|
22
|
-
{% endif %}
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
{{ super() }}
|
|
27
|
-
{% endblock before_content %}
|
|
28
|
-
|
|
29
|
-
{% block content %}
|
|
12
|
+
{% block dynQuestionContent %}
|
|
30
13
|
<div class="govuk-grid-row">
|
|
31
14
|
<div class="govuk-grid-column-two-thirds">
|
|
32
15
|
<form action="" method="POST" novalidate>
|
|
@@ -1,27 +1,10 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/input/macro.njk" import govukInput %}
|
|
5
4
|
{% from "govuk/components/label/macro.njk" import govukLabel %}
|
|
6
5
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
7
6
|
|
|
8
|
-
{% block
|
|
9
|
-
<div class="govuk-grid-row">
|
|
10
|
-
<div class="govuk-grid-column-two-thirds">
|
|
11
|
-
{% if errorSummary %}
|
|
12
|
-
{{ govukErrorSummary({
|
|
13
|
-
titleText: "There is a problem",
|
|
14
|
-
errorList: errorSummary,
|
|
15
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
16
|
-
}) }}
|
|
17
|
-
{% endif %}
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
{{ super() }}
|
|
22
|
-
{% endblock before_content %}
|
|
23
|
-
|
|
24
|
-
{% block content %}
|
|
7
|
+
{% block dynQuestionContent %}
|
|
25
8
|
<div class="govuk-grid-row">
|
|
26
9
|
<div class="govuk-grid-column-two-thirds">
|
|
27
10
|
<form action="" method="post" novalidate>
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
|
+
|
|
2
3
|
{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
|
|
3
4
|
{% from "govuk/components/tag/macro.njk" import govukTag %}
|
|
4
5
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
5
6
|
{% from "./task-list-multi-section.njk" import multiTaskList %}
|
|
6
7
|
{% from "./task-list-single-section.njk" import singleTaskList %}
|
|
7
8
|
|
|
8
|
-
{% block
|
|
9
|
-
{% block beforeTaskList %}
|
|
10
|
-
{% endblock %}
|
|
11
|
-
|
|
9
|
+
{% block dynTaskList %}
|
|
12
10
|
<style {% if cspNonce %}nonce={{ cspNonce }}{% endif %}>
|
|
13
11
|
.app-task-list {
|
|
14
12
|
padding-left: 0;
|
|
@@ -37,8 +35,4 @@
|
|
|
37
35
|
{% endif %}
|
|
38
36
|
</div>
|
|
39
37
|
</div>
|
|
40
|
-
|
|
41
|
-
{% block afterTaskList %}
|
|
42
|
-
{% endblock %}
|
|
43
|
-
|
|
44
38
|
{% endblock %}
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/textarea/macro.njk" import govukTextarea %}
|
|
5
4
|
{% from "govuk/components/label/macro.njk" import govukLabel %}
|
|
6
5
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
7
6
|
{% from "govuk/components/checkboxes/macro.njk" import govukCheckboxes %}
|
|
8
7
|
|
|
9
|
-
{% block
|
|
10
|
-
<div class="govuk-grid-row">
|
|
11
|
-
<div class="govuk-grid-column-two-thirds">
|
|
12
|
-
{% if errorSummary %}
|
|
13
|
-
{{ govukErrorSummary({
|
|
14
|
-
titleText: "There is a problem",
|
|
15
|
-
errorList: errorSummary,
|
|
16
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
17
|
-
}) }}
|
|
18
|
-
{% endif %}
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
{{ super() }}
|
|
23
|
-
{% endblock before_content %}
|
|
24
|
-
|
|
25
|
-
{% block content %}
|
|
8
|
+
{% block dynQuestionContent %}
|
|
26
9
|
<div class="govuk-grid-row">
|
|
27
10
|
<div class="govuk-grid-column-two-thirds">
|
|
28
11
|
<form action="" method="post" novalidate>
|
|
@@ -3,28 +3,11 @@
|
|
|
3
3
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
4
4
|
{% from "govuk/components/checkboxes/macro.njk" import govukCheckboxes %}
|
|
5
5
|
{% from "govuk/components/details/macro.njk" import govukDetails %}
|
|
6
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
7
6
|
{% from "govuk/components/label/macro.njk" import govukLabel %}
|
|
8
7
|
{% from "govuk/components/table/macro.njk" import govukTable %}
|
|
9
8
|
{% from "govuk/components/textarea/macro.njk" import govukTextarea %}
|
|
10
9
|
|
|
11
|
-
{% block
|
|
12
|
-
<div class="govuk-grid-row">
|
|
13
|
-
<div class="govuk-grid-column-two-thirds">
|
|
14
|
-
{% if errorSummary %}
|
|
15
|
-
{{ govukErrorSummary({
|
|
16
|
-
titleText: "There is a problem",
|
|
17
|
-
errorList: errorSummary,
|
|
18
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
19
|
-
}) }}
|
|
20
|
-
{% endif %}
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
{{ super() }}
|
|
25
|
-
{% endblock before_content %}
|
|
26
|
-
|
|
27
|
-
{% block content %}
|
|
10
|
+
{% block dynQuestionContent %}
|
|
28
11
|
<div class="govuk-grid-row">
|
|
29
12
|
<div class="govuk-grid-column-two-thirds">
|
|
30
13
|
<form action="" method="post" novalidate>
|
|
@@ -55,7 +55,7 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
|
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
57
|
const customViewData = {
|
|
58
|
-
layoutTemplate: 'views/layout-
|
|
58
|
+
layoutTemplate: 'views/layout-journey.njk',
|
|
59
59
|
question: {
|
|
60
60
|
question: 'Redaction Question',
|
|
61
61
|
fieldName: 'field-name',
|
|
@@ -94,7 +94,7 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
|
|
|
94
94
|
}
|
|
95
95
|
};
|
|
96
96
|
const customViewData = {
|
|
97
|
-
layoutTemplate: 'views/layout-
|
|
97
|
+
layoutTemplate: 'views/layout-journey.njk',
|
|
98
98
|
question: {
|
|
99
99
|
question: 'Redaction Question',
|
|
100
100
|
fieldName: 'field-name',
|
|
@@ -134,7 +134,7 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
|
|
|
134
134
|
}
|
|
135
135
|
};
|
|
136
136
|
const customViewData = {
|
|
137
|
-
layoutTemplate: 'views/layout-
|
|
137
|
+
layoutTemplate: 'views/layout-journey.njk',
|
|
138
138
|
question: {
|
|
139
139
|
question: 'Redaction Question',
|
|
140
140
|
fieldName: 'field-name',
|
|
@@ -181,7 +181,7 @@ describe('./src/dynamic-forms/components/text-entry-redact/question.js', () => {
|
|
|
181
181
|
}
|
|
182
182
|
};
|
|
183
183
|
const customViewData = {
|
|
184
|
-
layoutTemplate: 'views/layout-
|
|
184
|
+
layoutTemplate: 'views/layout-journey.njk',
|
|
185
185
|
question: {
|
|
186
186
|
question: 'Redaction Question',
|
|
187
187
|
fieldName: 'field-name',
|
|
@@ -1,27 +1,10 @@
|
|
|
1
1
|
{% extends layoutTemplate %}
|
|
2
2
|
|
|
3
|
-
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
4
3
|
{% from "govuk/components/radios/macro.njk" import govukRadios %}
|
|
5
4
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
6
5
|
{% from "govuk/components/fieldset/macro.njk" import govukFieldset %}
|
|
7
6
|
|
|
8
|
-
{% block
|
|
9
|
-
<div class="govuk-grid-row">
|
|
10
|
-
<div class="govuk-grid-column-two-thirds">
|
|
11
|
-
{% if errorSummary %}
|
|
12
|
-
{{ govukErrorSummary({
|
|
13
|
-
titleText: "There is a problem",
|
|
14
|
-
errorList: errorSummary,
|
|
15
|
-
attributes: {"data-cy": "error-wrapper"}
|
|
16
|
-
}) }}
|
|
17
|
-
{% endif %}
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
{{ super() }}
|
|
22
|
-
{% endblock before_content %}
|
|
23
|
-
|
|
24
|
-
{% block content %}
|
|
7
|
+
{% block dynQuestionContent %}
|
|
25
8
|
<div class="govuk-grid-row">
|
|
26
9
|
<div class="govuk-grid-column-two-thirds">
|
|
27
10
|
<form action="" method="post" novalidate>
|
package/src/controller.js
CHANGED
|
@@ -124,12 +124,12 @@ export async function list(req, res, pageCaption, viewData) {
|
|
|
124
124
|
summaryListData.sections.push(sectionView);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
return res.render(
|
|
127
|
+
return res.render('components/task-list/index', {
|
|
128
128
|
...viewData,
|
|
129
129
|
pageCaption,
|
|
130
130
|
summaryListData,
|
|
131
131
|
journeyComplete: journey.isComplete(),
|
|
132
|
-
layoutTemplate: journey.
|
|
132
|
+
layoutTemplate: journey.taskListTemplate,
|
|
133
133
|
journeyTitle: journey.journeyTitle
|
|
134
134
|
});
|
|
135
135
|
}
|
package/src/controller.test.js
CHANGED
|
@@ -156,7 +156,7 @@ const journeyParams = {
|
|
|
156
156
|
taskListUrl: 'task-list',
|
|
157
157
|
makeBaseUrl: () => `${mockBaseUrl}/${mockRef}`,
|
|
158
158
|
journeyTemplate: mockTemplateUrl,
|
|
159
|
-
|
|
159
|
+
taskListTemplate: mockListingPath,
|
|
160
160
|
journeyTitle: mockJourneyTitle
|
|
161
161
|
};
|
|
162
162
|
|
|
@@ -223,11 +223,11 @@ describe('dynamic-form/controller', () => {
|
|
|
223
223
|
const mockFn = res.render.mock;
|
|
224
224
|
assert.strictEqual(mockFn.callCount(), 1);
|
|
225
225
|
assert.deepStrictEqual(mockFn.calls[0].arguments, [
|
|
226
|
-
|
|
226
|
+
'components/task-list/index',
|
|
227
227
|
{
|
|
228
228
|
appeal,
|
|
229
229
|
summaryListData: mockSummaryListData,
|
|
230
|
-
layoutTemplate:
|
|
230
|
+
layoutTemplate: mockListingPath,
|
|
231
231
|
journeyComplete: false,
|
|
232
232
|
pageCaption: pageCaption,
|
|
233
233
|
journeyTitle: mockJourneyTitle
|
|
@@ -269,11 +269,11 @@ describe('dynamic-form/controller', () => {
|
|
|
269
269
|
|
|
270
270
|
assert.strictEqual(mockFn.callCount(), 1);
|
|
271
271
|
assert.deepStrictEqual(mockFn.calls[0].arguments, [
|
|
272
|
-
|
|
272
|
+
'components/task-list/index',
|
|
273
273
|
{
|
|
274
274
|
appeal,
|
|
275
275
|
summaryListData: mockSummaryListData,
|
|
276
|
-
layoutTemplate:
|
|
276
|
+
layoutTemplate: mockListingPath,
|
|
277
277
|
journeyComplete: false,
|
|
278
278
|
pageCaption: pageCaption,
|
|
279
279
|
journeyTitle: mockJourneyTitle
|
package/src/journey/journey.js
CHANGED
|
@@ -29,8 +29,8 @@ export class Journey {
|
|
|
29
29
|
taskListUrl = '';
|
|
30
30
|
/** @type {string} journeyTemplate - nunjucks template file used for */
|
|
31
31
|
journeyTemplate = '';
|
|
32
|
-
/** @type {string}
|
|
33
|
-
|
|
32
|
+
/** @type {string} taskListTemplate - nunjucks template file used for listing page */
|
|
33
|
+
taskListTemplate = '';
|
|
34
34
|
/** @type {string} informationPageViewPath - nunjucks template file used for pdf summary information page */
|
|
35
35
|
informationPageViewPath = '';
|
|
36
36
|
/** @type {boolean} defines how the next/previous question handles end of sections */
|
|
@@ -46,7 +46,7 @@ export class Journey {
|
|
|
46
46
|
* @param {string} [options.taskListUrl] - task list url - added to base url, can be left undefined
|
|
47
47
|
* @param {JourneyResponse} options.response - user's response
|
|
48
48
|
* @param {string} options.journeyTemplate - template used for all views
|
|
49
|
-
* @param {string} options.
|
|
49
|
+
* @param {string} options.taskListTemplate - path to njk view for listing page
|
|
50
50
|
* @param {string} [options.informationPageViewPath] - path to njk view for pdf summary page
|
|
51
51
|
* @param {string} options.journeyTitle - part of the title in the njk view
|
|
52
52
|
* @param {boolean} [options.returnToListing] - defines how the next/previous question handles end of sections
|
|
@@ -59,7 +59,7 @@ export class Journey {
|
|
|
59
59
|
taskListUrl,
|
|
60
60
|
response,
|
|
61
61
|
journeyTemplate,
|
|
62
|
-
|
|
62
|
+
taskListTemplate,
|
|
63
63
|
informationPageViewPath,
|
|
64
64
|
journeyTitle,
|
|
65
65
|
returnToListing,
|
|
@@ -86,10 +86,10 @@ export class Journey {
|
|
|
86
86
|
}
|
|
87
87
|
this.journeyTemplate = journeyTemplate;
|
|
88
88
|
|
|
89
|
-
if (!
|
|
90
|
-
throw new Error('
|
|
89
|
+
if (!taskListTemplate || typeof taskListTemplate !== 'string') {
|
|
90
|
+
throw new Error('taskListTemplate should be a string.');
|
|
91
91
|
}
|
|
92
|
-
this.
|
|
92
|
+
this.taskListTemplate = taskListTemplate;
|
|
93
93
|
|
|
94
94
|
this.informationPageViewPath = informationPageViewPath || '';
|
|
95
95
|
|
|
@@ -53,7 +53,7 @@ describe('Journey class', () => {
|
|
|
53
53
|
answers: {}
|
|
54
54
|
},
|
|
55
55
|
journeyTemplate: 'mock template',
|
|
56
|
-
|
|
56
|
+
taskListTemplate: 'mock path',
|
|
57
57
|
journeyTitle: 'mock title'
|
|
58
58
|
};
|
|
59
59
|
});
|
|
@@ -114,23 +114,23 @@ describe('Journey class', () => {
|
|
|
114
114
|
assert.throws(() => new Journey(constructorArgs), new Error('journeyTemplate should be a string.'));
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
it('should set
|
|
118
|
-
constructorArgs.
|
|
117
|
+
it('should set taskListTemplate', () => {
|
|
118
|
+
constructorArgs.taskListTemplate = 'test';
|
|
119
119
|
const journey = new Journey(constructorArgs);
|
|
120
120
|
|
|
121
|
-
assert.strictEqual(journey.
|
|
121
|
+
assert.strictEqual(journey.taskListTemplate, constructorArgs.taskListTemplate);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
it('should error if
|
|
125
|
-
constructorArgs.
|
|
124
|
+
it('should error if taskListTemplate not provided', () => {
|
|
125
|
+
constructorArgs.taskListTemplate = '';
|
|
126
126
|
|
|
127
|
-
assert.throws(() => new Journey(constructorArgs), new Error('
|
|
127
|
+
assert.throws(() => new Journey(constructorArgs), new Error('taskListTemplate should be a string.'));
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
it('should error if
|
|
131
|
-
constructorArgs.
|
|
130
|
+
it('should error if taskListTemplate not a string', () => {
|
|
131
|
+
constructorArgs.taskListTemplate = 123;
|
|
132
132
|
|
|
133
|
-
assert.throws(() => new Journey(constructorArgs), new Error('
|
|
133
|
+
assert.throws(() => new Journey(constructorArgs), new Error('taskListTemplate should be a string.'));
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
it('should set journeyTitle', () => {
|
|
@@ -46,7 +46,7 @@ describe('redirectToUnansweredQuestion Middleware', () => {
|
|
|
46
46
|
const params = {
|
|
47
47
|
journeyId: 'id-1',
|
|
48
48
|
journeyTemplate: 'statement-template.njk',
|
|
49
|
-
|
|
49
|
+
taskListTemplate: 'dynamic-components/task-list/statement',
|
|
50
50
|
journeyTitle: 'Manage your appeals',
|
|
51
51
|
sections: [
|
|
52
52
|
new Section('', 'section-1')
|
|
@@ -143,7 +143,7 @@ export default class AddressValidator extends BaseValidator {
|
|
|
143
143
|
return validator
|
|
144
144
|
.isLength({ min: postcodeMinLength, max: postcodeMaxLength })
|
|
145
145
|
.bail()
|
|
146
|
-
.withMessage(`Postcode must be
|
|
146
|
+
.withMessage(`Postcode must be less than ${postcodeMaxLength} characters`)
|
|
147
147
|
.custom((postcode) => {
|
|
148
148
|
return validatePostcode(postcode);
|
|
149
149
|
});
|
|
@@ -6,7 +6,6 @@ import AddressValidator, {
|
|
|
6
6
|
addressLine1MaxLength,
|
|
7
7
|
addressLine2MaxLength,
|
|
8
8
|
postcodeMaxLength,
|
|
9
|
-
postcodeMinLength,
|
|
10
9
|
townCityMaxLength
|
|
11
10
|
} from './address-validator.js';
|
|
12
11
|
|
|
@@ -108,10 +107,7 @@ describe('AddressValidator', () => {
|
|
|
108
107
|
`Address line 2 must be ${addressLine2MaxLength} characters or less`
|
|
109
108
|
);
|
|
110
109
|
assert.strictEqual(errors.testField_townCity.msg, `Town or city must be ${townCityMaxLength} characters or less`);
|
|
111
|
-
assert.strictEqual(
|
|
112
|
-
errors.testField_postcode.msg,
|
|
113
|
-
`Postcode must be between ${postcodeMinLength} and ${postcodeMaxLength} characters`
|
|
114
|
-
);
|
|
110
|
+
assert.strictEqual(errors.testField_postcode.msg, `Postcode must be less than ${postcodeMaxLength} characters`);
|
|
115
111
|
});
|
|
116
112
|
});
|
|
117
113
|
|
package/test/journey.js
CHANGED
|
@@ -30,8 +30,8 @@ export function createJourney(questions, response) {
|
|
|
30
30
|
.addQuestion(questions.luggageWeight)
|
|
31
31
|
],
|
|
32
32
|
taskListUrl: 'check-your-answers',
|
|
33
|
-
journeyTemplate: 'views/layout-
|
|
34
|
-
|
|
33
|
+
journeyTemplate: 'views/layout-journey.njk',
|
|
34
|
+
taskListTemplate: 'views/layout-check-your-answers.njk',
|
|
35
35
|
journeyTitle: 'Holiday Booking',
|
|
36
36
|
returnToListing: false,
|
|
37
37
|
makeBaseUrl: () => '/',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{%
|
|
1
|
+
{% block dynTaskList %}{% endblock %}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{% block dynQuestionContent %}{% endblock %}
|