glastree_on_gitea
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
<IfModule mod_negotiation.c>
|
||||
Options -MultiViews -Indexes
|
||||
</IfModule>
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
# Handle Authorization Header
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
|
||||
# Handle X-XSRF-Token Header
|
||||
RewriteCond %{HTTP:x-xsrf-token} .
|
||||
RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}]
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Send Requests To Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
</IfModule>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Determine if the application is in maintenance mode...
|
||||
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
|
||||
require $maintenance;
|
||||
}
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the request...
|
||||
/** @var Application $app */
|
||||
$app = require_once __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
$app->handleRequest(Request::capture());
|
||||
@@ -0,0 +1,276 @@
|
||||
/**
|
||||
* Table Utils - Gestione avanzata tabelle
|
||||
* Include: scelta colonne, ordinamento, filtri, ricerca, export, salvataggio vista
|
||||
*/
|
||||
|
||||
class TableUtils {
|
||||
constructor(tableId, options = {}) {
|
||||
this.tableId = tableId;
|
||||
this.table = document.getElementById(tableId);
|
||||
this.options = options;
|
||||
|
||||
this.columns = options.columns || [];
|
||||
this.currentPage = 1;
|
||||
this.perPage = options.perPage || 20;
|
||||
|
||||
// Carica stato salvato se presente
|
||||
this.loadState();
|
||||
|
||||
// Inizializza eventi
|
||||
this.initEvents();
|
||||
}
|
||||
|
||||
loadState() {
|
||||
// Leggi parametri URL
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
this.vistaId = urlParams.get('vista_id');
|
||||
|
||||
if (this.vistaId) {
|
||||
this.loadVista(this.vistaId);
|
||||
}
|
||||
}
|
||||
|
||||
async loadVista(vistaId) {
|
||||
try {
|
||||
const response = await fetch(`/viste/${vistaId}/json`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.colonne_visibili) {
|
||||
this.setVisibleColumns(data.colonne_visibili);
|
||||
}
|
||||
if (data.colonne_ordinamento) {
|
||||
this.setOrder(data.colonne_ordinamento);
|
||||
}
|
||||
if (data.filtri) {
|
||||
this.setFilters(data.filtri);
|
||||
}
|
||||
if (data.ricerca) {
|
||||
document.getElementById('table-search').value = data.ricerca;
|
||||
this.search(data.ricerca);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Errore caricamento vista:', e);
|
||||
}
|
||||
}
|
||||
|
||||
initEvents() {
|
||||
// Pulsante impostazioni tabella
|
||||
document.getElementById('table-settings-btn')?.addEventListener('click', () => this.showSettingsModal());
|
||||
|
||||
// Ricerca
|
||||
document.getElementById('table-search')?.addEventListener('input', (e) => {
|
||||
this.search(e.target.value);
|
||||
});
|
||||
|
||||
// Ordinamento click su header
|
||||
this.table?.querySelectorAll('th[data-sortable]').forEach(th => {
|
||||
th.addEventListener('click', () => this.toggleSort(th.dataset.column));
|
||||
});
|
||||
|
||||
// Checkbox colonne
|
||||
document.querySelectorAll('.column-toggle').forEach(cb => {
|
||||
cb.addEventListener('change', () => this.toggleColumn(cb.dataset.column, cb.checked));
|
||||
});
|
||||
|
||||
// Salva vista
|
||||
document.getElementById('save-vista-btn')?.addEventListener('click', () => this.saveVista());
|
||||
|
||||
// Esporta
|
||||
document.getElementById('export-csv-btn')?.addEventListener('click', () => this.exportCSV());
|
||||
document.getElementById('export-pdf-btn')?.addEventListener('click', () => this.exportPDF());
|
||||
|
||||
// Applica filtri
|
||||
document.getElementById('apply-filters-btn')?.addEventListener('click', () => this.applyFilters());
|
||||
}
|
||||
|
||||
showSettingsModal() {
|
||||
const modal = document.getElementById('table-settings-modal');
|
||||
if (modal) {
|
||||
$(modal).modal('show');
|
||||
}
|
||||
}
|
||||
|
||||
toggleColumn(column, visible) {
|
||||
const colIndex = this.columns.findIndex(c => c.key === column);
|
||||
if (colIndex >= 0) {
|
||||
this.columns[colIndex].visible = visible;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
setVisibleColumns(visibleColumns) {
|
||||
this.columns.forEach(col => {
|
||||
col.visible = visibleColumns.includes(col.key);
|
||||
});
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.columns.forEach(col => {
|
||||
const th = this.table?.querySelector(`th[data-column="${col.key}"]`);
|
||||
const cells = this.table?.querySelectorAll(`td:nth-child(${this.columns.indexOf(col) + 1})`);
|
||||
|
||||
if (th) th.style.display = col.visible ? '' : 'none';
|
||||
cells?.forEach(cell => cell.style.display = col.visible ? '' : 'none');
|
||||
});
|
||||
}
|
||||
|
||||
toggleSort(column) {
|
||||
const currentOrder = this.options.order || [];
|
||||
const existing = currentOrder.find(o => o[0] === column);
|
||||
|
||||
if (existing) {
|
||||
existing[1] = existing[1] === 'asc' ? 'desc' : 'asc';
|
||||
} else {
|
||||
currentOrder.push([column, 'asc']);
|
||||
}
|
||||
|
||||
this.options.order = currentOrder;
|
||||
this.sort();
|
||||
}
|
||||
|
||||
setOrder(order) {
|
||||
this.options.order = order;
|
||||
this.sort();
|
||||
}
|
||||
|
||||
sort() {
|
||||
const tbody = this.table?.querySelector('tbody');
|
||||
if (!tbody) return;
|
||||
|
||||
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||
|
||||
rows.sort((a, b) => {
|
||||
for (const [col, dir] of (this.options.order || [])) {
|
||||
const colIndex = this.columns.findIndex(c => c.key === col);
|
||||
if (colIndex < 0) continue;
|
||||
|
||||
const aVal = a.querySelectorAll('td')[colIndex]?.textContent?.trim() || '';
|
||||
const bVal = b.querySelectorAll('td')[colIndex]?.textContent?.trim() || '';
|
||||
|
||||
let cmp = aVal.localeCompare(bVal, undefined, { numeric: true });
|
||||
if (cmp !== 0) return dir === 'asc' ? cmp : -cmp;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
rows.forEach(row => tbody.appendChild(row));
|
||||
}
|
||||
|
||||
search(query) {
|
||||
this.options.search = query.toLowerCase();
|
||||
this.filter();
|
||||
}
|
||||
|
||||
setFilters(filters) {
|
||||
this.options.filters = filters;
|
||||
this.filter();
|
||||
}
|
||||
|
||||
applyFilters() {
|
||||
const filters = [];
|
||||
document.querySelectorAll('.filter-row').forEach(row => {
|
||||
const col = row.querySelector('.filter-column')?.value;
|
||||
const op = row.querySelector('.filter-operator')?.value;
|
||||
const val = row.querySelector('.filter-value')?.value;
|
||||
if (col && val) filters.push({ column: col, operator: op, value: val });
|
||||
});
|
||||
this.options.filters = filters;
|
||||
this.filter();
|
||||
}
|
||||
|
||||
filter() {
|
||||
this.table?.querySelectorAll('tbody tr').forEach(row => {
|
||||
const text = row.textContent.toLowerCase();
|
||||
const matchesSearch = !this.options.search || text.includes(this.options.search);
|
||||
|
||||
let matchesFilters = true;
|
||||
if (this.options.filters) {
|
||||
for (const f of this.options.filters) {
|
||||
const colIndex = this.columns.findIndex(c => c.key === f.column);
|
||||
if (colIndex < 0) continue;
|
||||
|
||||
const cell = row.querySelectorAll('td')[colIndex]?.textContent?.trim() || '';
|
||||
|
||||
switch (f.operator) {
|
||||
case 'contains': matchesFilters = cell.toLowerCase().includes(f.value.toLowerCase()); break;
|
||||
case 'equals': matchesFilters = cell === f.value; break;
|
||||
case 'starts': matchesFilters = cell.startsWith(f.value); break;
|
||||
case 'ends': matchesFilters = cell.endsWith(f.value); break;
|
||||
case 'gt': matchesFilters = parseFloat(cell) > parseFloat(f.value); break;
|
||||
case 'lt': matchesFilters = parseFloat(cell) < parseFloat(f.value); break;
|
||||
}
|
||||
if (!matchesFilters) break;
|
||||
}
|
||||
}
|
||||
|
||||
row.style.display = (matchesSearch && matchesFilters) ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
async saveVista() {
|
||||
const nome = document.getElementById('vista-nome')?.value;
|
||||
if (!nome) {
|
||||
alert('Inserisci un nome per la vista');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
nome: nome,
|
||||
tipo: this.options.type || 'individui',
|
||||
colonne_visibili: this.columns.filter(c => c.visible).map(c => c.key),
|
||||
colonne_ordinamento: this.options.order || [],
|
||||
filtri: this.options.filters || [],
|
||||
ricerca: this.options.search || ''
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('/viste', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Vista salvata!');
|
||||
$(document.getElementById('table-settings-modal')).modal('hide');
|
||||
}
|
||||
} catch (e) {
|
||||
alert('Errore salvataggio vista');
|
||||
}
|
||||
}
|
||||
|
||||
exportCSV() {
|
||||
const rows = [];
|
||||
const headers = this.columns.filter(c => c.visible).map(c => c.label);
|
||||
rows.push(headers.join(','));
|
||||
|
||||
this.table?.querySelectorAll('tbody tr').forEach(row => {
|
||||
const cells = this.columns.filter(c => c.visible).map((c, i) => {
|
||||
const val = row.querySelectorAll('td')[i]?.textContent?.trim() || '';
|
||||
return `"${val.replace(/"/g, '""')}"`;
|
||||
});
|
||||
rows.push(cells.join(','));
|
||||
});
|
||||
|
||||
const blob = new Blob([rows.join('\n')], { type: 'text/csv' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `export_${this.options.type || 'data'}_${new Date().toISOString().slice(0,10)}.csv`;
|
||||
a.click();
|
||||
}
|
||||
|
||||
exportPDF() {
|
||||
alert('Export PDF in sviluppo');
|
||||
}
|
||||
}
|
||||
|
||||
// Funzioni globali per uso inline
|
||||
window.TableUtils = TableUtils;
|
||||
window.initTableUtils = function(tableId, options) {
|
||||
return new TableUtils(tableId, options);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/var/www/html/glastree/storage/app/public
|
||||
Reference in New Issue
Block a user