fixed column imballaggi

This commit is contained in:
Claudio Sironi
2026-10-30 16:17:19 +01:00
parent 60a4d427aa
commit 6f01180a2d
+217 -39
View File
@@ -68,41 +68,50 @@
vertical-align: middle;
}
/* Column widths */
#tabPackaging th:nth-child(1),
#tabPackaging td:nth-child(1) {
width: 60px;
max-width: 60px;
/* Ridimensionamento colonne: le larghezze stanno nel <colgroup> */
#tabPackaging thead th {
position: relative;
}
#tabPackaging th:nth-child(2),
#tabPackaging td:nth-child(2) {
width: 170px;
max-width: 170px;
.pkcol-grip {
position: absolute;
top: 0;
right: 0;
width: 14px;
height: 100%;
cursor: col-resize;
z-index: 6;
touch-action: none;
}
#tabPackaging th:nth-child(4),
#tabPackaging td:nth-child(4) {
width: 140px;
max-width: 140px;
.pkcol-grip::after {
content: "";
position: absolute;
top: 22%;
bottom: 22%;
right: 0;
width: 3px;
border-radius: 2px;
background: #8fb3e3;
}
#tabPackaging th:nth-child(5),
#tabPackaging td:nth-child(5) {
width: 110px;
max-width: 110px;
.pkcol-grip:hover::after,
.pkcol-grip.pkcol-active::after {
background: #0d6efd;
}
#tabPackaging th:nth-child(6),
#tabPackaging td:nth-child(6) {
width: 120px;
max-width: 120px;
body.pkcol-dragging,
body.pkcol-dragging * {
cursor: col-resize !important;
user-select: none !important;
}
#tabPackaging th:nth-child(7),
#tabPackaging td:nth-child(7) {
width: 420px;
max-width: 420px;
/* Pulsanti azione solo icona */
.pk-act {
min-width: 40px;
padding: 4px 8px;
font-size: 1.05rem;
line-height: 1.2;
}
.back-dashboard {
@@ -166,6 +175,7 @@
<option value="OTHER">Altro</option>
</select>
</div>
<button type="button" class="btn btn-sm btn-outline-secondary" id="pkColReset" title="Riporta le colonne alla larghezza iniziale">↔ Colonne predefinite</button>
</div>
<?php
@@ -229,6 +239,16 @@
<div class="table-responsive">
<table id="tabPackaging" class="table table-striped align-middle text-center" style="width:100%;">
<!-- Larghezze iniziali: la colonna senza width (Nome) prende lo spazio che resta -->
<colgroup>
<col data-w="60" style="width:60px">
<col data-w="150" style="width:150px">
<col data-flex="1">
<col data-w="220" style="width:220px">
<col data-w="120" style="width:120px">
<col data-w="110" style="width:110px">
<col data-w="230" data-min="210" style="width:230px">
</colgroup>
<thead>
<tr>
<th>ID</th>
@@ -259,7 +279,8 @@
? "<span class='badge bg-success'>Attivo</span>"
: "<span class='badge bg-secondary'>Inattivo</span>";
$toggleText = $isActive ? "Disattiva" : "Attiva";
$toggleClass = $isActive ? "btn-outline-warning" : "btn-outline-success";
$toggleClass = $isActive ? "btn-outline-danger" : "btn-outline-success";
$toggleIcon = $isActive ? "🚫" : "✅";
$qtyTot = number_format((float)$r['qty_totale'], 3, ',', '.');
$trClass = $isActive ? "" : " class='inactive-item'";
@@ -272,23 +293,19 @@
<td><span class='qty-badge'>{$qtyTot}</span></td>
<td>{$badge}</td>
<td>
<button class='btn btn-sm btn-outline-primary edit-item'
<button class='btn btn-sm btn-outline-primary pk-act edit-item'
title='Modifica' aria-label='Modifica'
data-id='{$r['id']}'
data-category='" . htmlspecialchars($r['category'], ENT_QUOTES) . "'
data-name='" . htmlspecialchars($r['item_name'], ENT_QUOTES) . "'
data-code='" . htmlspecialchars($r['item_code'], ENT_QUOTES) . "'>
✏️ Modifica
</button>
<button class='btn btn-sm btn-outline-dark manage-stock'
data-code='" . htmlspecialchars($r['item_code'], ENT_QUOTES) . "'>✏️</button>
<button class='btn btn-sm btn-outline-dark pk-act manage-stock'
title='Stock' aria-label='Stock'
data-id='{$r['id']}'
data-name='" . htmlspecialchars($r['item_name'], ENT_QUOTES) . "'>
📦 Stock
</button>
<button class='btn btn-sm {$toggleClass} toggle-item'
data-id='{$r['id']}'>
🔁 {$toggleText}
</button>
data-name='" . htmlspecialchars($r['item_name'], ENT_QUOTES) . "'>📦 Stock</button>
<button class='btn btn-sm {$toggleClass} pk-act toggle-item'
title='{$toggleText}' aria-label='{$toggleText}'
data-id='{$r['id']}'>{$toggleIcon}</button>
</td>
</tr>";
}
@@ -454,6 +471,7 @@
<script>
let dt;
let pkCols = null;
function refreshUrlParams() {
const url = new URL(window.location.href);
@@ -534,6 +552,153 @@
});
}
// ===== Colonne ridimensionabili =====
// Le larghezze stanno nel <colgroup>. La colonna "flex" (Nome) assorbe le differenze,
// quindi la tabella resta sempre larga quanto lo schermo e Azioni non esce mai.
// Trascinando un bordo, lo spazio si sposta tra le due colonne vicine.
function pkColResize(tableId) {
var table = document.getElementById(tableId);
if (!table) return null;
var KEY = 'zibo_pkcols_' + tableId;
var FLEX_MIN = 120;
var cols = Array.prototype.slice.call(table.querySelectorAll('colgroup col'));
var ths = Array.prototype.slice.call(table.querySelectorAll('thead tr:first-child th'));
var defaults = cols.map(function(c) {
return c.hasAttribute('data-flex') ? null : parseInt(c.getAttribute('data-w'), 10);
});
var justDragged = false;
function isFlex(i) {
return cols[i].hasAttribute('data-flex');
}
function minOf(i) {
if (isFlex(i)) return FLEX_MIN;
return parseInt(cols[i].getAttribute('data-min') || '50', 10);
}
function setW(i, w) {
if (!isFlex(i)) cols[i].style.width = Math.round(w) + 'px';
}
function realW(i) {
return ths[i].getBoundingClientRect().width;
}
function apply(widths) {
widths.forEach(function(w, i) {
if (w !== null) setW(i, w);
});
}
function current() {
return cols.map(function(c, i) {
return isFlex(i) ? null : parseInt(c.style.width, 10);
});
}
function save() {
try {
localStorage.setItem(KEY, JSON.stringify(current()));
} catch (e) {}
}
function reset() {
apply(defaults);
try {
localStorage.removeItem(KEY);
} catch (e) {}
}
// Ripristino: solo se le colonne salvate stanno nello schermo attuale
try {
var saved = JSON.parse(localStorage.getItem(KEY) || 'null');
if (Array.isArray(saved) && saved.length === cols.length) {
var sum = saved.reduce(function(a, b) {
return a + (b || 0);
}, 0);
if (sum + FLEX_MIN <= table.parentNode.clientWidth) apply(saved);
}
} catch (e) {}
ths.forEach(function(th, i) {
if (i === ths.length - 1) return; // ultima colonna: nessun bordo a destra
var grip = document.createElement('span');
grip.className = 'pkcol-grip';
grip.title = 'Trascina per allargare o stringere';
th.appendChild(grip);
grip.addEventListener('pointerdown', function(e) {
if (e.button !== undefined && e.button !== 0) return;
e.preventDefault();
e.stopPropagation();
var j = i + 1;
var startX = e.clientX;
var a0 = realW(i);
var b0 = realW(j);
var lo = minOf(i) - a0; // spostamento minimo (negativo)
var hi = b0 - minOf(j); // spostamento massimo
if (hi < 0) hi = 0;
if (lo > 0) lo = 0;
// fissa le due colonne alla larghezza reale attuale
setW(i, a0);
setW(j, b0);
try {
grip.setPointerCapture(e.pointerId);
} catch (err) {}
grip.classList.add('pkcol-active');
document.body.classList.add('pkcol-dragging');
function onMove(ev) {
var d = ev.clientX - startX;
if (d < lo) d = lo;
if (d > hi) d = hi;
setW(i, a0 + d);
setW(j, b0 - d);
}
function onUp() {
grip.removeEventListener('pointermove', onMove);
grip.removeEventListener('pointerup', onUp);
grip.removeEventListener('pointercancel', onUp);
grip.classList.remove('pkcol-active');
document.body.classList.remove('pkcol-dragging');
justDragged = true;
setTimeout(function() {
justDragged = false;
}, 300);
save();
}
grip.addEventListener('pointermove', onMove);
grip.addEventListener('pointerup', onUp);
grip.addEventListener('pointercancel', onUp);
});
grip.addEventListener('dblclick', function(e) {
e.stopPropagation();
reset();
});
});
// Il trascinamento non deve far partire l'ordinamento di DataTables
table.querySelector('thead').addEventListener('click', function(e) {
if (justDragged || (e.target.classList && e.target.classList.contains('pkcol-grip'))) {
e.stopPropagation();
e.preventDefault();
}
}, true);
return {
reset: reset
};
}
$(document).ready(function() {
// Init filters from URL
const urlParams = new URLSearchParams(window.location.search);
@@ -545,11 +710,24 @@
[2, 'asc']
],
pageLength: 50,
autoWidth: false,
columnDefs: [{
targets: -1,
orderable: false
}],
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json'
},
initComplete: function() {
// dopo che DataTables ha costruito le intestazioni
pkCols = pkColResize('tabPackaging');
}
});
$('#pkColReset').on('click', function() {
if (pkCols) pkCols.reset();
});
$('#filterActive, #filterCategory').on('change', refreshUrlParams);
});
// Open edit item modal