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
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
position: relative;
|
|
59
59
|
top: -1px;
|
|
60
60
|
margin-right: 1px;
|
|
61
|
-
fill:
|
|
61
|
+
fill: currentcolor;
|
|
62
62
|
vertical-align: top;
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
text-decoration: underline;
|
|
92
92
|
text-decoration-thickness: $govuk-header-link-underline-thickness;
|
|
93
93
|
|
|
94
|
-
@if
|
|
94
|
+
@if $govuk-link-underline-offset {
|
|
95
95
|
text-underline-offset: $govuk-link-underline-offset;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -111,6 +111,16 @@
|
|
|
111
111
|
font-size: 30px; // We don't have a mixin that produces 30px font size
|
|
112
112
|
line-height: 1;
|
|
113
113
|
|
|
114
|
+
@include govuk-media-query($from: tablet) {
|
|
115
|
+
display: inline;
|
|
116
|
+
|
|
117
|
+
&:focus {
|
|
118
|
+
// Replicate the focus box shadow but without the -2px y-offset of the first yellow shadow
|
|
119
|
+
// This is to stop the logo getting cut off by the box shadow when focused on above a product name
|
|
120
|
+
box-shadow: 0 0 $govuk-focus-colour;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
114
124
|
&:link,
|
|
115
125
|
&:visited {
|
|
116
126
|
text-decoration: none;
|
|
@@ -132,6 +142,9 @@
|
|
|
132
142
|
}
|
|
133
143
|
}
|
|
134
144
|
|
|
145
|
+
// The govuk-header__link--service-name class is deprecated - use
|
|
146
|
+
// govuk-header__service-name instead.
|
|
147
|
+
.govuk-header__service-name,
|
|
135
148
|
.govuk-header__link--service-name {
|
|
136
149
|
display: inline-block;
|
|
137
150
|
margin-bottom: govuk-spacing(2);
|
|
@@ -180,7 +193,7 @@
|
|
|
180
193
|
-webkit-text-decoration: solid underline $govuk-header-link-underline-thickness;
|
|
181
194
|
text-decoration: solid underline $govuk-header-link-underline-thickness;
|
|
182
195
|
|
|
183
|
-
@if
|
|
196
|
+
@if $govuk-link-underline-offset {
|
|
184
197
|
text-underline-offset: $govuk-link-underline-offset;
|
|
185
198
|
}
|
|
186
199
|
}
|
|
@@ -195,14 +208,21 @@
|
|
|
195
208
|
margin-left: govuk-spacing(1);
|
|
196
209
|
}
|
|
197
210
|
|
|
211
|
+
&[aria-expanded="true"]:after {
|
|
212
|
+
@include govuk-shape-arrow($direction: up, $base: 10px, $display: inline-block);
|
|
213
|
+
}
|
|
214
|
+
|
|
198
215
|
@include govuk-media-query ($from: tablet) {
|
|
199
216
|
top: govuk-spacing(3);
|
|
200
217
|
}
|
|
201
|
-
}
|
|
202
218
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
219
|
+
.js-enabled & {
|
|
220
|
+
display: block;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
&[hidden],
|
|
224
|
+
.js-enabled &[hidden] {
|
|
225
|
+
display: none;
|
|
206
226
|
}
|
|
207
227
|
}
|
|
208
228
|
|
|
@@ -217,25 +237,9 @@
|
|
|
217
237
|
margin: 0;
|
|
218
238
|
padding: 0;
|
|
219
239
|
list-style: none;
|
|
220
|
-
}
|
|
221
240
|
|
|
222
|
-
|
|
223
|
-
.govuk-header__menu-button {
|
|
224
|
-
display: block;
|
|
225
|
-
@include govuk-media-query ($from: desktop) {
|
|
226
|
-
display: none;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.govuk-header__navigation-list {
|
|
241
|
+
&[hidden] {
|
|
231
242
|
display: none;
|
|
232
|
-
@include govuk-media-query ($from: desktop) {
|
|
233
|
-
display: block;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
.govuk-header__navigation-list--open {
|
|
238
|
-
display: block;
|
|
239
243
|
}
|
|
240
244
|
}
|
|
241
245
|
|
|
@@ -247,6 +251,8 @@
|
|
|
247
251
|
}
|
|
248
252
|
}
|
|
249
253
|
|
|
254
|
+
// The govuk-header__navigation--no-service-name class is deprecated and will
|
|
255
|
+
// be removed in the next major release.
|
|
250
256
|
.govuk-header__navigation--no-service-name {
|
|
251
257
|
padding-top: govuk-spacing(7);
|
|
252
258
|
}
|
|
@@ -1014,12 +1014,29 @@ if (detect) return
|
|
|
1014
1014
|
})
|
|
1015
1015
|
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
1016
1016
|
|
|
1017
|
+
/**
|
|
1018
|
+
* Header component
|
|
1019
|
+
*
|
|
1020
|
+
* @class
|
|
1021
|
+
* @param {HTMLElement} $module - HTML element to use for header
|
|
1022
|
+
*/
|
|
1017
1023
|
function Header ($module) {
|
|
1018
1024
|
this.$module = $module;
|
|
1019
1025
|
this.$menuButton = $module && $module.querySelector('.govuk-js-header-toggle');
|
|
1020
1026
|
this.$menu = this.$menuButton && $module.querySelector(
|
|
1021
1027
|
'#' + this.$menuButton.getAttribute('aria-controls')
|
|
1022
1028
|
);
|
|
1029
|
+
|
|
1030
|
+
// Save the opened/closed state for the nav in memory so that we can
|
|
1031
|
+
// accurately maintain state when the screen is changed from small to
|
|
1032
|
+
// big and back to small
|
|
1033
|
+
this.menuIsOpen = false;
|
|
1034
|
+
|
|
1035
|
+
// A global const for storing a matchMedia instance which we'll use to
|
|
1036
|
+
// detect when a screen size change happens. We set this later during the
|
|
1037
|
+
// init function and rely on it being null if the feature isn't available
|
|
1038
|
+
// to initially apply hidden attributes
|
|
1039
|
+
this.mql = null;
|
|
1023
1040
|
}
|
|
1024
1041
|
|
|
1025
1042
|
/**
|
|
@@ -1027,27 +1044,58 @@ function Header ($module) {
|
|
|
1027
1044
|
*
|
|
1028
1045
|
* Check for the presence of the header, menu and menu button – if any are
|
|
1029
1046
|
* missing then there's nothing to do so return early.
|
|
1047
|
+
* Feature sniff for and apply a matchMedia for desktop which will
|
|
1048
|
+
* trigger a state sync if the browser viewport moves between states. If
|
|
1049
|
+
* matchMedia isn't available, hide the menu button and present the "no js"
|
|
1050
|
+
* version of the menu to the user.
|
|
1030
1051
|
*/
|
|
1031
1052
|
Header.prototype.init = function () {
|
|
1032
1053
|
if (!this.$module || !this.$menuButton || !this.$menu) {
|
|
1033
1054
|
return
|
|
1034
1055
|
}
|
|
1035
1056
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1057
|
+
if ('matchMedia' in window) {
|
|
1058
|
+
// Set the matchMedia to the govuk-frontend desktop breakpoint
|
|
1059
|
+
this.mql = window.matchMedia('(min-width: 48.0625em)');
|
|
1060
|
+
|
|
1061
|
+
if ('addEventListener' in this.mql) {
|
|
1062
|
+
this.mql.addEventListener('change', this.syncState.bind(this));
|
|
1063
|
+
} else {
|
|
1064
|
+
// addListener is a deprecated function, however addEventListener
|
|
1065
|
+
// isn't supported by IE or Safari. We therefore add this in as
|
|
1066
|
+
// a fallback for those browsers
|
|
1067
|
+
this.mql.addListener(this.syncState.bind(this));
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
this.syncState();
|
|
1071
|
+
this.$menuButton.addEventListener('click', this.handleMenuButtonClick.bind(this));
|
|
1072
|
+
} else {
|
|
1073
|
+
this.$menuButton.setAttribute('hidden', '');
|
|
1074
|
+
}
|
|
1038
1075
|
};
|
|
1039
1076
|
|
|
1040
1077
|
/**
|
|
1041
1078
|
* Sync menu state
|
|
1042
1079
|
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1080
|
+
* Uses the global variable menuIsOpen to correctly set the accessible and
|
|
1081
|
+
* visual states of the menu and the menu button.
|
|
1082
|
+
* Additionally will force the menu to be visible and the menu button to be
|
|
1083
|
+
* hidden if the matchMedia is triggered to desktop.
|
|
1047
1084
|
*/
|
|
1048
|
-
Header.prototype.syncState = function (
|
|
1049
|
-
this
|
|
1050
|
-
|
|
1085
|
+
Header.prototype.syncState = function () {
|
|
1086
|
+
if (this.mql.matches) {
|
|
1087
|
+
this.$menu.removeAttribute('hidden');
|
|
1088
|
+
this.$menuButton.setAttribute('hidden', '');
|
|
1089
|
+
} else {
|
|
1090
|
+
this.$menuButton.removeAttribute('hidden');
|
|
1091
|
+
this.$menuButton.setAttribute('aria-expanded', this.menuIsOpen);
|
|
1092
|
+
|
|
1093
|
+
if (this.menuIsOpen) {
|
|
1094
|
+
this.$menu.removeAttribute('hidden');
|
|
1095
|
+
} else {
|
|
1096
|
+
this.$menu.setAttribute('hidden', '');
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1051
1099
|
};
|
|
1052
1100
|
|
|
1053
1101
|
/**
|
|
@@ -1057,8 +1105,8 @@ Header.prototype.syncState = function (isVisible) {
|
|
|
1057
1105
|
* sync the accessibility state and menu button state
|
|
1058
1106
|
*/
|
|
1059
1107
|
Header.prototype.handleMenuButtonClick = function () {
|
|
1060
|
-
|
|
1061
|
-
this.syncState(
|
|
1108
|
+
this.menuIsOpen = !this.menuIsOpen;
|
|
1109
|
+
this.syncState();
|
|
1062
1110
|
};
|
|
1063
1111
|
|
|
1064
1112
|
return Header;
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
|
|
23
23
|
// Disable inner shadow and remove rounded corners
|
|
24
24
|
-webkit-appearance: none;
|
|
25
|
-
-moz-appearance: none;
|
|
26
25
|
appearance: none;
|
|
27
26
|
|
|
28
27
|
&:focus {
|
|
@@ -61,49 +60,44 @@
|
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
//
|
|
65
|
-
// Extra space is
|
|
66
|
-
// Linear regression estimation based on visual tests: y = 1.76 + 1.81x
|
|
63
|
+
// em measurements are based on the point size of the typeface
|
|
64
|
+
// Extra space is added on the right hand side to allow for the Safari prefill icon
|
|
67
65
|
|
|
68
66
|
.govuk-input--width-30 {
|
|
69
|
-
max-width:
|
|
67
|
+
max-width: 29.5em;
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
.govuk-input--width-20 {
|
|
73
|
-
max-width:
|
|
71
|
+
max-width: 20.5em;
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
.govuk-input--width-10 {
|
|
77
|
-
max-width:
|
|
75
|
+
max-width: 11.5em;
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
.govuk-input--width-5 {
|
|
81
|
-
max-width:
|
|
79
|
+
max-width: 5.5em;
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
.govuk-input--width-4 {
|
|
85
|
-
max-width:
|
|
83
|
+
max-width: 4.5em;
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
.govuk-input--width-3 {
|
|
89
|
-
max-width:
|
|
87
|
+
max-width: 3.75em;
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
.govuk-input--width-2 {
|
|
93
|
-
max-width:
|
|
91
|
+
max-width: 2.75em;
|
|
94
92
|
}
|
|
95
93
|
|
|
96
94
|
.govuk-input__wrapper {
|
|
97
|
-
display: -webkit-box;
|
|
98
|
-
display: -webkit-flex;
|
|
99
95
|
display: -ms-flexbox;
|
|
100
96
|
display: flex;
|
|
101
97
|
|
|
102
98
|
.govuk-input {
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
-ms-flex: 0 1 auto;
|
|
106
|
-
flex: 0 1 auto;
|
|
99
|
+
-ms-flex: 0 1 auto;
|
|
100
|
+
flex: 0 1 auto;
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
.govuk-input:focus {
|
|
@@ -150,13 +144,9 @@
|
|
|
150
144
|
// Emphasise non-editable status of prefixes and suffixes
|
|
151
145
|
cursor: default;
|
|
152
146
|
|
|
153
|
-
-
|
|
147
|
+
-ms-flex: 0 0 auto;
|
|
154
148
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
-ms-flex: 0 0 auto;
|
|
158
|
-
|
|
159
|
-
flex: 0 0 auto;
|
|
149
|
+
flex: 0 0 auto;
|
|
160
150
|
|
|
161
151
|
// Split prefix/suffix onto separate lines on narrow screens
|
|
162
152
|
@include govuk-media-query($until: mobile) {
|
data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js
CHANGED
|
@@ -501,8 +501,247 @@ if (detect) return
|
|
|
501
501
|
})
|
|
502
502
|
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
503
503
|
|
|
504
|
-
|
|
504
|
+
/**
|
|
505
|
+
* Common helpers which do not require polyfill.
|
|
506
|
+
*
|
|
507
|
+
* IMPORTANT: If a helper require a polyfill, please isolate it in its own module
|
|
508
|
+
* so that the polyfill can be properly tree-shaken and does not burden
|
|
509
|
+
* the components that do not need that helper
|
|
510
|
+
*
|
|
511
|
+
* @module common/index
|
|
512
|
+
*/
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Config flattening function
|
|
516
|
+
*
|
|
517
|
+
* Takes any number of objects, flattens them into namespaced key-value pairs,
|
|
518
|
+
* (e.g. {'i18n.showSection': 'Show section'}) and combines them together, with
|
|
519
|
+
* greatest priority on the LAST item passed in.
|
|
520
|
+
*
|
|
521
|
+
* @returns {object} A flattened object of key-value pairs.
|
|
522
|
+
*/
|
|
523
|
+
function mergeConfigs (/* configObject1, configObject2, ...configObjects */) {
|
|
524
|
+
/**
|
|
525
|
+
* Function to take nested objects and flatten them to a dot-separated keyed
|
|
526
|
+
* object. Doing this means we don't need to do any deep/recursive merging of
|
|
527
|
+
* each of our objects, nor transform our dataset from a flat list into a
|
|
528
|
+
* nested object.
|
|
529
|
+
*
|
|
530
|
+
* @param {object} configObject - Deeply nested object
|
|
531
|
+
* @returns {object} Flattened object with dot-separated keys
|
|
532
|
+
*/
|
|
533
|
+
var flattenObject = function (configObject) {
|
|
534
|
+
// Prepare an empty return object
|
|
535
|
+
var flattenedObject = {};
|
|
536
|
+
|
|
537
|
+
// Our flattening function, this is called recursively for each level of
|
|
538
|
+
// depth in the object. At each level we prepend the previous level names to
|
|
539
|
+
// the key using `prefix`.
|
|
540
|
+
var flattenLoop = function (obj, prefix) {
|
|
541
|
+
// Loop through keys...
|
|
542
|
+
for (var key in obj) {
|
|
543
|
+
// Check to see if this is a prototypical key/value,
|
|
544
|
+
// if it is, skip it.
|
|
545
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
546
|
+
continue
|
|
547
|
+
}
|
|
548
|
+
var value = obj[key];
|
|
549
|
+
var prefixedKey = prefix ? prefix + '.' + key : key;
|
|
550
|
+
if (typeof value === 'object') {
|
|
551
|
+
// If the value is a nested object, recurse over that too
|
|
552
|
+
flattenLoop(value, prefixedKey);
|
|
553
|
+
} else {
|
|
554
|
+
// Otherwise, add this value to our return object
|
|
555
|
+
flattenedObject[prefixedKey] = value;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// Kick off the recursive loop
|
|
561
|
+
flattenLoop(configObject);
|
|
562
|
+
return flattenedObject
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
// Start with an empty object as our base
|
|
566
|
+
var formattedConfigObject = {};
|
|
567
|
+
|
|
568
|
+
// Loop through each of the remaining passed objects and push their keys
|
|
569
|
+
// one-by-one into configObject. Any duplicate keys will override the existing
|
|
570
|
+
// key with the new value.
|
|
571
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
572
|
+
var obj = flattenObject(arguments[i]);
|
|
573
|
+
for (var key in obj) {
|
|
574
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
575
|
+
formattedConfigObject[key] = obj[key];
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return formattedConfigObject
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* @callback nodeListIterator
|
|
585
|
+
* @param {Element} value - The current node being iterated on
|
|
586
|
+
* @param {number} index - The current index in the iteration
|
|
587
|
+
* @param {NodeListOf<Element>} nodes - NodeList from querySelectorAll()
|
|
588
|
+
* @returns {undefined}
|
|
589
|
+
*/
|
|
590
|
+
|
|
591
|
+
(function(undefined) {
|
|
592
|
+
|
|
593
|
+
// Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-library/13cf7c340974d128d557580b5e2dafcd1b1192d1/polyfills/Element/prototype/dataset/detect.js
|
|
594
|
+
var detect = (function(){
|
|
595
|
+
if (!document.documentElement.dataset) {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
var el = document.createElement('div');
|
|
599
|
+
el.setAttribute("data-a-b", "c");
|
|
600
|
+
return el.dataset && el.dataset.aB == "c";
|
|
601
|
+
}());
|
|
602
|
+
|
|
603
|
+
if (detect) return
|
|
604
|
+
|
|
605
|
+
// Polyfill derived from https://raw.githubusercontent.com/Financial-Times/polyfill-library/13cf7c340974d128d557580b5e2dafcd1b1192d1/polyfills/Element/prototype/dataset/polyfill.js
|
|
606
|
+
Object.defineProperty(Element.prototype, 'dataset', {
|
|
607
|
+
get: function() {
|
|
608
|
+
var element = this;
|
|
609
|
+
var attributes = this.attributes;
|
|
610
|
+
var map = {};
|
|
611
|
+
|
|
612
|
+
for (var i = 0; i < attributes.length; i++) {
|
|
613
|
+
var attribute = attributes[i];
|
|
614
|
+
|
|
615
|
+
// This regex has been edited from the original polyfill, to add
|
|
616
|
+
// support for period (.) separators in data-* attribute names. These
|
|
617
|
+
// are allowed in the HTML spec, but were not covered by the original
|
|
618
|
+
// polyfill's regex. We use periods in our i18n implementation.
|
|
619
|
+
if (attribute && attribute.name && (/^data-\w[.\w-]*$/).test(attribute.name)) {
|
|
620
|
+
var name = attribute.name;
|
|
621
|
+
var value = attribute.value;
|
|
622
|
+
|
|
623
|
+
var propName = name.substr(5).replace(/-./g, function (prop) {
|
|
624
|
+
return prop.charAt(1).toUpperCase();
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// If this browser supports __defineGetter__ and __defineSetter__,
|
|
628
|
+
// continue using defineProperty. If not (like IE 8 and below), we use
|
|
629
|
+
// a hacky fallback which at least gives an object in the right format
|
|
630
|
+
if ('__defineGetter__' in Object.prototype && '__defineSetter__' in Object.prototype) {
|
|
631
|
+
Object.defineProperty(map, propName, {
|
|
632
|
+
enumerable: true,
|
|
633
|
+
get: function() {
|
|
634
|
+
return this.value;
|
|
635
|
+
}.bind({value: value || ''}),
|
|
636
|
+
set: function setter(name, value) {
|
|
637
|
+
if (typeof value !== 'undefined') {
|
|
638
|
+
this.setAttribute(name, value);
|
|
639
|
+
} else {
|
|
640
|
+
this.removeAttribute(name);
|
|
641
|
+
}
|
|
642
|
+
}.bind(element, name)
|
|
643
|
+
});
|
|
644
|
+
} else {
|
|
645
|
+
map[propName] = value;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return map;
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
656
|
+
|
|
657
|
+
(function(undefined) {
|
|
658
|
+
|
|
659
|
+
// Detection from https://github.com/mdn/content/blob/cf607d68522cd35ee7670782d3ee3a361eaef2e4/files/en-us/web/javascript/reference/global_objects/string/trim/index.md#polyfill
|
|
660
|
+
var detect = ('trim' in String.prototype);
|
|
661
|
+
|
|
662
|
+
if (detect) return
|
|
663
|
+
|
|
664
|
+
// Polyfill from https://github.com/mdn/content/blob/cf607d68522cd35ee7670782d3ee3a361eaef2e4/files/en-us/web/javascript/reference/global_objects/string/trim/index.md#polyfill
|
|
665
|
+
String.prototype.trim = function () {
|
|
666
|
+
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Normalise string
|
|
673
|
+
*
|
|
674
|
+
* 'If it looks like a duck, and it quacks like a duck…' 🦆
|
|
675
|
+
*
|
|
676
|
+
* If the passed value looks like a boolean or a number, convert it to a boolean
|
|
677
|
+
* or number.
|
|
678
|
+
*
|
|
679
|
+
* Designed to be used to convert config passed via data attributes (which are
|
|
680
|
+
* always strings) into something sensible.
|
|
681
|
+
*
|
|
682
|
+
* @param {string} value - The value to normalise
|
|
683
|
+
* @returns {string | boolean | number | undefined} Normalised data
|
|
684
|
+
*/
|
|
685
|
+
function normaliseString (value) {
|
|
686
|
+
if (typeof value !== 'string') {
|
|
687
|
+
return value
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
var trimmedValue = value.trim();
|
|
691
|
+
|
|
692
|
+
if (trimmedValue === 'true') {
|
|
693
|
+
return true
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (trimmedValue === 'false') {
|
|
697
|
+
return false
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Empty / whitespace-only strings are considered finite so we need to check
|
|
701
|
+
// the length of the trimmed string as well
|
|
702
|
+
if (trimmedValue.length > 0 && isFinite(trimmedValue)) {
|
|
703
|
+
return Number(trimmedValue)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return value
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Normalise dataset
|
|
711
|
+
*
|
|
712
|
+
* Loop over an object and normalise each value using normaliseData function
|
|
713
|
+
*
|
|
714
|
+
* @param {DOMStringMap} dataset - HTML element dataset
|
|
715
|
+
* @returns {Object<string, string | boolean | number | undefined>} Normalised dataset
|
|
716
|
+
*/
|
|
717
|
+
function normaliseDataset (dataset) {
|
|
718
|
+
var out = {};
|
|
719
|
+
|
|
720
|
+
for (var key in dataset) {
|
|
721
|
+
out[key] = normaliseString(dataset[key]);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return out
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Notification Banner component
|
|
729
|
+
*
|
|
730
|
+
* @class
|
|
731
|
+
* @param {HTMLElement} $module - HTML element to use for notification banner
|
|
732
|
+
* @param {NotificationBannerConfig} config - Notification banner config
|
|
733
|
+
*/
|
|
734
|
+
function NotificationBanner ($module, config) {
|
|
505
735
|
this.$module = $module;
|
|
736
|
+
|
|
737
|
+
var defaultConfig = {
|
|
738
|
+
disableAutoFocus: false
|
|
739
|
+
};
|
|
740
|
+
this.config = mergeConfigs(
|
|
741
|
+
defaultConfig,
|
|
742
|
+
config || {},
|
|
743
|
+
normaliseDataset($module.dataset)
|
|
744
|
+
);
|
|
506
745
|
}
|
|
507
746
|
|
|
508
747
|
/**
|
|
@@ -531,7 +770,7 @@ NotificationBanner.prototype.init = function () {
|
|
|
531
770
|
NotificationBanner.prototype.setFocus = function () {
|
|
532
771
|
var $module = this.$module;
|
|
533
772
|
|
|
534
|
-
if (
|
|
773
|
+
if (this.config.disableAutoFocus) {
|
|
535
774
|
return
|
|
536
775
|
}
|
|
537
776
|
|
|
@@ -553,6 +792,17 @@ NotificationBanner.prototype.setFocus = function () {
|
|
|
553
792
|
$module.focus();
|
|
554
793
|
};
|
|
555
794
|
|
|
795
|
+
/**
|
|
796
|
+
* Notification banner config
|
|
797
|
+
*
|
|
798
|
+
* @typedef {object} NotificationBannerConfig
|
|
799
|
+
* @property {boolean} [disableAutoFocus = false] -
|
|
800
|
+
* If set to `true` the notification banner will not be focussed when the page
|
|
801
|
+
* loads. This only applies if the component has a `role` of `alert` – in
|
|
802
|
+
* other cases the component will not be focused on page load, regardless of
|
|
803
|
+
* this option.
|
|
804
|
+
*/
|
|
805
|
+
|
|
556
806
|
return NotificationBanner;
|
|
557
807
|
|
|
558
808
|
})));
|