hof 24.4.0 → 24.5.0-jquery-removal-beta.1

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 2026-09-14 Version 24.5.1 (Stable), @nzorba @dk4g @dalglishdhandaHO
2
+
3
+ ### Changed
4
+ - Removed jQuery from the session timeout dialog and replaced its DOM operations with native browser APIs.
5
+ - Removed the jQuery dependency and updated frontend tests to use native DOM APIs and `fetch`.
6
+ - Migrated from `momentjs` to `dayjs`
7
+
8
+ ### Fixes
9
+ - Added missing Welsh cookie page translation entries to match the English cookie configuration ((#710)[https://github.com/UKHomeOfficeForms/hof/pull/710])
10
+
11
+ ### Chore & Maintenance
12
+ - Removed the vulnerable PhantomJS-based functional test driver stack and migrated the functional test browser runner to Playwright ((#699)[https://github.com/UKHomeOfficeForms/hof/pull/699])
13
+ - Updated node and Redis versions in testing matrix ((#700)[https://github.com/UKHomeOfficeForms/hof/pull/700])
14
+
1
15
  ## 2026-07-01, Version 24.4.0 (Stable), @vivekkumar-ho
2
16
 
3
17
  ### Security
package/README.md CHANGED
@@ -139,6 +139,16 @@ Each task (except Vite) has a common configuration format with the following opt
139
139
  - `match` - defines the pattern for files to watch to trigger a rebuild of this task
140
140
  - `restart` - defines if this task should result in a server restart
141
141
 
142
+ For Vite, the following configuration can be specified:
143
+ - `outDir` - Specifies the output directory (relative to project root). Only changes only the build output location, does not change runtime static mounting.
144
+ Example from hof settings:
145
+ ```js
146
+ "js": {
147
+ "outDir": './dist/public'
148
+ }
149
+ ```
150
+
151
+
142
152
  Additionally the server instance created by `watch` can be configured by setting `server` config. Available options are:
143
153
 
144
154
  - `cmd` - defines the command used to start the server
@@ -7,18 +7,23 @@ const hofDefaults = require('../../../config/hof-defaults');
7
7
 
8
8
  module.exports = config => {
9
9
  process.env.NODE_ENV = hofDefaults.env;
10
+ const publicDirectory = path.resolve(process.cwd(), config.js.outDir || 'public');
10
11
 
11
12
  if(!config.production) {
12
13
  return vite.build({
13
14
  configFile: viteConfig,
14
15
  mode: 'development',
15
16
  build: {
16
- sourcemap: config.js.sourceMaps
17
+ sourcemap: config.js.sourceMaps,
18
+ outDir: publicDirectory
17
19
  }
18
20
  });
19
21
  }
20
22
  return vite.build({
21
- configFile: viteConfig
23
+ configFile: viteConfig,
24
+ build: {
25
+ outDir: publicDirectory
26
+ }
22
27
  });
23
28
  };
24
29
  module.exports.task = 'vite';
@@ -7,7 +7,6 @@ import fs from 'fs';
7
7
  import { nodeResolve } from '@rollup/plugin-node-resolve';
8
8
  import commonjs from '@rollup/plugin-commonjs';
9
9
 
10
- const publicDirectory = resolve(process.cwd(), 'public');
11
10
  const entryFile = (() => {
12
11
  const src = resolve(process.cwd(), 'assets/js/index.js');
13
12
  if (fs.existsSync(src)) return src;
@@ -49,7 +48,6 @@ export default defineConfig({
49
48
  base: '/assets/',
50
49
  publicDir: 'static', // static files copied as-is
51
50
  build: {
52
- outDir: publicDirectory,
53
51
  emptyOutDir: false,
54
52
  sourcemap: false,
55
53
  rollupOptions: {
@@ -15,7 +15,8 @@ module.exports = {
15
15
  sourceMaps: false
16
16
  },
17
17
  js: {
18
- sourceMaps: false
18
+ sourceMaps: false,
19
+ outDir: 'public'
19
20
  },
20
21
  translate: {
21
22
  src: 'apps/**/translations/src',
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const moment = require('moment');
3
+ const dayjs = require('dayjs');
4
+ const customParseFormat = require('dayjs/plugin/customParseFormat');
4
5
  const _ = require('lodash');
5
6
  const libPhoneNumber = require('libphonenumber-js/max');
6
7
  const deprecate = require('deprecate');
@@ -11,6 +12,8 @@ const emailValidator = require('./email');
11
12
  const dateFormat = 'YYYY-MM-DD';
12
13
  let Validators;
13
14
 
15
+ dayjs.extend(customParseFormat);
16
+
14
17
  module.exports = Validators = {
15
18
 
16
19
  string(value) {
@@ -113,7 +116,7 @@ module.exports = Validators = {
113
116
  },
114
117
 
115
118
  date(value) {
116
- return value === '' || Validators.regex(value, /\d{4}\-\d{2}\-\d{2}/) && moment(value, dateFormat).isValid();
119
+ return value === '' || Validators.regex(value, /\d{4}\-\d{2}\-\d{2}/) && dayjs(value, dateFormat, true).isValid();
117
120
  },
118
121
 
119
122
  'date-year'(value) {
@@ -131,12 +134,12 @@ module.exports = Validators = {
131
134
  // eslint-disable-next-line no-inline-comments, spaced-comment
132
135
  before(value, date) {
133
136
  // validator can also do before(value, [diff, unit][, diff, unit])
134
- let valueDate = moment(value, dateFormat);
137
+ let valueDate = dayjs(value, dateFormat, true);
135
138
  let comparator;
136
139
  if (arguments.length === 2) {
137
140
  comparator = date;
138
141
  } else {
139
- comparator = moment();
142
+ comparator = dayjs();
140
143
  const args = [].slice.call(arguments, 1);
141
144
  let diff;
142
145
  let unit;
@@ -151,12 +154,12 @@ module.exports = Validators = {
151
154
 
152
155
  after(value, date) {
153
156
  // validator can also do after(value, [diff, unit][, diff, unit])
154
- let valueDate = moment(value, dateFormat);
157
+ let valueDate = dayjs(value, dateFormat, true);
155
158
  let comparator;
156
159
  if (arguments.length === 2) {
157
160
  comparator = date;
158
161
  } else {
159
- comparator = moment();
162
+ comparator = dayjs();
160
163
  const args = [].slice.call(arguments, 1);
161
164
  let diff;
162
165
  let unit;
@@ -0,0 +1,118 @@
1
+
2
+ <!DOCTYPE html>
3
+ <!--[if lt IE 9]><html class="lte-ie8" lang="{{htmlLang}}"><![endif]-->
4
+ <!--[if gt IE 8]><!--><html lang="{{htmlLang}}" class="govuk-template--rebranded"><!--<![endif]-->
5
+ <head>
6
+ <meta charset="utf-8" />
7
+ <title>{{$pageTitle}}{{/pageTitle}}</title>
8
+ {{$head}}{{/head}}
9
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
10
+ <meta name="theme-color" content="#1d70b8">
11
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
12
+ <link rel="icon" sizes="48x48" href="{{govukAssetPath}}rebrand/images/favicon.ico">
13
+ <link rel="icon" sizes="any" href="{{govukAssetPath}}rebrand/images/favicon.svg" type="image/svg+xml">
14
+ <link rel="mask-icon" href="{{govukAssetPath}}rebrand/images/govuk-icon-mask.svg" color="#1d70b8">
15
+ <link rel="apple-touch-icon" href="{{govukAssetPath}}rebrand/images/govuk-icon-180.png">
16
+ <link rel="manifest" href="{{govukAssetPath}}rebrand/manifest.json">
17
+ <meta property="og:image" content="{{govukAssetPath}}rebrand/images/govuk-opengraph-image.png">
18
+ </head>
19
+
20
+ <body class="{{$bodyClasses}}{{/bodyClasses}} govuk-template__body js-enabled" >
21
+ <script {{#nonce}}nonce="{{nonce}}"{{/nonce}}>document.body.className += ' js-enabled' + ('noModule' in HTMLScriptElement.prototype ? ' govuk-frontend-supported' : '');</script>
22
+
23
+
24
+ <div id="global-cookie-message" class="gem-c-cookie-banner govuk-clearfix" data-module="cookie-banner" role="region" aria-label="cookie banner" data-nosnippet="">
25
+ {{$cookieMessage}}{{/cookieMessage}}
26
+ </div>
27
+
28
+ {{$bodyStart}}{{/bodyStart}}
29
+
30
+ <header role="banner" id="govuk-header" class="{{$headerClass}}{{/headerClass}}">
31
+ <div class="govuk-header__container govuk-width-container">
32
+
33
+ <div class="govuk-header__logo">
34
+ <a href="{{$homepageUrl}}https://www.gov.uk{{/homepageUrl}}" title="{{$logoLinkTitle}}Go to the GOV.UK homepage{{/logoLinkTitle}}" id="logo" class="govuk-header__link govuk-header__link--homepage" target="_blank" data-module="track-click" data-track-category="homeLinkClicked" data-track-action="homeHeader">
35
+ <!--[if gt IE 8]><!-->
36
+ <div id="govuk-header__logo"></div>
37
+ <img src="/public/images/govuk-logo.svg" id="govuk-header__logo" alt="Logo" loading="lazy" />
38
+ <!--<![endif]-->
39
+ <!--[if IE 8]>
40
+ <img src="{{govukAssetPath}}rebrand/images/govuk-logotype-tudor-crown.png" class="govuk-header__logotype-crown-fallback-image" width="32" height="30" alt="">
41
+ <![endif]-->
42
+ </a>
43
+ </div>
44
+ {{$insideHeader}}{{/insideHeader}}
45
+
46
+ {{$propositionHeader}}{{/propositionHeader}}
47
+ </div>
48
+ </header>
49
+
50
+
51
+ {{$afterHeader}}{{/afterHeader}}
52
+
53
+
54
+ {{$main}}{{/main}}
55
+
56
+ <footer class="govuk-footer">
57
+ <div class="govuk-width-container">
58
+ <svg
59
+ focusable="false"
60
+ role="presentation"
61
+ xmlns="http://www.w3.org/2000/svg"
62
+ viewBox="0 0 64 60"
63
+ height="30"
64
+ width="32"
65
+ fill="currentcolor" class="govuk-footer__crown">
66
+ <g>
67
+ <circle cx="20" cy="17.6" r="3.7" />
68
+ <circle cx="10.2" cy="23.5" r="3.7" />
69
+ <circle cx="3.7" cy="33.2" r="3.7" />
70
+ <circle cx="31.7" cy="30.6" r="3.7" />
71
+ <circle cx="43.3" cy="17.6" r="3.7" />
72
+ <circle cx="53.2" cy="23.5" r="3.7" />
73
+ <circle cx="59.7" cy="33.2" r="3.7" />
74
+ <circle cx="31.7" cy="30.6" r="3.7" />
75
+ <path d="M33.1,9.8c.2-.1.3-.3.5-.5l4.6,2.4v-6.8l-4.6,1.5c-.1-.2-.3-.3-.5-.5l1.9-5.9h-6.7l1.9,5.9c-.2.1-.3.3-.5.5l-4.6-1.5v6.8l4.6-2.4c.1.2.3.3.5.5l-2.6,8c-.9,2.8,1.2,5.7,4.1,5.7h0c3,0,5.1-2.9,4.1-5.7l-2.6-8ZM37,37.9s-3.4,3.8-4.1,6.1c2.2,0,4.2-.5,6.4-2.8l-.7,8.5c-2-2.8-4.4-4.1-5.7-3.8.1,3.1.5,6.7,5.8,7.2,3.7.3,6.7-1.5,7-3.8.4-2.6-2-4.3-3.7-1.6-1.4-4.5,2.4-6.1,4.9-3.2-1.9-4.5-1.8-7.7,2.4-10.9,3,4,2.6,7.3-1.2,11.1,2.4-1.3,6.2,0,4,4.6-1.2-2.8-3.7-2.2-4.2.2-.3,1.7.7,3.7,3,4.2,1.9.3,4.7-.9,7-5.9-1.3,0-2.4.7-3.9,1.7l2.4-8c.6,2.3,1.4,3.7,2.2,4.5.6-1.6.5-2.8,0-5.3l5,1.8c-2.6,3.6-5.2,8.7-7.3,17.5-7.4-1.1-15.7-1.7-24.5-1.7h0c-8.8,0-17.1.6-24.5,1.7-2.1-8.9-4.7-13.9-7.3-17.5l5-1.8c-.5,2.5-.6,3.7,0,5.3.8-.8,1.6-2.3,2.2-4.5l2.4,8c-1.5-1-2.6-1.7-3.9-1.7,2.3,5,5.2,6.2,7,5.9,2.3-.4,3.3-2.4,3-4.2-.5-2.4-3-3.1-4.2-.2-2.2-4.6,1.6-6,4-4.6-3.7-3.7-4.2-7.1-1.2-11.1,4.2,3.2,4.3,6.4,2.4,10.9,2.5-2.8,6.3-1.3,4.9,3.2-1.8-2.7-4.1-1-3.7,1.6.3,2.3,3.3,4.1,7,3.8,5.4-.5,5.7-4.2,5.8-7.2-1.3-.2-3.7,1-5.7,3.8l-.7-8.5c2.2,2.3,4.2,2.7,6.4,2.8-.7-2.3-4.1-6.1-4.1-6.1h10.6,0Z" />
76
+ </g>
77
+ </svg>
78
+ <div class="govuk-footer__meta">
79
+ <div class="govuk-footer__meta-item govuk-footer__meta-item--grow">
80
+ <h2 class="govuk-visually-hidden">Support links</h2>
81
+ {{$footerSupportLinks}}{{/footerSupportLinks}}
82
+ <svg
83
+ aria-hidden="true"
84
+ focusable="false"
85
+ class="govuk-footer__licence-logo"
86
+ xmlns="http://www.w3.org/2000/svg"
87
+ viewBox="0 0 483.2 195.7"
88
+ height="17"
89
+ width="41">
90
+ <path
91
+ fill="currentColor"
92
+ d="M421.5 142.8V.1l-50.7 32.3v161.1h112.4v-50.7zm-122.3-9.6A47.12 47.12 0 0 1 221 97.8c0-26 21.1-47.1 47.1-47.1 16.7 0 31.4 8.7 39.7 21.8l42.7-27.2A97.63 97.63 0 0 0 268.1 0c-36.5 0-68.3 20.1-85.1 49.7A98 98 0 0 0 97.8 0C43.9 0 0 43.9 0 97.8s43.9 97.8 97.8 97.8c36.5 0 68.3-20.1 85.1-49.7a97.76 97.76 0 0 0 149.6 25.4l19.4 22.2h3v-87.8h-80l24.3 27.5zM97.8 145c-26 0-47.1-21.1-47.1-47.1s21.1-47.1 47.1-47.1 47.2 21 47.2 47S123.8 145 97.8 145" />
93
+ </svg>
94
+ <span class="govuk-footer__licence-description">
95
+ {{$licenceMessage}}All content is available under the <a href="https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/" id="open-government-licence" class="govuk-footer__link" target="_blank" rel="license">Open Government Licence v3.0</a>, except where otherwise stated{{/licenceMessage}}
96
+ </span>
97
+ </div>
98
+ <div class="govuk-footer__meta-item">
99
+ <a
100
+ class="govuk-footer__link govuk-footer__copyright-logo"
101
+ href="https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/">
102
+ {{$crownCopyrightMessage}}© Crown copyright{{/crownCopyrightMessage}}
103
+ </a>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </footer>
108
+
109
+ <div id="global-app-error" class="app-error hidden"></div>
110
+
111
+
112
+ {{$bodyEnd}}{{/bodyEnd}}
113
+
114
+
115
+ <script {{#nonce}}nonce="{{nonce}}"{{/nonce}}>if (typeof window.GOVUK === 'undefined') document.body.className = document.body.className.replace('js-enabled', '');</script>
116
+
117
+ </body>
118
+ </html>
@@ -3,7 +3,7 @@
3
3
 
4
4
  const querystring = require('querystring');
5
5
  const path = require('path');
6
- const moment = require('moment');
6
+ const { formatDate } = require('../../../utilities/date');
7
7
 
8
8
  const renderer = require('./render');
9
9
 
@@ -33,7 +33,7 @@ module.exports = options => (req, res, next) => {
33
33
  return function (txt) {
34
34
  txt = (txt || '').split('|');
35
35
  const value = hoganRender(txt[0], this);
36
- return moment(value).format(txt[1] || 'D MMMM YYYY');
36
+ return formatDate(value, txt[1]);
37
37
  };
38
38
  };
39
39
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "banner": {
3
- "message": "Mae GOV.UK yn defnyddio cwcis i wneud y safle’n symlach",
4
- "link": "Darganfyddwch fwy am gwcis"
3
+ "message": "Rydym yn defnyddio rhai cwcis hanfodol i wneud i'r wefan hon weithio.",
4
+ "link": "Gweld cwcis"
5
5
  },
6
6
  "header": "Cwcis",
7
7
  "intro": "Mae’r gwasanaeth hwn yn gosod ffeiliau bychan (a elwir yn ‘cwcis’) ar eich cyfrifiadur er mwyn:",
@@ -39,6 +39,11 @@
39
39
  "seen_cookie_message",
40
40
  "Yn gadael i ni wybod eich bod wedi gweld ein neges cwcis yn barod",
41
41
  "1 mis"
42
+ ],
43
+ [
44
+ "cookie_preferences",
45
+ "Rhowch wybod i ni eich bod wedi cadw eich gosodiadau caniatâd cwci",
46
+ "1 mis"
42
47
  ]
43
48
  ]
44
49
  },
@@ -56,6 +61,8 @@
56
61
  },
57
62
  "no-identify": "Nid oes unrhyw fanylion personol yn cael eu storio gyda’r wybodaeth hon, felly ni ellir eich adnabod.",
58
63
  "analytics-table": {
64
+ "containerIdExpires": "2 flynedd",
65
+ "containerIdPurpose": "Defnyddir er mwyn parhau'r sesiwn",
59
66
  "headers": [
60
67
  "Enw",
61
68
  "Pwrpas",
@@ -71,6 +78,11 @@
71
78
  "_gat",
72
79
  "Defnyddir i wasgu’r gyfradd ceisiadau",
73
80
  "10 munud"
81
+ ],
82
+ [
83
+ "_gid",
84
+ "Defnyddir i gyfrif ac olrhain y tudalennau rydych yn eu gweld",
85
+ "24 awr"
74
86
  ]
75
87
  ]
76
88
  },
@@ -1,40 +1,55 @@
1
1
  /* eslint max-len: 0 */
2
2
  'use strict';
3
3
 
4
- const $ = require('jquery');
5
4
  window.dialogPolyfill = require('dialog-polyfill');
6
5
 
6
+ function getTextContent(selector) {
7
+ const element = document.querySelector(selector);
8
+ return element ? element.textContent : '';
9
+ }
10
+
11
+ function dialogDatasetValue(key) {
12
+ const element = document.getElementById('js-modal-dialog');
13
+ return element ? element.dataset[key] : undefined;
14
+ }
15
+
16
+ function parseTimeout(value, fallback) {
17
+ const parsedValue = parseInt(value, 10);
18
+ return Number.isNaN(parsedValue) ? fallback : parsedValue;
19
+ }
20
+
7
21
  // Modal dialog prototype
8
22
  window.GOVUK.sessionDialog = {
9
23
  el: document.getElementById('js-modal-dialog'),
10
- $el: $('#js-modal-dialog'),
11
- $lastFocusedEl: null,
12
- $closeButton: $('.modal-dialog .js-dialog-close'),
13
- $fallBackElement: $('.govuk-timeout-warning-fallback'),
24
+ lastFocusedEl: null,
25
+ closeButton: document.querySelector('.modal-dialog .js-dialog-close'),
26
+ fallBackElement: document.querySelector('.govuk-timeout-warning-fallback'),
14
27
  dialogIsOpenClass: 'dialog-is-open',
15
28
  timers: [],
16
- warningTextPrefix: $('.dialog-text-prefix').text(),
29
+ warningTextPrefix: getTextContent('.dialog-text-prefix'),
17
30
  warningTextSuffix: '.',
18
- warningText: $('.dialog-text').text(),
31
+ warningText: getTextContent('.dialog-text'),
19
32
  warningTextExtra: '',
20
33
 
21
34
  // Timer specific markup. If these are not present, timeout and redirection are disabled
22
- $timer: $('#js-modal-dialog .timer'),
23
- $accessibleTimer: $('#js-modal-dialog .at-timer'),
35
+ timer: document.querySelector('#js-modal-dialog') ? document.querySelector('#js-modal-dialog .timer') : null,
36
+ accessibleTimer: document.querySelector('#js-modal-dialog') ? document.querySelector('#js-modal-dialog .at-timer') : null,
24
37
 
25
- secondsSessionTimeout: parseInt($('#js-modal-dialog').data('session-timeout'), 10 || 1800),
26
- secondsTimeoutWarning: parseInt($('#js-modal-dialog').data('session-timeout-warning'), 10 || 300),
27
- timeoutRedirectUrl: $('#js-modal-dialog').data('url-redirect'),
38
+ secondsSessionTimeout: parseTimeout(dialogDatasetValue('sessionTimeout'), 1800),
39
+ secondsTimeoutWarning: parseTimeout(dialogDatasetValue('sessionTimeoutWarning'), 300),
40
+ timeoutRedirectUrl: dialogDatasetValue('urlRedirect'),
28
41
  timeSessionRefreshed: new Date(),
29
42
 
30
43
  bindUIElements: function () {
31
- window.GOVUK.sessionDialog.$closeButton.on('click', function (e) {
32
- e.preventDefault();
33
- window.GOVUK.sessionDialog.closeDialog();
34
- });
44
+ if (window.GOVUK.sessionDialog.closeButton) {
45
+ window.GOVUK.sessionDialog.closeButton.addEventListener('click', function (e) {
46
+ e.preventDefault();
47
+ window.GOVUK.sessionDialog.closeDialog();
48
+ });
49
+ }
35
50
 
36
51
  // Close modal when ESC pressed
37
- $(document).keydown(function (e) {
52
+ document.addEventListener('keydown', function (e) {
38
53
  if (window.GOVUK.sessionDialog.isDialogOpen() && e.keyCode === 27) {
39
54
  window.GOVUK.sessionDialog.closeDialog();
40
55
  }
@@ -46,8 +61,8 @@ window.GOVUK.sessionDialog = {
46
61
  },
47
62
 
48
63
  isConfigured: function () {
49
- return window.GOVUK.sessionDialog.$timer.length > 0 &&
50
- window.GOVUK.sessionDialog.$accessibleTimer.length > 0 &&
64
+ return window.GOVUK.sessionDialog.timer &&
65
+ window.GOVUK.sessionDialog.accessibleTimer &&
51
66
  window.GOVUK.sessionDialog.secondsSessionTimeout &&
52
67
  window.GOVUK.sessionDialog.secondsTimeoutWarning &&
53
68
  window.GOVUK.sessionDialog.timeoutRedirectUrl;
@@ -55,7 +70,8 @@ window.GOVUK.sessionDialog = {
55
70
 
56
71
  openDialog: function () {
57
72
  if (!window.GOVUK.sessionDialog.isDialogOpen()) {
58
- $('html, body').addClass(window.GOVUK.sessionDialog.dialogIsOpenClass);
73
+ document.documentElement.classList.add(window.GOVUK.sessionDialog.dialogIsOpenClass);
74
+ document.body.classList.add(window.GOVUK.sessionDialog.dialogIsOpenClass);
59
75
  window.GOVUK.sessionDialog.saveLastFocusedEl();
60
76
  window.GOVUK.sessionDialog.makePageContentInert();
61
77
  window.GOVUK.sessionDialog.el.showModal();
@@ -65,7 +81,8 @@ window.GOVUK.sessionDialog = {
65
81
 
66
82
  closeDialog: function () {
67
83
  if (window.GOVUK.sessionDialog.isDialogOpen()) {
68
- $('html, body').removeClass(window.GOVUK.sessionDialog.dialogIsOpenClass);
84
+ document.documentElement.classList.remove(window.GOVUK.sessionDialog.dialogIsOpenClass);
85
+ document.body.classList.remove(window.GOVUK.sessionDialog.dialogIsOpenClass);
69
86
  window.GOVUK.sessionDialog.el.close();
70
87
  window.GOVUK.sessionDialog.el.open = false;
71
88
  window.GOVUK.sessionDialog.setFocusOnLastFocusedEl();
@@ -75,19 +92,19 @@ window.GOVUK.sessionDialog = {
75
92
  },
76
93
 
77
94
  saveLastFocusedEl: function () {
78
- window.GOVUK.sessionDialog.$lastFocusedEl = document.activeElement;
79
- if (!window.GOVUK.sessionDialog.$lastFocusedEl || window.GOVUK.sessionDialog.$lastFocusedEl === document.body) {
80
- window.GOVUK.sessionDialog.$lastFocusedEl = null;
95
+ window.GOVUK.sessionDialog.lastFocusedEl = document.activeElement;
96
+ if (!window.GOVUK.sessionDialog.lastFocusedEl || window.GOVUK.sessionDialog.lastFocusedEl === document.body) {
97
+ window.GOVUK.sessionDialog.lastFocusedEl = null;
81
98
  } else if (document.querySelector) {
82
- window.GOVUK.sessionDialog.$lastFocusedEl = document.querySelector(':focus');
99
+ window.GOVUK.sessionDialog.lastFocusedEl = document.querySelector(':focus');
83
100
  }
84
101
  },
85
102
 
86
103
  // Set focus back on last focused el when modal closed
87
104
  setFocusOnLastFocusedEl: function () {
88
- if (window.GOVUK.sessionDialog.$lastFocusedEl) {
105
+ if (window.GOVUK.sessionDialog.lastFocusedEl) {
89
106
  window.setTimeout(function () {
90
- window.GOVUK.sessionDialog.$lastFocusedEl.focus();
107
+ window.GOVUK.sessionDialog.lastFocusedEl.focus();
91
108
  }, 0);
92
109
  }
93
110
  },
@@ -222,15 +239,15 @@ window.GOVUK.sessionDialog = {
222
239
  },
223
240
 
224
241
  startCountdown: function () {
225
- const $timer = window.GOVUK.sessionDialog.$timer;
226
- const $accessibleTimer = window.GOVUK.sessionDialog.$accessibleTimer;
242
+ const timer = window.GOVUK.sessionDialog.timer;
243
+ const accessibleTimer = window.GOVUK.sessionDialog.accessibleTimer;
227
244
  let timerRunOnce = false;
228
245
  const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
229
246
 
230
247
  const seconds = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
231
248
  const minutes = seconds / 60;
232
249
 
233
- $timer.text(minutes + ' minute' + (minutes > 1 ? 's' : ''));
250
+ timer.textContent = minutes + ' minute' + (minutes > 1 ? 's' : '');
234
251
 
235
252
  (function countdown() {
236
253
  const secondsUntilSessionTimeout = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
@@ -250,17 +267,17 @@ window.GOVUK.sessionDialog = {
250
267
  const atText = window.GOVUK.sessionDialog.warningTextPrefix + countdownAtText + window.GOVUK.sessionDialog.warningTextSuffix + ' ' + window.GOVUK.sessionDialog.warningText;
251
268
  const extraText = '\n' + window.GOVUK.sessionDialog.warningTextExtra;
252
269
 
253
- $timer.html(text + ' ' + extraText);
270
+ timer.innerHTML = text + ' ' + extraText;
254
271
 
255
272
  // Update screen reader friendly content every 20 secs
256
273
  if (secondsLeft % 20 === 0) {
257
274
  // Read out the extra content only once.
258
275
  // Don't read out on iOS VoiceOver which stalls on the longer text
259
276
  if (!timerRunOnce && !iOS) {
260
- $accessibleTimer.text(atText + extraText);
277
+ accessibleTimer.textContent = atText + extraText;
261
278
  timerRunOnce = true;
262
279
  } else {
263
- $accessibleTimer.text(atText);
280
+ accessibleTimer.textContent = atText;
264
281
  }
265
282
  }
266
283
 
@@ -277,10 +294,17 @@ window.GOVUK.sessionDialog = {
277
294
  },
278
295
 
279
296
  refreshSession: function () {
280
- $.get('')
281
- .done(function () {
297
+ return fetch('')
298
+ .then(function (response) {
299
+ if (!response.ok) {
300
+ throw new Error('Session refresh failed');
301
+ }
282
302
  window.GOVUK.sessionDialog.timeSessionRefreshed = new Date();
283
303
  window.GOVUK.sessionDialog.controller();
304
+ })
305
+ .catch(function (error) {
306
+ // eslint-disable-next-line no-console
307
+ console.error(error);
284
308
  });
285
309
  },
286
310
 
@@ -327,7 +351,7 @@ window.GOVUK.sessionDialog = {
327
351
  },
328
352
 
329
353
  init: function (options) {
330
- $.extend(window.GOVUK.sessionDialog, options);
354
+ Object.assign(window.GOVUK.sessionDialog, options);
331
355
  if (window.GOVUK.sessionDialog.el && window.GOVUK.sessionDialog.isConfigured()) {
332
356
  // Native dialog is not supported by some browsers so use polyfill
333
357
  if (typeof HTMLDialogElement !== 'function') {
@@ -336,7 +360,7 @@ window.GOVUK.sessionDialog = {
336
360
  return true;
337
361
  } catch (error) {
338
362
  // Doesn't support polyfill (IE8) - display fallback element
339
- window.GOVUK.sessionDialog.$fallBackElement.classList.add('govuk-!-display-block');
363
+ window.GOVUK.sessionDialog.fallBackElement.classList.add('govuk-!-display-block');
340
364
  return false;
341
365
  }
342
366
  }
@@ -1,5 +1,5 @@
1
1
 
2
- const moment = require('moment');
2
+ const dayjs = require('dayjs');
3
3
  const redis = require('redis');
4
4
  const config = require('./../config/hof-defaults');
5
5
 
@@ -36,8 +36,8 @@ module.exports = (options, rateLimitType) => {
36
36
  logger.log('error', `Error with requesting redis session for rate limiting: ${err}`);
37
37
  return await closeConnection();
38
38
  }
39
- const currentRequestTime = moment();
40
- const windowStartTimestamp = moment().subtract(WINDOW_SIZE_IN_MINUTES, 'minutes').unix();
39
+ let currentRequestTime = dayjs();
40
+ const windowStartTimestamp = dayjs().subtract(WINDOW_SIZE_IN_MINUTES, 'minutes').unix();
41
41
  let oldRecord = false;
42
42
  let data;
43
43
  // if no record is found , create a new record for user and store to redis
@@ -74,9 +74,9 @@ module.exports = (options, rateLimitType) => {
74
74
  }
75
75
  // if number of requests made is less than allowed maximum, log new entry
76
76
  const lastRequestLog = data[data.length - 1];
77
- const potentialCurrentWindowIntervalStartTimeStamp = currentRequestTime
78
- .subtract(WINDOW_LOG_INTERVAL_IN_MINUTES, 'minutes')
79
- .unix();
77
+ currentRequestTime = currentRequestTime
78
+ .subtract(WINDOW_LOG_INTERVAL_IN_MINUTES, 'minutes');
79
+ const potentialCurrentWindowIntervalStartTimeStamp = currentRequestTime.unix();
80
80
  // if interval has not passed since last request log, increment counter
81
81
  if (lastRequestLog[timestampName] > potentialCurrentWindowIntervalStartTimeStamp) {
82
82
  lastRequestLog[countName]++;