{"version":3,"file":"character-count.mjs","sources":["../../../../src/govuk/components/character-count/character-count.mjs"],"sourcesContent":["import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'\nimport {\n  validateConfig,\n  ConfigurableComponent,\n  configOverride\n} from '../../common/configuration.mjs'\nimport { createElement } from '../../common/create-element.mjs'\nimport { formatErrorMessage } from '../../common/index.mjs'\nimport { ConfigError, ElementError, SupportError } from '../../errors/index.mjs'\nimport { I18n } from '../../i18n.mjs'\n\n/**\n * Character count component\n *\n * Tracks the number of characters or words in the `.govuk-js-character-count`\n * `<textarea>` inside the element. Displays a message with the remaining number\n * of characters/words available, or the number of characters/words in excess.\n *\n * You can configure the message to only appear after a certain percentage\n * of the available characters/words has been entered.\n *\n * @preserve\n * @augments ConfigurableComponent<CharacterCountConfig>\n */\nexport class CharacterCount extends ConfigurableComponent {\n  /** @private */\n  $textarea\n\n  /** @private */\n  count = 0\n\n  /**\n   * @type {Intl.Segmenter | null}\n   */\n  segmenter = null\n\n  /** @private */\n  $visibleCountMessage\n\n  /** @private */\n  $screenReaderCountMessage\n\n  /**\n   * @private\n   * @type {number | null}\n   */\n  lastInputTimestamp = null\n\n  /** @private */\n  lastInputValue = ''\n\n  /**\n   * @private\n   * @type {number | null}\n   */\n  valueChecker = null\n\n  /** @private */\n  i18n\n\n  /** @private */\n  maxLength;\n\n  /**\n   * Character count config override\n   *\n   * @internal\n   * @param {Partial<CharacterCountConfig>} datasetConfig - configuration specified by dataset\n   * @returns {Partial<CharacterCountConfig>} - configuration to override by dataset\n   */\n  [configOverride](datasetConfig) {\n    let configOverrides = /** @type {Partial<CharacterCountConfig>} */ ({})\n\n    // To ensure data-attributes take complete precedence, even if they change\n    // the type of count, we need to reset the `maxlength` and `maxwords` from\n    // the JavaScript config\n    if ('maxwords' in datasetConfig || 'maxlength' in datasetConfig) {\n      configOverrides = {\n        maxlength: undefined,\n        maxwords: undefined\n      }\n    }\n\n    if ('maxwords' in datasetConfig || this.config.maxwords !== undefined) {\n      console.warn(\n        formatErrorMessage(\n          CharacterCount,\n          'Option `maxwords` is deprecated. Use `maxlength` with `countType: \"words\"` instead.'\n        )\n      )\n\n      if (!('maxlength' in datasetConfig)) {\n        configOverrides.maxlength =\n          datasetConfig.maxwords ?? this.config.maxwords\n        configOverrides.countType = 'words'\n      }\n    }\n\n    return configOverrides\n  }\n\n  /**\n   * @param {Element | null} $root - HTML element to use for character count\n   * @param {CharacterCountConfig} [config] - Character count config\n   */\n  constructor($root, config = {}) {\n    super($root, config)\n\n    const $textarea = this.$root.querySelector('.govuk-js-character-count')\n    if (\n      !(\n        $textarea instanceof HTMLTextAreaElement ||\n        $textarea instanceof HTMLInputElement\n      )\n    ) {\n      throw new ElementError({\n        component: CharacterCount,\n        element: $textarea,\n        expectedType: 'HTMLTextareaElement or HTMLInputElement',\n        identifier: 'Form field (`.govuk-js-character-count`)'\n      })\n    }\n\n    // Check for valid config\n    const errors = validateConfig(CharacterCount.schema, this.config)\n    if (errors[0]) {\n      throw new ConfigError(formatErrorMessage(CharacterCount, errors[0]))\n    }\n\n    this.i18n = new I18n(this.config.i18n, {\n      // Read the fallback if necessary rather than have it set in the defaults\n      locale: closestAttributeValue(this.$root, 'lang')\n    })\n\n    if (\n      this.config.countType === 'characters' ||\n      (this.config.countType === 'words' && this.config.maxwords === undefined)\n    ) {\n      if (!('Segmenter' in Intl)) {\n        throw new SupportError(\n          formatErrorMessage(\n            CharacterCount,\n            'Support for \"Intl.Segmenter\" required'\n          )\n        )\n      }\n\n      this.segmenter = new Intl.Segmenter(this.i18n.locale, {\n        granularity: this.config.countType === 'words' ? 'word' : 'grapheme'\n      })\n    }\n\n    // Determine the limit attribute (characters or words)\n    this.maxLength = this.config.maxlength ?? Infinity\n\n    this.$textarea = $textarea\n\n    const textareaDescriptionId = `${this.$textarea.id}-info`\n    const $textareaDescription = document.getElementById(textareaDescriptionId)\n    if (!$textareaDescription) {\n      throw new ElementError({\n        component: CharacterCount,\n        element: $textareaDescription,\n        identifier: `Count message (\\`id=\"${textareaDescriptionId}\"\\`)`\n      })\n    }\n\n    // Pre-existing validation error rendered from server\n    this.$errorMessage = this.$root.querySelector('.govuk-error-message')\n\n    // Inject a description for the textarea if none is present already\n    // for when the component was rendered with no maxlength nor custom\n    // textareaDescriptionText\n    // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec\n    if ($textareaDescription.textContent.match(/^\\s*$/)) {\n      $textareaDescription.textContent = this.i18n.t('textareaDescription', {\n        count: this.maxLength\n      })\n    }\n\n    // Move the textarea description to be immediately after the textarea\n    // Kept for backwards compatibility\n    this.$textarea.insertAdjacentElement('afterend', $textareaDescription)\n\n    // Create the *screen reader* specific live-updating counter\n    // This doesn't need any styling classes, as it is never visible\n    const $screenReaderCountMessage = createElement('div', {\n      class: 'govuk-character-count__sr-status govuk-visually-hidden',\n      'aria-live': 'polite'\n    })\n\n    this.$screenReaderCountMessage = $screenReaderCountMessage\n    $textareaDescription.insertAdjacentElement(\n      'afterend',\n      $screenReaderCountMessage\n    )\n\n    // Create our live-updating counter element, copying the classes from the\n    // textarea description for backwards compatibility as these may have been\n    // configured\n    const $visibleCountMessage = createElement('div', {\n      class: `${$textareaDescription.className} govuk-character-count__status`,\n      'aria-hidden': 'true'\n    })\n\n    this.$visibleCountMessage = $visibleCountMessage\n    $textareaDescription.insertAdjacentElement('afterend', $visibleCountMessage)\n\n    // Hide the textarea description\n    $textareaDescription.classList.add('govuk-visually-hidden')\n\n    // Remove hard limit if set\n    this.$textarea.removeAttribute('maxlength')\n\n    this.bindChangeEvents()\n\n    // When the page is restored after navigating 'back' in some browsers the\n    // state of form controls is not restored until *after* the DOMContentLoaded\n    // event is fired, so we need to sync after the pageshow event.\n    window.addEventListener('pageshow', () => {\n      // If the current value of the textarea is the same as what's\n      // in the HTML, don't re-run when users have not edited the field yet\n      // (new page load or BF cache navigation without having edited).\n      if (this.$textarea.value !== this.$textarea.textContent) {\n        this.updateCount()\n        this.updateCountMessage()\n      }\n    })\n\n    // Although we've set up handlers to sync state on the pageshow event, init\n    // could be called after those events have fired, for example if they are\n    // added to the page dynamically, so update now too.\n    this.updateCount()\n    this.updateCountMessage()\n  }\n\n  /**\n   * Bind change events\n   *\n   * Set up event listeners on the $textarea so that the count messages update\n   * when the user types.\n   *\n   * @private\n   */\n  bindChangeEvents() {\n    this.$textarea.addEventListener('input', () => this.handleInput())\n\n    // Bind focus/blur events to start/stop polling\n    this.$textarea.addEventListener('focus', () => this.handleFocus())\n    this.$textarea.addEventListener('blur', () => this.handleBlur())\n  }\n\n  /**\n   * Handle input event\n   *\n   * Update the visible character counter and keep track of when the last update\n   * happened for each keypress\n   *\n   * @private\n   */\n  handleInput() {\n    this.updateCount()\n    this.updateVisibleCountMessage()\n    this.lastInputTimestamp = Date.now()\n  }\n\n  /**\n   * Handle focus event\n   *\n   * Speech recognition software such as Dragon NaturallySpeaking will modify\n   * the fields by directly changing its `value`. These changes don't trigger\n   * events in JavaScript, so we need to poll to handle when and if they occur.\n   *\n   * Once the keyup event hasn't been detected for at least 1000 ms (1s), check\n   * if the textarea value has changed and update the count message if it has.\n   *\n   * This is so that the update triggered by the manual comparison doesn't\n   * conflict with debounced KeyboardEvent updates.\n   *\n   * @private\n   */\n  handleFocus() {\n    this.valueChecker = window.setInterval(() => {\n      if (\n        !this.lastInputTimestamp ||\n        Date.now() - 500 >= this.lastInputTimestamp\n      ) {\n        this.updateIfValueChanged()\n      }\n    }, 1000)\n  }\n\n  /**\n   * Handle blur event\n   *\n   * Stop checking the textarea value once the textarea no longer has focus\n   *\n   * @private\n   */\n  handleBlur() {\n    // Cancel value checking on blur\n    if (this.valueChecker) {\n      window.clearInterval(this.valueChecker)\n    }\n  }\n\n  /**\n   * Update count message if textarea value has changed\n   *\n   * @private\n   */\n  updateIfValueChanged() {\n    if (this.$textarea.value !== this.lastInputValue) {\n      this.lastInputValue = this.$textarea.value\n      this.updateCountMessage()\n    }\n  }\n\n  /**\n   * Update count message\n   *\n   * Helper function to update both the visible and screen reader-specific\n   * counters simultaneously (e.g. on init)\n   *\n   * @private\n   */\n  updateCountMessage() {\n    this.updateVisibleCountMessage()\n    this.updateScreenReaderCountMessage()\n  }\n\n  /**\n   * Update visible count message\n   *\n   * @private\n   */\n  updateVisibleCountMessage() {\n    const remainingNumber = this.maxLength - this.count\n    const isError = remainingNumber < 0\n\n    // If input is over the threshold, remove the disabled class which renders\n    // the counter invisible.\n    this.$visibleCountMessage.classList.toggle(\n      'govuk-character-count__message--disabled',\n      !this.isOverThreshold()\n    )\n\n    // Update styles\n    if (!this.$errorMessage) {\n      // Only toggle the textarea error class if there isn't an error message\n      // already, as it may be unrelated to the limit (eg: allowed characters)\n      // and would set the border colour back to black.\n      this.$textarea.classList.toggle('govuk-textarea--error', isError)\n    }\n    this.$visibleCountMessage.classList.toggle('govuk-error-message', isError)\n    this.$visibleCountMessage.classList.toggle('govuk-hint', !isError)\n\n    // Update message\n    this.$visibleCountMessage.textContent = this.getCountMessage()\n  }\n\n  /**\n   * Update screen reader count message\n   *\n   * @private\n   */\n  updateScreenReaderCountMessage() {\n    // If over the threshold, remove the aria-hidden attribute, allowing screen\n    // readers to announce the content of the element.\n    if (this.isOverThreshold()) {\n      this.$screenReaderCountMessage.removeAttribute('aria-hidden')\n    } else {\n      this.$screenReaderCountMessage.setAttribute('aria-hidden', 'true')\n    }\n\n    // Update message\n    this.$screenReaderCountMessage.textContent = this.getCountMessage()\n  }\n\n  /**\n   * Count the number of characters (or words) in the given text, using the\n   * configured count type, and update the component-wide count\n   *\n   * @private\n   */\n  updateCount() {\n    const text = this.$textarea.value\n\n    // Count grapheme clusters (user-perceived characters)\n    if (this.config.countType === 'characters') {\n      this.count = this.segmenter\n        ? Array.from(this.segmenter.segment(text)).length\n        : 0\n\n      return\n    }\n\n    // Count words\n    //\n    // If the (deprecated) `maxwords` option is set, count consecutive\n    // non-whitespace results rather than using the segmenter\n    if (this.config.countType === 'words') {\n      if (this.config.maxwords !== undefined) {\n        this.count = text.match(/\\S+/g)?.length ?? 0\n        return\n      }\n\n      const segments = this.segmenter\n        ? Array.from(this.segmenter.segment(text))\n        : []\n\n      // Filter out punctuation and whitespace, leaving only words\n      this.count = segments.filter((segment) => segment.isWordLike).length\n      return\n    }\n\n    this.count = text.length\n  }\n\n  /**\n   * Get count message\n   *\n   * @private\n   * @returns {string} Status message\n   */\n  getCountMessage() {\n    const remainingNumber = this.maxLength - this.count\n    return this.formatCountMessage(remainingNumber)\n  }\n\n  /**\n   * Formats the message shown to users according to what's counted\n   * and how many remain\n   *\n   * @private\n   * @param {number} remainingNumber - The number of words/characters remaining\n   * @param {CharacterCountConfig['countType']} [countType] - Deprecated\n   * @returns {string} Status message\n   */\n  formatCountMessage(remainingNumber, countType) {\n    countType = countType ?? this.config.countType\n\n    let translationKeyPrefix = 'characters'\n    let translationKeySuffix = remainingNumber < 0 ? 'OverLimit' : 'UnderLimit'\n\n    if (countType === 'words') {\n      translationKeyPrefix = 'words'\n    }\n\n    if (remainingNumber === 0) {\n      translationKeySuffix = 'AtLimit'\n    }\n\n    return this.i18n.t(`${translationKeyPrefix}${translationKeySuffix}`, {\n      count: remainingNumber === 0 ? undefined : Math.abs(remainingNumber)\n    })\n  }\n\n  /**\n   * Check if count is over threshold\n   *\n   * Checks whether the value is over the configured threshold for the input.\n   * If there is no configured threshold, it is set to 0 and this function will\n   * always return true.\n   *\n   * @private\n   * @returns {boolean} true if the current count is over the config.threshold\n   *   (or no threshold is set)\n   */\n  isOverThreshold() {\n    // No threshold means we're always above threshold so save some computation\n    if (!this.config.threshold) {\n      return true\n    }\n\n    // Determine the remaining number of characters/words\n    const currentLength = this.count\n    const maxLength = this.maxLength\n\n    const thresholdValue = (maxLength * this.config.threshold) / 100\n\n    return thresholdValue <= currentLength\n  }\n\n  /**\n   * Name for the component used when initialising using data-module attributes.\n   */\n  static moduleName = 'govuk-character-count'\n\n  /**\n   * Character count default config\n   *\n   * @see {@link CharacterCountConfig}\n   * @constant\n   * @type {CharacterCountConfig}\n   */\n  static defaults = Object.freeze({\n    threshold: 0,\n    countType: 'length',\n    i18n: {\n      // Characters\n      charactersUnderLimit: {\n        one: 'You have %{count} character remaining',\n        other: 'You have %{count} characters remaining'\n      },\n      charactersAtLimit: 'You have 0 characters remaining',\n      charactersOverLimit: {\n        one: 'You have %{count} character too many',\n        other: 'You have %{count} characters too many'\n      },\n      // Words\n      wordsUnderLimit: {\n        one: 'You have %{count} word remaining',\n        other: 'You have %{count} words remaining'\n      },\n      wordsAtLimit: 'You have 0 words remaining',\n      wordsOverLimit: {\n        one: 'You have %{count} word too many',\n        other: 'You have %{count} words too many'\n      },\n      textareaDescription: {\n        other: ''\n      }\n    }\n  })\n\n  /**\n   * Character count config schema\n   *\n   * @constant\n   * @satisfies {Schema<CharacterCountConfig>}\n   */\n  static schema = Object.freeze({\n    properties: {\n      i18n: { type: 'object' },\n      maxwords: { type: 'number' },\n      maxlength: { type: 'number' },\n      threshold: { type: 'number' },\n      countType: { type: 'string' }\n    },\n    anyOf: [\n      {\n        required: ['maxwords'],\n        errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n      },\n      {\n        required: ['maxlength'],\n        errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n      }\n    ]\n  })\n}\n\n/**\n * Character count config\n *\n * @see {@link CharacterCount.defaults}\n * @typedef {object} CharacterCountConfig\n * @property {number} [maxlength] - The maximum number of characters (or words\n *   if `countType` is set to `\"words\"`).\n * @property {number} [maxwords] - Deprecated. Use `maxlength` and\n *   `countType: \"words\"` instead.\n * @property {number} [threshold=0] - The percentage value of the limit at\n *   which point the count message is displayed. If this attribute is set, the\n *   count message will be hidden by default.\n * @property {'characters' | 'length' | 'words'} [countType] - The count type\n *   (`\"characters\"`, `\"length\"` or `\"words\"`) used to count the text.\n * @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations\n */\n\n/**\n * Character count translations\n *\n * @see {@link CharacterCount.defaults.i18n}\n * @typedef {object} CharacterCountTranslations\n *\n * Messages shown to users as they type. It provides feedback on how many words\n * or characters they have remaining or if they are over the limit. This also\n * includes a message used as an accessible description for the textarea.\n * @property {TranslationPluralForms} [charactersUnderLimit] - Message displayed\n *   when the number of characters is under the configured maximum, `maxlength`.\n *   This message is displayed visually and through assistive technologies. The\n *   component will replace the `%{count}` placeholder with the number of\n *   remaining characters. This is a [pluralised list of\n *   messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {string} [charactersAtLimit] - Message displayed when the number of\n *   characters reaches the configured maximum, `maxlength`. This message is\n *   displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [charactersOverLimit] - Message displayed\n *   when the number of characters is over the configured maximum, `maxlength`.\n *   This message is displayed visually and through assistive technologies. The\n *   component will replace the `%{count}` placeholder with the number of\n *   remaining characters. This is a [pluralised list of\n *   messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {TranslationPluralForms} [wordsUnderLimit] - Message displayed when\n *   the number of words is under the configured maximum, `maxlength`. This\n *   message is displayed visually and through assistive technologies. The\n *   component will replace the `%{count}` placeholder with the number of\n *   remaining words. This is a [pluralised list of\n *   messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {string} [wordsAtLimit] - Message displayed when the number of\n *   words reaches the configured maximum, `maxlength`. This message is\n *   displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [wordsOverLimit] - Message displayed when\n *   the number of words is over the configured maximum, `maxlength`. This\n *   message is displayed visually and through assistive technologies. The\n *   component will replace the `%{count}` placeholder with the number of\n *   remaining words. This is a [pluralised list of\n *   messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {TranslationPluralForms} [textareaDescription] - Message made\n *   available to assistive technologies, if none is already present in the\n *   HTML, to describe that the component accepts only a limited amount of\n *   content. It is visible on the page if `countType` is not supported or\n *   JavaScript is unavailable. The component will replace the `%{count}`\n *   placeholder with the value of the `maxlength` parameter.\n */\n\n/**\n * @import { Schema } from '../../common/configuration.mjs'\n * @import { TranslationPluralForms } from '../../i18n.mjs'\n */\n"],"names":["CharacterCount","ConfigurableComponent","configOverride","datasetConfig","configOverrides","maxlength","undefined","maxwords","config","console","warn","formatErrorMessage","_datasetConfig$maxwor","countType","constructor","$root","_this$config$maxlengt","$textarea","count","segmenter","$visibleCountMessage","$screenReaderCountMessage","lastInputTimestamp","lastInputValue","valueChecker","i18n","maxLength","querySelector","HTMLTextAreaElement","HTMLInputElement","ElementError","component","element","expectedType","identifier","errors","validateConfig","schema","ConfigError","I18n","locale","closestAttributeValue","Intl","SupportError","Segmenter","granularity","Infinity","textareaDescriptionId","id","$textareaDescription","document","getElementById","$errorMessage","textContent","match","t","insertAdjacentElement","createElement","class","className","classList","add","removeAttribute","bindChangeEvents","window","addEventListener","value","updateCount","updateCountMessage","handleInput","handleFocus","handleBlur","updateVisibleCountMessage","Date","now","setInterval","updateIfValueChanged","clearInterval","updateScreenReaderCountMessage","remainingNumber","isError","toggle","isOverThreshold","getCountMessage","setAttribute","text","Array","from","segment","length","_text$match$length","_text$match","segments","filter","isWordLike","formatCountMessage","translationKeyPrefix","translationKeySuffix","Math","abs","threshold","currentLength","thresholdValue","moduleName","defaults","Object","freeze","charactersUnderLimit","one","other","charactersAtLimit","charactersOverLimit","wordsUnderLimit","wordsAtLimit","wordsOverLimit","textareaDescription","properties","type","anyOf","required","errorMessage"],"mappings":"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"}