PageSourceSearch

https://facednatest.com/wp-content/themes/HighendWP-Child/css/simple-dna-search.js?ver=1.0.0

js facednatest.com collected 2026-10-01 14:48:46 UTC 11,578 bytes, 312 lines download raw bytes

1// Simple DNA Location Search JavaScript
2jQuery(document).ready(function($){
3
4    // US States data
5    const states = [
6        { name: 'Alabama', code: 'AL' },
7        { name: 'Alaska', code: 'AK' },
8        { name: 'Arizona', code: 'AZ' },
9        { name: 'Arkansas', code: 'AR' },
10        { name: 'California', code: 'CA' },
11        { name: 'Colorado', code: 'CO' },
12        { name: 'Connecticut', code: 'CT' },
13        { name: 'Delaware', code: 'DE' },
14        { name: 'Florida', code: 'FL' },
15        { name: 'Georgia', code: 'GA' },
16        { name: 'Hawaii', code: 'HI' },
17        { name: 'Idaho', code: 'ID' },
18        { name: 'Illinois', code: 'IL' },
19        { name: 'Indiana', code: 'IN' },
20        { name: 'Iowa', code: 'IA' },
21        { name: 'Kansas', code: 'KS' },
22        { name: 'Kentucky', code: 'KY' },
23        { name: 'Louisiana', code: 'LA' },
24        { name: 'Maine', code: 'ME' },
25        { name: 'Maryland', code: 'MD' },
26        { name: 'Massachusetts', code: 'MA' },
27        { name: 'Michigan', code: 'MI' },
28        { name: 'Minnesota', code: 'MN' },
29        { name: 'Mississippi', code: 'MS' },
30        { name: 'Missouri', code: 'MO' },
31        { name: 'Montana', code: 'MT' },
32        { name: 'Nebraska', code: 'NE' },
33        { name: 'Nevada', code: 'NV' },
34        { name: 'New Hampshire', code: 'NH' },
35        { name: 'New Jersey', code: 'NJ' },
36        { name: 'New Mexico', code: 'NM' },
37        { name: 'New York', code: 'NY' },
38        { name: 'North Carolina', code: 'NC' },
39        { name: 'North Dakota', code: 'ND' },
40        { name: 'Ohio', code: 'OH' },
41        { name: 'Oklahoma', code: 'OK' },
42        { name: 'Oregon', code: 'OR' },
43        { name: 'Pennsylvania', code: 'PA' },
44        { name: 'Rhode Island', code: 'RI' },
45        { name: 'South Carolina', code: 'SC' },
46        { name: 'South Dakota', code: 'SD' },
47        { name: 'Tennessee', code: 'TN' },
48        { name: 'Texas', code: 'TX' },
49        { name: 'Utah', code: 'UT' },
50        { name: 'Vermont', code: 'VT' },
51        { name: 'Virginia', code: 'VA' },
52        { name: 'Washington', code: 'WA' },
53        { name: 'West Virginia', code: 'WV' },
54        { name: 'Wisconsin', code: 'WI' },
55        { name: 'Wyoming', code: 'WY' }
56    ];
57
58    // Global function to initialize search
59    window.initSimpleDnaSearch = function(uniqueId) {
60        const searchInput = document.getElementById(uniqueId + '-input');
61        const searchButton = document.getElementById(uniqueId + '-btn');
62        const suggestionsContainer = document.getElementById(uniqueId + '-suggestions');
63
64        if (!searchInput || !searchButton || !suggestionsContainer) {
65            console.error('Simple DNA Search: Required elements not found for ID: ' + uniqueId);
66            return;
67        }
68
69        let currentSuggestions = [];
70        let selectedIndex = -1;
71        let searchTimeout;
72
73        // URLs for redirection
74        const stateUrlPattern = 'https://www.facednatest.com/statedirs/';
75        const zipUrlBase = 'https://facednatest.com/dna-testing-locations/';
76        const defaultDistance = '25';
77
78        // Check if input is a zip code (5 digits)
79        function isZipCode(input) {
80            return /^\d{5}$/.test(input.trim());
81        }
82
83        // Check if input could be a zip code (1-5 digits)
84        function couldBeZipCode(input) {
85            return /^\d{1,5}$/.test(input.trim());
86        }
87
88        // Filter states based on input
89        function filterStates(input) {
90            const query = input.toLowerCase().trim();
91            if (!query || couldBeZipCode(query)) return [];
92            
93            return states.filter(state => 
94                state.name.toLowerCase().includes(query) ||
95                state.code.toLowerCase() === query
96            ).slice(0, 5);
97        }
98
99        // Show suggestions
100        function showSuggestions(input) {
101            const query = input.trim();
102            
103            if (!query || query.length < 2) {
104                hideSuggestions();
105                return;
106            }
107
108            let suggestions = [];
109            
110            // Handle zip code input
111            if (couldBeZipCode(query)) {
112                if (query.length === 5) {
113                    suggestions.push({
114                        text: query,
115                        type: 'ZIP',
116                        value: query,
117                        complete: true
118                    });
119                } else {
120                    suggestions.push({
121                        text: query + '...',
122                        type: 'ZIP',
123                        value: query,
124                        complete: false
125                    });
126                }
127            } else {
128                // Add state suggestions
129                const stateMatches = filterStates(query);
130                stateMatches.forEach(state => {
131                    suggestions.push({
132                        text: state.name,
133                        type: 'STATE',
134                        value: state.code,
135                        complete: true
136                    });
137                });
138            }
139
140            currentSuggestions = suggestions;
141            selectedIndex = -1;
142
143            if (suggestions.length > 0) {
144                renderSuggestions(suggestions);
145                suggestionsContainer.style.display = 'block';
146            } else {
147                hideSuggestions();
148            }
149        }
150
151        // Render suggestions
152        function renderSuggestions(suggestions) {
153            suggestionsContainer.innerHTML = suggestions.map((suggestion, index) => {
154                const selectedClass = index === selectedIndex ? 'selected' : '';
155                const typeClass = suggestion.type.toLowerCase();
156                return `
157                    <div class="simple-suggestion-item ${selectedClass}" 
158                         data-index="${index}">
159                        <span class="simple-suggestion-text">${suggestion.text}</span>
160                        <span class="simple-suggestion-type ${typeClass}">${suggestion.type}</span>
161                    </div>
162                `;
163            }).join('');
164
165            // Add click events
166            suggestionsContainer.querySelectorAll('.simple-suggestion-item').forEach((item, index) => {
167                item.addEventListener('click', () => selectSuggestion(index));
168            });
169        }
170
171        // Hide suggestions
172        function hideSuggestions() {
173            suggestionsContainer.style.display = 'none';
174            currentSuggestions = [];
175            selectedIndex = -1;
176        }
177
178        // Select suggestion
179        function selectSuggestion(index) {
180            if (index >= 0 && index < currentSuggestions.length) {
181                const suggestion = currentSuggestions[index];
182                
183                if (!suggestion.complete) return; // Don't select incomplete entries
184                
185                searchInput.value = suggestion.text;
186                hideSuggestions();
187                performSearch(suggestion.value, suggestion.type);
188            }
189        }
190
191        // Perform search
192        function performSearch(value, type = null) {
193            const trimmedValue = value.trim();
194            if (!trimmedValue) return;
195
196            // Determine search type if not specified
197            if (!type) {
198                if (isZipCode(trimmedValue)) {
199                    type = 'ZIP';
200                } else {
201                    const matchedState = states.find(state => 
202                        state.name.toLowerCase() === trimmedValue.toLowerCase() ||
203                        state.code.toLowerCase() === trimmedValue.toLowerCase()
204                    );
205                    if (matchedState) {
206                        type = 'STATE';
207                        value = matchedState.code;
208                    }
209                }
210            }
211
212            // Redirect based on type
213            if (type === 'ZIP') {
214                window.location.href = `${zipUrlBase}?zc=${encodeURIComponent(trimmedValue)}&zd=${encodeURIComponent(defaultDistance)}`;
215            } else if (type === 'STATE') {
216                window.location.href = `${stateUrlPattern}${encodeURIComponent(value)}`;
217            } else {
218                alert('Please enter a valid state name or 5-digit zip code');
219            }
220        }
221
222        // Input event with debouncing
223        searchInput.addEventListener('input', function() {
224            const value = this.value;
225            
226            // Limit zip code input to 5 digits
227            if (couldBeZipCode(value) && value.length > 5) {
228                this.value = value.slice(0, 5);
229                return;
230            }
231
232            // Debounce suggestions
233            clearTimeout(searchTimeout);
234            searchTimeout = setTimeout(() => {
235                showSuggestions(this.value);
236            }, 150);
237        });
238
239        // Keypress validation for zip codes
240        searchInput.addEventListener('keypress', function(e) {
241            const value = this.value;
242            const key = e.key;
243            
244            // If current value looks like a zip code
245            if (couldBeZipCode(value) || (value === '' && /^\d$/.test(key))) {
246                // Allow only digits and special keys
247                if (!/^\d$/.test(key) && !['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Enter'].includes(key)) {
248                    e.preventDefault();
249                }
250                // Prevent more than 5 digits
251                if (value.length >= 5 && /^\d$/.test(key)) {
252                    e.preventDefault();
253                }
254            }
255        });
256
257        // Keyboard navigation
258        searchInput.addEventListener('keydown', function(e) {
259            if (currentSuggestions.length === 0) {
260                if (e.key === 'Enter') {
261                    e.preventDefault();
262                    performSearch(this.value);
263                }
264                return;
265            }
266
267            switch(e.key) {
268                case 'ArrowDown':
269                    e.preventDefault();
270                    selectedIndex = Math.min(selectedIndex + 1, currentSuggestions.length - 1);
271                    renderSuggestions(currentSuggestions);
272                    break;
273                case 'ArrowUp':
274                    e.preventDefault();
275                    selectedIndex = Math.max(selectedIndex - 1, -1);
276                    renderSuggestions(currentSuggestions);
277                    break;
278                case 'Enter':
279                    e.preventDefault();
280                    if (selectedIndex >= 0) {
281                        selectSuggestion(selectedIndex);
282                    } else {
283                        performSearch(this.value);
284                    }
285                    break;
286                case 'Escape':
287                    hideSuggestions();
288                    break;
289            }
290        });
291
292        // Search button click
293        searchButton.addEventListener('click', function() {
294            performSearch(searchInput.value);
295        });
296
297        // Hide suggestions when clicking outside
298        document.addEventListener('click', function(e) {
299            if (!e.target.closest(`#${uniqueId}-input`) && !e.target.closest(`#${uniqueId}-suggestions`)) {
300                hideSuggestions();
301            }
302        });
303
304        // Focus management
305        searchInput.addEventListener('focus', function() {
306            if (this.value.trim() && this.value.length >= 2) {
307                showSuggestions(this.value);
308            }
309        });
310    };
311
312});

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.