Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Follow up questions #304

Merged
merged 7 commits into from
Feb 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,67 @@

Records breaking changes from major version bumps

## 21.0.0

PR: [#304](https://github.com/alphagov/digitalmarketplace-frontend-toolkit/pull/304)

### What changed

- The format of the followup questions has changed, so toolkit form macros need to pass in
the `content_question.values_followup` instead of the `content_question.followup`
- Since radio and checkbox questions can have followups too the related macros need to set
`followup=content_question.values_followup`
- Radio, boolean and list-entry questions can be follow-up questions, so related macros
need to set `hidden=question_content.hidden`
- We need to vendor a version of `show-hide-content.js` with added support for multiple
follow-up inputs, so it has to be used instead of the GOV.UK toolkit one

### Example app change

#### Loading the `show-hide-content.js` with support for multiple follow-up questions

Old:
```
//= include ../../../node_modules/govuk_frontend_toolkit/javascripts/govuk/show-hide-content.js
```

New:
```
//= include ../../../bower_components/digitalmarketplace-frontend-toolkit/toolkit/javascripts/show-hide-content.js
```

#### Updating application `form_toolkit` macros

Old:
```jinja
{% macro boolean(question_content, service_data, errors, question_number=None, get_question=None) -%}
{%
with
...
followup=question_content.followup,
...
%}
{% include "toolkit/forms/selection-buttons.html" %}
{% endwith %}
{%- endmacro %}
```

New:
```jinja
{% macro boolean(question_content, service_data, errors, question_number=None, get_question=None) -%}
{%
with
...
followup=question_content.values_followup,
hidden=question_content.hidden,
...
%}
{% include "toolkit/forms/selection-buttons.html" %}
{% endwith %}
{%- endmacro %}
```


## 20.0.0

PR: [#302](https://github.com/alphagov/digitalmarketplace-frontend-toolkit/pull/302)
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.0.1
21.0.0
72 changes: 67 additions & 5 deletions pages_builder/pages/forms/combinations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ grid: column-two-thirds
bodyEnd: >
<script type="text/javascript" src="../public/javascripts/govuk_frontend_toolkit/vendor/polyfills/bind.js"></script>
<script type="text/javascript" src="../public/javascripts/govuk_frontend_toolkit/govuk/selection-buttons.js"></script>
<script type="text/javascript" src="../public/javascripts/govuk_frontend_toolkit/govuk/show-hide-content.js"></script>
<script type="text/javascript" src="../public/javascripts/show-hide-content.js"></script>
<script type="text/javascript" src="../public/javascripts/vendor/hogan-3.0.2.min.js"></script>
<script type="text/javascript" src="../public/javascripts/list-entry.js"></script>
examples:
- |
<form>

<!-- `followup` field must be set to the `name` of the evidence textbox -->
{%
with
followup = "requirement-evidence-10",
followup = {True: ["requirement-evidence-10"]},
name = "requirement-10",
question = "Can you do this essential requirement",
value = true,
Expand All @@ -35,10 +36,9 @@ examples:
- |
<form>

<!-- `followup` field must be set to the `name` of the evidence textbox -->
{%
with
followup = "requirement-evidence-20",
followup = {True: ["requirement-evidence-20"]},
name = "evidence-20",
question = "Can you do this essential requirement - with errors",
value = true,
Expand All @@ -58,3 +58,65 @@ examples:
{% include "forms/textbox.html" %}
{% endwith %}
</form>
- |
<form>

{%
with
followup = {"Other": ["requirement-evidence-30"]},
name = "evidence-30",
question = "Checkboxes question with follow-up",
value = ["Option 1", "Other"],
type = "checkboxes",
options = [{"value": "Option 1", "label": "Option 1"},
{"value": "Option 2", "label": "Option 2"},
{"value": "Other", "label": "Other"}]
%}
{% include "forms/selection-buttons.html" %}
{% endwith %}
{%
with
large = true,
question = "Follow-up question for 'Other'",
name = "requirement-evidence-30",
hidden = true,
value = ""
%}
{% include "forms/textbox.html" %}
{% endwith %}
</form>
- |
<form>

{%
with
followup = {True: ["requirement-evidence-40", "requirement-boolean-followup-40"]},
name = "evidence-40",
question = "Question with multiple follow-ups",
value = true,
type = "boolean"
%}
{% include "forms/selection-buttons.html" %}
{% endwith %}
{%
with
name = "requirement-boolean-followup-40",
question = "Boolean follow-up",
hidden = true,
type = "boolean"
%}
{% include "forms/selection-buttons.html" %}
{% endwith %}
{%
with
large = true,
id = "requirement-evidence-40",
question = "List follow-up",
name = "requirement-evidence-40",
number_of_items=10,
hidden = true,
value = ""
%}
{% include "forms/list-entry.html" %}
{% endwith %}
</form>
4 changes: 3 additions & 1 deletion pages_builder/pages/forms/selection-buttons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ examples:
question: Can you do this essential requirement
question_number: 93
value: true
followup: requirement-evidence-110
followup:
true:
- requirement-evidence-110
Copy link
Contributor

@samuelhwilliams samuelhwilliams Feb 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the other way around, shouldn't it?

followup:
  requirement-evidence-110:
    - true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not YAML format used by the content loader, it's the data we'd normally pass into toolkit form macros, so this is what .values_followup would return, which is a reversed mapping.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok

surrounding_html: |
<form>
{{ example | safe }}
Expand Down
194 changes: 194 additions & 0 deletions toolkit/javascripts/show-hide-content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
;(function (global) {
'use strict'

var $ = global.jQuery
var GOVUK = global.GOVUK || {}

function ShowHideContent () {
var self = this

// Radio and Checkbox selectors
var selectors = {
namespace: 'ShowHideContent',
radio: '.block-label[data-target] input[type="radio"]',
checkbox: '.block-label[data-target] input[type="checkbox"]'
}

// Escape name attribute for use in DOM selector
function escapeElementName (str) {
var result = str.replace('[', '\\[').replace(']', '\\]')
return result
}

// Adds ARIA attributes to control + associated content
function initToggledContent () {
var $control = $(this)
var $content = getToggledContent($control)
var contentIds = ''

// Set aria-controls and defaults
if ($content.length) {
$content.each(function () {
$(this).attr('aria-hidden', 'true')
contentIds += ' ' + $(this).attr('id')
})

$control.attr('aria-controls', contentIds.trim())
$control.attr('aria-expanded', 'false')
}
}

// Return toggled content for control
function getToggledContent ($control) {
var targetIds = $control.attr('aria-controls')

// ARIA attributes aren't set before init
if (!targetIds) {
targetIds = $control.closest('label').data('target')
}

// turn a space-separated list of ids into a comma-separated css id selector
// ie, 'id-1 id-2 id-3' becomes '#id-1, #id-2, #id-3'
if (targetIds) {
targetIds = targetIds
.split(' ')
.map(function (targetId) { return '#' + targetId })
.join(', ')
}

// Find show/hide content by id
return $(targetIds)
}

// Show toggled content for control
function showToggledContent ($control, $content) {
if (!$content.length) {
return
}

// Show content
if ($content.hasClass('js-hidden')) {
$content.removeClass('js-hidden')
$content.attr('aria-hidden', 'false')

// If the controlling input, update aria-expanded
if ($control.attr('aria-controls')) {
$control.attr('aria-expanded', 'true')
}
}
}

// Hide toggled content for control
function hideToggledContent ($control, $content) {
$content = $content || getToggledContent($control)

if (!$content.length) {
return
}

// Hide content
if (!$content.hasClass('js-hidden')) {
$content.addClass('js-hidden')
$content.attr('aria-hidden', 'true')

// If the controlling input, update aria-expanded
if ($control.attr('aria-controls')) {
$control.attr('aria-expanded', 'false')
}
}
}

// Handle radio show/hide
function handleRadioContent ($control, $content) {
// All radios in this group which control content
var selector = selectors.radio + '[name=' + escapeElementName($control.attr('name')) + '][aria-controls]'
var $form = $control.closest('form')
var $radios = $form.length ? $form.find(selector) : $(selector)

// Hide content for radios in group
$radios.each(function () {
hideToggledContent($(this))
})

// Select content for this control
if ($control.is('[aria-controls]')) {
showToggledContent($control, $content)
}
}

// Handle checkbox show/hide
function handleCheckboxContent ($control, $content) {
// Show checkbox content
if ($control.is(':checked')) {
showToggledContent($control, $content)
} else { // Hide checkbox content
hideToggledContent($control, $content)
}
}

// Set up event handlers etc
function init ($container, elementSelector, eventSelectors, handler) {
$container = $container || $(document.body)

// Handle control clicks
function deferred () {
var $control = $(this)
handler($control, getToggledContent($control))
}

// Prepare ARIA attributes
var $controls = $(elementSelector)
$controls.each(initToggledContent)

// Handle events
$.each(eventSelectors, function (idx, eventSelector) {
$container.on('click.' + selectors.namespace, eventSelector, deferred)
})

// Any already :checked on init?
if ($controls.is(':checked')) {
$controls.filter(':checked').each(deferred)
}
}

// Get event selectors for all radio groups
function getEventSelectorsForRadioGroups () {
var radioGroups = []

// Build an array of radio group selectors
return $(selectors.radio).map(function () {
var groupName = $(this).attr('name')

if ($.inArray(groupName, radioGroups) === -1) {
radioGroups.push(groupName)
return 'input[type="radio"][name="' + $(this).attr('name') + '"]'
}
return null
})
}

// Set up radio show/hide content for container
self.showHideRadioToggledContent = function ($container) {
init($container, selectors.radio, getEventSelectorsForRadioGroups(), handleRadioContent)
}

// Set up checkbox show/hide content for container
self.showHideCheckboxToggledContent = function ($container) {
init($container, selectors.checkbox, [selectors.checkbox], handleCheckboxContent)
}

// Remove event handlers
self.destroy = function ($container) {
$container = $container || $(document.body)
$container.off('.' + selectors.namespace)
}
}

ShowHideContent.prototype.init = function ($container) {
this.showHideRadioToggledContent($container)
this.showHideCheckboxToggledContent($container)
}

GOVUK.ShowHideContent = ShowHideContent
global.GOVUK = GOVUK
})(window)
2 changes: 1 addition & 1 deletion toolkit/templates/forms/list-entry.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
{% elif message %}
<div class="message-wrapper">
{% endif %}
<fieldset class="question {% if first_question %}first-question{% endif %}" id="{{ id }}">
<fieldset class="question{% if first_question %} first-question{% endif %}{% if hidden %} js-hidden related-information{% endif %}" id="{{ id }}">
<legend>
<span class="question-heading">
{% if question_number %}
Expand Down
Loading