Index: gc_lang/fr/config.ini ================================================================== --- gc_lang/fr/config.ini +++ gc_lang/fr/config.ini @@ -15,26 +15,30 @@ logo = logo.png # main dictionary lexicon_src = lexicons/French.lex dic_filenames = fr-allvars,fr-classic,fr-reform -dic_name = Français,Français (Classique/Moderne),Français (Réforme 1990) +dic_name = fr-allvars,fr-classic,fr-reform +dic_description = Français (Toutes variantes),Français (Classique),Français (Réforme 1990) dic_filter = ,[*CMPX]$,[*RPX]$ dic_default_filename_py = fr-allvars dic_default_filename_js = fr-allvars # extended dictionary lexicon_extended_src = lexicons/French.extended.lex dic_extended_filename = fr.extended -dic_extended_name = Français - dictionnaire étendu +dic_extended_name = fr.extended +dic_extended_description = Français - dictionnaire étendu # community dictionary lexicon_community_src = lexicons/French.community.lex dic_community_filename = fr.community -dic_community_name = Français - dictionnaire communautaire +dic_community_name = fr.community +dic_community_description = Français - dictionnaire communautaire # personal dictionary lexicon_personal_src = lexicons/French.personal.lex dic_personal_filename = fr.personal -dic_personal_name = Français - dictionnaire personnel +dic_personal_name = fr.personal +dic_personal_description = Français - dictionnaire personnel # Finite state automaton compression: 1, 2 (experimental) or 3 (experimental) fsa_method = 1 # stemming method: S for suffixes only, A for prefixes and suffixes stemming_method = S @@ -46,11 +50,11 @@ # Firefox fx_identifier = French-GC@grammalecte.net fx_name = Grammalecte [fr] win_fx_dev_path = C:\Program Files\Firefox Developer Edition\firefox.exe -win_fx_nightly_path = C:\Program Files\Nightly\firefox.exe +win_fx_nightly_path = C:\Program Files\Firefox Nightly\firefox.exe linux_fx_dev_path = /usr/bin/firefox linux_fx_nightly_path = /usr/bin/firefox # Thunderbird tb_identifier = French-GC-TB@grammalecte.net Index: gc_lang/fr/dictionnaire/genfrdic.py ================================================================== --- gc_lang/fr/dictionnaire/genfrdic.py +++ gc_lang/fr/dictionnaire/genfrdic.py @@ -524,15 +524,10 @@ def writeGrammarCheckerLexicon (self, spfDst, version): echo(' * Lexique simplifié >> [ {} ] '.format(spfDst)) with open(spfDst[:-4]+".lex", 'w', encoding='utf-8', newline="\n") as hDst: hDst.write(MPLHEADER) hDst.write("# Lexique simplifié pour Grammalecte v{}\n# Licence : MPL v2.0\n\n".format(version)) - hDst.write("## LangCode: fr\n") - hDst.write("## LangName: Français\n") - hDst.write("## DicName: fr.commun\n") - hDst.write("## Description: Français commun (toutes variantes)\n") - hDst.write("## Author: Olivier R.\n\n") hDst.write(Flexion.simpleHeader()) for oFlex in self.lFlexions: hDst.write(oFlex.getGrammarCheckerRepr()) def createFiles (self, spDst, lDictVars, nMode, bSimplified): Index: gc_lang/fr/oxt/DictOptions/LexiconEditor.py ================================================================== --- gc_lang/fr/oxt/DictOptions/LexiconEditor.py +++ gc_lang/fr/oxt/DictOptions/LexiconEditor.py @@ -409,11 +409,11 @@ xGridDataModel = self.xGridModelLex.GridDataModel lEntry = [] for i in range(xGridDataModel.RowCount): lEntry.append(xGridDataModel.getRowData(i)) if lEntry: - oDAWG = dawg.DAWG(lEntry, "S", "fr", "Français", "fr.personal") + oDAWG = dawg.DAWG(lEntry, "S", "fr", "Français", "fr.personal", "Dictionnaire personnel") self.oPersonalDicJSON = oDAWG.getBinaryAsJSON() self.xOptionNode.setPropertyValue("personal_dic", json.dumps(self.oPersonalDicJSON, ensure_ascii=False)) self.xSettingNode.commitChanges() self.xNumDic.Label = str(self.oPersonalDicJSON["nEntry"]) self.xDateDic.Label = self.oPersonalDicJSON["sDate"] Index: gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-classique.aff ================================================================== --- gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-classique.aff +++ gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-classique.aff @@ -2,11 +2,11 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # AFFIXES DU DICTIONNAIRE ORTHOGRAPHIQUE FRANÇAIS “CLASSIQUE” v7.0 # par Olivier R. -- licence MPL 2.0 -# Généré le 09-01-2019 à 18:08 +# Généré le 11-01-2019 à 17:14 # Pour améliorer le dictionnaire, allez sur https://grammalecte.net/ SET UTF-8 Index: gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-moderne.aff ================================================================== --- gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-moderne.aff +++ gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-moderne.aff @@ -2,11 +2,11 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # AFFIXES DU DICTIONNAIRE ORTHOGRAPHIQUE FRANÇAIS “MODERNE” v7.0 # par Olivier R. -- licence MPL 2.0 -# Généré le 09-01-2019 à 18:08 +# Généré le 11-01-2019 à 17:14 # Pour améliorer le dictionnaire, allez sur https://grammalecte.net/ SET UTF-8 Index: gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-reforme1990.aff ================================================================== --- gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-reforme1990.aff +++ gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-reforme1990.aff @@ -2,11 +2,11 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # AFFIXES DU DICTIONNAIRE ORTHOGRAPHIQUE FRANÇAIS “RÉFORME 1990” v7.0 # par Olivier R. -- licence MPL 2.0 -# Généré le 09-01-2019 à 18:08 +# Généré le 11-01-2019 à 17:14 # Pour améliorer le dictionnaire, allez sur https://grammalecte.net/ SET UTF-8 Index: gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-toutesvariantes.aff ================================================================== --- gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-toutesvariantes.aff +++ gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-toutesvariantes.aff @@ -2,11 +2,11 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # AFFIXES DU DICTIONNAIRE ORTHOGRAPHIQUE FRANÇAIS “TOUTES VARIANTES” v7.0 # par Olivier R. -- licence MPL 2.0 -# Généré le 09-01-2019 à 18:08 +# Généré le 11-01-2019 à 17:14 # Pour améliorer le dictionnaire, allez sur https://grammalecte.net/ SET UTF-8 Index: gc_lang/fr/tb/content/lex_editor.js ================================================================== --- gc_lang/fr/tb/content/lex_editor.js +++ gc_lang/fr/tb/content/lex_editor.js @@ -476,11 +476,11 @@ build: function () { let xProgressNode = document.getElementById("wait_progress"); let lEntry = oLexiconTable.getEntries(); if (lEntry.length > 0) { - let oDAWG = new DAWG(lEntry, "S", "fr", "Français", "fr.personal", xProgressNode); + let oDAWG = new DAWG(lEntry, "S", "fr", "Français", "fr.personal", "Dictionnaire personnel", xProgressNode); let oJSON = oDAWG.createBinaryJSON(1); oFileHandler.saveFile("fr.personal.json", JSON.stringify(oJSON)); this.oIBDAWG = new IBDAWG(oJSON); this.setDictData(this.oIBDAWG.nEntry, this.oIBDAWG.sDate); //browser.runtime.sendMessage({ sCommand: "setDictionary", dParam: {sType: "personal", oDict: oJSON}, dInfo: {} }); Index: gc_lang/fr/webext/background.js ================================================================== --- gc_lang/fr/webext/background.js +++ gc_lang/fr/webext/background.js @@ -117,25 +117,22 @@ dParam: { sDictionary: sDictionary, bActivate: bActivate }, dInfo: {} }); } -function initSCOptions (dSavedOptions) { - if (!dSavedOptions.hasOwnProperty("sc_options")) { +function initSCOptions (oData) { + if (!oData.hasOwnProperty("sc_options")) { browser.storage.local.set({"sc_options": { extended: true, community: true, personal: true }}); - setDictionaryOnOff("extended", true); setDictionaryOnOff("community", true); setDictionaryOnOff("personal", true); } else { - let dOptions = dSavedOptions.sc_options; - setDictionaryOnOff("extended", dOptions["extended"]); - setDictionaryOnOff("community", dOptions["community"]); - setDictionaryOnOff("personal", dOptions["personal"]); + setDictionaryOnOff("community", oData.sc_options["community"]); + setDictionaryOnOff("personal", oData.sc_options["personal"]); } } function setDictionary (sDictionary, oDictionary) { xGCEWorker.postMessage({ @@ -143,37 +140,41 @@ dParam: { sDictionary: sDictionary, oDict: oDictionary }, dInfo: {} }); } -function setSpellingDictionary (dSavedDictionary) { - if (dSavedDictionary.hasOwnProperty("oExtendedDictionary")) { - setDictionary("extended", dSavedDictionary["oExtendedDictionary"]); - } - if (dSavedDictionary.hasOwnProperty("oCommunityDictionary")) { - setDictionary("community", dSavedDictionary["oCommunityDictionary"]); - } - if (dSavedDictionary.hasOwnProperty("oPersonalDictionary")) { - setDictionary("personal", dSavedDictionary["oPersonalDictionary"]); +function setSpellingDictionaries (oData) { + if (oData.hasOwnProperty("oPersonalDictionary")) { + // deprecated + console.log("personal dictionary migration"); + browser.storage.local.set({ "dictionaries": { "__personal__": oData["oPersonalDictionary"] } }); + setDictionary("personal", oData["oPersonalDictionary"]); + browser.storage.local.remove("oPersonalDictionary"); + } + if (oData.hasOwnProperty("dictionaries")) { + if (oData.dictionaries.hasOwnProperty("__personal__")) { + setDictionary("personal", oData.dictionaries["__personal__"]); + } + if (oData.dictionaries.hasOwnProperty("__community__")) { + setDictionary("personal", oData.dictionaries["__community__"]); + } } } function init () { if (bChrome) { browser.storage.local.get("gc_options", initGrammarChecker); browser.storage.local.get("ui_options", initUIOptions); - browser.storage.local.get("oExtendedDictionary", setSpellingDictionary); - browser.storage.local.get("oCommunityDictionary", setSpellingDictionary); - browser.storage.local.get("oPersonalDictionary", setSpellingDictionary); + browser.storage.local.get("dictionaries", setSpellingDictionaries); + browser.storage.local.get("oPersonalDictionary", setSpellingDictionaries); // deprecated browser.storage.local.get("sc_options", initSCOptions); return; } browser.storage.local.get("gc_options").then(initGrammarChecker, showError); browser.storage.local.get("ui_options").then(initUIOptions, showError); - browser.storage.local.get("oExtendedDictionary").then(setSpellingDictionary, showError); - browser.storage.local.get("oCommunityDictionary").then(setSpellingDictionary, showError); - browser.storage.local.get("oPersonalDictionary").then(setSpellingDictionary, showError); + browser.storage.local.get("dictionaries").then(setSpellingDictionaries, showError); + browser.storage.local.get("oPersonalDictionary").then(setSpellingDictionaries, showError); // deprecated browser.storage.local.get("sc_options").then(initSCOptions, showError); } init(); @@ -215,10 +216,19 @@ xGCEWorker.postMessage(oRequest); break; case "openURL": browser.tabs.create({url: dParam.sURL}); break; + case "openConjugueurTab": + openConjugueurTab(); + break; + case "openLexiconEditor": + openLexiconEditor(dParam["dictionary"]); + break; + case "openDictionaries": + openDictionaries(); + break; default: console.log("[background] Unknown command: " + sCommand); console.log(oRequest); } //sendResponse({response: "response from background script"}); @@ -226,10 +236,11 @@ browser.runtime.onMessage.addListener(handleMessage); function handleConnexion (xPort) { + // Messages from tabs let iPortId = xPort.sender.tab.id; // identifier for the port: each port can be found at dConnx[iPortId] dConnx.set(iPortId, xPort); xPort.onMessage.addListener(function (oRequest) { let {sCommand, dParam, dInfo} = oRequest; switch (sCommand) { @@ -277,13 +288,15 @@ browser.contextMenus.create({ id: "separator_editable", type: "separator", contexts: ["editable"] }); // Page browser.contextMenus.create({ id: "rightClickLxgPage", title: "Lexicographe (page)", contexts: ["all"] }); // on all parts, due to unwanted selection browser.contextMenus.create({ id: "rightClickGCPage", title: "Correction grammaticale (page)", contexts: ["all"] }); browser.contextMenus.create({ id: "separator_page", type: "separator", contexts: ["all"] }); -// Conjugueur +// Tools browser.contextMenus.create({ id: "conjugueur_window", title: "Conjugueur [fenêtre]", contexts: ["all"] }); browser.contextMenus.create({ id: "conjugueur_tab", title: "Conjugueur [onglet]", contexts: ["all"] }); +browser.contextMenus.create({ id: "dictionaries", title: "Dictionnaires", contexts: ["all"] }); +browser.contextMenus.create({ id: "lexicon_editor", title: "Éditeur lexical", contexts: ["all"] }); // Rescan page browser.contextMenus.create({ id: "separator_rescan", type: "separator", contexts: ["editable"] }); browser.contextMenus.create({ id: "rescanPage", title: "Rechercher à nouveau les zones de texte", contexts: ["editable"] }); @@ -323,10 +336,16 @@ openConjugueurWindow(); break; case "conjugueur_tab": openConjugueurTab(); break; + case "lexicon_editor": + openLexiconEditor(); + break; + case "dictionaries": + openDictionaries(); + break; // rescan page case "rescanPage": let xPort = dConnx.get(xTab.id); xPort.postMessage({sActionDone: "rescanPage"}); break; @@ -347,16 +366,35 @@ openConjugueurTab(); break; case "conjugueur_window": openConjugueurWindow(); break; - case "lex_editor": - openLexEditor(); + case "lexicon_editor": + openLexiconEditor(); + break; + case "dictionaries": + openDictionaries(); break; } }); + +/* + Tabs +*/ +let nTabLexiconEditor = null; +let nTabDictionaries = null; +let nTabConjugueur = null; + +browser.tabs.onRemoved.addListener(function (nTabId, xRemoveInfo) { + switch (nTabId) { + case nTabLexiconEditor: nTabLexiconEditor = null; break; + case nTabDictionaries: nTabDictionaries = null; break; + case nTabConjugueur: nTabConjugueur = null; break; + } +}); + /* Actions */ @@ -370,34 +408,74 @@ function sendCommandToTab (sCommand, iTab) { let xTabPort = dConnx.get(iTab); xTabPort.postMessage({sActionDone: sCommand, result: null, dInfo: null, bEnd: false, bError: false}); } -function openLexEditor () { - if (bChrome) { - browser.tabs.create({ +function openLexiconEditor (sName="__personal__") { + if (nTabLexiconEditor === null) { + if (bChrome) { + browser.tabs.create({ + url: browser.extension.getURL("panel/lex_editor.html") + }, onLexiconEditorOpened); + return; + } + let xLexEditor = browser.tabs.create({ url: browser.extension.getURL("panel/lex_editor.html") }); - return; + xLexEditor.then(onLexiconEditorOpened, onError); + } + else { + browser.tabs.update(nTabLexiconEditor, {active: true}); + } +} + +function onLexiconEditorOpened (xTab) { + nTabLexiconEditor = xTab.id; +} + +function openDictionaries () { + if (nTabDictionaries === null) { + if (bChrome) { + browser.tabs.create({ + url: browser.extension.getURL("panel/dictionaries.html") + }, onDictionariesOpened); + return; + } + let xLexEditor = browser.tabs.create({ + url: browser.extension.getURL("panel/dictionaries.html") + }); + xLexEditor.then(onDictionariesOpened, onError); + } + else { + browser.tabs.update(nTabDictionaries, {active: true}); } - let xLexEditor = browser.tabs.create({ - url: browser.extension.getURL("panel/lex_editor.html") - }); - xLexEditor.then(onCreated, onError); +} + +function onDictionariesOpened (xTab) { + nTabDictionaries = xTab.id; } function openConjugueurTab () { - if (bChrome) { - browser.tabs.create({ + if (nTabDictionaries === null) { + if (bChrome) { + browser.tabs.create({ + url: browser.extension.getURL("panel/conjugueur.html") + }, onConjugueurOpened); + return; + } + let xConjTab = browser.tabs.create({ url: browser.extension.getURL("panel/conjugueur.html") }); - return; + xConjTab.then(onConjugueurOpened, onError); + } + else { + browser.tabs.update(nTabConjugueur, {active: true}); } - let xConjTab = browser.tabs.create({ - url: browser.extension.getURL("panel/conjugueur.html") - }); - xConjTab.then(onCreated, onError); +} + +function onConjugueurOpened (xTab) { + nTabConjugueur = xTab.id; } function openConjugueurWindow () { if (bChrome) { browser.windows.create({ @@ -412,16 +490,11 @@ url: browser.extension.getURL("panel/conjugueur.html"), type: "popup", width: 710, height: 980 }); - xConjWindow.then(onCreated, onError); } -function onCreated (xWindowInfo) { - //console.log(`Created window: ${xWindowInfo.id}`); -} - -function onError (error) { - console.log(`Error: ${error}`); +function onError (e) { + console.error(e); } Index: gc_lang/fr/webext/gce_worker.js ================================================================== --- gc_lang/fr/webext/gce_worker.js +++ gc_lang/fr/webext/gce_worker.js @@ -318,13 +318,10 @@ //console.log("setDictionary", sDictionary); switch (sDictionary) { case "main": oSpellChecker.setMainDictionary(oDict); break; - case "extended": - oSpellChecker.setExtendedDictionary(oDict); - break; case "community": oSpellChecker.setCommunityDictionary(oDict); break; case "personal": oSpellChecker.setPersonalDictionary(oDict); @@ -340,17 +337,10 @@ postMessage(createResponse("setDictionary", "# Error. SpellChecker not loaded.", dInfo, true)); return; } //console.log("setDictionaryOnOff", sDictionary, bActivate); switch (sDictionary) { - case "extended": - if (bActivate) { - oSpellChecker.activateExtendedDictionary(); - } else { - oSpellChecker.deactivateExtendedDictionary(); - } - break; case "community": if (bActivate) { oSpellChecker.activateCommunityDictionary(); } else { oSpellChecker.deactivateCommunityDictionary(); Index: gc_lang/fr/webext/manifest.json ================================================================== --- gc_lang/fr/webext/manifest.json +++ gc_lang/fr/webext/manifest.json @@ -79,26 +79,24 @@ } ], "commands": { "conjugueur_tab": { - "suggested_key": { - "default": "Ctrl+Shift+6" - }, + "suggested_key": { "default": "Ctrl+Shift+6" }, "description": "Ouvre le conjugueur dans un onglet" }, "conjugueur_window": { - "suggested_key": { - "default": "Ctrl+Shift+7" - }, + "suggested_key": { "default": "Ctrl+Shift+7" }, "description": "Ouvre le conjugueur dans une fenêtre" }, - "lex_editor": { - "suggested_key": { - "default": "Ctrl+Shift+8" - }, + "lexicon_editor": { + "suggested_key": { "default": "Ctrl+Shift+8" }, "description": "Ouvre l’éditeur lexical" + }, + "dictionaries": { + "suggested_key": { "default": "Ctrl+Shift+9" }, + "description": "Ouvre le gestionnaire de dictionnaires communautaires" } }, "web_accessible_resources": [ "content_scripts/panel.css", ADDED gc_lang/fr/webext/panel/dictionaries.css Index: gc_lang/fr/webext/panel/dictionaries.css ================================================================== --- gc_lang/fr/webext/panel/dictionaries.css +++ gc_lang/fr/webext/panel/dictionaries.css @@ -0,0 +1,146 @@ +/* + CSS Document + White + Design par Olivier R. +*/ + +* { margin: 0; padding: 0; } +img { border: none; } + + +/* Generic classes */ + +.fleft { float: left; } +.fright { float: right; } +.center { text-align: center; } +.right { text-align: right; } +.left { text-align: left; } +.justify { text-align: justify; } +.hidden { display: none; } +.clearer { clear: both; font-size: 0; height: 0; } + +body { + background: hsl(0, 0%, 100%) url(../img/lines.png); + font: normal 16px "Trebuchet MS", "Fira Sans", "Liberation Sans", sans-serif; + color: #505050; +} + +.inbox { + width: 800px; + margin: 20px auto 10px auto; + padding: 10px 30px 30px 30px; + background: hsl(0, 0%, 100%); + border: 2px solid hsl(210, 0%, 90%); + border-radius: 20px; +} + +h1 { + margin: 5px 0 5px 0; + color: hsl(210, 50%, 50%); + font: bold 30px "Trebuchet MS", "Fira Sans", "Liberation Sans", sans-serif; + text-align: center; +} +h2 { + margin: 10px 0 2px 0; + color: hsl(0, 50%, 50%); + font: bold 20px "Trebuchet MS", "Fira Sans", "Liberation Sans", sans-serif; +} + + +/* + Main buttons +*/ + +ul { + margin-left: 30px; +} + +input[type=text].large { + display: inline-block; + width: 250px; + padding: 5px 10px; + border: 2px solid hsl(0, 0%, 80%); + border-radius: 3px; + height: 24px; + background: transparent; + font: normal 20px Tahoma, "Ubuntu Condensed"; + color: hsl(0, 0%, 20%); +} + +input[type=text].medium { + display: inline-block; + width: 175px; + padding: 2px 5px; + border: 2px solid hsl(0, 0%, 80%); + border-radius: 3px; + height: 20px; + background: transparent; + font: normal 18px Tahoma, "Ubuntu Condensed"; + color: hsl(0, 0%, 20%); +} + +input[placeholder] { + color: hsl(0, 0%, 50%); +} + + +.dic_button { + margin: 2px; + display: inline-block; +} +.dic_button_close { + display: inline-block; + padding: 1px 5px; + background-color: hsl(0, 50%, 50%); + color: hsl(0, 90%, 90%); + border-style: solid; + border-width: 1px 0 1px 1px; + border-color: hsl(0, 50%, 45%); + border-radius: 3px 0 0 3px; + cursor: pointer; +} +.dic_button_label { + display: inline-block; + padding: 1px 10px; + background-color: hsl(120, 50%, 94%); + border-style: solid; + border-width: 1px 1px 1px 0; + border-color: hsl(120, 50%, 70%); + border-radius: 0 3px 3px 0; +} + + +/* + Table +*/ +#wait_progress { + width: 100%; + height: 4px; +} + +table { + border: 1px solid hsl(210, 10%, 50%); + width: 100%; + font-size: 14px; +} +th { + padding: 5px 10px; + border-left: 1px solid hsl(210, 10%, 90%); + text-align: left; +} +td { + padding: 0 10px; + vertical-align: top; +} +.delete_entry { + cursor: pointer; + font-weight: bold; + color: hsl(0, 100%, 50%); +} +.select_entry { + cursor: pointer; + background-color: hsl(120, 50%, 30%); + color: hsl(120, 50%, 100%); + border-radius: 3px; + text-align: center; +} ADDED gc_lang/fr/webext/panel/dictionaries.html Index: gc_lang/fr/webext/panel/dictionaries.html ================================================================== --- gc_lang/fr/webext/panel/dictionaries.html +++ gc_lang/fr/webext/panel/dictionaries.html @@ -0,0 +1,34 @@ + + + + + Grammalecte · Dictionnaires communautaires + + + + + +
+ +

Dictionnaires communautaires

+ +

Dictionnaires sélectionnés

+

[Aucun]

+ +

0 dictionnaires disponibles

+ + +
+ +
+ + + + + + + + + + + ADDED gc_lang/fr/webext/panel/dictionaries.js Index: gc_lang/fr/webext/panel/dictionaries.js ================================================================== --- gc_lang/fr/webext/panel/dictionaries.js +++ gc_lang/fr/webext/panel/dictionaries.js @@ -0,0 +1,217 @@ +// JavaScript + +"use strict"; + + +// Chrome don’t follow the W3C specification: +// https://browserext.github.io/browserext/ +let bChrome = false; +if (typeof(browser) !== "object") { + var browser = chrome; + bChrome = true; +} + + +/* + Common functions +*/ + +function showError (e) { + console.error(e.fileName + "\n" + e.name + "\nline: " + e.lineNumber + "\n" + e.message); +} + +function createNode (sType, oAttr, oDataset=null) { + try { + let xNode = document.createElement(sType); + Object.assign(xNode, oAttr); + if (oDataset) { + Object.assign(xNode.dataset, oDataset); + } + return xNode; + } + catch (e) { + showError(e); + } +} + + + +class Table { + + constructor (sNodeId, lColumn, sProgressBarId, sResultId="", bDeleteButtons=true, bActionButtons) { + this.sNodeId = sNodeId; + this.xTable = document.getElementById(sNodeId); + this.nColumn = lColumn.length; + this.lColumn = lColumn; + this.xProgressBar = document.getElementById(sProgressBarId); + this.xNumEntry = document.getElementById(sResultId); + this.iEntryIndex = 0; + this.lEntry = []; + this.nEntry = 0; + this.aSelectedDict = new Map(); + this.bDeleteButtons = bDeleteButtons; + this.bActionButtons = bActionButtons; + this._createHeader(); + this.listen(); + } + + _createHeader () { + let xRowNode = createNode("tr"); + if (this.bDeleteButtons) { + xRowNode.appendChild(createNode("th", { textContent: "·", width: "12px" })); + } + for (let sColumn of this.lColumn) { + xRowNode.appendChild(createNode("th", { textContent: sColumn })); + } + this.xTable.appendChild(xRowNode); + } + + clear () { + while (this.xTable.firstChild) { + this.xTable.removeChild(this.xTable.firstChild); + } + this.lEntry = []; + this.nEntry = 0; + this.iEntryIndex = 0; + this._createHeader(); + this.showEntryNumber(); + } + + fill (lFlex) { + this.clear(); + if (lFlex.length > 0) { + this.xProgressBar.max = lFlex.length; + this.xProgressBar.value = 1; + for (let lData of lFlex) { + this._addRow(lData); + this.xProgressBar.value += 1; + } + this.xProgressBar.value = this.xProgressBar.max; + } + this.lEntry = lFlex; + this.nEntry = lFlex.length; + this.showEntryNumber(); + } + + addEntries (lFlex) { + this.lEntry.push(...lFlex); + for (let lData of lFlex) { + this._addRow(lData); + } + this.nEntry += lFlex.length; + this.showEntryNumber(); + } + + showEntryNumber () { + if (this.xNumEntry) { + this.xNumEntry.textContent = this.nEntry; + } + } + + _addRow (lData) { + let xRowNode = createNode("tr", { id: this.sNodeId + "_row_" + this.iEntryIndex }); + if (this.bDeleteButtons) { + xRowNode.appendChild(createNode("td", { textContent: "×", className: "delete_entry", title: "Effacer cette entrée" }, { id_entry: this.iEntryIndex })); + } + let [nDicId, sName, sOwner, nEntry, sDescription, ...data] = lData; + xRowNode.appendChild(createNode("td", { textContent: nDicId })); + xRowNode.appendChild(createNode("td", { textContent: sName })); + xRowNode.appendChild(createNode("td", { textContent: sOwner })); + xRowNode.appendChild(createNode("td", { textContent: nEntry })); + xRowNode.appendChild(createNode("td", { textContent: sDescription })); + if (this.bActionButtons) { + xRowNode.appendChild(createNode("td", { textContent: "+", className: "select_entry", title: "Sélectionner/Désélectionner cette entrée" }, { id_entry: this.iEntryIndex, dict_name: sName })); + } + this.xTable.appendChild(xRowNode); + this.iEntryIndex += 1; + } + + listen () { + if (this.bDeleteButtons || this.bActionButtons) { + this.xTable.addEventListener("click", (xEvent) => { this.onTableClick(xEvent); }, false); + } + } + + onTableClick (xEvent) { + try { + let xElem = xEvent.target; + if (xElem.className) { + switch (xElem.className) { + case "delete_entry": this.deleteRow(xElem.dataset.id_entry, xElem.dataset.dict_name); break; + case "select_entry": this.selectEntry(xElem.dataset.id_entry, xElem.dataset.dict_name); break; + } + } + } + catch (e) { + showError(e); + } + } + + deleteRow (iEntry) { + this.lEntry[parseInt(iEntry)] = null; + if (document.getElementById(this.sNodeId + "_row_" + iEntry)) { + document.getElementById(this.sNodeId + "_row_" + iEntry).style.display = "none"; + } + this.nEntry -= 1; + this.showEntryNumber(); + if (this.sNodeId == "lexicon_table") { + showElement("save_button", "inline-block"); + } + } + + selectEntry (nEntryId, sDicName) { + let sRowId = this.sNodeId + "_row_" + nEntryId; + if (!this.aSelectedDict.has(sDicName)) { + this.aSelectedDict.set(sDicName, nEntryId); + document.getElementById(sRowId).style.backgroundColor = "hsl(120, 50%, 90%)"; + } + else { + this.aSelectedDict.delete(sDicName); + document.getElementById(sRowId).style.backgroundColor = ""; + } + this.showSelectedDict(); + } + + clearSelectedDict () { + let xDicList = document.getElementById("dictionaries_list"); + while (xDicList.firstChild) { + xDicList.removeChild(xDicList.firstChild); + } + } + + showSelectedDict () { + this.clearSelectedDict(); + let xDicList = document.getElementById("dictionaries_list"); + if (this.aSelectedDict.size === 0) { + xDicList.textContent = "[Aucun]"; + return; + } + for (let [sName, nDicId] of this.aSelectedDict) { + xDicList.appendChild(this.createDictLabel(nDicId, sName)); + } + } + + createDictLabel (nDicId, sLabel) { + let xLabel = createNode("div", {className: "dic_button"}); + let xCloseButton = createNode("div", {className: "dic_button_close", textContent: "×"}, {id_entry: nDicId}); + xCloseButton.addEventListener("click", () => { + this.aSelectedDict.delete(sLabel); + document.getElementById(this.sNodeId+"_row_"+nDicId).style.backgroundColor = ""; + xLabel.style.display = "none"; + }); + xLabel.appendChild(xCloseButton); + xLabel.appendChild(createNode("div", {className: "dic_button_label", textContent: sLabel})); + return xLabel; + } +} + + +const oDicTable = new Table("dictionaries_table", ["Id", "Nom", "par", "Entrées", "Description"], "wait_progress", "num_dic", false, true); + +oDicTable.fill([ + [1, "Ambre", "Inconnu", "240", "Univers des Princes d’Ambre (de Roger Zelazny)"], + [2, "Malaz", "Inconnu", "2340", "Univers du Livre des Martyrs (de Steven Erikson)"], + [3, "Poudlard", "Inconnu", "1440", "Univers d’Harry Potter (de J. K. Rowlings)"], + [4, "Dune", "Inconnu", "2359", "Univers de Dune (de Frank Herbert)"], + [5, "StarWars", "Inconnu", "4359", "Univers de Star Wars (de George Lucas)"] +]); Index: gc_lang/fr/webext/panel/lex_editor.css ================================================================== --- gc_lang/fr/webext/panel/lex_editor.css +++ gc_lang/fr/webext/panel/lex_editor.css @@ -48,10 +48,15 @@ h3 { margin: 3px 0 2px 0; color: hsl(210, 50%, 50%); font: bold 16px "Trebuchet MS", "Fira Sans", "Liberation Sans", sans-serif; } + +#dic_selector { + color: hsl(210, 50%, 50%); + font: bold 16px "Trebuchet MS", "Fira Sans", "Liberation Sans", sans-serif; +} details { font-size: 11px; font-variant: small-caps; color: hsl(210, 50%, 50%); @@ -66,10 +71,11 @@ details.inline { padding: 3px; width: 260px; } + /* Main buttons */ #buttons { @@ -76,11 +82,11 @@ padding: 10px 0; justify-content: center; } .main_button { margin: 0 5px; - width: 100px; + min-width: 100px; padding: 10px 20px; background-color: hsl(210, 10%, 95%); border-radius: 5px; text-align: center; cursor: pointer; @@ -247,11 +253,11 @@ box-shadow: 0 0 2px hsl(150, 60%, 50%); } #lexicon_page { - + } /* Search page @@ -294,25 +300,30 @@ /* Dictionary */ -#save_button, #export_button, #import_button { +#save_button { display: none; - float: right; - padding: 2px 10px; + margin-left: 5px; + padding: 1px 5px; background-color: hsl(150, 50%, 50%); color: hsl(150, 0%, 100%); border-radius: 3px; cursor: pointer; } #export_button, #import_button { display: block; margin-left: 5px; + float: right; + padding: 2px 10px; background-color: hsl(210, 50%, 50%); color: hsl(210, 0%, 100%); + border-radius: 3px; + cursor: pointer; } + #wait_progress { width: 100%; height: 4px; } Index: gc_lang/fr/webext/panel/lex_editor.html ================================================================== --- gc_lang/fr/webext/panel/lex_editor.html +++ gc_lang/fr/webext/panel/lex_editor.html @@ -3,35 +3,44 @@ Grammalecte · Éditeur lexical - +

Éditeur lexical

-

Dictionnaire personnel

-
Enregistré le :
+

Dictionnaire

+
+ +
+
[]
0 entrées
- -
+
-
Exporter
+
Exporter
+
+
-
Lexique
+
+ Lexique · 0 entrées Enregistrer +
Ajout
Recherche
Informations
@@ -154,11 +163,11 @@
Je suis venu.
Je suis parti.
J’ai venu.
J’ai parti.
- +
@@ -229,15 +238,15 @@

- +

Mots générés

- +
Ajouter au lexique
@@ -245,19 +254,12 @@

Votre lexique

-
-
- Enregistrer -
-

Nombre d’entrées : 0.

-
- - +
@@ -281,11 +283,11 @@

Résultats

- +
@@ -311,11 +313,11 @@

Il est déconseillé d’utiliser la catégorie ‹Autre› pour générer autre chose que des noms, des adjectifs, des noms propres, des verbes et des adverbes. Il n’y a aucune garantie que les étiquettes pour les autres catégories, notamment les mots grammaticaux, ne changeront pas.

- +
@@ -331,7 +333,7 @@ - + Index: gc_lang/fr/webext/panel/lex_editor.js ================================================================== --- gc_lang/fr/webext/panel/lex_editor.js +++ gc_lang/fr/webext/panel/lex_editor.js @@ -31,13 +31,13 @@ catch (e) { showError(e); } } -function showElement (sElemId) { +function showElement (sElemId, sDisplay="block") { if (document.getElementById(sElemId)) { - document.getElementById(sElemId).style.display = "block"; + document.getElementById(sElemId).style.display = sDisplay; } else { console.log("HTML node named <" + sElemId + "> not found.") } } @@ -125,12 +125,15 @@ clear () { while (this.xTable.firstChild) { this.xTable.removeChild(this.xTable.firstChild); } + this.lEntry = []; + this.nEntry = 0; this.iEntryIndex = 0; this._createHeader(); + this.showEntryNumber(); } fill (lFlex) { this.clear(); if (lFlex.length > 0) { @@ -200,11 +203,11 @@ document.getElementById(this.sNodeId + "_row_" + iEntry).style.display = "none"; } this.nEntry -= 1; this.showEntryNumber(); if (this.sNodeId == "lexicon_table") { - showElement("save_button"); + showElement("save_button", "inline-block"); } } getEntries () { return this.lEntry.filter((e) => e !== null); @@ -480,49 +483,87 @@ oGenWordsTable.clear(); document.getElementById("lemma").value = ""; document.getElementById("lemma").focus(); this.hideAllSections(); hideElement("editor"); - showElement("save_button"); + showElement("save_button", "inline-block"); this.clear(); this.cMainTag = ""; } catch (e) { showError(e); } } } +const oDictHandler = { + oDictionaries: null, + + loadDictionaries: function () { + if (bChrome) { + browser.storage.local.get("dictionaries", this._loadDictionaries.bind(this)); + return; + } + let xPromise = browser.storage.local.get("dictionaries"); + xPromise.then(this._loadDictionaries.bind(this), showError); + }, + + _loadDictionaries: function (oResult) { + if (!oResult.hasOwnProperty("dictionaries")) { + return; + } + this.oDictionaries = oResult.dictionaries; + oBinaryDict.load("__personal__"); + }, + + getDictionary: function (sName) { + if (this.oDictionaries && this.oDictionaries.hasOwnProperty(sName)) { + //console.log(this.oDictionaries[sName]); + return this.oDictionaries[sName]; + } + return null; + }, + + saveDictionary: function (sName, oJSON) { + this.oDictionaries[sName] = oJSON; + if (sName == "__personal__") { + browser.runtime.sendMessage({ sCommand: "setDictionary", dParam: {sDictionary: "personal", oDict: oJSON}, dInfo: {} }); + } + else if (sName == "__community__") { + browser.runtime.sendMessage({ sCommand: "setDictionary", dParam: {sDictionary: "community", oDict: oJSON}, dInfo: {} }); + } + else { + // TODO: merge sub-dictionaries + } + this.storeDictionaries(); + }, + + storeDictionaries: function () { + browser.storage.local.set({ "dictionaries": this.oDictionaries }); + } +} const oBinaryDict = { oIBDAWG: null, - - load: function () { - if (bChrome) { - browser.storage.local.get("oPersonalDictionary", this._load.bind(this)); - return; - } - let xPromise = browser.storage.local.get("oPersonalDictionary"); - xPromise.then(this._load.bind(this), showError); - }, - - _load: function (oResult) { - if (!oResult.hasOwnProperty("oPersonalDictionary")) { - hideElement("export_button"); - return; - } - let oJSON = oResult.oPersonalDictionary; + sName: "", + sDescription: "", + + load: function (sName) { + console.log("lexicon editor, load: " + sName); + this.sName = sName; + let oJSON = oDictHandler.getDictionary(sName); if (oJSON) { - this.__load(oJSON); + this.parseDict(oJSON); } else { oLexiconTable.clear(); this.setDictData(0, "[néant]"); + hideElement("save_button"); } }, - __load: function (oJSON) { + parseDict: function (oJSON) { try { this.oIBDAWG = new IBDAWG(oJSON); } catch (e) { console.error(e); @@ -533,15 +574,11 @@ for (let aRes of this.oIBDAWG.select()) { lEntry.push(aRes); } oLexiconTable.fill(lEntry); this.setDictData(this.oIBDAWG.nEntry, this.oIBDAWG.sDate); - }, - - save: function (oJSON) { - browser.storage.local.set({ "oPersonalDictionary": oJSON }); - browser.runtime.sendMessage({ sCommand: "setDictionary", dParam: {sDictionary: "personal", oDict: oJSON}, dInfo: {} }); + hideElement("save_button"); }, import: function () { let xInput = document.getElementById("import_input"); let xFile = xInput.files[0]; @@ -548,21 +585,21 @@ let xURL = URL.createObjectURL(xFile); let sJSON = helpers.loadFile(xURL); if (sJSON) { try { let oJSON = JSON.parse(sJSON); - this.__load(oJSON); - this.save(oJSON); + this.parseDict(oJSON); + oDictHandler.saveDictionary(this.sName, oJSON); } catch (e) { console.error(e); this.setDictData(0, "#Erreur. Voir la console."); return; } } else { this.setDictData(0, "[néant]"); - this.save(null); + oDictHandler.saveDictionary(this.sName, null); } }, setDictData: function (nEntries, sDate) { document.getElementById("dic_num_entries").textContent = nEntries; @@ -573,35 +610,36 @@ showElement("export_button"); } }, listen: function () { + document.getElementById("dic_selector").addEventListener("change", () => {this.load(document.getElementById("dic_selector").value)}, false); document.getElementById("save_button").addEventListener("click", () => { this.build(); }, false); document.getElementById("export_button").addEventListener("click", () => { this.export(); }, false); document.getElementById("import_input").addEventListener("change", () => { this.import(); }, false); }, build: function () { let xProgressNode = document.getElementById("wait_progress"); let lEntry = oLexiconTable.getEntries(); if (lEntry.length > 0) { - let oDAWG = new DAWG(lEntry, "S", "fr", "Français", "fr.personal", xProgressNode); + let oDAWG = new DAWG(lEntry, "S", "fr", "Français", this.sName, this.sDescription, xProgressNode); let oJSON = oDAWG.createBinaryJSON(1); - this.save(oJSON); + oDictHandler.saveDictionary(this.sName, oJSON); this.oIBDAWG = new IBDAWG(oJSON); this.setDictData(this.oIBDAWG.nEntry, this.oIBDAWG.sDate); } else { + oDictHandler.saveDictionary(this.sName, null); this.setDictData(0, "[néant]"); - this.save(null); } hideElement("save_button"); }, export: function () { let xBlob = new Blob([ JSON.stringify(this.oIBDAWG.getJSON()) ], {type: 'application/json'}); let sURL = URL.createObjectURL(xBlob); - browser.downloads.download({ filename: "fr.personal.json", url: sURL, saveAs: true }); + browser.downloads.download({ filename: "fr."+this.sName+".json", url: sURL, saveAs: true }); } } const oSearch = { @@ -664,10 +702,10 @@ const oTagsTable = new Table("tags_table", ["Étiquette", "Signification"], "wait_progress", "", false); oTagsInfo.load(); oSearch.load(); -oBinaryDict.load(); +oDictHandler.loadDictionaries(); oBinaryDict.listen(); oGenerator.listen(); oTabulations.listen(); oSearch.listen(); Index: gc_lang/fr/webext/panel/main.css ================================================================== --- gc_lang/fr/webext/panel/main.css +++ gc_lang/fr/webext/panel/main.css @@ -84,11 +84,11 @@ } body { width: 450px; height: 500px; } -/* +/* Maximal height of a panel in WebExtention seems to be 500px. When going over this limit, a scrollbar appears which destructs the horizontal balance of elements. --> vertical scrolling is done with overflow in #page. #page must have the same height than body. @@ -245,10 +245,29 @@ font-size: 16px; text-align: center; cursor: pointer; } + +.option_section { + padding: 10px; + margin-top: 10px; + border-radius: 5px; + background-color: hsl(210, 20%, 96%); +} +.option_section label { + font-size: 16px; + line-height: 20px; + color: hsl(210, 20%, 50%); + font-weight: bold; +} +.option_description { + padding: 0 0 0 20px; + color: hsl(0, 0%, 0%); + font-size: 12px; +} + /* Spell checking options */ #sc_options_page { @@ -265,30 +284,24 @@ #sc_options_page h2 { margin-top: 20px; font: normal 22px 'Yanone Kaffeesatz', "Oswald", "Liberation Sans Narrow", sans-serif; color: hsl(210, 50%, 50%); } - -/* - Options -*/ -.option_section { - padding: 10px; - margin-top: 10px; - border-radius: 5px; - background-color: hsl(210, 20%, 96%); -} -.option_section label { - font-size: 16px; - line-height: 20px; - color: hsl(210, 20%, 50%); - font-weight: bold; -} -.option_description { - padding: 0 0 0 20px; - color: hsl(0, 0%, 0%); - font-size: 12px; +.button_row { + display: flex; + flex-direction: row-reverse; + padding: 5px 0 0 0; +} +.dic_button { + margin-left: 10px; + padding: 2px 10px; + background-color: hsl(210, 50%, 50%); + color: hsl(210, 10%, 96%); + cursor: pointer; + font-size: 14px; + font-variant-caps: small-caps; + border-radius: 3px; } /* Test page @@ -372,11 +385,11 @@ .double-bounce2 { animation-delay: -1.0s; } @keyframes sk-bounce { - 0%, 100% { + 0%, 100% { transform: scale(0.0); - } 50% { + } 50% { transform: scale(1.0); } } Index: gc_lang/fr/webext/panel/main.html ================================================================== --- gc_lang/fr/webext/panel/main.html +++ gc_lang/fr/webext/panel/main.html @@ -92,10 +92,12 @@

Conjugueur (dans un onglet)

CTRL+MAJ+7

Conjugueur (dans une fenêtre)

CTRL+MAJ+8

Éditeur lexical

+

CTRL+MAJ+9

+

Dictionnaires communautaires

OPTIONS GRAMMATICALES

@@ -106,26 +108,28 @@

OPTIONS ORTHOGRAPHIQUES

DICTIONNAIRES DE GRAMMALECTE

-

Ces dictionnaires ne sont utilisés que lors de l’analyse grammaticale.

-

-

Environ 83 000 entrées, 500 000 flexions.
Ni éditable, ni désactivable.

-
-
-

-

Fonctionnalité à venir.

-
-
-

-

Fonctionnalité à venir.

+

+

Environ 83 000 entrées, 500 000 flexions.
Ni éditable, ni désactivable.
Ce dictionnaire est créé à partir du dictionnaire orthographique pour Firefox et LibreOffice, conçu sur le site de Grammalecte.

+
+
+

+

Ce dictionnaire est créé et édité via l’éditeur lexical et est sauvegardé sur un serveur en ligne accessible à tous les membres.

+
+
Éditer
+
Dictionnaires en ligne
+

-

Ce dictionnaire est créé et édité via l’éditeur lexical.

+

Ce dictionnaire est créé et édité via l’éditeur lexical et n’est pas partagé.

+
+
Éditer
+