lib/widgets/mlVirtualKeyboard/ButtonChar.js

import { resetInputSize } from 'src/lib/mathquill/functions'
import VirtualKeyboard from 'src/lib/widgets/mlVirtualKeyboard/VirtualKeyboard'
import Button from './Button'

function insertTextAtCursor (element, text) {
  const startPos = element.selectionStart
  const endPos = element.selectionEnd
  element.value = element.value.substring(0, startPos) + text + element.value.substring(endPos, element.value.length)
  element.selectionStart = element.selectionEnd = startPos + text.length
}

class ButtonChar extends Button {
  /**
   * Créé un <button> rattaché à un input mathquill. Avec une value et sans onClick ça crée le onClick qui ajoutera la value dans l’input
   * @param {HTMLElement} editor L’éditeur Mathlive ou le input associé au clavier virtuel contenant le bouton
   * @param {HTMLSpanElement} editor L’input Mathfield (un span.mq-editable-field)
   * @param {ButtonOptions} options
   */
  constructor (editor, options = {}) {
    let { onClick, value } = options
    const text = editor.tagName.toLowerCase() === 'input'
    // Simule un événement keyup qui ne fait rien, au cas où le champ serait marqué en rouge à la suite d’une erreur (pour retirer cette marque)
    if (onClick) {
      options.onClick = onClick
    } else if (value) {
      // on crée un listener qui ajoute la value dans l’input
      if (text) {
        options.onClick = () => {
          const input = VirtualKeyboard.currentEditor
          if (input === this.editor) {
            if (input.demarqueErreur) input.demarqueErreur() // Si on a affecté à l’éditeur une fonction pour le démarquer comme avec erreur
            insertTextAtCursor(input, value)
            resetInputSize(input)
          }
        }
      } else {
        options.onClick = () => {
          const mf = VirtualKeyboard.currentEditor
          if (mf === this.editor) {
            if (mf.demarqueErreur) mf.demarqueErreur() // Si on a affecté à l’éditeur une fonction pour le démarquer comme avec erreur
            if (value === '.') value = ','
            // toujours feedback à false, ça génère des tonnes d’erreurs `Can’t find variable: AudioContext`
            // et c’est pas souhaitable de faire du bruit…
            // par ailleurs ce truc plante de temps à autre avec TypeError `Cannot read properties of undefined (reading 'type')`
            try {
              mf.executeCommand(['typedText', value, { feedback: false, focus: false, simulateKeystroke: true }])
            } catch (error) {
              console.error(error)
            }
          }
        }
      }
    }
    // Pour les lettes minuscumes on utilise la police Giorgia avec italique
    if (value?.length === 1 && /[a-z]/g.test(value)) options.className = 'mlBtnLetter' // pour que les lettres soient en italiques
    super(editor, options)
  }

  /**
   * Ajoute un bouton dans container
   * @param {HTMLElement} container
   * @param {mathfield} mathfiel L’éditeur mathfield associé
   * @param {ButtonOptions} options
   */
  static addInto (container, mathfield, options) {
    // on est une méthode statique, this fait référence à la classe elle-même
    // ne pas mettre ici ButtonMq mais this permet de faire fonctionner ça pour toutes les classes qui étendent ButtonMq
    const btn = new this(mathfield, options)
    container.appendChild(btn.element)
  }
}

export default ButtonChar