PageSourceSearch

https://dealdump.com/assets/js/header.js

js dealdump.com collected 2026-10-05 11:36:28 UTC 10,097 bytes, 254 lines download raw bytes

1// Mobile Menu Toggle
2const initMobileMenu = () => {
3    const mobileMenuBtn = document.getElementById('mobileMenuBtn');
4    const mobileMenu = document.getElementById('mobileMenu');
5
6    if (mobileMenuBtn && mobileMenu) {
7        mobileMenuBtn.addEventListener('click', (e) => {
8            e.preventDefault();
9            e.stopPropagation();
10            console.log('Mobile menu button clicked'); // Debug log
11            mobileMenu.classList.toggle('hidden');
12            
13            // Change hamburger to X when menu is open
14            const isOpen = !mobileMenu.classList.contains('hidden');
15            mobileMenuBtn.innerHTML = isOpen 
16                ? '<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>'
17                : '<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg>';
18            
19            // Toggle body scroll
20            document.body.style.overflow = isOpen ? 'hidden' : '';
21        });
22
23        // Close menu when clicking outside
24        document.addEventListener('click', (e) => {
25            if (!mobileMenu.contains(e.target) && !mobileMenuBtn.contains(e.target) && !mobileMenu.classList.contains('hidden')) {
26                mobileMenu.classList.add('hidden');
27                document.body.style.overflow = '';
28            }
29        });
30    }
31};
32
33// Category navigation scroll function
34function scrollCategories(direction) {
35    const container = document.getElementById('categoryContainer');
36    if (!container) return;
37    
38    const scrollAmount = 300;
39    if (direction === 'left') {
40        container.scrollBy({
41            left: -scrollAmount,
42            behavior: 'smooth'
43        });
44    } else {
45        container.scrollBy({
46            left: scrollAmount,
47            behavior: 'smooth'
48        });
49    }
50}
51
52// AJAX Search functionality
53const initSearch = () => {
54    const searchInput = document.getElementById('searchInput');
55    const searchResults = document.getElementById('searchResults');
56    let searchTimeout;
57
58    if (searchInput && searchResults) {
59        searchInput.addEventListener('input', function() {
60            clearTimeout(searchTimeout);
61            const query = this.value.trim();
62
63            if (query.length < 2) {
64                searchResults.innerHTML = '';
65                searchResults.classList.add('hidden');
66                return;
67            }
68
69            searchTimeout = setTimeout(() => {
70                fetch(`ajax_search.php?q=${encodeURIComponent(query)}`)
71                    .then(response => response.json())
72                    .then(data => {
73                        if (data.success && data.results.length > 0) {
74                            searchResults.innerHTML = data.results.map(deal => `
75                                <a href="${deal.url}" target="_blank" rel="noopener noreferrer"
76                                   class="block px-4 py-2 hover:bg-gray-50 border-b last:border-b-0">
77                                    <div class="flex items-center">
78                                        <img src="${deal.image}" 
79                                             alt="${deal.title}" 
80                                             class="w-12 h-12 object-contain mr-3">
81                                        <div class="flex-1 min-w-0">
82                                            <div class="text-sm font-medium text-gray-900 truncate">${deal.title}</div>
83                                            <div class="text-sm text-gray-500">${deal.brand}</div>
84                                            <div class="flex items-center mt-1">
85                                                <span class="text-red-600 font-bold">$${deal.price}</span>
86                                                <span class="ml-2 text-green-600">-${deal.discount}%</span>
87                                            </div>
88                                        </div>
89                                    </div>
90                                </a>
91                            `).join('');
92                            searchResults.classList.remove('hidden');
93                        } else {
94                            searchResults.innerHTML = `
95                                <div class="px-4 py-3 text-sm text-gray-500">
96                                    No deals found for "${query}"
97                                </div>
98                            `;
99                            searchResults.classList.remove('hidden');
100                        }
101                    })
102                    .catch(error => {
103                        console.error('Search error:', error);
104                        searchResults.innerHTML = `
105                            <div class="px-4 py-3 text-sm text-red-500">
106                                Error performing search. Please try again.
107                            </div>
108                        `;
109                        searchResults.classList.remove('hidden');
110                    });
111            }, 300);
112        });
113
114        // Hide search results when clicking outside
115        document.addEventListener('click', function(e) {
116            if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) {
117                searchResults.classList.add('hidden');
118            }
119        });
120    }
121};
122
123// Table sorting functionality
124const tableSortDirections = {};
125
126function sortTable(tableId, columnIndex, type = 'text') {
127    const table = document.getElementById(tableId);
128    const tbody = table.querySelector('tbody');
129    const rows = Array.from(tbody.querySelectorAll('tr'));
130    
131    // Toggle sort direction for this column
132    if (!tableSortDirections[tableId]) {
133        tableSortDirections[tableId] = {};
134    }
135    tableSortDirections[tableId][columnIndex] = tableSortDirections[tableId][columnIndex] === 'asc' ? 'desc' : 'asc';
136    
137    // Sort the rows
138    rows.sort((a, b) => {
139        let aValue, bValue;
140        
141        if (type === 'number') {
142            // Get numeric values from data-value attributes
143            aValue = parseFloat(a.children[columnIndex].getAttribute('data-value')) || 0;
144            bValue = parseFloat(b.children[columnIndex].getAttribute('data-value')) || 0;
145        } else {
146            // Get text content for text comparison
147            aValue = a.children[columnIndex].textContent.trim().toLowerCase();
148            bValue = b.children[columnIndex].textContent.trim().toLowerCase();
149        }
150        
151        if (type === 'number') {
152            return tableSortDirections[tableId][columnIndex] === 'asc' ? aValue - bValue : bValue - aValue;
153        } else {
154            return tableSortDirections[tableId][columnIndex] === 'asc' 
155                ? aValue.localeCompare(bValue) 
156                : bValue.localeCompare(aValue);
157        }
158    });
159    
160    // Remove existing rows
161    rows.forEach(row => tbody.removeChild(row));
162    
163    // Add sorted rows
164    rows.forEach(row => tbody.appendChild(row));
165    
166    // Update sort indicators
167    const headers = table.querySelectorAll('th');
168    headers.forEach((header, index) => {
169        header.classList.remove('sorted-asc', 'sorted-desc');
170        if (index === columnIndex) {
171            header.classList.add(tableSortDirections[tableId][columnIndex] === 'asc' ? 'sorted-asc' : 'sorted-desc');
172        }
173    });
174}
175
176// Initialize table sorting
177const initTableSorting = () => {
178    // Find all tables and initialize their sorting
179    document.querySelectorAll('table[id^="dealsTable_"]').forEach(table => {
180        const tableId = table.id;
181        if (!tableSortDirections[tableId]) {
182            tableSortDirections[tableId] = {};
183        }
184        // Set initial sort direction for savings column
185        tableSortDirections[tableId][3] = 'asc'; // This will be toggled to 'desc' by sortTable
186        sortTable(tableId, 3, 'number');
187    });
188};
189
190// View toggle functionality
191function toggleView() {
192    const cardViews = document.querySelectorAll('.card-view');
193    const tableViews = document.querySelectorAll('.table-view');
194    const viewIcon = document.getElementById('viewIcon');
195    
196    const preferredView = localStorage.getItem('preferredView') || 'card';
197    const newView = preferredView === 'card' ? 'table' : 'card';
198    
199    cardViews.forEach(cardView => {
200        if (newView === 'table') {
201            cardView.classList.add('hidden');
202        } else {
203            cardView.classList.remove('hidden');
204        }
205    });
206    
207    tableViews.forEach(tableView => {
208        if (newView === 'table') {
209            tableView.classList.remove('hidden');
210        } else {
211            tableView.classList.add('hidden');
212        }
213    });
214    
215    // Update icon
216    if (newView === 'table') {
217        viewIcon.classList.remove('fa-list');
218        viewIcon.classList.add('fa-th-large');
219    } else {
220        viewIcon.classList.remove('fa-th-large');
221        viewIcon.classList.add('fa-list');
222    }
223    
224    localStorage.setItem('preferredView', newView);
225}
226
227// Dark mode toggle
228function toggleDarkMode() {
229    const body = document.body;
230    const darkModeIcon = document.getElementById('darkModeIcon');
231    
232    body.classList.toggle('dark');
233    if (body.classList.contains('dark')) {
234        darkModeIcon.classList.remove('fa-moon');
235        darkModeIcon.classList.add('fa-sun');
236        localStorage.setItem('darkMode', 'enabled');
237    } else {
238        darkModeIcon.classList.remove('fa-sun');
239        darkModeIcon.classList.add('fa-moon');
240        localStorage.setItem('darkMode', 'disabled');
241    }
242}
243
244// Initialize everything when DOM is ready
245document.addEventListener('DOMContentLoaded', () => {
246    console.log('Initializing...'); // Debug log
247    initMobileMenu();
248    initSearch();
249    initTableSorting();
250    
251    if (localStorage.getItem('darkMode') === 'enabled') {
252        toggleDarkMode();
253    }
254});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.