fix(dossier): improuve decimal field formatting

This commit is contained in:
Paul Chavard 2023-10-16 10:58:11 +02:00
parent dbb68f29da
commit 63303e51f8
4 changed files with 57 additions and 49 deletions

View file

@ -1 +1 @@
= @form.text_field(:value, input_opts(id: @champ.input_id, aria: { describedby: @champ.describedby_id }, required: @champ.required?, pattern: "-?[0-9]+([\.,][0-9]{1,3})?", inputmode: :decimal, data: { controller: 'format decimal-number-input', format: :decimal }))
= @form.text_field(:value, input_opts(id: @champ.input_id, aria: { describedby: @champ.describedby_id }, required: @champ.required?, pattern: "-?[0-9]+([\.,][0-9]{1,3})?", inputmode: :decimal, data: { controller: 'format', format: :decimal }))

View file

@ -1,35 +0,0 @@
import { ApplicationController } from './application_controller';
export class DecimalNumberInputController extends ApplicationController {
connect() {
const value = this.inputElement.value;
if (value) {
this.formatValue(value);
}
}
formatValue(value: string) {
const number = parseFloat(value);
if (isNaN(number)) {
return;
}
this.inputElement.value = number.toLocaleString();
this.emitInputEvent(); // trigger format controller
}
private get inputElement(): HTMLInputElement {
return this.element as HTMLInputElement;
}
private emitInputEvent() {
const event = new InputEvent('input', {
bubbles: true,
cancelable: true
});
this.inputElement.dispatchEvent(event);
}
}

View file

@ -7,25 +7,29 @@ export class FormatController extends ApplicationController {
case 'list':
this.on('change', (event) => {
const target = event.target as HTMLInputElement;
target.value = this.formatList(target.value);
const value = this.formatList(target.value);
replaceValue(target, value);
});
break;
case 'iban':
this.on('input', (event) => {
const target = event.target as HTMLInputElement;
target.value = this.formatIBAN(target.value);
const value = this.formatIBAN(target.value);
replaceValue(target, value);
});
break;
case 'integer':
this.on('input', (event) => {
const target = event.target as HTMLInputElement;
target.value = this.formatInteger(target.value);
const value = this.formatInteger(target.value);
replaceValue(target, value);
});
break;
case 'decimal':
this.on('input', (event) => {
const target = event.target as HTMLInputElement;
target.value = this.formatDecimal(target.value);
const value = this.formatDecimal(target.value);
replaceValue(target, value);
});
break;
}
@ -48,12 +52,34 @@ export class FormatController extends ApplicationController {
}
private formatDecimal(value: string) {
// Le séparateur de décimales est toujours après le séparateur de milliers (un point ou une virgule).
// S'il n'y a qu'un seul séparateur, on considère que c'est celui des décimales.
// S'il n'y en a pas, ça n'a pas d'effet.
const decimalSeparator =
value.lastIndexOf(',') > value.lastIndexOf('.') ? ',' : '.';
return value.replace(new RegExp(`[^-?\\d${decimalSeparator}]`, 'g'), '');
const decimalSeparator = getDecimalSeparator(value);
const number =
decimalSeparator == ','
? value.replace(/\./g, '').replace(/,/g, '.')
: value.replace(/,/g, '');
return number.replace(new RegExp(`[^-?\\d.]`, 'g'), '');
}
}
function replaceValue(target: HTMLInputElement, value: string) {
const delta = target.value.length - value.length;
const start = target.selectionStart;
const end = target.selectionStart;
const dir = target.selectionDirection;
target.value = value;
target.selectionStart = start ? start - delta : 0;
target.selectionEnd = end ? end - delta : 0;
target.selectionDirection = dir;
}
function getDecimalSeparator(value: string) {
if (value.indexOf('.') != -1 && value.indexOf(',') != -1) {
if (value.lastIndexOf('.') < value.lastIndexOf(',')) {
return ',';
}
return '.';
} else if (value.indexOf(',') != -1) {
return ',';
}
return (1.1).toLocaleString().indexOf('.') != -1 ? '.' : ',';
}

View file

@ -195,15 +195,20 @@ describe 'The user' do
champ_value_for('nombre décimal') == '123456.78'
}
fill_in('nombre décimal', with: '1,234.56')
champ_past_value_for('nombre décimal', '1,234.56')
wait_until {
champ_value_for('nombre décimal') == '1234.56'
}
fill_in('nombre décimal', with: '-1,234.56')
champ_past_value_for('nombre décimal', '-1,234.56')
wait_until {
champ_value_for('nombre décimal') == '-1234.56'
}
champ_past_value_for('nombre décimal', '1.234,56')
wait_until {
champ_value_for('nombre décimal') == '1234.56'
}
end
scenario 'extends dossier experation date more than one time, ', js: true, retry: 3 do
@ -584,6 +589,18 @@ describe 'The user' do
champ_for(libelle).value
end
def champ_id_for(libelle)
champ_for(libelle).input_id
end
def champ_past_value_for(libelle, value)
execute_script("{
let target = document.querySelector('##{champ_id_for(libelle)}');
target.value = \"#{value}\";
target.dispatchEvent(new CustomEvent('input', { bubbles: true }));
}")
end
def champ_for(libelle)
champs = user_dossier.reload.champs_public
champs.find { |c| c.libelle == libelle }