setup viste
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
class ColumnManager {
|
||||
constructor(tableId, options = {}) {
|
||||
this.tableId = tableId;
|
||||
this.table = document.getElementById(tableId);
|
||||
if (!this.table) return;
|
||||
|
||||
this.options = Object.assign({
|
||||
entityType: 'individui',
|
||||
storageKey: null,
|
||||
resizable: true,
|
||||
reorderable: true,
|
||||
persistWidths: true,
|
||||
persistOrder: true,
|
||||
}, options);
|
||||
|
||||
this.columns = [];
|
||||
this.columnWidths = {};
|
||||
this.columnOrder = [];
|
||||
this.dragState = null;
|
||||
this.resizeState = null;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.loadState();
|
||||
this.initColumns();
|
||||
if (this.options.resizable) this.initResize();
|
||||
if (this.options.reorderable) this.initReorder();
|
||||
this.applyState();
|
||||
}
|
||||
|
||||
initColumns() {
|
||||
const ths = this.table.querySelectorAll('thead th');
|
||||
ths.forEach((th, idx) => {
|
||||
const colKey = th.dataset.column || `col_${idx}`;
|
||||
const col = {
|
||||
index: idx,
|
||||
key: colKey,
|
||||
element: th,
|
||||
width: th.style.width || '',
|
||||
visible: th.style.display !== 'none',
|
||||
label: th.textContent.trim(),
|
||||
};
|
||||
this.columns.push(col);
|
||||
});
|
||||
}
|
||||
|
||||
loadState() {
|
||||
if (this.options.storageKey) {
|
||||
try {
|
||||
const saved = sessionStorage.getItem(this.options.storageKey);
|
||||
if (saved) {
|
||||
const data = JSON.parse(saved);
|
||||
this.columnWidths = data.widths || {};
|
||||
this.columnOrder = data.order || [];
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
const vistaEl = document.getElementById('vista-data');
|
||||
if (vistaEl && vistaEl.textContent && vistaEl.textContent !== 'null') {
|
||||
try {
|
||||
const vista = JSON.parse(vistaEl.textContent);
|
||||
this.columnWidths = vista.colonne_larghezze || {};
|
||||
this.columnOrder = vista.colonne_ordine || [];
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
persistState() {
|
||||
if (!this.options.storageKey) return;
|
||||
try {
|
||||
sessionStorage.setItem(this.options.storageKey, JSON.stringify({
|
||||
widths: this.columnWidths,
|
||||
order: this.columnOrder,
|
||||
}));
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
applyState() {
|
||||
if (this.columnOrder.length > 0) {
|
||||
this.reorderColumns(this.columnOrder, false);
|
||||
}
|
||||
if (Object.keys(this.columnWidths).length > 0) {
|
||||
this.applyWidths();
|
||||
}
|
||||
}
|
||||
|
||||
applyWidths() {
|
||||
this.columns.forEach(col => {
|
||||
const w = this.columnWidths[col.key];
|
||||
if (w) {
|
||||
col.element.style.width = w;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initResize() {
|
||||
this.table.querySelectorAll('thead th').forEach(th => {
|
||||
const handle = document.createElement('div');
|
||||
handle.className = 'col-resize-handle';
|
||||
handle.style.cssText = 'position:absolute;right:0;top:0;bottom:0;width:5px;cursor:col-resize;z-index:10;';
|
||||
th.style.position = 'relative';
|
||||
th.appendChild(handle);
|
||||
|
||||
handle.addEventListener('mousedown', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const thEl = th;
|
||||
const startX = e.clientX;
|
||||
const startWidth = thEl.offsetWidth;
|
||||
|
||||
const onMouseMove = (ev) => {
|
||||
const diff = ev.clientX - startX;
|
||||
const newWidth = Math.max(30, startWidth + diff);
|
||||
thEl.style.width = newWidth + 'px';
|
||||
const colKey = thEl.dataset.column;
|
||||
if (colKey) {
|
||||
this.columnWidths[colKey] = newWidth + 'px';
|
||||
this.persistState();
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
document.body.style.cursor = '';
|
||||
document.body.style.userSelect = '';
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
document.body.style.cursor = 'col-resize';
|
||||
document.body.style.userSelect = 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
initReorder() {
|
||||
const thead = this.table.querySelector('thead');
|
||||
if (!thead) return;
|
||||
|
||||
let dragCol = null;
|
||||
let dragIndex = -1;
|
||||
let placeholder = null;
|
||||
|
||||
thead.querySelectorAll('th').forEach(th => {
|
||||
if (th.querySelector('.col-resize-handle')) return;
|
||||
th.draggable = true;
|
||||
|
||||
th.addEventListener('dragstart', (e) => {
|
||||
dragCol = th;
|
||||
dragIndex = Array.from(thead.querySelectorAll('th')).indexOf(th);
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('text/plain', '');
|
||||
th.classList.add('dragging');
|
||||
});
|
||||
|
||||
th.addEventListener('dragend', () => {
|
||||
th.classList.remove('dragging');
|
||||
if (placeholder && placeholder.parentNode) {
|
||||
placeholder.parentNode.removeChild(placeholder);
|
||||
}
|
||||
dragCol = null;
|
||||
dragIndex = -1;
|
||||
placeholder = null;
|
||||
});
|
||||
|
||||
th.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
if (!dragCol || dragCol === th) return;
|
||||
|
||||
if (!placeholder) {
|
||||
placeholder = document.createElement('th');
|
||||
placeholder.style.cssText = 'border:2px dashed #007bff;background:rgba(0,123,255,0.1);width:0;padding:0;';
|
||||
dragCol.parentNode.insertBefore(placeholder, dragCol);
|
||||
}
|
||||
|
||||
const rect = th.getBoundingClientRect();
|
||||
const midX = rect.left + rect.width / 2;
|
||||
const parent = th.parentNode;
|
||||
|
||||
if (e.clientX < midX) {
|
||||
parent.insertBefore(placeholder, th);
|
||||
} else {
|
||||
parent.insertBefore(placeholder, th.nextSibling);
|
||||
}
|
||||
});
|
||||
|
||||
th.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
if (!dragCol || dragCol === th) return;
|
||||
|
||||
const parent = th.parentNode;
|
||||
const allTh = Array.from(parent.querySelectorAll('th')).filter(el => el !== placeholder);
|
||||
|
||||
const fromIdx = allTh.indexOf(dragCol);
|
||||
let toIdx = allTh.indexOf(th);
|
||||
|
||||
if (placeholder) {
|
||||
toIdx = Array.from(parent.children).indexOf(placeholder);
|
||||
if (placeholder.parentNode) placeholder.parentNode.removeChild(placeholder);
|
||||
placeholder = null;
|
||||
}
|
||||
|
||||
if (fromIdx < 0) return;
|
||||
|
||||
const actualRows = this.table.querySelectorAll('tr');
|
||||
actualRows.forEach(row => {
|
||||
const cells = row.querySelectorAll('td, th');
|
||||
if (cells[fromIdx] && cells[toIdx]) {
|
||||
if (toIdx > fromIdx) {
|
||||
row.insertBefore(cells[fromIdx], cells[toIdx].nextSibling);
|
||||
} else {
|
||||
row.insertBefore(cells[fromIdx], cells[toIdx]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.updateColumnOrder();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updateColumnOrder() {
|
||||
const ths = this.table.querySelectorAll('thead th');
|
||||
this.columnOrder = [];
|
||||
const keysInOrder = [];
|
||||
ths.forEach((th, idx) => {
|
||||
const colKey = th.dataset.column || `col_${idx}`;
|
||||
keysInOrder.push(colKey);
|
||||
this.columnOrder.push(colKey);
|
||||
});
|
||||
this.columns.sort((a, b) => keysInOrder.indexOf(a.key) - keysInOrder.indexOf(b.key));
|
||||
this.columns.forEach((col, idx) => col.index = idx);
|
||||
this.persistState();
|
||||
}
|
||||
|
||||
reorderColumns(keyOrder, persist = true) {
|
||||
if (!keyOrder || keyOrder.length === 0) return;
|
||||
const thead = this.table.querySelector('thead');
|
||||
if (!thead) return;
|
||||
|
||||
const rows = this.table.querySelectorAll('tr');
|
||||
const keyToThIndex = {};
|
||||
const allTh = Array.from(thead.querySelectorAll('th'));
|
||||
|
||||
allTh.forEach((th, idx) => {
|
||||
const key = th.dataset.column || `col_${idx}`;
|
||||
keyToThIndex[key] = idx;
|
||||
});
|
||||
|
||||
rows.forEach(row => {
|
||||
const cells = row.querySelectorAll('td, th');
|
||||
const reordered = [];
|
||||
let lastRef = null;
|
||||
|
||||
keyOrder.forEach(key => {
|
||||
const srcIdx = keyToThIndex[key];
|
||||
if (srcIdx !== undefined && cells[srcIdx]) {
|
||||
reordered.push(cells[srcIdx]);
|
||||
}
|
||||
});
|
||||
|
||||
reordered.forEach(cell => {
|
||||
if (lastRef) {
|
||||
row.insertBefore(cell, lastRef.nextSibling);
|
||||
} else {
|
||||
row.insertBefore(cell, row.firstChild);
|
||||
}
|
||||
lastRef = cell;
|
||||
});
|
||||
});
|
||||
|
||||
this.columnOrder = [...keyOrder];
|
||||
this.columns.sort((a, b) => keyOrder.indexOf(a.key) - keyOrder.indexOf(b.key));
|
||||
this.columns.forEach((col, idx) => col.index = idx);
|
||||
|
||||
if (persist) this.persistState();
|
||||
}
|
||||
|
||||
setVisible(columnKey, visible) {
|
||||
const th = this.table.querySelector(`th[data-column="${columnKey}"]`);
|
||||
if (th) th.style.display = visible ? '' : 'none';
|
||||
|
||||
const colIdx = this.columns.findIndex(c => c.key === columnKey);
|
||||
if (colIdx >= 0) {
|
||||
this.columns[colIdx].visible = visible;
|
||||
const rows = this.table.querySelectorAll('tbody tr, thead tr');
|
||||
rows.forEach(row => {
|
||||
const cells = row.querySelectorAll('td, th');
|
||||
if (cells[colIdx]) {
|
||||
cells[colIdx].style.display = visible ? '' : 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getColumnWidths() {
|
||||
return { ...this.columnWidths };
|
||||
}
|
||||
|
||||
getColumnOrder() {
|
||||
return [...this.columnOrder];
|
||||
}
|
||||
|
||||
getVisibleColumns() {
|
||||
return this.columns.filter(c => c.visible).map(c => c.key);
|
||||
}
|
||||
|
||||
getColumnMetadata() {
|
||||
return {
|
||||
larghezze: this.getColumnWidths(),
|
||||
ordine: this.getColumnOrder(),
|
||||
visibili: this.getVisibleColumns(),
|
||||
};
|
||||
}
|
||||
|
||||
printWithSettings() {
|
||||
const printWindow = window.open('', '_blank');
|
||||
if (!printWindow) return;
|
||||
|
||||
const styles = Array.from(document.styleSheets)
|
||||
.filter(sheet => {
|
||||
try { return sheet.cssRules; } catch (e) { return false; }
|
||||
})
|
||||
.map(sheet => Array.from(sheet.cssRules).map(rule => rule.cssText).join('\n'))
|
||||
.join('\n');
|
||||
|
||||
const printStyles = `
|
||||
@media print {
|
||||
body { font-family: 'DejaVu Sans', Arial, sans-serif; font-size: 10pt; }
|
||||
.no-print { display: none !important; }
|
||||
.card { border: none !important; box-shadow: none !important; }
|
||||
.table { border-collapse: collapse; width: 100%; }
|
||||
.table th { background: #f5f5f5 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
||||
.table th, .table td { border: 1px solid #ddd; padding: 4px 6px; }
|
||||
a { text-decoration: none; color: #000; }
|
||||
.badge { border: 1px solid #999; padding: 1px 4px; font-size: 8pt; }
|
||||
.pagination, .card-header .card-tools { display: none !important; }
|
||||
.page-break { page-break-before: always; }
|
||||
}
|
||||
`;
|
||||
|
||||
const title = document.title || 'Stampa';
|
||||
const pageTitle = document.querySelector('.page_title, .card-title h1, h1')?.textContent?.trim() || title;
|
||||
|
||||
let content = '';
|
||||
const printArea = this.table?.cloneNode(true);
|
||||
if (printArea) {
|
||||
printArea.querySelectorAll('.col-resize-handle').forEach(h => h.remove());
|
||||
content = printArea.outerHTML;
|
||||
} else {
|
||||
content = document.getElementById(this.tableId)?.outerHTML || '';
|
||||
}
|
||||
|
||||
printWindow.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>${title}</title>
|
||||
<style>${styles}${printStyles}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="no-print" style="text-align:right;margin-bottom:10px;">
|
||||
<button onclick="window.print()" style="padding:6px 16px;font-size:12pt;">🖨️ Stampa</button>
|
||||
<button onclick="window.close()" style="padding:6px 16px;font-size:12pt;">✖ Chiudi</button>
|
||||
</div>
|
||||
<h2 style="margin-bottom:16px;">${pageTitle}</h2>
|
||||
${content}
|
||||
<p style="text-align:center;margin-top:16px;color:#999;font-size:8pt;">
|
||||
Stampato il ${new Date().toLocaleDateString('it-IT')} — ${document.location.href}
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
}
|
||||
}
|
||||
|
||||
window.ColumnManager = ColumnManager;
|
||||
Reference in New Issue
Block a user