@@ -25,6 +25,9 @@ export class CharacterCount extends ConfigurableComponent {
2525 /** @private */
2626 $textarea
2727
28+ /** @private */
29+ count = 0
30+
2831 /** @private */
2932 $visibleCountMessage
3033
@@ -173,11 +176,19 @@ export class CharacterCount extends ConfigurableComponent {
173176 // When the page is restored after navigating 'back' in some browsers the
174177 // state of form controls is not restored until *after* the DOMContentLoaded
175178 // event is fired, so we need to sync after the pageshow event.
176- window . addEventListener ( 'pageshow' , ( ) => this . updateCountMessage ( ) )
179+ window . addEventListener ( 'pageshow' , ( ) => {
180+ // If the current value of the textarea is the same as what's
181+ // in the HTML, don't re-run.
182+ if ( this . $textarea . value !== this . $textarea . innerHTML ) {
183+ this . updateCount ( )
184+ this . updateCountMessage ( )
185+ }
186+ } )
177187
178188 // Although we've set up handlers to sync state on the pageshow event, init
179189 // could be called after those events have fired, for example if they are
180190 // added to the page dynamically, so update now too.
191+ this . updateCount ( )
181192 this . updateCountMessage ( )
182193 }
183194
@@ -190,22 +201,23 @@ export class CharacterCount extends ConfigurableComponent {
190201 * @private
191202 */
192203 bindChangeEvents ( ) {
193- this . $textarea . addEventListener ( 'keyup ' , ( ) => this . handleKeyUp ( ) )
204+ this . $textarea . addEventListener ( 'input ' , ( ) => this . handleInput ( ) )
194205
195206 // Bind focus/blur events to start/stop polling
196207 this . $textarea . addEventListener ( 'focus' , ( ) => this . handleFocus ( ) )
197208 this . $textarea . addEventListener ( 'blur' , ( ) => this . handleBlur ( ) )
198209 }
199210
200211 /**
201- * Handle key up event
212+ * Handle input event
202213 *
203214 * Update the visible character counter and keep track of when the last update
204215 * happened for each keypress
205216 *
206217 * @private
207218 */
208- handleKeyUp ( ) {
219+ handleInput ( ) {
220+ this . updateCount ( )
209221 this . updateVisibleCountMessage ( )
210222 this . lastInputTimestamp = Date . now ( )
211223 }
@@ -281,7 +293,7 @@ export class CharacterCount extends ConfigurableComponent {
281293 * @private
282294 */
283295 updateVisibleCountMessage ( ) {
284- const remainingNumber = this . maxLength - this . count ( this . $textarea . value )
296+ const remainingNumber = this . maxLength - this . count
285297 const isError = remainingNumber < 0
286298
287299 // If input is over the threshold, remove the disabled class which renders
@@ -325,19 +337,20 @@ export class CharacterCount extends ConfigurableComponent {
325337
326338 /**
327339 * Count the number of characters (or words, if `config.maxwords` is set)
328- * in the given text
340+ * in the given text, and update the component-wide count
329341 *
330342 * @private
331- * @param {string } text - The text to count the characters of
332- * @returns {number } the number of characters (or words) in the text
333343 */
334- count ( text ) {
344+ updateCount ( ) {
345+ const text = this . $textarea . value
346+
335347 if ( this . config . maxwords ) {
336348 const tokens = text . match ( / \S + / g) ?? [ ] // Matches consecutive non-whitespace chars
337- return tokens . length
349+ this . count = tokens . length
350+ return
338351 }
339352
340- return text . length
353+ this . count = text . length
341354 }
342355
343356 /**
@@ -347,7 +360,7 @@ export class CharacterCount extends ConfigurableComponent {
347360 * @returns {string } Status message
348361 */
349362 getCountMessage ( ) {
350- const remainingNumber = this . maxLength - this . count ( this . $textarea . value )
363+ const remainingNumber = this . maxLength - this . count
351364 const countType = this . config . maxwords ? 'words' : 'characters'
352365 return this . formatCountMessage ( remainingNumber , countType )
353366 }
@@ -392,7 +405,7 @@ export class CharacterCount extends ConfigurableComponent {
392405 }
393406
394407 // Determine the remaining number of characters/words
395- const currentLength = this . count ( this . $textarea . value )
408+ const currentLength = this . count
396409 const maxLength = this . maxLength
397410
398411 const thresholdValue = ( maxLength * this . config . threshold ) / 100
0 commit comments