hof 20.3.7-beta-gtm → 20.3.7-timeout-beta

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,361 @@
1
+ /*
2
+ * This content is licensed according to the W3C Software License at
3
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
4
+ */
5
+ 'use strict';
6
+
7
+ require('./utils');
8
+
9
+ const aria = window.aria || {};
10
+
11
+ aria.Utils = aria.Utils || {};
12
+
13
+ /**
14
+ * @description
15
+ * Key code constants
16
+ */
17
+ aria.KeyCode = {
18
+ BACKSPACE: 8,
19
+ TAB: 9,
20
+ RETURN: 13,
21
+ SHIFT: 16,
22
+ ESC: 27,
23
+ SPACE: 32,
24
+ PAGE_UP: 33,
25
+ PAGE_DOWN: 34,
26
+ END: 35,
27
+ HOME: 36,
28
+ LEFT: 37,
29
+ UP: 38,
30
+ RIGHT: 39,
31
+ DOWN: 40,
32
+ DELETE: 46
33
+ };
34
+
35
+ (function () {
36
+ // eslint-disable-next-line no-console
37
+ console.log('TEST DIALOG.js', aria);
38
+ /*
39
+ * When util functions move focus around, set this true so the focus listener
40
+ * can ignore the events.
41
+ */
42
+ aria.Utils.IgnoreUtilFocusChanges = false;
43
+
44
+ aria.Utils.dialogOpenClass = 'has-dialog';
45
+
46
+ /**
47
+ * @description Set focus on descendant nodes until the first focusable element is
48
+ * found.
49
+ * @param element
50
+ * DOM node for which to find the first focusable descendant.
51
+ * @returns {boolean}
52
+ * true if a focusable element is found and focus is set.
53
+ */
54
+ aria.Utils.focusFirstDescendant = function (element) {
55
+ for (let i = 0; i < element.childNodes.length; i++) {
56
+ const child = element.childNodes[i];
57
+ if (
58
+ aria.Utils.attemptFocus(child) ||
59
+ aria.Utils.focusFirstDescendant(child)
60
+ ) {
61
+ return true;
62
+ }
63
+ }
64
+ return false;
65
+ }; // end focusFirstDescendant
66
+
67
+ /**
68
+ * @description Find the last descendant node that is focusable.
69
+ * @param element
70
+ * DOM node for which to find the last focusable descendant.
71
+ * @returns {boolean}
72
+ * true if a focusable element is found and focus is set.
73
+ */
74
+ aria.Utils.focusLastDescendant = function (element) {
75
+ for (let i = element.childNodes.length - 1; i >= 0; i--) {
76
+ const child = element.childNodes[i];
77
+ if (
78
+ aria.Utils.attemptFocus(child) ||
79
+ aria.Utils.focusLastDescendant(child)
80
+ ) {
81
+ return true;
82
+ }
83
+ }
84
+ return false;
85
+ }; // end focusLastDescendant
86
+
87
+ /**
88
+ * @description Set Attempt to set focus on the current node.
89
+ * @param element
90
+ * The node to attempt to focus on.
91
+ * @returns {boolean}
92
+ * true if element is focused.
93
+ */
94
+ aria.Utils.attemptFocus = function (element) {
95
+ if (!aria.Utils.isFocusable(element)) {
96
+ return false;
97
+ }
98
+
99
+ aria.Utils.IgnoreUtilFocusChanges = true;
100
+ try {
101
+ element.focus();
102
+ } catch (e) {
103
+ // continue regardless of error
104
+ }
105
+ aria.Utils.IgnoreUtilFocusChanges = false;
106
+ return document.activeElement === element;
107
+ }; // end attemptFocus
108
+
109
+ /* Modals can open modals. Keep track of them with this array. */
110
+ aria.OpenDialogList = aria.OpenDialogList || new Array(0);
111
+
112
+ /**
113
+ * @returns {object} the last opened dialog (the current dialog)
114
+ */
115
+ aria.getCurrentDialog = function () {
116
+ if (aria.OpenDialogList && aria.OpenDialogList.length) {
117
+ return aria.OpenDialogList[aria.OpenDialogList.length - 1];
118
+ }
119
+ return null;
120
+ };
121
+
122
+ aria.closeCurrentDialog = function () {
123
+ const currentDialog = aria.getCurrentDialog();
124
+ if (currentDialog) {
125
+ currentDialog.close();
126
+ return true;
127
+ }
128
+
129
+ return false;
130
+ };
131
+
132
+ aria.handleEscape = function (event) {
133
+ const key = event.which || event.keyCode;
134
+
135
+ if (key === aria.KeyCode.ESC && aria.closeCurrentDialog()) {
136
+ event.stopPropagation();
137
+ }
138
+ };
139
+
140
+ document.addEventListener('keyup', aria.handleEscape);
141
+
142
+ /**
143
+ * @class
144
+ * @description Dialog object providing modal focus management.
145
+ *
146
+ * Assumptions: The element serving as the dialog container is present in the
147
+ * DOM and hidden. The dialog container has role='dialog'.
148
+ * @param dialogId
149
+ * The ID of the element serving as the dialog container.
150
+ * @param focusAfterClosed
151
+ * Either the DOM node or the ID of the DOM node to focus when the
152
+ * dialog closes.
153
+ * @param focusFirst
154
+ * Optional parameter containing either the DOM node or the ID of the
155
+ * DOM node to focus when the dialog opens. If not specified, the
156
+ * first focusable element in the dialog will receive focus.
157
+ */
158
+ aria.Dialog = function (dialogId, focusAfterClosed, focusFirst) {
159
+ this.dialogNode = document.getElementById(dialogId);
160
+ if (this.dialogNode === null) {
161
+ throw new Error('No element found with id="' + dialogId + '".');
162
+ }
163
+
164
+ const validRoles = ['dialog', 'alertdialog'];
165
+ const isDialog = (this.dialogNode.getAttribute('role') || '')
166
+ .trim()
167
+ .split(/\s+/g)
168
+ .some(function (token) {
169
+ return validRoles.some(function (role) {
170
+ return token === role;
171
+ });
172
+ });
173
+ if (!isDialog) {
174
+ throw new Error(
175
+ 'Dialog() requires a DOM element with ARIA role of dialog or alertdialog.'
176
+ );
177
+ }
178
+
179
+ // Wrap in an individual backdrop element if one doesn't exist
180
+ // Native <dialog> elements use the ::backdrop pseudo-element, which
181
+ // works similarly.
182
+ const backdropClass = 'dialog-backdrop';
183
+ if (this.dialogNode.parentNode.classList.contains(backdropClass)) {
184
+ this.backdropNode = this.dialogNode.parentNode;
185
+ } else {
186
+ this.backdropNode = document.createElement('div');
187
+ this.backdropNode.className = backdropClass;
188
+ this.dialogNode.parentNode.insertBefore(
189
+ this.backdropNode,
190
+ this.dialogNode
191
+ );
192
+ this.backdropNode.appendChild(this.dialogNode);
193
+ }
194
+ this.backdropNode.classList.add('active');
195
+
196
+ // Disable scroll on the body element
197
+ document.body.classList.add(aria.Utils.dialogOpenClass);
198
+
199
+ if (typeof focusAfterClosed === 'string') {
200
+ this.focusAfterClosed = document.getElementById(focusAfterClosed);
201
+ } else if (typeof focusAfterClosed === 'object') {
202
+ this.focusAfterClosed = focusAfterClosed;
203
+ } else {
204
+ throw new Error(
205
+ 'the focusAfterClosed parameter is required for the aria.Dialog constructor.'
206
+ );
207
+ }
208
+
209
+ if (typeof focusFirst === 'string') {
210
+ this.focusFirst = document.getElementById(focusFirst);
211
+ } else if (typeof focusFirst === 'object') {
212
+ this.focusFirst = focusFirst;
213
+ } else {
214
+ this.focusFirst = null;
215
+ }
216
+
217
+ // Bracket the dialog node with two invisible, focusable nodes.
218
+ // While this dialog is open, we use these to make sure that focus never
219
+ // leaves the document even if dialogNode is the first or last node.
220
+ const preDiv = document.createElement('div');
221
+ this.preNode = this.dialogNode.parentNode.insertBefore(
222
+ preDiv,
223
+ this.dialogNode
224
+ );
225
+ this.preNode.tabIndex = 0;
226
+ const postDiv = document.createElement('div');
227
+ this.postNode = this.dialogNode.parentNode.insertBefore(
228
+ postDiv,
229
+ this.dialogNode.nextSibling
230
+ );
231
+ this.postNode.tabIndex = 0;
232
+
233
+ // If this modal is opening on top of one that is already open,
234
+ // get rid of the document focus listener of the open dialog.
235
+ if (aria.OpenDialogList.length > 0) {
236
+ aria.getCurrentDialog().removeListeners();
237
+ }
238
+
239
+ this.addListeners();
240
+ aria.OpenDialogList.push(this);
241
+ this.clearDialog();
242
+ this.dialogNode.className = 'default_dialog'; // make visible
243
+
244
+ if (this.focusFirst) {
245
+ this.focusFirst.focus();
246
+ } else {
247
+ aria.Utils.focusFirstDescendant(this.dialogNode);
248
+ }
249
+
250
+ this.lastFocus = document.activeElement;
251
+ }; // end Dialog constructor
252
+
253
+ aria.Dialog.prototype.clearDialog = function () {
254
+ Array.prototype.map.call(
255
+ this.dialogNode.querySelectorAll('input'),
256
+ function (input) {
257
+ input.value = '';
258
+ }
259
+ );
260
+ };
261
+
262
+ /**
263
+ * @description
264
+ * Hides the current top dialog,
265
+ * removes listeners of the top dialog,
266
+ * restore listeners of a parent dialog if one was open under the one that just closed,
267
+ * and sets focus on the element specified for focusAfterClosed.
268
+ */
269
+ aria.Dialog.prototype.close = function () {
270
+ aria.OpenDialogList.pop();
271
+ this.removeListeners();
272
+ aria.Utils.remove(this.preNode);
273
+ aria.Utils.remove(this.postNode);
274
+ this.dialogNode.className = 'hidden';
275
+ this.backdropNode.classList.remove('active');
276
+ this.focusAfterClosed.focus();
277
+
278
+ // If a dialog was open underneath this one, restore its listeners.
279
+ if (aria.OpenDialogList.length > 0) {
280
+ aria.getCurrentDialog().addListeners();
281
+ } else {
282
+ document.body.classList.remove(aria.Utils.dialogOpenClass);
283
+ }
284
+ }; // end close
285
+
286
+ /**
287
+ * @description
288
+ * Hides the current dialog and replaces it with another.
289
+ * @param newDialogId
290
+ * ID of the dialog that will replace the currently open top dialog.
291
+ * @param newFocusAfterClosed
292
+ * Optional ID or DOM node specifying where to place focus when the new dialog closes.
293
+ * If not specified, focus will be placed on the element specified by the dialog being replaced.
294
+ * @param newFocusFirst
295
+ * Optional ID or DOM node specifying where to place focus in the new dialog when it opens.
296
+ * If not specified, the first focusable element will receive focus.
297
+ */
298
+ aria.Dialog.prototype.replace = function (
299
+ newDialogId,
300
+ newFocusAfterClosed,
301
+ newFocusFirst
302
+ ) {
303
+ aria.OpenDialogList.pop();
304
+ this.removeListeners();
305
+ aria.Utils.remove(this.preNode);
306
+ aria.Utils.remove(this.postNode);
307
+ this.dialogNode.className = 'hidden';
308
+ this.backdropNode.classList.remove('active');
309
+
310
+ const focusAfterClosed = newFocusAfterClosed || this.focusAfterClosed;
311
+ // eslint-disable-next-line no-new
312
+ new aria.Dialog(newDialogId, focusAfterClosed, newFocusFirst);
313
+ }; // end replace
314
+
315
+ aria.Dialog.prototype.addListeners = function () {
316
+ document.addEventListener('focus', this.trapFocus, true);
317
+ }; // end addListeners
318
+
319
+ aria.Dialog.prototype.removeListeners = function () {
320
+ document.removeEventListener('focus', this.trapFocus, true);
321
+ }; // end removeListeners
322
+
323
+ aria.Dialog.prototype.trapFocus = function (event) {
324
+ if (aria.Utils.IgnoreUtilFocusChanges) {
325
+ return;
326
+ }
327
+ const currentDialog = aria.getCurrentDialog();
328
+ if (currentDialog.dialogNode.contains(event.target)) {
329
+ currentDialog.lastFocus = event.target;
330
+ } else {
331
+ aria.Utils.focusFirstDescendant(currentDialog.dialogNode);
332
+ if (currentDialog.lastFocus === document.activeElement) {
333
+ aria.Utils.focusLastDescendant(currentDialog.dialogNode);
334
+ }
335
+ currentDialog.lastFocus = document.activeElement;
336
+ }
337
+ }; // end trapFocus
338
+
339
+ window.openDialog = function (dialogId, focusAfterClosed, focusFirst) {
340
+ // eslint-disable-next-line no-new
341
+ new aria.Dialog(dialogId, focusAfterClosed, focusFirst);
342
+ };
343
+
344
+ window.closeDialog = function (closeButton) {
345
+ const topDialog = aria.getCurrentDialog();
346
+ if (topDialog.dialogNode.contains(closeButton)) {
347
+ topDialog.close();
348
+ }
349
+ }; // end closeDialog
350
+
351
+ window.replaceDialog = function (
352
+ newDialogId,
353
+ newFocusAfterClosed,
354
+ newFocusFirst
355
+ ) {
356
+ const topDialog = aria.getCurrentDialog();
357
+ if (topDialog.dialogNode.contains(document.activeElement)) {
358
+ topDialog.replace(newDialogId, newFocusAfterClosed, newFocusFirst);
359
+ }
360
+ }; // end replaceDialog
361
+ })();
@@ -0,0 +1,114 @@
1
+ 'use strict';
2
+ /**
3
+ * @namespace aria
4
+ */
5
+
6
+ window.aria = window.aria || {};
7
+
8
+ (function () {
9
+ // eslint-disable-next-line no-console
10
+ // console.log('TEST UTILS.js', aria);
11
+ })();
12
+
13
+ window.aria.Utils = window.aria.Utils || {};
14
+
15
+ // Polyfill src https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
16
+ window.aria.Utils.matches = function (element, selector) {
17
+ if (!Element.prototype.matches) {
18
+ Element.prototype.matches =
19
+ Element.prototype.matchesSelector ||
20
+ Element.prototype.mozMatchesSelector ||
21
+ Element.prototype.msMatchesSelector ||
22
+ Element.prototype.oMatchesSelector ||
23
+ Element.prototype.webkitMatchesSelector ||
24
+ function (s) {
25
+ const matches = element.parentNode.querySelectorAll(s);
26
+ let i = matches.length;
27
+ while (--i >= 0 && matches.item(i) !== this) {
28
+ // empty
29
+ }
30
+ return i > -1;
31
+ };
32
+ }
33
+
34
+ return element.matches(selector);
35
+ };
36
+
37
+ window.aria.Utils.remove = function (item) {
38
+ if (item.remove && typeof item.remove === 'function') {
39
+ return item.remove();
40
+ }
41
+ if (
42
+ item.parentNode &&
43
+ item.parentNode.removeChild &&
44
+ typeof item.parentNode.removeChild === 'function'
45
+ ) {
46
+ return item.parentNode.removeChild(item);
47
+ }
48
+ return false;
49
+ };
50
+
51
+ window.aria.Utils.isFocusable = function (element) {
52
+ if (element.tabIndex < 0) {
53
+ return false;
54
+ }
55
+
56
+ if (element.disabled) {
57
+ return false;
58
+ }
59
+
60
+ switch (element.nodeName) {
61
+ case 'A':
62
+ return !!element.href && element.rel !== 'ignore';
63
+ case 'INPUT':
64
+ return element.type !== 'hidden';
65
+ case 'BUTTON':
66
+ case 'SELECT':
67
+ case 'TEXTAREA':
68
+ return true;
69
+ default:
70
+ return false;
71
+ }
72
+ };
73
+
74
+ window.aria.Utils.getAncestorBySelector = function (element, selector) {
75
+ if (!window.aria.Utils.matches(element, selector + ' ' + element.tagName)) {
76
+ // Element is not inside an element that matches selector
77
+ return null;
78
+ }
79
+
80
+ // Move up the DOM tree until a parent matching the selector is found
81
+ let currentNode = element;
82
+ let ancestor = null;
83
+ while (ancestor === null) {
84
+ if (window.aria.Utils.matches(currentNode.parentNode, selector)) {
85
+ ancestor = currentNode.parentNode;
86
+ } else {
87
+ currentNode = currentNode.parentNode;
88
+ }
89
+ }
90
+
91
+ return ancestor;
92
+ };
93
+
94
+ window.aria.Utils.hasClass = function (element, className) {
95
+ return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className);
96
+ };
97
+
98
+ window.aria.Utils.addClass = function (element, className) {
99
+ if (!window.aria.Utils.hasClass(element, className)) {
100
+ element.className += ' ' + className;
101
+ }
102
+ };
103
+
104
+ window.aria.Utils.removeClass = function (element, className) {
105
+ const classRegex = new RegExp('(\\s|^)' + className + '(\\s|$)');
106
+ element.className = element.className.replace(classRegex, ' ').trim();
107
+ };
108
+
109
+ window.aria.Utils.bindMethods = function (object /* , ...methodNames */) {
110
+ const methodNames = Array.prototype.slice.call(arguments, 1);
111
+ methodNames.forEach(function (method) {
112
+ object[method] = object[method].bind(object);
113
+ });
114
+ };
@@ -11,6 +11,7 @@ var validation = toolkit.validation;
11
11
  var GOVUK = require('govuk-frontend');
12
12
  GOVUK.initAll();
13
13
  window.GOVUK = GOVUK;
14
+ var dialog = require('./dialog');
14
15
  var skipToMain = require('./skip-to-main');
15
16
  var cookie = require('./govuk-cookies');
16
17
  var cookieSettings = require('./cookieSettings');
package/lib/ga-tag.js CHANGED
@@ -52,12 +52,11 @@ const setupPageMap = routes => {
52
52
  module.exports = (app, config) => {
53
53
  const gaTagId = config.gaTagId;
54
54
  const ga4TagId = config.ga4TagId;
55
- const gtmTagId = config.gtmTagId;
56
- const environmentType = config.environmentType ? config.environmentType : 'dev';
55
+ const gtm = config.gtm;
57
56
  const gaCrossDomainTrackingTagId = config.gaCrossDomainTrackingTagId;
58
57
  const routes = config.routes;
59
58
 
60
- if (gaTagId || ga4TagId || gtmTagId) {
59
+ if (gaTagId || ga4TagId || gtm.tagId) {
61
60
  const pageMap = setupPageMap(routes);
62
61
 
63
62
  app.use((req, res, next) => {
@@ -74,17 +73,13 @@ module.exports = (app, config) => {
74
73
  };
75
74
 
76
75
  // Adding extra properties if a GTM TAG is available
77
- if (gtmTagId) {
76
+ if (gtm.tagId) {
77
+ gtm.config.pageName = gtm.composePageName(page, convertToGTMPage);
78
78
  Object.assign(properties, {
79
- gtmTagId: gtmTagId,
80
- 'gtm-page': convertToGTMPage(page),
81
- pageEvent: 'pageLoad',
82
- pageName: `ETA | Customer Contact Webform | ${convertToGTMPage(page)}`,
83
- applicationType: 'ETA | Customer Contact',
84
- environmentType: environmentType
79
+ gtmConfig: JSON.stringify(gtm.config),
80
+ gtmTagId: gtm.tagId
85
81
  });
86
82
  }
87
-
88
83
  res.locals = Object.assign(res.locals, properties);
89
84
  next();
90
85
  });
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+
3
+ module.exports = (options, timers) => {
4
+ return (req, res, next) => {
5
+ // eslint-disable-next-line no-console
6
+ console.log(req.url, 'SESSION TIMOUT:', options.session);
7
+ if (timers.length >= 2) {
8
+ // eslint-disable-next-line no-console
9
+ console.log(timers);
10
+ for (const t of timers) {
11
+ clearTimeout(t);
12
+ }
13
+ }
14
+ timers.push(setTimeout(() => {
15
+ // eslint-disable-next-line no-console,no-alert
16
+ console.log(req.originalUrl);
17
+ const err = new Error('Session will expire soon');
18
+ err.code = 'SESSION_TIMEOUT_WARNING';
19
+ return next(err);
20
+ }, 1000 * 10));
21
+ next();
22
+ };
23
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hof",
3
3
  "description": "A bootstrap for HOF projects",
4
- "version": "20.3.7-beta-gtm",
4
+ "version": "20.3.7-timeout-beta",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
7
7
  "author": "HomeOffice",
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ module.exports = SuperClass => class extends SuperClass {
4
+ getValues(req, res, next) {
5
+ // eslint-disable-next-line no-console
6
+ console.log(req.sessionModel);
7
+ next();
8
+ }
9
+ };
@@ -7,7 +7,7 @@
7
7
  border: 1px solid #ccc;
8
8
  width: 65%;
9
9
  }
10
-
10
+
11
11
  .tt-suggestion {
12
12
  padding: 0.5em;
13
13
 
@@ -25,3 +25,117 @@
25
25
  .twitter-typeahead {
26
26
  width: 100%;
27
27
  }
28
+
29
+ .hidden {
30
+ display: none;
31
+ }
32
+
33
+ [role="dialog"] {
34
+ box-sizing: border-box;
35
+ padding: 15px;
36
+ border: 1px solid #000;
37
+ background-color: #fff;
38
+ min-height: 100vh;
39
+ }
40
+
41
+ @media screen and (min-width: 640px) {
42
+ [role="dialog"] {
43
+ position: absolute;
44
+ top: 25vh;
45
+ left: 50vw; /* move to the middle of the screen (assumes relative parent is the body/viewport) */
46
+ transform: translateX(
47
+ -50%
48
+ ); /* move backwards 50% of this element's width */
49
+ min-width: calc(640px - (15px * 2)); /* == breakpoint - left+right margin */
50
+ min-height: auto;
51
+ box-shadow: 0 19px 38px rgb(0 0 0 / 12%), 0 15px 12px rgb(0 0 0 / 22%);
52
+ }
53
+ }
54
+
55
+ .dialog_form {
56
+ margin: 15px;
57
+ }
58
+
59
+ .dialog_form .label_text {
60
+ box-sizing: border-box;
61
+ padding-right: 0.5em;
62
+ display: inline-block;
63
+ font-size: 16px;
64
+ font-weight: bold;
65
+ width: 30%;
66
+ text-align: right;
67
+ }
68
+
69
+ .dialog_form .label_info {
70
+ box-sizing: border-box;
71
+ padding-right: 0.5em;
72
+ font-size: 12px;
73
+ width: 30%;
74
+ text-align: right;
75
+ display: inline-block;
76
+ }
77
+
78
+ .dialog_form_item {
79
+ margin: 10px 0;
80
+ font-size: 0;
81
+ }
82
+
83
+ .dialog_form_item .wide_input {
84
+ box-sizing: border-box;
85
+ max-width: 70%;
86
+ width: 27em;
87
+ }
88
+
89
+ .dialog_form_actions {
90
+ text-align: right;
91
+ padding: 0 20px 20px;
92
+ }
93
+
94
+ .dialog_close_button {
95
+ float: right;
96
+ position: absolute;
97
+ top: 10px;
98
+ left: 92%;
99
+ height: 25px;
100
+ }
101
+
102
+ .dialog_close_button img {
103
+ border: 0;
104
+ }
105
+
106
+ .dialog_desc {
107
+ padding: 10px 20px;
108
+ }
109
+
110
+ /* native <dialog> element uses the ::backdrop pseudo-element */
111
+
112
+ /* dialog::backdrop, */
113
+ .dialog-backdrop {
114
+ display: none;
115
+ position: fixed;
116
+ overflow-y: auto;
117
+ top: 0;
118
+ right: 0;
119
+ bottom: 0;
120
+ left: 0;
121
+ z-index: 1;
122
+ }
123
+
124
+ @media screen and (min-width: 640px) {
125
+ .dialog-backdrop {
126
+ background: rgb(0 0 0 / 30%);
127
+ }
128
+ }
129
+
130
+ .dialog-backdrop.active {
131
+ display: block;
132
+ }
133
+
134
+ .no-scroll {
135
+ overflow-y: auto !important;
136
+ }
137
+
138
+ /* this is added to the body when a dialog is open */
139
+ .has-dialog {
140
+ overflow: hidden;
141
+ }
@@ -16,7 +16,7 @@
16
16
  "author": "",
17
17
  "dependencies": {
18
18
  "govuk-frontend": "3.14",
19
- "jquery": "^3.6.0",
19
+ "jquery": "^3.6.1",
20
20
  "sass": "^1.53.0",
21
21
  "typeahead-aria": "^1.0.4"
22
22
  },