govuk_tech_docs 3.2.0 → 3.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/publish.yaml +1 -1
- data/CHANGELOG.md +26 -7
- data/README.md +2 -2
- data/example/source/code.html.md +3 -26
- data/lib/govuk_tech_docs/contribution_banner.rb +1 -1
- data/lib/govuk_tech_docs/tech_docs_html_renderer.rb +3 -3
- data/lib/govuk_tech_docs/version.rb +1 -1
- data/lib/source/layouts/core.erb +1 -1
- data/node_modules/govuk-frontend/govuk/all.js +1548 -311
- data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +70 -0
- data/node_modules/govuk-frontend/govuk/common/index.js +172 -0
- data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +373 -0
- data/node_modules/govuk-frontend/govuk/common.js +138 -3
- data/node_modules/govuk-frontend/govuk/components/_all.scss +1 -0
- data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +5 -6
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +754 -36
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +0 -2
- data/node_modules/govuk-frontend/govuk/components/button/_index.scss +29 -21
- data/node_modules/govuk-frontend/govuk/components/button/button.js +365 -107
- data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +9 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +1092 -109
- data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +3 -2
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +30 -2
- data/node_modules/govuk-frontend/govuk/components/details/details.js +51 -33
- data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +289 -6
- data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +13 -23
- data/node_modules/govuk-frontend/govuk/components/header/_index.scss +30 -24
- data/node_modules/govuk-frontend/govuk/components/header/header.js +59 -11
- data/node_modules/govuk-frontend/govuk/components/input/_index.scss +13 -23
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +252 -2
- data/node_modules/govuk-frontend/govuk/components/pagination/_index.scss +247 -0
- data/node_modules/govuk-frontend/govuk/components/pagination/_pagination.scss +2 -0
- data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +5 -12
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js +30 -2
- data/node_modules/govuk-frontend/govuk/components/select/_index.scss +11 -0
- data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +1 -3
- data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +10 -4
- data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +45 -13
- data/node_modules/govuk-frontend/govuk/components/table/_index.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +28 -0
- data/node_modules/govuk-frontend/govuk/core/_section-break.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +5 -5
- data/node_modules/govuk-frontend/govuk/helpers/_focused.scss +5 -0
- data/node_modules/govuk-frontend/govuk/helpers/_links.scss +13 -11
- data/node_modules/govuk-frontend/govuk/helpers/_media-queries.scss +2 -2
- data/node_modules/govuk-frontend/govuk/helpers/_shape-arrow.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +3 -3
- data/node_modules/govuk-frontend/govuk/helpers/_typography.scss +16 -9
- data/node_modules/govuk-frontend/govuk/i18n.js +390 -0
- data/node_modules/govuk-frontend/govuk/objects/_button-group.scss +10 -26
- data/node_modules/govuk-frontend/govuk/objects/_template.scss +1 -1
- data/node_modules/govuk-frontend/govuk/objects/_width-container.scss +0 -4
- data/node_modules/govuk-frontend/govuk/overrides/_spacing.scss +56 -12
- data/node_modules/govuk-frontend/govuk/settings/_all.scss +1 -0
- data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +12 -0
- data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +26 -0
- data/node_modules/govuk-frontend/govuk/settings/_spacing.scss +4 -8
- data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +23 -0
- data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +12 -0
- data/node_modules/govuk-frontend/govuk/settings/_warnings.scss +53 -0
- data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +20 -6
- data/node_modules/govuk-frontend/govuk/tools/_exports.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_font-url.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_image-url.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_px-to-em.scss +2 -2
- data/node_modules/govuk-frontend/govuk/tools/_px-to-rem.scss +1 -1
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +21 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +300 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +21 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit/init.js +7 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit/init.scss +12 -0
- data/package-lock.json +12 -12
- data/package.json +1 -1
- metadata +17 -5
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
left: 0;
|
|
84
84
|
width: $govuk-checkboxes-size;
|
|
85
85
|
height: $govuk-checkboxes-size;
|
|
86
|
-
border: $govuk-border-width-form-element solid
|
|
86
|
+
border: $govuk-border-width-form-element solid currentcolor;
|
|
87
87
|
background: transparent;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -155,7 +155,8 @@
|
|
|
155
155
|
cursor: default;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
.govuk-checkboxes__input:disabled + .govuk-checkboxes__label
|
|
158
|
+
.govuk-checkboxes__input:disabled + .govuk-checkboxes__label,
|
|
159
|
+
.govuk-checkboxes__input:disabled ~ .govuk-hint {
|
|
159
160
|
opacity: .5;
|
|
160
161
|
}
|
|
161
162
|
|
|
@@ -1014,10 +1014,24 @@ if (detect) return
|
|
|
1014
1014
|
|
|
1015
1015
|
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
1016
1016
|
|
|
1017
|
+
/**
|
|
1018
|
+
* Common helpers which do not require polyfill.
|
|
1019
|
+
*
|
|
1020
|
+
* IMPORTANT: If a helper require a polyfill, please isolate it in its own module
|
|
1021
|
+
* so that the polyfill can be properly tree-shaken and does not burden
|
|
1022
|
+
* the components that do not need that helper
|
|
1023
|
+
*
|
|
1024
|
+
* @module common/index
|
|
1025
|
+
*/
|
|
1026
|
+
|
|
1017
1027
|
/**
|
|
1018
1028
|
* TODO: Ideally this would be a NodeList.prototype.forEach polyfill
|
|
1019
1029
|
* This seems to fail in IE8, requires more investigation.
|
|
1020
1030
|
* See: https://github.com/imagitama/nodelist-foreach-polyfill
|
|
1031
|
+
*
|
|
1032
|
+
* @param {NodeListOf<Element>} nodes - NodeList from querySelectorAll()
|
|
1033
|
+
* @param {nodeListIterator} callback - Callback function to run for each node
|
|
1034
|
+
* @returns {undefined}
|
|
1021
1035
|
*/
|
|
1022
1036
|
function nodeListForEach (nodes, callback) {
|
|
1023
1037
|
if (window.NodeList.prototype.forEach) {
|
|
@@ -1028,6 +1042,20 @@ function nodeListForEach (nodes, callback) {
|
|
|
1028
1042
|
}
|
|
1029
1043
|
}
|
|
1030
1044
|
|
|
1045
|
+
/**
|
|
1046
|
+
* @callback nodeListIterator
|
|
1047
|
+
* @param {Element} value - The current node being iterated on
|
|
1048
|
+
* @param {number} index - The current index in the iteration
|
|
1049
|
+
* @param {NodeListOf<Element>} nodes - NodeList from querySelectorAll()
|
|
1050
|
+
* @returns {undefined}
|
|
1051
|
+
*/
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Checkboxes component
|
|
1055
|
+
*
|
|
1056
|
+
* @class
|
|
1057
|
+
* @param {HTMLElement} $module - HTML element to use for checkboxes
|
|
1058
|
+
*/
|
|
1031
1059
|
function Checkboxes ($module) {
|
|
1032
1060
|
this.$module = $module;
|
|
1033
1061
|
this.$inputs = $module.querySelectorAll('input[type="checkbox"]');
|
|
@@ -1097,7 +1125,7 @@ Checkboxes.prototype.syncAllConditionalReveals = function () {
|
|
|
1097
1125
|
* Synchronise the visibility of the conditional reveal, and its accessible
|
|
1098
1126
|
* state, with the input's checked state.
|
|
1099
1127
|
*
|
|
1100
|
-
* @param {HTMLInputElement} $input Checkbox input
|
|
1128
|
+
* @param {HTMLInputElement} $input - Checkbox input
|
|
1101
1129
|
*/
|
|
1102
1130
|
Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
|
|
1103
1131
|
var $target = document.getElementById($input.getAttribute('aria-controls'));
|
|
@@ -1155,7 +1183,7 @@ Checkboxes.prototype.unCheckExclusiveInputs = function ($input) {
|
|
|
1155
1183
|
* Handle a click within the $module – if the click occurred on a checkbox, sync
|
|
1156
1184
|
* the state of any associated conditional reveal with the checkbox state.
|
|
1157
1185
|
*
|
|
1158
|
-
* @param {MouseEvent} event Click event
|
|
1186
|
+
* @param {MouseEvent} event - Click event
|
|
1159
1187
|
*/
|
|
1160
1188
|
Checkboxes.prototype.handleClick = function (event) {
|
|
1161
1189
|
var $target = event.target;
|
|
@@ -660,14 +660,22 @@ if (detect) return
|
|
|
660
660
|
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
661
661
|
|
|
662
662
|
/**
|
|
663
|
-
*
|
|
664
|
-
*
|
|
665
|
-
*
|
|
663
|
+
* Common helpers which do not require polyfill.
|
|
664
|
+
*
|
|
665
|
+
* IMPORTANT: If a helper require a polyfill, please isolate it in its own module
|
|
666
|
+
* so that the polyfill can be properly tree-shaken and does not burden
|
|
667
|
+
* the components that do not need that helper
|
|
668
|
+
*
|
|
669
|
+
* @module common/index
|
|
666
670
|
*/
|
|
667
671
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
672
|
+
/**
|
|
673
|
+
* Used to generate a unique string, allows multiple instances of the component
|
|
674
|
+
* without them conflicting with each other.
|
|
675
|
+
* https://stackoverflow.com/a/8809472
|
|
676
|
+
*
|
|
677
|
+
* @returns {string} Unique ID
|
|
678
|
+
*/
|
|
671
679
|
function generateUniqueID () {
|
|
672
680
|
var d = new Date().getTime();
|
|
673
681
|
if (typeof window.performance !== 'undefined' && typeof window.performance.now === 'function') {
|
|
@@ -680,6 +688,14 @@ function generateUniqueID () {
|
|
|
680
688
|
})
|
|
681
689
|
}
|
|
682
690
|
|
|
691
|
+
/**
|
|
692
|
+
* @callback nodeListIterator
|
|
693
|
+
* @param {Element} value - The current node being iterated on
|
|
694
|
+
* @param {number} index - The current index in the iteration
|
|
695
|
+
* @param {NodeListOf<Element>} nodes - NodeList from querySelectorAll()
|
|
696
|
+
* @returns {undefined}
|
|
697
|
+
*/
|
|
698
|
+
|
|
683
699
|
/**
|
|
684
700
|
* JavaScript 'polyfill' for HTML5's <details> and <summary> elements
|
|
685
701
|
* and 'shim' to add accessiblity enhancements for all browsers
|
|
@@ -690,6 +706,12 @@ function generateUniqueID () {
|
|
|
690
706
|
var KEY_ENTER = 13;
|
|
691
707
|
var KEY_SPACE = 32;
|
|
692
708
|
|
|
709
|
+
/**
|
|
710
|
+
* Details component
|
|
711
|
+
*
|
|
712
|
+
* @class
|
|
713
|
+
* @param {HTMLElement} $module - HTML element to use for details
|
|
714
|
+
*/
|
|
693
715
|
function Details ($module) {
|
|
694
716
|
this.$module = $module;
|
|
695
717
|
}
|
|
@@ -744,13 +766,10 @@ Details.prototype.polyfillDetails = function () {
|
|
|
744
766
|
$summary.tabIndex = 0;
|
|
745
767
|
|
|
746
768
|
// Detect initial open state
|
|
747
|
-
|
|
748
|
-
if (openAttr === true) {
|
|
769
|
+
if (this.$module.hasAttribute('open')) {
|
|
749
770
|
$summary.setAttribute('aria-expanded', 'true');
|
|
750
|
-
$content.setAttribute('aria-hidden', 'false');
|
|
751
771
|
} else {
|
|
752
772
|
$summary.setAttribute('aria-expanded', 'false');
|
|
753
|
-
$content.setAttribute('aria-hidden', 'true');
|
|
754
773
|
$content.style.display = 'none';
|
|
755
774
|
}
|
|
756
775
|
|
|
@@ -759,37 +778,30 @@ Details.prototype.polyfillDetails = function () {
|
|
|
759
778
|
};
|
|
760
779
|
|
|
761
780
|
/**
|
|
762
|
-
* Define a statechange function that updates aria-expanded and style.display
|
|
763
|
-
*
|
|
764
|
-
|
|
781
|
+
* Define a statechange function that updates aria-expanded and style.display
|
|
782
|
+
*
|
|
783
|
+
* @returns {boolean} Returns true
|
|
784
|
+
*/
|
|
765
785
|
Details.prototype.polyfillSetAttributes = function () {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
var expanded = $summary.getAttribute('aria-expanded') === 'true';
|
|
771
|
-
var hidden = $content.getAttribute('aria-hidden') === 'true';
|
|
772
|
-
|
|
773
|
-
$summary.setAttribute('aria-expanded', (expanded ? 'false' : 'true'));
|
|
774
|
-
$content.setAttribute('aria-hidden', (hidden ? 'false' : 'true'));
|
|
775
|
-
|
|
776
|
-
$content.style.display = (expanded ? 'none' : '');
|
|
777
|
-
|
|
778
|
-
var hasOpenAttr = $module.getAttribute('open') !== null;
|
|
779
|
-
if (!hasOpenAttr) {
|
|
780
|
-
$module.setAttribute('open', 'open');
|
|
786
|
+
if (this.$module.hasAttribute('open')) {
|
|
787
|
+
this.$module.removeAttribute('open');
|
|
788
|
+
this.$summary.setAttribute('aria-expanded', 'false');
|
|
789
|
+
this.$content.style.display = 'none';
|
|
781
790
|
} else {
|
|
782
|
-
|
|
791
|
+
this.$module.setAttribute('open', 'open');
|
|
792
|
+
this.$summary.setAttribute('aria-expanded', 'true');
|
|
793
|
+
this.$content.style.display = '';
|
|
783
794
|
}
|
|
784
795
|
|
|
785
796
|
return true
|
|
786
797
|
};
|
|
787
798
|
|
|
788
799
|
/**
|
|
789
|
-
* Handle cross-modal click events
|
|
790
|
-
*
|
|
791
|
-
* @param {
|
|
792
|
-
|
|
800
|
+
* Handle cross-modal click events
|
|
801
|
+
*
|
|
802
|
+
* @param {object} node - element
|
|
803
|
+
* @param {polyfillHandleInputsCallback} callback - function
|
|
804
|
+
*/
|
|
793
805
|
Details.prototype.polyfillHandleInputs = function (node, callback) {
|
|
794
806
|
node.addEventListener('keypress', function (event) {
|
|
795
807
|
var target = event.target;
|
|
@@ -823,6 +835,12 @@ Details.prototype.polyfillHandleInputs = function (node, callback) {
|
|
|
823
835
|
node.addEventListener('click', callback);
|
|
824
836
|
};
|
|
825
837
|
|
|
838
|
+
/**
|
|
839
|
+
* @callback polyfillHandleInputsCallback
|
|
840
|
+
* @param {KeyboardEvent} event - Keyboard event
|
|
841
|
+
* @returns {undefined}
|
|
842
|
+
*/
|
|
843
|
+
|
|
826
844
|
return Details;
|
|
827
845
|
|
|
828
846
|
})));
|
|
@@ -706,8 +706,262 @@ if (detect) return
|
|
|
706
706
|
|
|
707
707
|
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
708
708
|
|
|
709
|
-
|
|
709
|
+
/**
|
|
710
|
+
* Common helpers which do not require polyfill.
|
|
711
|
+
*
|
|
712
|
+
* IMPORTANT: If a helper require a polyfill, please isolate it in its own module
|
|
713
|
+
* so that the polyfill can be properly tree-shaken and does not burden
|
|
714
|
+
* the components that do not need that helper
|
|
715
|
+
*
|
|
716
|
+
* @module common/index
|
|
717
|
+
*/
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Config flattening function
|
|
721
|
+
*
|
|
722
|
+
* Takes any number of objects, flattens them into namespaced key-value pairs,
|
|
723
|
+
* (e.g. {'i18n.showSection': 'Show section'}) and combines them together, with
|
|
724
|
+
* greatest priority on the LAST item passed in.
|
|
725
|
+
*
|
|
726
|
+
* @returns {object} A flattened object of key-value pairs.
|
|
727
|
+
*/
|
|
728
|
+
function mergeConfigs (/* configObject1, configObject2, ...configObjects */) {
|
|
729
|
+
/**
|
|
730
|
+
* Function to take nested objects and flatten them to a dot-separated keyed
|
|
731
|
+
* object. Doing this means we don't need to do any deep/recursive merging of
|
|
732
|
+
* each of our objects, nor transform our dataset from a flat list into a
|
|
733
|
+
* nested object.
|
|
734
|
+
*
|
|
735
|
+
* @param {object} configObject - Deeply nested object
|
|
736
|
+
* @returns {object} Flattened object with dot-separated keys
|
|
737
|
+
*/
|
|
738
|
+
var flattenObject = function (configObject) {
|
|
739
|
+
// Prepare an empty return object
|
|
740
|
+
var flattenedObject = {};
|
|
741
|
+
|
|
742
|
+
// Our flattening function, this is called recursively for each level of
|
|
743
|
+
// depth in the object. At each level we prepend the previous level names to
|
|
744
|
+
// the key using `prefix`.
|
|
745
|
+
var flattenLoop = function (obj, prefix) {
|
|
746
|
+
// Loop through keys...
|
|
747
|
+
for (var key in obj) {
|
|
748
|
+
// Check to see if this is a prototypical key/value,
|
|
749
|
+
// if it is, skip it.
|
|
750
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
751
|
+
continue
|
|
752
|
+
}
|
|
753
|
+
var value = obj[key];
|
|
754
|
+
var prefixedKey = prefix ? prefix + '.' + key : key;
|
|
755
|
+
if (typeof value === 'object') {
|
|
756
|
+
// If the value is a nested object, recurse over that too
|
|
757
|
+
flattenLoop(value, prefixedKey);
|
|
758
|
+
} else {
|
|
759
|
+
// Otherwise, add this value to our return object
|
|
760
|
+
flattenedObject[prefixedKey] = value;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
// Kick off the recursive loop
|
|
766
|
+
flattenLoop(configObject);
|
|
767
|
+
return flattenedObject
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
// Start with an empty object as our base
|
|
771
|
+
var formattedConfigObject = {};
|
|
772
|
+
|
|
773
|
+
// Loop through each of the remaining passed objects and push their keys
|
|
774
|
+
// one-by-one into configObject. Any duplicate keys will override the existing
|
|
775
|
+
// key with the new value.
|
|
776
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
777
|
+
var obj = flattenObject(arguments[i]);
|
|
778
|
+
for (var key in obj) {
|
|
779
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
780
|
+
formattedConfigObject[key] = obj[key];
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
return formattedConfigObject
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* @callback nodeListIterator
|
|
790
|
+
* @param {Element} value - The current node being iterated on
|
|
791
|
+
* @param {number} index - The current index in the iteration
|
|
792
|
+
* @param {NodeListOf<Element>} nodes - NodeList from querySelectorAll()
|
|
793
|
+
* @returns {undefined}
|
|
794
|
+
*/
|
|
795
|
+
|
|
796
|
+
(function(undefined) {
|
|
797
|
+
|
|
798
|
+
// Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-library/13cf7c340974d128d557580b5e2dafcd1b1192d1/polyfills/Element/prototype/dataset/detect.js
|
|
799
|
+
var detect = (function(){
|
|
800
|
+
if (!document.documentElement.dataset) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
var el = document.createElement('div');
|
|
804
|
+
el.setAttribute("data-a-b", "c");
|
|
805
|
+
return el.dataset && el.dataset.aB == "c";
|
|
806
|
+
}());
|
|
807
|
+
|
|
808
|
+
if (detect) return
|
|
809
|
+
|
|
810
|
+
// Polyfill derived from https://raw.githubusercontent.com/Financial-Times/polyfill-library/13cf7c340974d128d557580b5e2dafcd1b1192d1/polyfills/Element/prototype/dataset/polyfill.js
|
|
811
|
+
Object.defineProperty(Element.prototype, 'dataset', {
|
|
812
|
+
get: function() {
|
|
813
|
+
var element = this;
|
|
814
|
+
var attributes = this.attributes;
|
|
815
|
+
var map = {};
|
|
816
|
+
|
|
817
|
+
for (var i = 0; i < attributes.length; i++) {
|
|
818
|
+
var attribute = attributes[i];
|
|
819
|
+
|
|
820
|
+
// This regex has been edited from the original polyfill, to add
|
|
821
|
+
// support for period (.) separators in data-* attribute names. These
|
|
822
|
+
// are allowed in the HTML spec, but were not covered by the original
|
|
823
|
+
// polyfill's regex. We use periods in our i18n implementation.
|
|
824
|
+
if (attribute && attribute.name && (/^data-\w[.\w-]*$/).test(attribute.name)) {
|
|
825
|
+
var name = attribute.name;
|
|
826
|
+
var value = attribute.value;
|
|
827
|
+
|
|
828
|
+
var propName = name.substr(5).replace(/-./g, function (prop) {
|
|
829
|
+
return prop.charAt(1).toUpperCase();
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
// If this browser supports __defineGetter__ and __defineSetter__,
|
|
833
|
+
// continue using defineProperty. If not (like IE 8 and below), we use
|
|
834
|
+
// a hacky fallback which at least gives an object in the right format
|
|
835
|
+
if ('__defineGetter__' in Object.prototype && '__defineSetter__' in Object.prototype) {
|
|
836
|
+
Object.defineProperty(map, propName, {
|
|
837
|
+
enumerable: true,
|
|
838
|
+
get: function() {
|
|
839
|
+
return this.value;
|
|
840
|
+
}.bind({value: value || ''}),
|
|
841
|
+
set: function setter(name, value) {
|
|
842
|
+
if (typeof value !== 'undefined') {
|
|
843
|
+
this.setAttribute(name, value);
|
|
844
|
+
} else {
|
|
845
|
+
this.removeAttribute(name);
|
|
846
|
+
}
|
|
847
|
+
}.bind(element, name)
|
|
848
|
+
});
|
|
849
|
+
} else {
|
|
850
|
+
map[propName] = value;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return map;
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
861
|
+
|
|
862
|
+
(function(undefined) {
|
|
863
|
+
|
|
864
|
+
// Detection from https://github.com/mdn/content/blob/cf607d68522cd35ee7670782d3ee3a361eaef2e4/files/en-us/web/javascript/reference/global_objects/string/trim/index.md#polyfill
|
|
865
|
+
var detect = ('trim' in String.prototype);
|
|
866
|
+
|
|
867
|
+
if (detect) return
|
|
868
|
+
|
|
869
|
+
// Polyfill from https://github.com/mdn/content/blob/cf607d68522cd35ee7670782d3ee3a361eaef2e4/files/en-us/web/javascript/reference/global_objects/string/trim/index.md#polyfill
|
|
870
|
+
String.prototype.trim = function () {
|
|
871
|
+
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
|
872
|
+
};
|
|
873
|
+
|
|
874
|
+
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Normalise string
|
|
878
|
+
*
|
|
879
|
+
* 'If it looks like a duck, and it quacks like a duck…' 🦆
|
|
880
|
+
*
|
|
881
|
+
* If the passed value looks like a boolean or a number, convert it to a boolean
|
|
882
|
+
* or number.
|
|
883
|
+
*
|
|
884
|
+
* Designed to be used to convert config passed via data attributes (which are
|
|
885
|
+
* always strings) into something sensible.
|
|
886
|
+
*
|
|
887
|
+
* @param {string} value - The value to normalise
|
|
888
|
+
* @returns {string | boolean | number | undefined} Normalised data
|
|
889
|
+
*/
|
|
890
|
+
function normaliseString (value) {
|
|
891
|
+
if (typeof value !== 'string') {
|
|
892
|
+
return value
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
var trimmedValue = value.trim();
|
|
896
|
+
|
|
897
|
+
if (trimmedValue === 'true') {
|
|
898
|
+
return true
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (trimmedValue === 'false') {
|
|
902
|
+
return false
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Empty / whitespace-only strings are considered finite so we need to check
|
|
906
|
+
// the length of the trimmed string as well
|
|
907
|
+
if (trimmedValue.length > 0 && isFinite(trimmedValue)) {
|
|
908
|
+
return Number(trimmedValue)
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
return value
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Normalise dataset
|
|
916
|
+
*
|
|
917
|
+
* Loop over an object and normalise each value using normaliseData function
|
|
918
|
+
*
|
|
919
|
+
* @param {DOMStringMap} dataset - HTML element dataset
|
|
920
|
+
* @returns {Object<string, string | boolean | number | undefined>} Normalised dataset
|
|
921
|
+
*/
|
|
922
|
+
function normaliseDataset (dataset) {
|
|
923
|
+
var out = {};
|
|
924
|
+
|
|
925
|
+
for (var key in dataset) {
|
|
926
|
+
out[key] = normaliseString(dataset[key]);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
return out
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* JavaScript enhancements for the ErrorSummary
|
|
934
|
+
*
|
|
935
|
+
* Takes focus on initialisation for accessible announcement, unless disabled in configuration.
|
|
936
|
+
*
|
|
937
|
+
* @class
|
|
938
|
+
* @param {HTMLElement} $module - The element this component controls
|
|
939
|
+
* @param {ErrorSummaryConfig} config - Error summary config
|
|
940
|
+
*/
|
|
941
|
+
function ErrorSummary ($module, config) {
|
|
942
|
+
// Some consuming code may not be passing a module,
|
|
943
|
+
// for example if they initialise the component
|
|
944
|
+
// on their own by directly passing the result
|
|
945
|
+
// of `document.querySelector`.
|
|
946
|
+
// To avoid breaking further JavaScript initialisation
|
|
947
|
+
// we need to safeguard against this so things keep
|
|
948
|
+
// working the same now we read the elements data attributes
|
|
949
|
+
if (!$module) {
|
|
950
|
+
// Little safety in case code gets ported as-is
|
|
951
|
+
// into and ES6 class constructor, where the return value matters
|
|
952
|
+
return this
|
|
953
|
+
}
|
|
954
|
+
|
|
710
955
|
this.$module = $module;
|
|
956
|
+
|
|
957
|
+
var defaultConfig = {
|
|
958
|
+
disableAutoFocus: false
|
|
959
|
+
};
|
|
960
|
+
this.config = mergeConfigs(
|
|
961
|
+
defaultConfig,
|
|
962
|
+
config || {},
|
|
963
|
+
normaliseDataset($module.dataset)
|
|
964
|
+
);
|
|
711
965
|
}
|
|
712
966
|
|
|
713
967
|
ErrorSummary.prototype.init = function () {
|
|
@@ -715,16 +969,37 @@ ErrorSummary.prototype.init = function () {
|
|
|
715
969
|
if (!$module) {
|
|
716
970
|
return
|
|
717
971
|
}
|
|
718
|
-
$module.focus();
|
|
719
972
|
|
|
973
|
+
this.setFocus();
|
|
720
974
|
$module.addEventListener('click', this.handleClick.bind(this));
|
|
721
975
|
};
|
|
722
976
|
|
|
723
977
|
/**
|
|
724
|
-
*
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
978
|
+
* Focus the error summary
|
|
979
|
+
*/
|
|
980
|
+
ErrorSummary.prototype.setFocus = function () {
|
|
981
|
+
var $module = this.$module;
|
|
982
|
+
|
|
983
|
+
if (this.config.disableAutoFocus) {
|
|
984
|
+
return
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Set tabindex to -1 to make the element programmatically focusable, but
|
|
988
|
+
// remove it on blur as the error summary doesn't need to be focused again.
|
|
989
|
+
$module.setAttribute('tabindex', '-1');
|
|
990
|
+
|
|
991
|
+
$module.addEventListener('blur', function () {
|
|
992
|
+
$module.removeAttribute('tabindex');
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
$module.focus();
|
|
996
|
+
};
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Click event handler
|
|
1000
|
+
*
|
|
1001
|
+
* @param {MouseEvent} event - Click event
|
|
1002
|
+
*/
|
|
728
1003
|
ErrorSummary.prototype.handleClick = function (event) {
|
|
729
1004
|
var target = event.target;
|
|
730
1005
|
if (this.focusTarget(target)) {
|
|
@@ -848,6 +1123,14 @@ ErrorSummary.prototype.getAssociatedLegendOrLabel = function ($input) {
|
|
|
848
1123
|
$input.closest('label')
|
|
849
1124
|
};
|
|
850
1125
|
|
|
1126
|
+
/**
|
|
1127
|
+
* Error summary config
|
|
1128
|
+
*
|
|
1129
|
+
* @typedef {object} ErrorSummaryConfig
|
|
1130
|
+
* @property {boolean} [disableAutoFocus = false] -
|
|
1131
|
+
* If set to `true` the error summary will not be focussed when the page loads.
|
|
1132
|
+
*/
|
|
1133
|
+
|
|
851
1134
|
return ErrorSummary;
|
|
852
1135
|
|
|
853
1136
|
})));
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
$govuk-footer-text: $govuk-text-colour;
|
|
9
9
|
$govuk-footer-link-hover-colour: null; // Only used with the legacy palette
|
|
10
10
|
|
|
11
|
-
@if
|
|
11
|
+
@if $govuk-use-legacy-palette {
|
|
12
12
|
$govuk-footer-border-top: #a1acb2;
|
|
13
13
|
$govuk-footer-border: govuk-colour("grey-2");
|
|
14
14
|
$govuk-footer-text: #454a4c;
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
.govuk-footer__link {
|
|
36
36
|
@include govuk-link-common;
|
|
37
37
|
|
|
38
|
-
@if
|
|
38
|
+
@if $govuk-use-legacy-palette {
|
|
39
39
|
&:link,
|
|
40
40
|
&:visited {
|
|
41
41
|
color: $govuk-footer-text;
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
// alphagov/govuk_template includes a specific a:link:focus selector
|
|
53
53
|
// designed to make unvisited links a slightly darker blue when focussed, so
|
|
54
54
|
// we need to override the text colour for that combination of selectors.
|
|
55
|
-
@include
|
|
55
|
+
@include _govuk-compatibility(govuk_template) {
|
|
56
56
|
&:link:focus {
|
|
57
57
|
@include govuk-text-colour;
|
|
58
58
|
}
|
|
@@ -67,23 +67,16 @@
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
.govuk-footer__meta {
|
|
70
|
-
display: -webkit-box;
|
|
71
|
-
display: -webkit-flex;
|
|
72
70
|
display: -ms-flexbox;
|
|
73
71
|
display: flex; // Support: Flexbox
|
|
74
72
|
margin-right: -$govuk-gutter-half;
|
|
75
73
|
margin-left: -$govuk-gutter-half;
|
|
76
|
-
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
align-items: flex-end; // Support: Flexbox
|
|
83
|
-
-webkit-box-pack: center;
|
|
84
|
-
-webkit-justify-content: center;
|
|
85
|
-
-ms-flex-pack: center;
|
|
86
|
-
justify-content: center; // Support: Flexbox
|
|
74
|
+
-ms-flex-wrap: wrap;
|
|
75
|
+
flex-wrap: wrap; // Support: Flexbox
|
|
76
|
+
-ms-flex-align: end;
|
|
77
|
+
align-items: flex-end; // Support: Flexbox
|
|
78
|
+
-ms-flex-pack: center;
|
|
79
|
+
justify-content: center; // Support: Flexbox
|
|
87
80
|
}
|
|
88
81
|
|
|
89
82
|
.govuk-footer__meta-item {
|
|
@@ -93,14 +86,11 @@
|
|
|
93
86
|
}
|
|
94
87
|
|
|
95
88
|
.govuk-footer__meta-item--grow {
|
|
96
|
-
-
|
|
97
|
-
|
|
98
|
-
-ms-flex: 1;
|
|
99
|
-
flex: 1; // Support: Flexbox
|
|
89
|
+
-ms-flex: 1;
|
|
90
|
+
flex: 1; // Support: Flexbox
|
|
100
91
|
@include govuk-media-query ($until: tablet) {
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
flex-basis: 320px; // Support: Flexbox
|
|
92
|
+
-ms-flex-preferred-size: 320px;
|
|
93
|
+
flex-basis: 320px; // Support: Flexbox
|
|
104
94
|
}
|
|
105
95
|
}
|
|
106
96
|
|