diff --git a/src/assets/lexicon_icon.js b/src/assets/lexicon_icon.js index 2929fee20b3bb9437f34227045be257e7495b4a9..69833f84f9b59c886cdb7dece3627b8633610786 100644 --- a/src/assets/lexicon_icon.js +++ b/src/assets/lexicon_icon.js @@ -1,49 +1,101 @@ + +/** + * Récupère les couleurs des lexiques de l’utilisateur. + * Chaque lexique est censé posséder une propriété "rGB" contenant la couleur, par exemple "65, 148, 84". + * + * @param {string} authToken - Le token d'authentification. + * @returns {Promise<Object>} - Un objet associant l'ID du lexique à sa couleur. + */ +async function getLexiconsColors(authToken) { + const url = "https://babalex.lezinter.net/api/lexicon/search"; + + try { + const lexicons = await callApi(url, authToken); + const colors = {}; + lexicons.forEach(lexicon => { + colors[lexicon.id] = lexicon.rGB; + }); + + log("✅ Couleurs des lexiques récupérées :", colors); + return colors; + } catch (error) { + console.error("⌠Erreur lors de la récupération des couleurs des lexiques :", error); + return {}; + } +} + +/** + * Convertit une chaîne de caractères "rGB" (ex: "65, 148, 84") en couleur hexadécimale. + * @param {string} rgbString - La chaîne "rGB". + * @returns {string} La couleur au format hexadécimal. + */ +function convertColor(rgbString) { + const parts = rgbString.split(',').map(part => parseInt(part.trim(), 10)); + // if (parts.length !== 3 || parts.some(isNaN)) { + // return generateRandomColor(); + // } + return "#" + parts.map(n => n.toString(16).padStart(2, '0')).join(''); +} + /** * Sélectionne aléatoirement une couleur dans une palette prédéfinie. * @returns {string} Une couleur au format hexadécimal ou HSL. */ -function generateRandomColor() { - const palette = [ - "#231942", - "#5E548E", - "#9F86C0", - "#BE95C4", - "#E0B1CB", - "#b7094c", - "#a01a58", - "#892b64", - "#723c70", - "#5b4d7c", - "#455e89", - "#2e6f95", - "#1780a1", - "#0091ad", - "#30343f", - "#e4d9ff", - "#273469", - "#1e2749" - ]; - const index = Math.floor(Math.random() * palette.length); - return palette[index]; -} +// function generateRandomColor() { +// const palette = [ +// "#231942", +// "#5E548E", +// "#9F86C0", +// "#BE95C4", +// "#E0B1CB", +// "#b7094c", +// "#a01a58", +// "#892b64", +// "#723c70", +// "#5b4d7c", +// "#455e89", +// "#2e6f95", +// "#1780a1", +// "#0091ad", +// "#30343f", +// "#e4d9ff", +// "#273469", +// "#1e2749" +// ]; +// const index = Math.floor(Math.random() * palette.length); +// return palette[index]; +// } /** * Obtient (ou crée) la couleur associée à un lexique donné en utilisant browser.storage.local. * @param {string|number} lexiconId - L'identifiant du lexique. * @returns {Promise<string>} La couleur associée au lexique. */ -async function getOrCreateLexiconColor(lexiconId, forceReset = false) { +async function getOrCreateLexiconColor(lexiconId) { // Récupère la correspondance stockée dans storage let { lexiconColors } = await browser.storage.local.get("lexiconColors"); if (!lexiconColors || forceReset) { lexiconColors = {}; } - // Si aucune couleur n'est associée à ce lexiconId, on la génère et on la sauvegarde - if (!lexiconColors[lexiconId]) { - lexiconColors[lexiconId] = generateRandomColor(); - await browser.storage.local.set({ lexiconColors }); + if (window.authToken) { + try { + const apiColors = await window.getLexiconsColors(window.authToken); + // Pour chaque lexique récupéré depuis l'API, on convertit la couleur rGB en hexadécimal + for (const id in apiColors) { + if (Object.prototype.hasOwnProperty.call(apiColors, id)) { + lexiconColors[id] = convertColor(apiColors[id]); + } + } + } catch (error) { + console.error("Erreur lors de la récupération des couleurs via l'API :", error); + } } - return lexiconColors[lexiconId]; + // Si aucune couleur n'est associée, on la génère et on la sauvegarde + // if (!lexiconColors[lexiconId]) { + // lexiconColors[lexiconId] = generateRandomColor(); + // await browser.storage.local.set({ lexiconColors }); + // } + return lexiconColors[String(lexiconId)]; } /** @@ -63,7 +115,44 @@ function createColorCircle(color, size = 32) { return circle; } -window.generateRandomColor = generateRandomColor; +/** + * Récupère et met à jour les couleurs des lexiques dans le stockage local. + * @param {string} authToken - Le token d'authentification. + * @returns {Promise<Object>} La map des couleurs associant chaque ID de lexique à sa couleur hexadécimale. + */ +async function updateLexiconColors(authToken) { + try { + const apiColors = await getLexiconsColors(authToken); + const colorMapping = {}; + for (const id in apiColors) { + if (Object.prototype.hasOwnProperty.call(apiColors, id)) { + colorMapping[id] = convertColor(apiColors[id]); + } + } + log("✅ Mise à jour des couleurs des lexiques :", colorMapping); + await browser.storage.local.set({ lexiconColors: colorMapping }); + return colorMapping; + } catch (error) { + console.error("⌠Erreur lors de la mise à jour des couleurs :", error); + return {}; + } +} + +/** + * Récupère la couleur associée à un lexique depuis le stockage local. + * @param {string|number} lexiconId - L'identifiant du lexique. + * @returns {Promise<string>} La couleur en hexadécimal ou une couleur par défaut. + */ +async function getColorForLexicon(lexiconId) { + const { lexiconColors } = await browser.storage.local.get("lexiconColors"); + return (lexiconColors && lexiconColors[String(lexiconId)]) || "#cccccc"; +} + +window.updateLexiconColors = updateLexiconColors; +window.getColorForLexicon = getColorForLexicon; +// window.generateRandomColor = generateRandomColor; +window.convertColor = convertColor; window.getOrCreateLexiconColor = getOrCreateLexiconColor; window.createColorCircle = createColorCircle; +window.getLexiconsColors = getLexiconsColors; diff --git a/src/context_menu/custom_context_menu.css b/src/context_menu/custom_context_menu.css index 85266a6fe26e17726121f05af2c55806ce17fde6..622a8c6865d8805123fe9eb8bf0a86a4f6117267 100644 --- a/src/context_menu/custom_context_menu.css +++ b/src/context_menu/custom_context_menu.css @@ -90,7 +90,7 @@ padding: 4px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - width: 150px; + width: auto; font-family: Luciole; font-size: 10px; display: flex; diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index 196275fe3b83c088f35703061812cbf19014e8d0..271e490e8262ce1b1c5b9a2fdb6f35ccb80a0e1a 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -225,41 +225,6 @@ browser.storage.onChanged.addListener((changes) => { // ───────────────────────────────────────────────────────────────────────────── // Fonctions d'API pour l'ajout d'un mot via le sélecteur // ───────────────────────────────────────────────────────────────────────────── - -/** - * Crée (ou récupère) le sélecteur des lexiques. - */ -function createPicker() { - let picker = document.getElementById("lexiconPicker"); - if (!picker) { - picker = document.createElement("div"); - picker.id = "lexiconPicker"; - picker.style.position = "absolute"; - picker.style.zIndex = "10000"; - picker.style.backgroundColor = "rgba(255, 255, 255, 0.98)"; - picker.style.border = "1px solid #ddd"; - picker.style.padding = "8px"; - picker.style.borderRadius = "8px"; - picker.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.1)"; - picker.style.width = "220px"; - picker.style.fontFamily = "Luciole"; - picker.style.fontSize = "10px"; - picker.style.display = "flex"; - picker.style.flexDirection = "row"; - picker.style.flexWrap = "wrap"; - picker.style.alignItems = "center"; - picker.style.justifyContent = "center"; - picker.style.gap = "5px"; - - picker.addEventListener("mouseup", (e) => { - e.stopPropagation(); - }); - - document.body.appendChild(picker); - } - return picker; -} - /** * Affiche le sélecteur pour choisir le lexique dans lequel ajouter le mot. */ @@ -268,14 +233,14 @@ async function showPicker(event, selectedText) { if (!picker) { picker = document.createElement("div"); picker.id = "lexiconPicker"; + picker.addEventListener("mouseup", (e) => e.stopPropagation()); document.body.appendChild(picker); } - picker.innerHTML = ""; - + picker.innerHTML = ""; const selectedLexicons = new Set(); try { - const lexicons = await getLexicons(authToken, "fr"); + const lexicons = await getLexicons(authToken); log("Lexicons récupérés :", lexicons); if (!Array.isArray(lexicons) || lexicons.length === 0) { @@ -286,9 +251,10 @@ async function showPicker(event, selectedText) { const name = lex.category === "User" ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; - - const color = await getOrCreateLexiconColor(id); - const circleIcon = createColorCircle(color, 28); + + const color = await getColorForLexicon(id); + const circleIcon = await createColorCircle(color, 28); + const iconContainer = document.createElement("div"); iconContainer.className = "lexicon-option"; iconContainer.dataset.lexiconId = id; @@ -309,22 +275,18 @@ async function showPicker(event, selectedText) { const confirmButton = document.createElement("button"); confirmButton.className = "confirmButton"; confirmButton.textContent = "Ajouter le mot"; - confirmButton.addEventListener("click", async () => { if (selectedLexicons.size === 0) { alert("Veuillez sélectionner au moins un lexique."); return; } - log(`🔠Vérification si le mot "${selectedText}" existe déjà dans les lexiques sélectionnés...`); - let definitions = []; try { definitions = await fetchLexiconDefinitions(selectedText); } catch (error) { console.error("Erreur lors de la récupération des définitions :", error); } - const existingLexiconIds = new Set(); if (Array.isArray(definitions)) { for (const def of definitions) { @@ -333,25 +295,20 @@ async function showPicker(event, selectedText) { } } } - if (existingLexiconIds.size > 0) { alert(`âš ï¸ Le mot "${selectedText}" existe déjà dans les lexiques suivants : ${Array.from(existingLexiconIds).join(", ")}`); } - const lexiconsToAdd = [...selectedLexicons].filter(id => !existingLexiconIds.has(id)); if (lexiconsToAdd.length === 0) { alert(`✅ Le mot "${selectedText}" est déjà présent dans tous les lexiques sélectionnés.`); return; } - try { log(`📡 Ajout du mot "${selectedText}" dans les lexiques :`, lexiconsToAdd); const result = await AddWord(authToken, selectedText, lexiconsToAdd, false); log("Réponse API :", result); - await new Promise(resolve => setTimeout(resolve, 300)); browser.runtime.sendMessage({ action: "refreshUI" }); - picker.innerHTML = `<p style="color: green;">✅ Mot ajouté avec succès dans : ${lexiconsToAdd.join(", ")}.</p>`; setTimeout(() => picker.style.display = "none", 2000); browser.runtime.sendMessage({ @@ -368,10 +325,14 @@ async function showPicker(event, selectedText) { }); } }); - picker.appendChild(confirmButton); } + const lexiconCount = Array.isArray(lexicons) ? lexicons.length : 0; + const baseWidthPerLexicon = 40; + const extraPadding = 20; + const calculatedWidth = lexiconCount * baseWidthPerLexicon + extraPadding; + picker.style.width = calculatedWidth + "px"; picker.style.left = event.pageX + "px"; picker.style.top = event.pageY + "px"; picker.style.display = "flex"; diff --git a/src/sidebar/sidebar.js b/src/sidebar/sidebar.js index 99af50fb4c7e71673512d59cb41a95558beed4a7..652a75bce876540b9166e16b9fb55c6f7997b117 100644 --- a/src/sidebar/sidebar.js +++ b/src/sidebar/sidebar.js @@ -86,6 +86,10 @@ async function refreshSidebarState() { toggleHighlightMessage(isLoggedIn); if (isLoggedIn) { + if (!window.lexiconColorsUpdated) { + await updateLexiconColors(authToken); + window.lexiconColorsUpdated = true; + } await fetchLexicons(); } else { // Si l'utilisateur n'est pas connecté, on ferme tous les blocs @@ -190,8 +194,8 @@ async function fetchLexicons() { if (!authToken) { throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); } - log("getLexicons type:", typeof getLexicons); - const lexicons = await getLexicons(authToken, "fr"); + + const lexicons = await getLexicons(authToken); log("📚 Réponse brute de l'API :", lexicons); if (!Array.isArray(lexicons) || lexicons.length === 0) { @@ -200,18 +204,25 @@ async function fetchLexicons() { 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})`; + let lexiconName = ""; + if (lex.category === "User") { + lexiconName = `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})`; + if (lex.language) { + lexiconName += ` [${lex.language}]`; + } + } else if (lex.category === "Group") { + lexiconName = `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; + } else { + lexiconName = `Lexique : ${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})`, + ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})${(lex.language) ? ` [${lex.language}]` : ""}` + : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})${(lex.language) ? ` [${lex.language}]` : ""}`, lexiconId: lex.id, active: lex.active || false, }))); @@ -245,7 +256,7 @@ async function displayLexiconsWithCheckbox(lexicons) { const lexiqueDiv = document.createElement("div"); lexiqueDiv.className = "lexique-item"; - const color = await getOrCreateLexiconColor(lexiconId); + const color = await getColorForLexicon(lexiconId); const circleIcon = createColorCircle(color, 24); const iconDiv = document.createElement("div"); diff --git a/src/utils/api.js b/src/utils/api.js index 0c0fef486527fdb5f0336928d526da930f105c47..05d106e8fa137fa3af2587ac8c20c76b49d0cf05 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -71,11 +71,9 @@ async function getLexicons(authToken) { async function getAllCategoriesLexicons(authToken) { const categories = ["User", "Group", "Zero", "New words"]; - const groupId = 1; - const promises = categories.map(async (category) => { const baseUrl = "https://babalex.lezinter.net/api/lexicon/search"; - const url = `${baseUrl}?&group_id=${groupId}&category=${encodeURIComponent(category)}&language=fr`; + const url = `${baseUrl}?&category=${encodeURIComponent(category)}&language=fr`; try { return await callApi(url, authToken); @@ -97,6 +95,7 @@ async function getAllCategoriesLexicons(authToken) { } } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Récupération des entrées d'un lexique // ───────────────────────────────────────────────────────────────────────────── @@ -113,12 +112,9 @@ async function getLexiconEntries(authToken, lexiconId) { * Récupère toutes les graphies présentes dans tous les lexiques de l'utilisateur. */ async function getAllLexiconWords(authToken) { - const searchUrl = "https://babalex.lezinter.net/api/lexicon/search" - + "&language=fr"; - try { // 1) Récupération de la liste des lexiques - const lexicons = await callApi(searchUrl, authToken); + const lexicons = await getLexicons(authToken); if (!Array.isArray(lexicons) || lexicons.length === 0) { console.warn("âš ï¸ Aucun lexique retourné par l’API pour ces paramètres."); @@ -205,7 +201,7 @@ async function AddWord(authToken, selectedWord, lexiconIds, force = false) { force, target_lex: lexiconIds }; - + log("Body envoyé à AddWord :", body); return callApi(url, authToken, "POST", body); } @@ -217,10 +213,10 @@ async function AddWord(authToken, selectedWord, lexiconIds, force = false) { window.callApi = callApi; window.getLexicons = getLexicons; -log("getLexicons exposée, type:", typeof window.getLexicons); window.getAllCategoriesLexicons = getAllCategoriesLexicons; window.getLexiconEntries = getLexiconEntries; window.getAllLexiconWords = getAllLexiconWords; window.getWiktionaryDefinition = getWiktionaryDefinition; window.AddWord = AddWord; +window.getLexiconsColors = getLexiconsColors;