MSIN-4429 Implement range input functionality for quantity and end values in bib management
This commit introduces new JavaScript functions and PHP methods to enhance the handling of range inputs for quantity and end values in the bib management system. It includes the addition of input fields for quantity and end values, along with logic to manage their states based on user interaction. The CSS is updated to support the new layout and visual states for these fields. Additionally, data attributes are added to improve the handling of range validation and preview functionality. These changes aim to improve user experience and data integrity in the bib input process.
This commit is contained in:
@ -1961,13 +1961,14 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
}
|
||||
|
||||
/* MSIN-4379 — Cadenas + view/OK/stats ; badge auto à droite. */
|
||||
/* MSIN-4429 — colonne Début + bloc Qté/ou/Fin. */
|
||||
.epr-line{
|
||||
display:grid;
|
||||
grid-template-columns:
|
||||
40px
|
||||
40px
|
||||
58px
|
||||
58px
|
||||
minmax(148px, 1fr)
|
||||
44px
|
||||
48px
|
||||
auto
|
||||
@ -1983,7 +1984,7 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
40px
|
||||
40px
|
||||
58px
|
||||
58px
|
||||
minmax(148px, 1fr)
|
||||
44px
|
||||
48px
|
||||
auto
|
||||
@ -2039,10 +2040,86 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
}
|
||||
|
||||
.bib-range--locked .bib-start,
|
||||
.bib-range--locked .bib-qty,
|
||||
.bib-range--locked .bib-end{
|
||||
background-color:#f1f3f5;
|
||||
}
|
||||
|
||||
/* MSIN-4429 — Qté / ou / Fin : pilote actif vs champ calculé / choix. */
|
||||
.epr-col-range-spec,
|
||||
.bib-range-spec{
|
||||
display:grid;
|
||||
grid-template-columns:minmax(0, 1fr) auto minmax(0, 1fr);
|
||||
gap:6px;
|
||||
align-items:center;
|
||||
min-width:0;
|
||||
}
|
||||
|
||||
.epr-line-header .epr-col-range-spec{
|
||||
min-width:0;
|
||||
}
|
||||
|
||||
.epr-line-header .epr-col-range-spec > div{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
min-width:0;
|
||||
}
|
||||
|
||||
.bib-range-or{
|
||||
color:#6c757d;
|
||||
font-size:11px;
|
||||
font-weight:600;
|
||||
text-transform:lowercase;
|
||||
white-space:nowrap;
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
.bib-range-or--header{
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.bib-range-preview{
|
||||
grid-column:1 / -1;
|
||||
margin:-2px 0 2px;
|
||||
font-size:12px;
|
||||
line-height:1.3;
|
||||
}
|
||||
|
||||
.epr-line .bib-start,
|
||||
.epr-line .bib-qty,
|
||||
.epr-line .bib-end{
|
||||
width:100%;
|
||||
min-width:0;
|
||||
padding-left:4px;
|
||||
padding-right:4px;
|
||||
}
|
||||
|
||||
.bib-field--idle,
|
||||
.bib-field--pick,
|
||||
.bib-field--calc{
|
||||
background-color:#eef1f4;
|
||||
color:#6c757d;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.bib-field--idle{
|
||||
cursor:not-allowed;
|
||||
opacity:.85;
|
||||
}
|
||||
|
||||
.bib-field--active{
|
||||
background-color:#fff;
|
||||
color:inherit;
|
||||
cursor:text;
|
||||
}
|
||||
|
||||
.bib-field--pick:focus,
|
||||
.bib-field--calc:focus{
|
||||
outline:none;
|
||||
box-shadow:none;
|
||||
}
|
||||
|
||||
.epr-col-stats{
|
||||
display:grid;
|
||||
grid-template-columns:56px 48px 48px;
|
||||
@ -2067,14 +2144,6 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
min-width:0;
|
||||
}
|
||||
|
||||
.epr-line .bib-start,
|
||||
.epr-line .bib-end{
|
||||
width:100%;
|
||||
min-width:0;
|
||||
padding-left:4px;
|
||||
padding-right:4px;
|
||||
}
|
||||
|
||||
.epr-add-range-row{
|
||||
margin-top:6px;
|
||||
}
|
||||
@ -2217,6 +2286,7 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
}
|
||||
|
||||
.epr-row.auto-mode .bib-start,
|
||||
.epr-row.auto-mode .bib-qty,
|
||||
.epr-row.auto-mode .bib-end {
|
||||
pointer-events: none;
|
||||
background: #eee;
|
||||
@ -2232,6 +2302,7 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
}
|
||||
|
||||
.epr-row.batch-mode .bib-start,
|
||||
.epr-row.batch-mode .bib-qty,
|
||||
.epr-row.batch-mode .bib-end {
|
||||
pointer-events: none;
|
||||
background: #eee;
|
||||
|
||||
@ -2613,17 +2613,227 @@ if ($strLangue == 'fr') {
|
||||
}
|
||||
if (container) {
|
||||
initModuleBibTippy(row);
|
||||
initBibRangeRows(container);
|
||||
}
|
||||
syncBibUiState(row);
|
||||
refreshBibAnomaliesPanel();
|
||||
return container;
|
||||
}
|
||||
|
||||
// MSIN-4429 — Séquence : Début puis Qté ou Fin (pilote / calculé).
|
||||
function bibRangeParseInt(val) {
|
||||
var n = parseInt(String(val || '').trim(), 10);
|
||||
return isNaN(n) ? 0 : n;
|
||||
}
|
||||
|
||||
function bibRangeGetFields(row) {
|
||||
if (!row) return null;
|
||||
return {
|
||||
start: row.querySelector('.bib-start'),
|
||||
qty: row.querySelector('.bib-qty'),
|
||||
end: row.querySelector('.bib-end'),
|
||||
preview: row.querySelector('.bib-range-preview')
|
||||
};
|
||||
}
|
||||
|
||||
function bibRangeClearFieldClasses(row) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields) return;
|
||||
[fields.start, fields.qty, fields.end].forEach(function (el) {
|
||||
if (!el) return;
|
||||
el.classList.remove('bib-field--idle', 'bib-field--pick', 'bib-field--calc', 'bib-field--active');
|
||||
});
|
||||
}
|
||||
|
||||
function bibRangeUpdatePreview(row) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields || !fields.preview) 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);
|
||||
|
||||
if (start > 0 && end >= start && qty > 0) {
|
||||
fields.preview.textContent = bibJsFmt('jsRangePreview', start, end, qty);
|
||||
fields.preview.classList.remove('bib-ui-hidden');
|
||||
} else if (!row.dataset.rangePilot && bibJs('jsRangePickHint')) {
|
||||
var startVal = bibRangeParseInt(fields.start && fields.start.value);
|
||||
if (startVal > 0) {
|
||||
fields.preview.textContent = bibJs('jsRangePickHint');
|
||||
fields.preview.classList.remove('bib-ui-hidden');
|
||||
} else {
|
||||
fields.preview.textContent = '';
|
||||
fields.preview.classList.add('bib-ui-hidden');
|
||||
}
|
||||
} else {
|
||||
fields.preview.textContent = '';
|
||||
fields.preview.classList.add('bib-ui-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function applyBibRangeFieldState(row) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields || !fields.start || !fields.qty || !fields.end) return;
|
||||
|
||||
if (row.dataset.locked === '1') {
|
||||
bibRangeClearFieldClasses(row);
|
||||
bibRangeUpdatePreview(row);
|
||||
return;
|
||||
}
|
||||
|
||||
var start = bibRangeParseInt(fields.start.value);
|
||||
var pilot = row.dataset.rangePilot || '';
|
||||
|
||||
bibRangeClearFieldClasses(row);
|
||||
|
||||
if (start <= 0) {
|
||||
fields.qty.classList.add('bib-field--idle');
|
||||
fields.end.classList.add('bib-field--idle');
|
||||
fields.qty.readOnly = true;
|
||||
fields.end.readOnly = true;
|
||||
fields.qty.value = '';
|
||||
fields.end.value = '';
|
||||
row.dataset.rangePilot = '';
|
||||
bibRangeUpdatePreview(row);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pilot) {
|
||||
fields.qty.classList.add('bib-field--pick');
|
||||
fields.end.classList.add('bib-field--pick');
|
||||
fields.qty.readOnly = true;
|
||||
fields.end.readOnly = true;
|
||||
bibRangeUpdatePreview(row);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pilot === 'qty') {
|
||||
var qty = bibRangeParseInt(fields.qty.value);
|
||||
fields.qty.classList.add('bib-field--active');
|
||||
fields.end.classList.add('bib-field--calc');
|
||||
fields.qty.readOnly = false;
|
||||
fields.end.readOnly = true;
|
||||
if (qty > 0) {
|
||||
fields.end.value = String(start + qty - 1);
|
||||
} else {
|
||||
fields.end.value = '';
|
||||
}
|
||||
} else if (pilot === 'end') {
|
||||
var end = bibRangeParseInt(fields.end.value);
|
||||
fields.end.classList.add('bib-field--active');
|
||||
fields.qty.classList.add('bib-field--calc');
|
||||
fields.end.readOnly = false;
|
||||
fields.qty.readOnly = true;
|
||||
if (end >= start) {
|
||||
fields.qty.value = String(end - start + 1);
|
||||
} else {
|
||||
fields.qty.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
bibRangeUpdatePreview(row);
|
||||
}
|
||||
|
||||
function onBibRangeFieldPick(row, pilot) {
|
||||
if (!row || row.dataset.locked === '1') return;
|
||||
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields || !fields.start) return;
|
||||
|
||||
if (bibRangeParseInt(fields.start.value) <= 0) {
|
||||
fields.start.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
row.dataset.rangePilot = pilot;
|
||||
applyBibRangeFieldState(row);
|
||||
|
||||
var target = pilot === 'qty' ? fields.qty : fields.end;
|
||||
if (target) {
|
||||
target.focus();
|
||||
target.select();
|
||||
}
|
||||
}
|
||||
|
||||
function onBibRangeStartChange(row) {
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields || !fields.start) return;
|
||||
|
||||
var start = bibRangeParseInt(fields.start.value);
|
||||
var lastStart = bibRangeParseInt(row.dataset.rangeLastStart || '0');
|
||||
|
||||
if (start !== lastStart && !row.dataset.rangePilot) {
|
||||
fields.qty.value = '';
|
||||
fields.end.value = '';
|
||||
row.dataset.hasValues = '0';
|
||||
}
|
||||
|
||||
row.dataset.rangeLastStart = String(start);
|
||||
|
||||
if (start <= 0) {
|
||||
row.dataset.rangePilot = '';
|
||||
}
|
||||
|
||||
applyBibRangeFieldState(row);
|
||||
}
|
||||
|
||||
function bindBibRangeRow(row) {
|
||||
if (!row || row.dataset.bibRangeBound === '1') return;
|
||||
row.dataset.bibRangeBound = '1';
|
||||
|
||||
var fields = bibRangeGetFields(row);
|
||||
if (!fields || !fields.start || !fields.qty || !fields.end) return;
|
||||
|
||||
row.dataset.rangeLastStart = String(bibRangeParseInt(fields.start.value));
|
||||
|
||||
fields.start.addEventListener('input', function () {
|
||||
onBibRangeStartChange(row);
|
||||
});
|
||||
|
||||
fields.qty.addEventListener('input', function () {
|
||||
row.dataset.rangePilot = 'qty';
|
||||
applyBibRangeFieldState(row);
|
||||
});
|
||||
|
||||
fields.end.addEventListener('input', function () {
|
||||
row.dataset.rangePilot = 'end';
|
||||
applyBibRangeFieldState(row);
|
||||
});
|
||||
|
||||
fields.qty.addEventListener('click', function () {
|
||||
onBibRangeFieldPick(row, 'qty');
|
||||
});
|
||||
|
||||
fields.end.addEventListener('click', function () {
|
||||
onBibRangeFieldPick(row, 'end');
|
||||
});
|
||||
|
||||
fields.qty.addEventListener('focus', function () {
|
||||
onBibRangeFieldPick(row, 'qty');
|
||||
});
|
||||
|
||||
fields.end.addEventListener('focus', function () {
|
||||
onBibRangeFieldPick(row, 'end');
|
||||
});
|
||||
|
||||
applyBibRangeFieldState(row);
|
||||
|
||||
if (row.dataset.id === '0' && !fields.start.value) {
|
||||
fields.start.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function initBibRangeRows(root) {
|
||||
if (!root) return;
|
||||
root.querySelectorAll('.bib-range').forEach(bindBibRangeRow);
|
||||
}
|
||||
|
||||
function bibCsrfToken() {
|
||||
return moduleBib ? (moduleBib.dataset.csrfToken || '') : '';
|
||||
}
|
||||
|
||||
initModuleBibTippy(moduleBib);
|
||||
initBibRangeRows(moduleBib);
|
||||
|
||||
// ============================================================
|
||||
// MSIN-4379 — Étape 2 : assignation automatique (interface JS)
|
||||
@ -2676,7 +2886,7 @@ if ($strLangue == 'fr') {
|
||||
container.classList.remove('batch-mode');
|
||||
}
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.removeAttribute('readonly');
|
||||
});
|
||||
|
||||
@ -2720,7 +2930,7 @@ if ($strLangue == 'fr') {
|
||||
container.classList.add('batch-mode');
|
||||
}
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
@ -2747,7 +2957,7 @@ if ($strLangue == 'fr') {
|
||||
|
||||
bibContainer.classList.add('batch-mode');
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
@ -2990,7 +3200,7 @@ if ($strLangue == 'fr') {
|
||||
container.classList.add('batch-mode');
|
||||
|
||||
// 5. remettre readonly
|
||||
container.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
container.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
@ -3187,20 +3397,34 @@ if ($strLangue == 'fr') {
|
||||
errorDiv.innerText = '';
|
||||
}
|
||||
|
||||
let start = row.querySelector('.bib-start').value;
|
||||
let end = row.querySelector('.bib-end').value;
|
||||
applyBibRangeFieldState(row);
|
||||
|
||||
let start = bibRangeParseInt(row.querySelector('.bib-start').value);
|
||||
let end = bibRangeParseInt(row.querySelector('.bib-end').value);
|
||||
let id = btnSave.dataset.id;
|
||||
|
||||
// ligne temporaire vide = on la retire
|
||||
if (id == 0 && (!start || !end)) {
|
||||
if (id == 0 && start <= 0) {
|
||||
row.remove();
|
||||
if (errorDiv) errorDiv.remove();
|
||||
if (errorDiv && errorDiv.classList.contains('bib-error')) {
|
||||
errorDiv.remove();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!start || !end) {
|
||||
errorDiv.innerText = bibJs('jsFieldsRequired');
|
||||
errorDiv.style.display = 'block';
|
||||
if (start <= 0 || end <= 0) {
|
||||
if (errorDiv) {
|
||||
errorDiv.innerText = bibJs('jsRangeIncomplete') || bibJs('jsFieldsRequired');
|
||||
errorDiv.style.display = 'block';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (end < start) {
|
||||
if (errorDiv) {
|
||||
errorDiv.innerText = bibJs('jsRangeInvalid') || bibJs('jsFieldsRequired');
|
||||
errorDiv.style.display = 'block';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3367,7 +3591,7 @@ if ($strLangue == 'fr') {
|
||||
});
|
||||
container.classList.remove('batch-mode');
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.removeAttribute('readonly');
|
||||
});
|
||||
|
||||
@ -3390,7 +3614,7 @@ if ($strLangue == 'fr') {
|
||||
row.classList.add('batch-mode');
|
||||
container.classList.add('batch-mode');
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
@ -3491,7 +3715,7 @@ if ($strLangue == 'fr') {
|
||||
btnReset.textContent = row.dataset.resetLabel || btnReset.textContent;
|
||||
container.classList.remove('batch-mode');
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.removeAttribute('readonly');
|
||||
});
|
||||
|
||||
@ -3521,7 +3745,7 @@ if ($strLangue == 'fr') {
|
||||
row.dataset.mode = 'reset';
|
||||
container.classList.add('batch-mode');
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
@ -3553,7 +3777,7 @@ if ($strLangue == 'fr') {
|
||||
|
||||
container.classList.add('batch-mode');
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.setAttribute('readonly', true);
|
||||
});
|
||||
|
||||
@ -3642,7 +3866,7 @@ if ($strLangue == 'fr') {
|
||||
btnBatch.textContent = row.dataset.batchLabel || btnBatch.textContent;
|
||||
}
|
||||
|
||||
row.querySelectorAll('.bib-start, .bib-end').forEach(input => {
|
||||
row.querySelectorAll('.bib-start, .bib-qty, .bib-end').forEach(input => {
|
||||
input.removeAttribute('readonly');
|
||||
});
|
||||
|
||||
|
||||
@ -3102,6 +3102,10 @@ function fxBibModuleJsDataAttrs() {
|
||||
'lock-confirm' => 'bib_v4_js_lock_confirm',
|
||||
'unlock-confirm' => 'bib_v4_js_unlock_confirm',
|
||||
'auto-pending-bibs' => 'bib_v4_js_auto_pending_bibs',
|
||||
'range-incomplete' => 'bib_v4_js_range_incomplete',
|
||||
'range-invalid' => 'bib_v4_js_range_invalid',
|
||||
'range-preview' => 'bib_v4_js_range_preview',
|
||||
'range-pick-hint' => 'bib_v4_js_range_pick_hint',
|
||||
];
|
||||
$html = '';
|
||||
foreach ($map as $attr => $clef) {
|
||||
@ -3625,6 +3629,59 @@ function renderBibAddRangeButton($epr_id) {
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4429 — Bloc Qté / ou / Fin (saisie pilote + champ calculé).
|
||||
*
|
||||
* @return array{qty:int|string,start:int,end:int,has_values:bool}
|
||||
*/
|
||||
function fxBibRangeSpecValues(array $range) {
|
||||
$intStart = (int)($range['epr_bib_start'] ?? 0);
|
||||
$intEnd = (int)($range['epr_bib_finish'] ?? 0);
|
||||
$intId = (int)($range['epr_bib_id'] ?? 0);
|
||||
$intQty = '';
|
||||
|
||||
if ($intStart > 0 && $intEnd >= $intStart) {
|
||||
$intQty = $intEnd - $intStart + 1;
|
||||
}
|
||||
|
||||
return [
|
||||
'qty' => $intQty,
|
||||
'start' => $intStart,
|
||||
'end' => $intEnd,
|
||||
'has_values' => ($intId > 0 && $intStart > 0 && $intEnd >= $intStart),
|
||||
];
|
||||
}
|
||||
|
||||
/** MSIN-4429 — Inputs quantité + fin avec séparateur « ou ». */
|
||||
function fxBibRenderRangeQtyEndInputs(array $range, $blnRangeLocked) {
|
||||
$tabSpec = fxBibRangeSpecValues($range);
|
||||
$strQty = ($tabSpec['qty'] !== '') ? (int)$tabSpec['qty'] : '';
|
||||
$strEnd = ($tabSpec['end'] > 0) ? (int)$tabSpec['end'] : '';
|
||||
$strReadonly = $blnRangeLocked ? 'readonly' : '';
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="bib-range-spec">
|
||||
<input type="number"
|
||||
class="form-control form-control-sm bib-qty"
|
||||
min="1"
|
||||
value="<?php echo $strQty; ?>"
|
||||
placeholder="<?php echo fxBibEsc(fxBibTexte('bib_v4_range_qty_ph', 0)); ?>"
|
||||
<?php echo $strReadonly; ?>
|
||||
<?php echo fxBibAideTippyAttr('bib_v4_col_qty'); ?>>
|
||||
<span class="bib-range-or" aria-hidden="true"><?php fxBibTexte('bib_v4_range_or', 1); ?></span>
|
||||
<input type="number"
|
||||
class="form-control form-control-sm bib-end"
|
||||
min="1"
|
||||
value="<?php echo $strEnd; ?>"
|
||||
placeholder="<?php echo fxBibEsc(fxBibTexte('bib_v4_range_end_ph', 0)); ?>"
|
||||
<?php echo $strReadonly; ?>
|
||||
<?php echo fxBibAideTippyAttr('bib_v4_col_end'); ?>>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/** En-tête colonnes séquences — répété par épreuve, inclus dans renderBibRanges (y compris AJAX). */
|
||||
function renderBibRangeHeader() {
|
||||
ob_start();
|
||||
@ -3633,7 +3690,11 @@ function renderBibRangeHeader() {
|
||||
<div class="epr-col-lock"><?php echo fxBibColHeader('bib_v4_col_lock'); ?></div>
|
||||
<div><?php echo fxBibColHeader('bib_v4_col_view'); ?></div>
|
||||
<div><?php echo fxBibColHeader('bib_v4_col_start'); ?></div>
|
||||
<div><?php echo fxBibColHeader('bib_v4_col_end'); ?></div>
|
||||
<div class="epr-col-range-spec">
|
||||
<div><?php echo fxBibColHeader('bib_v4_col_qty'); ?></div>
|
||||
<div class="bib-range-or bib-range-or--header" aria-hidden="true"><?php fxBibTexte('bib_v4_range_or', 1); ?></div>
|
||||
<div><?php echo fxBibColHeader('bib_v4_col_end'); ?></div>
|
||||
</div>
|
||||
<div><?php echo fxBibColHeader('bib_v4_col_ok'); ?></div>
|
||||
<div><?php echo fxBibColHeader('bib_v4_col_del'); ?></div>
|
||||
<div class="epr-col-stats">
|
||||
@ -5143,13 +5204,15 @@ $nb_utilises = (int)($range['nb_utilises'] ?? 0);
|
||||
$mem_dispo = max(0, $nb_total - $nb_utilises);
|
||||
|
||||
$blnRangeLocked = fxBibRangeIsLocked($range);
|
||||
$tabSpec = fxBibRangeSpecValues($range);
|
||||
|
||||
|
||||
?>
|
||||
|
||||
<div class="bib-range epr-line<?php echo $blnRangeLocked ? ' bib-range--locked' : ''; ?>"
|
||||
data-id="<?php echo $range['epr_bib_id']; ?>"
|
||||
data-locked="<?php echo $blnRangeLocked ? '1' : '0'; ?>">
|
||||
data-locked="<?php echo $blnRangeLocked ? '1' : '0'; ?>"
|
||||
data-has-values="<?php echo $tabSpec['has_values'] ? '1' : '0'; ?>">
|
||||
|
||||
<?php echo fxBibRenderRangeLockButton($range, $epr_id); ?>
|
||||
|
||||
@ -5166,13 +5229,13 @@ $blnRangeLocked = fxBibRangeIsLocked($range);
|
||||
|
||||
<input type="number"
|
||||
class="form-control form-control-sm bib-start"
|
||||
min="1"
|
||||
value="<?php echo $range['epr_bib_start']; ?>"
|
||||
<?php echo $blnRangeLocked ? 'readonly' : ''; ?>>
|
||||
placeholder="<?php echo fxBibEsc(fxBibTexte('bib_v4_range_start_ph', 0)); ?>"
|
||||
<?php echo $blnRangeLocked ? 'readonly' : ''; ?>
|
||||
<?php echo fxBibAideTippyAttr('bib_v4_col_start'); ?>>
|
||||
|
||||
<input type="number"
|
||||
class="form-control form-control-sm bib-end"
|
||||
value="<?php echo $range['epr_bib_finish']; ?>"
|
||||
<?php echo $blnRangeLocked ? 'readonly' : ''; ?>>
|
||||
<?php echo fxBibRenderRangeQtyEndInputs($range, $blnRangeLocked); ?>
|
||||
|
||||
<?php echo fxBibBtnAideSegmentOpen(); ?>
|
||||
<button type="button"
|
||||
@ -5245,6 +5308,8 @@ if (!$blnRangeLocked && (
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bib-range-preview text-muted small bib-ui-hidden" aria-live="polite"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="bib-error text-danger small mb-2" style="<?php echo (!empty($range['liste_trous']) || !empty($range['liste_doublons'])) ? 'display:block;' : 'display:none;'; ?>">
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
* Constantes *
|
||||
*
|
||||
**************/
|
||||
define('_VERSION_CODE', '4.72.727');
|
||||
define('_DATE_CODE', '2026-07-03');
|
||||
define('_VERSION_CODE', '4.72.728');
|
||||
define('_DATE_CODE', '2026-07-07');
|
||||
//MSIN-4290
|
||||
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');
|
||||
// Outil temporaire ms1_kc_set.php — modifier key_chain_http (lien /kc/{pk}/)
|
||||
|
||||
1
sql/MSIN-4429-bib-range-qty.sql
Normal file
1
sql/MSIN-4429-bib-range-qty.sql
Normal file
@ -0,0 +1 @@
|
||||
MSIN-4429
|
||||
Reference in New Issue
Block a user