Source: ConstraintViolationMessages.js

import BaseCustomElement from "./BaseCustomElement"
import RichString from "./RichString"
import ConstraintViolationMessage from "./ConstraintViolationMessage"

/**
 * Custom element to translate keys from {@link external:ValidityState} into 
 * actual messges for a human.  This works by inserting `<brut-cv>` elements
 * as children, where the key represents the particular errors present in the `ValidityState` passed
 * to `createMessages`. Note that this will not insert an element for `customError`, since there can't be
 * any sort of general error message to correspond to that.
 *
 * @property {string} input-name if set, this indicates this element contains constraint violation messages
 *                               for the input with this name inside the form this element is in. Currently doesn't affect
 *                               this element's behavior, however AjaxSubmit will use it to locate where it 
 *                               should insert server-side errors.
 *
 * @see Form
 * @see ConstraintViolationMessage
 * @see AjaxSubmit
 *
 * @customElement brut-cv-messages
 */
class ConstraintViolationMessages extends BaseCustomElement {
  static tagName = "brut-cv-messages"

  static observedAttributes = [
    "show-warnings",
    "input-name",
  ]

  inputNameChangedCallback({newValue}) {
    // attribute listed for documentation purposes only
  }

  /** 
   * Creates error messages based on the passed `ValidityState` and input name.
   *
   * This should be called as part of a Form validation event to provide a customized UX for
   * the error messages, beyond what the browser would do by default.  The keys used are the same
   * as the attributes of a `ValidityState`, so for example, a range underflow would mean that `validity.rangeUnderflow` would return
   * true.  Thus, a `<brut-cv>` would be created with `key="cv.fe.rangeUnderflow"`.
   *
   * The `cv.fe` is hard-coded to be consistent with Brut's server-side translation management.
   *
   * @param {ValidityState} validityState - the return from an element's `validity` when it's found to have constraint violations.
   * @param {String} inputName - the element's `name`.
   */
  createMessages({validityState,inputName}) {
    const errors = this.#VALIDITY_STATE_ATTRIBUTES.filter( (attribute) => validityState[attribute] )
    this.clearClientSideMessages()
    errors.forEach( (key) => {
      const options = {
        key: key,
        "input-name": inputName,
      }
      const showWarnings = this.getAttribute("show-warnings")
      if (showWarnings != null) {
        options["show-warnings"] = showWarnings
      }
      const element = ConstraintViolationMessage.createElement(document,options)
      this.appendChild(element)
    })
  }

  /**
   * Clear any client-side messages previously inserted by another element.
   * This is useful to remove potentially out-of-date messages to replace with up-to-date ones.
   */
  clearClientSideMessages() {
    this.querySelectorAll(ConstraintViolationMessage.clientSideSelector()).forEach( (element) => {
      this.removeChild(element)
    })
  }

  /**
   * Clear any server-side messages previously inserted by another element or rendered from the server.
   * This is useful to remove potentially out-of-date messages to replace with up-to-date ones.
   */
  clearServerSideMessages() {
    this.querySelectorAll(ConstraintViolationMessage.serverSideSelector()).forEach( (element) => {
      this.removeChild(element)
    })
  }

  #VALIDITY_STATE_ATTRIBUTES = [
    "badInput",
    "patternMismatch",
    "rangeOverflow",
    "rangeUnderflow",
    "stepMismatch",
    "tooLong",
    "tooShort",
    "typeMismatch",
    "valueMissing",
    // customError omitted, since it makes no sense as a general error key to look up
  ]
}
export default ConstraintViolationMessages