Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assert Exit this page HTMLAnchorElement button and clearly guard all dynamic fields #4321

Merged
merged 4 commits into from
Oct 17, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ export class ExitThisPage extends GOVUKFrontendComponent {
}

const $button = $module.querySelector('.govuk-exit-this-page__button')
if (!($button instanceof HTMLElement)) {
if (!($button instanceof HTMLAnchorElement)) {
throw new ElementError($button, {
componentName: 'Exit this page',
identifier: 'Button',
expectedType: HTMLElement
expectedType: HTMLAnchorElement
})
}

Expand Down Expand Up @@ -191,6 +191,10 @@ export class ExitThisPage extends GOVUKFrontendComponent {
* @private
*/
updateIndicator() {
if (!this.$indicatorContainer) {
return
}

// Show or hide the indicator container depending on keypressCounter value
this.$indicatorContainer.classList.toggle(
'govuk-exit-this-page__indicator--visible',
Expand Down Expand Up @@ -218,6 +222,10 @@ export class ExitThisPage extends GOVUKFrontendComponent {
* @private
*/
exitPage() {
if (!this.$updateSpan) {
return
}

this.$updateSpan.textContent = ''

// Blank the page
Expand All @@ -235,7 +243,7 @@ export class ExitThisPage extends GOVUKFrontendComponent {
document.body.appendChild(this.$overlay)
this.$overlay.textContent = this.i18n.t('activated')

window.location.href = this.$button.getAttribute('href')
window.location.href = this.$button.href
}

/**
Expand All @@ -262,6 +270,10 @@ export class ExitThisPage extends GOVUKFrontendComponent {
* @param {KeyboardEvent} event - keyup event
*/
handleKeypress(event) {
if (!this.$updateSpan) {
return
}

// Detect if the 'Shift' key has been pressed. We want to only do things if it
// was pressed by itself and not in a combination with another key—so we keep
// track of whether the preceding keyup had shiftKey: true on it, and if it
Expand All @@ -280,15 +292,15 @@ export class ExitThisPage extends GOVUKFrontendComponent {
this.updateIndicator()

// Clear the timeout for the keypress timeout message clearing itself
if (this.timeoutMessageId !== null) {
if (this.timeoutMessageId) {
window.clearTimeout(this.timeoutMessageId)
this.timeoutMessageId = null
}

if (this.keypressCounter >= 3) {
this.keypressCounter = 0

if (this.keypressTimeoutId !== null) {
if (this.keypressTimeoutId) {
window.clearTimeout(this.keypressTimeoutId)
this.keypressTimeoutId = null
}
Expand All @@ -303,7 +315,7 @@ export class ExitThisPage extends GOVUKFrontendComponent {
}

this.setKeypressTimer()
} else if (this.keypressTimeoutId !== null) {
} else if (this.keypressTimeoutId) {
// If the user pressed any key other than 'Shift', after having pressed
// 'Shift' and activating the timer, stop and reset the timer.
this.resetKeypressTimer()
Expand All @@ -326,7 +338,9 @@ export class ExitThisPage extends GOVUKFrontendComponent {
setKeypressTimer() {
// Clear any existing timeout. This is so only one timer is running even if
// there are multiple keypresses in quick succession.
window.clearTimeout(this.keypressTimeoutId)
if (this.keypressTimeoutId) {
window.clearTimeout(this.keypressTimeoutId)
}

// Set a fresh timeout
this.keypressTimeoutId = window.setTimeout(
Expand All @@ -341,14 +355,22 @@ export class ExitThisPage extends GOVUKFrontendComponent {
* @private
*/
resetKeypressTimer() {
window.clearTimeout(this.keypressTimeoutId)
this.keypressTimeoutId = null
if (!this.$updateSpan) {
return
}

if (this.keypressTimeoutId) {
window.clearTimeout(this.keypressTimeoutId)
this.keypressTimeoutId = null
}

const $updateSpan = this.$updateSpan

this.keypressCounter = 0
this.$updateSpan.textContent = this.i18n.t('timedOut')
$updateSpan.textContent = this.i18n.t('timedOut')

this.timeoutMessageId = window.setTimeout(() => {
this.$updateSpan.textContent = ''
$updateSpan.textContent = ''
}, this.timeoutTime)

this.updateIndicator()
Expand All @@ -366,7 +388,7 @@ export class ExitThisPage extends GOVUKFrontendComponent {
* By running this check when the page is shown, we can programatically restore
* the page and the component to a "default" state
*
* @deprecated Will be made private in v5.0
* @private
*/
resetPage() {
// If an overlay is set, remove it and reset the value
Expand All @@ -378,8 +400,10 @@ export class ExitThisPage extends GOVUKFrontendComponent {
}

// Ensure the announcement span's role is status, not alert and clear any text
this.$updateSpan.setAttribute('role', 'status')
this.$updateSpan.textContent = ''
if (this.$updateSpan) {
this.$updateSpan.setAttribute('role', 'status')
this.$updateSpan.textContent = ''
}

// Sync the keypress indicator lights
this.updateIndicator()
Expand Down