fix(dossier): improuve decimal field formatting
This commit is contained in:
parent
dbb68f29da
commit
63303e51f8
4 changed files with 57 additions and 49 deletions
|
@ -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 }))
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,25 +7,29 @@ export class FormatController extends ApplicationController {
|
||||||
case 'list':
|
case 'list':
|
||||||
this.on('change', (event) => {
|
this.on('change', (event) => {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
target.value = this.formatList(target.value);
|
const value = this.formatList(target.value);
|
||||||
|
replaceValue(target, value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'iban':
|
case 'iban':
|
||||||
this.on('input', (event) => {
|
this.on('input', (event) => {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
target.value = this.formatIBAN(target.value);
|
const value = this.formatIBAN(target.value);
|
||||||
|
replaceValue(target, value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'integer':
|
case 'integer':
|
||||||
this.on('input', (event) => {
|
this.on('input', (event) => {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
target.value = this.formatInteger(target.value);
|
const value = this.formatInteger(target.value);
|
||||||
|
replaceValue(target, value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'decimal':
|
case 'decimal':
|
||||||
this.on('input', (event) => {
|
this.on('input', (event) => {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
target.value = this.formatDecimal(target.value);
|
const value = this.formatDecimal(target.value);
|
||||||
|
replaceValue(target, value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -48,12 +52,34 @@ export class FormatController extends ApplicationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatDecimal(value: string) {
|
private formatDecimal(value: string) {
|
||||||
// Le séparateur de décimales est toujours après le séparateur de milliers (un point ou une virgule).
|
const decimalSeparator = getDecimalSeparator(value);
|
||||||
// S'il n'y a qu'un seul séparateur, on considère que c'est celui des décimales.
|
const number =
|
||||||
// S'il n'y en a pas, ça n'a pas d'effet.
|
decimalSeparator == ','
|
||||||
const decimalSeparator =
|
? value.replace(/\./g, '').replace(/,/g, '.')
|
||||||
value.lastIndexOf(',') > value.lastIndexOf('.') ? ',' : '.';
|
: value.replace(/,/g, '');
|
||||||
|
return number.replace(new RegExp(`[^-?\\d.]`, 'g'), '');
|
||||||
return value.replace(new RegExp(`[^-?\\d${decimalSeparator}]`, '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 ? '.' : ',';
|
||||||
|
}
|
||||||
|
|
|
@ -195,15 +195,20 @@ describe 'The user' do
|
||||||
champ_value_for('nombre décimal') == '123456.78'
|
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 {
|
wait_until {
|
||||||
champ_value_for('nombre décimal') == '1234.56'
|
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 {
|
wait_until {
|
||||||
champ_value_for('nombre décimal') == '-1234.56'
|
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
|
end
|
||||||
|
|
||||||
scenario 'extends dossier experation date more than one time, ', js: true, retry: 3 do
|
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
|
champ_for(libelle).value
|
||||||
end
|
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)
|
def champ_for(libelle)
|
||||||
champs = user_dossier.reload.champs_public
|
champs = user_dossier.reload.champs_public
|
||||||
champs.find { |c| c.libelle == libelle }
|
champs.find { |c| c.libelle == libelle }
|
||||||
|
|
Loading…
Reference in a new issue