govuk_tech_docs 2.2.2 → 2.4.2
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.nvmrc +1 -1
- data/.travis.yml +2 -0
- data/CHANGELOG.md +24 -0
- data/example/config/tech-docs.yml +1 -0
- data/example/source/single-page-nav.html.md +13 -0
- data/govuk_tech_docs.gemspec +2 -1
- data/lib/assets/javascripts/_modules/collapsible-navigation.js +7 -7
- data/lib/assets/javascripts/_modules/in-page-navigation.js +2 -4
- data/lib/assets/stylesheets/_govuk_tech_docs.scss +9 -10
- data/lib/assets/stylesheets/modules/_search.scss +4 -25
- data/lib/assets/stylesheets/modules/_technical-documentation.scss +1 -1
- data/lib/assets/stylesheets/modules/_toc.scss +11 -11
- data/lib/govuk_tech_docs/table_of_contents/heading.rb +5 -1
- data/lib/govuk_tech_docs/table_of_contents/heading_tree_renderer.rb +2 -2
- data/lib/govuk_tech_docs/table_of_contents/helpers.rb +22 -11
- data/lib/govuk_tech_docs/tech_docs_html_renderer.rb +1 -1
- data/lib/govuk_tech_docs/version.rb +1 -1
- data/lib/source/layouts/_header.erb +1 -2
- data/lib/source/layouts/layout.erb +3 -1
- data/node_modules/govuk-frontend/govuk/_base.scss +3 -0
- data/node_modules/govuk-frontend/govuk/all.js +306 -94
- data/node_modules/govuk-frontend/govuk/all.scss +1 -3
- data/node_modules/govuk-frontend/govuk/components/_all.scss +33 -29
- data/node_modules/govuk-frontend/govuk/components/accordion/_accordion.scss +2 -208
- data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +197 -0
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +1 -1
- data/node_modules/govuk-frontend/govuk/components/back-link/_back-link.scss +2 -65
- data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +99 -0
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_breadcrumbs.scss +2 -118
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +138 -0
- data/node_modules/govuk-frontend/govuk/components/button/_button.scss +2 -284
- data/node_modules/govuk-frontend/govuk/components/button/_index.scss +288 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/_character-count.scss +2 -31
- data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +25 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +17 -9
- data/node_modules/govuk-frontend/govuk/components/checkboxes/_checkboxes.scss +2 -308
- data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +320 -0
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +129 -24
- data/node_modules/govuk-frontend/govuk/components/cookie-banner/_cookie-banner.scss +2 -0
- data/node_modules/govuk-frontend/govuk/components/cookie-banner/_index.scss +51 -0
- data/node_modules/govuk-frontend/govuk/components/date-input/_date-input.scss +2 -30
- data/node_modules/govuk-frontend/govuk/components/date-input/_index.scss +26 -0
- data/node_modules/govuk-frontend/govuk/components/details/_details.scss +2 -88
- data/node_modules/govuk-frontend/govuk/components/details/_index.scss +87 -0
- data/node_modules/govuk-frontend/govuk/components/error-message/_error-message.scss +2 -15
- data/node_modules/govuk-frontend/govuk/components/error-message/_index.scss +11 -0
- data/node_modules/govuk-frontend/govuk/components/error-summary/_error-summary.scss +2 -59
- data/node_modules/govuk-frontend/govuk/components/error-summary/_index.scss +43 -0
- data/node_modules/govuk-frontend/govuk/components/fieldset/_fieldset.scss +2 -68
- data/node_modules/govuk-frontend/govuk/components/fieldset/_index.scss +64 -0
- data/node_modules/govuk-frontend/govuk/components/file-upload/_file-upload.scss +2 -81
- data/node_modules/govuk-frontend/govuk/components/file-upload/_index.scss +49 -0
- data/node_modules/govuk-frontend/govuk/components/footer/_footer.scss +2 -244
- data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +241 -0
- data/node_modules/govuk-frontend/govuk/components/header/_header.scss +2 -318
- data/node_modules/govuk-frontend/govuk/components/header/_index.scss +331 -0
- data/node_modules/govuk-frontend/govuk/components/header/header.js +665 -316
- data/node_modules/govuk-frontend/govuk/components/hint/_hint.scss +2 -50
- data/node_modules/govuk-frontend/govuk/components/hint/_index.scss +44 -0
- data/node_modules/govuk-frontend/govuk/components/input/_index.scss +191 -0
- data/node_modules/govuk-frontend/govuk/components/input/_input.scss +2 -103
- data/node_modules/govuk-frontend/govuk/components/inset-text/_index.scss +24 -0
- data/node_modules/govuk-frontend/govuk/components/inset-text/_inset-text.scss +2 -28
- data/node_modules/govuk-frontend/govuk/components/label/_index.scss +41 -0
- data/node_modules/govuk-frontend/govuk/components/label/_label.scss +2 -45
- data/node_modules/govuk-frontend/govuk/components/notification-banner/_index.scss +89 -0
- data/node_modules/govuk-frontend/govuk/components/notification-banner/_notification-banner.scss +2 -0
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +61 -0
- data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +44 -0
- data/node_modules/govuk-frontend/govuk/components/panel/_panel.scss +2 -44
- data/node_modules/govuk-frontend/govuk/components/phase-banner/_index.scss +27 -0
- data/node_modules/govuk-frontend/govuk/components/phase-banner/_phase-banner.scss +2 -31
- data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +342 -0
- data/node_modules/govuk-frontend/govuk/components/radios/_radios.scss +2 -346
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js +76 -28
- data/node_modules/govuk-frontend/govuk/components/select/_index.scss +49 -0
- data/node_modules/govuk-frontend/govuk/components/select/_select.scss +2 -57
- data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +36 -0
- data/node_modules/govuk-frontend/govuk/components/skip-link/_skip-link.scss +2 -37
- data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +145 -0
- data/node_modules/govuk-frontend/govuk/components/summary-list/_summary-list.scss +2 -157
- data/node_modules/govuk-frontend/govuk/components/table/_index.scss +71 -0
- data/node_modules/govuk-frontend/govuk/components/table/_table.scss +2 -54
- data/node_modules/govuk-frontend/govuk/components/tabs/_index.scss +130 -0
- data/node_modules/govuk-frontend/govuk/components/tabs/_tabs.scss +2 -142
- data/node_modules/govuk-frontend/govuk/components/tag/_index.scss +86 -0
- data/node_modules/govuk-frontend/govuk/components/tag/_tag.scss +2 -91
- data/node_modules/govuk-frontend/govuk/components/textarea/_index.scss +47 -0
- data/node_modules/govuk-frontend/govuk/components/textarea/_textarea.scss +2 -55
- data/node_modules/govuk-frontend/govuk/components/warning-text/_index.scss +66 -0
- data/node_modules/govuk-frontend/govuk/components/warning-text/_warning-text.scss +2 -60
- data/node_modules/govuk-frontend/govuk/core/_global-styles.scss +5 -3
- data/node_modules/govuk-frontend/govuk/core/_links.scss +13 -3
- data/node_modules/govuk-frontend/govuk/core/_lists.scss +17 -3
- data/node_modules/govuk-frontend/govuk/core/_section-break.scss +5 -3
- data/node_modules/govuk-frontend/govuk/core/_template.scss +5 -4
- data/node_modules/govuk-frontend/govuk/core/_typography.scss +5 -3
- data/node_modules/govuk-frontend/govuk/helpers/_clearfix.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_device-pixels.scss +3 -3
- data/node_modules/govuk-frontend/govuk/helpers/_focused.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_font-faces.scss +9 -11
- data/node_modules/govuk-frontend/govuk/helpers/_grid.scss +2 -1
- data/node_modules/govuk-frontend/govuk/helpers/_links.scss +246 -33
- data/node_modules/govuk-frontend/govuk/helpers/_media-queries.scss +2 -6
- data/node_modules/govuk-frontend/govuk/helpers/_shape-arrow.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +3 -2
- data/node_modules/govuk-frontend/govuk/helpers/_typography.scss +8 -7
- data/node_modules/govuk-frontend/govuk/helpers/_visually-hidden.scss +1 -1
- data/node_modules/govuk-frontend/govuk/objects/_all.scss +1 -0
- data/node_modules/govuk-frontend/govuk/objects/_button-group.scss +101 -0
- data/node_modules/govuk-frontend/govuk/objects/_form-group.scss +1 -4
- data/node_modules/govuk-frontend/govuk/objects/_grid.scss +3 -6
- data/node_modules/govuk-frontend/govuk/objects/_main-wrapper.scss +5 -4
- data/node_modules/govuk-frontend/govuk/objects/_width-container.scss +6 -4
- data/node_modules/govuk-frontend/govuk/overrides/_display.scss +6 -4
- data/node_modules/govuk-frontend/govuk/overrides/_spacing.scss +5 -3
- data/node_modules/govuk-frontend/govuk/overrides/_typography.scss +5 -3
- data/node_modules/govuk-frontend/govuk/overrides/_width.scss +6 -3
- data/node_modules/govuk-frontend/govuk/settings/_all.scss +2 -0
- data/node_modules/govuk-frontend/govuk/settings/_colours-applied.scss +11 -5
- data/node_modules/govuk-frontend/govuk/settings/_colours-organisations.scss +3 -0
- data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +42 -35
- data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +0 -1
- data/node_modules/govuk-frontend/govuk/settings/_ie8.scss +1 -1
- data/node_modules/govuk-frontend/govuk/settings/_links.scss +62 -0
- data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +4 -5
- data/node_modules/govuk-frontend/govuk/settings/_typography-font-families.scss +2 -2
- data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +14 -5
- data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +6 -2
- data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_font-url.scss +1 -4
- data/node_modules/govuk-frontend/govuk/tools/_ie8.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_image-url.scss +1 -4
- data/node_modules/govuk-frontend/govuk/tools/_px-to-em.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_px-to-rem.scss +1 -1
- data/node_modules/govuk-frontend/govuk/utilities/_visually-hidden.scss +0 -1
- data/node_modules/govuk-frontend/govuk/vendor/_sass-mq.scss +0 -4
- data/package-lock.json +358 -288
- data/package.json +2 -2
- metadata +56 -4
|
@@ -891,7 +891,7 @@ Accordion.prototype.initHeaderAttributes = function ($headerWrapper, index) {
|
|
|
891
891
|
icon.className = this.iconClass;
|
|
892
892
|
icon.setAttribute('aria-hidden', 'true');
|
|
893
893
|
|
|
894
|
-
$
|
|
894
|
+
$button.appendChild(icon);
|
|
895
895
|
};
|
|
896
896
|
|
|
897
897
|
// When section toggled, set and store state
|
|
@@ -1498,7 +1498,7 @@ function CharacterCount ($module) {
|
|
|
1498
1498
|
this.$module = $module;
|
|
1499
1499
|
this.$textarea = $module.querySelector('.govuk-js-character-count');
|
|
1500
1500
|
if (this.$textarea) {
|
|
1501
|
-
this.$countMessage = $module.querySelector('[id=' + this.$textarea.id + '-info]');
|
|
1501
|
+
this.$countMessage = $module.querySelector('[id="' + this.$textarea.id + '-info"]');
|
|
1502
1502
|
}
|
|
1503
1503
|
}
|
|
1504
1504
|
|
|
@@ -1542,13 +1542,22 @@ CharacterCount.prototype.init = function () {
|
|
|
1542
1542
|
// Remove hard limit if set
|
|
1543
1543
|
$module.removeAttribute('maxlength');
|
|
1544
1544
|
|
|
1545
|
-
//
|
|
1546
|
-
|
|
1547
|
-
|
|
1545
|
+
// When the page is restored after navigating 'back' in some browsers the
|
|
1546
|
+
// state of the character count is not restored until *after* the DOMContentLoaded
|
|
1547
|
+
// event is fired, so we need to sync after the pageshow event in browsers
|
|
1548
|
+
// that support it.
|
|
1549
|
+
if ('onpageshow' in window) {
|
|
1550
|
+
window.addEventListener('pageshow', this.sync.bind(this));
|
|
1551
|
+
} else {
|
|
1552
|
+
window.addEventListener('DOMContentLoaded', this.sync.bind(this));
|
|
1553
|
+
}
|
|
1548
1554
|
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1555
|
+
this.sync();
|
|
1556
|
+
};
|
|
1557
|
+
|
|
1558
|
+
CharacterCount.prototype.sync = function () {
|
|
1559
|
+
this.bindChangeEvents();
|
|
1560
|
+
this.updateCountMessage();
|
|
1552
1561
|
};
|
|
1553
1562
|
|
|
1554
1563
|
// Read data attributes
|
|
@@ -1596,8 +1605,7 @@ CharacterCount.prototype.checkIfValueChanged = function () {
|
|
|
1596
1605
|
if (!this.$textarea.oldValue) this.$textarea.oldValue = '';
|
|
1597
1606
|
if (this.$textarea.value !== this.$textarea.oldValue) {
|
|
1598
1607
|
this.$textarea.oldValue = this.$textarea.value;
|
|
1599
|
-
|
|
1600
|
-
boundUpdateCountMessage();
|
|
1608
|
+
this.updateCountMessage();
|
|
1601
1609
|
}
|
|
1602
1610
|
};
|
|
1603
1611
|
|
|
@@ -1666,52 +1674,157 @@ function Checkboxes ($module) {
|
|
|
1666
1674
|
this.$inputs = $module.querySelectorAll('input[type="checkbox"]');
|
|
1667
1675
|
}
|
|
1668
1676
|
|
|
1677
|
+
/**
|
|
1678
|
+
* Initialise Checkboxes
|
|
1679
|
+
*
|
|
1680
|
+
* Checkboxes can be associated with a 'conditionally revealed' content block –
|
|
1681
|
+
* for example, a checkbox for 'Phone' could reveal an additional form field for
|
|
1682
|
+
* the user to enter their phone number.
|
|
1683
|
+
*
|
|
1684
|
+
* These associations are made using a `data-aria-controls` attribute, which is
|
|
1685
|
+
* promoted to an aria-controls attribute during initialisation.
|
|
1686
|
+
*
|
|
1687
|
+
* We also need to restore the state of any conditional reveals on the page (for
|
|
1688
|
+
* example if the user has navigated back), and set up event handlers to keep
|
|
1689
|
+
* the reveal in sync with the checkbox state.
|
|
1690
|
+
*/
|
|
1669
1691
|
Checkboxes.prototype.init = function () {
|
|
1670
1692
|
var $module = this.$module;
|
|
1671
1693
|
var $inputs = this.$inputs;
|
|
1672
1694
|
|
|
1673
|
-
/**
|
|
1674
|
-
* Loop over all items with [data-controls]
|
|
1675
|
-
* Check if they have a matching conditional reveal
|
|
1676
|
-
* If they do, assign attributes.
|
|
1677
|
-
**/
|
|
1678
1695
|
nodeListForEach($inputs, function ($input) {
|
|
1679
|
-
var
|
|
1696
|
+
var target = $input.getAttribute('data-aria-controls');
|
|
1680
1697
|
|
|
1681
|
-
//
|
|
1682
|
-
//
|
|
1683
|
-
if (!
|
|
1698
|
+
// Skip checkboxes without data-aria-controls attributes, or where the
|
|
1699
|
+
// target element does not exist.
|
|
1700
|
+
if (!target || !$module.querySelector('#' + target)) {
|
|
1684
1701
|
return
|
|
1685
1702
|
}
|
|
1686
1703
|
|
|
1687
|
-
//
|
|
1688
|
-
|
|
1704
|
+
// Promote the data-aria-controls attribute to a aria-controls attribute
|
|
1705
|
+
// so that the relationship is exposed in the AOM
|
|
1706
|
+
$input.setAttribute('aria-controls', target);
|
|
1689
1707
|
$input.removeAttribute('data-aria-controls');
|
|
1690
|
-
|
|
1691
|
-
|
|
1708
|
+
});
|
|
1709
|
+
|
|
1710
|
+
// When the page is restored after navigating 'back' in some browsers the
|
|
1711
|
+
// state of form controls is not restored until *after* the DOMContentLoaded
|
|
1712
|
+
// event is fired, so we need to sync after the pageshow event in browsers
|
|
1713
|
+
// that support it.
|
|
1714
|
+
if ('onpageshow' in window) {
|
|
1715
|
+
window.addEventListener('pageshow', this.syncAllConditionalReveals.bind(this));
|
|
1716
|
+
} else {
|
|
1717
|
+
window.addEventListener('DOMContentLoaded', this.syncAllConditionalReveals.bind(this));
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
// Although we've set up handlers to sync state on the pageshow or
|
|
1721
|
+
// DOMContentLoaded event, init could be called after those events have fired,
|
|
1722
|
+
// for example if they are added to the page dynamically, so sync now too.
|
|
1723
|
+
this.syncAllConditionalReveals();
|
|
1692
1724
|
|
|
1693
|
-
// Handle events
|
|
1694
1725
|
$module.addEventListener('click', this.handleClick.bind(this));
|
|
1695
1726
|
};
|
|
1696
1727
|
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1728
|
+
/**
|
|
1729
|
+
* Sync the conditional reveal states for all inputs in this $module.
|
|
1730
|
+
*/
|
|
1731
|
+
Checkboxes.prototype.syncAllConditionalReveals = function () {
|
|
1732
|
+
nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this));
|
|
1733
|
+
};
|
|
1700
1734
|
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1735
|
+
/**
|
|
1736
|
+
* Sync conditional reveal with the input state
|
|
1737
|
+
*
|
|
1738
|
+
* Synchronise the visibility of the conditional reveal, and its accessible
|
|
1739
|
+
* state, with the input's checked state.
|
|
1740
|
+
*
|
|
1741
|
+
* @param {HTMLInputElement} $input Checkbox input
|
|
1742
|
+
*/
|
|
1743
|
+
Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
|
|
1744
|
+
var $target = this.$module.querySelector('#' + $input.getAttribute('aria-controls'));
|
|
1745
|
+
|
|
1746
|
+
if ($target && $target.classList.contains('govuk-checkboxes__conditional')) {
|
|
1747
|
+
var inputIsChecked = $input.checked;
|
|
1748
|
+
|
|
1749
|
+
$input.setAttribute('aria-expanded', inputIsChecked);
|
|
1750
|
+
$target.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked);
|
|
1704
1751
|
}
|
|
1705
1752
|
};
|
|
1706
1753
|
|
|
1754
|
+
/**
|
|
1755
|
+
* Uncheck other checkboxes
|
|
1756
|
+
*
|
|
1757
|
+
* Find any other checkbox inputs with the same name value, and uncheck them.
|
|
1758
|
+
* This is useful for when a “None of these" checkbox is checked.
|
|
1759
|
+
*/
|
|
1760
|
+
Checkboxes.prototype.unCheckAllInputsExcept = function ($input) {
|
|
1761
|
+
var allInputsWithSameName = document.querySelectorAll('input[type="checkbox"][name="' + $input.name + '"]');
|
|
1762
|
+
|
|
1763
|
+
nodeListForEach(allInputsWithSameName, function ($inputWithSameName) {
|
|
1764
|
+
var hasSameFormOwner = ($input.form === $inputWithSameName.form);
|
|
1765
|
+
if (hasSameFormOwner && $inputWithSameName !== $input) {
|
|
1766
|
+
$inputWithSameName.checked = false;
|
|
1767
|
+
}
|
|
1768
|
+
});
|
|
1769
|
+
|
|
1770
|
+
this.syncAllConditionalReveals();
|
|
1771
|
+
};
|
|
1772
|
+
|
|
1773
|
+
/**
|
|
1774
|
+
* Uncheck exclusive inputs
|
|
1775
|
+
*
|
|
1776
|
+
* Find any checkbox inputs with the same name value and the 'exclusive' behaviour,
|
|
1777
|
+
* and uncheck them. This helps prevent someone checking both a regular checkbox and a
|
|
1778
|
+
* "None of these" checkbox in the same fieldset.
|
|
1779
|
+
*/
|
|
1780
|
+
Checkboxes.prototype.unCheckExclusiveInputs = function ($input) {
|
|
1781
|
+
var allInputsWithSameNameAndExclusiveBehaviour = document.querySelectorAll(
|
|
1782
|
+
'input[data-behaviour="exclusive"][type="checkbox"][name="' + $input.name + '"]'
|
|
1783
|
+
);
|
|
1784
|
+
|
|
1785
|
+
nodeListForEach(allInputsWithSameNameAndExclusiveBehaviour, function ($exclusiveInput) {
|
|
1786
|
+
var hasSameFormOwner = ($input.form === $exclusiveInput.form);
|
|
1787
|
+
if (hasSameFormOwner) {
|
|
1788
|
+
$exclusiveInput.checked = false;
|
|
1789
|
+
}
|
|
1790
|
+
});
|
|
1791
|
+
|
|
1792
|
+
this.syncAllConditionalReveals();
|
|
1793
|
+
};
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* Click event handler
|
|
1797
|
+
*
|
|
1798
|
+
* Handle a click within the $module – if the click occurred on a checkbox, sync
|
|
1799
|
+
* the state of any associated conditional reveal with the checkbox state.
|
|
1800
|
+
*
|
|
1801
|
+
* @param {MouseEvent} event Click event
|
|
1802
|
+
*/
|
|
1707
1803
|
Checkboxes.prototype.handleClick = function (event) {
|
|
1708
1804
|
var $target = event.target;
|
|
1709
1805
|
|
|
1710
|
-
//
|
|
1711
|
-
|
|
1806
|
+
// Ignore clicks on things that aren't checkbox inputs
|
|
1807
|
+
if ($target.type !== 'checkbox') {
|
|
1808
|
+
return
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
// If the checkbox conditionally-reveals some content, sync the state
|
|
1712
1812
|
var hasAriaControls = $target.getAttribute('aria-controls');
|
|
1713
|
-
if (
|
|
1714
|
-
this.
|
|
1813
|
+
if (hasAriaControls) {
|
|
1814
|
+
this.syncConditionalRevealWithInputState($target);
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
// No further behaviour needed for unchecking
|
|
1818
|
+
if (!$target.checked) {
|
|
1819
|
+
return
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
// Handle 'exclusive' checkbox behaviour (ie "None of these")
|
|
1823
|
+
var hasBehaviourExclusive = ($target.getAttribute('data-behaviour') === 'exclusive');
|
|
1824
|
+
if (hasBehaviourExclusive) {
|
|
1825
|
+
this.unCheckAllInputsExcept($target);
|
|
1826
|
+
} else {
|
|
1827
|
+
this.unCheckExclusiveInputs($target);
|
|
1715
1828
|
}
|
|
1716
1829
|
};
|
|
1717
1830
|
|
|
@@ -1904,122 +2017,216 @@ ErrorSummary.prototype.getAssociatedLegendOrLabel = function ($input) {
|
|
|
1904
2017
|
$input.closest('label')
|
|
1905
2018
|
};
|
|
1906
2019
|
|
|
1907
|
-
function
|
|
2020
|
+
function NotificationBanner ($module) {
|
|
1908
2021
|
this.$module = $module;
|
|
1909
2022
|
}
|
|
1910
2023
|
|
|
1911
|
-
|
|
1912
|
-
|
|
2024
|
+
/**
|
|
2025
|
+
* Initialise the component
|
|
2026
|
+
*/
|
|
2027
|
+
NotificationBanner.prototype.init = function () {
|
|
1913
2028
|
var $module = this.$module;
|
|
2029
|
+
// Check for module
|
|
1914
2030
|
if (!$module) {
|
|
1915
2031
|
return
|
|
1916
2032
|
}
|
|
1917
2033
|
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2034
|
+
this.setFocus();
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
/**
|
|
2038
|
+
* Focus the element
|
|
2039
|
+
*
|
|
2040
|
+
* If `role="alert"` is set, focus the element to help some assistive technologies
|
|
2041
|
+
* prioritise announcing it.
|
|
2042
|
+
*
|
|
2043
|
+
* You can turn off the auto-focus functionality by setting `data-disable-auto-focus="true"` in the
|
|
2044
|
+
* component HTML. You might wish to do this based on user research findings, or to avoid a clash
|
|
2045
|
+
* with another element which should be focused when the page loads.
|
|
2046
|
+
*/
|
|
2047
|
+
NotificationBanner.prototype.setFocus = function () {
|
|
2048
|
+
var $module = this.$module;
|
|
2049
|
+
|
|
2050
|
+
if ($module.getAttribute('data-disable-auto-focus') === 'true') {
|
|
1921
2051
|
return
|
|
1922
2052
|
}
|
|
1923
2053
|
|
|
1924
|
-
|
|
1925
|
-
|
|
2054
|
+
if ($module.getAttribute('role') !== 'alert') {
|
|
2055
|
+
return
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
// Set tabindex to -1 to make the element focusable with JavaScript.
|
|
2059
|
+
// Remove the tabindex on blur as the component doesn't need to be focusable after the page has
|
|
2060
|
+
// loaded.
|
|
2061
|
+
if (!$module.getAttribute('tabindex')) {
|
|
2062
|
+
$module.setAttribute('tabindex', '-1');
|
|
2063
|
+
|
|
2064
|
+
$module.addEventListener('blur', function () {
|
|
2065
|
+
$module.removeAttribute('tabindex');
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
$module.focus();
|
|
1926
2070
|
};
|
|
1927
2071
|
|
|
2072
|
+
function Header ($module) {
|
|
2073
|
+
this.$module = $module;
|
|
2074
|
+
this.$menuButton = $module && $module.querySelector('.govuk-js-header-toggle');
|
|
2075
|
+
this.$menu = this.$menuButton && $module.querySelector(
|
|
2076
|
+
'#' + this.$menuButton.getAttribute('aria-controls')
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
|
|
1928
2080
|
/**
|
|
1929
|
-
*
|
|
1930
|
-
*
|
|
1931
|
-
*
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
node.className += ' ' + className;
|
|
2081
|
+
* Initialise header
|
|
2082
|
+
*
|
|
2083
|
+
* Check for the presence of the header, menu and menu button – if any are
|
|
2084
|
+
* missing then there's nothing to do so return early.
|
|
2085
|
+
*/
|
|
2086
|
+
Header.prototype.init = function () {
|
|
2087
|
+
if (!this.$module || !this.$menuButton || !this.$menu) {
|
|
2088
|
+
return
|
|
1938
2089
|
}
|
|
2090
|
+
|
|
2091
|
+
this.syncState(this.$menu.classList.contains('govuk-header__navigation--open'));
|
|
2092
|
+
this.$menuButton.addEventListener('click', this.handleMenuButtonClick.bind(this));
|
|
1939
2093
|
};
|
|
1940
2094
|
|
|
1941
2095
|
/**
|
|
1942
|
-
*
|
|
1943
|
-
*
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
this.toggleClass($toggleButton, 'govuk-header__menu-button--open');
|
|
2096
|
+
* Sync menu state
|
|
2097
|
+
*
|
|
2098
|
+
* Sync the menu button class and the accessible state of the menu and the menu
|
|
2099
|
+
* button with the visible state of the menu
|
|
2100
|
+
*
|
|
2101
|
+
* @param {boolean} isVisible Whether the menu is currently visible
|
|
2102
|
+
*/
|
|
2103
|
+
Header.prototype.syncState = function (isVisible) {
|
|
2104
|
+
this.$menuButton.classList.toggle('govuk-header__menu-button--open', isVisible);
|
|
2105
|
+
this.$menuButton.setAttribute('aria-expanded', isVisible);
|
|
2106
|
+
};
|
|
1954
2107
|
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
2108
|
+
/**
|
|
2109
|
+
* Handle menu button click
|
|
2110
|
+
*
|
|
2111
|
+
* When the menu button is clicked, change the visibility of the menu and then
|
|
2112
|
+
* sync the accessibility state and menu button state
|
|
2113
|
+
*/
|
|
2114
|
+
Header.prototype.handleMenuButtonClick = function () {
|
|
2115
|
+
var isVisible = this.$menu.classList.toggle('govuk-header__navigation--open');
|
|
2116
|
+
this.syncState(isVisible);
|
|
1958
2117
|
};
|
|
1959
2118
|
|
|
1960
2119
|
function Radios ($module) {
|
|
1961
2120
|
this.$module = $module;
|
|
2121
|
+
this.$inputs = $module.querySelectorAll('input[type="radio"]');
|
|
1962
2122
|
}
|
|
1963
2123
|
|
|
2124
|
+
/**
|
|
2125
|
+
* Initialise Radios
|
|
2126
|
+
*
|
|
2127
|
+
* Radios can be associated with a 'conditionally revealed' content block – for
|
|
2128
|
+
* example, a radio for 'Phone' could reveal an additional form field for the
|
|
2129
|
+
* user to enter their phone number.
|
|
2130
|
+
*
|
|
2131
|
+
* These associations are made using a `data-aria-controls` attribute, which is
|
|
2132
|
+
* promoted to an aria-controls attribute during initialisation.
|
|
2133
|
+
*
|
|
2134
|
+
* We also need to restore the state of any conditional reveals on the page (for
|
|
2135
|
+
* example if the user has navigated back), and set up event handlers to keep
|
|
2136
|
+
* the reveal in sync with the radio state.
|
|
2137
|
+
*/
|
|
1964
2138
|
Radios.prototype.init = function () {
|
|
1965
2139
|
var $module = this.$module;
|
|
1966
|
-
var $inputs =
|
|
2140
|
+
var $inputs = this.$inputs;
|
|
1967
2141
|
|
|
1968
|
-
/**
|
|
1969
|
-
* Loop over all items with [data-controls]
|
|
1970
|
-
* Check if they have a matching conditional reveal
|
|
1971
|
-
* If they do, assign attributes.
|
|
1972
|
-
**/
|
|
1973
2142
|
nodeListForEach($inputs, function ($input) {
|
|
1974
|
-
var
|
|
2143
|
+
var target = $input.getAttribute('data-aria-controls');
|
|
1975
2144
|
|
|
1976
|
-
//
|
|
1977
|
-
//
|
|
1978
|
-
if (!
|
|
2145
|
+
// Skip radios without data-aria-controls attributes, or where the
|
|
2146
|
+
// target element does not exist.
|
|
2147
|
+
if (!target || !$module.querySelector('#' + target)) {
|
|
1979
2148
|
return
|
|
1980
2149
|
}
|
|
1981
2150
|
|
|
1982
|
-
//
|
|
1983
|
-
|
|
2151
|
+
// Promote the data-aria-controls attribute to a aria-controls attribute
|
|
2152
|
+
// so that the relationship is exposed in the AOM
|
|
2153
|
+
$input.setAttribute('aria-controls', target);
|
|
1984
2154
|
$input.removeAttribute('data-aria-controls');
|
|
1985
|
-
|
|
1986
|
-
|
|
2155
|
+
});
|
|
2156
|
+
|
|
2157
|
+
// When the page is restored after navigating 'back' in some browsers the
|
|
2158
|
+
// state of form controls is not restored until *after* the DOMContentLoaded
|
|
2159
|
+
// event is fired, so we need to sync after the pageshow event in browsers
|
|
2160
|
+
// that support it.
|
|
2161
|
+
if ('onpageshow' in window) {
|
|
2162
|
+
window.addEventListener('pageshow', this.syncAllConditionalReveals.bind(this));
|
|
2163
|
+
} else {
|
|
2164
|
+
window.addEventListener('DOMContentLoaded', this.syncAllConditionalReveals.bind(this));
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
// Although we've set up handlers to sync state on the pageshow or
|
|
2168
|
+
// DOMContentLoaded event, init could be called after those events have fired,
|
|
2169
|
+
// for example if they are added to the page dynamically, so sync now too.
|
|
2170
|
+
this.syncAllConditionalReveals();
|
|
1987
2171
|
|
|
1988
2172
|
// Handle events
|
|
1989
2173
|
$module.addEventListener('click', this.handleClick.bind(this));
|
|
1990
2174
|
};
|
|
1991
2175
|
|
|
1992
|
-
|
|
1993
|
-
|
|
2176
|
+
/**
|
|
2177
|
+
* Sync the conditional reveal states for all inputs in this $module.
|
|
2178
|
+
*/
|
|
2179
|
+
Radios.prototype.syncAllConditionalReveals = function () {
|
|
2180
|
+
nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this));
|
|
2181
|
+
};
|
|
2182
|
+
|
|
2183
|
+
/**
|
|
2184
|
+
* Sync conditional reveal with the input state
|
|
2185
|
+
*
|
|
2186
|
+
* Synchronise the visibility of the conditional reveal, and its accessible
|
|
2187
|
+
* state, with the input's checked state.
|
|
2188
|
+
*
|
|
2189
|
+
* @param {HTMLInputElement} $input Radio input
|
|
2190
|
+
*/
|
|
2191
|
+
Radios.prototype.syncConditionalRevealWithInputState = function ($input) {
|
|
2192
|
+
var $target = document.querySelector('#' + $input.getAttribute('aria-controls'));
|
|
1994
2193
|
|
|
1995
|
-
if ($
|
|
2194
|
+
if ($target && $target.classList.contains('govuk-radios__conditional')) {
|
|
1996
2195
|
var inputIsChecked = $input.checked;
|
|
1997
2196
|
|
|
1998
2197
|
$input.setAttribute('aria-expanded', inputIsChecked);
|
|
1999
|
-
|
|
2000
|
-
$content.classList.toggle('govuk-radios__conditional--hidden', !inputIsChecked);
|
|
2198
|
+
$target.classList.toggle('govuk-radios__conditional--hidden', !inputIsChecked);
|
|
2001
2199
|
}
|
|
2002
2200
|
};
|
|
2003
2201
|
|
|
2202
|
+
/**
|
|
2203
|
+
* Click event handler
|
|
2204
|
+
*
|
|
2205
|
+
* Handle a click within the $module – if the click occurred on a radio, sync
|
|
2206
|
+
* the state of the conditional reveal for all radio buttons in the same form
|
|
2207
|
+
* with the same name (because checking one radio could have un-checked a radio
|
|
2208
|
+
* in another $module)
|
|
2209
|
+
*
|
|
2210
|
+
* @param {MouseEvent} event Click event
|
|
2211
|
+
*/
|
|
2004
2212
|
Radios.prototype.handleClick = function (event) {
|
|
2005
2213
|
var $clickedInput = event.target;
|
|
2006
|
-
|
|
2214
|
+
|
|
2215
|
+
// Ignore clicks on things that aren't radio buttons
|
|
2007
2216
|
if ($clickedInput.type !== 'radio') {
|
|
2008
2217
|
return
|
|
2009
2218
|
}
|
|
2010
|
-
|
|
2011
|
-
//
|
|
2012
|
-
//
|
|
2013
|
-
// We also only want radios which have aria-controls, as they support conditional reveals.
|
|
2219
|
+
|
|
2220
|
+
// We only need to consider radios with conditional reveals, which will have
|
|
2221
|
+
// aria-controls attributes.
|
|
2014
2222
|
var $allInputs = document.querySelectorAll('input[type="radio"][aria-controls]');
|
|
2223
|
+
|
|
2015
2224
|
nodeListForEach($allInputs, function ($input) {
|
|
2016
|
-
// Only inputs with the same form owner should change.
|
|
2017
2225
|
var hasSameFormOwner = ($input.form === $clickedInput.form);
|
|
2018
|
-
|
|
2019
|
-
// In radios, only radios with the same name will affect each other.
|
|
2020
2226
|
var hasSameName = ($input.name === $clickedInput.name);
|
|
2227
|
+
|
|
2021
2228
|
if (hasSameName && hasSameFormOwner) {
|
|
2022
|
-
this.
|
|
2229
|
+
this.syncConditionalRevealWithInputState($input);
|
|
2023
2230
|
}
|
|
2024
2231
|
}.bind(this));
|
|
2025
2232
|
};
|
|
@@ -2379,6 +2586,11 @@ function initAll (options) {
|
|
|
2379
2586
|
var $toggleButton = scope.querySelector('[data-module="govuk-header"]');
|
|
2380
2587
|
new Header($toggleButton).init();
|
|
2381
2588
|
|
|
2589
|
+
var $notificationBanners = scope.querySelectorAll('[data-module="govuk-notification-banner"]');
|
|
2590
|
+
nodeListForEach($notificationBanners, function ($notificationBanner) {
|
|
2591
|
+
new NotificationBanner($notificationBanner).init();
|
|
2592
|
+
});
|
|
2593
|
+
|
|
2382
2594
|
var $radios = scope.querySelectorAll('[data-module="govuk-radios"]');
|
|
2383
2595
|
nodeListForEach($radios, function ($radio) {
|
|
2384
2596
|
new Radios($radio).init();
|