debounced saving on settings page for all drop-down, tick boxes, input boxes and sliders.
This commit is contained in:
parent
8cf0950d3b
commit
1d50ece62c
2 changed files with 52 additions and 13 deletions
|
|
@ -1542,14 +1542,39 @@ async function copyAddress(address, cryptoName) {
|
||||||
// SETTINGS FUNCTIONALITY
|
// SETTINGS FUNCTIONALITY
|
||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
|
let settingsAutoSaveTimer = null;
|
||||||
|
|
||||||
|
function debouncedAutoSaveSettings() {
|
||||||
|
if (settingsAutoSaveTimer) clearTimeout(settingsAutoSaveTimer);
|
||||||
|
settingsAutoSaveTimer = setTimeout(() => saveSettings(true), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleManualSaveClick() {
|
||||||
|
if (settingsAutoSaveTimer) clearTimeout(settingsAutoSaveTimer);
|
||||||
|
saveSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
function initializeSettings() {
|
function initializeSettings() {
|
||||||
// This function is called when the settings page is loaded.
|
// This function is called when the settings page is loaded.
|
||||||
// It attaches event listeners to all interactive elements on the page.
|
// It attaches event listeners to all interactive elements on the page.
|
||||||
|
|
||||||
// Main save button
|
// Main save button (manual save, non-quiet)
|
||||||
|
// Uses named function reference so addEventListener deduplicates across repeated calls
|
||||||
const saveButton = document.getElementById('save-settings');
|
const saveButton = document.getElementById('save-settings');
|
||||||
if (saveButton) {
|
if (saveButton) {
|
||||||
saveButton.addEventListener('click', saveSettings);
|
saveButton.addEventListener('click', handleManualSaveClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debounced auto-save on all settings inputs
|
||||||
|
// Uses named function reference (debouncedAutoSaveSettings) so addEventListener deduplicates
|
||||||
|
const settingsPage = document.getElementById('settings-page');
|
||||||
|
if (settingsPage) {
|
||||||
|
settingsPage.querySelectorAll('input[type="text"], input[type="url"], input[type="password"], input[type="number"], input[type="range"]').forEach(input => {
|
||||||
|
input.addEventListener('input', debouncedAutoSaveSettings);
|
||||||
|
});
|
||||||
|
settingsPage.querySelectorAll('input[type="checkbox"], select').forEach(input => {
|
||||||
|
input.addEventListener('change', debouncedAutoSaveSettings);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server toggle buttons
|
// Server toggle buttons
|
||||||
|
|
@ -1592,7 +1617,7 @@ function resetFileOrganizationTemplates() {
|
||||||
document.getElementById('template-single-path').value = defaults.single;
|
document.getElementById('template-single-path').value = defaults.single;
|
||||||
document.getElementById('template-playlist-path').value = defaults.playlist;
|
document.getElementById('template-playlist-path').value = defaults.playlist;
|
||||||
|
|
||||||
showToast('Templates reset to defaults. Click "Save Settings" to apply.', 'success');
|
debouncedAutoSaveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateFileOrganizationTemplates() {
|
function validateFileOrganizationTemplates() {
|
||||||
|
|
@ -1886,6 +1911,9 @@ function toggleServer(serverType) {
|
||||||
loadJellyfinUsers();
|
loadJellyfinUsers();
|
||||||
loadJellyfinMusicLibraries();
|
loadJellyfinMusicLibraries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-save after server toggle change
|
||||||
|
debouncedAutoSaveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDownloadSourceUI() {
|
function updateDownloadSourceUI() {
|
||||||
|
|
@ -2112,11 +2140,11 @@ async function saveQualityProfile() {
|
||||||
// END QUALITY PROFILE FUNCTIONS
|
// END QUALITY PROFILE FUNCTIONS
|
||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
async function saveSettings() {
|
async function saveSettings(quiet = false) {
|
||||||
// Validate file organization templates before saving
|
// Validate file organization templates before saving
|
||||||
const validationErrors = validateFileOrganizationTemplates();
|
const validationErrors = validateFileOrganizationTemplates();
|
||||||
if (validationErrors.length > 0) {
|
if (validationErrors.length > 0) {
|
||||||
showToast('Template validation failed: ' + validationErrors.join(', '), 'error');
|
if (!quiet) showToast('Template validation failed: ' + validationErrors.join(', '), 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2197,7 +2225,7 @@ async function saveSettings() {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showLoadingOverlay('Saving settings...');
|
if (!quiet) showLoadingOverlay('Saving settings...');
|
||||||
|
|
||||||
// Save main settings
|
// Save main settings
|
||||||
const response = await fetch(API.settings, {
|
const response = await fetch(API.settings, {
|
||||||
|
|
@ -2228,8 +2256,7 @@ async function saveSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.success && qualityProfileSaved && lookbackSaved) {
|
if (result.success && qualityProfileSaved && lookbackSaved) {
|
||||||
showToast('Settings saved successfully', 'success');
|
showToast(quiet ? 'Settings auto-saved' : 'Settings saved successfully', 'success');
|
||||||
// Trigger immediate status update
|
|
||||||
setTimeout(updateServiceStatus, 1000);
|
setTimeout(updateServiceStatus, 1000);
|
||||||
} else if (result.success && qualityProfileSaved && !lookbackSaved) {
|
} else if (result.success && qualityProfileSaved && !lookbackSaved) {
|
||||||
showToast('Settings saved, but discovery lookback period failed to save', 'warning');
|
showToast('Settings saved, but discovery lookback period failed to save', 'warning');
|
||||||
|
|
@ -2244,7 +2271,7 @@ async function saveSettings() {
|
||||||
console.error('Error saving settings:', error);
|
console.error('Error saving settings:', error);
|
||||||
showToast('Failed to save settings', 'error');
|
showToast('Failed to save settings', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
hideLoadingOverlay();
|
if (!quiet) hideLoadingOverlay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8246,8 +8246,15 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes batchBarSlideIn {
|
@keyframes batchBarSlideIn {
|
||||||
from { opacity: 0; transform: translateY(-8px); }
|
from {
|
||||||
to { opacity: 1; transform: translateY(0); }
|
opacity: 0;
|
||||||
|
transform: translateY(-8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.watchlist-batch-count {
|
.watchlist-batch-count {
|
||||||
|
|
@ -8301,12 +8308,12 @@ body {
|
||||||
background: rgba(255, 255, 255, 0.06);
|
background: rgba(255, 255, 255, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.watchlist-checkbox-wrapper input:checked + .watchlist-checkbox-custom {
|
.watchlist-checkbox-wrapper input:checked+.watchlist-checkbox-custom {
|
||||||
background: rgba(29, 185, 84, 0.3);
|
background: rgba(29, 185, 84, 0.3);
|
||||||
border-color: #1db954;
|
border-color: #1db954;
|
||||||
}
|
}
|
||||||
|
|
||||||
.watchlist-checkbox-wrapper input:checked + .watchlist-checkbox-custom::after {
|
.watchlist-checkbox-wrapper input:checked+.watchlist-checkbox-custom::after {
|
||||||
content: '✓';
|
content: '✓';
|
||||||
color: #1db954;
|
color: #1db954;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
@ -13212,6 +13219,11 @@ body {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#artist-hero-section #artist-detail-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.artist-detail-image {
|
.artist-detail-image {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue