// — Début du script JavaScript pour le tableau comparatif interactif —
// 1. Données pour le tableau
// Ces données sont fournies directement dans le script comme demandé.
// Si l’outil nécessitait des données externes, voici comment on pourrait les charger depuis une API publique gratuite (sans clé) :
/*
const API_URL = ‘https://api.example.com/grece-mai-data’;
// Exemple de structure JSON attendue de l’API :
// [
// {
// “Destination”: “Crète”,
// “Ambiance en Mai”: “Active, nature, histoire”,
// “Température Moyenne”: “20-25°C”,
// “Activité Phare”: “Randonnée gorges Samaria 🥾”,
// “Idéal pour”: “Aventuriers, familles, culture”
// },
// // … autres objets …
// ]
// Exemple d’appel d’API (non utilisé ici car les données sont intégrées) :
// fetch(API_URL)
// .then(response => response.json())
// .then(data => {
// destinationsData = data; // Assigner les données chargées
// renderTable(destinationsData); // Rendre le tableau avec les données de l’API
// })
// .catch(error => console.error(‘Erreur lors du chargement des données :’, error));
*/
const destinationsData = [
{
‘Destination’: ‘Crète’,
‘Ambiance en Mai’: ‘Active, nature, histoire’,
‘Température Moyenne’: ’20-25°C’,
‘Activité Phare’: ‘Randonnée gorges Samaria 🥾’,
‘Idéal pour’: ‘Aventuriers, familles, culture’
},
{
‘Destination’: ‘Rhodes’,
‘Ambiance en Mai’: ‘Médiévale, balnéaire’,
‘Température Moyenne’: ’22-26°C’,
‘Activité Phare’: ‘Exploration vieille ville 🏰’,
‘Idéal pour’: ‘Histoire, plages, détente’
},
{
‘Destination’: ‘Santorin’,
‘Ambiance en Mai’: ‘Romantique, paysages, luxe’,
‘Température Moyenne’: ’21-24°C’,
‘Activité Phare’: ‘Coucher de soleil à Oia 🌅’,
‘Idéal pour’: ‘Couples, photos, farniente’
},
{
‘Destination’: ‘Corfou’,
‘Ambiance en Mai’: ‘Verdoyante, plages, culture’,
‘Température Moyenne’: ’18-23°C’,
‘Activité Phare’: ‘Visite du Palais de l’Achilleion 🏛️’,
‘Idéal pour’: ‘Nature, familles, exploration’
},
{
‘Destination’: ‘Mykonos’,
‘Ambiance en Mai’: ‘Festive, plages, glamour’,
‘Température Moyenne’: ’20-25°C’,
‘Activité Phare’: ‘Soirée à Little Venice 🥂’,
‘Idéal pour’: ‘Fêtards, jeunes, luxe’
},
{
‘Destination’: ‘Athènes’,
‘Ambiance en Mai’: ‘Urbaine, historique, culturelle’,
‘Température Moyenne’: ’20-27°C’,
‘Activité Phare’: ‘Découverte de l’Acropole 🏺’,
‘Idéal pour’: ‘Culture, histoire, city-trip’
},
{
‘Destination’: ‘Zante (Zakynthos)’,
‘Ambiance en Mai’: ‘Naturelle, plages, grottes’,
‘Température Moyenne’: ’20-24°C’,
‘Activité Phare’: ‘Excursion à la Plage du Naufrage ⚓’,
‘Idéal pour’: ‘Nature, plages, couples’
}
];
// Variables pour stocker l’état actuel du tri (colonne et direction)
let currentSortColumn = ”;
let currentSortDirection = ‘asc’; // ‘asc’ pour croissant, ‘desc’ pour décroissant
// Récupération des éléments du DOM
const tableBody = document.getElementById(‘comparateurTableBody’);
const searchInput = document.getElementById(‘searchInput’);
// Sélectionne tous les en-têtes de colonnes qui ont l’attribut `data-sort-by`
const tableHeaders = document.querySelectorAll(‘#greceComparateur thead th[data-sort-by]’);
const resetFiltersButton = document.getElementById(‘resetFiltersButton’);
const noResultsMessage = document.getElementById(‘noResults’);
// 2. Fonction pour rendre le tableau avec les données fournies
function renderTable(dataToRender) {
tableBody.innerHTML = ”; // Nettoyer le contenu actuel du tableau
// Afficher/masquer le message “Aucun résultat”
if (dataToRender.length === 0) {
noResultsMessage.classList.remove(‘hidden’);
return;
}
noResultsMessage.classList.add(‘hidden’);
// Créer une ligne pour chaque élément de données
dataToRender.forEach(item => {
const row = document.createElement(‘tr’);
row.classList.add(‘hover:bg-gray-100’, ‘transition’, ‘duration-150’, ‘ease-in-out’); // Styles pour survol
// Parcourir les clés de chaque objet pour créer les cellules correspondantes
for (const key in item) {
const cell = document.createElement(‘td’);
cell.classList.add(‘px-6’, ‘py-4’, ‘whitespace-nowrap’, ‘text-gray-900’); // Styles de cellule
cell.textContent = item[key];
row.appendChild(cell);
}
tableBody.appendChild(row); // Ajouter la ligne au corps du tableau
});
}
// 3. Fonction pour filtrer les données en fonction du terme de recherche
function filterData(data, searchTerm) {
if (!searchTerm) {
return data; // Si le champ de recherche est vide, retourner toutes les données
}
const lowerCaseSearchTerm = searchTerm.toLowerCase();
return data.filter(item =>
// Vérifier si une des valeurs de l’objet inclut le terme de recherche
Object.values(item).some(value =>
String(value).toLowerCase().includes(lowerCaseSearchTerm)
)
);
}
// 4. Fonction pour trier les données en fonction d’une colonne et d’une direction
function sortData(data, column, direction) {
// Détecter si la colonne à trier est celle de la température
const isTemperatureColumn = column === ‘Température Moyenne’;
// Créer une copie du tableau pour ne pas modifier l’original
return […data].sort((a, b) => {
let valA = a[column];
let valB = b[column];
// Traitement spécifique pour la colonne “Température Moyenne” pour un tri numérique
if (isTemperatureColumn) {
const extractAvgTemp = (tempStr) => {
const match = tempStr.match(/(d+)-(d+)°C/); // Ex: “20-25°C”
if (match) {
return (parseInt(match[1]) + parseInt(match[2])) / 2; // Calculer la moyenne
}
return parseFloat(tempStr); // Si format simple “22°C” ou “22”
};
valA = extractAvgTemp(String(valA));
valB = extractAvgTemp(String(valB));
} else {
// Pour les autres colonnes, convertir en chaîne et normaliser pour gérer les accents
valA = String(valA).normalize(“NFD”).replace(/[u0300-u036f]/g, “”);
valB = String(valB).normalize(“NFD”).replace(/[u0300-u036f]/g, “”);
}
// Comparaison des valeurs
if (valA valB) {
return direction === ‘asc’ ? 1 : -1;
}
return 0; // Si les valeurs sont égales, leur ordre relatif ne change pas
});
}
// 5. Gestionnaire d’événements pour la recherche (input)
searchInput.addEventListener(‘input’, () => {
const searchTerm = searchInput.value;
let filteredData = filterData(destinationsData, searchTerm); // Filtrer les données originales
// Si une colonne est actuellement triée, appliquer ce tri aux données filtrées
if (currentSortColumn) {
filteredData = sortData(filteredData, currentSortColumn, currentSortDirection);
}
renderTable(filteredData); // Afficher le tableau avec les données filtrées et/ou triées
});
// 6. Gestionnaire d’événements pour le tri des colonnes (clic sur l’en-tête)
tableHeaders.forEach(header => {
header.addEventListener(‘click’, () => {
const column = header.dataset.sortBy; // Récupérer le nom de la colonne à trier
let direction = ‘asc’;
// Si l’en-tête cliqué est celui déjà trié, inverser la direction de tri
if (currentSortColumn === column) {
direction = currentSortDirection === ‘asc’ ? ‘desc’ : ‘asc’;
}
// Mettre à jour l’état global du tri
currentSortColumn = column;
currentSortDirection = direction;
// Mettre à jour les icônes de tri dans les en-têtes
tableHeaders.forEach(h => {
const icon = h.querySelector(‘.sort-icon’);
h.removeAttribute(‘aria-sort’); // Réinitialiser l’attribut ARIA pour tous
if (h === header) {
// Mettre à jour l’icône et l’attribut ARIA pour l’en-tête actuellement trié
if (direction === ‘asc’) {
icon.innerHTML = ‘ ▲’; // Flèche vers le haut pour ASC
h.setAttribute(‘aria-sort’, ‘ascending’);
} else {
icon.innerHTML = ‘ ▼’; // Flèche vers le bas pour DESC
h.setAttribute(‘aria-sort’, ‘descending’);
}
} else {
icon.innerHTML = ”; // Retirer les icônes des autres en-têtes
}
});
// Appliquer le filtre (si présent) puis le tri sur les données
let dataToDisplay = filterData(destinationsData, searchInput.value);
dataToDisplay = sortData(dataToDisplay, currentSortColumn, currentSortDirection);
renderTable(dataToDisplay); // Afficher les données triées
});
});
// 7. Gestionnaire d’événements pour le bouton de réinitialisation
resetFiltersButton.addEventListener(‘click’, () => {
searchInput.value = ”; // Vider le champ de recherche
currentSortColumn = ”; // Réinitialiser la colonne de tri
currentSortDirection = ‘asc’; // Réinitialiser la direction par défaut
// Réinitialiser toutes les icônes de tri et attributs aria-sort des en-têtes
tableHeaders.forEach(h => {
h.querySelector(‘.sort-icon’).innerHTML = ”;
h.removeAttribute(‘aria-sort’);
});
// Rendre le tableau avec les données originales, sans filtre ni tri
renderTable(destinationsData);
});
// 8. Initialisation : Rendre le tableau au chargement du DOM
// L’événement `DOMContentLoaded` assure que le HTML est entièrement chargé avant d’exécuter le script
document.addEventListener(‘DOMContentLoaded’, () => {
renderTable(destinationsData);
});
// — Fin du script JavaScript —
{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”Pourquoi le mois de mai est-il idu00e9al pour visiter la Gru00e8ce ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Le mois de mai offre un u00e9quilibre parfait entre des tempu00e9ratures agru00e9ables (environ 20-26u00b0C), un faible niveau d’affluence touristique et une nature verdoyante, rendant l’exploration des sites historiques et la du00e9tente sur les plages particuliu00e8rement plaisantes. Les journu00e9es sont longues et ensoleillu00e9es, idu00e9ales pour toutes les activitu00e9s de plein air.”}},{“@type”:”Question”,”name”:”Quels sont les incontournables u00e0 visiter en Gru00e8ce en mai ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Les incontournables incluent l’Acropole u00e0 Athu00e8nes, les villages d’Oia et Fira u00e0 Santorin, les moulins de Mykonos, le Palais de Knossos en Cru00e8te, la vieille ville de Rhodes et les ruines de Mycu00e8nes dans le Pu00e9loponnu00e8se. Chaque destination offre une expu00e9rience unique, entre histoire, culture et paysages magnifiques.”}},{“@type”:”Question”,”name”:”Faut-il ru00e9server les hu00e9bergements et transports u00e0 l’avance pour un voyage en mai ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Oui, mu00eame si l’affluence est moindre qu’en plein u00e9tu00e9, il est fortement conseillu00e9 de ru00e9server vos hu00e9bergements et vos billets de ferry ou de vol intu00e9rieur u00e0 l’avance, surtout si vous visez des destinations populaires ou des u00e9tablissements spu00e9cifiques. Cela garantit les meilleurs choix et des tarifs plus avantageux.”}},{“@type”:”Question”,”name”:”Quelles activitu00e9s sont recommandu00e9es en Gru00e8ce en mai ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”En mai, il est recommandu00e9 de faire des visites de sites archu00e9ologiques et de musu00e9es, des randonnu00e9es dans la nature (comme les gorges de Samaria), des baignades et des sports nautiques (l’eau est du00e9ju00e0 agru00e9able), des excursions en bateau entre les u00eeles et de savourer la gastronomie locale dans les tavernes.”}}]}