(function($) {
$(window).on('elementor/frontend/init', function () {
elementorFrontend.hooks.addAction('frontend/element_ready/ep-search.default', function($scope){
var $body = $('body');
/* -----------------------------------------
Ajax Search
----------------------------------------- */
var $elementSearchForm = $($scope).find('.element-search-form');
var $categoriesSelect = $elementSearchForm.find('.element-search-category-select');
var $searchInput = $elementSearchForm.find('.element-search-input');
var $searchResults = $elementSearchForm.find('.element-search-results');
var $searchResultsTemplate = $elementSearchForm.find('.element-search-results-item');
var $spinner = $elementSearchForm.find('.element-search-spinner');
var postType = $elementSearchForm.find('input[name="post_type"]').val();
var taxonomy = $elementSearchForm.find('input[name="taxonomy"]').val();
var postNo = $elementSearchForm.find('input[name="num_posts"]').val();
var searchNoItemsText = $elementSearchForm.data('no-results');
var searchUrl = $elementSearchForm.attr('action');
var allResultsText = $elementSearchForm.data('all-results');
var numWords = $elementSearchForm.find('input[name="num_words"]').val();
function dismissSearchResults() {
$searchResults.hide();
}
function queryItems(category, string) {
return $.ajax({
url: ep_search_vars.ajaxurl,
method: 'get',
data: {
action: 'elements_plus_search',
term: category,
s: string,
post_type: postType,
post_taxonomy: taxonomy,
num_posts: postNo,
num_words: numWords,
},
});
}
function queryItemsAndPopulateResults(category, string) {
if (string.trim().length < 3) {
dismissSearchResults();
return;
}
$spinner.addClass('visible');
return queryItems(category, string)
.done(function (response) {
$spinner.removeClass('visible');
if (response.error) {
var $errorMessage = $searchResultsTemplate.clone();
var errorString = response.errors.join(', ');
$errorMessage
.addClass('error')
.find('.element-search-results-item-title')
.text('Error: ' + errorString);
$searchResults.html($errorMessage).show();
return;
}
var items = response.data;
if (items.length === 0) {
var $notFoundMessage = $searchResultsTemplate.clone();
$notFoundMessage.find('.element-search-results-item-thumb').remove();
$notFoundMessage
.find('.element-search-results-item-title')
.text(searchNoItemsText);
$searchResults.html($notFoundMessage).show();
return;
}
var $items = items.map(function (item) {
var $template = $searchResultsTemplate.clone();
$template.find('a').attr('href', item.url);
if ( ! item.image ) {
$template.find('.element-search-results-item-thumb').remove();
} else {
$template.find('.element-search-results-item-thumb img').attr('src', item.image);
}
$template.find('.element-search-results-item-title')
.text(item.title);
$template.find('.element-search-results-item-excerpt')
.text(item.excerpt);
return $template;
});
$searchResults.html($items);
if ( parseInt(postNo, 10) < parseInt(items[0].found, 10) ) {
$searchResults.append( '
' + allResultsText + '' );
}
$searchResults.show();
});
}
var throttledQuery = throttle(queryItemsAndPopulateResults, 500);
if ($elementSearchForm.hasClass('form-ajax-enabled')) {
$searchInput.on('input', function (event) {
// Do nothing on arrow up / down as we're using them for navigation
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
return;
}
var $this = $(this);
var string = $this.val();
if (string.trim().length < 3) {
dismissSearchResults();
return;
}
throttledQuery($categoriesSelect.val(), $this.val());
});
// Bind up / down arrow navigation on search results
$searchInput.on('keydown', function (event) {
if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') {
return;
}
var $items = $searchResults.children();
var $highlighted = $searchResults.find('.highlighted');
var currentIndex = $highlighted.index();
if ($items.length === 0 || !$items) {
return;
}
if (event.key === 'ArrowDown') {
var $next = $items.eq(currentIndex + 1);
if ($next.length) {
$items.removeClass('highlighted');
$next.addClass('highlighted');
}
}
if (event.key === 'ArrowUp') {
var $prev = $items.eq(currentIndex - 1);
if ($prev.length) {
$items.removeClass('highlighted');
$prev.addClass('highlighted');
}
}
});
// Bind form submit to go the highlighted item on submit
// instead of normal search
$elementSearchForm.on('submit', function (event) {
var $highlighted = $searchResults.find('.highlighted');
if ($highlighted.length > 0) {
event.preventDefault();
window.location = $highlighted.find('a').attr('href');
}
});
}
/**
* Returns a function, that, when invoked, will only be triggered at most once
* during a given window of time. Normally, the throttled function will run
* as much as it can, without ever going more than once per `wait` duration;
* but if you'd like to disable the execution on the leading edge, pass
* `{leading: false}`. To disable execution on the trailing edge, ditto.
*
* @param {Function} func - The function to be throttled
* @param {Number} wait - Wait time in millis
* @param {Object} [options]
* @returns {function(): *} - The throttled function
*/
function throttle( func, wait, options ) {
var context, args, result;
var timeout = null;
var previous = 0;
if ( ! options ) {
options = {};
}
var later = function () {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
result = func.apply( context, args );
if ( ! timeout ) {
context = args = null;
}
};
return function () {
var now = Date.now();
if ( ! previous && options.leading === false ) {
previous = now;
}
var remaining = wait - (now - previous);
context = this;
args = arguments;
if ( remaining <= 0 || remaining > wait ) {
if ( timeout ) {
clearTimeout( timeout );
timeout = null;
}
previous = now;
result = func.apply( context, args );
if ( ! timeout ) {
context = args = null;
}
} else if ( ! timeout && options.trailing !== false ) {
timeout = setTimeout( later, remaining );
}
return result;
};
}
$body
.on('click', function (event) {
dismissSearchResults();
})
.find('.element-search-input ',
'.element-search-select')
.on('click', function (event) {
event.stopPropagation();
});
});
});
})( jQuery );