Index: gc_lang/fr/config.ini ================================================================== --- gc_lang/fr/config.ini +++ gc_lang/fr/config.ini @@ -29,13 +29,14 @@ # Firefox fx_identifier = French-GC@grammalecte.net fx_name = Grammalecte [fr] -fx_standard_path = C:\Program Files\Mozilla Firefox\firefox.exe -fx_beta_path = C:\Program Files\Mozilla Firefox Beta\firefox.exe -fx_nightly_path = C:\Program Files (x86)\Nightly\firefox.exe +win_fx_dev_path = C:\Program Files\Firefox Developer Edition\firefox.exe +win_fx_nightly_path = C:\Program Files (x86)\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 tb_name = Grammalecte [fr] Index: gc_lang/fr/modules-js/conj.js ================================================================== --- gc_lang/fr/modules-js/conj.js +++ gc_lang/fr/modules-js/conj.js @@ -483,11 +483,11 @@ conj.init(helpers.loadFile(browser.extension.getURL("grammalecte/fr/conj_data.json"))); } else if (typeof(require) !== 'undefined') { // Add-on SDK and Thunderbird let helpers = require("resource://grammalecte/helpers.js"); conj.init(helpers.loadFile("resource://grammalecte/fr/conj_data.json")); -} else if (typeof(self) !== 'undefined' && typeof(self.port) !== 'undefined' && typeof(self.port.on) === "undefined") { +} else if (typeof(self) !== 'undefined' && typeof(self.port) !== 'undefined' && typeof(self.port.on) !== "undefined") { // used within Firefox content script (conjugation panel). // can’t load JSON from here, so we do it in ui.js and send it here. self.port.on("provideConjData", function (sJSONData) { conj.init(sJSONData); }); Index: gc_lang/fr/webext/background.js ================================================================== --- gc_lang/fr/webext/background.js +++ gc_lang/fr/webext/background.js @@ -1,58 +1,121 @@ // Background "use strict"; +function showError (e) { + console.error(e.fileName + "\n" + e.name + "\nline: " + e.lineNumber + "\n" + e.message); +} + +/* + Worker (separate thread to avoid freezing Firefox) +*/ let xGCEWorker = new Worker("gce_worker.js"); xGCEWorker.onmessage = function (e) { - switch (e.data[0]) { - case "grammar_errors": - console.log("GRAMMAR ERRORS"); - console.log(e.data[1].aGrammErr); - break; - case "spelling_and_grammar_errors": - console.log("SPELLING AND GRAMMAR ERRORS"); - console.log(e.data[1].aSpellErr); - console.log(e.data[1].aGrammErr); - break; - case "tests_results": - console.log("TESTS RESULTS"); - console.log(e.data[1]); - break; - case "options": - console.log("OPTIONS"); - console.log(e.data[1]); - break; - case "tokens": - console.log("TOKENS"); - console.log(e.data[1]); - break; - case "error": - console.log("ERROR"); - console.log(e.data[1]); - break; - default: - console.log("Unknown command: " + e.data[0]); + // https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent + try { + switch (e.data[0]) { + case "grammar_errors": + console.log("GRAMMAR ERRORS"); + console.log(e.data[1].aGrammErr); + browser.runtime.sendMessage({sCommand: "grammar_errors", aGrammErr: e.data[1].aGrammErr}); + break; + case "spelling_and_grammar_errors": + console.log("SPELLING AND GRAMMAR ERRORS"); + console.log(e.data[1].aSpellErr); + console.log(e.data[1].aGrammErr); + break; + case "text_to_test_result": + browser.runtime.sendMessage({sCommand: "text_to_test_result", sResult: e.data[1]}); + break; + case "fulltests_result": + console.log("TESTS RESULTS"); + browser.runtime.sendMessage({sCommand: "fulltests_result", sResult: e.data[1]}); + break; + case "options": + console.log("OPTIONS"); + console.log(e.data[1]); + break; + case "tokens": + console.log("TOKENS"); + console.log(e.data[1]); + browser.browserAction.setPopup({popup: "panel/main.html"}); + browser.runtime.sendMessage({sCommand: "show_tokens", oResult: e.data[1]}); + break; + case "error": + console.log("ERROR"); + console.log(e.data[1]); + break; + default: + console.log("Unknown command: " + e.data[0]); + } + } + catch (e) { + showError(e); } }; xGCEWorker.postMessage(["init", {sExtensionPath: browser.extension.getURL("."), sOptions: "", sContext: "Firefox"}]); -xGCEWorker.postMessage(["parse", {sText: "J’en aie mare...", sCountry: "FR", bDebug: false, bContext: false}]); - -xGCEWorker.postMessage(["parseAndSpellcheck", {sText: "C’est terribles, ils va tout perdrre.", sCountry: "FR", bDebug: false, bContext: false}]); - -xGCEWorker.postMessage(["getListOfTokens", {sText: "J’en ai assez de ces âneries ! Merci bien. Ça suffira."}]); - -xGCEWorker.postMessage(["fullTests"]); - /* Messages from the extension (not the Worker) */ function handleMessage (oRequest, xSender, sendResponse) { - console.log(`[background] received: ${oRequest.content}`); - sendResponse({response: "response from background script"}); + //console.log(xSender); + switch(oRequest.sCommand) { + case "parse": + xGCEWorker.postMessage(["parse", {sText: oRequest.sText, sCountry: "FR", bDebug: false, bContext: false}]); + break; + case "parse_and_spellcheck": + xGCEWorker.postMessage(["parseAndSpellcheck", {sText: oRequest.sText, sCountry: "FR", bDebug: false, bContext: false}]); + break; + case "get_list_of_tokens": + xGCEWorker.postMessage(["getListOfTokens", {sText: oRequest.sText}]); + break; + case "text_to_test": + xGCEWorker.postMessage(["textToTest", {sText: oRequest.sText, sCountry: "FR", bDebug: false, bContext: false}]); + break; + case "fulltests": + xGCEWorker.postMessage(["fullTests"]); + break; + } + //sendResponse({response: "response from background script"}); } browser.runtime.onMessage.addListener(handleMessage); + + +/* + Context Menu +*/ +browser.contextMenus.create({ + id: "grammar_checking", + title: "Correction grammaticale", + contexts: ["selection", "editable", "page"] +}); + +browser.contextMenus.create({ + id: "lexicographer", + title: "Lexicographe", + contexts: ["selection", "editable", "page"] +}); + +browser.contextMenus.onClicked.addListener(function (xInfo, xTab) { + // xInfo = https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/contextMenus/OnClickData + // xTab = https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/Tab + console.log(xInfo); + console.log(xTab); + console.log("Item " + xInfo.menuItemId + " clicked in tab " + xTab.id); + console.log("editable: " + xInfo.editable + " · selected: " + xInfo.selectionText); + // confusing: no way to get the node where we click?! + switch (xInfo.menuItemId) { + case "grammar_checking": + break; + case "lexicographer": + if (xInfo.selectionText) { + xGCEWorker.postMessage(["getListOfTokens", {sText: xInfo.selectionText}]); + } + break; + } +}); Index: gc_lang/fr/webext/gce_worker.js ================================================================== --- gc_lang/fr/webext/gce_worker.js +++ gc_lang/fr/webext/gce_worker.js @@ -83,10 +83,13 @@ setOption(oParam.sOptName, oParam.bValue); break; case "resetOptions": resetOptions(); break; + case "textToTest": + textToTest(oParam.sText, oParam.sCountry, oParam.bDebug, oParam.bContext); + break; case "fullTests": fullTests(); break; case "getListOfTokens": getListOfTokens(oParam.sText); @@ -170,10 +173,23 @@ let aRes = gc_engine.parse("Je suit..."); for (let oErr of aRes) { console.log(text.getReadableError(oErr)); } } + +function textToTest (sText, sCountry, bDebug, bContext) { + if (!gc_engine || !oDict) { + postMessage(["error", "# Error: grammar checker or dictionary not loaded."]); + return; + } + let aGrammErr = gc_engine.parse(sText, sCountry, bDebug, bContext); + let sMsg = ""; + for (let oErr of aGrammErr) { + sMsg += text.getReadableError(oErr) + "\n"; + } + postMessage(["text_to_test_result", sMsg]); +} function fullTests (sGCOptions='{"nbsp":true, "esp":true, "unit":true, "num":true}') { if (!gc_engine || !oDict) { postMessage(["error", "# Error: grammar checker or dictionary not loaded."]); return; @@ -186,11 +202,11 @@ for (let sRes of oTest.testParse()) { sMsg += sRes + "\n"; console.log(sRes); } gc_engine.setOptions(dMemoOptions); - postMessage(["tests_results", sMsg]); + postMessage(["fulltests_result", sMsg]); } // Lexicographer Index: gc_lang/fr/webext/manifest.json ================================================================== --- gc_lang/fr/webext/manifest.json +++ gc_lang/fr/webext/manifest.json @@ -39,8 +39,9 @@ "grammalecte/fr/mfsp_data.json", "grammalecte/fr/phonet_data.json", "grammalecte/fr/tests_data.json" ], "permissions": [ - "activeTab" + "activeTab", + "contextMenus" ] } Index: gc_lang/fr/webext/panel/main.css ================================================================== --- gc_lang/fr/webext/panel/main.css +++ gc_lang/fr/webext/panel/main.css @@ -67,51 +67,62 @@ /* Main classes */ html { box-sizing: border-box; width: 530px; - height: 880px; + height: 500px; font-family: "Trebuchet MS", "Liberation Sans", sans-serif; } body { width: 530px; - height: 880px; + 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. +*/ #main { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: stretch; background-color: hsl(210, 0%, 100%); min-height: 100%; } -#left { - width: 54px; +#menu { + position: fixed; + left: 5px; + width: 50px; + border-left: solid 2px hsl(210, 0%, 70%); + border-bottom: solid 2px hsl(210, 0%, 70%); + border-right: solid 2px hsl(210, 0%, 70%); + border-radius: 0 0 5px 5px; background-color: hsl(210, 10%, 96%); - border-right: solid 1px hsl(210, 0%, 70%); color: hsl(210, 10%, 96%); } #logo { - padding: 10px; -} -#left li { - padding: 10px 5px; - border-bottom: 1px solid hsl(210, 10%, 90%); - text-align: center; - cursor: pointer; - color: hsl(210, 10%, 50%); - list-style-type: none; -} -#left li:hover { - background-color: hsl(210, 10%, 92%); - -} + padding: 10px; +} +#menu li { + padding: 10px 5px; + border-bottom: 1px solid hsl(210, 10%, 90%); + text-align: center; + cursor: pointer; + color: hsl(210, 10%, 50%); + list-style-type: none; +} +#menu li:hover { + background-color: hsl(210, 10%, 92%); +} + #page { + padding-left: 60px; background-color: hsl(210, 0%, 100%); + height: 500px; + overflow: auto; } #page h1 { margin: 0 0 10px 0; color: hsl(210, 70%, 70%); font: bold 30px 'Yanone Kaffeesatz', "Liberation Sans Narrow", sans-serif; @@ -119,33 +130,33 @@ #page p { margin: 10px 0 5px 0; } #home_page { - display: block; - padding: 20px; + display: block; + padding: 20px; } #tf_page { - display: none; - padding: 20px; + display: none; + padding: 20px; } #gc_page { - display: none; - padding: 20px 20px 30px 20px; + display: none; + padding: 20px 20px 30px 20px; } #gc_options_page { - display: none; - padding: 20px; + display: none; + padding: 20px; } #sc_options_page { - display: none; - padding: 20px; + display: none; + padding: 20px; } #lxg_page { - display: none; - padding: 20px; + display: none; + padding: 20px; } /* Conjugueur page @@ -243,21 +254,20 @@ #test_page { display: none; } #test_cmd { padding: 15px; - background-color: hsl(0, 0%, 92%); - border-bottom: 1px solid hsl(0, 0%, 86%); + border-bottom: 1px solid hsl(0, 0%, 90%); } #test_cmd textarea { width: 100%; border: 2px solid hsl(0, 0%, 89%); border-radius: 3px; resize: vertical; } -#test_results { +#tests_result { padding: 15px; background-color: hsl(0, 0%, 96%); } #test_page .button { Index: gc_lang/fr/webext/panel/main.html ================================================================== --- gc_lang/fr/webext/panel/main.html +++ gc_lang/fr/webext/panel/main.html @@ -7,12 +7,12 @@
-
-