(function() { 'use strict'; // Party presets for archive browser — IIFE module // State (module scope, NOT on window.app) let presets = []; let activePresetName = null; let isOpen = false; let isNamingMode = false; // Get localStorage key based on source mode and directory function getStorageKey() { if (window.app.sourceMode === 'http' && window.app.directories.length > 0) { var u = window.app.directories[0].url || ''; return 'zddc-presets:http:' + u; } else if (window.app.sourceMode === 'local' && window.app.directories.length > 0) { return 'zddc-presets:local:' + window.app.directories[0].name; } return 'zddc-presets:default'; } // Load presets from localStorage function loadFromStorage() { try { var stored = localStorage.getItem(getStorageKey()); if (stored) { var parsed = JSON.parse(stored); if (parsed && Array.isArray(parsed.presets)) { presets = parsed.presets; } else { presets = []; } } else { presets = []; } } catch (e) { presets = []; } } // Save presets to localStorage function saveToStorage() { try { localStorage.setItem(getStorageKey(), JSON.stringify({ presets: presets })); } catch (e) { // Silently fail on storage errors } } // Load a preset by name function loadPreset(name) { var preset = presets.find(p => p.name === name); if (!preset) return; // Filter paths to only include folders that exist in groupingFolders var validPaths = preset.paths.filter(p => window.app.groupingFolders.some(f => f.path === p) ); window.app.selectedGroupingFolders = new Set(validPaths); window.app.selectAllGroupingFolders = false; var checkbox = document.getElementById('selectAllGroupingCheckbox'); if (checkbox) checkbox.checked = false; activePresetName = name; // Trigger UI updates window.app.modules.app.updateFolderSelectionState('groupingFoldersList'); window.app.modules.app.renderTransmittalFolders(); window.app.modules.filtering.applyFilters(); renderButton(); renderDropdown(); } // Save current selection as a preset function savePreset(name) { // Build paths array from current selection var paths = Array.from(window.app.selectedGroupingFolders); // Upsert preset var existingIndex = presets.findIndex(p => p.name === name); if (existingIndex >= 0) { presets[existingIndex] = { name: name, paths: paths }; } else { presets.push({ name: name, paths: paths }); } saveToStorage(); activePresetName = name; isNamingMode = false; renderButton(); renderDropdown(); } // Delete a preset by name function deletePreset(name) { presets = presets.filter(p => p.name !== name); if (activePresetName === name) { activePresetName = null; } saveToStorage(); renderButton(); renderDropdown(); } // Check if current selection differs from active preset function checkDirty() { if (activePresetName === null) return; var preset = presets.find(p => p.name === activePresetName); if (!preset) return; var currentPaths = new Set(window.app.selectedGroupingFolders); var presetPaths = new Set(preset.paths || []); // Compare sets var dirty = currentPaths.size !== presetPaths.size || !Array.from(currentPaths).every(p => presetPaths.has(p)); if (dirty) { renderButton(); } } // Get minimum depth of grouping folders (for top-level Only) function getMinDepth() { if (window.app.groupingFolders.length === 0) return 1; return Math.min.apply(null, window.app.groupingFolders.map(f => f.path.split('/').length)); } // Render the preset button label function renderButton() { var btn = document.getElementById('presetBtn'); if (!btn) return; if (activePresetName !== null) { // Check if dirty var preset = presets.find(p => p.name === activePresetName); var dirty = false; if (preset) { var currentPaths = new Set(window.app.selectedGroupingFolders); var presetPaths = new Set(preset.paths || []); dirty = currentPaths.size !== presetPaths.size || !Array.from(currentPaths).every(p => presetPaths.has(p)); } btn.textContent = '▾ ' + activePresetName + (dirty ? '*' : ''); } else { btn.textContent = '▾ Presets'; } } // Escape HTML for safe insertion function escapeHtml(text) { var div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Render the dropdown panel function renderDropdown() { var dropdown = document.getElementById('presetDropdown'); if (!dropdown) return; var minDepth = getMinDepth(); // Build presets list HTML var presetsHtml = ''; if (presets.length === 0) { presetsHtml = '
No saved presets
'; } else { presetsHtml = presets.map(preset => { var escapedName = escapeHtml(preset.name); return ( '
' + '' + escapedName + '' + '' + '
' ); }).join(''); } // Build project checkboxes HTML var projectsHtml = ''; window.app.groupingFolders.forEach(folder => { // Only include top-level folders (minDepth) var pathParts = folder.path.split('/'); if (pathParts.length !== minDepth) return; var isSelected = window.app.selectedGroupingFolders.has(folder.path); var escapedPath = escapeHtml(folder.path); var escapedName = escapeHtml(folder.name); projectsHtml += ( '
' + '' + '
' ); }); // Footer HTML var footerHtml = ''; if (activePresetName !== null) { // Check if dirty var preset = presets.find(p => p.name === activePresetName); var dirty = false; if (preset) { var currentPaths = new Set(window.app.selectedGroupingFolders); var presetPaths = new Set(preset.paths || []); dirty = currentPaths.size !== presetPaths.size || !Array.from(currentPaths).every(p => presetPaths.has(p)); } if (isNamingMode) { footerHtml = ( '' ); } else if (dirty) { footerHtml = ( '' ); } else { footerHtml = ( '' ); } } else { // No active preset — disabled if nothing selected var selectedCount = window.app.selectedGroupingFolders.size; var disabledAttr = selectedCount === 0 ? ' disabled' : ''; footerHtml = ( '' ); } dropdown.innerHTML = ( '
' + '
Saved Presets:
' + '
' + presetsHtml + '
' + '
' + '
' + '
' + '
Projects:
' + '
' + projectsHtml + '
' + '
' + footerHtml ); } // Toggle dropdown visibility function toggleDropdown() { var dropdown = document.getElementById('presetDropdown'); if (isOpen) { closeDropdown(); } else { isOpen = true; if (dropdown) dropdown.classList.remove('hidden'); renderDropdown(); } } // Close dropdown function closeDropdown() { isOpen = false; var dropdown = document.getElementById('presetDropdown'); if (dropdown) dropdown.classList.add('hidden'); isNamingMode = false; } // Set up event delegation on dropdown function setupDropdownDelegation() { var dropdown = document.getElementById('presetDropdown'); if (!dropdown) return; dropdown.addEventListener('click', function(e) { // Close on clicks inside dropdown e.stopPropagation(); // Preset item click — load preset (do NOT close dropdown) var presetItem = e.target.closest('.preset-item'); if (presetItem && !e.target.classList.contains('preset-delete')) { var name = presetItem.getAttribute('data-name'); if (name) loadPreset(name); return; } // Delete button var deleteBtn = e.target.closest('.preset-delete'); if (deleteBtn) { e.stopPropagation(); var name = deleteBtn.getAttribute('data-name'); if (name) deletePreset(name); return; } // Checkbox click var checkbox = e.target.closest('.preset-checkbox'); if (checkbox) { var path = checkbox.getAttribute('data-path'); if (path) { if (checkbox.checked) { window.app.selectedGroupingFolders.add(path); } else { window.app.selectedGroupingFolders.delete(path); } window.app.modules.app.updateFolderSelectionState('groupingFoldersList'); window.app.modules.app.renderTransmittalFolders(); window.app.modules.filtering.applyFilters(); checkDirty(); renderButton(); renderDropdown(); // Re-render to update checkbox states and footer } return; } // Save button (not in naming mode) var saveBtn = e.target.closest('.preset-save-btn'); if (saveBtn && !isNamingMode) { if (saveBtn.getAttribute('data-disabled') !== 'true') { isNamingMode = true; renderDropdown(); } return; } // Update button — save current selection as active preset var updateBtn = e.target.closest('.preset-update-btn'); if (updateBtn) { if (activePresetName) savePreset(activePresetName); return; } // Save as New button var saveNewBtn = e.target.closest('.preset-save-new-btn'); if (saveNewBtn) { isNamingMode = true; renderDropdown(); return; } // Confirm name input var confirmBtn = e.target.closest('.preset-confirm-name'); if (confirmBtn) { var input = dropdown.querySelector('.preset-name-input'); if (input && input.value.trim()) { savePreset(input.value.trim()); } return; } // Cancel name input var cancelBtn = e.target.closest('.preset-cancel-name'); if (cancelBtn) { isNamingMode = false; renderDropdown(); return; } }); // Keydown on name input dropdown.addEventListener('keydown', function(e) { var input = e.target.closest('.preset-name-input'); if (!input) return; if (e.key === 'Enter') { e.stopPropagation(); if (input.value.trim()) { savePreset(input.value.trim()); } } else if (e.key === 'Escape') { e.stopPropagation(); isNamingMode = false; renderDropdown(); } }); } // Handle outside click to close dropdown function setupOutsideClickHandler() { document.addEventListener('click', function(e) { var section = document.getElementById('presetSection'); var dropdown = document.getElementById('presetDropdown'); if (isOpen && section && dropdown && !section.contains(e.target)) { closeDropdown(); } }); } // Initialize presets module — called after first scan completes function init() { // Idempotent: skip if button listener already attached var btn = document.getElementById('presetBtn'); if (!btn || btn.dataset.presetInit) return; btn.dataset.presetInit = '1'; btn.addEventListener('click', function(e) { e.stopPropagation(); toggleDropdown(); }); setupDropdownDelegation(); setupOutsideClickHandler(); loadFromStorage(); renderButton(); } // Register module window.app.modules.presets = { init: init, loadPreset: loadPreset, savePreset: savePreset, deletePreset: deletePreset, checkDirty: checkDirty, renderButton: renderButton, toggleDropdown: toggleDropdown, closeDropdown: closeDropdown }; })();