Enhance bib range validation and user feedback in management system
This commit introduces new JavaScript functions for validating range inputs for quantity and end values in the bib management system. It adds visual feedback for invalid fields and updates the preview display based on user input. CSS styles are also added to highlight invalid fields and error messages. Additionally, new SQL entries are created for localized validation messages, improving user guidance. The version code is incremented to reflect these enhancements, aiming to improve user experience and data integrity in the bib input process.
This commit is contained in:
@ -2139,6 +2139,17 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
cursor:text;
|
||||
}
|
||||
|
||||
.bib-field--invalid{
|
||||
border-color:#dc3545 !important;
|
||||
background-color:#fff5f5 !important;
|
||||
color:inherit;
|
||||
}
|
||||
|
||||
.bib-range-preview--error{
|
||||
color:#dc3545;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.bib-field--pick:focus,
|
||||
.bib-field--calc:focus{
|
||||
outline:none;
|
||||
|
||||
@ -2645,14 +2645,123 @@ if ($strLangue == 'fr') {
|
||||
});
|
||||
}
|
||||
|
||||
function bibRangeClearValidationUi(row) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields) return;
|
||||
|
||||
[fields.start, fields.qty, fields.end].forEach(function (el) {
|
||||
if (el) {
|
||||
el.classList.remove('bib-field--invalid');
|
||||
}
|
||||
});
|
||||
|
||||
if (fields.preview) {
|
||||
fields.preview.classList.remove('bib-range-preview--error');
|
||||
}
|
||||
}
|
||||
|
||||
/** MSIN-4429 — Validation différée (blur / OK), pas pendant la frappe. */
|
||||
function bibRangeValidate(row) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields) return null;
|
||||
|
||||
var start = bibRangeParseInt(fields.start && fields.start.value);
|
||||
if (start <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var pilot = row.dataset.rangePilot || '';
|
||||
if (!pilot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pilot === 'end') {
|
||||
var strEnd = String(fields.end && fields.end.value || '').trim();
|
||||
if (strEnd === '') {
|
||||
return null;
|
||||
}
|
||||
var end = bibRangeParseInt(strEnd);
|
||||
if (end <= 0) {
|
||||
return { key: 'incomplete', field: 'end' };
|
||||
}
|
||||
if (end < start) {
|
||||
return { key: 'invalidEnd', field: 'end', start: start };
|
||||
}
|
||||
}
|
||||
|
||||
if (pilot === 'qty') {
|
||||
var strQty = String(fields.qty && fields.qty.value || '').trim();
|
||||
if (strQty === '') {
|
||||
return null;
|
||||
}
|
||||
var qty = bibRangeParseInt(strQty);
|
||||
if (qty <= 0) {
|
||||
return { key: 'invalidQty', field: 'qty' };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function bibRangeValidationMessage(validation) {
|
||||
if (!validation) {
|
||||
return '';
|
||||
}
|
||||
if (validation.key === 'invalidEnd') {
|
||||
return bibJsFmt('jsRangeInvalidEnd', validation.start);
|
||||
}
|
||||
if (validation.key === 'invalidQty') {
|
||||
return bibJs('jsRangeInvalidQty');
|
||||
}
|
||||
if (validation.key === 'incomplete') {
|
||||
return bibJs('jsRangeIncomplete') || bibJs('jsFieldsRequired');
|
||||
}
|
||||
return bibJs('jsRangeInvalid') || bibJs('jsFieldsRequired');
|
||||
}
|
||||
|
||||
function bibRangeShowValidation(row, validation) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields || !fields.preview) {
|
||||
return;
|
||||
}
|
||||
|
||||
bibRangeClearValidationUi(row);
|
||||
|
||||
if (!validation) {
|
||||
bibRangeUpdatePreview(row);
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = bibRangeValidationMessage(validation);
|
||||
var target = validation.field === 'qty' ? fields.qty : fields.end;
|
||||
if (target) {
|
||||
target.classList.add('bib-field--invalid');
|
||||
}
|
||||
|
||||
fields.preview.textContent = msg;
|
||||
fields.preview.classList.remove('bib-ui-hidden');
|
||||
fields.preview.classList.add('bib-range-preview--error');
|
||||
}
|
||||
|
||||
function bibRangeValidateOnBlur(row) {
|
||||
applyBibRangeFieldState(row);
|
||||
bibRangeShowValidation(row, bibRangeValidate(row));
|
||||
}
|
||||
|
||||
function bibRangeUpdatePreview(row) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields || !fields.preview) return;
|
||||
|
||||
if (fields.preview.classList.contains('bib-range-preview--error')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var start = bibRangeParseInt(fields.start && fields.start.value);
|
||||
var end = bibRangeParseInt(fields.end && fields.end.value);
|
||||
var qty = bibRangeParseInt(fields.qty && fields.qty.value);
|
||||
|
||||
fields.preview.classList.remove('bib-range-preview--error');
|
||||
|
||||
if (start > 0 && end >= start && qty > 0) {
|
||||
fields.preview.textContent = bibJsFmt('jsRangePreview', start, end, qty);
|
||||
fields.preview.classList.remove('bib-ui-hidden');
|
||||
@ -2787,19 +2896,34 @@ if ($strLangue == 'fr') {
|
||||
row.dataset.rangeLastStart = String(bibRangeParseInt(fields.start.value));
|
||||
|
||||
fields.start.addEventListener('input', function () {
|
||||
bibRangeClearValidationUi(row);
|
||||
onBibRangeStartChange(row);
|
||||
});
|
||||
|
||||
fields.qty.addEventListener('input', function () {
|
||||
bibRangeClearValidationUi(row);
|
||||
row.dataset.rangePilot = 'qty';
|
||||
applyBibRangeFieldState(row);
|
||||
});
|
||||
|
||||
fields.end.addEventListener('input', function () {
|
||||
bibRangeClearValidationUi(row);
|
||||
row.dataset.rangePilot = 'end';
|
||||
applyBibRangeFieldState(row);
|
||||
});
|
||||
|
||||
fields.start.addEventListener('blur', function () {
|
||||
bibRangeValidateOnBlur(row);
|
||||
});
|
||||
|
||||
fields.qty.addEventListener('blur', function () {
|
||||
bibRangeValidateOnBlur(row);
|
||||
});
|
||||
|
||||
fields.end.addEventListener('blur', function () {
|
||||
bibRangeValidateOnBlur(row);
|
||||
});
|
||||
|
||||
fields.qty.addEventListener('click', function () {
|
||||
onBibRangeFieldPick(row, 'qty');
|
||||
});
|
||||
@ -3402,6 +3526,7 @@ if ($strLangue == 'fr') {
|
||||
let start = bibRangeParseInt(row.querySelector('.bib-start').value);
|
||||
let end = bibRangeParseInt(row.querySelector('.bib-end').value);
|
||||
let id = btnSave.dataset.id;
|
||||
let validation = bibRangeValidate(row);
|
||||
|
||||
// ligne temporaire vide = on la retire
|
||||
if (id == 0 && start <= 0) {
|
||||
@ -3413,18 +3538,25 @@ if ($strLangue == 'fr') {
|
||||
}
|
||||
|
||||
if (start <= 0 || end <= 0) {
|
||||
if (errorDiv) {
|
||||
errorDiv.innerText = bibJs('jsRangeIncomplete') || bibJs('jsFieldsRequired');
|
||||
errorDiv.style.display = 'block';
|
||||
}
|
||||
return;
|
||||
validation = validation || { key: 'incomplete' };
|
||||
}
|
||||
|
||||
if (end < start) {
|
||||
if (!validation && end < start) {
|
||||
validation = { key: 'invalidEnd', field: 'end', start: start };
|
||||
}
|
||||
|
||||
if (validation) {
|
||||
bibRangeShowValidation(row, validation);
|
||||
if (errorDiv) {
|
||||
errorDiv.innerText = bibJs('jsRangeInvalid') || bibJs('jsFieldsRequired');
|
||||
errorDiv.innerText = bibRangeValidationMessage(validation);
|
||||
errorDiv.style.display = 'block';
|
||||
}
|
||||
var invalidField = validation.field === 'qty'
|
||||
? row.querySelector('.bib-qty')
|
||||
: row.querySelector('.bib-end');
|
||||
if (invalidField) {
|
||||
invalidField.focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -3106,6 +3106,8 @@ function fxBibModuleJsDataAttrs() {
|
||||
'range-invalid' => 'bib_v4_js_range_invalid',
|
||||
'range-preview' => 'bib_v4_js_range_preview',
|
||||
'range-pick-hint' => 'bib_v4_js_range_pick_hint',
|
||||
'range-invalid-end' => 'bib_v4_js_range_invalid_end',
|
||||
'range-invalid-qty' => 'bib_v4_js_range_invalid_qty',
|
||||
];
|
||||
$html = '';
|
||||
foreach ($map as $attr => $clef) {
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
* Constantes *
|
||||
*
|
||||
**************/
|
||||
define('_VERSION_CODE', '4.72.730');
|
||||
define('_VERSION_CODE', '4.72.731');
|
||||
define('_DATE_CODE', '2026-07-07');
|
||||
//MSIN-4290
|
||||
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');
|
||||
|
||||
@ -72,3 +72,19 @@ FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_rang
|
||||
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
|
||||
SELECT 'bib_v4_js_range_pick_hint', 'en', 'Click Qty or End to choose which value to enter.', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_range_pick_hint' AND info_langue = 'en' AND info_prg = 'compte.php');
|
||||
|
||||
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
|
||||
SELECT 'bib_v4_js_range_invalid_end', 'fr', 'La fin doit être supérieure ou égale au début (%d).', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_range_invalid_end' AND info_langue = 'fr' AND info_prg = 'compte.php');
|
||||
|
||||
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
|
||||
SELECT 'bib_v4_js_range_invalid_end', 'en', 'End must be greater than or equal to start (%d).', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_range_invalid_end' AND info_langue = 'en' AND info_prg = 'compte.php');
|
||||
|
||||
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
|
||||
SELECT 'bib_v4_js_range_invalid_qty', 'fr', 'La quantité doit être d''au moins 1.', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_range_invalid_qty' AND info_langue = 'fr' AND info_prg = 'compte.php');
|
||||
|
||||
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation)
|
||||
SELECT 'bib_v4_js_range_invalid_qty', 'en', 'Quantity must be at least 1.', '', 'compte.php', '', 0, 1, '', '', '', NOW()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM info WHERE info_clef = 'bib_v4_js_range_invalid_qty' AND info_langue = 'en' AND info_prg = 'compte.php');
|
||||
|
||||
Reference in New Issue
Block a user