hof 21.0.19-axios-beta → 22.0.0-timeout-warning-beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. package/.nyc_output/39337dba-f075-4b5c-ad46-31665a16d443.json +1 -0
  2. package/.nyc_output/processinfo/39337dba-f075-4b5c-ad46-31665a16d443.json +1 -0
  3. package/.nyc_output/processinfo/index.json +1 -1
  4. package/CHANGELOG.md +16 -0
  5. package/codeReviewChecklist.md +22 -0
  6. package/config/hof-defaults.js +11 -1
  7. package/frontend/govuk-template/build/govuk_template.html +20 -22
  8. package/frontend/govuk-template/govuk_template_generated.html +20 -22
  9. package/frontend/template-mixins/mixins/template-mixins.js +1 -0
  10. package/frontend/template-mixins/partials/forms/checkbox.html +5 -0
  11. package/frontend/template-mixins/partials/forms/input-text-group.html +1 -1
  12. package/frontend/template-mixins/partials/forms/select.html +6 -6
  13. package/frontend/template-mixins/partials/forms/textarea-group.html +4 -4
  14. package/frontend/template-partials/views/partials/gatag.html +0 -1
  15. package/frontend/template-partials/views/partials/head.html +26 -0
  16. package/frontend/template-partials/views/partials/page.html +1 -0
  17. package/frontend/template-partials/views/partials/session-timeout-warning.html +17 -0
  18. package/frontend/themes/gov-uk/client-js/index.js +2 -0
  19. package/frontend/themes/gov-uk/client-js/session-timeout-dialog.js +345 -0
  20. package/frontend/themes/gov-uk/styles/_session-timeout-dialog.scss +209 -0
  21. package/frontend/themes/gov-uk/styles/govuk.scss +1 -0
  22. package/index.js +8 -4
  23. package/lib/ga-tag.js +33 -7
  24. package/middleware/cookies.js +2 -0
  25. package/model/apis/html-to-pdf-converter.js +8 -11
  26. package/model/index.js +31 -47
  27. package/package.json +9 -10
  28. package/pull_request.md +16 -0
  29. package/sandbox/apps/sandbox/index.js +1 -0
  30. package/sandbox/package.json +1 -1
  31. package/sandbox/public/css/app.css +251 -6
  32. package/sandbox/public/js/bundle.js +37331 -26262
  33. package/sandbox/yarn.lock +14 -9
  34. package/.nyc_output/61a079f0-003b-4167-8f31-77e3abe4f072.json +0 -1
  35. package/.nyc_output/processinfo/61a079f0-003b-4167-8f31-77e3abe4f072.json +0 -1
  36. package/model/apis/axios-settings.js +0 -9
@@ -0,0 +1,345 @@
1
+ const $ = require('jquery');
2
+
3
+ // Modal dialog prototype
4
+ window.GOVUK.sessionDialog = {
5
+ el: document.getElementById('js-modal-dialog'),
6
+ $el: $('#js-modal-dialog'),
7
+ $lastFocusedEl: null,
8
+ $closeButton: $('.modal-dialog .js-dialog-close'),
9
+ dialogIsOpenClass: 'dialog-is-open',
10
+ timers: [],
11
+ warningTextPrefix: 'To protect your information, this page will time out in ',
12
+ warningTextSuffix: '.',
13
+ warningText: $('.dialog-text').text(),
14
+ warningTextExtra: '',
15
+
16
+ // Timer specific markup. If these are not present, timeout and redirection are disabled
17
+ $timer: $('#js-modal-dialog .timer'),
18
+ $accessibleTimer: $('#js-modal-dialog .at-timer'),
19
+
20
+ secondsSessionTimeout: parseInt($('#js-modal-dialog').data('session-timeout') || 1800),
21
+ secondsTimeoutWarning: parseInt($('#js-modal-dialog').data('session-timeout-warning') || 300),
22
+ timeoutRedirectUrl: $('#js-modal-dialog').data('url-redirect'),
23
+ timeSessionRefreshed: new Date(),
24
+
25
+ bindUIElements: function () {
26
+ window.GOVUK.sessionDialog.$closeButton.on('click', function (e) {
27
+ e.preventDefault();
28
+ window.GOVUK.sessionDialog.closeDialog();
29
+ })
30
+
31
+ // Close modal when ESC pressed
32
+ $(document).keydown(function (e) {
33
+ if (window.GOVUK.sessionDialog.isDialogOpen() && e.keyCode === 27) {
34
+ window.GOVUK.sessionDialog.closeDialog();
35
+ }
36
+ })
37
+ },
38
+
39
+ isDialogOpen: function () {
40
+ return window.GOVUK.sessionDialog.el['open'];
41
+ },
42
+
43
+ isConfigured: function () {
44
+ return window.GOVUK.sessionDialog.$timer.length > 0 &&
45
+ window.GOVUK.sessionDialog.$accessibleTimer.length > 0 &&
46
+ window.GOVUK.sessionDialog.secondsSessionTimeout &&
47
+ window.GOVUK.sessionDialog.secondsTimeoutWarning &&
48
+ window.GOVUK.sessionDialog.timeoutRedirectUrl;
49
+ },
50
+
51
+ openDialog: function () {
52
+ if (!window.GOVUK.sessionDialog.isDialogOpen()) {
53
+ $('html, body').addClass(window.GOVUK.sessionDialog.dialogIsOpenClass);
54
+ window.GOVUK.sessionDialog.saveLastFocusedEl();
55
+ window.GOVUK.sessionDialog.makePageContentInert();
56
+ window.GOVUK.sessionDialog.el.showModal();
57
+ }
58
+ },
59
+
60
+ closeDialog: function () {
61
+ if (window.GOVUK.sessionDialog.isDialogOpen()) {
62
+ $('html, body').removeClass(window.GOVUK.sessionDialog.dialogIsOpenClass);
63
+ window.GOVUK.sessionDialog.el.close();
64
+ window.GOVUK.sessionDialog.setFocusOnLastFocusedEl();
65
+ window.GOVUK.sessionDialog.removeInertFromPageContent();
66
+ window.GOVUK.sessionDialog.refreshSession();
67
+ }
68
+ },
69
+
70
+ saveLastFocusedEl: function () {
71
+ window.GOVUK.sessionDialog.$lastFocusedEl = document.activeElement;
72
+ if (!window.GOVUK.sessionDialog.$lastFocusedEl || window.GOVUK.sessionDialog.$lastFocusedEl === document.body) {
73
+ window.GOVUK.sessionDialog.$lastFocusedEl = null;
74
+ } else if (document.querySelector) {
75
+ window.GOVUK.sessionDialog.$lastFocusedEl = document.querySelector(':focus');
76
+ }
77
+ },
78
+
79
+ // Set focus back on last focused el when modal closed
80
+ setFocusOnLastFocusedEl: function () {
81
+ if (window.GOVUK.sessionDialog.$lastFocusedEl) {
82
+ window.setTimeout(function () {
83
+ window.GOVUK.sessionDialog.$lastFocusedEl.focus();
84
+ }, 0)
85
+ }
86
+ },
87
+
88
+ // Set page content to inert to indicate to screenreaders it's inactive
89
+ // NB: This will look for #content for toggling inert state
90
+ makePageContentInert: function () {
91
+ if (document.querySelector('#content')) {
92
+ document.querySelector('#content').inert = true;
93
+ document.querySelector('#content').setAttribute('aria-hidden', 'true');
94
+ }
95
+ },
96
+
97
+ // Make page content active when modal is not open
98
+ // NB: This will look for #content for toggling inert state
99
+ removeInertFromPageContent: function () {
100
+ if (document.querySelector('#content')) {
101
+ document.querySelector('#content').inert = false;
102
+ document.querySelector('#content').setAttribute('aria-hidden', 'false');
103
+ }
104
+ },
105
+
106
+ numberToWords: function (n) {
107
+ let string = n.toString()
108
+ let units
109
+ let tens
110
+ let scales
111
+ let start
112
+ let end
113
+ let chunks
114
+ let chunksLen
115
+ let chunk
116
+ let ints
117
+ let i
118
+ let word
119
+ let words = 'and'
120
+
121
+ if (parseInt(string) === 0) {
122
+ return 'zero';
123
+ }
124
+
125
+ /* Array of units as words */
126
+ units = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
127
+
128
+ /* Array of tens as words */
129
+ tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
130
+
131
+ /* Array of scales as words */
132
+ scales = ['', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quatttuor-decillion', 'quindecillion', 'sexdecillion', 'septen-decillion', 'octodecillion', 'novemdecillion', 'vigintillion', 'centillion'];
133
+
134
+ /* Split user arguemnt into 3 digit chunks from right to left */
135
+ start = string.length;
136
+ chunks = [];
137
+ while (start > 0) {
138
+ end = start;
139
+ chunks.push(string.slice((start = Math.max(0, start - 3)), end));
140
+ }
141
+
142
+ /* Check if function has enough scale words to be able to stringify the user argument */
143
+ chunksLen = chunks.length
144
+ if (chunksLen > scales.length) {
145
+ return '';
146
+ }
147
+
148
+ /* Stringify each integer in each chunk */
149
+ words = []
150
+ for (i = 0; i < chunksLen; i++) {
151
+ chunk = parseInt(chunks[i]);
152
+
153
+ if (chunk) {
154
+ /* Split chunk into array of individual integers */
155
+ ints = chunks[i].split('').reverse().map(parseFloat);
156
+
157
+ /* If tens integer is 1, i.e. 10, then add 10 to units integer */
158
+ if (ints[1] === 1) {
159
+ ints[0] += 10;
160
+ }
161
+
162
+ /* Add scale word if chunk is not zero and array item exists */
163
+ if ((word = scales[i])) {
164
+ words.push(word);
165
+ }
166
+
167
+ /* Add unit word if array item exists */
168
+ if ((word = units[ints[0]])) {
169
+ words.push(word);
170
+ }
171
+
172
+ /* Add tens word if array item exists */
173
+ if ((word = tens[ints[1]])) {
174
+ words.push(word);
175
+ }
176
+
177
+ /* Add hundreds word if array item exists */
178
+ if ((word = units[ints[2]])) {
179
+ words.push(word + ' hundred');
180
+ }
181
+ }
182
+ }
183
+ return words.reverse().join(' ');
184
+ },
185
+
186
+ // Attempt to convert numerics into text as OS VoiceOver
187
+ // occasionally stalled when encountering numbers
188
+ timeToWords: function (t, unit) {
189
+ let words;
190
+ if (t > 0) {
191
+ try {
192
+ words = window.GOVUK.sessionDialog.numberToWords(t);
193
+ } catch (e) {
194
+ words = t;
195
+ }
196
+ words = words + ' ' + window.GOVUK.sessionDialog.pluralise(t, unit);
197
+ } else {
198
+ words = '';
199
+ }
200
+ return words;
201
+ },
202
+
203
+ pluralise: function (n, unit) {
204
+ return n == 1 ? unit : unit + 's';
205
+ },
206
+
207
+ numericSpan: function (n, unit) {
208
+ return '<span class="tabular-numbers">' + n + '</span> ' + window.GOVUK.sessionDialog.pluralise(n, unit);
209
+ },
210
+
211
+ countdownText: function (minutes, seconds) {
212
+ const minutesText = window.GOVUK.sessionDialog.numericSpan(minutes, 'minute');
213
+ const secondsText = window.GOVUK.sessionDialog.numericSpan(seconds, 'second');
214
+ return minutes > 0 ? minutesText : secondsText;
215
+ },
216
+
217
+ countdownAtText: function (minutes, seconds) {
218
+ const minutesText = window.GOVUK.sessionDialog.timeToWords(minutes, 'minute');
219
+ const secondsText = window.GOVUK.sessionDialog.timeToWords(seconds, 'second');
220
+ return minutes > 0 ? minutesText : secondsText;
221
+ },
222
+
223
+ startCountdown: function () {
224
+ const $timer = window.GOVUK.sessionDialog.$timer;
225
+ const $accessibleTimer = window.GOVUK.sessionDialog.$accessibleTimer;
226
+ let timerRunOnce = false;
227
+ const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
228
+
229
+ const seconds = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
230
+ const minutes = seconds / 60;
231
+
232
+ $timer.text(minutes + ' minute' + (minutes > 1 ? 's' : ''));
233
+
234
+ (function countdown() {
235
+ const secondsUntilSessionTimeout = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
236
+ const timerExpired = secondsUntilSessionTimeout <= window.GOVUK.sessionDialog.secondsFinalWarning;
237
+
238
+ if (!timerExpired) {
239
+
240
+ const minutesLeft = parseInt(secondsUntilSessionTimeout / 60, 10);
241
+ const secondsLeft = parseInt(secondsUntilSessionTimeout % 60, 10);
242
+
243
+
244
+ const atMinutesText = window.GOVUK.sessionDialog.timeToWords(minutesLeft, 'minute');
245
+ const atSecondsText = window.GOVUK.sessionDialog.timeToWords(secondsLeft, 'second');
246
+
247
+ // Below string will get read out by screen readers every time
248
+ // the timeout refreshes.
249
+ // Add additional information in extraText which will get announced to AT the
250
+ // first time the time out opens
251
+ const countdownText = window.GOVUK.sessionDialog.countdownText(minutesLeft, secondsLeft);
252
+ const text = window.GOVUK.sessionDialog.warningTextPrefix + '<strong>' + countdownText + '</strong>' + window.GOVUK.sessionDialog.warningTextSuffix;
253
+ const countdownAtText = window.GOVUK.sessionDialog.countdownAtText(atMinutesText, atSecondsText);
254
+ const atText = window.GOVUK.sessionDialog.warningTextPrefix + countdownAtText + window.GOVUK.sessionDialog.warningTextSuffix + 'bgbhj ' + window.GOVUK.sessionDialog.warningText;
255
+ const extraText = '\n' + window.GOVUK.sessionDialog.warningTextExtra;
256
+
257
+ $timer.html(text + ' ' + extraText);
258
+
259
+ // Update screen reader friendly content every 20 secs
260
+ if (secondsLeft % 20 === 0) {
261
+
262
+ // Read out the extra content only once.
263
+ // Don't read out on iOS VoiceOver which stalls on the longer text
264
+ if (!timerRunOnce && !iOS) {
265
+ $accessibleTimer.text(atText + extraText);
266
+ timerRunOnce = true;
267
+ } else {
268
+ $accessibleTimer.text(atText);
269
+ }
270
+ }
271
+
272
+ window.GOVUK.sessionDialog.addTimer(countdown,20);
273
+ }
274
+ })()
275
+ },
276
+
277
+ // Clears all timers
278
+ clearTimers: function () {
279
+ for (let i = 0; i < window.GOVUK.sessionDialog.timers.length; i++) {
280
+ clearInterval(window.GOVUK.sessionDialog.timers[i]);
281
+ }
282
+ },
283
+
284
+ refreshSession: function () {
285
+ $.get("");
286
+ window.GOVUK.sessionDialog.timeSessionRefreshed = new Date();
287
+ window.GOVUK.sessionDialog.controller();
288
+ },
289
+
290
+ redirect: function () {
291
+ window.location = window.GOVUK.sessionDialog.timeoutRedirectUrl;
292
+ },
293
+
294
+ // JS doesn't allow resetting timers globally so timers need
295
+ // to be retained for resetting.
296
+ addTimer: function (f, seconds) {
297
+ window.GOVUK.sessionDialog.timers.push(setInterval(f, seconds * 1000));
298
+ },
299
+
300
+ secondsSinceRefresh: function () {
301
+ return Math.round(Math.abs((window.GOVUK.sessionDialog.timeSessionRefreshed - new Date()) / 1000));
302
+ },
303
+
304
+ secondsUntilSessionTimeout: function () {
305
+ return window.GOVUK.sessionDialog.secondsSessionTimeout - window.GOVUK.sessionDialog.secondsSinceRefresh();
306
+ },
307
+
308
+ secondsUntilTimeoutWarning: function () {
309
+ return window.GOVUK.sessionDialog.secondsUntilSessionTimeout() - window.GOVUK.sessionDialog.secondsTimeoutWarning;
310
+ },
311
+
312
+ // countdown controller logic
313
+ controller: function () {
314
+ window.GOVUK.sessionDialog.clearTimers();
315
+
316
+ const secondsUntilSessionTimeout = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
317
+
318
+ //timed out - redirect
319
+ if (secondsUntilSessionTimeout <= 0) {
320
+ window.GOVUK.sessionDialog.redirect();
321
+ }
322
+
323
+ //timeout warning - show countdown and schedule redirect
324
+ else if (secondsUntilSessionTimeout <= window.GOVUK.sessionDialog.secondsTimeoutWarning) {
325
+ window.GOVUK.sessionDialog.openDialog();
326
+ window.GOVUK.sessionDialog.startCountdown();
327
+ window.GOVUK.sessionDialog.addTimer(window.GOVUK.sessionDialog.controller,window.GOVUK.sessionDialog.secondsUntilSessionTimeout());
328
+ }
329
+
330
+ //wait for warning
331
+ else {
332
+ window.GOVUK.sessionDialog.addTimer(window.GOVUK.sessionDialog.controller, window.GOVUK.sessionDialog.secondsUntilTimeoutWarning());
333
+ }
334
+ },
335
+
336
+ init: function (options) {
337
+ $.extend(window.GOVUK.sessionDialog, options);
338
+ if (window.GOVUK.sessionDialog.el && window.GOVUK.sessionDialog.isConfigured()) {
339
+ window.GOVUK.sessionDialog.bindUIElements();
340
+ window.GOVUK.sessionDialog.controller();
341
+ }
342
+ }
343
+ }
344
+
345
+ window.GOVUK = GOVUK;
@@ -0,0 +1,209 @@
1
+ .modal-dialog {
2
+ display: none;
3
+ }
4
+
5
+ .modal-dialog--no-js-persistent {
6
+ display: inline-block;
7
+ }
8
+
9
+ .js-enabled {
10
+ .modal-dialog--no-js-persistent {
11
+ display: none;
12
+
13
+ &[open], .dialog-button {
14
+ display: inline-block;
15
+ }
16
+ }
17
+
18
+ .modal-dialog[open] {
19
+ display: inline-block;
20
+ }
21
+ }
22
+
23
+ .modal-dialog[open] {
24
+ overflow-x: hidden;
25
+ overflow-y: auto;
26
+ max-height: 90vh;
27
+ padding: 0;
28
+ margin-bottom: 0;
29
+ margin-top: 0;
30
+ position: fixed;
31
+ top: 50% !important;
32
+ -webkit-transform: translate(0, -50%);
33
+ -ms-transform: translate(0, -50%);
34
+ transform: translate(0, -50%);
35
+ }
36
+
37
+ @media (min-width: 641px) {
38
+ .modal-dialog[open] {
39
+ padding: 0;
40
+ }
41
+ }
42
+
43
+ .modal-dialog__inner {
44
+ padding: 20px;
45
+ }
46
+
47
+ @media (min-width: 641px) {
48
+ .modal-dialog__inner {
49
+ padding: 30px;
50
+ }
51
+ }
52
+
53
+ .modal-dialog__inner__text {
54
+ font-family: "nta", Arial, sans-serif;
55
+ font-weight: 400;
56
+ text-transform: none;
57
+ font-size: 16px;
58
+ line-height: 1.25;
59
+ padding-top: 2px;
60
+ padding-bottom: 8px;
61
+ margin-bottom: 20px;
62
+ }
63
+
64
+ @media (min-width: 641px) {
65
+ .modal-dialog__inner__text {
66
+ font-size: 19px;
67
+ line-height: 1.31579;
68
+ }
69
+ }
70
+
71
+ @media (min-width: 641px) {
72
+ .modal-dialog__inner__text {
73
+ padding-top: 0;
74
+ padding-bottom: 5px;
75
+ }
76
+ }
77
+
78
+ .modal-dialog__inner__button {
79
+ font-size: 19px;
80
+ margin-top: 10px;
81
+ }
82
+
83
+ .modal-dialog__inner__link {
84
+ font-family: "nta", Arial, sans-serif;
85
+ font-weight: 400;
86
+ text-transform: none;
87
+ font-size: 16px;
88
+ line-height: 1.25;
89
+ padding-top: 2px;
90
+ padding-bottom: 8px;
91
+ background: none;
92
+ border: none;
93
+ vertical-align: middle;
94
+ margin-top: 20px;
95
+
96
+ &:hover {
97
+ cursor: pointer;
98
+ }
99
+ }
100
+
101
+ @media (min-width: 641px) {
102
+ .modal-dialog__inner__link {
103
+ font-size: 19px;
104
+ line-height: 1.31579;
105
+ }
106
+ }
107
+
108
+ @media (min-width: 641px) {
109
+ .modal-dialog__inner__link {
110
+ padding-top: 0;
111
+ padding-bottom: 5px;
112
+ }
113
+ }
114
+
115
+ @media (max-width: 640px) {
116
+ .modal-dialog__inner__link {
117
+ text-align: center;
118
+ display: block;
119
+ margin-top: 25px;
120
+ }
121
+ }
122
+
123
+ @media (min-width: 641px) {
124
+ .modal-dialog__inner__link {
125
+ position: absolute;
126
+ top: 50%;
127
+ transform: translateY(-50%);
128
+ padding: 0;
129
+ margin: 0 0 0 30px;
130
+ }
131
+ }
132
+
133
+ .modal-dialog__inner__block {
134
+ position: relative;
135
+ }
136
+
137
+ .modal-dialog #dialog-title {
138
+ margin-top: 0;
139
+ }
140
+
141
+ .dialog-is-open {
142
+ overflow: hidden;
143
+ }
144
+
145
+ dialog {
146
+ left: 0;
147
+ right: 0;
148
+ width: -moz-fit-content;
149
+ width: -webkit-fit-content;
150
+ width: fit-content;
151
+ height: -moz-fit-content;
152
+ height: -webkit-fit-content;
153
+ height: fit-content;
154
+ margin: auto;
155
+ border: solid;
156
+ padding: 1em;
157
+ background: white;
158
+ color: black;
159
+ display: none;
160
+ border: 5px solid black;
161
+
162
+ + .backdrop {
163
+ position: fixed;
164
+ top: 0;
165
+ right: 0;
166
+ bottom: 0;
167
+ left: 0;
168
+ background: rgba(0, 0, 0, 0.8);
169
+ }
170
+
171
+ &[open] {
172
+ display: block;
173
+ box-sizing: border-box;
174
+ margin: 0 auto;
175
+ padding: 15px;
176
+ width: 90%;
177
+
178
+ + .backdrop, &::backdrop {
179
+ background: rgba(0, 0, 0, 0.8);
180
+ }
181
+ }
182
+ }
183
+
184
+ @media (min-width: 641px) {
185
+ dialog[open] {
186
+ padding: 30px;
187
+ margin: 30px auto;
188
+ max-width: 500px;
189
+ }
190
+ }
191
+
192
+ .tabular-numbers {
193
+ font-family: "ntatabularnumbers", "nta", Arial, sans-serif;
194
+ }
195
+
196
+ .dialog-sign-out-link {
197
+ @include govuk-font($size: 24);
198
+ display: inline-block;
199
+ margin: 5px;
200
+
201
+ @include govuk-media-query($from: tablet) {
202
+ @include govuk-font($size: 19);
203
+
204
+ position: relative;
205
+ top: 2px;
206
+ padding: 0.526315em 0.789473em 0.263157em;
207
+ line-height: 1.5;
208
+ }
209
+ }
@@ -26,6 +26,7 @@ $path: "/public/images/" !default;
26
26
  @import "cookie-settings";
27
27
  @import "check_your_answers";
28
28
  @import "pdf";
29
+ @import "session-timeout-dialog";
29
30
 
30
31
  // Modules
31
32
  @import "modules/validation";
package/index.js CHANGED
@@ -84,6 +84,7 @@ const getContentSecurityPolicy = (config, res) => {
84
84
  'www.google.co.uk/ads/ga-audiences'
85
85
  ],
86
86
  connectSrc: [
87
+ "'self'",
87
88
  'https://www.google-analytics.com',
88
89
  'https://region1.google-analytics.com',
89
90
  'https://region1.analytics.google.com'
@@ -147,6 +148,9 @@ function bootstrap(options) {
147
148
  res.locals.appName = config.appName;
148
149
  res.locals.htmlLang = config.htmlLang;
149
150
  res.locals.cookieName = config.session.name;
151
+ // session timeout warning configs
152
+ res.locals.sessionTimeOut = config.session.ttl;
153
+ res.locals.sessionTimeOutWarning = config.sessionTimeOutWarning;
150
154
  next();
151
155
  });
152
156
 
@@ -189,10 +193,10 @@ function bootstrap(options) {
189
193
  app.use(morgan('sessionId=:id ' + morgan.combined, {
190
194
  stream: config.logger.stream,
191
195
  skip: (req, res) => config.loglevel !== 'debug' &&
192
- (
193
- res.statusCode >= 300 || !_.get(req, 'session.id') ||
194
- config.ignoreMiddlewareLogs.some(v => req.originalUrl.includes(v))
195
- )
196
+ (
197
+ res.statusCode >= 300 || !_.get(req, 'session.id') ||
198
+ config.ignoreMiddlewareLogs.some(v => req.originalUrl.includes(v))
199
+ )
196
200
  }));
197
201
 
198
202
  serveStatic(app, config);
package/lib/ga-tag.js CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  const _ = require('lodash');
4
4
 
5
+ const convertToGTMPage = text => {
6
+ // Remove leading and trailing slashes
7
+ let str = text.replace(/^\/|\/$/g, '');
8
+ // Replace hyphens with spaces and capitalize each word
9
+ str = str.replace(/-+/g, ' ').replace(/(^|\s)\S/g, function (match) {
10
+ return match.toUpperCase();
11
+ });
12
+ return str;
13
+ };
14
+
5
15
  const pageView = (path, pageMap) => pageMap.get(path) || path;
6
16
 
7
17
  const createUris = routes => {
@@ -42,19 +52,35 @@ const setupPageMap = routes => {
42
52
  module.exports = (app, config) => {
43
53
  const gaTagId = config.gaTagId;
44
54
  const ga4TagId = config.ga4TagId;
55
+ const gtm = config.gtm;
45
56
  const gaCrossDomainTrackingTagId = config.gaCrossDomainTrackingTagId;
46
57
  const routes = config.routes;
47
58
 
48
- if (gaTagId || ga4TagId) {
59
+ if (gaTagId || ga4TagId || gtm.tagId) {
49
60
  const pageMap = setupPageMap(routes);
50
61
 
51
62
  app.use((req, res, next) => {
52
- res.locals.gaAllowDebug = config.env === 'development';
53
- res.locals.gaTagId = gaTagId;
54
- res.locals.ga4TagId = ga4TagId;
55
- res.locals.gaCrossDomainTrackingTagId = gaCrossDomainTrackingTagId;
56
- res.locals['ga-id'] = gaTagId;
57
- res.locals['ga-page'] = pageView(req.path, pageMap);
63
+ const page = pageView(req.path, pageMap);
64
+
65
+ // Preparing common res.locals properties
66
+ const properties = {
67
+ gaAllowDebug: config.env === 'development',
68
+ gaTagId: gaTagId,
69
+ ga4TagId: ga4TagId,
70
+ gaCrossDomainTrackingTagId: gaCrossDomainTrackingTagId,
71
+ 'ga-id': gaTagId,
72
+ 'ga-page': page
73
+ };
74
+
75
+ // Adding extra properties if a GTM TAG is available
76
+ if (gtm.tagId) {
77
+ gtm.config.pageName = gtm.composePageName(page, convertToGTMPage);
78
+ Object.assign(properties, {
79
+ gtmConfig: JSON.stringify(gtm.config),
80
+ gtmTagId: gtm.tagId
81
+ });
82
+ }
83
+ res.locals = Object.assign(res.locals, properties);
58
84
  next();
59
85
  });
60
86
  }
@@ -22,6 +22,8 @@ module.exports = options => {
22
22
  const reqIsCookieCheckRedirect = req.query[paramName] !== undefined;
23
23
 
24
24
  if (reqIncludesCookies || isHealthcheckUrl(req.path, healthcheckUrls)) {
25
+ const prefs = 'cookie_preferences' in req.cookies ? JSON.parse(req.cookies.cookie_preferences) : {};
26
+ res.locals.cookiesAccepted = Boolean(prefs.usage);
25
27
  next();
26
28
  } else if (req.cookies === undefined || (!Object.keys(req.cookies).length && reqIsCookieCheckRedirect)) {
27
29
  const err = new Error('Cookies required');
@@ -9,8 +9,6 @@ module.exports = class PDFModel extends Model {
9
9
  const settings = super.requestConfig(options);
10
10
  settings.encoding = null;
11
11
  settings.rejectUnauthorized = false;
12
- settings.responseType = 'arraybuffer';
13
- console.log("settings------+_+_+_+_---------: ", settings);
14
12
  return settings;
15
13
  }
16
14
 
@@ -19,18 +17,17 @@ module.exports = class PDFModel extends Model {
19
17
  }
20
18
 
21
19
  handleResponse(response, callback) {
22
- if (isPdf(Buffer.from(response.data))) {
23
- return this.parseResponse(response.status, response.data, callback);
20
+ if (isPdf(Buffer.from(response.body))) {
21
+ return this.parseResponse(response.statusCode, response.body, callback);
24
22
  }
25
23
  const err = new Error();
26
-
27
- if (parseInt(response.status, 10) === 400) {
28
- err.title = response.status;
29
- err.message = response.statusText;
24
+ if (parseInt(response.statusCode, 10) === 400) {
25
+ err.title = response.body.code;
26
+ err.message = response.body.message;
30
27
  } else {
31
- err.body = response.data;
28
+ err.body = response.body;
32
29
  }
33
- err.status = response.status;
34
- return callback(err, null, response.status);
30
+ err.status = response.statusCode;
31
+ return callback(err, null, response.statusCode);
35
32
  }
36
33
  };