refactor(ui): remove unnecessary checks (i18n is always defined)
This commit is contained in:
@@ -511,10 +511,7 @@ function initLanguageSelector() {
|
||||
localStorage.setItem(LOCALE_KEY, selectedLanguage);
|
||||
localStorage.setItem(FIRST_RUN_KEY, 'true');
|
||||
|
||||
// Update i18n if available
|
||||
if (i18n?.setLocale) {
|
||||
await i18n.setLocale(selectedLanguage);
|
||||
}
|
||||
await i18n.setLocale(selectedLanguage);
|
||||
|
||||
// Hide language panel
|
||||
hidePanel(languagePanel);
|
||||
@@ -635,7 +632,7 @@ async function configureOidcLoginUI() {
|
||||
// Update button text with provider name
|
||||
const btnTextEl = oidcBtn.querySelector('span');
|
||||
if (btnTextEl && oidcInfo.provider_name) {
|
||||
const template = i18n?.t ? i18n.t('auth.sso_login_provider') : 'Sign in with {{provider}}';
|
||||
const template = i18n.t('auth.sso_login_provider');
|
||||
btnTextEl.textContent = template.replace('{{provider}}', oidcInfo.provider_name);
|
||||
}
|
||||
|
||||
@@ -942,8 +939,7 @@ if (isLoginPage && registerForm) {
|
||||
|
||||
// Validate passwords match
|
||||
if (password !== confirmPassword) {
|
||||
const errorMsg = i18n ? i18n.t('auth.passwords_mismatch') : 'Passwords do not match';
|
||||
registerError.textContent = errorMsg;
|
||||
registerError.textContent = i18n.t('auth.passwords_mismatch');
|
||||
registerError.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
@@ -951,9 +947,7 @@ if (isLoginPage && registerForm) {
|
||||
try {
|
||||
await register(username, email, password);
|
||||
|
||||
// Show success message
|
||||
const successMsg = i18n ? i18n.t('auth.account_success') : 'Account created successfully! You can now log in.';
|
||||
registerSuccess.textContent = successMsg;
|
||||
registerSuccess.textContent = i18n.t('auth.account_success');
|
||||
registerSuccess.style.display = 'block';
|
||||
|
||||
// Clear form
|
||||
@@ -965,8 +959,7 @@ if (isLoginPage && registerForm) {
|
||||
hidePanel(registerPanel);
|
||||
}, 2000);
|
||||
} catch (error) {
|
||||
const errorMsg = i18n ? i18n.t('auth.admin_create_error') : 'Error registering account';
|
||||
registerError.textContent = error.message || errorMsg;
|
||||
registerError.textContent = error.message || i18n.t('auth.admin_create_error');
|
||||
registerError.style.display = 'block';
|
||||
}
|
||||
});
|
||||
@@ -988,8 +981,7 @@ if (isLoginPage && adminSetupForm) {
|
||||
|
||||
// Validate passwords match
|
||||
if (password !== confirmPassword) {
|
||||
const errorMsg = i18n ? i18n.t('auth.passwords_mismatch') : 'Passwords do not match';
|
||||
adminSetupError.textContent = errorMsg;
|
||||
adminSetupError.textContent = i18n.t('auth.passwords_mismatch');
|
||||
adminSetupError.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
@@ -1012,11 +1004,8 @@ if (isLoginPage && adminSetupForm) {
|
||||
}
|
||||
await response.json();
|
||||
|
||||
// Show success message in the GUI instead of alert
|
||||
const successMsg = i18n ? i18n.t('auth.admin_success') : 'Admin account created successfully! You can now log in.';
|
||||
|
||||
if (adminSetupSuccess) {
|
||||
adminSetupSuccess.textContent = successMsg;
|
||||
adminSetupSuccess.textContent = i18n.t('auth.admin_success');
|
||||
adminSetupSuccess.style.display = 'block';
|
||||
}
|
||||
|
||||
@@ -1027,8 +1016,7 @@ if (isLoginPage && adminSetupForm) {
|
||||
if (adminSetupSuccess) adminSetupSuccess.style.display = 'none';
|
||||
}, 2000);
|
||||
} catch (error) {
|
||||
const errorMsg = i18n ? i18n.t('auth.admin_create_error') : 'Error creating admin account';
|
||||
adminSetupError.textContent = error.message || errorMsg;
|
||||
adminSetupError.textContent = error.message || i18n.t('auth.admin_create_error');
|
||||
adminSetupError.style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -27,7 +27,7 @@ const contextMenus = {
|
||||
if (!option) return;
|
||||
const label = option.querySelector('span');
|
||||
if (!label) return;
|
||||
label.textContent = i18n ? i18n.t(isFavorite ? 'actions.unfavorite' : 'actions.favorite') : isFavorite ? 'Remove from favorites' : 'Add to favorites';
|
||||
label.textContent = i18n.t(isFavorite ? 'actions.unfavorite' : 'actions.favorite');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -382,7 +382,7 @@ const contextMenus = {
|
||||
renameInput.value = folder.name;
|
||||
// Update header text
|
||||
const headerSpan = renameDialog.querySelector('.rename-dialog-header span');
|
||||
if (headerSpan) headerSpan.textContent = i18n ? i18n.t('dialogs.rename_folder') : 'Rename folder';
|
||||
if (headerSpan) headerSpan.textContent = i18n.t('dialogs.rename_folder');
|
||||
renameDialog?.classList.remove('hidden');
|
||||
renameInput.focus();
|
||||
renameInput.select();
|
||||
@@ -402,7 +402,7 @@ const contextMenus = {
|
||||
renameInput.value = file.name;
|
||||
// Update header text
|
||||
const headerSpan = renameDialog.querySelector('.rename-dialog-header span');
|
||||
if (headerSpan) headerSpan.textContent = i18n ? i18n.t('dialogs.rename_file') : 'Rename file';
|
||||
if (headerSpan) headerSpan.textContent = i18n.t('dialogs.rename_file');
|
||||
renameDialog?.classList.remove('hidden');
|
||||
renameInput.focus();
|
||||
renameInput.select();
|
||||
@@ -471,7 +471,7 @@ const contextMenus = {
|
||||
|
||||
// Update dialog title (preserve icon)
|
||||
const dialogHeader = document.getElementById('move-file-dialog').querySelector('.rename-dialog-header');
|
||||
const titleText = mode === 'file' ? (i18n ? i18n.t('dialogs.move_file') : 'Move file') : i18n ? i18n.t('dialogs.move_folder') : 'Move folder';
|
||||
const titleText = mode === 'file' ? i18n.t('dialogs.move_file') : i18n.t('dialogs.move_folder');
|
||||
dialogHeader.innerHTML = `<i class="fas fa-arrows-alt dialog-header-icon"></i> <span>${titleText}</span>`;
|
||||
|
||||
// Load folders for the starting location
|
||||
@@ -496,7 +496,7 @@ const contextMenus = {
|
||||
async renameItem() {
|
||||
const newName = document.getElementById('rename-input').value.trim();
|
||||
if (!newName) {
|
||||
alert(i18n ? i18n.t('errors.empty_name') : 'Name cannot be empty');
|
||||
alert(i18n.t('errors.empty_name'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -587,7 +587,7 @@ const contextMenus = {
|
||||
currentFolderOption.className = 'folder-select-item folder-select-current';
|
||||
currentFolderOption.innerHTML = `
|
||||
<i class="fas fa-check-circle check-icon"></i>
|
||||
<span>${i18n ? i18n.t('dialogs.select_this_folder') : 'Select this folder'}</span>
|
||||
<span>${i18n.t('dialogs.select_this_folder')}</span>
|
||||
`;
|
||||
currentFolderOption.addEventListener('click', () => {
|
||||
document.querySelectorAll('.folder-select-item').forEach((item) => {
|
||||
@@ -606,7 +606,7 @@ const contextMenus = {
|
||||
parentOption.className = 'folder-select-item folder-navigate-up';
|
||||
parentOption.innerHTML = `
|
||||
<i class="fas fa-level-up-alt"></i>
|
||||
<span>${i18n ? i18n.t('dialogs.go_to_parent') : '.. (parent folder)'}</span>
|
||||
<span>${i18n.t('dialogs.go_to_parent')}</span>
|
||||
`;
|
||||
parentOption.addEventListener('click', () => {
|
||||
// Navigate to parent folder
|
||||
@@ -664,7 +664,7 @@ const contextMenus = {
|
||||
homeOption.className = 'folder-select-item folder-select-current';
|
||||
homeOption.innerHTML = `
|
||||
<i class="fas fa-check-circle check-icon"></i>
|
||||
<span>${i18n ? i18n.t('dialogs.move_to_home') : 'Move to Home folder'}</span>
|
||||
<span>${i18n.t('dialogs.move_to_home')}</span>
|
||||
`;
|
||||
homeOption.addEventListener('click', () => {
|
||||
document.querySelectorAll('.folder-select-item').forEach((item) => {
|
||||
@@ -678,7 +678,7 @@ const contextMenus = {
|
||||
// Inside a subfolder with no children - show empty message
|
||||
const emptyMsg = document.createElement('div');
|
||||
emptyMsg.className = 'folder-select-empty';
|
||||
emptyMsg.innerHTML = `<i class="fas fa-folder-open"></i> <span>${i18n ? i18n.t('dialogs.no_subfolders') : 'No subfolders to navigate'}</span>`;
|
||||
emptyMsg.innerHTML = `<i class="fas fa-folder-open"></i> <span>${i18n.t('dialogs.no_subfolders')}</span>`;
|
||||
folderSelectContainer.appendChild(emptyMsg);
|
||||
}
|
||||
|
||||
@@ -686,9 +686,7 @@ const contextMenus = {
|
||||
app.selectedTargetFolderId = parentFolderId || '';
|
||||
|
||||
// Translate new elements
|
||||
if (i18n?.translateElement) {
|
||||
i18n.translateElement(folderSelectContainer);
|
||||
}
|
||||
i18n.translateElement(folderSelectContainer);
|
||||
} catch (error) {
|
||||
console.error('Error loading folders:', error);
|
||||
}
|
||||
@@ -799,7 +797,7 @@ const contextMenus = {
|
||||
if (dialogHeader) {
|
||||
const headerSpan = dialogHeader.querySelector('span');
|
||||
const titleText =
|
||||
itemType === 'file' ? (i18n ? i18n.t('dialogs.share_file') : 'Share file') : i18n ? i18n.t('dialogs.share_folder') : 'Share folder';
|
||||
itemType === 'file' ? i18n.t('dialogs.share_file') : i18n.t('dialogs.share_folder');
|
||||
if (headerSpan) {
|
||||
headerSpan.textContent = titleText;
|
||||
} else {
|
||||
@@ -900,9 +898,9 @@ const contextMenus = {
|
||||
const shareId = btn.getAttribute('data-share-id');
|
||||
|
||||
showConfirmDialog({
|
||||
title: i18n ? i18n.t('dialogs.confirm_delete_share') : 'Delete link',
|
||||
message: i18n ? i18n.t('dialogs.confirm_delete_share_msg') : 'Are you sure you want to delete this shared link?',
|
||||
confirmText: i18n ? i18n.t('actions.delete') : 'Delete'
|
||||
title: i18n.t('dialogs.confirm_delete_share'),
|
||||
message: i18n.t('dialogs.confirm_delete_share_msg'),
|
||||
confirmText: i18n.t('actions.delete')
|
||||
}).then(async (confirmed) => {
|
||||
if (confirmed) {
|
||||
await fileSharing.removeSharedLink(shareId);
|
||||
@@ -998,8 +996,8 @@ const contextMenus = {
|
||||
|
||||
// Show success message
|
||||
ui.showNotification(
|
||||
i18n ? i18n.t('notifications.link_created') : 'Link created',
|
||||
i18n ? i18n.t('notifications.share_success') : 'Shared link created successfully'
|
||||
i18n.t('notifications.link_created'),
|
||||
i18n.t('notifications.share_success')
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error creating shared link:', error);
|
||||
@@ -1088,7 +1086,7 @@ const contextMenus = {
|
||||
|
||||
// Update files info
|
||||
if (filesInfo) {
|
||||
filesInfo.innerHTML = `<strong>${i18n ? i18n.t('music.selected_files', 'Selected:') : 'Selected:'} </strong>${file.name}`;
|
||||
filesInfo.innerHTML = `<strong>${i18n.t('music.selected_files')} </strong>${file.name}`;
|
||||
}
|
||||
|
||||
// Reset selection
|
||||
@@ -1112,12 +1110,12 @@ const contextMenus = {
|
||||
this._renderPlaylistSelect(container, playlists);
|
||||
} catch (err) {
|
||||
console.error('Error loading playlists:', err);
|
||||
container.innerHTML = `<div class="folder-select-empty">${i18n ? i18n.t('music.load_error', 'Error loading playlists') : 'Error loading playlists'}</div>`;
|
||||
container.innerHTML = `<div class="folder-select-empty">${i18n.t('music.load_error')}</div>`;
|
||||
}
|
||||
},
|
||||
|
||||
_renderPlaylistSelect(container, playlists) {
|
||||
const t = (key, fallback) => (i18n ? i18n.t(key, fallback) : fallback);
|
||||
const t = i18n.t.bind(i18n);
|
||||
|
||||
container.innerHTML = '';
|
||||
|
||||
@@ -1177,8 +1175,8 @@ const contextMenus = {
|
||||
|
||||
await resp.json();
|
||||
ui.showNotification(
|
||||
i18n ? i18n.t('music.added', 'Added!') : 'Added!',
|
||||
`${files.length} ${files.length === 1 ? 'track' : 'tracks'} ${i18n ? i18n.t('music.added_to_playlist', 'added to playlist') : 'added to playlist'}`
|
||||
i18n.t('music.added'),
|
||||
`${files.length} ${files.length === 1 ? 'track' : 'tracks'} ${i18n.t('music.added_to_playlist')}`
|
||||
);
|
||||
|
||||
this.closePlaylistDialog();
|
||||
@@ -1189,7 +1187,7 @@ const contextMenus = {
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error adding to playlist:', err);
|
||||
ui.showNotification(i18n ? i18n.t('music.error', 'Error') : 'Error', err.message || i18n.t('music.add_error', 'Could not add tracks to playlist'));
|
||||
ui.showNotification(i18n.t('music.error'), err.message || i18n.t('music.add_error'));
|
||||
if (addBtn) addBtn.disabled = false;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -30,12 +30,12 @@ const fileOps = {
|
||||
|
||||
/** Start a new upload batch in the notification bell */
|
||||
_initUploadToast(totalFiles, folderName) {
|
||||
this._currentBatchId = notifications ? notifications.addUploadBatch(totalFiles, folderName) : null;
|
||||
this._currentBatchId = notifications.addUploadBatch(totalFiles, folderName);
|
||||
},
|
||||
|
||||
/** Finalise the batch in the notification bell */
|
||||
_finishUploadToast(successCount, totalFiles) {
|
||||
if (notifications && this._currentBatchId) {
|
||||
if (this._currentBatchId) {
|
||||
notifications.finishBatch(this._currentBatchId, successCount, totalFiles);
|
||||
}
|
||||
},
|
||||
@@ -361,7 +361,7 @@ const fileOps = {
|
||||
progressBar.style.width = `${(uploadedCount / totalFiles) * 100}%`;
|
||||
}
|
||||
// Notify bell of per-file completion
|
||||
if (notifications && batchId) {
|
||||
if (batchId) {
|
||||
try {
|
||||
notifications.fileCompleted(batchId, result.ok);
|
||||
} catch (e) {
|
||||
@@ -383,7 +383,7 @@ const fileOps = {
|
||||
});
|
||||
}
|
||||
if (result.isQuotaError) {
|
||||
const msg = result.errorMsg || i18n?.t('storage_quota_exceeded') || 'Storage quota exceeded';
|
||||
const msg = result.errorMsg || i18n.t('storage_quota_exceeded');
|
||||
if (notifications) {
|
||||
notifications.addNotification({
|
||||
icon: 'fa-exclamation-triangle',
|
||||
@@ -591,7 +591,7 @@ const fileOps = {
|
||||
console.warn(`[SKIP] #${idx} ${rel} — cannot read 0-byte file (FIFO/pipe?), skipping`);
|
||||
uploadedCount++;
|
||||
successCount++;
|
||||
if (notifications && batchId) {
|
||||
if (batchId) {
|
||||
try {
|
||||
notifications.fileCompleted(batchId, true);
|
||||
} catch (_) {}
|
||||
@@ -623,7 +623,7 @@ const fileOps = {
|
||||
|
||||
uploadedCount++;
|
||||
|
||||
if (notifications && batchId) {
|
||||
if (batchId) {
|
||||
try {
|
||||
notifications.fileCompleted(batchId, result.ok);
|
||||
} catch (_) {}
|
||||
@@ -995,8 +995,8 @@ const fileOps = {
|
||||
|
||||
if (response.ok) {
|
||||
ui.showNotification(
|
||||
i18n ? i18n.t('notifications.file_renamed') : 'File renamed',
|
||||
i18n ? i18n.t('notifications.file_renamed_to', { name: newName }) : `File renamed to "${newName}"`
|
||||
i18n.t('notifications.file_renamed'),
|
||||
i18n.t('notifications.file_renamed_to', { name: newName })
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
@@ -1075,9 +1075,9 @@ const fileOps = {
|
||||
*/
|
||||
async deleteFile(fileId, fileName) {
|
||||
const confirmed = await showConfirmDialog({
|
||||
title: i18n ? i18n.t('dialogs.confirm_delete') : 'Move to trash',
|
||||
message: i18n ? i18n.t('dialogs.confirm_delete_file', { name: fileName }) : `Are you sure you want to move the file "${fileName}" to trash?`,
|
||||
confirmText: i18n ? i18n.t('actions.delete') : 'Delete'
|
||||
title: i18n.t('dialogs.confirm_delete'),
|
||||
message: i18n.t('dialogs.confirm_delete_file', { name: fileName }),
|
||||
confirmText: i18n.t('actions.delete')
|
||||
});
|
||||
if (!confirmed) return false;
|
||||
|
||||
@@ -1123,11 +1123,9 @@ const fileOps = {
|
||||
*/
|
||||
async deleteFolder(folderId, folderName) {
|
||||
const confirmed = await showConfirmDialog({
|
||||
title: i18n ? i18n.t('dialogs.confirm_delete') : 'Move to trash',
|
||||
message: i18n
|
||||
? 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: i18n ? i18n.t('actions.delete') : 'Delete'
|
||||
title: i18n.t('dialogs.confirm_delete'),
|
||||
message: i18n.t('dialogs.confirm_delete_folder', { name: folderName }),
|
||||
confirmText: i18n.t('actions.delete')
|
||||
});
|
||||
if (!confirmed) return false;
|
||||
|
||||
@@ -1234,11 +1232,9 @@ const fileOps = {
|
||||
*/
|
||||
async deletePermanently(trashId) {
|
||||
const confirmed = await showConfirmDialog({
|
||||
title: i18n ? i18n.t('dialogs.confirm_permanent_delete') : 'Delete permanently',
|
||||
message: i18n
|
||||
? i18n.t('dialogs.confirm_permanent_delete_msg')
|
||||
: 'Are you sure you want to permanently delete this item? This action cannot be undone.',
|
||||
confirmText: i18n ? i18n.t('actions.delete_permanently') : 'Delete permanently'
|
||||
title: i18n.t('dialogs.confirm_permanent_delete'),
|
||||
message: i18n.t('dialogs.confirm_permanent_delete_msg'),
|
||||
confirmText: i18n.t('actions.delete_permanently')
|
||||
});
|
||||
if (!confirmed) return false;
|
||||
|
||||
@@ -1268,9 +1264,9 @@ const fileOps = {
|
||||
*/
|
||||
async emptyTrash() {
|
||||
const confirmed = await showConfirmDialog({
|
||||
title: i18n ? i18n.t('dialogs.confirm_empty_trash') : 'Empty trash',
|
||||
message: i18n ? i18n.t('trash.empty_confirm') : 'Are you sure you want to empty the trash? This action will permanently delete all items.',
|
||||
confirmText: i18n ? i18n.t('actions.empty_trash') : 'Empty trash'
|
||||
title: i18n.t('dialogs.confirm_empty_trash'),
|
||||
message: i18n.t('trash.empty_confirm'),
|
||||
confirmText: i18n.t('actions.empty_trash')
|
||||
});
|
||||
if (!confirmed) return false;
|
||||
|
||||
|
||||
@@ -50,12 +50,8 @@ const multiSelect = {
|
||||
// ── Helpers for i18n ────────────────────────────────────
|
||||
|
||||
_t(key, vars) {
|
||||
if (i18n && typeof i18n.t === 'function') {
|
||||
const val = i18n.t(key, vars);
|
||||
// If i18n returned the key itself, it's missing → fall back
|
||||
if (val && val !== key) return val;
|
||||
}
|
||||
return null;
|
||||
const val = i18n.t(key, vars);
|
||||
return val !== key ? val : null;
|
||||
},
|
||||
|
||||
// ── Selection state management ──────────────────────────
|
||||
|
||||
@@ -111,8 +111,8 @@ const favorites = {
|
||||
// Notify user
|
||||
if (ui?.showNotification) {
|
||||
ui.showNotification(
|
||||
i18n ? i18n.t('favorites.added_title') : 'Added to favorites',
|
||||
`"${name}" ${i18n ? i18n.t('favorites.added_msg') : 'added to favorites'}`
|
||||
i18n.t('favorites.added_title'),
|
||||
`"${name}" ${i18n.t('favorites.added_msg')}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -146,8 +146,8 @@ const favorites = {
|
||||
|
||||
if (ui?.showNotification) {
|
||||
ui.showNotification(
|
||||
i18n ? i18n.t('favorites.removed_title') : 'Removed from favorites',
|
||||
`"${itemName}" ${i18n ? i18n.t('favorites.removed_msg') : 'removed from favorites'}`
|
||||
i18n.t('favorites.removed_title'),
|
||||
`"${itemName}" ${i18n.t('favorites.removed_msg')}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -182,8 +182,8 @@ const favorites = {
|
||||
if (this._cache.size === 0) {
|
||||
ui.showError(`
|
||||
<i class="fas fa-star empty-state-icon"></i>
|
||||
<p>${i18n ? i18n.t('favorites.empty_state') : 'No favorite items'}</p>
|
||||
<p>${i18n ? i18n.t('favorites.empty_hint') : 'To mark as favorite, right-click on any file or folder'}</p>
|
||||
<p>${i18n.t('favorites.empty_state')}</p>
|
||||
<p>${i18n.t('favorites.empty_hint')}</p>
|
||||
`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -186,9 +186,7 @@ const musicView = {
|
||||
const listEl = document.getElementById('music-playlist-list');
|
||||
if (!listEl) return;
|
||||
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
if (this.playlists.length === 0) {
|
||||
listEl.innerHTML = `
|
||||
@@ -291,9 +289,7 @@ const musicView = {
|
||||
if (detailEl) detailEl.classList.remove('hidden');
|
||||
if (nameEl) nameEl.textContent = playlist.name;
|
||||
if (metaEl) {
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
metaEl.textContent = `${playlist.track_count || 0} ${t('music.tracks', 'tracks')}`;
|
||||
}
|
||||
|
||||
@@ -314,7 +310,7 @@ const musicView = {
|
||||
}
|
||||
const togglePublicBtn = document.getElementById('music-toggle-public-btn');
|
||||
if (togglePublicBtn) {
|
||||
const t2 = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t2 = (key) => i18n.t(key);
|
||||
togglePublicBtn.title = playlist.is_public ? t2('music.make_private', 'Make private') : t2('music.make_public', 'Make public');
|
||||
togglePublicBtn.classList.toggle('active', playlist.is_public);
|
||||
}
|
||||
@@ -352,9 +348,7 @@ const musicView = {
|
||||
const trackListEl = document.getElementById('music-track-list');
|
||||
if (!trackListEl) return;
|
||||
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
if (this.currentTracks.length === 0) {
|
||||
trackListEl.innerHTML = `
|
||||
@@ -467,9 +461,7 @@ const musicView = {
|
||||
_playTrack(idx) {
|
||||
if (!this.currentTracks[idx]) return;
|
||||
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
musicPlayer.setQueue(this.currentTracks, this.currentPlaylist?.name || t('music.playlists', 'Playlist'));
|
||||
musicPlayer.playTrack(idx);
|
||||
},
|
||||
@@ -487,18 +479,14 @@ const musicView = {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||
}
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
musicPlayer.setQueue(shuffled, this.currentPlaylist?.name || t('music.shuffle', 'Shuffle'));
|
||||
musicPlayer.playTrack(0);
|
||||
}
|
||||
},
|
||||
|
||||
async _showCreatePlaylistDialog() {
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
const name = await Modal.prompt({
|
||||
title: t('music.create_playlist', 'Create Playlist'),
|
||||
@@ -513,9 +501,7 @@ const musicView = {
|
||||
},
|
||||
|
||||
async _createPlaylist(name) {
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
const createBtn = document.getElementById('music-create-playlist-btn');
|
||||
if (createBtn) createBtn.disabled = true;
|
||||
try {
|
||||
@@ -556,9 +542,7 @@ const musicView = {
|
||||
},
|
||||
|
||||
async _deletePlaylist() {
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
if (!this.currentPlaylist) return;
|
||||
|
||||
@@ -644,9 +628,7 @@ const musicView = {
|
||||
|
||||
async _showEditPlaylistDialog() {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
const newName = await Modal.prompt({
|
||||
title: t('music.edit', 'Edit'),
|
||||
@@ -690,9 +672,7 @@ const musicView = {
|
||||
|
||||
async _showSharePlaylistDialog() {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
const userId = await Modal.prompt({
|
||||
title: t('music.share', 'Share'),
|
||||
@@ -736,9 +716,7 @@ const musicView = {
|
||||
|
||||
async _showAddTracksDialog() {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
// ── Build modal overlay ──
|
||||
const overlay = document.createElement('div');
|
||||
@@ -900,7 +878,7 @@ const musicView = {
|
||||
|
||||
async _removeTrackFromPlaylist(_trackId, fileId) {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
try {
|
||||
const resp = await fetch(`/api/playlists/${this.currentPlaylist.id}/tracks/${encodeURIComponent(fileId)}`, {
|
||||
@@ -942,7 +920,7 @@ const musicView = {
|
||||
|
||||
async _reorderTrack(fromIdx, toIdx) {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
const tracks = [...this.currentTracks];
|
||||
const [moved] = tracks.splice(fromIdx, 1);
|
||||
@@ -975,7 +953,7 @@ const musicView = {
|
||||
|
||||
async _showManageSharesDialog() {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
const existing = document.getElementById('music-shares-dialog');
|
||||
if (existing) existing.remove();
|
||||
@@ -1052,7 +1030,7 @@ const musicView = {
|
||||
|
||||
async _loadSharesList(dialog) {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t = (key) => i18n.t(key);
|
||||
const body = dialog.querySelector('.music-shares-body');
|
||||
if (!body) return;
|
||||
|
||||
@@ -1097,7 +1075,7 @@ const musicView = {
|
||||
|
||||
async _removeShare(userId, dialog) {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
try {
|
||||
const resp = await fetch(`/api/playlists/${this.currentPlaylist.id}/share/${encodeURIComponent(userId)}`, {
|
||||
@@ -1121,7 +1099,7 @@ const musicView = {
|
||||
|
||||
async _togglePublic() {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t = (key) => i18n.t(key);
|
||||
const newValue = !this.currentPlaylist.is_public;
|
||||
|
||||
try {
|
||||
@@ -1170,7 +1148,7 @@ const musicView = {
|
||||
|
||||
async _showCoverPicker() {
|
||||
if (!this.currentPlaylist) return;
|
||||
const t = (key, fallback = '') => (i18n?.t ? i18n.t(key) : fallback || key);
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
@@ -1289,25 +1267,25 @@ const musicPlayer = {
|
||||
<i class="fas fa-music"></i>
|
||||
</div>
|
||||
<div class="player-track-details">
|
||||
<span class="player-track-name">${i18n?.t('music.not_playing', 'Not playing') || 'Not playing'}</span>
|
||||
<span class="player-track-name">${i18n.t('music.not_playing')}</span>
|
||||
<span class="player-track-artist"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="player-controls">
|
||||
<div class="player-buttons">
|
||||
<button class="player-btn" id="player-shuffle-btn" title="${i18n?.t('music.shuffle', 'Shuffle') || 'Shuffle'}">
|
||||
<button class="player-btn" id="player-shuffle-btn" title="${i18n.t('music.shuffle')}">
|
||||
<i class="fas fa-shuffle"></i>
|
||||
</button>
|
||||
<button class="player-btn" id="player-prev-btn" title="${i18n?.t('music.previous', 'Previous') || 'Previous'}">
|
||||
<button class="player-btn" id="player-prev-btn" title="${i18n.t('music.previous')}">
|
||||
<i class="fas fa-backward"></i>
|
||||
</button>
|
||||
<button class="player-btn player-btn-main" id="player-play-btn" title="${i18n?.t('music.play', 'Play') || 'Play'}">
|
||||
<button class="player-btn player-btn-main" id="player-play-btn" title="${i18n.t('music.play')}">
|
||||
<i class="fas fa-play"></i>
|
||||
</button>
|
||||
<button class="player-btn" id="player-next-btn" title="${i18n?.t('music.next', 'Next') || 'Next'}">
|
||||
<button class="player-btn" id="player-next-btn" title="${i18n.t('music.next')}">
|
||||
<i class="fas fa-forward"></i>
|
||||
</button>
|
||||
<button class="player-btn" id="player-repeat-btn" title="${i18n?.t('music.repeat', 'Repeat') || 'Repeat'}">
|
||||
<button class="player-btn" id="player-repeat-btn" title="${i18n.t('music.repeat')}">
|
||||
<i class="fas fa-repeat"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1321,22 +1299,22 @@ const musicPlayer = {
|
||||
</div>
|
||||
</div>
|
||||
<div class="player-extra">
|
||||
<button class="player-btn player-btn-small" id="player-playlist-btn" title="${i18n?.t('music.queue', 'Queue') || 'Queue'}">
|
||||
<button class="player-btn player-btn-small" id="player-playlist-btn" title="${i18n.t('music.queue')}">
|
||||
<i class="fas fa-list"></i>
|
||||
</button>
|
||||
<button class="player-btn player-btn-small" id="player-vol-btn" title="${i18n?.t('music.volume', 'Volume') || 'Volume'}">
|
||||
<button class="player-btn player-btn-small" id="player-vol-btn" title="${i18n.t('music.volume')}">
|
||||
<i class="fas fa-volume-up"></i>
|
||||
</button>
|
||||
<div class="player-volume-slider" id="player-volume-slider">
|
||||
<input type="range" min="0" max="100" value="70" id="player-volume-input">
|
||||
</div>
|
||||
<button class="player-btn player-btn-small player-close-btn" id="player-close-btn" title="${i18n?.t('actions.close', 'Close') || 'Close'}">
|
||||
<button class="player-btn player-btn-small player-close-btn" id="player-close-btn" title="${i18n.t('actions.close')}">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="player-queue hidden" id="player-queue">
|
||||
<div class="player-queue-header">
|
||||
<h3>${i18n?.t('music.queue', 'Queue') || 'Queue'}</h3>
|
||||
<h3>${i18n.t('music.queue')}</h3>
|
||||
<button class="player-btn player-btn-small" id="player-close-queue-btn">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
@@ -1648,9 +1626,7 @@ const musicPlayer = {
|
||||
console.error('Audio error:', e);
|
||||
this.isPlaying = false;
|
||||
this._updateUI();
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
if (notifications) {
|
||||
const trackName = this.currentTrack?.title || this.currentTrack?.file_name || t('music.unknown_title', 'Unknown');
|
||||
notifications.addNotification({
|
||||
@@ -1681,9 +1657,7 @@ const musicPlayer = {
|
||||
}
|
||||
|
||||
if (trackName) {
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
trackName.textContent = this.currentTrack
|
||||
? this.currentTrack.title || this.currentTrack.file_name || t('music.unknown_title', 'Unknown')
|
||||
: t('music.not_playing', 'Not playing');
|
||||
@@ -1736,9 +1710,7 @@ const musicPlayer = {
|
||||
const queueList = document.getElementById('player-queue-list');
|
||||
if (!queueList) return;
|
||||
|
||||
const t = (key, fallback = '') => {
|
||||
return i18n?.t ? i18n.t(key) : fallback || key;
|
||||
};
|
||||
const t = (key) => i18n.t(key);
|
||||
|
||||
if (this.queue.length === 0) {
|
||||
queueList.innerHTML = `
|
||||
|
||||
@@ -410,7 +410,7 @@ const photosView = {
|
||||
|
||||
/** Render the group mode toolbar */
|
||||
_renderToolbar() {
|
||||
const t = (k, d) => (i18n ? i18n.t(k) : d);
|
||||
const t = (k) => i18n.t(k);
|
||||
const modes = [
|
||||
['daily', t('photos.view_daily', 'Day')],
|
||||
['monthly', t('photos.view_monthly', 'Month')],
|
||||
@@ -427,7 +427,7 @@ const photosView = {
|
||||
|
||||
/** Render empty state */
|
||||
_renderEmpty() {
|
||||
const t = (k, d) => (i18n ? i18n.t(k) : d);
|
||||
const t = (k) => i18n.t(k);
|
||||
this._container.innerHTML = `
|
||||
<div class="photos-empty">
|
||||
<i class="fas fa-images"></i>
|
||||
@@ -520,7 +520,7 @@ const photosView = {
|
||||
document.body.appendChild(bar);
|
||||
}
|
||||
|
||||
const t = (k, d) => (i18n ? i18n.t(k) : d);
|
||||
const t = (k) => i18n.t(k);
|
||||
const count = this.selected.size;
|
||||
bar.innerHTML = `
|
||||
<span class="selection-count">${count} ${t('photos.items_selected', 'selected')}</span>
|
||||
|
||||
@@ -114,8 +114,8 @@ const recent = {
|
||||
if (recentItems.length === 0) {
|
||||
ui.showError(`
|
||||
<i class="fas fa-clock empty-state-icon"></i>
|
||||
<p>${i18n ? i18n.t('recent.empty_state') : 'No recent files'}</p>
|
||||
<p>${i18n ? i18n.t('recent.empty_hint') : 'Files you open will appear here'}</p>
|
||||
<p>${i18n.t('recent.empty_state')}</p>
|
||||
<p>${i18n.t('recent.empty_hint')}</p>
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user