Skip to content
Snippets Groups Projects
definitions.js 21.25 KiB
// ─────────────────────────────────────────────────────────────────────────────
// ▌ Récupération des définitions (lexiques + Wiktionnaire)
// ─────────────────────────────────────────────────────────────────────────────

window.lexiconMap = new Map();

/**
 * Récupère les définitions d'un mot dans les lexiques de l'utilisateur.
 * @param {string} word - Le mot dont on veut les définitions.
 * @returns {Promise<object[]>} - Un tableau d'objets contenant les définitions.
 */
async function fetchLexiconDefinitions(word) {
  try {
    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 lexUrl = `https://babalex.lezinter.net/api/lexicon/search?`;
    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();
    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);
    });
    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}`;
      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);
      });

      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 => {
      log(`Pour le lexique ${result.lexiconId}, entrées filtrées :`, result.entries);
      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;
          }
        }

        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,
                lexiconId: lexiconId
              });
            }
          });
        });
      });
    });

    log("Résultat final filtré :", allDefinitions);
    return allDefinitions;
  } catch (error) {
    log("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: '...' }]
 * @param {string} word - Le mot dont on veut la définition.
 * @returns {Promise<object[]>} - Un tableau d'objets contenant la définition.
 */
async function fetchWiktionaryDefinition(word) {
  try {
    const result = await browser.storage.local.get("accessToken");
    authToken = result.accessToken;

    if (!authToken) {
      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();
      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.";

      log("Définition Wiktionnaire extraite :", definitionText);

      return [
        {
          source: "Wiktionnaire",
          text: definitionText
        }
      ];
    } else {
      log(` Recherche de la définition pour : ${word}`);

      // Récupération des données depuis l'API
      const apiResponse = await wikiApiResponse(word);
      log("Réponse brute de l'API :", apiResponse);

      if (!Array.isArray(apiResponse) || apiResponse.length === 0) {
          console.warn(`Aucune définition trouvée pour "${word}"`);
          return [];  // Retourne un tableau vide si aucune définition
      }

      // Formatage des données
      const formattedData = formatDefinitionData(apiResponse);
      log("Données formatées :", formattedData);

      return [
          {
              source: "Wiktionnaire",
              text: formattedData.definitions.length > 0 ? formattedData.definitions.join(" | ") : "⚠️ Aucune définition disponible."
          }
      ];
    }
  } catch (error) {
    log("Erreur lors de la récupération de la définition :", error);
    return [{ source: "Wiktionnaire", text: "Erreur lors de la récupération sur le Wiktionnaire." }];
  }
}

/**
 * Récupère la définition d'un mot depuis l'API de BaLex (Wiktionnaire).
 * @param {string} word - Le mot dont on veut la définition.
 * @returns {Promise<object[]>} - Un tableau d'objets contenant la réponse de l'API.
 */
async function wikiApiResponse(word) {
  const result = await browser.storage.local.get("accessToken");
  authToken = result.accessToken;
  // 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`;

  try {
    const response = await fetch(wiktionaryApiUrl, {
      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 depuis le Wiktionnaire : ${response.statusText}`);
    }
    
    const data = await response.json();
    log(`Résultats du Wiktionnaire pour le mot "${word}" :`, data);
    return data;
  } catch (error) {
    log('Erreur lors de la récupération de la définition depuis le Wiktionnaire :', error);
    throw error; 
  }
}

/**
 * Formate les données de la réponse de l'API de BaLex (Wiktionnaire).
 * @param {object[]} apiResponse - La réponse de l'API de BaLex (Wiktionnaire).
 * @returns {object} - Un objet contenant les données formatées.
 */
function formatDefinitionData(apiResponse) {
  let formattedData = {
      word: apiResponse[0]?.id.split("-").slice(2).join("-") || "",
      pronunciations: [],
      definitions: [],
      examples: [],
      translations: {},
  };

  apiResponse.forEach(entry => {
      const wordData = entry[entry.id.split(".").slice(-1)[0]]; // Accéder aux données via la clé dynamique

      // Ajout des prononciations
      if (wordData.pronunciations) {
          formattedData.pronunciations.push(...wordData.pronunciations);
      }

      // Ajout des définitions
      if (wordData.senses) {
          for (let senseKey in wordData.senses) {
              let sense = wordData.senses[senseKey];
              if (sense.Definitions) {
                  formattedData.definitions.push(...sense.Definitions.map(d => d.definition));
              }
              if (sense.Examples) {
                  formattedData.examples.push(...sense.Examples.map(e => e.example));
              }
          }
      }

      // Ajout des traductions
      if (entry.translations) {
          entry.translations.forEach(translation => {
              if (!formattedData.translations[translation.lang_name]) {
                  formattedData.translations[translation.lang_name] = [];
              }
              formattedData.translations[translation.lang_name].push(translation.sense);
          });
      }
  });

  return formattedData;
}

// ─────────────────────────────────────────────────────────────────────────────
// ▌ Affichage des définitions dans la barre latérale (lexiques + Wiktionnaire)
// ─────────────────────────────────────────────────────────────────────────────

const MAX_LENGTH = 200;

/**
 * Affiche les définitions dans la barre latérale.
 * @param {object[]} definitions - Les définitions à afficher.
 */
function displayDefinitions(definitions) {
  log("Affichage des définitions reçues :", definitions);
  if (!Array.isArray(definitions)) return;

  const mesLexiquesList = document.getElementById("mesLexiquesList");
  const wiktionnaireList = document.getElementById("wiktionnaireList");
  const noLexiconDefinitionsContainer = document.getElementById("noLexiconDefinitionsContainer");
  const noWiktionaryDefinitionsContainer = document.getElementById("noWiktionaryDefinitionsContainer");

  mesLexiquesList.innerHTML = "";
  wiktionnaireList.innerHTML = "";

  if (noLexiconDefinitionsContainer) noLexiconDefinitionsContainer.style.display = "none";
  if (noWiktionaryDefinitionsContainer) noWiktionaryDefinitionsContainer.style.display = "none";
  let hasLexiconDefinitions = false;
  let hasWiktionaryDefinitions = false;

  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) + "... ";
      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/Lexiques
    if (source === "Wiktionnaire") {
      wiktionnaireList.appendChild(li);
      hasWiktionaryDefinitions = true;
    } else {
      if (!lexiconGroups[source]) {
        lexiconGroups[source] = [];
      }
      lexiconGroups[source].push(li);
      hasLexiconDefinitions = true;
    }
  });

  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;
    lexiconHeader.addEventListener("click", () => {
      lexiconContent.classList.toggle("hidden");
    });

    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);
  });

  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) {
    noWiktionaryDefinitionsContainer.style.display = "block";
  }

  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";
  }
}

/**
 * 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) {
  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];

  log("[combineDefinitions] Résultat fusionné :", allDefinitions);

  return allDefinitions;
}

/**
 * Récupère et affiche toutes les définitions (lexiques + Wiktionnaire).
 * @param {string} word - Le mot dont on veut les définitions.
 */
async function showDefinitions(word) {
  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);

    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) {
    log("[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 [];
  }
}

/**
 * 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.
 * @param {string} word - Le mot dont on veut la définition.
 */
async function fetchDefinition(word) {
  log(`🔍 Recherche de la définition pour '${word}'...`);

  const noDefinitionsContainer = document.getElementById("noDefinitionsContainer");
  if (!noDefinitionsContainer) {
    log("Élément #noDefinitionsContainer introuvable.");
    return;
  }

  try {
    const definition = await fetchLexiconDefinitions(word);
    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) {
    log("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.
 * @param {object[]} lexicons - Les lexiques où le mot est présent.
*/
function displayLexiconResults(lexicons) {
  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);

  const ul = document.createElement("ul");
  ul.style.paddingLeft = "20px";

  lexicons.forEach((lexicon) => {
    if (!lexicon) {
      console.warn("⚠️ Lexique incorrect :", lexicon);
      return;
    }
    if (!lexicon.id) {
      console.warn("ID non défini :", lexicon.id);
      return;
    }

    const lexiconName = lexicon.name || `Lexique #${lexicon.id}`;
    const li = document.createElement("li");
    li.innerHTML = `<strong>${lexiconName}</strong>`;
    ul.appendChild(li);

    log(`✅ Lexique ajouté : ${lexiconName} (ID: ${lexicon.id})`);
  });

  resultDiv.appendChild(ul);
}

// ─────────────────────────────────────────────────────────────────────────────
// ▌ Gestion de la boîte modale pour afficher la définition complète du Wiktionnaire
// ─────────────────────────────────────────────────────────────────────────────
/**
 * Ouvre la boîte modale pour afficher la définition complète du Wiktionnaire.
 * @param {string} fullText - La définition complète du mot.
 */
function openDefinitionPopup(fullText) {
  const modalOverlay = document.getElementById("modalOverlay");
  const modalFullText = document.getElementById("modalFullText");
  if (!modalOverlay || !modalFullText) {
    log("Modal elements not found!");
    return;
  }
  modalFullText.innerHTML = "<p>" + fullText.replace(/\n/g, "<br>") + "</p>";
  modalOverlay.style.display = "flex";
}

/**
 * Ferme la boîte modale et nettoie le contenu
 * @returns {void}
 */
function closeDefinitionPopup() {
  const modalOverlay = document.getElementById("modalOverlay");
  const modalFullText = document.getElementById("modalFullText");
  if (!modalOverlay || !modalFullText) return;
  modalOverlay.style.display = "none";
  modalFullText.innerHTML = "";
}

// ─────────────────────────────────────────────────────────────────────────────
// ▌ Exposition des fonctions pour un usage global
// ─────────────────────────────────────────────────────────────────────────────

window.fetchLexiconDefinitions = fetchLexiconDefinitions;
window.fetchWiktionaryDefinition = fetchWiktionaryDefinition;
window.wikiApiResponse = wikiApiResponse;
window.formatDefinitionData = formatDefinitionData;
window.displayDefinitions = displayDefinitions;
window.combineDefinitions = combineDefinitions;
window.showDefinitions = showDefinitions;
window.fetchDefinition = fetchDefinition;
window.displayLexiconResults = displayLexiconResults;
window.openDefinitionPopup = openDefinitionPopup;
window.closeDefinitionPopup = closeDefinitionPopup;