PageSourceSearch

https://victimscommissioner.org.uk/wp-content/themes/hale/dist/js/…33e1b1cfcd9fb72e5ef5c1f63830&ver=1790759237

js victimscommissioner.org.uk collected 2026-10-03 20:41:54 UTC 9,761 bytes, 228 lines download raw bytes

1/* Autocomplete filter for listing page */
2var taxonomies_with_terms = {};
3
4// Check if the object exists and extract terms
5if (typeof listing_page_object !== 'undefined') {
6    // Store taxonomy terms
7    Object.entries(listing_page_object.taxonomies).forEach(([taxonomy_name, taxonomy_terms]) => {
8        taxonomies_with_terms[taxonomy_name] = taxonomy_terms;
9    });
10}
11
12// Function to update subtopic dropdown when parent term is selected
13function updateSubtopicDropdown(taxonomy_name, parent_term_id, container, selectedSubtopic = null) {
14    const hasSubtopics = container.getAttribute('data-has-subtopics') === '1';
15    
16    if (!hasSubtopics) return;
17    
18    const childClass = container.getAttribute('data-child-class');
19    const wrapper = document.getElementById(childClass + '-wrapper');
20    const subtopicSelect = document.getElementById(childClass);
21    
22    if (!wrapper || !subtopicSelect) {
23        console.warn(`Subtopic elements not found for ${taxonomy_name}`);
24        return;
25    }
26    
27    // Remember current selection if not provided
28    if (!selectedSubtopic) {
29        selectedSubtopic = subtopicSelect.value;
30    }
31    
32    // Clear existing options
33    subtopicSelect.innerHTML = '<option value="0">Select option</option>';
34
35    if (parent_term_id && parent_term_id !== '0') {
36        // Get child terms for the selected parent
37        const childTerms = taxonomies_with_terms[taxonomy_name]
38            ?.filter(term => term.parent == parent_term_id) || [];
39        
40        if (childTerms.length > 0) {
41            // Show subtopic dropdown and enable it
42            wrapper.classList.remove('govuk-visually-hidden');
43            subtopicSelect.removeAttribute('disabled');
44            
45            // Add child options
46            childTerms.forEach(term => {
47                const option = document.createElement('option');
48                option.value = term.term_id;
49                option.textContent = term.name;
50                subtopicSelect.appendChild(option);
51            });
52            
53            // Restore the selected subtopic if it exists in the new options
54            if (selectedSubtopic && selectedSubtopic !== '0') {
55                const optionExists = childTerms.some(term => term.term_id == selectedSubtopic);
56                if (optionExists) {
57                    subtopicSelect.value = selectedSubtopic;
58                }
59            }
60        } else {
61            // Hide subtopic dropdown if no children
62            wrapper.classList.add('govuk-visually-hidden');
63            subtopicSelect.setAttribute('disabled', 'disabled');
64        }
65    } else {
66        // Hide subtopic dropdown when no parent selected
67        wrapper.classList.add('govuk-visually-hidden');
68        subtopicSelect.setAttribute('disabled', 'disabled');
69    }
70}
71
72document.addEventListener("DOMContentLoaded", function() {
73    // Find all autocomplete containers
74    const containers = document.querySelectorAll('[id^="listing-template-autocomplete-container-"]');
75    
76    containers.forEach(container => {
77        const taxonomy_name = container.getAttribute('data-taxonomy');
78        const selected_name = container.getAttribute('data-selected-name');
79        const selected_value = container.getAttribute('data-selected-value');
80        const exclude_terms = container.getAttribute('data-exclude-terms');
81        const has_subtopics = container.getAttribute('data-has-subtopics') === '1';
82        const show_option_all = container.getAttribute('data-show-option-all');
83        
84        if (!taxonomy_name) {
85            console.warn('No taxonomy name found for container:', container);
86            return;
87        }
88        
89        // Get terms for this taxonomy
90        let taxonomy_terms = taxonomies_with_terms[taxonomy_name] || [];
91        
92        // Filter out excluded terms if needed
93        if (exclude_terms && exclude_terms !== '') {
94            const excludeIds = exclude_terms.split(',').map(id => parseInt(id.trim()));
95            taxonomy_terms = taxonomy_terms.filter(term => !excludeIds.includes(parseInt(term.term_id)));
96        }
97        
98        // For hierarchical taxonomies, only show parent terms in autocomplete
99        let source_terms; 
100        if (has_subtopics) {
101            source_terms = taxonomy_terms
102                .filter(term => term.parent == 0) // Only parent terms
103                .map(term => term.name);
104        } else {
105            source_terms = taxonomy_terms.map(term => term.name);
106        }
107        
108        // Validation function
109        function validateAndGetValue(input) {
110            if (!input) return '';
111            const value = input.value?.trim() || '';
112            return value && source_terms.includes(value) ? value : '';
113        }
114        
115        // Function to update hidden input (shared between all handlers)
116        function updateHiddenInput(selectedValue) {
117            // Determine what value to set
118            let valueToSet = '';
119            let subtopicValue = '';
120            
121            // If we have a valid value, try to find the term
122            if (selectedValue && selectedValue.trim() !== '') {
123                const selectedTerm = taxonomy_terms.find(term => term.name === selectedValue);
124                if (selectedTerm) {
125                    valueToSet = selectedTerm.term_id;
126                    subtopicValue = selectedTerm.term_id;
127                }
128            }
129            
130            // Update the hidden input (always, whether clearing or setting)
131            const hiddenInput = document.getElementById(`listing-template-hidden-input-${taxonomy_name}`);
132            if (hiddenInput) {
133                hiddenInput.value = valueToSet;
134                hiddenInput.dispatchEvent(new Event('change'));
135            } else {
136                console.warn(`Hidden input not found for ${taxonomy_name}`);
137            }
138            
139            // Update subtopic dropdown (preserve existing selection when possible)
140            if (has_subtopics) {
141                updateSubtopicDropdown(taxonomy_name, subtopicValue, container);
142            }
143        }
144        
145        // Form submission helper
146        function submitFormDelayed(delay = 50) {
147            setTimeout(() => {
148                const form = container.closest('form');
149                if (form) {
150                    form.submit();
151                } else {
152                    console.warn('Form not found for submission');
153                }
154            }, delay);
155        }
156        
157        // Create the autocomplete widget
158        accessibleAutocomplete({
159            element: container,
160            id: `listing-template-autocomplete-${taxonomy_name}`,
161            name: `${taxonomy_name}-autocomplete-term`,
162            displayMenu: 'overlay',
163            placeholder: show_option_all || 'Select option',
164            defaultValue: selected_name || '',
165            source: function (query, populateResults) {
166                const results = source_terms.filter(term => 
167                    term.toLowerCase().includes(query.toLowerCase())
168                );
169                populateResults(results);
170            },
171            showAllValues: true,
172            dropdownArrow: function (config) {
173                return `<svg class="${config.className}" 
174                             style="width: 12px; height: 12px; top: 16px;" 
175                             viewBox="0 0 512 512">
176                            <path d="M256,298.3L256,298.3L256,298.3l174.2-167.2c4.3-4.2,11.4-4.1,15.8,0.2l30.6,29.9c4.4,4.3,4.5,11.3,0.2,15.5L264.1,380.9
177                                     c-2.2,2.2-5.2,3.2-8.1,3c-3,0.1-5.9-0.9-8.1-3L35.2,176.7c-4.3-4.2-4.2-11.2,0.2-15.5L66,131.3c4.4-4.3,11.5-4.4,15.8-0.2L256,298.3z"/>
178                        </svg>`;
179            },
180            onConfirm: (selectedValue) => {
181                updateHiddenInput(selectedValue);
182            }
183        });
184        
185        // Initialize subtopics and selected subtopic on page load
186        const selected_subtopic = container.getAttribute('data-selected-subtopic');
187        
188        if (has_subtopics && selected_value && selected_value !== '0') {
189            // Pass the selected subtopic to preserve it
190            updateSubtopicDropdown(taxonomy_name, selected_value, container, selected_subtopic);
191        }
192        
193        // Add event listeners with consistent validation
194        const autocompleteInput = container.querySelector('input[type="text"]');
195        if (autocompleteInput) {
196            // Update hidden input when autocomplete input loses focus
197            autocompleteInput.addEventListener('blur', () => {
198                const validValue = validateAndGetValue(autocompleteInput);
199                updateHiddenInput(validValue);
200            });
201            
202            // Enter key handler
203            autocompleteInput.addEventListener('keydown', (e) => {
204                if (e.key === 'Enter') {
205                    e.preventDefault();
206                    const validValue = validateAndGetValue(autocompleteInput);
207                    updateHiddenInput(validValue);
208                    submitFormDelayed(100);
209                }
210            });
211        }
212        
213        // Add form submit handler to ensure hidden input is updated before submission
214        const form = container.closest('form');
215        if (form) {
216            form.addEventListener('submit', (e) => {
217                const autocompleteInput = container.querySelector('input[type="text"]');
218                const validValue = validateAndGetValue(autocompleteInput);
219                
220                if (validValue) {
221                    e.preventDefault();
222                    updateHiddenInput(validValue);
223                    submitFormDelayed();
224                }
225            });
226        }
227    });
228});

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.