1946 lines
96 KiB
PHP
1946 lines
96 KiB
PHP
@extends('layouts.adminlte')
|
|
@section('title', 'Documenti')
|
|
@section('page_title', 'Gestione Documenti')
|
|
|
|
@php
|
|
$canWriteDocumenti = Auth::user()->canManage('documenti');
|
|
$canDeleteDocumenti = Auth::user()->canDelete('documenti');
|
|
@endphp
|
|
|
|
@section('css')
|
|
<style>
|
|
.list-group-item .folder-actions { display: inline-flex; }
|
|
.list-group-item .folder-actions .btn-link:hover i { opacity: 0.7; }
|
|
</style>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<div class="row">
|
|
{{-- Sidebar cartelle --}}
|
|
<div class="col-md-3">
|
|
<div class="card card-secondary card-outline">
|
|
<div class="card-header">
|
|
<h3 class="card-title">
|
|
<i class="fas fa-folder mr-2"></i>Cartelle
|
|
</h3>
|
|
@if($canWriteDocumenti)
|
|
<div class="card-tools">
|
|
<button type="button" class="btn btn-tool" onclick="$('#newFolderModal').modal('show')" title="Nuova cartella">
|
|
<i class="fas fa-plus"></i>
|
|
</button>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="list-group list-group-flush">
|
|
<a href="/documenti"
|
|
class="list-group-item list-group-item-action d-flex align-items-center py-2 {{ !$currentFolder && !$currentRepo ? 'active' : '' }}">
|
|
<i class="fas fa-folder-open {{ !$currentFolder && !$currentRepo ? 'text-white' : 'text-primary' }} mr-2"></i>
|
|
<span class="small">Tutti i documenti</span>
|
|
</a>
|
|
@if($cartelle->count() > 0)
|
|
@include('documenti._folder_tree', [
|
|
'cartelle' => $cartelle,
|
|
'currentFolderId' => $currentFolder ? $currentFolder->id : null,
|
|
'level' => 0,
|
|
'canWrite' => $canWriteDocumenti,
|
|
'canDelete' => $canDeleteDocumenti,
|
|
])
|
|
@elseif(!$repositories->count())
|
|
<div class="text-center text-muted py-3 small">
|
|
<i class="fas fa-folder-open d-block mb-1"></i>
|
|
Nessuna cartella
|
|
</div>
|
|
@endif
|
|
|
|
@if($repositories->count() > 0)
|
|
<div class="list-group-item list-group-item-info d-flex align-items-center py-1 bg-light">
|
|
<i class="fas fa-cloud mr-2 text-info"></i>
|
|
<span class="small font-weight-bold">Repository Remoti</span>
|
|
</div>
|
|
@foreach($repositories as $repo)
|
|
@php
|
|
$isRepoActive = $currentRepo && $currentRepo->id === $repo->id;
|
|
$repoIcon = $repo->tipo === 'webdav' ? 'fa-server' : 'fa-google-drive';
|
|
$repoColor = $repo->tipo === 'webdav' ? 'text-secondary' : 'text-danger';
|
|
@endphp
|
|
<a href="#"
|
|
onclick='event.preventDefault(); browseRepo({{ $repo->id }}, {{ json_encode($repo->nome) }}, "/"); return false;'
|
|
class="list-group-item list-group-item-action d-flex align-items-center py-2 repo-link {{ $isRepoActive ? 'active' : '' }}"
|
|
data-repo-id="{{ $repo->id }}"
|
|
style="padding-left: 40px !important;">
|
|
<i class="fab {{ $repoIcon }} {{ $isRepoActive ? 'text-white' : $repoColor }} mr-2"></i>
|
|
<span class="small text-truncate">{{ $repo->nome }}</span>
|
|
</a>
|
|
@endforeach
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Contenuto principale --}}
|
|
<div class="col-md-9">
|
|
<div class="card card-primary card-outline">
|
|
<div class="card-header">
|
|
{{-- Breadcrumb --}}
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb mb-0 p-0 bg-transparent">
|
|
<li class="breadcrumb-item">
|
|
<a href="/documenti"><i class="fas fa-home mr-1"></i>Documenti</a>
|
|
</li>
|
|
@if($currentRepo)
|
|
<li class="breadcrumb-item active">
|
|
<i class="fab {{ $currentRepo->tipo === 'webdav' ? 'fa-server' : 'fa-google-drive' }} mr-1"></i>
|
|
{{ $currentRepo->nome }}
|
|
</li>
|
|
@else
|
|
@foreach($breadcrumb as $anc)
|
|
<li class="breadcrumb-item">
|
|
<a href="/documenti?folder_id={{ $anc->id }}">{{ $anc->nome }}</a>
|
|
</li>
|
|
@endforeach
|
|
@if($currentFolder)
|
|
<li class="breadcrumb-item active">{{ $currentFolder->nome }}</li>
|
|
@endif
|
|
@endif
|
|
</ol>
|
|
</nav>
|
|
<div class="card-tools d-flex align-items-center">
|
|
<div class="btn-group btn-group-sm mr-2" role="group">
|
|
<button type="button" class="btn btn-outline-secondary" id="viewGridBtn" onclick="setView('grid')" title="Vista griglia">
|
|
<i class="fas fa-th-large"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" id="viewListBtn" onclick="setView('list')" title="Vista lista">
|
|
<i class="fas fa-list"></i>
|
|
</button>
|
|
</div>
|
|
@if($canWriteDocumenti)
|
|
<button type="button" class="btn btn-sm btn-success" onclick="$('#uploadModal').modal('show')">
|
|
<i class="fas fa-upload mr-1"></i> Carica
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
@include('partials._tag-filter-bar', ['filterTags' => $allTags])
|
|
|
|
<div class="card-body p-0">
|
|
{{-- Toolbar azioni massive --}}
|
|
<form id="massForm" method="POST">
|
|
@csrf
|
|
<input type="hidden" name="_method" id="formMethod" value="POST">
|
|
@if($canDeleteDocumenti)
|
|
<div class="p-3 bg-light border-bottom d-flex align-items-center flex-wrap gap-2">
|
|
<span class="font-weight-bold mr-2">Azioni:</span>
|
|
<button type="button" class="btn btn-sm btn-danger" onclick="massAction('delete')">
|
|
<i class="fas fa-trash mr-1"></i> Elimina selezionati
|
|
</button>
|
|
@if($canWriteDocumenti)
|
|
<button type="button" class="btn btn-sm btn-warning" onclick="$('#associateModal').modal('show')">
|
|
<i class="fas fa-link mr-1"></i> Associa a...
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-info" onclick="$('#updateModal').modal('show')">
|
|
<i class="fas fa-edit mr-1"></i> Cambia tipo/contesto
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-secondary" onclick="$('#massMoveModal').modal('show')">
|
|
<i class="fas fa-folder-open mr-1"></i> Sposta selezionati in...
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-info" onclick="$('#massTagModal').modal('show')">
|
|
<i class="fas fa-tags mr-1"></i> Tag
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-success" onclick="massDownload()">
|
|
<i class="fas fa-download mr-1"></i> Scarica
|
|
</button>
|
|
@endif
|
|
<span class="ml-auto text-muted small" id="selectedCount">0 selezionati</span>
|
|
</div>
|
|
@endif
|
|
|
|
<div id="localContent">
|
|
{{-- View: Griglia --}}
|
|
<div id="viewGrid">
|
|
<div class="row p-3">
|
|
@if($sottoCartelle->count() > 0)
|
|
@foreach($sottoCartelle as $cartella)
|
|
<div class="col-md-4 col-sm-6 mb-3">
|
|
<div class="card card-outline card-warning h-100">
|
|
<div class="card-body p-3 text-center">
|
|
<div class="py-3" style="font-size: 2.5rem;">
|
|
<i class="fas fa-folder text-warning"></i>
|
|
</div>
|
|
<h6 class="font-weight-bold text-truncate mb-0" title="{{ $cartella->nome }}">
|
|
<a href="/documenti?folder_id={{ $cartella->id }}">{{ $cartella->nome }}</a>
|
|
</h6>
|
|
</div>
|
|
@if($canWriteDocumenti || $canDeleteDocumenti)
|
|
<div class="card-footer p-2 text-center">
|
|
@if($canWriteDocumenti)
|
|
<button type="button" class="btn btn-xs btn-warning" onclick='renameFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Rinomina">
|
|
<i class="fas fa-pen"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-xs btn-info" onclick='moveFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Sposta">
|
|
<i class="fas fa-folder-open"></i>
|
|
</button>
|
|
@endif
|
|
@if($canDeleteDocumenti)
|
|
<button type="button" class="btn btn-xs btn-danger" onclick='deleteFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Elimina">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
@endif
|
|
@if($documenti->count() > 0)
|
|
@foreach($documenti as $documento)
|
|
@php
|
|
$icon = match($documento->mime_type) {
|
|
'application/pdf' => 'fa-file-pdf text-danger',
|
|
'image/jpeg','image/png','image/gif','image/webp','image/svg+xml' => 'fa-file-image text-success',
|
|
'text/plain','text/csv','text/html' => 'fa-file-alt text-info',
|
|
'application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'fa-file-word text-primary',
|
|
'application/vnd.ms-excel','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'fa-file-excel text-success',
|
|
'application/zip','application/x-rar-compressed' => 'fa-file-archive text-warning',
|
|
default => 'fa-file text-secondary',
|
|
};
|
|
@endphp
|
|
<div class="col-md-4 col-sm-6 mb-3">
|
|
<div class="card card-outline card-secondary h-100">
|
|
<div class="card-body p-3">
|
|
@if($canDeleteDocumenti)
|
|
<div class="float-right">
|
|
<input type="checkbox" name="ids[]" value="{{ $documento->id }}" class="doc-checkbox" onchange="updateCount()">
|
|
</div>
|
|
@endif
|
|
<h6 class="card-title font-weight-bold text-truncate mb-2" title="{{ $documento->nome_file }}">
|
|
{{ $documento->nome_file }}
|
|
</h6>
|
|
<div class="text-center py-2" style="font-size: 2.5rem;">
|
|
<i class="fas {{ $icon }}"></i>
|
|
</div>
|
|
<div class="text-center mb-2">
|
|
<span class="badge badge-{{ $documento->tipologia === 'avatar' ? 'primary' : ($documento->tipologia === 'galleria' ? 'success' : 'secondary') }}">
|
|
{{ ucfirst($documento->tipologia) }}
|
|
</span>
|
|
@if($documento->dimensione)
|
|
<span class="badge badge-light">
|
|
{{ number_format($documento->dimensione / 1024, 1) }} KB
|
|
</span>
|
|
@endif
|
|
</div>
|
|
<div class="text-center mb-1" style="display:flex;flex-wrap:wrap;gap:2px;justify-content:center;">
|
|
@foreach($documento->tags as $tag)
|
|
<a href="{{ route('documenti.index', ['tag[]' => $tag->slug]) }}" class="badge" style="background-color: {{ $tag->color ?? '#6c757d' }}; color: #fff; font-size:0.7rem;">{{ $tag->name }}</a>
|
|
@endforeach
|
|
</div>
|
|
<div class="small text-muted text-center">
|
|
@if($documento->user)
|
|
{{ $documento->user->name }}
|
|
@endif
|
|
· {{ $documento->created_at->format('d/m/Y') }}
|
|
</div>
|
|
</div>
|
|
<div class="card-footer p-2 text-center">
|
|
@if($documento->file_path)
|
|
<button type="button" class="btn btn-xs btn-primary" onclick="previewDoc({{ $documento->id }}, '{{ $documento->mime_type }}')" title="Anteprima">
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
<a href="/documenti/{{ $documento->id }}/download" class="btn btn-xs btn-info" title="Scarica">
|
|
<i class="fas fa-download"></i>
|
|
</a>
|
|
@endif
|
|
@if($canWriteDocumenti)
|
|
<a href="/documenti/{{ $documento->id }}/edit" class="btn btn-xs btn-warning" title="Modifica">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<button type="button" class="btn btn-xs btn-secondary" onclick="showMoveModal({{ $documento->id }}, '{{ e($documento->nome_file) }}')" title="Sposta in altra cartella">
|
|
<i class="fas fa-folder-open"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-xs btn-info" onclick="showAssociateModal({{ $documento->id }})" title="Associa a...">
|
|
<i class="fas fa-link"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-xs btn-secondary" onclick="showUpdateModal({{ $documento->id }})" title="Cambia tipo/contesto">
|
|
<i class="fas fa-tag"></i>
|
|
</button>
|
|
@endif
|
|
@if($canDeleteDocumenti)
|
|
<button type="button" class="btn btn-xs btn-danger" onclick="deleteDocumento({{ $documento->id }}, '{{ e($documento->nome_file) }}')" title="Elimina">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
@endif
|
|
</div>
|
|
@if($sottoCartelle->count() === 0 && $documenti->count() === 0)
|
|
<div class="text-center text-muted py-5">
|
|
<i class="fas {{ $currentRepo ? ($currentRepo->tipo === 'webdav' ? 'fa-server' : 'fa-google-drive') : 'fa-folder-open' }} fa-3x mb-3"></i>
|
|
<p class="mb-0">Nessun elemento presente</p>
|
|
@if($currentFolder)
|
|
<p class="small">Questa cartella è vuota</p>
|
|
@elseif($currentRepo)
|
|
<p class="small">Il repository remoto <strong>{{ $currentRepo->nome }}</strong> è vuoto</p>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- View: Lista --}}
|
|
<div id="viewList" style="display:none;">
|
|
@if($sottoCartelle->count() > 0 || $documenti->count() > 0)
|
|
<table class="table table-bordered table-hover table-striped mb-0">
|
|
<thead class="thead-light">
|
|
<tr>
|
|
@if($canDeleteDocumenti)
|
|
<th style="width: 40px;">
|
|
<input type="checkbox" id="selectAll" onchange="toggleAll(this)">
|
|
</th>
|
|
@endif
|
|
<th>Nome</th>
|
|
<th style="width: 100px;">Tipologia</th>
|
|
<th style="width: 90px;">Dimensione</th>
|
|
<th style="width: 120px;">Contesto</th>
|
|
<th style="width: 100px;">Tag</th>
|
|
<th style="width: 110px;">Data</th>
|
|
<th style="width: 130px;">Azioni</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($sottoCartelle as $cartella)
|
|
<tr class="table-warning">
|
|
@if($canDeleteDocumenti)
|
|
<td></td>
|
|
@endif
|
|
<td>
|
|
<i class="fas fa-folder text-warning mr-2"></i>
|
|
<a href="/documenti?folder_id={{ $cartella->id }}" class="font-weight-bold">{{ $cartella->nome }}</a>
|
|
<div class="small text-muted">Cartella</div>
|
|
</td>
|
|
<td><span class="badge badge-warning">Cartella</span></td>
|
|
<td class="small text-muted">-</td>
|
|
<td class="small text-muted">-</td>
|
|
<td class="small text-muted">-</td>
|
|
<td class="small text-muted">-</td>
|
|
<td>
|
|
<a href="/documenti?folder_id={{ $cartella->id }}" class="btn btn-xs btn-warning" title="Apri cartella">
|
|
<i class="fas fa-folder-open"></i>
|
|
</a>
|
|
@if($canWriteDocumenti)
|
|
<button type="button" class="btn btn-xs btn-warning" onclick='renameFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Rinomina">
|
|
<i class="fas fa-pen"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-xs btn-info" onclick='moveFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Sposta">
|
|
<i class="fas fa-folder-open"></i>
|
|
</button>
|
|
@endif
|
|
@if($canDeleteDocumenti)
|
|
<button type="button" class="btn btn-xs btn-danger" onclick='deleteFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Elimina">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
@foreach($documenti as $documento)
|
|
@php
|
|
$icon = match($documento->mime_type) {
|
|
'application/pdf' => 'fa-file-pdf text-danger',
|
|
'image/jpeg','image/png','image/gif','image/webp','image/svg+xml' => 'fa-file-image text-success',
|
|
'text/plain','text/csv','text/html' => 'fa-file-alt text-info',
|
|
'application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'fa-file-word text-primary',
|
|
'application/vnd.ms-excel','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'fa-file-excel text-success',
|
|
'application/zip','application/x-rar-compressed' => 'fa-file-archive text-warning',
|
|
default => 'fa-file text-secondary',
|
|
};
|
|
@endphp
|
|
<tr>
|
|
@if($canDeleteDocumenti)
|
|
<td>
|
|
<input type="checkbox" name="ids[]" value="{{ $documento->id }}" class="doc-checkbox" onchange="updateCount()">
|
|
</td>
|
|
@endif
|
|
<td>
|
|
<i class="fas {{ $icon }} mr-2"></i>
|
|
<span class="font-weight-bold">{{ $documento->nome_file }}</span>
|
|
<div class="small text-muted">
|
|
@if($documento->user){{ $documento->user->name }}@endif
|
|
@if($documento->cartella) in <a href="/documenti?folder_id={{ $documento->cartella_id }}" class="text-muted">{{ $documento->cartella->nome }}</a>@endif
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="badge badge-{{ $documento->tipologia === 'avatar' ? 'primary' : ($documento->tipologia === 'galleria' ? 'success' : 'secondary') }}">
|
|
{{ ucfirst($documento->tipologia) }}
|
|
</span>
|
|
</td>
|
|
<td class="small">
|
|
@if($documento->dimensione)
|
|
{{ number_format($documento->dimensione / 1024, 1) }} KB
|
|
@else
|
|
<span class="text-muted">-</span>
|
|
@endif
|
|
</td>
|
|
<td>
|
|
@switch($documento->visibilita)
|
|
@case('individuo')
|
|
@if($documento->target instanceof \App\Models\Individuo)
|
|
<a href="/individui/{{ $documento->target->id }}" class="small">
|
|
<i class="fas fa-user text-info mr-1"></i>{{ $documento->target->cognome }} {{ $documento->target->nome }}
|
|
</a>
|
|
@else
|
|
<span class="badge badge-info">Individuo</span>
|
|
@endif
|
|
@break
|
|
@case('gruppo')
|
|
@if($documento->target instanceof \App\Models\Gruppo)
|
|
<a href="/gruppi/{{ $documento->target->id }}" class="small">
|
|
<i class="fas fa-folder text-warning mr-1"></i>{{ $documento->target->nome }}
|
|
</a>
|
|
@else
|
|
<span class="badge badge-success">Gruppo</span>
|
|
@endif
|
|
@break
|
|
@case('evento')
|
|
@if($documento->target instanceof \App\Models\Evento)
|
|
<a href="/eventi/{{ $documento->target->id }}" class="small">
|
|
<i class="fas fa-calendar text-primary mr-1"></i>{{ $documento->target->nome_evento }}
|
|
</a>
|
|
@else
|
|
<span class="badge badge-warning">Evento</span>
|
|
@endif
|
|
@break
|
|
@case('mailing')
|
|
@if($documento->target instanceof \App\Models\MailingList)
|
|
<a href="/mailing-liste/{{ $documento->target->id }}" class="small">
|
|
<i class="fas fa-envelope text-secondary mr-1"></i>{{ $documento->target->nome }}
|
|
</a>
|
|
@else
|
|
<span class="badge badge-secondary">Mailing</span>
|
|
@endif
|
|
@break
|
|
@case('pubblico')
|
|
<span class="badge badge-light">Pubblico</span>
|
|
@break
|
|
@case('associazione')
|
|
<span class="badge badge-dark">Associazione</span>
|
|
@break
|
|
@case('federazione')
|
|
<span class="badge badge-purple">Federazione</span>
|
|
@break
|
|
@default
|
|
<span class="text-muted small">-</span>
|
|
@endswitch
|
|
</td>
|
|
<td>
|
|
@foreach($documento->tags as $tag)
|
|
<a href="{{ route('documenti.index', ['tag[]' => $tag->slug]) }}" class="badge" style="background-color: {{ $tag->color ?? '#6c757d' }}; color: #fff;">{{ $tag->name }}</a>
|
|
@endforeach
|
|
</td>
|
|
<td class="small">{{ $documento->created_at->format('d/m/Y') }}</td>
|
|
<td>
|
|
@if($documento->file_path)
|
|
<button type="button" class="btn btn-xs btn-primary" onclick="previewDoc({{ $documento->id }}, '{{ $documento->mime_type }}')" title="Anteprima">
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
<a href="/documenti/{{ $documento->id }}/download" class="btn btn-xs btn-info" title="Scarica">
|
|
<i class="fas fa-download"></i>
|
|
</a>
|
|
@endif
|
|
@if($canWriteDocumenti)
|
|
<a href="/documenti/{{ $documento->id }}/edit" class="btn btn-xs btn-warning" title="Modifica">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<button type="button" class="btn btn-xs btn-secondary" onclick="showMoveModal({{ $documento->id }}, '{{ e($documento->nome_file) }}')" title="Sposta in altra cartella">
|
|
<i class="fas fa-folder-open"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-xs btn-info" onclick="showAssociateModal({{ $documento->id }})" title="Associa a...">
|
|
<i class="fas fa-link"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-xs btn-secondary" onclick="showUpdateModal({{ $documento->id }})" title="Cambia tipo/contesto">
|
|
<i class="fas fa-tag"></i>
|
|
</button>
|
|
@endif
|
|
@if($canDeleteDocumenti)
|
|
<button type="button" class="btn btn-xs btn-danger" onclick="deleteDocumento({{ $documento->id }}, '{{ e($documento->nome_file) }}')" title="Elimina">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
@else
|
|
<div class="text-center text-muted py-5">
|
|
<i class="fas {{ $currentRepo ? ($currentRepo->tipo === 'webdav' ? 'fa-server' : 'fa-google-drive') : 'fa-folder-open' }} fa-3x mb-3"></i>
|
|
<p class="mb-0">Nessun elemento presente</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Paginazione --}}
|
|
@if($documenti->hasPages())
|
|
<div class="p-3 border-top">
|
|
{{ $documenti->links() }}
|
|
</div>
|
|
@endif
|
|
</div>{{-- /localContent --}}
|
|
|
|
<div id="remoteContent" style="display:none;">
|
|
<div class="p-3 border-bottom bg-light d-flex align-items-center">
|
|
<i class="fas fa-cloud mr-2 text-info"></i>
|
|
<span id="remoteBreadcrumb" class="small font-weight-bold"></span>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary ml-auto" onclick="showLocalContent()">
|
|
<i class="fas fa-folder mr-1"></i> Documenti locali
|
|
</button>
|
|
</div>
|
|
<div id="remoteGrid" class="row p-3"></div>
|
|
<div id="remoteList" style="display:none;"></div>
|
|
<div id="remoteEmpty" class="text-center text-muted py-5" style="display:none;">
|
|
<i class="fas fa-folder-open fa-3x mb-3"></i>
|
|
<p class="mb-0">Repository vuoto</p>
|
|
</div>
|
|
<div id="remoteLoading" class="text-center py-5" style="display:none;">
|
|
<i class="fas fa-spinner fa-spin fa-3x text-muted"></i>
|
|
<p class="mt-2 text-muted">Caricamento contenuti remoti...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>{{-- /massForm --}}
|
|
|
|
{{-- MODAL: Nuova Cartella --}}
|
|
<div class="modal fade" id="newFolderModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-folder-plus mr-2"></i>Nuova Cartella</h5>
|
|
<button type="button" class="close" onclick="$('#newFolderModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<form id="newFolderForm">
|
|
@csrf
|
|
<div class="modal-body">
|
|
<div class="form-group">
|
|
<label>Nome cartella *</label>
|
|
<input type="text" name="nome" class="form-control" placeholder="Nome della cartella" required>
|
|
</div>
|
|
@if($currentFolder)
|
|
<input type="hidden" name="parent_id" value="{{ $currentFolder->id }}">
|
|
<p class="text-muted small mb-0">Sarà creata all'interno di: <strong>{{ $currentFolder->nome }}</strong></p>
|
|
@else
|
|
<p class="text-muted small mb-0">Sarà creata nella radice</p>
|
|
@endif
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#newFolderModal').modal('hide')">Annulla</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save mr-1"></i> Crea
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Upload --}}
|
|
<div class="modal fade" id="uploadModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-upload mr-2"></i>Carica Documento</h5>
|
|
<button type="button" class="close" onclick="$('#uploadModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form action="/documenti" method="POST" enctype="multipart/form-data" id="uploadForm">
|
|
@csrf
|
|
<div class="form-group">
|
|
<label>Nome *</label>
|
|
<input type="text" name="nome_file" class="form-control" placeholder="Nome del documento" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Tipologia *</label>
|
|
<select name="tipologia" class="form-control" required>
|
|
@foreach($tipologie as $tip)
|
|
<option value="{{ $tip->nome }}">{{ $tip->descrizione ?? ucfirst($tip->nome) }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Visibilità *</label>
|
|
<select name="visibilita" id="uploadVisibilita" class="form-control" onchange="loadUploadTargets()">
|
|
<option value="pubblico">Pubblico</option>
|
|
<option value="individuo">Individuo</option>
|
|
<option value="gruppo">Gruppo</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" id="uploadTargetGroup" style="display:none;">
|
|
<label>Riferimento</label>
|
|
<select name="visibilita_target_id" class="form-control" id="uploadTargetId">
|
|
<option value="">Seleziona...</option>
|
|
</select>
|
|
<input type="hidden" name="visibilita_target_type" id="uploadTargetType">
|
|
</div>
|
|
@if($repositories->count() > 0)
|
|
<div class="form-group">
|
|
<label>Repository di destinazione</label>
|
|
<select name="repository_id" id="uploadRepository" class="form-control" onchange="toggleUploadRepo()">
|
|
<option value="">Locale (predefinito)</option>
|
|
@foreach($repositories as $repo)
|
|
<option value="{{ $repo->id }}" {{ $currentRepo && $currentRepo->id === $repo->id ? 'selected' : '' }}>
|
|
<i class="fas {{ $repo->tipo === 'webdav' ? 'fa-server' : 'fa-google-drive' }}"></i>
|
|
{{ $repo->nome }} ({{ \App\Models\StorageRepository::etichettaTipo($repo->tipo) }})
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
<small class="text-muted">Seleziona un repository remoto o lascia "Locale" per il salvataggio predefinito</small>
|
|
</div>
|
|
@endif
|
|
<div class="form-group">
|
|
<label>File *</label>
|
|
<input type="file" name="file" class="form-control" required>
|
|
<small class="text-muted">Max 10MB</small>
|
|
</div>
|
|
<div class="form-group" id="uploadFolderGroup">
|
|
<label>Cartella</label>
|
|
<select name="cartella_id" id="uploadCartellaId" class="form-control">
|
|
<option value="">— Nessuna cartella —</option>
|
|
@foreach($cartelle as $cartella)
|
|
<option value="{{ $cartella->id }}" {{ $currentFolder && $currentFolder->id === $cartella->id ? 'selected' : '' }}>{{ $cartella->nome }}</option>
|
|
@if($cartella->children->count() > 0)
|
|
@foreach($cartella->children as $child)
|
|
<option value="{{ $child->id }}" {{ $currentFolder && $currentFolder->id === $child->id ? 'selected' : '' }}> {{ $child->nome }}</option>
|
|
@endforeach
|
|
@endif
|
|
@endforeach
|
|
</select>
|
|
<button type="button" class="btn btn-sm btn-outline-success mt-2" id="uploadNewFolderBtn">
|
|
<i class="fas fa-plus mr-1"></i> Nuova cartella
|
|
</button>
|
|
</div>
|
|
@if($currentRepo)
|
|
<input type="hidden" name="repository_id" value="{{ $currentRepo->id }}">
|
|
<p class="text-muted small mb-0">Caricamento su repository remoto: <strong>{{ $currentRepo->nome }}</strong></p>
|
|
@endif
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#uploadModal').modal('hide')">Annulla</button>
|
|
<button type="submit" class="btn btn-primary" form="uploadForm">
|
|
<i class="fas fa-upload mr-1"></i> Carica
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Associa --}}
|
|
<div class="modal fade" id="associateModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-link mr-2"></i>Associa a</h5>
|
|
<button type="button" class="close" onclick="$('#associateModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="associateForm" method="POST" action="/documenti/mass-associate">
|
|
@csrf
|
|
<div class="form-group">
|
|
<label>Tipo collegamento</label>
|
|
<select name="target_type" class="form-control" required onchange="loadTargets(this.value)">
|
|
<option value="">Seleziona...</option>
|
|
<option value="individuo">Individuo</option>
|
|
<option value="gruppo">Gruppo</option>
|
|
<option value="evento">Evento</option>
|
|
<option value="mailing">Mailing List</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Riferimento</label>
|
|
<select name="target_id" class="form-control" required id="targetSelect">
|
|
<option value="">Seleziona prima il tipo...</option>
|
|
</select>
|
|
</div>
|
|
<input type="hidden" name="ids" id="associateIds">
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#associateModal').modal('hide')">Annulla</button>
|
|
<button type="button" class="btn btn-primary" onclick="submitAssociate()">Associa</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Cambia tipo/contesto --}}
|
|
<div class="modal fade" id="updateModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-edit mr-2"></i>Cambia tipo/contesto</h5>
|
|
<button type="button" class="close" onclick="$('#updateModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="updateForm" method="POST" action="/documenti/mass-update">
|
|
@csrf
|
|
<div class="form-group">
|
|
<label>Nuova tipologia</label>
|
|
<select name="tipologia" class="form-control">
|
|
<option value="">Non modificare</option>
|
|
@foreach($tipologie as $tip)
|
|
<option value="{{ $tip->nome }}">{{ $tip->descrizione ?? ucfirst($tip->nome) }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Nuovo contesto</label>
|
|
<select name="visibilita" id="updateVisibilita" class="form-control" onchange="toggleUpdateTarget(this.value)">
|
|
<option value="">Non modificare</option>
|
|
<option value="pubblico">Pubblico</option>
|
|
<option value="individuo">Individuo</option>
|
|
<option value="gruppo">Gruppo</option>
|
|
<option value="evento">Evento</option>
|
|
<option value="associazione">Associazione</option>
|
|
<option value="federazione">Federazione</option>
|
|
<option value="mailing">Mailing List</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" id="updateTargetGroup" style="display:none;">
|
|
<label>Elemento collegato</label>
|
|
<select name="visibilita_target_id" class="form-control" id="updateTargetSelect">
|
|
<option value="">Seleziona...</option>
|
|
</select>
|
|
<input type="hidden" name="visibilita_target_type" id="updateTargetType">
|
|
</div>
|
|
<input type="hidden" name="ids" id="updateIds">
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#updateModal').modal('hide')">Annulla</button>
|
|
<button type="button" class="btn btn-primary" onclick="submitUpdate()">Aggiorna</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Preview --}}
|
|
<div class="modal fade" id="previewModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-lg" style="max-width: 90vw;">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-eye mr-2"></i>Anteprima</h5>
|
|
<button type="button" class="close" data-dismiss="modal">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body p-0" style="min-height: 400px;">
|
|
<iframe id="previewFrame" src="" style="width: 100%; height: 70vh; border: none;"></iframe>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<a id="previewDownloadBtn" href="#" class="btn btn-primary" download>
|
|
<i class="fas fa-download mr-1"></i> Scarica
|
|
</a>
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Chiudi</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Conferma eliminazione singola --}}
|
|
<div class="modal fade" id="deleteConfirmModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-danger text-white">
|
|
<h5 class="modal-title"><i class="fas fa-exclamation-triangle mr-2"></i>Conferma Eliminazione</h5>
|
|
<button type="button" class="close text-white" onclick="$('#deleteConfirmModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p id="deleteConfirmMessage"></p>
|
|
<div id="deleteConfirmLinks" class="mt-3"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#deleteConfirmModal').modal('hide')">Annulla</button>
|
|
<button type="button" class="btn btn-danger" id="confirmDeleteBtn">
|
|
<i class="fas fa-trash mr-1"></i> Elimina comunque
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Conferma eliminazione multipla --}}
|
|
<div class="modal fade" id="massDeleteConfirmModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-danger text-white">
|
|
<h5 class="modal-title"><i class="fas fa-exclamation-triangle mr-2"></i>Conferma Eliminazione Multipla</h5>
|
|
<button type="button" class="close text-white" onclick="$('#massDeleteConfirmModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>Stai per eliminare <strong id="massDeleteCount">0</strong> documenti.</p>
|
|
<div id="massDeleteLinks" class="mt-3"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#massDeleteConfirmModal').modal('hide')">Annulla</button>
|
|
<button type="button" class="btn btn-danger" id="confirmMassDeleteBtn">
|
|
<i class="fas fa-trash mr-1"></i> Elimina comunque
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Sposta massivo --}}
|
|
<div class="modal fade" id="massMoveModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-folder-open mr-2"></i>Sposta documenti selezionati</h5>
|
|
<button type="button" class="close" onclick="$('#massMoveModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<form id="massMoveForm">
|
|
@csrf
|
|
<input type="hidden" name="ids" id="massMoveIds">
|
|
<div class="modal-body">
|
|
<p>Spostare <strong id="massMoveCount">0</strong> documenti nella cartella:</p>
|
|
<div class="form-group">
|
|
<label>Cartella di destinazione</label>
|
|
<select name="cartella_id" class="form-control">
|
|
<option value="">— Radice (nessuna cartella) —</option>
|
|
@foreach(\App\Models\DocumentoCartella::with('children')->whereNull('parent_id')->orderBy('nome')->get() as $cartella)
|
|
<option value="{{ $cartella->id }}">{{ $cartella->nome }}</option>
|
|
@if($cartella->children->count() > 0)
|
|
@foreach($cartella->children as $child)
|
|
<option value="{{ $child->id }}"> {{ $child->nome }}</option>
|
|
@endforeach
|
|
@endif
|
|
@endforeach
|
|
</select>
|
|
<button type="button" class="btn btn-sm btn-outline-success mt-2" id="massMoveNewFolderBtn">
|
|
<i class="fas fa-plus mr-1"></i> Nuova cartella
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#massMoveModal').modal('hide')">Annulla</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-folder-open mr-1"></i> Sposta
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Gestione Tag massiva --}}
|
|
<div class="modal fade" id="massTagModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-tags mr-2"></i>Gestione Tag</h5>
|
|
<button type="button" class="close" onclick="$('#massTagModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<form id="massTagForm" method="POST" action="/documenti/mass-tag">
|
|
@csrf
|
|
<div class="modal-body">
|
|
<p class="mb-2">Operazione su <strong id="massTagCount">0</strong> documenti selezionati.</p>
|
|
|
|
<div class="form-group mb-3">
|
|
<label class="font-weight-bold">Azione</label>
|
|
<div class="d-flex" style="gap:1.5rem;">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="mode" id="mtModeAssign" value="assign" checked>
|
|
<label class="form-check-label" for="mtModeAssign">Assegna tag</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="mode" id="mtModeRemove" value="remove">
|
|
<label class="form-check-label" for="mtModeRemove">Rimuovi tag</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@include('partials._tag-selector', ['label' => 'Seleziona tag'])
|
|
|
|
<input type="hidden" name="ids" id="massTagIds" value="">
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#massTagModal').modal('hide')">Annulla</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-tags mr-1"></i> Applica
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- MODAL: Sposta documento --}}
|
|
<div class="modal fade" id="moveModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-folder-open mr-2"></i>Sposta documento</h5>
|
|
<button type="button" class="close" onclick="$('#moveModal').modal('hide')">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<form id="moveForm">
|
|
@csrf
|
|
<input type="hidden" name="documento_id" id="moveDocumentoId">
|
|
<div class="modal-body">
|
|
<p>Spostare il documento <strong id="moveDocumentoNome"></strong> in:</p>
|
|
<div class="form-group">
|
|
<label>Cartella di destinazione</label>
|
|
<select name="cartella_id" id="moveCartellaId" class="form-control">
|
|
<option value="">— Radice (nessuna cartella) —</option>
|
|
@foreach(\App\Models\DocumentoCartella::with('children')->whereNull('parent_id')->orderBy('nome')->get() as $cartella)
|
|
<option value="{{ $cartella->id }}">{{ $cartella->nome }}</option>
|
|
@if($cartella->children->count() > 0)
|
|
@foreach($cartella->children as $child)
|
|
<option value="{{ $child->id }}"> {{ $child->nome }}</option>
|
|
@endforeach
|
|
@endif
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="$('#moveModal').modal('hide')">Annulla</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-folder-open mr-1"></i> Sposta
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script>
|
|
const individui = @json($individui->map(fn($i) => ['id' => $i->id, 'label' => $i->cognome . ' ' . $i->nome]));
|
|
const gruppi = @json($gruppi->map(fn($g) => ['id' => $g->id, 'label' => $g->nome]));
|
|
const eventi = @json($eventi->map(fn($e) => ['id' => $e->id, 'label' => $e->nome_evento]));
|
|
const mailingLists = @json($mailingLists ? $mailingLists->map(fn($m) => ['id' => $m->id, 'label' => $m->nome]) : []);
|
|
const cartelle = @json($cartelleMoveOptions);
|
|
|
|
$('#uploadModal').on('shown.bs.modal', function () {
|
|
loadUploadTargets();
|
|
toggleUploadRepo();
|
|
});
|
|
|
|
$('#newFolderModal').on('show.bs.modal', function () {
|
|
$(this).css('z-index', 1060);
|
|
$('.modal-backdrop:last').css('z-index', 1050);
|
|
});
|
|
|
|
$('#newFolderModal').on('hidden.bs.modal', function () {
|
|
window._uploadNewFolder = false;
|
|
$(this).css('z-index', '');
|
|
});
|
|
|
|
function toggleAll(source) {
|
|
document.querySelectorAll('.doc-checkbox').forEach(cb => cb.checked = source.checked);
|
|
updateCount();
|
|
}
|
|
|
|
function updateCount() {
|
|
const count = document.querySelectorAll('.doc-checkbox:checked').length;
|
|
document.getElementById('selectedCount').textContent = count + ' selezionati';
|
|
}
|
|
|
|
function getSelectedIds() {
|
|
return Array.from(document.querySelectorAll('.doc-checkbox:checked')).map(cb => cb.value);
|
|
}
|
|
|
|
let pendingMassDeleteIds = [];
|
|
|
|
function massAction(action) {
|
|
const ids = getSelectedIds();
|
|
if (ids.length === 0) {
|
|
alert('Seleziona almeno un documento');
|
|
return;
|
|
}
|
|
|
|
if (action === 'delete') {
|
|
fetch('/documenti/check-links', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: JSON.stringify({ ids: ids })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
pendingMassDeleteIds = ids;
|
|
document.getElementById('massDeleteCount').textContent = ids.length;
|
|
|
|
if (data.linked_count > 0) {
|
|
let linksHtml = '<div class="alert alert-warning mb-0"><p><strong>Attenzione:</strong> ' + data.linked_count + ' documento(i) sono collegati a elementi nel database:</p><ul class="mb-0">';
|
|
data.links.forEach(function(link) {
|
|
if (link.url) {
|
|
linksHtml += '<li><a href="' + link.url + '" target="_blank">' + link.name + '</a></li>';
|
|
} else {
|
|
linksHtml += '<li>' + link.name + '</li>';
|
|
}
|
|
});
|
|
linksHtml += '</ul></div>';
|
|
document.getElementById('massDeleteLinks').innerHTML = linksHtml;
|
|
} else {
|
|
document.getElementById('massDeleteLinks').innerHTML = '<div class="alert alert-info mb-0">Nessun documento risulta collegato.</div>';
|
|
}
|
|
|
|
document.getElementById('confirmMassDeleteBtn').onclick = function() { performMassDelete(); };
|
|
$('#massDeleteConfirmModal').modal('show');
|
|
})
|
|
.catch(error => {
|
|
alert('Errore controllo collegamenti: ' + error.message);
|
|
});
|
|
}
|
|
}
|
|
|
|
function massDownload() {
|
|
const ids = getSelectedIds();
|
|
if (ids.length === 0) {
|
|
alert('Seleziona almeno un documento');
|
|
return;
|
|
}
|
|
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = '/documenti/mass-download';
|
|
const csrf = document.createElement('input');
|
|
csrf.type = 'hidden';
|
|
csrf.name = '_token';
|
|
csrf.value = '{{ csrf_token() }}';
|
|
form.appendChild(csrf);
|
|
ids.forEach(id => {
|
|
const input = document.createElement('input');
|
|
input.type = 'hidden';
|
|
input.name = 'ids[]';
|
|
input.value = id;
|
|
form.appendChild(input);
|
|
});
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
document.body.removeChild(form);
|
|
}
|
|
|
|
function performMassDelete() {
|
|
const ids = pendingMassDeleteIds;
|
|
$('#massDeleteConfirmModal').modal('hide');
|
|
|
|
fetch('/documenti/mass-destroy', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: 'ids=' + ids.join(',')
|
|
})
|
|
.then(response => {
|
|
if (response.redirected) {
|
|
window.location.href = response.url;
|
|
} else {
|
|
window.location.reload();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Errore: ' + error.message);
|
|
});
|
|
}
|
|
|
|
function deleteDocumento(id, nomeFile) {
|
|
fetch('/documenti/' + id + '/check-links', {
|
|
method: 'GET',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Accept': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.has_links) {
|
|
let linksHtml = '<div class="alert alert-warning mb-0"><p class="mb-2"><strong>Attenzione:</strong> Questo documento è collegato a:</p><ul class="mb-0">';
|
|
data.links.forEach(function(link) {
|
|
if (link.url) {
|
|
linksHtml += '<li><a href="' + link.url + '" target="_blank">' + link.name + '</a></li>';
|
|
} else {
|
|
linksHtml += '<li>' + link.name + '</li>';
|
|
}
|
|
});
|
|
linksHtml += '</ul></div>';
|
|
document.getElementById('deleteConfirmLinks').innerHTML = linksHtml;
|
|
document.getElementById('deleteConfirmMessage').textContent = 'Eliminare il documento "' + nomeFile + '"?';
|
|
document.getElementById('confirmDeleteBtn').onclick = function() { performDelete(id); };
|
|
$('#deleteConfirmModal').modal('show');
|
|
} else {
|
|
if (confirm('Eliminare il documento "' + nomeFile + '"?')) {
|
|
performDelete(id);
|
|
}
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Errore: ' + error.message);
|
|
});
|
|
}
|
|
|
|
function performDelete(id) {
|
|
fetch('/documenti/' + id, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: '_method=DELETE'
|
|
})
|
|
.then(response => {
|
|
if (response.redirected) {
|
|
window.location.href = response.url;
|
|
} else {
|
|
window.location.reload();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Errore: ' + error.message);
|
|
});
|
|
}
|
|
|
|
function previewDoc(id, mimeType) {
|
|
document.getElementById('previewFrame').src = '/documenti/' + id + '/preview';
|
|
document.getElementById('previewDownloadBtn').href = '/documenti/' + id + '/download';
|
|
$('#previewModal').modal('show');
|
|
}
|
|
|
|
function loadUploadTargets() {
|
|
const visibilita = document.getElementById('uploadVisibilita').value;
|
|
const group = document.getElementById('uploadTargetGroup');
|
|
const select = document.getElementById('uploadTargetId');
|
|
const type = document.getElementById('uploadTargetType');
|
|
|
|
if (visibilita === 'pubblico') {
|
|
group.style.display = 'none';
|
|
select.innerHTML = '<option value="">Seleziona...</option>';
|
|
type.value = '';
|
|
return;
|
|
}
|
|
|
|
group.style.display = 'block';
|
|
let data = [];
|
|
if (visibilita === 'individuo') {
|
|
data = individui;
|
|
type.value = 'individuo';
|
|
} else if (visibilita === 'gruppo') {
|
|
data = gruppi;
|
|
type.value = 'gruppo';
|
|
}
|
|
|
|
select.innerHTML = '<option value="">Seleziona...</option>';
|
|
data.forEach(item => {
|
|
const opt = document.createElement('option');
|
|
opt.value = item.id;
|
|
opt.textContent = item.label;
|
|
select.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
function loadTargets(type) {
|
|
const select = document.getElementById('targetSelect');
|
|
select.innerHTML = '<option value="">Caricamento...</option>';
|
|
|
|
let data = [];
|
|
if (type === 'individuo') data = individui;
|
|
else if (type === 'gruppo') data = gruppi;
|
|
else if (type === 'evento') data = eventi;
|
|
else if (type === 'mailing') data = mailingLists;
|
|
|
|
select.innerHTML = '<option value="">Seleziona...</option>';
|
|
data.forEach(item => {
|
|
const opt = document.createElement('option');
|
|
opt.value = item.id;
|
|
opt.textContent = item.label;
|
|
select.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
function submitAssociate() {
|
|
const ids = getSelectedIds();
|
|
if (ids.length === 0) {
|
|
alert('Seleziona almeno un documento');
|
|
return;
|
|
}
|
|
const targetType = document.querySelector('#associateForm select[name="target_type"]').value;
|
|
const targetId = document.getElementById('targetSelect').value;
|
|
if (!targetType || !targetId) {
|
|
alert('Seleziona tipo e riferimento');
|
|
return;
|
|
}
|
|
document.getElementById('associateIds').value = ids.join(',');
|
|
document.getElementById('associateForm').submit();
|
|
}
|
|
|
|
function toggleUpdateTarget(value) {
|
|
const group = document.getElementById('updateTargetGroup');
|
|
const select = document.getElementById('updateTargetSelect');
|
|
const type = document.getElementById('updateTargetType');
|
|
|
|
if (!value || value === 'pubblico' || value === 'associazione' || value === 'federazione') {
|
|
group.style.display = 'none';
|
|
select.innerHTML = '<option value="">Seleziona...</option>';
|
|
type.value = '';
|
|
return;
|
|
}
|
|
|
|
group.style.display = 'block';
|
|
let data = [];
|
|
let targetType = '';
|
|
if (value === 'individuo') { data = individui; targetType = 'individuo'; }
|
|
else if (value === 'gruppo') { data = gruppi; targetType = 'gruppo'; }
|
|
else if (value === 'evento') { data = eventi; targetType = 'evento'; }
|
|
else if (value === 'mailing') { data = mailingLists; targetType = 'mailing'; }
|
|
|
|
type.value = targetType;
|
|
select.innerHTML = '<option value="">Seleziona...</option>';
|
|
data.forEach(item => {
|
|
const opt = document.createElement('option');
|
|
opt.value = item.id;
|
|
opt.textContent = item.label;
|
|
select.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
function submitUpdate() {
|
|
const ids = getSelectedIds();
|
|
if (ids.length === 0) {
|
|
alert('Seleziona almeno un documento');
|
|
return;
|
|
}
|
|
const tipologia = document.querySelector('#updateForm select[name="tipologia"]').value;
|
|
const visibilita = document.querySelector('#updateForm select[name="visibilita"]').value;
|
|
if (!tipologia && !visibilita) {
|
|
alert('Seleziona almeno una tipologia o un contesto da modificare');
|
|
return;
|
|
}
|
|
document.getElementById('updateIds').value = ids.join(',');
|
|
document.getElementById('updateForm').submit();
|
|
}
|
|
|
|
// Associa documento singolo
|
|
function showAssociateModal(id) {
|
|
document.getElementById('associateIds').value = id;
|
|
document.querySelector('#associateForm select[name="target_type"]').value = '';
|
|
document.getElementById('targetSelect').innerHTML = '<option value="">Seleziona prima il tipo...</option>';
|
|
$('#associateModal').modal('show');
|
|
}
|
|
|
|
// Cambia tipo/contesto documento singolo
|
|
function showUpdateModal(id) {
|
|
document.getElementById('updateIds').value = id;
|
|
document.querySelector('#updateForm select[name="tipologia"]').value = '';
|
|
document.querySelector('#updateForm select[name="visibilita"]').value = '';
|
|
document.getElementById('updateTargetGroup').style.display = 'none';
|
|
document.getElementById('updateTargetSelect').innerHTML = '<option value="">Seleziona...</option>';
|
|
$('#updateModal').modal('show');
|
|
}
|
|
|
|
// Sposta documento
|
|
function showMoveModal(id, nome) {
|
|
document.getElementById('moveDocumentoId').value = id;
|
|
document.getElementById('moveDocumentoNome').textContent = nome;
|
|
$('#moveModal').modal('show');
|
|
}
|
|
|
|
document.getElementById('massMoveModal')?.addEventListener('show.bs.modal', function() {
|
|
const ids = getSelectedIds();
|
|
document.getElementById('massMoveIds').value = ids.join(',');
|
|
document.getElementById('massMoveCount').textContent = ids.length;
|
|
});
|
|
|
|
document.getElementById('massTagModal')?.addEventListener('show.bs.modal', function() {
|
|
const ids = getSelectedIds();
|
|
document.getElementById('massTagIds').value = ids.join(',');
|
|
document.getElementById('massTagCount').textContent = ids.length;
|
|
});
|
|
|
|
document.getElementById('massMoveNewFolderBtn')?.addEventListener('click', function() {
|
|
Swal.fire({
|
|
title: 'Nuova cartella',
|
|
input: 'text',
|
|
inputLabel: 'Nome della cartella',
|
|
inputPlaceholder: 'Inserisci il nome...',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Crea',
|
|
cancelButtonText: 'Annulla',
|
|
confirmButtonColor: '#28a745',
|
|
inputValidator: (value) => {
|
|
if (!value || !value.trim()) {
|
|
return 'Il nome non può essere vuoto';
|
|
}
|
|
},
|
|
preConfirm: (nome) => {
|
|
return fetch('/documenti/cartelle', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: 'nome=' + encodeURIComponent(nome.trim()),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
return response.json().then(err => { throw new Error(err.message || 'Errore creazione cartella'); });
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (!data.success) {
|
|
throw new Error(data.message || 'Errore creazione cartella');
|
|
}
|
|
return data;
|
|
})
|
|
.catch(error => {
|
|
Swal.showValidationMessage(error.message);
|
|
});
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
const data = result.value;
|
|
const select = document.querySelector('#massMoveModal select[name="cartella_id"]');
|
|
const opt = document.createElement('option');
|
|
opt.value = data.cartella.id;
|
|
opt.textContent = data.cartella.nome;
|
|
opt.selected = true;
|
|
select.appendChild(opt);
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Cartella creata',
|
|
text: 'Cartella "' + data.cartella.nome + '" creata e selezionata.',
|
|
timer: 2000,
|
|
showConfirmButton: false,
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
document.getElementById('uploadNewFolderBtn')?.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
window._uploadNewFolder = true;
|
|
$('#uploadModal').modal('hide');
|
|
$('#newFolderModal').modal('show');
|
|
});
|
|
|
|
document.getElementById('massMoveForm')?.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
const form = this;
|
|
const formData = new FormData(form);
|
|
|
|
fetch('/documenti/mass-move', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
},
|
|
body: formData,
|
|
})
|
|
.then(response => {
|
|
if (response.redirected) {
|
|
window.location.href = response.url;
|
|
} else {
|
|
window.location.reload();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Errore: ' + error.message);
|
|
});
|
|
});
|
|
|
|
document.getElementById('moveForm')?.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
const form = this;
|
|
const formData = new FormData(form);
|
|
const id = document.getElementById('moveDocumentoId').value;
|
|
|
|
fetch('/documenti/' + id + '/move', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: formData,
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
$('#moveModal').modal('hide');
|
|
window.location.reload();
|
|
} else {
|
|
alert('Errore: ' + (data.message || 'Impossibile spostare il documento'));
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Errore: ' + error.message);
|
|
});
|
|
});
|
|
|
|
// Toggle vista griglia/lista
|
|
function setView(view) {
|
|
localStorage.setItem('documenti_view', view);
|
|
var isGrid = view === 'grid';
|
|
document.getElementById('viewGrid').style.display = isGrid ? '' : 'none';
|
|
document.getElementById('viewList').style.display = isGrid ? 'none' : '';
|
|
document.getElementById('viewGridBtn').classList.toggle('active', isGrid);
|
|
document.getElementById('viewListBtn').classList.toggle('active', !isGrid);
|
|
if (currentRepoBrowse) {
|
|
loadRemoteContents(currentRepoBrowse.id, currentRepoBrowse.path);
|
|
}
|
|
}
|
|
|
|
// Init vista da localStorage
|
|
(function() {
|
|
const saved = localStorage.getItem('documenti_view');
|
|
if (saved === 'list') {
|
|
setView('list');
|
|
} else {
|
|
setView('grid');
|
|
}
|
|
})();
|
|
|
|
// Nuova cartella AJAX
|
|
document.getElementById('newFolderForm')?.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
const form = this;
|
|
const formData = new FormData(form);
|
|
|
|
fetch('/documenti/cartelle', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: formData,
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
if (window._uploadNewFolder) {
|
|
window._uploadNewFolder = false;
|
|
$('#newFolderModal').modal('hide');
|
|
$('#uploadModal').modal('show');
|
|
const select = document.getElementById('uploadCartellaId');
|
|
if (select) {
|
|
const opt = document.createElement('option');
|
|
opt.value = data.cartella.id;
|
|
opt.textContent = data.cartella.nome;
|
|
opt.selected = true;
|
|
select.appendChild(opt);
|
|
}
|
|
} else {
|
|
window.location.reload();
|
|
}
|
|
} else {
|
|
alert('Errore: ' + (data.message || 'Impossibile creare la cartella'));
|
|
}
|
|
})
|
|
.catch(error => {
|
|
alert('Errore: ' + error.message);
|
|
});
|
|
});
|
|
|
|
function toggleUploadRepo() {
|
|
const repoSelect = document.getElementById('uploadRepository');
|
|
const folderGroup = document.getElementById('uploadFolderGroup');
|
|
const cartellaSelect = document.getElementById('uploadCartellaId');
|
|
if (repoSelect && repoSelect.value !== '') {
|
|
if (folderGroup) folderGroup.style.display = 'none';
|
|
if (cartellaSelect) cartellaSelect.disabled = true;
|
|
} else {
|
|
if (folderGroup) folderGroup.style.display = '';
|
|
if (cartellaSelect) cartellaSelect.disabled = false;
|
|
}
|
|
}
|
|
|
|
// === Remote Repository AJAX Browser ===
|
|
var currentRepoBrowse = null;
|
|
|
|
function showLocalContent() {
|
|
document.getElementById('localContent').style.display = '';
|
|
document.getElementById('remoteContent').style.display = 'none';
|
|
document.querySelectorAll('.repo-link').forEach(el => el.classList.remove('active'));
|
|
currentRepoBrowse = null;
|
|
}
|
|
|
|
function browseRepo(repoId, repoNome, path) {
|
|
currentRepoBrowse = { id: repoId, nome: repoNome, path: path };
|
|
document.getElementById('localContent').style.display = 'none';
|
|
document.getElementById('remoteContent').style.display = 'block';
|
|
document.querySelectorAll('.repo-link').forEach(el => el.classList.remove('active'));
|
|
const link = document.querySelector('.repo-link[data-repo-id="' + repoId + '"]');
|
|
if (link) link.classList.add('active');
|
|
updateRemoteBreadcrumb(repoNome, path);
|
|
loadRemoteContents(repoId, path);
|
|
}
|
|
|
|
function updateRemoteBreadcrumb(nome, path) {
|
|
const bc = document.getElementById('remoteBreadcrumb');
|
|
const parts = path.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
|
|
let html = '<i class="' + (currentRepoBrowse && currentRepoBrowse.id ? repoIconFromId(currentRepoBrowse.id) : 'fa fa-server') + ' mr-1"></i> ' + escHtml(nome);
|
|
if (parts.length > 0 && parts[0] !== '') {
|
|
html += ' / ' + parts.map(p => escHtml(p)).join(' / ');
|
|
}
|
|
bc.innerHTML = html;
|
|
}
|
|
|
|
function repoIconFromId(repoId) {
|
|
const link = document.querySelector('.repo-link[data-repo-id="' + repoId + '"]');
|
|
if (!link) return 'fa-server';
|
|
const icon = link.querySelector('i');
|
|
return icon ? icon.className : 'fa-server';
|
|
}
|
|
|
|
function loadRemoteContents(repoId, path) {
|
|
document.getElementById('remoteGrid').innerHTML = '';
|
|
document.getElementById('remoteList').innerHTML = '';
|
|
document.getElementById('remoteEmpty').style.display = 'none';
|
|
document.getElementById('remoteLoading').style.display = 'block';
|
|
const view = localStorage.getItem('documenti_view') || 'grid';
|
|
|
|
const url = '/storage-repositories/' + repoId + '/browse?path=' + encodeURIComponent(path);
|
|
console.log('Loading remote contents from:', url);
|
|
|
|
fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
}
|
|
})
|
|
.then(response => {
|
|
console.log('Response status:', response.status);
|
|
if (!response.ok) {
|
|
throw new Error('HTTP Error: ' + response.status);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
console.log('Data received:', data);
|
|
document.getElementById('remoteLoading').style.display = 'none';
|
|
if (data.success && data.contents !== undefined) {
|
|
console.log('Contents count:', data.contents.length);
|
|
renderRemoteContents(data.contents, repoId, path, view);
|
|
} else if (data.contents !== undefined && data.contents.length === 0) {
|
|
document.getElementById('remoteEmpty').style.display = 'block';
|
|
document.getElementById('remoteEmpty').querySelector('p').textContent = 'Cartella vuota';
|
|
} else {
|
|
document.getElementById('remoteEmpty').style.display = 'block';
|
|
const msg = data.message || 'Errore caricamento repository.';
|
|
console.error('Error response:', msg);
|
|
document.getElementById('remoteEmpty').querySelector('p').textContent = msg;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
document.getElementById('remoteLoading').style.display = 'none';
|
|
document.getElementById('remoteEmpty').style.display = 'block';
|
|
console.error('Fetch error:', error);
|
|
document.getElementById('remoteEmpty').querySelector('p').textContent = 'Errore: ' + error.message;
|
|
});
|
|
}
|
|
|
|
function renderRemoteContents(contents, repoId, currentPath, view) {
|
|
contents.sort(function(a, b) {
|
|
if (a.type === 'dir' && b.type !== 'dir') return -1;
|
|
if (b.type === 'dir' && a.type !== 'dir') return 1;
|
|
return (a.basename || '').localeCompare(b.basename || '');
|
|
});
|
|
|
|
if (contents.length === 0) {
|
|
document.getElementById('remoteEmpty').style.display = 'block';
|
|
document.getElementById('remoteEmpty').querySelector('p').textContent = 'Cartella vuota';
|
|
return;
|
|
}
|
|
|
|
var gridContainer = document.getElementById('remoteGrid');
|
|
var listContainer = document.getElementById('remoteList');
|
|
gridContainer.innerHTML = '';
|
|
listContainer.innerHTML = '';
|
|
|
|
if (view === 'grid') {
|
|
document.getElementById('remoteGrid').style.display = '';
|
|
document.getElementById('remoteList').style.display = 'none';
|
|
var html = '';
|
|
contents.forEach(function(item) {
|
|
if (item.type === 'dir') {
|
|
html += '<div class="col-md-4 col-sm-6 mb-3">';
|
|
html += '<div class="card card-outline card-warning h-100" style="cursor:pointer;" onclick="browseRepo(' + repoId + ',\'' + escJs(currentRepoBrowse ? currentRepoBrowse.nome : '') + '\',\'' + escJs(item.path) + '\')">';
|
|
html += '<div class="card-body p-3 text-center">';
|
|
html += '<div class="py-3" style="font-size:2.5rem;"><i class="fas fa-folder text-warning"></i></div>';
|
|
html += '<h6 class="font-weight-bold text-truncate mb-0" title="' + escHtml(item.basename) + '">' + escHtml(item.basename) + '</h6>';
|
|
html += '</div></div></div>';
|
|
} else {
|
|
var icon = getFileIcon(item.mimeType, item.basename);
|
|
var size = item.fileSize ? formatFileSize(item.fileSize) : '-';
|
|
var isPreviewable = item.mimeType && item.mimeType.match(/^(image\/|application\/pdf|text\/)/);
|
|
html += '<div class="col-md-4 col-sm-6 mb-3">';
|
|
html += '<div class="card card-outline card-secondary h-100">';
|
|
html += '<div class="card-body p-3">';
|
|
html += '<h6 class="card-title font-weight-bold text-truncate mb-2" title="' + escHtml(item.basename) + '">' + escHtml(item.basename) + '</h6>';
|
|
html += '<div class="text-center py-2" style="font-size:2.5rem;"><i class="fas ' + icon + '"></i></div>';
|
|
html += '<div class="text-center mb-2"><span class="badge badge-light">' + size + '</span></div>';
|
|
html += '</div>';
|
|
html += '<div class="card-footer p-2 text-center">';
|
|
if (isPreviewable) {
|
|
html += '<button type="button" class="btn btn-xs btn-primary" onclick="previewRepoFile(' + repoId + ',\'' + escJs(item.path) + '\',\'' + escJs(item.mimeType || '') + '\')" title="Anteprima"><i class="fas fa-eye"></i></button> ';
|
|
}
|
|
html += '<button type="button" class="btn btn-xs btn-info" onclick="downloadRepoFile(' + repoId + ',\'' + escJs(item.path) + '\')" title="Scarica"><i class="fas fa-download"></i></button> ';
|
|
html += '<button type="button" class="btn btn-xs btn-success" onclick="importRepoFile(' + repoId + ',\'' + escJs(item.path) + '\',\'' + escJs(item.basename) + '\')" title="Salva tra i documenti"><i class="fas fa-save"></i></button>';
|
|
html += '</div></div></div>';
|
|
}
|
|
});
|
|
gridContainer.innerHTML = html;
|
|
} else {
|
|
document.getElementById('remoteGrid').style.display = 'none';
|
|
document.getElementById('remoteList').style.display = '';
|
|
var tblHtml = '<table class="table table-bordered table-hover table-striped mb-0"><thead class="thead-light"><tr><th>Nome</th><th style="width:90px;">Dimensione</th><th style="width:100px;">Data</th><th style="width:150px;">Azioni</th></tr></thead><tbody>';
|
|
contents.forEach(function(item) {
|
|
if (item.type === 'dir') {
|
|
tblHtml += '<tr class="table-warning" style="cursor:pointer;" onclick="browseRepo(' + repoId + ',\'' + escJs(currentRepoBrowse ? currentRepoBrowse.nome : '') + '\',\'' + escJs(item.path) + '\')">';
|
|
tblHtml += '<td><i class="fas fa-folder text-warning mr-2"></i><span class="font-weight-bold">' + escHtml(item.basename) + '</span></td>';
|
|
tblHtml += '<td class="small text-muted">-</td>';
|
|
tblHtml += '<td class="small text-muted">' + (item.lastModified ? formatTimestamp(item.lastModified) : '-') + '</td>';
|
|
tblHtml += '<td><button class="btn btn-xs btn-warning" onclick="event.stopPropagation(); browseRepo(' + repoId + ',\'' + escJs(currentRepoBrowse ? currentRepoBrowse.nome : '') + '\',\'' + escJs(item.path) + '\')"><i class="fas fa-folder-open"></i></button></td>';
|
|
tblHtml += '</tr>';
|
|
} else {
|
|
var icon = getFileIcon(item.mimeType, item.basename);
|
|
var size = item.fileSize ? formatFileSize(item.fileSize) : '-';
|
|
var isPreviewable = item.mimeType && item.mimeType.match(/^(image\/|application\/pdf|text\/)/);
|
|
tblHtml += '<tr>';
|
|
tblHtml += '<td><i class="fas ' + icon + ' mr-2"></i><span class="font-weight-bold">' + escHtml(item.basename) + '</span></td>';
|
|
tblHtml += '<td class="small">' + size + '</td>';
|
|
tblHtml += '<td class="small">' + (item.lastModified ? formatTimestamp(item.lastModified) : '-') + '</td>';
|
|
tblHtml += '<td>';
|
|
if (isPreviewable) {
|
|
tblHtml += '<button type="button" class="btn btn-xs btn-primary" onclick="previewRepoFile(' + repoId + ',\'' + escJs(item.path) + '\',\'' + escJs(item.mimeType || '') + '\')" title="Anteprima"><i class="fas fa-eye"></i></button> ';
|
|
}
|
|
tblHtml += '<button type="button" class="btn btn-xs btn-info" onclick="downloadRepoFile(' + repoId + ',\'' + escJs(item.path) + '\')" title="Scarica"><i class="fas fa-download"></i></button> ';
|
|
tblHtml += '<button type="button" class="btn btn-xs btn-success" onclick="importRepoFile(' + repoId + ',\'' + escJs(item.path) + '\',\'' + escJs(item.basename) + '\')" title="Salva tra i documenti"><i class="fas fa-save"></i></button>';
|
|
tblHtml += '</td></tr>';
|
|
}
|
|
});
|
|
tblHtml += '</tbody></table>';
|
|
listContainer.innerHTML = tblHtml;
|
|
}
|
|
}
|
|
|
|
function downloadRepoFile(repoId, path) {
|
|
window.location.href = '/storage-repositories/' + repoId + '/download?path=' + encodeURIComponent(path);
|
|
}
|
|
|
|
function previewRepoFile(repoId, path, mimeType) {
|
|
document.getElementById('previewFrame').src = '/storage-repositories/' + repoId + '/preview?path=' + encodeURIComponent(path);
|
|
document.getElementById('previewDownloadBtn').href = '/storage-repositories/' + repoId + '/download?path=' + encodeURIComponent(path);
|
|
$('#previewModal').modal('show');
|
|
}
|
|
|
|
function toggleImportTarget(value) {
|
|
var group = document.getElementById('swal-target-group');
|
|
var select = document.getElementById('swal-target-select');
|
|
if (!value || value === 'pubblico') {
|
|
group.style.display = 'none';
|
|
select.innerHTML = '<option value="">-- Nessuno --</option>';
|
|
return;
|
|
}
|
|
group.style.display = 'block';
|
|
var data = [];
|
|
if (value === 'individuo') data = individui;
|
|
else if (value === 'gruppo') data = gruppi;
|
|
else if (value === 'evento') data = eventi;
|
|
else if (value === 'mailing') data = mailingLists;
|
|
select.innerHTML = '<option value="">-- Seleziona --</option>';
|
|
data.forEach(function(item) {
|
|
var opt = document.createElement('option');
|
|
opt.value = item.id;
|
|
opt.textContent = item.label;
|
|
select.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
function importRepoFile(repoId, path, basename) {
|
|
var folderOptions = '<option value="">-- Nessuna --</option>';
|
|
cartelle.forEach(function(f) {
|
|
folderOptions += '<option value="' + f.id + '">' + escHtml(f.nome) + '</option>';
|
|
if (f.children) {
|
|
f.children.forEach(function(c) {
|
|
folderOptions += '<option value="' + c.id + '"> ' + escHtml(c.nome) + '</option>';
|
|
});
|
|
}
|
|
});
|
|
|
|
Swal.fire({
|
|
title: 'Importa come documento locale',
|
|
html:
|
|
'<div class="text-left">' +
|
|
'<p class="mb-1"><strong>File:</strong> ' + escHtml(basename) + '</p>' +
|
|
'<div class="form-group mb-2">' +
|
|
'<label class="small">Tipologia</label>' +
|
|
'<select id="swal-tipologia" class="form-control form-control-sm">' +
|
|
'<option value="documento" selected>Documento</option>' +
|
|
'<option value="avatar">Avatar</option>' +
|
|
'<option value="galleria">Galleria</option>' +
|
|
'<option value="statuto">Statuto</option>' +
|
|
'<option value="altro">Altro</option>' +
|
|
'</select></div>' +
|
|
'<div class="form-group mb-2">' +
|
|
'<label class="small">Cartella (opzionale)</label>' +
|
|
'<select id="swal-cartella" class="form-control form-control-sm">' + folderOptions + '</select></div>' +
|
|
'<div class="form-group mb-2">' +
|
|
'<label class="small">Visibilità</label>' +
|
|
'<select id="swal-visibilita" class="form-control form-control-sm" onchange="toggleImportTarget(this.value)">' +
|
|
'<option value="pubblico" selected>Pubblico</option>' +
|
|
'<option value="individuo">Individuo</option>' +
|
|
'<option value="gruppo">Gruppo</option>' +
|
|
'<option value="evento">Evento</option>' +
|
|
'<option value="mailing">Mailing List</option>' +
|
|
'</select></div>' +
|
|
'<div id="swal-target-group" class="form-group mb-0" style="display:none;">' +
|
|
'<label class="small">Collega a</label>' +
|
|
'<select id="swal-target-select" class="form-control form-control-sm">' +
|
|
'<option value="">-- Seleziona --</option>' +
|
|
'</select></div>' +
|
|
'</div>',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Importa',
|
|
cancelButtonText: 'Annulla',
|
|
preConfirm: function() {
|
|
var visibilita = document.getElementById('swal-visibilita').value;
|
|
var targetEl = document.getElementById('swal-target-select');
|
|
return {
|
|
tipologia: document.getElementById('swal-tipologia').value,
|
|
cartella_id: document.getElementById('swal-cartella').value,
|
|
visibilita: visibilita,
|
|
visibilita_target_id: visibilita !== 'pubblico' && targetEl && targetEl.value ? targetEl.value : null
|
|
};
|
|
}
|
|
}).then(function(result) {
|
|
if (!result.isConfirmed) return;
|
|
var data = result.value;
|
|
fetch('/storage-repositories/' + repoId + '/import', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-TOKEN': document.querySelector('meta[name=\"csrf-token\"]').getAttribute('content'),
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
path: path,
|
|
basename: basename,
|
|
tipologia: data.tipologia,
|
|
cartella_id: data.cartella_id || null,
|
|
visibilita: data.visibilita,
|
|
visibilita_target_id: data.visibilita_target_id
|
|
})
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(r) {
|
|
if (r.success) {
|
|
Swal.fire('Importato!', r.message, 'success');
|
|
} else {
|
|
Swal.fire('Errore', r.message || 'Errore durante l\'importazione.', 'error');
|
|
}
|
|
})
|
|
.catch(function(e) {
|
|
Swal.fire('Errore', 'Errore di rete: ' + e.message, 'error');
|
|
});
|
|
});
|
|
}
|
|
|
|
function getFileIcon(mimeType, basename) {
|
|
if (!mimeType) {
|
|
var ext = (basename || '').split('.').pop().toLowerCase();
|
|
mimeType = '';
|
|
if (['jpg','jpeg','png','gif','webp','svg'].indexOf(ext) >= 0) mimeType = 'image/';
|
|
else if (ext === 'pdf') mimeType = 'application/pdf';
|
|
else if (['doc','docx'].indexOf(ext) >= 0) mimeType = 'application/msword';
|
|
else if (['xls','xlsx'].indexOf(ext) >= 0) mimeType = 'application/vnd.ms-excel';
|
|
else if (['zip','rar','7z','tar','gz'].indexOf(ext) >= 0) mimeType = 'application/zip';
|
|
else if (['txt','csv','html','htm'].indexOf(ext) >= 0) mimeType = 'text/plain';
|
|
}
|
|
if (mimeType === 'application/pdf') return 'fa-file-pdf text-danger';
|
|
if (mimeType.match(/^image\//)) return 'fa-file-image text-success';
|
|
if (mimeType.match(/^text\//)) return 'fa-file-alt text-info';
|
|
if (mimeType.match(/word/)) return 'fa-file-word text-primary';
|
|
if (mimeType.match(/excel|spreadsheet/)) return 'fa-file-excel text-success';
|
|
if (mimeType.match(/zip|rar|compress/)) return 'fa-file-archive text-warning';
|
|
return 'fa-file text-secondary';
|
|
}
|
|
|
|
function formatFileSize(bytes) {
|
|
if (!bytes) return '-';
|
|
return (bytes / 1024).toFixed(1) + ' KB';
|
|
}
|
|
|
|
function formatTimestamp(ts) {
|
|
if (!ts) return '-';
|
|
var d = new Date(ts * 1000);
|
|
return d.toLocaleDateString('it-IT');
|
|
}
|
|
|
|
function escHtml(str) {
|
|
if (!str) return '';
|
|
var div = document.createElement('div');
|
|
div.appendChild(document.createTextNode(str));
|
|
return div.innerHTML;
|
|
}
|
|
|
|
function escJs(str) {
|
|
if (!str) return '';
|
|
return str.replace(/'/g, "\\'").replace(/"/g, '"').replace(/\n/g, '\\n');
|
|
}
|
|
// === End Remote Repository AJAX Browser ===
|
|
|
|
// Folder rename
|
|
function renameFolder(id, currentName) {
|
|
Swal.fire({
|
|
title: 'Rinomina cartella',
|
|
input: 'text',
|
|
inputLabel: 'Nuovo nome',
|
|
inputValue: currentName,
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Salva',
|
|
cancelButtonText: 'Annulla',
|
|
inputValidator: (value) => {
|
|
if (!value || !value.trim()) return 'Il nome non può essere vuoto';
|
|
},
|
|
preConfirm: (nome) => {
|
|
return fetch('/documenti/cartelle/' + id, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: 'nome=' + encodeURIComponent(nome.trim()),
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.success) throw new Error(data.message || 'Errore');
|
|
return data;
|
|
})
|
|
.catch(error => {
|
|
Swal.showValidationMessage(error.message);
|
|
});
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
window.location.reload();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Folder move
|
|
function moveFolder(id, nome) {
|
|
const folders = @json($cartelleMoveOptions);
|
|
|
|
let options = '<option value="">— Radice —</option>';
|
|
folders.forEach(function(f) {
|
|
if (f.id !== id) {
|
|
options += '<option value="' + f.id + '">' + escHtml(f.nome) + '</option>';
|
|
(f.children || []).forEach(function(c) {
|
|
if (c.id !== id) {
|
|
options += '<option value="' + c.id + '"> ' + escHtml(c.nome) + '</option>';
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
Swal.fire({
|
|
title: 'Sposta cartella',
|
|
html: '<p class="mb-2">Spostare la cartella <strong>' + escHtml(nome) + '</strong> in:</p>' +
|
|
'<select id="moveFolderParent" class="form-control">' + options + '</select>',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Sposta',
|
|
cancelButtonText: 'Annulla',
|
|
preConfirm: () => {
|
|
const parentId = document.getElementById('moveFolderParent').value;
|
|
return fetch('/documenti/cartelle/' + id, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: 'nome=' + encodeURIComponent(nome) + '&parent_id=' + encodeURIComponent(parentId),
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.success) throw new Error(data.message || 'Errore spostamento');
|
|
return data;
|
|
})
|
|
.catch(error => {
|
|
Swal.showValidationMessage(error.message);
|
|
});
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
window.location.reload();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Folder delete
|
|
function deleteFolder(id, nome) {
|
|
Swal.fire({
|
|
title: 'Elimina cartella',
|
|
text: 'Eliminare la cartella "' + nome + '"?',
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#dc3545',
|
|
confirmButtonText: 'Elimina',
|
|
cancelButtonText: 'Annulla',
|
|
preConfirm: () => {
|
|
return fetch('/documenti/cartelle/' + id, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Accept': 'application/json',
|
|
},
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.success) throw new Error(data.message || 'Errore');
|
|
return data;
|
|
})
|
|
.catch(error => {
|
|
Swal.showValidationMessage(error.message);
|
|
});
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
window.location.reload();
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
@endsection
|