chore: translate all Spanish comments and log messages to English

This commit is contained in:
Dionisio
2026-02-12 09:41:25 +01:00
parent bc169de8f6
commit d31a413e57
89 changed files with 2480 additions and 2482 deletions
+69 -69
View File
@@ -197,7 +197,7 @@ function setupUserMenu() {
// Theme switching could be expanded here in the future
window.ui.showNotification(
dark ? '🌙' : '☀️',
dark ? 'Modo oscuro activado (próximamente)' : 'Modo claro activado'
dark ? 'Dark mode enabled (coming soon)' : 'Light mode enabled'
);
}
});
@@ -476,12 +476,12 @@ function setupEventListeners() {
if (filesListView) filesListView.style.display = app.currentView === 'list' ? 'block' : 'none';
// Update UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.trash') : 'Papelera';
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.trash') : 'Trash';
elements.actionsBar.innerHTML = `
<div class="action-buttons">
<button class="btn btn-danger" id="empty-trash-btn">
<i class="fas fa-trash-alt"></i>
<span>${window.i18n ? window.i18n.t('trash.empty_trash') : 'Vaciar papelera'}</span>
<span>${window.i18n ? window.i18n.t('trash.empty_trash') : 'Empty trash'}</span>
</button>
</div>
`;
@@ -519,35 +519,35 @@ function setupEventListeners() {
app.currentSection = 'files';
// Reset UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.files') : 'Archivos';
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.files') : 'Files';
elements.actionsBar.innerHTML = `
<div class="action-buttons">
<div class="upload-dropdown" id="upload-dropdown">
<button class="btn btn-primary" id="upload-btn">
<i class="fas fa-cloud-upload-alt" style="margin-right: 5px;"></i>
<span data-i18n="actions.upload">Subir</span>
<span data-i18n="actions.upload">Upload</span>
<i class="fas fa-caret-down" style="margin-left: 4px; font-size: 12px;"></i>
</button>
<div class="upload-dropdown-menu" id="upload-dropdown-menu">
<button class="upload-dropdown-item" id="upload-files-btn">
<i class="fas fa-file"></i>
<span data-i18n="actions.upload_files">Subir archivos</span>
<span data-i18n="actions.upload_files">Upload files</span>
</button>
<button class="upload-dropdown-item" id="upload-folder-btn">
<i class="fas fa-folder-open"></i>
<span data-i18n="actions.upload_folder">Subir carpeta</span>
<span data-i18n="actions.upload_folder">Upload folder</span>
</button>
</div>
</div>
<button class="btn btn-secondary" id="new-folder-btn">
<i class="fas fa-folder-plus" style="margin-right: 5px;"></i> <span data-i18n="actions.new_folder">Nueva carpeta</span>
<i class="fas fa-folder-plus" style="margin-right: 5px;"></i> <span data-i18n="actions.new_folder">New folder</span>
</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Vista de cuadrícula">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="Vista de lista">
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
@@ -623,14 +623,14 @@ function setupEventListeners() {
*/
async function loadFiles(options = {}) {
try {
console.log("Iniciando loadFiles() - cargando archivos...", options);
console.log("Starting loadFiles() - loading files...", options);
// Flag para forzar el refresco completo ignorando caché
// Flag to force complete refresh ignoring cache
const forceRefresh = options.forceRefresh || false;
// Prevenir múltiples solicitudes de carga simultáneas
// Prevent multiple simultaneous load requests
if (window.isLoadingFiles) {
console.log("Ya hay una carga de archivos en progreso, ignorando solicitud");
console.log("A file load is already in progress, ignoring request");
return;
}
@@ -640,7 +640,7 @@ async function loadFiles(options = {}) {
elements.filesGrid.innerHTML = `
<div class="files-loading-spinner">
<div class="spinner"></div>
<span>${window.i18n ? window.i18n.t('files.loading') : 'Cargando archivos…'}</span>
<span>${window.i18n ? window.i18n.t('files.loading') : 'Loading files…'}</span>
</div>
`;
@@ -651,12 +651,12 @@ async function loadFiles(options = {}) {
const userData = JSON.parse(localStorage.getItem(USER_DATA_KEY) || '{}');
if (userData.username) {
// Find user's home folder
console.log("Buscando carpeta de usuario para", userData.username);
console.log("Looking for user folder for", userData.username);
await findUserHomeFolder(userData.username);
}
}
// Agregar timestamp para evitar caché
// Add timestamp to avoid cache
const timestamp = new Date().getTime();
let url;
@@ -667,7 +667,7 @@ async function loadFiles(options = {}) {
url = `/api/folders/${app.userHomeFolderId}/contents?t=${timestamp}`;
app.currentPath = app.userHomeFolderId;
ui.updateBreadcrumb(app.userHomeFolderName || 'Home');
console.log(`Cargando carpeta del usuario: ${app.userHomeFolderName} (${app.userHomeFolderId})`);
console.log(`Loading user folder: ${app.userHomeFolderName} (${app.userHomeFolderId})`);
} else {
// Emergency fallback - this should rarely happen but prevents errors
url = `/api/folders?t=${timestamp}`;
@@ -676,7 +676,7 @@ async function loadFiles(options = {}) {
} else {
// Normal case - viewing subfolder contents
url = `/api/folders/${app.currentPath}/contents?t=${timestamp}`;
console.log(`Cargando contenido de subcarpeta: ${app.currentPath}`);
console.log(`Loading subfolder content: ${app.currentPath}`);
}
const token = localStorage.getItem('oxicloud_token');
@@ -686,14 +686,14 @@ async function loadFiles(options = {}) {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache'
},
cache: 'no-store' // Instruir al navegador a no usar caché
cache: 'no-store' // Instruct the browser not to use cache
};
// Si se especifica forceRefresh, agregar un parámetro adicional para evitar caché
// If forceRefresh is specified, add an additional parameter to avoid cache
if (forceRefresh) {
url += `&force_refresh=true`;
requestOptions.headers['X-Force-Refresh'] = 'true';
console.log('Forzando refresco completo ignorando caché');
console.log('Forcing complete refresh ignoring cache');
}
console.log(`Loading files from ${url}`);
@@ -703,13 +703,13 @@ async function loadFiles(options = {}) {
if (response.status === 401 || response.status === 403) {
console.warn("Auth error when loading files, showing empty list");
// Just show empty state instead of causing redirect loops
elements.filesGrid.innerHTML = '<div class="empty-state"><p>No se pudieron cargar los archivos</p></div>';
elements.filesGrid.innerHTML = '<div class="empty-state"><p>Could not load files</p></div>';
elements.filesListView.innerHTML = `
<div class="list-header">
<div>Nombre</div>
<div>Tipo</div>
<div>Tamaño</div>
<div>Modificado</div>
<div>Name</div>
<div>Type</div>
<div>Size</div>
<div>Modified</div>
</div>
`;
return;
@@ -724,10 +724,10 @@ async function loadFiles(options = {}) {
elements.filesGrid.innerHTML = '';
elements.filesListView.innerHTML = `
<div class="list-header">
<div data-i18n="files.name">Nombre</div>
<div data-i18n="files.type">Tipo</div>
<div data-i18n="files.size">Tamaño</div>
<div data-i18n="files.modified">Modificado</div>
<div data-i18n="files.name">Name</div>
<div data-i18n="files.type">Type</div>
<div data-i18n="files.size">Size</div>
<div data-i18n="files.modified">Modified</div>
</div>
`;
@@ -766,11 +766,11 @@ async function loadFiles(options = {}) {
// Also load files in this folder
const cacheTimestamp = new Date().getTime();
let filesUrl = `/api/files?t=${cacheTimestamp}`; // Agregar timestamp para evitar problemas de caché
let filesUrl = `/api/files?t=${cacheTimestamp}`; // Add timestamp to avoid cache issues
if (app.currentPath) {
filesUrl += `&folder_id=${app.currentPath}`;
}
console.log(`Cargando archivos desde: ${filesUrl}`);
console.log(`Loading files from: ${filesUrl}`);
try {
console.log(`Fetching files from: ${filesUrl}`);
@@ -810,7 +810,7 @@ async function loadFiles(options = {}) {
console.error('Error loading folders:', error);
ui.showNotification('Error', 'Could not load files and folders');
} finally {
// Marcar que ya no estamos cargando archivos para permitir solicitudes futuras
// Mark that we are no longer loading files to allow future requests
window.isLoadingFiles = false;
}
}
@@ -839,11 +839,11 @@ async function loadTrashItems() {
elements.filesGrid.innerHTML = '';
elements.filesListView.innerHTML = `
<div class="list-header">
<div data-i18n="files.name">Nombre</div>
<div data-i18n="files.type">Tipo</div>
<div data-i18n="trash.original_location">Ubicación original</div>
<div data-i18n="trash.deleted_date">Fecha eliminación</div>
<div data-i18n="trash.actions">Acciones</div>
<div data-i18n="files.name">Name</div>
<div data-i18n="files.type">Type</div>
<div data-i18n="trash.original_location">Original location</div>
<div data-i18n="trash.deleted_date">Deletion date</div>
<div data-i18n="trash.actions">Actions</div>
</div>
`;
@@ -864,7 +864,7 @@ async function loadTrashItems() {
emptyState.className = 'empty-state';
emptyState.innerHTML = `
<i class="fas fa-trash" style="font-size: 48px; color: #ddd; margin-bottom: 16px;"></i>
<p>${window.i18n ? window.i18n.t('trash.empty_state') : 'La papelera está vacía'}</p>
<p>${window.i18n ? window.i18n.t('trash.empty_state') : 'The trash is empty'}</p>
`;
elements.filesGrid.appendChild(emptyState);
return;
@@ -877,7 +877,7 @@ async function loadTrashItems() {
} catch (error) {
console.error('Error loading trash items:', error);
window.ui.showNotification('Error', 'Error al cargar elementos de la papelera');
window.ui.showNotification('Error', 'Error loading trash items');
}
}
@@ -896,8 +896,8 @@ function addTrashItemToView(item) {
// Item type label
const typeLabel = isFile ?
(window.i18n ? window.i18n.t('files.file_types.file') : 'Archivo') :
(window.i18n ? window.i18n.t('files.file_types.folder') : 'Carpeta');
(window.i18n ? window.i18n.t('files.file_types.file') : 'File') :
(window.i18n ? window.i18n.t('files.file_types.folder') : 'Folder');
// Grid view element
const gridElement = document.createElement('div');
@@ -912,10 +912,10 @@ function addTrashItemToView(item) {
<div class="file-name">${item.name}</div>
<div class="file-info">${typeLabel} - ${formattedDate}</div>
<div class="trash-actions">
<button class="btn-restore" title="${window.i18n ? window.i18n.t('trash.restore') : 'Restaurar'}">
<button class="btn-restore" title="${window.i18n ? window.i18n.t('trash.restore') : 'Restore'}">
<i class="fas fa-undo"></i>
</button>
<button class="btn-delete" title="${window.i18n ? window.i18n.t('trash.delete_permanently') : 'Eliminar permanentemente'}">
<button class="btn-delete" title="${window.i18n ? window.i18n.t('trash.delete_permanently') : 'Delete permanently'}">
<i class="fas fa-trash"></i>
</button>
</div>
@@ -956,10 +956,10 @@ function addTrashItemToView(item) {
<div class="path-cell">${item.original_path || '--'}</div>
<div class="date-cell">${formattedDate}</div>
<div class="actions-cell">
<button class="btn-restore" title="${window.i18n ? window.i18n.t('trash.restore') : 'Restaurar'}">
<button class="btn-restore" title="${window.i18n ? window.i18n.t('trash.restore') : 'Restore'}">
<i class="fas fa-undo"></i>
</button>
<button class="btn-delete" title="${window.i18n ? window.i18n.t('trash.delete_permanently') : 'Eliminar permanentemente'}">
<button class="btn-delete" title="${window.i18n ? window.i18n.t('trash.delete_permanently') : 'Delete permanently'}">
<i class="fas fa-trash"></i>
</button>
</div>
@@ -995,7 +995,7 @@ async function performSearch(query) {
app.isSearchMode = true;
// Set breadcrumb for search
ui.updateBreadcrumb(`Búsqueda: "${query}"`);
ui.updateBreadcrumb(`Search: "${query}"`);
// Prepare search options
const options = {
@@ -1037,7 +1037,7 @@ async function performSearch(query) {
} catch (error) {
console.error('Search error:', error);
window.ui.showNotification('Error', 'Error al realizar la búsqueda');
window.ui.showNotification('Error', 'Error performing search');
}
}
@@ -1076,7 +1076,7 @@ function switchToSharedView() {
}
// Update UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.shared') : 'Compartidos';
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.shared') : 'Shared';
// Clear breadcrumb and show root
ui.updateBreadcrumb('');
@@ -1105,7 +1105,7 @@ function switchToFilesView() {
app.currentSection = 'files';
// Update UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.files') : 'Archivos';
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.files') : 'Files';
// Remove active class from all nav items
elements.navItems.forEach(navItem => navItem.classList.remove('active'));
@@ -1122,29 +1122,29 @@ function switchToFilesView() {
<div class="upload-dropdown" id="upload-dropdown">
<button class="btn btn-primary" id="upload-btn">
<i class="fas fa-cloud-upload-alt" style="margin-right: 5px;"></i>
<span data-i18n="actions.upload">Subir</span>
<span data-i18n="actions.upload">Upload</span>
<i class="fas fa-caret-down" style="margin-left: 4px; font-size: 12px;"></i>
</button>
<div class="upload-dropdown-menu" id="upload-dropdown-menu">
<button class="upload-dropdown-item" id="upload-files-btn">
<i class="fas fa-file"></i>
<span data-i18n="actions.upload_files">Subir archivos</span>
<span data-i18n="actions.upload_files">Upload files</span>
</button>
<button class="upload-dropdown-item" id="upload-folder-btn">
<i class="fas fa-folder-open"></i>
<span data-i18n="actions.upload_folder">Subir carpeta</span>
<span data-i18n="actions.upload_folder">Upload folder</span>
</button>
</div>
</div>
<button class="btn btn-secondary" id="new-folder-btn">
<i class="fas fa-folder-plus" style="margin-right: 5px;"></i> <span data-i18n="actions.new_folder">Nueva carpeta</span>
<i class="fas fa-folder-plus" style="margin-right: 5px;"></i> <span data-i18n="actions.new_folder">New folder</span>
</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Vista de cuadrícula">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="Vista de lista">
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
@@ -1219,7 +1219,7 @@ function switchToFavoritesView() {
}
// Update UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.favorites') : 'Favoritos';
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.favorites') : 'Favorites';
// Clear breadcrumb and show root
ui.updateBreadcrumb('');
@@ -1235,10 +1235,10 @@ function switchToFavoritesView() {
<!-- No actions needed for favorites view -->
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Vista de cuadrícula">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="Vista de lista">
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
@@ -1278,7 +1278,7 @@ function switchToFavoritesView() {
filesGrid.innerHTML = `
<div class="empty-state">
<i class="fas fa-exclamation-circle" style="font-size: 48px; color: #f44336; margin-bottom: 16px;"></i>
<p>Error al cargar el módulo de favoritos</p>
<p>Error loading the favorites module</p>
</div>
`;
}
@@ -1308,7 +1308,7 @@ function switchToRecentFilesView() {
}
// Update UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.recent') : 'Recientes';
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.recent') : 'Recent';
// Clear breadcrumb and show root
ui.updateBreadcrumb('');
@@ -1322,14 +1322,14 @@ function switchToRecentFilesView() {
elements.actionsBar.innerHTML = `
<div class="action-buttons">
<button class="btn btn-secondary" id="clear-recent-btn">
<i class="fas fa-broom" style="margin-right: 5px;"></i> <span data-i18n="actions.clear_recent">Limpiar recientes</span>
<i class="fas fa-broom" style="margin-right: 5px;"></i> <span data-i18n="actions.clear_recent">Clear recent</span>
</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Vista de cuadrícula">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="Vista de lista">
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
@@ -1341,7 +1341,7 @@ function switchToRecentFilesView() {
if (window.recent) {
window.recent.clearRecentFiles();
window.recent.displayRecentFiles();
window.ui.showNotification('Limpieza completada', 'Se ha limpiado el historial de archivos recientes');
window.ui.showNotification('Cleanup completed', 'Recent files history has been cleared');
}
});
@@ -1378,7 +1378,7 @@ function switchToRecentFilesView() {
filesGrid.innerHTML = `
<div class="empty-state">
<i class="fas fa-exclamation-circle" style="font-size: 48px; color: #f44336; margin-bottom: 16px;"></i>
<p>Error al cargar el módulo de archivos recientes</p>
<p>Error loading the recent files module</p>
</div>
`;
}
@@ -1450,7 +1450,7 @@ window.refreshUserData = refreshUserData;
function showUserProfileModal() {
const USER_DATA_KEY = 'oxicloud_user';
const userData = JSON.parse(localStorage.getItem(USER_DATA_KEY) || '{}');
const username = userData.username || 'Usuario';
const username = userData.username || 'User';
const email = userData.email || '';
const role = userData.role || 'user';
const initials = username.substring(0, 2).toUpperCase();
@@ -1847,7 +1847,7 @@ async function findUserHomeFolder(username) {
* Logout - clear all auth data and redirect to login
*/
function logout() {
// Nombres de variables según auth.js
// Variable names as per auth.js
const TOKEN_KEY = 'oxicloud_token';
const REFRESH_TOKEN_KEY = 'oxicloud_refresh_token';
const TOKEN_EXPIRY_KEY = 'oxicloud_token_expiry';
+20 -20
View File
@@ -34,7 +34,7 @@ const LANGUAGE_TEXTS = {
subtitle: 'Por favor, selecciona tu idioma',
continue: 'Continuar',
autodetected: 'Hemos detectado tu idioma',
moreLanguages: 'Más idiomas...',
moreLanguages: 'More languages...',
modalTitle: 'Seleccionar idioma',
searchPlaceholder: 'Buscar idioma...'
},
@@ -494,8 +494,8 @@ document.addEventListener('DOMContentLoaded', () => {
console.error('Error showing initial panel:', err);
});
// Siempre limpiar los contadores al cargar la página de login
// para asegurar que no quedamos atrapados en un bucle
// Always clear counters when loading the login page
// to ensure we don't get trapped in a loop
console.log('Login page loaded, clearing all counters');
sessionStorage.removeItem('redirect_count');
localStorage.removeItem('refresh_attempts');
@@ -589,14 +589,14 @@ if (isLoginPage && loginForm) {
localStorage.setItem(TOKEN_KEY, token);
localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);
// Extraer fecha de expiración desde el token JWT
// Extract expiration date from the JWT token
let parsedExpiry = false;
const tokenParts = token.split('.');
if (tokenParts.length === 3) {
try {
const payload = JSON.parse(atob(tokenParts[1]));
if (payload.exp) {
// payload.exp está en segundos desde epoch
// payload.exp is in seconds since epoch
const expiryDate = new Date(payload.exp * 1000);
// Verify the date is valid
@@ -642,7 +642,7 @@ if (isLoginPage && loginForm) {
// Redirect to main app
redirectToMainApp();
} catch (error) {
loginError.textContent = error.message || 'Error al iniciar sesión';
loginError.textContent = error.message || 'Error logging in';
loginError.style.display = 'block';
}
});
@@ -664,7 +664,7 @@ if (isLoginPage && registerForm) {
// Validate passwords match
if (password !== confirmPassword) {
const errorMsg = window.i18n ? window.i18n.t('auth.passwords_mismatch') : 'Las contraseñas no coinciden';
const errorMsg = window.i18n ? window.i18n.t('auth.passwords_mismatch') : 'Passwords do not match';
registerError.textContent = errorMsg;
registerError.style.display = 'block';
return;
@@ -674,7 +674,7 @@ if (isLoginPage && registerForm) {
const data = await register(username, email, password);
// Show success message
const successMsg = window.i18n ? window.i18n.t('auth.account_success') : '¡Cuenta creada con éxito! Puedes iniciar sesión ahora.';
const successMsg = window.i18n ? window.i18n.t('auth.account_success') : 'Account created successfully! You can now log in.';
registerSuccess.textContent = successMsg;
registerSuccess.style.display = 'block';
@@ -687,7 +687,7 @@ if (isLoginPage && registerForm) {
registerPanel.style.display = 'none';
}, 2000);
} catch (error) {
const errorMsg = window.i18n ? window.i18n.t('auth.admin_create_error') : 'Error al registrar cuenta';
const errorMsg = window.i18n ? window.i18n.t('auth.admin_create_error') : 'Error registering account';
registerError.textContent = error.message || errorMsg;
registerError.style.display = 'block';
}
@@ -710,7 +710,7 @@ if (isLoginPage && adminSetupForm) {
// Validate passwords match
if (password !== confirmPassword) {
const errorMsg = window.i18n ? window.i18n.t('auth.passwords_mismatch') : 'Las contraseñas no coinciden';
const errorMsg = window.i18n ? window.i18n.t('auth.passwords_mismatch') : 'Passwords do not match';
adminSetupError.textContent = errorMsg;
adminSetupError.style.display = 'block';
return;
@@ -721,7 +721,7 @@ if (isLoginPage && adminSetupForm) {
const data = await register('admin', email, password, 'admin');
// Show success message in the GUI instead of alert
const successMsg = window.i18n ? window.i18n.t('auth.admin_success') : '¡Cuenta de administrador creada con éxito! Ahora puedes iniciar sesión.';
const successMsg = window.i18n ? window.i18n.t('auth.admin_success') : 'Admin account created successfully! You can now log in.';
if (adminSetupSuccess) {
adminSetupSuccess.textContent = successMsg;
@@ -736,7 +736,7 @@ if (isLoginPage && adminSetupForm) {
}, 2000);
} catch (error) {
const errorMsg = window.i18n ? window.i18n.t('auth.admin_create_error') : 'Error al crear cuenta de administrador';
const errorMsg = window.i18n ? window.i18n.t('auth.admin_create_error') : 'Error creating admin account';
adminSetupError.textContent = error.message || errorMsg;
adminSetupError.style.display = 'block';
}
@@ -792,10 +792,10 @@ async function login(username, password) {
if (!response.ok) {
try {
const errorData = await response.json();
throw new Error(errorData.error || 'Falló la autenticación');
throw new Error(errorData.error || 'Authentication failed');
} catch (jsonError) {
// If the error response is not valid JSON
throw new Error(`Error de autenticación (${response.status}): ${response.statusText}`);
throw new Error(`Authentication error (${response.status}): ${response.statusText}`);
}
}
@@ -806,7 +806,7 @@ async function login(username, password) {
return data;
} catch (jsonError) {
console.error('Error parsing login response:', jsonError);
throw new Error('Error al procesar la respuesta del servidor');
throw new Error('Error processing server response');
}
} catch (error) {
console.error('Login error:', error);
@@ -848,10 +848,10 @@ async function register(username, email, password, role = 'user') {
if (!response.ok) {
try {
const errorData = await response.json();
throw new Error(errorData.error || 'Error en el registro');
throw new Error(errorData.error || 'Registration error');
} catch (jsonError) {
// If the error response is not valid JSON
throw new Error(`Error de registro (${response.status}): ${response.statusText}`);
throw new Error(`Registration error (${response.status}): ${response.statusText}`);
}
}
@@ -862,7 +862,7 @@ async function register(username, email, password, role = 'user') {
return data;
} catch (jsonError) {
console.error('Error parsing registration response:', jsonError);
throw new Error('Error al procesar la respuesta del servidor');
throw new Error('Error processing server response');
}
} catch (error) {
console.error('Registration error:', error);
@@ -883,7 +883,7 @@ async function fetchUserData(token) {
});
if (!response.ok) {
throw new Error('Error al obtener datos del usuario');
throw new Error('Error fetching user data');
}
return await response.json();
@@ -1092,7 +1092,7 @@ function redirectToMainApp() {
window.location.href = '/login.html?error=redirect_fatal';
} catch (e) {
// Nothing more we can do
alert('Error crítico en la redirección. Por favor, recarga la página e intenta nuevamente.');
alert('Critical redirect error. Please reload the page and try again.');
}
}
+26 -26
View File
@@ -30,7 +30,7 @@ const contextMenus = {
window.favorites.removeFromFavorites(folder.id, 'folder');
// Update menu item text
document.getElementById('favorite-folder-option').querySelector('span').textContent =
window.i18n ? window.i18n.t('actions.favorite') : 'Añadir a favoritos';
window.i18n ? window.i18n.t('actions.favorite') : 'Add to favorites';
} else {
// Add to favorites
window.favorites.addToFavorites(
@@ -41,7 +41,7 @@ const contextMenus = {
);
// Update menu item text
document.getElementById('favorite-folder-option').querySelector('span').textContent =
window.i18n ? window.i18n.t('actions.unfavorite') : 'Quitar de favoritos';
window.i18n ? window.i18n.t('actions.unfavorite') : 'Remove from favorites';
}
}
window.ui.closeContextMenu();
@@ -143,7 +143,7 @@ const contextMenus = {
window.favorites.removeFromFavorites(file.id, 'file');
// Update menu item text
document.getElementById('favorite-file-option').querySelector('span').textContent =
window.i18n ? window.i18n.t('actions.favorite') : 'Añadir a favoritos';
window.i18n ? window.i18n.t('actions.favorite') : 'Add to favorites';
} else {
// Add to favorites
window.favorites.addToFavorites(
@@ -154,7 +154,7 @@ const contextMenus = {
);
// Update menu item text
document.getElementById('favorite-file-option').querySelector('span').textContent =
window.i18n ? window.i18n.t('actions.unfavorite') : 'Quitar de favoritos';
window.i18n ? window.i18n.t('actions.unfavorite') : 'Remove from favorites';
}
}
window.ui.closeFileContextMenu();
@@ -246,7 +246,7 @@ const contextMenus = {
renameInput.value = folder.name;
// Update header text
const headerSpan = renameDialog.querySelector('.rename-dialog-header span');
if (headerSpan) headerSpan.textContent = window.i18n ? window.i18n.t('dialogs.rename_folder') : 'Renombrar carpeta';
if (headerSpan) headerSpan.textContent = window.i18n ? window.i18n.t('dialogs.rename_folder') : 'Rename folder';
renameDialog.style.display = 'flex';
renameInput.focus();
renameInput.select();
@@ -264,7 +264,7 @@ const contextMenus = {
renameInput.value = file.name;
// Update header text
const headerSpan = renameDialog.querySelector('.rename-dialog-header span');
if (headerSpan) headerSpan.textContent = window.i18n ? window.i18n.t('dialogs.rename_file') : 'Renombrar archivo';
if (headerSpan) headerSpan.textContent = window.i18n ? window.i18n.t('dialogs.rename_file') : 'Rename file';
renameDialog.style.display = 'flex';
renameInput.focus();
renameInput.select();
@@ -293,8 +293,8 @@ const contextMenus = {
// Update dialog title (preserve icon)
const dialogHeader = document.getElementById('move-file-dialog').querySelector('.rename-dialog-header');
const titleText = mode === 'file' ?
(window.i18n ? window.i18n.t('dialogs.move_file') : 'Mover archivo') :
(window.i18n ? window.i18n.t('dialogs.move_folder') : 'Mover carpeta');
(window.i18n ? window.i18n.t('dialogs.move_file') : 'Move file') :
(window.i18n ? window.i18n.t('dialogs.move_folder') : 'Move folder');
dialogHeader.innerHTML = `<i class="fas fa-arrows-alt" style="color:#ff5e3a"></i> <span>${titleText}</span>`;
// Load all available folders
@@ -319,7 +319,7 @@ const contextMenus = {
async renameItem() {
const newName = document.getElementById('rename-input').value.trim();
if (!newName) {
alert(window.i18n ? window.i18n.t('errors.empty_name') : 'El nombre no puede estar vacío');
alert(window.i18n ? window.i18n.t('errors.empty_name') : 'Name cannot be empty');
return;
}
@@ -361,7 +361,7 @@ const contextMenus = {
// Clear container except root option
folderSelectContainer.innerHTML = `
<div class="folder-select-item selected" data-folder-id="">
<i class="fas fa-folder"></i> <span data-i18n="dialogs.root">Raíz</span>
<i class="fas fa-folder"></i> <span data-i18n="dialogs.root">Root</span>
</div>
`;
@@ -438,8 +438,8 @@ const contextMenus = {
// Update dialog content
dialogHeader.textContent = itemType === 'file' ?
(window.i18n ? window.i18n.t('dialogs.share_file') : 'Compartir archivo') :
(window.i18n ? window.i18n.t('dialogs.share_folder') : 'Compartir carpeta');
(window.i18n ? window.i18n.t('dialogs.share_file') : 'Share file') :
(window.i18n ? window.i18n.t('dialogs.share_folder') : 'Share folder');
itemName.textContent = item.name;
@@ -470,21 +470,21 @@ const contextMenus = {
shareEl.className = 'existing-share-item';
const expiresText = share.expires_at ?
`Vence: ${window.fileSharing.formatExpirationDate(share.expires_at)}` :
'Sin vencimiento';
`Expires: ${window.fileSharing.formatExpirationDate(share.expires_at)}` :
'No expiration';
shareEl.innerHTML = `
<div class="share-url">${share.url}</div>
<div class="share-info">
${share.password_protected ? '<span class="share-protected"><i class="fas fa-lock"></i> Con contraseña</span>' : ''}
${share.password_protected ? '<span class="share-protected"><i class="fas fa-lock"></i> Password protected</span>' : ''}
<span class="share-expiration">${expiresText}</span>
</div>
<div class="share-actions">
<button class="btn btn-small copy-link-btn" data-share-url="${share.url}">
<i class="fas fa-copy"></i> Copiar
<i class="fas fa-copy"></i> Copy
</button>
<button class="btn btn-small btn-danger delete-link-btn" data-share-id="${share.id}">
<i class="fas fa-trash"></i> Eliminar
<i class="fas fa-trash"></i> Delete
</button>
</div>
`;
@@ -507,9 +507,9 @@ const contextMenus = {
const shareId = btn.getAttribute('data-share-id');
showConfirmDialog({
title: window.i18n ? window.i18n.t('dialogs.confirm_delete_share') : 'Eliminar enlace',
message: window.i18n ? window.i18n.t('dialogs.confirm_delete_share_msg') : '¿Estás seguro de que quieres eliminar este enlace compartido?',
confirmText: window.i18n ? window.i18n.t('actions.delete') : 'Eliminar',
title: window.i18n ? window.i18n.t('dialogs.confirm_delete_share') : 'Delete link',
message: window.i18n ? window.i18n.t('dialogs.confirm_delete_share_msg') : 'Are you sure you want to delete this shared link?',
confirmText: window.i18n ? window.i18n.t('actions.delete') : 'Delete',
}).then(confirmed => {
if (confirmed) {
window.fileSharing.removeSharedLink(shareId);
@@ -534,7 +534,7 @@ const contextMenus = {
*/
createSharedLink() {
if (!window.app.shareDialogItem || !window.app.shareDialogItemType) {
window.ui.showNotification('Error', 'No se pudo compartir el elemento');
window.ui.showNotification('Error', 'Could not share the item');
return;
}
@@ -577,14 +577,14 @@ const contextMenus = {
shareUrl.select();
// Show success message
window.ui.showNotification('Enlace creado', 'Enlace compartido creado correctamente');
window.ui.showNotification('Link created', 'Shared link created successfully');
// Reload existing shares
this.showShareDialog(item, itemType);
} catch (error) {
console.error('Error creating shared link:', error);
window.ui.showNotification('Error', 'No se pudo crear el enlace compartido');
window.ui.showNotification('Error', 'Could not create shared link');
}
},
@@ -614,14 +614,14 @@ const contextMenus = {
const shareUrl = window.app.notificationShareUrl;
if (!email || !shareUrl) {
window.ui.showNotification('Error', 'Por favor, ingresa un correo electrónico válido');
window.ui.showNotification('Error', 'Please enter a valid email address');
return;
}
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
window.ui.showNotification('Error', 'Por favor, ingresa un correo electrónico válido');
window.ui.showNotification('Error', 'Please enter a valid email address');
return;
}
@@ -630,7 +630,7 @@ const contextMenus = {
document.getElementById('notification-dialog').style.display = 'none';
} catch (error) {
console.error('Error sending notification:', error);
window.ui.showNotification('Error', 'No se pudo enviar la notificación');
window.ui.showNotification('Error', 'Could not send notification');
}
},
+17 -17
View File
@@ -230,8 +230,8 @@ const favorites = {
// Show success notification
window.ui.showNotification(
'Añadido a favoritos',
`"${name}" añadido a favoritos`
'Added to favorites',
`"${name}" added to favorites`
);
return true;
@@ -271,8 +271,8 @@ const favorites = {
// Show success notification if item was found
if (item) {
window.ui.showNotification(
'Eliminado de favoritos',
`"${item.name}" eliminado de favoritos`
'Removed from favorites',
`"${item.name}" removed from favorites`
);
}
return true;
@@ -310,10 +310,10 @@ const favorites = {
filesGrid.innerHTML = '';
filesListView.innerHTML = `
<div class="list-header">
<div data-i18n="files.name">Nombre</div>
<div data-i18n="files.type">Tipo</div>
<div data-i18n="files.size">Tamaño</div>
<div data-i18n="files.modified">Modificado</div>
<div data-i18n="files.name">Name</div>
<div data-i18n="files.type">Type</div>
<div data-i18n="files.size">Size</div>
<div data-i18n="files.modified">Modified</div>
</div>
`;
@@ -326,8 +326,8 @@ const favorites = {
emptyState.className = 'empty-state';
emptyState.innerHTML = `
<i class="fas fa-star" style="font-size: 48px; color: #ddd; margin-bottom: 16px;"></i>
<p>${window.i18n ? window.i18n.t('favorites.empty_state') : 'No hay elementos favoritos'}</p>
<p>${window.i18n ? window.i18n.t('favorites.empty_hint') : 'Para marcar como favorito, haz clic derecho en cualquier archivo o carpeta'}</p>
<p>${window.i18n ? window.i18n.t('favorites.empty_state') : 'No favorite items'}</p>
<p>${window.i18n ? window.i18n.t('favorites.empty_hint') : 'To mark as favorite, right-click on any file or folder'}</p>
`;
filesGrid.appendChild(emptyState);
return;
@@ -359,7 +359,7 @@ const favorites = {
} catch (error) {
console.error('Error displaying favorites:', error);
window.ui.showNotification('Error', 'Error al cargar elementos favoritos');
window.ui.showNotification('Error', 'Error loading favorite items');
}
},
@@ -468,7 +468,7 @@ const favorites = {
<i class="fas fa-folder"></i>
</div>
<div class="file-name">${folder.name}</div>
<div class="file-info">Carpeta</div>
<div class="file-info">Folder</div>
`;
// Click to navigate
@@ -518,7 +518,7 @@ const favorites = {
</div>
<span>${folder.name}</span>
</div>
<div class="type-cell">${window.i18n ? window.i18n.t('files.file_types.folder') : 'Carpeta'}</div>
<div class="type-cell">${window.i18n ? window.i18n.t('files.file_types.folder') : 'Folder'}</div>
<div class="size-cell">--</div>
<div class="date-cell">${formattedDate}</div>
`;
@@ -559,17 +559,17 @@ const favorites = {
// Determine icon and type
let iconClass = 'fas fa-file';
let iconSpecialClass = '';
let typeLabel = 'Documento';
let typeLabel = 'Document';
if (file.mime_type) {
if (file.mime_type.startsWith('image/')) {
iconClass = 'fas fa-file-image';
iconSpecialClass = 'image-icon';
typeLabel = window.i18n ? window.i18n.t('files.file_types.image') : 'Imagen';
typeLabel = window.i18n ? window.i18n.t('files.file_types.image') : 'Image';
} else if (file.mime_type.startsWith('text/')) {
iconClass = 'fas fa-file-alt';
iconSpecialClass = 'text-icon';
typeLabel = window.i18n ? window.i18n.t('files.file_types.text') : 'Texto';
typeLabel = window.i18n ? window.i18n.t('files.file_types.text') : 'Text';
} else if (file.mime_type.startsWith('video/')) {
iconClass = 'fas fa-file-video';
iconSpecialClass = 'video-icon';
@@ -606,7 +606,7 @@ const favorites = {
<i class="${iconClass}"></i>
</div>
<div class="file-name">${file.name}</div>
<div class="file-info">Modificado ${formattedDate.split(' ')[0]}</div>
<div class="file-info">Modified ${formattedDate.split(' ')[0]}</div>
`;
// Download on click
+91 -91
View File
@@ -49,8 +49,8 @@ const fileOps = {
try {
console.log(`Uploading file to folder: ${targetFolderId || 'root'}`);
// Usamos la URL correcta para la subida de archivos
console.log('Formulario a enviar:', {
// We use the correct URL for file upload
console.log('Form to submit:', {
file: file.name,
size: file.size,
folder_id: targetFolderId || 'root'
@@ -59,16 +59,16 @@ const fileOps = {
const response = await fetch('/api/files/upload', {
method: 'POST',
body: formData,
// Añadir cache: 'no-store' para evitar problemas de caché durante la subida
// Add cache: 'no-store' to avoid cache issues during upload
cache: 'no-store',
headers: {
...getAuthHeaders(),
// Agregar este encabezado para forzar recargas frescas
// Add this header to force fresh reloads
'Cache-Control': 'no-cache, no-store, must-revalidate'
}
});
console.log('Respuesta del servidor:', {
console.log('Server response:', {
status: response.status,
statusText: response.statusText
});
@@ -83,11 +83,11 @@ const fileOps = {
console.log(`Successfully uploaded ${file.name}`, responseData);
// Show success notification immediately
window.ui.showNotification('Archivo subido', `${file.name} completado`);
window.ui.showNotification('File uploaded', `${file.name} completed`);
if (i === totalFiles - 1) {
// Last file uploaded - wait and reload once
console.log('Último archivo subido, esperando antes de recargar...');
console.log('Last file uploaded, waiting before reloading...');
// Wait for backend to persist
await new Promise(resolve => setTimeout(resolve, 800));
@@ -96,7 +96,7 @@ const fileOps = {
try {
await window.loadFiles({forceRefresh: true});
} catch (reloadError) {
console.error("Error recargando archivos:", reloadError);
console.error("Error reloading files:", reloadError);
}
// Hide upload UI
@@ -109,11 +109,11 @@ const fileOps = {
} else {
const errorData = await response.text();
console.error('Upload error:', errorData);
window.ui.showNotification('Error', `Error al subir el archivo: ${file.name}`);
window.ui.showNotification('Error', `Error uploading file: ${file.name}`);
}
} catch (error) {
console.error('Network error during upload:', error);
window.ui.showNotification('Error', `Error de red al subir el archivo: ${file.name}`);
window.ui.showNotification('Error', `Network error uploading file: ${file.name}`);
}
}
},
@@ -181,7 +181,7 @@ const fileOps = {
console.log(`Created folder: ${folderPath} -> ${folder.id}`);
} else {
console.error(`Error creating folder ${folderPath}:`, await response.text());
window.ui.showNotification('Error', `Error creando carpeta: ${folderName}`);
window.ui.showNotification('Error', `Error creating folder: ${folderName}`);
}
} catch (error) {
console.error(`Network error creating folder ${folderPath}:`, error);
@@ -228,7 +228,7 @@ const fileOps = {
}
// Finish up
window.ui.showNotification('Carpeta subida', `${uploadedCount} archivos subidos correctamente`);
window.ui.showNotification('Folder uploaded', `${uploadedCount} files uploaded successfully`);
await new Promise(resolve => setTimeout(resolve, 800));
@@ -253,7 +253,7 @@ const fileOps = {
try {
console.log('Creating folder with name:', name);
// Enviar la solicitud real al backend para crear la carpeta
// Send the actual request to the backend to create the folder
const response = await fetch('/api/folders', {
method: 'POST',
headers: {
@@ -268,28 +268,28 @@ const fileOps = {
});
if (response.ok) {
// Obtener la carpeta creada del backend
// Get the created folder from the backend
const folder = await response.json();
console.log('Folder created successfully:', folder);
// Añadir la carpeta a la vista de inmediato para feedback instantáneo
// Add the folder to the view immediately for instant feedback
window.ui.addFolderToView(folder);
// Esperar para permitir que el backend guarde los cambios
// Wait to allow the backend to save the changes
await new Promise(resolve => setTimeout(resolve, 1000));
// Recargar los archivos para refrescar la vista
// Reload files to refresh the view
await window.loadFiles({forceRefresh: true});
window.ui.showNotification('Carpeta creada', `"${name}" creada correctamente`);
window.ui.showNotification('Folder created', `"${name}" created successfully`);
} else {
const errorData = await response.text();
console.error('Create folder error:', errorData);
window.ui.showNotification('Error', 'Error al crear la carpeta');
window.ui.showNotification('Error', 'Error creating the folder');
}
} catch (error) {
console.error('Error creating folder:', error);
window.ui.showNotification('Error', 'Error al crear la carpeta');
window.ui.showNotification('Error', 'Error creating the folder');
}
},
@@ -315,22 +315,22 @@ const fileOps = {
if (response.ok) {
// Reload files after moving
await window.loadFiles();
window.ui.showNotification('Archivo movido', 'Archivo movido correctamente');
window.ui.showNotification('File moved', 'File moved successfully');
return true;
} else {
let errorMessage = 'Error desconocido';
let errorMessage = 'Unknown error';
try {
const errorData = await response.json();
errorMessage = errorData.error || 'Error desconocido';
errorMessage = errorData.error || 'Unknown error';
} catch (e) {
errorMessage = 'Error al procesar la respuesta del servidor';
errorMessage = 'Error processing server response';
}
window.ui.showNotification('Error', `Error al mover el archivo: ${errorMessage}`);
window.ui.showNotification('Error', `Error moving the file: ${errorMessage}`);
return false;
}
} catch (error) {
console.error('Error moving file:', error);
window.ui.showNotification('Error', 'Error al mover el archivo');
window.ui.showNotification('Error', 'Error moving the file');
return false;
}
},
@@ -357,22 +357,22 @@ const fileOps = {
if (response.ok) {
// Reload files after moving
await window.loadFiles();
window.ui.showNotification('Carpeta movida', 'Carpeta movida correctamente');
window.ui.showNotification('Folder moved', 'Folder moved successfully');
return true;
} else {
let errorMessage = 'Error desconocido';
let errorMessage = 'Unknown error';
try {
const errorData = await response.json();
errorMessage = errorData.error || 'Error desconocido';
errorMessage = errorData.error || 'Unknown error';
} catch (e) {
errorMessage = 'Error al procesar la respuesta del servidor';
errorMessage = 'Error processing server response';
}
window.ui.showNotification('Error', `Error al mover la carpeta: ${errorMessage}`);
window.ui.showNotification('Error', `Error moving the folder: ${errorMessage}`);
return false;
}
} catch (error) {
console.error('Error moving folder:', error);
window.ui.showNotification('Error', 'Error al mover la carpeta');
window.ui.showNotification('Error', 'Error moving the folder');
return false;
}
},
@@ -400,26 +400,26 @@ const fileOps = {
if (response.ok) {
window.ui.showNotification(
window.i18n ? window.i18n.t('notifications.file_renamed') : 'Archivo renombrado',
window.i18n ? window.i18n.t('notifications.file_renamed_to', { name: newName }) : `Archivo renombrado a "${newName}"`
window.i18n ? window.i18n.t('notifications.file_renamed') : 'File renamed',
window.i18n ? window.i18n.t('notifications.file_renamed_to', { name: newName }) : `File renamed to "${newName}"`
);
return true;
} else {
const errorText = await response.text();
console.error('Error response:', errorText);
let errorMessage = 'Error desconocido';
let errorMessage = 'Unknown error';
try {
const errorData = JSON.parse(errorText);
errorMessage = errorData.error || response.statusText;
} catch (e) {
errorMessage = errorText || response.statusText;
}
window.ui.showNotification('Error', `Error al renombrar el archivo: ${errorMessage}`);
window.ui.showNotification('Error', `Error renaming the file: ${errorMessage}`);
return false;
}
} catch (error) {
console.error('Error renaming file:', error);
window.ui.showNotification('Error', 'Error al renombrar el archivo');
window.ui.showNotification('Error', 'Error renaming the file');
return false;
}
},
@@ -446,13 +446,13 @@ const fileOps = {
console.log('Response status:', response.status);
if (response.ok) {
window.ui.showNotification('Carpeta renombrada', `Carpeta renombrada a "${newName}"`);
window.ui.showNotification('Folder renamed', `Folder renamed to "${newName}"`);
return true;
} else {
const errorText = await response.text();
console.error('Error response:', errorText);
let errorMessage = 'Error desconocido';
let errorMessage = 'Unknown error';
try {
// Try to parse as JSON
const errorData = JSON.parse(errorText);
@@ -462,12 +462,12 @@ const fileOps = {
errorMessage = errorText || response.statusText;
}
window.ui.showNotification('Error', `Error al renombrar la carpeta: ${errorMessage}`);
window.ui.showNotification('Error', `Error renaming the folder: ${errorMessage}`);
return false;
}
} catch (error) {
console.error('Error renaming folder:', error);
window.ui.showNotification('Error', 'Error al renombrar la carpeta');
window.ui.showNotification('Error', 'Error renaming the folder');
return false;
}
},
@@ -480,9 +480,9 @@ const fileOps = {
*/
async deleteFile(fileId, fileName) {
const confirmed = await showConfirmDialog({
title: window.i18n ? window.i18n.t('dialogs.confirm_delete') : 'Mover a papelera',
message: window.i18n ? window.i18n.t('dialogs.confirm_delete_file', { name: fileName }) : `¿Estás seguro de que quieres mover a la papelera el archivo "${fileName}"?`,
confirmText: window.i18n ? window.i18n.t('actions.delete') : 'Eliminar',
title: window.i18n ? window.i18n.t('dialogs.confirm_delete') : 'Move to trash',
message: window.i18n ? window.i18n.t('dialogs.confirm_delete_file', { name: fileName }) : `Are you sure you want to move the file "${fileName}" to trash?`,
confirmText: window.i18n ? window.i18n.t('actions.delete') : 'Delete',
});
if (!confirmed) return false;
@@ -495,7 +495,7 @@ const fileOps = {
if (response.ok) {
window.loadFiles();
window.ui.showNotification('Archivo movido a papelera', `"${fileName}" movido a la papelera`);
window.ui.showNotification('File moved to trash', `"${fileName}" moved to trash`);
return true;
} else {
// Fallback to direct deletion if trash fails
@@ -506,16 +506,16 @@ const fileOps = {
if (fallbackResponse.ok) {
window.loadFiles();
window.ui.showNotification('Archivo eliminado', `"${fileName}" eliminado correctamente`);
window.ui.showNotification('File deleted', `"${fileName}" deleted successfully`);
return true;
} else {
window.ui.showNotification('Error', 'Error al eliminar el archivo');
window.ui.showNotification('Error', 'Error deleting the file');
return false;
}
}
} catch (error) {
console.error('Error deleting file:', error);
window.ui.showNotification('Error', 'Error al eliminar el archivo');
window.ui.showNotification('Error', 'Error deleting the file');
return false;
}
},
@@ -528,9 +528,9 @@ const fileOps = {
*/
async deleteFolder(folderId, folderName) {
const confirmed = await showConfirmDialog({
title: window.i18n ? window.i18n.t('dialogs.confirm_delete') : 'Mover a papelera',
message: window.i18n ? window.i18n.t('dialogs.confirm_delete_folder', { name: folderName }) : `¿Estás seguro de que quieres mover a la papelera la carpeta "${folderName}" y todo su contenido?`,
confirmText: window.i18n ? window.i18n.t('actions.delete') : 'Eliminar',
title: window.i18n ? window.i18n.t('dialogs.confirm_delete') : 'Move to trash',
message: window.i18n ? window.i18n.t('dialogs.confirm_delete_folder', { name: folderName }) : `Are you sure you want to move the folder "${folderName}" and all its contents to trash?`,
confirmText: window.i18n ? window.i18n.t('actions.delete') : 'Delete',
});
if (!confirmed) return false;
@@ -548,7 +548,7 @@ const fileOps = {
window.ui.updateBreadcrumb('');
}
window.loadFiles();
window.ui.showNotification('Carpeta movida a papelera', `"${folderName}" movida a la papelera`);
window.ui.showNotification('Folder moved to trash', `"${folderName}" moved to trash`);
return true;
} else {
// Fallback to direct deletion if trash fails
@@ -564,23 +564,23 @@ const fileOps = {
window.ui.updateBreadcrumb('');
}
window.loadFiles();
window.ui.showNotification('Carpeta eliminada', `"${folderName}" eliminada correctamente`);
window.ui.showNotification('Folder deleted', `"${folderName}" deleted successfully`);
return true;
} else {
window.ui.showNotification('Error', 'Error al eliminar la carpeta');
window.ui.showNotification('Error', 'Error deleting the folder');
return false;
}
}
} catch (error) {
console.error('Error deleting folder:', error);
window.ui.showNotification('Error', 'Error al eliminar la carpeta');
window.ui.showNotification('Error', 'Error deleting the folder');
return false;
}
},
/**
* Obtener elementos de la papelera
* @returns {Promise<Array>} - Lista de elementos en la papelera
* Get trash items
* @returns {Promise<Array>} - List of trash items
*/
async getTrashItems() {
try {
@@ -601,9 +601,9 @@ const fileOps = {
},
/**
* Restaurar un elemento desde la papelera
* @param {string} trashId - ID del elemento en la papelera
* @returns {Promise<boolean>} - Éxito de la operación
* Restore an item from trash
* @param {string} trashId - Trash item ID
* @returns {Promise<boolean>} - Operation success
*/
async restoreFromTrash(trashId) {
try {
@@ -617,29 +617,29 @@ const fileOps = {
});
if (response.ok) {
window.ui.showNotification('Elemento restaurado', 'Elemento restaurado correctamente');
window.ui.showNotification('Item restored', 'Item restored successfully');
return true;
} else {
window.ui.showNotification('Error', 'Error al restaurar el elemento');
window.ui.showNotification('Error', 'Error restoring the item');
return false;
}
} catch (error) {
console.error('Error restoring item from trash:', error);
window.ui.showNotification('Error', 'Error al restaurar el elemento');
window.ui.showNotification('Error', 'Error restoring the item');
return false;
}
},
/**
* Eliminar permanentemente un elemento de la papelera
* @param {string} trashId - ID del elemento en la papelera
* @returns {Promise<boolean>} - Éxito de la operación
* Permanently delete a trash item
* @param {string} trashId - Trash item ID
* @returns {Promise<boolean>} - Operation success
*/
async deletePermanently(trashId) {
const confirmed = await showConfirmDialog({
title: window.i18n ? window.i18n.t('dialogs.confirm_permanent_delete') : 'Eliminar permanentemente',
message: window.i18n ? window.i18n.t('dialogs.confirm_permanent_delete_msg') : '¿Estás seguro de que quieres eliminar permanentemente este elemento? Esta acción no se puede deshacer.',
confirmText: window.i18n ? window.i18n.t('actions.delete_permanently') : 'Eliminar permanentemente',
title: window.i18n ? window.i18n.t('dialogs.confirm_permanent_delete') : 'Delete permanently',
message: window.i18n ? window.i18n.t('dialogs.confirm_permanent_delete_msg') : 'Are you sure you want to permanently delete this item? This action cannot be undone.',
confirmText: window.i18n ? window.i18n.t('actions.delete_permanently') : 'Delete permanently',
});
if (!confirmed) return false;
@@ -650,28 +650,28 @@ const fileOps = {
});
if (response.ok) {
window.ui.showNotification('Elemento eliminado', 'Elemento eliminado permanentemente');
window.ui.showNotification('Item deleted', 'Item permanently deleted');
return true;
} else {
window.ui.showNotification('Error', 'Error al eliminar el elemento');
window.ui.showNotification('Error', 'Error deleting the item');
return false;
}
} catch (error) {
console.error('Error deleting item permanently:', error);
window.ui.showNotification('Error', 'Error al eliminar el elemento');
window.ui.showNotification('Error', 'Error deleting the item');
return false;
}
},
/**
* Vaciar la papelera
* @returns {Promise<boolean>} - Éxito de la operación
* Empty the trash
* @returns {Promise<boolean>} - Operation success
*/
async emptyTrash() {
const confirmed = await showConfirmDialog({
title: window.i18n ? window.i18n.t('dialogs.confirm_empty_trash') : 'Vaciar papelera',
message: window.i18n ? window.i18n.t('trash.empty_confirm') : '¿Estás seguro de que quieres vaciar la papelera? Esta acción eliminará permanentemente todos los elementos.',
confirmText: window.i18n ? window.i18n.t('actions.empty_trash') : 'Vaciar papelera',
title: window.i18n ? window.i18n.t('dialogs.confirm_empty_trash') : 'Empty trash',
message: window.i18n ? window.i18n.t('trash.empty_confirm') : 'Are you sure you want to empty the trash? This action will permanently delete all items.',
confirmText: window.i18n ? window.i18n.t('actions.empty_trash') : 'Empty trash',
});
if (!confirmed) return false;
@@ -682,23 +682,23 @@ const fileOps = {
});
if (response.ok) {
window.ui.showNotification('Papelera vaciada', 'La papelera ha sido vaciada correctamente');
window.ui.showNotification('Trash emptied', 'The trash has been emptied successfully');
return true;
} else {
window.ui.showNotification('Error', 'Error al vaciar la papelera');
window.ui.showNotification('Error', 'Error emptying the trash');
return false;
}
} catch (error) {
console.error('Error emptying trash:', error);
window.ui.showNotification('Error', 'Error al vaciar la papelera');
window.ui.showNotification('Error', 'Error emptying the trash');
return false;
}
},
/**
* Descargar un archivo
* @param {string} fileId - ID del archivo
* @param {string} fileName - Nombre del archivo
* Download a file
* @param {string} fileId - File ID
* @param {string} fileName - File name
*/
async downloadFile(fileId, fileName) {
try {
@@ -716,23 +716,23 @@ const fileOps = {
document.body.removeChild(link);
URL.revokeObjectURL(url);
} else {
window.ui.showNotification('Error', 'Error al descargar el archivo');
window.ui.showNotification('Error', 'Error downloading the file');
}
} catch (error) {
console.error('Error downloading file:', error);
window.ui.showNotification('Error', 'Error al descargar el archivo');
window.ui.showNotification('Error', 'Error downloading the file');
}
},
/**
* Descargar una carpeta como ZIP
* @param {string} folderId - ID de la carpeta
* @param {string} folderName - Nombre de la carpeta
* Download a folder as ZIP
* @param {string} folderId - Folder ID
* @param {string} folderName - Folder name
*/
async downloadFolder(folderId, folderName) {
try {
// Show notification to user
window.ui.showNotification('Preparando descarga', 'Preparando la carpeta para descargar...');
window.ui.showNotification('Preparing download', 'Preparing the folder for download...');
const response = await fetch(`/api/folders/${folderId}/download?format=zip`, {
headers: getAuthHeaders()
@@ -748,11 +748,11 @@ const fileOps = {
document.body.removeChild(link);
URL.revokeObjectURL(url);
} else {
window.ui.showNotification('Error', 'Error al descargar la carpeta');
window.ui.showNotification('Error', 'Error downloading the folder');
}
} catch (error) {
console.error('Error downloading folder:', error);
window.ui.showNotification('Error', 'Error al descargar la carpeta');
window.ui.showNotification('Error', 'Error downloading the folder');
}
}
};
+5 -5
View File
@@ -214,11 +214,11 @@ const fileSharing = {
copyLinkToClipboard(url) {
try {
navigator.clipboard.writeText(url);
window.ui.showNotification('Enlace copiado', 'Enlace copiado al portapapeles');
window.ui.showNotification('Link copied', 'Link copied to clipboard');
return true;
} catch (error) {
console.error('Error copying to clipboard:', error);
window.ui.showNotification('Error', 'No se pudo copiar el enlace');
window.ui.showNotification('Error', 'Could not copy link');
return false;
}
},
@@ -229,7 +229,7 @@ const fileSharing = {
* @returns {string} - Formatted date string
*/
formatExpirationDate(dateString) {
if (!dateString) return 'Sin vencimiento';
if (!dateString) return 'No expiration';
const date = new Date(dateString);
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
@@ -252,11 +252,11 @@ const fileSharing = {
// Simulate network delay
//await new Promise(resolve => setTimeout(resolve, 800));
window.ui.showNotification('Notificación enviada', `Se envió notificación a ${recipientEmail}`);
window.ui.showNotification('Notification sent', `Notification sent to ${recipientEmail}`);
return true;
} catch (error) {
console.error('Error sending share notification:', error);
window.ui.showNotification('Error', 'No se pudo enviar la notificación');
window.ui.showNotification('Error', 'Could not send notification');
return false;
}
},
+11 -11
View File
@@ -110,10 +110,10 @@ const recent = {
filesGrid.innerHTML = '';
filesListView.innerHTML = `
<div class="list-header">
<div data-i18n="files.name">Nombre</div>
<div data-i18n="files.type">Tipo</div>
<div data-i18n="files.size">Tamaño</div>
<div data-i18n="files.last_accessed">Último acceso</div>
<div data-i18n="files.name">Name</div>
<div data-i18n="files.type">Type</div>
<div data-i18n="files.size">Size</div>
<div data-i18n="files.last_accessed">Last accessed</div>
</div>
`;
@@ -126,8 +126,8 @@ const recent = {
emptyState.className = 'empty-state';
emptyState.innerHTML = `
<i class="fas fa-clock" style="font-size: 48px; color: #ddd; margin-bottom: 16px;"></i>
<p>${window.i18n ? window.i18n.t('recent.empty_state') : 'No hay archivos recientes'}</p>
<p>${window.i18n ? window.i18n.t('recent.empty_hint') : 'Los archivos que abras aparecerán aquí'}</p>
<p>${window.i18n ? window.i18n.t('recent.empty_state') : 'No recent files'}</p>
<p>${window.i18n ? window.i18n.t('recent.empty_hint') : 'Files you open will appear here'}</p>
`;
filesGrid.appendChild(emptyState);
return;
@@ -143,7 +143,7 @@ const recent = {
} catch (error) {
console.error('Error displaying recent files:', error);
window.ui.showNotification('Error', 'Error al cargar archivos recientes');
window.ui.showNotification('Error', 'Error loading recent files');
}
},
@@ -157,17 +157,17 @@ const recent = {
// Determine icon and type
let iconClass = 'fas fa-file';
let iconSpecialClass = '';
let typeLabel = 'Documento';
let typeLabel = 'Document';
if (file.mime_type) {
if (file.mime_type.startsWith('image/')) {
iconClass = 'fas fa-file-image';
iconSpecialClass = 'image-icon';
typeLabel = window.i18n ? window.i18n.t('files.file_types.image') : 'Imagen';
typeLabel = window.i18n ? window.i18n.t('files.file_types.image') : 'Image';
} else if (file.mime_type.startsWith('text/')) {
iconClass = 'fas fa-file-alt';
iconSpecialClass = 'text-icon';
typeLabel = window.i18n ? window.i18n.t('files.file_types.text') : 'Texto';
typeLabel = window.i18n ? window.i18n.t('files.file_types.text') : 'Text';
} else if (file.mime_type.startsWith('video/')) {
iconClass = 'fas fa-file-video';
iconSpecialClass = 'video-icon';
@@ -204,7 +204,7 @@ const recent = {
<i class="${iconClass}"></i>
</div>
<div class="file-name">${file.name}</div>
<div class="file-info">Accedido ${formattedDate.split(' ')[0]}</div>
<div class="file-info">Accessed ${formattedDate.split(' ')[0]}</div>
`;
// Download on click
+12 -12
View File
@@ -52,7 +52,7 @@ const search = {
}
} catch (error) {
console.error('Error performing search:', error);
window.ui.showNotification('Error', 'Error al realizar la búsqueda');
window.ui.showNotification('Error', 'Error performing search');
return { files: [], folders: [], total_count: 0 };
}
},
@@ -91,7 +91,7 @@ const search = {
}
} catch (error) {
console.error('Error performing advanced search:', error);
window.ui.showNotification('Error', 'Error al realizar la búsqueda avanzada');
window.ui.showNotification('Error', 'Error performing advanced search');
return { files: [], folders: [], total_count: 0 };
}
},
@@ -109,10 +109,10 @@ const search = {
filesGrid.innerHTML = '';
filesListView.innerHTML = `
<div class="list-header">
<div data-i18n="files.name">Nombre</div>
<div data-i18n="files.type">Tipo</div>
<div data-i18n="files.size">Tamaño</div>
<div data-i18n="files.modified">Modificado</div>
<div data-i18n="files.name">Name</div>
<div data-i18n="files.type">Type</div>
<div data-i18n="files.size">Size</div>
<div data-i18n="files.modified">Modified</div>
</div>
`;
@@ -120,9 +120,9 @@ const search = {
const searchHeader = document.createElement('div');
searchHeader.className = 'search-results-header';
searchHeader.innerHTML = `
<h3>Resultados de búsqueda (${results.total_count || (results.files.length + results.folders.length)})</h3>
<h3>Search results (${results.total_count || (results.files.length + results.folders.length)})</h3>
<button class="btn btn-secondary" id="clear-search-btn">
<i class="fas fa-times"></i> Limpiar búsqueda
<i class="fas fa-times"></i> Clear search
</button>
`;
filesGrid.appendChild(searchHeader);
@@ -147,7 +147,7 @@ const search = {
emptyState.className = 'empty-state';
emptyState.innerHTML = `
<i class="fas fa-search" style="font-size: 48px; color: #ddd; margin-bottom: 16px;"></i>
<p>No se encontraron resultados para esta búsqueda</p>
<p>No results found for this search</p>
`;
filesGrid.appendChild(emptyState);
return;
@@ -178,15 +178,15 @@ const search = {
});
if (response.ok) {
window.ui.showNotification('Caché limpiada', 'Caché de búsqueda limpiada correctamente');
window.ui.showNotification('Cache cleared', 'Search cache cleared successfully');
return true;
} else {
window.ui.showNotification('Error', 'Error al limpiar la caché de búsqueda');
window.ui.showNotification('Error', 'Error clearing search cache');
return false;
}
} catch (error) {
console.error('Error clearing search cache:', error);
window.ui.showNotification('Error', 'Error al limpiar la caché de búsqueda');
window.ui.showNotification('Error', 'Error clearing search cache');
return false;
}
}
+66 -66
View File
@@ -16,24 +16,24 @@ const ui = {
folderMenu.id = 'folder-context-menu';
folderMenu.innerHTML = `
<div class="context-menu-item" id="download-folder-option">
<i class="fas fa-download"></i> <span data-i18n="actions.download">Descargar</span>
<i class="fas fa-download"></i> <span data-i18n="actions.download">Download</span>
</div>
<div class="context-menu-item" id="favorite-folder-option">
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Añadir a favoritos</span>
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Add to favorites</span>
</div>
<div class="context-menu-item" id="share-folder-option">
<i class="fas fa-share-alt"></i> <span data-i18n="actions.share">Compartir</span>
<i class="fas fa-share-alt"></i> <span data-i18n="actions.share">Share</span>
</div>
<div class="context-menu-separator"></div>
<div class="context-menu-item" id="rename-folder-option">
<i class="fas fa-pen"></i> <span data-i18n="actions.rename">Renombrar</span>
<i class="fas fa-pen"></i> <span data-i18n="actions.rename">Rename</span>
</div>
<div class="context-menu-item" id="move-folder-option">
<i class="fas fa-arrows-alt"></i> <span data-i18n="actions.move">Mover a...</span>
<i class="fas fa-arrows-alt"></i> <span data-i18n="actions.move">Move to...</span>
</div>
<div class="context-menu-separator"></div>
<div class="context-menu-item context-menu-item-danger" id="delete-folder-option">
<i class="fas fa-trash-alt"></i> <span data-i18n="actions.delete">Eliminar</span>
<i class="fas fa-trash-alt"></i> <span data-i18n="actions.delete">Delete</span>
</div>
`;
document.body.appendChild(folderMenu);
@@ -46,28 +46,28 @@ const ui = {
fileMenu.id = 'file-context-menu';
fileMenu.innerHTML = `
<div class="context-menu-item" id="view-file-option">
<i class="fas fa-eye"></i> <span data-i18n="actions.view">Ver</span>
<i class="fas fa-eye"></i> <span data-i18n="actions.view">View</span>
</div>
<div class="context-menu-item" id="download-file-option">
<i class="fas fa-download"></i> <span data-i18n="actions.download">Descargar</span>
<i class="fas fa-download"></i> <span data-i18n="actions.download">Download</span>
</div>
<div class="context-menu-separator"></div>
<div class="context-menu-item" id="favorite-file-option">
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Añadir a favoritos</span>
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Add to favorites</span>
</div>
<div class="context-menu-item" id="share-file-option">
<i class="fas fa-share-alt"></i> <span data-i18n="actions.share">Compartir</span>
<i class="fas fa-share-alt"></i> <span data-i18n="actions.share">Share</span>
</div>
<div class="context-menu-separator"></div>
<div class="context-menu-item" id="rename-file-option">
<i class="fas fa-pen"></i> <span data-i18n="actions.rename">Renombrar</span>
<i class="fas fa-pen"></i> <span data-i18n="actions.rename">Rename</span>
</div>
<div class="context-menu-item" id="move-file-option">
<i class="fas fa-arrows-alt"></i> <span data-i18n="actions.move">Mover a...</span>
<i class="fas fa-arrows-alt"></i> <span data-i18n="actions.move">Move to...</span>
</div>
<div class="context-menu-separator"></div>
<div class="context-menu-item context-menu-item-danger" id="delete-file-option">
<i class="fas fa-trash-alt"></i> <span data-i18n="actions.delete">Eliminar</span>
<i class="fas fa-trash-alt"></i> <span data-i18n="actions.delete">Delete</span>
</div>
`;
document.body.appendChild(fileMenu);
@@ -82,14 +82,14 @@ const ui = {
<div class="rename-dialog-content">
<div class="rename-dialog-header">
<i class="fas fa-pen" style="color:#ff5e3a"></i>
<span data-i18n="dialogs.rename_folder">Renombrar</span>
<span data-i18n="dialogs.rename_folder">Rename</span>
</div>
<div class="rename-dialog-body">
<input type="text" id="rename-input" data-i18n-placeholder="dialogs.new_name" placeholder="Nuevo nombre">
<input type="text" id="rename-input" data-i18n-placeholder="dialogs.new_name" placeholder="New name">
</div>
<div class="rename-dialog-buttons">
<button class="btn btn-secondary" id="rename-cancel-btn" data-i18n="actions.cancel">Cancelar</button>
<button class="btn btn-primary" id="rename-confirm-btn" data-i18n="actions.rename">Renombrar</button>
<button class="btn btn-secondary" id="rename-cancel-btn" data-i18n="actions.cancel">Cancel</button>
<button class="btn btn-primary" id="rename-confirm-btn" data-i18n="actions.rename">Rename</button>
</div>
</div>
`;
@@ -105,19 +105,19 @@ const ui = {
<div class="rename-dialog-content">
<div class="rename-dialog-header">
<i class="fas fa-arrows-alt" style="color:#ff5e3a"></i>
<span data-i18n="dialogs.move_file">Mover</span>
<span data-i18n="dialogs.move_file">Move</span>
</div>
<div class="rename-dialog-body">
<p style="margin:0 0 12px;color:#718096;font-size:14px" data-i18n="dialogs.select_destination">Selecciona la carpeta destino:</p>
<p style="margin:0 0 12px;color:#718096;font-size:14px" data-i18n="dialogs.select_destination">Select destination folder:</p>
<div id="folder-select-container" style="max-height:220px;overflow-y:auto;">
<div class="folder-select-item selected" data-folder-id="">
<i class="fas fa-folder"></i> <span data-i18n="dialogs.root">Raíz</span>
<i class="fas fa-folder"></i> <span data-i18n="dialogs.root">Root</span>
</div>
</div>
</div>
<div class="rename-dialog-buttons">
<button class="btn btn-secondary" id="move-cancel-btn" data-i18n="actions.cancel">Cancelar</button>
<button class="btn btn-primary" id="move-confirm-btn" data-i18n="actions.move_to">Mover</button>
<button class="btn btn-secondary" id="move-cancel-btn" data-i18n="actions.cancel">Cancel</button>
<button class="btn btn-primary" id="move-confirm-btn" data-i18n="actions.move_to">Move</button>
</div>
</div>
`;
@@ -133,67 +133,67 @@ const ui = {
<div class="share-dialog-content">
<div class="share-dialog-header">
<i class="fas fa-share-alt" style="color:#ff5e3a"></i>
<span data-i18n="dialogs.share_file">Compartir archivo</span>
<span data-i18n="dialogs.share_file">Share file</span>
</div>
<div class="shared-item-info">
<strong>Elemento:</strong> <span id="shared-item-name"></span>
<strong>Item:</strong> <span id="shared-item-name"></span>
</div>
<div id="existing-shares-section" style="display:none; margin: 15px 0;">
<h3 data-i18n="dialogs.existing_shares">Enlaces compartidos existentes</h3>
<h3 data-i18n="dialogs.existing_shares">Existing shared links</h3>
<div id="existing-shares-container"></div>
</div>
<div class="share-options">
<h3 data-i18n="dialogs.share_options">Opciones de compartición</h3>
<h3 data-i18n="dialogs.share_options">Share options</h3>
<div class="form-group">
<label for="share-password" data-i18n="dialogs.password">Contraseña (opcional):</label>
<input type="password" id="share-password" placeholder="Proteger con contraseña">
<label for="share-password" data-i18n="dialogs.password">Password (optional):</label>
<input type="password" id="share-password" placeholder="Protect with password">
</div>
<div class="form-group">
<label for="share-expiration" data-i18n="dialogs.expiration">Fecha de vencimiento (opcional):</label>
<label for="share-expiration" data-i18n="dialogs.expiration">Expiration date (optional):</label>
<input type="date" id="share-expiration">
</div>
<div class="form-group">
<label data-i18n="dialogs.permissions">Permisos:</label>
<label data-i18n="dialogs.permissions">Permissions:</label>
<div class="permission-options">
<div class="permission-option">
<input type="checkbox" id="share-permission-read" checked>
<label for="share-permission-read" data-i18n="permissions.read">Lectura</label>
<label for="share-permission-read" data-i18n="permissions.read">Read</label>
</div>
<div class="permission-option">
<input type="checkbox" id="share-permission-write">
<label for="share-permission-write" data-i18n="permissions.write">Escritura</label>
<label for="share-permission-write" data-i18n="permissions.write">Write</label>
</div>
<div class="permission-option">
<input type="checkbox" id="share-permission-reshare">
<label for="share-permission-reshare" data-i18n="permissions.reshare">Permitir compartir</label>
<label for="share-permission-reshare" data-i18n="permissions.reshare">Allow sharing</label>
</div>
</div>
</div>
</div>
<div id="new-share-section" style="display:none; margin: 15px 0;">
<h3 data-i18n="dialogs.generated_link">Enlace generado</h3>
<h3 data-i18n="dialogs.generated_link">Generated link</h3>
<div class="form-group">
<input type="text" id="generated-share-url" readonly>
<div class="share-link-actions">
<button class="btn btn-small" id="copy-share-btn">
<i class="fas fa-copy"></i> <span data-i18n="actions.copy">Copiar</span>
<i class="fas fa-copy"></i> <span data-i18n="actions.copy">Copy</span>
</button>
<button class="btn btn-small" id="notify-share-btn">
<i class="fas fa-envelope"></i> <span data-i18n="actions.notify">Notificar</span>
<i class="fas fa-envelope"></i> <span data-i18n="actions.notify">Notify</span>
</button>
</div>
</div>
</div>
<div class="share-dialog-buttons">
<button class="btn btn-secondary" id="share-cancel-btn" data-i18n="actions.cancel">Cancelar</button>
<button class="btn btn-primary" id="share-confirm-btn" data-i18n="actions.share">Compartir</button>
<button class="btn btn-secondary" id="share-cancel-btn" data-i18n="actions.cancel">Cancel</button>
<button class="btn btn-primary" id="share-confirm-btn" data-i18n="actions.share">Share</button>
</div>
</div>
`;
@@ -228,24 +228,24 @@ const ui = {
<div class="share-dialog-content">
<div class="share-dialog-header">
<i class="fas fa-envelope" style="color:#ff5e3a"></i>
<span data-i18n="dialogs.notify">Notificar enlace compartido</span>
<span data-i18n="dialogs.notify">Notify shared link</span>
</div>
<p><strong>URL:</strong> <span id="notification-share-url"></span></p>
<div class="form-group">
<label for="notification-email" data-i18n="dialogs.recipient">Destinatario:</label>
<input type="email" id="notification-email" placeholder="Correo electrónico">
<label for="notification-email" data-i18n="dialogs.recipient">Recipient:</label>
<input type="email" id="notification-email" placeholder="Email address">
</div>
<div class="form-group">
<label for="notification-message" data-i18n="dialogs.message">Mensaje (opcional):</label>
<label for="notification-message" data-i18n="dialogs.message">Message (optional):</label>
<textarea id="notification-message" rows="3"></textarea>
</div>
<div class="share-dialog-buttons">
<button class="btn btn-secondary" id="notification-cancel-btn" data-i18n="actions.cancel">Cancelar</button>
<button class="btn btn-primary" id="notification-send-btn" data-i18n="actions.send">Enviar</button>
<button class="btn btn-secondary" id="notification-cancel-btn" data-i18n="actions.cancel">Cancel</button>
<button class="btn btn-primary" id="notification-send-btn" data-i18n="actions.send">Send</button>
</div>
</div>
`;
@@ -402,7 +402,7 @@ const ui = {
homeItem.textContent = getTranslatedText('breadcrumb.home', 'Home');
// For searching, we might have a custom breadcrumb text
if (folderName && folderName.startsWith('Búsqueda:')) {
if (folderName && folderName.startsWith('Search:')) {
// We're in search mode - don't add click handler
breadcrumb.appendChild(homeItem);
return;
@@ -421,7 +421,7 @@ const ui = {
breadcrumb.appendChild(homeItem);
// If we have a subfolder, add it to the breadcrumb
if (folderName && !folderName.startsWith('Mi Carpeta') && !folderName.startsWith('Búsqueda:')) {
if (folderName && !folderName.startsWith('Mi Carpeta') && !folderName.startsWith('Search:')) {
const separator = document.createElement('span');
separator.className = 'breadcrumb-separator';
separator.textContent = '>';
@@ -633,14 +633,14 @@ const ui = {
* @param {Object} folder - Folder object
*/
addFolderToView(folder) {
// Verificar si la carpeta ya existe en la vista para evitar duplicados
// Check if the folder already exists in the view to avoid duplicates
if (document.querySelector(`.file-card[data-folder-id="${folder.id}"]`) ||
document.querySelector(`.file-item[data-folder-id="${folder.id}"]`)) {
console.log(`Carpeta ${folder.name} (${folder.id}) ya existe en la vista, no duplicando`);
console.log(`Folder ${folder.name} (${folder.id}) already exists in the view, not duplicating`);
return;
}
console.log(`Añadiendo carpeta a la vista: ${folder.name} (${folder.id})`);
console.log(`Adding folder to the view: ${folder.name} (${folder.id})`);
// Grid view element
const folderGridElement = document.createElement('div');
@@ -655,7 +655,7 @@ const ui = {
<i class="fas fa-folder"></i>
</div>
<div class="file-name">${folder.name}</div>
<div class="file-info">Carpeta</div>
<div class="file-info">Folder</div>
`;
// Drag and drop setup for folders
@@ -746,7 +746,7 @@ const ui = {
if (id) {
if (isFolder) {
if (id === folder.id) {
alert("No puedes mover una carpeta a sí misma");
alert("You cannot move a folder to itself");
return;
}
await fileOps.moveFolder(id, folder.id);
@@ -758,7 +758,7 @@ const ui = {
document.getElementById('files-grid').appendChild(folderGridElement);
// List view element - Mejorado
// List view element - Improved
const folderListElement = document.createElement('div');
folderListElement.className = 'file-item';
folderListElement.dataset.folderId = folder.id;
@@ -788,7 +788,7 @@ const ui = {
});
}
// Mejorado: Estructura y clases para la vista de lista
// Improved: Structure and classes for list view
folderListElement.innerHTML = `
<div class="name-cell">
<div class="file-icon folder-icon">
@@ -796,7 +796,7 @@ const ui = {
</div>
<span>${folder.name}</span>
</div>
<div class="type-cell">${window.i18n ? window.i18n.t('files.file_types.folder') : 'Carpeta'}</div>
<div class="type-cell">${window.i18n ? window.i18n.t('files.file_types.folder') : 'Folder'}</div>
<div class="size-cell">--</div>
<div class="date-cell">${formattedDate}</div>
`;
@@ -844,7 +844,7 @@ const ui = {
if (id) {
if (isFolder) {
if (id === folder.id) {
alert("No puedes mover una carpeta a sí misma");
alert("You cannot move a folder to itself");
return;
}
await fileOps.moveFolder(id, folder.id);
@@ -862,29 +862,29 @@ const ui = {
* @param {Object} file - File object
*/
addFileToView(file) {
// Verificar si el archivo ya existe en la vista para evitar duplicados
// Check if the file already exists in the view to avoid duplicates
if (document.querySelector(`.file-card[data-file-id="${file.id}"]`) ||
document.querySelector(`.file-item[data-file-id="${file.id}"]`)) {
console.log(`Archivo ${file.name} (${file.id}) ya existe en la vista, no duplicando`);
console.log(`File ${file.name} (${file.id}) already exists in the view, not duplicating`);
return;
}
console.log(`Añadiendo archivo a la vista: ${file.name} (${file.id})`);
console.log(`Adding file to the view: ${file.name} (${file.id})`);
// Determine icon and type
let iconClass = 'fas fa-file';
let iconSpecialClass = '';
let typeLabel = 'Documento';
let typeLabel = 'Document';
if (file.mime_type) {
if (file.mime_type.startsWith('image/')) {
iconClass = 'fas fa-file-image';
iconSpecialClass = 'image-icon';
typeLabel = window.i18n ? window.i18n.t('files.file_types.image') : 'Imagen';
typeLabel = window.i18n ? window.i18n.t('files.file_types.image') : 'Image';
} else if (file.mime_type.startsWith('text/')) {
iconClass = 'fas fa-file-alt';
iconSpecialClass = 'text-icon';
typeLabel = window.i18n ? window.i18n.t('files.file_types.text') : 'Texto';
typeLabel = window.i18n ? window.i18n.t('files.file_types.text') : 'Text';
} else if (file.mime_type.startsWith('video/')) {
iconClass = 'fas fa-file-video';
iconSpecialClass = 'video-icon';
@@ -916,7 +916,7 @@ const ui = {
<i class="${iconClass}"></i>
</div>
<div class="file-name">${file.name}</div>
<div class="file-info">Modificado ${formattedDate.split(' ')[0]}</div>
<div class="file-info">Modified ${formattedDate.split(' ')[0]}</div>
`;
fileGridElement.dataset.fileId = file.id;
@@ -1007,7 +1007,7 @@ const ui = {
document.getElementById('files-grid').appendChild(fileGridElement);
// List view element - Mejorado con clases específicas y diseño mejorado
// List view element - Improved with specific classes and enhanced layout
const fileListElement = document.createElement('div');
fileListElement.className = 'file-item';
fileListElement.dataset.fileId = file.id;
@@ -1238,9 +1238,9 @@ window.initRubberBandSelection = initRubberBandSelection;
* @returns {Promise<boolean>} true if confirmed, false if cancelled
*/
function showConfirmDialog({ title, message, confirmText, cancelText, danger = true } = {}) {
const ct = confirmText || (window.i18n ? window.i18n.t('actions.delete') : 'Eliminar');
const cc = cancelText || (window.i18n ? window.i18n.t('actions.cancel') : 'Cancelar');
const t = title || (window.i18n ? window.i18n.t('dialogs.confirm_title') : 'Confirmar acción');
const ct = confirmText || (window.i18n ? window.i18n.t('actions.delete') : 'Delete');
const cc = cancelText || (window.i18n ? window.i18n.t('actions.cancel') : 'Cancel');
const t = title || (window.i18n ? window.i18n.t('dialogs.confirm_title') : 'Confirm action');
return new Promise((resolve) => {
// Remove any previous confirm dialog