fixed column parts

This commit is contained in:
2026-10-05 13:38:42 +02:00
parent 65608712ad
commit 76f4a8e291
2 changed files with 198 additions and 88 deletions
+126 -77
View File
@@ -147,10 +147,9 @@ $(document).ready(function () {
return `
<td class="extra-field-td" style="width:200px;">
<input type="hidden" class="part-extra-field-id" value="${partsExtraField.field_id}">
<input type="text" class="form-control form-control-sm part-extra-field" data-type="${partsExtraField.data_type || ""}" value="${selectedValueText || ""}">
<textarea rows="1" class="form-control form-control-sm part-extra-field" data-type="${partsExtraField.data_type || ""}">${selectedValueText || ""}</textarea>
</td>`;
}
function buildExtraFieldHeaderHtml() {
if (!partsExtraField) return "";
@@ -888,6 +887,17 @@ $(document).ready(function () {
$("#partsTableBody").empty();
$("#global-matrice").empty();
$("#macro-matrice-filter").empty();
// Ripristina lo stato di default: foto nascosta
const $partsRow = $("#partsModal .parts-row");
$partsRow.find("> .col-md-3").addClass("d-none");
$partsRow
.find("> div:first-child")
.removeClass("col-md-9")
.addClass("col-md-12");
$("#showHideImageBtn").html(
"<i class='fas fa-eye' style='font-size: 0.8rem;'></i><i class='fas fa-image ms-1' style='font-size: 0.8rem;'></i>",
);
$(".temp-alert").remove();
$(".modal-backdrop").remove();
$("body").removeClass("modal-open").css("padding-right", "");
@@ -2154,6 +2164,9 @@ $(document).ready(function () {
});
window.saveAllParts = saveAllParts;
window.markUnsaved = function () {
markUnsaved();
};
function renumberParts() {
console.log(
"Inizio rinumera parts, numero righe:",
@@ -2672,135 +2685,171 @@ $(document).on("click", "#showHideImageBtn", function () {
// RESIZABLE PARTS TABLE COLUMNS - FIXED COLGROUP VERSION
// ===================
(function () {
// Larghezze default per indice colonna (0-based)
const defaultWidths = [55, 320, 360, 150, 220, 230];
const savedWidths = [...defaultWidths];
const NUM_W = 55; // colonna Num fissa
const MIN_W = 70; // larghezza minima di ogni colonna
// Pesi di default delle colonne dopo Num
// senza extra: Descrizione, Matrice, Data, Azioni
// con extra: Descrizione, Matrice, Data, Extra, Azioni
const DEFAULT_NO_EXTRA = [320, 360, 150, 200];
const DEFAULT_EXTRA = [280, 320, 140, 240, 180];
let weights = null;
let weightsCount = 0;
function getColgroup() {
return $("#partsTableColgroup");
}
function syncColgroupToHeaders() {
const $table = $("#partsTable");
const $ths = $table.find("thead tr:first th");
const $colgroup = getColgroup();
const thCount = $ths.length;
// Assicura che ci siano esattamente tante <col> quante <th>
while ($colgroup.find("col").length < thCount) {
$colgroup.append("<col>");
}
while ($colgroup.find("col").length > thCount) {
$colgroup.find("col:last").remove();
}
// Applica le larghezze salvate
$colgroup.find("col").each(function (i) {
const w = savedWidths[i] !== undefined ? savedWidths[i] : 150;
$(this).css("width", w + "px");
});
// Imposta larghezza totale della tabella = somma colonne (evita reflow)
const total = savedWidths.slice(0, thCount).reduce((a, b) => a + b, 0);
$table.css("width", total + "px");
function getThs() {
return $("#partsTable thead tr:first th");
}
function applyColumnWidth(colIndex, newWidth) {
const w = Math.max(40, Math.round(newWidth));
savedWidths[colIndex] = w;
function getAvail() {
const w = $("#partsModal .parts-table-scroll").innerWidth();
return w > 0 ? Math.floor(w) : 0;
}
const $col = getColgroup().find("col").eq(colIndex);
if ($col.length) {
$col.css("width", w + "px");
function ensureCols(n) {
const $cg = getColgroup();
while ($cg.find("col").length < n) $cg.append("<col>");
while ($cg.find("col").length > n) $cg.find("col:last").remove();
}
function ensureWeights(n) {
const k = n - 1;
if (weights && weightsCount === k) return;
if (k === 4) weights = DEFAULT_NO_EXTRA.slice();
else if (k === 5) weights = DEFAULT_EXTRA.slice();
else weights = Array(k).fill(150);
weightsCount = k;
}
// Converte i pesi in pixel: la somma è sempre = larghezza disponibile
function computePx(n) {
const avail = getAvail();
const rest = Math.max(avail - NUM_W, MIN_W * (n - 1));
const sum = weights.reduce((a, b) => a + b, 0) || 1;
const px = [NUM_W];
let used = 0;
for (let i = 0; i < weights.length; i++) {
const v =
i === weights.length - 1
? rest - used
: Math.floor((rest * weights[i]) / sum);
px.push(v);
used += v;
}
return px;
}
// Aggiorna larghezza totale tabella senza toccare le altre colonne
const thCount = $("#partsTable thead tr:first th").length;
const total = savedWidths.slice(0, thCount).reduce((a, b) => a + b, 0);
$("#partsTable").css("width", total + "px");
function render() {
const n = getThs().length;
if (!n || !getAvail()) return;
ensureCols(n);
ensureWeights(n);
const px = computePx(n);
getColgroup()
.find("col")
.each(function (i) {
$(this).css("width", px[i] + "px");
});
}
function addResizers() {
const $table = $("#partsTable");
if (!$table.length) return;
const $ths = getThs();
const n = $ths.length;
if (!n) return;
$ths.find(".parts-resizer").remove();
// Resizer sul bordo destro delle colonne da 1 a n-2:
// sposta spazio tra la colonna e quella alla sua destra
$ths.each(function (i) {
if (i === 0 || i >= n - 1) return;
$table.find("thead tr:first th").each(function (colIndex) {
const $th = $(this);
// Salta colonna Num (indice 0) — non ridimensionabile
if (colIndex === 0) return;
// Non aggiungere due volte
if ($th.find(".parts-resizer").length) return;
$th.css("position", "relative");
const $resizer = $("<span class='parts-resizer'></span>");
$th.css("position", "relative"); // necessario per il posizionamento assoluto
$th.append($resizer);
$resizer.on("mousedown", function (e) {
e.preventDefault();
e.stopPropagation();
ensureWeights(n);
const startPx = computePx(n);
const a = startPx[i];
const b = startPx[i + 1];
const startX = e.pageX;
// Leggi la larghezza ESATTA dalla <col>, non dal <th>
const startWidth =
savedWidths[colIndex] !== undefined
? savedWidths[colIndex]
: parseInt(
getColgroup()
.find("col")
.eq(colIndex)
.css("width"),
10,
) || 150;
$("body")
.css("user-select", "none")
.css("cursor", "col-resize");
$("body").css({ "user-select": "none", cursor: "col-resize" });
$(document).on("mousemove.partsResize", function (ev) {
const delta = ev.pageX - startX;
applyColumnWidth(colIndex, startWidth + delta);
const newA = Math.min(
Math.max(a + delta, MIN_W),
a + b - MIN_W,
);
const newB = a + b - newA;
const px = startPx.slice();
px[i] = newA;
px[i + 1] = newB;
weights = px.slice(1); // i pixel diventano i nuovi pesi
render();
});
$(document).on("mouseup.partsResize", function () {
$("body").css("user-select", "").css("cursor", "");
$("body").css({ "user-select": "", cursor: "" });
$(document).off(".partsResize");
});
});
});
}
function init() {
syncColgroupToHeaders();
function refresh() {
render();
addResizers();
}
// Init al primo show del modale
$(document).on("shown.bs.modal", "#partsModal", function () {
setTimeout(init, 120);
setTimeout(refresh, 120);
});
// Re-init dopo ogni AJAX (nuove righe, caricamenti)
$(document).ajaxComplete(function () {
if ($("#partsModal").hasClass("show")) {
setTimeout(syncColgroupToHeaders, 200);
setTimeout(addResizers, 220);
setTimeout(refresh, 200);
}
});
// Re-init dopo aggiunta/rimozione righe
$(document).on(
"click",
".add-row-global, .add-mix-global, .add-mix-row, .remove-row, #renumberPartsBtn, #clonePartsBtn",
function () {
setTimeout(syncColgroupToHeaders, 120);
setTimeout(addResizers, 140);
setTimeout(refresh, 120);
},
);
window.initPartsResizableColumns = init;
window.applyPartsColumnWidths = syncColgroupToHeaders;
let resizeTimer = null;
$(window).on("resize.partsCols", function () {
if (!$("#partsModal").hasClass("show")) return;
clearTimeout(resizeTimer);
resizeTimer = setTimeout(render, 150);
});
// Textarea campo extra: auto-altezza (per browser senza field-sizing)
$(document).on(
"input focus",
"#partsTable textarea.part-extra-field",
function () {
this.style.height = "auto";
this.style.height = this.scrollHeight + "px";
},
);
window.initPartsResizableColumns = refresh;
window.applyPartsColumnWidths = refresh;
})();
// ===================
// NAVIGAZIONE TABELLA PARTI CON FRECCE TASTIERA