const MatchModal = (function() { let _config = { onSearch: async (query, provider) => [], // Debe devolver Array de objetos onSelect: (item, provider) => {}, provider: 'generic' }; let elements = {}; let searchTimeout = null; function init() { if (document.getElementById('waifu-match-modal')) return; // Inyectar HTML const modalHTML = `

Manual Match

Type to start searching...
`; document.body.insertAdjacentHTML('beforeend', modalHTML); // Cachear elementos elements = { overlay: document.getElementById('waifu-match-modal'), input: document.getElementById('match-input'), results: document.getElementById('match-results-container'), badge: document.getElementById('match-provider-badge'), closeBtn: document.getElementById('match-close-btn'), searchBtn: document.getElementById('match-btn-action') }; // Event Listeners elements.closeBtn.onclick = close; elements.overlay.onclick = (e) => { if(e.target === elements.overlay) close(); }; // Búsqueda al hacer clic elements.searchBtn.onclick = () => performSearch(elements.input.value); // Búsqueda al escribir (Debounce) elements.input.addEventListener('input', (e) => { clearTimeout(searchTimeout); if(e.target.value.trim().length === 0) return; searchTimeout = setTimeout(() => performSearch(e.target.value), 600); }); // Enter key elements.input.addEventListener('keypress', (e) => { if (e.key === 'Enter') performSearch(elements.input.value); }); } function open(options) { init(); // Asegurar que el DOM existe _config = { ..._config, ...options }; // Resetear UI elements.input.value = options.initialQuery || ''; elements.results.innerHTML = '
Search above to find matches...
'; elements.badge.innerText = options.provider ? `(${options.provider})` : ''; // Mostrar Modal elements.overlay.classList.add('active'); // Auto-search si hay query inicial if (options.initialQuery) { performSearch(options.initialQuery); } setTimeout(() => elements.input.focus(), 100); } function close() { if(elements.overlay) elements.overlay.classList.remove('active'); } async function performSearch(query) { if (!query || query.trim().length < 2) return; elements.results.innerHTML = '
'; try { // Ejecutar la función de búsqueda pasada en la config const results = await _config.onSearch(query, _config.provider); renderResults(results); } catch (err) { console.error(err); elements.results.innerHTML = '
Error searching provider.
'; } } function renderResults(results) { elements.results.innerHTML = ''; if (!results || results.length === 0) { elements.results.innerHTML = '
No matches found.
'; return; } const grid = document.createElement('div'); grid.className = 'match-list-grid'; results.forEach(item => { const el = document.createElement('div'); el.className = 'match-item'; // Normalización de datos para asegurar compatibilidad con Anime/Libros const img = item.coverImage?.large || item.coverImage || item.image || '/public/assets/no-image.png'; const title = item.title?.english || item.title?.romaji || item.title || 'Unknown Title'; const meta = item.releaseDate || item.year || item.startDate?.year || ''; const url = item.url || item.externalUrl || null; el.innerHTML = `
${title}
${meta}
`; // Botón de enlace externo (si existe URL) if (url) { const linkBtn = document.createElement('a'); linkBtn.href = url; linkBtn.target = "_blank"; linkBtn.className = "match-link-btn"; linkBtn.title = "View Source"; linkBtn.innerHTML = ` `; // Evitar que el click en el enlace dispare el select linkBtn.onclick = (e) => e.stopPropagation(); el.appendChild(linkBtn); } // Click en la tarjeta selecciona el.onclick = () => { _config.onSelect(item); close(); }; grid.appendChild(el); }); elements.results.appendChild(grid); } return { open, close }; })();