jQuery(document).ready(function($){
var privateLocationStoreKey='em_private_search_locations';
function getSearchForm($element){
return $element.closest('.em-event-search-form, .em-artist-search-form, form');
}
function getField($form, role, fallbackName){
var $field=role ? $form.find('[data-role="' + role + '"]'):$();
if(!$field.length&&fallbackName){
$field=$form.find('[name="' + fallbackName + '"]');
}
return $field;
}
function submitSearchForm($form){
if(!$form.length){
return;
}
$form.trigger('submit');
}
function syncDateClearButton($input){
$input.closest('.em-search-date-control').toggleClass('is-empty', !$.trim($input.val()));
}
function clearLocationMode($form){
getField($form, 'search-coord', 'coord').val('').removeAttr('name');
getField($form, 'search-user-coord', 'usercoord').val('').removeAttr('name');
getField($form, 'search-nearby', 'nearby').val('0').removeAttr('name');
}
function clearNearbyMode($form){
var $coord=getField($form, 'search-coord', 'coord');
getField($form, 'search-nearby', 'nearby').val('0').removeAttr('name');
getField($form, 'search-user-coord', 'usercoord').val('').removeAttr('name');
if(!getFormValue($form, 'search-place', 'luogo')){
$coord.val('').removeAttr('name');
}else if($coord.val()){
$coord.attr('name', 'coord');
}}
function clearPlaceField($form){
getField($form, 'search-place', 'luogo').val('');
}
function setSearchCoordinate($form, latitude, longitude, nearby){
latitude=normalizeCoordinate(latitude, nearby);
longitude=normalizeCoordinate(longitude, nearby);
var coord=latitude + ':' + longitude;
var $coordField=getField($form, 'search-coord', 'coord').val(coord);
if(nearby){
$coordField.removeAttr('name');
}else{
$coordField.attr('name', 'coord');
}
getField($form, 'search-nearby', 'nearby').val(nearby ? '1':'0').attr('name', nearby ? 'nearby':null);
if(!nearby){
getField($form, 'search-nearby', 'nearby').removeAttr('name');
}
getField($form, 'search-user-coord', 'usercoord').val('').removeAttr('name');
if(nearby){
getField($form, 'search-user-coord', 'usercoord').val(coord);
}
savePrivateLocation($form, latitude, longitude, nearby);
}
function normalizeCoordinate(value, isUserLocation){
var number=parseFloat(value);
if(!isFinite(number)){
return '';
}
return number.toFixed(isUserLocation ? 3:6);
}
function storageAvailable(){
try {
var key='__em_private_location_test__';
window.sessionStorage.setItem(key, '1');
window.sessionStorage.removeItem(key);
return true;
} catch (error){
return false;
}}
function getFormValue($form, role, fallbackName){
var $field=getField($form, role, fallbackName);
return $field.length ? $.trim($field.val()):'';
}
function getSearchSignature($form){
return [
getFormValue($form, 'artist-slug', 'artist'),
getFormValue($form, 'search-place', 'luogo'),
getFormValue($form, '', 'se'),
getFormValue($form, '', 'dtfrom'),
getFormValue($form, '', 'event-category'),
getFormValue($form, 'search-nearby', 'nearby')
].join('|').toLowerCase();
}
function savePrivateLocation($form, latitude, longitude, nearby){
if(!storageAvailable()||!latitude||!longitude){
return;
}
try {
var signature=getSearchSignature($form);
var raw=window.sessionStorage.getItem(privateLocationStoreKey);
var store=raw ? JSON.parse(raw):{};
store[signature]={
lat: latitude,
lng: longitude,
userLat: nearby ? latitude:'',
userLng: nearby ? longitude:'',
savedAt: Date.now()
};
window.sessionStorage.setItem(privateLocationStoreKey, JSON.stringify(store));
} catch (error){
return;
}}
function geocodePlaceAndSubmit($form){
var $place=getField($form, 'search-place', 'luogo');
var place=$place.val();
if(!place||getField($form, 'search-coord', 'coord').val()){
return true;
}
$.ajax({
url: 'https://nominatim.openstreetmap.org/search',
method: 'GET',
dataType: 'json',
data: {
q: place,
format: 'json',
addressdetails: 1,
limit: 1
},
success: function(data){
if(data&&data[0]&&data[0].lat&&data[0].lon){
setSearchCoordinate($form, data[0].lat, data[0].lon, false);
}
$form.data('emGeocodedSubmit', true);
submitSearchForm($form);
},
error: function(){
$form.data('emGeocodedSubmit', true);
submitSearchForm($form);
}});
return false;
}
$(document).on('submit', '.em-event-search-form', function(event){
var $form=$(this);
if(!$form.data('emNearbySubmit')){
clearNearbyMode($form);
}
if($form.data('emGeocodedSubmit')){
$form.removeData('emGeocodedSubmit');
$form.removeData('emNearbySubmit');
return true;
}
if($form.data('emNearbySubmit')&&getField($form, 'search-nearby', 'nearby').val()==='1'){
$form.removeData('emNearbySubmit');
return true;
}
if(!geocodePlaceAndSubmit($form)){
event.preventDefault();
return false;
}
return true;
});
$(document).on('click', '[data-role="geo-search"], .em-localizzazione, #em-localizzazione', function(){
var $form=getSearchForm($(this));
clearPlaceField($form);
getField($form, 'search-nearby', 'nearby').val('1').attr('name', 'nearby');
$form.data('emNearbySubmit', true);
geolocalizzazione($form, true);
});
$(document).on('change keypress', '[data-role="search-place"], .em-search-place-input, #form-field-f_luogo', function(event){
var $form=getSearchForm($(this));
clearLocationMode($form);
if(event.type==='keypress'&&event.keyCode===13){
event.preventDefault();
submitSearchForm($form);
}});
$(document).on('click', '[data-role="clear-search-date"]', function(event){
event.preventDefault();
event.stopPropagation();
var $input=$(this).closest('.em-search-date-control').find('input').first();
$input.val('').trigger('change').trigger('input').trigger('blur');
});
$(document).on('change input', '.em-search-date-control input', function(){
syncDateClearButton($(this));
});
$('.em-search-date-control input').each(function(){
syncDateClearButton($(this));
});
enhanceCategoryPickers();
enhanceKeywordAutocomplete();
watchCategoryPickerMounts();
$('[data-role="search-place"], .em-search-place-input, #form-field-f_luogo').each(function(){
var $input=$(this);
if($input.data('emAutocompleteReady')){
return;
}
$input.data('emAutocompleteReady', true);
$input.autocomplete({
source: function(request, response){
$.ajax({
url: 'https://nominatim.openstreetmap.org/search',
method: 'GET',
dataType: 'json',
data: {
q: request.term,
format: 'json',
addressdetails: 1
},
success: function(data){
response($.map(data, function(item){
return {
label: item.display_name,
value: item.display_name,
latitude: item.lat,
longitude: item.lon,
village: item.address&&(item.address.village||item.address.city||item.address.town)
};}));
}});
},
minLength: 3,
select: function(event, ui){
var $form=getSearchForm($(this));
var locationName=ui.item.village||ui.item.value||ui.item.label||'';
$(this).val(locationName);
setSearchCoordinate($form, ui.item.latitude, ui.item.longitude, false);
return false;
},
open: function(){
$('.ui-autocomplete').addClass('em-search-place-menu');
}}).autocomplete('instance')._renderItem=function(ul, item){
return $('<li>')
.append($('<div>', { class: 'em-search-suggestion' })
.append($('<span>', { class: 'em-search-suggestion__type' }).text('Luogo'))
.append($('<span>', { class: 'em-search-suggestion__label' }).text(item.label||item.value||''))
)
.appendTo(ul);
};});
function enhanceKeywordAutocomplete(){
$('.em-search-keyword').each(function(){
var $input=$(this);
if($input.data('emKeywordAutocompleteReady')||typeof $input.autocomplete!=='function'){
return;
}
$input.data('emKeywordAutocompleteReady', true);
$input.autocomplete({
source: function(request, response){
var ajaxConfig=typeof nc!=='undefined' ? nc:{};
$.ajax({
url: ajaxConfig.url||'',
method: 'GET',
dataType: 'json',
data: {
action: 'em_search_suggestions',
_nonce: ajaxConfig.nonce||'',
q: request.term
}}).done(function(result){
var data=result&&result.success&&result.data ? result.data.suggestions||[]:[];
response(data);
}).fail(function(){
response([]);
});
},
minLength: 2,
delay: 160,
select: function(event, ui){
$input.val(ui.item.value||ui.item.label||'');
return false;
},
open: function(){
$('.ui-autocomplete').addClass('em-search-keyword-menu');
}}).autocomplete('instance')._renderItem=function(ul, item){
return $('<li>')
.append($('<div>', { class: 'em-search-suggestion' })
.append($('<span>', { class: 'em-search-suggestion__type' }).text(item.type||''))
.append($('<span>', { class: 'em-search-suggestion__label' }).text(item.label||item.value||''))
)
.appendTo(ul);
};});
}
function getCategoryPickerSelects(){
var selector=[
'.em-search-category-select',
'.em-event-search-form select[name="event-category"]',
'.em-event-search-form select[data-role="search-category"]',
'form.elementor-form select[id*="categoria"]',
'form.elementor-form select[name*="categoria"]',
'form.elementor-form select[id*="category"]',
'form.elementor-form select[name*="category"]'
].join(',');
return $(selector).filter(function(){
var $select=$(this);
if($select.closest('.wp-admin, .em-submit-shell, .em-user-events-filters').length){
return false;
}
return isLikelyCategorySelect($select);
});
}
function isLikelyCategorySelect($select){
var identity=[
$select.attr('id')||'',
$select.attr('name')||'',
$select.attr('data-role')||'',
$select.attr('class')||''
].join(' ').toLowerCase();
if(identity.indexOf('categoria')!==-1||identity.indexOf('category')!==-1){
return true;
}
return $select.find('option').filter(function(){
return /tutte le categorie|categoria|arte e cultura|concerti|eventi vari|feste e sagre/i.test($.trim($(this).text()));
}).length > 0;
}
function watchCategoryPickerMounts(){
if(!window.MutationObserver||!document.body){
return;
}
var scheduled=false;
var observer=new MutationObserver(function(mutations){
var hasNewSelect=mutations.some(function(mutation){
return Array.prototype.some.call(mutation.addedNodes||[], function(node){
return node.nodeType===1&&($(node).is('select')||$(node).find('select').length);
});
});
if(!hasNewSelect||scheduled){
return;
}
scheduled=true;
window.setTimeout(function(){
scheduled=false;
enhanceCategoryPickers();
}, 80);
});
observer.observe(document.body, { childList: true, subtree: true });
}
function enhanceCategoryPickers(){
getCategoryPickerSelects().each(function(){
var $select=$(this);
if($select.data('emCategoryPickerReady')){
return;
}
$select.data('emCategoryPickerReady', true);
var pickerId=($select.attr('id')||'em-category') + '-picker';
var groups=readCategoryGroups($select);
var activeGroup='';
var $picker=$('<div>', { class: 'em-category-picker', id: pickerId });
var $button=$('<button>', {
type: 'button',
class: 'em-category-picker__button',
'aria-haspopup': 'listbox',
'aria-expanded': 'false'
});
var $buttonText=$('<span>', { class: 'em-category-picker__value' });
var $panel=$('<div>', { class: 'em-category-picker__panel', role: 'listbox' });
var $search=$('<input>', {
type: 'search',
class: 'em-category-picker__search',
placeholder: 'Cerca categoria',
'aria-label': 'Cerca categoria'
}).attr('autocomplete', 'off');
var $parents=$('<div>', { class: 'em-category-picker__parents' });
var $list=$('<div>', { class: 'em-category-picker__list' });
$button.append($buttonText, $('<span>', { class: 'em-category-picker__chevron', 'aria-hidden': 'true', text: '⌄' }));
$panel.append($search, $parents, $list);
$picker.append($button, $panel);
$select.after($picker).addClass('em-search-native-select');
function readCategoryGroups($source){
var result=[];
$source.children().each(function(){
var $node=$(this);
if($node.is('option')){
result.push({ label: $.trim($node.text()), value: $node.val(), parent: true, children: [] });
}
if($node.is('optgroup')){
var group={ label: $.trim($node.attr('label')||''), value: '', parent: true, children: [] };
$node.children('option').each(function(){
var $option=$(this);
var label=$.trim($option.text());
var isParent=label.indexOf('Tutti:')===0;
if(isParent){
group.value=$option.val();
group.parentLabel=label.replace(/^Tutti:\s*/i, '');
}
group.children.push({ label: label, value: $option.val(), parent: isParent, group: group.label });
});
result.push(group);
}});
return result;
}
function initials(label){
return $.trim(label||'T').slice(0, 2).toUpperCase();
}
function selectedOptionLabel(){
var $selected=$select.find('option:selected');
return ($.trim($selected.text())||'Tutte le categorie').replace(/^Tutti:\s*/i, '');
}
function syncButton(){
var value=$select.val();
$button.toggleClass('has-selection', value!=='');
$buttonText.empty();
if(value){
$buttonText.append($('<span>', { class: 'em-category-picker__selected-badge' })
.text(selectedOptionLabel())
.append($('<span>', { class: 'em-category-picker__clear', 'aria-hidden': 'true', text: 'x' }))
);
}else{
$buttonText.text('Tutte le categorie');
}}
function optionMatches(option, filter){
return !filter||option.label.toLowerCase().indexOf(filter)!==-1||(option.group||'').toLowerCase().indexOf(filter)!==-1;
}
function renderParents(filter){
$parents.empty();
$.each(groups, function(index, group){
if(!group.label||(filter&&group.label.toLowerCase().indexOf(filter)===-1&&!group.children.some(function(option){ return optionMatches(option, filter); }))){
return;
}
var value=group.value||'';
var isActive=activeGroup===group.label||(!activeGroup&&value==='');
var $parent=$('<button>', {
type: 'button',
class: 'em-category-picker__parent' + (isActive ? ' is-active':''),
'data-group': group.label,
'data-value': value
});
$parent.append($('<span>', { class: 'em-category-picker__parent-icon', text: value ? initials(group.label):'*' }));
$parent.append($('<span>').text(group.parentLabel||group.label));
$parents.append($parent);
});
}
function appendOption(option){
var isSelected=option.value===$select.val();
var $item=$('<button>', {
type: 'button',
class: 'em-category-picker__option' + (isSelected ? ' is-selected':'') + (option.parent ? ' is-parent':''),
'data-value': option.value,
role: 'option',
'aria-selected': isSelected ? 'true':'false'
});
$item.append($('<span>', { class: 'em-category-picker__option-label', text: option.label }));
if(option.group&&!option.parent){
$item.append($('<span>', { class: 'em-category-picker__option-group', text: option.group }));
}
$list.append($item);
}
function buildList(){
var filter=$.trim($search.val()||'').toLowerCase();
$list.empty();
renderParents(filter);
$.each(groups, function(index, group){
if(activeGroup&&group.label!==activeGroup&&!filter){
return;
}
var matching=group.children.filter(function(option){
return optionMatches(option, filter);
});
if(!matching.length){
return;
}
if(!activeGroup||filter){
$list.append($('<div>', { class: 'em-category-picker__group', text: group.label }));
}
$.each(matching, function(childIndex, option){
appendOption(option);
});
});
if(!$list.children().length){
$list.append($('<div>', { class: 'em-category-picker__empty', text: 'Nessuna categoria trovata' }));
}}
function openPicker(){
$('.em-category-picker.is-open').not($picker).removeClass('is-open').find('.em-category-picker__button').attr('aria-expanded', 'false');
$picker.addClass('is-open');
$button.attr('aria-expanded', 'true');
buildList();
setTimeout(function(){ $search.trigger('focus'); }, 0);
}
function closePicker(){
$picker.removeClass('is-open');
$button.attr('aria-expanded', 'false');
}
syncButton();
buildList();
$button.on('click', function(event){
if($(event.target).closest('.em-category-picker__clear').length){
event.preventDefault();
event.stopPropagation();
$select.val('').trigger('change');
activeGroup='';
syncButton();
buildList();
return;
}
$picker.hasClass('is-open') ? closePicker():openPicker();
});
$button.on('keydown', function(event){
if(event.key==='Enter'||event.key===' '||event.key==='ArrowDown'){
event.preventDefault();
openPicker();
}});
$search.on('input', buildList);
$search.on('keydown', function(event){
if(event.key==='Escape'){
closePicker();
$button.trigger('focus');
}});
$parents.on('click', '.em-category-picker__parent', function(){
activeGroup=$(this).attr('data-group')||'';
buildList();
});
$list.on('click', '.em-category-picker__option', function(){
$select.val($(this).attr('data-value')).trigger('change');
syncButton();
closePicker();
});
$list.on('keydown', '.em-category-picker__option', function(event){
if(event.key==='Enter'||event.key===' '){
event.preventDefault();
$(this).trigger('click');
}
if(event.key==='Escape'){
closePicker();
$button.trigger('focus');
}});
$select.on('change', function(){
syncButton();
buildList();
});
$(document).on('click', function(event){
if(!$picker.is(event.target)&&!$picker.has(event.target).length){
closePicker();
}});
});
}
function geolocalizzazione($form, submitAfter){
if(!navigator.geolocation){
return;
}
navigator.geolocation.getCurrentPosition(function(position){
setSearchCoordinate($form, position.coords.latitude, position.coords.longitude, true);
if(submitAfter){
submitSearchForm($form);
}});
}
function getPlaceName($form, latitude, longitude, submitAfter){
$.ajax({
url: 'https://nominatim.openstreetmap.org/reverse',
method: 'GET',
dataType: 'json',
data: {
lat: latitude,
lon: longitude,
format: 'json',
addressdetails: 1
},
success: function(response){
var address=response&&response.address ? response.address:{};
var loc=address.city||address.village||address.town||address.municipality||'';
getField($form, 'search-place', 'luogo').val(loc);
setSearchCoordinate($form, latitude, longitude, true);
if(submitAfter){
submitSearchForm($form);
}},
error: function(xhr, status, error){
console.error('Errore durante la richiesta a Nominatim:', error);
}});
}});