(function (){
'use strict';
var STORAGE_KEY='em_favorites';
var MAX_FAVORITES=60;
var config=window.emFavorites||{};
var strings=config.strings||{};
function readFavorites(){
var raw;
try {
raw=window.localStorage.getItem(STORAGE_KEY);
} catch (e){
return [];
}
if(!raw){
return [];
}
var parsed;
try {
parsed=JSON.parse(raw);
} catch (e){
return [];
}
if(!Array.isArray(parsed)){
return [];
}
var seen={};
var clean=[];
for (var i=0; i < parsed.length; i++){
var id=parseInt(parsed[i], 10);
if(!isFinite(id)||id <=0){
continue;
}
if(seen[id]){
continue;
}
seen[id]=true;
clean.push(id);
if(clean.length >=MAX_FAVORITES){
break;
}}
return clean;
}
function writeFavorites(ids){
try {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(ids));
} catch (e){
}
updateCountBadges(ids.length);
}
function hasFavorite(id){
id=parseInt(id, 10);
return readFavorites().indexOf(id)!==-1;
}
function toggleFavorite(id){
id=parseInt(id, 10);
if(!isFinite(id)||id <=0){
return false;
}
var ids=readFavorites();
var index=ids.indexOf(id);
var active;
if(index===-1){
if(ids.length >=MAX_FAVORITES){
ids.shift();
}
ids.push(id);
active=true;
}else{
ids.splice(index, 1);
active=false;
}
writeFavorites(ids);
return active;
}
function removeFavorite(id){
id=parseInt(id, 10);
var ids=readFavorites();
var index=ids.indexOf(id);
if(index!==-1){
ids.splice(index, 1);
writeFavorites(ids);
}
return ids;
}
function updateCountBadges(count){
var badges=document.querySelectorAll('[data-em-favorites-count]');
for (var i=0; i < badges.length; i++){
badges[i].textContent=String(count);
if(count > 0){
badges[i].removeAttribute('hidden');
}else if(badges[i].hasAttribute('data-hide-empty')){
badges[i].setAttribute('hidden', 'hidden');
}}
}
function syncToggleButton(button){
var id=parseInt(button.getAttribute('data-event-id'), 10);
var active=hasFavorite(id);
button.classList.toggle('is-active', active);
button.setAttribute('aria-pressed', active ? 'true':'false');
var label=button.querySelector('.em-favorite-toggle__label');
var text=active
? (strings.remove||'Salvato nei preferiti')
: (strings.add||'Aggiungi ai preferiti');
if(label){
label.textContent=text;
}
button.setAttribute('aria-label', text);
button.setAttribute('title', text);
}
function bindToggleButtons(){
var buttons=document.querySelectorAll('.em-favorite-toggle');
for (var i=0; i < buttons.length; i++){
(function (button){
syncToggleButton(button);
button.addEventListener('click', function (e){
e.preventDefault();
var id=parseInt(button.getAttribute('data-event-id'), 10);
if(!isFinite(id)||id <=0){
return;
}
toggleFavorite(id);
syncToggleButton(button);
button.classList.add('is-pulsing');
window.setTimeout(function (){
button.classList.remove('is-pulsing');
}, 320);
});
})(buttons[i]);
}}
function createEl(tag, className, text){
var el=document.createElement(tag);
if(className){
el.className=className;
}
if(text!==undefined&&text!==null&&text!==''){
el.textContent=text;
}
return el;
}
function safeUrl(url){
if(typeof url!=='string'||url===''){
return '';
}
if(/^https?:\/\//i.test(url)||url.charAt(0)==='/'){
return url;
}
return '';
}
function buildFavoriteCard(event, layout){
var cardLayout=(layout==='horizontal') ? 'horizontal':'grid';
var wrap=createEl('div', 'em-favorites-card');
var url=safeUrl(event.url);
var card=createEl('a', 'em-event-card em-event-card--' + cardLayout);
card.setAttribute('href', url||'#');
var media=createEl('div', 'em-event-card-media');
var imageUrl=safeUrl(event.image);
if(imageUrl){
var img=createEl('img');
img.setAttribute('src', imageUrl);
img.setAttribute('alt', event.title||'');
img.setAttribute('loading', 'lazy');
media.appendChild(img);
}else{
media.appendChild(createEl('div', 'em-event-card-placeholder'));
}
card.appendChild(media);
var body=createEl('div', 'em-event-card-body');
if(event.category&&event.category.name){
body.appendChild(createEl('span', 'em-event-card-category', event.category.name));
}
body.appendChild(createEl('h3', 'em-event-card-title', event.title||''));
var meta=createEl('div', 'em-event-card-meta');
meta.appendChild(createEl('span', 'em-event-card-kicker', strings.kicker||'Prossimo evento'));
if(event.date_label){
meta.appendChild(createEl('span', 'em-event-card-date', event.date_label));
}
if(event.location){
meta.appendChild(createEl('span', 'em-event-card-place', event.location));
}
body.appendChild(meta);
card.appendChild(body);
wrap.appendChild(card);
var remove=createEl('button', 'em-favorites-remove');
remove.setAttribute('type', 'button');
remove.setAttribute('data-event-id', String(event.id));
remove.setAttribute('aria-label', strings.remove||'Rimuovi dai preferiti');
remove.setAttribute('title', strings.remove||'Rimuovi dai preferiti');
remove.appendChild(createEl('span', 'em-favorites-remove__icon', '★'));
wrap.appendChild(remove);
return wrap;
}
function renderFavoritesPage(container){
var grid=container.querySelector('[data-role="grid"]');
var status=container.querySelector('[data-role="status"]');
var empty=container.querySelector('[data-role="empty"]');
var layout=(grid&&grid.getAttribute('data-layout')==='horizontal') ? 'horizontal':'grid';
function showEmpty(){
if(grid){ grid.innerHTML=''; }
if(status){ status.setAttribute('hidden', 'hidden'); }
if(empty){ empty.removeAttribute('hidden'); }}
function showStatus(text){
if(empty){ empty.setAttribute('hidden', 'hidden'); }
if(status){
status.textContent=text;
status.removeAttribute('hidden');
}}
var ids=readFavorites();
updateCountBadges(ids.length);
if(!ids.length){
showEmpty();
return;
}
showStatus(strings.loading||'Caricamento preferiti...');
fetchFavorites(ids, false)
.then(function (events){
renderCards(events, ids);
})
.catch(function (){
if(status){
showStatus(strings.error||'Impossibile caricare i preferiti.');
}});
function renderCards(events, requestedIds){
if(!grid){
return;
}
grid.innerHTML='';
var returnedIds={};
for (var i=0; i < events.length; i++){
returnedIds[parseInt(events[i].id, 10)]=true;
}
var stale=[];
for (var j=0; j < requestedIds.length; j++){
if(!returnedIds[requestedIds[j]]){
stale.push(requestedIds[j]);
}}
if(stale.length){
var cleaned=readFavorites().filter(function (id){
return stale.indexOf(id)===-1;
});
writeFavorites(cleaned);
}
if(!events.length){
showEmpty();
return;
}
if(status){ status.setAttribute('hidden', 'hidden'); }
if(empty){ empty.setAttribute('hidden', 'hidden'); }
for (var k=0; k < events.length; k++){
grid.appendChild(buildFavoriteCard(events[k], layout));
}}
if(grid&&!grid._emFavoritesBound){
grid._emFavoritesBound=true;
grid.addEventListener('click', function (e){
var btn=e.target.closest ? e.target.closest('.em-favorites-remove'):null;
if(!btn){
return;
}
e.preventDefault();
var id=parseInt(btn.getAttribute('data-event-id'), 10);
removeFavorite(id);
var cardWrap=btn.closest('.em-favorites-card');
if(cardWrap){
cardWrap.classList.add('is-removing');
window.setTimeout(function (){
if(cardWrap.parentNode){
cardWrap.parentNode.removeChild(cardWrap);
}
if(!readFavorites().length){
showEmpty();
}}, 220);
}});
}}
function fetchFavorites(ids, isRetry){
var body=new URLSearchParams();
body.append('action', 'em_favorites_events');
body.append('_nonce', config.nonce||'');
for (var i=0; i < ids.length; i++){
body.append('ids[]', String(ids[i]));
}
return fetch(config.ajaxUrl, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: body.toString()
}).then(function (response){
if(response.status===403&&!isRetry){
return refreshNonce().then(function (){
return fetchFavorites(ids, true);
});
}
if(!response.ok){
throw new Error('http_error');
}
return response.json().then(function (json){
if(!json||!json.success||!json.data||!Array.isArray(json.data.events)){
throw new Error('bad_response');
}
return json.data.events;
});
});
}
function refreshNonce(){
var body=new URLSearchParams();
body.append('action', 'em_event_list_nonce');
return fetch(config.ajaxUrl, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: body.toString()
}).then(function (response){
return response.json();
}).then(function (json){
if(json&&json.success&&json.data&&json.data.nonce){
config.nonce=json.data.nonce;
}});
}
function init(){
updateCountBadges(readFavorites().length);
bindToggleButtons();
var favPage=document.querySelector('[data-em-favorites]');
if(favPage){
renderFavoritesPage(favPage);
}}
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', init);
}else{
init();
}})();