From 684c1397b0c6ba894f6989e885c806503bedd78a Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Wed, 29 Jan 2025 18:51:31 +0100 Subject: [PATCH 01/32] =?UTF-8?q?D=C3=A9finition=20Wiktionnaire?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.js | 152 +++++++++++++------ background/background.js | 42 ++++-- background/browser_context_menu.js | 2 +- "barre_lat\303\251rale/sidebar.html" | 10 +- "barre_lat\303\251rale/sidebar.js" | 198 ++++++++++++++++++++++-- manifest.json | 2 +- menu_contextuel/custom_context_menu.js | 201 ++++++++++--------------- 7 files changed, 422 insertions(+), 185 deletions(-) diff --git a/api.js b/api.js index ded9972..d7da84a 100644 --- a/api.js +++ b/api.js @@ -1,6 +1,25 @@ console.log("api.js chargé correctement"); -// Fonction pour récupérer les lexiques (personnels) de l'utilisateur +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Sélection de texte sur la page +// ───────────────────────────────────────────────────────────────────────────── +document.addEventListener("mouseup", () => { + const selectedText = window.getSelection().toString().trim(); + if (selectedText) { + browser.runtime.sendMessage({ + action: "mot_selectionne", + selectedText + }); + } +}); + +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Fonctions d’appel à l’API Babalex +// ───────────────────────────────────────────────────────────────────────────── + +/** + * Récupère les lexiques personnels de l'utilisateur. + */ async function getUserLexicons(authToken) { const lexiconsApiUrl = 'https://babalex.lezinter.net/api/user/lexicons'; try { @@ -13,7 +32,9 @@ async function getUserLexicons(authToken) { }); if (!response.ok) { - throw new Error(`Erreur lors de la récupération des lexiques : ${response.statusText}`); + throw new Error( + `Erreur lors de la récupération des lexiques : ${response.status} ${response.statusText}` + ); } return await response.json(); @@ -23,9 +44,12 @@ async function getUserLexicons(authToken) { } } -// Fonction pour récupérer les lexiques de l'utilisateur (ici utilisateur test) +/** + * Récupère les lexiques de l'utilisateur + */ async function getLexicons(authToken, userId = 52, language = 'fr') { - const lexiconsApiUrl = `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=${language}`; + const lexiconsApiUrl = + `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=${language}`; try { const response = await fetch(lexiconsApiUrl, { method: 'GET', @@ -36,8 +60,11 @@ async function getLexicons(authToken, userId = 52, language = 'fr') { }); if (!response.ok) { - throw new Error(`Erreur lors de la récupération des lexiques : ${response.statusText}`); + throw new Error( + `Erreur lors de la récupération des lexiques : ${response.status} ${response.statusText}` + ); } + return await response.json(); } catch (error) { console.error('Erreur lors de la récupération des lexiques :', error); @@ -45,8 +72,9 @@ async function getLexicons(authToken, userId = 52, language = 'fr') { } } - -// Fonction pour récupérer les entrées d'un lexique donné (simple liste des mots) +/** + * Récupère la liste des mots d'un lexique. + */ async function getLexiconEntries(authToken, idLexicon) { const entriesApiUrl = `https://babalex.lezinter.net/api/lexicon/extract/0?lexiconId=${idLexicon}`; @@ -60,13 +88,15 @@ async function getLexiconEntries(authToken, idLexicon) { }); if (!response.ok) { - throw new Error(`Erreur lors de la récupération des entrées du lexique : ${response.statusText}`); + throw new Error( + `Erreur lors de la récupération des entrées du lexique : ${response.status} ${response.statusText}` + ); } const data = await response.json(); if (Array.isArray(data)) { console.log(`Entrées récupérées pour le lexique ID ${idLexicon} :`, data); - return data; // Retourne un tableau de mots ex. ["raquette", "chat", "science"] + return data; } else { console.warn('Le format des données retournées est inattendu.', data); return []; @@ -77,8 +107,9 @@ async function getLexiconEntries(authToken, idLexicon) { } } - -// Fonction pour récupérer les graphies et leurs ID +/** + * Récupère la liste des entrées (graphies + ID) d'un lexique donné. + */ async function getLexiconEntriesID(authToken, idLexicon) { const entriesApiUrl = `https://babalex.lezinter.net/api/lexicon/entries/${idLexicon}`; @@ -92,18 +123,21 @@ async function getLexiconEntriesID(authToken, idLexicon) { }); if (!response.ok) { - throw new Error(`Erreur lors de la récupération des graphies : ${response.statusText}`); + throw new Error( + `Erreur lors de la récupération des graphies : ${response.status} ${response.statusText}` + ); } - return await response.json(); + return await response.json(); } catch (error) { console.error('Erreur lors de la récupération des graphies :', error); throw error; } } - -// Fonction pour obtenir les informations d'un mot par la graphie (dans quels lexiques utilisateur ou de groupe la graphie est présente) +/** + * Récupère les infos d'un mot par sa graphie (quels lexiques contiennent ce mot). + */ async function getGraphyInfo(authToken, word) { const definitionApiUrl = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=3&target_lex=4`; @@ -117,7 +151,9 @@ async function getGraphyInfo(authToken, word) { }); if (!response.ok) { - throw new Error(`Erreur lors de la récupération de la définition : ${response.statusText}`); + throw new Error( + `Erreur lors de la récupération de la définition : ${response.status} ${response.statusText}` + ); } return await response.json(); @@ -127,8 +163,9 @@ async function getGraphyInfo(authToken, word) { } } - -// Fonction pour obtenir les informations sur un mot par son ID +/** + * Récupère toutes les informations sur un mot (via son ID) depuis l’API. + */ async function getDefinition(authToken, entryId) { const entryInfoApiUrl = `https://babalex.lezinter.net/api/entry/get/${entryId}`; @@ -142,7 +179,9 @@ async function getDefinition(authToken, entryId) { }); if (!response.ok) { - throw new Error(`Erreur lors de la récupération des informations sur l'entrée : ${response.statusText}`); + throw new Error( + `Erreur lors de la récupération des informations sur l'entrée : ${response.status} ${response.statusText}` + ); } const data = await response.json(); @@ -154,42 +193,71 @@ async function getDefinition(authToken, entryId) { } } - -// Fonction pour obtenir une définition depuis le Wiktionnaire -async function getWiktionaryDefinition(authToken, word) { - // Construire l'URL de l'API avec le mot sélectionné - const wiktionaryApiUrl = `https://babalex.lezinter.net/api/wiktionary/search?graphy=${encodeURIComponent(word)}&language=fr`; - +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Récupération au Wiktionnaire : https://fr.wiktionary.org +// ───────────────────────────────────────────────────────────────────────────── + +/** + * Récupère la définition d’un mot depuis le Wiktionnaire (fr) **directement**. + * + * @param {string} word - Le mot à définir + * @returns {Promise<string[]>} Tableau de définitions (chaînes) + */ +async function getWiktionaryDefinition(word) { try { - const response = await fetch(wiktionaryApiUrl, { - method: 'GET', - headers: { - Authorization: `Bearer ${authToken}`, - 'Content-Type': 'application/json', - }, - }); + console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); + if (!word || word.trim() === "") { + throw new Error("Mot vide, impossible d'envoyer la requête."); + } + // Le paramètre "origin=*" est requis pour les appels cross-domain + // "prop=extracts & exintro=true" renvoie seulement le début de l’article + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&exintro=true&titles=${encodeURIComponent(word)}`; + + const response = await fetch(wiktionaryURL); if (!response.ok) { - throw new Error(`Erreur lors de la récupération de la définition depuis le Wiktionnaire : ${response.statusText}`); + throw new Error(`Erreur API Wiktionnaire: ${response.statusText}`); } - const data = await response.json(); - console.log(`Résultats du Wiktionnaire pour le mot "${word}" :`, data); - return data; - } catch (error) { - console.error('Erreur lors de la récupération de la définition depuis le Wiktionnaire :', error); - throw error; - } -} + console.log("📖 Réponse API (Wiktionnaire) :", data); + const pages = data.query.pages; + // pages est un objet dont la clé est l'ID de la page => on récupère la première + const page = Object.values(pages)[0]; + if (!page || !page.extract) { + console.warn("âš ï¸ Aucune définition trouvée sur le Wiktionnaire."); + return ["âš ï¸ Aucune définition trouvée sur le Wiktionnaire."]; + } + // page.extract contient du HTML : on le parse pour en extraire du texte brut + const parser = new DOMParser(); + const doc = parser.parseFromString(page.extract, "text/html"); + const cleanText = doc.body.textContent.trim(); -// METTRE LES FONCTIONS GLOBALES + console.log("✅ Définition extraite :", cleanText); + + // Tu peux renvoyer un tableau avec 1 seule définition + return [cleanText]; + } catch (error) { + console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); + // On renvoie un tableau contenant un message d'erreur + return [`âš ï¸ Erreur : ${error.message}`]; + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Mise à disposition globale de nos fonctions +// ───────────────────────────────────────────────────────────────────────────── window.getUserLexicons = getUserLexicons; +window.getLexicons = getLexicons; window.getLexiconEntries = getLexiconEntries; window.getLexiconEntriesID = getLexiconEntriesID; window.getGraphyInfo = getGraphyInfo; window.getDefinition = getDefinition; + +// Utilisons la version directe pour Wiktionnaire window.getWiktionaryDefinition = getWiktionaryDefinition; + +console.log("api.js : toutes les fonctions sont prêtes !"); \ No newline at end of file diff --git a/background/background.js b/background/background.js index 65b528a..10ac502 100644 --- a/background/background.js +++ b/background/background.js @@ -124,16 +124,20 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { switch (message.action) { // --- Authentification --- - case "toggleAuth": { - console.log("Action toggleAuth reçue"); + case "toggleAuth": const isConnected = await isUserConnected(); - if (isConnected) { - await disconnectFromLexicalDB(); + isConnected ? await disconnectFromLexicalDB() : await openLoginPage(); + break; + case "getDefinitionWiki": + if (message.selectedText && message.selectedText.trim() !== "") { + console.log("📤 Envoi de la requête au Wiktionnaire pour :", message.selectedText); + browser.runtime.sendMessage({ + action: "fetchWiktionaryDefinition", + selectedText: message.selectedText.trim(), + }); } else { - await openLoginPage(); + console.warn("âš ï¸ Texte sélectionné vide. Annulation de la requête."); } - break; - } case "checkAuthStatus": { const connected = await isUserConnected(); @@ -157,9 +161,6 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { break; } - // (Optionnel) Si d’autres messages… - // ex: "toggleLexiconHighlight", etc. - default: break; } @@ -364,3 +365,24 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { function showNotification(title, message, iconPath) { console.log(`🔔 NOTIFICATION: [${title}] ${message}`); } + +browser.contextMenus.onClicked.addListener(async (info, tab) => { + if (info.menuItemId === "getDefinition") { + browser.tabs.sendMessage(tab.id, { + action: "mot_selectionne", + selectedText: info.selectionText, + }); + } +}); + +browser.notifications.create({ + type: "basic", + iconUrl: browser.runtime.getURL("icons/notification.png"), + title: "Définition trouvée", + message: `🌠Définition trouvée pour "${selectedText}". Consultez le Wiktionnaire.`, +}); + +browser.runtime.sendMessage({ + action: "showDefinitionNotification", + selectedText: selectedText +}); \ No newline at end of file diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index d562cab..f5d6285 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -206,7 +206,7 @@ async function getDefinitionWiki(selectedText) { try { const result = await fetch(`https://fr.wiktionary.org/wiki/${encodeURIComponent(selectedText)}`); if (result.ok) { - alert(`🌠Définition trouvée pour "${selectedText}". Consultez le Wiktionnaire.`); + console.log(`🌠Définition trouvée pour "${selectedText}". Consultez le Wiktionnaire.`); } else { alert(`⌠Aucune définition trouvée sur le Wiktionnaire pour "${selectedText}".`); } diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 55e12d5..cc40401 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -4,7 +4,7 @@ <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BaLex - Barre Latérale</title> - <script src="sidebar.js"></script> + <script src="sidebar.js" defer></script> <style> /* Style global */ body { @@ -155,7 +155,13 @@ </div> <!-- Définition affichée --> - <div id="definition"></div> + <div id="definitionContainer"> + <h3>Définitions</h3> + <ul id="definitionsList"></ul> + </div> + <div id="notificationContainer" style="display: none; padding: 10px; background: #ffeb3b; color: #000; border-radius: 5px;"> + </div> + </body> </html> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 947a854..a650668 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -1,5 +1,6 @@ // ✅ Chargement du script de la barre latérale -console.log("✅ sidebar.js chargé avec succès !"); +console.log("✅ sidebar.js chargé !"); +console.log("🌠Vérification API browser :", typeof browser !== "undefined" ? "✅ Disponible" : "⌠Non disponible"); // Variable globale pour le token d'authentification let authToken = null; @@ -9,6 +10,10 @@ window.addEventListener('error', (e) => { console.error("â—ï¸ Erreur globale détectée :", e.message, "dans", e.filename, ":", e.lineno); }); +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Fonctions utilitaires liées au token +// ───────────────────────────────────────────────────────────────────────────── + // Fonction pour valider le format du token (JWT par exemple) function validateToken(token) { const isValid = /^\S+\.\S+\.\S+$/.test(token); @@ -35,7 +40,10 @@ async function getAuthTokenFromStorage() { return null; } -// Met à jour le bouton de connexion/déconnexion +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Fonctions de mise à jour de l'UI de la barre latérale +// ───────────────────────────────────────────────────────────────────────────── + function updateAuthButton(isLoggedIn) { const authButton = document.getElementById("auth-button"); if (authButton) { @@ -46,7 +54,6 @@ function updateAuthButton(isLoggedIn) { } } -// Affiche/masque certains éléments quand l'utilisateur est connecté/déconnecté function toggleElementsVisibility(isLoggedIn) { const elementsToShowOrHide = [ { id: 'add-to-lexiques', shouldShow: isLoggedIn }, @@ -64,7 +71,6 @@ function toggleElementsVisibility(isLoggedIn) { }); } -// Affiche/masque un message de surlignage function toggleHighlightMessage(isLoggedIn) { const highlightNote = document.getElementById('highlight-note'); if (highlightNote) { @@ -96,6 +102,10 @@ async function refreshSidebarState() { console.log("✅ Barre latérale actualisée. Utilisateur connecté :", isLoggedIn); } +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Lexiques +// ───────────────────────────────────────────────────────────────────────────── + // Affiche les lexiques (checkbox + icône) function displayLexicons(lexicons) { const lexiquesContainer = document.getElementById('lexiques'); @@ -163,7 +173,7 @@ async function fetchLexicons() { throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); } - // Appel à l'API + // Appel à l'API (exemple) const lexicons = await getLexicons(authToken, 52, 'fr'); // À adapter console.log("📚 Réponse brute de l'API :", lexicons); @@ -198,20 +208,154 @@ async function fetchLexicons() { } } -// Gestion du clic sur le bouton de connexion/déconnexion +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Bouton de connexion/déconnexion +// ───────────────────────────────────────────────────────────────────────────── + async function handleAuthButtonClick() { await browser.runtime.sendMessage({ action: "toggleAuth" }); await refreshSidebarState(); } -// Écoute des messages envoyés par d'autres parties de l'extension +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Gestion des définitions : lexiques + Wiktionnaire +// ───────────────────────────────────────────────────────────────────────────── + +/** + * Récupère les définitions d'un mot dans nos lexiques + * (utilise notre API protégée par token). + */ +async function fetchLexiconDefinitions(word) { + try { + console.log(`🔠Recherche des définitions de '${word}' dans les lexiques...`); + + if (!authToken) { + throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); + } + + // Appel à l'API pour récupérer les définitions du mot sélectionné + const response = await fetch( + `https://prisms.lezinter.net/api/definitions?word=${encodeURIComponent(word)}`, + { headers: { Authorization: `Bearer ${authToken}` } } + ); + + if (!response.ok) { + throw new Error(`⌠Erreur API: ${response.statusText}`); + } + + const data = await response.json(); + console.log("📚 Réponse API (lexiques) :", data); + + // Vérification des résultats + if (!data.definitions || data.definitions.length === 0) { + throw new Error("âš ï¸ Aucune définition trouvée dans les lexiques."); + } + + return data.definitions; + } catch (error) { + console.error("⌠Erreur lors de la récupération des définitions des lexiques :", error); + return []; + } +} + +/** + * Récupère la définition d'un mot depuis le Wiktionnaire (fr). + */ +async function fetchWiktionaryDefinition(word) { + try { + console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); + + if (!word || word.trim() === "") { + throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); + } + + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&exintro=true&titles=${encodeURIComponent(word)}`; + + const response = await fetch(wiktionaryURL); + if (!response.ok) { + throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + } + + const data = await response.json(); + console.log("📖 Réponse API (Wiktionnaire) :", data); + + const pages = data.query.pages; + const page = Object.values(pages)[0]; + + if (!page || !page.extract) { + throw new Error("âš ï¸ Aucune définition trouvée sur le Wiktionnaire."); + } + + // Extraction et nettoyage de la définition + const parser = new DOMParser(); + const doc = parser.parseFromString(page.extract, "text/html"); + const cleanText = doc.body.textContent.trim(); + + console.log("✅ Définition extraite :", cleanText); + return [cleanText]; + } catch (error) { + console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); + return ["âš ï¸ Aucune définition disponible."]; + } +} + +/** + * Fonction principale pour afficher les définitions + * (cumul lexiques + Wiktionnaire) + */ +async function showDefinitions(word) { + console.log(`📖 Recherche des définitions pour '${word}'...`); + + const lexiconDefinitions = await fetchLexiconDefinitions(word); + const wiktionaryDefinitions = await fetchWiktionaryDefinition(word); + + // Fusion des résultats et affichage + const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; + displayDefinitions(allDefinitions); +} + +/** + * Affiche la liste des définitions dans la barre latérale. + */ +function displayDefinitions(definitions) { + const definitionsList = document.getElementById("definitionsList"); + if (!definitionsList) { + console.warn("âš ï¸ Ã‰lément #definitionsList introuvable."); + return; + } + + console.log("📖 Affichage des définitions dans la barre latérale :", definitions); + + definitionsList.innerHTML = ""; + + if (!definitions || definitions.length === 0) { + definitionsList.innerHTML = "<li>Aucune définition trouvée.</li>"; + return; + } + + definitions.forEach((definition) => { + const listItem = document.createElement("li"); + listItem.textContent = definition; + definitionsList.appendChild(listItem); + }); + + console.log("✅ Définitions affichées avec succès !"); +} + +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Gestion des messages envoyés par d'autres parties de l'extension +// ───────────────────────────────────────────────────────────────────────────── + browser.runtime.onMessage.addListener((message) => { console.log("📩 Message reçu dans sidebar.js :", message); + // Rafraîchit la barre latérale (bouton "Se connecter"/"Se déconnecter" etc.) if (message.action === "refreshUI") { console.log("🔄 Rafraîchissement de la barre latérale demandé."); refreshSidebarState(); - } else if (message.action === "mot_selectionne" && message.selectedText) { + } + // Met à jour le mot sélectionné dans l'UI + else if (message.action === "mot_selectionne" && message.selectedText) { console.log("ðŸ–‹ï¸ Mise à jour du mot sélectionné :", message.selectedText); const selectedWordElement = document.getElementById("motSelectionne"); @@ -221,15 +365,51 @@ browser.runtime.onMessage.addListener((message) => { console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); } } + // Quand on demande les définitions pour un mot + else if (message.action === "getDefinition" && message.selectedText) { + console.log("📖 Recherche et affichage des définitions pour :", message.selectedText); + showDefinitions(message.selectedText); + } + // Récupération des définitions Wiktionnaire + else if (message.action === "fetchWiktionaryDefinition" && message.selectedText) { + console.log("🔠Récupération de la définition du Wiktionnaire pour :", message.selectedText); + + fetchWiktionaryDefinition(message.selectedText).then((definitions) => { + console.log("📖 Définitions récupérées :", definitions); + displayDefinitions(definitions); + }); + } + // Affichage d'une notification quand une définition est trouvée + else if (message.action === "showDefinitionNotification") { + console.log(`📢 Définition trouvée pour "${message.selectedText}".`); + + const notificationContainer = document.getElementById("notificationContainer"); + if (notificationContainer) { + notificationContainer.textContent = `🌠Définition trouvée pour "${message.selectedText}". Consultez le Wiktionnaire.`; + notificationContainer.style.display = "block"; + } + } }); -// Initialisation de la barre latérale après chargement du DOM +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Initialisation après chargement du DOM +// ───────────────────────────────────────────────────────────────────────────── + document.addEventListener('DOMContentLoaded', async () => { console.log("📦 DOM entièrement chargé. Initialisation de la sidebar."); + + // Rafraîchit l'UI (bouton, etc.) await refreshSidebarState(); + // Gère le clic sur le bouton de connexion/déconnexion const authButton = document.getElementById("auth-button"); if (authButton) { authButton.addEventListener("click", handleAuthButtonClick); } }); + + +console.log( + "🔠Vérification de l'élément #definitionsList :", + document.getElementById("definitionsList") +); diff --git a/manifest.json b/manifest.json index 012ee57..581db69 100644 --- a/manifest.json +++ b/manifest.json @@ -39,7 +39,7 @@ "default_title": "BaLex", "default_panel": "barre_latérale/sidebar.html", "default_icon": { - "16": "icons/icon-16.png", + "16": "icons/logo.png", "48": "icons/icon-48.png" } }, diff --git a/menu_contextuel/custom_context_menu.js b/menu_contextuel/custom_context_menu.js index 4c1da22..ee6b200 100644 --- a/menu_contextuel/custom_context_menu.js +++ b/menu_contextuel/custom_context_menu.js @@ -22,7 +22,7 @@ function injectWhiteBox() { const whiteBox = document.createElement("div"); whiteBox.id = WHITE_BOX_ID; - // Exemple pour générer toutes les URLs + // Exemples pour générer les URLs des icônes const addLexiconPath = browser.runtime.getURL("icons/ajout_lexique.png"); const getDefinitionPath = browser.runtime.getURL("icons/definition.png"); const getDefinitionWikiPath = browser.runtime.getURL("icons/definition_wiktionnaire.png"); @@ -30,17 +30,17 @@ function injectWhiteBox() { // Construction du HTML whiteBox.innerHTML = ` - <p id="selectedWord">Mot sélectionné : Aucun</p> - <hr style="border: 0; height: 1px; background-color: #323046; margin: 8px 0;"> - <div style="display: flex; flex-wrap: wrap; justify-content: center;"> + <p id="selectedWord" style="margin: 0; padding: 0;">Mot sélectionné : Aucun</p> + <hr style="border: 0; height: 1px; background-color: #323046; margin: 8px 0;"> + <div style="display: flex; flex-wrap: wrap; justify-content: center;"> - <!-- Bouton 1 - Ajout lexique --> - <div class="icon-container" title="Ajoutez ce mot à votre lexique"> + <!-- Bouton 1 - Ajouter au lexique --> + <div class="icon-container" title="Ajouter ce mot à votre lexique"> <img src="${addLexiconPath}" alt="Ajouter au lexique" class="icon" id="addLexiconButton"> </div> - <!-- Bouton 2 - Définition interne --> - <div class="icon-container" title="Obtenez la définition de ce mot"> + <!-- Bouton 2 - Définition interne (Babalex) --> + <div class="icon-container" title="Obtenir la définition (Babalex)"> <img src="${getDefinitionPath}" alt="Obtenir la définition" class="icon" id="getDefinitionButton"> </div> @@ -57,8 +57,6 @@ function injectWhiteBox() { `; document.body.appendChild(whiteBox); - - // Configure les actions de chaque bouton setupWhiteBoxActions(); } else { console.log(`#${WHITE_BOX_ID} déjà présent dans le DOM.`); @@ -72,10 +70,12 @@ function setupWhiteBoxActions() { const getDefinitionWikiBtn = document.getElementById("getDefinitionWikiButton"); const loginBtn = document.getElementById("loginButton"); - // Ajout au lexique + // Ajouter le mot au lexique perso addLexiconBtn.onclick = async () => { const selectedText = getSelectedWord(); console.log("🔠Ajout au lexique :", selectedText); + if (!selectedText) return; // rien à faire si vide + if (authToken) { await searchLexicon(selectedText); } else { @@ -83,12 +83,20 @@ function setupWhiteBoxActions() { } }; - // Obtenir la définition + // Obtenir une définition depuis Babalex getDefinitionBtn.onclick = async () => { const selectedText = getSelectedWord(); - console.log("📖 Recherche des définitions :", selectedText); + console.log("📖 Recherche des définitions (Babalex) :", selectedText); + if (!selectedText) return; + if (authToken) { - await getDefinition(selectedText); + // ICI, on envoie le mot à la barre latérale (ou background) + // pour qu'il affiche la définition. + // Ex: "getDefinition" = action gérée dans sidebar.js + browser.runtime.sendMessage({ + action: "getDefinition", + selectedText + }); } else { alert("âš ï¸ Veuillez vous connecter pour utiliser cette fonction."); } @@ -98,10 +106,17 @@ function setupWhiteBoxActions() { getDefinitionWikiBtn.onclick = () => { const selectedText = getSelectedWord(); console.log("🌠Recherche sur le Wiktionnaire :", selectedText); - alert(`Recherche sur le Wiktionnaire pour "${selectedText}".`); + if (!selectedText) return; + + // On envoie un message pour que la barre latérale (ou background) + // récupère la définition Wiktionnaire et l'affiche + browser.runtime.sendMessage({ + action: "fetchWiktionaryDefinition", + selectedText + }); }; - // Login + // Login / Toggle Auth loginBtn.onclick = () => { alert("Vous allez être redirigé(e) vers la page de connexion."); browser.runtime.sendMessage({ action: "toggleAuth" }); @@ -110,8 +125,7 @@ function setupWhiteBoxActions() { // Met à jour la visibilité des boutons en fonction de l'état de connexion function updateMenuVisibility() { - // S'assurer que la whiteBox est injectée - injectWhiteBox(); + injectWhiteBox(); // s'assurer que la whiteBox est injectée const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); @@ -124,13 +138,13 @@ function updateMenuVisibility() { } if (authToken) { - // Utilisateur connecté + // Utilisateur connecté => tout sauf login addLexiconBtn.style.display = "inline-block"; getDefinitionBtn.style.display = "inline-block"; getDefinitionWikiBtn.style.display = "inline-block"; loginBtn.style.display = "none"; } else { - // Utilisateur déconnecté + // Utilisateur déconnecté => seul Wiktionnaire + login addLexiconBtn.style.display = "none"; getDefinitionBtn.style.display = "none"; getDefinitionWikiBtn.style.display = "inline-block"; @@ -138,16 +152,24 @@ function updateMenuVisibility() { } } -// Récupère le mot affiché dans #selectedWord. +/** + * Récupère le mot affiché dans #selectedWord. + * On suppose maintenant que le contenu est "Mot sélectionné : XXX". + */ function getSelectedWord() { const selectedWordElement = document.getElementById("selectedWord"); - if (!selectedWordElement) { - return ""; + if (!selectedWordElement) return ""; + + // Si le texte est "Mot sélectionné : XXX" on récupère la partie après la " : " + const text = selectedWordElement.textContent || ""; + const prefix = "Mot sélectionné : "; + if (text.startsWith(prefix)) { + return text.slice(prefix.length).trim(); } - return selectedWordElement.textContent.split(": ")[1] || ""; + return ""; } -// Affiche le menu contextuel (whiteBox) à la position du clic en mettant à jour le mot sélectionné. +// Affiche le menu contextuel (whiteBox) à la position du clic function showWhiteBox(event, selectedText) { const whiteBox = document.getElementById(WHITE_BOX_ID); if (!whiteBox) { @@ -155,28 +177,28 @@ function showWhiteBox(event, selectedText) { return; } - if (selectedText) { - // Met à jour l'affichage du mot sélectionné - const selectedWordElement = document.getElementById("selectedWord"); - selectedWordElement.textContent = `${selectedText}`; - - // Récupère la position de la sélection - const selection = window.getSelection(); - const range = selection.getRangeAt(0); - const rect = range.getBoundingClientRect(); // Obtenez la position et taille du mot sélectionné - - // Calcule la position du menu en bas à droite du mot sélectionné - const top = rect.bottom + window.scrollY; // Bas du mot + défilement vertical - const left = rect.right + window.scrollX; // Droite du mot + défilement horizontal - - // Positionne la whiteBox - whiteBox.style.left = `${left}px`; - whiteBox.style.top = `${top}px`; - whiteBox.style.display = "block";nsole.log("Affichage du menu contextuel avec le mot :", selectedText); - - // Mettre à jour la visibilité des boutons - updateMenuVisibility(); - } + // Met à jour l'affichage du mot sélectionné => "Mot sélectionné : XXX" + const selectedWordElement = document.getElementById("selectedWord"); + selectedWordElement.textContent = `Mot sélectionné : ${selectedText}`; + + // Récupère la position de la sélection + const selection = window.getSelection(); + const range = selection.getRangeAt(0); + const rect = range.getBoundingClientRect(); // position/taille du mot sélectionné + + // Calcule la position du menu en bas à droite du mot sélectionné + const top = rect.bottom + window.scrollY; + const left = rect.right + window.scrollX; + + // Positionne la whiteBox et l'affiche + whiteBox.style.left = `${left}px`; + whiteBox.style.top = `${top}px`; + whiteBox.style.display = "block"; + + console.log("Affichage du menu contextuel avec le mot :", selectedText); + + // Mettre à jour la visibilité des boutons + updateMenuVisibility(); } // Masque la whiteBox. @@ -195,7 +217,7 @@ document.addEventListener("mouseup", (event) => { injectWhiteBox(); showWhiteBox(event, selectedText); - // Envoie le mot sélectionné à la barre latérale + // Envoie aussi le mot sélectionné à la barre latérale (ou background) browser.runtime.sendMessage({ action: "mot_selectionne", selectedText, @@ -206,7 +228,7 @@ document.addEventListener("mouseup", (event) => { } }); -// Réécouter les messages envoyés par le background script +// Réécouter les messages envoyés par le background script ou la barre latérale browser.runtime.onMessage.addListener((message) => { if (message.action === "refreshUI") { console.log("🔄 Mise à jour du menu contextuel personnalisé (double-clic/sélection)."); @@ -223,11 +245,18 @@ loadAuthToken().then(() => { updateMenuVisibility(); }); +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Fonctions d'API Babalex pour l'ajout ou la vérification d'un mot +// ───────────────────────────────────────────────────────────────────────────── -// Recherche un mot dans le lexique personnel +/** + * Vérifie si le mot existe dans le lexique perso, ou l'ajoute, etc. + * (Ici, c'est un exemple de logique "searchLexicon") + */ async function searchLexicon(selectedText) { console.log("🔄 Recherche dans le lexique personnel pour :", selectedText); try { + // getUserLexicons = fonction définie dans api.js (s'assurer que api.js est chargé avant) const lexicons = await getUserLexicons(authToken); console.log("📚 Lexiques récupérés :", lexicons); @@ -237,6 +266,7 @@ async function searchLexicon(selectedText) { return; } + // getLexiconEntriesID = fonction dans api.js const entries = await getLexiconEntriesID(authToken, frenchLexicon.id); const isWordPresent = entries.some( (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() @@ -246,79 +276,10 @@ async function searchLexicon(selectedText) { alert(`✅ Le mot "${selectedText}" est présent dans votre lexique personnel.`); } else { alert(`⌠Le mot "${selectedText}" n'est pas présent dans votre lexique personnel.`); + // Ici tu pourrais lancer l'ajout, si tu as une API pour ajouter. } } catch (error) { console.error("⌠Erreur lors de la recherche dans le lexique :", error); alert(`Erreur lors de la recherche : ${error.message}`); } } - -// Vérifie dans quels lexiques le mot est présent -async function checkLexicon(selectedText) { - try { - const lexicons = await getLexicons(authToken); - const results = lexicons.map((lexicon) => ({ - name: lexicon.name, - isPresent: lexicon.entries.some( - (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() - ), - })); - - console.log("📋 Résultats des lexiques :", results); - let message = `Résultats pour "${selectedText}":\n\n`; - results.forEach(({ name, isPresent }) => { - message += `- ${name}: ${isPresent ? "✅ Présent" : "⌠Non présent"}\n`; - }); - alert(message); - } catch (error) { - console.error("⌠Erreur lors de la vérification des lexiques :", error); - alert(`Erreur lors de la vérification : ${error.message}`); - } -} - -// Obtenir les définitions d'un mot à partir de plusieurs lexiques. -async function getDefinition(selectedText) { - try { - const lexicons = await getLexicons(authToken); - let definitions = []; - - for (const lexicon of lexicons) { - const entries = await getLexiconEntriesID(authToken, lexicon.id); - const entry = entries.find( - (e) => e.graphy.toLowerCase() === selectedText.toLowerCase() - ); - - if (entry) { - const definitionData = await getDefinitionAPI(authToken, entry.id); - // Remarque: j'ai renommé en getDefinitionAPI pour éviter - // la confusion avec la fonction "getDefinition" ci-dessus. - definitions.push(...extractDefinitions(definitionData)); - } - } - - console.log("📖 Définitions trouvées :", definitions); - if (definitions.length > 0) { - alert(`📖 Définitions pour "${selectedText}":\n\n` + definitions.join("\n")); - } else { - alert(`⌠Aucune définition trouvée pour "${selectedText}".`); - } - } catch (error) { - console.error("⌠Erreur lors de la récupération des définitions :", error); - alert(`Erreur lors de la récupération des définitions : ${error.message}`); - } -} - -// Extrait un tableau de définitions à partir d'une réponse JSON de l'API. -function extractDefinitions(response) { - if (!response || !response.attributes || !response.attributes.Items) { - console.warn("âš ï¸ Structure de réponse inattendue."); - return []; - } - - const items = response.attributes.Items; - return items.flatMap((item) => { - const defs = item.Sense?.Definitions?.map((def) => def.Def || "Définition non disponible"); - return defs || []; - }); -} - -- GitLab From 7e946db90e8d280322080b7332f2df222d6f886c Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 30 Jan 2025 12:49:41 +0100 Subject: [PATCH 02/32] =?UTF-8?q?Bouton=20d=C3=A9finition=20Wiktionnaire?= =?UTF-8?q?=20menu=20perso?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.js | 32 +++++++-------- "barre_lat\303\251rale/sidebar.js" | 66 ++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/api.js b/api.js index d7da84a..90667c2 100644 --- a/api.js +++ b/api.js @@ -206,47 +206,45 @@ async function getDefinition(authToken, entryId) { async function getWiktionaryDefinition(word) { try { console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); + if (!word || word.trim() === "") { - throw new Error("Mot vide, impossible d'envoyer la requête."); + throw new Error("âš ï¸ Mot vide, requête impossible."); } - // Le paramètre "origin=*" est requis pour les appels cross-domain - // "prop=extracts & exintro=true" renvoie seulement le début de l’article const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&exintro=true&titles=${encodeURIComponent(word)}`; const response = await fetch(wiktionaryURL); if (!response.ok) { - throw new Error(`Erreur API Wiktionnaire: ${response.statusText}`); + throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); } const data = await response.json(); - console.log("📖 Réponse API (Wiktionnaire) :", data); + console.log("📖 Réponse API Wiktionnaire :", data); - const pages = data.query.pages; - // pages est un objet dont la clé est l'ID de la page => on récupère la première - const page = Object.values(pages)[0]; + if (!data.query || !data.query.pages) { + return ["âš ï¸ Réponse inattendue du Wiktionnaire."]; + } - if (!page || !page.extract) { - console.warn("âš ï¸ Aucune définition trouvée sur le Wiktionnaire."); + // Récupérer la première page (clé dynamique) + const pages = Object.values(data.query.pages); + if (pages.length === 0 || !pages[0].extract) { return ["âš ï¸ Aucune définition trouvée sur le Wiktionnaire."]; } - // page.extract contient du HTML : on le parse pour en extraire du texte brut + // Convertir l'HTML en texte brut propre const parser = new DOMParser(); - const doc = parser.parseFromString(page.extract, "text/html"); + const doc = parser.parseFromString(pages[0].extract, "text/html"); const cleanText = doc.body.textContent.trim(); console.log("✅ Définition extraite :", cleanText); - - // Tu peux renvoyer un tableau avec 1 seule définition - return [cleanText]; + return [cleanText]; // Toujours un tableau } catch (error) { console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); - // On renvoie un tableau contenant un message d'erreur - return [`âš ï¸ Erreur : ${error.message}`]; + return ["âš ï¸ Erreur : " + error.message]; } } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Mise à disposition globale de nos fonctions // ───────────────────────────────────────────────────────────────────────────── diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index a650668..9051a4a 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -10,6 +10,20 @@ window.addEventListener('error', (e) => { console.error("â—ï¸ Erreur globale détectée :", e.message, "dans", e.filename, ":", e.lineno); }); +document.addEventListener("DOMContentLoaded", () => { + console.log("📦 DOM entièrement chargé, vérification des éléments..."); + + // Vérifier si #definitionsList est maintenant disponible + const definitionsList = document.getElementById("definitionsList"); + + if (!definitionsList) { + console.error("⌠Échec : #definitionsList est toujours introuvable."); + } else { + console.log("✅ Succès : #definitionsList est bien détecté."); + } +}); + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Fonctions utilitaires liées au token // ───────────────────────────────────────────────────────────────────────────── @@ -269,7 +283,7 @@ async function fetchWiktionaryDefinition(word) { throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); } - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&exintro=true&titles=${encodeURIComponent(word)}`; + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; const response = await fetch(wiktionaryURL); if (!response.ok) { @@ -279,20 +293,26 @@ async function fetchWiktionaryDefinition(word) { const data = await response.json(); console.log("📖 Réponse API (Wiktionnaire) :", data); - const pages = data.query.pages; - const page = Object.values(pages)[0]; + // Vérifier si des redirections ont été suivies + if (data.query && data.query.redirects) { + console.log("🔄 Redirection détectée :", data.query.redirects); + } - if (!page || !page.extract) { - throw new Error("âš ï¸ Aucune définition trouvée sur le Wiktionnaire."); + if (!data.query || !data.query.pages) { + return ["âš ï¸ Réponse inattendue du Wiktionnaire."]; } - // Extraction et nettoyage de la définition - const parser = new DOMParser(); - const doc = parser.parseFromString(page.extract, "text/html"); - const cleanText = doc.body.textContent.trim(); + // Récupérer la première page (clé dynamique) + const pages = Object.values(data.query.pages); + if (pages.length === 0 || !pages[0].extract) { + return ["âš ï¸ Aucune définition trouvée sur le Wiktionnaire."]; + } + // Extraire la définition sous forme de texte brut + const cleanText = pages[0].extract.trim(); console.log("✅ Définition extraite :", cleanText); - return [cleanText]; + + return [cleanText]; // Toujours un tableau pour `displayDefinitions()` } catch (error) { console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); return ["âš ï¸ Aucune définition disponible."]; @@ -318,18 +338,27 @@ async function showDefinitions(word) { * Affiche la liste des définitions dans la barre latérale. */ function displayDefinitions(definitions) { - const definitionsList = document.getElementById("definitionsList"); - if (!definitionsList) { - console.warn("âš ï¸ Ã‰lément #definitionsList introuvable."); + // Vérifier si le DOM est prêt + if (document.readyState === "loading") { + console.log("â³ DOM pas encore prêt, attente..."); + document.addEventListener("DOMContentLoaded", () => displayDefinitions(definitions)); return; } - console.log("📖 Affichage des définitions dans la barre latérale :", definitions); + let definitionsList = document.getElementById("definitionsList"); + if (!definitionsList) { + console.warn("âš ï¸ Ã‰lément #definitionsList introuvable. Attente du chargement..."); + + setTimeout(() => displayDefinitions(definitions), 500); + return; + } + + console.log("📖 Affichage des définitions :", definitions); definitionsList.innerHTML = ""; if (!definitions || definitions.length === 0) { - definitionsList.innerHTML = "<li>Aucune définition trouvée.</li>"; + definitionsList.innerHTML = "<li>âš ï¸ Aucune définition trouvée.</li>"; return; } @@ -339,7 +368,7 @@ function displayDefinitions(definitions) { definitionsList.appendChild(listItem); }); - console.log("✅ Définitions affichées avec succès !"); + console.log("✅ Définitions affichées !"); } // ───────────────────────────────────────────────────────────────────────────── @@ -376,6 +405,11 @@ browser.runtime.onMessage.addListener((message) => { fetchWiktionaryDefinition(message.selectedText).then((definitions) => { console.log("📖 Définitions récupérées :", definitions); + + if (definitions.length === 0) { + console.warn("âš ï¸ Aucune définition reçue."); + } + displayDefinitions(definitions); }); } -- GitLab From f22b7f116d1fc3dd9f525c8881a94e46ed914325 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 30 Jan 2025 13:12:01 +0100 Subject: [PATCH 03/32] Bouton def Wiktionnaire menu navigateur --- background/background.js | 7 +++--- "barre_lat\303\251rale/sidebar.js" | 35 +++++++++++++++++------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/background/background.js b/background/background.js index 10ac502..259d691 100644 --- a/background/background.js +++ b/background/background.js @@ -299,7 +299,7 @@ async function createBrowserContextMenu() { // Option accessible à tout le monde browser.contextMenus.create({ id: "getDefinitionWiki", - title: "Rechercher une définition sur le Wiktionnaire", + title: "Rechercher la définition sur le Wiktionnaire", contexts: ["selection"], }); @@ -340,8 +340,8 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { break; case "getDefinitionWiki": - browser.tabs.sendMessage(tab.id, { - action: "getDefinitionWiki", + browser.runtime.sendMessage({ + action: "fetchWiktionaryDefinition", selectedText: info.selectionText, }); break; @@ -361,6 +361,7 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } }); + // === Exemple de notification === function showNotification(title, message, iconPath) { console.log(`🔔 NOTIFICATION: [${title}] ${message}`); diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 9051a4a..d45115f 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -375,7 +375,7 @@ function displayDefinitions(definitions) { // â–Œ Gestion des messages envoyés par d'autres parties de l'extension // ───────────────────────────────────────────────────────────────────────────── -browser.runtime.onMessage.addListener((message) => { +browser.runtime.onMessage.addListener(async (message) => { console.log("📩 Message reçu dans sidebar.js :", message); // Rafraîchit la barre latérale (bouton "Se connecter"/"Se déconnecter" etc.) @@ -401,17 +401,12 @@ browser.runtime.onMessage.addListener((message) => { } // Récupération des définitions Wiktionnaire else if (message.action === "fetchWiktionaryDefinition" && message.selectedText) { - console.log("🔠Récupération de la définition du Wiktionnaire pour :", message.selectedText); + console.log("🌠Recherche des définitions sur le Wiktionnaire pour :", message.selectedText); - fetchWiktionaryDefinition(message.selectedText).then((definitions) => { - console.log("📖 Définitions récupérées :", definitions); - - if (definitions.length === 0) { - console.warn("âš ï¸ Aucune définition reçue."); - } + const definitions = await fetchWiktionaryDefinition(message.selectedText); + console.log("📖 Définitions récupérées :", definitions); - displayDefinitions(definitions); - }); + displayDefinitions(definitions); } // Affichage d'une notification quand une définition est trouvée else if (message.action === "showDefinitionNotification") { @@ -440,10 +435,20 @@ document.addEventListener('DOMContentLoaded', async () => { if (authButton) { authButton.addEventListener("click", handleAuthButtonClick); } -}); + // Gestion du bouton "Chercher la/les définition(s)" + const chercherDefButton = document.getElementById("chercherDef"); + if (chercherDefButton) { + chercherDefButton.addEventListener("click", () => { + const selectedWord = document.getElementById("motSelectionne")?.textContent?.trim(); + if (selectedWord && selectedWord !== "Aucun mot sélectionné") { + console.log(`🔠Recherche des définitions pour '${selectedWord}' depuis le bouton.`); + browser.runtime.sendMessage({ action: "fetchWiktionaryDefinition", selectedText: selectedWord }); + } else { + console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); + } + }); + } + +}); -console.log( - "🔠Vérification de l'élément #definitionsList :", - document.getElementById("definitionsList") -); -- GitLab From d0afe99822152bf2ceddd6b60895098e797fcf71 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:12:05 +0100 Subject: [PATCH 04/32] 3 boutons fonctionnels def Wiktionnaire --- api.js | 16 +- background/background.js | 335 +++++++---------------------- "barre_lat\303\251rale/sidebar.js" | 282 +++++++++++++----------- 3 files changed, 237 insertions(+), 396 deletions(-) diff --git a/api.js b/api.js index 90667c2..4de4708 100644 --- a/api.js +++ b/api.js @@ -14,7 +14,7 @@ document.addEventListener("mouseup", () => { }); // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Fonctions d’appel à l’API Babalex +// â–Œ Fonctions d’appel à l’API // ───────────────────────────────────────────────────────────────────────────── /** @@ -194,11 +194,11 @@ async function getDefinition(authToken, entryId) { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Récupération au Wiktionnaire : https://fr.wiktionary.org +// â–Œ Récupération au Wiktionnaire // ───────────────────────────────────────────────────────────────────────────── /** - * Récupère la définition d’un mot depuis le Wiktionnaire (fr) **directement**. + * Récupère la définition d’un mot depuis le Wiktionnaire * * @param {string} word - Le mot à définir * @returns {Promise<string[]>} Tableau de définitions (chaînes) @@ -225,7 +225,6 @@ async function getWiktionaryDefinition(word) { return ["âš ï¸ Réponse inattendue du Wiktionnaire."]; } - // Récupérer la première page (clé dynamique) const pages = Object.values(data.query.pages); if (pages.length === 0 || !pages[0].extract) { return ["âš ï¸ Aucune définition trouvée sur le Wiktionnaire."]; @@ -237,16 +236,13 @@ async function getWiktionaryDefinition(word) { const cleanText = doc.body.textContent.trim(); console.log("✅ Définition extraite :", cleanText); - return [cleanText]; // Toujours un tableau + return [cleanText]; } catch (error) { console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); return ["âš ï¸ Erreur : " + error.message]; } } - -// ───────────────────────────────────────────────────────────────────────────── -// â–Œ Mise à disposition globale de nos fonctions // ───────────────────────────────────────────────────────────────────────────── window.getUserLexicons = getUserLexicons; window.getLexicons = getLexicons; @@ -254,8 +250,4 @@ window.getLexiconEntries = getLexiconEntries; window.getLexiconEntriesID = getLexiconEntriesID; window.getGraphyInfo = getGraphyInfo; window.getDefinition = getDefinition; - -// Utilisons la version directe pour Wiktionnaire window.getWiktionaryDefinition = getWiktionaryDefinition; - -console.log("api.js : toutes les fonctions sont prêtes !"); \ No newline at end of file diff --git a/background/background.js b/background/background.js index 259d691..6a0d19f 100644 --- a/background/background.js +++ b/background/background.js @@ -1,5 +1,5 @@ // === Variables globales / de configuration === -let isExtensionActive = true; // Activation globale de l'extension +let isExtensionActive = true; let areStatsActive = false; let originalTabId = null; @@ -19,103 +19,69 @@ browser.runtime.onStartup.addListener(() => { console.log("🔄 Extension démarrée (onStartup)."); }); -// === Suivi des changements dans le stockage (extensionActive, statsActive) === -browser.storage.onChanged.addListener((changes) => { - if (changes.extensionActive) { - isExtensionActive = changes.extensionActive.newValue; - console.log("✅ Extension activée :", isExtensionActive); - } - if (changes.statsActive) { - areStatsActive = changes.statsActive.newValue; - console.log("📊 Statistiques activées :", areStatsActive); - } - // Recréer le menu contextuel du navigateur quand l'état change (ex: extension désactivée) - createBrowserContextMenu(); -}); - // === Vérifie si l'utilisateur est connecté (token présent) === async function isUserConnected() { const { accessToken } = await browser.storage.local.get("accessToken"); return !!accessToken; } -// === Ouvre la page de login BaLex === -async function openLoginPage() { - console.log("🔗 Ouverture de la page de connexion."); +async function saveToken(token) { + console.log("💾 Sauvegarde du token (à implémenter)..."); + await browser.storage.local.set({ accessToken: token }); + await createBrowserContextMenu(); +} - // 1) Retrouver l'onglet actuellement actif (pour y revenir plus tard) - const [currentTab] = await browser.tabs.query({ active: true, currentWindow: true }); - if (currentTab) { - originalTabId = currentTab.id; - console.log("✅ Onglet courant mémorisé, ID =", originalTabId); - } +// === Fonction pour récupérer la définition du Wiktionnaire === +async function fetchWiktionaryDefinition(word) { + try { + console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); - // 2) Créer l’onglet de login - const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL }); - loginTabId = loginTab.id; - console.log("✅ Onglet de login créé, ID =", loginTabId); + if (!word || word.trim() === "") { + throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); + } - // Notifie (éventuellement) qu'on est “en cours†de connexion - browser.runtime.sendMessage({ action: "authStatusChanged", isLoggedIn: false }); -} + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; + const response = await fetch(wiktionaryURL); -// === Déconnecte l'utilisateur (supprime le token) === -async function disconnectFromLexicalDB() { - console.log("🔓 Déconnexion en cours..."); - await browser.storage.local.remove("accessToken"); - console.log("🔓 Token supprimé avec succès."); + if (!response.ok) { + throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + } - showNotification( - "Déconnexion réussie", - "Vous êtes maintenant déconnecté(e).", - "icons/logout.png" - ); + const data = await response.json(); + console.log("📖 Réponse API (Wiktionnaire) :", data); - // On effectue un rafraîchissement global - await refreshAllUI(); -} + const pages = data.query?.pages; + const page = pages ? Object.values(pages)[0] : null; + const definition = page && page.extract + ? page.extract.trim() + : "âš ï¸ Aucune définition trouvée sur le Wiktionnaire."; -// === Sauvegarde du token et finalisation de la connexion === -async function saveToken(token) { - console.log("✅ Sauvegarde du token :", token); - await browser.storage.local.set({ accessToken: token }); + console.log("📤 Envoi de la définition extraite à sidebar.js :", definition); - // On ferme la page de login si encore ouverte - if (loginTabId) { - try { - await browser.tabs.remove(loginTabId); - console.log("🗙 Onglet de login fermé après connexion réussie."); - } catch (err) { - console.warn("Impossible de fermer l'onglet de login :", err); - } - loginTabId = null; // Reset l'identifiant - } + browser.runtime.sendMessage({ + action: "fetchWiktionaryDefinitionResponse", + selectedText: word, + definitions: [definition], + }); - // On refait apparaître l’onglet initial, s'il existe encore - if (originalTabId) { - try { - await browser.tabs.update(originalTabId, { active: true }); - console.log("🔙 Retour sur l'onglet initial :", originalTabId); - } catch (err) { - console.warn("Impossible de basculer sur l'onglet initial :", err); - } - originalTabId = null; // Reset l'identifiant + } catch (error) { + console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); + browser.runtime.sendMessage({ + action: "fetchWiktionaryDefinitionResponse", + selectedText: word, + definitions: ["âš ï¸ Aucune définition disponible."], + }); } - - // Et on rafraîchit toute l’UI - await refreshAllUI(); } -// === Fonction de REFRESH centralisée === -async function refreshAllUI() { - console.log("🔄 Rafraîchissement global de l'UI..."); - - // 1) Recrée le menu contextuel “navigateur†(clic-droit) - createBrowserContextMenu(); - - // 2) Envoie un message unique “refreshUI†à toutes les parties - // (sidebar, popup, content script) pour qu'elles se mettent à jour. - browser.runtime.sendMessage({ action: "refreshUI" }); +// Exemple de fonction pour afficher une notification +function showWiktionaryNotification(selectedText) { + browser.notifications.create({ + type: "basic", + iconUrl: browser.runtime.getURL("icons/notification.png"), + title: "Définition trouvée", + message: `🌠Définition trouvée pour "${selectedText}". Consultez le Wiktionnaire.` + }); } // === Gestion des messages reçus === @@ -123,21 +89,25 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { console.log("📩 Message reçu dans background.js :", message); switch (message.action) { - // --- Authentification --- - case "toggleAuth": + case "toggleAuth": { const isConnected = await isUserConnected(); - isConnected ? await disconnectFromLexicalDB() : await openLoginPage(); + if (isConnected) { + await disconnectFromLexicalDB(); + } else { + await openLoginPage(); + } break; - case "getDefinitionWiki": + } + + case "getDefinitionWiki": { if (message.selectedText && message.selectedText.trim() !== "") { console.log("📤 Envoi de la requête au Wiktionnaire pour :", message.selectedText); - browser.runtime.sendMessage({ - action: "fetchWiktionaryDefinition", - selectedText: message.selectedText.trim(), - }); + fetchWiktionaryDefinition(message.selectedText.trim()); } else { console.warn("âš ï¸ Texte sélectionné vide. Annulation de la requête."); } + break; + } case "checkAuthStatus": { const connected = await isUserConnected(); @@ -147,12 +117,10 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { case "authStatusChanged": { console.log("🔄 Mise à jour de l'état d'authentification :", message.isLoggedIn); - // Éventuellement on peut relancer un refreshAllUI() si souhaité break; } case "saveToken": { - // Lorsqu'on reçoit le token depuis la page BaLex if (message.token) { await saveToken(message.token); } else { @@ -164,131 +132,17 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { default: break; } - return true; -}); - -// === Navigation : injection / récupération token sur la page BaLex === -browser.webNavigation.onCompleted.addListener(async (details) => { - if (!isExtensionActive) { - console.log("🚫 Extension désactivée, aucune injection script."); - return; - } - - const url = new URL(details.url); - // Sur la page de login : injecter un petit popup d’instruction - if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/login") { - console.log("📘 Injection du popup d'instruction sur la page de login Prisms."); - showInstructionPopup(details); - } - - // Sur la page /balex : tenter de récupérer le token - if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/headquarters/balex") { - console.log("🟢 Page /balex détectée. Tentative de récupération du token."); - try { - await new Promise(resolve => setTimeout(resolve, 3000)); // Attendre 3s - await browser.tabs.executeScript(details.tabId, { - code: ` - console.log("🔠Recherche du token..."); - const tokenElement = document.getElementById("accesToken"); - if (tokenElement) { - const token = tokenElement.innerText.trim(); - console.log("🔠Token détecté :", token); - browser.runtime.sendMessage({ action: "saveToken", token }); - } else { - console.error("⌠Token introuvable."); - } - ` - }); - } catch (error) { - console.error("⌠Erreur lors de la récupération du token :", error); - } - } -}, { - url: [{ hostContains: "prisms.lezinter.net" }] + return true; }); -// === Redirection automatique vers /balex (facultatif) === -browser.webRequest.onBeforeRequest.addListener( - function(details) { - if (details.url === "https://prisms.lezinter.net/fr/headquarters/") { - console.log("🚀 Redirection automatique vers /balex."); - return { redirectUrl: AUTH_BALEX_URL }; - } - }, - { urls: ["https://prisms.lezinter.net/fr/headquarters/*"] }, - ["blocking"] -); - -// === Affichage d'un popup d’instruction sur /fr/login === -function showInstructionPopup(details) { - browser.tabs.executeScript(details.tabId, { - code: ` - if (!document.getElementById("balex-instruction-popup")) { - const popup = document.createElement("div"); - popup.id = "balex-instruction-popup"; - popup.style.position = "fixed"; - popup.style.top = "50%"; - popup.style.left = "50%"; - popup.style.transform = "translate(-50%, -50%)"; - popup.style.backgroundColor = "#a08e9f"; - popup.style.color = "#323046"; - popup.style.padding = "20px"; - popup.style.borderRadius = "10px"; - popup.style.boxShadow = "0 2px 10px rgba(0, 0, 0, 0.3)"; - popup.style.zIndex = "10000"; - popup.style.fontFamily = "Helvetica, sans-serif"; - popup.style.fontSize = "14px"; - popup.style.width = "300px"; - popup.style.textAlign = "center"; - - popup.innerHTML = \` - <h5 style="color: #fff; font-weight: bold; margin-top: 0;">🔑 Connexion à l'extension</h5> - <p style="margin: 15px 0;"> - Après avoir renseigné vos identifiants, cliquez sur - <strong>"Se connecter avec BaLex"</strong>. - </p> - <button id="close-popup-btn" style=" - width: 100%; - margin-top: 15px; - padding: 10px; - border: none; - background-color: #8d5c70; - color: #fbfcfc; - font-weight: bold; - cursor: pointer; - border-radius: 5px; - ">Fermer</button> - \`; - - document.body.appendChild(popup); - - const closeBtn = document.getElementById("close-popup-btn"); - closeBtn.onclick = () => popup.remove(); - } - ` - }); -} - -// === Création du menu contextuel (navigateur) standard === +// === Création du menu contextuel (navigateur) === async function createBrowserContextMenu() { - // Supprimer les items existants - browser.contextMenus.removeAll(); - + await browser.contextMenus.removeAll(); const isConnected = await isUserConnected(); - // Si connecté : options supplémentaires + // Menu "Obtenir une définition de mes lexiques" if (isConnected) { - browser.contextMenus.create({ - id: "searchLexicon", - title: "Vérifier si le mot est dans le lexique personnel", - contexts: ["selection"], - }); - browser.contextMenus.create({ - id: "checkLexicon", - title: "Afficher dans quels lexiques le mot est présent", - contexts: ["selection"], - }); browser.contextMenus.create({ id: "getDefinition", title: "Obtenir une définition à partir de mes lexiques", @@ -296,14 +150,14 @@ async function createBrowserContextMenu() { }); } - // Option accessible à tout le monde + // Menu "Rechercher la définition sur le Wiktionnaire" browser.contextMenus.create({ id: "getDefinitionWiki", title: "Rechercher la définition sur le Wiktionnaire", contexts: ["selection"], }); - // Bouton de connexion/déconnexion + // Menu "Connexion / Déconnexion" browser.contextMenus.create({ id: "login", title: isConnected ? "Se déconnecter de BaLex" : "Se connecter à BaLex", @@ -311,37 +165,25 @@ async function createBrowserContextMenu() { }); } -// Initialise le menu contextuel du navigateur une première fois createBrowserContextMenu(); -// Gère les clics sur les items du menu contextuel du navigateur browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log("📦 Menu contextuel - item cliqué :", info.menuItemId); - switch (info.menuItemId) { - case "searchLexicon": - browser.tabs.sendMessage(tab.id, { - action: "searchLexicon", - selectedText: info.selectionText, - }); - break; - case "checkLexicon": - browser.tabs.sendMessage(tab.id, { - action: "checkLexicon", - selectedText: info.selectionText, - }); + switch (info.menuItemId) { + case "getDefinitionWiki": + if (info.selectionText) { + console.log("🌠Recherche Wiktionnaire pour :", info.selectionText); + await fetchWiktionaryDefinition(info.selectionText); + } else { + console.warn("âš ï¸ Aucun texte sélectionné pour la recherche Wiktionnaire."); + } break; case "getDefinition": + console.log("🔎 Demande de définition via mes lexiques pour :", info.selectionText); browser.tabs.sendMessage(tab.id, { - action: "getDefinition", - selectedText: info.selectionText, - }); - break; - - case "getDefinitionWiki": - browser.runtime.sendMessage({ - action: "fetchWiktionaryDefinition", + action: "mot_selectionne", selectedText: info.selectionText, }); break; @@ -357,33 +199,6 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } default: - console.warn(`Aucune action définie pour l'élément : ${info.menuItemId}`); - } -}); - - -// === Exemple de notification === -function showNotification(title, message, iconPath) { - console.log(`🔔 NOTIFICATION: [${title}] ${message}`); -} - -browser.contextMenus.onClicked.addListener(async (info, tab) => { - if (info.menuItemId === "getDefinition") { - browser.tabs.sendMessage(tab.id, { - action: "mot_selectionne", - selectedText: info.selectionText, - }); + console.warn(`âš ï¸ Aucune action définie pour l'élément : ${info.menuItemId}`); } }); - -browser.notifications.create({ - type: "basic", - iconUrl: browser.runtime.getURL("icons/notification.png"), - title: "Définition trouvée", - message: `🌠Définition trouvée pour "${selectedText}". Consultez le Wiktionnaire.`, -}); - -browser.runtime.sendMessage({ - action: "showDefinitionNotification", - selectedText: selectedText -}); \ No newline at end of file diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index d45115f..72b7e69 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -1,34 +1,17 @@ -// ✅ Chargement du script de la barre latérale console.log("✅ sidebar.js chargé !"); -console.log("🌠Vérification API browser :", typeof browser !== "undefined" ? "✅ Disponible" : "⌠Non disponible"); +console.log( + "🌠Vérification API browser :", + typeof browser !== "undefined" ? "✅ Disponible" : "⌠Non disponible" +); // Variable globale pour le token d'authentification let authToken = null; -// Gestionnaire global des erreurs -window.addEventListener('error', (e) => { - console.error("â—ï¸ Erreur globale détectée :", e.message, "dans", e.filename, ":", e.lineno); -}); - -document.addEventListener("DOMContentLoaded", () => { - console.log("📦 DOM entièrement chargé, vérification des éléments..."); - - // Vérifier si #definitionsList est maintenant disponible - const definitionsList = document.getElementById("definitionsList"); - - if (!definitionsList) { - console.error("⌠Échec : #definitionsList est toujours introuvable."); - } else { - console.log("✅ Succès : #definitionsList est bien détecté."); - } -}); - - // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Fonctions utilitaires liées au token +// â–Œ Fonctions liées au token // ───────────────────────────────────────────────────────────────────────────── -// Fonction pour valider le format du token (JWT par exemple) +// Vérifie le format du token function validateToken(token) { const isValid = /^\S+\.\S+\.\S+$/.test(token); if (!isValid) { @@ -37,7 +20,7 @@ function validateToken(token) { return isValid; } -// Lecture du token depuis le stockage local +// Récupération du token depuis le stockage local async function getAuthTokenFromStorage() { try { const { accessToken } = await browser.storage.local.get("accessToken"); @@ -70,14 +53,14 @@ function updateAuthButton(isLoggedIn) { function toggleElementsVisibility(isLoggedIn) { const elementsToShowOrHide = [ - { id: 'add-to-lexiques', shouldShow: isLoggedIn }, - { id: 'possible-definitions', shouldShow: isLoggedIn }, + { id: "add-to-lexiques", shouldShow: isLoggedIn }, + { id: "possible-definitions", shouldShow: isLoggedIn }, ]; elementsToShowOrHide.forEach(({ id, shouldShow }) => { const element = document.getElementById(id); if (element) { - element.style.display = shouldShow ? 'block' : 'none'; + element.style.display = shouldShow ? "block" : "none"; console.log(`🔄 Élément #${id} ${shouldShow ? "affiché" : "masqué"}.`); } else { console.warn(`âš ï¸ Ã‰lément #${id} introuvable.`); @@ -86,13 +69,15 @@ function toggleElementsVisibility(isLoggedIn) { } function toggleHighlightMessage(isLoggedIn) { - const highlightNote = document.getElementById('highlight-note'); + const highlightNote = document.getElementById("highlight-note"); if (highlightNote) { - highlightNote.style.display = isLoggedIn ? 'block' : 'none'; + highlightNote.style.display = isLoggedIn ? "block" : "none"; } } -// Rafraîchit l'état de la barre latérale +/** + * Rafraîchit l'état de la barre latérale (bouton de connexion, lexiques, etc.) + */ async function refreshSidebarState() { console.log("🔄 Début de l'actualisation de la barre latérale..."); const token = await getAuthTokenFromStorage(); @@ -117,22 +102,24 @@ async function refreshSidebarState() { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Lexiques +// â–Œ Lexiques (récupération et affichage) // ───────────────────────────────────────────────────────────────────────────── -// Affiche les lexiques (checkbox + icône) +/** + * Affiche les lexiques (checkbox + icône). + */ function displayLexicons(lexicons) { - const lexiquesContainer = document.getElementById('lexiques'); + const lexiquesContainer = document.getElementById("lexiques"); if (!lexiquesContainer) { console.warn("âš ï¸ Ã‰lément #lexiques introuvable."); return; } - lexiquesContainer.innerHTML = ''; + lexiquesContainer.innerHTML = ""; if (lexicons.length === 0) { console.log("âš ï¸ Aucun lexique à afficher."); - lexiquesContainer.textContent = 'Aucun lexique disponible.'; + lexiquesContainer.textContent = "Aucun lexique disponible."; return; } @@ -140,33 +127,33 @@ function displayLexicons(lexicons) { lexicons.forEach(({ lexiconName, lexiconId, active }) => { console.log(`âž¡ï¸ Affichage du lexique : ${lexiconName} (ID: ${lexiconId})`); - const lexiqueDiv = document.createElement('div'); - lexiqueDiv.className = 'lexique-item'; + const lexiqueDiv = document.createElement("div"); + lexiqueDiv.className = "lexique-item"; - const iconDiv = document.createElement('div'); - iconDiv.className = 'lexique-icon'; - iconDiv.style.backgroundColor = '#ccc'; + const iconDiv = document.createElement("div"); + iconDiv.className = "lexique-icon"; + iconDiv.style.backgroundColor = "#ccc"; - const labelSpan = document.createElement('span'); - labelSpan.className = 'lexique-label'; + const labelSpan = document.createElement("span"); + labelSpan.className = "lexique-label"; labelSpan.textContent = lexiconName; - const checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.className = 'lexique-checkbox'; + const checkbox = document.createElement("input"); + checkbox.type = "checkbox"; + checkbox.className = "lexique-checkbox"; checkbox.checked = active; - checkbox.addEventListener('change', async () => { + checkbox.addEventListener("change", async () => { console.log( `🔄 Changement de surlignage pour ${lexiconName} (ID: ${lexiconId}): ${ - checkbox.checked ? 'activé' : 'désactivé' + checkbox.checked ? "activé" : "désactivé" }` ); - // Envoyer un message au background + await browser.runtime.sendMessage({ action: "toggleLexiconHighlight", lexiconId, - isActive: checkbox.checked + isActive: checkbox.checked, }); }); @@ -177,7 +164,9 @@ function displayLexicons(lexicons) { }); } -// Récupération des lexiques +/** + * Récupère la liste des lexiques depuis l'API (exemple). + */ async function fetchLexicons() { try { console.log("🔄 Début de la récupération des lexiques..."); @@ -188,7 +177,7 @@ async function fetchLexicons() { } // Appel à l'API (exemple) - const lexicons = await getLexicons(authToken, 52, 'fr'); // À adapter + const lexicons = await getLexicons(authToken, 52, "fr"); console.log("📚 Réponse brute de l'API :", lexicons); if (!Array.isArray(lexicons) || lexicons.length === 0) { @@ -199,9 +188,10 @@ async function fetchLexicons() { const results = lexicons.map((lexicon) => { console.log("📋 Transformation du lexique :", lexicon); return { - lexiconName: lexicon.category === 'User' - ? `Lexique personnel (${lexicon.user?.pseudo || 'Inconnu'})` - : `Lexique de groupe (${lexicon.group?.name || 'Inconnu'})`, + lexiconName: + lexicon.category === "User" + ? `Lexique personnel (${lexicon.user?.pseudo || "Inconnu"})` + : `Lexique de groupe (${lexicon.group?.name || "Inconnu"})`, lexiconId: lexicon.id, active: lexicon.active || false, }; @@ -211,13 +201,13 @@ async function fetchLexicons() { // Affichage des lexiques displayLexicons(results); - } catch (error) { console.error("⌠Erreur lors du chargement des lexiques :", error.message); console.error("Détails de l'erreur :", error); const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { - lexiquesContainer.textContent = error.message || "Erreur lors du chargement des lexiques."; + lexiquesContainer.textContent = + error.message || "Erreur lors du chargement des lexiques."; } } } @@ -236,8 +226,7 @@ async function handleAuthButtonClick() { // ───────────────────────────────────────────────────────────────────────────── /** - * Récupère les définitions d'un mot dans nos lexiques - * (utilise notre API protégée par token). + * Récupère les définitions d'un mot dans les lexiques de l'utilisateur. */ async function fetchLexiconDefinitions(word) { try { @@ -247,7 +236,6 @@ async function fetchLexiconDefinitions(word) { throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); } - // Appel à l'API pour récupérer les définitions du mot sélectionné const response = await fetch( `https://prisms.lezinter.net/api/definitions?word=${encodeURIComponent(word)}`, { headers: { Authorization: `Bearer ${authToken}` } } @@ -260,14 +248,16 @@ async function fetchLexiconDefinitions(word) { const data = await response.json(); console.log("📚 Réponse API (lexiques) :", data); - // Vérification des résultats if (!data.definitions || data.definitions.length === 0) { throw new Error("âš ï¸ Aucune définition trouvée dans les lexiques."); } return data.definitions; } catch (error) { - console.error("⌠Erreur lors de la récupération des définitions des lexiques :", error); + console.error( + "⌠Erreur lors de la récupération des définitions des lexiques :", + error + ); return []; } } @@ -280,88 +270,76 @@ async function fetchWiktionaryDefinition(word) { console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); if (!word || word.trim() === "") { - throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); + console.warn("âš ï¸ Mot vide, impossible d'envoyer la requête."); + return ["âš ï¸ Mot vide, impossible d'envoyer la requête."]; } - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent( + word + )}`; + console.log(`🌠Requête envoyée à : ${wiktionaryURL}`); const response = await fetch(wiktionaryURL); if (!response.ok) { - throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + return [`⌠Erreur API Wiktionnaire: ${response.statusText}`]; } const data = await response.json(); console.log("📖 Réponse API (Wiktionnaire) :", data); - // Vérifier si des redirections ont été suivies - if (data.query && data.query.redirects) { - console.log("🔄 Redirection détectée :", data.query.redirects); - } - if (!data.query || !data.query.pages) { return ["âš ï¸ Réponse inattendue du Wiktionnaire."]; } - // Récupérer la première page (clé dynamique) const pages = Object.values(data.query.pages); if (pages.length === 0 || !pages[0].extract) { return ["âš ï¸ Aucune définition trouvée sur le Wiktionnaire."]; } - // Extraire la définition sous forme de texte brut const cleanText = pages[0].extract.trim(); console.log("✅ Définition extraite :", cleanText); - return [cleanText]; // Toujours un tableau pour `displayDefinitions()` + return [cleanText]; } catch (error) { - console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); + console.error( + "⌠Erreur lors de la récupération de la définition du Wiktionnaire :", + error + ); return ["âš ï¸ Aucune définition disponible."]; } } -/** - * Fonction principale pour afficher les définitions - * (cumul lexiques + Wiktionnaire) - */ -async function showDefinitions(word) { - console.log(`📖 Recherche des définitions pour '${word}'...`); - - const lexiconDefinitions = await fetchLexiconDefinitions(word); - const wiktionaryDefinitions = await fetchWiktionaryDefinition(word); - - // Fusion des résultats et affichage - const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; - displayDefinitions(allDefinitions); -} - /** * Affiche la liste des définitions dans la barre latérale. */ function displayDefinitions(definitions) { - // Vérifier si le DOM est prêt - if (document.readyState === "loading") { - console.log("â³ DOM pas encore prêt, attente..."); - document.addEventListener("DOMContentLoaded", () => displayDefinitions(definitions)); - return; - } - - let definitionsList = document.getElementById("definitionsList"); + console.log("📖 Tentative d'affichage des définitions :", definitions); + const definitionsList = document.getElementById("definitionsList"); if (!definitionsList) { - console.warn("âš ï¸ Ã‰lément #definitionsList introuvable. Attente du chargement..."); - - setTimeout(() => displayDefinitions(definitions), 500); + console.error("⌠ERREUR : Élément #definitionsList introuvable dans le DOM !"); return; + } else { + console.log("✅ Élément #definitionsList trouvé dans le DOM."); + } + + // Vérifier si l'élément est caché et le rendre visible + if (definitionsList.style.display === "none") { + console.warn("âš ï¸ L'élément #definitionsList est caché. Tentative d'affichage..."); + definitionsList.style.display = "block"; } - console.log("📖 Affichage des définitions :", definitions); + // Vider l'élément avant d'ajouter du contenu definitionsList.innerHTML = ""; if (!definitions || definitions.length === 0) { + console.warn("âš ï¸ Aucune définition reçue."); definitionsList.innerHTML = "<li>âš ï¸ Aucune définition trouvée.</li>"; return; } + console.log("📖 Ajout des définitions dans la barre latérale."); definitions.forEach((definition) => { const listItem = document.createElement("li"); listItem.textContent = definition; @@ -371,22 +349,54 @@ function displayDefinitions(definitions) { console.log("✅ Définitions affichées !"); } +/** + * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire + * puis les afficher. + */ +async function showDefinitions(word) { + console.log(`📖 Recherche des définitions pour '${word}'...`); + + // Récupère définitions du lexique + const lexiconDefinitions = await fetchLexiconDefinitions(word); + // Récupère définitions du Wiktionnaire + const wiktionaryDefinitions = await fetchWiktionaryDefinition(word); + + // Fusion des résultats et affichage + const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; + displayDefinitions(allDefinitions); +} + +/** + * Récupère la définition d'un mot via le background. + */ +function requestWiktionaryDefinition(word) { + console.log(`📩 Envoi du message 'fetchWiktionaryDefinition' pour '${word}'`); + browser.runtime + .sendMessage({ action: "fetchWiktionaryDefinition", selectedText: word }) + .then(() => { + console.log("📩 Message envoyé avec succès à background.js !"); + }) + .catch((error) => { + console.error("⌠Erreur lors de l'envoi du message à background.js :", error); + }); +} + // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion des messages envoyés par d'autres parties de l'extension +// â–Œ Gestion des messages reçus // ───────────────────────────────────────────────────────────────────────────── browser.runtime.onMessage.addListener(async (message) => { console.log("📩 Message reçu dans sidebar.js :", message); - // Rafraîchit la barre latérale (bouton "Se connecter"/"Se déconnecter" etc.) + // 1. Rafraîchit la barre latérale if (message.action === "refreshUI") { console.log("🔄 Rafraîchissement de la barre latérale demandé."); refreshSidebarState(); } - // Met à jour le mot sélectionné dans l'UI + + // 2. Met à jour le mot sélectionné else if (message.action === "mot_selectionne" && message.selectedText) { console.log("ðŸ–‹ï¸ Mise à jour du mot sélectionné :", message.selectedText); - const selectedWordElement = document.getElementById("motSelectionne"); if (selectedWordElement) { selectedWordElement.textContent = message.selectedText; @@ -394,24 +404,30 @@ browser.runtime.onMessage.addListener(async (message) => { console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); } } - // Quand on demande les définitions pour un mot + + // 3. Quand on demande les définitions pour un mot else if (message.action === "getDefinition" && message.selectedText) { console.log("📖 Recherche et affichage des définitions pour :", message.selectedText); showDefinitions(message.selectedText); } - // Récupération des définitions Wiktionnaire + + // 4. Récupération des définitions Wiktionnaire côté barre latérale directement else if (message.action === "fetchWiktionaryDefinition" && message.selectedText) { console.log("🌠Recherche des définitions sur le Wiktionnaire pour :", message.selectedText); - const definitions = await fetchWiktionaryDefinition(message.selectedText); console.log("📖 Définitions récupérées :", definitions); - displayDefinitions(definitions); } - // Affichage d'une notification quand une définition est trouvée + + // 4bis. Réception de la définition Wiktionnaire envoyée par le background + else if (message.action === "fetchWiktionaryDefinitionResponse" && message.selectedText) { + console.log(`📖 Réception de la définition du Wiktionnaire pour '${message.selectedText}'`); + displayDefinitions(message.definitions); + } + + // 5. Notification d'une définition trouvée else if (message.action === "showDefinitionNotification") { console.log(`📢 Définition trouvée pour "${message.selectedText}".`); - const notificationContainer = document.getElementById("notificationContainer"); if (notificationContainer) { notificationContainer.textContent = `🌠Définition trouvée pour "${message.selectedText}". Consultez le Wiktionnaire.`; @@ -424,10 +440,10 @@ browser.runtime.onMessage.addListener(async (message) => { // â–Œ Initialisation après chargement du DOM // ───────────────────────────────────────────────────────────────────────────── -document.addEventListener('DOMContentLoaded', async () => { +document.addEventListener("DOMContentLoaded", async () => { console.log("📦 DOM entièrement chargé. Initialisation de la sidebar."); - - // Rafraîchit l'UI (bouton, etc.) + + // Rafraîchit l'UI await refreshSidebarState(); // Gère le clic sur le bouton de connexion/déconnexion @@ -438,17 +454,35 @@ document.addEventListener('DOMContentLoaded', async () => { // Gestion du bouton "Chercher la/les définition(s)" const chercherDefButton = document.getElementById("chercherDef"); - if (chercherDefButton) { - chercherDefButton.addEventListener("click", () => { - const selectedWord = document.getElementById("motSelectionne")?.textContent?.trim(); - if (selectedWord && selectedWord !== "Aucun mot sélectionné") { - console.log(`🔠Recherche des définitions pour '${selectedWord}' depuis le bouton.`); - browser.runtime.sendMessage({ action: "fetchWiktionaryDefinition", selectedText: selectedWord }); - } else { - console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); - } - }); + if (!chercherDefButton) { + console.error("⌠ERREUR : Bouton #chercherDef introuvable."); + return; } -}); + console.log("✅ Bouton #chercherDef détecté dans le DOM."); + + // Forcer l'activation du bouton + chercherDefButton.style.pointerEvents = "auto"; + chercherDefButton.style.display = "block"; + chercherDefButton.style.visibility = "visible"; + chercherDefButton.disabled = false; + + chercherDefButton.addEventListener("click", () => { + const selectedWord = document + .getElementById("motSelectionne") + ?.textContent?.trim(); + console.log("📖 Mot sélectionné :", selectedWord); + if (selectedWord && selectedWord !== "Aucun mot sélectionné") { + console.log( + `📩 Envoi du message 'getDefinitionWiki' pour '${selectedWord}'` + ); + browser.runtime.sendMessage({ + action: "getDefinitionWiki", + selectedText: selectedWord, + }); + } else { + console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); + } + }); +}); -- GitLab From a5c9465446c9f94b47681d3a0afbdac0ea592384 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:42:20 +0100 Subject: [PATCH 05/32] Affichage def Wiktionnaire --- "barre_lat\303\251rale/sidebar.js" | 61 ++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 72b7e69..8cc2882 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -311,44 +311,63 @@ async function fetchWiktionaryDefinition(word) { } /** - * Affiche la liste des définitions dans la barre latérale. + * Affiche simplement les définitions sous forme de <pre>, avec tronquage + * et un bouton "Afficher la suite" si le texte est trop long. */ function displayDefinitions(definitions) { - console.log("📖 Tentative d'affichage des définitions :", definitions); - const definitionsList = document.getElementById("definitionsList"); if (!definitionsList) { - console.error("⌠ERREUR : Élément #definitionsList introuvable dans le DOM !"); + console.warn("⌠Élément #definitionsList introuvable dans le DOM !"); return; - } else { - console.log("✅ Élément #definitionsList trouvé dans le DOM."); - } - - // Vérifier si l'élément est caché et le rendre visible - if (definitionsList.style.display === "none") { - console.warn("âš ï¸ L'élément #definitionsList est caché. Tentative d'affichage..."); - definitionsList.style.display = "block"; } - // Vider l'élément avant d'ajouter du contenu + // Rendre visible si c’était caché + definitionsList.style.display = "block"; + // Vider le conteneur avant d’ajouter du contenu definitionsList.innerHTML = ""; if (!definitions || definitions.length === 0) { - console.warn("âš ï¸ Aucune définition reçue."); definitionsList.innerHTML = "<li>âš ï¸ Aucune définition trouvée.</li>"; return; } - console.log("📖 Ajout des définitions dans la barre latérale."); - definitions.forEach((definition) => { - const listItem = document.createElement("li"); - listItem.textContent = definition; - definitionsList.appendChild(listItem); - }); + // Parcours de chaque définition + definitions.forEach((def) => { + const li = document.createElement("li"); + + // Tronquer à 300 caractères + let truncated = def; + const maxLength = 300; + if (def.length > maxLength) { + truncated = def.slice(0, maxLength) + "..."; + } + + // Affichage brut dans un <pre> pour garder les sauts de ligne + const pre = document.createElement("pre"); + pre.style.whiteSpace = "pre-wrap"; + pre.textContent = truncated; - console.log("✅ Définitions affichées !"); + li.appendChild(pre); + + // S’il y a un tronquage, on ajoute le bouton "Afficher la suite" + if (def.length > maxLength) { + const readMoreBtn = document.createElement("button"); + readMoreBtn.textContent = "Afficher la suite"; + readMoreBtn.addEventListener("click", () => { + pre.textContent = def; // On remplace par la définition complète + readMoreBtn.remove(); // On retire le bouton + }); + + // Petite séparation + li.appendChild(document.createElement("br")); + li.appendChild(readMoreBtn); + } + + definitionsList.appendChild(li); + }); } + /** * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire * puis les afficher. -- GitLab From f2573a1a5373c3c69ae338f259baa25d8af1f120 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Fri, 31 Jan 2025 13:39:39 +0100 Subject: [PATCH 06/32] =?UTF-8?q?R=C3=A9glages=20affichage=20def=20Wiktion?= =?UTF-8?q?naire?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- background/browser_context_menu.js | 43 ++++++++-- "barre_lat\303\251rale/sidebar.html" | 30 +++++-- "barre_lat\303\251rale/sidebar.js" | 113 ++++++++++++--------------- 3 files changed, 113 insertions(+), 73 deletions(-) diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index f5d6285..1e0fbd2 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -204,17 +204,50 @@ async function getDefinition(selectedText) { // Fonction pour rechercher une définition sur le Wiktionnaire async function getDefinitionWiki(selectedText) { try { - const result = await fetch(`https://fr.wiktionary.org/wiki/${encodeURIComponent(selectedText)}`); - if (result.ok) { - console.log(`🌠Définition trouvée pour "${selectedText}". Consultez le Wiktionnaire.`); - } else { - alert(`⌠Aucune définition trouvée sur le Wiktionnaire pour "${selectedText}".`); + console.log(`🌠Recherche sur le Wiktionnaire pour '${selectedText}'...`); + + if (!selectedText || selectedText.trim() === "") { + console.warn("âš ï¸ Aucun texte sélectionné."); + return; + } + + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(selectedText)}`; + + const response = await fetch(wiktionaryURL); + if (!response.ok) { + console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + alert(`⌠Aucune définition trouvée pour "${selectedText}" sur le Wiktionnaire.`); + return; + } + + const data = await response.json(); + if (!data.query || !data.query.pages) { + alert(`⌠Aucune définition trouvée pour "${selectedText}" sur le Wiktionnaire.`); + return; } + + const pages = Object.values(data.query.pages); + if (pages.length === 0 || !pages[0].extract) { + alert(`⌠Aucune définition trouvée pour "${selectedText}" sur le Wiktionnaire.`); + return; + } + + const cleanText = pages[0].extract.trim(); + console.log(`✅ Définition trouvée : ${cleanText}`); + + // Envoyer la définition au script de la barre latérale + browser.runtime.sendMessage({ + action: "fetchWiktionaryDefinitionResponse", + selectedText, + definitions: [{ source: "Wiktionnaire", text: cleanText }], + }); + } catch (error) { console.error("⌠Erreur lors de la recherche sur le Wiktionnaire :", error); } } + // Fonction pour extraire les définitions d'une réponse API function extractDefinitions(response) { if (!response || !response.attributes || !response.attributes.Items) { diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index cc40401..82c706f 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -103,10 +103,10 @@ background-color: #ccc; margin-right: 10px; flex-shrink: 0; - } + } /* Définition */ - #definition { + #definitionContainer { margin-top: 10px; background-color: #444; padding: 10px; @@ -114,6 +114,14 @@ color: white; } + #definitionsList li { + margin-bottom: 10px; + } + + .definition-source { + font-weight: bold; + color: #ffa500; + } /* Activer/désactiver le surlignage */ #highlighting-options p { @@ -155,13 +163,21 @@ </div> <!-- Définition affichée --> - <div id="definitionContainer"> - <h3>Définitions</h3> - <ul id="definitionsList"></ul> +<div id="definitionContainer"> + <h3>Définitions</h3> + + <!-- Définitions des lexiques de l'utilisateur --> + <div id="mesLexiquesContainer"> + <h4>📚 Mes lexiques</h4> + <ul id="mesLexiquesList"></ul> </div> - <div id="notificationContainer" style="display: none; padding: 10px; background: #ffeb3b; color: #000; border-radius: 5px;"> + + <!-- Définitions issues du Wiktionnaire --> + <div id="wiktionnaireContainer"> + <h4>🌠Wiktionnaire</h4> + <ul id="wiktionnaireList"></ul> </div> - +</div> </body> </html> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 8cc2882..47dbb0e 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -299,15 +299,12 @@ async function fetchWiktionaryDefinition(word) { const cleanText = pages[0].extract.trim(); console.log("✅ Définition extraite :", cleanText); - - return [cleanText]; - } catch (error) { - console.error( - "⌠Erreur lors de la récupération de la définition du Wiktionnaire :", - error - ); - return ["âš ï¸ Aucune définition disponible."]; - } + // Retourner sous le format [{ source: "Wiktionnaire", text: "définition" }] + return [{ source: "Wiktionnaire", text: cleanText }]; + } catch (error) { + console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); + return []; + } } /** @@ -315,57 +312,56 @@ async function fetchWiktionaryDefinition(word) { * et un bouton "Afficher la suite" si le texte est trop long. */ function displayDefinitions(definitions) { - const definitionsList = document.getElementById("definitionsList"); - if (!definitionsList) { - console.warn("⌠Élément #definitionsList introuvable dans le DOM !"); + console.log("📖 Tentative d'affichage des définitions, données reçues :", definitions); + + if (!Array.isArray(definitions)) { + console.error("⌠Structure de définition incorrecte, attendu un tableau !"); return; } - // Rendre visible si c’était caché - definitionsList.style.display = "block"; - // Vider le conteneur avant d’ajouter du contenu - definitionsList.innerHTML = ""; + const mesLexiquesList = document.getElementById("mesLexiquesList"); + const wiktionnaireList = document.getElementById("wiktionnaireList"); + const mesLexiquesContainer = document.getElementById("mesLexiquesContainer"); + const wiktionnaireContainer = document.getElementById("wiktionnaireContainer"); - if (!definitions || definitions.length === 0) { - definitionsList.innerHTML = "<li>âš ï¸ Aucune définition trouvée.</li>"; + if (!mesLexiquesList || !wiktionnaireList) { + console.warn("⌠Impossible de trouver les conteneurs de définitions !"); return; } - // Parcours de chaque définition - definitions.forEach((def) => { - const li = document.createElement("li"); + mesLexiquesList.innerHTML = ""; + wiktionnaireList.innerHTML = ""; + + let hasLexiconDefinitions = false; + let hasWiktionaryDefinitions = false; - // Tronquer à 300 caractères - let truncated = def; - const maxLength = 300; - if (def.length > maxLength) { - truncated = def.slice(0, maxLength) + "..."; + definitions.forEach(({ source, text }) => { + if (!source || !text) { + console.warn("âš ï¸ Structure incorrecte détectée pour une définition :", { source, text }); + return; + } + + const li = document.createElement("li"); + li.textContent = text; + + if (source === "Lexiques") { + mesLexiquesList.appendChild(li); + hasLexiconDefinitions = true; + } else if (source === "Wiktionnaire") { + wiktionnaireList.appendChild(li); + hasWiktionaryDefinitions = true; } + }); - // Affichage brut dans un <pre> pour garder les sauts de ligne - const pre = document.createElement("pre"); - pre.style.whiteSpace = "pre-wrap"; - pre.textContent = truncated; + mesLexiquesContainer.style.display = hasLexiconDefinitions ? "block" : "none"; + wiktionnaireContainer.style.display = hasWiktionaryDefinitions ? "block" : "none"; - li.appendChild(pre); + console.log(`📚 Mes lexiques affichés: ${hasLexiconDefinitions}`); + console.log(`🌠Wiktionnaire affiché: ${hasWiktionaryDefinitions}`); +} - // S’il y a un tronquage, on ajoute le bouton "Afficher la suite" - if (def.length > maxLength) { - const readMoreBtn = document.createElement("button"); - readMoreBtn.textContent = "Afficher la suite"; - readMoreBtn.addEventListener("click", () => { - pre.textContent = def; // On remplace par la définition complète - readMoreBtn.remove(); // On retire le bouton - }); - // Petite séparation - li.appendChild(document.createElement("br")); - li.appendChild(readMoreBtn); - } - definitionsList.appendChild(li); - }); -} /** @@ -375,13 +371,16 @@ function displayDefinitions(definitions) { async function showDefinitions(word) { console.log(`📖 Recherche des définitions pour '${word}'...`); - // Récupère définitions du lexique - const lexiconDefinitions = await fetchLexiconDefinitions(word); + // Récupère définitions des lexiques (sera vide pour l'instant) + const lexiconDefinitions = []; // À remplacer avec une vraie requête API plus tard + // Récupère définitions du Wiktionnaire const wiktionaryDefinitions = await fetchWiktionaryDefinition(word); // Fusion des résultats et affichage const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; + console.log("📚 Définitions combinées :", allDefinitions); + displayDefinitions(allDefinitions); } @@ -479,29 +478,21 @@ document.addEventListener("DOMContentLoaded", async () => { } console.log("✅ Bouton #chercherDef détecté dans le DOM."); - - // Forcer l'activation du bouton chercherDefButton.style.pointerEvents = "auto"; chercherDefButton.style.display = "block"; chercherDefButton.style.visibility = "visible"; chercherDefButton.disabled = false; - chercherDefButton.addEventListener("click", () => { - const selectedWord = document - .getElementById("motSelectionne") - ?.textContent?.trim(); + chercherDefButton.addEventListener("click", async () => { + const selectedWord = document.getElementById("motSelectionne")?.textContent?.trim(); console.log("📖 Mot sélectionné :", selectedWord); if (selectedWord && selectedWord !== "Aucun mot sélectionné") { - console.log( - `📩 Envoi du message 'getDefinitionWiki' pour '${selectedWord}'` - ); - browser.runtime.sendMessage({ - action: "getDefinitionWiki", - selectedText: selectedWord, - }); + console.log(`📩 Recherche des définitions pour '${selectedWord}'`); + await showDefinitions(selectedWord); } else { console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); } }); }); + -- GitLab From 3a298aa0d5699db4d36de48ea100af0a15d95dc3 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 1 Feb 2025 15:42:00 +0100 Subject: [PATCH 07/32] 3 options def Wiktionnaire OK --- background/background.js | 120 ++++++----- background/browser_context_menu.js | 288 ++++++++++++++----------- "barre_lat\303\251rale/sidebar.html" | 54 ++++- "barre_lat\303\251rale/sidebar.js" | 235 +++++++++++--------- menu_contextuel/custom_context_menu.js | 67 ++---- 5 files changed, 427 insertions(+), 337 deletions(-) diff --git a/background/background.js b/background/background.js index 6a0d19f..7b1eda6 100644 --- a/background/background.js +++ b/background/background.js @@ -26,15 +26,31 @@ async function isUserConnected() { } async function saveToken(token) { - console.log("💾 Sauvegarde du token (à implémenter)..."); + console.log("💾 Sauvegarde du token..."); await browser.storage.local.set({ accessToken: token }); + // Recréer le menu contextuel pour refléter l'état connecté await createBrowserContextMenu(); } -// === Fonction pour récupérer la définition du Wiktionnaire === +// === Déconnexion simple (nettoie le token) === +async function disconnectFromLexicalDB() { + console.log("🔓 Déconnexion en cours..."); + await browser.storage.local.remove("accessToken"); + await createBrowserContextMenu(); + console.log("✅ Déconnecté !"); +} + +// === Ouvre la page de login BaLex (pour l'authentification) === +async function openLoginPage() { + console.log("🔑 Ouverture de la page de connexion..."); + const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL }); + loginTabId = loginTab.id; +} + +// === Fonction pour récupérer la définition du Wiktionnaire (utilisée si besoin) === async function fetchWiktionaryDefinition(word) { try { - console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); + console.log(`🔠Requête Wiktionnaire pour "${word}"...`); if (!word || word.trim() === "") { throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); @@ -56,25 +72,16 @@ async function fetchWiktionaryDefinition(word) { ? page.extract.trim() : "âš ï¸ Aucune définition trouvée sur le Wiktionnaire."; - console.log("📤 Envoi de la définition extraite à sidebar.js :", definition); - - browser.runtime.sendMessage({ - action: "fetchWiktionaryDefinitionResponse", - selectedText: word, - definitions: [definition], - }); + console.log("🌠Définition Wiktionnaire extraite :", definition); + return definition; } catch (error) { - console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); - browser.runtime.sendMessage({ - action: "fetchWiktionaryDefinitionResponse", - selectedText: word, - definitions: ["âš ï¸ Aucune définition disponible."], - }); + console.error("⌠Erreur Wiktionnaire :", error); + return "âš ï¸ Erreur lors de la récupération sur le Wiktionnaire."; } } -// Exemple de fonction pour afficher une notification +// === Exemples de fonctions additionnelles : connexion, notifications, etc. === function showWiktionaryNotification(selectedText) { browser.notifications.create({ type: "basic", @@ -84,11 +91,13 @@ function showWiktionaryNotification(selectedText) { }); } -// === Gestion des messages reçus === +// === Gestion des messages reçus (envoyés par la barre latérale, etc.) === browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { console.log("📩 Message reçu dans background.js :", message); switch (message.action) { + + // Bascule de l'authentification case "toggleAuth": { const isConnected = await isUserConnected(); if (isConnected) { @@ -99,27 +108,43 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { break; } + // Ancien message (Wiktionnaire direct) + // On peut le laisser si on veut juste Wiktionnaire, ou l'enlever case "getDefinitionWiki": { if (message.selectedText && message.selectedText.trim() !== "") { - console.log("📤 Envoi de la requête au Wiktionnaire pour :", message.selectedText); - fetchWiktionaryDefinition(message.selectedText.trim()); + console.log("🌠Requête Wiktionnaire pour :", message.selectedText); + const definition = await fetchWiktionaryDefinition(message.selectedText.trim()); + // Renvoyer la réponse vers la sidebar + browser.runtime.sendMessage({ + action: "fetchWiktionaryDefinitionResponse", + selectedText: message.selectedText, + definitions: [ + { + source: "Wiktionnaire", + text: definition, + }, + ], + }); } else { console.warn("âš ï¸ Texte sélectionné vide. Annulation de la requête."); } break; } + // Vérification du statut de connexion case "checkAuthStatus": { const connected = await isUserConnected(); sendResponse(connected); break; } + // Événement si l'auth change case "authStatusChanged": { console.log("🔄 Mise à jour de l'état d'authentification :", message.isLoggedIn); break; } + // Enregistrement du token case "saveToken": { if (message.token) { await saveToken(message.token); @@ -133,61 +158,56 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { break; } - return true; + return true; // Indique qu'on va éventuellement utiliser sendResponse async }); -// === Création du menu contextuel (navigateur) === +// === Création (ou mise à jour) du menu contextuel (navigateur) === async function createBrowserContextMenu() { await browser.contextMenus.removeAll(); const isConnected = await isUserConnected(); - // Menu "Obtenir une définition de mes lexiques" - if (isConnected) { - browser.contextMenus.create({ - id: "getDefinition", - title: "Obtenir une définition à partir de mes lexiques", - contexts: ["selection"], - }); - } - - // Menu "Rechercher la définition sur le Wiktionnaire" + // Autres items en fonction de ton besoin + // Par exemple, un bouton de connexion/déconnexion dans le menu browser.contextMenus.create({ - id: "getDefinitionWiki", - title: "Rechercher la définition sur le Wiktionnaire", - contexts: ["selection"], + id: "login", + title: isConnected ? "Se déconnecter de BaLex" : "Se connecter à BaLex", + contexts: ["all"], }); - // Menu "Connexion / Déconnexion" + // Séparateur browser.contextMenus.create({ - id: "login", - title: isConnected ? "Se déconnecter de BaLex" : "Se connecter à BaLex", + id: "separator", + type: "separator", contexts: ["all"], }); } createBrowserContextMenu(); +// === Écouteur des clics sur le menu contextuel === browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log("📦 Menu contextuel - item cliqué :", info.menuItemId); switch (info.menuItemId) { - case "getDefinitionWiki": + + // Cas unique : on veut lancer la recherche Lexiques + Wiktionnaire + case "getDefinition": if (info.selectionText) { - console.log("🌠Recherche Wiktionnaire pour :", info.selectionText); - await fetchWiktionaryDefinition(info.selectionText); + console.log("📖 Demande de définition combinée pour :", info.selectionText); + + // Envoi d'un message vers le script `browser_context_menu.js` ou la sidebar + // pour lancer la recherche combinée (ou on la fait ici directement). + browser.runtime.sendMessage({ + action: "getDefinition", + selectedText: info.selectionText.trim(), + }); + } else { - console.warn("âš ï¸ Aucun texte sélectionné pour la recherche Wiktionnaire."); + console.warn("âš ï¸ Aucun texte sélectionné pour la recherche."); } break; - case "getDefinition": - console.log("🔎 Demande de définition via mes lexiques pour :", info.selectionText); - browser.tabs.sendMessage(tab.id, { - action: "mot_selectionne", - selectedText: info.selectionText, - }); - break; - + // Bouton de connexion/déconnexion case "login": { const connected = await isUserConnected(); if (connected) { diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index 1e0fbd2..e75d0dd 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -17,74 +17,66 @@ async function loadAuthToken() { // Charger le token dès le démarrage du script loadAuthToken(); -// Création des options du menu contextuel du navigateur +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Création du menu contextuel du navigateur +// ───────────────────────────────────────────────────────────────────────────── + +// 1. Vérifier si le mot est dans le lexique browser.contextMenus.create({ id: "searchLexicon", title: "Ce mot est-il dans mon lexique ?", contexts: ["selection"], // Affiché uniquement lorsqu'un texte est sélectionné - icons: { - "16": "icons/recherche_lexique.png" - }, + icons: { "16": "icons/recherche_lexique.png" }, }); +// 2. Vérifier dans quels lexiques le mot est présent browser.contextMenus.create({ id: "checkLexicon", title: "Afficher dans quel(s) lexique(s) ce mot est présent", contexts: ["selection"], - icons: { - "16": "icons/quel_lexique.png" - }, - + icons: { "16": "icons/quel_lexique.png" }, }); +// 3. Ajouter un mot au lexique browser.contextMenus.create({ id: "addtoLexicon", title: "Ajouter ce mot à mon lexique", contexts: ["selection"], - icons: { - "16": "icons/ajout_lexique.png" - }, + icons: { "16": "icons/ajout_lexique.png" }, }); - +// Séparateur browser.contextMenus.create({ id: "separatorExtension", type: "separator", contexts: ["all"], }); +// 4. Recherche globale de définition : Lexiques + Wiktionnaire browser.contextMenus.create({ id: "getDefinition", - title: "Obtenir une définition à partir de mes lexiques", - contexts: ["selection"], - icons: { - "16": "icons/definition.png" - }, -}); - -browser.contextMenus.create({ - id: "getDefinitionWiki", - title: "Rechercher une définition dans le Wiktionnaire", + title: "Obtenir une définition", contexts: ["selection"], - icons: { - "16": "icons/definition_wiktionnaire.png" - }, + icons: { "16": "icons/definition.png" }, }); -// Ajouter un séparateur après les options de l'extension pour les distinguer des autres éléments du menu +// Séparateur après browser.contextMenus.create({ id: "separatorAfterExtension", type: "separator", contexts: ["all"], }); -// Gestion des clics sur les options du menu contextuel +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Gestion des clics sur le menu contextuel +// ───────────────────────────────────────────────────────────────────────────── + browser.contextMenus.onClicked.addListener(async (info, tab) => { if (info.selectionText) { console.log(`📩 Texte sélectionné dans le menu du navigateur : ${info.selectionText}`); - // Vérifier quelle option a été cliquée switch (info.menuItemId) { + // 1) Vérifier si le mot est dans le lexique case "searchLexicon": console.log("🔠Recherche dans le lexique :", info.selectionText); if (authToken) { @@ -94,6 +86,7 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } break; + // 2) Vérifier dans quels lexiques le mot est présent case "checkLexicon": console.log("📋 Vérification des lexiques :", info.selectionText); if (authToken) { @@ -103,18 +96,10 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } break; - case "getDefinition": - console.log("📖 Recherche des définitions :", info.selectionText); - if (authToken) { - await getDefinition(info.selectionText); - } else { - alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); - } - break; - - case "getDefinitionWiki": - console.log("🌠Recherche sur le Wiktionnaire :", info.selectionText); - await getDefinitionWiki(info.selectionText); + // 4) Un seul bouton pour une définition (Lexiques + Wiki) + case "getDefinitionAll": + console.log("🌠Recherche de définition :", info.selectionText); + await getDefinitionAll(info.selectionText); break; default: @@ -123,7 +108,123 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } }); -// Fonction pour rechercher un mot dans le lexique personnel +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Fonctions combinées : Lexiques + Wiktionnaire +// ───────────────────────────────────────────────────────────────────────────── + +/** + * Lance la recherche d’une définition à la fois dans : + * 1) Les lexiques de l’utilisateur (si authToken) + * 2) Le Wiktionnaire + * Puis envoie le tout à la barre latérale. + */ +async function getDefinition(selectedText) { + try { + // 1) Récupérer définitions dans les lexiques utilisateur + let userLexiconDefinitions = []; + if (authToken) { + userLexiconDefinitions = await getDefinitionFromUserLexicons(selectedText); + // getDefinitionFromUserLexicons => fonction qui retourne un tableau + // du style : [{ source: 'Lexiques', text: '...' }, ...] + } + + // 2) Récupérer définitions du Wiktionnaire + let wiktionaryDefinitions = await getDefinitionFromWiktionary(selectedText); + // idem, un tableau : [{ source: 'Wiktionnaire', text: '...' }] + + // 3) Fusion + const allDefinitions = [...userLexiconDefinitions, ...wiktionaryDefinitions]; + console.log("📠Définitions combinées :", allDefinitions); + + // 4) Envoi au script de la barre latérale pour affichage + browser.runtime.sendMessage({ + action: "showDefinitions", + selectedText, + definitions: allDefinitions, + }); + } catch (error) { + console.error("⌠Erreur lors de la recherche combinée des définitions :", error); + } +} + +/** + * Renvoie les définitions d’un mot provenant des lexiques de l’utilisateur. + * Retourne un tableau d’objets : [{ source: 'Lexiques', text: '...' }, ...] + */ +async function getDefinitionFromUserLexicons(selectedText) { + try { + console.log("🔎 getDefinitionFromUserLexicons pour :", selectedText); + // Ici, tu fais ton appel API vers tes lexiques + // Par exemple : + const response = await fetch( + `https://prisms.lezinter.net/api/definitions?word=${encodeURIComponent(selectedText)}`, + { headers: { Authorization: `Bearer ${authToken}` } } + ); + if (!response.ok) { + throw new Error(`⌠Erreur API lexiques : ${response.statusText}`); + } + const data = await response.json(); + + if (!data.definitions || data.definitions.length === 0) { + return []; + } + // On formate pour l'affichage + return data.definitions.map((def) => ({ + source: "Lexiques", + text: def, + })); + } catch (err) { + console.error("⌠getDefinitionFromUserLexicons :", err); + return []; + } +} + +/** + * Renvoie la définition Wiktionnaire d’un mot (FR). + * Retourne un tableau d’objets : [{ source: 'Wiktionnaire', text: '...' }] + */ +async function getDefinitionFromWiktionary(selectedText) { + try { + console.log("🔎 getDefinitionFromWiktionary pour :", selectedText); + if (!selectedText || selectedText.trim() === "") { + console.warn("âš ï¸ Aucun texte sélectionné."); + return []; + } + + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(selectedText)}`; + const response = await fetch(wiktionaryURL); + if (!response.ok) { + console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + return []; + } + + const data = await response.json(); + if (!data.query || !data.query.pages) { + return []; + } + + const pages = Object.values(data.query.pages); + if (pages.length === 0 || !pages[0].extract) { + return []; + } + + const definitionText = pages[0].extract.trim(); + console.log("✅ Définition Wiktionnaire :", definitionText); + + return [{ source: "Wiktionnaire", text: definitionText }]; + } catch (err) { + console.error("⌠getDefinitionFromWiktionary :", err); + return []; + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Autres fonctions de ton extension (recherche, vérification, etc.) +// ───────────────────────────────────────────────────────────────────────────── + +/** + * searchLexicon : Vérifie si le mot est présent dans le lexique personnel + */ async function searchLexicon(selectedText) { try { const lexicons = await getUserLexicons(authToken); @@ -150,7 +251,9 @@ async function searchLexicon(selectedText) { } } -// Fonction pour vérifier dans quels lexiques un mot est présent +/** + * checkLexicon : Affiche les lexiques dans lesquels le mot sélectionné est présent + */ async function checkLexicon(selectedText) { try { const lexicons = await getLexicons(authToken); @@ -172,93 +275,16 @@ async function checkLexicon(selectedText) { } } -// Fonction pour obtenir les définitions d'un mot -async function getDefinition(selectedText) { - try { - const lexicons = await getLexicons(authToken); - let definitions = []; - - for (const lexicon of lexicons) { - const entries = await getLexiconEntriesID(authToken, lexicon.id); - const entry = entries.find( - (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() - ); - - if (entry) { - const definitionData = await getDefinition(authToken, entry.id); - definitions.push(...extractDefinitions(definitionData)); - } - } - - console.log("📖 Définitions trouvées :", definitions); - if (definitions.length > 0) { - alert(`📖 Définitions pour "${selectedText}":\n\n` + definitions.join("\n")); - } else { - alert(`⌠Aucune définition trouvée pour "${selectedText}".`); - } - } catch (error) { - console.error("⌠Erreur lors de la récupération des définitions :", error); - } -} - -// Fonction pour rechercher une définition sur le Wiktionnaire -async function getDefinitionWiki(selectedText) { - try { - console.log(`🌠Recherche sur le Wiktionnaire pour '${selectedText}'...`); - - if (!selectedText || selectedText.trim() === "") { - console.warn("âš ï¸ Aucun texte sélectionné."); - return; - } - - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(selectedText)}`; - - const response = await fetch(wiktionaryURL); - if (!response.ok) { - console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); - alert(`⌠Aucune définition trouvée pour "${selectedText}" sur le Wiktionnaire.`); - return; - } - - const data = await response.json(); - if (!data.query || !data.query.pages) { - alert(`⌠Aucune définition trouvée pour "${selectedText}" sur le Wiktionnaire.`); - return; - } - - const pages = Object.values(data.query.pages); - if (pages.length === 0 || !pages[0].extract) { - alert(`⌠Aucune définition trouvée pour "${selectedText}" sur le Wiktionnaire.`); - return; - } - - const cleanText = pages[0].extract.trim(); - console.log(`✅ Définition trouvée : ${cleanText}`); - - // Envoyer la définition au script de la barre latérale - browser.runtime.sendMessage({ - action: "fetchWiktionaryDefinitionResponse", - selectedText, - definitions: [{ source: "Wiktionnaire", text: cleanText }], - }); - - } catch (error) { - console.error("⌠Erreur lors de la recherche sur le Wiktionnaire :", error); - } -} - - -// Fonction pour extraire les définitions d'une réponse API -function extractDefinitions(response) { - if (!response || !response.attributes || !response.attributes.Items) { - console.warn("âš ï¸ Structure de réponse inattendue."); - return []; +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Listeners supplémentaires (si besoin) +// ───────────────────────────────────────────────────────────────────────────── + +/** + * Écouteur pour d’autres actions envoyées par la barre latérale (optionnel). + * Par exemple, si la sidebar envoie `browser.runtime.sendMessage({action: 'getDefinitionAll'})`. + */ +browser.runtime.onMessage.addListener(async (message) => { + if (message.action === "getDefinitionAll") { + await getDefinitionAll(message.selectedText); } - - const items = response.attributes.Items; - return items - .flatMap((item) => - item.Sense?.Definitions?.map((def) => def.Def || "Définition non disponible") || [] - ) - .filter(Boolean); -} +}); diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 82c706f..4f9cd9f 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -113,6 +113,11 @@ border-radius: 5px; color: white; } + + #definitionsList { + list-style: none; + padding: 0; + } #definitionsList li { margin-bottom: 10px; @@ -123,6 +128,40 @@ color: #ffa500; } + /* Popup (modal) caché par défaut */ + .modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: rgba(0,0,0,0.5); + display: none; + align-items: center; + justify-content: center; + z-index: 9999; + } + + .modal-content { + background: white; + color:#8d5c70; + padding: 1rem; + max-width: 600px; + max-height: 80vh; + overflow-y: auto; + border-radius: 8px; + } + + .close-button { + float: right; + cursor: pointer; + font-weight: bold; + color: #666; + } + .close-button:hover { + color: #000; + } + /* Activer/désactiver le surlignage */ #highlighting-options p { margin: 5px 0; @@ -153,7 +192,7 @@ <button id="add-word-button">Ajouter le mot sélectionné</button> </div> - <button id="chercherDef">Chercher la/les définition(s)</button> + <button id="chercherDef">Rechercher une définition</button> <div id="possible-definitions" style="display: none;"> <label style="font-size: small;"> <input type="checkbox" id="toggle-definitions"> @@ -177,6 +216,19 @@ <h4>🌠Wiktionnaire</h4> <ul id="wiktionnaireList"></ul> </div> + + <div id="noDefinitionsContainer" style="display: none; color: #8d5c70;"> + <p>Aucune définition trouvée.</p> + </div> + + <!-- Fenêtre modale cachée --> + <div id="modalOverlay" class="modal-overlay"> + <div class="modal-content"> + <span id="closeModal" class="close-button">X</span> + <div id="modalFullText"></div> + </div> + </div> + </div> </body> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 47dbb0e..79e2bec 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -11,16 +11,20 @@ let authToken = null; // â–Œ Fonctions liées au token // ───────────────────────────────────────────────────────────────────────────── -// Vérifie le format du token +/** + * Vérifie le format du token + */ function validateToken(token) { - const isValid = /^\S+\.\S+\.\S+$/.test(token); + const isValid = /^\S+\\.\\S+\\.\\S+$/.test(token); if (!isValid) { console.warn("âš ï¸ Le format du token semble incorrect :", token); } return isValid; } -// Récupération du token depuis le stockage local +/** + * Récupération du token depuis le stockage local + */ async function getAuthTokenFromStorage() { try { const { accessToken } = await browser.storage.local.get("accessToken"); @@ -177,7 +181,7 @@ async function fetchLexicons() { } // Appel à l'API (exemple) - const lexicons = await getLexicons(authToken, 52, "fr"); + const lexicons = await getLexicons(authToken, 52, "fr"); console.log("📚 Réponse brute de l'API :", lexicons); if (!Array.isArray(lexicons) || lexicons.length === 0) { @@ -226,14 +230,16 @@ async function handleAuthButtonClick() { // ───────────────────────────────────────────────────────────────────────────── /** - * Récupère les définitions d'un mot dans les lexiques de l'utilisateur. + * Récupère les définitions d'un mot dans les lexiques de l'utilisateur + * Retourne un tableau d'objets : [{ source: 'Lexiques', text: '...' }, ...] */ async function fetchLexiconDefinitions(word) { try { console.log(`🔠Recherche des définitions de '${word}' dans les lexiques...`); if (!authToken) { - throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); + // Pas de token => pas de recherche possible dans les lexiques + return []; } const response = await fetch( @@ -249,21 +255,24 @@ async function fetchLexiconDefinitions(word) { console.log("📚 Réponse API (lexiques) :", data); if (!data.definitions || data.definitions.length === 0) { - throw new Error("âš ï¸ Aucune définition trouvée dans les lexiques."); + // Aucune définition trouvée, on renvoie un tableau vide + return []; } - return data.definitions; + // On formate pour respecter { source, text } + return data.definitions.map((def) => ({ + source: "Lexiques", + text: def, + })); } catch (error) { - console.error( - "⌠Erreur lors de la récupération des définitions des lexiques :", - error - ); + console.error("⌠Erreur lors de la récupération des définitions des lexiques :", error); return []; } } /** * Récupère la définition d'un mot depuis le Wiktionnaire (fr). + * Retourne un tableau d'objets : [{ source: 'Wiktionnaire', text: '...' }] */ async function fetchWiktionaryDefinition(word) { try { @@ -271,7 +280,7 @@ async function fetchWiktionaryDefinition(word) { if (!word || word.trim() === "") { console.warn("âš ï¸ Mot vide, impossible d'envoyer la requête."); - return ["âš ï¸ Mot vide, impossible d'envoyer la requête."]; + return []; } const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent( @@ -282,52 +291,48 @@ async function fetchWiktionaryDefinition(word) { const response = await fetch(wiktionaryURL); if (!response.ok) { console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); - return [`⌠Erreur API Wiktionnaire: ${response.statusText}`]; + return []; } const data = await response.json(); console.log("📖 Réponse API (Wiktionnaire) :", data); if (!data.query || !data.query.pages) { - return ["âš ï¸ Réponse inattendue du Wiktionnaire."]; + return []; } const pages = Object.values(data.query.pages); if (pages.length === 0 || !pages[0].extract) { - return ["âš ï¸ Aucune définition trouvée sur le Wiktionnaire."]; + return []; } const cleanText = pages[0].extract.trim(); console.log("✅ Définition extraite :", cleanText); - // Retourner sous le format [{ source: "Wiktionnaire", text: "définition" }] + return [{ source: "Wiktionnaire", text: cleanText }]; - } catch (error) { - console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); - return []; - } + } catch (error) { + console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); + return []; + } } /** - * Affiche simplement les définitions sous forme de <pre>, avec tronquage - * et un bouton "Afficher la suite" si le texte est trop long. + * Affiche les définitions dans deux listes : + * - Mes lexiques (#mesLexiquesList) + * - Wiktionnaire (#wiktionnaireList) */ -function displayDefinitions(definitions) { - console.log("📖 Tentative d'affichage des définitions, données reçues :", definitions); +const MAX_LENGTH = 200; +const modalOverlay = document.getElementById("modalOverlay"); +const modalFullText = document.getElementById("modalFullText"); +const closeModalBtn = document.getElementById("closeModal"); - if (!Array.isArray(definitions)) { - console.error("⌠Structure de définition incorrecte, attendu un tableau !"); - return; - } +function displayDefinitions(definitions) { + console.log("📖 Affichage des définitions reçues :", definitions); + if (!Array.isArray(definitions)) return; const mesLexiquesList = document.getElementById("mesLexiquesList"); const wiktionnaireList = document.getElementById("wiktionnaireList"); - const mesLexiquesContainer = document.getElementById("mesLexiquesContainer"); - const wiktionnaireContainer = document.getElementById("wiktionnaireContainer"); - - if (!mesLexiquesList || !wiktionnaireList) { - console.warn("⌠Impossible de trouver les conteneurs de définitions !"); - return; - } + const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); mesLexiquesList.innerHTML = ""; wiktionnaireList.innerHTML = ""; @@ -336,13 +341,28 @@ function displayDefinitions(definitions) { let hasWiktionaryDefinitions = false; definitions.forEach(({ source, text }) => { - if (!source || !text) { - console.warn("âš ï¸ Structure incorrecte détectée pour une définition :", { source, text }); - return; - } + if (!source || !text) return; const li = document.createElement("li"); - li.textContent = text; + let displayedText = text; + if (text.length > MAX_LENGTH) { + displayedText = text.slice(0, MAX_LENGTH) + "... "; + const readMoreLink = document.createElement("a"); + readMoreLink.href = "#"; + readMoreLink.textContent = "[Lire la suite]"; + readMoreLink.style.marginLeft = "5px"; + readMoreLink.style.color = "#a08e9f"; + readMoreLink.style.textDecoration = "underline"; + readMoreLink.style.cursor = "pointer"; + readMoreLink.addEventListener("click", (event) => { + event.preventDefault(); + openDefinitionPopup(text); + }); + li.appendChild(document.createTextNode(displayedText)); + li.appendChild(readMoreLink); + } else { + li.textContent = displayedText; + } if (source === "Lexiques") { mesLexiquesList.appendChild(li); @@ -353,16 +373,26 @@ function displayDefinitions(definitions) { } }); - mesLexiquesContainer.style.display = hasLexiconDefinitions ? "block" : "none"; - wiktionnaireContainer.style.display = hasWiktionaryDefinitions ? "block" : "none"; - - console.log(`📚 Mes lexiques affichés: ${hasLexiconDefinitions}`); - console.log(`🌠Wiktionnaire affiché: ${hasWiktionaryDefinitions}`); + document.getElementById("mesLexiquesContainer").style.display = hasLexiconDefinitions ? "block" : "none"; + document.getElementById("wiktionnaireContainer").style.display = hasWiktionaryDefinitions ? "block" : "none"; + noDefinitionsContainer.style.display = (!hasLexiconDefinitions && !hasWiktionaryDefinitions) ? "block" : "none"; + noDefinitionsContainer.textContent = "Aucune définition trouvée pour ce mot."; } +function openDefinitionPopup(fullText) { + modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; + modalOverlay.style.display = "flex"; +} +function closeDefinitionPopup() { + modalOverlay.style.display = "none"; + modalFullText.innerHTML = ""; +} - +closeModalBtn.addEventListener("click", closeDefinitionPopup); +modalOverlay.addEventListener("click", (event) => { + if (event.target === modalOverlay) closeDefinitionPopup(); +}); /** * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire @@ -371,36 +401,41 @@ function displayDefinitions(definitions) { async function showDefinitions(word) { console.log(`📖 Recherche des définitions pour '${word}'...`); - // Récupère définitions des lexiques (sera vide pour l'instant) - const lexiconDefinitions = []; // À remplacer avec une vraie requête API plus tard + // (Optionnel) On peut afficher un message de "Chargement..." dans noDefinitionsContainer + const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = "Chargement des définitions..."; + noDefinitionsContainer.style.display = "block"; + } - // Récupère définitions du Wiktionnaire - const wiktionaryDefinitions = await fetchWiktionaryDefinition(word); + try { + // Lance en parallèle la récupération côté Babalex et Wiktionnaire + const [lexiconDefinitions, wiktionaryDefinitions] = await Promise.all([ + fetchLexiconDefinitions(word), // Par ex: renvoie [{ source: "Lexiques", text: "..."} ...] + fetchWiktionaryDefinition(word) // Par ex: renvoie [{ source: "Wiktionnaire", text: "..."} ...] + ]); - // Fusion des résultats et affichage - const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; - console.log("📚 Définitions combinées :", allDefinitions); + // Fusion des deux tableaux + const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; + console.log("📚 Définitions combinées :", allDefinitions); - displayDefinitions(allDefinitions); -} + // Affichage + displayDefinitions(allDefinitions); -/** - * Récupère la définition d'un mot via le background. - */ -function requestWiktionaryDefinition(word) { - console.log(`📩 Envoi du message 'fetchWiktionaryDefinition' pour '${word}'`); - browser.runtime - .sendMessage({ action: "fetchWiktionaryDefinition", selectedText: word }) - .then(() => { - console.log("📩 Message envoyé avec succès à background.js !"); - }) - .catch((error) => { - console.error("⌠Erreur lors de l'envoi du message à background.js :", error); - }); + } catch (error) { + console.error("⌠Erreur lors de la récupération des définitions :", error); + + // En cas d'erreur, on peut l'afficher dans noDefinitionsContainer + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = "⌠Une erreur est survenue lors de la récupération des définitions."; + noDefinitionsContainer.style.display = "block"; + } + } } + // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion des messages reçus +// â–Œ Gestion des messages reçus (notamment si le background nous en envoie) // ───────────────────────────────────────────────────────────────────────────── browser.runtime.onMessage.addListener(async (message) => { @@ -429,15 +464,7 @@ browser.runtime.onMessage.addListener(async (message) => { showDefinitions(message.selectedText); } - // 4. Récupération des définitions Wiktionnaire côté barre latérale directement - else if (message.action === "fetchWiktionaryDefinition" && message.selectedText) { - console.log("🌠Recherche des définitions sur le Wiktionnaire pour :", message.selectedText); - const definitions = await fetchWiktionaryDefinition(message.selectedText); - console.log("📖 Définitions récupérées :", definitions); - displayDefinitions(definitions); - } - - // 4bis. Réception de la définition Wiktionnaire envoyée par le background + // 4. Reception d'une définition Wiktionnaire envoyée par le background else if (message.action === "fetchWiktionaryDefinitionResponse" && message.selectedText) { console.log(`📖 Réception de la définition du Wiktionnaire pour '${message.selectedText}'`); displayDefinitions(message.definitions); @@ -454,6 +481,14 @@ browser.runtime.onMessage.addListener(async (message) => { } }); +browser.runtime.onMessage.addListener(async (message) => { + if (message.action === "showDefinitions" && Array.isArray(message.definitions)) { + displayDefinitions(message.definitions); + } +}); + + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Initialisation après chargement du DOM // ───────────────────────────────────────────────────────────────────────────── @@ -470,29 +505,27 @@ document.addEventListener("DOMContentLoaded", async () => { authButton.addEventListener("click", handleAuthButtonClick); } - // Gestion du bouton "Chercher la/les définition(s)" + // Gestion du bouton de recherche de définitions const chercherDefButton = document.getElementById("chercherDef"); - if (!chercherDefButton) { + if (chercherDefButton) { + chercherDefButton.addEventListener("click", async () => { + const selectedWord = document.getElementById("motSelectionne")?.textContent?.trim(); + console.log("📖 Mot sélectionné :", selectedWord); + + if (selectedWord && selectedWord !== "Aucun mot sélectionné") { + console.log(`📩 Recherche des définitions (lexiques + Wiktionnaire) pour '${selectedWord}'`); + await showDefinitions(selectedWord); + } else { + console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); + } + }); + + console.log("✅ Bouton #chercherDef détecté dans le DOM."); + chercherDefButton.style.pointerEvents = "auto"; + chercherDefButton.style.display = "block"; + chercherDefButton.style.visibility = "visible"; + chercherDefButton.disabled = false; + } else { console.error("⌠ERREUR : Bouton #chercherDef introuvable."); - return; } - - console.log("✅ Bouton #chercherDef détecté dans le DOM."); - chercherDefButton.style.pointerEvents = "auto"; - chercherDefButton.style.display = "block"; - chercherDefButton.style.visibility = "visible"; - chercherDefButton.disabled = false; - - chercherDefButton.addEventListener("click", async () => { - const selectedWord = document.getElementById("motSelectionne")?.textContent?.trim(); - console.log("📖 Mot sélectionné :", selectedWord); - - if (selectedWord && selectedWord !== "Aucun mot sélectionné") { - console.log(`📩 Recherche des définitions pour '${selectedWord}'`); - await showDefinitions(selectedWord); - } else { - console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); - } - }); }); - diff --git a/menu_contextuel/custom_context_menu.js b/menu_contextuel/custom_context_menu.js index ee6b200..a631f1f 100644 --- a/menu_contextuel/custom_context_menu.js +++ b/menu_contextuel/custom_context_menu.js @@ -25,7 +25,6 @@ function injectWhiteBox() { // Exemples pour générer les URLs des icônes const addLexiconPath = browser.runtime.getURL("icons/ajout_lexique.png"); const getDefinitionPath = browser.runtime.getURL("icons/definition.png"); - const getDefinitionWikiPath = browser.runtime.getURL("icons/definition_wiktionnaire.png"); const loginPath = browser.runtime.getURL("icons/connexion.png"); // Construction du HTML @@ -39,17 +38,12 @@ function injectWhiteBox() { <img src="${addLexiconPath}" alt="Ajouter au lexique" class="icon" id="addLexiconButton"> </div> - <!-- Bouton 2 - Définition interne (Babalex) --> - <div class="icon-container" title="Obtenir la définition (Babalex)"> + <!-- Bouton 2 - Définition (Babalex + Wiki) --> + <div class="icon-container" title="Obtenir la définition"> <img src="${getDefinitionPath}" alt="Obtenir la définition" class="icon" id="getDefinitionButton"> </div> - <!-- Bouton 3 - Wiktionnaire --> - <div class="icon-container" title="Rechercher dans le Wiktionnaire"> - <img src="${getDefinitionWikiPath}" alt="Wiktionnaire" class="icon" id="getDefinitionWikiButton"> - </div> - - <!-- Bouton 4 - Connexion --> + <!-- Bouton 3 - Connexion --> <div class="icon-container" title="Connectez-vous à BaLex"> <img src="${loginPath}" alt="Se connecter" class="icon" id="loginButton" style="display: none;"> </div> @@ -67,7 +61,6 @@ function injectWhiteBox() { function setupWhiteBoxActions() { const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); - const getDefinitionWikiBtn = document.getElementById("getDefinitionWikiButton"); const loginBtn = document.getElementById("loginButton"); // Ajouter le mot au lexique perso @@ -83,39 +76,17 @@ function setupWhiteBoxActions() { } }; - // Obtenir une définition depuis Babalex - getDefinitionBtn.onclick = async () => { - const selectedText = getSelectedWord(); - console.log("📖 Recherche des définitions (Babalex) :", selectedText); - if (!selectedText) return; - - if (authToken) { - // ICI, on envoie le mot à la barre latérale (ou background) - // pour qu'il affiche la définition. - // Ex: "getDefinition" = action gérée dans sidebar.js + // Obtenir une définition (Babalex + Wiktionnaire) + getDefinitionBtn.onclick = () => { + const selectedText = getSelectedWord().trim(); + if (selectedText) { browser.runtime.sendMessage({ action: "getDefinition", selectedText }); - } else { - alert("âš ï¸ Veuillez vous connecter pour utiliser cette fonction."); } }; - // Définition Wiktionnaire - getDefinitionWikiBtn.onclick = () => { - const selectedText = getSelectedWord(); - console.log("🌠Recherche sur le Wiktionnaire :", selectedText); - if (!selectedText) return; - - // On envoie un message pour que la barre latérale (ou background) - // récupère la définition Wiktionnaire et l'affiche - browser.runtime.sendMessage({ - action: "fetchWiktionaryDefinition", - selectedText - }); - }; - // Login / Toggle Auth loginBtn.onclick = () => { alert("Vous allez être redirigé(e) vers la page de connexion."); @@ -129,44 +100,32 @@ function updateMenuVisibility() { const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); - const getDefinitionWikiBtn = document.getElementById("getDefinitionWikiButton"); const loginBtn = document.getElementById("loginButton"); - if (!addLexiconBtn || !getDefinitionBtn || !getDefinitionWikiBtn || !loginBtn) { + if (!addLexiconBtn || !getDefinitionBtn || !loginBtn) { console.warn("âš ï¸ Un des boutons n'a pas été trouvé dans le DOM."); return; } if (authToken) { - // Utilisateur connecté => tout sauf login + // Utilisateur connecté => on affiche tout sauf le login addLexiconBtn.style.display = "inline-block"; getDefinitionBtn.style.display = "inline-block"; - getDefinitionWikiBtn.style.display = "inline-block"; loginBtn.style.display = "none"; } else { - // Utilisateur déconnecté => seul Wiktionnaire + login + // Utilisateur déconnecté => on masque l'ajout de lexique, on affiche le bouton définition et login addLexiconBtn.style.display = "none"; - getDefinitionBtn.style.display = "none"; - getDefinitionWikiBtn.style.display = "inline-block"; + getDefinitionBtn.style.display = "inline-block"; // Toujours visible loginBtn.style.display = "inline-block"; } } /** * Récupère le mot affiché dans #selectedWord. - * On suppose maintenant que le contenu est "Mot sélectionné : XXX". */ function getSelectedWord() { const selectedWordElement = document.getElementById("selectedWord"); - if (!selectedWordElement) return ""; - - // Si le texte est "Mot sélectionné : XXX" on récupère la partie après la " : " - const text = selectedWordElement.textContent || ""; - const prefix = "Mot sélectionné : "; - if (text.startsWith(prefix)) { - return text.slice(prefix.length).trim(); - } - return ""; + return selectedWordElement ? selectedWordElement.textContent.trim() : ""; } // Affiche le menu contextuel (whiteBox) à la position du clic @@ -179,7 +138,7 @@ function showWhiteBox(event, selectedText) { // Met à jour l'affichage du mot sélectionné => "Mot sélectionné : XXX" const selectedWordElement = document.getElementById("selectedWord"); - selectedWordElement.textContent = `Mot sélectionné : ${selectedText}`; + selectedWordElement.textContent = `${selectedText}`; // Récupère la position de la sélection const selection = window.getSelection(); -- GitLab From d5b26e50fcaa08dc03eaec7ef356f24afb0d4b64 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 1 Feb 2025 16:26:45 +0100 Subject: [PATCH 08/32] Correction connexion --- background/background.js | 342 +++++++++++++++++++++++------ "barre_lat\303\251rale/sidebar.js" | 14 +- 2 files changed, 271 insertions(+), 85 deletions(-) diff --git a/background/background.js b/background/background.js index 7b1eda6..803d7f9 100644 --- a/background/background.js +++ b/background/background.js @@ -1,7 +1,6 @@ // === Variables globales / de configuration === -let isExtensionActive = true; -let areStatsActive = false; - +let isExtensionActive = true; // Activation globale de l'extension +let areStatsActive = false; // Activation des statistiques let originalTabId = null; let loginTabId = null; @@ -19,61 +18,135 @@ browser.runtime.onStartup.addListener(() => { console.log("🔄 Extension démarrée (onStartup)."); }); -// === Vérifie si l'utilisateur est connecté (token présent) === +// === Suivi des changements dans le stockage === +browser.storage.onChanged.addListener((changes) => { + if (changes.extensionActive) { + isExtensionActive = changes.extensionActive.newValue; + console.log("✅ Extension activée :", isExtensionActive); + } + if (changes.statsActive) { + areStatsActive = changes.statsActive.newValue; + console.log("📊 Statistiques activées :", areStatsActive); + } + // Recréer le menu contextuel du navigateur quand l'état change + createBrowserContextMenu(); +}); + +// === Fonctions utilitaires === + +/** + * Vérifie si l'utilisateur est connecté (token présent dans le stockage). + */ async function isUserConnected() { const { accessToken } = await browser.storage.local.get("accessToken"); return !!accessToken; } -async function saveToken(token) { - console.log("💾 Sauvegarde du token..."); - await browser.storage.local.set({ accessToken: token }); - // Recréer le menu contextuel pour refléter l'état connecté +/** + * Rafraîchit l'UI globale : recrée le menu contextuel et notifie les autres parties. + */ +async function refreshAllUI() { + console.log("🔄 Rafraîchissement global de l'UI..."); await createBrowserContextMenu(); + browser.runtime.sendMessage({ action: "refreshUI" }); +} + +// === Fonctions d'authentification === + +/** + * Ouvre la page de connexion BaLex. + * Mémorise l'onglet courant pour y revenir, puis ouvre un nouvel onglet pour la connexion. + */ +async function openLoginPage() { + console.log("🔗 Ouverture de la page de connexion."); + // 1) Retrouver l'onglet actuellement actif (pour y revenir plus tard) + const [currentTab] = await browser.tabs.query({ active: true, currentWindow: true }); + if (currentTab) { + originalTabId = currentTab.id; + console.log("✅ Onglet courant mémorisé, ID =", originalTabId); + } + // 2) Créer l’onglet de login + const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL }); + loginTabId = loginTab.id; + console.log("✅ Onglet de login créé, ID =", loginTabId); + // Notifier que l'authentification est en cours + browser.runtime.sendMessage({ action: "authStatusChanged", isLoggedIn: false }); } -// === Déconnexion simple (nettoie le token) === +/** + * Déconnecte l'utilisateur en supprimant le token et en rafraîchissant l'UI. + */ async function disconnectFromLexicalDB() { console.log("🔓 Déconnexion en cours..."); await browser.storage.local.remove("accessToken"); - await createBrowserContextMenu(); - console.log("✅ Déconnecté !"); + console.log("🔓 Token supprimé avec succès."); + showNotification( + "Déconnexion réussie", + "Vous êtes maintenant déconnecté(e).", + "icons/logout.png" + ); + // Rafraîchissement global de l'UI + await refreshAllUI(); } -// === Ouvre la page de login BaLex (pour l'authentification) === -async function openLoginPage() { - console.log("🔑 Ouverture de la page de connexion..."); - const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL }); - loginTabId = loginTab.id; +/** + * Sauvegarde le token et ferme la page de login si nécessaire. + * Ramène l'utilisateur sur l'onglet initial et rafraîchit l'UI. + */ +async function saveToken(token) { + console.log("✅ Sauvegarde du token :", token); + await browser.storage.local.set({ accessToken: token }); + + // Fermer l'onglet de login s'il est ouvert + if (loginTabId) { + try { + await browser.tabs.remove(loginTabId); + console.log("🗙 Onglet de login fermé après connexion réussie."); + } catch (err) { + console.warn("Impossible de fermer l'onglet de login :", err); + } + loginTabId = null; + } + // Rétablir l'onglet initial + if (originalTabId) { + try { + await browser.tabs.update(originalTabId, { active: true }); + console.log("🔙 Retour sur l'onglet initial :", originalTabId); + } catch (err) { + console.warn("Impossible de basculer sur l'onglet initial :", err); + } + originalTabId = null; + } + // Rafraîchir toute l'UI + await refreshAllUI(); } -// === Fonction pour récupérer la définition du Wiktionnaire (utilisée si besoin) === +// === Fonction pour récupérer la définition du Wiktionnaire === + +/** + * Récupère la définition d'un mot depuis le Wiktionnaire. + * @param {string} word - Le mot à rechercher. + * @returns {Promise<string>} - La définition extraite ou un message d'erreur. + */ async function fetchWiktionaryDefinition(word) { try { console.log(`🔠Requête Wiktionnaire pour "${word}"...`); - if (!word || word.trim() === "") { throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); } - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; const response = await fetch(wiktionaryURL); - if (!response.ok) { throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); } - const data = await response.json(); console.log("📖 Réponse API (Wiktionnaire) :", data); - const pages = data.query?.pages; const page = pages ? Object.values(pages)[0] : null; const definition = page && page.extract ? page.extract.trim() : "âš ï¸ Aucune définition trouvée sur le Wiktionnaire."; - console.log("🌠Définition Wiktionnaire extraite :", definition); - return definition; } catch (error) { console.error("⌠Erreur Wiktionnaire :", error); @@ -81,7 +154,10 @@ async function fetchWiktionaryDefinition(word) { } } -// === Exemples de fonctions additionnelles : connexion, notifications, etc. === +/** + * Affiche une notification indiquant qu'une définition Wiktionnaire a été trouvée. + * @param {string} selectedText - Le mot concerné. + */ function showWiktionaryNotification(selectedText) { browser.notifications.create({ type: "basic", @@ -91,13 +167,12 @@ function showWiktionaryNotification(selectedText) { }); } -// === Gestion des messages reçus (envoyés par la barre latérale, etc.) === +// === Gestion des messages reçus === browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { console.log("📩 Message reçu dans background.js :", message); switch (message.action) { - - // Bascule de l'authentification + // Bascule d'authentification case "toggleAuth": { const isConnected = await isUserConnected(); if (isConnected) { @@ -107,14 +182,12 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { } break; } - - // Ancien message (Wiktionnaire direct) - // On peut le laisser si on veut juste Wiktionnaire, ou l'enlever + // Demande de définition via le Wiktionnaire case "getDefinitionWiki": { if (message.selectedText && message.selectedText.trim() !== "") { console.log("🌠Requête Wiktionnaire pour :", message.selectedText); const definition = await fetchWiktionaryDefinition(message.selectedText.trim()); - // Renvoyer la réponse vers la sidebar + // Envoyer la réponse (ex: vers la sidebar) browser.runtime.sendMessage({ action: "fetchWiktionaryDefinitionResponse", selectedText: message.selectedText, @@ -130,21 +203,18 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { } break; } - - // Vérification du statut de connexion + // Vérification du statut d'authentification case "checkAuthStatus": { const connected = await isUserConnected(); sendResponse(connected); break; } - - // Événement si l'auth change + // Notification de changement d'état d'authentification case "authStatusChanged": { console.log("🔄 Mise à jour de l'état d'authentification :", message.isLoggedIn); break; } - - // Enregistrement du token + // Enregistrement du token reçu case "saveToken": { if (message.token) { await saveToken(message.token); @@ -153,61 +223,82 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { } break; } - default: break; } - - return true; // Indique qu'on va éventuellement utiliser sendResponse async + return true; }); -// === Création (ou mise à jour) du menu contextuel (navigateur) === +// === Création et gestion du menu contextuel === + +/** + * Crée (ou recrée) le menu contextuel du navigateur en fonction du statut de connexion. + */ async function createBrowserContextMenu() { await browser.contextMenus.removeAll(); const isConnected = await isUserConnected(); - // Autres items en fonction de ton besoin - // Par exemple, un bouton de connexion/déconnexion dans le menu + // Si connecté : options supplémentaires pour le lexique + if (isConnected) { + browser.contextMenus.create({ + id: "searchLexicon", + title: "Vérifier si le mot est dans le lexique personnel", + contexts: ["selection"], + }); + browser.contextMenus.create({ + id: "checkLexicon", + title: "Afficher dans quels lexiques le mot est présent", + contexts: ["selection"], + }); + browser.contextMenus.create({ + id: "getDefinition", + title: "Obtenir une définition à partir de mes lexiques", + contexts: ["selection"], + }); + } + // Option pour rechercher sur le Wiktionnaire (accessible à tous) browser.contextMenus.create({ - id: "login", - title: isConnected ? "Se déconnecter de BaLex" : "Se connecter à BaLex", - contexts: ["all"], + id: "getDefinitionWiki", + title: "Rechercher une définition sur le Wiktionnaire", + contexts: ["selection"], }); - - // Séparateur + // Bouton de connexion/déconnexion browser.contextMenus.create({ - id: "separator", - type: "separator", + id: "login", + title: isConnected ? "Se déconnecter de BaLex" : "Se connecter à BaLex", contexts: ["all"], }); } createBrowserContextMenu(); -// === Écouteur des clics sur le menu contextuel === browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log("📦 Menu contextuel - item cliqué :", info.menuItemId); - switch (info.menuItemId) { - - // Cas unique : on veut lancer la recherche Lexiques + Wiktionnaire + case "searchLexicon": + browser.tabs.sendMessage(tab.id, { + action: "searchLexicon", + selectedText: info.selectionText, + }); + break; + case "checkLexicon": + browser.tabs.sendMessage(tab.id, { + action: "checkLexicon", + selectedText: info.selectionText, + }); + break; case "getDefinition": - if (info.selectionText) { - console.log("📖 Demande de définition combinée pour :", info.selectionText); - - // Envoi d'un message vers le script `browser_context_menu.js` ou la sidebar - // pour lancer la recherche combinée (ou on la fait ici directement). - browser.runtime.sendMessage({ - action: "getDefinition", - selectedText: info.selectionText.trim(), - }); - - } else { - console.warn("âš ï¸ Aucun texte sélectionné pour la recherche."); - } + browser.tabs.sendMessage(tab.id, { + action: "getDefinition", + selectedText: info.selectionText, + }); + break; + case "getDefinitionWiki": + browser.tabs.sendMessage(tab.id, { + action: "getDefinitionWiki", + selectedText: info.selectionText, + }); break; - - // Bouton de connexion/déconnexion case "login": { const connected = await isUserConnected(); if (connected) { @@ -217,8 +308,115 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } break; } - default: - console.warn(`âš ï¸ Aucune action définie pour l'élément : ${info.menuItemId}`); + console.warn(`Aucune action définie pour l'élément : ${info.menuItemId}`); } }); + +// === Web Navigation : Injection de scripts et récupération du token === + +browser.webNavigation.onCompleted.addListener(async (details) => { + if (!isExtensionActive) { + console.log("🚫 Extension désactivée, aucune injection script."); + return; + } + const url = new URL(details.url); + + // Sur la page de login : injection d'un popup d'instruction + if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/login") { + console.log("📘 Injection du popup d'instruction sur la page de login Prisms."); + showInstructionPopup(details); + } + // Sur la page /balex : tentative de récupération du token + if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/headquarters/balex") { + console.log("🟢 Page /balex détectée. Tentative de récupération du token."); + try { + await new Promise(resolve => setTimeout(resolve, 3000)); // Attendre 3 secondes + await browser.tabs.executeScript(details.tabId, { + code: ` + console.log("🔠Recherche du token..."); + const tokenElement = document.getElementById("accesToken"); + if (tokenElement) { + const token = tokenElement.innerText.trim(); + console.log("🔠Token détecté :", token); + browser.runtime.sendMessage({ action: "saveToken", token }); + } else { + console.error("⌠Token introuvable."); + } + ` + }); + } catch (error) { + console.error("⌠Erreur lors de la récupération du token :", error); + } + } +}, { url: [{ hostContains: "prisms.lezinter.net" }] }); + +// === Web Request : Redirection automatique vers /balex === + +browser.webRequest.onBeforeRequest.addListener( + function(details) { + if (details.url === "https://prisms.lezinter.net/fr/headquarters/") { + console.log("🚀 Redirection automatique vers /balex."); + return { redirectUrl: AUTH_BALEX_URL }; + } + }, + { urls: ["https://prisms.lezinter.net/fr/headquarters/*"] }, + ["blocking"] +); + +// === Affichage d'un popup d'instruction sur /fr/login === + +function showInstructionPopup(details) { + browser.tabs.executeScript(details.tabId, { + code: ` + if (!document.getElementById("balex-instruction-popup")) { + const popup = document.createElement("div"); + popup.id = "balex-instruction-popup"; + popup.style.position = "fixed"; + popup.style.top = "50%"; + popup.style.left = "50%"; + popup.style.transform = "translate(-50%, -50%)"; + popup.style.backgroundColor = "#a08e9f"; + popup.style.color = "#323046"; + popup.style.padding = "20px"; + popup.style.borderRadius = "10px"; + popup.style.boxShadow = "0 2px 10px rgba(0, 0, 0, 0.3)"; + popup.style.zIndex = "10000"; + popup.style.fontFamily = "Helvetica, sans-serif"; + popup.style.fontSize = "14px"; + popup.style.width = "300px"; + popup.style.textAlign = "center"; + + popup.innerHTML = \` + <h5 style="color: #fff; font-weight: bold; margin-top: 0;">🔑 Connexion à l'extension</h5> + <p style="margin: 15px 0;"> + Après avoir renseigné vos identifiants, cliquez sur + <strong>"Se connecter avec BaLex"</strong>. + </p> + <button id="close-popup-btn" style=" + width: 100%; + margin-top: 15px; + padding: 10px; + border: none; + background-color: #8d5c70; + color: #fbfcfc; + font-weight: bold; + cursor: pointer; + border-radius: 5px; + ">Fermer</button> + \`; + + document.body.appendChild(popup); + + const closeBtn = document.getElementById("close-popup-btn"); + closeBtn.onclick = () => popup.remove(); + } + ` + }); +} + +// === Notification (exemple) === + +function showNotification(title, message, iconPath) { + console.log(`🔔 NOTIFICATION: [${title}] ${message}`); +} diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 79e2bec..677980a 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -10,25 +10,13 @@ let authToken = null; // ───────────────────────────────────────────────────────────────────────────── // â–Œ Fonctions liées au token // ───────────────────────────────────────────────────────────────────────────── - -/** - * Vérifie le format du token - */ -function validateToken(token) { - const isValid = /^\S+\\.\\S+\\.\\S+$/.test(token); - if (!isValid) { - console.warn("âš ï¸ Le format du token semble incorrect :", token); - } - return isValid; -} - /** * Récupération du token depuis le stockage local */ async function getAuthTokenFromStorage() { try { const { accessToken } = await browser.storage.local.get("accessToken"); - if (accessToken && validateToken(accessToken)) { + if (accessToken) { console.log(`🔑 Token récupéré depuis le stockage local : [${accessToken}]`); authToken = accessToken; return authToken; -- GitLab From 4cebb371a26c8acec0df14f09fe63650c064e73b Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sun, 2 Feb 2025 18:15:25 +0100 Subject: [PATCH 09/32] =?UTF-8?q?Affichage=20des=20d=C3=A9finitions=20(lex?= =?UTF-8?q?iques+Wiktionnaire)=20OK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.js | 313 +++++++++----------- background/background.js | 68 +++-- background/browser_context_menu.js | 15 +- "barre_lat\303\251rale/sidebar.html" | 34 +++ "barre_lat\303\251rale/sidebar.js" | 379 +++++++++++++++++-------- menu_contextuel/custom_context_menu.js | 33 +-- 6 files changed, 497 insertions(+), 345 deletions(-) diff --git a/api.js b/api.js index 4de4708..3519298 100644 --- a/api.js +++ b/api.js @@ -1,4 +1,4 @@ -console.log("api.js chargé correctement"); +console.log("✅ api.js chargé correctement"); // ───────────────────────────────────────────────────────────────────────────── // â–Œ Sélection de texte sur la page @@ -14,240 +14,209 @@ document.addEventListener("mouseup", () => { }); // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Fonctions d’appel à l’API +// â–Œ Fonction utilitaire pour appeler l’API // ───────────────────────────────────────────────────────────────────────────── - /** - * Récupère les lexiques personnels de l'utilisateur. + * Effectue une requête API + * @param {string} url - L'URL de l'API à appeler. + * @param {string|null} authToken - Le token d'authentification. + * @param {string} [method='GET'] - La méthode HTTP. + * @returns {Promise<any>} - La réponse en JSON. + * @throws {Error} - En cas d'échec. */ -async function getUserLexicons(authToken) { - const lexiconsApiUrl = 'https://babalex.lezinter.net/api/user/lexicons'; - try { - const response = await fetch(lexiconsApiUrl, { - method: 'GET', - headers: { - Authorization: `Bearer ${authToken}`, - 'Content-Type': 'application/json', - }, - }); +async function callApi(url, authToken = null, method = 'GET') { + const headers = { 'Content-Type': 'application/json' }; + if (authToken) headers.Authorization = `Bearer ${authToken}`; + try { + const response = await fetch(url, { method, headers }); if (!response.ok) { - throw new Error( - `Erreur lors de la récupération des lexiques : ${response.status} ${response.statusText}` - ); + throw new Error(`⌠Erreur API (${response.status}): ${response.statusText}`); } - return await response.json(); } catch (error) { - console.error('Erreur lors de la récupération des lexiques :', error); + console.error(`🚨 Erreur lors de l'appel API [${url}]:`, error); throw error; } } /** - * Récupère les lexiques de l'utilisateur + * Décode un token JWT + * (Cette fonction est là au cas où) + * @param {string} token - Le token JWT. + * @returns {Object|null} - La charge utile du token ou null en cas d'erreur. */ -async function getLexicons(authToken, userId = 52, language = 'fr') { - const lexiconsApiUrl = - `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=${language}`; +function parseJwt(token) { try { - const response = await fetch(lexiconsApiUrl, { - method: 'GET', - headers: { - Authorization: `Bearer ${authToken}`, - 'Content-Type': 'application/json', - }, - }); - - if (!response.ok) { - throw new Error( - `Erreur lors de la récupération des lexiques : ${response.status} ${response.statusText}` - ); - } - - return await response.json(); + const base64Url = token.split('.')[1]; + const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); + const jsonPayload = decodeURIComponent( + atob(base64) + .split('') + .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) + .join('') + ); + return JSON.parse(jsonPayload); } catch (error) { - console.error('Erreur lors de la récupération des lexiques :', error); - throw error; + console.error("⌠Erreur lors du décodage du token :", error); + return null; } -} +}console.log("✅ api.js chargé correctement"); -/** - * Récupère la liste des mots d'un lexique. - */ -async function getLexiconEntries(authToken, idLexicon) { - const entriesApiUrl = `https://babalex.lezinter.net/api/lexicon/extract/0?lexiconId=${idLexicon}`; - try { - const response = await fetch(entriesApiUrl, { - method: 'GET', - headers: { - Authorization: `Bearer ${authToken}`, - 'Content-Type': 'application/json', - }, - }); +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Récupération des lexiques de l'utilisateur +// ───────────────────────────────────────────────────────────────────────────── - if (!response.ok) { - throw new Error( - `Erreur lors de la récupération des entrées du lexique : ${response.status} ${response.statusText}` - ); - } +/** + * Récupère les lexiques pour l’utilisateur 4, + * en langue par défaut "fr". + * + * @param {string} authToken - Le token d'authentification. + * @param {string} [language='fr'] - La langue (optionnel). + * @returns {Promise<any[]>} - Liste des lexiques trouvés. + */ +async function getLexicons(authToken, language = 'fr') { + const userId = 4; + const baseUrl = "https://babalex.lezinter.net/api/lexicon/search"; + const url = `${baseUrl}?user_id=${userId}&language=${encodeURIComponent(language)}`; - const data = await response.json(); - if (Array.isArray(data)) { - console.log(`Entrées récupérées pour le lexique ID ${idLexicon} :`, data); - return data; - } else { - console.warn('Le format des données retournées est inattendu.', data); - return []; - } - } catch (error) { - console.error('Erreur lors de la récupération des entrées du lexique :', error); - throw error; - } + return callApi(url, authToken); } /** - * Récupère la liste des entrées (graphies + ID) d'un lexique donné. + * Récupère tous les lexiques pour l’utilisateur 4 + * @param {string} authToken - Le token d'authentification (Bearer ...). + * @returns {Promise<any[]>} - Un grand tableau combinant tous les lexiques trouvés, + * quelle que soit la catégorie. */ -async function getLexiconEntriesID(authToken, idLexicon) { - const entriesApiUrl = `https://babalex.lezinter.net/api/lexicon/entries/${idLexicon}`; +async function getAllCategoriesLexicons(authToken) { + // Les différentes catégories à tester + const categories = ["User", "Group", "Zero", "New words"]; + + // Paramètres fixes + const userId = 4; + const groupId = 1; + + const promises = categories.map(async (category) => { + const baseUrl = "https://babalex.lezinter.net/api/lexicon/search"; + const url = `${baseUrl}?user_id=${userId}&group_id=${groupId}&category=${encodeURIComponent(category)}&language=fr`; + + try { + return await callApi(url, authToken); + } catch (error) { + console.warn(`âš ï¸ Aucune donnée trouvée (ou accès refusé) pour la catégorie "${category}" :`, error.message); + return []; + } + }); try { - const response = await fetch(entriesApiUrl, { - method: 'GET', - headers: { - Authorization: `Bearer ${authToken}`, - 'Content-Type': 'application/json', - }, - }); - - if (!response.ok) { - throw new Error( - `Erreur lors de la récupération des graphies : ${response.status} ${response.statusText}` - ); - } + const resultsByCategory = await Promise.all(promises); + // On a un tableau de 4 éléments, un pour chaque catégorie + // Concaténation en un seul tableau + const combined = resultsByCategory.flat(); - return await response.json(); + console.log("✅ Lexiques récupérés (toutes catégories confondues) :", combined); + return combined; } catch (error) { - console.error('Erreur lors de la récupération des graphies :', error); - throw error; + console.error("⌠Erreur lors de la récupération multi-catégories :", error); + return []; } } +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Récupération des entrées d'un lexique +// ───────────────────────────────────────────────────────────────────────────── + /** - * Récupère les infos d'un mot par sa graphie (quels lexiques contiennent ce mot). + * Récupère les entrées (mots) d'un lexique donné. + * @param {string} authToken - Le token d'authentification. + * @param {number|string} lexiconId - L'ID du lexique à récupérer. + * @returns {Promise<any[]>} - Liste des entrées du lexique. */ -async function getGraphyInfo(authToken, word) { - const definitionApiUrl = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=3&target_lex=4`; - - try { - const response = await fetch(definitionApiUrl, { - method: 'GET', - headers: { - Authorization: `Bearer ${authToken}`, - 'Content-Type': 'application/json', - }, - }); - - if (!response.ok) { - throw new Error( - `Erreur lors de la récupération de la définition : ${response.status} ${response.statusText}` - ); - } - - return await response.json(); - } catch (error) { - console.error('Erreur lors de la récupération de la définition :', error); - throw error; - } +async function getLexiconEntries(authToken, lexiconId) { + const url = `https://babalex.lezinter.net/api/lexicon/entries/${lexiconId}`; + return callApi(url, authToken); } /** - * Récupère toutes les informations sur un mot (via son ID) depuis l’API. + * Récupère toutes les graphies présentes dans tous les lexiques de l'utilisateur. + * (basé sur l'endpoint /api/lexicon/search + /api/lexicon/entries/{id}) + * + * @param {string} authToken - Le token d'authentification. + * @returns {Promise<Object>} - Un objet dont les clés sont les noms de lexiques + * et la valeur un tableau de leurs graphies. */ -async function getDefinition(authToken, entryId) { - const entryInfoApiUrl = `https://babalex.lezinter.net/api/entry/get/${entryId}`; +async function getAllLexiconWords(authToken) { + const searchUrl = "https://babalex.lezinter.net/api/lexicon/search" + + "?user_id=4" + + "&language=fr"; try { - const response = await fetch(entryInfoApiUrl, { - method: 'GET', - headers: { - Authorization: `Bearer ${authToken}`, - 'Content-Type': 'application/json', - }, - }); + // 1) Récupération de la liste des lexiques + const lexicons = await callApi(searchUrl, authToken); + + if (!Array.isArray(lexicons) || lexicons.length === 0) { + console.warn("âš ï¸ Aucun lexique retourné par l’API pour ces paramètres."); + return {}; + } - if (!response.ok) { - throw new Error( - `Erreur lors de la récupération des informations sur l'entrée : ${response.status} ${response.statusText}` - ); + // 2) Pour chaque lexique, on récupère ses entrées via /api/lexicon/entries/{id} + const allGraphiesByLexicon = {}; + + for (const lexicon of lexicons) { + const entries = await getLexiconEntries(authToken, lexicon.id); + const allGraphies = entries.map(entry => entry.graphy); + allGraphiesByLexicon[lexicon.name] = allGraphies; } - const data = await response.json(); - console.log(`Informations pour l'entrée ID ${entryId} :`, data); - return data; + console.log("✅ Toutes les graphies récupérées :", allGraphiesByLexicon); + return allGraphiesByLexicon; } catch (error) { - console.error('Erreur lors de la récupération des informations sur l’entrée :', error); - throw error; + console.error("⌠Erreur lors de la récupération des graphies des lexiques :", error); + return {}; } } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Récupération au Wiktionnaire +// â–Œ Récupération de définition du Wiktionnaire // ───────────────────────────────────────────────────────────────────────────── /** - * Récupère la définition d’un mot depuis le Wiktionnaire - * - * @param {string} word - Le mot à définir - * @returns {Promise<string[]>} Tableau de définitions (chaînes) + * Récupère une définition du Wiktionnaire. + * @param {string} word - Le mot recherché. + * @returns {Promise<string[]>} - Tableau contenant la définition (HTML). */ async function getWiktionaryDefinition(word) { try { - console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); - - if (!word || word.trim() === "") { - throw new Error("âš ï¸ Mot vide, requête impossible."); - } - - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&exintro=true&titles=${encodeURIComponent(word)}`; - - const response = await fetch(wiktionaryURL); + const url = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&exintro=true&titles=${encodeURIComponent(word)}`; + const response = await fetch(url); if (!response.ok) { - throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + throw new Error(`Erreur API Wiktionnaire: ${response.statusText}`); } const data = await response.json(); - console.log("📖 Réponse API Wiktionnaire :", data); + const pages = data.query?.pages; + const page = pages ? Object.values(pages)[0] : null; + const definition = page?.extract?.trim() || "Aucune définition trouvée."; - if (!data.query || !data.query.pages) { - return ["âš ï¸ Réponse inattendue du Wiktionnaire."]; - } - - const pages = Object.values(data.query.pages); - if (pages.length === 0 || !pages[0].extract) { - return ["âš ï¸ Aucune définition trouvée sur le Wiktionnaire."]; - } - - // Convertir l'HTML en texte brut propre - const parser = new DOMParser(); - const doc = parser.parseFromString(pages[0].extract, "text/html"); - const cleanText = doc.body.textContent.trim(); - - console.log("✅ Définition extraite :", cleanText); - return [cleanText]; + console.log(`📖 Définition trouvée pour '${word}':`, definition); + return [definition]; } catch (error) { - console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); - return ["âš ï¸ Erreur : " + error.message]; + console.error("Erreur lors de la récupération du Wiktionnaire :", error); + return ["Erreur : " + error.message]; } } // ───────────────────────────────────────────────────────────────────────────── -window.getUserLexicons = getUserLexicons; +// â–Œ Exposition des fonctions pour un usage global +// ───────────────────────────────────────────────────────────────────────────── + +window.callApi = callApi; +window.parseJwt = parseJwt; + window.getLexicons = getLexicons; +window.getAllCategoriesLexicons = getAllCategoriesLexicons; window.getLexiconEntries = getLexiconEntries; -window.getLexiconEntriesID = getLexiconEntriesID; -window.getGraphyInfo = getGraphyInfo; -window.getDefinition = getDefinition; -window.getWiktionaryDefinition = getWiktionaryDefinition; +window.getAllLexiconWords = getAllLexiconWords; +window.getWiktionaryDefinition = getWiktionaryDefinition; \ No newline at end of file diff --git a/background/background.js b/background/background.js index 803d7f9..1805474 100644 --- a/background/background.js +++ b/background/background.js @@ -1,24 +1,31 @@ -// === Variables globales / de configuration === -let isExtensionActive = true; // Activation globale de l'extension -let areStatsActive = false; // Activation des statistiques +// ───────────────────────────────────────────────────────────────────────────── +// Variables globales +// ───────────────────────────────────────────────────────────────────────────── + +let isExtensionActive = true; +let areStatsActive = false; let originalTabId = null; let loginTabId = null; const AUTH_LOGIN_URL = "https://prisms.lezinter.net/fr/login"; const AUTH_BALEX_URL = "https://prisms.lezinter.net/fr/headquarters/balex"; -// === Logs de démarrage === -console.log("🚀 ff2BaLex (background) chargé."); +// ───────────────────────────────────────────────────────────────────────────── +// Logs de démarrage +// ───────────────────────────────────────────────────────────────────────────── +console.log("🚀 ff2BaLex (background) chargé."); browser.runtime.onInstalled.addListener((details) => { console.log("🔔 Extension installée ou mise à jour. Raison :", details.reason); }); - browser.runtime.onStartup.addListener(() => { console.log("🔄 Extension démarrée (onStartup)."); }); -// === Suivi des changements dans le stockage === +// ───────────────────────────────────────────────────────────────────────────── +// Suivi des changements dans le stockage +// ───────────────────────────────────────────────────────────────────────────── + browser.storage.onChanged.addListener((changes) => { if (changes.extensionActive) { isExtensionActive = changes.extensionActive.newValue; @@ -28,11 +35,12 @@ browser.storage.onChanged.addListener((changes) => { areStatsActive = changes.statsActive.newValue; console.log("📊 Statistiques activées :", areStatsActive); } - // Recréer le menu contextuel du navigateur quand l'état change createBrowserContextMenu(); }); -// === Fonctions utilitaires === +// ───────────────────────────────────────────────────────────────────────────── +// Fonctions utilitaires +// ───────────────────────────────────────────────────────────────────────────── /** * Vérifie si l'utilisateur est connecté (token présent dans le stockage). @@ -51,7 +59,9 @@ async function refreshAllUI() { browser.runtime.sendMessage({ action: "refreshUI" }); } -// === Fonctions d'authentification === +// ───────────────────────────────────────────────────────────────────────────── +// Fonctions d'authentification +// ───────────────────────────────────────────────────────────────────────────── /** * Ouvre la page de connexion BaLex. @@ -85,7 +95,6 @@ async function disconnectFromLexicalDB() { "Vous êtes maintenant déconnecté(e).", "icons/logout.png" ); - // Rafraîchissement global de l'UI await refreshAllUI(); } @@ -117,11 +126,12 @@ async function saveToken(token) { } originalTabId = null; } - // Rafraîchir toute l'UI await refreshAllUI(); } -// === Fonction pour récupérer la définition du Wiktionnaire === +// ───────────────────────────────────────────────────────────────────────────── +// Fonction pour récupérer une définition sur le Wiktionnaire +// ───────────────────────────────────────────────────────────────────────────── /** * Récupère la définition d'un mot depuis le Wiktionnaire. @@ -167,7 +177,10 @@ function showWiktionaryNotification(selectedText) { }); } -// === Gestion des messages reçus === +// ───────────────────────────────────────────────────────────────────────────── +// Gestion des messages reçus +// ───────────────────────────────────────────────────────────────────────────── + browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { console.log("📩 Message reçu dans background.js :", message); @@ -187,7 +200,6 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { if (message.selectedText && message.selectedText.trim() !== "") { console.log("🌠Requête Wiktionnaire pour :", message.selectedText); const definition = await fetchWiktionaryDefinition(message.selectedText.trim()); - // Envoyer la réponse (ex: vers la sidebar) browser.runtime.sendMessage({ action: "fetchWiktionaryDefinitionResponse", selectedText: message.selectedText, @@ -229,7 +241,9 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { return true; }); -// === Création et gestion du menu contextuel === +// ───────────────────────────────────────────────────────────────────────────── +// Création et gestion du menu contextuel +// ───────────────────────────────────────────────────────────────────────────── /** * Crée (ou recrée) le menu contextuel du navigateur en fonction du statut de connexion. @@ -313,7 +327,9 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } }); -// === Web Navigation : Injection de scripts et récupération du token === +// ───────────────────────────────────────────────────────────────────────────── +// Web Navigation : Injection de scripts et récupération du token +// ───────────────────────────────────────────────────────────────────────────── browser.webNavigation.onCompleted.addListener(async (details) => { if (!isExtensionActive) { @@ -322,16 +338,16 @@ browser.webNavigation.onCompleted.addListener(async (details) => { } const url = new URL(details.url); - // Sur la page de login : injection d'un popup d'instruction + // Sur la page de login : popup d'instruction if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/login") { console.log("📘 Injection du popup d'instruction sur la page de login Prisms."); showInstructionPopup(details); } - // Sur la page /balex : tentative de récupération du token + // Sur la page /balex : récupération du token if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/headquarters/balex") { console.log("🟢 Page /balex détectée. Tentative de récupération du token."); try { - await new Promise(resolve => setTimeout(resolve, 3000)); // Attendre 3 secondes + await new Promise(resolve => setTimeout(resolve, 3000)); await browser.tabs.executeScript(details.tabId, { code: ` console.log("🔠Recherche du token..."); @@ -351,7 +367,9 @@ browser.webNavigation.onCompleted.addListener(async (details) => { } }, { url: [{ hostContains: "prisms.lezinter.net" }] }); -// === Web Request : Redirection automatique vers /balex === +// ───────────────────────────────────────────────────────────────────────────── +// Web Request : Redirection automatique vers /balex +// ───────────────────────────────────────────────────────────────────────────── browser.webRequest.onBeforeRequest.addListener( function(details) { @@ -364,7 +382,9 @@ browser.webRequest.onBeforeRequest.addListener( ["blocking"] ); -// === Affichage d'un popup d'instruction sur /fr/login === +// ───────────────────────────────────────────────────────────────────────────── +// Affichage d'un popup d'instruction sur /fr/login +// ───────────────────────────────────────────────────────────────────────────── function showInstructionPopup(details) { browser.tabs.executeScript(details.tabId, { @@ -415,7 +435,9 @@ function showInstructionPopup(details) { }); } -// === Notification (exemple) === +// ───────────────────────────────────────────────────────────────────────────── +// Notification +// ───────────────────────────────────────────────────────────────────────────── function showNotification(title, message, iconPath) { console.log(`🔔 NOTIFICATION: [${title}] ${message}`); diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index e75d0dd..ae2a6be 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -1,4 +1,4 @@ -console.log("browser_context_menu.js chargé correctement"); // Vérifie que le script est correctement chargé +console.log("browser_context_menu.js chargé correctement"); // Variable globale qui contient le token pour les requêtes API let authToken = null; @@ -25,7 +25,7 @@ loadAuthToken(); browser.contextMenus.create({ id: "searchLexicon", title: "Ce mot est-il dans mon lexique ?", - contexts: ["selection"], // Affiché uniquement lorsqu'un texte est sélectionné + contexts: ["selection"], icons: { "16": "icons/recherche_lexique.png" }, }); @@ -124,13 +124,10 @@ async function getDefinition(selectedText) { let userLexiconDefinitions = []; if (authToken) { userLexiconDefinitions = await getDefinitionFromUserLexicons(selectedText); - // getDefinitionFromUserLexicons => fonction qui retourne un tableau - // du style : [{ source: 'Lexiques', text: '...' }, ...] } // 2) Récupérer définitions du Wiktionnaire let wiktionaryDefinitions = await getDefinitionFromWiktionary(selectedText); - // idem, un tableau : [{ source: 'Wiktionnaire', text: '...' }] // 3) Fusion const allDefinitions = [...userLexiconDefinitions, ...wiktionaryDefinitions]; @@ -154,8 +151,6 @@ async function getDefinition(selectedText) { async function getDefinitionFromUserLexicons(selectedText) { try { console.log("🔎 getDefinitionFromUserLexicons pour :", selectedText); - // Ici, tu fais ton appel API vers tes lexiques - // Par exemple : const response = await fetch( `https://prisms.lezinter.net/api/definitions?word=${encodeURIComponent(selectedText)}`, { headers: { Authorization: `Bearer ${authToken}` } } @@ -168,7 +163,7 @@ async function getDefinitionFromUserLexicons(selectedText) { if (!data.definitions || data.definitions.length === 0) { return []; } - // On formate pour l'affichage + return data.definitions.map((def) => ({ source: "Lexiques", text: def, @@ -219,7 +214,7 @@ async function getDefinitionFromWiktionary(selectedText) { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Autres fonctions de ton extension (recherche, vérification, etc.) +// â–Œ Autres fonctions de l'extension (recherche, vérification, etc.) // ───────────────────────────────────────────────────────────────────────────── /** @@ -276,7 +271,7 @@ async function checkLexicon(selectedText) { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Listeners supplémentaires (si besoin) +// â–Œ Listeners supplémentaires // ───────────────────────────────────────────────────────────────────────────── /** diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 4f9cd9f..13088fb 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -5,6 +5,7 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BaLex - Barre Latérale</title> <script src="sidebar.js" defer></script> + <script src="../api.js" defer></script> <style> /* Style global */ body { @@ -105,6 +106,39 @@ flex-shrink: 0; } + .lexicon-section { + margin-bottom: 10px; + } + + .lexicon-header { + font-weight: bold; + cursor: pointer; + padding: 5px; + background-color: #8d5c70; + border-radius: 5px; + text-align: center; + } + + .lexicon-header:hover { + background-color: #dddedd; + color: #8d5c70; + } + + .lexicon-content { + margin-top: 5px; + } + + .hidden { + display: none; + } + + #mesLexiquesList { + display: inline; + padding: 0; + align-items: center; + } + + /* Définition */ #definitionContainer { margin-top: 10px; diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 677980a..959a911 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -1,3 +1,6 @@ +// ───────────────────────────────────────────────────────────────────────────── +// Initialisation & vérification de l'API browser +// ───────────────────────────────────────────────────────────────────────────── console.log("✅ sidebar.js chargé !"); console.log( "🌠Vérification API browser :", @@ -11,7 +14,7 @@ let authToken = null; // â–Œ Fonctions liées au token // ───────────────────────────────────────────────────────────────────────────── /** - * Récupération du token depuis le stockage local + * Récupère le token d'authentification depuis le stockage local. */ async function getAuthTokenFromStorage() { try { @@ -21,7 +24,7 @@ async function getAuthTokenFromStorage() { authToken = accessToken; return authToken; } - console.warn("âš ï¸ Aucun token valide trouvé dans le stockage local."); + console.warn("âš ï¸ Aucun token trouvé dans le stockage local."); } catch (error) { console.error("⌠Erreur lors de la récupération du token :", error); } @@ -30,9 +33,8 @@ async function getAuthTokenFromStorage() { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Fonctions de mise à jour de l'UI de la barre latérale +// â–Œ Mise à jour de l'interface utilisateur (UI) // ───────────────────────────────────────────────────────────────────────────── - function updateAuthButton(isLoggedIn) { const authButton = document.getElementById("auth-button"); if (authButton) { @@ -60,6 +62,9 @@ function toggleElementsVisibility(isLoggedIn) { }); } +/** + * Permet d’afficher ou non la note de surlignage + */ function toggleHighlightMessage(isLoggedIn) { const highlightNote = document.getElementById("highlight-note"); if (highlightNote) { @@ -68,7 +73,7 @@ function toggleHighlightMessage(isLoggedIn) { } /** - * Rafraîchit l'état de la barre latérale (bouton de connexion, lexiques, etc.) + * Rafraîchit l'état de la barre latérale (bouton d'authentification, lexiques, etc.) */ async function refreshSidebarState() { console.log("🔄 Début de l'actualisation de la barre latérale..."); @@ -80,10 +85,8 @@ async function refreshSidebarState() { toggleHighlightMessage(isLoggedIn); if (isLoggedIn) { - // Charger les lexiques - await fetchLexicons(); + await fetchLexicons(); } else { - // Masquer ou vider le container des lexiques const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { lexiquesContainer.textContent = "Veuillez vous connecter pour voir vos lexiques."; @@ -94,61 +97,109 @@ async function refreshSidebarState() { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Lexiques (récupération et affichage) +// â–Œ Lexiques : deux affichages possibles // ───────────────────────────────────────────────────────────────────────────── /** - * Affiche les lexiques (checkbox + icône). + * (1) Affichage des lexiques sous forme de liste */ -function displayLexicons(lexicons) { +async function displayLexiconsList() { const lexiquesContainer = document.getElementById("lexiques"); if (!lexiquesContainer) { console.warn("âš ï¸ Ã‰lément #lexiques introuvable."); return; } + + lexiquesContainer.innerHTML = "Chargement des lexiques..."; + const token = await getAuthTokenFromStorage(); + console.log("Token utilisé pour l'appel API :", token); + if (!token) { + lexiquesContainer.textContent = "âš ï¸ Veuillez vous connecter pour voir vos lexiques."; + return; + } + + try { + const lexicons = await getAllLexiconWords(token); + lexiquesContainer.innerHTML = ""; + + if (Object.keys(lexicons).length === 0) { + lexiquesContainer.textContent = "Aucun lexique disponible."; + return; + } + + Object.entries(lexicons).forEach(([lexique, mots]) => { + const lexiqueTitle = document.createElement("h3"); + lexiqueTitle.textContent = lexique; + lexiquesContainer.appendChild(lexiqueTitle); + + const list = document.createElement("ul"); + mots.forEach((mot) => { + const listItem = document.createElement("li"); + listItem.textContent = mot.graphy || mot; + list.appendChild(listItem); + }); + + lexiquesContainer.appendChild(list); + }); + + } catch (error) { + console.error("⌠Erreur lors de l'affichage des lexiques :", error); + lexiquesContainer.textContent = "Erreur lors du chargement des lexiques."; + } +} +/** + * (2) Affichage des lexiques avec checkbox + * Permet de modifier dynamiquement le surlignage. + */ +function displayLexiconsWithCheckbox(lexicons) { + const lexiquesContainer = document.getElementById("lexiques"); + if (!lexiquesContainer) { + console.warn("âš ï¸ Ã‰lément #lexiques introuvable."); + return; + } + lexiquesContainer.innerHTML = ""; - + if (lexicons.length === 0) { console.log("âš ï¸ Aucun lexique à afficher."); lexiquesContainer.textContent = "Aucun lexique disponible."; return; } - - console.log("ðŸ–¼ï¸ Affichage des lexiques..."); + lexicons.forEach(({ lexiconName, lexiconId, active }) => { console.log(`âž¡ï¸ Affichage du lexique : ${lexiconName} (ID: ${lexiconId})`); - + const lexiqueDiv = document.createElement("div"); lexiqueDiv.className = "lexique-item"; - + const iconDiv = document.createElement("div"); iconDiv.className = "lexique-icon"; iconDiv.style.backgroundColor = "#ccc"; - + const labelSpan = document.createElement("span"); labelSpan.className = "lexique-label"; labelSpan.textContent = lexiconName; - + const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.className = "lexique-checkbox"; checkbox.checked = active; - + checkbox.addEventListener("change", async () => { console.log( `🔄 Changement de surlignage pour ${lexiconName} (ID: ${lexiconId}): ${ checkbox.checked ? "activé" : "désactivé" }` ); - + await browser.runtime.sendMessage({ action: "toggleLexiconHighlight", lexiconId, isActive: checkbox.checked, }); }); - + lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); lexiqueDiv.appendChild(checkbox); @@ -157,26 +208,24 @@ function displayLexicons(lexicons) { } /** - * Récupère la liste des lexiques depuis l'API (exemple). + * Récupère la liste des lexiques depuis l'API via getLexicons puis affiche avec displayLexiconsWithCheckbox. */ async function fetchLexicons() { try { console.log("🔄 Début de la récupération des lexiques..."); console.log("🔑 Token utilisé :", authToken); - + if (!authToken) { throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); } - - // Appel à l'API (exemple) - const lexicons = await getLexicons(authToken, 52, "fr"); + + const lexicons = await getLexicons(authToken, "fr"); console.log("📚 Réponse brute de l'API :", lexicons); - + if (!Array.isArray(lexicons) || lexicons.length === 0) { throw new Error("âš ï¸ Aucun lexique trouvé."); } - - // Transformation des données + const results = lexicons.map((lexicon) => { console.log("📋 Transformation du lexique :", lexicon); return { @@ -188,11 +237,11 @@ async function fetchLexicons() { active: lexicon.active || false, }; }); - - console.log("Appel de displayLexicons avec :", results); - - // Affichage des lexiques - displayLexicons(results); + + console.log("Appel de displayLexiconsWithCheckbox avec :", results); + + // Affichage des lexiques avec checkbox + displayLexiconsWithCheckbox(results); } catch (error) { console.error("⌠Erreur lors du chargement des lexiques :", error.message); console.error("Détails de l'erreur :", error); @@ -205,55 +254,118 @@ async function fetchLexicons() { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Bouton de connexion/déconnexion +// â–Œ Gestion du bouton de connexion/déconnexion // ───────────────────────────────────────────────────────────────────────────── - async function handleAuthButtonClick() { await browser.runtime.sendMessage({ action: "toggleAuth" }); await refreshSidebarState(); } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion des définitions : lexiques + Wiktionnaire +// â–Œ Gestion des définitions (Lexiques + Wiktionnaire) // ───────────────────────────────────────────────────────────────────────────── /** - * Récupère les définitions d'un mot dans les lexiques de l'utilisateur - * Retourne un tableau d'objets : [{ source: 'Lexiques', text: '...' }, ...] + * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), + * en faisant un appel séparé pour chaque lexique : + * GET /api/entry/search?graphy={word}&language=fr&target_lex={lexicon.id} + * + * Retourne un tableau d'objets { source, text } où: + * - source = nom du lexique (ou "Lexique #ID") + * - text = texte de la définition + * + * @param {string} word - Le mot recherché (ex. "chat"). + * @returns {Promise<Array<{ source: string, text: string }>>} */ async function fetchLexiconDefinitions(word) { try { - console.log(`🔠Recherche des définitions de '${word}' dans les lexiques...`); + console.log(`🔠Recherche des définitions de '${word}' dans les lexiques de l'utilisateur...`); if (!authToken) { - // Pas de token => pas de recherche possible dans les lexiques + console.warn("Aucun token disponible, impossible de requêter l'API protégée."); return []; } - const response = await fetch( - `https://prisms.lezinter.net/api/definitions?word=${encodeURIComponent(word)}`, - { headers: { Authorization: `Bearer ${authToken}` } } - ); + // 1) Récupérer la liste complète des lexiques de l'utilisateur + // Par défaut : user_id=4 et language=fr + const userId = 4; + const lexUrl = `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=fr`; + const lexResponse = await fetch(lexUrl, { + headers: { Authorization: `Bearer ${authToken}` } + }); - if (!response.ok) { - throw new Error(`⌠Erreur API: ${response.statusText}`); + if (!lexResponse.ok) { + throw new Error(`⌠Erreur API lors de la récupération des lexiques: ${lexResponse.statusText}`); } - const data = await response.json(); - console.log("📚 Réponse API (lexiques) :", data); + const userLexicons = await lexResponse.json(); + console.log("ðŸ—‚ï¸ Lexiques de l'utilisateur :", userLexicons); - if (!data.definitions || data.definitions.length === 0) { - // Aucune définition trouvée, on renvoie un tableau vide + if (!Array.isArray(userLexicons) || userLexicons.length === 0) { + console.warn("âš ï¸ Aucuns lexiques trouvés pour cet utilisateur."); return []; } - // On formate pour respecter { source, text } - return data.definitions.map((def) => ({ - source: "Lexiques", - text: def, - })); + // 2) Pour chaque lexique, on va faire une requête + // GET /api/entry/search?graphy=word&language=fr&target_lex={lexicon.id} + let allDefinitions = []; + + for (const lex of userLexicons) { + const lexId = lex.id; // ID du lexique + const lexName = lex.name || `Lexique #${lexId}`; + + const url = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=${lexId}`; + console.log(`🔎 Appel API pour le lexique #${lexId} (${lexName}) => ${url}`); + + try { + const response = await fetch(url, { + headers: { Authorization: `Bearer ${authToken}` } + }); + + if (!response.ok) { + console.warn(`⌠Lexique ${lexId} : Erreur API (${response.status}): ${response.statusText}`); + continue; + } + + const data = await response.json(); + if (!Array.isArray(data) || data.length === 0) { + continue; + } + + // On parse pour extraire toutes les définitions + for (const entry of data) { + const items = entry.attributes?.Items; + if (!Array.isArray(items)) { + continue; + } + + for (const subItem of items) { + const definitionsArray = subItem.Sense?.Definitions; + if (!Array.isArray(definitionsArray)) { + continue; + } + + for (const defObj of definitionsArray) { + if (defObj.Def) { + const fullLexName = `${lex.name || `Lexique` } (#${lex.id})`; + allDefinitions.push({ + source: fullLexName, + text: defObj.Def + }); + } + } + } + } + + } catch (err) { + console.error(`Erreur lors de la requête pour le lexique #${lexId} :`, err); + } + } + console.log("Résultat final :", allDefinitions); + // 3) Retourne le tableau de toutes les définitions trouvées + return allDefinitions; } catch (error) { - console.error("⌠Erreur lors de la récupération des définitions des lexiques :", error); + console.error("⌠Erreur générale lors de la récupération des définitions :", error); return []; } } @@ -328,13 +440,19 @@ function displayDefinitions(definitions) { let hasLexiconDefinitions = false; let hasWiktionaryDefinitions = false; + // Regrouper les définitions par lexique + const lexiconGroups = {}; + definitions.forEach(({ source, text }) => { if (!source || !text) return; const li = document.createElement("li"); + let displayedText = text; if (text.length > MAX_LENGTH) { displayedText = text.slice(0, MAX_LENGTH) + "... "; + + // Bouton "Lire la suite" const readMoreLink = document.createElement("a"); readMoreLink.href = "#"; readMoreLink.textContent = "[Lire la suite]"; @@ -346,27 +464,59 @@ function displayDefinitions(definitions) { event.preventDefault(); openDefinitionPopup(text); }); + li.appendChild(document.createTextNode(displayedText)); li.appendChild(readMoreLink); } else { li.textContent = displayedText; } - if (source === "Lexiques") { - mesLexiquesList.appendChild(li); - hasLexiconDefinitions = true; - } else if (source === "Wiktionnaire") { + if (source === "Wiktionnaire") { + // Ajouter directement les définitions du Wiktionnaire wiktionnaireList.appendChild(li); hasWiktionaryDefinitions = true; + } else { + // Regrouper par lexique + if (!lexiconGroups[source]) { + lexiconGroups[source] = []; + } + lexiconGroups[source].push(li); + hasLexiconDefinitions = true; } }); + // Création des listes déroulantes par lexique + Object.entries(lexiconGroups).forEach(([lexicon, definitionItems]) => { + const lexiconContainer = document.createElement("div"); + lexiconContainer.className = "lexicon-section"; + + const lexiconHeader = document.createElement("div"); + lexiconHeader.className = "lexicon-header"; + lexiconHeader.textContent = lexicon; + lexiconHeader.addEventListener("click", () => { + lexiconContent.classList.toggle("hidden"); + }); + + // Liste des définitions + const lexiconContent = document.createElement("ul"); + lexiconContent.className = "lexicon-content hidden"; + + definitionItems.forEach((li) => lexiconContent.appendChild(li)); + + lexiconContainer.appendChild(lexiconHeader); + lexiconContainer.appendChild(lexiconContent); + mesLexiquesList.appendChild(lexiconContainer); + }); + + // Afficher ou cacher les sections document.getElementById("mesLexiquesContainer").style.display = hasLexiconDefinitions ? "block" : "none"; document.getElementById("wiktionnaireContainer").style.display = hasWiktionaryDefinitions ? "block" : "none"; noDefinitionsContainer.style.display = (!hasLexiconDefinitions && !hasWiktionaryDefinitions) ? "block" : "none"; noDefinitionsContainer.textContent = "Aucune définition trouvée pour ce mot."; } + + function openDefinitionPopup(fullText) { modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; modalOverlay.style.display = "flex"; @@ -389,7 +539,6 @@ modalOverlay.addEventListener("click", (event) => { async function showDefinitions(word) { console.log(`📖 Recherche des définitions pour '${word}'...`); - // (Optionnel) On peut afficher un message de "Chargement..." dans noDefinitionsContainer const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); if (noDefinitionsContainer) { noDefinitionsContainer.textContent = "Chargement des définitions..."; @@ -397,23 +546,18 @@ async function showDefinitions(word) { } try { - // Lance en parallèle la récupération côté Babalex et Wiktionnaire const [lexiconDefinitions, wiktionaryDefinitions] = await Promise.all([ - fetchLexiconDefinitions(word), // Par ex: renvoie [{ source: "Lexiques", text: "..."} ...] - fetchWiktionaryDefinition(word) // Par ex: renvoie [{ source: "Wiktionnaire", text: "..."} ...] + fetchLexiconDefinitions(word), + fetchWiktionaryDefinition(word) ]); - // Fusion des deux tableaux const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; console.log("📚 Définitions combinées :", allDefinitions); - // Affichage displayDefinitions(allDefinitions); } catch (error) { console.error("⌠Erreur lors de la récupération des définitions :", error); - - // En cas d'erreur, on peut l'afficher dans noDefinitionsContainer if (noDefinitionsContainer) { noDefinitionsContainer.textContent = "⌠Une erreur est survenue lors de la récupération des définitions."; noDefinitionsContainer.style.display = "block"; @@ -421,73 +565,74 @@ async function showDefinitions(word) { } } - // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion des messages reçus (notamment si le background nous en envoie) +// â–Œ Gestion des messages reçus (depuis le background ou ailleurs) // ───────────────────────────────────────────────────────────────────────────── - browser.runtime.onMessage.addListener(async (message) => { console.log("📩 Message reçu dans sidebar.js :", message); - // 1. Rafraîchit la barre latérale - if (message.action === "refreshUI") { - console.log("🔄 Rafraîchissement de la barre latérale demandé."); - refreshSidebarState(); - } - - // 2. Met à jour le mot sélectionné - else if (message.action === "mot_selectionne" && message.selectedText) { - console.log("ðŸ–‹ï¸ Mise à jour du mot sélectionné :", message.selectedText); - const selectedWordElement = document.getElementById("motSelectionne"); - if (selectedWordElement) { - selectedWordElement.textContent = message.selectedText; - } else { - console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); - } - } + switch (message.action) { + case "refreshUI": + console.log("🔄 Demande de rafraîchissement de la barre latérale."); + await refreshSidebarState(); + break; + + case "mot_selectionne": + if (message.selectedText) { + console.log("ðŸ–‹ï¸ Mot sélectionné :", message.selectedText); + const selectedWordElement = document.getElementById("motSelectionne"); + if (selectedWordElement) { + selectedWordElement.textContent = message.selectedText; + } else { + console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); + } + } + break; - // 3. Quand on demande les définitions pour un mot - else if (message.action === "getDefinition" && message.selectedText) { - console.log("📖 Recherche et affichage des définitions pour :", message.selectedText); - showDefinitions(message.selectedText); - } + case "getDefinition": + if (message.selectedText) { + console.log("📖 Recherche des définitions pour :", message.selectedText); + await showDefinitions(message.selectedText); + } + break; - // 4. Reception d'une définition Wiktionnaire envoyée par le background - else if (message.action === "fetchWiktionaryDefinitionResponse" && message.selectedText) { - console.log(`📖 Réception de la définition du Wiktionnaire pour '${message.selectedText}'`); - displayDefinitions(message.definitions); - } + case "showDefinitions": + if (Array.isArray(message.definitions)) { + displayDefinitions(message.definitions); + } + break; - // 5. Notification d'une définition trouvée - else if (message.action === "showDefinitionNotification") { - console.log(`📢 Définition trouvée pour "${message.selectedText}".`); - const notificationContainer = document.getElementById("notificationContainer"); - if (notificationContainer) { - notificationContainer.textContent = `🌠Définition trouvée pour "${message.selectedText}". Consultez le Wiktionnaire.`; - notificationContainer.style.display = "block"; - } - } -}); + case "fetchWiktionaryDefinitionResponse": + if (message.selectedText) { + console.log(`📖 Réception de la définition du Wiktionnaire pour '${message.selectedText}'`); + displayDefinitions(message.definitions); + } + break; + + case "showDefinitionNotification": + console.log(`📢 Définition trouvée pour "${message.selectedText}".`); + const notificationContainer = document.getElementById("notificationContainer"); + if (notificationContainer) { + notificationContainer.textContent = `🌠Définition trouvée pour "${message.selectedText}". Consultez le Wiktionnaire.`; + notificationContainer.style.display = "block"; + } + break; -browser.runtime.onMessage.addListener(async (message) => { - if (message.action === "showDefinitions" && Array.isArray(message.definitions)) { - displayDefinitions(message.definitions); + default: + console.warn("âš ï¸ Action inconnue reçue :", message.action); } }); - - // ───────────────────────────────────────────────────────────────────────────── // â–Œ Initialisation après chargement du DOM // ───────────────────────────────────────────────────────────────────────────── - document.addEventListener("DOMContentLoaded", async () => { console.log("📦 DOM entièrement chargé. Initialisation de la sidebar."); - // Rafraîchit l'UI + // Mise à jour de l'UI await refreshSidebarState(); - // Gère le clic sur le bouton de connexion/déconnexion + // Gestion du bouton de connexion/déconnexion const authButton = document.getElementById("auth-button"); if (authButton) { authButton.addEventListener("click", handleAuthButtonClick); @@ -501,7 +646,7 @@ document.addEventListener("DOMContentLoaded", async () => { console.log("📖 Mot sélectionné :", selectedWord); if (selectedWord && selectedWord !== "Aucun mot sélectionné") { - console.log(`📩 Recherche des définitions (lexiques + Wiktionnaire) pour '${selectedWord}'`); + console.log(`📩 Recherche des définitions pour '${selectedWord}'`); await showDefinitions(selectedWord); } else { console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); diff --git a/menu_contextuel/custom_context_menu.js b/menu_contextuel/custom_context_menu.js index a631f1f..46a5bd6 100644 --- a/menu_contextuel/custom_context_menu.js +++ b/menu_contextuel/custom_context_menu.js @@ -2,7 +2,7 @@ console.log("custom_context_menu.js chargé correctement"); // === Variables globales === let authToken = null; -const WHITE_BOX_ID = "whiteBox"; // Pour éviter les "magic strings" +const WHITE_BOX_ID = "whiteBox"; // Récupère le token depuis le stockage local et le stocke dans authToken async function loadAuthToken() { @@ -67,7 +67,7 @@ function setupWhiteBoxActions() { addLexiconBtn.onclick = async () => { const selectedText = getSelectedWord(); console.log("🔠Ajout au lexique :", selectedText); - if (!selectedText) return; // rien à faire si vide + if (!selectedText) return; if (authToken) { await searchLexicon(selectedText); @@ -87,7 +87,7 @@ function setupWhiteBoxActions() { } }; - // Login / Toggle Auth + // Login Auth loginBtn.onclick = () => { alert("Vous allez être redirigé(e) vers la page de connexion."); browser.runtime.sendMessage({ action: "toggleAuth" }); @@ -96,7 +96,7 @@ function setupWhiteBoxActions() { // Met à jour la visibilité des boutons en fonction de l'état de connexion function updateMenuVisibility() { - injectWhiteBox(); // s'assurer que la whiteBox est injectée + injectWhiteBox(); const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); @@ -115,7 +115,7 @@ function updateMenuVisibility() { } else { // Utilisateur déconnecté => on masque l'ajout de lexique, on affiche le bouton définition et login addLexiconBtn.style.display = "none"; - getDefinitionBtn.style.display = "inline-block"; // Toujours visible + getDefinitionBtn.style.display = "inline-block"; loginBtn.style.display = "inline-block"; } } @@ -128,7 +128,7 @@ function getSelectedWord() { return selectedWordElement ? selectedWordElement.textContent.trim() : ""; } -// Affiche le menu contextuel (whiteBox) à la position du clic +// Affiche le menu contextuel à la position du clic function showWhiteBox(event, selectedText) { const whiteBox = document.getElementById(WHITE_BOX_ID); if (!whiteBox) { @@ -136,31 +136,27 @@ function showWhiteBox(event, selectedText) { return; } - // Met à jour l'affichage du mot sélectionné => "Mot sélectionné : XXX" + // Mettre à jour le mot sélectionné const selectedWordElement = document.getElementById("selectedWord"); selectedWordElement.textContent = `${selectedText}`; // Récupère la position de la sélection const selection = window.getSelection(); const range = selection.getRangeAt(0); - const rect = range.getBoundingClientRect(); // position/taille du mot sélectionné + const rect = range.getBoundingClientRect(); - // Calcule la position du menu en bas à droite du mot sélectionné const top = rect.bottom + window.scrollY; const left = rect.right + window.scrollX; - // Positionne la whiteBox et l'affiche whiteBox.style.left = `${left}px`; whiteBox.style.top = `${top}px`; whiteBox.style.display = "block"; console.log("Affichage du menu contextuel avec le mot :", selectedText); - // Mettre à jour la visibilité des boutons updateMenuVisibility(); } -// Masque la whiteBox. function hideWhiteBox() { const whiteBox = document.getElementById(WHITE_BOX_ID); if (whiteBox) { @@ -176,22 +172,20 @@ document.addEventListener("mouseup", (event) => { injectWhiteBox(); showWhiteBox(event, selectedText); - // Envoie aussi le mot sélectionné à la barre latérale (ou background) + // Envoie aussi le mot sélectionné browser.runtime.sendMessage({ action: "mot_selectionne", selectedText, }); } else { - // Masquer le menu si rien n'est sélectionné hideWhiteBox(); } }); -// Réécouter les messages envoyés par le background script ou la barre latérale +// Réécouter les messages envoyés browser.runtime.onMessage.addListener((message) => { if (message.action === "refreshUI") { console.log("🔄 Mise à jour du menu contextuel personnalisé (double-clic/sélection)."); - // Recharger le token puis mettre à jour l'affichage loadAuthToken().then(() => { updateMenuVisibility(); }); @@ -208,14 +202,9 @@ loadAuthToken().then(() => { // â–Œ Fonctions d'API Babalex pour l'ajout ou la vérification d'un mot // ───────────────────────────────────────────────────────────────────────────── -/** - * Vérifie si le mot existe dans le lexique perso, ou l'ajoute, etc. - * (Ici, c'est un exemple de logique "searchLexicon") - */ async function searchLexicon(selectedText) { console.log("🔄 Recherche dans le lexique personnel pour :", selectedText); try { - // getUserLexicons = fonction définie dans api.js (s'assurer que api.js est chargé avant) const lexicons = await getUserLexicons(authToken); console.log("📚 Lexiques récupérés :", lexicons); @@ -225,7 +214,6 @@ async function searchLexicon(selectedText) { return; } - // getLexiconEntriesID = fonction dans api.js const entries = await getLexiconEntriesID(authToken, frenchLexicon.id); const isWordPresent = entries.some( (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() @@ -235,7 +223,6 @@ async function searchLexicon(selectedText) { alert(`✅ Le mot "${selectedText}" est présent dans votre lexique personnel.`); } else { alert(`⌠Le mot "${selectedText}" n'est pas présent dans votre lexique personnel.`); - // Ici tu pourrais lancer l'ajout, si tu as une API pour ajouter. } } catch (error) { console.error("⌠Erreur lors de la recherche dans le lexique :", error); -- GitLab From 2b3de12088a4d13b18b04c6f554a16a288f7d85e Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sun, 2 Feb 2025 20:22:54 +0100 Subject: [PATCH 10/32] Message mot absent des lexiques --- "barre_lat\303\251rale/sidebar.html" | 18 +++- "barre_lat\303\251rale/sidebar.js" | 119 +++++++++++++++++++++------ 2 files changed, 110 insertions(+), 27 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 13088fb..b788ded 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -202,6 +202,12 @@ font-size: small; color: #333; } + + #noDefinitionsContainer { + display: block !important; + color: red !important; + font-weight: bold; + } </style> </head> <body> @@ -245,16 +251,20 @@ <ul id="mesLexiquesList"></ul> </div> + <div id="noLexiconDefinitionsContainer" style="display: none; color: #8d5c70;"> + <p>Aucune définition trouvée dans vos lexiques.</p> + </div> + + <div id="noWiktionaryDefinitionsContainer" style="display: none; color: #8d5c70;"> + <p>Aucune définition trouvée dans le Wiktionnaire.</p> + </div> + <!-- Définitions issues du Wiktionnaire --> <div id="wiktionnaireContainer"> <h4>🌠Wiktionnaire</h4> <ul id="wiktionnaireList"></ul> </div> - <div id="noDefinitionsContainer" style="display: none; color: #8d5c70;"> - <p>Aucune définition trouvée.</p> - </div> - <!-- Fenêtre modale cachée --> <div id="modalOverlay" class="modal-overlay"> <div class="modal-content"> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 959a911..02d079d 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -90,7 +90,11 @@ async function refreshSidebarState() { const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { lexiquesContainer.textContent = "Veuillez vous connecter pour voir vos lexiques."; - } + } else if (!lexiquesContainer) { + console.error("⌠Élément #lexiques introuvable dans le DOM."); + return; +} + } console.log("✅ Barre latérale actualisée. Utilisateur connecté :", isLoggedIn); @@ -416,6 +420,7 @@ async function fetchWiktionaryDefinition(word) { } } + /** * Affiche les définitions dans deux listes : * - Mes lexiques (#mesLexiquesList) @@ -426,38 +431,51 @@ const modalOverlay = document.getElementById("modalOverlay"); const modalFullText = document.getElementById("modalFullText"); const closeModalBtn = document.getElementById("closeModal"); +/** + * Affiche les définitions dans la barre latérale. + * @param {Array} definitions - Tableau d'objets de la forme { source, text } + */ function displayDefinitions(definitions) { console.log("📖 Affichage des définitions reçues :", definitions); if (!Array.isArray(definitions)) return; const mesLexiquesList = document.getElementById("mesLexiquesList"); const wiktionnaireList = document.getElementById("wiktionnaireList"); - const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); + // Messages d'erreur/absence de définitions + const noLexiconDefinitionsContainer = document.getElementById("noLexiconDefinitionsContainer"); + const noWiktionaryDefinitionsContainer = document.getElementById("noWiktionaryDefinitionsContainer"); + + // On réinitialise les listes existantes mesLexiquesList.innerHTML = ""; wiktionnaireList.innerHTML = ""; + // On masque d'emblée les messages d'erreur + if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "none"; + if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "none"; + + // Variables pour suivre la présence de définitions let hasLexiconDefinitions = false; let hasWiktionaryDefinitions = false; - // Regrouper les définitions par lexique + // Objet pour regrouper les définitions par lexique const lexiconGroups = {}; + // Parcours de chaque définition definitions.forEach(({ source, text }) => { if (!source || !text) return; + // Création de l'élément <li> et gestion du "Lire la suite" const li = document.createElement("li"); - let displayedText = text; + if (text.length > MAX_LENGTH) { displayedText = text.slice(0, MAX_LENGTH) + "... "; - - // Bouton "Lire la suite" const readMoreLink = document.createElement("a"); readMoreLink.href = "#"; readMoreLink.textContent = "[Lire la suite]"; readMoreLink.style.marginLeft = "5px"; - readMoreLink.style.color = "#a08e9f"; + readMoreLink.style.color = "#8d5c70"; readMoreLink.style.textDecoration = "underline"; readMoreLink.style.cursor = "pointer"; readMoreLink.addEventListener("click", (event) => { @@ -465,18 +483,19 @@ function displayDefinitions(definitions) { openDefinitionPopup(text); }); + // On assemble le li li.appendChild(document.createTextNode(displayedText)); li.appendChild(readMoreLink); } else { li.textContent = displayedText; } + // Vérification de la source (Wiktionnaire / Lexiques) if (source === "Wiktionnaire") { - // Ajouter directement les définitions du Wiktionnaire wiktionnaireList.appendChild(li); hasWiktionaryDefinitions = true; } else { - // Regrouper par lexique + // Si on veut grouper par nom de lexique if (!lexiconGroups[source]) { lexiconGroups[source] = []; } @@ -485,38 +504,56 @@ function displayDefinitions(definitions) { } }); - // Création des listes déroulantes par lexique - Object.entries(lexiconGroups).forEach(([lexicon, definitionItems]) => { + // Création d'une structure pour les différents lexiques + Object.entries(lexiconGroups).forEach(([lexiconName, definitionItems]) => { const lexiconContainer = document.createElement("div"); lexiconContainer.className = "lexicon-section"; const lexiconHeader = document.createElement("div"); lexiconHeader.className = "lexicon-header"; - lexiconHeader.textContent = lexicon; + lexiconHeader.textContent = lexiconName; + // Toggle d'affichage au clic lexiconHeader.addEventListener("click", () => { lexiconContent.classList.toggle("hidden"); }); - // Liste des définitions const lexiconContent = document.createElement("ul"); - lexiconContent.className = "lexicon-content hidden"; - - definitionItems.forEach((li) => lexiconContent.appendChild(li)); + lexiconContent.className = "lexicon-content hidden"; + definitionItems.forEach(li => lexiconContent.appendChild(li)); lexiconContainer.appendChild(lexiconHeader); lexiconContainer.appendChild(lexiconContent); mesLexiquesList.appendChild(lexiconContainer); }); - // Afficher ou cacher les sections - document.getElementById("mesLexiquesContainer").style.display = hasLexiconDefinitions ? "block" : "none"; - document.getElementById("wiktionnaireContainer").style.display = hasWiktionaryDefinitions ? "block" : "none"; - noDefinitionsContainer.style.display = (!hasLexiconDefinitions && !hasWiktionaryDefinitions) ? "block" : "none"; - noDefinitionsContainer.textContent = "Aucune définition trouvée pour ce mot."; + // Condition : s'il n'y a AUCUNE définition dans les lexiques + if (!hasLexiconDefinitions) { + console.warn("âš ï¸ Aucune définition trouvée dans les lexiques de l'utilisateur."); + if (noLexiconDefinitionsContainer) { + noLexiconDefinitionsContainer.style.display = "block"; + } + } + + // Condition : s'il n'y a AUCUNE définition Wiktionnaire + if (!hasWiktionaryDefinitions) { + console.warn("âš ï¸ Aucune définition trouvée dans le Wiktionnaire."); + if (noWiktionaryDefinitionsContainer) { + noWiktionaryDefinitionsContainer.style.display = "block"; + } + } + + // Affiche ou masque la section "Mes lexiques" selon l'existence de définitions + document.getElementById("mesLexiquesContainer").style.display = + hasLexiconDefinitions ? "block" : "none"; + + // Affiche ou masque la section "Wiktionnaire" selon l'existence de définitions + document.getElementById("wiktionnaireContainer").style.display = + hasWiktionaryDefinitions ? "block" : "none"; } + function openDefinitionPopup(fullText) { modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; modalOverlay.style.display = "flex"; @@ -533,38 +570,45 @@ modalOverlay.addEventListener("click", (event) => { }); /** - * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire + * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire, * puis les afficher. */ async function showDefinitions(word) { console.log(`📖 Recherche des définitions pour '${word}'...`); + // Sélection du conteneur d'erreur/message const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); if (noDefinitionsContainer) { + // On indique clairement que la recherche est en cours noDefinitionsContainer.textContent = "Chargement des définitions..."; noDefinitionsContainer.style.display = "block"; } try { + // On lance en parallèle la récupération des définitions const [lexiconDefinitions, wiktionaryDefinitions] = await Promise.all([ fetchLexiconDefinitions(word), fetchWiktionaryDefinition(word) ]); + // Fusion des résultats const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; console.log("📚 Définitions combinées :", allDefinitions); + // On délègue l'affichage final à displayDefinitions displayDefinitions(allDefinitions); } catch (error) { console.error("⌠Erreur lors de la récupération des définitions :", error); if (noDefinitionsContainer) { - noDefinitionsContainer.textContent = "⌠Une erreur est survenue lors de la récupération des définitions."; + noDefinitionsContainer.textContent = + "⌠Une erreur est survenue lors de la récupération des définitions."; noDefinitionsContainer.style.display = "block"; } } } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Gestion des messages reçus (depuis le background ou ailleurs) // ───────────────────────────────────────────────────────────────────────────── @@ -623,6 +667,35 @@ browser.runtime.onMessage.addListener(async (message) => { } }); +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Recherche et affichage des définitions +// ───────────────────────────────────────────────────────────────────────────── +async function fetchDefinition(word) { + console.log(`🔠Recherche de la définition pour '${word}'...`); + + const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); + if (!noDefinitionsContainer) { + console.error("⌠Élément #noDefinitionsContainer introuvable."); + return; + } + + try { + const definition = await getDefinitionFromLexicons(word, authToken); + console.log("🔠Résultat API :", definition); + + if (!definition || definition.length === 0) { + console.warn(`âš ï¸ Aucune définition trouvée pour '${word}'`); + noDefinitionsContainer.style.display = "block"; // Afficher le message d'erreur + return; + } + + noDefinitionsContainer.style.display = "none"; // Cacher le message si une définition est trouvée + } catch (error) { + console.error("⌠Erreur lors de la récupération de la définition :", error); + noDefinitionsContainer.style.display = "block"; // Afficher une erreur générale + } +} + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Initialisation après chargement du DOM // ───────────────────────────────────────────────────────────────────────────── -- GitLab From ce3a0d1a3d019c982e14fa85c5e42cd81c26a2f8 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:08:10 +0100 Subject: [PATCH 11/32] =?UTF-8?q?Actualisation=20barre=20apr=C3=A8s=20d?= =?UTF-8?q?=C3=A9connexion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- background/background.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/background/background.js b/background/background.js index 1805474..d0d83db 100644 --- a/background/background.js +++ b/background/background.js @@ -95,7 +95,9 @@ async function disconnectFromLexicalDB() { "Vous êtes maintenant déconnecté(e).", "icons/logout.png" ); - await refreshAllUI(); + setTimeout(async () => { + await refreshAllUI(); + }, 500); } /** -- GitLab From 346252edfe148285bb4b0a5a29a3e247b4d31138 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Mon, 3 Feb 2025 17:37:25 +0100 Subject: [PATCH 12/32] Correction affichage options menu contextuel navigateur --- background/background.js | 24 ---------- background/browser_context_menu.js | 72 +++++++++++++++++++----------- 2 files changed, 46 insertions(+), 50 deletions(-) diff --git a/background/background.js b/background/background.js index d0d83db..c0fa9fc 100644 --- a/background/background.js +++ b/background/background.js @@ -254,30 +254,6 @@ async function createBrowserContextMenu() { await browser.contextMenus.removeAll(); const isConnected = await isUserConnected(); - // Si connecté : options supplémentaires pour le lexique - if (isConnected) { - browser.contextMenus.create({ - id: "searchLexicon", - title: "Vérifier si le mot est dans le lexique personnel", - contexts: ["selection"], - }); - browser.contextMenus.create({ - id: "checkLexicon", - title: "Afficher dans quels lexiques le mot est présent", - contexts: ["selection"], - }); - browser.contextMenus.create({ - id: "getDefinition", - title: "Obtenir une définition à partir de mes lexiques", - contexts: ["selection"], - }); - } - // Option pour rechercher sur le Wiktionnaire (accessible à tous) - browser.contextMenus.create({ - id: "getDefinitionWiki", - title: "Rechercher une définition sur le Wiktionnaire", - contexts: ["selection"], - }); // Bouton de connexion/déconnexion browser.contextMenus.create({ id: "login", diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index ae2a6be..fee1730 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -21,18 +21,10 @@ loadAuthToken(); // â–Œ Création du menu contextuel du navigateur // ───────────────────────────────────────────────────────────────────────────── -// 1. Vérifier si le mot est dans le lexique -browser.contextMenus.create({ - id: "searchLexicon", - title: "Ce mot est-il dans mon lexique ?", - contexts: ["selection"], - icons: { "16": "icons/recherche_lexique.png" }, -}); - // 2. Vérifier dans quels lexiques le mot est présent browser.contextMenus.create({ - id: "checkLexicon", - title: "Afficher dans quel(s) lexique(s) ce mot est présent", + id: "searchInLexicons", + title: "Rechercher dans mes lexiques", contexts: ["selection"], icons: { "16": "icons/quel_lexique.png" }, }); @@ -76,27 +68,17 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log(`📩 Texte sélectionné dans le menu du navigateur : ${info.selectionText}`); switch (info.menuItemId) { - // 1) Vérifier si le mot est dans le lexique - case "searchLexicon": - console.log("🔠Recherche dans le lexique :", info.selectionText); + // Recherche dans les lexiques de l’utilisateur + case "searchInLexicons": + console.log("🔠Recherche du mot dans les lexiques :", info.selectionText); if (authToken) { - await searchLexicon(info.selectionText); + await searchInLexicons(info.selectionText); } else { alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); } break; - // 2) Vérifier dans quels lexiques le mot est présent - case "checkLexicon": - console.log("📋 Vérification des lexiques :", info.selectionText); - if (authToken) { - await checkLexicon(info.selectionText); - } else { - alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); - } - break; - - // 4) Un seul bouton pour une définition (Lexiques + Wiki) + // Un seul bouton pour une définition (Lexiques + Wiki) case "getDefinitionAll": console.log("🌠Recherche de définition :", info.selectionText); await getDefinitionAll(info.selectionText); @@ -222,7 +204,7 @@ async function getDefinitionFromWiktionary(selectedText) { */ async function searchLexicon(selectedText) { try { - const lexicons = await getUserLexicons(authToken); + const lexicons = await getLexicons(authToken); console.log("📚 Lexiques récupérés :", lexicons); const frenchLexicon = lexicons.find((lexicon) => lexicon.language === "fr"); @@ -270,6 +252,44 @@ async function checkLexicon(selectedText) { } } +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Fonction combinée : Recherche du mot dans les lexiques +// ───────────────────────────────────────────────────────────────────────────── + +async function searchInLexicons(selectedText) { + try { + console.log("🔎 Vérification des lexiques pour :", selectedText); + const lexicons = await getLexiconEntries(authToken); + + if (!lexicons.length) { + alert("âš ï¸ Aucun lexique disponible."); + return; + } + + let foundInLexicons = []; + + for (const lexicon of lexicons) { + const entries = await getLexiconEntries(authToken, lexicon.id); + const isWordPresent = entries.some( + (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() + ); + + if (isWordPresent) { + foundInLexicons.push(lexicon.name); + } + } + + if (foundInLexicons.length > 0) { + alert(`✅ Le mot "${selectedText}" est présent dans les lexiques suivants :\n\n- ${foundInLexicons.join("\n- ")}`); + } else { + alert(`⌠Le mot "${selectedText}" n'est pas présent dans vos lexiques.`); + } + } catch (error) { + console.error("⌠Erreur lors de la recherche dans les lexiques :", error); + alert("⌠Une erreur est survenue lors de la recherche."); + } +} + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Listeners supplémentaires // ───────────────────────────────────────────────────────────────────────────── -- GitLab From 7af6d0c90a45e05f52c943985af2be9ed8b16b3b Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Mon, 3 Feb 2025 20:27:32 +0100 Subject: [PATCH 13/32] =?UTF-8?q?Affichage=20pr=C3=A9sence=20mot=20dans=20?= =?UTF-8?q?lexiques=20utilisateur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- background/background.js | 7 +++ background/browser_context_menu.js | 77 ++++++++++++++++++++++------ "barre_lat\303\251rale/sidebar.html" | 1 + "barre_lat\303\251rale/sidebar.js" | 50 +++++++++++++++++- manifest.json | 5 +- 5 files changed, 121 insertions(+), 19 deletions(-) diff --git a/background/background.js b/background/background.js index c0fa9fc..0d84f3b 100644 --- a/background/background.js +++ b/background/background.js @@ -279,6 +279,12 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { selectedText: info.selectionText, }); break; + case "searchInLexicons": + browser.tabs.sendMessage(tab.id, { + action: "searchInLexicons", + selectedText: info.selectionText, + }); + break; case "getDefinition": browser.tabs.sendMessage(tab.id, { action: "getDefinition", @@ -305,6 +311,7 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } }); + // ───────────────────────────────────────────────────────────────────────────── // Web Navigation : Injection de scripts et récupération du token // ───────────────────────────────────────────────────────────────────────────── diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index fee1730..910f7ca 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -258,38 +258,81 @@ async function checkLexicon(selectedText) { async function searchInLexicons(selectedText) { try { - console.log("🔎 Vérification des lexiques pour :", selectedText); - const lexicons = await getLexiconEntries(authToken); - - if (!lexicons.length) { - alert("âš ï¸ Aucun lexique disponible."); + console.log("🔎 Recherche dans les lexiques pour :", selectedText); + + // Récupérer les lexiques en français + const lexicons = await getLexicons(authToken, "fr"); + if (!Array.isArray(lexicons) || lexicons.length === 0) { + console.log("âš ï¸ Aucun lexique disponible."); return; } - + let foundInLexicons = []; - + for (const lexicon of lexicons) { - const entries = await getLexiconEntries(authToken, lexicon.id); - const isWordPresent = entries.some( - (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() - ); - + // Récupération des entrées du lexique + let entriesResponse = await getLexiconEntries(authToken, lexicon.id); + console.log(`Réponse pour le lexique ${lexicon.id}:`, entriesResponse); + + // Extraction du tableau d’entrées selon différents formats possibles + let entries; + if (Array.isArray(entriesResponse)) { + entries = entriesResponse; + } else if (entriesResponse && Array.isArray(entriesResponse.entries)) { + entries = entriesResponse.entries; + } else if (entriesResponse && Array.isArray(entriesResponse.data)) { + entries = entriesResponse.data; + } else { + console.warn(`Format inattendu pour les entrées du lexique ${lexicon.id}`, entriesResponse); + continue; // Passez au lexique suivant + } + + // Vérification de la présence du mot (en s’assurant que entry.graphy existe) + const isWordPresent = entries.some(entry => { + return entry.graphy && entry.graphy.toLowerCase() === selectedText.toLowerCase(); + }); + if (isWordPresent) { - foundInLexicons.push(lexicon.name); + // Utilise un nom par défaut si lexicon.name est vide ou non défini + foundInLexicons.push(lexicon.name || `Lexique #${lexicon.id}`); } } - + if (foundInLexicons.length > 0) { - alert(`✅ Le mot "${selectedText}" est présent dans les lexiques suivants :\n\n- ${foundInLexicons.join("\n- ")}`); + const lexiconList = foundInLexicons.map((lexicon) => ({ + name: lexicon.name || `Lexique #${lexicon.id || "inconnu"}`, + id: lexicon.id || "inconnu" + })); + + console.log("📩 Envoi du message `showLexiconResult` à sidebar.js :", lexiconList); + + browser.runtime.sendMessage({ + action: "showLexiconResult", + lexicons: lexiconList, // On envoie un tableau d'objets avec noms et IDs + selectedText: selectedText + }); } else { - alert(`⌠Le mot "${selectedText}" n'est pas présent dans vos lexiques.`); + console.log("⌠Aucun lexique trouvé."); + browser.runtime.sendMessage({ + action: "showLexiconResult", + lexicons: [], + selectedText: selectedText + }); } + + + } catch (error) { console.error("⌠Erreur lors de la recherche dans les lexiques :", error); - alert("⌠Une erreur est survenue lors de la recherche."); + console.log("⌠Une erreur est survenue lors de la recherche."); } } + + + + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Listeners supplémentaires // ───────────────────────────────────────────────────────────────────────────── diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index b788ded..f961305 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -228,6 +228,7 @@ <div id="etat"> <h3>Mot sélectionné</h3> <p id="motSelectionne">Aucun mot sélectionné</p> + <p id="lexiconResult" style="color: green; font-weight: bold;"></p> <div id="add-to-lexiques" style="display: none;"> <button id="add-word-button">Ajouter le mot sélectionné</button> </div> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 02d079d..d81ed97 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -257,6 +257,7 @@ async function fetchLexicons() { } } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Gestion du bouton de connexion/déconnexion // ───────────────────────────────────────────────────────────────────────────── @@ -662,11 +663,58 @@ browser.runtime.onMessage.addListener(async (message) => { } break; + case "showLexiconResult": + console.log("📚 Résultat des lexiques reçus :", message.lexicons); + displayLexiconResults(message.lexicons); + break; + default: console.warn("âš ï¸ Action inconnue reçue :", message.action); } }); +/** + * Affiche les lexiques où le mot sélectionné est présent. + */ +function displayLexiconResults(lexicons) { + const resultDiv = document.getElementById("lexiconResult"); + + if (!resultDiv) return; // Sécurité si l'élément n'existe pas + + // Vider le contenu précédent + resultDiv.innerHTML = ""; + + if (!lexicons || lexicons.length === 0) { + resultDiv.textContent = "⌠Ce mot n'est présent dans aucun lexique."; + return; + } + + // Création d'un titre pour la section + const title = document.createElement("p"); + title.textContent = "✅ Ce mot est présent dans les lexiques suivants :"; + resultDiv.appendChild(title); + + // Création de la liste UL + const ul = document.createElement("ul"); + ul.style.paddingLeft = "20px"; // Ajouter une indentation pour la liste + + // Remplir la liste avec les lexiques trouvés + lexicons.forEach((lexicon) => { + if (!lexicon || !lexicon.name || !lexicon.id) { + console.warn("âš ï¸ Objet lexique incorrect :", lexicon); + return; + } + + const li = document.createElement("li"); + li.innerHTML = `<strong>${lexicon.name}</strong> (ID: ${lexicon.id})`; + ul.appendChild(li); + }); + + // Ajouter la liste au conteneur + resultDiv.appendChild(ul); +} + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Recherche et affichage des définitions // ───────────────────────────────────────────────────────────────────────────── @@ -680,7 +728,7 @@ async function fetchDefinition(word) { } try { - const definition = await getDefinitionFromLexicons(word, authToken); + const definition = await fetchLexiconDefinitions(word); console.log("🔠Résultat API :", definition); if (!definition || definition.length === 0) { diff --git a/manifest.json b/manifest.json index 581db69..936ae01 100644 --- a/manifest.json +++ b/manifest.json @@ -18,7 +18,10 @@ ], "background": { - "scripts": ["background/background.js", "background/browser_context_menu.js"], + "scripts": [ + "background/background.js", + "background/browser_context_menu.js", + "api.js"], "persistent": true }, -- GitLab From e38c4b810d94aea046743f0047c21c04b8d0829f Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 4 Feb 2025 14:02:16 +0100 Subject: [PATCH 14/32] =?UTF-8?q?Corrections=20affichage=20mot=20pr=C3=A9s?= =?UTF-8?q?ent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- background/browser_context_menu.js | 19 ++++----- "barre_lat\303\251rale/sidebar.html" | 3 +- "barre_lat\303\251rale/sidebar.js" | 61 ++++++++++++++++++++-------- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index 910f7ca..db2a98e 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -293,22 +293,20 @@ async function searchInLexicons(selectedText) { }); if (isWordPresent) { - // Utilise un nom par défaut si lexicon.name est vide ou non défini - foundInLexicons.push(lexicon.name || `Lexique #${lexicon.id}`); + // On stocke l'objet complet avec id et name + foundInLexicons.push({ + id: lexicon.id, + name: lexicon.name || `Lexique #${lexicon.id || "inconnu"}` + }); } } if (foundInLexicons.length > 0) { - const lexiconList = foundInLexicons.map((lexicon) => ({ - name: lexicon.name || `Lexique #${lexicon.id || "inconnu"}`, - id: lexicon.id || "inconnu" - })); - - console.log("📩 Envoi du message `showLexiconResult` à sidebar.js :", lexiconList); + console.log("📩 Envoi du message `showLexiconResult` à sidebar.js :", foundInLexicons); browser.runtime.sendMessage({ action: "showLexiconResult", - lexicons: lexiconList, // On envoie un tableau d'objets avec noms et IDs + lexicons: foundInLexicons, // On envoie un tableau d'objets avec noms et IDs selectedText: selectedText }); } else { @@ -320,8 +318,6 @@ async function searchInLexicons(selectedText) { }); } - - } catch (error) { console.error("⌠Erreur lors de la recherche dans les lexiques :", error); console.log("⌠Une erreur est survenue lors de la recherche."); @@ -333,6 +329,7 @@ async function searchInLexicons(selectedText) { + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Listeners supplémentaires // ───────────────────────────────────────────────────────────────────────────── diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index f961305..66b125c 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -55,6 +55,7 @@ /* Mot sélectionné */ #motSelectionne { font-style: italic; + font-weight: bold; text-align: center; margin-top: 5px; } @@ -228,7 +229,7 @@ <div id="etat"> <h3>Mot sélectionné</h3> <p id="motSelectionne">Aucun mot sélectionné</p> - <p id="lexiconResult" style="color: green; font-weight: bold;"></p> + <p id="lexiconResult"></p> <div id="add-to-lexiques" style="display: none;"> <button id="add-word-button">Ajouter le mot sélectionné</button> </div> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index d81ed97..6749b80 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -10,6 +10,10 @@ console.log( // Variable globale pour le token d'authentification let authToken = null; +// Variable pour stocker les lexiques avec leur ID et leur nom +const lexiconMap = new Map(); + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Fonctions liées au token // ───────────────────────────────────────────────────────────────────────────── @@ -214,36 +218,46 @@ function displayLexiconsWithCheckbox(lexicons) { /** * Récupère la liste des lexiques depuis l'API via getLexicons puis affiche avec displayLexiconsWithCheckbox. */ + async function fetchLexicons() { try { console.log("🔄 Début de la récupération des lexiques..."); console.log("🔑 Token utilisé :", authToken); - + if (!authToken) { throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); } - + const lexicons = await getLexicons(authToken, "fr"); console.log("📚 Réponse brute de l'API :", lexicons); - + if (!Array.isArray(lexicons) || lexicons.length === 0) { throw new Error("âš ï¸ Aucun lexique trouvé."); } - + + lexiconMap.clear(); // Vider la Map pour éviter d'accumuler de vieux lexiques + const results = lexicons.map((lexicon) => { console.log("📋 Transformation du lexique :", lexicon); + + // Déterminer le nom du lexique + const lexiconName = + lexicon.category === "User" + ? `Lexique personnel (${lexicon.user?.pseudo || "Inconnu"})` + : `Lexique de groupe (${lexicon.group?.name || "Inconnu"})`; + + // Ajouter l'ID et le nom dans lexiconMap + lexiconMap.set(lexicon.id, lexiconName); + return { - lexiconName: - lexicon.category === "User" - ? `Lexique personnel (${lexicon.user?.pseudo || "Inconnu"})` - : `Lexique de groupe (${lexicon.group?.name || "Inconnu"})`, + lexiconName, lexiconId: lexicon.id, active: lexicon.active || false, }; }); - - console.log("Appel de displayLexiconsWithCheckbox avec :", results); - + + console.log("📌 Contenu de lexiconMap après mise à jour :", lexiconMap); + // Affichage des lexiques avec checkbox displayLexiconsWithCheckbox(results); } catch (error) { @@ -258,6 +272,8 @@ async function fetchLexicons() { } + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Gestion du bouton de connexion/déconnexion // ───────────────────────────────────────────────────────────────────────────── @@ -691,23 +707,32 @@ function displayLexiconResults(lexicons) { // Création d'un titre pour la section const title = document.createElement("p"); - title.textContent = "✅ Ce mot est présent dans les lexiques suivants :"; + title.innerHTML = "Ce mot est présent dans le(s) lexique(s) suivant(s) :"; + title.style.fontSize = "12px"; resultDiv.appendChild(title); // Création de la liste UL const ul = document.createElement("ul"); - ul.style.paddingLeft = "20px"; // Ajouter une indentation pour la liste + ul.style.paddingLeft = "20px"; + + // Vérification que lexiconMap est bien rempli + console.log("📌 Vérification de lexiconMap avant affichage :", lexiconMap); // Remplir la liste avec les lexiques trouvés lexicons.forEach((lexicon) => { - if (!lexicon || !lexicon.name || !lexicon.id) { - console.warn("âš ï¸ Objet lexique incorrect :", lexicon); + if (!lexicon || !lexicon.id) { + console.warn("âš ï¸ Lexique incorrect ou ID non défini :", lexicon); return; } + // Récupérer le nom depuis lexiconMap + const lexiconName = lexiconMap.get(lexicon.id) || `Lexique #${lexicon.id} (Nom inconnu)`; + const li = document.createElement("li"); - li.innerHTML = `<strong>${lexicon.name}</strong> (ID: ${lexicon.id})`; + li.innerHTML = `<strong>${lexiconName}</strong> (${lexicon.id})`; ul.appendChild(li); + + console.log(`✅ Lexique ajouté : ${lexiconName} (ID: ${lexicon.id})`); }); // Ajouter la liste au conteneur @@ -715,6 +740,10 @@ function displayLexiconResults(lexicons) { } + + + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Recherche et affichage des définitions // ───────────────────────────────────────────────────────────────────────────── -- GitLab From fb0019b2432e002f28b94e96b86a70bf3ec002ba Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 4 Feb 2025 17:15:21 +0100 Subject: [PATCH 15/32] =?UTF-8?q?Corrections=20affichage=20d=C3=A9finition?= =?UTF-8?q?s=20lexiques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.js | 10 +- "barre_lat\303\251rale/sidebar.html" | 5 +- "barre_lat\303\251rale/sidebar.js" | 208 +++++++++++++++------------ 3 files changed, 132 insertions(+), 91 deletions(-) diff --git a/api.js b/api.js index 3519298..785142a 100644 --- a/api.js +++ b/api.js @@ -167,7 +167,14 @@ async function getAllLexiconWords(authToken) { for (const lexicon of lexicons) { const entries = await getLexiconEntries(authToken, lexicon.id); const allGraphies = entries.map(entry => entry.graphy); - allGraphiesByLexicon[lexicon.name] = allGraphies; + + // Création d'un libellé unique pour le lexique + const lexiconName = + lexicon.category === "User" + ? `Lexique personnel (${lexicon.user?.pseudo || "Inconnu"}) [${lexicon.id}]` + : `Lexique de groupe (${lexicon.group?.name || "Inconnu"}) [${lexicon.id}]`; + + allGraphiesByLexicon[lexiconName] = allGraphies; } console.log("✅ Toutes les graphies récupérées :", allGraphiesByLexicon); @@ -178,6 +185,7 @@ async function getAllLexiconWords(authToken) { } } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Récupération de définition du Wiktionnaire // ───────────────────────────────────────────────────────────────────────────── diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 66b125c..07944d2 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -4,8 +4,9 @@ <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BaLex - Barre Latérale</title> - <script src="sidebar.js" defer></script> <script src="../api.js" defer></script> + <script src="sidebar.js" defer></script> + <style> /* Style global */ body { @@ -254,7 +255,7 @@ </div> <div id="noLexiconDefinitionsContainer" style="display: none; color: #8d5c70;"> - <p>Aucune définition trouvée dans vos lexiques.</p> + <p>Aucune définition trouvée dans les lexiques.</p> </div> <div id="noWiktionaryDefinitionsContainer" style="display: none; color: #8d5c70;"> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 6749b80..39849d8 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -89,16 +89,15 @@ async function refreshSidebarState() { toggleHighlightMessage(isLoggedIn); if (isLoggedIn) { - await fetchLexicons(); + await fetchLexicons(); } else { const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { lexiquesContainer.textContent = "Veuillez vous connecter pour voir vos lexiques."; } else if (!lexiquesContainer) { console.error("⌠Élément #lexiques introuvable dans le DOM."); - return; -} - + return; + } } console.log("✅ Barre latérale actualisée. Utilisateur connecté :", isLoggedIn); @@ -288,8 +287,22 @@ async function handleAuthButtonClick() { /** * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), - * en faisant un appel séparé pour chaque lexique : - * GET /api/entry/search?graphy={word}&language=fr&target_lex={lexicon.id} + * en effectuant un appel global à l'API pour le mot recherché, puis en filtrant + * les entrées pour ne conserver que celles dont le lexicon.id est présent dans la liste + * des lexiques de l'utilisateur. + * + * Retourne un tableau d'objets { source, text } où: + * - source = nom du lexique (ou "Lexique #ID") + * - text = texte de la définition + * + * @param {string} word - Le mot recherché (ex. "chat"). + * @returns {Promise<Array<{ source: string, text: string }>>} + */ +/** + * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), + * en effectuant un appel global à l'API pour le mot recherché, puis en filtrant + * les entrées pour ne conserver que celles dont le lexicon.id est présent dans la liste + * des lexiques de l'utilisateur. * * Retourne un tableau d'objets { source, text } où: * - source = nom du lexique (ou "Lexique #ID") @@ -308,82 +321,97 @@ async function fetchLexiconDefinitions(word) { } // 1) Récupérer la liste complète des lexiques de l'utilisateur - // Par défaut : user_id=4 et language=fr const userId = 4; const lexUrl = `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=fr`; const lexResponse = await fetch(lexUrl, { headers: { Authorization: `Bearer ${authToken}` } }); - if (!lexResponse.ok) { throw new Error(`⌠Erreur API lors de la récupération des lexiques: ${lexResponse.statusText}`); } - const userLexicons = await lexResponse.json(); console.log("ðŸ—‚ï¸ Lexiques de l'utilisateur :", userLexicons); if (!Array.isArray(userLexicons) || userLexicons.length === 0) { - console.warn("âš ï¸ Aucuns lexiques trouvés pour cet utilisateur."); + console.warn("âš ï¸ Aucun lexique trouvé pour cet utilisateur."); return []; } - // 2) Pour chaque lexique, on va faire une requête - // GET /api/entry/search?graphy=word&language=fr&target_lex={lexicon.id} - let allDefinitions = []; + // Mise à jour de lexiconMap avec des libellés uniques (ajout de l'ID) + lexiconMap.clear(); + userLexicons.forEach((lex) => { + const lexiconName = + lex.category === "User" + ? `Lexique personnel (${lex.user?.pseudo || "Inconnu"})` + : `Lexique de groupe (${lex.group?.name || "Inconnu"})`; + lexiconMap.set(lex.id, lexiconName); + }); + console.log("📌 LexiconMap :", lexiconMap); - for (const lex of userLexicons) { - const lexId = lex.id; // ID du lexique - const lexName = lex.name || `Lexique #${lexId}`; + // 2) Pour chaque lexique, rechercher le mot en ajoutant target_lex + const definitionsPromises = userLexicons.map(async (lex) => { + const searchUrl = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=${lex.id}`; + console.log(`🔎 Appel API pour le lexique ${lex.id} avec l'URL : ${searchUrl}`); - const url = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=${lexId}`; - console.log(`🔎 Appel API pour le lexique #${lexId} (${lexName}) => ${url}`); + const searchResponse = await fetch(searchUrl, { + headers: { Authorization: `Bearer ${authToken}` } + }); + if (!searchResponse.ok) { + console.warn(`âš ï¸ Erreur pour le lexique ${lex.id} : ${searchResponse.statusText}`); + return { lexiconId: lex.id, entries: [] }; + } + const entries = await searchResponse.json(); - try { - const response = await fetch(url, { - headers: { Authorization: `Bearer ${authToken}` } - }); + // Filtrage côté client : ne garder que les entrées dont entry.lexicon.id correspond exactement à lex.id + const filteredEntries = entries.filter(entry => { + if (!entry.lexicon) return false; + return Number(entry.lexicon.id) === Number(lex.id); + }); - if (!response.ok) { - console.warn(`⌠Lexique ${lexId} : Erreur API (${response.status}): ${response.statusText}`); - continue; - } + console.log(`Pour le lexique ${lex.id} (${lexiconMap.get(lex.id)}), entrées filtrées :`, filteredEntries); - const data = await response.json(); - if (!Array.isArray(data) || data.length === 0) { - continue; - } + return { lexiconId: lex.id, entries: filteredEntries }; + }); - // On parse pour extraire toutes les définitions - for (const entry of data) { - const items = entry.attributes?.Items; - if (!Array.isArray(items)) { - continue; + const results = await Promise.all(definitionsPromises); + + // 3) Parcourir les résultats et extraire les définitions + let allDefinitions = []; + results.forEach(result => { + const lexiconId = result.lexiconId; + const sourceName = lexiconMap.get(lexiconId) || `Lexique #${lexiconId}`; + + result.entries.forEach(entry => { + // Vérifier à nouveau que l'entrée appartient bien au lexique ciblé + if (!entry.lexicon || Number(entry.lexicon.id) !== Number(lexiconId)) return; + + let items = entry.attributes?.Items; + // Si items n'est pas un tableau mais est un objet, convertir en tableau + if (!Array.isArray(items)) { + if (typeof items === 'object' && items !== null) { + items = Object.values(items); + } else { + return; } + } - for (const subItem of items) { - const definitionsArray = subItem.Sense?.Definitions; - if (!Array.isArray(definitionsArray)) { - continue; - } + items.forEach(item => { + const definitionsArray = item.Sense?.Definitions; + if (!Array.isArray(definitionsArray)) return; - for (const defObj of definitionsArray) { - if (defObj.Def) { - const fullLexName = `${lex.name || `Lexique` } (#${lex.id})`; - allDefinitions.push({ - source: fullLexName, - text: defObj.Def - }); - } + definitionsArray.forEach(defObj => { + if (defObj.Def) { + allDefinitions.push({ + source: sourceName, + text: defObj.Def + }); } - } - } + }); + }); + }); + }); - } catch (err) { - console.error(`Erreur lors de la requête pour le lexique #${lexId} :`, err); - } - } - console.log("Résultat final :", allDefinitions); - // 3) Retourne le tableau de toutes les définitions trouvées + console.log("Résultat final filtré :", allDefinitions); return allDefinitions; } catch (error) { console.error("⌠Erreur générale lors de la récupération des définitions :", error); @@ -391,6 +419,7 @@ async function fetchLexiconDefinitions(word) { } } + /** * Récupère la définition d'un mot depuis le Wiktionnaire (fr). * Retourne un tableau d'objets : [{ source: 'Wiktionnaire', text: '...' }] @@ -463,26 +492,24 @@ function displayDefinitions(definitions) { const noLexiconDefinitionsContainer = document.getElementById("noLexiconDefinitionsContainer"); const noWiktionaryDefinitionsContainer = document.getElementById("noWiktionaryDefinitionsContainer"); - // On réinitialise les listes existantes + // Réinitialiser les listes existantes mesLexiquesList.innerHTML = ""; wiktionnaireList.innerHTML = ""; - // On masque d'emblée les messages d'erreur + // Masquer les messages d'erreur dès le départ if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "none"; if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "none"; - // Variables pour suivre la présence de définitions let hasLexiconDefinitions = false; let hasWiktionaryDefinitions = false; - // Objet pour regrouper les définitions par lexique + // Regrouper les définitions par lexique (source) const lexiconGroups = {}; - // Parcours de chaque définition definitions.forEach(({ source, text }) => { if (!source || !text) return; - // Création de l'élément <li> et gestion du "Lire la suite" + // Créer l'élément <li> pour la définition const li = document.createElement("li"); let displayedText = text; @@ -499,20 +526,17 @@ function displayDefinitions(definitions) { event.preventDefault(); openDefinitionPopup(text); }); - - // On assemble le li li.appendChild(document.createTextNode(displayedText)); li.appendChild(readMoreLink); } else { li.textContent = displayedText; } - // Vérification de la source (Wiktionnaire / Lexiques) + // Vérifier la source : Wiktionnaire ou Lexiques if (source === "Wiktionnaire") { wiktionnaireList.appendChild(li); hasWiktionaryDefinitions = true; } else { - // Si on veut grouper par nom de lexique if (!lexiconGroups[source]) { lexiconGroups[source] = []; } @@ -521,7 +545,7 @@ function displayDefinitions(definitions) { } }); - // Création d'une structure pour les différents lexiques + // Créer une section pour chaque lexique Object.entries(lexiconGroups).forEach(([lexiconName, definitionItems]) => { const lexiconContainer = document.createElement("div"); lexiconContainer.className = "lexicon-section"; @@ -529,13 +553,15 @@ function displayDefinitions(definitions) { const lexiconHeader = document.createElement("div"); lexiconHeader.className = "lexicon-header"; lexiconHeader.textContent = lexiconName; - // Toggle d'affichage au clic + // Lorsque l'utilisateur clique sur le header, on bascule l'affichage lexiconHeader.addEventListener("click", () => { lexiconContent.classList.toggle("hidden"); }); + // Création de la liste et ajout de la classe "hidden" pour qu'elle soit masquée par défaut const lexiconContent = document.createElement("ul"); lexiconContent.className = "lexicon-content hidden"; + definitionItems.forEach(li => lexiconContent.appendChild(li)); lexiconContainer.appendChild(lexiconHeader); @@ -543,27 +569,17 @@ function displayDefinitions(definitions) { mesLexiquesList.appendChild(lexiconContainer); }); - // Condition : s'il n'y a AUCUNE définition dans les lexiques + // Gestion de l'affichage des messages d'erreur si aucune définition n'est trouvée if (!hasLexiconDefinitions) { - console.warn("âš ï¸ Aucune définition trouvée dans les lexiques de l'utilisateur."); - if (noLexiconDefinitionsContainer) { - noLexiconDefinitionsContainer.style.display = "block"; - } + if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "block"; } - - // Condition : s'il n'y a AUCUNE définition Wiktionnaire if (!hasWiktionaryDefinitions) { - console.warn("âš ï¸ Aucune définition trouvée dans le Wiktionnaire."); - if (noWiktionaryDefinitionsContainer) { - noWiktionaryDefinitionsContainer.style.display = "block"; - } + if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "block"; } - // Affiche ou masque la section "Mes lexiques" selon l'existence de définitions + // Affichage ou masquage des sections en fonction de l'existence de définitions document.getElementById("mesLexiquesContainer").style.display = hasLexiconDefinitions ? "block" : "none"; - - // Affiche ou masque la section "Wiktionnaire" selon l'existence de définitions document.getElementById("wiktionnaireContainer").style.display = hasWiktionaryDefinitions ? "block" : "none"; } @@ -571,6 +587,10 @@ function displayDefinitions(definitions) { + + + + function openDefinitionPopup(fullText) { modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; modalOverlay.style.display = "flex"; @@ -593,28 +613,36 @@ modalOverlay.addEventListener("click", (event) => { async function showDefinitions(word) { console.log(`📖 Recherche des définitions pour '${word}'...`); - // Sélection du conteneur d'erreur/message const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); if (noDefinitionsContainer) { - // On indique clairement que la recherche est en cours noDefinitionsContainer.textContent = "Chargement des définitions..."; noDefinitionsContainer.style.display = "block"; } try { - // On lance en parallèle la récupération des définitions - const [lexiconDefinitions, wiktionaryDefinitions] = await Promise.all([ + // Utilisation de Promise.allSettled pour récupérer les deux sources + const results = await Promise.allSettled([ fetchLexiconDefinitions(word), fetchWiktionaryDefinition(word) ]); + // Extraction des résultats réussis + const lexiconDefinitions = + results[0].status === "fulfilled" ? results[0].value : []; + const wiktionaryDefinitions = + results[1].status === "fulfilled" ? results[1].value : []; + // Fusion des résultats const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; console.log("📚 Définitions combinées :", allDefinitions); - // On délègue l'affichage final à displayDefinitions + // Affichage final displayDefinitions(allDefinitions); + // Masquer le conteneur de message si tout s'est bien passé + if (noDefinitionsContainer) { + noDefinitionsContainer.style.display = "none"; + } } catch (error) { console.error("⌠Erreur lors de la récupération des définitions :", error); if (noDefinitionsContainer) { @@ -626,6 +654,7 @@ async function showDefinitions(word) { } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Gestion des messages reçus (depuis le background ou ailleurs) // ───────────────────────────────────────────────────────────────────────────── @@ -726,7 +755,10 @@ function displayLexiconResults(lexicons) { } // Récupérer le nom depuis lexiconMap - const lexiconName = lexiconMap.get(lexicon.id) || `Lexique #${lexicon.id} (Nom inconnu)`; + const lexiconName = + lex.category === "User" + ? `Lexique personnel (${lex.user?.pseudo || "Inconnu"}) [${lex.id}]` + : `Lexique de groupe (${lex.group?.name || "Inconnu"}) [${lex.id}]`; const li = document.createElement("li"); li.innerHTML = `<strong>${lexiconName}</strong> (${lexicon.id})`; -- GitLab From 00ff41e4bac31a4b56292daa926a375a35b74249 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 4 Feb 2025 17:48:04 +0100 Subject: [PATCH 16/32] Correction rechercher dans lexiques menu contextuel --- background/browser_context_menu.js | 17 +++++++++++------ "barre_lat\303\251rale/sidebar.js" | 23 ++++++++--------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index db2a98e..d9358f9 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -270,9 +270,14 @@ async function searchInLexicons(selectedText) { let foundInLexicons = []; for (const lexicon of lexicons) { - // Récupération des entrées du lexique + // Calculer le nom complet pour le lexique + const computedName = lexicon.category === "User" + ? `Lexique personnel : ${lexicon.user?.pseudo || "Inconnu"} (${lexicon.id})` + : `Lexique de groupe : ${lexicon.group?.name || "Inconnu"} (${lexicon.id})`; + + // Récupération des entrées du lexique let entriesResponse = await getLexiconEntries(authToken, lexicon.id); - console.log(`Réponse pour le lexique ${lexicon.id}:`, entriesResponse); + console.log(`Réponse pour le lexicon ${lexicon.id}:`, entriesResponse); // Extraction du tableau d’entrées selon différents formats possibles let entries; @@ -283,8 +288,8 @@ async function searchInLexicons(selectedText) { } else if (entriesResponse && Array.isArray(entriesResponse.data)) { entries = entriesResponse.data; } else { - console.warn(`Format inattendu pour les entrées du lexique ${lexicon.id}`, entriesResponse); - continue; // Passez au lexique suivant + console.warn(`Format inattendu pour les entrées du lexicon ${lexicon.id}`, entriesResponse); + continue; // Passez au lexicon suivant } // Vérification de la présence du mot (en s’assurant que entry.graphy existe) @@ -293,10 +298,9 @@ async function searchInLexicons(selectedText) { }); if (isWordPresent) { - // On stocke l'objet complet avec id et name foundInLexicons.push({ id: lexicon.id, - name: lexicon.name || `Lexique #${lexicon.id || "inconnu"}` + name: computedName // Utilise le nom complet calculé }); } } @@ -330,6 +334,7 @@ async function searchInLexicons(selectedText) { + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Listeners supplémentaires // ───────────────────────────────────────────────────────────────────────────── diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 39849d8..0f9f7b7 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -242,8 +242,8 @@ async function fetchLexicons() { // Déterminer le nom du lexique const lexiconName = lexicon.category === "User" - ? `Lexique personnel (${lexicon.user?.pseudo || "Inconnu"})` - : `Lexique de groupe (${lexicon.group?.name || "Inconnu"})`; + ? `Lexique personnel : ${lexicon.user?.pseudo || "Inconnu"} (${lexicon.id})` + : `Lexique de groupe : ${lexicon.group?.name || "Inconnu"} (${lexicon.id})`; // Ajouter l'ID et le nom dans lexiconMap lexiconMap.set(lexicon.id, lexiconName); @@ -342,8 +342,8 @@ async function fetchLexiconDefinitions(word) { userLexicons.forEach((lex) => { const lexiconName = lex.category === "User" - ? `Lexique personnel (${lex.user?.pseudo || "Inconnu"})` - : `Lexique de groupe (${lex.group?.name || "Inconnu"})`; + ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"}` + : `Lexique de groupe : ${lex.group?.name || "Inconnu"}`; lexiconMap.set(lex.id, lexiconName); }); console.log("📌 LexiconMap :", lexiconMap); @@ -723,7 +723,6 @@ browser.runtime.onMessage.addListener(async (message) => { */ function displayLexiconResults(lexicons) { const resultDiv = document.getElementById("lexiconResult"); - if (!resultDiv) return; // Sécurité si l'élément n'existe pas // Vider le contenu précédent @@ -744,9 +743,6 @@ function displayLexiconResults(lexicons) { const ul = document.createElement("ul"); ul.style.paddingLeft = "20px"; - // Vérification que lexiconMap est bien rempli - console.log("📌 Vérification de lexiconMap avant affichage :", lexiconMap); - // Remplir la liste avec les lexiques trouvés lexicons.forEach((lexicon) => { if (!lexicon || !lexicon.id) { @@ -754,14 +750,10 @@ function displayLexiconResults(lexicons) { return; } - // Récupérer le nom depuis lexiconMap - const lexiconName = - lex.category === "User" - ? `Lexique personnel (${lex.user?.pseudo || "Inconnu"}) [${lex.id}]` - : `Lexique de groupe (${lex.group?.name || "Inconnu"}) [${lex.id}]`; - + // Utiliser la propriété "name" reçue + const lexiconName = lexicon.name || `Lexique #${lexicon.id}`; const li = document.createElement("li"); - li.innerHTML = `<strong>${lexiconName}</strong> (${lexicon.id})`; + li.innerHTML = `<strong>${lexiconName}</strong>`; ul.appendChild(li); console.log(`✅ Lexique ajouté : ${lexiconName} (ID: ${lexicon.id})`); @@ -776,6 +768,7 @@ function displayLexiconResults(lexicons) { + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Recherche et affichage des définitions // ───────────────────────────────────────────────────────────────────────────── -- GitLab From 3285695a32321f62cd112dc184f1f4587adfb43d Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 4 Feb 2025 18:29:54 +0100 Subject: [PATCH 17/32] =?UTF-8?q?Am=C3=A9lioration=20affichage=20d=C3=A9fi?= =?UTF-8?q?nitions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.html" | 12 ++++++++---- "barre_lat\303\251rale/sidebar.js" | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 07944d2..05fd5ba 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -140,6 +140,9 @@ align-items: center; } + #mesLexiquesContainer h4 { + margin-bottom: 5px; + } /* Définition */ #definitionContainer { @@ -237,10 +240,6 @@ <button id="chercherDef">Rechercher une définition</button> <div id="possible-definitions" style="display: none;"> - <label style="font-size: small;"> - <input type="checkbox" id="toggle-definitions"> - Afficher toutes les définitions - </label> </div> </div> @@ -251,8 +250,13 @@ <!-- Définitions des lexiques de l'utilisateur --> <div id="mesLexiquesContainer"> <h4>📚 Mes lexiques</h4> + <label style="font-size: small;"> + <input type="checkbox" id="toggle-definitions"> + Afficher toutes les définitions + </label> <ul id="mesLexiquesList"></ul> </div> + <div id="noLexiconDefinitionsContainer" style="display: none; color: #8d5c70;"> <p>Aucune définition trouvée dans les lexiques.</p> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 0f9f7b7..5d79844 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -836,4 +836,21 @@ document.addEventListener("DOMContentLoaded", async () => { } else { console.error("⌠ERREUR : Bouton #chercherDef introuvable."); } + + // Écouteur pour la case à cocher "toggle-definitions" --- + const toggleCheckbox = document.getElementById("toggle-definitions"); + if (toggleCheckbox) { + toggleCheckbox.addEventListener("change", (event) => { + const showAll = event.target.checked; + // Sélectionner toutes les sections de définitions dans "mesLexiquesList" + const lexiconContents = document.querySelectorAll("#mesLexiquesList .lexicon-content"); + lexiconContents.forEach(content => { + if (showAll) { + content.classList.remove("hidden"); + } else { + content.classList.add("hidden"); + } + }); + }); + } }); -- GitLab From 9175b5aeeaf0ece7b24c8eb325f88f70b63434ef Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 4 Feb 2025 18:37:39 +0100 Subject: [PATCH 18/32] =?UTF-8?q?Correction=20beug=20d=C3=A9finition=20men?= =?UTF-8?q?u=20contextuel=20personnalis=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- menu_contextuel/custom_context_menu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu_contextuel/custom_context_menu.js b/menu_contextuel/custom_context_menu.js index 46a5bd6..66c6542 100644 --- a/menu_contextuel/custom_context_menu.js +++ b/menu_contextuel/custom_context_menu.js @@ -34,7 +34,7 @@ function injectWhiteBox() { <div style="display: flex; flex-wrap: wrap; justify-content: center;"> <!-- Bouton 1 - Ajouter au lexique --> - <div class="icon-container" title="Ajouter ce mot à votre lexique"> + <div class="icon-container" title="Ajouter ce mot à un lexique"> <img src="${addLexiconPath}" alt="Ajouter au lexique" class="icon" id="addLexiconButton"> </div> -- GitLab From 02d7accd2bbc68da42e1cae0e36a87fe33e99558 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Wed, 5 Feb 2025 12:31:02 +0100 Subject: [PATCH 19/32] =?UTF-8?q?Ajout=20blocs=20repliables=20barre=20lat?= =?UTF-8?q?=C3=A9rale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.html" | 182 ++++++++++++++++----------- "barre_lat\303\251rale/sidebar.js" | 18 +++ 2 files changed, 125 insertions(+), 75 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 05fd5ba..15979eb 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -18,20 +18,49 @@ color: #323046; } - /* Conteneurs */ - #menu, #etat { + /* Conteneurs principaux */ + #menu, #etat, #definitionContainer { padding: 10px; - margin-bottom: 0px; + margin-bottom: 10px; border-radius: 10px; background-color: #a08e9f; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } - /* Titre */ - h3 { + /* En-têtes de blocs */ + .block-header { + position: relative; + text-align: center; + margin-top: 2px; + } + + .block-header h3 { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; + } + + .toggle-btn { + position: absolute; + right: 8px; + background: none; + margin: 0; + border: none; color: #fff; - text-align: center; - font-weight: bold; + font-size: 15px; + padding: 3px 5px; + cursor: pointer; + width: auto; + display: inline-block; + } + + /* Contenu des blocs */ + .block-content { + padding-top: 2px; + } + + .hidden { + display: none; } /* Boutons */ @@ -56,7 +85,6 @@ /* Mot sélectionné */ #motSelectionne { font-style: italic; - font-weight: bold; text-align: center; margin-top: 5px; } @@ -100,12 +128,12 @@ /* Espace pour les pictogrammes */ .lexique-icon { - width: 25px; - height: 25px; - border-radius: 50%; - background-color: #ccc; - margin-right: 10px; - flex-shrink: 0; + width: 25px; + height: 25px; + border-radius: 50%; + background-color: #ccc; + margin-right: 10px; + flex-shrink: 0; } .lexicon-section { @@ -130,10 +158,6 @@ margin-top: 5px; } - .hidden { - display: none; - } - #mesLexiquesList { display: inline; padding: 0; @@ -141,15 +165,14 @@ } #mesLexiquesContainer h4 { - margin-bottom: 5px; + margin-bottom: 5px; } /* Définition */ #definitionContainer { - margin-top: 10px; background-color: #444; padding: 10px; - border-radius: 5px; + border-radius: 10px; color: white; } @@ -183,7 +206,7 @@ .modal-content { background: white; - color:#8d5c70; + color: #8d5c70; padding: 1rem; max-width: 600px; max-height: 80vh; @@ -214,73 +237,82 @@ font-weight: bold; } </style> + </head> <body> - <!-- Menu des lexiques --> + <!-- Bloc 1 : Menu des lexiques --> <div id="menu"> - <h3>Lexiques</h3> - <p id="highlight-note" style="display: none;">Cochez un/des lexique(s) pour activer le surlignage des mots sur la page.</p> - <div id="lexiques">Chargement...</div> - - <div id="auth-section"> - <button id="auth-button">Se connecter</button> + <div class="block-header"> + <h3>Lexiques</h3> + <button class="toggle-btn" onclick="toggleBlock('menuContent', this)">–</button> + </div> + <div id="menuContent" class="block-content"> + <p id="highlight-note" style="display: none;">Cochez un/des lexique(s) pour activer le surlignage des mots sur la page.</p> + <div id="lexiques">Chargement...</div> + <div id="auth-section"> + <button id="auth-button">Se connecter</button> + </div> </div> </div> - <!-- État de la sélection --> - <hr> + <!-- Bloc 2 : État de la sélection --> <div id="etat"> - <h3>Mot sélectionné</h3> - <p id="motSelectionne">Aucun mot sélectionné</p> - <p id="lexiconResult"></p> - <div id="add-to-lexiques" style="display: none;"> - <button id="add-word-button">Ajouter le mot sélectionné</button> + <div class="block-header"> + <h3>Mot sélectionné</h3> + <button class="toggle-btn" onclick="toggleBlock('etatContent', this)">–</button> </div> - - <button id="chercherDef">Rechercher une définition</button> - <div id="possible-definitions" style="display: none;"> + <div id="etatContent" class="block-content"> + <p id="motSelectionne">Aucun mot sélectionné</p> + <p id="lexiconResult"></p> + <div id="add-to-lexiques" style="display: none;"> + <button id="add-word-button">Ajouter le mot sélectionné</button> + </div> + <button id="chercherDef">Rechercher une définition</button> + <div id="possible-definitions" style="display: none;"></div> </div> </div> - - <!-- Définition affichée --> -<div id="definitionContainer"> - <h3>Définitions</h3> - - <!-- Définitions des lexiques de l'utilisateur --> - <div id="mesLexiquesContainer"> - <h4>📚 Mes lexiques</h4> - <label style="font-size: small;"> - <input type="checkbox" id="toggle-definitions"> - Afficher toutes les définitions - </label> - <ul id="mesLexiquesList"></ul> - </div> - - - <div id="noLexiconDefinitionsContainer" style="display: none; color: #8d5c70;"> - <p>Aucune définition trouvée dans les lexiques.</p> - </div> - <div id="noWiktionaryDefinitionsContainer" style="display: none; color: #8d5c70;"> - <p>Aucune définition trouvée dans le Wiktionnaire.</p> - </div> - - <!-- Définitions issues du Wiktionnaire --> - <div id="wiktionnaireContainer"> - <h4>🌠Wiktionnaire</h4> - <ul id="wiktionnaireList"></ul> - </div> - - <!-- Fenêtre modale cachée --> - <div id="modalOverlay" class="modal-overlay"> - <div class="modal-content"> - <span id="closeModal" class="close-button">X</span> - <div id="modalFullText"></div> + <!-- Bloc 3 : Définitions --> + <div id="definitionContainer"> + <div class="block-header"> + <h3>Définitions</h3> + <button class="toggle-btn" onclick="toggleBlock('definitionContent', this)">–</button> + </div> + <div id="definitionContent" class="block-content"> + <!-- Définitions des lexiques de l'utilisateur --> + <div id="mesLexiquesContainer"> + <h4>📚 Mes lexiques</h4> + <label style="font-size: small;"> + <input type="checkbox" id="toggle-definitions"> + Afficher toutes les définitions + </label> + <ul id="mesLexiquesList"></ul> + </div> + + <div id="noLexiconDefinitionsContainer" style="display: none; color: #8d5c70;"> + <p>Aucune définition trouvée dans les lexiques.</p> + </div> + + <div id="noWiktionaryDefinitionsContainer" style="display: none; color: #8d5c70;"> + <p>Aucune définition trouvée dans le Wiktionnaire.</p> + </div> + + <!-- Définitions issues du Wiktionnaire --> + <div id="wiktionnaireContainer"> + <h4>🌠Wiktionnaire</h4> + <ul id="wiktionnaireList"></ul> + </div> + + <!-- Fenêtre modale cachée --> + <div id="modalOverlay" class="modal-overlay"> + <div class="modal-content"> + <span id="closeModal" class="close-button">X</span> + <div id="modalFullText"></div> + </div> + </div> </div> </div> -</div> - </body> </html> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 5d79844..6671956 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -854,3 +854,21 @@ document.addEventListener("DOMContentLoaded", async () => { }); } }); + +document.addEventListener("DOMContentLoaded", () => { + // Attache un écouteur de clic à tous les boutons de bascule + const toggleButtons = document.querySelectorAll(".toggle-btn"); + toggleButtons.forEach((btn) => { + btn.addEventListener("click", (event) => { + event.stopPropagation(); // Pour éviter que d'autres gestionnaires sur l'en-tête ne soient déclenchés + const header = btn.parentElement; + // On suppose que le contenu à basculer se trouve juste après l'en-tête + const content = header.nextElementSibling; + if (content) { + content.classList.toggle("hidden"); + // Met à jour le texte du bouton + btn.textContent = content.classList.contains("hidden") ? "+" : "–"; + } + }); + }); +}); -- GitLab From b9dce0e2a0a02a09187fa464eb6ee72d1ff901e0 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Wed, 5 Feb 2025 16:13:55 +0100 Subject: [PATCH 20/32] =?UTF-8?q?Ouverture=20automatique=20des=20blocs=20b?= =?UTF-8?q?arre=20lat=C3=A9rale=20selon=20action=20utilisateur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.js" | 65 +++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 6671956..1f1a9d2 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -585,12 +585,6 @@ function displayDefinitions(definitions) { } - - - - - - function openDefinitionPopup(fullText) { modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; modalOverlay.style.display = "flex"; @@ -653,7 +647,47 @@ async function showDefinitions(word) { } } +/** + * Bascule l’affichage d’un bloc. + * @param {string} blockId - L’ID du conteneur à basculer (ex. "definitionContent"). + * @param {HTMLElement} btn - Le bouton qui déclenche la bascule, pour mettre à jour son texte. + */ +function toggleBlock(blockId, btn) { + const block = document.getElementById(blockId); + if (block) { + if (block.classList.contains("hidden")) { + block.classList.remove("hidden"); + if (btn) btn.textContent = "–"; + } else { + block.classList.add("hidden"); + if (btn) btn.textContent = "+"; + } + } +} +/** + * Ouvre un bloc s’il est fermé et met à jour le bouton de bascule. + * @param {string} blockId - L’ID du conteneur à ouvrir (ex. "definitionContent"). + * @param {HTMLElement} [btn] - (Optionnel) Le bouton de bascule à mettre à jour. + */ +function openBlock(blockId, btn) { + const block = document.getElementById(blockId); + if (block && block.classList.contains("hidden")) { + block.classList.remove("hidden"); + + if (btn) { + btn.textContent = "–"; + } else { + const header = block.previousElementSibling; + if (header) { + const toggleBtn = header.querySelector(".toggle-btn"); + if (toggleBtn) { + toggleBtn.textContent = "–"; + } + } + } + } +} // ───────────────────────────────────────────────────────────────────────────── // â–Œ Gestion des messages reçus (depuis le background ou ailleurs) @@ -673,6 +707,7 @@ browser.runtime.onMessage.addListener(async (message) => { const selectedWordElement = document.getElementById("motSelectionne"); if (selectedWordElement) { selectedWordElement.textContent = message.selectedText; + openBlock("etatContent"); } else { console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); } @@ -682,6 +717,7 @@ browser.runtime.onMessage.addListener(async (message) => { case "getDefinition": if (message.selectedText) { console.log("📖 Recherche des définitions pour :", message.selectedText); + openBlock("definitionContent"); await showDefinitions(message.selectedText); } break; @@ -763,12 +799,6 @@ function displayLexiconResults(lexicons) { resultDiv.appendChild(ul); } - - - - - - // ───────────────────────────────────────────────────────────────────────────── // â–Œ Recherche et affichage des définitions // ───────────────────────────────────────────────────────────────────────────── @@ -787,14 +817,14 @@ async function fetchDefinition(word) { if (!definition || definition.length === 0) { console.warn(`âš ï¸ Aucune définition trouvée pour '${word}'`); - noDefinitionsContainer.style.display = "block"; // Afficher le message d'erreur + noDefinitionsContainer.style.display = "block"; return; } - noDefinitionsContainer.style.display = "none"; // Cacher le message si une définition est trouvée + noDefinitionsContainer.style.display = "none"; } catch (error) { console.error("⌠Erreur lors de la récupération de la définition :", error); - noDefinitionsContainer.style.display = "block"; // Afficher une erreur générale + noDefinitionsContainer.style.display = "block"; } } @@ -817,6 +847,7 @@ document.addEventListener("DOMContentLoaded", async () => { const chercherDefButton = document.getElementById("chercherDef"); if (chercherDefButton) { chercherDefButton.addEventListener("click", async () => { + openBlock("definitionContent"); const selectedWord = document.getElementById("motSelectionne")?.textContent?.trim(); console.log("📖 Mot sélectionné :", selectedWord); @@ -860,13 +891,11 @@ document.addEventListener("DOMContentLoaded", () => { const toggleButtons = document.querySelectorAll(".toggle-btn"); toggleButtons.forEach((btn) => { btn.addEventListener("click", (event) => { - event.stopPropagation(); // Pour éviter que d'autres gestionnaires sur l'en-tête ne soient déclenchés + event.stopPropagation(); const header = btn.parentElement; - // On suppose que le contenu à basculer se trouve juste après l'en-tête const content = header.nextElementSibling; if (content) { content.classList.toggle("hidden"); - // Met à jour le texte du bouton btn.textContent = content.classList.contains("hidden") ? "+" : "–"; } }); -- GitLab From 115779e9240c98e6f457b4c44659219a8d23e37c Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:21:03 +0100 Subject: [PATCH 21/32] Correction beug affichage --- "barre_lat\303\251rale/sidebar.js" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 1f1a9d2..4db6043 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -53,6 +53,7 @@ function toggleElementsVisibility(isLoggedIn) { const elementsToShowOrHide = [ { id: "add-to-lexiques", shouldShow: isLoggedIn }, { id: "possible-definitions", shouldShow: isLoggedIn }, + { id: "mesLexiquesContainer", shouldShow: isLoggedIn }, ]; elementsToShowOrHide.forEach(({ id, shouldShow }) => { @@ -90,6 +91,7 @@ async function refreshSidebarState() { if (isLoggedIn) { await fetchLexicons(); + } else { const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { -- GitLab From c745b4010b24f04de790fade989b1a5cb2c0168f Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:56:01 +0100 Subject: [PATCH 22/32] Correction beug connexion menus contextuels --- background/background.js | 140 +++++-------- background/browser_context_menu.js | 261 +++++++++++-------------- "barre_lat\303\251rale/sidebar.js" | 9 + menu_contextuel/custom_context_menu.js | 126 ++++++++---- 4 files changed, 254 insertions(+), 282 deletions(-) diff --git a/background/background.js b/background/background.js index 0d84f3b..69c00de 100644 --- a/background/background.js +++ b/background/background.js @@ -1,7 +1,6 @@ // ───────────────────────────────────────────────────────────────────────────── // Variables globales // ───────────────────────────────────────────────────────────────────────────── - let isExtensionActive = true; let areStatsActive = false; let originalTabId = null; @@ -13,11 +12,12 @@ const AUTH_BALEX_URL = "https://prisms.lezinter.net/fr/headquarters/balex"; // ───────────────────────────────────────────────────────────────────────────── // Logs de démarrage // ───────────────────────────────────────────────────────────────────────────── - console.log("🚀 ff2BaLex (background) chargé."); + browser.runtime.onInstalled.addListener((details) => { console.log("🔔 Extension installée ou mise à jour. Raison :", details.reason); }); + browser.runtime.onStartup.addListener(() => { console.log("🔄 Extension démarrée (onStartup)."); }); @@ -25,7 +25,6 @@ browser.runtime.onStartup.addListener(() => { // ───────────────────────────────────────────────────────────────────────────── // Suivi des changements dans le stockage // ───────────────────────────────────────────────────────────────────────────── - browser.storage.onChanged.addListener((changes) => { if (changes.extensionActive) { isExtensionActive = changes.extensionActive.newValue; @@ -35,13 +34,13 @@ browser.storage.onChanged.addListener((changes) => { areStatsActive = changes.statsActive.newValue; console.log("📊 Statistiques activées :", areStatsActive); } - createBrowserContextMenu(); + // Lorsqu'un changement pertinent se produit, on rafraîchit l'UI. + refreshAllUI(); }); // ───────────────────────────────────────────────────────────────────────────── // Fonctions utilitaires // ───────────────────────────────────────────────────────────────────────────── - /** * Vérifie si l'utilisateur est connecté (token présent dans le stockage). */ @@ -51,18 +50,16 @@ async function isUserConnected() { } /** - * Rafraîchit l'UI globale : recrée le menu contextuel et notifie les autres parties. + * Rafraîchit l'UI globale : envoie un message "refreshUI" aux autres scripts. */ async function refreshAllUI() { console.log("🔄 Rafraîchissement global de l'UI..."); - await createBrowserContextMenu(); browser.runtime.sendMessage({ action: "refreshUI" }); } // ───────────────────────────────────────────────────────────────────────────── // Fonctions d'authentification // ───────────────────────────────────────────────────────────────────────────── - /** * Ouvre la page de connexion BaLex. * Mémorise l'onglet courant pour y revenir, puis ouvre un nouvel onglet pour la connexion. @@ -75,8 +72,8 @@ async function openLoginPage() { originalTabId = currentTab.id; console.log("✅ Onglet courant mémorisé, ID =", originalTabId); } - // 2) Créer l’onglet de login - const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL }); + // 2) Créer l’onglet de login et l'activer + const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL, active: true }); loginTabId = loginTab.id; console.log("✅ Onglet de login créé, ID =", loginTabId); // Notifier que l'authentification est en cours @@ -95,6 +92,7 @@ async function disconnectFromLexicalDB() { "Vous êtes maintenant déconnecté(e).", "icons/logout.png" ); + // Rafraîchir l'UI après un délai court pour laisser le temps au token d'être supprimé setTimeout(async () => { await refreshAllUI(); }, 500); @@ -134,7 +132,6 @@ async function saveToken(token) { // ───────────────────────────────────────────────────────────────────────────── // Fonction pour récupérer une définition sur le Wiktionnaire // ───────────────────────────────────────────────────────────────────────────── - /** * Récupère la définition d'un mot depuis le Wiktionnaire. * @param {string} word - Le mot à rechercher. @@ -182,12 +179,12 @@ function showWiktionaryNotification(selectedText) { // ───────────────────────────────────────────────────────────────────────────── // Gestion des messages reçus // ───────────────────────────────────────────────────────────────────────────── - browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { console.log("📩 Message reçu dans background.js :", message); switch (message.action) { - // Bascule d'authentification + // Le message "toggleAuth" est destiné à déclencher la connexion/déconnexion. + // Ici, nous le traitons pour ouvrir ou fermer la session. case "toggleAuth": { const isConnected = await isUserConnected(); if (isConnected) { @@ -205,12 +202,10 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { browser.runtime.sendMessage({ action: "fetchWiktionaryDefinitionResponse", selectedText: message.selectedText, - definitions: [ - { - source: "Wiktionnaire", - text: definition, - }, - ], + definitions: [{ + source: "Wiktionnaire", + text: definition, + }], }); } else { console.warn("âš ï¸ Texte sélectionné vide. Annulation de la requête."); @@ -237,85 +232,21 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { } break; } - default: - break; - } - return true; -}); -// ───────────────────────────────────────────────────────────────────────────── -// Création et gestion du menu contextuel -// ───────────────────────────────────────────────────────────────────────────── - -/** - * Crée (ou recrée) le menu contextuel du navigateur en fonction du statut de connexion. - */ -async function createBrowserContextMenu() { - await browser.contextMenus.removeAll(); - const isConnected = await isUserConnected(); - - // Bouton de connexion/déconnexion - browser.contextMenus.create({ - id: "login", - title: isConnected ? "Se déconnecter de BaLex" : "Se connecter à BaLex", - contexts: ["all"], - }); -} - -createBrowserContextMenu(); - -browser.contextMenus.onClicked.addListener(async (info, tab) => { - console.log("📦 Menu contextuel - item cliqué :", info.menuItemId); - switch (info.menuItemId) { - case "searchLexicon": - browser.tabs.sendMessage(tab.id, { - action: "searchLexicon", - selectedText: info.selectionText, - }); - break; - case "checkLexicon": - browser.tabs.sendMessage(tab.id, { - action: "checkLexicon", - selectedText: info.selectionText, - }); - break; - case "searchInLexicons": - browser.tabs.sendMessage(tab.id, { - action: "searchInLexicons", - selectedText: info.selectionText, - }); - break; - case "getDefinition": - browser.tabs.sendMessage(tab.id, { - action: "getDefinition", - selectedText: info.selectionText, - }); - break; - case "getDefinitionWiki": - browser.tabs.sendMessage(tab.id, { - action: "getDefinitionWiki", - selectedText: info.selectionText, - }); - break; - case "login": { - const connected = await isUserConnected(); - if (connected) { - await disconnectFromLexicalDB(); - } else { - await openLoginPage(); - } + case "showNotification": { + showNotification(message.title, message.message, message.iconPath); break; } + default: - console.warn(`Aucune action définie pour l'élément : ${info.menuItemId}`); + break; } + return true; }); - // ───────────────────────────────────────────────────────────────────────────── // Web Navigation : Injection de scripts et récupération du token // ───────────────────────────────────────────────────────────────────────────── - browser.webNavigation.onCompleted.addListener(async (details) => { if (!isExtensionActive) { console.log("🚫 Extension désactivée, aucune injection script."); @@ -332,7 +263,7 @@ browser.webNavigation.onCompleted.addListener(async (details) => { if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/headquarters/balex") { console.log("🟢 Page /balex détectée. Tentative de récupération du token."); try { - await new Promise(resolve => setTimeout(resolve, 3000)); + await new Promise(resolve => setTimeout(resolve, 3000)); await browser.tabs.executeScript(details.tabId, { code: ` console.log("🔠Recherche du token..."); @@ -355,7 +286,6 @@ browser.webNavigation.onCompleted.addListener(async (details) => { // ───────────────────────────────────────────────────────────────────────────── // Web Request : Redirection automatique vers /balex // ───────────────────────────────────────────────────────────────────────────── - browser.webRequest.onBeforeRequest.addListener( function(details) { if (details.url === "https://prisms.lezinter.net/fr/headquarters/") { @@ -370,7 +300,6 @@ browser.webRequest.onBeforeRequest.addListener( // ───────────────────────────────────────────────────────────────────────────── // Affichage d'un popup d'instruction sur /fr/login // ───────────────────────────────────────────────────────────────────────────── - function showInstructionPopup(details) { browser.tabs.executeScript(details.tabId, { code: ` @@ -391,7 +320,7 @@ function showInstructionPopup(details) { popup.style.fontSize = "14px"; popup.style.width = "300px"; popup.style.textAlign = "center"; - + popup.innerHTML = \` <h5 style="color: #fff; font-weight: bold; margin-top: 0;">🔑 Connexion à l'extension</h5> <p style="margin: 15px 0;"> @@ -410,9 +339,9 @@ function showInstructionPopup(details) { border-radius: 5px; ">Fermer</button> \`; - + document.body.appendChild(popup); - + const closeBtn = document.getElementById("close-popup-btn"); closeBtn.onclick = () => popup.remove(); } @@ -423,7 +352,28 @@ function showInstructionPopup(details) { // ───────────────────────────────────────────────────────────────────────────── // Notification // ───────────────────────────────────────────────────────────────────────────── +// Fonction utilitaire pour envoyer une notification via le background +function sendNotification(title, message, iconPath) { + browser.runtime.sendMessage({ + action: "showNotification", + title: title, + message: message, + iconPath: iconPath + }); +} function showNotification(title, message, iconPath) { - console.log(`🔔 NOTIFICATION: [${title}] ${message}`); + // Vérifier que l'URL de l'icône est bien résolue par browser.runtime.getURL() + const iconUrl = browser.runtime.getURL(iconPath); + + // Créer la notification + browser.notifications.create({ + type: "basic", + iconUrl: iconUrl, + title: title, + message: message + }, (notificationId) => { + console.log(`Notification créée (${notificationId}): [${title}] ${message}`); + }); } + diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index d9358f9..a61c4eb 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -1,9 +1,11 @@ -console.log("browser_context_menu.js chargé correctement"); +console.log("browser_context_menu.js chargé correctement"); // Variable globale qui contient le token pour les requêtes API let authToken = null; -// Fonction pour charger le token depuis le stockage local +/** + * Charge le token depuis le stockage local et le stocke dans la variable globale authToken. + */ async function loadAuthToken() { try { const result = await browser.storage.local.get("accessToken"); @@ -14,108 +16,138 @@ async function loadAuthToken() { } } -// Charger le token dès le démarrage du script -loadAuthToken(); - -// ───────────────────────────────────────────────────────────────────────────── -// â–Œ Création du menu contextuel du navigateur -// ───────────────────────────────────────────────────────────────────────────── - -// 2. Vérifier dans quels lexiques le mot est présent -browser.contextMenus.create({ - id: "searchInLexicons", - title: "Rechercher dans mes lexiques", - contexts: ["selection"], - icons: { "16": "icons/quel_lexique.png" }, -}); - -// 3. Ajouter un mot au lexique -browser.contextMenus.create({ - id: "addtoLexicon", - title: "Ajouter ce mot à mon lexique", - contexts: ["selection"], - icons: { "16": "icons/ajout_lexique.png" }, -}); - -// Séparateur -browser.contextMenus.create({ - id: "separatorExtension", - type: "separator", - contexts: ["all"], -}); +/** + * Crée l'ensemble des items du menu contextuel en centralisant leur création. + * L'item "login" affiche "Se connecter à BaLex" ou "Se déconnecter de BaLex" selon le token. + */ +async function createContextMenu() { + // Supprime tous les items existants afin de recréer le menu complet + await browser.contextMenus.removeAll(); + + // Item de connexion/déconnexion + browser.contextMenus.create({ + id: "login", + title: authToken ? "Se déconnecter de BaLex" : "Se connecter à BaLex", + contexts: ["all"], + }); + + // Item 1 : Recherche dans les lexiques de l’utilisateur + browser.contextMenus.create({ + id: "searchInLexicons", + title: "Rechercher dans mes lexiques", + contexts: ["selection"], + icons: { "16": "icons/quel_lexique.png" }, + }); + + // Item 2 : Ajouter un mot au lexique personnel + browser.contextMenus.create({ + id: "addtoLexicon", + title: "Ajouter ce mot à mon lexique", + contexts: ["selection"], + icons: { "16": "icons/ajout_lexique.png" }, + }); + + // Séparateur + browser.contextMenus.create({ + id: "separatorExtension", + type: "separator", + contexts: ["all"], + }); + + // Item 3 : Recherche globale de définition (Lexiques + Wiktionnaire) + browser.contextMenus.create({ + id: "getDefinition", + title: "Obtenir une définition", + contexts: ["selection"], + icons: { "16": "icons/definition.png" }, + }); + + // Séparateur final + browser.contextMenus.create({ + id: "separatorAfterExtension", + type: "separator", + contexts: ["all"], + }); +} -// 4. Recherche globale de définition : Lexiques + Wiktionnaire -browser.contextMenus.create({ - id: "getDefinition", - title: "Obtenir une définition", - contexts: ["selection"], - icons: { "16": "icons/definition.png" }, -}); +// Charger le token au démarrage puis créer le menu contextuel +loadAuthToken().then(createContextMenu); -// Séparateur après -browser.contextMenus.create({ - id: "separatorAfterExtension", - type: "separator", - contexts: ["all"], +// Listener pour mettre à jour le menu quand un message "refreshUI" est reçu +browser.runtime.onMessage.addListener((message) => { + if (message.action === "refreshUI") { + console.log("🔄 refreshUI reçu dans browser_context_menu.js"); + loadAuthToken().then(createContextMenu); + } }); // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion des clics sur le menu contextuel +// Gestion des clics sur le menu contextuel // ───────────────────────────────────────────────────────────────────────────── - browser.contextMenus.onClicked.addListener(async (info, tab) => { - if (info.selectionText) { - console.log(`📩 Texte sélectionné dans le menu du navigateur : ${info.selectionText}`); + console.log("Item de menu cliqué :", info.menuItemId); + + // Pour les actions qui ne nécessitent pas de texte sélectionné + if (info.menuItemId === "login") { + console.log("🔄 Action login/déconnexion demandée."); + // Ajoutez une propriété 'from' pour identifier l'origine + browser.runtime.sendMessage({ action: "toggleAuth", from: "browser_context_menu" }); + return; + } + + // Pour les actions qui nécessitent une sélection de texte + if (!info.selectionText) { + console.warn("Aucun texte sélectionné pour cette action :", info.menuItemId); + return; + } + + console.log(`📩 Texte sélectionné dans le menu du navigateur : ${info.selectionText}`); + switch (info.menuItemId) { + // Recherche dans les lexiques de l’utilisateur + case "searchInLexicons": + console.log("🔠Recherche du mot dans les lexiques :", info.selectionText); + if (authToken) { + await searchInLexicons(info.selectionText); + } else { + alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); + } + break; - switch (info.menuItemId) { - // Recherche dans les lexiques de l’utilisateur - case "searchInLexicons": - console.log("🔠Recherche du mot dans les lexiques :", info.selectionText); - if (authToken) { - await searchInLexicons(info.selectionText); - } else { - alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); - } - break; + // Ajouter le mot au lexique personnel + case "addtoLexicon": + console.log("🔠Ajout du mot au lexique :", info.selectionText); + if (authToken) { + await searchLexicon(info.selectionText); + } else { + alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); + } + break; - // Un seul bouton pour une définition (Lexiques + Wiki) - case "getDefinitionAll": - console.log("🌠Recherche de définition :", info.selectionText); - await getDefinitionAll(info.selectionText); - break; + // Recherche globale de définition (Lexiques + Wiktionnaire) + case "getDefinition": + console.log("🌠Recherche de définition :", info.selectionText); + await getDefinition(info.selectionText); + break; - default: - console.error(`⌠Action inconnue : ${info.menuItemId}`); - } + default: + console.error(`⌠Action inconnue : ${info.menuItemId}`); } }); // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Fonctions combinées : Lexiques + Wiktionnaire +// Fonctions combinées : Lexiques + Wiktionnaire +// (Les fonctions getDefinition, getDefinitionFromUserLexicons, getDefinitionFromWiktionary, etc. restent inchangées) // ───────────────────────────────────────────────────────────────────────────── -/** - * Lance la recherche d’une définition à la fois dans : - * 1) Les lexiques de l’utilisateur (si authToken) - * 2) Le Wiktionnaire - * Puis envoie le tout à la barre latérale. - */ async function getDefinition(selectedText) { try { - // 1) Récupérer définitions dans les lexiques utilisateur let userLexiconDefinitions = []; if (authToken) { userLexiconDefinitions = await getDefinitionFromUserLexicons(selectedText); } - - // 2) Récupérer définitions du Wiktionnaire let wiktionaryDefinitions = await getDefinitionFromWiktionary(selectedText); - - // 3) Fusion const allDefinitions = [...userLexiconDefinitions, ...wiktionaryDefinitions]; console.log("📠Définitions combinées :", allDefinitions); - - // 4) Envoi au script de la barre latérale pour affichage browser.runtime.sendMessage({ action: "showDefinitions", selectedText, @@ -126,10 +158,6 @@ async function getDefinition(selectedText) { } } -/** - * Renvoie les définitions d’un mot provenant des lexiques de l’utilisateur. - * Retourne un tableau d’objets : [{ source: 'Lexiques', text: '...' }, ...] - */ async function getDefinitionFromUserLexicons(selectedText) { try { console.log("🔎 getDefinitionFromUserLexicons pour :", selectedText); @@ -141,11 +169,9 @@ async function getDefinitionFromUserLexicons(selectedText) { throw new Error(`⌠Erreur API lexiques : ${response.statusText}`); } const data = await response.json(); - if (!data.definitions || data.definitions.length === 0) { return []; } - return data.definitions.map((def) => ({ source: "Lexiques", text: def, @@ -156,10 +182,6 @@ async function getDefinitionFromUserLexicons(selectedText) { } } -/** - * Renvoie la définition Wiktionnaire d’un mot (FR). - * Retourne un tableau d’objets : [{ source: 'Wiktionnaire', text: '...' }] - */ async function getDefinitionFromWiktionary(selectedText) { try { console.log("🔎 getDefinitionFromWiktionary pour :", selectedText); @@ -167,27 +189,22 @@ async function getDefinitionFromWiktionary(selectedText) { console.warn("âš ï¸ Aucun texte sélectionné."); return []; } - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(selectedText)}`; const response = await fetch(wiktionaryURL); if (!response.ok) { console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); return []; } - const data = await response.json(); if (!data.query || !data.query.pages) { return []; } - const pages = Object.values(data.query.pages); if (pages.length === 0 || !pages[0].extract) { return []; } - const definitionText = pages[0].extract.trim(); console.log("✅ Définition Wiktionnaire :", definitionText); - return [{ source: "Wiktionnaire", text: definitionText }]; } catch (err) { console.error("⌠getDefinitionFromWiktionary :", err); @@ -196,28 +213,22 @@ async function getDefinitionFromWiktionary(selectedText) { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Autres fonctions de l'extension (recherche, vérification, etc.) +// Autres fonctions de l'extension (searchLexicon, checkLexicon, searchInLexicons, etc.) restent inchangées // ───────────────────────────────────────────────────────────────────────────── -/** - * searchLexicon : Vérifie si le mot est présent dans le lexique personnel - */ async function searchLexicon(selectedText) { try { const lexicons = await getLexicons(authToken); console.log("📚 Lexiques récupérés :", lexicons); - const frenchLexicon = lexicons.find((lexicon) => lexicon.language === "fr"); if (!frenchLexicon) { alert("âš ï¸ Aucun lexique français trouvé."); return; } - const entries = await getLexiconEntriesID(authToken, frenchLexicon.id); const isWordPresent = entries.some( (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() ); - if (isWordPresent) { alert(`✅ Le mot "${selectedText}" est présent dans votre lexique personnel.`); } else { @@ -228,9 +239,6 @@ async function searchLexicon(selectedText) { } } -/** - * checkLexicon : Affiche les lexiques dans lesquels le mot sélectionné est présent - */ async function checkLexicon(selectedText) { try { const lexicons = await getLexicons(authToken); @@ -240,7 +248,6 @@ async function checkLexicon(selectedText) { (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() ), })); - console.log("📋 Résultats des lexiques :", results); let message = `Résultats pour "${selectedText}":\n\n`; results.forEach(({ name, isPresent }) => { @@ -252,34 +259,21 @@ async function checkLexicon(selectedText) { } } -// ───────────────────────────────────────────────────────────────────────────── -// â–Œ Fonction combinée : Recherche du mot dans les lexiques -// ───────────────────────────────────────────────────────────────────────────── - async function searchInLexicons(selectedText) { try { console.log("🔎 Recherche dans les lexiques pour :", selectedText); - - // Récupérer les lexiques en français const lexicons = await getLexicons(authToken, "fr"); if (!Array.isArray(lexicons) || lexicons.length === 0) { console.log("âš ï¸ Aucun lexique disponible."); return; } - let foundInLexicons = []; - for (const lexicon of lexicons) { - // Calculer le nom complet pour le lexique const computedName = lexicon.category === "User" ? `Lexique personnel : ${lexicon.user?.pseudo || "Inconnu"} (${lexicon.id})` : `Lexique de groupe : ${lexicon.group?.name || "Inconnu"} (${lexicon.id})`; - - // Récupération des entrées du lexique let entriesResponse = await getLexiconEntries(authToken, lexicon.id); console.log(`Réponse pour le lexicon ${lexicon.id}:`, entriesResponse); - - // Extraction du tableau d’entrées selon différents formats possibles let entries; if (Array.isArray(entriesResponse)) { entries = entriesResponse; @@ -289,28 +283,23 @@ async function searchInLexicons(selectedText) { entries = entriesResponse.data; } else { console.warn(`Format inattendu pour les entrées du lexicon ${lexicon.id}`, entriesResponse); - continue; // Passez au lexicon suivant + continue; } - - // Vérification de la présence du mot (en s’assurant que entry.graphy existe) const isWordPresent = entries.some(entry => { return entry.graphy && entry.graphy.toLowerCase() === selectedText.toLowerCase(); }); - if (isWordPresent) { foundInLexicons.push({ - id: lexicon.id, - name: computedName // Utilise le nom complet calculé + id: lexicon.id, + name: computedName }); } } - if (foundInLexicons.length > 0) { console.log("📩 Envoi du message `showLexiconResult` à sidebar.js :", foundInLexicons); - browser.runtime.sendMessage({ action: "showLexiconResult", - lexicons: foundInLexicons, // On envoie un tableau d'objets avec noms et IDs + lexicons: foundInLexicons, selectedText: selectedText }); } else { @@ -321,30 +310,14 @@ async function searchInLexicons(selectedText) { selectedText: selectedText }); } - } catch (error) { console.error("⌠Erreur lors de la recherche dans les lexiques :", error); console.log("⌠Une erreur est survenue lors de la recherche."); } } - - - - - - - -// ───────────────────────────────────────────────────────────────────────────── -// â–Œ Listeners supplémentaires -// ───────────────────────────────────────────────────────────────────────────── - -/** - * Écouteur pour d’autres actions envoyées par la barre latérale (optionnel). - * Par exemple, si la sidebar envoie `browser.runtime.sendMessage({action: 'getDefinitionAll'})`. - */ browser.runtime.onMessage.addListener(async (message) => { if (message.action === "getDefinitionAll") { - await getDefinitionAll(message.selectedText); + await getDefinition(message.selectedText); } }); diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 4db6043..efce418 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -751,6 +751,15 @@ browser.runtime.onMessage.addListener(async (message) => { displayLexiconResults(message.lexicons); break; + case "authStatusChanged": + alert("Vous allez être redirigé(e) vers la page de connexion."); + break; + + case "toggleAuth": + await browser.runtime.sendMessage({ action: "toggleAuth" }); + await refreshSidebarState(); + break; + default: console.warn("âš ï¸ Action inconnue reçue :", message.action); } diff --git a/menu_contextuel/custom_context_menu.js b/menu_contextuel/custom_context_menu.js index 66c6542..510295e 100644 --- a/menu_contextuel/custom_context_menu.js +++ b/menu_contextuel/custom_context_menu.js @@ -2,7 +2,17 @@ console.log("custom_context_menu.js chargé correctement"); // === Variables globales === let authToken = null; -const WHITE_BOX_ID = "whiteBox"; +const WHITE_BOX_ID = "whiteBox"; + +// Fonction utilitaire pour envoyer une notification via le background +function sendNotification(title, message, iconPath) { + browser.runtime.sendMessage({ + action: "showNotification", + title, + message, + iconPath + }); +} // Récupère le token depuis le stockage local et le stocke dans authToken async function loadAuthToken() { @@ -16,13 +26,25 @@ async function loadAuthToken() { } } -// Crée le menu contextuel personnalisé s'il n'existe pas déjà +/** + * Crée le menu contextuel personnalisé (whiteBox) s'il n'existe pas déjà . + */ function injectWhiteBox() { - if (!document.getElementById(WHITE_BOX_ID)) { - const whiteBox = document.createElement("div"); + let whiteBox = document.getElementById(WHITE_BOX_ID); + if (!whiteBox) { + whiteBox = document.createElement("div"); whiteBox.id = WHITE_BOX_ID; - // Exemples pour générer les URLs des icônes + // Définition de styles essentiels pour le positionnement et la visibilité + whiteBox.style.position = "absolute"; + whiteBox.style.zIndex = "9999"; + whiteBox.style.backgroundColor = "#fff"; + whiteBox.style.border = "1px solid #ccc"; + whiteBox.style.padding = "5px"; + whiteBox.style.borderRadius = "4px"; + whiteBox.style.boxShadow = "0px 2px 10px rgba(0,0,0,0.2)"; + + // Génération des URLs des icônes const addLexiconPath = browser.runtime.getURL("icons/ajout_lexique.png"); const getDefinitionPath = browser.runtime.getURL("icons/definition.png"); const loginPath = browser.runtime.getURL("icons/connexion.png"); @@ -32,51 +54,59 @@ function injectWhiteBox() { <p id="selectedWord" style="margin: 0; padding: 0;">Mot sélectionné : Aucun</p> <hr style="border: 0; height: 1px; background-color: #323046; margin: 8px 0;"> <div style="display: flex; flex-wrap: wrap; justify-content: center;"> - <!-- Bouton 1 - Ajouter au lexique --> <div class="icon-container" title="Ajouter ce mot à un lexique"> <img src="${addLexiconPath}" alt="Ajouter au lexique" class="icon" id="addLexiconButton"> </div> - <!-- Bouton 2 - Définition (Babalex + Wiki) --> <div class="icon-container" title="Obtenir la définition"> <img src="${getDefinitionPath}" alt="Obtenir la définition" class="icon" id="getDefinitionButton"> </div> - <!-- Bouton 3 - Connexion --> <div class="icon-container" title="Connectez-vous à BaLex"> <img src="${loginPath}" alt="Se connecter" class="icon" id="loginButton" style="display: none;"> </div> </div> `; - document.body.appendChild(whiteBox); setupWhiteBoxActions(); - } else { - console.log(`#${WHITE_BOX_ID} déjà présent dans le DOM.`); } + return whiteBox; } -// Configure les actions/boutons du menu +/** + * Renvoie le whiteBox s'il existe, ou le crée via injectWhiteBox(). + */ +function getOrCreateWhiteBox() { + return document.getElementById(WHITE_BOX_ID) || injectWhiteBox(); +} + +/** + * Configure les actions/boutons du menu contextuel. + */ function setupWhiteBoxActions() { const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); const loginBtn = document.getElementById("loginButton"); - // Ajouter le mot au lexique perso + // Bouton : Ajouter le mot au lexique personnel addLexiconBtn.onclick = async () => { const selectedText = getSelectedWord(); console.log("🔠Ajout au lexique :", selectedText); - if (!selectedText) return; + if (!selectedText) return; if (authToken) { await searchLexicon(selectedText); } else { - alert("âš ï¸ Veuillez vous connecter pour utiliser cette fonction."); + sendNotification( + "Connexion requise", + "âš ï¸ Veuillez vous connecter pour utiliser cette fonction.", + "icons/connexion.png" + ); } }; - // Obtenir une définition (Babalex + Wiktionnaire) + // Bouton : Obtenir une définition (Babalex + Wiktionnaire) getDefinitionBtn.onclick = () => { const selectedText = getSelectedWord().trim(); if (selectedText) { @@ -87,17 +117,23 @@ function setupWhiteBoxActions() { } }; - // Login Auth + // Bouton : Connexion loginBtn.onclick = () => { - alert("Vous allez être redirigé(e) vers la page de connexion."); + sendNotification( + "Redirection", + "Vous allez être redirigé(e) vers la page de connexion.", + "icons/connexion.png" + ); browser.runtime.sendMessage({ action: "toggleAuth" }); }; } -// Met à jour la visibilité des boutons en fonction de l'état de connexion +/** + * Met à jour la visibilité des boutons en fonction de l'état d'authentification. + */ function updateMenuVisibility() { - injectWhiteBox(); - + // S'assurer que le whiteBox existe + getOrCreateWhiteBox(); const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); const loginBtn = document.getElementById("loginButton"); @@ -108,14 +144,14 @@ function updateMenuVisibility() { } if (authToken) { - // Utilisateur connecté => on affiche tout sauf le login + // Utilisateur connecté => afficher "Ajouter" et "Définition", masquer "Connexion" addLexiconBtn.style.display = "inline-block"; getDefinitionBtn.style.display = "inline-block"; loginBtn.style.display = "none"; } else { - // Utilisateur déconnecté => on masque l'ajout de lexique, on affiche le bouton définition et login + // Utilisateur déconnecté => masquer "Ajouter", afficher "Définition" et "Connexion" addLexiconBtn.style.display = "none"; - getDefinitionBtn.style.display = "inline-block"; + getDefinitionBtn.style.display = "inline-block"; loginBtn.style.display = "inline-block"; } } @@ -128,23 +164,19 @@ function getSelectedWord() { return selectedWordElement ? selectedWordElement.textContent.trim() : ""; } -// Affiche le menu contextuel à la position du clic +/** + * Affiche le menu contextuel à la position du clic. + */ function showWhiteBox(event, selectedText) { - const whiteBox = document.getElementById(WHITE_BOX_ID); - if (!whiteBox) { - console.error(`#${WHITE_BOX_ID} introuvable dans le DOM.`); - return; - } - - // Mettre à jour le mot sélectionné + const whiteBox = getOrCreateWhiteBox(); const selectedWordElement = document.getElementById("selectedWord"); selectedWordElement.textContent = `${selectedText}`; - // Récupère la position de la sélection + // Calculer la position du menu en fonction de la sélection const selection = window.getSelection(); + if (!selection.rangeCount) return; // sécurité au cas où const range = selection.getRangeAt(0); - const rect = range.getBoundingClientRect(); - + const rect = range.getBoundingClientRect(); const top = rect.bottom + window.scrollY; const left = rect.right + window.scrollX; @@ -153,7 +185,6 @@ function showWhiteBox(event, selectedText) { whiteBox.style.display = "block"; console.log("Affichage du menu contextuel avec le mot :", selectedText); - updateMenuVisibility(); } @@ -164,15 +195,15 @@ function hideWhiteBox() { } } -// === Écoute les événements de sélection de texte (mouseup) === +// === Écoute des événements de sélection de texte (mouseup) === document.addEventListener("mouseup", (event) => { const selectedText = window.getSelection().toString().trim(); if (selectedText) { console.log("Événement de sélection détecté. Texte sélectionné :", selectedText); - injectWhiteBox(); + getOrCreateWhiteBox(); showWhiteBox(event, selectedText); - // Envoie aussi le mot sélectionné + // Envoi du mot sélectionné au background browser.runtime.sendMessage({ action: "mot_selectionne", selectedText, @@ -182,22 +213,31 @@ document.addEventListener("mouseup", (event) => { } }); -// Réécouter les messages envoyés +// Réécoute des messages envoyés browser.runtime.onMessage.addListener((message) => { if (message.action === "refreshUI") { - console.log("🔄 Mise à jour du menu contextuel personnalisé (double-clic/sélection)."); + console.log("🔄 Mise à jour du menu contextuel personnalisé."); loadAuthToken().then(() => { updateMenuVisibility(); }); } }); -// === Charger le token au démarrage, puis mettre à jour le menu === +// Initialisation au démarrage loadAuthToken().then(() => { - injectWhiteBox(); + getOrCreateWhiteBox(); updateMenuVisibility(); }); +browser.storage.onChanged.addListener((changes) => { + if (changes.accessToken) { + console.log("🔄 Token changé dans le stockage, mise à jour du menu personnalisé."); + loadAuthToken().then(() => { + updateMenuVisibility(); + }); + } +}); + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Fonctions d'API Babalex pour l'ajout ou la vérification d'un mot // ───────────────────────────────────────────────────────────────────────────── -- GitLab From b5f2f4a090105ee9a1aa494a510cf36c50f7ad7b Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:05:02 +0100 Subject: [PATCH 23/32] Affichage options menu navigateur selon connexion --- background/browser_context_menu.js | 61 +++++++++++++++++++----------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index a61c4eb..1b066ad 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -24,29 +24,23 @@ async function createContextMenu() { // Supprime tous les items existants afin de recréer le menu complet await browser.contextMenus.removeAll(); - // Item de connexion/déconnexion - browser.contextMenus.create({ - id: "login", - title: authToken ? "Se déconnecter de BaLex" : "Se connecter à BaLex", - contexts: ["all"], - }); - - // Item 1 : Recherche dans les lexiques de l’utilisateur - browser.contextMenus.create({ - id: "searchInLexicons", - title: "Rechercher dans mes lexiques", - contexts: ["selection"], - icons: { "16": "icons/quel_lexique.png" }, - }); - - // Item 2 : Ajouter un mot au lexique personnel - browser.contextMenus.create({ - id: "addtoLexicon", - title: "Ajouter ce mot à mon lexique", - contexts: ["selection"], - icons: { "16": "icons/ajout_lexique.png" }, - }); + if (authToken) { + // Item 1 : Recherche dans les lexiques de l’utilisateur + browser.contextMenus.create({ + id: "searchInLexicons", + title: "Rechercher dans mes lexiques", + contexts: ["selection"], + icons: { "16": "icons/quel_lexique.png" }, + }); + // Item 2 : Ajouter un mot au lexique personnel + browser.contextMenus.create({ + id: "addtoLexicon", + title: "Ajouter ce mot à mon lexique", + contexts: ["selection"], + icons: { "16": "icons/ajout_lexique.png" }, + }); + } // Séparateur browser.contextMenus.create({ id: "separatorExtension", @@ -62,12 +56,26 @@ async function createContextMenu() { icons: { "16": "icons/definition.png" }, }); + // Séparateur + browser.contextMenus.create({ + id: "separatorExtension", + type: "separator", + contexts: ["all"], + }); + // Séparateur final browser.contextMenus.create({ id: "separatorAfterExtension", type: "separator", contexts: ["all"], }); + + // Item de connexion/déconnexion + browser.contextMenus.create({ + id: "login", + title: authToken ? "Se déconnecter de BaLex" : "Se connecter à BaLex", + contexts: ["all"], + }); } // Charger le token au démarrage puis créer le menu contextuel @@ -81,6 +89,14 @@ browser.runtime.onMessage.addListener((message) => { } }); +browser.storage.onChanged.addListener((changes, area) => { + if (area === "local" && changes.accessToken) { + console.log("🔄 Token modifié, actualisation du menu contextuel."); + // Recharge le token et recrée le menu + loadAuthToken().then(createContextMenu); + } +}); + // ───────────────────────────────────────────────────────────────────────────── // Gestion des clics sur le menu contextuel // ───────────────────────────────────────────────────────────────────────────── @@ -90,7 +106,6 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { // Pour les actions qui ne nécessitent pas de texte sélectionné if (info.menuItemId === "login") { console.log("🔄 Action login/déconnexion demandée."); - // Ajoutez une propriété 'from' pour identifier l'origine browser.runtime.sendMessage({ action: "toggleAuth", from: "browser_context_menu" }); return; } -- GitLab From 88b7495ec2b740c637c69d9eac87231bc98cde1c Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:26:44 +0100 Subject: [PATCH 24/32] Affichage boutons ouverture/fermeture blocs --- background/background.js | 102 +++++++++++++-------------- "barre_lat\303\251rale/sidebar.html" | 7 +- "barre_lat\303\251rale/sidebar.js" | 8 ++- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/background/background.js b/background/background.js index 69c00de..b3e58b1 100644 --- a/background/background.js +++ b/background/background.js @@ -1,8 +1,8 @@ // ───────────────────────────────────────────────────────────────────────────── // Variables globales // ───────────────────────────────────────────────────────────────────────────── -let isExtensionActive = true; -let areStatsActive = false; +let isExtensionActive = true; +let areStatsActive = false; let originalTabId = null; let loginTabId = null; @@ -34,55 +34,78 @@ browser.storage.onChanged.addListener((changes) => { areStatsActive = changes.statsActive.newValue; console.log("📊 Statistiques activées :", areStatsActive); } - // Lorsqu'un changement pertinent se produit, on rafraîchit l'UI. + // Rafraîchit l'UI globale refreshAllUI(); }); // ───────────────────────────────────────────────────────────────────────────── // Fonctions utilitaires // ───────────────────────────────────────────────────────────────────────────── -/** - * Vérifie si l'utilisateur est connecté (token présent dans le stockage). - */ async function isUserConnected() { const { accessToken } = await browser.storage.local.get("accessToken"); return !!accessToken; } -/** - * Rafraîchit l'UI globale : envoie un message "refreshUI" aux autres scripts. - */ async function refreshAllUI() { console.log("🔄 Rafraîchissement global de l'UI..."); browser.runtime.sendMessage({ action: "refreshUI" }); } // ───────────────────────────────────────────────────────────────────────────── -// Fonctions d'authentification +// Fonctions d'authentification & de redirection avec confirmation // ───────────────────────────────────────────────────────────────────────────── -/** - * Ouvre la page de connexion BaLex. - * Mémorise l'onglet courant pour y revenir, puis ouvre un nouvel onglet pour la connexion. - */ -async function openLoginPage() { - console.log("🔗 Ouverture de la page de connexion."); - // 1) Retrouver l'onglet actuellement actif (pour y revenir plus tard) + +// Affiche une notification de confirmation de redirection vers la page de connexion +function confirmLoginRedirection() { + const options = { + type: "basic", + iconUrl: browser.runtime.getURL("icons/connexion.png"), + title: "Redirection vers la connexion", + message: "Vous allez être redirigé vers la page de connexion. Acceptez-vous cette redirection ?", + buttons: [ + { title: "Accepter" }, + { title: "Annuler" } + ] + }; + + // Crée la notification avec un identifiant fixe "loginRedirect" + browser.notifications.create("loginRedirect", options, (notificationId) => { + console.log("Notification de redirection créée :", notificationId); + }); +} + +// Ouvre effectivement la page de connexion +async function actuallyOpenLoginPage() { + console.log("🔗 Ouverture de la page de connexion (après confirmation)."); + + // Mémoriser l'onglet actif const [currentTab] = await browser.tabs.query({ active: true, currentWindow: true }); if (currentTab) { originalTabId = currentTab.id; console.log("✅ Onglet courant mémorisé, ID =", originalTabId); } - // 2) Créer l’onglet de login et l'activer + // Ouvre un nouvel onglet pour la page de connexion et l'active const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL, active: true }); loginTabId = loginTab.id; console.log("✅ Onglet de login créé, ID =", loginTabId); - // Notifier que l'authentification est en cours + // Notifie que l'authentification est en cours browser.runtime.sendMessage({ action: "authStatusChanged", isLoggedIn: false }); } -/** - * Déconnecte l'utilisateur en supprimant le token et en rafraîchissant l'UI. - */ +// Écoute le clic sur les boutons de la notification +browser.notifications.onButtonClicked.addListener((notificationId, buttonIndex) => { + if (notificationId === "loginRedirect") { + if (buttonIndex === 0) { + console.log("L'utilisateur a accepté la redirection."); + actuallyOpenLoginPage(); + } else { + console.log("Redirection annulée par l'utilisateur."); + } + browser.notifications.clear(notificationId); + } +}); + +// Déconnecte l'utilisateur async function disconnectFromLexicalDB() { console.log("🔓 Déconnexion en cours..."); await browser.storage.local.remove("accessToken"); @@ -92,21 +115,16 @@ async function disconnectFromLexicalDB() { "Vous êtes maintenant déconnecté(e).", "icons/logout.png" ); - // Rafraîchir l'UI après un délai court pour laisser le temps au token d'être supprimé setTimeout(async () => { await refreshAllUI(); }, 500); } -/** - * Sauvegarde le token et ferme la page de login si nécessaire. - * Ramène l'utilisateur sur l'onglet initial et rafraîchit l'UI. - */ +// Sauvegarde le token et ferme l'onglet de login si nécessaire async function saveToken(token) { console.log("✅ Sauvegarde du token :", token); await browser.storage.local.set({ accessToken: token }); - // Fermer l'onglet de login s'il est ouvert if (loginTabId) { try { await browser.tabs.remove(loginTabId); @@ -116,7 +134,6 @@ async function saveToken(token) { } loginTabId = null; } - // Rétablir l'onglet initial if (originalTabId) { try { await browser.tabs.update(originalTabId, { active: true }); @@ -132,11 +149,6 @@ async function saveToken(token) { // ───────────────────────────────────────────────────────────────────────────── // Fonction pour récupérer une définition sur le Wiktionnaire // ───────────────────────────────────────────────────────────────────────────── -/** - * Récupère la définition d'un mot depuis le Wiktionnaire. - * @param {string} word - Le mot à rechercher. - * @returns {Promise<string>} - La définition extraite ou un message d'erreur. - */ async function fetchWiktionaryDefinition(word) { try { console.log(`🔠Requête Wiktionnaire pour "${word}"...`); @@ -163,10 +175,7 @@ async function fetchWiktionaryDefinition(word) { } } -/** - * Affiche une notification indiquant qu'une définition Wiktionnaire a été trouvée. - * @param {string} selectedText - Le mot concerné. - */ +// Affiche une notification pour le Wiktionnaire function showWiktionaryNotification(selectedText) { browser.notifications.create({ type: "basic", @@ -183,18 +192,16 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { console.log("📩 Message reçu dans background.js :", message); switch (message.action) { - // Le message "toggleAuth" est destiné à déclencher la connexion/déconnexion. - // Ici, nous le traitons pour ouvrir ou fermer la session. case "toggleAuth": { const isConnected = await isUserConnected(); if (isConnected) { await disconnectFromLexicalDB(); } else { - await openLoginPage(); + // Affiche la notification de confirmation avant redirection + confirmLoginRedirection(); } break; } - // Demande de définition via le Wiktionnaire case "getDefinitionWiki": { if (message.selectedText && message.selectedText.trim() !== "") { console.log("🌠Requête Wiktionnaire pour :", message.selectedText); @@ -212,18 +219,15 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { } break; } - // Vérification du statut d'authentification case "checkAuthStatus": { const connected = await isUserConnected(); sendResponse(connected); break; } - // Notification de changement d'état d'authentification case "authStatusChanged": { console.log("🔄 Mise à jour de l'état d'authentification :", message.isLoggedIn); break; } - // Enregistrement du token reçu case "saveToken": { if (message.token) { await saveToken(message.token); @@ -232,12 +236,10 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { } break; } - case "showNotification": { showNotification(message.title, message.message, message.iconPath); break; } - default: break; } @@ -254,7 +256,7 @@ browser.webNavigation.onCompleted.addListener(async (details) => { } const url = new URL(details.url); - // Sur la page de login : popup d'instruction + // Sur la page de login : injection d'un popup d'instruction if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/login") { console.log("📘 Injection du popup d'instruction sur la page de login Prisms."); showInstructionPopup(details); @@ -363,10 +365,7 @@ function sendNotification(title, message, iconPath) { } function showNotification(title, message, iconPath) { - // Vérifier que l'URL de l'icône est bien résolue par browser.runtime.getURL() const iconUrl = browser.runtime.getURL(iconPath); - - // Créer la notification browser.notifications.create({ type: "basic", iconUrl: iconUrl, @@ -376,4 +375,3 @@ function showNotification(title, message, iconPath) { console.log(`Notification créée (${notificationId}): [${title}] ${message}`); }); } - diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 15979eb..abf90f8 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -40,6 +40,7 @@ margin-bottom: 0; } + /* Utilisation de la classe pour les boutons de bascule */ .toggle-btn { position: absolute; right: 8px; @@ -245,7 +246,7 @@ <div id="menu"> <div class="block-header"> <h3>Lexiques</h3> - <button class="toggle-btn" onclick="toggleBlock('menuContent', this)">–</button> + <button class="toggle-btn"></button> </div> <div id="menuContent" class="block-content"> <p id="highlight-note" style="display: none;">Cochez un/des lexique(s) pour activer le surlignage des mots sur la page.</p> @@ -260,7 +261,7 @@ <div id="etat"> <div class="block-header"> <h3>Mot sélectionné</h3> - <button class="toggle-btn" onclick="toggleBlock('etatContent', this)">–</button> + <button class="toggle-btn"></button> </div> <div id="etatContent" class="block-content"> <p id="motSelectionne">Aucun mot sélectionné</p> @@ -277,7 +278,7 @@ <div id="definitionContainer"> <div class="block-header"> <h3>Définitions</h3> - <button class="toggle-btn" onclick="toggleBlock('definitionContent', this)">–</button> + <button class="toggle-btn"></button> </div> <div id="definitionContent" class="block-content"> <!-- Définitions des lexiques de l'utilisateur --> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index efce418..16348c8 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -898,11 +898,15 @@ document.addEventListener("DOMContentLoaded", async () => { }); document.addEventListener("DOMContentLoaded", () => { - // Attache un écouteur de clic à tous les boutons de bascule const toggleButtons = document.querySelectorAll(".toggle-btn"); toggleButtons.forEach((btn) => { + if (!btn.textContent.trim()) { + btn.textContent = "-"; + btn.style.fontSize = "15px"; + } + btn.addEventListener("click", (event) => { - event.stopPropagation(); + event.stopPropagation(); const header = btn.parentElement; const content = header.nextElementSibling; if (content) { -- GitLab From 09c1753853b552f420b608b80c8fb209794c07d3 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:09:21 +0100 Subject: [PATCH 25/32] Suppression des notifications de connexion (beugs) --- background/background.js | 109 +++++++---------------------- background/browser_context_menu.js | 18 ++--- "barre_lat\303\251rale/sidebar.js" | 22 +----- manifest.json | 3 +- 4 files changed, 33 insertions(+), 119 deletions(-) diff --git a/background/background.js b/background/background.js index b3e58b1..a019572 100644 --- a/background/background.js +++ b/background/background.js @@ -34,7 +34,6 @@ browser.storage.onChanged.addListener((changes) => { areStatsActive = changes.statsActive.newValue; console.log("📊 Statistiques activées :", areStatsActive); } - // Rafraîchit l'UI globale refreshAllUI(); }); @@ -52,31 +51,28 @@ async function refreshAllUI() { } // ───────────────────────────────────────────────────────────────────────────── -// Fonctions d'authentification & de redirection avec confirmation +// Fonctions d'authentification & de redirection // ───────────────────────────────────────────────────────────────────────────── +browser.runtime.onConnect.addListener((port) => { + if (port.name === "auth") { + port.onMessage.addListener(async (message) => { + if (message.action === "toggleAuth") { + console.log("🔄 toggleAuth reçu via port dans le background."); + const isConnected = await isUserConnected(); + if (isConnected) { + await disconnectFromLexicalDB(); + } else { + // Ouvre directement la page de connexion + actuallyOpenLoginPage(); + } + } + }); + } +}); -// Affiche une notification de confirmation de redirection vers la page de connexion -function confirmLoginRedirection() { - const options = { - type: "basic", - iconUrl: browser.runtime.getURL("icons/connexion.png"), - title: "Redirection vers la connexion", - message: "Vous allez être redirigé vers la page de connexion. Acceptez-vous cette redirection ?", - buttons: [ - { title: "Accepter" }, - { title: "Annuler" } - ] - }; - - // Crée la notification avec un identifiant fixe "loginRedirect" - browser.notifications.create("loginRedirect", options, (notificationId) => { - console.log("Notification de redirection créée :", notificationId); - }); -} - -// Ouvre effectivement la page de connexion +// Ouvre directement la page de connexion async function actuallyOpenLoginPage() { - console.log("🔗 Ouverture de la page de connexion (après confirmation)."); + console.log("🔗 Ouverture de la page de connexion."); // Mémoriser l'onglet actif const [currentTab] = await browser.tabs.query({ active: true, currentWindow: true }); @@ -92,29 +88,11 @@ async function actuallyOpenLoginPage() { browser.runtime.sendMessage({ action: "authStatusChanged", isLoggedIn: false }); } -// Écoute le clic sur les boutons de la notification -browser.notifications.onButtonClicked.addListener((notificationId, buttonIndex) => { - if (notificationId === "loginRedirect") { - if (buttonIndex === 0) { - console.log("L'utilisateur a accepté la redirection."); - actuallyOpenLoginPage(); - } else { - console.log("Redirection annulée par l'utilisateur."); - } - browser.notifications.clear(notificationId); - } -}); - -// Déconnecte l'utilisateur +// Déconnecte l'utilisateur (sans notification) async function disconnectFromLexicalDB() { console.log("🔓 Déconnexion en cours..."); await browser.storage.local.remove("accessToken"); console.log("🔓 Token supprimé avec succès."); - showNotification( - "Déconnexion réussie", - "Vous êtes maintenant déconnecté(e).", - "icons/logout.png" - ); setTimeout(async () => { await refreshAllUI(); }, 500); @@ -175,16 +153,6 @@ async function fetchWiktionaryDefinition(word) { } } -// Affiche une notification pour le Wiktionnaire -function showWiktionaryNotification(selectedText) { - browser.notifications.create({ - type: "basic", - iconUrl: browser.runtime.getURL("icons/notification.png"), - title: "Définition trouvée", - message: `🌠Définition trouvée pour "${selectedText}". Consultez le Wiktionnaire.` - }); -} - // ───────────────────────────────────────────────────────────────────────────── // Gestion des messages reçus // ───────────────────────────────────────────────────────────────────────────── @@ -197,8 +165,8 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { if (isConnected) { await disconnectFromLexicalDB(); } else { - // Affiche la notification de confirmation avant redirection - confirmLoginRedirection(); + // Ouvre directement la page de connexion + actuallyOpenLoginPage(); } break; } @@ -236,10 +204,6 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { } break; } - case "showNotification": { - showNotification(message.title, message.message, message.iconPath); - break; - } default: break; } @@ -256,12 +220,12 @@ browser.webNavigation.onCompleted.addListener(async (details) => { } const url = new URL(details.url); - // Sur la page de login : injection d'un popup d'instruction + // Injection d'un popup d'instruction sur la page de login if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/login") { console.log("📘 Injection du popup d'instruction sur la page de login Prisms."); showInstructionPopup(details); } - // Sur la page /balex : récupération du token + // Récupération du token sur la page /balex if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/headquarters/balex") { console.log("🟢 Page /balex détectée. Tentative de récupération du token."); try { @@ -350,28 +314,3 @@ function showInstructionPopup(details) { ` }); } - -// ───────────────────────────────────────────────────────────────────────────── -// Notification -// ───────────────────────────────────────────────────────────────────────────── -// Fonction utilitaire pour envoyer une notification via le background -function sendNotification(title, message, iconPath) { - browser.runtime.sendMessage({ - action: "showNotification", - title: title, - message: message, - iconPath: iconPath - }); -} - -function showNotification(title, message, iconPath) { - const iconUrl = browser.runtime.getURL(iconPath); - browser.notifications.create({ - type: "basic", - iconUrl: iconUrl, - title: title, - message: message - }, (notificationId) => { - console.log(`Notification créée (${notificationId}): [${title}] ${message}`); - }); -} diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js index 1b066ad..f2ff526 100644 --- a/background/browser_context_menu.js +++ b/background/browser_context_menu.js @@ -57,13 +57,6 @@ async function createContextMenu() { }); // Séparateur - browser.contextMenus.create({ - id: "separatorExtension", - type: "separator", - contexts: ["all"], - }); - - // Séparateur final browser.contextMenus.create({ id: "separatorAfterExtension", type: "separator", @@ -103,10 +96,13 @@ browser.storage.onChanged.addListener((changes, area) => { browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log("Item de menu cliqué :", info.menuItemId); - // Pour les actions qui ne nécessitent pas de texte sélectionné if (info.menuItemId === "login") { console.log("🔄 Action login/déconnexion demandée."); - browser.runtime.sendMessage({ action: "toggleAuth", from: "browser_context_menu" }); + if (typeof actuallyOpenLoginPage === "function") { + actuallyOpenLoginPage(); + } else { + console.error("La fonction actuallyOpenLoginPage n'est pas accessible."); + } return; } @@ -227,10 +223,6 @@ async function getDefinitionFromWiktionary(selectedText) { } } -// ───────────────────────────────────────────────────────────────────────────── -// Autres fonctions de l'extension (searchLexicon, checkLexicon, searchInLexicons, etc.) restent inchangées -// ───────────────────────────────────────────────────────────────────────────── - async function searchLexicon(selectedText) { try { const lexicons = await getLexicons(authToken); diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 16348c8..962b6d0 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -469,11 +469,6 @@ async function fetchWiktionaryDefinition(word) { } -/** - * Affiche les définitions dans deux listes : - * - Mes lexiques (#mesLexiquesList) - * - Wiktionnaire (#wiktionnaireList) - */ const MAX_LENGTH = 200; const modalOverlay = document.getElementById("modalOverlay"); const modalFullText = document.getElementById("modalFullText"); @@ -737,27 +732,14 @@ browser.runtime.onMessage.addListener(async (message) => { } break; - case "showDefinitionNotification": - console.log(`📢 Définition trouvée pour "${message.selectedText}".`); - const notificationContainer = document.getElementById("notificationContainer"); - if (notificationContainer) { - notificationContainer.textContent = `🌠Définition trouvée pour "${message.selectedText}". Consultez le Wiktionnaire.`; - notificationContainer.style.display = "block"; - } - break; - case "showLexiconResult": console.log("📚 Résultat des lexiques reçus :", message.lexicons); displayLexiconResults(message.lexicons); break; - case "authStatusChanged": - alert("Vous allez être redirigé(e) vers la page de connexion."); - break; - case "toggleAuth": - await browser.runtime.sendMessage({ action: "toggleAuth" }); - await refreshSidebarState(); + break; + case "authStatusChanged": break; default: diff --git a/manifest.json b/manifest.json index 936ae01..2b59919 100644 --- a/manifest.json +++ b/manifest.json @@ -14,7 +14,8 @@ "notifications", "*://babalex.lezinter.net/*", "*://prisms.lezinter.net/*", - "*://fr.wiktionary.org/*" + "*://fr.wiktionary.org/*", + "<all_urls>" ], "background": { -- GitLab From a0bbc5604059f16c045658898401542485748a46 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Fri, 7 Feb 2025 18:13:33 +0100 Subject: [PATCH 26/32] =?UTF-8?q?R=C3=A9organisation=20des=20scripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- background/background.js | 33 +- background/browser_context_menu.js | 330 ----------- "barre_lat\303\251rale/sidebar.html" | 26 +- "barre_lat\303\251rale/sidebar.js" | 723 ++++-------------------- definitions.js | 461 +++++++++++++++ manifest.json | 3 +- menu_contextuel/browser_context_menu.js | 268 +++++++++ 7 files changed, 855 insertions(+), 989 deletions(-) delete mode 100644 background/browser_context_menu.js create mode 100644 definitions.js create mode 100644 menu_contextuel/browser_context_menu.js diff --git a/background/background.js b/background/background.js index a019572..3f0213a 100644 --- a/background/background.js +++ b/background/background.js @@ -124,35 +124,6 @@ async function saveToken(token) { await refreshAllUI(); } -// ───────────────────────────────────────────────────────────────────────────── -// Fonction pour récupérer une définition sur le Wiktionnaire -// ───────────────────────────────────────────────────────────────────────────── -async function fetchWiktionaryDefinition(word) { - try { - console.log(`🔠Requête Wiktionnaire pour "${word}"...`); - if (!word || word.trim() === "") { - throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); - } - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; - const response = await fetch(wiktionaryURL); - if (!response.ok) { - throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); - } - const data = await response.json(); - console.log("📖 Réponse API (Wiktionnaire) :", data); - const pages = data.query?.pages; - const page = pages ? Object.values(pages)[0] : null; - const definition = page && page.extract - ? page.extract.trim() - : "âš ï¸ Aucune définition trouvée sur le Wiktionnaire."; - console.log("🌠Définition Wiktionnaire extraite :", definition); - return definition; - } catch (error) { - console.error("⌠Erreur Wiktionnaire :", error); - return "âš ï¸ Erreur lors de la récupération sur le Wiktionnaire."; - } -} - // ───────────────────────────────────────────────────────────────────────────── // Gestion des messages reçus // ───────────────────────────────────────────────────────────────────────────── @@ -173,7 +144,7 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { case "getDefinitionWiki": { if (message.selectedText && message.selectedText.trim() !== "") { console.log("🌠Requête Wiktionnaire pour :", message.selectedText); - const definition = await fetchWiktionaryDefinition(message.selectedText.trim()); + const definition = await window.fetchWiktionaryDefinition(message.selectedText.trim()); browser.runtime.sendMessage({ action: "fetchWiktionaryDefinitionResponse", selectedText: message.selectedText, @@ -233,7 +204,7 @@ browser.webNavigation.onCompleted.addListener(async (details) => { await browser.tabs.executeScript(details.tabId, { code: ` console.log("🔠Recherche du token..."); - const tokenElement = document.getElementById("accesToken"); + const tokenElement = document.getElementById("accessToken"); if (tokenElement) { const token = tokenElement.innerText.trim(); console.log("🔠Token détecté :", token); diff --git a/background/browser_context_menu.js b/background/browser_context_menu.js deleted file mode 100644 index f2ff526..0000000 --- a/background/browser_context_menu.js +++ /dev/null @@ -1,330 +0,0 @@ -console.log("browser_context_menu.js chargé correctement"); - -// Variable globale qui contient le token pour les requêtes API -let authToken = null; - -/** - * Charge le token depuis le stockage local et le stocke dans la variable globale authToken. - */ -async function loadAuthToken() { - try { - const result = await browser.storage.local.get("accessToken"); - authToken = result.accessToken; - console.log("🔑 Token chargé au démarrage :", authToken); - } catch (error) { - console.error("⌠Erreur lors de la récupération du token :", error); - } -} - -/** - * Crée l'ensemble des items du menu contextuel en centralisant leur création. - * L'item "login" affiche "Se connecter à BaLex" ou "Se déconnecter de BaLex" selon le token. - */ -async function createContextMenu() { - // Supprime tous les items existants afin de recréer le menu complet - await browser.contextMenus.removeAll(); - - if (authToken) { - // Item 1 : Recherche dans les lexiques de l’utilisateur - browser.contextMenus.create({ - id: "searchInLexicons", - title: "Rechercher dans mes lexiques", - contexts: ["selection"], - icons: { "16": "icons/quel_lexique.png" }, - }); - - // Item 2 : Ajouter un mot au lexique personnel - browser.contextMenus.create({ - id: "addtoLexicon", - title: "Ajouter ce mot à mon lexique", - contexts: ["selection"], - icons: { "16": "icons/ajout_lexique.png" }, - }); - } - // Séparateur - browser.contextMenus.create({ - id: "separatorExtension", - type: "separator", - contexts: ["all"], - }); - - // Item 3 : Recherche globale de définition (Lexiques + Wiktionnaire) - browser.contextMenus.create({ - id: "getDefinition", - title: "Obtenir une définition", - contexts: ["selection"], - icons: { "16": "icons/definition.png" }, - }); - - // Séparateur - browser.contextMenus.create({ - id: "separatorAfterExtension", - type: "separator", - contexts: ["all"], - }); - - // Item de connexion/déconnexion - browser.contextMenus.create({ - id: "login", - title: authToken ? "Se déconnecter de BaLex" : "Se connecter à BaLex", - contexts: ["all"], - }); -} - -// Charger le token au démarrage puis créer le menu contextuel -loadAuthToken().then(createContextMenu); - -// Listener pour mettre à jour le menu quand un message "refreshUI" est reçu -browser.runtime.onMessage.addListener((message) => { - if (message.action === "refreshUI") { - console.log("🔄 refreshUI reçu dans browser_context_menu.js"); - loadAuthToken().then(createContextMenu); - } -}); - -browser.storage.onChanged.addListener((changes, area) => { - if (area === "local" && changes.accessToken) { - console.log("🔄 Token modifié, actualisation du menu contextuel."); - // Recharge le token et recrée le menu - loadAuthToken().then(createContextMenu); - } -}); - -// ───────────────────────────────────────────────────────────────────────────── -// Gestion des clics sur le menu contextuel -// ───────────────────────────────────────────────────────────────────────────── -browser.contextMenus.onClicked.addListener(async (info, tab) => { - console.log("Item de menu cliqué :", info.menuItemId); - - if (info.menuItemId === "login") { - console.log("🔄 Action login/déconnexion demandée."); - if (typeof actuallyOpenLoginPage === "function") { - actuallyOpenLoginPage(); - } else { - console.error("La fonction actuallyOpenLoginPage n'est pas accessible."); - } - return; - } - - // Pour les actions qui nécessitent une sélection de texte - if (!info.selectionText) { - console.warn("Aucun texte sélectionné pour cette action :", info.menuItemId); - return; - } - - console.log(`📩 Texte sélectionné dans le menu du navigateur : ${info.selectionText}`); - switch (info.menuItemId) { - // Recherche dans les lexiques de l’utilisateur - case "searchInLexicons": - console.log("🔠Recherche du mot dans les lexiques :", info.selectionText); - if (authToken) { - await searchInLexicons(info.selectionText); - } else { - alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); - } - break; - - // Ajouter le mot au lexique personnel - case "addtoLexicon": - console.log("🔠Ajout du mot au lexique :", info.selectionText); - if (authToken) { - await searchLexicon(info.selectionText); - } else { - alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); - } - break; - - // Recherche globale de définition (Lexiques + Wiktionnaire) - case "getDefinition": - console.log("🌠Recherche de définition :", info.selectionText); - await getDefinition(info.selectionText); - break; - - default: - console.error(`⌠Action inconnue : ${info.menuItemId}`); - } -}); - -// ───────────────────────────────────────────────────────────────────────────── -// Fonctions combinées : Lexiques + Wiktionnaire -// (Les fonctions getDefinition, getDefinitionFromUserLexicons, getDefinitionFromWiktionary, etc. restent inchangées) -// ───────────────────────────────────────────────────────────────────────────── - -async function getDefinition(selectedText) { - try { - let userLexiconDefinitions = []; - if (authToken) { - userLexiconDefinitions = await getDefinitionFromUserLexicons(selectedText); - } - let wiktionaryDefinitions = await getDefinitionFromWiktionary(selectedText); - const allDefinitions = [...userLexiconDefinitions, ...wiktionaryDefinitions]; - console.log("📠Définitions combinées :", allDefinitions); - browser.runtime.sendMessage({ - action: "showDefinitions", - selectedText, - definitions: allDefinitions, - }); - } catch (error) { - console.error("⌠Erreur lors de la recherche combinée des définitions :", error); - } -} - -async function getDefinitionFromUserLexicons(selectedText) { - try { - console.log("🔎 getDefinitionFromUserLexicons pour :", selectedText); - const response = await fetch( - `https://prisms.lezinter.net/api/definitions?word=${encodeURIComponent(selectedText)}`, - { headers: { Authorization: `Bearer ${authToken}` } } - ); - if (!response.ok) { - throw new Error(`⌠Erreur API lexiques : ${response.statusText}`); - } - const data = await response.json(); - if (!data.definitions || data.definitions.length === 0) { - return []; - } - return data.definitions.map((def) => ({ - source: "Lexiques", - text: def, - })); - } catch (err) { - console.error("⌠getDefinitionFromUserLexicons :", err); - return []; - } -} - -async function getDefinitionFromWiktionary(selectedText) { - try { - console.log("🔎 getDefinitionFromWiktionary pour :", selectedText); - if (!selectedText || selectedText.trim() === "") { - console.warn("âš ï¸ Aucun texte sélectionné."); - return []; - } - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(selectedText)}`; - const response = await fetch(wiktionaryURL); - if (!response.ok) { - console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); - return []; - } - const data = await response.json(); - if (!data.query || !data.query.pages) { - return []; - } - const pages = Object.values(data.query.pages); - if (pages.length === 0 || !pages[0].extract) { - return []; - } - const definitionText = pages[0].extract.trim(); - console.log("✅ Définition Wiktionnaire :", definitionText); - return [{ source: "Wiktionnaire", text: definitionText }]; - } catch (err) { - console.error("⌠getDefinitionFromWiktionary :", err); - return []; - } -} - -async function searchLexicon(selectedText) { - try { - const lexicons = await getLexicons(authToken); - console.log("📚 Lexiques récupérés :", lexicons); - const frenchLexicon = lexicons.find((lexicon) => lexicon.language === "fr"); - if (!frenchLexicon) { - alert("âš ï¸ Aucun lexique français trouvé."); - return; - } - const entries = await getLexiconEntriesID(authToken, frenchLexicon.id); - const isWordPresent = entries.some( - (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() - ); - if (isWordPresent) { - alert(`✅ Le mot "${selectedText}" est présent dans votre lexique personnel.`); - } else { - alert(`⌠Le mot "${selectedText}" n'est pas présent dans votre lexique personnel.`); - } - } catch (error) { - console.error("⌠Erreur lors de la recherche dans le lexique :", error); - } -} - -async function checkLexicon(selectedText) { - try { - const lexicons = await getLexicons(authToken); - const results = lexicons.map((lexicon) => ({ - name: lexicon.name, - isPresent: lexicon.entries.some( - (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() - ), - })); - console.log("📋 Résultats des lexiques :", results); - let message = `Résultats pour "${selectedText}":\n\n`; - results.forEach(({ name, isPresent }) => { - message += `- ${name}: ${isPresent ? "✅ Présent" : "⌠Non présent"}\n`; - }); - alert(message); - } catch (error) { - console.error("⌠Erreur lors de la vérification des lexiques :", error); - } -} - -async function searchInLexicons(selectedText) { - try { - console.log("🔎 Recherche dans les lexiques pour :", selectedText); - const lexicons = await getLexicons(authToken, "fr"); - if (!Array.isArray(lexicons) || lexicons.length === 0) { - console.log("âš ï¸ Aucun lexique disponible."); - return; - } - let foundInLexicons = []; - for (const lexicon of lexicons) { - const computedName = lexicon.category === "User" - ? `Lexique personnel : ${lexicon.user?.pseudo || "Inconnu"} (${lexicon.id})` - : `Lexique de groupe : ${lexicon.group?.name || "Inconnu"} (${lexicon.id})`; - let entriesResponse = await getLexiconEntries(authToken, lexicon.id); - console.log(`Réponse pour le lexicon ${lexicon.id}:`, entriesResponse); - let entries; - if (Array.isArray(entriesResponse)) { - entries = entriesResponse; - } else if (entriesResponse && Array.isArray(entriesResponse.entries)) { - entries = entriesResponse.entries; - } else if (entriesResponse && Array.isArray(entriesResponse.data)) { - entries = entriesResponse.data; - } else { - console.warn(`Format inattendu pour les entrées du lexicon ${lexicon.id}`, entriesResponse); - continue; - } - const isWordPresent = entries.some(entry => { - return entry.graphy && entry.graphy.toLowerCase() === selectedText.toLowerCase(); - }); - if (isWordPresent) { - foundInLexicons.push({ - id: lexicon.id, - name: computedName - }); - } - } - if (foundInLexicons.length > 0) { - console.log("📩 Envoi du message `showLexiconResult` à sidebar.js :", foundInLexicons); - browser.runtime.sendMessage({ - action: "showLexiconResult", - lexicons: foundInLexicons, - selectedText: selectedText - }); - } else { - console.log("⌠Aucun lexique trouvé."); - browser.runtime.sendMessage({ - action: "showLexiconResult", - lexicons: [], - selectedText: selectedText - }); - } - } catch (error) { - console.error("⌠Erreur lors de la recherche dans les lexiques :", error); - console.log("⌠Une erreur est survenue lors de la recherche."); - } -} - -browser.runtime.onMessage.addListener(async (message) => { - if (message.action === "getDefinitionAll") { - await getDefinition(message.selectedText); - } -}); diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index abf90f8..74c9ba2 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -5,6 +5,7 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BaLex - Barre Latérale</title> <script src="../api.js" defer></script> + <script src="../definitions.js" defer></script> <script src="sidebar.js" defer></script> <style> @@ -308,10 +309,33 @@ <!-- Fenêtre modale cachée --> <div id="modalOverlay" class="modal-overlay"> <div class="modal-content"> - <span id="closeModal" class="close-button">X</span> + <span id="closeModalBtn" class="close-button" onclick="closeDefinitionPopup()">X</span> <div id="modalFullText"></div> </div> </div> + <script> + function initModal() { + window.modalOverlay = document.getElementById("modalOverlay"); + window.modalFullText = document.getElementById("modalFullText"); + window.closeModalBtn = document.getElementById("closeModalBtn"); + + if (!modalOverlay || !modalFullText || !closeModalBtn) { + console.error("Les éléments modaux ne sont pas trouvés !"); + return; + } + + modalOverlay.addEventListener("click", (event) => { + if (event.target === modalOverlay) closeDefinitionPopup(); + }); + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", initModal); + } else { + initModal(); + } + </script> + </div> </div> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 962b6d0..c81ae6f 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -1,31 +1,28 @@ -// ───────────────────────────────────────────────────────────────────────────── -// Initialisation & vérification de l'API browser -// ───────────────────────────────────────────────────────────────────────────── console.log("✅ sidebar.js chargé !"); console.log( "🌠Vérification API browser :", typeof browser !== "undefined" ? "✅ Disponible" : "⌠Non disponible" ); -// Variable globale pour le token d'authentification -let authToken = null; -// Variable pour stocker les lexiques avec leur ID et leur nom -const lexiconMap = new Map(); +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Variables globales +// ───────────────────────────────────────────────────────────────────────────── +let authToken = null; +window.lexiconMap = lexiconMap; +window.authToken = authToken; // ───────────────────────────────────────────────────────────────────────────── // â–Œ Fonctions liées au token // ───────────────────────────────────────────────────────────────────────────── -/** - * Récupère le token d'authentification depuis le stockage local. - */ async function getAuthTokenFromStorage() { try { const { accessToken } = await browser.storage.local.get("accessToken"); if (accessToken) { console.log(`🔑 Token récupéré depuis le stockage local : [${accessToken}]`); authToken = accessToken; + window.authToken = accessToken; return authToken; } console.warn("âš ï¸ Aucun token trouvé dans le stockage local."); @@ -33,6 +30,7 @@ async function getAuthTokenFromStorage() { console.error("⌠Erreur lors de la récupération du token :", error); } authToken = null; + window.authToken = null; return null; } @@ -67,9 +65,6 @@ function toggleElementsVisibility(isLoggedIn) { }); } -/** - * Permet d’afficher ou non la note de surlignage - */ function toggleHighlightMessage(isLoggedIn) { const highlightNote = document.getElementById("highlight-note"); if (highlightNote) { @@ -78,7 +73,7 @@ function toggleHighlightMessage(isLoggedIn) { } /** - * Rafraîchit l'état de la barre latérale (bouton d'authentification, lexiques, etc.) + * Met à jour l'état global de la sidebar (bouton d'authentification, etc.) */ async function refreshSidebarState() { console.log("🔄 Début de l'actualisation de la barre latérale..."); @@ -91,124 +86,141 @@ async function refreshSidebarState() { if (isLoggedIn) { await fetchLexicons(); - } else { const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { lexiquesContainer.textContent = "Veuillez vous connecter pour voir vos lexiques."; - } else if (!lexiquesContainer) { - console.error("⌠Élément #lexiques introuvable dans le DOM."); - return; } } console.log("✅ Barre latérale actualisée. Utilisateur connecté :", isLoggedIn); } -// ───────────────────────────────────────────────────────────────────────────── -// â–Œ Lexiques : deux affichages possibles -// ───────────────────────────────────────────────────────────────────────────── - /** - * (1) Affichage des lexiques sous forme de liste + * Bascule l’affichage d’un bloc. + * @param {string} blockId - L’ID du conteneur à basculer. + * @param {HTMLElement} btn - Le bouton qui déclenche la bascule, pour mettre à jour son texte. */ -async function displayLexiconsList() { - const lexiquesContainer = document.getElementById("lexiques"); - if (!lexiquesContainer) { - console.warn("âš ï¸ Ã‰lément #lexiques introuvable."); - return; +function toggleBlock(blockId, btn) { + const block = document.getElementById(blockId); + if (block) { + if (block.classList.contains("hidden")) { + block.classList.remove("hidden"); + if (btn) btn.textContent = "–"; + } else { + block.classList.add("hidden"); + if (btn) btn.textContent = "+"; + } } - - lexiquesContainer.innerHTML = "Chargement des lexiques..."; - const token = await getAuthTokenFromStorage(); - console.log("Token utilisé pour l'appel API :", token); - if (!token) { - lexiquesContainer.textContent = "âš ï¸ Veuillez vous connecter pour voir vos lexiques."; - return; +} + +/** + * Ouvre un bloc s’il est fermé et met à jour le bouton de bascule. + * @param {string} blockId - L’ID du conteneur à ouvrir. + * @param {HTMLElement} [btn] - (Optionnel) Le bouton de bascule à mettre à jour. + */ +function openBlock(blockId, btn) { + const block = document.getElementById(blockId); + if (block && block.classList.contains("hidden")) { + block.classList.remove("hidden"); + + if (btn) { + btn.textContent = "–"; + } else { + const header = block.previousElementSibling; + if (header) { + const toggleBtn = header.querySelector(".toggle-btn"); + if (toggleBtn) { + toggleBtn.textContent = "–"; + } + } + } } - +} + +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Gestion des lexiques (Affichage) +// ───────────────────────────────────────────────────────────────────────────── + +async function fetchLexicons() { try { - const lexicons = await getAllLexiconWords(token); - lexiquesContainer.innerHTML = ""; - - if (Object.keys(lexicons).length === 0) { - lexiquesContainer.textContent = "Aucun lexique disponible."; - return; + console.log("🔄 Début de la récupération des lexiques..."); + console.log("🔑 Token utilisé :", authToken); + + if (!authToken) { + throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); } - - Object.entries(lexicons).forEach(([lexique, mots]) => { - const lexiqueTitle = document.createElement("h3"); - lexiqueTitle.textContent = lexique; - lexiquesContainer.appendChild(lexiqueTitle); - - const list = document.createElement("ul"); - mots.forEach((mot) => { - const listItem = document.createElement("li"); - listItem.textContent = mot.graphy || mot; - list.appendChild(listItem); - }); - - lexiquesContainer.appendChild(list); + + const lexicons = await getLexicons(authToken, "fr"); + console.log("📚 Réponse brute de l'API :", lexicons); + + if (!Array.isArray(lexicons) || lexicons.length === 0) { + throw new Error("âš ï¸ Aucun lexique trouvé."); + } + + lexiconMap.clear(); + lexicons.forEach((lex) => { + const lexiconName = + lex.category === "User" + ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` + : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; + lexiconMap.set(lex.id, lexiconName); }); - + + displayLexiconsWithCheckbox(lexicons.map((lex) => ({ + lexiconName: + lex.category === "User" + ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` + : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`, + lexiconId: lex.id, + active: lex.active || false, + }))); } catch (error) { - console.error("⌠Erreur lors de l'affichage des lexiques :", error); - lexiquesContainer.textContent = "Erreur lors du chargement des lexiques."; + console.error("⌠Erreur lors du chargement des lexiques :", error.message); + const lexiquesContainer = document.getElementById("lexiques"); + if (lexiquesContainer) { + lexiquesContainer.textContent = error.message || "Erreur lors du chargement des lexiques."; + } } } -/** - * (2) Affichage des lexiques avec checkbox - * Permet de modifier dynamiquement le surlignage. - */ function displayLexiconsWithCheckbox(lexicons) { const lexiquesContainer = document.getElementById("lexiques"); if (!lexiquesContainer) { console.warn("âš ï¸ Ã‰lément #lexiques introuvable."); return; } - lexiquesContainer.innerHTML = ""; - if (lexicons.length === 0) { console.log("âš ï¸ Aucun lexique à afficher."); lexiquesContainer.textContent = "Aucun lexique disponible."; return; } - lexicons.forEach(({ lexiconName, lexiconId, active }) => { - console.log(`âž¡ï¸ Affichage du lexique : ${lexiconName} (ID: ${lexiconId})`); - const lexiqueDiv = document.createElement("div"); lexiqueDiv.className = "lexique-item"; - const iconDiv = document.createElement("div"); iconDiv.className = "lexique-icon"; iconDiv.style.backgroundColor = "#ccc"; - const labelSpan = document.createElement("span"); labelSpan.className = "lexique-label"; labelSpan.textContent = lexiconName; - const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.className = "lexique-checkbox"; checkbox.checked = active; - checkbox.addEventListener("change", async () => { console.log( `🔄 Changement de surlignage pour ${lexiconName} (ID: ${lexiconId}): ${ checkbox.checked ? "activé" : "désactivé" }` ); - await browser.runtime.sendMessage({ action: "toggleLexiconHighlight", lexiconId, isActive: checkbox.checked, }); }); - lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); lexiqueDiv.appendChild(checkbox); @@ -216,67 +228,8 @@ function displayLexiconsWithCheckbox(lexicons) { }); } -/** - * Récupère la liste des lexiques depuis l'API via getLexicons puis affiche avec displayLexiconsWithCheckbox. - */ - -async function fetchLexicons() { - try { - console.log("🔄 Début de la récupération des lexiques..."); - console.log("🔑 Token utilisé :", authToken); - - if (!authToken) { - throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); - } - - const lexicons = await getLexicons(authToken, "fr"); - console.log("📚 Réponse brute de l'API :", lexicons); - - if (!Array.isArray(lexicons) || lexicons.length === 0) { - throw new Error("âš ï¸ Aucun lexique trouvé."); - } - - lexiconMap.clear(); // Vider la Map pour éviter d'accumuler de vieux lexiques - - const results = lexicons.map((lexicon) => { - console.log("📋 Transformation du lexique :", lexicon); - - // Déterminer le nom du lexique - const lexiconName = - lexicon.category === "User" - ? `Lexique personnel : ${lexicon.user?.pseudo || "Inconnu"} (${lexicon.id})` - : `Lexique de groupe : ${lexicon.group?.name || "Inconnu"} (${lexicon.id})`; - - // Ajouter l'ID et le nom dans lexiconMap - lexiconMap.set(lexicon.id, lexiconName); - - return { - lexiconName, - lexiconId: lexicon.id, - active: lexicon.active || false, - }; - }); - - console.log("📌 Contenu de lexiconMap après mise à jour :", lexiconMap); - - // Affichage des lexiques avec checkbox - displayLexiconsWithCheckbox(results); - } catch (error) { - console.error("⌠Erreur lors du chargement des lexiques :", error.message); - console.error("Détails de l'erreur :", error); - const lexiquesContainer = document.getElementById("lexiques"); - if (lexiquesContainer) { - lexiquesContainer.textContent = - error.message || "Erreur lors du chargement des lexiques."; - } - } -} - - - - // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion du bouton de connexion/déconnexion +// â–Œ Bouton de connexion/déconnexion // ───────────────────────────────────────────────────────────────────────────── async function handleAuthButtonClick() { await browser.runtime.sendMessage({ action: "toggleAuth" }); @@ -284,414 +237,14 @@ async function handleAuthButtonClick() { } // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion des définitions (Lexiques + Wiktionnaire) +// â–Œ Interaction avec definitions.js // ───────────────────────────────────────────────────────────────────────────── -/** - * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), - * en effectuant un appel global à l'API pour le mot recherché, puis en filtrant - * les entrées pour ne conserver que celles dont le lexicon.id est présent dans la liste - * des lexiques de l'utilisateur. - * - * Retourne un tableau d'objets { source, text } où: - * - source = nom du lexique (ou "Lexique #ID") - * - text = texte de la définition - * - * @param {string} word - Le mot recherché (ex. "chat"). - * @returns {Promise<Array<{ source: string, text: string }>>} - */ -/** - * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), - * en effectuant un appel global à l'API pour le mot recherché, puis en filtrant - * les entrées pour ne conserver que celles dont le lexicon.id est présent dans la liste - * des lexiques de l'utilisateur. - * - * Retourne un tableau d'objets { source, text } où: - * - source = nom du lexique (ou "Lexique #ID") - * - text = texte de la définition - * - * @param {string} word - Le mot recherché (ex. "chat"). - * @returns {Promise<Array<{ source: string, text: string }>>} - */ -async function fetchLexiconDefinitions(word) { - try { - console.log(`🔠Recherche des définitions de '${word}' dans les lexiques de l'utilisateur...`); - - if (!authToken) { - console.warn("Aucun token disponible, impossible de requêter l'API protégée."); - return []; - } - - // 1) Récupérer la liste complète des lexiques de l'utilisateur - const userId = 4; - const lexUrl = `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=fr`; - const lexResponse = await fetch(lexUrl, { - headers: { Authorization: `Bearer ${authToken}` } - }); - if (!lexResponse.ok) { - throw new Error(`⌠Erreur API lors de la récupération des lexiques: ${lexResponse.statusText}`); - } - const userLexicons = await lexResponse.json(); - console.log("ðŸ—‚ï¸ Lexiques de l'utilisateur :", userLexicons); - - if (!Array.isArray(userLexicons) || userLexicons.length === 0) { - console.warn("âš ï¸ Aucun lexique trouvé pour cet utilisateur."); - return []; - } - - // Mise à jour de lexiconMap avec des libellés uniques (ajout de l'ID) - lexiconMap.clear(); - userLexicons.forEach((lex) => { - const lexiconName = - lex.category === "User" - ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"}` - : `Lexique de groupe : ${lex.group?.name || "Inconnu"}`; - lexiconMap.set(lex.id, lexiconName); - }); - console.log("📌 LexiconMap :", lexiconMap); - - // 2) Pour chaque lexique, rechercher le mot en ajoutant target_lex - const definitionsPromises = userLexicons.map(async (lex) => { - const searchUrl = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=${lex.id}`; - console.log(`🔎 Appel API pour le lexique ${lex.id} avec l'URL : ${searchUrl}`); - - const searchResponse = await fetch(searchUrl, { - headers: { Authorization: `Bearer ${authToken}` } - }); - if (!searchResponse.ok) { - console.warn(`âš ï¸ Erreur pour le lexique ${lex.id} : ${searchResponse.statusText}`); - return { lexiconId: lex.id, entries: [] }; - } - const entries = await searchResponse.json(); - - // Filtrage côté client : ne garder que les entrées dont entry.lexicon.id correspond exactement à lex.id - const filteredEntries = entries.filter(entry => { - if (!entry.lexicon) return false; - return Number(entry.lexicon.id) === Number(lex.id); - }); - - console.log(`Pour le lexique ${lex.id} (${lexiconMap.get(lex.id)}), entrées filtrées :`, filteredEntries); - - return { lexiconId: lex.id, entries: filteredEntries }; - }); - - const results = await Promise.all(definitionsPromises); - - // 3) Parcourir les résultats et extraire les définitions - let allDefinitions = []; - results.forEach(result => { - const lexiconId = result.lexiconId; - const sourceName = lexiconMap.get(lexiconId) || `Lexique #${lexiconId}`; - - result.entries.forEach(entry => { - // Vérifier à nouveau que l'entrée appartient bien au lexique ciblé - if (!entry.lexicon || Number(entry.lexicon.id) !== Number(lexiconId)) return; - - let items = entry.attributes?.Items; - // Si items n'est pas un tableau mais est un objet, convertir en tableau - if (!Array.isArray(items)) { - if (typeof items === 'object' && items !== null) { - items = Object.values(items); - } else { - return; - } - } - - items.forEach(item => { - const definitionsArray = item.Sense?.Definitions; - if (!Array.isArray(definitionsArray)) return; - - definitionsArray.forEach(defObj => { - if (defObj.Def) { - allDefinitions.push({ - source: sourceName, - text: defObj.Def - }); - } - }); - }); - }); - }); - - console.log("Résultat final filtré :", allDefinitions); - return allDefinitions; - } catch (error) { - console.error("⌠Erreur générale lors de la récupération des définitions :", error); - return []; - } -} - - -/** - * Récupère la définition d'un mot depuis le Wiktionnaire (fr). - * Retourne un tableau d'objets : [{ source: 'Wiktionnaire', text: '...' }] - */ -async function fetchWiktionaryDefinition(word) { - try { - console.log(`🔠Envoi de la requête au Wiktionnaire pour '${word}'...`); - - if (!word || word.trim() === "") { - console.warn("âš ï¸ Mot vide, impossible d'envoyer la requête."); - return []; - } - - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent( - word - )}`; - console.log(`🌠Requête envoyée à : ${wiktionaryURL}`); - - const response = await fetch(wiktionaryURL); - if (!response.ok) { - console.error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); - return []; - } - - const data = await response.json(); - console.log("📖 Réponse API (Wiktionnaire) :", data); - - if (!data.query || !data.query.pages) { - return []; - } - - const pages = Object.values(data.query.pages); - if (pages.length === 0 || !pages[0].extract) { - return []; - } - - const cleanText = pages[0].extract.trim(); - console.log("✅ Définition extraite :", cleanText); - - return [{ source: "Wiktionnaire", text: cleanText }]; - } catch (error) { - console.error("⌠Erreur lors de la récupération de la définition du Wiktionnaire :", error); - return []; - } -} - - -const MAX_LENGTH = 200; -const modalOverlay = document.getElementById("modalOverlay"); -const modalFullText = document.getElementById("modalFullText"); -const closeModalBtn = document.getElementById("closeModal"); - -/** - * Affiche les définitions dans la barre latérale. - * @param {Array} definitions - Tableau d'objets de la forme { source, text } - */ -function displayDefinitions(definitions) { - console.log("📖 Affichage des définitions reçues :", definitions); - if (!Array.isArray(definitions)) return; - - const mesLexiquesList = document.getElementById("mesLexiquesList"); - const wiktionnaireList = document.getElementById("wiktionnaireList"); - - // Messages d'erreur/absence de définitions - const noLexiconDefinitionsContainer = document.getElementById("noLexiconDefinitionsContainer"); - const noWiktionaryDefinitionsContainer = document.getElementById("noWiktionaryDefinitionsContainer"); - - // Réinitialiser les listes existantes - mesLexiquesList.innerHTML = ""; - wiktionnaireList.innerHTML = ""; - - // Masquer les messages d'erreur dès le départ - if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "none"; - if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "none"; - - let hasLexiconDefinitions = false; - let hasWiktionaryDefinitions = false; - - // Regrouper les définitions par lexique (source) - const lexiconGroups = {}; - - definitions.forEach(({ source, text }) => { - if (!source || !text) return; - - // Créer l'élément <li> pour la définition - const li = document.createElement("li"); - let displayedText = text; - - if (text.length > MAX_LENGTH) { - displayedText = text.slice(0, MAX_LENGTH) + "... "; - const readMoreLink = document.createElement("a"); - readMoreLink.href = "#"; - readMoreLink.textContent = "[Lire la suite]"; - readMoreLink.style.marginLeft = "5px"; - readMoreLink.style.color = "#8d5c70"; - readMoreLink.style.textDecoration = "underline"; - readMoreLink.style.cursor = "pointer"; - readMoreLink.addEventListener("click", (event) => { - event.preventDefault(); - openDefinitionPopup(text); - }); - li.appendChild(document.createTextNode(displayedText)); - li.appendChild(readMoreLink); - } else { - li.textContent = displayedText; - } - - // Vérifier la source : Wiktionnaire ou Lexiques - if (source === "Wiktionnaire") { - wiktionnaireList.appendChild(li); - hasWiktionaryDefinitions = true; - } else { - if (!lexiconGroups[source]) { - lexiconGroups[source] = []; - } - lexiconGroups[source].push(li); - hasLexiconDefinitions = true; - } - }); - - // Créer une section pour chaque lexique - Object.entries(lexiconGroups).forEach(([lexiconName, definitionItems]) => { - const lexiconContainer = document.createElement("div"); - lexiconContainer.className = "lexicon-section"; - - const lexiconHeader = document.createElement("div"); - lexiconHeader.className = "lexicon-header"; - lexiconHeader.textContent = lexiconName; - // Lorsque l'utilisateur clique sur le header, on bascule l'affichage - lexiconHeader.addEventListener("click", () => { - lexiconContent.classList.toggle("hidden"); - }); - - // Création de la liste et ajout de la classe "hidden" pour qu'elle soit masquée par défaut - const lexiconContent = document.createElement("ul"); - lexiconContent.className = "lexicon-content hidden"; - - definitionItems.forEach(li => lexiconContent.appendChild(li)); - - lexiconContainer.appendChild(lexiconHeader); - lexiconContainer.appendChild(lexiconContent); - mesLexiquesList.appendChild(lexiconContainer); - }); - - // Gestion de l'affichage des messages d'erreur si aucune définition n'est trouvée - if (!hasLexiconDefinitions) { - if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "block"; - } - if (!hasWiktionaryDefinitions) { - if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "block"; - } - - // Affichage ou masquage des sections en fonction de l'existence de définitions - document.getElementById("mesLexiquesContainer").style.display = - hasLexiconDefinitions ? "block" : "none"; - document.getElementById("wiktionnaireContainer").style.display = - hasWiktionaryDefinitions ? "block" : "none"; -} - - -function openDefinitionPopup(fullText) { - modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; - modalOverlay.style.display = "flex"; -} - -function closeDefinitionPopup() { - modalOverlay.style.display = "none"; - modalFullText.innerHTML = ""; -} - -closeModalBtn.addEventListener("click", closeDefinitionPopup); -modalOverlay.addEventListener("click", (event) => { - if (event.target === modalOverlay) closeDefinitionPopup(); -}); - -/** - * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire, - * puis les afficher. - */ -async function showDefinitions(word) { - console.log(`📖 Recherche des définitions pour '${word}'...`); - - const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); - if (noDefinitionsContainer) { - noDefinitionsContainer.textContent = "Chargement des définitions..."; - noDefinitionsContainer.style.display = "block"; - } - - try { - // Utilisation de Promise.allSettled pour récupérer les deux sources - const results = await Promise.allSettled([ - fetchLexiconDefinitions(word), - fetchWiktionaryDefinition(word) - ]); - - // Extraction des résultats réussis - const lexiconDefinitions = - results[0].status === "fulfilled" ? results[0].value : []; - const wiktionaryDefinitions = - results[1].status === "fulfilled" ? results[1].value : []; - - // Fusion des résultats - const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; - console.log("📚 Définitions combinées :", allDefinitions); - - // Affichage final - displayDefinitions(allDefinitions); - - // Masquer le conteneur de message si tout s'est bien passé - if (noDefinitionsContainer) { - noDefinitionsContainer.style.display = "none"; - } - } catch (error) { - console.error("⌠Erreur lors de la récupération des définitions :", error); - if (noDefinitionsContainer) { - noDefinitionsContainer.textContent = - "⌠Une erreur est survenue lors de la récupération des définitions."; - noDefinitionsContainer.style.display = "block"; - } - } -} - -/** - * Bascule l’affichage d’un bloc. - * @param {string} blockId - L’ID du conteneur à basculer (ex. "definitionContent"). - * @param {HTMLElement} btn - Le bouton qui déclenche la bascule, pour mettre à jour son texte. - */ -function toggleBlock(blockId, btn) { - const block = document.getElementById(blockId); - if (block) { - if (block.classList.contains("hidden")) { - block.classList.remove("hidden"); - if (btn) btn.textContent = "–"; - } else { - block.classList.add("hidden"); - if (btn) btn.textContent = "+"; - } - } -} - -/** - * Ouvre un bloc s’il est fermé et met à jour le bouton de bascule. - * @param {string} blockId - L’ID du conteneur à ouvrir (ex. "definitionContent"). - * @param {HTMLElement} [btn] - (Optionnel) Le bouton de bascule à mettre à jour. - */ -function openBlock(blockId, btn) { - const block = document.getElementById(blockId); - if (block && block.classList.contains("hidden")) { - block.classList.remove("hidden"); - - if (btn) { - btn.textContent = "–"; - } else { - const header = block.previousElementSibling; - if (header) { - const toggleBtn = header.querySelector(".toggle-btn"); - if (toggleBtn) { - toggleBtn.textContent = "–"; - } - } - } - } -} - // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Gestion des messages reçus (depuis le background ou ailleurs) +// â–Œ Réception des messages // ───────────────────────────────────────────────────────────────────────────── browser.runtime.onMessage.addListener(async (message) => { console.log("📩 Message reçu dans sidebar.js :", message); - switch (message.action) { case "refreshUI": console.log("🔄 Demande de rafraîchissement de la barre latérale."); @@ -715,30 +268,31 @@ browser.runtime.onMessage.addListener(async (message) => { if (message.selectedText) { console.log("📖 Recherche des définitions pour :", message.selectedText); openBlock("definitionContent"); - await showDefinitions(message.selectedText); + await window.showDefinitions(message.selectedText); } break; case "showDefinitions": if (Array.isArray(message.definitions)) { - displayDefinitions(message.definitions); + window.displayDefinitions(message.definitions); } break; case "fetchWiktionaryDefinitionResponse": if (message.selectedText) { console.log(`📖 Réception de la définition du Wiktionnaire pour '${message.selectedText}'`); - displayDefinitions(message.definitions); + window.displayDefinitions(message.definitions); } break; case "showLexiconResult": console.log("📚 Résultat des lexiques reçus :", message.lexicons); - displayLexiconResults(message.lexicons); + window.displayLexiconResults(message.lexicons); break; case "toggleAuth": break; + case "authStatusChanged": break; @@ -747,111 +301,30 @@ browser.runtime.onMessage.addListener(async (message) => { } }); -/** - * Affiche les lexiques où le mot sélectionné est présent. - */ -function displayLexiconResults(lexicons) { - const resultDiv = document.getElementById("lexiconResult"); - if (!resultDiv) return; // Sécurité si l'élément n'existe pas - - // Vider le contenu précédent - resultDiv.innerHTML = ""; - - if (!lexicons || lexicons.length === 0) { - resultDiv.textContent = "⌠Ce mot n'est présent dans aucun lexique."; - return; - } - - // Création d'un titre pour la section - const title = document.createElement("p"); - title.innerHTML = "Ce mot est présent dans le(s) lexique(s) suivant(s) :"; - title.style.fontSize = "12px"; - resultDiv.appendChild(title); - - // Création de la liste UL - const ul = document.createElement("ul"); - ul.style.paddingLeft = "20px"; - - // Remplir la liste avec les lexiques trouvés - lexicons.forEach((lexicon) => { - if (!lexicon || !lexicon.id) { - console.warn("âš ï¸ Lexique incorrect ou ID non défini :", lexicon); - return; - } - - // Utiliser la propriété "name" reçue - const lexiconName = lexicon.name || `Lexique #${lexicon.id}`; - const li = document.createElement("li"); - li.innerHTML = `<strong>${lexiconName}</strong>`; - ul.appendChild(li); - - console.log(`✅ Lexique ajouté : ${lexiconName} (ID: ${lexicon.id})`); - }); - - // Ajouter la liste au conteneur - resultDiv.appendChild(ul); -} - // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Recherche et affichage des définitions -// ───────────────────────────────────────────────────────────────────────────── -async function fetchDefinition(word) { - console.log(`🔠Recherche de la définition pour '${word}'...`); - - const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); - if (!noDefinitionsContainer) { - console.error("⌠Élément #noDefinitionsContainer introuvable."); - return; - } - - try { - const definition = await fetchLexiconDefinitions(word); - console.log("🔠Résultat API :", definition); - - if (!definition || definition.length === 0) { - console.warn(`âš ï¸ Aucune définition trouvée pour '${word}'`); - noDefinitionsContainer.style.display = "block"; - return; - } - - noDefinitionsContainer.style.display = "none"; - } catch (error) { - console.error("⌠Erreur lors de la récupération de la définition :", error); - noDefinitionsContainer.style.display = "block"; - } -} - -// ───────────────────────────────────────────────────────────────────────────── -// â–Œ Initialisation après chargement du DOM +// â–Œ DOMContentLoaded // ───────────────────────────────────────────────────────────────────────────── document.addEventListener("DOMContentLoaded", async () => { console.log("📦 DOM entièrement chargé. Initialisation de la sidebar."); - - // Mise à jour de l'UI await refreshSidebarState(); - // Gestion du bouton de connexion/déconnexion const authButton = document.getElementById("auth-button"); if (authButton) { authButton.addEventListener("click", handleAuthButtonClick); } - // Gestion du bouton de recherche de définitions const chercherDefButton = document.getElementById("chercherDef"); if (chercherDefButton) { chercherDefButton.addEventListener("click", async () => { openBlock("definitionContent"); const selectedWord = document.getElementById("motSelectionne")?.textContent?.trim(); - console.log("📖 Mot sélectionné :", selectedWord); - if (selectedWord && selectedWord !== "Aucun mot sélectionné") { console.log(`📩 Recherche des définitions pour '${selectedWord}'`); - await showDefinitions(selectedWord); + await window.showDefinitions(selectedWord); } else { console.warn("âš ï¸ Aucun mot sélectionné pour la recherche."); } }); - console.log("✅ Bouton #chercherDef détecté dans le DOM."); chercherDefButton.style.pointerEvents = "auto"; chercherDefButton.style.display = "block"; @@ -861,12 +334,11 @@ document.addEventListener("DOMContentLoaded", async () => { console.error("⌠ERREUR : Bouton #chercherDef introuvable."); } - // Écouteur pour la case à cocher "toggle-definitions" --- + // Écouteur pour la case à cocher "toggle-definitions" const toggleCheckbox = document.getElementById("toggle-definitions"); if (toggleCheckbox) { toggleCheckbox.addEventListener("change", (event) => { const showAll = event.target.checked; - // Sélectionner toutes les sections de définitions dans "mesLexiquesList" const lexiconContents = document.querySelectorAll("#mesLexiquesList .lexicon-content"); lexiconContents.forEach(content => { if (showAll) { @@ -886,7 +358,6 @@ document.addEventListener("DOMContentLoaded", () => { btn.textContent = "-"; btn.style.fontSize = "15px"; } - btn.addEventListener("click", (event) => { event.stopPropagation(); const header = btn.parentElement; diff --git a/definitions.js b/definitions.js new file mode 100644 index 0000000..88ce36a --- /dev/null +++ b/definitions.js @@ -0,0 +1,461 @@ +const lexiconMap = new Map(); + +/** + * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), + * en effectuant un appel global à l'API pour le mot recherché, puis en filtrant + * les entrées pour ne conserver que celles dont le lexicon.id est présent dans la liste + * des lexiques de l'utilisateur. + * + * Retourne un tableau d'objets { source, text } où: + * - source = nom du lexique (ou "Lexique #ID") + * - text = texte de la définition + * + * @param {string} word - Le mot recherché (ex. "chat"). + * @returns {Promise<Array<{ source: string, text: string }>>} + */ +async function fetchLexiconDefinitions(word) { + try { + console.log(`🔠Recherche des définitions de '${word}' dans les lexiques de l'utilisateur...`); + + if (!authToken) { + console.warn("Aucun token disponible, impossible de requêter l'API protégée."); + return []; + } + + // 1) Récupérer la liste complète des lexiques de l'utilisateur + const userId = 4; + const lexUrl = `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=fr`; + const lexResponse = await fetch(lexUrl, { + headers: { Authorization: `Bearer ${authToken}` } + }); + if (!lexResponse.ok) { + throw new Error(`⌠Erreur API lors de la récupération des lexiques: ${lexResponse.statusText}`); + } + const userLexicons = await lexResponse.json(); + console.log("ðŸ—‚ï¸ Lexiques de l'utilisateur :", userLexicons); + + if (!Array.isArray(userLexicons) || userLexicons.length === 0) { + console.warn("âš ï¸ Aucun lexique trouvé pour cet utilisateur."); + return []; + } + + // Mise à jour de lexiconMap avec des libellés uniques (ajout de l'ID) + lexiconMap.clear(); + userLexicons.forEach((lex) => { + const lexiconName = + lex.category === "User" + ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"}` + : `Lexique de groupe : ${lex.group?.name || "Inconnu"}`; + lexiconMap.set(lex.id, lexiconName); + }); + console.log("📌 LexiconMap :", lexiconMap); + + // 2) Pour chaque lexique, rechercher le mot en ajoutant target_lex + const definitionsPromises = userLexicons.map(async (lex) => { + const searchUrl = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=${lex.id}`; + console.log(`🔎 Appel API pour le lexique ${lex.id} avec l'URL : ${searchUrl}`); + + const searchResponse = await fetch(searchUrl, { + headers: { Authorization: `Bearer ${authToken}` } + }); + if (!searchResponse.ok) { + console.warn(`âš ï¸ Erreur pour le lexique ${lex.id} : ${searchResponse.statusText}`); + return { lexiconId: lex.id, entries: [] }; + } + const entries = await searchResponse.json(); + + // Filtrage côté client : ne garder que les entrées dont entry.lexicon.id correspond exactement à lex.id + const filteredEntries = entries.filter(entry => { + if (!entry.lexicon) return false; + return Number(entry.lexicon.id) === Number(lex.id); + }); + + console.log(`Pour le lexique ${lex.id} (${lexiconMap.get(lex.id)}), entrées filtrées :`, filteredEntries); + + return { lexiconId: lex.id, entries: filteredEntries }; + }); + + const results = await Promise.all(definitionsPromises); + + // 3) Parcourir les résultats et extraire les définitions + let allDefinitions = []; + results.forEach(result => { + const lexiconId = result.lexiconId; + const sourceName = lexiconMap.get(lexiconId) || `Lexique #${lexiconId}`; + + result.entries.forEach(entry => { + // Vérifier à nouveau que l'entrée appartient bien au lexique ciblé + if (!entry.lexicon || Number(entry.lexicon.id) !== Number(lexiconId)) return; + + let items = entry.attributes?.Items; + // Si items n'est pas un tableau mais est un objet, convertir en tableau + if (!Array.isArray(items)) { + if (typeof items === 'object' && items !== null) { + items = Object.values(items); + } else { + return; + } + } + + items.forEach(item => { + const definitionsArray = item.Sense?.Definitions; + if (!Array.isArray(definitionsArray)) return; + + definitionsArray.forEach(defObj => { + if (defObj.Def) { + allDefinitions.push({ + source: sourceName, + text: defObj.Def + }); + } + }); + }); + }); + }); + + console.log("Résultat final filtré :", allDefinitions); + return allDefinitions; + } catch (error) { + console.error("⌠Erreur générale lors de la récupération des définitions :", error); + return []; + } + } + + +/** + * Récupère la définition d'un mot depuis le Wiktionnaire (fr). + * Retourne un tableau d'objets : [{ source: 'Wiktionnaire', text: '...' }] + */ +async function fetchWiktionaryDefinition(word) { + try { + console.log(`🔠Requête Wiktionnaire pour "${word}"...`); + if (!word || word.trim() === "") { + throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); + } + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; + const response = await fetch(wiktionaryURL); + if (!response.ok) { + throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + } + const data = await response.json(); + console.log("📖 Réponse API (Wiktionnaire) :", data); + + const pages = data.query?.pages; + const page = pages ? Object.values(pages)[0] : null; + + const definitionText = page && page.extract + ? page.extract.trim() + : "âš ï¸ Aucune définition trouvée sur le Wiktionnaire."; + + console.log("🌠Définition Wiktionnaire extraite :", definitionText); + + return [ + { + source: "Wiktionnaire", + text: definitionText + } + ]; + } catch (error) { + console.error("⌠Erreur Wiktionnaire :", error); + return [ + { + source: "Wiktionnaire", + text: "âš ï¸ Erreur lors de la récupération sur le Wiktionnaire." + } + ]; + } + } + + + +const MAX_LENGTH = 200; + +/** + * Affiche les définitions dans la barre latérale. + * @param {Array} definitions - Tableau d'objets de la forme { source, text } + */ +function displayDefinitions(definitions) { + console.log("📖 Affichage des définitions reçues :", definitions); + if (!Array.isArray(definitions)) return; + + const mesLexiquesList = document.getElementById("mesLexiquesList"); + const wiktionnaireList = document.getElementById("wiktionnaireList"); + + // Messages d'erreur/absence de définitions + const noLexiconDefinitionsContainer = document.getElementById("noLexiconDefinitionsContainer"); + const noWiktionaryDefinitionsContainer = document.getElementById("noWiktionaryDefinitionsContainer"); + + // Réinitialiser les listes existantes + mesLexiquesList.innerHTML = ""; + wiktionnaireList.innerHTML = ""; + + // Masquer les messages d'erreur dès le départ + if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "none"; + if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "none"; + + let hasLexiconDefinitions = false; + let hasWiktionaryDefinitions = false; + + // Regrouper les définitions par lexique (source) + const lexiconGroups = {}; + + definitions.forEach(({ source, text }) => { + if (!source || !text) return; + + // Créer l'élément <li> pour la définition + const li = document.createElement("li"); + let displayedText = text; + + if (text.length > MAX_LENGTH) { + displayedText = text.slice(0, MAX_LENGTH) + "... "; + const readMoreLink = document.createElement("a"); + readMoreLink.href = "#"; + readMoreLink.textContent = "[Lire la suite]"; + readMoreLink.style.marginLeft = "5px"; + readMoreLink.style.color = "#8d5c70"; + readMoreLink.style.textDecoration = "underline"; + readMoreLink.style.cursor = "pointer"; + readMoreLink.addEventListener("click", (event) => { + event.preventDefault(); + openDefinitionPopup(text); + }); + li.appendChild(document.createTextNode(displayedText)); + li.appendChild(readMoreLink); + } else { + li.textContent = displayedText; + } + + // Vérifier la source : Wiktionnaire ou Lexiques + if (source === "Wiktionnaire") { + wiktionnaireList.appendChild(li); + hasWiktionaryDefinitions = true; + } else { + if (!lexiconGroups[source]) { + lexiconGroups[source] = []; + } + lexiconGroups[source].push(li); + hasLexiconDefinitions = true; + } + }); + + // Créer une section pour chaque lexique + Object.entries(lexiconGroups).forEach(([lexiconName, definitionItems]) => { + const lexiconContainer = document.createElement("div"); + lexiconContainer.className = "lexicon-section"; + + const lexiconHeader = document.createElement("div"); + lexiconHeader.className = "lexicon-header"; + lexiconHeader.textContent = lexiconName; + // Lorsque l'utilisateur clique sur le header, on bascule l'affichage + lexiconHeader.addEventListener("click", () => { + lexiconContent.classList.toggle("hidden"); + }); + + // Création de la liste et ajout de la classe "hidden" pour qu'elle soit masquée par défaut + const lexiconContent = document.createElement("ul"); + lexiconContent.className = "lexicon-content hidden"; + + definitionItems.forEach(li => lexiconContent.appendChild(li)); + + lexiconContainer.appendChild(lexiconHeader); + lexiconContainer.appendChild(lexiconContent); + mesLexiquesList.appendChild(lexiconContainer); + }); + + // Gestion de l'affichage des messages d'erreur si aucune définition n'est trouvée + if (!hasLexiconDefinitions) { + if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "block"; + } + if (!hasWiktionaryDefinitions) { + if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "block"; + } + + // Affichage ou masquage des sections en fonction de l'existence de définitions + document.getElementById("mesLexiquesContainer").style.display = + hasLexiconDefinitions ? "block" : "none"; + document.getElementById("wiktionnaireContainer").style.display = + hasWiktionaryDefinitions ? "block" : "none"; +} + + +function openDefinitionPopup(fullText) { + const modalOverlay = document.getElementById("modalOverlay"); + const modalFullText = document.getElementById("modalFullText"); + if (!modalFullText || !modalOverlay) { + console.error("Modal elements not found!"); + return; + } + modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; + modalOverlay.style.display = "flex"; + } + + function closeDefinitionPopup() { + const modalOverlay = document.getElementById("modalOverlay"); + const modalFullText = document.getElementById("modalFullText"); + if (!modalOverlay || !modalFullText) return; + modalOverlay.style.display = "none"; + modalFullText.innerHTML = ""; + } + + + +/** + * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire, + * puis les afficher. + */ +async function combineDefinitions(word) { + console.log(`[combineDefinitions] Récupération des définitions pour "${word}"...`); + + const results = await Promise.allSettled([ + fetchLexiconDefinitions(word), + fetchWiktionaryDefinition(word) + ]); + + const lexiconDefinitions = + results[0].status === "fulfilled" ? results[0].value : []; + const wiktionaryDefinitions = + results[1].status === "fulfilled" ? results[1].value : []; + + // Fusion + const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; + + console.log("📚 [combineDefinitions] Résultat fusionné :", allDefinitions); + + // Renvoi du tableau final (sans affichage direct) : + return allDefinitions; + } + + + async function fetchDefinition(word) { + console.log(`🔠Recherche de la définition pour '${word}'...`); + + const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); + if (!noDefinitionsContainer) { + console.error("⌠Élément #noDefinitionsContainer introuvable."); + return; + } + + try { + const definition = await fetchLexiconDefinitions(word); + console.log("🔠Résultat API :", definition); + + if (!definition || definition.length === 0) { + console.warn(`âš ï¸ Aucune définition trouvée pour '${word}'`); + noDefinitionsContainer.style.display = "block"; + return; + } + + noDefinitionsContainer.style.display = "none"; + } catch (error) { + console.error("⌠Erreur lors de la récupération de la définition :", error); + noDefinitionsContainer.style.display = "block"; + } +} + + +/** + * Affiche les lexiques où le mot sélectionné est présent. + */ +function displayLexiconResults(lexicons) { + const resultDiv = document.getElementById("lexiconResult"); + if (!resultDiv) return; // Sécurité si l'élément n'existe pas + + // Vider le contenu précédent + resultDiv.innerHTML = ""; + + if (!lexicons || lexicons.length === 0) { + resultDiv.textContent = "⌠Ce mot n'est présent dans aucun lexique."; + return; + } + + // Création d'un titre pour la section + const title = document.createElement("p"); + title.innerHTML = "Ce mot est présent dans le(s) lexique(s) suivant(s) :"; + title.style.fontSize = "12px"; + resultDiv.appendChild(title); + + // Création de la liste UL + const ul = document.createElement("ul"); + ul.style.paddingLeft = "20px"; + + // Remplir la liste avec les lexiques trouvés + lexicons.forEach((lexicon) => { + if (!lexicon || !lexicon.id) { + console.warn("âš ï¸ Lexique incorrect ou ID non défini :", lexicon); + return; + } + + // Utiliser la propriété "name" reçue + const lexiconName = lexicon.name || `Lexique #${lexicon.id}`; + const li = document.createElement("li"); + li.innerHTML = `<strong>${lexiconName}</strong>`; + ul.appendChild(li); + + console.log(`✅ Lexique ajouté : ${lexiconName} (ID: ${lexicon.id})`); + }); + + // Ajouter la liste au conteneur + resultDiv.appendChild(ul); + } + +async function showDefinitions(word) { + console.log(`[showDefinitions] Recherche + affichage pour "${word}"...`); + + // 1) Indiquer à l’utilisateur le début du chargement + const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = "Chargement des définitions..."; + noDefinitionsContainer.style.display = "block"; + } + + try { + // 2) Récupérer la liste de définitions + const allDefinitions = await combineDefinitions(word); + + console.log("[showDefinitions] Définitions récupérées :", allDefinitions); + + // 3) S’il n’y a aucune définition + if (!allDefinitions || allDefinitions.length === 0) { + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = "âš ï¸ Aucune définition trouvée."; + // on laisse afficher pour signaler qu’on n’a rien + } + return; + } + + // 4) Afficher via displayDefinitions + displayDefinitions(allDefinitions); + + // 5) Masquer le message de chargement s’il existe + if (noDefinitionsContainer) { + noDefinitionsContainer.style.display = "none"; + } + + // Eventuellement, renvoyer la liste pour un usage ultérieur + return allDefinitions; + } catch (error) { + // Gérer l’erreur si combineDefinitions lève une exception + console.error("⌠[showDefinitions] Erreur : ", error); + + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = + "⌠Une erreur est survenue lors de la récupération des définitions."; + noDefinitionsContainer.style.display = "block"; + } + // On peut renvoyer un tableau vide ou lever l’erreur + return []; + } + } + + + + + +window.fetchLexiconDefinitions = fetchLexiconDefinitions; +window.fetchWiktionaryDefinition = fetchWiktionaryDefinition; +window.displayDefinitions = displayDefinitions; +window.openDefinitionPopup = openDefinitionPopup; +window.closeDefinitionPopup = closeDefinitionPopup; +window.showDefinitions = showDefinitions; +window.fetchDefinition = fetchDefinition; +window.displayLexiconResults = displayLexiconResults; diff --git a/manifest.json b/manifest.json index 2b59919..c2b94ca 100644 --- a/manifest.json +++ b/manifest.json @@ -21,7 +21,8 @@ "background": { "scripts": [ "background/background.js", - "background/browser_context_menu.js", + "definitions.js", + "menu_contextuel/browser_context_menu.js", "api.js"], "persistent": true }, diff --git a/menu_contextuel/browser_context_menu.js b/menu_contextuel/browser_context_menu.js new file mode 100644 index 0000000..bbaf1a6 --- /dev/null +++ b/menu_contextuel/browser_context_menu.js @@ -0,0 +1,268 @@ +console.log("browser_context_menu.js chargé correctement"); + +// ───────────────────────────────────────────────────────────────────────────── +// Variable globale qui contient le token pour les requêtes API +// (Utilisée par fetchLexiconDefinitions, etc.) +// ───────────────────────────────────────────────────────────────────────────── +let authToken = null; + +/** + * Charge le token depuis le stockage local et le stocke dans la variable globale authToken. + */ +async function loadAuthToken() { + try { + const result = await browser.storage.local.get("accessToken"); + authToken = result.accessToken; + console.log("🔑 Token chargé au démarrage :", authToken); + } catch (error) { + console.error("⌠Erreur lors de la récupération du token :", error); + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// Création du menu contextuel en fonction de l'authentification +// ───────────────────────────────────────────────────────────────────────────── +async function createContextMenu() { + // Supprime tous les items existants afin de recréer le menu complet + await browser.contextMenus.removeAll(); + + if (authToken) { + // Item 1 : Recherche dans les lexiques de l’utilisateur + browser.contextMenus.create({ + id: "searchInLexicons", + title: "Rechercher dans mes lexiques", + contexts: ["selection"], + icons: { "16": "icons/quel_lexique.png" }, + }); + + // Item 2 : Ajouter un mot au lexique personnel + browser.contextMenus.create({ + id: "addtoLexicon", + title: "Ajouter ce mot à mon lexique", + contexts: ["selection"], + icons: { "16": "icons/ajout_lexique.png" }, + }); + } + + // Séparateur + browser.contextMenus.create({ + id: "separatorExtension", + type: "separator", + contexts: ["all"], + }); + + // Item 3 : Recherche globale de définition (Lexiques + Wiktionnaire) + browser.contextMenus.create({ + id: "getDefinition", + title: "Obtenir une définition", + contexts: ["selection"], + icons: { "16": "icons/definition.png" }, + }); + + // Séparateur + browser.contextMenus.create({ + id: "separatorAfterExtension", + type: "separator", + contexts: ["all"], + }); + + // Item de connexion/déconnexion + browser.contextMenus.create({ + id: "login", + title: authToken ? "Se déconnecter de BaLex" : "Se connecter à BaLex", + contexts: ["all"], + }); +} + +// Charger le token au démarrage puis créer le menu contextuel +loadAuthToken().then(createContextMenu); + +// Listener pour mettre à jour le menu quand un message "refreshUI" est reçu +browser.runtime.onMessage.addListener((message) => { + if (message.action === "refreshUI") { + console.log("🔄 refreshUI reçu dans browser_context_menu.js"); + loadAuthToken().then(createContextMenu); + } +}); + +// Quand le token change dans le storage +browser.storage.onChanged.addListener((changes, area) => { + if (area === "local" && changes.accessToken) { + console.log("🔄 Token modifié, actualisation du menu contextuel."); + loadAuthToken().then(createContextMenu); + } +}); + +// ───────────────────────────────────────────────────────────────────────────── +// GESTION DES CLICS SUR LE MENU CONTEXTUEL +// ───────────────────────────────────────────────────────────────────────────── +browser.contextMenus.onClicked.addListener(async (info, tab) => { + console.log("Item de menu cliqué :", info.menuItemId); + + // Cas de l’item login/déconnexion + if (info.menuItemId === "login") { + console.log("🔄 Action login/déconnexion demandée."); + if (typeof actuallyOpenLoginPage === "function") { + actuallyOpenLoginPage(); + } else { + console.error("La fonction actuallyOpenLoginPage n'est pas accessible."); + } + return; + } + + // Les items ci-dessous nécessitent un texte sélectionné + if (!info.selectionText) { + console.warn("Aucun texte sélectionné pour cette action :", info.menuItemId); + return; + } + console.log(`📩 Texte sélectionné : ${info.selectionText}`); + + // Rediriger vers la fonction appropriée + switch (info.menuItemId) { + case "searchInLexicons": + if (!authToken) { + alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); + return; + } + await searchInLexicons(info.selectionText); + break; + + case "addtoLexicon": + if (!authToken) { + alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); + return; + } + await addWordToLexicon(info.selectionText); + break; + + case "getDefinition": + // Pas forcément besoin d'être connecté, car on peut récupérer + // la définition via Wiktionnaire même sans authToken. + await getDefinition(info.selectionText); + break; + + default: + console.error(`⌠Action inconnue : ${info.menuItemId}`); + } +}); + +// ───────────────────────────────────────────────────────────────────────────── +// FONCTIONS ADAPTÉES AUX NOUVELLES APPELS DE definitions.js +// ───────────────────────────────────────────────────────────────────────────── + +/** + * 1) Recherche de la définition combinée (lexiques + Wiktionnaire) + * et envoi des résultats à la sidebar (ou autre script) pour affichage. + */ +async function getDefinition(selectedText) { + try { + // On utilise la même logique que la fonction combineDefinitions, + // mais sans modifier le DOM (car on est dans le background). + // On récupère les définitions de mes lexiques (si authToken) et du Wiktionnaire. + let lexiconDefs = []; + if (authToken) { + lexiconDefs = await fetchLexiconDefinitions(selectedText); + } + + const wiktionaryDef = await fetchWiktionaryDefinition(selectedText); + // Dans definitions.js, fetchWiktionaryDefinition renvoie un string (ou un message d’erreur). + // Pour l'uniformiser, on le place dans un tableau [{ source: "Wiktionnaire", text: ... }] + let wikiDefs = []; + if (wiktionaryDef && typeof wiktionaryDef === "string") { + // On vérifie si c’est un message d'erreur ou pas + if (!wiktionaryDef.startsWith("âš ï¸")) { + wikiDefs.push({ source: "Wiktionnaire", text: wiktionaryDef }); + } + } + + // Combinaison + const allDefinitions = [...lexiconDefs, ...wikiDefs]; + + console.log("📠Définitions combinées :", allDefinitions); + + // Envoyer les définitions à la sidebar (ou autre) pour affichage + browser.runtime.sendMessage({ + action: "showDefinitions", + selectedText, + definitions: allDefinitions, + }); + } catch (error) { + console.error("⌠Erreur lors de la recherche combinée des définitions :", error); + } +} + +/** + * 2) Recherche dans les lexiques pour savoir dans quels lexiques se trouve le mot. + * On utilise fetchLexiconDefinitions pour récupérer les définitions + * et déduire ainsi les lexiques (source). + */ +async function searchInLexicons(selectedText) { + try { + console.log("🔎 Recherche dans mes lexiques :", selectedText); + + // Récupère toutes les définitions, triées par lexique + const allDefinitions = await fetchLexiconDefinitions(selectedText); + if (!allDefinitions || allDefinitions.length === 0) { + // Rien trouvé + console.log("⌠Aucun lexique trouvé pour ce mot."); + browser.runtime.sendMessage({ + action: "showLexiconResult", + lexicons: [], + selectedText, + }); + return; + } + + // On récupère la liste unique des sources (lexiques) trouvées + // (ex: "Lexique personnel : Alice", "Lexique de groupe : Francophiles", etc.) + const uniqueSources = [...new Set(allDefinitions.map((d) => d.source))]; + + // On construit un tableau d'objets { name: "Nom du lexique" } + // (L'ID n'est pas directement renvoyé par fetchLexiconDefinitions, à moins de l’ajouter.) + const foundInLexicons = uniqueSources.map((src) => ({ + // On ne sait pas forcément l’ID, on affiche le nom en l’état + name: src, + })); + + console.log("📩 Envoi du message 'showLexiconResult' avec :", foundInLexicons); + browser.runtime.sendMessage({ + action: "showLexiconResult", + lexicons: foundInLexicons, + selectedText, + }); + } catch (error) { + console.error("⌠Erreur lors de la recherche dans les lexiques :", error); + browser.runtime.sendMessage({ + action: "showLexiconResult", + lexicons: [], + selectedText, + }); + } +} + +/** + * 3) Ajouter un mot dans le lexique personnel. + * Cette partie n’existe pas (encore) dans definitions.js, + * donc on la conserve ou on l’adapte si vous avez un endpoint pour ça. + */ +async function addWordToLexicon(selectedText) { + try { + console.log("🔠Ajout du mot à mon lexique :", selectedText); + // À adapter selon votre API. + // Exemple d’endpoint hypothétique : POST /api/entry/create?lexicon_id=123 + // ... + alert(`(Exemple) Le mot "${selectedText}" a été ajouté à votre lexique personnel !`); + } catch (error) { + console.error("⌠Erreur lors de l'ajout au lexique :", error); + alert("⌠Impossible d'ajouter ce mot au lexique."); + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// Écouteur interne pour d’autres messages éventuels +// ───────────────────────────────────────────────────────────────────────────── +browser.runtime.onMessage.addListener(async (message) => { + if (message.action === "getDefinitionAll") { + await getDefinition(message.selectedText); + } +}); -- GitLab From b1e0322d0255652cad11d0f594de77817772d15b Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Fri, 7 Feb 2025 20:36:47 +0100 Subject: [PATCH 27/32] =?UTF-8?q?Correction=20affichage=20d=C3=A9finition?= =?UTF-8?q?=20compl=C3=A8te=20Wiktionnaire?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.js | 46 +- background/background.js | 22 +- "barre_lat\303\251rale/sidebar.html" | 25 +- "barre_lat\303\251rale/sidebar.js" | 28 +- definitions.js | 605 +++++++++++++-------------- 5 files changed, 335 insertions(+), 391 deletions(-) diff --git a/api.js b/api.js index 785142a..c1a046d 100644 --- a/api.js +++ b/api.js @@ -40,30 +40,6 @@ async function callApi(url, authToken = null, method = 'GET') { } } -/** - * Décode un token JWT - * (Cette fonction est là au cas où) - * @param {string} token - Le token JWT. - * @returns {Object|null} - La charge utile du token ou null en cas d'erreur. - */ -function parseJwt(token) { - try { - const base64Url = token.split('.')[1]; - const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); - const jsonPayload = decodeURIComponent( - atob(base64) - .split('') - .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) - .join('') - ); - return JSON.parse(jsonPayload); - } catch (error) { - console.error("⌠Erreur lors du décodage du token :", error); - return null; - } -}console.log("✅ api.js chargé correctement"); - - // ───────────────────────────────────────────────────────────────────────────── // â–Œ Récupération des lexiques de l'utilisateur // ───────────────────────────────────────────────────────────────────────────── @@ -86,15 +62,10 @@ async function getLexicons(authToken, language = 'fr') { /** * Récupère tous les lexiques pour l’utilisateur 4 - * @param {string} authToken - Le token d'authentification (Bearer ...). - * @returns {Promise<any[]>} - Un grand tableau combinant tous les lexiques trouvés, - * quelle que soit la catégorie. */ async function getAllCategoriesLexicons(authToken) { - // Les différentes catégories à tester const categories = ["User", "Group", "Zero", "New words"]; - // Paramètres fixes const userId = 4; const groupId = 1; @@ -112,8 +83,6 @@ async function getAllCategoriesLexicons(authToken) { try { const resultsByCategory = await Promise.all(promises); - // On a un tableau de 4 éléments, un pour chaque catégorie - // Concaténation en un seul tableau const combined = resultsByCategory.flat(); console.log("✅ Lexiques récupérés (toutes catégories confondues) :", combined); @@ -129,10 +98,7 @@ async function getAllCategoriesLexicons(authToken) { // ───────────────────────────────────────────────────────────────────────────── /** - * Récupère les entrées (mots) d'un lexique donné. - * @param {string} authToken - Le token d'authentification. - * @param {number|string} lexiconId - L'ID du lexique à récupérer. - * @returns {Promise<any[]>} - Liste des entrées du lexique. + * Récupère les entrées d'un lexique donné. */ async function getLexiconEntries(authToken, lexiconId) { const url = `https://babalex.lezinter.net/api/lexicon/entries/${lexiconId}`; @@ -141,11 +107,6 @@ async function getLexiconEntries(authToken, lexiconId) { /** * Récupère toutes les graphies présentes dans tous les lexiques de l'utilisateur. - * (basé sur l'endpoint /api/lexicon/search + /api/lexicon/entries/{id}) - * - * @param {string} authToken - Le token d'authentification. - * @returns {Promise<Object>} - Un objet dont les clés sont les noms de lexiques - * et la valeur un tableau de leurs graphies. */ async function getAllLexiconWords(authToken) { const searchUrl = "https://babalex.lezinter.net/api/lexicon/search" @@ -185,15 +146,12 @@ async function getAllLexiconWords(authToken) { } } - // ───────────────────────────────────────────────────────────────────────────── // â–Œ Récupération de définition du Wiktionnaire // ───────────────────────────────────────────────────────────────────────────── /** * Récupère une définition du Wiktionnaire. - * @param {string} word - Le mot recherché. - * @returns {Promise<string[]>} - Tableau contenant la définition (HTML). */ async function getWiktionaryDefinition(word) { try { @@ -221,8 +179,6 @@ async function getWiktionaryDefinition(word) { // ───────────────────────────────────────────────────────────────────────────── window.callApi = callApi; -window.parseJwt = parseJwt; - window.getLexicons = getLexicons; window.getAllCategoriesLexicons = getAllCategoriesLexicons; window.getLexiconEntries = getLexiconEntries; diff --git a/background/background.js b/background/background.js index 3f0213a..e1f36c5 100644 --- a/background/background.js +++ b/background/background.js @@ -136,7 +136,6 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { if (isConnected) { await disconnectFromLexicalDB(); } else { - // Ouvre directement la page de connexion actuallyOpenLoginPage(); } break; @@ -203,15 +202,18 @@ browser.webNavigation.onCompleted.addListener(async (details) => { await new Promise(resolve => setTimeout(resolve, 3000)); await browser.tabs.executeScript(details.tabId, { code: ` - console.log("🔠Recherche du token..."); - const tokenElement = document.getElementById("accessToken"); - if (tokenElement) { - const token = tokenElement.innerText.trim(); - console.log("🔠Token détecté :", token); - browser.runtime.sendMessage({ action: "saveToken", token }); - } else { - console.error("⌠Token introuvable."); - } + (function() { + console.log("🔠Recherche du token..."); + const tokenElement = document.getElementById("accessToken") || document.getElementById("accesToken"); + if (tokenElement) { + const token = tokenElement.innerText.trim(); + console.log("🔠Token détecté :", token); + browser.runtime.sendMessage({ action: "saveToken", token }); + } else { + console.error("⌠Token introuvable."); + } + return null; + })(); ` }); } catch (error) { diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 74c9ba2..5ea40ba 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -309,33 +309,10 @@ <!-- Fenêtre modale cachée --> <div id="modalOverlay" class="modal-overlay"> <div class="modal-content"> - <span id="closeModalBtn" class="close-button" onclick="closeDefinitionPopup()">X</span> + <span id="closeModalBtn" class="close-button">X</span> <div id="modalFullText"></div> </div> </div> - <script> - function initModal() { - window.modalOverlay = document.getElementById("modalOverlay"); - window.modalFullText = document.getElementById("modalFullText"); - window.closeModalBtn = document.getElementById("closeModalBtn"); - - if (!modalOverlay || !modalFullText || !closeModalBtn) { - console.error("Les éléments modaux ne sont pas trouvés !"); - return; - } - - modalOverlay.addEventListener("click", (event) => { - if (event.target === modalOverlay) closeDefinitionPopup(); - }); - } - - if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", initModal); - } else { - initModal(); - } - </script> - </div> </div> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index c81ae6f..92718b1 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -228,6 +228,30 @@ function displayLexiconsWithCheckbox(lexicons) { }); } +function initModal() { + console.log("initModal appelé"); + const modalOverlay = document.getElementById("modalOverlay"); + const modalFullText = document.getElementById("modalFullText"); + const closeModalBtn = document.getElementById("closeModalBtn"); + + console.log("closeModalBtn =", closeModalBtn); + + if (!modalOverlay || !modalFullText || !closeModalBtn) { + console.error("Les éléments modaux ne sont pas trouvés !"); + return; + } + + closeModalBtn.addEventListener("click", () => { + console.log("clic sur closeModalBtn !"); + closeDefinitionPopup(); + }); + modalOverlay.addEventListener("click", (event) => { + if (event.target === modalOverlay) closeDefinitionPopup(); + }); +} + +document.addEventListener("DOMContentLoaded", initModal); + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Bouton de connexion/déconnexion // ───────────────────────────────────────────────────────────────────────────── @@ -236,10 +260,6 @@ async function handleAuthButtonClick() { await refreshSidebarState(); } -// ───────────────────────────────────────────────────────────────────────────── -// â–Œ Interaction avec definitions.js -// ───────────────────────────────────────────────────────────────────────────── - // ───────────────────────────────────────────────────────────────────────────── // â–Œ Réception des messages // ───────────────────────────────────────────────────────────────────────────── diff --git a/definitions.js b/definitions.js index 88ce36a..4bf8699 100644 --- a/definitions.js +++ b/definitions.js @@ -1,208 +1,200 @@ +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Fonctions pour récupérer/afficher les définitions +// ───────────────────────────────────────────────────────────────────────────── + const lexiconMap = new Map(); /** - * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), - * en effectuant un appel global à l'API pour le mot recherché, puis en filtrant - * les entrées pour ne conserver que celles dont le lexicon.id est présent dans la liste - * des lexiques de l'utilisateur. - * - * Retourne un tableau d'objets { source, text } où: - * - source = nom du lexique (ou "Lexique #ID") - * - text = texte de la définition - * - * @param {string} word - Le mot recherché (ex. "chat"). - * @returns {Promise<Array<{ source: string, text: string }>>} - */ +* Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), +* en effectuant un appel global à l'API pour le mot recherché, puis en filtrant +* les entrées pour ne conserver que celles dont le lexicon.id est présent dans la liste +* des lexiques de l'utilisateur. +* +* Retourne un tableau d'objets { source, text } où: +* - source = nom du lexique (ou "Lexique #ID") +* - text = texte de la définition +*/ async function fetchLexiconDefinitions(word) { - try { - console.log(`🔠Recherche des définitions de '${word}' dans les lexiques de l'utilisateur...`); - - if (!authToken) { - console.warn("Aucun token disponible, impossible de requêter l'API protégée."); - return []; - } - - // 1) Récupérer la liste complète des lexiques de l'utilisateur - const userId = 4; - const lexUrl = `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=fr`; - const lexResponse = await fetch(lexUrl, { + try { + console.log(`🔠Recherche des définitions de '${word}' dans les lexiques de l'utilisateur...`); + + if (!authToken) { + console.warn("Aucun token disponible, impossible de requêter l'API protégée."); + return []; + } + + // 1) Récupérer la liste complète des lexiques de l'utilisateur + const userId = 4; + const lexUrl = `https://babalex.lezinter.net/api/lexicon/search?user_id=${userId}&language=fr`; + const lexResponse = await fetch(lexUrl, { + headers: { Authorization: `Bearer ${authToken}` } + }); + if (!lexResponse.ok) { + throw new Error(`⌠Erreur API lors de la récupération des lexiques: ${lexResponse.statusText}`); + } + const userLexicons = await lexResponse.json(); + console.log("ðŸ—‚ï¸ Lexiques de l'utilisateur :", userLexicons); + + if (!Array.isArray(userLexicons) || userLexicons.length === 0) { + console.warn("âš ï¸ Aucun lexique trouvé pour cet utilisateur."); + return []; + } + + // Mise à jour de lexiconMap avec des libellés uniques (ajout de l'ID) + lexiconMap.clear(); + userLexicons.forEach((lex) => { + const lexiconName = + lex.category === "User" + ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"}` + : `Lexique de groupe : ${lex.group?.name || "Inconnu"}`; + lexiconMap.set(lex.id, lexiconName); + }); + console.log("📌 LexiconMap :", lexiconMap); + + // 2) Pour chaque lexique, rechercher le mot en ajoutant target_lex + const definitionsPromises = userLexicons.map(async (lex) => { + const searchUrl = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=${lex.id}`; + console.log(`🔎 Appel API pour le lexique ${lex.id} avec l'URL : ${searchUrl}`); + + const searchResponse = await fetch(searchUrl, { headers: { Authorization: `Bearer ${authToken}` } }); - if (!lexResponse.ok) { - throw new Error(`⌠Erreur API lors de la récupération des lexiques: ${lexResponse.statusText}`); + if (!searchResponse.ok) { + console.warn(`âš ï¸ Erreur pour le lexique ${lex.id} : ${searchResponse.statusText}`); + return { lexiconId: lex.id, entries: [] }; } - const userLexicons = await lexResponse.json(); - console.log("ðŸ—‚ï¸ Lexiques de l'utilisateur :", userLexicons); - - if (!Array.isArray(userLexicons) || userLexicons.length === 0) { - console.warn("âš ï¸ Aucun lexique trouvé pour cet utilisateur."); - return []; - } - - // Mise à jour de lexiconMap avec des libellés uniques (ajout de l'ID) - lexiconMap.clear(); - userLexicons.forEach((lex) => { - const lexiconName = - lex.category === "User" - ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"}` - : `Lexique de groupe : ${lex.group?.name || "Inconnu"}`; - lexiconMap.set(lex.id, lexiconName); + const entries = await searchResponse.json(); + + // Filtrage côté client : ne garder que les entrées dont entry.lexicon.id correspond exactement à lex.id + const filteredEntries = entries.filter(entry => { + if (!entry.lexicon) return false; + return Number(entry.lexicon.id) === Number(lex.id); }); - console.log("📌 LexiconMap :", lexiconMap); - - // 2) Pour chaque lexique, rechercher le mot en ajoutant target_lex - const definitionsPromises = userLexicons.map(async (lex) => { - const searchUrl = `https://babalex.lezinter.net/api/entry/search?graphy=${encodeURIComponent(word)}&language=fr&target_lex=${lex.id}`; - console.log(`🔎 Appel API pour le lexique ${lex.id} avec l'URL : ${searchUrl}`); - - const searchResponse = await fetch(searchUrl, { - headers: { Authorization: `Bearer ${authToken}` } - }); - if (!searchResponse.ok) { - console.warn(`âš ï¸ Erreur pour le lexique ${lex.id} : ${searchResponse.statusText}`); - return { lexiconId: lex.id, entries: [] }; + + console.log(`Pour le lexique ${lex.id} (${lexiconMap.get(lex.id)}), entrées filtrées :`, filteredEntries); + + return { lexiconId: lex.id, entries: filteredEntries }; + }); + + const results = await Promise.all(definitionsPromises); + + // 3) Parcourir les résultats et extraire les définitions + let allDefinitions = []; + results.forEach(result => { + const lexiconId = result.lexiconId; + const sourceName = lexiconMap.get(lexiconId) || `Lexique #${lexiconId}`; + + result.entries.forEach(entry => { + if (!entry.lexicon || Number(entry.lexicon.id) !== Number(lexiconId)) return; + + let items = entry.attributes?.Items; + if (!Array.isArray(items)) { + if (typeof items === 'object' && items !== null) { + items = Object.values(items); + } else { + return; + } } - const entries = await searchResponse.json(); - - // Filtrage côté client : ne garder que les entrées dont entry.lexicon.id correspond exactement à lex.id - const filteredEntries = entries.filter(entry => { - if (!entry.lexicon) return false; - return Number(entry.lexicon.id) === Number(lex.id); - }); - - console.log(`Pour le lexique ${lex.id} (${lexiconMap.get(lex.id)}), entrées filtrées :`, filteredEntries); - - return { lexiconId: lex.id, entries: filteredEntries }; - }); - - const results = await Promise.all(definitionsPromises); - - // 3) Parcourir les résultats et extraire les définitions - let allDefinitions = []; - results.forEach(result => { - const lexiconId = result.lexiconId; - const sourceName = lexiconMap.get(lexiconId) || `Lexique #${lexiconId}`; - - result.entries.forEach(entry => { - // Vérifier à nouveau que l'entrée appartient bien au lexique ciblé - if (!entry.lexicon || Number(entry.lexicon.id) !== Number(lexiconId)) return; - - let items = entry.attributes?.Items; - // Si items n'est pas un tableau mais est un objet, convertir en tableau - if (!Array.isArray(items)) { - if (typeof items === 'object' && items !== null) { - items = Object.values(items); - } else { - return; + + items.forEach(item => { + const definitionsArray = item.Sense?.Definitions; + if (!Array.isArray(definitionsArray)) return; + + definitionsArray.forEach(defObj => { + if (defObj.Def) { + allDefinitions.push({ + source: sourceName, + text: defObj.Def + }); } - } - - items.forEach(item => { - const definitionsArray = item.Sense?.Definitions; - if (!Array.isArray(definitionsArray)) return; - - definitionsArray.forEach(defObj => { - if (defObj.Def) { - allDefinitions.push({ - source: sourceName, - text: defObj.Def - }); - } - }); }); }); }); - - console.log("Résultat final filtré :", allDefinitions); - return allDefinitions; - } catch (error) { - console.error("⌠Erreur générale lors de la récupération des définitions :", error); - return []; - } - } + }); + console.log("Résultat final filtré :", allDefinitions); + return allDefinitions; + } catch (error) { + console.error("⌠Erreur générale lors de la récupération des définitions :", error); + return []; + } +} /** - * Récupère la définition d'un mot depuis le Wiktionnaire (fr). - * Retourne un tableau d'objets : [{ source: 'Wiktionnaire', text: '...' }] - */ +* Récupère la définition d'un mot depuis le Wiktionnaire (fr). +* Retourne un tableau d'objets : [{ source: 'Wiktionnaire', text: '...' }] +*/ async function fetchWiktionaryDefinition(word) { - try { - console.log(`🔠Requête Wiktionnaire pour "${word}"...`); - if (!word || word.trim() === "") { - throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); + try { + console.log(`🔠Requête Wiktionnaire pour "${word}"...`); + if (!word || word.trim() === "") { + throw new Error("âš ï¸ Mot vide, impossible d'envoyer la requête."); + } + const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; + const response = await fetch(wiktionaryURL); + if (!response.ok) { + throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + } + const data = await response.json(); + console.log("📖 Réponse API (Wiktionnaire) :", data); + + const pages = data.query?.pages; + const page = pages ? Object.values(pages)[0] : null; + + const definitionText = page && page.extract + ? page.extract.trim() + : "âš ï¸ Aucune définition trouvée sur le Wiktionnaire."; + + console.log("🌠Définition Wiktionnaire extraite :", definitionText); + + return [ + { + source: "Wiktionnaire", + text: definitionText } - const wiktionaryURL = `https://fr.wiktionary.org/w/api.php?action=query&format=json&origin=*&prop=extracts&explaintext=true&redirects=1&titles=${encodeURIComponent(word)}`; - const response = await fetch(wiktionaryURL); - if (!response.ok) { - throw new Error(`⌠Erreur API Wiktionnaire: ${response.statusText}`); + ]; + } catch (error) { + console.error("⌠Erreur Wiktionnaire :", error); + return [ + { + source: "Wiktionnaire", + text: "âš ï¸ Erreur lors de la récupération sur le Wiktionnaire." } - const data = await response.json(); - console.log("📖 Réponse API (Wiktionnaire) :", data); - - const pages = data.query?.pages; - const page = pages ? Object.values(pages)[0] : null; - - const definitionText = page && page.extract - ? page.extract.trim() - : "âš ï¸ Aucune définition trouvée sur le Wiktionnaire."; - - console.log("🌠Définition Wiktionnaire extraite :", definitionText); - - return [ - { - source: "Wiktionnaire", - text: definitionText - } - ]; - } catch (error) { - console.error("⌠Erreur Wiktionnaire :", error); - return [ - { - source: "Wiktionnaire", - text: "âš ï¸ Erreur lors de la récupération sur le Wiktionnaire." - } - ]; - } + ]; } - +} +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Affichage des définitions dans la barre latérale +// ───────────────────────────────────────────────────────────────────────────── const MAX_LENGTH = 200; /** - * Affiche les définitions dans la barre latérale. - * @param {Array} definitions - Tableau d'objets de la forme { source, text } - */ +* Affiche les définitions dans la barre latérale. +*/ function displayDefinitions(definitions) { console.log("📖 Affichage des définitions reçues :", definitions); if (!Array.isArray(definitions)) return; const mesLexiquesList = document.getElementById("mesLexiquesList"); const wiktionnaireList = document.getElementById("wiktionnaireList"); - - // Messages d'erreur/absence de définitions const noLexiconDefinitionsContainer = document.getElementById("noLexiconDefinitionsContainer"); const noWiktionaryDefinitionsContainer = document.getElementById("noWiktionaryDefinitionsContainer"); - // Réinitialiser les listes existantes mesLexiquesList.innerHTML = ""; wiktionnaireList.innerHTML = ""; - // Masquer les messages d'erreur dès le départ if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "none"; if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "none"; - let hasLexiconDefinitions = false; let hasWiktionaryDefinitions = false; - // Regrouper les définitions par lexique (source) const lexiconGroups = {}; definitions.forEach(({ source, text }) => { if (!source || !text) return; - - // Créer l'élément <li> pour la définition + const li = document.createElement("li"); let displayedText = text; @@ -225,7 +217,7 @@ function displayDefinitions(definitions) { li.textContent = displayedText; } - // Vérifier la source : Wiktionnaire ou Lexiques + // Vérifier la source : Wiktionnaire/Lexiques if (source === "Wiktionnaire") { wiktionnaireList.appendChild(li); hasWiktionaryDefinitions = true; @@ -238,7 +230,6 @@ function displayDefinitions(definitions) { } }); - // Créer une section pour chaque lexique Object.entries(lexiconGroups).forEach(([lexiconName, definitionItems]) => { const lexiconContainer = document.createElement("div"); lexiconContainer.className = "lexicon-section"; @@ -246,12 +237,10 @@ function displayDefinitions(definitions) { const lexiconHeader = document.createElement("div"); lexiconHeader.className = "lexicon-header"; lexiconHeader.textContent = lexiconName; - // Lorsque l'utilisateur clique sur le header, on bascule l'affichage lexiconHeader.addEventListener("click", () => { lexiconContent.classList.toggle("hidden"); }); - // Création de la liste et ajout de la classe "hidden" pour qu'elle soit masquée par défaut const lexiconContent = document.createElement("ul"); lexiconContent.className = "lexicon-content hidden"; @@ -262,71 +251,127 @@ function displayDefinitions(definitions) { mesLexiquesList.appendChild(lexiconContainer); }); - // Gestion de l'affichage des messages d'erreur si aucune définition n'est trouvée - if (!hasLexiconDefinitions) { - if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "block"; + if (!hasLexiconDefinitions && noLexiconDefinitionsContainer) { + noLexiconDefinitionsContainer.style.display = "block"; } - if (!hasWiktionaryDefinitions) { - if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "block"; + if (!hasWiktionaryDefinitions && noWiktionaryDefinitionsContainer) { + noWiktionaryDefinitionsContainer.style.display = "block"; } - // Affichage ou masquage des sections en fonction de l'existence de définitions - document.getElementById("mesLexiquesContainer").style.display = - hasLexiconDefinitions ? "block" : "none"; - document.getElementById("wiktionnaireContainer").style.display = - hasWiktionaryDefinitions ? "block" : "none"; + const mesLexiquesContainer = document.getElementById("mesLexiquesContainer"); + if (mesLexiquesContainer) { + mesLexiquesContainer.style.display = hasLexiconDefinitions ? "block" : "none"; + } + const wiktionnaireContainer = document.getElementById("wiktionnaireContainer"); + if (wiktionnaireContainer) { + wiktionnaireContainer.style.display = hasWiktionaryDefinitions ? "block" : "none"; + } } +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Gestion du popup pour afficher la définition complète du Wiktionnaire +// ───────────────────────────────────────────────────────────────────────────── function openDefinitionPopup(fullText) { - const modalOverlay = document.getElementById("modalOverlay"); - const modalFullText = document.getElementById("modalFullText"); - if (!modalFullText || !modalOverlay) { - console.error("Modal elements not found!"); - return; - } - modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; - modalOverlay.style.display = "flex"; - } - - function closeDefinitionPopup() { - const modalOverlay = document.getElementById("modalOverlay"); - const modalFullText = document.getElementById("modalFullText"); - if (!modalOverlay || !modalFullText) return; - modalOverlay.style.display = "none"; - modalFullText.innerHTML = ""; + const modalOverlay = document.getElementById("modalOverlay"); + const modalFullText = document.getElementById("modalFullText"); + if (!modalOverlay || !modalFullText) { + console.error("Modal elements not found!"); + return; } - + modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>"; + modalOverlay.style.display = "flex"; +} +/** +* Ferme le popup et nettoie le contenu +*/ +function closeDefinitionPopup() { + const modalOverlay = document.getElementById("modalOverlay"); + const modalFullText = document.getElementById("modalFullText"); + if (!modalOverlay || !modalFullText) return; + modalOverlay.style.display = "none"; + modalFullText.innerHTML = ""; +} + +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Affichage des définitions Babalex + Wiktionnaire +// ───────────────────────────────────────────────────────────────────────────── /** - * Fonction principale pour cumuler définitions API (lexiques) + Wiktionnaire, - * puis les afficher. - */ +* Récupère en parallèle : +* - les définitions des lexiques de l'utilisateur (fetchLexiconDefinitions) +* - la définition Wiktionnaire (fetchWiktionaryDefinition) +* Puis fusionne les résultats. +*/ async function combineDefinitions(word) { - console.log(`[combineDefinitions] Récupération des définitions pour "${word}"...`); - - const results = await Promise.allSettled([ - fetchLexiconDefinitions(word), - fetchWiktionaryDefinition(word) - ]); - - const lexiconDefinitions = - results[0].status === "fulfilled" ? results[0].value : []; - const wiktionaryDefinitions = - results[1].status === "fulfilled" ? results[1].value : []; - - // Fusion - const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; - - console.log("📚 [combineDefinitions] Résultat fusionné :", allDefinitions); - - // Renvoi du tableau final (sans affichage direct) : + console.log(`[combineDefinitions] Récupération des définitions pour "${word}"...`); + + const results = await Promise.allSettled([ + fetchLexiconDefinitions(word), + fetchWiktionaryDefinition(word) + ]); + + const lexiconDefinitions = + results[0].status === "fulfilled" ? results[0].value : []; + const wiktionaryDefinitions = + results[1].status === "fulfilled" ? results[1].value : []; + + const allDefinitions = [...lexiconDefinitions, ...wiktionaryDefinitions]; + + console.log("📚 [combineDefinitions] Résultat fusionné :", allDefinitions); + + return allDefinitions; +} + +/** +* Récupère et affiche toutes les définitions (lexiques + Wiktionnaire). +*/ +async function showDefinitions(word) { + console.log(`[showDefinitions] Recherche + affichage pour "${word}"...`); + + const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = "Chargement des définitions..."; + noDefinitionsContainer.style.display = "block"; + } + + try { + const allDefinitions = await combineDefinitions(word); + + console.log("[showDefinitions] Définitions récupérées :", allDefinitions); + + if (!allDefinitions || allDefinitions.length === 0) { + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = "âš ï¸ Aucune définition trouvée."; + } + return; + } + + displayDefinitions(allDefinitions); + + if (noDefinitionsContainer) { + noDefinitionsContainer.style.display = "none"; + } return allDefinitions; + + } catch (error) { + console.error("⌠[showDefinitions] Erreur : ", error); + + if (noDefinitionsContainer) { + noDefinitionsContainer.textContent = + "⌠Une erreur est survenue lors de la récupération des définitions."; + noDefinitionsContainer.style.display = "block"; + } + return []; } - +} - async function fetchDefinition(word) { +/** +* Appel direct pour récupérer les définitions d’un mot uniquement via l’API +* (sans Wiktionnaire), puis gérer l’affichage d’erreur ou non. +*/ +async function fetchDefinition(word) { console.log(`🔠Recherche de la définition pour '${word}'...`); const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); @@ -341,121 +386,65 @@ async function combineDefinitions(word) { if (!definition || definition.length === 0) { console.warn(`âš ï¸ Aucune définition trouvée pour '${word}'`); - noDefinitionsContainer.style.display = "block"; + noDefinitionsContainer.style.display = "block"; return; } - noDefinitionsContainer.style.display = "none"; + noDefinitionsContainer.style.display = "none"; } catch (error) { console.error("⌠Erreur lors de la récupération de la définition :", error); noDefinitionsContainer.style.display = "block"; } } - /** - * Affiche les lexiques où le mot sélectionné est présent. - */ +* Affiche les lexiques où le mot sélectionné est présent. +*/ function displayLexiconResults(lexicons) { - const resultDiv = document.getElementById("lexiconResult"); - if (!resultDiv) return; // Sécurité si l'élément n'existe pas - - // Vider le contenu précédent - resultDiv.innerHTML = ""; - - if (!lexicons || lexicons.length === 0) { - resultDiv.textContent = "⌠Ce mot n'est présent dans aucun lexique."; - return; - } - - // Création d'un titre pour la section - const title = document.createElement("p"); - title.innerHTML = "Ce mot est présent dans le(s) lexique(s) suivant(s) :"; - title.style.fontSize = "12px"; - resultDiv.appendChild(title); - - // Création de la liste UL - const ul = document.createElement("ul"); - ul.style.paddingLeft = "20px"; - - // Remplir la liste avec les lexiques trouvés - lexicons.forEach((lexicon) => { - if (!lexicon || !lexicon.id) { - console.warn("âš ï¸ Lexique incorrect ou ID non défini :", lexicon); - return; - } - - // Utiliser la propriété "name" reçue - const lexiconName = lexicon.name || `Lexique #${lexicon.id}`; - const li = document.createElement("li"); - li.innerHTML = `<strong>${lexiconName}</strong>`; - ul.appendChild(li); - - console.log(`✅ Lexique ajouté : ${lexiconName} (ID: ${lexicon.id})`); - }); - - // Ajouter la liste au conteneur - resultDiv.appendChild(ul); + const resultDiv = document.getElementById("lexiconResult"); + if (!resultDiv) return; + + resultDiv.innerHTML = ""; + + if (!lexicons || lexicons.length === 0) { + resultDiv.textContent = "⌠Ce mot n'est présent dans aucun lexique."; + return; } + const title = document.createElement("p"); + title.innerHTML = "Ce mot est présent dans le(s) lexique(s) suivant(s) :"; + title.style.fontSize = "12px"; + resultDiv.appendChild(title); -async function showDefinitions(word) { - console.log(`[showDefinitions] Recherche + affichage pour "${word}"...`); - - // 1) Indiquer à l’utilisateur le début du chargement - const noDefinitionsContainer = document.getElementById("noDefinitionsContainer"); - if (noDefinitionsContainer) { - noDefinitionsContainer.textContent = "Chargement des définitions..."; - noDefinitionsContainer.style.display = "block"; - } - - try { - // 2) Récupérer la liste de définitions - const allDefinitions = await combineDefinitions(word); - - console.log("[showDefinitions] Définitions récupérées :", allDefinitions); - - // 3) S’il n’y a aucune définition - if (!allDefinitions || allDefinitions.length === 0) { - if (noDefinitionsContainer) { - noDefinitionsContainer.textContent = "âš ï¸ Aucune définition trouvée."; - // on laisse afficher pour signaler qu’on n’a rien - } - return; - } - - // 4) Afficher via displayDefinitions - displayDefinitions(allDefinitions); - - // 5) Masquer le message de chargement s’il existe - if (noDefinitionsContainer) { - noDefinitionsContainer.style.display = "none"; - } - - // Eventuellement, renvoyer la liste pour un usage ultérieur - return allDefinitions; - } catch (error) { - // Gérer l’erreur si combineDefinitions lève une exception - console.error("⌠[showDefinitions] Erreur : ", error); - - if (noDefinitionsContainer) { - noDefinitionsContainer.textContent = - "⌠Une erreur est survenue lors de la récupération des définitions."; - noDefinitionsContainer.style.display = "block"; - } - // On peut renvoyer un tableau vide ou lever l’erreur - return []; + const ul = document.createElement("ul"); + ul.style.paddingLeft = "20px"; + + lexicons.forEach((lexicon) => { + if (!lexicon || !lexicon.id) { + console.warn("âš ï¸ Lexique incorrect ou ID non défini :", lexicon); + return; } - } - - - - + + const lexiconName = lexicon.name || `Lexique #${lexicon.id}`; + const li = document.createElement("li"); + li.innerHTML = `<strong>${lexiconName}</strong>`; + ul.appendChild(li); + + console.log(`✅ Lexique ajouté : ${lexiconName} (ID: ${lexicon.id})`); + }); + + resultDiv.appendChild(ul); +} + +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Utilisation des fonctions dans d'autres scripts +// ───────────────────────────────────────────────────────────────────────────── window.fetchLexiconDefinitions = fetchLexiconDefinitions; window.fetchWiktionaryDefinition = fetchWiktionaryDefinition; window.displayDefinitions = displayDefinitions; window.openDefinitionPopup = openDefinitionPopup; window.closeDefinitionPopup = closeDefinitionPopup; +window.combineDefinitions = combineDefinitions; window.showDefinitions = showDefinitions; window.fetchDefinition = fetchDefinition; window.displayLexiconResults = displayLexiconResults; -- GitLab From ca65716ddaeff20c55ec6f4ab93a6d7928b5b156 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Fri, 7 Feb 2025 21:07:14 +0100 Subject: [PATCH 28/32] Correction beug recherche dans lexiques --- definitions.js | 11 +++++-- menu_contextuel/browser_context_menu.js | 38 ++++++++++--------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/definitions.js b/definitions.js index 4bf8699..6e6fd79 100644 --- a/definitions.js +++ b/definitions.js @@ -104,7 +104,8 @@ async function fetchLexiconDefinitions(word) { if (defObj.Def) { allDefinitions.push({ source: sourceName, - text: defObj.Def + text: defObj.Def, + lexiconId: lexiconId }); } }); @@ -419,8 +420,12 @@ function displayLexiconResults(lexicons) { ul.style.paddingLeft = "20px"; lexicons.forEach((lexicon) => { - if (!lexicon || !lexicon.id) { - console.warn("âš ï¸ Lexique incorrect ou ID non défini :", lexicon); + if (!lexicon) { + console.warn("âš ï¸ Lexique incorrect :", lexicon); + return; + } + if (!lexicon.id) { + console.warn("ID non défini :", lexicon.id); return; } diff --git a/menu_contextuel/browser_context_menu.js b/menu_contextuel/browser_context_menu.js index bbaf1a6..0829ce3 100644 --- a/menu_contextuel/browser_context_menu.js +++ b/menu_contextuel/browser_context_menu.js @@ -156,31 +156,23 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { */ async function getDefinition(selectedText) { try { - // On utilise la même logique que la fonction combineDefinitions, - // mais sans modifier le DOM (car on est dans le background). - // On récupère les définitions de mes lexiques (si authToken) et du Wiktionnaire. let lexiconDefs = []; if (authToken) { lexiconDefs = await fetchLexiconDefinitions(selectedText); } const wiktionaryDef = await fetchWiktionaryDefinition(selectedText); - // Dans definitions.js, fetchWiktionaryDefinition renvoie un string (ou un message d’erreur). - // Pour l'uniformiser, on le place dans un tableau [{ source: "Wiktionnaire", text: ... }] + let wikiDefs = []; if (wiktionaryDef && typeof wiktionaryDef === "string") { - // On vérifie si c’est un message d'erreur ou pas if (!wiktionaryDef.startsWith("âš ï¸")) { wikiDefs.push({ source: "Wiktionnaire", text: wiktionaryDef }); } } - // Combinaison const allDefinitions = [...lexiconDefs, ...wikiDefs]; - console.log("📠Définitions combinées :", allDefinitions); - // Envoyer les définitions à la sidebar (ou autre) pour affichage browser.runtime.sendMessage({ action: "showDefinitions", selectedText, @@ -200,10 +192,8 @@ async function searchInLexicons(selectedText) { try { console.log("🔎 Recherche dans mes lexiques :", selectedText); - // Récupère toutes les définitions, triées par lexique const allDefinitions = await fetchLexiconDefinitions(selectedText); if (!allDefinitions || allDefinitions.length === 0) { - // Rien trouvé console.log("⌠Aucun lexique trouvé pour ce mot."); browser.runtime.sendMessage({ action: "showLexiconResult", @@ -213,18 +203,23 @@ async function searchInLexicons(selectedText) { return; } - // On récupère la liste unique des sources (lexiques) trouvées - // (ex: "Lexique personnel : Alice", "Lexique de groupe : Francophiles", etc.) - const uniqueSources = [...new Set(allDefinitions.map((d) => d.source))]; + // On veut regrouper par lexiconId => name + // => On suppose que each definition = { source, text, lexiconId } + const lexMap = new Map(); + for (const def of allDefinitions) { + if (def.lexiconId) { + lexMap.set(def.lexiconId, def.source); + } + } - // On construit un tableau d'objets { name: "Nom du lexique" } - // (L'ID n'est pas directement renvoyé par fetchLexiconDefinitions, à moins de l’ajouter.) - const foundInLexicons = uniqueSources.map((src) => ({ - // On ne sait pas forcément l’ID, on affiche le nom en l’état - name: src, - })); + // Transformer en tableau { id, name } + const foundInLexicons = []; + for (const [id, name] of lexMap.entries()) { + foundInLexicons.push({ id, name }); + } console.log("📩 Envoi du message 'showLexiconResult' avec :", foundInLexicons); + browser.runtime.sendMessage({ action: "showLexiconResult", lexicons: foundInLexicons, @@ -248,9 +243,6 @@ async function searchInLexicons(selectedText) { async function addWordToLexicon(selectedText) { try { console.log("🔠Ajout du mot à mon lexique :", selectedText); - // À adapter selon votre API. - // Exemple d’endpoint hypothétique : POST /api/entry/create?lexicon_id=123 - // ... alert(`(Exemple) Le mot "${selectedText}" a été ajouté à votre lexique personnel !`); } catch (error) { console.error("⌠Erreur lors de l'ajout au lexique :", error); -- GitLab From 65f1b34833b72924d1ffaa15031054cc77620593 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Fri, 7 Feb 2025 21:40:56 +0100 Subject: [PATCH 29/32] =?UTF-8?q?Am=C3=A9lioration=20affichage=20barre=20l?= =?UTF-8?q?at=C3=A9rale=20lexiques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.js" | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 92718b1..52b3130 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -271,18 +271,22 @@ browser.runtime.onMessage.addListener(async (message) => { await refreshSidebarState(); break; - case "mot_selectionne": - if (message.selectedText) { - console.log("ðŸ–‹ï¸ Mot sélectionné :", message.selectedText); - const selectedWordElement = document.getElementById("motSelectionne"); - if (selectedWordElement) { - selectedWordElement.textContent = message.selectedText; + case "mot_selectionne": + if (message.selectedText) { + console.log("ðŸ–‹ï¸ Mot sélectionné :", message.selectedText); + const selectedWordElement = document.getElementById("motSelectionne"); + if (selectedWordElement) { + selectedWordElement.textContent = message.selectedText; + } else { + console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); + } + const lexiconResultElement = document.getElementById("lexiconResult"); + if (lexiconResultElement) { + lexiconResultElement.innerHTML = ""; + } openBlock("etatContent"); - } else { - console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); } - } - break; + break; case "getDefinition": if (message.selectedText) { -- GitLab From 6f41a84edbd90ffe61431a78a1e9bda6677442d9 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 10:42:22 +0100 Subject: [PATCH 30/32] =?UTF-8?q?Correction=20rafra=C3=AEchissement=20barr?= =?UTF-8?q?e=20lat=C3=A9rale=20d=C3=A9connexion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.js" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 52b3130..f9b54e3 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -91,6 +91,10 @@ async function refreshSidebarState() { if (lexiquesContainer) { lexiquesContainer.textContent = "Veuillez vous connecter pour voir vos lexiques."; } + const lexiconResultElement = document.getElementById("lexiconResult"); + if (lexiconResultElement) { + lexiconResultElement.innerHTML = ""; + } } console.log("✅ Barre latérale actualisée. Utilisateur connecté :", isLoggedIn); -- GitLab From e03750a9b0cec9852494cc2495366c4ff24f7978 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 10:52:20 +0100 Subject: [PATCH 31/32] =?UTF-8?q?Style=20messages=20barre=20lat=C3=A9rale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.js" | 2 ++ definitions.js | 7 +++++++ 2 files changed, 9 insertions(+) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index f9b54e3..b920188 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -90,6 +90,8 @@ async function refreshSidebarState() { const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { lexiquesContainer.textContent = "Veuillez vous connecter pour voir vos lexiques."; + lexiquesContainer.style.textAlign = "center"; + lexiquesContainer.style.fontStyle = "italic"; } const lexiconResultElement = document.getElementById("lexiconResult"); if (lexiconResultElement) { diff --git a/definitions.js b/definitions.js index 6e6fd79..0e22bff 100644 --- a/definitions.js +++ b/definitions.js @@ -253,6 +253,13 @@ function displayDefinitions(definitions) { }); if (!hasLexiconDefinitions && noLexiconDefinitionsContainer) { + if (!authToken) { + noLexiconDefinitionsContainer.textContent = "Veuillez vous connecter pour accéder aux définitions de vos lexiques."; + noLexiconDefinitionsContainer.style.textAlign = "center"; + noLexiconDefinitionsContainer.style.fontStyle = "italic"; + } else { + noLexiconDefinitionsContainer.textContent = "Aucune définition trouvée dans les lexiques."; + } noLexiconDefinitionsContainer.style.display = "block"; } if (!hasWiktionaryDefinitions && noWiktionaryDefinitionsContainer) { -- GitLab From 9869fa75ca460f945cad48a53642e4a86a0d156d Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 11:12:06 +0100 Subject: [PATCH 32/32] Correction def Wiktionnaire menu contextuel navigateur --- menu_contextuel/browser_context_menu.js | 38 +++---------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/menu_contextuel/browser_context_menu.js b/menu_contextuel/browser_context_menu.js index 0829ce3..a2ba1fa 100644 --- a/menu_contextuel/browser_context_menu.js +++ b/menu_contextuel/browser_context_menu.js @@ -1,9 +1,5 @@ console.log("browser_context_menu.js chargé correctement"); -// ───────────────────────────────────────────────────────────────────────────── -// Variable globale qui contient le token pour les requêtes API -// (Utilisée par fetchLexiconDefinitions, etc.) -// ───────────────────────────────────────────────────────────────────────────── let authToken = null; /** @@ -23,7 +19,6 @@ async function loadAuthToken() { // Création du menu contextuel en fonction de l'authentification // ───────────────────────────────────────────────────────────────────────────── async function createContextMenu() { - // Supprime tous les items existants afin de recréer le menu complet await browser.contextMenus.removeAll(); if (authToken) { @@ -44,7 +39,6 @@ async function createContextMenu() { }); } - // Séparateur browser.contextMenus.create({ id: "separatorExtension", type: "separator", @@ -59,14 +53,12 @@ async function createContextMenu() { icons: { "16": "icons/definition.png" }, }); - // Séparateur browser.contextMenus.create({ id: "separatorAfterExtension", type: "separator", contexts: ["all"], }); - // Item de connexion/déconnexion browser.contextMenus.create({ id: "login", title: authToken ? "Se déconnecter de BaLex" : "Se connecter à BaLex", @@ -74,10 +66,8 @@ async function createContextMenu() { }); } -// Charger le token au démarrage puis créer le menu contextuel loadAuthToken().then(createContextMenu); -// Listener pour mettre à jour le menu quand un message "refreshUI" est reçu browser.runtime.onMessage.addListener((message) => { if (message.action === "refreshUI") { console.log("🔄 refreshUI reçu dans browser_context_menu.js"); @@ -85,7 +75,6 @@ browser.runtime.onMessage.addListener((message) => { } }); -// Quand le token change dans le storage browser.storage.onChanged.addListener((changes, area) => { if (area === "local" && changes.accessToken) { console.log("🔄 Token modifié, actualisation du menu contextuel."); @@ -94,12 +83,11 @@ browser.storage.onChanged.addListener((changes, area) => { }); // ───────────────────────────────────────────────────────────────────────────── -// GESTION DES CLICS SUR LE MENU CONTEXTUEL +// Gestion des clics sur le menu contextuel // ───────────────────────────────────────────────────────────────────────────── browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log("Item de menu cliqué :", info.menuItemId); - // Cas de l’item login/déconnexion if (info.menuItemId === "login") { console.log("🔄 Action login/déconnexion demandée."); if (typeof actuallyOpenLoginPage === "function") { @@ -110,14 +98,12 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { return; } - // Les items ci-dessous nécessitent un texte sélectionné if (!info.selectionText) { console.warn("Aucun texte sélectionné pour cette action :", info.menuItemId); return; } console.log(`📩 Texte sélectionné : ${info.selectionText}`); - // Rediriger vers la fonction appropriée switch (info.menuItemId) { case "searchInLexicons": if (!authToken) { @@ -136,8 +122,6 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { break; case "getDefinition": - // Pas forcément besoin d'être connecté, car on peut récupérer - // la définition via Wiktionnaire même sans authToken. await getDefinition(info.selectionText); break; @@ -147,12 +131,12 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { }); // ───────────────────────────────────────────────────────────────────────────── -// FONCTIONS ADAPTÉES AUX NOUVELLES APPELS DE definitions.js +// Fonctions liées aux définitions (definitions.js) // ───────────────────────────────────────────────────────────────────────────── /** * 1) Recherche de la définition combinée (lexiques + Wiktionnaire) - * et envoi des résultats à la sidebar (ou autre script) pour affichage. + * et envoi des résultats pour affichage. */ async function getDefinition(selectedText) { try { @@ -161,14 +145,7 @@ async function getDefinition(selectedText) { lexiconDefs = await fetchLexiconDefinitions(selectedText); } - const wiktionaryDef = await fetchWiktionaryDefinition(selectedText); - - let wikiDefs = []; - if (wiktionaryDef && typeof wiktionaryDef === "string") { - if (!wiktionaryDef.startsWith("âš ï¸")) { - wikiDefs.push({ source: "Wiktionnaire", text: wiktionaryDef }); - } - } + const wikiDefs = await fetchWiktionaryDefinition(selectedText); const allDefinitions = [...lexiconDefs, ...wikiDefs]; console.log("📠Définitions combinées :", allDefinitions); @@ -185,8 +162,6 @@ async function getDefinition(selectedText) { /** * 2) Recherche dans les lexiques pour savoir dans quels lexiques se trouve le mot. - * On utilise fetchLexiconDefinitions pour récupérer les définitions - * et déduire ainsi les lexiques (source). */ async function searchInLexicons(selectedText) { try { @@ -203,8 +178,6 @@ async function searchInLexicons(selectedText) { return; } - // On veut regrouper par lexiconId => name - // => On suppose que each definition = { source, text, lexiconId } const lexMap = new Map(); for (const def of allDefinitions) { if (def.lexiconId) { @@ -212,7 +185,6 @@ async function searchInLexicons(selectedText) { } } - // Transformer en tableau { id, name } const foundInLexicons = []; for (const [id, name] of lexMap.entries()) { foundInLexicons.push({ id, name }); @@ -237,8 +209,6 @@ async function searchInLexicons(selectedText) { /** * 3) Ajouter un mot dans le lexique personnel. - * Cette partie n’existe pas (encore) dans definitions.js, - * donc on la conserve ou on l’adapte si vous avez un endpoint pour ça. */ async function addWordToLexicon(selectedText) { try { -- GitLab