Skip to content
Open
Show file tree
Hide file tree
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ For advice on how to use these release notes, see [our guidance on staying up to

## Unreleased

### Fixes

We've made fixes to GOV.UK Frontend in the following pull requests:

- [#6449: Refactor Character count method to reduce repeated updates](https://github.com/alphagov/govuk-frontend/pull/6449)

## v6.0.0-beta.1 (Beta breaking release)

### Breaking changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export class CharacterCount extends ConfigurableComponent {
/** @private */
$textarea

/** @private */
count = 0

/** @private */
$visibleCountMessage

Expand Down Expand Up @@ -173,11 +176,19 @@ export class CharacterCount extends ConfigurableComponent {
// When the page is restored after navigating 'back' in some browsers the
// state of form controls is not restored until *after* the DOMContentLoaded
// event is fired, so we need to sync after the pageshow event.
window.addEventListener('pageshow', () => this.updateCountMessage())
window.addEventListener('pageshow', () => {
// If the current value of the textarea is the same as what's
// in the HTML, don't re-run.
if(this.$textarea.value !== this.$textarea.innerHTML) {
this.updateCount()
this.updateCountMessage()
}
})

// Although we've set up handlers to sync state on the pageshow event, init
// could be called after those events have fired, for example if they are
// added to the page dynamically, so update now too.
this.updateCount()
this.updateCountMessage()
}

Expand All @@ -190,22 +201,23 @@ export class CharacterCount extends ConfigurableComponent {
* @private
*/
bindChangeEvents() {
this.$textarea.addEventListener('keyup', () => this.handleKeyUp())
this.$textarea.addEventListener('input', () => this.handleInput())

// Bind focus/blur events to start/stop polling
this.$textarea.addEventListener('focus', () => this.handleFocus())
this.$textarea.addEventListener('blur', () => this.handleBlur())
}

/**
* Handle key up event
* Handle input event
*
* Update the visible character counter and keep track of when the last update
* happened for each keypress
*
* @private
*/
handleKeyUp() {
handleInput() {
this.updateCount()
this.updateVisibleCountMessage()
this.lastInputTimestamp = Date.now()
}
Expand Down Expand Up @@ -281,7 +293,7 @@ export class CharacterCount extends ConfigurableComponent {
* @private
*/
updateVisibleCountMessage() {
const remainingNumber = this.maxLength - this.count(this.$textarea.value)
const remainingNumber = this.maxLength - this.count
const isError = remainingNumber < 0

// If input is over the threshold, remove the disabled class which renders
Expand Down Expand Up @@ -325,19 +337,20 @@ export class CharacterCount extends ConfigurableComponent {

/**
* Count the number of characters (or words, if `config.maxwords` is set)
* in the given text
* in the given text, and update the component-wide count
*
* @private
* @param {string} text - The text to count the characters of
* @returns {number} the number of characters (or words) in the text
*/
count(text) {
updateCount() {
const text = this.$textarea.value

if (this.config.maxwords) {
const tokens = text.match(/\S+/g) ?? [] // Matches consecutive non-whitespace chars
return tokens.length
this.count = tokens.length
return
}

return text.length
this.count = text.length
}

/**
Expand All @@ -347,7 +360,7 @@ export class CharacterCount extends ConfigurableComponent {
* @returns {string} Status message
*/
getCountMessage() {
const remainingNumber = this.maxLength - this.count(this.$textarea.value)
const remainingNumber = this.maxLength - this.count
const countType = this.config.maxwords ? 'words' : 'characters'
return this.formatCountMessage(remainingNumber, countType)
}
Expand Down Expand Up @@ -392,7 +405,7 @@ export class CharacterCount extends ConfigurableComponent {
}

// Determine the remaining number of characters/words
const currentLength = this.count(this.$textarea.value)
const currentLength = this.count
const maxLength = this.maxLength

const thresholdValue = (maxLength * this.config.threshold) / 100
Expand Down