@govuk-one-login/frontend-ui 3.1.0 → 4.0.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.
@@ -289,10 +289,23 @@ class Spinner {
289
289
  }
290
290
  }
291
291
 
292
- function initialiseProgressButtons() {
293
- const progressButtons = document.querySelectorAll('[data-frontendui="di-progress-button"]');
294
- progressButtons.forEach((button) => {
295
- button.addEventListener('click', (event) => {
292
+ function initialiseProgressButtons(document = window.document) {
293
+ const progressButtons = Array.prototype.slice.call(document.querySelectorAll('[data-frontendui="di-progress-button"]'));
294
+ function findClosestForm(element) {
295
+ let el = element;
296
+ while (el && el.nodeName !== 'FORM') {
297
+ el = el.parentElement;
298
+ }
299
+ return el;
300
+ }
301
+ progressButtons.forEach(function (button) {
302
+ const form = findClosestForm(button);
303
+ let isSubmitting = false;
304
+ button.addEventListener('click', function (event) {
305
+ if (isSubmitting) {
306
+ event.preventDefault();
307
+ return;
308
+ }
296
309
  const waitingText = button.getAttribute('data-waiting-text');
297
310
  const longWaitingText = button.getAttribute('data-long-waiting-text');
298
311
  const errorPage = button.getAttribute('data-error-page');
@@ -301,14 +314,44 @@ function initialiseProgressButtons() {
301
314
  console.error('Progress button is missing required data attributes.');
302
315
  return;
303
316
  }
317
+ isSubmitting = true;
318
+ // Always handle the button click, regardless of form presence
304
319
  handleProgressButtonClick(button, waitingText, longWaitingText, errorPage, isInput);
320
+ // If no form, we're done. If there is a form, the form submit handler will take over
321
+ if (!form) {
322
+ return;
323
+ }
324
+ // For form buttons, let the click propagate to trigger form submission
305
325
  });
326
+ if (form) {
327
+ form.addEventListener('submit', function (event) {
328
+ // The button click handler has already set isSubmitting and handled the button state
329
+ if (isSubmitting) {
330
+ // Allow the first submission, prevent subsequent ones
331
+ if (event.target === form && event.submitter === button) {
332
+ return; // Allow the first submission to proceed
333
+ }
334
+ event.preventDefault ? event.preventDefault() : (event.returnValue = false);
335
+ return;
336
+ }
337
+ // If the form is submitted through another method (not our button),
338
+ // prevent double submission but don't show progress state
339
+ isSubmitting = true;
340
+ });
341
+ }
306
342
  });
307
343
  }
308
- const handleProgressButtonClick = (element, waitingText, longWaitingText, errorPage, isInput = false) => {
309
- element.blur();
344
+ function handleProgressButtonClick(element, waitingText, longWaitingText, errorPage, isInput) {
345
+ var originalText = isInput && element instanceof HTMLInputElement ? element.value : element.innerText;
346
+ if (typeof element.blur === 'function') {
347
+ element.blur();
348
+ }
310
349
  element.setAttribute('data-prevent-double-click', 'true');
311
- element.classList.add('govuk-button--progress-loading');
350
+ var classes = element.className.split(' ');
351
+ if (classes.indexOf('govuk-button--progress-loading') === -1) {
352
+ classes.push('govuk-button--progress-loading');
353
+ element.className = classes.join(' ');
354
+ }
312
355
  if (isInput && element instanceof HTMLInputElement) {
313
356
  element.value = waitingText;
314
357
  }
@@ -316,7 +359,7 @@ const handleProgressButtonClick = (element, waitingText, longWaitingText, errorP
316
359
  element.innerText = waitingText;
317
360
  }
318
361
  element.setAttribute('aria-label', waitingText);
319
- setTimeout(() => {
362
+ var longWaitTimeout = window.setTimeout(function () {
320
363
  if (isInput && element instanceof HTMLInputElement) {
321
364
  element.value = longWaitingText;
322
365
  }
@@ -325,10 +368,30 @@ const handleProgressButtonClick = (element, waitingText, longWaitingText, errorP
325
368
  }
326
369
  element.setAttribute('aria-label', longWaitingText);
327
370
  }, 5000);
328
- setTimeout(() => {
371
+ var errorTimeout = window.setTimeout(function () {
329
372
  window.location.href = errorPage;
330
373
  }, 10000);
331
- };
374
+ function resetButton() {
375
+ var classes = element.className.split(' ');
376
+ var loadingIndex = classes.indexOf('govuk-button--progress-loading');
377
+ if (loadingIndex !== -1) {
378
+ classes.splice(loadingIndex, 1);
379
+ element.className = classes.join(' ');
380
+ }
381
+ element.setAttribute('data-prevent-double-click', 'false');
382
+ if (isInput && element instanceof HTMLInputElement) {
383
+ element.value = originalText;
384
+ }
385
+ else {
386
+ element.innerText = originalText;
387
+ }
388
+ element.setAttribute('aria-label', originalText);
389
+ window.clearTimeout(errorTimeout);
390
+ window.clearTimeout(longWaitTimeout);
391
+ }
392
+ element.resetProgressButton = resetButton;
393
+ return resetButton;
394
+ }
332
395
 
333
396
  exports.initialiseProgressButtons = initialiseProgressButtons;
334
397
  exports.useSpinner = useSpinner;
@@ -1,2 +1,2 @@
1
- export declare function initialiseProgressButtons(): void;
1
+ export declare function initialiseProgressButtons(document?: Document): void;
2
2
  //# sourceMappingURL=progress-button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress-button.d.ts","sourceRoot":"","sources":["../../../../frontend-src/progress-button/progress-button.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,SAgBxC"}
1
+ {"version":3,"file":"progress-button.d.ts","sourceRoot":"","sources":["../../../../frontend-src/progress-button/progress-button.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,CAAC,QAAQ,GAAE,QAA0B,QAgE7E"}
@@ -100,8 +100,8 @@
100
100
  translations: {
101
101
  footerNavItems: [
102
102
  {
103
- href: "/accessibilitystatement",
104
- text: 'general.base.footer.accessibility' | translate
103
+ href: 'general.base.footer.accessibility.link' | translate | safe,
104
+ text: 'general.base.footer.accessibility.linkText' | translate
105
105
  },
106
106
  {
107
107
  href: 'general.cookieBanner.viewCookiesLink' | translate,
@@ -287,10 +287,23 @@ class Spinner {
287
287
  }
288
288
  }
289
289
 
290
- function initialiseProgressButtons() {
291
- const progressButtons = document.querySelectorAll('[data-frontendui="di-progress-button"]');
292
- progressButtons.forEach((button) => {
293
- button.addEventListener('click', (event) => {
290
+ function initialiseProgressButtons(document = window.document) {
291
+ const progressButtons = Array.prototype.slice.call(document.querySelectorAll('[data-frontendui="di-progress-button"]'));
292
+ function findClosestForm(element) {
293
+ let el = element;
294
+ while (el && el.nodeName !== 'FORM') {
295
+ el = el.parentElement;
296
+ }
297
+ return el;
298
+ }
299
+ progressButtons.forEach(function (button) {
300
+ const form = findClosestForm(button);
301
+ let isSubmitting = false;
302
+ button.addEventListener('click', function (event) {
303
+ if (isSubmitting) {
304
+ event.preventDefault();
305
+ return;
306
+ }
294
307
  const waitingText = button.getAttribute('data-waiting-text');
295
308
  const longWaitingText = button.getAttribute('data-long-waiting-text');
296
309
  const errorPage = button.getAttribute('data-error-page');
@@ -299,14 +312,44 @@ function initialiseProgressButtons() {
299
312
  console.error('Progress button is missing required data attributes.');
300
313
  return;
301
314
  }
315
+ isSubmitting = true;
316
+ // Always handle the button click, regardless of form presence
302
317
  handleProgressButtonClick(button, waitingText, longWaitingText, errorPage, isInput);
318
+ // If no form, we're done. If there is a form, the form submit handler will take over
319
+ if (!form) {
320
+ return;
321
+ }
322
+ // For form buttons, let the click propagate to trigger form submission
303
323
  });
324
+ if (form) {
325
+ form.addEventListener('submit', function (event) {
326
+ // The button click handler has already set isSubmitting and handled the button state
327
+ if (isSubmitting) {
328
+ // Allow the first submission, prevent subsequent ones
329
+ if (event.target === form && event.submitter === button) {
330
+ return; // Allow the first submission to proceed
331
+ }
332
+ event.preventDefault ? event.preventDefault() : (event.returnValue = false);
333
+ return;
334
+ }
335
+ // If the form is submitted through another method (not our button),
336
+ // prevent double submission but don't show progress state
337
+ isSubmitting = true;
338
+ });
339
+ }
304
340
  });
305
341
  }
306
- const handleProgressButtonClick = (element, waitingText, longWaitingText, errorPage, isInput = false) => {
307
- element.blur();
342
+ function handleProgressButtonClick(element, waitingText, longWaitingText, errorPage, isInput) {
343
+ var originalText = isInput && element instanceof HTMLInputElement ? element.value : element.innerText;
344
+ if (typeof element.blur === 'function') {
345
+ element.blur();
346
+ }
308
347
  element.setAttribute('data-prevent-double-click', 'true');
309
- element.classList.add('govuk-button--progress-loading');
348
+ var classes = element.className.split(' ');
349
+ if (classes.indexOf('govuk-button--progress-loading') === -1) {
350
+ classes.push('govuk-button--progress-loading');
351
+ element.className = classes.join(' ');
352
+ }
310
353
  if (isInput && element instanceof HTMLInputElement) {
311
354
  element.value = waitingText;
312
355
  }
@@ -314,7 +357,7 @@ const handleProgressButtonClick = (element, waitingText, longWaitingText, errorP
314
357
  element.innerText = waitingText;
315
358
  }
316
359
  element.setAttribute('aria-label', waitingText);
317
- setTimeout(() => {
360
+ var longWaitTimeout = window.setTimeout(function () {
318
361
  if (isInput && element instanceof HTMLInputElement) {
319
362
  element.value = longWaitingText;
320
363
  }
@@ -323,9 +366,29 @@ const handleProgressButtonClick = (element, waitingText, longWaitingText, errorP
323
366
  }
324
367
  element.setAttribute('aria-label', longWaitingText);
325
368
  }, 5000);
326
- setTimeout(() => {
369
+ var errorTimeout = window.setTimeout(function () {
327
370
  window.location.href = errorPage;
328
371
  }, 10000);
329
- };
372
+ function resetButton() {
373
+ var classes = element.className.split(' ');
374
+ var loadingIndex = classes.indexOf('govuk-button--progress-loading');
375
+ if (loadingIndex !== -1) {
376
+ classes.splice(loadingIndex, 1);
377
+ element.className = classes.join(' ');
378
+ }
379
+ element.setAttribute('data-prevent-double-click', 'false');
380
+ if (isInput && element instanceof HTMLInputElement) {
381
+ element.value = originalText;
382
+ }
383
+ else {
384
+ element.innerText = originalText;
385
+ }
386
+ element.setAttribute('aria-label', originalText);
387
+ window.clearTimeout(errorTimeout);
388
+ window.clearTimeout(longWaitTimeout);
389
+ }
390
+ element.resetProgressButton = resetButton;
391
+ return resetButton;
392
+ }
330
393
 
331
394
  export { PollResult, initialiseProgressButtons, useSpinner };
@@ -1,2 +1,2 @@
1
- export declare function initialiseProgressButtons(): void;
1
+ export declare function initialiseProgressButtons(document?: Document): void;
2
2
  //# sourceMappingURL=progress-button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress-button.d.ts","sourceRoot":"","sources":["../../../../frontend-src/progress-button/progress-button.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,SAgBxC"}
1
+ {"version":3,"file":"progress-button.d.ts","sourceRoot":"","sources":["../../../../frontend-src/progress-button/progress-button.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,CAAC,QAAQ,GAAE,QAA0B,QAgE7E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@govuk-one-login/frontend-ui",
3
- "version": "3.1.0",
3
+ "version": "4.0.0",
4
4
  "description": "",
5
5
  "main": "build/cjs/backend/index.cjs",
6
6
  "module": "build/esm/backend/index.js",