fixed column parts
This commit is contained in:
@@ -24,7 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="row parts-row">
|
<div class="row parts-row">
|
||||||
<div class="col-md-9">
|
<div class="col-md-12">
|
||||||
<!-- Prima riga: Elenco Parti, Rinumera, Voce -->
|
<!-- Prima riga: Elenco Parti, Rinumera, Voce -->
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; min-width: 0;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; min-width: 0;">
|
||||||
<h6 style="margin: 0; white-space: nowrap;">Elenco Parti</h6>
|
<h6 style="margin: 0; white-space: nowrap;">Elenco Parti</h6>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<i class="fas fa-microphone"></i> Voce
|
<i class="fas fa-microphone"></i> Voce
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-outline-primary btn-sm ms-2" id="showHideImageBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
<button type="button" class="btn btn-outline-primary btn-sm ms-2" id="showHideImageBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
<i class="fas fa-eye-slash" style="font-size: 0.8rem;"></i>
|
<i class="fas fa-eye" style="font-size: 0.8rem;"></i>
|
||||||
<i class="fas fa-image ms-1" style="font-size: 0.8rem;"></i>
|
<i class="fas fa-image ms-1" style="font-size: 0.8rem;"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,7 +119,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3 d-none">
|
||||||
<h6>Foto del Campione</h6>
|
<h6>Foto del Campione</h6>
|
||||||
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
||||||
<button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i></button>
|
<button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i></button>
|
||||||
@@ -432,7 +432,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Evita stretching del flex nella riga dei filtri */
|
/* Evita stretching del flex nella riga dei filtri */
|
||||||
#partsModal .modal-body>.row .col-md-9>div[style*="display: flex"]>* {
|
#partsModal .parts-row>div:first-child>div[style*="display: flex"]>* {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,7 +611,7 @@
|
|||||||
|
|
||||||
#partsTable {
|
#partsTable {
|
||||||
table-layout: fixed !important;
|
table-layout: fixed !important;
|
||||||
width: max-content !important;
|
width: 100% !important;
|
||||||
min-width: unset !important;
|
min-width: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,9 +733,6 @@
|
|||||||
|
|
||||||
/* Extra field propagation header - full column width */
|
/* Extra field propagation header - full column width */
|
||||||
#partsTable th.extra-field-th {
|
#partsTable th.extra-field-th {
|
||||||
width: auto !important;
|
|
||||||
min-width: 220px !important;
|
|
||||||
max-width: none !important;
|
|
||||||
padding: 0.25rem !important;
|
padding: 0.25rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,9 +754,9 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
color: #222;
|
color: #222;
|
||||||
white-space: nowrap !important;
|
white-space: normal !important;
|
||||||
overflow: visible !important;
|
word-break: break-word;
|
||||||
text-overflow: unset !important;
|
overflow: hidden !important;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,5 +803,69 @@
|
|||||||
z-index: 1065 !important
|
z-index: 1065 !important
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Campi nelle celle: occupano tutta la cella */
|
||||||
|
#partsTable td input.form-control,
|
||||||
|
#partsTable td textarea.form-control {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable td>div[style*="display: flex"] {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select2 nelle celle (Matrice ed Extra): occupano la cella e vanno a capo */
|
||||||
|
#partsTable td .select2-container {
|
||||||
|
width: 100% !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable td .part-matrice+.select2 {
|
||||||
|
flex: 1 1 auto !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable td .select2-selection--single {
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 24px !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable td .select2-selection__rendered {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
white-space: normal !important;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow: visible !important;
|
||||||
|
text-overflow: clip !important;
|
||||||
|
line-height: 1.2 !important;
|
||||||
|
padding: 2px 22px 2px 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable td .select2-selection__arrow {
|
||||||
|
height: 100% !important;
|
||||||
|
top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Campo extra di tipo testo: textarea che cresce col contenuto */
|
||||||
|
#partsTable textarea.part-extra-field {
|
||||||
|
field-sizing: content;
|
||||||
|
min-height: 24px;
|
||||||
|
height: auto;
|
||||||
|
padding: 0.1rem 0.3rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
resize: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Voci del dropdown che vanno a capo */
|
||||||
|
.select2-results__option {
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
/* rosso */
|
/* rosso */
|
||||||
</style>
|
</style>
|
||||||
+126
-77
@@ -147,10 +147,9 @@ $(document).ready(function () {
|
|||||||
return `
|
return `
|
||||||
<td class="extra-field-td" style="width:200px;">
|
<td class="extra-field-td" style="width:200px;">
|
||||||
<input type="hidden" class="part-extra-field-id" value="${partsExtraField.field_id}">
|
<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>`;
|
</td>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildExtraFieldHeaderHtml() {
|
function buildExtraFieldHeaderHtml() {
|
||||||
if (!partsExtraField) return "";
|
if (!partsExtraField) return "";
|
||||||
|
|
||||||
@@ -888,6 +887,17 @@ $(document).ready(function () {
|
|||||||
$("#partsTableBody").empty();
|
$("#partsTableBody").empty();
|
||||||
$("#global-matrice").empty();
|
$("#global-matrice").empty();
|
||||||
$("#macro-matrice-filter").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();
|
$(".temp-alert").remove();
|
||||||
$(".modal-backdrop").remove();
|
$(".modal-backdrop").remove();
|
||||||
$("body").removeClass("modal-open").css("padding-right", "");
|
$("body").removeClass("modal-open").css("padding-right", "");
|
||||||
@@ -2154,6 +2164,9 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.saveAllParts = saveAllParts;
|
window.saveAllParts = saveAllParts;
|
||||||
|
window.markUnsaved = function () {
|
||||||
|
markUnsaved();
|
||||||
|
};
|
||||||
function renumberParts() {
|
function renumberParts() {
|
||||||
console.log(
|
console.log(
|
||||||
"Inizio rinumera parts, numero righe:",
|
"Inizio rinumera parts, numero righe:",
|
||||||
@@ -2672,135 +2685,171 @@ $(document).on("click", "#showHideImageBtn", function () {
|
|||||||
// RESIZABLE PARTS TABLE COLUMNS - FIXED COLGROUP VERSION
|
// RESIZABLE PARTS TABLE COLUMNS - FIXED COLGROUP VERSION
|
||||||
// ===================
|
// ===================
|
||||||
(function () {
|
(function () {
|
||||||
// Larghezze default per indice colonna (0-based)
|
const NUM_W = 55; // colonna Num fissa
|
||||||
const defaultWidths = [55, 320, 360, 150, 220, 230];
|
const MIN_W = 70; // larghezza minima di ogni colonna
|
||||||
const savedWidths = [...defaultWidths];
|
|
||||||
|
// 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() {
|
function getColgroup() {
|
||||||
return $("#partsTableColgroup");
|
return $("#partsTableColgroup");
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncColgroupToHeaders() {
|
function getThs() {
|
||||||
const $table = $("#partsTable");
|
return $("#partsTable thead tr:first th");
|
||||||
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 applyColumnWidth(colIndex, newWidth) {
|
function getAvail() {
|
||||||
const w = Math.max(40, Math.round(newWidth));
|
const w = $("#partsModal .parts-table-scroll").innerWidth();
|
||||||
savedWidths[colIndex] = w;
|
return w > 0 ? Math.floor(w) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
const $col = getColgroup().find("col").eq(colIndex);
|
function ensureCols(n) {
|
||||||
if ($col.length) {
|
const $cg = getColgroup();
|
||||||
$col.css("width", w + "px");
|
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
|
function render() {
|
||||||
const thCount = $("#partsTable thead tr:first th").length;
|
const n = getThs().length;
|
||||||
const total = savedWidths.slice(0, thCount).reduce((a, b) => a + b, 0);
|
if (!n || !getAvail()) return;
|
||||||
$("#partsTable").css("width", total + "px");
|
ensureCols(n);
|
||||||
|
ensureWeights(n);
|
||||||
|
const px = computePx(n);
|
||||||
|
getColgroup()
|
||||||
|
.find("col")
|
||||||
|
.each(function (i) {
|
||||||
|
$(this).css("width", px[i] + "px");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addResizers() {
|
function addResizers() {
|
||||||
const $table = $("#partsTable");
|
const $ths = getThs();
|
||||||
if (!$table.length) return;
|
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);
|
const $th = $(this);
|
||||||
|
$th.css("position", "relative");
|
||||||
// Salta colonna Num (indice 0) — non ridimensionabile
|
|
||||||
if (colIndex === 0) return;
|
|
||||||
|
|
||||||
// Non aggiungere due volte
|
|
||||||
if ($th.find(".parts-resizer").length) return;
|
|
||||||
|
|
||||||
const $resizer = $("<span class='parts-resizer'></span>");
|
const $resizer = $("<span class='parts-resizer'></span>");
|
||||||
$th.css("position", "relative"); // necessario per il posizionamento assoluto
|
|
||||||
$th.append($resizer);
|
$th.append($resizer);
|
||||||
|
|
||||||
$resizer.on("mousedown", function (e) {
|
$resizer.on("mousedown", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
ensureWeights(n);
|
||||||
|
const startPx = computePx(n);
|
||||||
|
const a = startPx[i];
|
||||||
|
const b = startPx[i + 1];
|
||||||
const startX = e.pageX;
|
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")
|
$("body").css({ "user-select": "none", cursor: "col-resize" });
|
||||||
.css("user-select", "none")
|
|
||||||
.css("cursor", "col-resize");
|
|
||||||
|
|
||||||
$(document).on("mousemove.partsResize", function (ev) {
|
$(document).on("mousemove.partsResize", function (ev) {
|
||||||
const delta = ev.pageX - startX;
|
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 () {
|
$(document).on("mouseup.partsResize", function () {
|
||||||
$("body").css("user-select", "").css("cursor", "");
|
$("body").css({ "user-select": "", cursor: "" });
|
||||||
$(document).off(".partsResize");
|
$(document).off(".partsResize");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function refresh() {
|
||||||
syncColgroupToHeaders();
|
render();
|
||||||
addResizers();
|
addResizers();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init al primo show del modale
|
|
||||||
$(document).on("shown.bs.modal", "#partsModal", function () {
|
$(document).on("shown.bs.modal", "#partsModal", function () {
|
||||||
setTimeout(init, 120);
|
setTimeout(refresh, 120);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-init dopo ogni AJAX (nuove righe, caricamenti)
|
|
||||||
$(document).ajaxComplete(function () {
|
$(document).ajaxComplete(function () {
|
||||||
if ($("#partsModal").hasClass("show")) {
|
if ($("#partsModal").hasClass("show")) {
|
||||||
setTimeout(syncColgroupToHeaders, 200);
|
setTimeout(refresh, 200);
|
||||||
setTimeout(addResizers, 220);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-init dopo aggiunta/rimozione righe
|
|
||||||
$(document).on(
|
$(document).on(
|
||||||
"click",
|
"click",
|
||||||
".add-row-global, .add-mix-global, .add-mix-row, .remove-row, #renumberPartsBtn, #clonePartsBtn",
|
".add-row-global, .add-mix-global, .add-mix-row, .remove-row, #renumberPartsBtn, #clonePartsBtn",
|
||||||
function () {
|
function () {
|
||||||
setTimeout(syncColgroupToHeaders, 120);
|
setTimeout(refresh, 120);
|
||||||
setTimeout(addResizers, 140);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
window.initPartsResizableColumns = init;
|
let resizeTimer = null;
|
||||||
window.applyPartsColumnWidths = syncColgroupToHeaders;
|
$(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
|
// NAVIGAZIONE TABELLA PARTI CON FRECCE TASTIERA
|
||||||
|
|||||||
Reference in New Issue
Block a user