diff --git a/frontend/modules/transport/pages/carriers/[id]/edit.vue b/frontend/modules/transport/pages/carriers/[id]/edit.vue index 6d7256b..b36a921 100644 --- a/frontend/modules/transport/pages/carriers/[id]/edit.vue +++ b/frontend/modules/transport/pages/carriers/[id]/edit.vue @@ -30,9 +30,8 @@ MalioInputText (inheritAttrs:false) renvoie `class` sur l'input. -->
{ it('sanitizeDecimal : ne garde que chiffres + un seul point', () => { @@ -20,11 +21,13 @@ describe('numberInput — saisie volume / indexation (ERP-170)', () => { expect(clampPercent('')).toBe('') }) - it('sanitizeLiotPlates : garde lettres/chiffres/tiret/point-virgule, retire espaces et reste', () => { - expect(sanitizeLiotPlates('AB-123-CD;EF-456-GH')).toBe('AB-123-CD;EF-456-GH') - expect(sanitizeLiotPlates('ab-123-cd ; ef-456-gh')).toBe('ab-123-cd;ef-456-gh') // espaces retirés - expect(sanitizeLiotPlates('AB 123 CD')).toBe('AB123CD') // espaces retirés - expect(sanitizeLiotPlates('AB.123/CD#42')).toBe('AB123CD42') // . / # retirés - expect(sanitizeLiotPlates('')).toBe('') + it('LIOT_PLATES_MASK : garde lettres/chiffres/tiret/point-virgule, bloque espaces et reste', () => { + // Reproduit ce que fait maska au runtime (MaskInput) : preProcess puis masked. + const masked = (v: string) => new Mask(LIOT_PLATES_MASK).masked(LIOT_PLATES_MASK.preProcess!(v)) + expect(masked('AB-123-CD;EF-456-GH')).toBe('AB-123-CD;EF-456-GH') + expect(masked('ab-123-cd ; ef-456-gh')).toBe('ab-123-cd;ef-456-gh') // espaces retirés + expect(masked('AB 123 CD')).toBe('AB123CD') // espaces retirés + expect(masked('AB.123/CD#42&²²')).toBe('AB123CD42') // . / # & ² retirés + expect(masked('')).toBe('') }) }) diff --git a/frontend/modules/transport/utils/forms/numberInput.ts b/frontend/modules/transport/utils/forms/numberInput.ts index 79b8d98..86b1089 100644 --- a/frontend/modules/transport/utils/forms/numberInput.ts +++ b/frontend/modules/transport/utils/forms/numberInput.ts @@ -1,7 +1,9 @@ /** - * Helpers de saisie numérique du formulaire principal transporteur (ERP-170). - * Champs texte restreints (volume m³ décimal, indexation plafonnée). Purs / testables. + * Helpers de saisie du formulaire principal transporteur (ERP-170). + * Champs texte restreints (volume m³ décimal, indexation plafonnée, immatriculations + * LIOT via mask maska). Purs / testables. */ +import type { MaskInputOptions } from 'maska' /** * Restreint une saisie à un nombre décimal : chiffres + UN seul point (RG volume m³, @@ -28,11 +30,18 @@ export function clampPercent(value: string): string { } /** - * Restreint la saisie des immatriculations LIOT : ne garde que lettres, chiffres, - * tiret et point-virgule (séparateur de plaques). Les espaces et tout autre - * caractère sont supprimés à la frappe / au collage. La normalisation finale - * (majuscules + « ; » espacé) reste au back (RG-4.13). + * Mask maska des immatriculations LIOT : n'autorise que lettres, chiffres, tiret et + * point-virgule (séparateur de plaques), longueur libre. Filtrage NATIF (maska gère + * le focus et le curseur, contrairement à un nettoyage manuel). Espaces et tout autre + * caractère sont bloqués à la frappe / au collage. La normalisation finale (majuscules + * + « ; » espacé) reste au back (RG-4.13). + * + * `preProcess` retire d'abord tout caractère interdit (espaces, &, ², …) OÙ QU'IL + * SOIT (le masque positionnel seul s'arrêterait au 1er caractère invalide) ; le + * token `P` en `multiple: true` laisse ensuite passer le reste (longueur libre). */ -export function sanitizeLiotPlates(value: string): string { - return (value ?? '').replace(/[^A-Za-z0-9;-]/g, '') +export const LIOT_PLATES_MASK: MaskInputOptions = { + mask: 'P', + tokens: { P: { pattern: /[A-Za-z0-9;-]/, multiple: true } }, + preProcess: (value: string) => value.replace(/[^A-Za-z0-9;-]/g, ''), }