From b3918c928d19195a463f2547e91ce41d31fbfd01 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 12:47:36 +0100 Subject: [PATCH 01/23] Ajout de mot v1 --- api.js | 52 +++++++++++++++-- "barre_lat\303\251rale/sidebar.js" | 90 +++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 6 deletions(-) diff --git a/api.js b/api.js index c1a046d..43f05dc 100644 --- a/api.js +++ b/api.js @@ -17,19 +17,27 @@ document.addEventListener("mouseup", () => { // â–Œ Fonction utilitaire pour appeler l’API // ───────────────────────────────────────────────────────────────────────────── /** - * Effectue une requête API + * Effectue une requête API (GET, POST, etc.) avec ou sans body JSON * @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. + * @param {object|null} [data=null] - Les données à envoyer dans le body (pour POST/PUT...). * @returns {Promise<any>} - La réponse en JSON. * @throws {Error} - En cas d'échec. */ -async function callApi(url, authToken = null, method = 'GET') { +async function callApi(url, authToken = null, method = 'GET', data = null) { const headers = { 'Content-Type': 'application/json' }; if (authToken) headers.Authorization = `Bearer ${authToken}`; + const fetchOptions = { method, headers }; + + if (data) { + // Si on veut envoyer un body JSON + fetchOptions.body = JSON.stringify(data); + } + try { - const response = await fetch(url, { method, headers }); + const response = await fetch(url, fetchOptions); if (!response.ok) { throw new Error(`⌠Erreur API (${response.status}): ${response.statusText}`); } @@ -40,6 +48,7 @@ async function callApi(url, authToken = null, method = 'GET') { } } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Récupération des lexiques de l'utilisateur // ───────────────────────────────────────────────────────────────────────────── @@ -174,6 +183,40 @@ async function getWiktionaryDefinition(word) { } } +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Ajout d'un mot dans un/des lexique(s) +// ───────────────────────────────────────────────────────────────────────────── +/** + * Ajoute un mot (selectedWord) dans un ou plusieurs lexiques (lexiconIds). + * @param {string} authToken - Jeton d'authentification (Bearer). + * @param {string} selectedWord - Le mot à ajouter. + * @param {number[]} lexiconIds - Tableau d'IDs de lexiques cibles. + * @param {boolean} [force=false] - Paramètre optionnel pour l'API. + * @returns {Promise<any>} - La réponse JSON de l'API, ou une exception si échec. + */ +async function AddWord(authToken, selectedWord, lexiconIds, force = false) { + if (!authToken) { + throw new Error("Aucun token d’authentification fourni."); + } + if (!selectedWord) { + throw new Error("Aucun mot n’a été spécifié pour l’ajout."); + } + if (!Array.isArray(lexiconIds) || lexiconIds.length === 0) { + throw new Error("Aucun lexique sélectionné pour l’ajout."); + } + + const url = "https://babalex.lezinter.net/api/entry/create"; + const body = { + graphy: selectedWord, + force, + target_lex: lexiconIds + }; + + return callApi(url, authToken, "POST", body); +} + + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Exposition des fonctions pour un usage global // ───────────────────────────────────────────────────────────────────────────── @@ -183,4 +226,5 @@ window.getLexicons = getLexicons; window.getAllCategoriesLexicons = getAllCategoriesLexicons; window.getLexiconEntries = getLexiconEntries; window.getAllLexiconWords = getAllLexiconWords; -window.getWiktionaryDefinition = getWiktionaryDefinition; \ No newline at end of file +window.getWiktionaryDefinition = getWiktionaryDefinition; +window.AddWord = AddWord; diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index b920188..79a2bab 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -190,6 +190,11 @@ async function fetchLexicons() { } } +/** + * Affiche la liste des lexiques avec des checkboxes. + * Les checkboxes servent ici à activer/désactiver le surlignage, + * mais on va aussi s’en servir pour déterminer où ajouter le mot. + */ function displayLexiconsWithCheckbox(lexicons) { const lexiquesContainer = document.getElementById("lexiques"); if (!lexiquesContainer) { @@ -202,31 +207,41 @@ function displayLexiconsWithCheckbox(lexicons) { lexiquesContainer.textContent = "Aucun lexique disponible."; return; } + lexicons.forEach(({ lexiconName, lexiconId, active }) => { 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; + // On stocke l'ID du lexique dans un attribut data pour le récupérer plus tard + checkbox.dataset.lexiconId = lexiconId; + + // Toggle highlight checkbox.addEventListener("change", async () => { console.log( `🔄 Changement de surlignage pour ${lexiconName} (ID: ${lexiconId}): ${ checkbox.checked ? "activé" : "désactivé" }` ); + // On envoie un message au background script pour gérer le highlight await browser.runtime.sendMessage({ action: "toggleLexiconHighlight", lexiconId, isActive: checkbox.checked, }); }); + lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); lexiqueDiv.appendChild(checkbox); @@ -266,6 +281,70 @@ async function handleAuthButtonClick() { await refreshSidebarState(); } +// ───────────────────────────────────────────────────────────────────────────── +// â–Œ Ajout d'un mot au(x) lexique(s) +// ───────────────────────────────────────────────────────────────────────────── +/** + * Au clic sur le bouton "add-word-button", + * on récupère le mot sélectionné (#motSelectionne) + * et les lexiques cochés, puis on appelle AddWord. + */ +async function handleAddWordClick() { + if (!authToken) { + console.warn("âš ï¸ Impossible d’ajouter le mot : pas de token d’authentification."); + return; + } + + const selectedWordElement = document.getElementById("motSelectionne"); + const lexiconResultElement = document.getElementById("lexiconResult"); + + if (!selectedWordElement) { + console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); + return; + } + + const selectedWord = selectedWordElement.textContent.trim(); + if (!selectedWord || selectedWord === "Aucun mot sélectionné") { + console.warn("âš ï¸ Aucun mot à ajouter."); + if (lexiconResultElement) { + lexiconResultElement.textContent = "Aucun mot à ajouter."; + } + return; + } + + // On récupère toutes les checkboxes cochées dans #lexiques + const checkboxList = document.querySelectorAll("#lexiques .lexique-checkbox:checked"); + const selectedLexiconIds = Array.from(checkboxList).map((cb) => + parseInt(cb.dataset.lexiconId, 10) + ); + + if (selectedLexiconIds.length === 0) { + console.warn("âš ï¸ Aucun lexique sélectionné."); + if (lexiconResultElement) { + lexiconResultElement.textContent = "Veuillez cocher au moins un lexique."; + } + return; + } + + console.log("📦 Ajout du mot :", selectedWord, "dans lexique(s) :", selectedLexiconIds); + + // Appel à la fonction AddWord (définie dans api.js et exposée en window) + try { + const result = await window.AddWord(authToken, selectedWord, selectedLexiconIds, false); + console.log("✅ Réponse d’ajout :", result); + + if (lexiconResultElement) { + lexiconResultElement.textContent = "Mot ajouté avec succès !"; + // Si l’API renvoie plus d’infos, vous pouvez les afficher ici + } + } catch (error) { + console.error("⌠Erreur lors de l’ajout du mot :", error); + if (lexiconResultElement) { + lexiconResultElement.textContent = "Erreur lors de l’ajout : " + error.message; + } + } +} + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Réception des messages // ───────────────────────────────────────────────────────────────────────────── @@ -379,9 +458,16 @@ document.addEventListener("DOMContentLoaded", async () => { }); }); } -}); -document.addEventListener("DOMContentLoaded", () => { + // Bouton "Ajouter au(x) lexique(s)" + const addWordButton = document.getElementById("add-word-button"); + if (addWordButton) { + addWordButton.addEventListener("click", handleAddWordClick); + } else { + console.warn("âš ï¸ Bouton #add-word-button introuvable dans le DOM."); + } + + // Écouteur pour la case à cocher "toggle-definitions" const toggleButtons = document.querySelectorAll(".toggle-btn"); toggleButtons.forEach((btn) => { if (!btn.textContent.trim()) { -- GitLab From 4f6a18eeb13495112d81e367e2b5ea50e860656d Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 14:29:22 +0100 Subject: [PATCH 02/23] Message d'erreur si mot existant dans lexique --- "barre_lat\303\251rale/sidebar.js" | 103 +++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 29 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 79a2bab..e885de2 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -209,46 +209,66 @@ function displayLexiconsWithCheckbox(lexicons) { } lexicons.forEach(({ lexiconName, lexiconId, active }) => { + // Création du conteneur pour ce lexique const lexiqueDiv = document.createElement("div"); lexiqueDiv.className = "lexique-item"; + // Optionnel : un élément visuel (icône) const iconDiv = document.createElement("div"); iconDiv.className = "lexique-icon"; iconDiv.style.backgroundColor = "#ccc"; + // Le label affichant le nom du lexique 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; - // On stocke l'ID du lexique dans un attribut data pour le récupérer plus tard - checkbox.dataset.lexiconId = lexiconId; - - // Toggle highlight - checkbox.addEventListener("change", async () => { - console.log( - `🔄 Changement de surlignage pour ${lexiconName} (ID: ${lexiconId}): ${ - checkbox.checked ? "activé" : "désactivé" - }` - ); - // On envoie un message au background script pour gérer le highlight - await browser.runtime.sendMessage({ - action: "toggleLexiconHighlight", - lexiconId, - isActive: checkbox.checked, - }); + // La case à cocher servant à sélectionner le lexique pour l'ajout d'un mot + const addCheckbox = document.createElement("input"); + addCheckbox.type = "checkbox"; + addCheckbox.className = "lexique-add-checkbox"; + // On stocke l'ID du lexique dans le dataset pour l'utiliser lors de l'ajout + addCheckbox.dataset.lexiconId = lexiconId; + + // Le bouton pour activer/désactiver le surlignage + const highlightButton = document.createElement("button"); + highlightButton.className = "lexique-highlight-toggle"; + highlightButton.dataset.lexiconId = lexiconId; + // Stocke l'état initial dans le dataset ("true" si actif, sinon "false") + highlightButton.dataset.active = active ? "true" : "false"; + // Définition du texte du bouton en fonction de l'état initial + highlightButton.textContent = active ? "Désactiver surlignage" : "Activer surlignage"; + + // Gestion du clic sur le bouton de surlignage + highlightButton.addEventListener("click", async () => { + // On récupère l'état courant depuis le dataset + let currentState = highlightButton.dataset.active === "true"; + let newState = !currentState; + try { + // Envoi d'un message pour demander au background de changer l'état de surlignage + await browser.runtime.sendMessage({ + action: "toggleLexiconHighlight", + lexiconId, + isActive: newState, + }); + // Mise à jour de l'état stocké et du texte du bouton + highlightButton.dataset.active = newState ? "true" : "false"; + highlightButton.textContent = newState ? "Désactiver surlignage" : "Activer surlignage"; + } catch (error) { + console.error("Erreur lors du toggle de surlignage pour le lexique", lexiconId, ":", error); + } }); + // Assemblage de l'élément du lexique lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); - lexiqueDiv.appendChild(checkbox); + lexiqueDiv.appendChild(addCheckbox); + lexiqueDiv.appendChild(highlightButton); lexiquesContainer.appendChild(lexiqueDiv); }); } + function initModal() { console.log("initModal appelé"); const modalOverlay = document.getElementById("modalOverlay"); @@ -313,7 +333,7 @@ async function handleAddWordClick() { } // On récupère toutes les checkboxes cochées dans #lexiques - const checkboxList = document.querySelectorAll("#lexiques .lexique-checkbox:checked"); + const checkboxList = document.querySelectorAll("#lexiques .lexique-add-checkbox:checked"); const selectedLexiconIds = Array.from(checkboxList).map((cb) => parseInt(cb.dataset.lexiconId, 10) ); @@ -326,16 +346,41 @@ async function handleAddWordClick() { return; } - console.log("📦 Ajout du mot :", selectedWord, "dans lexique(s) :", selectedLexiconIds); - - // Appel à la fonction AddWord (définie dans api.js et exposée en window) + // Vérifier si le mot existe déjà dans l'un des lexiques sélectionnés + let definitions = []; try { - const result = await window.AddWord(authToken, selectedWord, selectedLexiconIds, false); - console.log("✅ Réponse d’ajout :", result); + definitions = await fetchLexiconDefinitions(selectedWord); + } catch (error) { + console.error("Erreur lors de la récupération des définitions pour vérification :", error); + } + let exists = false; + if (definitions && definitions.length > 0) { + for (const def of definitions) { + if (selectedLexiconIds.includes(def.lexiconId)) { + exists = true; + break; + } + } + } + + if (exists) { + if (lexiconResultElement) { + lexiconResultElement.innerHTML = + "Le mot <strong>" + selectedWord + "</strong> existe déjà dans le(s) lexique(s) : " + selectedLexiconIds.join(", ") + "."; + } + return; + } + + // Procéder à l'ajout dans chaque lexique sélectionné + try { + for (const lexId of selectedLexiconIds) { + const result = await window.AddWord(authToken, selectedWord, [lexId], false); + console.log("✅ Réponse d’ajout pour le lexique", lexId, ":", result); + } if (lexiconResultElement) { - lexiconResultElement.textContent = "Mot ajouté avec succès !"; - // Si l’API renvoie plus d’infos, vous pouvez les afficher ici + lexiconResultElement.textContent = + "✅ Mot <strong>" + selectedWord + "</strong> ajouté avec succès dans les lexiques : " + selectedLexiconIds.join(", ") + "."; } } catch (error) { console.error("⌠Erreur lors de l’ajout du mot :", error); -- GitLab From 5c91991d64c85b464f226a5ba94b8ae1dd53b815 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 17:26:00 +0100 Subject: [PATCH 03/23] Correction erreur 500 --- "barre_lat\303\251rale/sidebar.js" | 69 +++++++++++++++++++----------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index e885de2..6b7e389 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -310,8 +310,9 @@ async function handleAuthButtonClick() { * et les lexiques cochés, puis on appelle AddWord. */ async function handleAddWordClick() { + // 1) Vérifier la présence du token et du mot if (!authToken) { - console.warn("âš ï¸ Impossible d’ajouter le mot : pas de token d’authentification."); + console.warn("âš ï¸ Pas de token d'authentification : impossible d'ajouter le mot."); return; } @@ -322,7 +323,6 @@ async function handleAddWordClick() { console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); return; } - const selectedWord = selectedWordElement.textContent.trim(); if (!selectedWord || selectedWord === "Aucun mot sélectionné") { console.warn("âš ï¸ Aucun mot à ajouter."); @@ -332,12 +332,11 @@ async function handleAddWordClick() { return; } - // On récupère toutes les checkboxes cochées dans #lexiques + // 2) Récupérer les IDs des lexiques sélectionnés (cases à cocher “add-checkboxâ€) const checkboxList = document.querySelectorAll("#lexiques .lexique-add-checkbox:checked"); - const selectedLexiconIds = Array.from(checkboxList).map((cb) => + const selectedLexiconIds = Array.from(checkboxList).map(cb => parseInt(cb.dataset.lexiconId, 10) ); - if (selectedLexiconIds.length === 0) { console.warn("âš ï¸ Aucun lexique sélectionné."); if (lexiconResultElement) { @@ -346,7 +345,7 @@ async function handleAddWordClick() { return; } - // Vérifier si le mot existe déjà dans l'un des lexiques sélectionnés + // 3) Vérifier si le mot existe déjà dans l'un des lexiques sélectionnés let definitions = []; try { definitions = await fetchLexiconDefinitions(selectedWord); @@ -354,42 +353,64 @@ async function handleAddWordClick() { console.error("Erreur lors de la récupération des définitions pour vérification :", error); } - let exists = false; - if (definitions && definitions.length > 0) { + // Construire un ensemble (ou tableau) des IDs dans lesquels le mot existe déjà + const existingLexiconIds = []; + if (Array.isArray(definitions)) { for (const def of definitions) { - if (selectedLexiconIds.includes(def.lexiconId)) { - exists = true; - break; + if (selectedLexiconIds.includes(def.lexiconId) && !existingLexiconIds.includes(def.lexiconId)) { + existingLexiconIds.push(def.lexiconId); } } } - if (exists) { + if (existingLexiconIds.length > 0) { if (lexiconResultElement) { lexiconResultElement.innerHTML = - "Le mot <strong>" + selectedWord + "</strong> existe déjà dans le(s) lexique(s) : " + selectedLexiconIds.join(", ") + "."; + "Le mot <strong>" + selectedWord + "</strong> existe déjà dans le(s) lexique(s) : " + + existingLexiconIds.join(", ") + "."; } return; } - // Procéder à l'ajout dans chaque lexique sélectionné - try { - for (const lexId of selectedLexiconIds) { + // 4) Déterminer les lexiques où ajouter le mot (ceux où il n’existe pas) + const lexiconsToAdd = selectedLexiconIds.filter(id => !existingLexiconIds.includes(id)); + if (lexiconsToAdd.length === 0) { + // Le mot existe déjà dans tous les lexiques sélectionnés + return; + } + + // 5) Ajouter le mot dans les lexiques restants + let addResults = []; + for (const lexId of lexiconsToAdd) { + try { const result = await window.AddWord(authToken, selectedWord, [lexId], false); - console.log("✅ Réponse d’ajout pour le lexique", lexId, ":", result); + console.log("✅ Ajout réussi dans le lexique", lexId, ":", result); + addResults.push({ lexId, success: true }); + // Envoyer un message pour rafraîchir l'UI si nécessaire + browser.runtime.sendMessage({ action: "refreshUI" }); + } catch (error) { + console.error("⌠Erreur lors de l’ajout dans le lexique", lexId, ":", error); + addResults.push({ lexId, success: false, error }); } - if (lexiconResultElement) { - lexiconResultElement.textContent = - "✅ Mot <strong>" + selectedWord + "</strong> ajouté avec succès dans les lexiques : " + selectedLexiconIds.join(", ") + "."; + } + + // 6) Afficher un message récapitulatif + if (lexiconResultElement) { + let message = ""; + const successful = addResults.filter(r => r.success).map(r => r.lexId); + const failed = addResults.filter(r => !r.success).map(r => r.lexId); + + if (successful.length > 0) { + message += "✅ Mot <strong>" + selectedWord + "</strong> ajouté avec succès dans les lexiques : " + successful.join(", ") + "."; } - } catch (error) { - console.error("⌠Erreur lors de l’ajout du mot :", error); - if (lexiconResultElement) { - lexiconResultElement.textContent = "Erreur lors de l’ajout : " + error.message; + if (failed.length > 0) { + message += "<br>⌠Échec de l'ajout dans les lexiques : " + failed.join(", ") + "."; } + lexiconResultElement.innerHTML = message; } } + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Réception des messages // ───────────────────────────────────────────────────────────────────────────── -- GitLab From a5b78ec2c316b110143b318c0736cd90639f32a6 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:27:59 +0100 Subject: [PATCH 04/23] Correction beug ajout multiple --- api.js | 4 +- "barre_lat\303\251rale/sidebar.js" | 81 +++++++++++++----------------- definitions.js | 1 + 3 files changed, 39 insertions(+), 47 deletions(-) diff --git a/api.js b/api.js index 43f05dc..72eb48c 100644 --- a/api.js +++ b/api.js @@ -30,9 +30,9 @@ async function callApi(url, authToken = null, method = 'GET', data = null) { if (authToken) headers.Authorization = `Bearer ${authToken}`; const fetchOptions = { method, headers }; - + console.log("Envoi de la requête vers :", url); if (data) { - // Si on veut envoyer un body JSON + console.log("Body JSON :", JSON.stringify(data, null, 2)); fetchOptions.body = JSON.stringify(data); } diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 6b7e389..c01621b 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -326,26 +326,21 @@ async function handleAddWordClick() { const selectedWord = selectedWordElement.textContent.trim(); if (!selectedWord || selectedWord === "Aucun mot sélectionné") { console.warn("âš ï¸ Aucun mot à ajouter."); - if (lexiconResultElement) { - lexiconResultElement.textContent = "Aucun mot à ajouter."; - } + if (lexiconResultElement) lexiconResultElement.textContent = "Aucun mot à ajouter."; return; } // 2) Récupérer les IDs des lexiques sélectionnés (cases à cocher “add-checkboxâ€) const checkboxList = document.querySelectorAll("#lexiques .lexique-add-checkbox:checked"); - const selectedLexiconIds = Array.from(checkboxList).map(cb => - parseInt(cb.dataset.lexiconId, 10) - ); + const selectedLexiconIds = Array.from(checkboxList).map(cb => parseInt(cb.dataset.lexiconId, 10)); + if (selectedLexiconIds.length === 0) { console.warn("âš ï¸ Aucun lexique sélectionné."); - if (lexiconResultElement) { - lexiconResultElement.textContent = "Veuillez cocher au moins un lexique."; - } + if (lexiconResultElement) lexiconResultElement.textContent = "Veuillez cocher au moins un lexique."; return; } - // 3) Vérifier si le mot existe déjà dans l'un des lexiques sélectionnés + // 3) Vérifier si le mot existe déjà dans l’un des lexiques sélectionnés let definitions = []; try { definitions = await fetchLexiconDefinitions(selectedWord); @@ -353,64 +348,60 @@ async function handleAddWordClick() { console.error("Erreur lors de la récupération des définitions pour vérification :", error); } - // Construire un ensemble (ou tableau) des IDs dans lesquels le mot existe déjà - const existingLexiconIds = []; + const existingLexiconIds = new Set(); if (Array.isArray(definitions)) { for (const def of definitions) { - if (selectedLexiconIds.includes(def.lexiconId) && !existingLexiconIds.includes(def.lexiconId)) { - existingLexiconIds.push(def.lexiconId); + if (selectedLexiconIds.includes(def.lexiconId)) { + existingLexiconIds.add(def.lexiconId); } } } - if (existingLexiconIds.length > 0) { + // 4) Si le mot existe déjà dans certains lexiques, on les affiche + if (existingLexiconIds.size > 0) { if (lexiconResultElement) { lexiconResultElement.innerHTML = "Le mot <strong>" + selectedWord + "</strong> existe déjà dans le(s) lexique(s) : " + - existingLexiconIds.join(", ") + "."; + Array.from(existingLexiconIds).join(", ") + "."; } - return; } - // 4) Déterminer les lexiques où ajouter le mot (ceux où il n’existe pas) - const lexiconsToAdd = selectedLexiconIds.filter(id => !existingLexiconIds.includes(id)); + // 5) Déterminer les lexiques où ajouter le mot + const lexiconsToAdd = selectedLexiconIds.filter(id => !existingLexiconIds.has(id)); if (lexiconsToAdd.length === 0) { - // Le mot existe déjà dans tous les lexiques sélectionnés - return; + return; // Rien à ajouter, tous les lexiques sélectionnés contiennent déjà le mot } - // 5) Ajouter le mot dans les lexiques restants - let addResults = []; - for (const lexId of lexiconsToAdd) { - try { - const result = await window.AddWord(authToken, selectedWord, [lexId], false); - console.log("✅ Ajout réussi dans le lexique", lexId, ":", result); - addResults.push({ lexId, success: true }); - // Envoyer un message pour rafraîchir l'UI si nécessaire - browser.runtime.sendMessage({ action: "refreshUI" }); - } catch (error) { - console.error("⌠Erreur lors de l’ajout dans le lexique", lexId, ":", error); - addResults.push({ lexId, success: false, error }); - } - } + // 6) Envoi d’une seule requête pour tous les lexiques restants + try { + console.log(`📡 Envoi de l'ajout du mot "${selectedWord}" dans les lexiques :`, lexiconsToAdd); + const result = await window.AddWord(authToken, selectedWord, lexiconsToAdd, false); + + console.log("✅ Réponse API :", result); - // 6) Afficher un message récapitulatif - if (lexiconResultElement) { - let message = ""; - const successful = addResults.filter(r => r.success).map(r => r.lexId); - const failed = addResults.filter(r => !r.success).map(r => r.lexId); + // Rafraîchir l'UI et la liste des entrées + await new Promise(resolve => setTimeout(resolve, 300)); + browser.runtime.sendMessage({ action: "refreshUI" }); - if (successful.length > 0) { - message += "✅ Mot <strong>" + selectedWord + "</strong> ajouté avec succès dans les lexiques : " + successful.join(", ") + "."; + // 7) Affichage du message de succès + if (lexiconResultElement) { + lexiconResultElement.innerHTML += + "<br>✅ Mot <strong>" + selectedWord + "</strong> ajouté avec succès dans : " + + lexiconsToAdd.join(", ") + "."; } - if (failed.length > 0) { - message += "<br>⌠Échec de l'ajout dans les lexiques : " + failed.join(", ") + "."; + + } catch (error) { + console.error("⌠Erreur lors de l’ajout du mot :", error); + if (lexiconResultElement) { + lexiconResultElement.textContent = "Erreur lors de l’ajout : " + error.message; } - lexiconResultElement.innerHTML = message; } } + + + // ───────────────────────────────────────────────────────────────────────────── // â–Œ Réception des messages // ───────────────────────────────────────────────────────────────────────────── diff --git a/definitions.js b/definitions.js index 0e22bff..c8832d8 100644 --- a/definitions.js +++ b/definitions.js @@ -81,6 +81,7 @@ async function fetchLexiconDefinitions(word) { // 3) Parcourir les résultats et extraire les définitions let allDefinitions = []; results.forEach(result => { + console.log(`Pour le lexique ${result.lexiconId}, entrées filtrées :`, result.entries); const lexiconId = result.lexiconId; const sourceName = lexiconMap.get(lexiconId) || `Lexique #${lexiconId}`; -- GitLab From 6291ea0ef5ea70e26db10dc2a32df86cf9e38c88 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 19:04:22 +0100 Subject: [PATCH 05/23] Style bouton de connexion --- "barre_lat\303\251rale/sidebar.html" | 55 +++++++++++++++++++++++++--- "barre_lat\303\251rale/sidebar.js" | 1 + 2 files changed, 51 insertions(+), 5 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 5ea40ba..4f9fc73 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -41,6 +41,45 @@ margin-bottom: 0; } + /* Bouton de connexion */ + #auth-button { + width: auto; + display: inline-flex; + padding: 6px 12px; + font-size: 18px; + font-family: Bradley Hand, cursive; + background: none; + border: none; + color: white; + align-items: center; + gap: 6px; + border-radius: 20px; + cursor: pointer; + transition: background 0.3s; + } + + #auth-button:hover { + background: rgba(255, 255, 255, 0.2); + } + + #auth-button svg { + width: 18px; + height: 18px; + fill: white; + transition: transform 0.3s ease-in-out; + } + + #auth-button:hover svg { + transform: scale(1.1); + } + + #auth-section { + display: flex; + justify-content: flex-end; + margin-bottom: 10px; + } + + /* Utilisation de la classe pour les boutons de bascule */ .toggle-btn { position: absolute; @@ -96,8 +135,9 @@ display: flex; align-items: center; justify-content: space-between; - padding: 8px; + padding: 6px; margin-bottom: 5px; + margin-top: 2px; border-radius: 5px; background-color: #dcdde1; width: 100%; @@ -242,6 +282,15 @@ </head> <body> + <!-- Bouton de connexion --> + <div id="auth-section"> + <button id="auth-button"> + <span id="auth-icon"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 2a1 1 0 0 1 1 1v2h2V3a1 1 0 0 1 2 0v2h2a2 2 0 0 1 2 2v3h-2V7h-2v3a1 1 0 1 1-2 0V7h-2v3a1 1 0 1 1-2 0V7H6v3H4V7a2 2 0 0 1 2-2h2V3a1 1 0 0 1 1-1Zm-6 10h16v4a2 2 0 0 1-2 2h-4v2h2a1 1 0 1 1 0 2H8a1 1 0 1 1 0-2h2v-2H6a2 2 0 0 1-2-2v-4Z"/></svg> + </span> + <span id="auth-text">Se connecter</span> + </button> + </div> <!-- Bloc 1 : Menu des lexiques --> <div id="menu"> @@ -250,11 +299,7 @@ <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> <div id="lexiques">Chargement...</div> - <div id="auth-section"> - <button id="auth-button">Se connecter</button> - </div> </div> </div> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index c01621b..c6400d6 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -47,6 +47,7 @@ function updateAuthButton(isLoggedIn) { } } + function toggleElementsVisibility(isLoggedIn) { const elementsToShowOrHide = [ { id: "add-to-lexiques", shouldShow: isLoggedIn }, -- GitLab From 478194b8bf3608a46e191c52e2a8fa07ba6bea95 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sat, 8 Feb 2025 19:35:38 +0100 Subject: [PATCH 06/23] =?UTF-8?q?Ajout=20ic=C3=B4ne=20pour=20surligner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.html" | 61 +++++++++++++++++++++++++-- "barre_lat\303\251rale/sidebar.js" | 41 +++++++++++++++--- icons/feutre.png | Bin 0 -> 992 bytes 3 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 icons/feutre.png diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 4f9fc73..61f46c8 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -151,6 +151,7 @@ font-weight: bold; color: #323046; flex-grow: 1; + font-size: 15px; text-align: center; } @@ -161,13 +162,65 @@ margin-left: 10px; } - /* Texte explicatif */ - #highlight-note { - font-size: small; - margin-bottom: 10px; + /* Surlignage */ + .lexique-highlight-toggle { + background: none; + border: none; + cursor: pointer; + font-size: 16px; + padding: 2px; + transition: transform 0.2s ease-in-out; + width: 15%; + position: relative; + } + + .feutre-icon { + width: 20px; + height: 20px; + filter: brightness(0) saturate(100%) invert(40%) sepia(0%) saturate(0%) hue-rotate(0deg); /* Gris par défaut */ + transition: filter 0.3s ease-in-out; + } + + .lexique-highlight-toggle[data-active="true"] .feutre-icon { + filter: brightness(0) saturate(100%) invert(83%) sepia(89%) saturate(588%) hue-rotate(360deg); /* Jaune */ + } + + .lexique-highlight-toggle:hover { + transform: scale(1.1); + } + + /* Tooltip */ + .tooltip { + position: absolute; + bottom: 120%; + transform: translateX(-50%); + background-color: rgba(0, 0, 0, 0.75); + color: #fff; + font-size: 12px; + padding: 6px 10px; + border-radius: 5px; + white-space: normal; + width: 150px; text-align: center; + opacity: 0; + transition: opacity 0.3s ease-in-out; + pointer-events: none; } + /* Si l'icône est proche du bord gauche, décalage du tooltip vers la droite */ + .lexique-highlight-toggle.left .tooltip { + left: 0; + transform: translateX(0); + } + + /* Si l'icône est proche du bord droit, décalage du tooltip vers la gauche */ + .lexique-highlight-toggle.right .tooltip { + right: 0; + left: auto; + transform: translateX(0); + } + + /* Espace pour les pictogrammes */ .lexique-icon { width: 25px; diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index c6400d6..fbe771d 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -228,21 +228,27 @@ function displayLexiconsWithCheckbox(lexicons) { const addCheckbox = document.createElement("input"); addCheckbox.type = "checkbox"; addCheckbox.className = "lexique-add-checkbox"; - // On stocke l'ID du lexique dans le dataset pour l'utiliser lors de l'ajout addCheckbox.dataset.lexiconId = lexiconId; // Le bouton pour activer/désactiver le surlignage const highlightButton = document.createElement("button"); highlightButton.className = "lexique-highlight-toggle"; highlightButton.dataset.lexiconId = lexiconId; - // Stocke l'état initial dans le dataset ("true" si actif, sinon "false") highlightButton.dataset.active = active ? "true" : "false"; - // Définition du texte du bouton en fonction de l'état initial - highlightButton.textContent = active ? "Désactiver surlignage" : "Activer surlignage"; + + const feutreIcon = document.createElement("img"); + feutreIcon.src = "/icons/feutre.png"; // Chemin de ton fichier SVG + feutreIcon.alt = "Feutre"; + feutreIcon.className = "feutre-icon"; + + const tooltip = document.createElement("span"); + tooltip.className = "tooltip"; + tooltip.textContent = "Activer/Désactiver le surlignage des mots du lexique"; + + highlightButton.appendChild(feutreIcon); // Gestion du clic sur le bouton de surlignage highlightButton.addEventListener("click", async () => { - // On récupère l'état courant depuis le dataset let currentState = highlightButton.dataset.active === "true"; let newState = !currentState; try { @@ -252,24 +258,45 @@ function displayLexiconsWithCheckbox(lexicons) { lexiconId, isActive: newState, }); - // Mise à jour de l'état stocké et du texte du bouton + + // Mise à jour de l'état et du bouton highlightButton.dataset.active = newState ? "true" : "false"; - highlightButton.textContent = newState ? "Désactiver surlignage" : "Activer surlignage"; } catch (error) { console.error("Erreur lors du toggle de surlignage pour le lexique", lexiconId, ":", error); } }); + highlightButton.addEventListener("mouseover", () => { + tooltip.style.opacity = "1"; + }); + highlightButton.addEventListener("mouseleave", () => { + tooltip.style.opacity = "0"; + }); + // Assemblage de l'élément du lexique lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); lexiqueDiv.appendChild(addCheckbox); + highlightButton.appendChild(tooltip); lexiqueDiv.appendChild(highlightButton); lexiquesContainer.appendChild(lexiqueDiv); + + // Vérification de la position pour éviter la coupure du tooltip + setTimeout(() => { + const rect = highlightButton.getBoundingClientRect(); + const screenWidth = window.innerWidth; + + if (rect.left < 100) { + highlightButton.classList.add("left"); + } else if (rect.right > screenWidth - 100) { + highlightButton.classList.add("right"); + } + }, 100); }); } + function initModal() { console.log("initModal appelé"); const modalOverlay = document.getElementById("modalOverlay"); diff --git a/icons/feutre.png b/icons/feutre.png new file mode 100644 index 0000000000000000000000000000000000000000..ac98bf24c087760a7df319769db987664e72c3a6 GIT binary patch literal 992 zcmV<610Vc}P)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&00009a7bBm000XU z000XU0RWnu7ytkRl1W5CRCt{2nQ4fPQ5eU6w!si#tRb>QSt4up62%u=6tX4xpiEOF zpDf82U+~GU>`^EtjEG4nWNXGGQ?iXU8Af9pJ@tR<xXp6!yWKnGUvKx`?m5qM{_lCt zbDr}*@E@^YAaESW2WC=FF%|d%R5{N&>KRr6zcl!LKpya0zjLVvXaH=`fdA;bhougg zjGmdMz%dQ95?EMGn~W#Z4k*+BKLHbKX`8WRdI2RGSSipyi9Q)eW-RbQ1G)`#Orh^G zhs+Yvh<U(w4dgVC?Zd`$^?ym4uufUY2C*Gz<kQXs*?3FLXbkL<a|?^r0c`bk!g4(^ zq9t%njxD6-2F!9LvUL(@NKEJq+?8W{i(>-VY6jeJ5`>?%<qHFV=W_fM=o4_~KO$St zfDXij$-rkhwzrrQ(B3v@R&9;M0?X|`oH(|S2!a*P`U(=7z6w7ty#`&3(}15!*$apP zS->F?urhpQ2sVcT<+8b!7|;f|Du?EHdI&bV0xx894>6!8P$Y-1fFU8+Yy~`&&3tX9 zkzzPdCWq#@dk8k000px72xv{jm;ro~!-9|;HUJJf#b7rg#%kwWy<cxJ3~ZE56CMVW zrgL>r%$H5uf2I&2Y*RbooU6mk>2|!Wl<hFmc8##p+bucz2#gQ89`j0>%|wV!K(R9u z<~S^Laf-^r3f;(N;&FoFcPgaCovl*bY+jQj6gi0^)jS_VB4fwfGqP2z${=zQ_ni`a zXh>vs%Eo)3HxZ&xj_&Db>0+d_I8XX0AJ(X^ZKflL_<UU@)vs+0ZTym%E8*d{Duc+& z@p3t9UrW1G$&7KdtRM<XO7Ij9+ieMfOdqWW@30jca^-Yy5^d`ulOy4wN}0;9Am>{+ zFvpjYY+qA0bLE>mKnr5VXgR-`LZ8H$$<n8%w5K9chlV^2V0ViBTr#Cj_DklvAavNi z@mg7Hn2-KOroySsYP-0J49y%7A=TM%)pk!wsVnP6M&g1~93J(NVO$c`-2+CB=D<Y_ zqRi2f4kwW50nE}Ri(TRma{l*7SV%5P7l{H5;tkMG*J3Ui+m){;l=I$WY4?glVsSc1 zWCNEINO*9`c#mBVYy~zc^gIF0Ti9tKVL0yy3A6bZrrDm={}r{wyoK8&og~wSCkb!d za{msg82cOvbQ~FumcSg~0PwDw`2VU)$9jc^z$jn~@IZ^$Lgqh+34Z}-bU0uhh%Gq) O0000<MNUMnLSTX*lDmTd literal 0 HcmV?d00001 -- GitLab From 177e7108f042f036510749cd575925a47fd9d20b Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sun, 9 Feb 2025 14:28:12 +0100 Subject: [PATCH 07/23] =?UTF-8?q?Tooltips=20ic=C3=B4nes=20ajout+surlignage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.html" | 220 ++++++++++++++------------- "barre_lat\303\251rale/sidebar.js" | 81 +++++----- 2 files changed, 158 insertions(+), 143 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 61f46c8..54335af 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -25,16 +25,16 @@ margin-bottom: 10px; border-radius: 10px; background-color: #a08e9f; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 5px rgba(0,0,0,0.2); + overflow: visible; } /* En-têtes de blocs */ .block-header { position: relative; - text-align: center; + text-align: center; margin-top: 2px; } - .block-header h3 { display: inline-block; margin-top: 5px; @@ -45,7 +45,7 @@ #auth-button { width: auto; display: inline-flex; - padding: 6px 12px; + padding: 6px 12px; font-size: 18px; font-family: Bradley Hand, cursive; background: none; @@ -57,30 +57,25 @@ cursor: pointer; transition: background 0.3s; } - #auth-button:hover { - background: rgba(255, 255, 255, 0.2); + background: rgba(255,255,255,0.2); } - #auth-button svg { width: 18px; height: 18px; fill: white; transition: transform 0.3s ease-in-out; } - #auth-button:hover svg { transform: scale(1.1); } - #auth-section { display: flex; justify-content: flex-end; margin-bottom: 10px; } - - /* Utilisation de la classe pour les boutons de bascule */ + /* Boutons de bascule (toggle) */ .toggle-btn { position: absolute; right: 8px; @@ -88,23 +83,22 @@ margin: 0; border: none; color: #fff; - font-size: 15px; - padding: 3px 5px; + font-size: 15px; + padding: 3px 5px; cursor: pointer; - width: auto; - display: inline-block; + width: auto; + display: inline-block; } /* Contenu des blocs */ .block-content { padding-top: 2px; } - .hidden { display: none; } - /* Boutons */ + /* Boutons standards */ button { width: 100%; margin-top: 5px; @@ -117,7 +111,6 @@ text-align: center; border-radius: 5px; } - button:hover { background-color: #dddedd; color: #8d5c70; @@ -137,16 +130,13 @@ justify-content: space-between; padding: 6px; margin-bottom: 5px; - margin-top: 2px; border-radius: 5px; background-color: #dcdde1; - width: 100%; + position: relative; } - .lexique-item:hover { background-color: #c4c7ce; } - .lexique-label { font-weight: bold; color: #323046; @@ -155,86 +145,123 @@ text-align: center; } - .lexique-checkbox { - transform: scale(1.2); - cursor: pointer; + /* Icône du lexique */ + .lexique-icon { + width: 25px; + height: 25px; + border-radius: 50%; + background-color: #ccc; + margin-right: 10px; flex-shrink: 0; - margin-left: 10px; } - /* Surlignage */ - .lexique-highlight-toggle { - background: none; - border: none; - cursor: pointer; - font-size: 16px; - padding: 2px; - transition: transform 0.2s ease-in-out; - width: 15%; + /* Conteneur pour tooltip (pour checkbox et surlignage) */ + .tooltip-container { position: relative; + display: inline-block; + cursor: pointer; + overflow: visible; } - .feutre-icon { - width: 20px; - height: 20px; - filter: brightness(0) saturate(100%) invert(40%) sepia(0%) saturate(0%) hue-rotate(0deg); /* Gris par défaut */ - transition: filter 0.3s ease-in-out; - } - - .lexique-highlight-toggle[data-active="true"] .feutre-icon { - filter: brightness(0) saturate(100%) invert(83%) sepia(89%) saturate(588%) hue-rotate(360deg); /* Jaune */ - } - - .lexique-highlight-toggle:hover { - transform: scale(1.1); - } - - /* Tooltip */ + /* Style uniformisé pour tous les tooltips */ .tooltip { + all: unset; + display: block; + box-sizing: border-box; position: absolute; bottom: 120%; + left: 50%; transform: translateX(-50%); - background-color: rgba(0, 0, 0, 0.75); + background-color: rgba(0,0,0,0.75); color: #fff; - font-size: 12px; + font-size: 12px !important; + font-weight: lighter !important; padding: 6px 10px; border-radius: 5px; - white-space: normal; - width: 150px; + white-space: normal; + overflow-wrap: break-word; + width: 180px; text-align: center; opacity: 0; - transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out, transform 0.2s ease-in-out; pointer-events: none; + z-index: 10; + line-height: normal; } - /* Si l'icône est proche du bord gauche, décalage du tooltip vers la droite */ - .lexique-highlight-toggle.left .tooltip { + .tooltip-container:hover .tooltip { + opacity: 1; + transform: translateX(-50%) translateY(-5px); + } + /* Positionnement ajusté si le conteneur est trop proche des bords */ + .tooltip-container.left .tooltip { left: 0; - transform: translateX(0); + transform: translateX(0) translateY(-5px); } - - /* Si l'icône est proche du bord droit, décalage du tooltip vers la gauche */ - .lexique-highlight-toggle.right .tooltip { + .tooltip-container.right .tooltip { right: 0; left: auto; - transform: translateX(0); + transform: translateX(0) translateY(-5px); } + /* Cases à cocher personnalisées */ + .lexique-checkbox { + appearance: none; + width: 20px; + height: 20px; + border: 2px solid #8d5c70; + border-radius: 5px; + background-color: #fff; + transition: background 0.3s ease, border-color 0.3s ease; + cursor: pointer; + position: relative; + } + .lexique-checkbox:hover { + border-color: #6a3e50; + } + .lexique-checkbox:checked { + background-color: #8d5c70; + border-color: #8d5c70; + } + .lexique-checkbox:checked::after { + content: '✔'; + font-size: 16px; + color: white; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } - /* Espace pour les pictogrammes */ - .lexique-icon { - width: 25px; - height: 25px; - border-radius: 50%; - background-color: #ccc; - margin-right: 10px; - flex-shrink: 0; + /* Bouton de surlignage */ + .lexique-highlight-toggle { + background: none; + border: none; + cursor: pointer; + font-size: 16px; + padding: 2px; + transition: transform 0.2s ease-in-out; + width: 15%; + position: relative; + } + + .feutre-icon { + width: 20px; + height: 20px; + filter: brightness(0) saturate(100%) invert(40%) sepia(0%) saturate(0%) hue-rotate(0deg); + transition: filter 0.3s ease-in-out; + } + .lexique-highlight-toggle[data-active="true"] .feutre-icon { + filter: brightness(0) saturate(100%) invert(83%) sepia(89%) saturate(588%) hue-rotate(360deg); + } + .lexique-highlight-toggle:hover { + transform: scale(1.1); } + /* Autres styles divers */ .lexicon-section { margin-bottom: 10px; } - .lexicon-header { font-weight: bold; cursor: pointer; @@ -243,72 +270,59 @@ border-radius: 5px; text-align: center; } - .lexicon-header:hover { background-color: #dddedd; color: #8d5c70; } - .lexicon-content { margin-top: 5px; } - #mesLexiquesList { display: inline; padding: 0; align-items: center; } - #mesLexiquesContainer h4 { margin-bottom: 5px; } - - /* Définition */ #definitionContainer { background-color: #444; padding: 10px; border-radius: 10px; color: white; } - #definitionsList { list-style: none; padding: 0; } - #definitionsList li { margin-bottom: 10px; } - .definition-source { font-weight: bold; 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; + 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; + background: white; color: #8d5c70; - padding: 1rem; - max-width: 600px; + padding: 1rem; + max-width: 600px; max-height: 80vh; overflow-y: auto; border-radius: 8px; } - .close-button { float: right; cursor: pointer; @@ -318,28 +332,26 @@ .close-button:hover { color: #000; } - - /* Activer/désactiver le surlignage */ #highlighting-options p { margin: 5px 0; font-size: small; color: #333; } - #noDefinitionsContainer { display: block !important; color: red !important; font-weight: bold; } </style> - </head> <body> <!-- Bouton de connexion --> <div id="auth-section"> <button id="auth-button"> <span id="auth-icon"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 2a1 1 0 0 1 1 1v2h2V3a1 1 0 0 1 2 0v2h2a2 2 0 0 1 2 2v3h-2V7h-2v3a1 1 0 1 1-2 0V7h-2v3a1 1 0 1 1-2 0V7H6v3H4V7a2 2 0 0 1 2-2h2V3a1 1 0 0 1 1-1Zm-6 10h16v4a2 2 0 0 1-2 2h-4v2h2a1 1 0 1 1 0 2H8a1 1 0 1 1 0-2h2v-2H6a2 2 0 0 1-2-2v-4Z"/></svg> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path d="M10 2a1 1 0 0 1 1 1v2h2V3a1 1 0 0 1 2 0v2h2a2 2 0 0 1 2 2v3h-2V7h-2v3a1 1 0 1 1-2 0V7h-2v3a1 1 0 1 1-2 0V7H6v3H4V7a2 2 0 0 1 2-2h2V3a1 1 0 0 1 1-1Z"/> + </svg> </span> <span id="auth-text">Se connecter</span> </button> @@ -355,7 +367,7 @@ <div id="lexiques">Chargement...</div> </div> </div> - + <!-- Bloc 2 : État de la sélection --> <div id="etat"> <div class="block-header"> @@ -372,7 +384,7 @@ <div id="possible-definitions" style="display: none;"></div> </div> </div> - + <!-- Bloc 3 : Définitions --> <div id="definitionContainer"> <div class="block-header"> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index fbe771d..cca0470 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -210,93 +210,96 @@ function displayLexiconsWithCheckbox(lexicons) { } lexicons.forEach(({ lexiconName, lexiconId, active }) => { - // Création du conteneur pour ce lexique const lexiqueDiv = document.createElement("div"); lexiqueDiv.className = "lexique-item"; - // Optionnel : un élément visuel (icône) + // Icône du lexique const iconDiv = document.createElement("div"); iconDiv.className = "lexique-icon"; - iconDiv.style.backgroundColor = "#ccc"; - // Le label affichant le nom du lexique const labelSpan = document.createElement("span"); labelSpan.className = "lexique-label"; labelSpan.textContent = lexiconName; - // La case à cocher servant à sélectionner le lexique pour l'ajout d'un mot + // Conteneur pour la case à cocher avec tooltip + const checkboxContainer = document.createElement("label"); + checkboxContainer.className = "tooltip-container lexique-checkbox-container"; + const addCheckbox = document.createElement("input"); addCheckbox.type = "checkbox"; - addCheckbox.className = "lexique-add-checkbox"; + addCheckbox.className = "lexique-checkbox"; addCheckbox.dataset.lexiconId = lexiconId; - // Le bouton pour activer/désactiver le surlignage + const checkboxTooltip = document.createElement("span"); + checkboxTooltip.className = "tooltip"; + checkboxTooltip.textContent = "Ajouter le mot à ce lexique"; + + // Conteneur pour le bouton de surlignage avec tooltip const highlightButton = document.createElement("button"); - highlightButton.className = "lexique-highlight-toggle"; + highlightButton.className = "tooltip-container lexique-highlight-toggle"; highlightButton.dataset.lexiconId = lexiconId; highlightButton.dataset.active = active ? "true" : "false"; const feutreIcon = document.createElement("img"); - feutreIcon.src = "/icons/feutre.png"; // Chemin de ton fichier SVG + feutreIcon.src = "/icons/feutre.png"; feutreIcon.alt = "Feutre"; feutreIcon.className = "feutre-icon"; - const tooltip = document.createElement("span"); - tooltip.className = "tooltip"; - tooltip.textContent = "Activer/Désactiver le surlignage des mots du lexique"; - - highlightButton.appendChild(feutreIcon); + const highlightTooltip = document.createElement("span"); + highlightTooltip.className = "tooltip"; + highlightTooltip.textContent = "Activer/Désactiver le surlignage des mots du lexique"; - // Gestion du clic sur le bouton de surlignage + // Gestion du clic pour activer/désactiver le surlignage highlightButton.addEventListener("click", async () => { let currentState = highlightButton.dataset.active === "true"; let newState = !currentState; try { - // Envoi d'un message pour demander au background de changer l'état de surlignage await browser.runtime.sendMessage({ action: "toggleLexiconHighlight", lexiconId, isActive: newState, }); - - // Mise à jour de l'état et du bouton highlightButton.dataset.active = newState ? "true" : "false"; } catch (error) { console.error("Erreur lors du toggle de surlignage pour le lexique", lexiconId, ":", error); } }); - highlightButton.addEventListener("mouseover", () => { - tooltip.style.opacity = "1"; - }); - highlightButton.addEventListener("mouseleave", () => { - tooltip.style.opacity = "0"; - }); + // Assemblage + highlightButton.appendChild(feutreIcon); + highlightButton.appendChild(highlightTooltip); + checkboxContainer.appendChild(addCheckbox); + checkboxContainer.appendChild(checkboxTooltip); - // Assemblage de l'élément du lexique lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); - lexiqueDiv.appendChild(addCheckbox); - highlightButton.appendChild(tooltip); + lexiqueDiv.appendChild(checkboxContainer); lexiqueDiv.appendChild(highlightButton); lexiquesContainer.appendChild(lexiqueDiv); - - // Vérification de la position pour éviter la coupure du tooltip - setTimeout(() => { - const rect = highlightButton.getBoundingClientRect(); - const screenWidth = window.innerWidth; - - if (rect.left < 100) { - highlightButton.classList.add("left"); - } else if (rect.right > screenWidth - 100) { - highlightButton.classList.add("right"); - } - }, 100); }); + + // Ajustement dynamique des tooltips pour éviter qu'ils ne soient coupés + setTimeout(() => { + const containers = document.querySelectorAll('.tooltip-container'); + const menuRect = document.getElementById("menu").getBoundingClientRect(); + containers.forEach(container => { + container.classList.remove('left', 'right'); + const rect = container.getBoundingClientRect(); + // Si le conteneur est trop proche du bord gauche du menu + if (rect.left < menuRect.left + 50) { + container.classList.add("left"); + } + // Si le conteneur est trop proche du bord droit du menu + else if (rect.right > menuRect.right - 50) { + container.classList.add("right"); + } + }); + }, 100); } + function initModal() { console.log("initModal appelé"); const modalOverlay = document.getElementById("modalOverlay"); -- GitLab From f66780c18ae8abfc8e7e53f294d67a08161de185 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sun, 9 Feb 2025 14:59:42 +0100 Subject: [PATCH 08/23] Fermeture des blocs ouverture extension --- "barre_lat\303\251rale/sidebar.html" | 8 +++---- "barre_lat\303\251rale/sidebar.js" | 35 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 54335af..40e9ed6 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -361,9 +361,9 @@ <div id="menu"> <div class="block-header"> <h3>Lexiques</h3> - <button class="toggle-btn"></button> + <button class="toggle-btn">+</button> </div> - <div id="menuContent" class="block-content"> + <div id="menuContent" class="block-content hidden"> <div id="lexiques">Chargement...</div> </div> </div> @@ -374,7 +374,7 @@ <h3>Mot sélectionné</h3> <button class="toggle-btn"></button> </div> - <div id="etatContent" class="block-content"> + <div id="etatContent" class="block-content hidden"> <p id="motSelectionne">Aucun mot sélectionné</p> <p id="lexiconResult"></p> <div id="add-to-lexiques" style="display: none;"> @@ -391,7 +391,7 @@ <h3>Définitions</h3> <button class="toggle-btn"></button> </div> - <div id="definitionContent" class="block-content"> + <div id="definitionContent" class="block-content hidden"> <!-- Définitions des lexiques de l'utilisateur --> <div id="mesLexiquesContainer"> <h4>📚 Mes lexiques</h4> diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index cca0470..2bf8125 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -571,5 +571,40 @@ document.addEventListener("DOMContentLoaded", async () => { btn.textContent = content.classList.contains("hidden") ? "+" : "–"; } }); + + document.querySelectorAll('.block-content').forEach(block => { + block.classList.add('hidden'); + }); + + document.querySelectorAll('.toggle-btn').forEach(btn => { + // Forcer l'affichage initial à "+" + btn.textContent = '+'; + btn.style.fontSize = '15px'; + + // Gestion du clic sur le bouton + btn.addEventListener('click', (event) => { + event.stopPropagation(); + const header = btn.parentElement; + const content = header.nextElementSibling; + if (content) { + content.classList.toggle('hidden'); + // Mettre à jour le texte du bouton selon l'état du bloc + btn.textContent = content.classList.contains('hidden') ? '+' : '–'; + } + }); + }); + }); +}); + +document.querySelectorAll('.toggle-btn').forEach(btn => { + btn.addEventListener('click', function() { + const blockContent = this.parentElement.nextElementSibling; + if (blockContent.classList.contains('hidden')) { + blockContent.classList.remove('hidden'); + this.textContent = '–'; // affiche le symbole pour fermer + } else { + blockContent.classList.add('hidden'); + this.textContent = '+'; // affiche le symbole pour ouvrir + } }); }); -- GitLab From cd6332be8763092f1b900f8db7ad71df5a46d65d Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sun, 9 Feb 2025 17:13:32 +0100 Subject: [PATCH 09/23] Correction affichage tooltips --- "barre_lat\303\251rale/sidebar.html" | 40 +++++++++++++++++++++++++--- "barre_lat\303\251rale/sidebar.js" | 29 ++++++++++++-------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 40e9ed6..28f7552 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -174,7 +174,7 @@ transform: translateX(-50%); background-color: rgba(0,0,0,0.75); color: #fff; - font-size: 12px !important; + font-size: 14px !important; font-weight: lighter !important; padding: 6px 10px; border-radius: 5px; @@ -238,7 +238,6 @@ background: none; border: none; cursor: pointer; - font-size: 16px; padding: 2px; transition: transform 0.2s ease-in-out; width: 15%; @@ -251,13 +250,46 @@ filter: brightness(0) saturate(100%) invert(40%) sepia(0%) saturate(0%) hue-rotate(0deg); transition: filter 0.3s ease-in-out; } + .lexique-highlight-toggle[data-active="true"] .feutre-icon { filter: brightness(0) saturate(100%) invert(83%) sepia(89%) saturate(588%) hue-rotate(360deg); } - .lexique-highlight-toggle:hover { - transform: scale(1.1); + + /* Cibler les tooltips à l'intérieur d'un bouton de surlignage */ + button.lexique-highlight-toggle .tooltip { + /* Réinitialiser toute influence du style global du bouton */ + all: unset; + /* Appliquer les styles désirés pour le tooltip */ + display: block; + box-sizing: border-box; + position: absolute; + bottom: 120%; + left: 50%; + transform: translateX(-50%) translateY(-5px); + background-color: rgba(0, 0, 0, 0.75); + color: #fff; + font-size: 14px; + font-weight: lighter; + padding: 6px 10px; + border-radius: 5px; + white-space: normal; + overflow-wrap: break-word; + width: 180px; + text-align: center; + opacity: 0; + transition: opacity 0.3s ease-in-out, transform 0.2s ease-in-out; + pointer-events: none; + z-index: 10; + line-height: normal; + } + + /* Lors du survol du conteneur, afficher le tooltip */ + button.lexique-highlight-toggle:hover .tooltip { + opacity: 1; + transform: translateX(-50%) translateY(-5px); } + /* Autres styles divers */ .lexicon-section { margin-bottom: 10px; diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 2bf8125..0ec7390 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -278,24 +278,31 @@ function displayLexiconsWithCheckbox(lexicons) { lexiquesContainer.appendChild(lexiqueDiv); }); - // Ajustement dynamique des tooltips pour éviter qu'ils ne soient coupés + // Ajustement dynamique des tooltips setTimeout(() => { + const menu = document.getElementById("menu"); + const menuRect = menu.getBoundingClientRect(); const containers = document.querySelectorAll('.tooltip-container'); - const menuRect = document.getElementById("menu").getBoundingClientRect(); + containers.forEach(container => { - container.classList.remove('left', 'right'); - const rect = container.getBoundingClientRect(); - // Si le conteneur est trop proche du bord gauche du menu - if (rect.left < menuRect.left + 50) { - container.classList.add("left"); + const tooltip = container.querySelector('.tooltip'); + if (!tooltip) return; + + tooltip.style.left = '50%'; + tooltip.style.transform = 'translateX(-50%) translateY(-5px)'; + + const tooltipRect = tooltip.getBoundingClientRect(); + if (tooltipRect.left < menuRect.left) { + const overflowLeft = menuRect.left - tooltipRect.left; + tooltip.style.transform = `translateX(calc(-100% + ${overflowLeft}px)) translateY(-5px)`; } - // Si le conteneur est trop proche du bord droit du menu - else if (rect.right > menuRect.right - 50) { - container.classList.add("right"); + else if (tooltipRect.right > menuRect.right) { + const overflowRight = tooltipRect.right - menuRect.right; + tooltip.style.transform = `translateX(calc(-100% - ${overflowRight}px)) translateY(-5px)`; } }); }, 100); -} +} -- GitLab From ed17ad8f12fa2358df09191b7460d6c17e0502f7 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sun, 9 Feb 2025 17:22:12 +0100 Subject: [PATCH 10/23] Correction ouverture automatique bloc Lexiques --- "barre_lat\303\251rale/sidebar.js" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 0ec7390..33bf220 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -348,6 +348,7 @@ async function handleAuthButtonClick() { * et les lexiques cochés, puis on appelle AddWord. */ async function handleAddWordClick() { + openBlock("menuContent"); // 1) Vérifier la présence du token et du mot if (!authToken) { console.warn("âš ï¸ Pas de token d'authentification : impossible d'ajouter le mot."); @@ -554,7 +555,7 @@ document.addEventListener("DOMContentLoaded", async () => { }); } - // Bouton "Ajouter au(x) lexique(s)" + // Bouton "Ajouter le mot sélectionné" const addWordButton = document.getElementById("add-word-button"); if (addWordButton) { addWordButton.addEventListener("click", handleAddWordClick); -- GitLab From 6ef851cfa48b212ff7fd3c9485d85e70b51d4315 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Sun, 9 Feb 2025 17:26:54 +0100 Subject: [PATCH 11/23] =?UTF-8?q?Fermeture=20automatiquement=20blocs=20d?= =?UTF-8?q?=C3=A9connexion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.js" | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 33bf220..289ed8c 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -88,6 +88,19 @@ async function refreshSidebarState() { if (isLoggedIn) { await fetchLexicons(); } else { + // Si l'utilisateur n'est pas connecté, on ferme tous les blocs + document.querySelectorAll('.block-content').forEach(block => { + block.classList.add('hidden'); + // Mise à jour des boutons de bascule associés pour afficher le symbole "+" + const header = block.previousElementSibling; + if (header) { + const toggleBtn = header.querySelector(".toggle-btn"); + if (toggleBtn) { + toggleBtn.textContent = '+'; + } + } + }); + const lexiquesContainer = document.getElementById("lexiques"); if (lexiquesContainer) { lexiquesContainer.textContent = "Veuillez vous connecter pour voir vos lexiques."; -- GitLab From 5893ca872d2d3387ae9946218a937c1a4ef84314 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:05:04 +0100 Subject: [PATCH 12/23] =?UTF-8?q?Affichage=20automatique=20d=C3=A9finition?= =?UTF-8?q?s=20menu=20navigateur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.js" | 56 +++++-- manifest.json | 5 +- menu_contextuel/browser_context_menu.js | 207 +++++++++++++++++------- 3 files changed, 194 insertions(+), 74 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index 289ed8c..a6ac96e 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -382,8 +382,8 @@ async function handleAddWordClick() { return; } - // 2) Récupérer les IDs des lexiques sélectionnés (cases à cocher “add-checkboxâ€) - const checkboxList = document.querySelectorAll("#lexiques .lexique-add-checkbox:checked"); + // 2) Récupérer les IDs des lexiques sélectionnés + const checkboxList = document.querySelectorAll("#lexiques .lexique-checkbox:checked"); const selectedLexiconIds = Array.from(checkboxList).map(cb => parseInt(cb.dataset.lexiconId, 10)); if (selectedLexiconIds.length === 0) { @@ -465,22 +465,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; - } else { - console.warn("âš ï¸ Ã‰lément #motSelectionne introuvable."); - } - const lexiconResultElement = document.getElementById("lexiconResult"); - if (lexiconResultElement) { - lexiconResultElement.innerHTML = ""; - } - openBlock("etatContent"); + 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 = ""; } - break; + openBlock("etatContent"); + } + break; case "getDefinition": if (message.selectedText) { @@ -514,6 +514,28 @@ browser.runtime.onMessage.addListener(async (message) => { case "authStatusChanged": break; + case "wordAdded": + { + // Affichage du message de succès dans la sidebar + const lexiconResultElement = document.getElementById("lexiconResult"); + if (lexiconResultElement) { + lexiconResultElement.innerHTML += + "<br>✅ Mot <strong>" + message.selectedWord + "</strong> ajouté avec succès dans : " + + message.lexiconIds.join(", ") + "."; + } + } + break; + + case "wordAddFailed": + { + // Affichage du message d'erreur dans la sidebar + const lexiconResultElement = document.getElementById("lexiconResult"); + if (lexiconResultElement) { + lexiconResultElement.textContent = "Erreur lors de l'ajout du mot : " + message.error; + } + } + break; + default: console.warn("âš ï¸ Action inconnue reçue :", message.action); } diff --git a/manifest.json b/manifest.json index c2b94ca..b652cb0 100644 --- a/manifest.json +++ b/manifest.json @@ -22,8 +22,9 @@ "scripts": [ "background/background.js", "definitions.js", - "menu_contextuel/browser_context_menu.js", - "api.js"], + "api.js", + "menu_contextuel/browser_context_menu.js" + ], "persistent": true }, diff --git a/menu_contextuel/browser_context_menu.js b/menu_contextuel/browser_context_menu.js index a2ba1fa..8528524 100644 --- a/menu_contextuel/browser_context_menu.js +++ b/menu_contextuel/browser_context_menu.js @@ -1,6 +1,7 @@ console.log("browser_context_menu.js chargé correctement"); let authToken = null; +let selectedLexicons = new Set(); /** * Charge le token depuis le stockage local et le stocke dans la variable globale authToken. @@ -15,9 +16,12 @@ async function loadAuthToken() { } } -// ───────────────────────────────────────────────────────────────────────────── -// Création du menu contextuel en fonction de l'authentification -// ───────────────────────────────────────────────────────────────────────────── +/** + * Crée le menu contextuel en fonction de l'authentification. + * Si l'utilisateur est connecté, on ajoute un item pour la recherche et + * un menu parent pour l'ajout du mot avec des cases à cocher pour chaque lexique + * et un item de confirmation. + */ async function createContextMenu() { await browser.contextMenus.removeAll(); @@ -30,15 +34,58 @@ async function createContextMenu() { icons: { "16": "icons/quel_lexique.png" }, }); - // Item 2 : Ajouter un mot au lexique personnel + // Menu parent pour ajouter le mot dans les lexiques choisis browser.contextMenus.create({ - id: "addtoLexicon", - title: "Ajouter ce mot à mon lexique", + id: "parentAddLexicon", + title: "Ajouter ce mot à …", contexts: ["selection"], - icons: { "16": "icons/ajout_lexique.png" }, + }); + + // Récupérer dynamiquement les lexiques + let lexicons = []; + try { + lexicons = await window.getLexicons(authToken); + } catch (error) { + console.error("Erreur lors de la récupération des lexiques :", error); + } + + if (Array.isArray(lexicons) && lexicons.length > 0) { + lexicons.forEach(lexicon => { + let title = ""; + if (lexicon.category === "User") { + title = `Lexique personnel (${(lexicon.user && lexicon.user.pseudo) || "Inconnu"}) [${lexicon.id}]`; + } else { + title = `Lexique de groupe (${(lexicon.group && lexicon.group.name) || "Inconnu"}) [${lexicon.id}]`; + } + browser.contextMenus.create({ + id: `addWord_${lexicon.id}`, + title: title, + type: "checkbox", + contexts: ["selection"], + parentId: "parentAddLexicon", + checked: false + }); + }); + } else { + browser.contextMenus.create({ + id: "noLexiconsFound", + title: "Aucun lexique trouvé", + contexts: ["selection"], + parentId: "parentAddLexicon", + enabled: false + }); + } + + // Item de confirmation pour lancer l'ajout dans les lexiques sélectionnés + browser.contextMenus.create({ + id: "confirmAddWord", + title: "Confirmer l'ajout", + contexts: ["selection"], + parentId: "parentAddLexicon", }); } + // Séparateur browser.contextMenus.create({ id: "separatorExtension", type: "separator", @@ -59,6 +106,7 @@ async function createContextMenu() { contexts: ["all"], }); + // Item de connexion/déconnexion browser.contextMenus.create({ id: "login", title: authToken ? "Se déconnecter de BaLex" : "Se connecter à BaLex", @@ -87,7 +135,8 @@ browser.storage.onChanged.addListener((changes, area) => { // ───────────────────────────────────────────────────────────────────────────── browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log("Item de menu cliqué :", info.menuItemId); - + + // Action pour le bouton de connexion/déconnexion if (info.menuItemId === "login") { console.log("🔄 Action login/déconnexion demandée."); if (typeof actuallyOpenLoginPage === "function") { @@ -102,7 +151,8 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { console.warn("Aucun texte sélectionné pour cette action :", info.menuItemId); return; } - console.log(`📩 Texte sélectionné : ${info.selectionText}`); + const selectedText = info.selectionText.trim(); + console.log(`📩 Texte sélectionné : ${selectedText}`); switch (info.menuItemId) { case "searchInLexicons": @@ -110,46 +160,122 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); return; } - await searchInLexicons(info.selectionText); + await searchInLexicons(selectedText); break; - case "addtoLexicon": + case "confirmAddWord": if (!authToken) { alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); return; } - await addWordToLexicon(info.selectionText); + if (!selectedText || selectedText === "Aucun mot sélectionné") { + console.warn("âš ï¸ Aucun mot à ajouter."); + browser.runtime.sendMessage({ + action: "wordAddFailed", + error: "Aucun mot à ajouter." + }); + return; + } + if (selectedLexicons.size === 0) { + alert("Veuillez sélectionner au moins un lexique."); + return; + } + { + // Vérifier si le mot existe déjà dans les lexiques sélectionnés + let definitions = []; + try { + definitions = await window.fetchLexiconDefinitions(selectedText); + } catch (error) { + console.error("Erreur lors de la récupération des définitions pour vérification :", error); + } + const existingLexiconIds = new Set(); + if (Array.isArray(definitions)) { + for (const def of definitions) { + if (selectedLexicons.has(def.lexiconId)) { + existingLexiconIds.add(def.lexiconId); + } + } + } + if (existingLexiconIds.size > 0) { + alert(`Le mot "${selectedText}" existe déjà dans le(s) lexique(s) : ${Array.from(existingLexiconIds).join(", ")}`); + browser.runtime.sendMessage({ + action: "wordAlreadyExists", + selectedWord: selectedText, + lexiconIds: Array.from(existingLexiconIds) + }); + return; + } + // On détermine quels lexiques ajouter (ceux non existants) + const lexiconsToAdd = Array.from(selectedLexicons).filter(id => !existingLexiconIds.has(id)); + if (lexiconsToAdd.length === 0) { + return; // Rien à ajouter + } + // Envoi de la requête d'ajout + try { + console.log(`📡 Envoi de l'ajout du mot "${selectedText}" dans le(s) lexique(s) :`, lexiconsToAdd); + const result = await window.AddWord(authToken, selectedText, lexiconsToAdd, false); + console.log("✅ Réponse API :", result); + await browser.runtime.sendMessage({ action: "refreshUI" }); + browser.runtime.sendMessage({ + action: "wordAdded", + selectedWord: selectedText, + lexiconIds: lexiconsToAdd, + result + }); + // Réinitialiser la sélection après ajout + selectedLexicons.clear(); + } catch (error) { + console.error("⌠Erreur lors de l’ajout du mot :", error); + alert("⌠Une erreur est survenue lors de l’ajout du mot : " + error.message); + browser.runtime.sendMessage({ + action: "wordAddFailed", + selectedWord: selectedText, + lexiconIds: Array.from(selectedLexicons), + error: error.message + }); + } + } break; - case "getDefinition": - await getDefinition(info.selectionText); - break; - default: - console.error(`⌠Action inconnue : ${info.menuItemId}`); + // Gérer les items de type "checkbox" + if (info.menuItemId.startsWith("addWord_")) { + const lexiconId = parseInt(info.menuItemId.replace("addWord_", ""), 10); + if (isNaN(lexiconId)) { + console.error("⌠ID de lexique invalide :", info.menuItemId); + return; + } + if (info.checked) { + selectedLexicons.add(lexiconId); + } else { + selectedLexicons.delete(lexiconId); + } + console.log("Lexicons sélectionnés :", Array.from(selectedLexicons)); + } else if (info.menuItemId === "getDefinition") { + await browser.runtime.sendMessage({ + action: "getDefinition", + selectedText: info.selectionText.trim(), + }); + return; + } else { + console.error(`⌠Action inconnue : ${info.menuItemId}`); + } + break; } }); // ───────────────────────────────────────────────────────────────────────────── -// Fonctions liées aux définitions (definitions.js) +// Fonctions liées aux définitions // ───────────────────────────────────────────────────────────────────────────── - -/** - * 1) Recherche de la définition combinée (lexiques + Wiktionnaire) - * et envoi des résultats pour affichage. - */ async function getDefinition(selectedText) { try { let lexiconDefs = []; if (authToken) { lexiconDefs = await fetchLexiconDefinitions(selectedText); } - const wikiDefs = await fetchWiktionaryDefinition(selectedText); - const allDefinitions = [...lexiconDefs, ...wikiDefs]; console.log("📠Définitions combinées :", allDefinitions); - browser.runtime.sendMessage({ action: "showDefinitions", selectedText, @@ -160,13 +286,9 @@ async function getDefinition(selectedText) { } } -/** - * 2) Recherche dans les lexiques pour savoir dans quels lexiques se trouve le mot. - */ async function searchInLexicons(selectedText) { try { console.log("🔎 Recherche dans mes lexiques :", selectedText); - const allDefinitions = await fetchLexiconDefinitions(selectedText); if (!allDefinitions || allDefinitions.length === 0) { console.log("⌠Aucun lexique trouvé pour ce mot."); @@ -177,21 +299,17 @@ async function searchInLexicons(selectedText) { }); return; } - const lexMap = new Map(); for (const def of allDefinitions) { if (def.lexiconId) { lexMap.set(def.lexiconId, def.source); } } - 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, @@ -207,24 +325,3 @@ async function searchInLexicons(selectedText) { } } -/** - * 3) Ajouter un mot dans le lexique personnel. - */ -async function addWordToLexicon(selectedText) { - try { - console.log("🔠Ajout du mot à mon lexique :", selectedText); - 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 951838ff1542c5e94f0ce3e0152d52dfd3b51f2b Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:28:03 +0100 Subject: [PATCH 13/23] =?UTF-8?q?Redirection=20ajout=20menu=20navigateur?= =?UTF-8?q?=20vers=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" | 28 +--- menu_contextuel/browser_context_menu.js | 177 +++++------------------- 2 files changed, 36 insertions(+), 169 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.js" "b/barre_lat\303\251rale/sidebar.js" index a6ac96e..6768d2f 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ "b/barre_lat\303\251rale/sidebar.js" @@ -507,35 +507,17 @@ browser.runtime.onMessage.addListener(async (message) => { console.log("📚 Résultat des lexiques reçus :", message.lexicons); window.displayLexiconResults(message.lexicons); break; - + + case "addToLexicon": + handleAddWordClick(); + break; + case "toggleAuth": break; case "authStatusChanged": break; - case "wordAdded": - { - // Affichage du message de succès dans la sidebar - const lexiconResultElement = document.getElementById("lexiconResult"); - if (lexiconResultElement) { - lexiconResultElement.innerHTML += - "<br>✅ Mot <strong>" + message.selectedWord + "</strong> ajouté avec succès dans : " + - message.lexiconIds.join(", ") + "."; - } - } - break; - - case "wordAddFailed": - { - // Affichage du message d'erreur dans la sidebar - const lexiconResultElement = document.getElementById("lexiconResult"); - if (lexiconResultElement) { - lexiconResultElement.textContent = "Erreur lors de l'ajout du mot : " + message.error; - } - } - break; - default: console.warn("âš ï¸ Action inconnue reçue :", message.action); } diff --git a/menu_contextuel/browser_context_menu.js b/menu_contextuel/browser_context_menu.js index 8528524..4f9f7c6 100644 --- a/menu_contextuel/browser_context_menu.js +++ b/menu_contextuel/browser_context_menu.js @@ -34,54 +34,12 @@ async function createContextMenu() { icons: { "16": "icons/quel_lexique.png" }, }); - // Menu parent pour ajouter le mot dans les lexiques choisis + // Item 2 : Ajouter le mot au(x) lexique(s) de l’utilisateur browser.contextMenus.create({ - id: "parentAddLexicon", - title: "Ajouter ce mot à …", + id: "addToLexicon", + title: "Ajouter ce mot à mes lexiques", contexts: ["selection"], - }); - - // Récupérer dynamiquement les lexiques - let lexicons = []; - try { - lexicons = await window.getLexicons(authToken); - } catch (error) { - console.error("Erreur lors de la récupération des lexiques :", error); - } - - if (Array.isArray(lexicons) && lexicons.length > 0) { - lexicons.forEach(lexicon => { - let title = ""; - if (lexicon.category === "User") { - title = `Lexique personnel (${(lexicon.user && lexicon.user.pseudo) || "Inconnu"}) [${lexicon.id}]`; - } else { - title = `Lexique de groupe (${(lexicon.group && lexicon.group.name) || "Inconnu"}) [${lexicon.id}]`; - } - browser.contextMenus.create({ - id: `addWord_${lexicon.id}`, - title: title, - type: "checkbox", - contexts: ["selection"], - parentId: "parentAddLexicon", - checked: false - }); - }); - } else { - browser.contextMenus.create({ - id: "noLexiconsFound", - title: "Aucun lexique trouvé", - contexts: ["selection"], - parentId: "parentAddLexicon", - enabled: false - }); - } - - // Item de confirmation pour lancer l'ajout dans les lexiques sélectionnés - browser.contextMenus.create({ - id: "confirmAddWord", - title: "Confirmer l'ajout", - contexts: ["selection"], - parentId: "parentAddLexicon", + icons: { "16": "icons/ajout_lexique.png" }, }); } @@ -151,9 +109,33 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { console.warn("Aucun texte sélectionné pour cette action :", info.menuItemId); return; } + const selectedText = info.selectionText.trim(); console.log(`📩 Texte sélectionné : ${selectedText}`); + // Item "Ajouter ce mot à mes lexiques" + if (info.menuItemId === "addToLexicon") { + if (!authToken) { + alert("âš ï¸ Vous devez être connecté pour ajouter un mot à un lexique."); + return; + } + browser.runtime.sendMessage({ + action: "addToLexicon", + selectedText, + }); + return; + } + + // Item "Obtenir une définition" + if (info.menuItemId === "getDefinition") { + await browser.runtime.sendMessage({ + action: "getDefinition", + selectedText, + }); + return; + } + + // Item "Rechercher dans mes lexiques" switch (info.menuItemId) { case "searchInLexicons": if (!authToken) { @@ -162,106 +144,9 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { } await searchInLexicons(selectedText); break; - - case "confirmAddWord": - if (!authToken) { - alert("âš ï¸ Vous devez être connecté pour utiliser cette fonction."); - return; - } - if (!selectedText || selectedText === "Aucun mot sélectionné") { - console.warn("âš ï¸ Aucun mot à ajouter."); - browser.runtime.sendMessage({ - action: "wordAddFailed", - error: "Aucun mot à ajouter." - }); - return; - } - if (selectedLexicons.size === 0) { - alert("Veuillez sélectionner au moins un lexique."); - return; - } - { - // Vérifier si le mot existe déjà dans les lexiques sélectionnés - let definitions = []; - try { - definitions = await window.fetchLexiconDefinitions(selectedText); - } catch (error) { - console.error("Erreur lors de la récupération des définitions pour vérification :", error); - } - const existingLexiconIds = new Set(); - if (Array.isArray(definitions)) { - for (const def of definitions) { - if (selectedLexicons.has(def.lexiconId)) { - existingLexiconIds.add(def.lexiconId); - } - } - } - if (existingLexiconIds.size > 0) { - alert(`Le mot "${selectedText}" existe déjà dans le(s) lexique(s) : ${Array.from(existingLexiconIds).join(", ")}`); - browser.runtime.sendMessage({ - action: "wordAlreadyExists", - selectedWord: selectedText, - lexiconIds: Array.from(existingLexiconIds) - }); - return; - } - // On détermine quels lexiques ajouter (ceux non existants) - const lexiconsToAdd = Array.from(selectedLexicons).filter(id => !existingLexiconIds.has(id)); - if (lexiconsToAdd.length === 0) { - return; // Rien à ajouter - } - // Envoi de la requête d'ajout - try { - console.log(`📡 Envoi de l'ajout du mot "${selectedText}" dans le(s) lexique(s) :`, lexiconsToAdd); - const result = await window.AddWord(authToken, selectedText, lexiconsToAdd, false); - console.log("✅ Réponse API :", result); - await browser.runtime.sendMessage({ action: "refreshUI" }); - browser.runtime.sendMessage({ - action: "wordAdded", - selectedWord: selectedText, - lexiconIds: lexiconsToAdd, - result - }); - // Réinitialiser la sélection après ajout - selectedLexicons.clear(); - } catch (error) { - console.error("⌠Erreur lors de l’ajout du mot :", error); - alert("⌠Une erreur est survenue lors de l’ajout du mot : " + error.message); - browser.runtime.sendMessage({ - action: "wordAddFailed", - selectedWord: selectedText, - lexiconIds: Array.from(selectedLexicons), - error: error.message - }); - } - } - break; - - default: - // Gérer les items de type "checkbox" - if (info.menuItemId.startsWith("addWord_")) { - const lexiconId = parseInt(info.menuItemId.replace("addWord_", ""), 10); - if (isNaN(lexiconId)) { - console.error("⌠ID de lexique invalide :", info.menuItemId); - return; - } - if (info.checked) { - selectedLexicons.add(lexiconId); - } else { - selectedLexicons.delete(lexiconId); - } - console.log("Lexicons sélectionnés :", Array.from(selectedLexicons)); - } else if (info.menuItemId === "getDefinition") { - await browser.runtime.sendMessage({ - action: "getDefinition", - selectedText: info.selectionText.trim(), - }); - return; - } else { - console.error(`⌠Action inconnue : ${info.menuItemId}`); - } - break; - } + } + + console.error(`⌠Action inconnue : ${info.menuItemId}`); }); // ───────────────────────────────────────────────────────────────────────────── -- GitLab From 025f01fa50dc85ff76c981fde1424a5b583be8ce Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Mon, 10 Feb 2025 15:37:55 +0100 Subject: [PATCH 14/23] =?UTF-8?q?Bouton=20ajouter=20menu=20contextuel=20pe?= =?UTF-8?q?rsonnalis=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "barre_lat\303\251rale/sidebar.html" | 3 + menu_contextuel/custom_context_menu.js | 214 +++++++++++++++++-------- 2 files changed, 146 insertions(+), 71 deletions(-) diff --git "a/barre_lat\303\251rale/sidebar.html" "b/barre_lat\303\251rale/sidebar.html" index 28f7552..6724c96 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ "b/barre_lat\303\251rale/sidebar.html" @@ -309,6 +309,9 @@ .lexicon-content { margin-top: 5px; } + .lexicon-option { + margin-right: -10px; + } #mesLexiquesList { display: inline; padding: 0; diff --git a/menu_contextuel/custom_context_menu.js b/menu_contextuel/custom_context_menu.js index 510295e..1852073 100644 --- a/menu_contextuel/custom_context_menu.js +++ b/menu_contextuel/custom_context_menu.js @@ -26,6 +26,19 @@ async function loadAuthToken() { } } +/** + * Récupère les lexiques via l'API. + * On utilise getLexicons(authToken, "fr") et on vérifie si la réponse se trouve dans response.data. + */ +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 response = await callApi(url, authToken); + console.log("Réponse API dans getLexicons :", response); + return Array.isArray(response) ? response : (response.data || []); +} + /** * Crée le menu contextuel personnalisé (whiteBox) s'il n'existe pas déjà . */ @@ -34,8 +47,7 @@ function injectWhiteBox() { if (!whiteBox) { whiteBox = document.createElement("div"); whiteBox.id = WHITE_BOX_ID; - - // Définition de styles essentiels pour le positionnement et la visibilité + // Styles essentiels whiteBox.style.position = "absolute"; whiteBox.style.zIndex = "9999"; whiteBox.style.backgroundColor = "#fff"; @@ -43,26 +55,24 @@ function injectWhiteBox() { 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"); - - // Construction du HTML + // Construction du HTML du menu contextuel whiteBox.innerHTML = ` <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 --> + <!-- Bouton : 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) --> + <!-- Bouton : Obtenir une définition --> <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 --> + <!-- Bouton : Connexion --> <div class="icon-container" title="Connectez-vous à BaLex"> <img src="${loginPath}" alt="Se connecter" class="icon" id="loginButton" style="display: none;"> </div> @@ -71,42 +81,43 @@ function injectWhiteBox() { document.body.appendChild(whiteBox); setupWhiteBoxActions(); } + // Empêcher la propagation des clics dans le menu + whiteBox.addEventListener("mouseup", (e) => { + e.stopPropagation(); + }); return whiteBox; } /** - * Renvoie le whiteBox s'il existe, ou le crée via injectWhiteBox(). + * Renvoie le whiteBox s'il existe, ou le crée. */ function getOrCreateWhiteBox() { return document.getElementById(WHITE_BOX_ID) || injectWhiteBox(); } /** - * Configure les actions/boutons du menu contextuel. + * Configure les actions des boutons du menu contextuel. */ function setupWhiteBoxActions() { const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); const loginBtn = document.getElementById("loginButton"); - // Bouton : Ajouter le mot au lexique personnel - addLexiconBtn.onclick = async () => { - const selectedText = getSelectedWord(); - console.log("🔠Ajout au lexique :", selectedText); + // Bouton : Ajouter le mot au lexique + addLexiconBtn.onclick = async (e) => { + e.stopPropagation(); + e.preventDefault(); + const selectedText = getSelectedWord().trim(); + console.log("🔠Bouton Ajouter au lexique cliqué avec le mot :", selectedText); if (!selectedText) return; - if (authToken) { - await searchLexicon(selectedText); + await showPicker(e, selectedText); } else { - sendNotification( - "Connexion requise", - "âš ï¸ Veuillez vous connecter pour utiliser cette fonction.", - "icons/connexion.png" - ); + alert("Vous devez être connecté pour ajouter un mot."); } }; - // Bouton : Obtenir une définition (Babalex + Wiktionnaire) + // Bouton : Obtenir une définition getDefinitionBtn.onclick = () => { const selectedText = getSelectedWord().trim(); if (selectedText) { @@ -119,20 +130,14 @@ function setupWhiteBoxActions() { // Bouton : Connexion loginBtn.onclick = () => { - 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 d'authentification. + * Met à jour la visibilité des boutons du menu selon l'authentification. */ function updateMenuVisibility() { - // S'assurer que le whiteBox existe getOrCreateWhiteBox(); const addLexiconBtn = document.getElementById("addLexiconButton"); const getDefinitionBtn = document.getElementById("getDefinitionButton"); @@ -144,12 +149,10 @@ function updateMenuVisibility() { } if (authToken) { - // 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é => masquer "Ajouter", afficher "Définition" et "Connexion" addLexiconBtn.style.display = "none"; getDefinitionBtn.style.display = "inline-block"; loginBtn.style.display = "inline-block"; @@ -157,7 +160,7 @@ function updateMenuVisibility() { } /** - * Récupère le mot affiché dans #selectedWord. + * Récupère le texte affiché dans #selectedWord. */ function getSelectedWord() { const selectedWordElement = document.getElementById("selectedWord"); @@ -170,18 +173,17 @@ function getSelectedWord() { function showWhiteBox(event, selectedText) { const whiteBox = getOrCreateWhiteBox(); const selectedWordElement = document.getElementById("selectedWord"); - selectedWordElement.textContent = `${selectedText}`; + selectedWordElement.textContent = selectedText; - // Calculer la position du menu en fonction de la sélection const selection = window.getSelection(); - if (!selection.rangeCount) return; // sécurité au cas où + if (!selection.rangeCount) return; const range = selection.getRangeAt(0); const rect = range.getBoundingClientRect(); const top = rect.bottom + window.scrollY; const left = rect.right + window.scrollX; - whiteBox.style.left = `${left}px`; - whiteBox.style.top = `${top}px`; + whiteBox.style.left = left + "px"; + whiteBox.style.top = top + "px"; whiteBox.style.display = "block"; console.log("Affichage du menu contextuel avec le mot :", selectedText); @@ -195,15 +197,15 @@ function hideWhiteBox() { } } -// === Écoute des événements de sélection de texte (mouseup) === +// Écoute globale pour la sélection de texte document.addEventListener("mouseup", (event) => { + // Si le clic se fait à l'intérieur du whiteBox, ne rien faire + if (event.target.closest("#whiteBox")) return; const selectedText = window.getSelection().toString().trim(); if (selectedText) { - console.log("Événement de sélection détecté. Texte sélectionné :", selectedText); + console.log("Texte sélectionné :", selectedText); getOrCreateWhiteBox(); showWhiteBox(event, selectedText); - - // Envoi du mot sélectionné au background browser.runtime.sendMessage({ action: "mot_selectionne", selectedText, @@ -213,13 +215,11 @@ document.addEventListener("mouseup", (event) => { } }); -// Réécoute des messages envoyés +// Écoute des messages entrants browser.runtime.onMessage.addListener((message) => { if (message.action === "refreshUI") { console.log("🔄 Mise à jour du menu contextuel personnalisé."); - loadAuthToken().then(() => { - updateMenuVisibility(); - }); + loadAuthToken().then(updateMenuVisibility); } }); @@ -228,44 +228,116 @@ loadAuthToken().then(() => { 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(); - }); + console.log("🔄 Token modifié dans le stockage, mise à jour du menu contextuel."); + loadAuthToken().then(updateMenuVisibility); } }); + // ───────────────────────────────────────────────────────────────────────────── -// â–Œ Fonctions d'API Babalex pour l'ajout ou la vérification d'un mot +// Fonctions d'API pour l'ajout d'un mot via le picker // ───────────────────────────────────────────────────────────────────────────── -async function searchLexicon(selectedText) { - console.log("🔄 Recherche dans le lexique personnel pour :", selectedText); - try { - const lexicons = await getUserLexicons(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; - } +/** + * Crée (ou récupère) le picker de sélection des lexiques. + */ +function createPicker() { + let picker = document.getElementById("lexiconPicker"); + if (!picker) { + picker = document.createElement("div"); + picker.id = "lexiconPicker"; + // Styles pour le picker + picker.style.position = "absolute"; + picker.style.zIndex = "10000"; + picker.style.backgroundColor = "rgba(255, 255, 255, 0.95)"; + picker.style.border = "1px solid #ccc"; + picker.style.padding = "10px"; + picker.style.borderRadius = "4px"; + picker.style.boxShadow = "0 2px 10px rgba(0,0,0,0.3)"; + picker.style.display = "none"; + document.body.appendChild(picker); + } + return picker; +} - const entries = await getLexiconEntriesID(authToken, frenchLexicon.id); - const isWordPresent = entries.some( - (entry) => entry.graphy.toLowerCase() === selectedText.toLowerCase() - ); +/** + * Affiche le picker pour choisir le lexique dans lequel ajouter le mot. + * Pour chaque lexique, vérifie si le mot existe déjà dans ce lexique en appelant fetchLexiconDefinitions. + * S'il n'existe pas, appelle window.AddWord pour l'ajouter. + */ +async function showPicker(event, selectedText) { + console.log("showPicker appelé avec", event, selectedText); + const picker = createPicker(); + picker.innerHTML = ""; // Vider le picker - if (isWordPresent) { - alert(`✅ Le mot "${selectedText}" est présent dans votre lexique personnel.`); + try { + const lexicons = await getLexicons(authToken, "fr"); + console.log("Lexicons récupérés :", lexicons); + if (!Array.isArray(lexicons) || lexicons.length === 0) { + picker.innerHTML = "<p>Aucun lexique trouvé.</p>"; } else { - alert(`⌠Le mot "${selectedText}" n'est pas présent dans votre lexique personnel.`); + lexicons.forEach(lex => { + // Extraction des propriétés en se basant sur la logique de fetchLexicons() + const id = lex.id; + const name = lex.category === "User" + ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` + : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; + const iconURL = lex.iconURL || browser.runtime.getURL("icons/default_lexicon.png"); + + const iconDiv = document.createElement("div"); + iconDiv.className = "lexicon-option"; + iconDiv.dataset.lexiconId = id; + iconDiv.style.display = "inline-block"; + iconDiv.style.margin = "5px"; + iconDiv.style.cursor = "pointer"; + iconDiv.style.position = "relative"; + + const iconImg = document.createElement("img"); + iconImg.src = iconURL; + iconImg.alt = name; + iconImg.title = name; + iconImg.style.width = "32px"; + iconImg.style.height = "32px"; + + iconDiv.appendChild(iconImg); + picker.appendChild(iconDiv); + + iconDiv.addEventListener("click", async () => { + console.log(`Tentative d'ajout du mot "${selectedText}" au lexique ${id} (${name})`); + try { + // Vérifier si le mot existe déjà dans ce lexique + let definitions = []; + try { + definitions = await fetchLexiconDefinitions(selectedText); + } catch (err) { + console.error("Erreur lors de la récupération des définitions :", err); + } + const exists = Array.isArray(definitions) && definitions.some(def => def.lexiconId === id); + if (exists) { + alert(`Le mot "${selectedText}" existe déjà dans le lexique ${name}.`); + } else { + await window.AddWord(authToken, selectedText, [id], false); + alert(`Le mot "${selectedText}" a été ajouté dans le lexique ${name}.`); + } + picker.style.display = "none"; + } catch (error) { + console.error("Erreur lors de l'ajout du mot :", error); + alert(`Erreur : ${error.message}`); + } + }); + }); } + + // Positionner le picker en fonction de l'événement + console.log("Positionnement du picker en X:", event.pageX, "Y:", event.pageY); + picker.style.left = event.pageX + "px"; + picker.style.top = event.pageY + "px"; + picker.style.display = "block"; } catch (error) { - console.error("⌠Erreur lors de la recherche dans le lexique :", error); - alert(`Erreur lors de la recherche : ${error.message}`); + console.error("Erreur lors de la récupération des lexiques :", error); + picker.innerHTML = "<p>Erreur lors du chargement des lexiques.</p>"; + picker.style.display = "block"; } } -- GitLab From 08d0cad8d01dbbcf1ccc87066138bf119d12a78d Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:34:06 +0100 Subject: [PATCH 15/23] =?UTF-8?q?R=C3=A9organisation=20des=20dossiers/fich?= =?UTF-8?q?iers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manifest.json | 33 ++++++++---------- {icons => src/assets/icons}/ajout_lexique.png | Bin {icons => src/assets/icons}/connexion.png | Bin {icons => src/assets/icons}/definition.png | Bin .../assets/icons}/definition_wiktionnaire.png | Bin {icons => src/assets/icons}/feutre.png | Bin {icons => src/assets/icons}/logo.png | Bin {icons => src/assets/icons}/quel_lexique.png | Bin .../assets/icons}/recherche_lexique.png | Bin {background => src/background}/background.js | 0 .../context_menu}/browser_context_menu.js | 0 .../context_menu}/custom_context_menu.css | 0 .../context_menu}/custom_context_menu.js | 8 ++--- {menu_extension => src/options}/options.html | 0 {menu_extension => src/options}/options.js | 0 {menu_extension => src/popup}/popup.html | 0 {menu_extension => src/popup}/popup.js | 0 .../sidebar.html" => src/sidebar/sidebar.html | 4 +-- .../sidebar.js" => src/sidebar/sidebar.js | 2 +- api.js => src/utils/api.js | 0 definitions.js => src/utils/definitions.js | 0 21 files changed, 22 insertions(+), 25 deletions(-) rename {icons => src/assets/icons}/ajout_lexique.png (100%) rename {icons => src/assets/icons}/connexion.png (100%) rename {icons => src/assets/icons}/definition.png (100%) rename {icons => src/assets/icons}/definition_wiktionnaire.png (100%) rename {icons => src/assets/icons}/feutre.png (100%) rename {icons => src/assets/icons}/logo.png (100%) rename {icons => src/assets/icons}/quel_lexique.png (100%) rename {icons => src/assets/icons}/recherche_lexique.png (100%) rename {background => src/background}/background.js (100%) rename {menu_contextuel => src/context_menu}/browser_context_menu.js (100%) rename {menu_contextuel => src/context_menu}/custom_context_menu.css (100%) rename {menu_contextuel => src/context_menu}/custom_context_menu.js (97%) rename {menu_extension => src/options}/options.html (100%) rename {menu_extension => src/options}/options.js (100%) rename {menu_extension => src/popup}/popup.html (100%) rename {menu_extension => src/popup}/popup.js (100%) rename "barre_lat\303\251rale/sidebar.html" => src/sidebar/sidebar.html (99%) rename "barre_lat\303\251rale/sidebar.js" => src/sidebar/sidebar.js (99%) rename api.js => src/utils/api.js (100%) rename definitions.js => src/utils/definitions.js (100%) diff --git a/manifest.json b/manifest.json index b652cb0..642aaa8 100644 --- a/manifest.json +++ b/manifest.json @@ -20,58 +20,55 @@ "background": { "scripts": [ - "background/background.js", - "definitions.js", - "api.js", - "menu_contextuel/browser_context_menu.js" + "src/background/background.js", + "src/utils/definitions.js", + "src/utils/api.js", + "src/context_menu/browser_context_menu.js" ], "persistent": true }, "browser_action": { - "default_popup": "menu_extension/popup.html", + "default_popup": "src/popup/popup.html", "default_icon": { - "16": "icons/logo.png" + "16": "src/assets/icons/logo.png" }, "default_title": "ff2BaLex" }, "options_ui": { - "page": "menu_extension/options.html", + "page": "src/options/options.html", "open_in_tab": false }, "sidebar_action": { "default_title": "BaLex", - "default_panel": "barre_latérale/sidebar.html", + "default_panel": "src/sidebar/sidebar.html", "default_icon": { - "16": "icons/logo.png", - "48": "icons/icon-48.png" + "16": "src/assets/icons/logo.png", + "48": "src/assets/icons/icon-48.png" } }, "content_scripts": [ { "matches": ["<all_urls>"], - "js": ["api.js"] + "js": ["src/utils/api.js"] }, { "matches": ["<all_urls>"], - "js": ["menu_contextuel/custom_context_menu.js"], - "css": ["menu_contextuel/custom_context_menu.css"], + "js": ["src/context_menu/custom_context_menu.js"], + "css": ["src/context_menu/custom_context_menu.css"], "run_at": "document_end" } ], "web_accessible_resources": [ - "icons/*.png", - "menu_extension/*", - "barre_latérale/*", - "menu_contextuel/*" + "src/*" ], "icons": { - "16": "icons/logo.png" + "16": "src/assets/icons/logo.png" } } diff --git a/icons/ajout_lexique.png b/src/assets/icons/ajout_lexique.png similarity index 100% rename from icons/ajout_lexique.png rename to src/assets/icons/ajout_lexique.png diff --git a/icons/connexion.png b/src/assets/icons/connexion.png similarity index 100% rename from icons/connexion.png rename to src/assets/icons/connexion.png diff --git a/icons/definition.png b/src/assets/icons/definition.png similarity index 100% rename from icons/definition.png rename to src/assets/icons/definition.png diff --git a/icons/definition_wiktionnaire.png b/src/assets/icons/definition_wiktionnaire.png similarity index 100% rename from icons/definition_wiktionnaire.png rename to src/assets/icons/definition_wiktionnaire.png diff --git a/icons/feutre.png b/src/assets/icons/feutre.png similarity index 100% rename from icons/feutre.png rename to src/assets/icons/feutre.png diff --git a/icons/logo.png b/src/assets/icons/logo.png similarity index 100% rename from icons/logo.png rename to src/assets/icons/logo.png diff --git a/icons/quel_lexique.png b/src/assets/icons/quel_lexique.png similarity index 100% rename from icons/quel_lexique.png rename to src/assets/icons/quel_lexique.png diff --git a/icons/recherche_lexique.png b/src/assets/icons/recherche_lexique.png similarity index 100% rename from icons/recherche_lexique.png rename to src/assets/icons/recherche_lexique.png diff --git a/background/background.js b/src/background/background.js similarity index 100% rename from background/background.js rename to src/background/background.js diff --git a/menu_contextuel/browser_context_menu.js b/src/context_menu/browser_context_menu.js similarity index 100% rename from menu_contextuel/browser_context_menu.js rename to src/context_menu/browser_context_menu.js diff --git a/menu_contextuel/custom_context_menu.css b/src/context_menu/custom_context_menu.css similarity index 100% rename from menu_contextuel/custom_context_menu.css rename to src/context_menu/custom_context_menu.css diff --git a/menu_contextuel/custom_context_menu.js b/src/context_menu/custom_context_menu.js similarity index 97% rename from menu_contextuel/custom_context_menu.js rename to src/context_menu/custom_context_menu.js index 1852073..011478f 100644 --- a/menu_contextuel/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -56,9 +56,9 @@ function injectWhiteBox() { 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"); + const addLexiconPath = browser.runtime.getURL("src/assets/icons/ajout_lexique.png"); + const getDefinitionPath = browser.runtime.getURL("src/assets/icons/definition.png"); + const loginPath = browser.runtime.getURL("src/assets/icons/connexion.png"); // Construction du HTML du menu contextuel whiteBox.innerHTML = ` <p id="selectedWord" style="margin: 0; padding: 0;">Mot sélectionné : Aucun</p> @@ -284,7 +284,7 @@ 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 iconURL = lex.iconURL || browser.runtime.getURL("icons/default_lexicon.png"); + const iconURL = lex.iconURL || browser.runtime.getURL("src/assets/icons/default_lexicon.png"); const iconDiv = document.createElement("div"); iconDiv.className = "lexicon-option"; diff --git a/menu_extension/options.html b/src/options/options.html similarity index 100% rename from menu_extension/options.html rename to src/options/options.html diff --git a/menu_extension/options.js b/src/options/options.js similarity index 100% rename from menu_extension/options.js rename to src/options/options.js diff --git a/menu_extension/popup.html b/src/popup/popup.html similarity index 100% rename from menu_extension/popup.html rename to src/popup/popup.html diff --git a/menu_extension/popup.js b/src/popup/popup.js similarity index 100% rename from menu_extension/popup.js rename to src/popup/popup.js diff --git "a/barre_lat\303\251rale/sidebar.html" b/src/sidebar/sidebar.html similarity index 99% rename from "barre_lat\303\251rale/sidebar.html" rename to src/sidebar/sidebar.html index 6724c96..2327900 100644 --- "a/barre_lat\303\251rale/sidebar.html" +++ b/src/sidebar/sidebar.html @@ -4,8 +4,8 @@ <meta charset="UTF-8"> <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="../utils/api.js" defer></script> + <script src="../utils/definitions.js" defer></script> <script src="sidebar.js" defer></script> <style> diff --git "a/barre_lat\303\251rale/sidebar.js" b/src/sidebar/sidebar.js similarity index 99% rename from "barre_lat\303\251rale/sidebar.js" rename to src/sidebar/sidebar.js index 6768d2f..c5707e9 100644 --- "a/barre_lat\303\251rale/sidebar.js" +++ b/src/sidebar/sidebar.js @@ -254,7 +254,7 @@ function displayLexiconsWithCheckbox(lexicons) { highlightButton.dataset.active = active ? "true" : "false"; const feutreIcon = document.createElement("img"); - feutreIcon.src = "/icons/feutre.png"; + feutreIcon.src = "../assets/icons/feutre.png"; feutreIcon.alt = "Feutre"; feutreIcon.className = "feutre-icon"; diff --git a/api.js b/src/utils/api.js similarity index 100% rename from api.js rename to src/utils/api.js diff --git a/definitions.js b/src/utils/definitions.js similarity index 100% rename from definitions.js rename to src/utils/definitions.js -- GitLab From 3f4965ad0d5e7f93b22f397a80a924d0091a8920 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 11 Feb 2025 17:38:46 +0100 Subject: [PATCH 16/23] =?UTF-8?q?Ic=C3=B4nes=20lexiques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manifest.json | 11 +++-- src/assets/lexicon_icon.js | 52 +++++++++++++++++++++ src/context_menu/custom_context_menu.js | 62 +++++++++---------------- src/sidebar/sidebar.html | 1 + src/sidebar/sidebar.js | 12 +++-- src/utils/api.js | 4 +- src/utils/definitions.js | 2 +- 7 files changed, 92 insertions(+), 52 deletions(-) create mode 100644 src/assets/lexicon_icon.js diff --git a/manifest.json b/manifest.json index 642aaa8..a74107e 100644 --- a/manifest.json +++ b/manifest.json @@ -53,11 +53,12 @@ "content_scripts": [ { "matches": ["<all_urls>"], - "js": ["src/utils/api.js"] - }, - { - "matches": ["<all_urls>"], - "js": ["src/context_menu/custom_context_menu.js"], + "js": [ + "src/assets/lexicon_icon.js", + "src/utils/api.js", + "src/utils/definitions.js", + "src/sidebar/sidebar.js", + "src/context_menu/custom_context_menu.js"], "css": ["src/context_menu/custom_context_menu.css"], "run_at": "document_end" } diff --git a/src/assets/lexicon_icon.js b/src/assets/lexicon_icon.js new file mode 100644 index 0000000..021073d --- /dev/null +++ b/src/assets/lexicon_icon.js @@ -0,0 +1,52 @@ +console.log("lexicon_icon.js chargé"); + +/** + * Génère une couleur hexadécimale aléatoire (#RRGGBB). + * @returns {string} Une couleur hexadécimale, ex: "#A1B2C3". + */ +function generateRandomColor() { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +} + +/** + * Retourne (ou crée) la couleur associée à un lexique donné. + * La couleur est stockée dans l'objet global window.lexiconColors pour la persistance durant la session. + * @param {string|number} lexiconId - L'identifiant du lexique. + * @returns {string} La couleur associée. + */ +function getOrCreateLexiconColor(lexiconId) { + // Crée l'objet global s'il n'existe pas déjà . + window.lexiconColors = window.lexiconColors || {}; + if (!window.lexiconColors[lexiconId]) { + window.lexiconColors[lexiconId] = generateRandomColor(); + } + return window.lexiconColors[lexiconId]; +} + +/** + * Crée un élément HTML (div) stylisé en cercle de la couleur donnée. + * @param {string} color - Couleur au format "#RRGGBB". + * @param {number} [size=32] - Taille (largeur et hauteur) en pixels. + * @returns {HTMLElement} Le div stylisé en cercle. + */ +function createColorCircle(color, size = 32) { + const circle = document.createElement("div"); + circle.style.width = `${size}px`; + circle.style.height = `${size}px`; + circle.style.borderRadius = "50%"; + circle.style.backgroundColor = color; + circle.style.border = "1px solid black"; // Optionnel + return circle; +} + +// Exposez ces fonctions globalement pour qu'elles soient accessibles dans d'autres scripts. +window.generateRandomColor = generateRandomColor; +window.getOrCreateLexiconColor = getOrCreateLexiconColor; +window.createColorCircle = createColorCircle; + +console.log("lexicon_icon.js chargé"); diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index 011478f..2d38fba 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -1,7 +1,6 @@ console.log("custom_context_menu.js chargé correctement"); // === Variables globales === -let authToken = null; const WHITE_BOX_ID = "whiteBox"; // Fonction utilitaire pour envoyer une notification via le background @@ -26,19 +25,6 @@ async function loadAuthToken() { } } -/** - * Récupère les lexiques via l'API. - * On utilise getLexicons(authToken, "fr") et on vérifie si la réponse se trouve dans response.data. - */ -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 response = await callApi(url, authToken); - console.log("Réponse API dans getLexicons :", response); - return Array.isArray(response) ? response : (response.data || []); -} - /** * Crée le menu contextuel personnalisé (whiteBox) s'il n'existe pas déjà . */ @@ -269,7 +255,7 @@ function createPicker() { */ async function showPicker(event, selectedText) { console.log("showPicker appelé avec", event, selectedText); - const picker = createPicker(); + const picker = createPicker(); // supposez que createPicker est défini ailleurs dans ce fichier picker.innerHTML = ""; // Vider le picker try { @@ -279,35 +265,31 @@ async function showPicker(event, selectedText) { picker.innerHTML = "<p>Aucun lexique trouvé.</p>"; } else { lexicons.forEach(lex => { - // Extraction des propriétés en se basant sur la logique de fetchLexicons() const id = lex.id; const name = lex.category === "User" ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; - const iconURL = lex.iconURL || browser.runtime.getURL("src/assets/icons/default_lexicon.png"); - - const iconDiv = document.createElement("div"); - iconDiv.className = "lexicon-option"; - iconDiv.dataset.lexiconId = id; - iconDiv.style.display = "inline-block"; - iconDiv.style.margin = "5px"; - iconDiv.style.cursor = "pointer"; - iconDiv.style.position = "relative"; - - const iconImg = document.createElement("img"); - iconImg.src = iconURL; - iconImg.alt = name; - iconImg.title = name; - iconImg.style.width = "32px"; - iconImg.style.height = "32px"; - - iconDiv.appendChild(iconImg); - picker.appendChild(iconDiv); - - iconDiv.addEventListener("click", async () => { + + // Obtenir la couleur et créer le cercle + const color = getOrCreateLexiconColor(id); + const circleIcon = createColorCircle(color, 32); + + // Crée un conteneur pour l'icône + const iconContainer = document.createElement("div"); + iconContainer.className = "lexicon-option"; + iconContainer.dataset.lexiconId = id; + iconContainer.style.margin = "5px"; + iconContainer.style.cursor = "pointer"; + iconContainer.title = name; + + // Ajoute le cercle coloré au conteneur + iconContainer.appendChild(circleIcon); + picker.appendChild(iconContainer); + + // Écouteur de clic pour ajouter le mot au lexique sélectionné + iconContainer.addEventListener("click", async () => { console.log(`Tentative d'ajout du mot "${selectedText}" au lexique ${id} (${name})`); try { - // Vérifier si le mot existe déjà dans ce lexique let definitions = []; try { definitions = await fetchLexiconDefinitions(selectedText); @@ -330,8 +312,7 @@ async function showPicker(event, selectedText) { }); } - // Positionner le picker en fonction de l'événement - console.log("Positionnement du picker en X:", event.pageX, "Y:", event.pageY); + // Positionner et afficher le picker picker.style.left = event.pageX + "px"; picker.style.top = event.pageY + "px"; picker.style.display = "block"; @@ -341,3 +322,4 @@ async function showPicker(event, selectedText) { picker.style.display = "block"; } } + diff --git a/src/sidebar/sidebar.html b/src/sidebar/sidebar.html index 2327900..6d189ef 100644 --- a/src/sidebar/sidebar.html +++ b/src/sidebar/sidebar.html @@ -4,6 +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="../assets/lexicon_icon.js" defer></script> <script src="../utils/api.js" defer></script> <script src="../utils/definitions.js" defer></script> <script src="sidebar.js" defer></script> diff --git a/src/sidebar/sidebar.js b/src/sidebar/sidebar.js index c5707e9..e31a0dd 100644 --- a/src/sidebar/sidebar.js +++ b/src/sidebar/sidebar.js @@ -3,14 +3,13 @@ console.log( "🌠Vérification API browser :", typeof browser !== "undefined" ? "✅ Disponible" : "⌠Non disponible" ); - +console.log("getLexicons type:", typeof getLexicons); +console.log("window.getLexicons type:", typeof window.getLexicons); // ───────────────────────────────────────────────────────────────────────────── // â–Œ Variables globales // ───────────────────────────────────────────────────────────────────────────── -let authToken = null; - -window.lexiconMap = lexiconMap; +let authToken = window.authToken; window.authToken = authToken; // ───────────────────────────────────────────────────────────────────────────── @@ -170,7 +169,7 @@ async function fetchLexicons() { if (!authToken) { throw new Error("âš ï¸ Aucun token disponible. Veuillez vous connecter."); } - + console.log("getLexicons type:", typeof getLexicons); const lexicons = await getLexicons(authToken, "fr"); console.log("📚 Réponse brute de l'API :", lexicons); @@ -227,8 +226,11 @@ function displayLexiconsWithCheckbox(lexicons) { lexiqueDiv.className = "lexique-item"; // Icône du lexique + const color = getOrCreateLexiconColor(lexiconId); + const circleIcon = createColorCircle(color, 24); const iconDiv = document.createElement("div"); iconDiv.className = "lexique-icon"; + iconDiv.appendChild(circleIcon); const labelSpan = document.createElement("span"); labelSpan.className = "lexique-label"; diff --git a/src/utils/api.js b/src/utils/api.js index 72eb48c..c1bc41c 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -1,5 +1,5 @@ console.log("✅ api.js chargé correctement"); - +window.authToken = null; // ───────────────────────────────────────────────────────────────────────────── // â–Œ Sélection de texte sur la page // ───────────────────────────────────────────────────────────────────────────── @@ -223,8 +223,10 @@ async function AddWord(authToken, selectedWord, lexiconIds, force = false) { window.callApi = callApi; window.getLexicons = getLexicons; +console.log("getLexicons exposée, type:", typeof window.getLexicons); window.getAllCategoriesLexicons = getAllCategoriesLexicons; window.getLexiconEntries = getLexiconEntries; window.getAllLexiconWords = getAllLexiconWords; window.getWiktionaryDefinition = getWiktionaryDefinition; window.AddWord = AddWord; + diff --git a/src/utils/definitions.js b/src/utils/definitions.js index c8832d8..d295160 100644 --- a/src/utils/definitions.js +++ b/src/utils/definitions.js @@ -2,7 +2,7 @@ // â–Œ Fonctions pour récupérer/afficher les définitions // ───────────────────────────────────────────────────────────────────────────── -const lexiconMap = new Map(); +window.lexiconMap = new Map(); /** * Récupère les définitions d'un mot dans les lexiques de l'utilisateur (ex. user_id=4), -- GitLab From 4062393843b4bf07e67866df6553cbaed824bb04 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Tue, 11 Feb 2025 17:55:00 +0100 Subject: [PATCH 17/23] Association couleurs lexiques --- src/assets/lexicon_icon.js | 23 +++++---- src/context_menu/browser_context_menu.js | 6 +-- src/context_menu/custom_context_menu.js | 7 +-- src/sidebar/sidebar.js | 64 +++++++++++------------- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/assets/lexicon_icon.js b/src/assets/lexicon_icon.js index 021073d..5fc780a 100644 --- a/src/assets/lexicon_icon.js +++ b/src/assets/lexicon_icon.js @@ -14,18 +14,22 @@ function generateRandomColor() { } /** - * Retourne (ou crée) la couleur associée à un lexique donné. - * La couleur est stockée dans l'objet global window.lexiconColors pour la persistance durant la session. + * 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 {string} La couleur associée. + * @returns {Promise<string>} La couleur associée au lexique. */ -function getOrCreateLexiconColor(lexiconId) { - // Crée l'objet global s'il n'existe pas déjà . - window.lexiconColors = window.lexiconColors || {}; - if (!window.lexiconColors[lexiconId]) { - window.lexiconColors[lexiconId] = generateRandomColor(); +async function getOrCreateLexiconColor(lexiconId) { + // Récupère la correspondance stockée dans storage + let { lexiconColors } = await browser.storage.local.get("lexiconColors"); + if (!lexiconColors) { + lexiconColors = {}; } - return window.lexiconColors[lexiconId]; + // 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 }); + } + return lexiconColors[lexiconId]; } /** @@ -49,4 +53,3 @@ window.generateRandomColor = generateRandomColor; window.getOrCreateLexiconColor = getOrCreateLexiconColor; window.createColorCircle = createColorCircle; -console.log("lexicon_icon.js chargé"); diff --git a/src/context_menu/browser_context_menu.js b/src/context_menu/browser_context_menu.js index 4f9f7c6..7c24d4a 100644 --- a/src/context_menu/browser_context_menu.js +++ b/src/context_menu/browser_context_menu.js @@ -31,7 +31,7 @@ async function createContextMenu() { id: "searchInLexicons", title: "Rechercher dans mes lexiques", contexts: ["selection"], - icons: { "16": "icons/quel_lexique.png" }, + icons: { "16": "src/assets/icons/quel_lexique.png" }, }); // Item 2 : Ajouter le mot au(x) lexique(s) de l’utilisateur @@ -39,7 +39,7 @@ async function createContextMenu() { id: "addToLexicon", title: "Ajouter ce mot à mes lexiques", contexts: ["selection"], - icons: { "16": "icons/ajout_lexique.png" }, + icons: { "16": "src/assets/icons/ajout_lexique.png" }, }); } @@ -55,7 +55,7 @@ async function createContextMenu() { id: "getDefinition", title: "Obtenir une définition", contexts: ["selection"], - icons: { "16": "icons/definition.png" }, + icons: { "16": "src/assets/icons/definition.png" }, }); browser.contextMenus.create({ diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index 2d38fba..06f2530 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -264,14 +264,14 @@ async function showPicker(event, selectedText) { if (!Array.isArray(lexicons) || lexicons.length === 0) { picker.innerHTML = "<p>Aucun lexique trouvé.</p>"; } else { - lexicons.forEach(lex => { + for (const lex of lexicons) { const id = lex.id; const name = lex.category === "User" ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; // Obtenir la couleur et créer le cercle - const color = getOrCreateLexiconColor(id); + const color = await getOrCreateLexiconColor(id); const circleIcon = createColorCircle(color, 32); // Crée un conteneur pour l'icône @@ -309,7 +309,7 @@ async function showPicker(event, selectedText) { alert(`Erreur : ${error.message}`); } }); - }); + } } // Positionner et afficher le picker @@ -323,3 +323,4 @@ async function showPicker(event, selectedText) { } } + diff --git a/src/sidebar/sidebar.js b/src/sidebar/sidebar.js index e31a0dd..ef05621 100644 --- a/src/sidebar/sidebar.js +++ b/src/sidebar/sidebar.js @@ -204,11 +204,10 @@ async function fetchLexicons() { } /** - * Affiche la liste des lexiques avec des checkboxes. - * Les checkboxes servent ici à activer/désactiver le surlignage, - * mais on va aussi s’en servir pour déterminer où ajouter le mot. + * Affiche la liste des lexiques avec des checkboxes dans la barre latérale. + * @param {Array} lexicons - Liste des lexiques à afficher. */ -function displayLexiconsWithCheckbox(lexicons) { +async function displayLexiconsWithCheckbox(lexicons) { const lexiquesContainer = document.getElementById("lexiques"); if (!lexiquesContainer) { console.warn("âš ï¸ Ã‰lément #lexiques introuvable."); @@ -220,50 +219,49 @@ function displayLexiconsWithCheckbox(lexicons) { lexiquesContainer.textContent = "Aucun lexique disponible."; return; } - - lexicons.forEach(({ lexiconName, lexiconId, active }) => { + + for (const { lexiconName, lexiconId, active } of lexicons) { const lexiqueDiv = document.createElement("div"); lexiqueDiv.className = "lexique-item"; - - // Icône du lexique - const color = getOrCreateLexiconColor(lexiconId); + + // Obtenir la couleur associée de façon asynchrone + const color = await getOrCreateLexiconColor(lexiconId); const circleIcon = createColorCircle(color, 24); + const iconDiv = document.createElement("div"); iconDiv.className = "lexique-icon"; iconDiv.appendChild(circleIcon); - + const labelSpan = document.createElement("span"); labelSpan.className = "lexique-label"; labelSpan.textContent = lexiconName; - - // Conteneur pour la case à cocher avec tooltip + + // Conteneur pour la checkbox (avec tooltip) const checkboxContainer = document.createElement("label"); checkboxContainer.className = "tooltip-container lexique-checkbox-container"; - const addCheckbox = document.createElement("input"); addCheckbox.type = "checkbox"; addCheckbox.className = "lexique-checkbox"; addCheckbox.dataset.lexiconId = lexiconId; - const checkboxTooltip = document.createElement("span"); checkboxTooltip.className = "tooltip"; checkboxTooltip.textContent = "Ajouter le mot à ce lexique"; - - // Conteneur pour le bouton de surlignage avec tooltip + checkboxContainer.appendChild(addCheckbox); + checkboxContainer.appendChild(checkboxTooltip); + + // Conteneur pour le bouton de surlignage (avec tooltip) const highlightButton = document.createElement("button"); highlightButton.className = "tooltip-container lexique-highlight-toggle"; highlightButton.dataset.lexiconId = lexiconId; highlightButton.dataset.active = active ? "true" : "false"; - const feutreIcon = document.createElement("img"); - feutreIcon.src = "../assets/icons/feutre.png"; + feutreIcon.src = "../assets/icons/feutre.png"; // Vérifiez le chemin relatif feutreIcon.alt = "Feutre"; feutreIcon.className = "feutre-icon"; - const highlightTooltip = document.createElement("span"); highlightTooltip.className = "tooltip"; highlightTooltip.textContent = "Activer/Désactiver le surlignage des mots du lexique"; - + // Gestion du clic pour activer/désactiver le surlignage highlightButton.addEventListener("click", async () => { let currentState = highlightButton.dataset.active === "true"; @@ -279,45 +277,43 @@ function displayLexiconsWithCheckbox(lexicons) { console.error("Erreur lors du toggle de surlignage pour le lexique", lexiconId, ":", error); } }); - - // Assemblage + highlightButton.appendChild(feutreIcon); highlightButton.appendChild(highlightTooltip); - checkboxContainer.appendChild(addCheckbox); - checkboxContainer.appendChild(checkboxTooltip); - + + // Assemblage final lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); lexiqueDiv.appendChild(checkboxContainer); lexiqueDiv.appendChild(highlightButton); + lexiquesContainer.appendChild(lexiqueDiv); - }); - - // Ajustement dynamique des tooltips + } + + // Ajustement dynamique des tooltips (après un court délai) setTimeout(() => { const menu = document.getElementById("menu"); + if (!menu) return; const menuRect = menu.getBoundingClientRect(); const containers = document.querySelectorAll('.tooltip-container'); - + containers.forEach(container => { const tooltip = container.querySelector('.tooltip'); if (!tooltip) return; - tooltip.style.left = '50%'; tooltip.style.transform = 'translateX(-50%) translateY(-5px)'; - + const tooltipRect = tooltip.getBoundingClientRect(); if (tooltipRect.left < menuRect.left) { const overflowLeft = menuRect.left - tooltipRect.left; tooltip.style.transform = `translateX(calc(-100% + ${overflowLeft}px)) translateY(-5px)`; - } - else if (tooltipRect.right > menuRect.right) { + } else if (tooltipRect.right > menuRect.right) { const overflowRight = tooltipRect.right - menuRect.right; tooltip.style.transform = `translateX(calc(-100% - ${overflowRight}px)) translateY(-5px)`; } }); }, 100); -} +} -- GitLab From 99ef6749a83c75c4a2a9d2211919c727fd1918fc Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Wed, 12 Feb 2025 11:33:03 +0100 Subject: [PATCH 18/23] Correction beugs --- manifest.json | 2 +- src/assets/lexicon_icon.js | 29 +++++++++++++++++++---------- src/background/background.js | 10 +++++++++- src/sidebar/sidebar.js | 2 +- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/manifest.json b/manifest.json index a74107e..08791cc 100644 --- a/manifest.json +++ b/manifest.json @@ -60,7 +60,7 @@ "src/sidebar/sidebar.js", "src/context_menu/custom_context_menu.js"], "css": ["src/context_menu/custom_context_menu.css"], - "run_at": "document_end" + "run_at": "document_idle" } ], diff --git a/src/assets/lexicon_icon.js b/src/assets/lexicon_icon.js index 5fc780a..9228f82 100644 --- a/src/assets/lexicon_icon.js +++ b/src/assets/lexicon_icon.js @@ -1,16 +1,25 @@ console.log("lexicon_icon.js chargé"); /** - * Génère une couleur hexadécimale aléatoire (#RRGGBB). - * @returns {string} Une couleur hexadécimale, ex: "#A1B2C3". + * 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 letters = '0123456789ABCDEF'; - let color = '#'; - for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * 16)]; - } - return color; + const palette = [ + "#6e76c7", + "#00a0bd", + "#96cd95", + "#ffeac2", + "#fff6ff", + "#e67e22", + "#20bad8", + "#f290e7", + "#f4ab9d", + "#f1e87a", + "#84e8e6" + ]; + const index = Math.floor(Math.random() * palette.length); + return palette[index]; } /** @@ -18,10 +27,10 @@ function generateRandomColor() { * @param {string|number} lexiconId - L'identifiant du lexique. * @returns {Promise<string>} La couleur associée au lexique. */ -async function getOrCreateLexiconColor(lexiconId) { +async function getOrCreateLexiconColor(lexiconId, forceReset = false) { // Récupère la correspondance stockée dans storage let { lexiconColors } = await browser.storage.local.get("lexiconColors"); - if (!lexiconColors) { + if (!lexiconColors || forceReset) { lexiconColors = {}; } // Si aucune couleur n'est associée à ce lexiconId, on la génère et on la sauvegarde diff --git a/src/background/background.js b/src/background/background.js index e1f36c5..6203313 100644 --- a/src/background/background.js +++ b/src/background/background.js @@ -88,11 +88,18 @@ async function actuallyOpenLoginPage() { browser.runtime.sendMessage({ action: "authStatusChanged", isLoggedIn: false }); } -// Déconnecte l'utilisateur (sans notification) +// Déconnecte l'utilisateur async function disconnectFromLexicalDB() { console.log("🔓 Déconnexion en cours..."); await browser.storage.local.remove("accessToken"); console.log("🔓 Token supprimé avec succès."); + // Réinitialiser les couleurs des lexiques dans le local storage + try { + await browser.storage.local.remove("lexiconColors"); + console.log("Les couleurs des lexiques ont été réinitialisées dans le local storage."); + } catch (error) { + console.error("Erreur lors de la réinitialisation des couleurs :", error); + } setTimeout(async () => { await refreshAllUI(); }, 500); @@ -135,6 +142,7 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { const isConnected = await isUserConnected(); if (isConnected) { await disconnectFromLexicalDB(); + await browser.storage.local.remove("lexiconColors"); } else { actuallyOpenLoginPage(); } diff --git a/src/sidebar/sidebar.js b/src/sidebar/sidebar.js index ef05621..5d619b5 100644 --- a/src/sidebar/sidebar.js +++ b/src/sidebar/sidebar.js @@ -533,7 +533,7 @@ document.addEventListener("DOMContentLoaded", async () => { authButton.addEventListener("click", handleAuthButtonClick); } - const chercherDefButton = document.getElementById("chercherDef"); + const chercherDefButton = document.querySelector("#chercherDef"); if (chercherDefButton) { chercherDefButton.addEventListener("click", async () => { openBlock("definitionContent"); -- GitLab From 4074ed53d806830c736a1b9d8b1a84980171ef8d Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Wed, 12 Feb 2025 13:18:35 +0100 Subject: [PATCH 19/23] Ouverture auto bloc Lexiques menu contextuel perso bouton ajout --- src/context_menu/custom_context_menu.js | 56 +++++++++++++++++++++++-- src/sidebar/sidebar.js | 4 ++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index 06f2530..2e0ea97 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -97,7 +97,8 @@ function setupWhiteBoxActions() { console.log("🔠Bouton Ajouter au lexique cliqué avec le mot :", selectedText); if (!selectedText) return; if (authToken) { - await showPicker(e, selectedText); + browser.runtime.sendMessage({ action: "openLexiconBlock" }); + showPicker(e, selectedText); } else { alert("Vous devez être connecté pour ajouter un mot."); } @@ -234,20 +235,26 @@ function createPicker() { if (!picker) { picker = document.createElement("div"); picker.id = "lexiconPicker"; - // Styles pour le picker picker.style.position = "absolute"; picker.style.zIndex = "10000"; picker.style.backgroundColor = "rgba(255, 255, 255, 0.95)"; picker.style.border = "1px solid #ccc"; - picker.style.padding = "10px"; + picker.style.padding = "5px"; picker.style.borderRadius = "4px"; picker.style.boxShadow = "0 2px 10px rgba(0,0,0,0.3)"; picker.style.display = "none"; + + picker.style.display = "flex"; + picker.style.flexWrap = "wrap"; + picker.style.gap = "10px"; + picker.style.alignItems = "center"; + document.body.appendChild(picker); } return picker; } + /** * Affiche le picker pour choisir le lexique dans lequel ajouter le mot. * Pour chaque lexique, vérifie si le mot existe déjà dans ce lexique en appelant fetchLexiconDefinitions. @@ -278,9 +285,14 @@ async function showPicker(event, selectedText) { const iconContainer = document.createElement("div"); iconContainer.className = "lexicon-option"; iconContainer.dataset.lexiconId = id; - iconContainer.style.margin = "5px"; + iconContainer.style.margin = "2px"; iconContainer.style.cursor = "pointer"; iconContainer.title = name; + iconContainer.style.display = "inline-flex"; + iconContainer.style.flexDirection = "row"; // Assurez-vous que c'est horizontal + iconContainer.style.alignItems = "center"; // Alignement centré + iconContainer.style.justifyContent = "center"; + // Ajoute le cercle coloré au conteneur iconContainer.appendChild(circleIcon); @@ -323,4 +335,40 @@ async function showPicker(event, selectedText) { } } +function hideLexiconPicker() { + const picker = document.getElementById("lexiconPicker"); + if (picker) { + picker.style.display = "none"; + } +} + +document.addEventListener("mouseup", (event) => { + const whiteBox = document.getElementById(WHITE_BOX_ID); + const picker = document.getElementById("lexiconPicker"); + + if (picker && picker.style.display === "block" && !picker.contains(event.target)) { + hideLexiconPicker(); + } + + // Vérifier si le clic est à l'extérieur des éléments + if ( + whiteBox && whiteBox.style.display === "block" && + !whiteBox.contains(event.target) && + (!picker || !picker.contains(event.target)) + ) { + hideWhiteBox(); + if (picker) picker.style.display = "none"; + } + + // Vérifier s'il y a du texte sélectionné + const selectedText = window.getSelection().toString().trim(); + if (selectedText) { + console.log("Texte sélectionné :", selectedText); + showWhiteBox(event, selectedText); + browser.runtime.sendMessage({ + action: "mot_selectionne", + selectedText, + }); + } +}); diff --git a/src/sidebar/sidebar.js b/src/sidebar/sidebar.js index 5d619b5..0668c86 100644 --- a/src/sidebar/sidebar.js +++ b/src/sidebar/sidebar.js @@ -509,6 +509,10 @@ browser.runtime.onMessage.addListener(async (message) => { case "addToLexicon": handleAddWordClick(); break; + + case "openLexiconBlock": + openBlock("menuContent"); + break; case "toggleAuth": break; -- GitLab From 6cf36ddf183699b7ed90bce32b926eafa2c84240 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Wed, 12 Feb 2025 15:22:10 +0100 Subject: [PATCH 20/23] =?UTF-8?q?Liens=20fonctions=20ajout=20mot=20menu=20?= =?UTF-8?q?contextuel/barre=20lat=C3=A9rale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_menu/custom_context_menu.js | 133 ++++++++++++++++++------ src/sidebar/sidebar.js | 7 ++ 2 files changed, 111 insertions(+), 29 deletions(-) diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index 2e0ea97..b9f6617 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -262,12 +262,14 @@ function createPicker() { */ async function showPicker(event, selectedText) { console.log("showPicker appelé avec", event, selectedText); - const picker = createPicker(); // supposez que createPicker est défini ailleurs dans ce fichier + const picker = createPicker(); picker.innerHTML = ""; // Vider le picker + const selectedLexicons = new Set(); // Stocke les lexiques sélectionnés try { const lexicons = await getLexicons(authToken, "fr"); console.log("Lexicons récupérés :", lexicons); + if (!Array.isArray(lexicons) || lexicons.length === 0) { picker.innerHTML = "<p>Aucun lexique trouvé.</p>"; } else { @@ -276,52 +278,121 @@ 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})`; - + // Obtenir la couleur et créer le cercle const color = await getOrCreateLexiconColor(id); const circleIcon = createColorCircle(color, 32); - // Crée un conteneur pour l'icône + // Créer un conteneur pour l'icône const iconContainer = document.createElement("div"); iconContainer.className = "lexicon-option"; iconContainer.dataset.lexiconId = id; - iconContainer.style.margin = "2px"; + iconContainer.style.margin = "5px"; iconContainer.style.cursor = "pointer"; iconContainer.title = name; iconContainer.style.display = "inline-flex"; - iconContainer.style.flexDirection = "row"; // Assurez-vous que c'est horizontal - iconContainer.style.alignItems = "center"; // Alignement centré + iconContainer.style.flexDirection = "row"; + iconContainer.style.alignItems = "center"; iconContainer.style.justifyContent = "center"; - + iconContainer.style.border = "2px solid transparent"; // Ajoute le cercle coloré au conteneur iconContainer.appendChild(circleIcon); picker.appendChild(iconContainer); - // Écouteur de clic pour ajouter le mot au lexique sélectionné - iconContainer.addEventListener("click", async () => { - console.log(`Tentative d'ajout du mot "${selectedText}" au lexique ${id} (${name})`); - try { - let definitions = []; - try { - definitions = await fetchLexiconDefinitions(selectedText); - } catch (err) { - console.error("Erreur lors de la récupération des définitions :", err); - } - const exists = Array.isArray(definitions) && definitions.some(def => def.lexiconId === id); - if (exists) { - alert(`Le mot "${selectedText}" existe déjà dans le lexique ${name}.`); - } else { - await window.AddWord(authToken, selectedText, [id], false); - alert(`Le mot "${selectedText}" a été ajouté dans le lexique ${name}.`); - } - picker.style.display = "none"; - } catch (error) { - console.error("Erreur lors de l'ajout du mot :", error); - alert(`Erreur : ${error.message}`); + // Écouteur de clic pour sélectionner/désélectionner le lexique + iconContainer.addEventListener("click", () => { + if (selectedLexicons.has(id)) { + selectedLexicons.delete(id); + iconContainer.style.border = "2px solid transparent"; + } else { + selectedLexicons.add(id); + iconContainer.style.border = "2px solid black"; } }); } + + // Ajouter un bouton de validation + const confirmButton = document.createElement("button"); + confirmButton.textContent = "Ajouter aux lexiques sélectionnés"; + confirmButton.style.fontStyle = "italic"; + confirmButton.style.fontSize = "8px"; + confirmButton.style.marginTop = "10px"; + confirmButton.style.padding = "5px 10px"; + confirmButton.style.cursor = "pointer"; + confirmButton.style.border = "none"; + confirmButton.style.borderRadius = "4px"; + confirmButton.style.backgroundColor = "#6e76c7"; + confirmButton.style.color = "white"; + + confirmButton.addEventListener("click", async () => { + if (selectedLexicons.size === 0) { + alert("Veuillez sélectionner au moins un lexique."); + return; + } + + console.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) { + if (selectedLexicons.has(def.lexiconId)) { + existingLexiconIds.add(def.lexiconId); + } + } + } + + // Affichage des lexiques où le mot existe déjà + if (existingLexiconIds.size > 0) { + alert(`âš ï¸ Le mot "${selectedText}" existe déjà dans les lexiques suivants : ${Array.from(existingLexiconIds).join(", ")}`); + } + + // Filtrer les lexiques où le mot n'existe pas encore + 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; + } + + // Envoi de la requête d'ajout + try { + console.log(`📡 Ajout du mot "${selectedText}" dans les lexiques :`, lexiconsToAdd); + const result = await AddWord(authToken, selectedText, lexiconsToAdd, false); + console.log("✅ Réponse API :", result); + + // Rafraîchir l'UI après l'ajout + await new Promise(resolve => setTimeout(resolve, 300)); + browser.runtime.sendMessage({ action: "refreshUI" }); + + // Affichage du message de confirmation dans le picker + picker.innerHTML = `<p style="color: green;">✅ Mot ajouté avec succès dans : ${lexiconsToAdd.join(", ")}.</p>`; + setTimeout(() => picker.style.display = "none", 2000); + browser.runtime.sendMessage({ + action: "addWordResult", + lexicons:`✅ Mot ajouté avec succès dans : ${lexiconsToAdd.join(", ")}.` + }); + } catch (error) { + console.error("⌠Erreur lors de l'ajout du mot :", error); + + // Affichage du message d'erreur dans le picker + picker.innerHTML = `<p style="color: red;">⌠Erreur : ${error.message}</p>`; + setTimeout(() => picker.style.display = "none", 3000); + browser.runtime.sendMessage({ + action: "addWordResult", + lexicons: `⌠Erreur lors de l'ajout du mot : ${error.message}` + }); + } + }); + + picker.appendChild(confirmButton); } // Positionner et afficher le picker @@ -329,12 +400,16 @@ async function showPicker(event, selectedText) { picker.style.top = event.pageY + "px"; picker.style.display = "block"; } catch (error) { - console.error("Erreur lors de la récupération des lexiques :", error); + console.error("⌠Erreur lors de la récupération des lexiques :", error); picker.innerHTML = "<p>Erreur lors du chargement des lexiques.</p>"; picker.style.display = "block"; } } + + + + function hideLexiconPicker() { const picker = document.getElementById("lexiconPicker"); if (picker) { diff --git a/src/sidebar/sidebar.js b/src/sidebar/sidebar.js index 0668c86..c937cc6 100644 --- a/src/sidebar/sidebar.js +++ b/src/sidebar/sidebar.js @@ -506,6 +506,13 @@ browser.runtime.onMessage.addListener(async (message) => { window.displayLexiconResults(message.lexicons); break; + case "addWordResult": + const lexiconResultElement = document.getElementById("lexiconResult"); + if (lexiconResultElement) { + lexiconResultElement.innerHTML = message.lexicons; + } + break; + case "addToLexicon": handleAddWordClick(); break; -- GitLab From 34c86229ee6d4ac7a0ee10e14b30e34af7c205ce Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:21:18 +0100 Subject: [PATCH 21/23] Messages confirmation/erreur ajout mot menu contextuel --- src/assets/lexicon_icon.js | 3 +- src/context_menu/custom_context_menu.css | 233 +++++++++++++++-------- src/context_menu/custom_context_menu.js | 99 ++++------ 3 files changed, 193 insertions(+), 142 deletions(-) diff --git a/src/assets/lexicon_icon.js b/src/assets/lexicon_icon.js index 9228f82..394d73d 100644 --- a/src/assets/lexicon_icon.js +++ b/src/assets/lexicon_icon.js @@ -49,11 +49,12 @@ async function getOrCreateLexiconColor(lexiconId, forceReset = false) { */ function createColorCircle(color, size = 32) { const circle = document.createElement("div"); + circle.className = "color-circle"; circle.style.width = `${size}px`; circle.style.height = `${size}px`; circle.style.borderRadius = "50%"; circle.style.backgroundColor = color; - circle.style.border = "1px solid black"; // Optionnel + circle.style.border = "1px solid black"; return circle; } diff --git a/src/context_menu/custom_context_menu.css b/src/context_menu/custom_context_menu.css index 30f66df..7bc2f23 100644 --- a/src/context_menu/custom_context_menu.css +++ b/src/context_menu/custom_context_menu.css @@ -1,81 +1,156 @@ /* === Conteneur principal du menu contextuel === */ #whiteBox { - position: absolute; - display: none; - min-width: 50px; - max-width: 300px; - background-color: white; - color: #323046; - border: 2px solid #323046; - border-radius: 10px; - padding: 10px; - box-shadow: 0 4px 12px rgba(0,0,0,0.2); - font-family: "Helvetica", sans-serif; - z-index: 10000; - } - - /* === Titre/texte indiquant le mot sélectionné === */ - #whiteBox #selectedWord { - margin: 0; - margin-bottom: 8px; - font-size: 14px; - line-height: 1.3; - color: #323046; - font-weight: bold; - text-align: center; - } - - /* === Conteneur des icônes === */ - #whiteBox .icon-container { - position: relative; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - cursor: pointer; - margin: 0; - padding: 0; - } - - #whiteBox .icon-container:hover { - background-color: rgba(255, 255, 255, 0.1); - border-radius: 6px; - } - - /* === Les icônes elles-mêmes === */ - #whiteBox .icon { - width: 40px; - height: 40px; - transition: transform 0.2s ease; - margin : 0 auto; - display: block; - } - - #whiteBox .icon:hover { - transform: scale(1.15); - } - - /* === Message (tooltips) === */ - #whiteBox .tooltip { - visibility: hidden; - background-color: #333; - color: #fff; - text-align: center; - padding: 6px; - border-radius: 5px; - position: absolute; - bottom: -34px; - left: 50%; - transform: translateX(-50%); - white-space: nowrap; - font-size: 12px; - opacity: 0; - transition: opacity 0.2s ease, visibility 0.2s ease; - z-index: 1000; - } - - #whiteBox .icon-container:hover .tooltip { - visibility: visible; - opacity: 1; - } - \ No newline at end of file + position: absolute; + display: none; + min-width: 50px; + max-width: 300px; + background-color: white; + color: #323046; + border: 2px solid #323046; + border-radius: 10px; + padding: 10px; + box-shadow: 0 4px 12px rgba(0,0,0,0.2); + font-family: "Helvetica", sans-serif; + z-index: 10000; +} + +/* === Titre/texte indiquant le mot sélectionné === */ +#whiteBox #selectedWord { + margin: 0; + margin-bottom: 8px; + font-size: 14px; + line-height: 1.3; + color: #323046; + font-weight: bold; + text-align: center; +} + +/* === Conteneur des icônes === */ +#whiteBox .icon-container { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + margin: 0; + padding: 0; +} + +#whiteBox .icon-container:hover { + background-color: rgba(255, 255, 255, 0.1); + border-radius: 6px; +} + +/* === Les icônes elles-mêmes === */ +#whiteBox .icon { + width: 40px; + height: 40px; + transition: transform 0.2s ease; + margin : 0 auto; + display: block; +} + +#whiteBox .icon:hover { + transform: scale(1.15); +} + +/* === Message (tooltips) === */ +#whiteBox .tooltip { + visibility: hidden; + background-color: #333; + color: #fff; + text-align: center; + padding: 6px; + border-radius: 5px; + position: absolute; + bottom: -34px; + left: 50%; + transform: translateX(-50%); + white-space: nowrap; + font-size: 12px; + opacity: 0; + transition: opacity 0.2s ease, visibility 0.2s ease; + z-index: 1000; +} + +#whiteBox .icon-container:hover .tooltip { + visibility: visible; + opacity: 1; +} + +/* === Style global du lexiconPicker === */ +#lexiconPicker { + position: absolute; + z-index: 10000; + background-color: rgba(255, 255, 255, 0.98); + border: 1px solid #ddd; + padding: 4px; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + width: 150px; + font-family: Arial, sans-serif; + font-size: 10px; + display: flex !important; + flex-direction: row !important; + flex-wrap: wrap !important; + align-items: center; + justify-content: center; + gap: 2px; +} + +/* Style pour les icônes de lexique */ +#lexiconPicker .lexicon-option { + cursor: pointer; + display: inline-flex !important; + flex-direction: row !important; + align-items: center; + justify-content: center; + border: 2px solid transparent; + border-radius: 50%; + width: 40px; + height: 40px; + transition: border 0.2s ease; + flex: 0 0 auto; +} + +/* Effet au survol pour les icônes */ +#lexiconPicker .lexicon-option:hover { + border: 2px solid #6e76c7; +} + +/* Classe pour indiquer qu'une icône est sélectionnée */ +#lexiconPicker .lexicon-option.selected { + border: 2px solid #323046; +} + +/* Style pour le cercle de couleur (icône interne) */ +#lexiconPicker .color-circle { + width: 28px; /* ajustez la taille si besoin */ + height: 28px; + border-radius: 50%; + display: inline-block; + /* La couleur de fond sera définie dynamiquement via JS */ + border: 1px solid black; /* optionnel */ +} + +/* Style pour le bouton de confirmation */ +#lexiconPicker button.confirmButton { + font-style: italic; + font-size: 10px; + padding: 6px 10px; + cursor: pointer; + border: none; + border-radius: 4px; + background-color: #323046; + color: white; + flex-basis: 100%; /* force le bouton à occuper toute la largeur et à passer à la ligne */ + margin-top: 8px; +} + +#lexiconPicker p { + font-size: 12px; + font-weight: bold; + text-align: center; +} + diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index b9f6617..91e117b 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -237,93 +237,80 @@ function createPicker() { picker.id = "lexiconPicker"; picker.style.position = "absolute"; picker.style.zIndex = "10000"; - picker.style.backgroundColor = "rgba(255, 255, 255, 0.95)"; - picker.style.border = "1px solid #ccc"; - picker.style.padding = "5px"; - picker.style.borderRadius = "4px"; - picker.style.boxShadow = "0 2px 10px rgba(0,0,0,0.3)"; - picker.style.display = "none"; - + 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"; // largeur adaptée pour afficher les icônes sur une ligne + picker.style.fontFamily = "Arial, sans-serif"; + picker.style.fontSize = "10px"; + // Définir le picker en flex avec direction horizontale picker.style.display = "flex"; - picker.style.flexWrap = "wrap"; - picker.style.gap = "10px"; - picker.style.alignItems = "center"; - + picker.style.flexDirection = "row"; // IMPORTANT : aligne les éléments en ligne + picker.style.flexWrap = "wrap"; // autorise le retour à la ligne si nécessaire + picker.style.alignItems = "center"; + picker.style.justifyContent = "center"; + picker.style.gap = "5px"; document.body.appendChild(picker); } return picker; } - /** * Affiche le picker pour choisir le lexique dans lequel ajouter le mot. - * Pour chaque lexique, vérifie si le mot existe déjà dans ce lexique en appelant fetchLexiconDefinitions. - * S'il n'existe pas, appelle window.AddWord pour l'ajouter. */ async function showPicker(event, selectedText) { - console.log("showPicker appelé avec", event, selectedText); - const picker = createPicker(); - picker.innerHTML = ""; // Vider le picker - const selectedLexicons = new Set(); // Stocke les lexiques sélectionnés + let picker = document.getElementById("lexiconPicker"); + if (!picker) { + picker = document.createElement("div"); + picker.id = "lexiconPicker"; + document.body.appendChild(picker); + } + picker.innerHTML = ""; + + const selectedLexicons = new Set(); try { const lexicons = await getLexicons(authToken, "fr"); console.log("Lexicons récupérés :", lexicons); if (!Array.isArray(lexicons) || lexicons.length === 0) { - picker.innerHTML = "<p>Aucun lexique trouvé.</p>"; + picker.innerHTML = "<p style='color:#333;'>Aucun lexique trouvé.</p>"; } else { + // Ajout des icônes directement dans le picker for (const lex of lexicons) { const id = lex.id; const name = lex.category === "User" ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; - // Obtenir la couleur et créer le cercle + // Obtenir la couleur et créer un cercle (l'icône) const color = await getOrCreateLexiconColor(id); - const circleIcon = createColorCircle(color, 32); + const circleIcon = createColorCircle(color, 28); - // Créer un conteneur pour l'icône + // Création du conteneur pour l'icône const iconContainer = document.createElement("div"); iconContainer.className = "lexicon-option"; iconContainer.dataset.lexiconId = id; - iconContainer.style.margin = "5px"; - iconContainer.style.cursor = "pointer"; iconContainer.title = name; - iconContainer.style.display = "inline-flex"; - iconContainer.style.flexDirection = "row"; - iconContainer.style.alignItems = "center"; - iconContainer.style.justifyContent = "center"; - iconContainer.style.border = "2px solid transparent"; - - // Ajoute le cercle coloré au conteneur - iconContainer.appendChild(circleIcon); - picker.appendChild(iconContainer); - - // Écouteur de clic pour sélectionner/désélectionner le lexique iconContainer.addEventListener("click", () => { if (selectedLexicons.has(id)) { selectedLexicons.delete(id); - iconContainer.style.border = "2px solid transparent"; + iconContainer.classList.remove("selected"); } else { selectedLexicons.add(id); - iconContainer.style.border = "2px solid black"; + iconContainer.classList.add("selected"); } }); + iconContainer.appendChild(circleIcon); + picker.appendChild(iconContainer); } - // Ajouter un bouton de validation + // Création du bouton de validation qui passera sur une nouvelle ligne const confirmButton = document.createElement("button"); - confirmButton.textContent = "Ajouter aux lexiques sélectionnés"; - confirmButton.style.fontStyle = "italic"; - confirmButton.style.fontSize = "8px"; - confirmButton.style.marginTop = "10px"; - confirmButton.style.padding = "5px 10px"; - confirmButton.style.cursor = "pointer"; - confirmButton.style.border = "none"; - confirmButton.style.borderRadius = "4px"; - confirmButton.style.backgroundColor = "#6e76c7"; - confirmButton.style.color = "white"; + confirmButton.className = "confirmButton"; + confirmButton.textContent = "Ajouter le mot"; confirmButton.addEventListener("click", async () => { if (selectedLexicons.size === 0) { @@ -349,40 +336,32 @@ async function showPicker(event, selectedText) { } } - // Affichage des lexiques où le mot existe déjà if (existingLexiconIds.size > 0) { alert(`âš ï¸ Le mot "${selectedText}" existe déjà dans les lexiques suivants : ${Array.from(existingLexiconIds).join(", ")}`); } - // Filtrer les lexiques où le mot n'existe pas encore 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; } - // Envoi de la requête d'ajout try { console.log(`📡 Ajout du mot "${selectedText}" dans les lexiques :`, lexiconsToAdd); const result = await AddWord(authToken, selectedText, lexiconsToAdd, false); console.log("✅ Réponse API :", result); - // Rafraîchir l'UI après l'ajout await new Promise(resolve => setTimeout(resolve, 300)); browser.runtime.sendMessage({ action: "refreshUI" }); - // Affichage du message de confirmation dans le picker picker.innerHTML = `<p style="color: green;">✅ Mot ajouté avec succès dans : ${lexiconsToAdd.join(", ")}.</p>`; setTimeout(() => picker.style.display = "none", 2000); browser.runtime.sendMessage({ action: "addWordResult", - lexicons:`✅ Mot ajouté avec succès dans : ${lexiconsToAdd.join(", ")}.` + lexicons: `✅ Mot ajouté avec succès dans : ${lexiconsToAdd.join(", ")}.` }); } catch (error) { console.error("⌠Erreur lors de l'ajout du mot :", error); - - // Affichage du message d'erreur dans le picker picker.innerHTML = `<p style="color: red;">⌠Erreur : ${error.message}</p>`; setTimeout(() => picker.style.display = "none", 3000); browser.runtime.sendMessage({ @@ -401,15 +380,11 @@ async function showPicker(event, selectedText) { picker.style.display = "block"; } catch (error) { console.error("⌠Erreur lors de la récupération des lexiques :", error); - picker.innerHTML = "<p>Erreur lors du chargement des lexiques.</p>"; + picker.innerHTML = "<p style='color:#333;'>Erreur lors du chargement des lexiques.</p>"; picker.style.display = "block"; } } - - - - function hideLexiconPicker() { const picker = document.getElementById("lexiconPicker"); if (picker) { -- GitLab From 25f0c7137219e4de46b82c06c5c17ea3c07ed9c9 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 13 Feb 2025 17:09:34 +0100 Subject: [PATCH 22/23] =?UTF-8?q?Changement=20couleurs=20ic=C3=B4nes=20lex?= =?UTF-8?q?iques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/lexicon_icon.js | 29 ++++++++++++-------- src/context_menu/custom_context_menu.css | 11 ++++---- src/context_menu/custom_context_menu.js | 34 ++++++++++++------------ 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/assets/lexicon_icon.js b/src/assets/lexicon_icon.js index 394d73d..7b843b8 100644 --- a/src/assets/lexicon_icon.js +++ b/src/assets/lexicon_icon.js @@ -6,17 +6,24 @@ console.log("lexicon_icon.js chargé"); */ function generateRandomColor() { const palette = [ - "#6e76c7", - "#00a0bd", - "#96cd95", - "#ffeac2", - "#fff6ff", - "#e67e22", - "#20bad8", - "#f290e7", - "#f4ab9d", - "#f1e87a", - "#84e8e6" + "#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]; diff --git a/src/context_menu/custom_context_menu.css b/src/context_menu/custom_context_menu.css index 7bc2f23..f763805 100644 --- a/src/context_menu/custom_context_menu.css +++ b/src/context_menu/custom_context_menu.css @@ -91,7 +91,7 @@ width: 150px; font-family: Arial, sans-serif; font-size: 10px; - display: flex !important; + display: flex; flex-direction: row !important; flex-wrap: wrap !important; align-items: center; @@ -126,12 +126,11 @@ /* Style pour le cercle de couleur (icône interne) */ #lexiconPicker .color-circle { - width: 28px; /* ajustez la taille si besoin */ + width: 28px; height: 28px; border-radius: 50%; display: inline-block; - /* La couleur de fond sera définie dynamiquement via JS */ - border: 1px solid black; /* optionnel */ + border: 1px solid black; } /* Style pour le bouton de confirmation */ @@ -141,10 +140,12 @@ padding: 6px 10px; cursor: pointer; border: none; + align-items: center; + text-align: center; border-radius: 4px; background-color: #323046; color: white; - flex-basis: 100%; /* force le bouton à occuper toute la largeur et à passer à la ligne */ + flex-basis: 100%; margin-top: 8px; } diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index 91e117b..c37004a 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -242,21 +242,26 @@ function createPicker() { picker.style.padding = "8px"; picker.style.borderRadius = "8px"; picker.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.1)"; - picker.style.width = "220px"; // largeur adaptée pour afficher les icônes sur une ligne + picker.style.width = "220px"; picker.style.fontFamily = "Arial, sans-serif"; picker.style.fontSize = "10px"; - // Définir le picker en flex avec direction horizontale picker.style.display = "flex"; - picker.style.flexDirection = "row"; // IMPORTANT : aligne les éléments en ligne - picker.style.flexWrap = "wrap"; // autorise le retour à la ligne si nécessaire + 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 picker pour choisir le lexique dans lequel ajouter le mot. */ @@ -377,7 +382,7 @@ async function showPicker(event, selectedText) { // Positionner et afficher le picker picker.style.left = event.pageX + "px"; picker.style.top = event.pageY + "px"; - picker.style.display = "block"; + picker.style.display = "flex"; } catch (error) { console.error("⌠Erreur lors de la récupération des lexiques :", error); picker.innerHTML = "<p style='color:#333;'>Erreur lors du chargement des lexiques.</p>"; @@ -392,23 +397,18 @@ function hideLexiconPicker() { } } - document.addEventListener("mouseup", (event) => { const whiteBox = document.getElementById(WHITE_BOX_ID); const picker = document.getElementById("lexiconPicker"); - if (picker && picker.style.display === "block" && !picker.contains(event.target)) { - hideLexiconPicker(); - } - - // Vérifier si le clic est à l'extérieur des éléments - if ( - whiteBox && whiteBox.style.display === "block" && - !whiteBox.contains(event.target) && - (!picker || !picker.contains(event.target)) - ) { + // Masquer whiteBox si le clic est en dehors + if (whiteBox && !whiteBox.contains(event.target)) { hideWhiteBox(); - if (picker) picker.style.display = "none"; + } + + // Masquer picker si le clic est en dehors + if (picker && !picker.contains(event.target)) { + hideLexiconPicker(); } // Vérifier s'il y a du texte sélectionné -- GitLab From fb3a0c195407966c3465faf8547c362484161108 Mon Sep 17 00:00:00 2001 From: Lucie Bader <167515375+Lucie-Bdr@users.noreply.github.com> Date: Thu, 13 Feb 2025 17:29:07 +0100 Subject: [PATCH 23/23] Correction code --- src/assets/lexicon_icon.js | 3 --- src/context_menu/custom_context_menu.js | 28 +++++----------------- src/sidebar/sidebar.html | 9 +------ src/sidebar/sidebar.js | 31 +++++-------------------- 4 files changed, 13 insertions(+), 58 deletions(-) diff --git a/src/assets/lexicon_icon.js b/src/assets/lexicon_icon.js index 7b843b8..2929fee 100644 --- a/src/assets/lexicon_icon.js +++ b/src/assets/lexicon_icon.js @@ -1,5 +1,3 @@ -console.log("lexicon_icon.js chargé"); - /** * Sélectionne aléatoirement une couleur dans une palette prédéfinie. * @returns {string} Une couleur au format hexadécimal ou HSL. @@ -65,7 +63,6 @@ function createColorCircle(color, size = 32) { return circle; } -// Exposez ces fonctions globalement pour qu'elles soient accessibles dans d'autres scripts. window.generateRandomColor = generateRandomColor; window.getOrCreateLexiconColor = getOrCreateLexiconColor; window.createColorCircle = createColorCircle; diff --git a/src/context_menu/custom_context_menu.js b/src/context_menu/custom_context_menu.js index c37004a..ae90611 100644 --- a/src/context_menu/custom_context_menu.js +++ b/src/context_menu/custom_context_menu.js @@ -33,7 +33,6 @@ function injectWhiteBox() { if (!whiteBox) { whiteBox = document.createElement("div"); whiteBox.id = WHITE_BOX_ID; - // Styles essentiels whiteBox.style.position = "absolute"; whiteBox.style.zIndex = "9999"; whiteBox.style.backgroundColor = "#fff"; @@ -41,7 +40,6 @@ function injectWhiteBox() { 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("src/assets/icons/ajout_lexique.png"); const getDefinitionPath = browser.runtime.getURL("src/assets/icons/definition.png"); const loginPath = browser.runtime.getURL("src/assets/icons/connexion.png"); @@ -67,7 +65,6 @@ function injectWhiteBox() { document.body.appendChild(whiteBox); setupWhiteBoxActions(); } - // Empêcher la propagation des clics dans le menu whiteBox.addEventListener("mouseup", (e) => { e.stopPropagation(); }); @@ -186,7 +183,6 @@ function hideWhiteBox() { // Écoute globale pour la sélection de texte document.addEventListener("mouseup", (event) => { - // Si le clic se fait à l'intérieur du whiteBox, ne rien faire if (event.target.closest("#whiteBox")) return; const selectedText = window.getSelection().toString().trim(); if (selectedText) { @@ -222,13 +218,12 @@ browser.storage.onChanged.addListener((changes) => { } }); - // ───────────────────────────────────────────────────────────────────────────── -// Fonctions d'API pour l'ajout d'un mot via le picker +// Fonctions d'API pour l'ajout d'un mot via le sélecteur // ───────────────────────────────────────────────────────────────────────────── /** - * Crée (ou récupère) le picker de sélection des lexiques. + * Crée (ou récupère) le sélecteur des lexiques. */ function createPicker() { let picker = document.getElementById("lexiconPicker"); @@ -261,9 +256,8 @@ function createPicker() { return picker; } - /** - * Affiche le picker pour choisir le lexique dans lequel ajouter le mot. + * Affiche le sélecteur pour choisir le lexique dans lequel ajouter le mot. */ async function showPicker(event, selectedText) { let picker = document.getElementById("lexiconPicker"); @@ -283,18 +277,14 @@ async function showPicker(event, selectedText) { if (!Array.isArray(lexicons) || lexicons.length === 0) { picker.innerHTML = "<p style='color:#333;'>Aucun lexique trouvé.</p>"; } else { - // Ajout des icônes directement dans le picker for (const lex of lexicons) { const id = lex.id; const name = lex.category === "User" ? `Lexique personnel : ${lex.user?.pseudo || "Inconnu"} (${lex.id})` : `Lexique de groupe : ${lex.group?.name || "Inconnu"} (${lex.id})`; - // Obtenir la couleur et créer un cercle (l'icône) const color = await getOrCreateLexiconColor(id); const circleIcon = createColorCircle(color, 28); - - // Création du conteneur pour l'icône const iconContainer = document.createElement("div"); iconContainer.className = "lexicon-option"; iconContainer.dataset.lexiconId = id; @@ -312,7 +302,6 @@ async function showPicker(event, selectedText) { picker.appendChild(iconContainer); } - // Création du bouton de validation qui passera sur une nouvelle ligne const confirmButton = document.createElement("button"); confirmButton.className = "confirmButton"; confirmButton.textContent = "Ajouter le mot"; @@ -329,7 +318,7 @@ async function showPicker(event, selectedText) { try { definitions = await fetchLexiconDefinitions(selectedText); } catch (error) { - console.error("⌠Erreur lors de la récupération des définitions :", error); + console.error("Erreur lors de la récupération des définitions :", error); } const existingLexiconIds = new Set(); @@ -354,7 +343,7 @@ async function showPicker(event, selectedText) { try { console.log(`📡 Ajout du mot "${selectedText}" dans les lexiques :`, lexiconsToAdd); const result = await AddWord(authToken, selectedText, lexiconsToAdd, false); - console.log("✅ Réponse API :", result); + console.log("Réponse API :", result); await new Promise(resolve => setTimeout(resolve, 300)); browser.runtime.sendMessage({ action: "refreshUI" }); @@ -379,7 +368,6 @@ async function showPicker(event, selectedText) { picker.appendChild(confirmButton); } - // Positionner et afficher le picker picker.style.left = event.pageX + "px"; picker.style.top = event.pageY + "px"; picker.style.display = "flex"; @@ -401,17 +389,13 @@ document.addEventListener("mouseup", (event) => { const whiteBox = document.getElementById(WHITE_BOX_ID); const picker = document.getElementById("lexiconPicker"); - // Masquer whiteBox si le clic est en dehors if (whiteBox && !whiteBox.contains(event.target)) { hideWhiteBox(); } - - // Masquer picker si le clic est en dehors if (picker && !picker.contains(event.target)) { hideLexiconPicker(); } - - // Vérifier s'il y a du texte sélectionné + const selectedText = window.getSelection().toString().trim(); if (selectedText) { console.log("Texte sélectionné :", selectedText); diff --git a/src/sidebar/sidebar.html b/src/sidebar/sidebar.html index 6d189ef..84ab2a2 100644 --- a/src/sidebar/sidebar.html +++ b/src/sidebar/sidebar.html @@ -164,7 +164,7 @@ overflow: visible; } - /* Style uniformisé pour tous les tooltips */ + /* Style pour tous les tooltips */ .tooltip { all: unset; display: block; @@ -194,7 +194,6 @@ opacity: 1; transform: translateX(-50%) translateY(-5px); } - /* Positionnement ajusté si le conteneur est trop proche des bords */ .tooltip-container.left .tooltip { left: 0; transform: translateX(0) translateY(-5px); @@ -256,11 +255,8 @@ filter: brightness(0) saturate(100%) invert(83%) sepia(89%) saturate(588%) hue-rotate(360deg); } - /* Cibler les tooltips à l'intérieur d'un bouton de surlignage */ button.lexique-highlight-toggle .tooltip { - /* Réinitialiser toute influence du style global du bouton */ all: unset; - /* Appliquer les styles désirés pour le tooltip */ display: block; box-sizing: border-box; position: absolute; @@ -284,14 +280,11 @@ line-height: normal; } - /* Lors du survol du conteneur, afficher le tooltip */ button.lexique-highlight-toggle:hover .tooltip { opacity: 1; transform: translateX(-50%) translateY(-5px); } - - /* Autres styles divers */ .lexicon-section { margin-bottom: 10px; } diff --git a/src/sidebar/sidebar.js b/src/sidebar/sidebar.js index c937cc6..8b80001 100644 --- a/src/sidebar/sidebar.js +++ b/src/sidebar/sidebar.js @@ -224,7 +224,6 @@ async function displayLexiconsWithCheckbox(lexicons) { const lexiqueDiv = document.createElement("div"); lexiqueDiv.className = "lexique-item"; - // Obtenir la couleur associée de façon asynchrone const color = await getOrCreateLexiconColor(lexiconId); const circleIcon = createColorCircle(color, 24); @@ -255,7 +254,7 @@ async function displayLexiconsWithCheckbox(lexicons) { highlightButton.dataset.lexiconId = lexiconId; highlightButton.dataset.active = active ? "true" : "false"; const feutreIcon = document.createElement("img"); - feutreIcon.src = "../assets/icons/feutre.png"; // Vérifiez le chemin relatif + feutreIcon.src = "../assets/icons/feutre.png"; feutreIcon.alt = "Feutre"; feutreIcon.className = "feutre-icon"; const highlightTooltip = document.createElement("span"); @@ -280,8 +279,6 @@ async function displayLexiconsWithCheckbox(lexicons) { highlightButton.appendChild(feutreIcon); highlightButton.appendChild(highlightTooltip); - - // Assemblage final lexiqueDiv.appendChild(iconDiv); lexiqueDiv.appendChild(labelSpan); lexiqueDiv.appendChild(checkboxContainer); @@ -290,7 +287,6 @@ async function displayLexiconsWithCheckbox(lexicons) { lexiquesContainer.appendChild(lexiqueDiv); } - // Ajustement dynamique des tooltips (après un court délai) setTimeout(() => { const menu = document.getElementById("menu"); if (!menu) return; @@ -315,9 +311,6 @@ async function displayLexiconsWithCheckbox(lexicons) { }, 100); } - - - function initModal() { console.log("initModal appelé"); const modalOverlay = document.getElementById("modalOverlay"); @@ -353,11 +346,6 @@ async function handleAuthButtonClick() { // ───────────────────────────────────────────────────────────────────────────── // â–Œ Ajout d'un mot au(x) lexique(s) // ───────────────────────────────────────────────────────────────────────────── -/** - * Au clic sur le bouton "add-word-button", - * on récupère le mot sélectionné (#motSelectionne) - * et les lexiques cochés, puis on appelle AddWord. - */ async function handleAddWordClick() { openBlock("menuContent"); // 1) Vérifier la présence du token et du mot @@ -419,7 +407,7 @@ async function handleAddWordClick() { // 5) Déterminer les lexiques où ajouter le mot const lexiconsToAdd = selectedLexiconIds.filter(id => !existingLexiconIds.has(id)); if (lexiconsToAdd.length === 0) { - return; // Rien à ajouter, tous les lexiques sélectionnés contiennent déjà le mot + return; } // 6) Envoi d’une seule requête pour tous les lexiques restants @@ -427,7 +415,7 @@ async function handleAddWordClick() { console.log(`📡 Envoi de l'ajout du mot "${selectedWord}" dans les lexiques :`, lexiconsToAdd); const result = await window.AddWord(authToken, selectedWord, lexiconsToAdd, false); - console.log("✅ Réponse API :", result); + console.log("Réponse API :", result); // Rafraîchir l'UI et la liste des entrées await new Promise(resolve => setTimeout(resolve, 300)); @@ -441,17 +429,13 @@ async function handleAddWordClick() { } } catch (error) { - console.error("⌠Erreur lors de l’ajout du mot :", error); + console.error("Erreur lors de l’ajout du mot :", error); if (lexiconResultElement) { lexiconResultElement.textContent = "Erreur lors de l’ajout : " + error.message; } } } - - - - // ───────────────────────────────────────────────────────────────────────────── // â–Œ Réception des messages // ───────────────────────────────────────────────────────────────────────────── @@ -611,18 +595,15 @@ document.addEventListener("DOMContentLoaded", async () => { }); document.querySelectorAll('.toggle-btn').forEach(btn => { - // Forcer l'affichage initial à "+" btn.textContent = '+'; btn.style.fontSize = '15px'; - // Gestion du clic sur le bouton btn.addEventListener('click', (event) => { event.stopPropagation(); const header = btn.parentElement; const content = header.nextElementSibling; if (content) { content.classList.toggle('hidden'); - // Mettre à jour le texte du bouton selon l'état du bloc btn.textContent = content.classList.contains('hidden') ? '+' : '–'; } }); @@ -635,10 +616,10 @@ document.querySelectorAll('.toggle-btn').forEach(btn => { const blockContent = this.parentElement.nextElementSibling; if (blockContent.classList.contains('hidden')) { blockContent.classList.remove('hidden'); - this.textContent = '–'; // affiche le symbole pour fermer + this.textContent = '–'; } else { blockContent.classList.add('hidden'); - this.textContent = '+'; // affiche le symbole pour ouvrir + this.textContent = '+'; } }); }); -- GitLab