Auto Delete: ${file.auto_delete ? formatDate(file.auto_delete) : 'Never'}
` : ''}
`;
});
}
}
/**
* Fetches files from the server.
* Handles both trash and starred file endpoints.
* @async
* @function
*/
async function fetchFiles() {
try {
const endpoint = isTrashPage ? '/api/rooms/trash' : '/api/rooms/starred';
const response = await fetch(endpoint);
const files = await response.json();
if (files) {
window.currentFiles = files;
// Sort files by name by default
window.currentFiles.sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
renderFiles(files);
}
} catch (error) {
console.error('Error loading files:', error);
document.getElementById('fileGrid').innerHTML = '
Failed to load files. Please try refreshing the page.
';
}
}
/**
* Gets the CSRF token from various possible locations in the DOM.
* @function
* @returns {string} The CSRF token or empty string if not found
*/
function getCsrfToken() {
// First try to get it from the meta tag
const metaTag = document.querySelector('meta[name="csrf-token"]');
if (metaTag) {
const token = metaTag.getAttribute('content');
if (token && token.trim() !== '') {
return token;
}
}
// If not found in meta tag, try to get it from any form
const forms = document.querySelectorAll('form');
for (const form of forms) {
const csrfInput = form.querySelector('input[name="csrf_token"]');
if (csrfInput && csrfInput.value && csrfInput.value.trim() !== '') {
return csrfInput.value;
}
}
// If still not found, try to get it from any hidden input
const hiddenInputs = document.querySelectorAll('input[name="csrf_token"]');
for (const input of hiddenInputs) {
if (input.value && input.value.trim() !== '') {
return input.value;
}
}
console.error('CSRF token not found in any of the expected locations');
return '';
}
/**
* Toggles the star status of a file.
* @function
* @param {string} filename - The name of the file
* @param {string} path - The path of the file
* @param {number} roomId - The ID of the room containing the file
*/
function toggleStar(filename, path = '', roomId) {
const csrfToken = getCsrfToken();
if (!csrfToken) {
console.error('CSRF token not available');
return;
}
fetch(`/api/rooms/${roomId}/star`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify({
filename: filename,
path: path
})
})
.then(r => r.json())
.then(res => {
if (res.success) {
// Remove the file from the current view since it's no longer starred
currentFiles = currentFiles.filter(f => !(f.name === filename && f.path === path && f.room_id === roomId));
renderFiles(currentFiles);
} else {
console.error('Failed to toggle star:', res.error);
}
})
.catch(error => {
console.error('Error toggling star:', error);
});
}
/**
* Restores a file from the trash.
* @function
* @param {string} filename - The name of the file
* @param {string} path - The path of the file
* @param {number} roomId - The ID of the room containing the file
*/
function restoreFile(filename, path = '', roomId) {
const csrfToken = getCsrfToken();
if (!csrfToken) {
console.error('CSRF token not available');
return;
}
fetch(`/api/rooms/${roomId}/restore`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify({
filename: filename,
path: path
})
})
.then(r => r.json())
.then(res => {
if (res.success) {
// Remove the file from the current view since it's been restored
currentFiles = currentFiles.filter(f => !(f.name === filename && f.path === path && f.room_id === roomId));
renderFiles(currentFiles);
} else {
console.error('Failed to restore file:', res.error);
}
})
.catch(error => {
console.error('Error restoring file:', error);
});
}
/**
* Shows the permanent delete confirmation modal.
* @function
* @param {string} filename - The name of the file
* @param {string} path - The path of the file
* @param {number} roomId - The ID of the room containing the file
*/
function showPermanentDeleteModal(filename, path = '', roomId) {
fileToDelete = { filename, path, roomId };
document.getElementById('permanentDeleteItemName').textContent = filename;
const modal = new bootstrap.Modal(document.getElementById('permanentDeleteModal'));
modal.show();
}
/**
* Permanently deletes a file after confirmation.
* @function
*/
function permanentDeleteFile() {
if (!fileToDelete) return;
const { filename, path, roomId } = fileToDelete;
const csrfToken = getCsrfToken();
if (!csrfToken) {
console.error('CSRF token not available');
return;
}
fetch(`/api/rooms/${roomId}/delete-permanent`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify({
filename: filename,
path: path
})
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// Check if the response is empty
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return response.json();
}
return { success: true }; // If no JSON response, assume success
})
.then(res => {
if (res.success) {
// Remove the file from the current view since it's been deleted
currentFiles = currentFiles.filter(f => !(f.name === filename && f.path === path && f.room_id === roomId));
renderFiles(currentFiles);
// Close the modal
const modal = bootstrap.Modal.getInstance(document.getElementById('permanentDeleteModal'));
if (modal) {
modal.hide();
}
} else {
console.error('Failed to delete file:', res.error || 'Unknown error');
}
})
.catch(error => {
console.error('Error deleting file:', error);
// Show error to user
const modal = bootstrap.Modal.getInstance(document.getElementById('permanentDeleteModal'));
if (modal) {
modal.hide();
}
// You might want to show an error message to the user here
});
}
/**
* Navigates to a file or folder.
* @function
* @param {number} roomId - The ID of the room
* @param {string} filename - The name of the file/folder
* @param {string} path - The path of the file/folder
* @param {string} type - The type of item ('file' or 'folder')
*/
function navigateToFile(roomId, filename, path, type) {
if (type === 'folder') {
window.location.href = `/room/${roomId}?path=${encodeURIComponent(path ? path + '/' + filename : filename)}`;
} else {
window.location.href = `/api/rooms/${roomId}/files/${encodeURIComponent(filename)}?path=${encodeURIComponent(path)}`;
}
}
/**
* Shows the empty trash confirmation modal.
* @function
*/
function showEmptyTrashModal() {
const modal = new bootstrap.Modal(document.getElementById('emptyTrashModal'));
modal.show();
}
/**
* Shows the file details modal.
* @function
* @param {number} idx - The index of the file in the currentFiles array
*/
function showDetailsModal(idx) {
const item = currentFiles[idx];
const icon = item.type === 'folder'
? ``
: ``;
const uploaderPic = item.uploader_profile_pic
? `/uploads/profile_pics/${item.uploader_profile_pic}`
: '/static/default-avatar.png';
const detailsHtml = `