hmrc-frontend 5.4.0 → 5.7.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.
package/hmrc/VERSION.txt CHANGED
@@ -1 +1 @@
1
- 5.4.0
1
+ 5.7.0
package/hmrc/all.js CHANGED
@@ -40,6 +40,31 @@
40
40
  }, _typeof(obj);
41
41
  }
42
42
 
43
+ function _classCallCheck(instance, Constructor) {
44
+ if (!(instance instanceof Constructor)) {
45
+ throw new TypeError("Cannot call a class as a function");
46
+ }
47
+ }
48
+
49
+ function _defineProperties(target, props) {
50
+ for (var i = 0; i < props.length; i++) {
51
+ var descriptor = props[i];
52
+ descriptor.enumerable = descriptor.enumerable || false;
53
+ descriptor.configurable = true;
54
+ if ("value" in descriptor) descriptor.writable = true;
55
+ Object.defineProperty(target, descriptor.key, descriptor);
56
+ }
57
+ }
58
+
59
+ function _createClass(Constructor, protoProps, staticProps) {
60
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
61
+ if (staticProps) _defineProperties(Constructor, staticProps);
62
+ Object.defineProperty(Constructor, "prototype", {
63
+ writable: false
64
+ });
65
+ return Constructor;
66
+ }
67
+
43
68
  function _defineProperty(obj, key, value) {
44
69
  if (key in obj) {
45
70
  Object.defineProperty(obj, key, {
@@ -1385,7 +1410,11 @@
1385
1410
  };
1386
1411
 
1387
1412
  ValidateInput.string = function (stringToValidate) {
1388
- return stringToValidate && ("".concat(stringToValidate) || undefined);
1413
+ return typeof stringToValidate === 'string' ? stringToValidate : undefined;
1414
+ };
1415
+
1416
+ ValidateInput["boolean"] = function (stringToValidate) {
1417
+ return String(stringToValidate).toLowerCase() === 'true';
1389
1418
  };
1390
1419
 
1391
1420
  function RedirectHelper() {}
@@ -1395,11 +1424,12 @@
1395
1424
  window.location.href = url;
1396
1425
  };
1397
1426
 
1398
- function TimeoutDialog($module) {
1427
+ function TimeoutDialog($module, $sessionActivityService) {
1399
1428
  var options = {};
1400
1429
  var settings = {};
1401
1430
  var cleanupFunctions = [];
1402
1431
  var currentTimer;
1432
+ var sessionActivityService = $sessionActivityService;
1403
1433
  cleanupFunctions.push(function () {
1404
1434
  if (currentTimer) {
1405
1435
  window.clearTimeout(currentTimer);
@@ -1446,15 +1476,31 @@
1446
1476
  message: validate.string(lookupData('data-message')),
1447
1477
  messageSuffix: validate.string(lookupData('data-message-suffix')),
1448
1478
  keepAliveButtonText: validate.string(lookupData('data-keep-alive-button-text')),
1449
- signOutButtonText: validate.string(lookupData('data-sign-out-button-text'))
1479
+ signOutButtonText: validate.string(lookupData('data-sign-out-button-text')),
1480
+ synchroniseTabs: validate["boolean"](lookupData('data-synchronise-tabs') || false)
1450
1481
  }; // Default timeoutUrl to signOutUrl if not set
1451
1482
 
1452
1483
  options.timeoutUrl = options.timeoutUrl || options.signOutUrl;
1453
1484
  validateInput(options);
1454
1485
  settings = mergeOptionsWithDefaults(options, localisedDefaults);
1455
1486
  setupDialogTimer();
1487
+ listenForSessionActivityAndResetDialogTimer();
1456
1488
  }
1457
1489
 
1490
+ var broadcastSessionActivity = function broadcastSessionActivity() {
1491
+ sessionActivityService.logActivity();
1492
+ };
1493
+
1494
+ var listenForSessionActivityAndResetDialogTimer = function listenForSessionActivityAndResetDialogTimer() {
1495
+ if (settings.synchroniseTabs) {
1496
+ sessionActivityService.onActivity(function (event) {
1497
+ var timeOfActivity = event.timestamp;
1498
+ cleanup();
1499
+ setupDialogTimer(timeOfActivity);
1500
+ });
1501
+ }
1502
+ };
1503
+
1458
1504
  var validateInput = function validateInput(config) {
1459
1505
  var requiredConfig = ['timeout', 'countdown', 'keepAliveUrl', 'signOutUrl'];
1460
1506
  var missingRequiredConfig = [];
@@ -1485,10 +1531,13 @@
1485
1531
  };
1486
1532
 
1487
1533
  var setupDialogTimer = function setupDialogTimer() {
1488
- settings.signout_time = getDateNow() + settings.timeout * 1000;
1534
+ var timeOfLastActivity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getDateNow();
1535
+ var signoutTime = timeOfLastActivity + settings.timeout * 1000;
1536
+ var delta = getDateNow() - timeOfLastActivity;
1537
+ var secondsUntilTimeoutDialog = settings.timeout - settings.countdown;
1489
1538
  var timeout = window.setTimeout(function () {
1490
- setupDialog();
1491
- }, (settings.timeout - settings.countdown) * 1000);
1539
+ setupDialog(signoutTime);
1540
+ }, secondsUntilTimeoutDialog * 1000 - delta);
1492
1541
  cleanupFunctions.push(function () {
1493
1542
  window.clearTimeout(timeout);
1494
1543
  });
@@ -1501,7 +1550,7 @@
1501
1550
  return $wrapper;
1502
1551
  };
1503
1552
 
1504
- var setupDialog = function setupDialog() {
1553
+ var setupDialog = function setupDialog(signoutTime) {
1505
1554
  var $element = utils.generateDomElementFromString('<div>');
1506
1555
 
1507
1556
  if (settings.title) {
@@ -1536,18 +1585,15 @@
1536
1585
  });
1537
1586
  dialogControl.addCloseHandler(keepAliveAndClose);
1538
1587
  dialogControl.setAriaLabelledBy('hmrc-timeout-heading hmrc-timeout-message');
1539
- startCountdown($countdownElement, $audibleMessage);
1540
- };
1541
1588
 
1542
- var getMillisecondsRemaining = function getMillisecondsRemaining() {
1543
- return settings.signout_time - getDateNow();
1544
- };
1589
+ var getMillisecondsRemaining = function getMillisecondsRemaining() {
1590
+ return signoutTime - getDateNow();
1591
+ };
1545
1592
 
1546
- var getSecondsRemaining = function getSecondsRemaining() {
1547
- return Math.round(getMillisecondsRemaining() / 1000);
1548
- };
1593
+ var getSecondsRemaining = function getSecondsRemaining() {
1594
+ return Math.round(getMillisecondsRemaining() / 1000);
1595
+ };
1549
1596
 
1550
- var startCountdown = function startCountdown($countdownElement, $screenReaderCountdownElement) {
1551
1597
  var getHumanText = function getHumanText(counter) {
1552
1598
  var minutes;
1553
1599
  var visibleMessage;
@@ -1597,7 +1643,7 @@
1597
1643
  var visibleMessage = getHumanText(counter);
1598
1644
  var audibleHumanText = getAudibleHumanText(counter);
1599
1645
  updateTextIfChanged($countdownElement, visibleMessage);
1600
- updateTextIfChanged($screenReaderCountdownElement, audibleHumanText);
1646
+ updateTextIfChanged($audibleMessage, audibleHumanText);
1601
1647
  };
1602
1648
 
1603
1649
  var getNextTimeout = function getNextTimeout() {
@@ -1629,6 +1675,7 @@
1629
1675
  cleanup();
1630
1676
  setupDialogTimer();
1631
1677
  utils.ajaxGet(settings.keepAliveUrl, function () {});
1678
+ broadcastSessionActivity();
1632
1679
  };
1633
1680
 
1634
1681
  var getDateNow = function getDateNow() {
@@ -3005,6 +3052,37 @@
3005
3052
  clearInterval(this.valueChecker);
3006
3053
  };
3007
3054
 
3055
+ var SessionActivityService = /*#__PURE__*/function () {
3056
+ function SessionActivityService(BrowserBroadcastChannel) {
3057
+ _classCallCheck(this, SessionActivityService);
3058
+
3059
+ this.activityChannel = BrowserBroadcastChannel && new BrowserBroadcastChannel('session-activity');
3060
+ }
3061
+
3062
+ _createClass(SessionActivityService, [{
3063
+ key: "logActivity",
3064
+ value: function logActivity() {
3065
+ if (this.activityChannel) {
3066
+ var event = {
3067
+ timestamp: Date.now()
3068
+ };
3069
+ this.activityChannel.postMessage(event);
3070
+ }
3071
+ }
3072
+ }, {
3073
+ key: "onActivity",
3074
+ value: function onActivity(callback) {
3075
+ if (this.activityChannel) {
3076
+ this.activityChannel.onmessage = function (event) {
3077
+ callback(event.data);
3078
+ };
3079
+ }
3080
+ }
3081
+ }]);
3082
+
3083
+ return SessionActivityService;
3084
+ }();
3085
+
3008
3086
  function initAll() {
3009
3087
  var $AccountMenuSelector = '[data-module="hmrc-account-menu"]';
3010
3088
 
@@ -3012,10 +3090,12 @@
3012
3090
  new AccountMenu($AccountMenuSelector).init();
3013
3091
  }
3014
3092
 
3093
+ var sessionActivityService = new SessionActivityService(window.BroadcastChannel);
3094
+ sessionActivityService.logActivity();
3015
3095
  var $TimeoutDialog = document.querySelector('meta[name="hmrc-timeout-dialog"]');
3016
3096
 
3017
3097
  if ($TimeoutDialog) {
3018
- new TimeoutDialog($TimeoutDialog).init();
3098
+ new TimeoutDialog($TimeoutDialog, sessionActivityService).init();
3019
3099
  }
3020
3100
 
3021
3101
  var $UserResearchBanner = document.querySelector('[data-module="hmrc-user-research-banner"]');
@@ -60,7 +60,7 @@
60
60
  {% endif %}
61
61
  {% if params.navigation | length %}
62
62
  <nav class="govuk-header__navigation" aria-label="Top Level Navigation">
63
- <button type="button" class="govuk-header__menu-button govuk-js-header-toggle" aria-controls="navigation" aria-label="Show or hide Top Level Navigation">Menu</button>
63
+ <button type="button" class="govuk-header__menu-button govuk-js-header-toggle" aria-controls="navigation" aria-label="Show or hide Top Level Navigation" hidden>Menu</button>
64
64
  <ul id="navigation" class="govuk-header__navigation-list{{ (' ' + params.navigationClasses) if params.navigationClasses }}">
65
65
  {% for item in params.navigation %}
66
66
  {% if item.text or item.html %}
@@ -0,0 +1,20 @@
1
+ export default class SessionActivityService {
2
+ constructor(BrowserBroadcastChannel) {
3
+ this.activityChannel = BrowserBroadcastChannel && new BrowserBroadcastChannel('session-activity');
4
+ }
5
+
6
+ logActivity() {
7
+ if (this.activityChannel) {
8
+ const event = { timestamp: Date.now() };
9
+ this.activityChannel.postMessage(event);
10
+ }
11
+ }
12
+
13
+ onActivity(callback) {
14
+ if (this.activityChannel) {
15
+ this.activityChannel.onmessage = (event) => {
16
+ callback(event.data);
17
+ };
18
+ }
19
+ }
20
+ }
@@ -11,4 +11,5 @@
11
11
  data-message="{{ params.message }}"
12
12
  data-message-suffix="{{ params.messageSuffix }}"
13
13
  data-keep-alive-button-text="{{ params.keepAliveButtonText }}"
14
- data-sign-out-button-text="{{ params.signOutButtonText }}" />
14
+ data-sign-out-button-text="{{ params.signOutButtonText }}"
15
+ data-synchronise-tabs="{{ params.synchroniseTabs }}"/>
@@ -8,13 +8,14 @@ import ValidateInput from './validate-input';
8
8
  import RedirectHelper from './redirectHelper';
9
9
  import utils from './utils';
10
10
 
11
- // TODO: rewruite this to follow govuk-frontend's protoytpe module pattern
11
+ // TODO: rewrite this to follow govuk-frontend prototype module pattern
12
12
 
13
- function TimeoutDialog($module) {
13
+ function TimeoutDialog($module, $sessionActivityService) {
14
14
  let options = {};
15
15
  let settings = {};
16
16
  const cleanupFunctions = [];
17
17
  let currentTimer;
18
+ const sessionActivityService = $sessionActivityService;
18
19
 
19
20
  cleanupFunctions.push(() => {
20
21
  if (currentTimer) {
@@ -68,6 +69,9 @@ function TimeoutDialog($module) {
68
69
  signOutButtonText: validate.string(
69
70
  lookupData('data-sign-out-button-text'),
70
71
  ),
72
+ synchroniseTabs: validate.boolean(
73
+ lookupData('data-synchronise-tabs') || false,
74
+ ),
71
75
  };
72
76
 
73
77
  // Default timeoutUrl to signOutUrl if not set
@@ -76,8 +80,23 @@ function TimeoutDialog($module) {
76
80
  validateInput(options);
77
81
  settings = mergeOptionsWithDefaults(options, localisedDefaults);
78
82
  setupDialogTimer();
83
+ listenForSessionActivityAndResetDialogTimer();
79
84
  }
80
85
 
86
+ const broadcastSessionActivity = () => {
87
+ sessionActivityService.logActivity();
88
+ };
89
+
90
+ const listenForSessionActivityAndResetDialogTimer = () => {
91
+ if (settings.synchroniseTabs) {
92
+ sessionActivityService.onActivity((event) => {
93
+ const timeOfActivity = event.timestamp;
94
+ cleanup();
95
+ setupDialogTimer(timeOfActivity);
96
+ });
97
+ }
98
+ };
99
+
81
100
  const validateInput = (config) => {
82
101
  const requiredConfig = ['timeout', 'countdown', 'keepAliveUrl', 'signOutUrl'];
83
102
  const missingRequiredConfig = [];
@@ -113,12 +132,14 @@ function TimeoutDialog($module) {
113
132
  return clone;
114
133
  };
115
134
 
116
- const setupDialogTimer = () => {
117
- settings.signout_time = getDateNow() + settings.timeout * 1000;
135
+ const setupDialogTimer = (timeOfLastActivity = getDateNow()) => {
136
+ const signoutTime = timeOfLastActivity + settings.timeout * 1000;
118
137
 
138
+ const delta = getDateNow() - timeOfLastActivity;
139
+ const secondsUntilTimeoutDialog = settings.timeout - settings.countdown;
119
140
  const timeout = window.setTimeout(() => {
120
- setupDialog();
121
- }, (settings.timeout - settings.countdown) * 1000);
141
+ setupDialog(signoutTime);
142
+ }, (secondsUntilTimeoutDialog * 1000) - delta);
122
143
 
123
144
  cleanupFunctions.push(() => {
124
145
  window.clearTimeout(timeout);
@@ -133,7 +154,7 @@ function TimeoutDialog($module) {
133
154
  return $wrapper;
134
155
  };
135
156
 
136
- const setupDialog = () => {
157
+ const setupDialog = (signoutTime) => {
137
158
  const $element = utils.generateDomElementFromString('<div>');
138
159
 
139
160
  if (settings.title) {
@@ -189,14 +210,9 @@ function TimeoutDialog($module) {
189
210
 
190
211
  dialogControl.setAriaLabelledBy('hmrc-timeout-heading hmrc-timeout-message');
191
212
 
192
- startCountdown($countdownElement, $audibleMessage);
193
- };
194
-
195
- const getMillisecondsRemaining = () => settings.signout_time - getDateNow();
213
+ const getMillisecondsRemaining = () => signoutTime - getDateNow();
214
+ const getSecondsRemaining = () => Math.round(getMillisecondsRemaining() / 1000);
196
215
 
197
- const getSecondsRemaining = () => Math.round(getMillisecondsRemaining() / 1000);
198
-
199
- const startCountdown = ($countdownElement, $screenReaderCountdownElement) => {
200
216
  const getHumanText = (counter) => {
201
217
  let minutes; let
202
218
  visibleMessage;
@@ -240,7 +256,7 @@ function TimeoutDialog($module) {
240
256
  const audibleHumanText = getAudibleHumanText(counter);
241
257
 
242
258
  updateTextIfChanged($countdownElement, visibleMessage);
243
- updateTextIfChanged($screenReaderCountdownElement, audibleHumanText);
259
+ updateTextIfChanged($audibleMessage, audibleHumanText);
244
260
  };
245
261
 
246
262
  const getNextTimeout = () => {
@@ -267,8 +283,8 @@ function TimeoutDialog($module) {
267
283
  const keepAliveAndClose = () => {
268
284
  cleanup();
269
285
  setupDialogTimer();
270
- utils.ajaxGet(settings.keepAliveUrl, () => {
271
- });
286
+ utils.ajaxGet(settings.keepAliveUrl, () => {});
287
+ broadcastSessionActivity();
272
288
  };
273
289
 
274
290
  const getDateNow = () => Date.now();
@@ -8,6 +8,8 @@ ValidateInput.int = (stringToValidate) => {
8
8
  return Number.isNaN(parsedInt) ? undefined : parsedInt;
9
9
  };
10
10
 
11
- ValidateInput.string = (stringToValidate) => stringToValidate && ((`${stringToValidate}`) || undefined);
11
+ ValidateInput.string = (stringToValidate) => (typeof stringToValidate === 'string' ? stringToValidate : undefined);
12
+
13
+ ValidateInput.boolean = (stringToValidate) => String(stringToValidate).toLowerCase() === 'true';
12
14
 
13
15
  export default ValidateInput;