2026-10-09 04:51:45 -04:00
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
// La table des raccourcis clavier de l'interface (§ 7.3, § 13.5, § 19.8) :
|
|
|
|
|
// la seule source du tableau des raccourcis de la documentation. Le code qui
|
[REF] interface: read every key through the shortcut table
Twelve components still compared key names themselves, so the shortcut
table could drift from what they actually did; a guard listed them as
pending. Each now reads its effect from RACCOURCIS through effetDe, the
pending list and its guard are removed, and the generated shortcut
table is unchanged. The keys the old guard pinned without a behaviour
test (Escape on the plan root with no active element, ArrowLeft in the
grid, and those of the participant and table lists) each gain one.
Checked: 3852 node, 766 browser, 101 long tests, from the index alone.
--- FR ---
[REF] interface : chaque touche lue par la table des raccourcis
Douze composants comparaient encore eux-mêmes les noms de touches : la
table des raccourcis pouvait s'écarter de ce qu'ils faisaient, et une
garde les tenait en attente. Chacun lit désormais son effet dans
RACCOURCIS par effetDe ; la liste d'attente et sa garde disparaissent,
la table engendrée ne change pas. Les touches que l'ancienne garde
figeait sans épreuve de comportement (Échap sur le plan sans élément
actif, flèche gauche dans la grille, listes des personnes et des
tables) en reçoivent chacune une.
Vérifié : 3852 node, 766 navigateur, 101 longues, depuis l'index seul.
Assisted-by: Claude Opus 5.5
2026-10-10 17:25:03 -04:00
|
|
|
// répond à une touche la lit par effetDe, et la garde de
|
|
|
|
|
// test/sources_interface.test.js relève toute touche nommée hors d'ici :
|
|
|
|
|
// l'interface ne répond qu'aux touches de la table, et le tableau décrit
|
|
|
|
|
// chacune de ses réponses.
|
2026-10-09 04:51:45 -04:00
|
|
|
//
|
|
|
|
|
// Une entrée est { touche, contexte, effet, cle } :
|
|
|
|
|
// touche la valeur de KeyboardEvent.key, précédée de « Maj+ » quand la
|
|
|
|
|
// majuscule change l'effet (Maj+Tab dans la grille) ;
|
|
|
|
|
// contexte là où elle agit — 'plan' (l'élément actif du plan, les listes
|
|
|
|
|
// de travail et la réserve), 'grille' (une cellule de la grille
|
|
|
|
|
// des participants), 'champ' (une saisie), 'commande' (un
|
|
|
|
|
// bouton qui exécute une commande), 'geste' (un geste du
|
|
|
|
|
// pointeur en cours), 'fenetre' (un panneau, une infobulle) ;
|
|
|
|
|
// effet ce qu'elle y fait, un nom que le code du contexte interprète ;
|
|
|
|
|
// cle la clé du libellé qui décrit l'effet, raccourcis.<contexte>.<effet>.
|
|
|
|
|
// Deux touches d'un même effet partagent sa clé : Entrée et l'espace sur le
|
|
|
|
|
// plan, Entrée et F2 dans la grille.
|
|
|
|
|
|
|
|
|
|
/** @typedef {'plan'|'grille'|'champ'|'commande'|'geste'|'fenetre'} ContexteRaccourci */
|
|
|
|
|
|
|
|
|
|
/** Les contextes, dans l'ordre du tableau. */
|
|
|
|
|
export const CONTEXTES_RACCOURCIS = Object.freeze(['plan', 'grille', 'champ', 'commande', 'geste', 'fenetre']);
|
|
|
|
|
|
|
|
|
|
const raccourci = (touche, contexte, effet) => Object.freeze({ touche, contexte, effet, cle: `raccourcis.${contexte}.${effet}` });
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Les raccourcis, par contexte dans l'ordre de CONTEXTES_RACCOURCIS. Sur le
|
|
|
|
|
* plan, les flèches mènent à la table voisine, ou au siège suivant (droite,
|
|
|
|
|
* bas) et précédent (gauche, haut) ; Entrée et l'espace descendent dans les
|
|
|
|
|
* sièges ou choisissent la place ; Échap remonte, et oublie le choix des
|
|
|
|
|
* listes (plan/clavier.js). Dans la grille des participants, les flèches
|
|
|
|
|
* mènent à la cellule voisine, Tab et Maj+Tab à la suivante et à la
|
|
|
|
|
* précédente — une saisie en cours validée d'abord —, Entrée et F2 ouvrent
|
|
|
|
|
* la saisie de la cellule ou basculent l'exclusion, Échap efface le refus
|
|
|
|
|
* de la cellule. Dans un champ, Entrée valide la saisie et Échap rend la
|
|
|
|
|
* valeur d'avant. Sur une commande, Entrée et l'espace l'exécutent une fois,
|
|
|
|
|
* maintenues comprises. Échap annule le geste en cours et ferme une
|
|
|
|
|
* fenêtre.
|
|
|
|
|
*
|
|
|
|
|
* @type {ReadonlyArray<Readonly<{touche: string, contexte: ContexteRaccourci, effet: string, cle: string}>>}
|
|
|
|
|
*/
|
|
|
|
|
export const RACCOURCIS = Object.freeze([
|
|
|
|
|
raccourci('ArrowRight', 'plan', 'droite'),
|
|
|
|
|
raccourci('ArrowDown', 'plan', 'bas'),
|
|
|
|
|
raccourci('ArrowLeft', 'plan', 'gauche'),
|
|
|
|
|
raccourci('ArrowUp', 'plan', 'haut'),
|
|
|
|
|
raccourci('Enter', 'plan', 'entrer'),
|
|
|
|
|
raccourci(' ', 'plan', 'entrer'),
|
|
|
|
|
raccourci('Escape', 'plan', 'remonter'),
|
|
|
|
|
raccourci('ArrowRight', 'grille', 'droite'),
|
|
|
|
|
raccourci('ArrowDown', 'grille', 'bas'),
|
|
|
|
|
raccourci('ArrowLeft', 'grille', 'gauche'),
|
|
|
|
|
raccourci('ArrowUp', 'grille', 'haut'),
|
|
|
|
|
raccourci('Tab', 'grille', 'suivante'),
|
|
|
|
|
raccourci('Maj+Tab', 'grille', 'precedente'),
|
|
|
|
|
raccourci('Enter', 'grille', 'editer'),
|
|
|
|
|
raccourci('F2', 'grille', 'editer'),
|
|
|
|
|
raccourci('Escape', 'grille', 'effacer'),
|
|
|
|
|
raccourci('Enter', 'champ', 'valider'),
|
|
|
|
|
raccourci('Escape', 'champ', 'rendre'),
|
|
|
|
|
raccourci('Enter', 'commande', 'activer'),
|
|
|
|
|
raccourci(' ', 'commande', 'activer'),
|
|
|
|
|
raccourci('Escape', 'geste', 'annuler'),
|
|
|
|
|
raccourci('Escape', 'fenetre', 'fermer'),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// L'effet de chaque touche, par contexte.
|
|
|
|
|
const EFFETS = new Map(
|
|
|
|
|
CONTEXTES_RACCOURCIS.map((contexte) => [
|
|
|
|
|
contexte,
|
|
|
|
|
new Map(RACCOURCIS.filter((entree) => entree.contexte === contexte).map(({ touche, effet }) => [touche, effet])),
|
|
|
|
|
]),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* L'effet d'une touche dans un contexte, ou null pour une touche que le
|
|
|
|
|
* contexte ne prend pas.
|
|
|
|
|
*
|
|
|
|
|
* @param {ContexteRaccourci} contexte
|
|
|
|
|
* @param {string} touche KeyboardEvent.key
|
|
|
|
|
* @returns {string|null}
|
|
|
|
|
* @throws {RangeError} pour un contexte hors de CONTEXTES_RACCOURCIS
|
|
|
|
|
*/
|
|
|
|
|
export function effetDe(contexte, touche) {
|
|
|
|
|
const effets = EFFETS.get(contexte);
|
|
|
|
|
if (effets === undefined) throw new RangeError(`contexte de raccourci inconnu : ${JSON.stringify(contexte)}`);
|
|
|
|
|
return effets.get(touche) ?? null;
|
|
|
|
|
}
|