@ons/design-system 44.0.2 → 45.0.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/components/access-code/uac.scss +5 -5
- package/components/address-input/_macro.njk +1 -0
- package/components/address-input/autosuggest.address.js +0 -1
- package/components/autosuggest/_macro.njk +1 -0
- package/components/autosuggest/autosuggest.ui.js +3 -3
- package/components/autosuggest/{code.list.searcher.js → fuse-config.js} +1 -3
- package/components/checkboxes/_checkbox-macro.njk +1 -1
- package/components/checkboxes/_macro.njk +1 -1
- package/components/fieldset/_macro.njk +1 -1
- package/components/header/_header.scss +3 -4
- package/components/header/_macro.njk +2 -2
- package/components/highlight/_highlight.scss +5 -0
- package/components/input/_input.scss +2 -2
- package/components/metadata/_macro.njk +1 -1
- package/components/metadata/_metadata.scss +1 -1
- package/components/modal/_macro.njk +23 -0
- package/components/modal/_modal.scss +32 -0
- package/components/modal/modal.dom.js +14 -0
- package/components/modal/modal.js +104 -0
- package/components/radios/_macro.njk +2 -2
- package/components/table-of-contents/_macro.njk +7 -7
- package/components/textarea/_macro.njk +2 -2
- package/components/timeout-modal/_macro.njk +26 -0
- package/components/timeout-modal/timeout.dom.js +16 -0
- package/components/timeout-modal/timeout.js +289 -0
- package/css/census.css +1 -1
- package/css/main.css +1 -1
- package/favicons/census/cy/android-chrome-192x192.png +0 -0
- package/favicons/census/cy/android-chrome-512x512.png +0 -0
- package/favicons/census/cy/apple-touch-icon.png +0 -0
- package/favicons/census/cy/browserconfig.xml +12 -0
- package/favicons/census/cy/favicon-16x16.png +0 -0
- package/favicons/census/cy/favicon-32x32.png +0 -0
- package/favicons/census/cy/favicon.ico +0 -0
- package/favicons/census/cy/manifest.json +20 -0
- package/favicons/census/cy/mstitle-150x150.png +0 -0
- package/favicons/census/cy/mstitle-310x150.png +0 -0
- package/favicons/census/cy/mstitle-310x310.png +0 -0
- package/favicons/census/cy/mstitle-70x70.png +0 -0
- package/favicons/census/cy/opengraph.png +0 -0
- package/favicons/census/cy/safari-pinned-tab.svg +3 -0
- package/favicons/census/cy/site.webmanifest +19 -0
- package/favicons/census/cy/twitter.png +0 -0
- package/favicons/census/en/android-chrome-192x192.png +0 -0
- package/favicons/census/en/android-chrome-512x512.png +0 -0
- package/favicons/census/en/apple-touch-icon.png +0 -0
- package/favicons/census/en/browserconfig.xml +12 -0
- package/favicons/census/en/favicon-16x16.png +0 -0
- package/favicons/census/en/favicon-32x32.png +0 -0
- package/favicons/census/en/favicon.ico +0 -0
- package/favicons/census/en/manifest.json +20 -0
- package/favicons/census/en/mstitle-150x150.png +0 -0
- package/favicons/census/en/mstitle-310x150.png +0 -0
- package/favicons/census/en/mstitle-310x310.png +0 -0
- package/favicons/census/en/mstitle-70x70.png +0 -0
- package/favicons/census/en/opengraph.png +0 -0
- package/favicons/census/en/safari-pinned-tab.svg +3 -0
- package/favicons/census/en/site.webmanifest +19 -0
- package/favicons/census/en/twitter.png +0 -0
- package/favicons/census/ni/favicon.ico +0 -0
- package/js/abortable-fetch.js +55 -0
- package/js/analytics.js +70 -0
- package/js/cookies-functions.js +182 -0
- package/js/cookies-settings.dom.js +13 -0
- package/js/cookies-settings.js +105 -0
- package/js/domready.js +17 -0
- package/js/fetch.js +19 -0
- package/js/inpagelink.dom.js +13 -0
- package/js/inpagelink.js +31 -0
- package/js/main.js +27 -0
- package/js/polyfills.js +9 -0
- package/js/print-button.js +16 -0
- package/{page-templates → layout}/_template.njk +0 -0
- package/package.json +4 -4
- package/scripts/main.es5.js +2 -2
- package/scripts/main.js +1 -1
- package/scss/main.scss +2 -5
- package/scss/patternlib.scss +3 -0
- package/scss/vars/_vars.scss +1 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import Modal from '../modal/modal';
|
|
2
|
+
|
|
3
|
+
export default class Timeout {
|
|
4
|
+
constructor(context, url, time) {
|
|
5
|
+
this.context = context;
|
|
6
|
+
this.sessionExpiryEndpoint = url;
|
|
7
|
+
this.initialExpiryTime = time;
|
|
8
|
+
this.continueButton = context.querySelector('.ons-js-modal-btn');
|
|
9
|
+
this.countdown = context.querySelector('.ons-js-timeout-timer');
|
|
10
|
+
this.accessibleCountdown = context.querySelector('.ons-js-timeout-timer-acc');
|
|
11
|
+
this.timeOutRedirectUrl = context.getAttribute('data-redirect-url');
|
|
12
|
+
this.modalVisibleInMilliseconds = context.getAttribute('data-show-modal-time') * 1000;
|
|
13
|
+
|
|
14
|
+
// Language dependent text strings
|
|
15
|
+
this.minutesTextSingular = context.getAttribute('data-minutes-text-singular');
|
|
16
|
+
this.minutesTextPlural = context.getAttribute('data-minutes-text-plural');
|
|
17
|
+
this.secondsTextSingular = context.getAttribute('data-seconds-text-singular');
|
|
18
|
+
this.secondsTextPlural = context.getAttribute('data-seconds-text-plural');
|
|
19
|
+
this.countdownText = context.getAttribute('data-countdown-text');
|
|
20
|
+
this.redirectingText = context.getAttribute('data-redirecting-text');
|
|
21
|
+
|
|
22
|
+
// Settings
|
|
23
|
+
this.expiryTimeInMilliseconds = 0;
|
|
24
|
+
this.expiryTime = '';
|
|
25
|
+
this.showModalTimeout = null;
|
|
26
|
+
this.timers = [];
|
|
27
|
+
this.timerRunOnce = false;
|
|
28
|
+
|
|
29
|
+
// Create modal instance
|
|
30
|
+
this.modal = new Modal(this.context);
|
|
31
|
+
|
|
32
|
+
// Start module
|
|
33
|
+
this.initialise();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async initialise() {
|
|
37
|
+
this.expiryTime = await this.setNewExpiryTime();
|
|
38
|
+
this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(this.expiryTime);
|
|
39
|
+
|
|
40
|
+
this.bindEventListeners();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
bindEventListeners() {
|
|
44
|
+
window.onload = this.startTimeout();
|
|
45
|
+
window.addEventListener('focus', this.handleWindowFocus.bind(this));
|
|
46
|
+
window.addEventListener('keydown', this.escToClose.bind(this));
|
|
47
|
+
this.continueButton.addEventListener('click', this.closeModalAndRestartTimeout.bind(this));
|
|
48
|
+
this.addThrottledEvents();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
startTimeout() {
|
|
52
|
+
clearTimeout(this.showModalTimeout);
|
|
53
|
+
this.showModalTimeout = setTimeout(this.openModal.bind(this), this.expiryTimeInMilliseconds - this.modalVisibleInMilliseconds);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async openModal() {
|
|
57
|
+
const modalWillOpen = await this.hasExpiryTimeResetInAnotherTab();
|
|
58
|
+
if (modalWillOpen && !this.modal.isDialogOpen()) {
|
|
59
|
+
this.modal.openDialog();
|
|
60
|
+
this.startUiCountdown();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async startUiCountdown() {
|
|
65
|
+
this.clearTimers();
|
|
66
|
+
clearInterval(this.shouldModalCloseCheck);
|
|
67
|
+
|
|
68
|
+
this.shouldModalCloseCheck = setInterval(async () => {
|
|
69
|
+
await this.hasExpiryTimeResetInAnotherTab();
|
|
70
|
+
}, 20000);
|
|
71
|
+
|
|
72
|
+
let millseconds = this.modalVisibleInMilliseconds;
|
|
73
|
+
let seconds = millseconds / 1000;
|
|
74
|
+
let timers = this.timers;
|
|
75
|
+
let $this = this;
|
|
76
|
+
|
|
77
|
+
(async function runTimer() {
|
|
78
|
+
const minutesLeft = parseInt(seconds / 60, 10);
|
|
79
|
+
const secondsLeft = parseInt(seconds % 60, 10);
|
|
80
|
+
const timerExpired = minutesLeft < 1 && secondsLeft < 1;
|
|
81
|
+
|
|
82
|
+
const minutesText =
|
|
83
|
+
minutesLeft + ' ' + (minutesLeft >= 2 ? $this.minutesTextPlural : minutesLeft === 1 ? $this.minutesTextSingular : '');
|
|
84
|
+
const secondsText =
|
|
85
|
+
secondsLeft + ' ' + (secondsLeft >= 2 ? $this.secondsTextPlural : secondsLeft === 1 ? $this.secondsTextSingular : '');
|
|
86
|
+
|
|
87
|
+
let timeLeftText =
|
|
88
|
+
$this.countdownText +
|
|
89
|
+
' <span class="ons-u-fw-b">' +
|
|
90
|
+
(minutesLeft > 0 ? minutesText : '') +
|
|
91
|
+
(minutesLeft > 0 && secondsLeft > 0 ? ' ' : '') +
|
|
92
|
+
(secondsLeft > 0 ? secondsText : '') +
|
|
93
|
+
'</span>.';
|
|
94
|
+
|
|
95
|
+
if (timerExpired) {
|
|
96
|
+
const shouldExpire = await $this.hasExpiryTimeResetInAnotherTab();
|
|
97
|
+
|
|
98
|
+
if (shouldExpire) {
|
|
99
|
+
$this.countdown.innerHTML = '<span class="ons-u-fw-b">' + $this.redirectingText + '</span>';
|
|
100
|
+
$this.accessibleCountdown.innerHTML = $this.redirectingText;
|
|
101
|
+
setTimeout($this.redirect.bind($this), 2000);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
seconds--;
|
|
105
|
+
$this.expiryTimeInMilliseconds = seconds * 1000;
|
|
106
|
+
$this.countdown.innerHTML = timeLeftText;
|
|
107
|
+
|
|
108
|
+
if (minutesLeft < 1 && secondsLeft < 20) {
|
|
109
|
+
$this.accessibleCountdown.setAttribute('aria-live', 'assertive');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!$this.timerRunOnce) {
|
|
113
|
+
$this.accessibleCountdown.innerHTML = timeLeftText;
|
|
114
|
+
$this.timerRunOnce = true;
|
|
115
|
+
} else if (secondsLeft % 15 === 0) {
|
|
116
|
+
$this.accessibleCountdown.innerHTML = timeLeftText;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
timers.push(setTimeout(runTimer.bind($this), 1000));
|
|
120
|
+
}
|
|
121
|
+
})();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async hasExpiryTimeResetInAnotherTab() {
|
|
125
|
+
const checkExpiryTime = await this.getExpiryTime();
|
|
126
|
+
|
|
127
|
+
if (checkExpiryTime != this.expiryTime) {
|
|
128
|
+
this.expiryTime = checkExpiryTime;
|
|
129
|
+
this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(checkExpiryTime);
|
|
130
|
+
this.closeModalAndRestartTimeout(this.expiryTimeInMilliseconds);
|
|
131
|
+
} else {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
closeModalAndRestartTimeout(timeInMilliSeconds) {
|
|
137
|
+
if (typeof timeInMilliSeconds !== 'string') {
|
|
138
|
+
timeInMilliSeconds = false;
|
|
139
|
+
}
|
|
140
|
+
if (this.modal.isDialogOpen()) {
|
|
141
|
+
this.modal.closeDialog();
|
|
142
|
+
}
|
|
143
|
+
this.restartTimeout(timeInMilliSeconds);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async restartTimeout(timeInMilliSeconds) {
|
|
147
|
+
this.clearTimers();
|
|
148
|
+
clearInterval(this.shouldModalCloseCheck);
|
|
149
|
+
|
|
150
|
+
if (timeInMilliSeconds) {
|
|
151
|
+
this.expiryTimeInMilliseconds = timeInMilliSeconds;
|
|
152
|
+
} else {
|
|
153
|
+
const createNewExpiryTime = await this.setNewExpiryTime();
|
|
154
|
+
this.expiryTime = createNewExpiryTime;
|
|
155
|
+
this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(createNewExpiryTime);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.startTimeout();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async handleWindowFocus() {
|
|
162
|
+
if (this.sessionExpiryEndpoint) {
|
|
163
|
+
const canSetNewExpiry = await this.setNewExpiryTime();
|
|
164
|
+
if (!canSetNewExpiry) {
|
|
165
|
+
this.redirect();
|
|
166
|
+
} else {
|
|
167
|
+
this.closeModalAndRestartTimeout();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
escToClose(event) {
|
|
173
|
+
if (this.modal.isDialogOpen() && event.keyCode === 27) {
|
|
174
|
+
this.closeModalAndRestartTimeout();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async setNewExpiryTime() {
|
|
179
|
+
let newExpiryTime;
|
|
180
|
+
if (!this.sessionExpiryEndpoint) {
|
|
181
|
+
// For demo purposes
|
|
182
|
+
const demoTime = new Date(this.initialExpiryTime ? this.initialExpiryTime : Date.now() + 60 * 1000);
|
|
183
|
+
newExpiryTime = new Date(demoTime).toISOString();
|
|
184
|
+
} else {
|
|
185
|
+
newExpiryTime = await this.fetchExpiryTime('PATCH');
|
|
186
|
+
}
|
|
187
|
+
return newExpiryTime;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async getExpiryTime() {
|
|
191
|
+
if (this.sessionExpiryEndpoint) {
|
|
192
|
+
const currentExpiryTime = await this.fetchExpiryTime('GET');
|
|
193
|
+
return currentExpiryTime;
|
|
194
|
+
} else {
|
|
195
|
+
// For demo purposes
|
|
196
|
+
return this.expiryTime;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async fetchExpiryTime(fetchMethod) {
|
|
201
|
+
let response = await fetch(this.sessionExpiryEndpoint, {
|
|
202
|
+
method: fetchMethod,
|
|
203
|
+
headers: { 'Cache-Control': 'no-cache', 'Content-type': 'application/json; charset=UTF-8' },
|
|
204
|
+
});
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
this.redirect();
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let json = await response.json();
|
|
211
|
+
|
|
212
|
+
return json.expires_at;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
convertTimeToMilliSeconds(expiryTime) {
|
|
216
|
+
const time = new Date(expiryTime);
|
|
217
|
+
const calculateTimeInMilliSeconds = Math.abs(time - new Date());
|
|
218
|
+
|
|
219
|
+
return calculateTimeInMilliSeconds;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
redirect() {
|
|
223
|
+
window.location.replace(this.timeOutRedirectUrl);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
clearTimers() {
|
|
227
|
+
for (let i = 0; i < this.timers.length; i++) {
|
|
228
|
+
clearTimeout(this.timers[i]);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
addThrottledEvents() {
|
|
233
|
+
window.onclick = this.throttle(() => {
|
|
234
|
+
/* istanbul ignore next */
|
|
235
|
+
if (!this.modal.isDialogOpen()) {
|
|
236
|
+
this.restartTimeout();
|
|
237
|
+
}
|
|
238
|
+
}, 61000);
|
|
239
|
+
|
|
240
|
+
window.onmousemove = this.throttle(() => {
|
|
241
|
+
/* istanbul ignore next */
|
|
242
|
+
if (!this.modal.isDialogOpen()) {
|
|
243
|
+
this.restartTimeout();
|
|
244
|
+
}
|
|
245
|
+
}, 61000);
|
|
246
|
+
|
|
247
|
+
window.onmousedown = this.throttle(() => {
|
|
248
|
+
/* istanbul ignore next */
|
|
249
|
+
if (!this.modal.isDialogOpen()) {
|
|
250
|
+
this.restartTimeout();
|
|
251
|
+
}
|
|
252
|
+
}, 61000);
|
|
253
|
+
|
|
254
|
+
window.onscroll = this.throttle(() => {
|
|
255
|
+
/* istanbul ignore next */
|
|
256
|
+
if (!this.modal.isDialogOpen()) {
|
|
257
|
+
this.restartTimeout();
|
|
258
|
+
}
|
|
259
|
+
}, 61000);
|
|
260
|
+
|
|
261
|
+
window.onkeypress = this.throttle(() => {
|
|
262
|
+
/* istanbul ignore next */
|
|
263
|
+
if (!this.modal.isDialogOpen()) {
|
|
264
|
+
this.restartTimeout();
|
|
265
|
+
}
|
|
266
|
+
}, 61000);
|
|
267
|
+
|
|
268
|
+
window.onkeyup = this.throttle(() => {
|
|
269
|
+
/* istanbul ignore next */
|
|
270
|
+
if (!this.modal.isDialogOpen()) {
|
|
271
|
+
this.restartTimeout();
|
|
272
|
+
}
|
|
273
|
+
}, 61000);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
throttle(func, wait) {
|
|
277
|
+
let waiting = false;
|
|
278
|
+
return function() {
|
|
279
|
+
if (waiting) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
waiting = true;
|
|
283
|
+
setTimeout(async () => {
|
|
284
|
+
func.apply(this, arguments);
|
|
285
|
+
waiting = false;
|
|
286
|
+
}, wait);
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|