11570 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous
Je dois souvent saisir dans une <textarea> des noms de notes comme Fa dièse ou Si bémol en utilisant les codes utf8 correspondant.
Pour obtenir ces caractères je dois faire un copier/coller à partir d'une zone qui contient ces caractères (et d'autres caractères musicaux).
Ma question:
Il serait plus pratique d'avoir un script déclenché sur l'évènement keydown qui regarde les caractères précédents et fait la transformation nécessaire pour modifier le caractère entré en fonction de ce qui précède, par exemple si le texte qui précède est un nom de note ("Do" ou "Sol" par exemple) et que le caractère entré est #, il faut remplacer ce caractère par le code utf8 de dièse (U+266F), ou si le caractère entré est b après un nom de note, le remplacer par le code utf8 de bémol (U+266D)
Comment peut on écrire cette fonction ?
Merci de votre aide
Modifié par PapyJP (05 Feb 2026 - 12:47)
Administrateur
Bonjour,

vibe codé avec le tout récent Claude Opus 4.6, il... s'en sort très bien. Ta demande très claire est évidemment pour beaucoup là dedans. Smiley lol

https://codepen.io/PhilippeVay/pen/RNRYGPB

Les contrastes pas glop, c'est pas moi...
Le panneau d'aide (raccourcis clavier) ou les logs, ben... je lui ai pas demandé. Smiley crazy Juste précisé "Oh, fais-en une démo complète"

EDIT : l'iso-8859-1 du Forum a comme d'hab' mangé Smiley question plein de caractères... Voir le Codepen Smiley fut
/**
 * setupMusicInput(textarea)
 *
 * Écoute les frappes clavier sur un <textarea> et remplace
 * automatiquement les caractères d'altération musicale :
 *
 *   Note + #   ?  ?   dièse       (U+266F)
 *   Note + b   ?  ?   bémol       (U+266D)
 *   Note + =   ?  ?   bécarre     (U+266E)
 *   ?    + #   ?  ????   double dièse (U+1D12A)  — remplace le ? précédent
 *   ?    + b   ?  ????   double bémol (U+1D12B)  — remplace le ? précédent
 */
function setupMusicInput(textarea, logEl) {
  // Le nom de note doit être précédé d'un séparateur ou être en début de texte
  const notePattern = /(?:^|[\s,;. [decu])\[\]\/\-])(?:Do|Ré|Re|Mi|Fa|Sol|La|Si)$/i;

  textarea.addEventListener('keydown', function (e) {
    // Ne pas interférer avec les raccourcis système
    if (e.ctrlKey || e.altKey || e.metaKey) return;

    const pos  = this.selectionStart;
    const text = this.value;
    const textBefore = text.substring(0, pos);

    // ?? Double dièse : ? + # ? ???? ??
    if (e.key === '#' && textBefore.endsWith('\u266F')) {
      e.preventDefault();
      replaceBack(this, pos, 1, '\uD834\uDD2A'); // ????
      log(logEl, '? + #', '????', 'double dièse');
      return;
    }

    // ?? Double bémol : ? + b ? ???? ??
    if (e.key === 'b' && textBefore.endsWith('\u266D')) {
      e.preventDefault();
      replaceBack(this, pos, 1, '\uD834\uDD2B'); // ????
      log(logEl, '? + b', '????', 'double bémol');
      return;
    }

    // ?? Dièse : Note + # ? ? ??
    if (e.key === '#' && notePattern.test(textBefore)) {
      e.preventDefault();
      insertChar(this, pos, '\u266F'); // ?
      log(logEl, extractNote(textBefore) + ' + #', extractNote(textBefore) + '?', 'dièse');
      return;
    }

    // ?? Bémol : Note + b ? ? ??
    if (e.key === 'b' && notePattern.test(textBefore)) {
      e.preventDefault();
      insertChar(this, pos, '\u266D'); // ?
      log(logEl, extractNote(textBefore) + ' + b', extractNote(textBefore) + '?', 'bémol');
      return;
    }

    // ?? Bécarre : Note + = ? ? ??
    if (e.key === '=' && notePattern.test(textBefore)) {
      e.preventDefault();
      insertChar(this, pos, '\u266E'); // ?
      log(logEl, extractNote(textBefore) + ' + =', extractNote(textBefore) + '?', 'bécarre');
      return;
    }
  });

  /** Insère un caractère à la position du curseur */
  function insertChar(el, pos, char) {
    const before = el.value.substring(0, pos);
    const after  = el.value.substring(el.selectionEnd);
    el.value = before + char + after;
    el.selectionStart = el.selectionEnd = pos + char.length;
    el.dispatchEvent(new Event('input', { bubbles: true }));
  }

  /** Remplace `count` caractères avant le curseur par `char` */
  function replaceBack(el, pos, count, char) {
    const before = el.value.substring(0, pos - count);
    const after  = el.value.substring(el.selectionEnd);
    el.value = before + char + after;
    el.selectionStart = el.selectionEnd = pos - count + char.length;
    el.dispatchEvent(new Event('input', { bubbles: true }));
  }

  /** Extrait le nom de note à la fin du texte */
  function extractNote(text) {
    const m = text.match(/(?:Do|Ré|Re|Mi|Fa|Sol|La|Si)$/i);
    return m ? m[0] : '';
  }

  /** Ajoute une entrée dans le journal */
  function log(el, from, to, label) {
    if (!el) return;
    const entry = document.createElement('div');
    entry.className = 'entry';
    entry.innerHTML =
      '<span class="highlight">' + escHtml(from) + '</span>' +
      ' ? ' +
      '<span class="highlight">' + escHtml(to) + '</span>' +
      ' <span style="color:#556677">(' + escHtml(label) + ')</span>';
    el.prepend(entry);
  }

  function escHtml(s) {
    return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  }
}

// ?? Initialisation ??
const textarea = document.getElementById('music-notes');
const logEl    = document.getElementById('log');
setupMusicInput(textarea, logEl);

Modifié par Felipe (06 Feb 2026 - 12:53)
Modérateur
Salut,

Hier soir, j'ai pensé à ceci. Le thème vient d'une IA. Je lui ai donné le SVG, et j'ai demandé de me faire un thème.

@PapyJP
Si tu veux que le système de saisie, ça se résume à ce code :

const notesList = ['Do', 'Ré', 'Mi', 'Fa', 'Sol', 'La', 'Si', 'Re']
const editor = document.getElementById('editor')

editor.addEventListener('input', (e) => {
    const substitutions = { '#': '\u266F', 'b': '\u266D' }
    
    if (e.inputType === 'insertText' && substitutions[e.data]) {
        const pos = editor.selectionStart
        const text = editor.value
        
        // regarde les 2 ou 3 caractères avant le curseur
        // cherche un nom de note (Do, Ré, Mi...)
        const textBefore = text.substring(0, pos - 1).trim()
        const words = textBefore.split(/\s+/)
        const lastWord = words[words.length - 1]

        if (notesList.includes(lastWord)) {
            // remplace le # ou b par le symbole musical
            const newText = text.substring(0, pos - 1) + substitutions[e.data] + text.substring(pos)
            editor.value = newText
            
            // replace le curseur après le nouveau symbole
            editor.selectionStart = editor.selectionEnd = pos
        }
    }
});

function insertNote(val) {
    const start = editor.selectionStart
    const end = editor.selectionEnd
    editor.setRangeText(val, start, end, 'end')
    editor.focus()
}


@Felipe :
le code généré est beaucoup trop verbeux pour si peu. Je te l'accorde, je l'ai lu en Z.
Modifié par Niuxe (06 Feb 2026 - 16:28)