/**
* User Directory Search - Shortcode Version
* Search manager for shortcode-based user directory layouts
*
* @package WPUF
* @subpackage Free/User_Directory
* @since 4.3.0
*/
(function(window, document) {
'use strict';
const SEARCH_DEBOUNCE = 300;
let debounceTimeout = null;
function fetchUsers({
blockId = '',
pageId = '',
directoryId = '',
layout = '',
search = '',
page = 1,
orderby = '',
order = '',
roles = '',
exclude_users = '',
search_by = '',
avatar_size = '',
max_item = '',
onSuccess = () => {},
onError = () => {},
apiUrl = (typeof wpufUserDirectorySearch !== 'undefined' && wpufUserDirectorySearch.restUrl)
? wpufUserDirectorySearch.restUrl
: '/wp-json/wpuf/v1/user_directory/search',
}) {
const params = new URLSearchParams();
if (blockId) params.append('block_id', blockId);
if (pageId) params.append('page_id', pageId);
if (directoryId) params.append('directory_id', directoryId);
if (layout) params.append('directory_layout', layout);
if (search) params.append('search', search);
if (page && page > 1) params.append('page', page);
if (orderby) params.append('orderby', orderby);
if (order) params.append('order', order);
if (roles && roles !== 'all') params.append('roles', roles);
if (exclude_users) params.append('exclude_users', exclude_users);
if (search_by) params.append('search_by', search_by);
if (avatar_size) params.append('avatar_size', avatar_size);
if (max_item) params.append('max_item', max_item);
params.append('base_url', window.location.pathname);
const headers = {};
if (typeof wpufUserDirectorySearch !== 'undefined' && wpufUserDirectorySearch.nonce) {
headers['X-WP-Nonce'] = wpufUserDirectorySearch.nonce;
}
fetch(apiUrl + '?' + params.toString(), {
credentials: 'same-origin',
headers: headers,
})
.then(res => res.json())
.then(data => {
if (data && data.success) {
onSuccess(data);
} else {
onError(data);
}
})
.catch(onError);
}
function initUserDirectorySearch(container, blockId, pageId) {
let currentRequestId = 0;
const listingDiv = document.querySelector('.wpuf-user-listing[data-block-id="' + blockId + '"]');
const input = listingDiv ? listingDiv.querySelector('.wpuf-ud-search-input') : null;
let userList = listingDiv ? (
listingDiv.querySelector('.wpuf-ud-tbody') ||
listingDiv.querySelector('ul[role="list"]')
) : null;
const pagination = listingDiv ? listingDiv.querySelector('.wpuf-ud-pagination') : null;
const liveRegion = listingDiv ? listingDiv.querySelector('[aria-live]') : null;
const sortBySelect = listingDiv ? listingDiv.querySelector('.wpuf-ud-sort-by') : null;
const sortOrderSelect = listingDiv ? listingDiv.querySelector('.wpuf-ud-sort-order') : null;
const searchBySelect = listingDiv ? listingDiv.querySelector('.wpuf-ud-search-by') : null;
const resetButton = listingDiv ? listingDiv.querySelector('.wpuf-ud-reset-filters') : null;
const layout = listingDiv ? listingDiv.dataset.layout || '' : '';
const directoryId = listingDiv ? listingDiv.dataset.directoryId || '' : '';
const roles = listingDiv ? listingDiv.dataset.roles || '' : '';
const excludeUsers = listingDiv ? listingDiv.dataset.excludeUsers || '' : '';
const avatarSize = listingDiv ? listingDiv.dataset.avatarSize || '' : '';
const maxItem = listingDiv ? listingDiv.dataset.maxItem || '' : '';
if (!input || !userList) return;
function showLoading() {
if (listingDiv) {
listingDiv.classList.add('wpuf-ud-loading');
}
if (userList) {
let loadingOverlay = listingDiv.querySelector('.wpuf-ud-loading-overlay');
if (!loadingOverlay) {
loadingOverlay = document.createElement('div');
loadingOverlay.className = 'wpuf-ud-loading-overlay';
loadingOverlay.style.cssText = 'position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.8); display: flex; align-items: center; justify-content: center; z-index: 10;';
const spinner = document.createElement('div');
spinner.className = 'wpuf-ud-spinner';
spinner.style.cssText = 'width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #10b981; border-radius: 50%; animation: wpuf-spin 1s linear infinite;';
loadingOverlay.appendChild(spinner);
if (!document.querySelector('#wpuf-spinner-styles')) {
const style = document.createElement('style');
style.id = 'wpuf-spinner-styles';
style.textContent = '@keyframes wpuf-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }';
document.head.appendChild(style);
}
const listContainer = userList.closest('.wpuf-ud-list, .wpuf-table-responsive');
if (listContainer) {
listContainer.style.position = 'relative';
listContainer.appendChild(loadingOverlay);
}
} else {
loadingOverlay.style.display = 'flex';
}
}
}
function hideLoading() {
if (listingDiv) {
listingDiv.classList.remove('wpuf-ud-loading');
}
const loadingOverlay = listingDiv ? listingDiv.querySelector('.wpuf-ud-loading-overlay') : null;
if (loadingOverlay) {
loadingOverlay.style.display = 'none';
}
}
function performSearch(searchTerm, page = 1) {
const requestId = ++currentRequestId;
const currentOrderby = sortBySelect ? sortBySelect.value : '';
const currentOrder = sortOrderSelect ? sortOrderSelect.value : '';
const searchByField = searchBySelect ? searchBySelect.value : '';
showLoading();
fetchUsers({
blockId,
pageId,
directoryId,
layout,
search: searchTerm,
page: page,
orderby: currentOrderby,
order: currentOrder,
roles: roles,
exclude_users: excludeUsers,
search_by: searchByField,
avatar_size: avatarSize,
max_item: maxItem,
onSuccess: (data) => {
if (requestId !== currentRequestId) {
return;
}
hideLoading();
try {
// If we have results, restore the user list container first
if (data.rows_html && data.rows_html.trim() !== '') {
// Remove "no results" message if it exists
const noResultsContainer = listingDiv.querySelector('.wpuf-no-users-container');
if (noResultsContainer) {
const listContainer = listingDiv.querySelector('.wpuf-ud-list');
if (listContainer) {
// Restore the original list structure (matches layout-3.php template)
listContainer.innerHTML = '
';
}
// Re-query the user list element
userList = listingDiv.querySelector('.wpuf-ud-tbody, ul[role="list"]');
}
// Now update the user list with new data
if (userList) {
userList.innerHTML = data.rows_html;
}
} else {
// No results - show "no users found" message
if (!data.usercount || data.usercount === 0) {
if (userList) {
userList.innerHTML = '';
}
let noResultsContainer = listingDiv.querySelector('.wpuf-no-users-container');
if (!noResultsContainer) {
noResultsContainer = document.createElement('div');
noResultsContainer.className = 'wpuf-no-users-container';
noResultsContainer.style.cssText = 'display: flex; align-items: center; justify-content: center; min-height: 400px;';
const noResultsContent = document.createElement('div');
noResultsContent.style.cssText = 'display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;';
const iconContainer = document.createElement('div');
iconContainer.style.cssText = 'background-color: #f3f4f6; border-radius: 50%; padding: 1rem; margin-bottom: 1rem;';
iconContainer.innerHTML = '';
const heading = document.createElement('h3');
heading.style.cssText = 'font-size: 1rem; font-weight: 600; color: #111827; margin-bottom: 0.5rem;';
heading.textContent = 'No users found matching your search criteria.';
const description = document.createElement('p');
description.style.cssText = 'font-size: 0.875rem; color: #6b7280;';
description.textContent = 'Try adjusting your search or filter to find what you\'re looking for.';
noResultsContent.appendChild(iconContainer);
noResultsContent.appendChild(heading);
noResultsContent.appendChild(description);
noResultsContainer.appendChild(noResultsContent);
const listContainer = listingDiv.querySelector('.wpuf-ud-list');
if (listContainer) {
listContainer.innerHTML = '';
listContainer.appendChild(noResultsContainer);
}
}
noResultsContainer.style.display = 'flex';
}
}
if (data.pagination_html && pagination) {
pagination.innerHTML = data.pagination_html;
attachPaginationListeners();
} else if (pagination) {
pagination.innerHTML = '';
}
if (liveRegion && data.announce) {
liveRegion.textContent = data.announce;
}
// Update browser URL
const url = new URL(window.location);
if (searchTerm) {
url.searchParams.set('search', searchTerm);
} else {
url.searchParams.delete('search');
}
if (currentOrderby) {
url.searchParams.set('orderby', currentOrderby);
} else {
url.searchParams.delete('orderby');
}
if (currentOrder) {
url.searchParams.set('order', currentOrder);
} else {
url.searchParams.delete('order');
}
// Remove udpage if present (legacy)
url.searchParams.delete('udpage');
// Use clean /page/X/ URL structure like Pro
let basePath = url.pathname.replace(/\/page\/\d+\/?$/, '');
basePath = basePath.replace(/\/$/, '');
if (page > 1) {
url.pathname = basePath + '/page/' + page + '/';
} else {
url.pathname = basePath + '/';
}
window.history.replaceState({}, '', url);
const event = new CustomEvent('wpuf:ud:search:results', { detail: data });
container.dispatchEvent(event);
} catch (error) {
console.error('Error processing search results:', error);
}
},
onError: (err) => {
if (requestId !== currentRequestId) {
return;
}
hideLoading();
if (liveRegion) {
liveRegion.textContent = 'Search failed.';
}
const event = new CustomEvent('wpuf:ud:search:error', { detail: err });
container.dispatchEvent(event);
}
});
}
function attachPaginationListeners() {
if (!pagination) return;
const paginationLinks = pagination.querySelectorAll('a.wpuf-pagination-link');
paginationLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const href = this.getAttribute('href');
const url = new URL(href, window.location.origin);
// Get page from URL path (clean URL) or legacy udpage param
let page = 1;
const pathMatch = url.pathname.match(/\/page\/(\d+)\/?$/);
if (pathMatch) {
page = pathMatch[1];
} else if (url.searchParams.get('udpage')) {
page = url.searchParams.get('udpage');
}
const currentSearch = input.value.trim();
const orderby = url.searchParams.get('orderby');
const order = url.searchParams.get('order');
if (orderby && sortBySelect) {
sortBySelect.value = orderby;
}
if (order && sortOrderSelect) {
sortOrderSelect.value = order;
}
performSearch(currentSearch, parseInt(page));
});
});
}
// Search input handler
input.addEventListener('input', function(e) {
const value = e.target.value.trim();
if (debounceTimeout) clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(() => {
performSearch(value, 1);
}, SEARCH_DEBOUNCE);
});
// Sort handlers
if (sortBySelect) {
sortBySelect.addEventListener('change', function() {
const currentSearch = input.value.trim();
performSearch(currentSearch, 1);
});
}
if (sortOrderSelect) {
sortOrderSelect.addEventListener('change', function() {
const currentSearch = input.value.trim();
performSearch(currentSearch, 1);
});
}
if (searchBySelect) {
searchBySelect.addEventListener('change', function() {
const currentSearch = input.value.trim();
if (currentSearch) {
performSearch(currentSearch, 1);
}
});
}
// Reset handler
if (resetButton) {
resetButton.addEventListener('click', function(e) {
e.preventDefault();
input.value = '';
if (sortBySelect) {
const defaultSortBy = sortBySelect.getAttribute('data-default-value') || '';
sortBySelect.value = defaultSortBy;
}
if (sortOrderSelect) {
const defaultSortOrder = sortOrderSelect.getAttribute('data-default-value') || 'desc';
sortOrderSelect.value = defaultSortOrder;
}
if (searchBySelect) {
searchBySelect.value = '';
}
performSearch('', 1);
});
}
// Initialize
attachPaginationListeners();
// Check URL params on load
const urlParams = new URLSearchParams(window.location.search);
const initialSearch = urlParams.get('search');
const initialOrderby = urlParams.get('orderby');
const initialOrder = urlParams.get('order');
if (initialSearch && input.value !== initialSearch) {
input.value = initialSearch;
}
if (initialOrderby && sortBySelect) {
sortBySelect.value = initialOrderby;
}
if (initialOrder && sortOrderSelect) {
sortOrderSelect.value = initialOrder;
}
// Get initial page from URL path or legacy udpage param
let initialPage = 1;
const pagePathMatch = window.location.pathname.match(/\/page\/(\d+)\/?$/);
if (pagePathMatch) {
initialPage = parseInt(pagePathMatch[1]);
} else if (urlParams.get('udpage')) {
initialPage = parseInt(urlParams.get('udpage'));
}
if (initialSearch || initialOrderby || initialOrder) {
performSearch(initialSearch || '', initialPage);
}
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', function() {
const listings = document.querySelectorAll('.wpuf-user-listing');
listings.forEach((listing) => {
const blockId = listing.dataset.blockId || '';
const pageId = listing.dataset.pageId || '';
// Initialize for any listing with a block ID (shortcode or block)
if (blockId) {
initUserDirectorySearch(listing, blockId, pageId);
}
});
});
})(window, document);