/** * SearchInterface Module * Handles the creation and management of the search UI */ class SearchInterface { constructor(options) { this.options = options; this.isVisible = false; this.modal = null; this.input = null; this.resultsContainer = null; this.statsContainer = null; } /** * Create the search interface elements */ create() { // Check if we're on the search page if (this.isSearchPage()) { this.enhanceSearchPage(); } else { // On other pages, create the modal for search functionality this.createModal(); this.enhanceSearchButton(); } console.log('✅ Search interface created'); } /** * Check if we're on the search page */ isSearchPage() { return window.location.pathname.includes('/search') || window.location.pathname.includes('/search.html') || window.location.pathname.endsWith('search/') || document.querySelector('#search-results') !== null || document.querySelector('.search-page') !== null || document.querySelector('form[action*="search"]') !== null || document.title.toLowerCase().includes('search') || document.querySelector('h1')?.textContent.toLowerCase().includes('search'); } /** * Enhance the existing search page using the template structure */ enhanceSearchPage() { console.log('🔍 Enhancing search page using existing template...'); console.log('📄 Page URL:', window.location.href); console.log('📋 Page title:', document.title); // Use the template's existing elements this.input = document.querySelector('#enhanced-search-page-input'); this.resultsContainer = document.querySelector('#enhanced-search-page-results'); console.log('🔎 Template search input found:', !!this.input); console.log('📦 Template results container found:', !!this.resultsContainer); if (this.input && this.resultsContainer) { console.log('✅ Using existing template structure - no additional setup needed'); // The template's JavaScript will handle everything return; } // Fallback for non-template pages console.log('⚠️ Template elements not found, falling back to generic search page detection'); this.fallbackToGenericSearchPage(); } /** * Fallback for pages that don't use the template */ fallbackToGenericSearchPage() { // Find existing search elements on generic pages this.input = document.querySelector('#searchbox input[type="text"]') || document.querySelector('input[name="q"]') || document.querySelector('.search input[type="text"]'); // Find or create results container this.resultsContainer = document.querySelector('#search-results') || document.querySelector('.search-results') || this.createResultsContainer(); // Create stats container this.statsContainer = this.createStatsContainer(); // Hide default Sphinx search results if they exist this.hideDefaultResults(); // Initialize with empty state this.showEmptyState(); console.log('✅ Generic search page enhanced'); } /** * Create results container if it doesn't exist */ createResultsContainer() { const container = document.createElement('div'); container.id = 'enhanced-search-results'; container.className = 'enhanced-search-results'; // Add basic styling to ensure proper positioning container.style.cssText = ` width: 100%; max-width: none; margin: 1rem 0; clear: both; position: relative; z-index: 1; `; // Find the best place to insert it within the main content area const insertLocation = this.findBestInsertLocation(); if (insertLocation.parent && insertLocation.method === 'append') { insertLocation.parent.appendChild(container); console.log(`✅ Results container added to: ${insertLocation.parent.className || insertLocation.parent.tagName}`); } else if (insertLocation.parent && insertLocation.method === 'after') { insertLocation.parent.insertAdjacentElement('afterend', container); console.log(`✅ Results container added after: ${insertLocation.parent.className || insertLocation.parent.tagName}`); } else { // Last resort - create a wrapper in main content this.createInMainContent(container); } return container; } /** * Find the best location to insert search results */ findBestInsertLocation() { // Try to find existing search-related elements first let searchResults = document.querySelector('.search-results, #search-results'); if (searchResults) { return { parent: searchResults, method: 'append' }; } // Look for search form and place results after it let searchForm = document.querySelector('#searchbox, .search form, form[action*="search"]'); if (searchForm) { return { parent: searchForm, method: 'after' }; } // Look for main content containers (common Sphinx/theme classes) const mainSelectors = [ '.document .body', '.document .documentwrapper', '.content', '.main-content', '.page-content', 'main', '.container .row .col', '.rst-content', '.body-content' ]; for (const selector of mainSelectors) { const element = document.querySelector(selector); if (element) { return { parent: element, method: 'append' }; } } // Try to find any container that's not the body const anyContainer = document.querySelector('.container, .wrapper, .page, #content'); if (anyContainer) { return { parent: anyContainer, method: 'append' }; } return { parent: null, method: null }; } /** * Create container in main content as last resort */ createInMainContent(container) { // Create a wrapper section const wrapper = document.createElement('section'); wrapper.className = 'search-page-content'; wrapper.style.cssText = ` max-width: 800px; margin: 2rem auto; padding: 0 1rem; `; // Add a title const title = document.createElement('h1'); title.textContent = 'Search Results'; title.style.cssText = 'margin-bottom: 1rem;'; wrapper.appendChild(title); // Add the container wrapper.appendChild(container); // Insert into body, but with proper styling document.body.appendChild(wrapper); console.log('⚠️ Created search results in body with wrapper - consider improving page structure'); } /** * Create stats container */ createStatsContainer() { const container = document.createElement('div'); container.className = 'enhanced-search-stats'; container.style.cssText = 'margin: 1rem 0; font-size: 0.9rem; color: #666;'; // Insert before results if (this.resultsContainer && this.resultsContainer.parentNode) { this.resultsContainer.parentNode.insertBefore(container, this.resultsContainer); } return container; } /** * Hide default Sphinx search results */ hideDefaultResults() { // Hide default search results that Sphinx might show const defaultResults = document.querySelectorAll( '.search-summary, .search li, #search-results .search, .searchresults' ); defaultResults.forEach(el => { el.style.display = 'none'; }); } /** * Create the main search modal (legacy - kept for compatibility) */ createModal() { // Enhanced search modal const modal = document.createElement('div'); modal.id = 'enhanced-search-modal'; modal.className = 'enhanced-search-modal'; modal.innerHTML = `
Start typing to search documentation...
No results found for "${this.escapeHtml(query)}"
${this.escapeHtml(message)}