PageSourceSearch

https://www.insidearm.com/wp-content/themes/insidearm/assets/js/advanced-search.js?ver=20260924065855

js insidearm.com collected 2026-09-24 18:59:13 UTC 7,607 bytes, 244 lines download raw bytes

1
2/**
3 *
4 * Advanced Search Panel Toggle & Filter Management
5 *
6 * Handles collapsible advanced search functionality and mutual exclusivity
7 * between tag filters and content type selector
8 */
9
10document.addEventListener("DOMContentLoaded", () => {
11	const toggleButton = document.querySelector(".advanced-search-toggle");
12	const searchContent = document.getElementById("advanced-search-content");
13	const contentTypeSelect = document.getElementById("content_type");
14	const tagCheckboxes = document.querySelectorAll(".tag-filter-checkbox");
15
16	if (!toggleButton || !searchContent) {
17		return;
18	}
19
20	// ===== Toggle Functionality =====
21	function toggleSearch() {
22		const isExpanded = toggleButton.getAttribute("aria-expanded") === "true";
23
24		toggleButton.setAttribute("aria-expanded", !isExpanded);
25
26		if (isExpanded) {
27			searchContent.setAttribute("hidden", "");
28		} else {
29			searchContent.removeAttribute("hidden");
30		}
31	}
32
33	toggleButton.addEventListener("click", toggleSearch);
34
35	// ===== Filter Mutual Exclusivity =====
36	// Tags only apply to posts (News). When "Everything" is selected, tags are locked.
37	// When a tag is checked, content type switches to "News".
38	function updateFilterStates() {
39		const isEverythingSelected =
40			contentTypeSelect && contentTypeSelect.value === "all";
41
42		// Disable/enable tag checkboxes based on content type
43		const tagFilterSection = document.querySelector(".search-filter-tags");
44		tagCheckboxes.forEach((checkbox) => {
45			if (isEverythingSelected) {
46				checkbox.disabled = true;
47				checkbox.checked = false;
48			} else {
49				checkbox.disabled = false;
50			}
51		});
52
53		// Disable/enable search operator radios
54		const searchOperatorRadios = document.querySelectorAll(".search-operator-radio");
55		searchOperatorRadios.forEach((radio) => {
56			radio.disabled = isEverythingSelected;
57		});
58
59		// Visual feedback for tag section
60		if (tagFilterSection) {
61			if (isEverythingSelected) {
62				tagFilterSection.style.opacity = "0.6";
63				tagFilterSection.style.pointerEvents = "none";
64			} else {
65				tagFilterSection.style.opacity = "1";
66				tagFilterSection.style.pointerEvents = "auto";
67			}
68		}
69
70		// Update selected tags display
71		updateSelectedTagsList();
72	}
73
74	// ===== Update Selected Tags Display =====
75	function updateSelectedTagsList() {
76		const selectedTagsList = document.getElementById("selected_tags_list");
77		if (!selectedTagsList) {
78			return;
79		}
80
81		// Get all checked checkboxes
82		const checkedCheckboxes = Array.from(tagCheckboxes).filter((checkbox) => checkbox.checked);
83
84		if (checkedCheckboxes.length === 0) {
85			selectedTagsList.innerHTML = "";
86			return;
87		}
88
89		// Build comma-separated list
90		const tagLabels = checkedCheckboxes.map((checkbox) => {
91			return checkbox.closest(".tag-checkbox-inline").querySelector(".tag-label").textContent;
92		});
93
94		selectedTagsList.innerHTML = `<span class="selected-tags-text">Selected: ${tagLabels.join(", ")}</span>`;
95	}
96
97	// Add event listeners to content type select
98	if (contentTypeSelect) {
99		contentTypeSelect.addEventListener("change", updateFilterStates);
100	}
101
102	// Add event listeners to all tag checkboxes
103	tagCheckboxes.forEach((checkbox) => {
104		checkbox.addEventListener("change", () => {
105			// When a tag is checked, switch content type to News (tags only apply to posts)
106			if (checkbox.checked && contentTypeSelect && contentTypeSelect.value === "all") {
107				contentTypeSelect.value = "news";
108			}
109			updateFilterStates();
110		});
111	});
112
113	// Initial state update
114	updateFilterStates();
115
116	// ===== Auto-Expand on Active Filters =====
117	const form = document.querySelector(".advanced-search-form");
118	const mainSearchForm = document.querySelector(".search-bar-top .search-form, .search-prompt .search-form");
119
120	// Helper to add a hidden input to a form
121	function addHiddenInput(targetForm, name, value) {
122		const input = document.createElement("input");
123		input.type = "hidden";
124		input.name = name;
125		input.value = value;
126		input.className = "synced-filter";
127		targetForm.appendChild(input);
128	}
129
130	// Helper to get current filter values from the advanced search form
131	function getCurrentFilters() {
132		const filters = {};
133		const dateRange = document.getElementById("date_range");
134		const orderby = document.getElementById("orderby");
135		const searchOperator = document.querySelector('input[name="search_operator"]:checked');
136
137		if (dateRange && dateRange.value !== "all") {
138			filters.date_range = dateRange.value;
139		}
140		if (contentTypeSelect && contentTypeSelect.value !== "all") {
141			filters.content_type = contentTypeSelect.value;
142		}
143		if (orderby && orderby.value !== "date_desc") {
144			filters.orderby = orderby.value;
145		}
146		if (searchOperator && searchOperator.value !== "AND") {
147			filters.search_operator = searchOperator.value;
148		}
149
150		// Get selected tags from checkboxes
151		const selectedTags = Array.from(tagCheckboxes)
152			.filter((cb) => cb.checked)
153			.map((cb) => cb.value);
154		if (selectedTags.length > 0) {
155			filters.tag_filter = selectedTags.join(",");
156		}
157
158		return filters;
159	}
160
161	// ===== Sync: Main search form includes advanced filters =====
162	if (mainSearchForm) {
163		mainSearchForm.addEventListener("submit", () => {
164			// Remove any previously synced hidden inputs
165			mainSearchForm.querySelectorAll(".synced-filter").forEach((el) => el.remove());
166
167			// Inject current filter values as hidden inputs
168			const filters = getCurrentFilters();
169			for (const [name, value] of Object.entries(filters)) {
170				addHiddenInput(mainSearchForm, name, value);
171			}
172		});
173	}
174
175	// Handle form submission to populate tag_filter hidden field with comma-separated values
176	if (form) {
177		form.addEventListener("submit", () => {
178			// ===== Sync: Advanced form uses current search input value =====
179			if (mainSearchForm) {
180				const mainSearchInput = mainSearchForm.querySelector('input[name="s"]');
181				const hiddenSearchInput = form.querySelector('input[name="s"]');
182				if (mainSearchInput && hiddenSearchInput) {
183					hiddenSearchInput.value = mainSearchInput.value;
184				}
185			}
186
187			const tagFilterHidden = document.getElementById("tag_filter_hidden");
188			if (tagFilterHidden) {
189				// Clear tags when Everything is selected (tags only apply to posts)
190				const isEverything = contentTypeSelect && contentTypeSelect.value === "all";
191				if (isEverything) {
192					tagFilterHidden.value = '';
193				} else {
194					// Collect all checked tag filter checkboxes and create comma-separated list
195					const selectedTags = Array.from(tagCheckboxes)
196						.filter((checkbox) => checkbox.checked)
197						.map((checkbox) => checkbox.value);
198					tagFilterHidden.value = selectedTags.join(',');
199				}
200			}
201
202		});
203	}
204	if (form) {
205		let hasActiveFilters = false;
206
207		// Check for active filters
208		tagCheckboxes.forEach((checkbox) => {
209			if (checkbox.checked) {
210				hasActiveFilters = true;
211			}
212		});
213
214		if (contentTypeSelect && contentTypeSelect.value !== "all") {
215			hasActiveFilters = true;
216		}
217
218		const dateRangeSelect = document.getElementById("date_range");
219		if (dateRangeSelect && dateRangeSelect.value !== "all") {
220			hasActiveFilters = true;
221		}
222
223		const orderbySelect = document.getElementById("orderby");
224		if (orderbySelect && orderbySelect.value !== "date_desc") {
225			hasActiveFilters = true;
226		}
227
228		const searchOperatorRadios = document.querySelectorAll(
229			'input[name="search_operator"]',
230		);
231		for (const radio of searchOperatorRadios) {
232			if (radio.checked && radio.value !== "AND") {
233				hasActiveFilters = true;
234				break;
235			}
236		}
237
238		// Expand if filters are active
239		if (hasActiveFilters) {
240			toggleButton.setAttribute("aria-expanded", "true");
241			searchContent.removeAttribute("hidden");
242		}
243	}
244});

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.