|
{% extends 'base.html' %} |
|
|
|
{% block title %}Мои файлы{% endblock %} |
|
|
|
{% block content %} |
|
<div class="row mb-4"> |
|
<div class="col-md-8"> |
|
<nav aria-label="breadcrumb" class="breadcrumb-container"> |
|
<ol class="breadcrumb"> |
|
{% for path, name in breadcrumbs %} |
|
<li class="breadcrumb-item {% if loop.last %}active{% endif %}"> |
|
{% if not loop.last %} |
|
<a href="{{ url_for('dashboard', folder=path) }}">{{ name }}</a> |
|
{% else %} |
|
{{ name }} |
|
{% endif %} |
|
</li> |
|
{% endfor %} |
|
</ol> |
|
</nav> |
|
</div> |
|
<div class="col-md-4"> |
|
<form action="{{ url_for('search') }}" method="get" class="search-form"> |
|
<div class="search-container"> |
|
<input type="text" name="query" class="form-control search-input" placeholder="Поиск файлов..."> |
|
<button type="submit" class="search-button"><i class="fas fa-search"></i></button> |
|
</div> |
|
</form> |
|
</div> |
|
</div> |
|
|
|
<div class="row mb-4"> |
|
<div class="col-md-12"> |
|
<div class="card"> |
|
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center"> |
|
<h5 class="mb-0">Управление файлами</h5> |
|
<div> |
|
<button type="button" class="btn btn-light btn-sm" data-bs-toggle="modal" data-bs-target="#uploadModal"> |
|
<i class="fas fa-upload"></i> Загрузить файл |
|
</button> |
|
<button type="button" class="btn btn-light btn-sm ms-2" data-bs-toggle="modal" data-bs-target="#createFolderModal"> |
|
<i class="fas fa-folder-plus"></i> Создать папку |
|
</button> |
|
</div> |
|
</div> |
|
<div class="card-body"> |
|
{% if files %} |
|
<div class="table-responsive"> |
|
<table class="table table-hover"> |
|
<thead> |
|
<tr> |
|
<th>Имя</th> |
|
<th>Тип</th> |
|
<th>Размер</th> |
|
<th>Дата создания</th> |
|
<th>Действия</th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
{% for file in files %} |
|
<tr> |
|
<td> |
|
{% if file.is_folder %} |
|
<a href="{{ url_for('dashboard', folder=file.filename) }}" class="text-decoration-none"> |
|
<i class="fas fa-folder text-warning"></i> {{ file.original_filename }} |
|
</a> |
|
{% else %} |
|
{% if file.file_type in ['image', 'video', 'audio'] %} |
|
<a href="#" class="text-decoration-none" data-bs-toggle="modal" data-bs-target="#mediaModal" |
|
data-file-type="{{ file.file_type }}" |
|
data-file-path="{{ url_for('download_file', file_id=file.id) }}" |
|
data-file-name="{{ file.original_filename }}"> |
|
<i class="fas fa-file text-primary"></i> {{ file.original_filename }} |
|
</a> |
|
{% else %} |
|
<i class="fas fa-file text-primary"></i> {{ file.original_filename }} |
|
{% endif %} |
|
{% endif %} |
|
</td> |
|
<td> |
|
{% if file.is_folder %} |
|
Папка |
|
{% else %} |
|
{% if file.file_type == 'image' %} |
|
<i class="fas fa-image text-info"></i> Изображение |
|
{% elif file.file_type == 'video' %} |
|
<i class="fas fa-video text-danger"></i> Видео |
|
{% elif file.file_type == 'audio' %} |
|
<i class="fas fa-music text-success"></i> Аудио |
|
{% elif file.file_type == 'text' %} |
|
<i class="fas fa-file-alt text-secondary"></i> Текст |
|
{% else %} |
|
<i class="fas fa-file text-secondary"></i> Файл |
|
{% endif %} |
|
{% endif %} |
|
</td> |
|
<td>{{ file.size|filesizeformat if not file.is_folder else '-' }}</td> |
|
<td>{{ file.created_at }}</td> |
|
<td> |
|
<div class="d-flex gap-2"> |
|
{% if not file.is_folder %} |
|
<a href="{{ url_for('download_file', file_id=file.id) }}" class="btn btn-sm btn-primary rounded-circle" title="Скачать"> |
|
<i class="fas fa-download"></i> |
|
</a> |
|
{% if file.file_type in ['text', 'code', 'document'] or file.original_filename.endswith(('.txt', '.html', '.css', '.js', '.py', '.md', '.json', '.xml', '.csv')) %} |
|
<button class="btn btn-sm btn-info rounded-circle" title="Редактировать" onclick="openTextEditor('{{ file.id }}', '{{ file.original_filename }}')"> |
|
<i class="fas fa-edit"></i> |
|
</button> |
|
{% endif %} |
|
<a href="{{ url_for('share_file', file_id=file.id) }}" class="btn btn-sm btn-success rounded-circle" title="Поделиться"> |
|
<i class="fas fa-share-alt"></i> |
|
</a> |
|
{% endif %} |
|
<form action="{{ url_for('delete_file', file_id=file.id) }}" method="post" class="d-inline" onsubmit="return confirm('Вы уверены, что хотите удалить этот элемент?');"> |
|
<button type="submit" class="btn btn-sm btn-danger rounded-circle" title="Удалить"> |
|
<i class="fas fa-trash"></i> |
|
</button> |
|
</form> |
|
</div> |
|
</td> |
|
</tr> |
|
{% endfor %} |
|
</tbody> |
|
</table> |
|
</div> |
|
{% else %} |
|
<div class="text-center py-5"> |
|
<i class="fas fa-folder-open fa-4x text-muted mb-3"></i> |
|
<h5>Эта папка пуста</h5> |
|
<p>Загрузите файлы или создайте новую папку</p> |
|
</div> |
|
{% endif %} |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="modal fade" id="uploadModal" tabindex="-1" aria-hidden="true"> |
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title">Загрузить файл</h5> |
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> |
|
</div> |
|
<form action="{{ url_for('upload_file') }}" method="post" enctype="multipart/form-data"> |
|
<div class="modal-body"> |
|
<input type="hidden" name="current_folder" value="{{ current_folder }}"> |
|
<div class="mb-3"> |
|
<label for="file" class="form-label">Выберите файл</label> |
|
<input type="file" class="form-control" id="file" name="files[]" multiple required> |
|
</div> |
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button> |
|
<button type="submit" class="btn btn-primary">Загрузить</button> |
|
</div> |
|
</form> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="modal fade" id="createFolderModal" tabindex="-1" aria-hidden="true"> |
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title">Создать папку</h5> |
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> |
|
</div> |
|
<form action="{{ url_for('create_folder') }}" method="post"> |
|
<div class="modal-body"> |
|
<input type="hidden" name="current_folder" value="{{ current_folder }}"> |
|
<div class="mb-3"> |
|
<label for="folder_name" class="form-label">Имя папки</label> |
|
<input type="text" class="form-control" id="folder_name" name="folder_name" required> |
|
</div> |
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button> |
|
<button type="submit" class="btn btn-primary">Создать</button> |
|
</div> |
|
</form> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="modal fade" id="editModal" tabindex="-1"> |
|
<div class="modal-dialog modal-xl"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title">Редактор: <span id="editFileName"></span></h5> |
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> |
|
</div> |
|
<div class="modal-body"> |
|
<textarea id="editorContent" class="form-control font-monospace" rows="20"></textarea> |
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn btn-primary" onclick="saveChanges()">Сохранить</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="modal fade" id="mediaModal" tabindex="-1" aria-hidden="true"> |
|
<div class="modal-dialog modal-lg"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title">Просмотр файла: <span id="mediaFileName"></span></h5> |
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> |
|
</div> |
|
<div class="modal-body text-center"> |
|
|
|
<img id="imageViewer" class="img-fluid d-none" alt="Просмотр изображения"> |
|
|
|
|
|
<video id="videoPlayer" class="d-none w-100" controls> |
|
Ваш браузер не поддерживает воспроизведение видео. |
|
</video> |
|
|
|
|
|
<audio id="audioPlayer" class="d-none w-100" controls> |
|
Ваш браузер не поддерживает воспроизведение аудио. |
|
</audio> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
document.addEventListener('DOMContentLoaded', function() { |
|
const mediaModal = document.getElementById('mediaModal'); |
|
mediaModal.addEventListener('show.bs.modal', function(event) { |
|
const button = event.relatedTarget; |
|
const fileType = button.getAttribute('data-file-type'); |
|
const filePath = button.getAttribute('data-file-path'); |
|
const fileName = button.getAttribute('data-file-name'); |
|
|
|
document.getElementById('mediaFileName').textContent = fileName; |
|
|
|
|
|
document.getElementById('imageViewer').classList.add('d-none'); |
|
document.getElementById('videoPlayer').classList.add('d-none'); |
|
document.getElementById('audioPlayer').classList.add('d-none'); |
|
|
|
|
|
if (fileType === 'image') { |
|
const imageViewer = document.getElementById('imageViewer'); |
|
imageViewer.src = filePath; |
|
imageViewer.classList.remove('d-none'); |
|
} else if (fileType === 'video') { |
|
const videoPlayer = document.getElementById('videoPlayer'); |
|
videoPlayer.src = filePath; |
|
videoPlayer.classList.remove('d-none'); |
|
} else if (fileType === 'audio') { |
|
const audioPlayer = document.getElementById('audioPlayer'); |
|
audioPlayer.src = filePath; |
|
audioPlayer.classList.remove('d-none'); |
|
} |
|
}); |
|
|
|
|
|
mediaModal.addEventListener('hidden.bs.modal', function() { |
|
document.getElementById('imageViewer').src = ''; |
|
document.getElementById('videoPlayer').src = ''; |
|
document.getElementById('audioPlayer').src = ''; |
|
}); |
|
}); |
|
|
|
|
|
let currentFileId = null; |
|
|
|
function openTextEditor(fileId, fileName) { |
|
currentFileId = fileId; |
|
document.getElementById('editFileName').textContent = fileName; |
|
|
|
|
|
fetch(`/get_file_content/${fileId}`) |
|
.then(response => response.text()) |
|
.then(content => { |
|
document.getElementById('editorContent').value = content; |
|
const editModal = new bootstrap.Modal(document.getElementById('editModal')); |
|
editModal.show(); |
|
}) |
|
.catch(error => { |
|
alert('Ошибка при загрузке файла: ' + error); |
|
}); |
|
} |
|
|
|
function saveChanges() { |
|
if (!currentFileId) return; |
|
|
|
const content = document.getElementById('editorContent').value; |
|
|
|
fetch(`/save_file_content/${currentFileId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ content: content }) |
|
}) |
|
.then(response => response.json()) |
|
.then(data => { |
|
if (data.success) { |
|
alert('Файл успешно сохранен!'); |
|
const editModal = bootstrap.Modal.getInstance(document.getElementById('editModal')); |
|
editModal.hide(); |
|
} else { |
|
alert('Ошибка при сохранении файла: ' + data.error); |
|
} |
|
}) |
|
.catch(error => { |
|
alert('Ошибка при сохранении файла: ' + error); |
|
}); |
|
} |
|
</script> |
|
{% endblock %} |