Index: gc_lang/fr/build.py ================================================================== --- gc_lang/fr/build.py +++ gc_lang/fr/build.py @@ -6,14 +6,15 @@ from distutils import dir_util, file_util import helpers -def build (sLang, dVars, spLangPack): +def build (sLang, dVars): "complementary build launched from make.py" createWebExtension(sLang, dVars) - createThunderbirdExtension(sLang, dVars, spLangPack) + createThunderbirdExtension(sLang, dVars) + createMailExtension(sLang, dVars) createNodeJSPackage(sLang) def createWebExtension (sLang, dVars): "create Web-extension" @@ -38,27 +39,40 @@ sHTML += f'

\n' sHTML += '\n' return sHTML -def createThunderbirdExtension (sLang, dVars, spLangPack): - "create extension for Thunderbird" +def createMailExtension (sLang, dVars): + "create extension for Thunderbird (as MailExtension)" + print("Building extension for Thunderbird (MailExtension)") + spfZip = "_build/" + dVars['tb_identifier'] + "-v" + dVars['version'] + '.mailext.xpi' + hZip = zipfile.ZipFile(spfZip, mode='w', compression=zipfile.ZIP_DEFLATED) + _copyGrammalecteJSPackageInZipFile(hZip, sLang) + for spf in ["LICENSE.txt", "LICENSE.fr.txt"]: + hZip.write(spf) + dVars = _createOptionsForThunderbird(dVars) + helpers.addFolderToZipAndFileFile(hZip, "gc_lang/"+sLang+"/mailext", "", dVars, True) + hZip.close() + spExtension = dVars['win_tb_debug_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_debug_extension_path'] + file_util.copy_file(spfZip, spExtension + "/" + dVars['tb_identifier']+ ".xpi") # Filename for TB is just + spExtension = dVars['win_tb_beta_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_beta_extension_path'] + file_util.copy_file(spfZip, spExtension + "/" + dVars['tb_identifier']+ ".xpi") # Filename for TB is just + + +def createThunderbirdExtension (sLang, dVars): + "create extension for Thunderbird (as XUL addon)" print("Building extension for Thunderbird") - sExtensionName = dVars['tb_identifier'] + "-v" + dVars['version'] + '.xpi' - spfZip = "_build/" + sExtensionName + spfZip = "_build/" + dVars['tb_identifier'] + "-v" + dVars['version'] + '.xpi' hZip = zipfile.ZipFile(spfZip, mode='w', compression=zipfile.ZIP_DEFLATED) - _copyGrammalecteJSPackageInZipFile(hZip, spLangPack) + _copyGrammalecteJSPackageInZipFile(hZip, sLang) for spf in ["LICENSE.txt", "LICENSE.fr.txt"]: hZip.write(spf) dVars = _createOptionsForThunderbird(dVars) helpers.addFolderToZipAndFileFile(hZip, "gc_lang/"+sLang+"/tb", "", dVars, True) hZip.close() - spDebugProfile = dVars['win_tb_debug_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_debug_extension_path'] - helpers.unzip(spfZip, spDebugProfile) - spfBetaExtension = dVars['win_tb_beta_extension_filepath'] if platform.system() == "Windows" else dVars['linux_tb_beta_extension_filepath'] - #helpers.unzip(spfZip, spBetaProfile) - file_util.copy_file(spfZip, spfBetaExtension) + #spDebugProfile = dVars['win_tb_debug_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_debug_extension_path'] + #helpers.unzip(spfZip, spDebugProfile) def _createOptionsForThunderbird (dVars): dVars['sXULTabs'] = "" dVars['sXULTabPanels'] = "" @@ -74,24 +88,24 @@ for sLang in dVars['dOptLabel'].keys(): dVars['gc_options_labels_'+sLang] = "\n".join( [ "' for sOpt in dVars['dOptLabel'][sLang] ] ) return dVars -def _copyGrammalecteJSPackageInZipFile (hZip, spLangPack, sAddPath=""): +def _copyGrammalecteJSPackageInZipFile (hZip, sLang, sAddPath=""): for sf in os.listdir("grammalecte-js"): if not os.path.isdir("grammalecte-js/"+sf): - hZip.write("grammalecte-js/"+sf, sAddPath+"grammalecte-js/"+sf) + hZip.write("grammalecte-js/"+sf, sAddPath+"grammalecte/"+sf) for sf in os.listdir("grammalecte-js/graphspell"): if not os.path.isdir("grammalecte-js/graphspell/"+sf): - hZip.write("grammalecte-js/graphspell/"+sf, sAddPath+"grammalecte-js/graphspell/"+sf) + hZip.write("grammalecte-js/graphspell/"+sf, sAddPath+"grammalecte/graphspell/"+sf) for sf in os.listdir("grammalecte-js/graphspell/_dictionaries"): if not os.path.isdir("grammalecte-js/graphspell/_dictionaries/"+sf): - hZip.write("grammalecte-js/graphspell/_dictionaries/"+sf, sAddPath+"grammalecte-js/graphspell/_dictionaries/"+sf) - for sf in os.listdir(spLangPack): - if not os.path.isdir(spLangPack+"/"+sf): - hZip.write(spLangPack+"/"+sf, sAddPath+spLangPack+"/"+sf) + hZip.write("grammalecte-js/graphspell/_dictionaries/"+sf, sAddPath+"grammalecte/graphspell/_dictionaries/"+sf) + for sf in os.listdir("grammalecte-js/"+sLang): + if not os.path.isdir("grammalecte-js/"+sLang+"/"+sf): + hZip.write("grammalecte-js/"+sLang+"/"+sf, sAddPath+"grammalecte/"+sLang+"/"+sf) def createNodeJSPackage (sLang): helpers.createCleanFolder("_build/nodejs/"+sLang) dir_util.copy_tree("gc_lang/"+sLang+"/nodejs/", "_build/nodejs/"+sLang) dir_util.copy_tree("grammalecte-js", "_build/nodejs/"+sLang+"/core/grammalecte") Index: gc_lang/fr/config.ini ================================================================== --- gc_lang/fr/config.ini +++ gc_lang/fr/config.ini @@ -8,11 +8,11 @@ # always use 3 numbers for version: x.y.z version = 1.3.2 author = Olivier R. provider = Grammalecte.net link = https://grammalecte.net -description = Correcteur grammatical pour le français. +description = Correcteur grammatical, orthographique et typographique pour le français. extras = README_fr.txt logo = logo.png # main dictionary lexicon_src = lexicons/French.lex @@ -54,18 +54,17 @@ # Thunderbird tb_identifier = French-GC-TB@grammalecte.net tb_name = Grammalecte [fr] win_tb_path = C:\Program Files (x86)\Mozilla Thunderbird\thunderbird.exe -#win_tb_beta_path = C:\Program Files (x86)\Mozilla Thunderbird (Beta)\thunderbird.exe -win_tb_beta_path = C:\Program Files (x86)\Mozilla Thunderbird (Beta)\thunderbird.exe +win_tb_beta_path = C:\Program Files\Thunderbird Daily\thunderbird.exe linux_tb_path = /usr/bin/thunderbird linux_tb_beta_path = /usr/bin/thunderbird -win_tb_debug_extension_path = D:\_temp\tb-debug.profile\extensions\French-GC-TB@grammalecte.net -linux_tb_debug_extension_path = ~/tb-debug.profile/extensions/French-GC-TB@grammalecte.net -win_tb_beta_extension_filepath = D:\_temp\tb-beta.profile\extensions\French-GC-TB@grammalecte.net.xpi -linux_tb_beta_extension_filepath = ~/tb-beta.profile/extensions/French-GC-TB@grammalecte.net.xpi +win_tb_debug_extension_path = D:\_temp\tb-debug.profile\extensions +linux_tb_debug_extension_path = ~/tb-debug.profile/extensions +win_tb_beta_extension_path = D:\_temp\tb-beta.profile\extensions +linux_tb_beta_extension_path = ~/tb-beta.profile/extensions # Set Thunderbird folder in your PATH variable # Create a local profile: # thunderbird -CreateProfile "debug _build\tb-debug.profile" # Or you can use the GUI with: # thunderbird -P ADDED gc_lang/fr/mailext/README.txt Index: gc_lang/fr/mailext/README.txt ================================================================== --- gc_lang/fr/mailext/README.txt +++ gc_lang/fr/mailext/README.txt @@ -0,0 +1,14 @@ + += GRAMMALECTE = + +French grammar checker +By Olivier R. (olivier /at/ grammalecte /dot/ net) + +Website: https://grammalecte.net/ + +License: GPL 3 -- http://www.gnu.org/copyleft/gpl.html + +Grammalecte for Firefox is a derivative tool born from the version +for LibreOffice written in Python. + +Written in JavaScript ES6/ES7. ADDED gc_lang/fr/mailext/background.js Index: gc_lang/fr/mailext/background.js ================================================================== --- gc_lang/fr/mailext/background.js +++ gc_lang/fr/mailext/background.js @@ -0,0 +1,204 @@ +// Background + +"use strict"; + +console.log("THUNDERBIRD!!! BACKGROUND"); + + +const oWorkerHandler = { + xGCEWorker: null, + + nLastTimeWorkerResponse: 0, // milliseconds since 1970-01-01 + + oTask: {}, + + start: function () { + this.xGCEWorker = new Worker("gce_worker.js"); + this.xGCEWorker.onmessage = function (e) { + // Messages received from the Worker + // https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent + try { + this.nLastTimeWorkerResponse = Date.now(); + let {sActionDone, result, dInfo, bEnd, bError} = e.data; + if (bError) { + console.log(result); + console.log(dInfo); + return; + } + switch (sActionDone) { + case "init": + storeGCOptions(result); + break; + case "parse": + case "parseAndSpellcheck": + case "parseAndSpellcheck1": + case "parseFull": + case "getListOfTokens": + case "getSpellSuggestions": + case "getVerb": + // send result to content script + if (typeof(dInfo.iReturnPort) === "number") { + let xPort = dConnx.get(dInfo.iReturnPort); + xPort.postMessage(e.data); + } else { + console.log("[background] don’t know where to send results"); + console.log(e.data); + } + break; + case "textToTest": + case "fullTests": + // send result to panel + browser.runtime.sendMessage(e.data); + break; + case "getOptions": + case "getDefaultOptions": + case "resetOptions": + // send result to panel + storeGCOptions(result); + browser.runtime.sendMessage(e.data); + break; + case "setOptions": + case "setOption": + storeGCOptions(result); + break; + case "setDictionary": + case "setDictionaryOnOff": + //console.log("[background] " + sActionDone + ": " + result); + break; + default: + console.log("[background] Unknown command: " + sActionDone); + console.log(e.data); + } + } + catch (error) { + showError(error); + console.log(e.data); + } + }; + }, + + getTimeSinceLastResponse: function () { + // result in seconds + return Math.floor((Date.now() - this.nLastTimeWorkerResponse) / 1000); + }, + + restart: function (nDelay=5) { + if (this.getTimeSinceLastResponse() <= nDelay) { + console.log("Worker not restarted. Worked ", nDelay, " seconds ago."); + return false; + } + if (this.xGCEWorker) { + this.xGCEWorker.terminate(); + } + this.start(); + oInitHandler.initGrammarChecker(); + sendCommandToAllTabs("workerRestarted"); + console.log("Worker restarted."); + return true; + }, + + addTask: function () { + // + }, + + closeTask: function () { + // + } +} + + +const oInitHandler = { + + initUIOptions: function () { + browser.storage.local.get("ui_options").then(this._initUIOptions, showError); + browser.storage.local.get("autorefresh_option").then(this._initUIOptions, showError); + }, + + initGrammarChecker: function () { + browser.storage.local.get("gc_options").then(this._initGrammarChecker, showError); + browser.storage.local.get("personal_dictionary").then(this._setSpellingDictionaries, showError); + browser.storage.local.get("community_dictionary").then(this._setSpellingDictionaries, showError); + browser.storage.local.get("oPersonalDictionary").then(this._setSpellingDictionaries, showError); // deprecated + browser.storage.local.get("sc_options").then(this._initSCOptions, showError); + }, + + _initUIOptions: function (oSavedOptions) { + if (!oSavedOptions.hasOwnProperty("ui_options")) { + browser.storage.local.set({"ui_options": { + textarea: true, + editablenode: true + }}); + } + if (!oSavedOptions.hasOwnProperty("autorefresh_option")) { + browser.storage.local.set({"autorefresh_option": true}); + } + }, + + _initGrammarChecker: function (oSavedOptions) { + try { + let dOptions = (oSavedOptions.hasOwnProperty("gc_options")) ? oSavedOptions.gc_options : null; + if (dOptions !== null && Object.getOwnPropertyNames(dOptions).length == 0) { + console.log("# Error: the saved options was an empty object."); + dOptions = null; + } + oWorkerHandler.xGCEWorker.postMessage({ + sCommand: "init", + dParam: {sExtensionPath: browser.extension.getURL(""), dOptions: dOptions, sContext: "Firefox"}, + dInfo: {} + }); + } + catch (e) { + console.log("initGrammarChecker failed"); + showError(e); + } + }, + + _setSpellingDictionaries: function (oData) { + if (oData.hasOwnProperty("community_dictionary")) { + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionary", dParam: { sDictionary: "community", oDict: oData["community_dictionary"] }, dInfo: {} }); + } + if (oData.hasOwnProperty("personal_dictionary")) { + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionary", dParam: { sDictionary: "personal", oDict: oData["personal_dictionary"] }, dInfo: {} }); + } + }, + + _initSCOptions: function (oData) { + if (!oData.hasOwnProperty("sc_options")) { + browser.storage.local.set({"sc_options": { + community: true, + personal: true + }}); + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "community", bActivate: true }, dInfo: {} }); + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "personal", bActivate: true }, dInfo: {} }); + } else { + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "community", bActivate: oData.sc_options["community"] }, dInfo: {} }); + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "personal", bActivate: oData.sc_options["personal"] }, dInfo: {} }); + } + } +} + +// start the Worker for the GC +oWorkerHandler.start(); + +// init the options stuff and start the GC +oInitHandler.initUIOptions(); +oInitHandler.initGrammarChecker(); + + + +/* + Actions +*/ + +function storeGCOptions (dOptions) { + if (dOptions instanceof Map) { + dOptions = helpers.mapToObject(dOptions); + } + browser.storage.local.set({"gc_options": dOptions}); +} + + +function showError (e) { + console.error(e); + //console.error(e.fileName + "\n" + e.name + "\nline: " + e.lineNumber + "\n" + e.message); +} ADDED gc_lang/fr/mailext/gce_worker.js Index: gc_lang/fr/mailext/gce_worker.js ================================================================== --- gc_lang/fr/mailext/gce_worker.js +++ gc_lang/fr/mailext/gce_worker.js @@ -0,0 +1,428 @@ +/* + WORKER: + https://developer.mozilla.org/en-US/docs/Web/API/Worker + https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope + + + JavaScript sucks. + No module available in WebExtension at the moment! :( + No require, no import/export. + + In Worker, we have importScripts() which imports everything in this scope. + + In order to use the same base of code with XUL-addon for Thunderbird and SDK-addon for Firefox, + all modules have been “objectified”. And while they are still imported via “require” + in the previous extensions, they are loaded as background scripts in WebExtension sharing + the same memory space… + + When JavaScript become a modern language, “deobjectify” the modules… + + ATM, import/export are not available by default: + — Chrome 60 – behind the Experimental Web Platform flag in chrome:flags. + — Firefox 54 – behind the dom.moduleScripts.enabled setting in about:config. + — Edge 15 – behind the Experimental JavaScript Features setting in about:flags. + + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export +*/ + +"use strict"; + + +//console.log("[Worker] GC Engine Worker [start]"); +//console.log(self); + +importScripts("grammalecte/graphspell/helpers.js"); +importScripts("grammalecte/graphspell/str_transform.js"); +importScripts("grammalecte/graphspell/char_player.js"); +importScripts("grammalecte/graphspell/suggest.js"); +importScripts("grammalecte/graphspell/ibdawg.js"); +importScripts("grammalecte/graphspell/spellchecker.js"); +importScripts("grammalecte/text.js"); +importScripts("grammalecte/graphspell/tokenizer.js"); +importScripts("grammalecte/fr/conj.js"); +importScripts("grammalecte/fr/mfsp.js"); +importScripts("grammalecte/fr/phonet.js"); +importScripts("grammalecte/fr/cregex.js"); +importScripts("grammalecte/fr/gc_options.js"); +importScripts("grammalecte/fr/gc_rules.js"); +importScripts("grammalecte/fr/gc_rules_graph.js"); +importScripts("grammalecte/fr/gc_engine.js"); +importScripts("grammalecte/fr/lexicographe.js"); +importScripts("grammalecte/tests.js"); +/* + Warning. + Initialization can’t be completed at startup of the worker, + for we need the path of the extension to load data stored in JSON files. + This path is retrieved in background.js and passed with the event “init”. +*/ + + +function createResponse (sActionDone, result, dInfo, bEnd, bError=false) { + return { + "sActionDone": sActionDone, + "result": result, // can be of any type + "dInfo": dInfo, + "bEnd": bEnd, + "bError": bError + }; +} + +function createErrorResult (e, sDescr="no description") { + return { + "sType": "error", + "sDescription": sDescr, + "sMessage": e.fileName + "\n" + e.name + "\nline: " + e.lineNumber + "\n" + e.message + }; +} + +function showData (e) { + for (let sParam in e) { + console.log(sParam); + console.log(e[sParam]); + } +} + + +/* + Message Event Object + https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent +*/ +onmessage = function (e) { + let {sCommand, dParam, dInfo} = e.data; + switch (sCommand) { + case "init": + init(dParam.sExtensionPath, dParam.dOptions, dParam.sContext, dInfo); + break; + case "parse": + parse(dParam.sText, dParam.sCountry, dParam.bDebug, dParam.bContext, dInfo); + break; + case "parseAndSpellcheck": + parseAndSpellcheck(dParam.sText, dParam.sCountry, dParam.bDebug, dParam.bContext, dInfo); + break; + case "parseAndSpellcheck1": + parseAndSpellcheck1(dParam.sText, dParam.sCountry, dParam.bDebug, dParam.bContext, dInfo); + break; + case "parseFull": + parseFull(dParam.sText, dParam.sCountry, dParam.bDebug, dParam.bContext, dInfo); + break; + case "getListOfTokens": + getListOfTokens(dParam.sText, dInfo); + break; + case "getOptions": + getOptions(dInfo); + break; + case "getDefaultOptions": + getDefaultOptions(dInfo); + break; + case "setOptions": + setOptions(dParam.sOptions, dInfo); + break; + case "setOption": + setOption(dParam.sOptName, dParam.bValue, dInfo); + break; + case "resetOptions": + resetOptions(dInfo); + break; + case "textToTest": + textToTest(dParam.sText, dParam.sCountry, dParam.bDebug, dParam.bContext, dInfo); + break; + case "fullTests": + fullTests(dInfo); + break; + case "setDictionary": + setDictionary(dParam.sDictionary, dParam.oDict, dInfo); + break; + case "setDictionaryOnOff": + setDictionaryOnOff(dParam.sDictionary, dParam.bActivate, dInfo); + break; + case "getSpellSuggestions": + getSpellSuggestions(dParam.sWord, dInfo); + break; + case "getVerb": + getVerb(dParam.sVerb, dParam.bPro, dParam.bNeg, dParam.bTpsCo, dParam.bInt, dParam.bFem, dInfo); + break; + default: + console.log("[Worker] Unknown command: " + sCommand); + showData(e.data); + } +} + + + +let bInitDone = false; + +let oSpellChecker = null; +let oTokenizer = null; +let oLxg = null; +let oTest = null; +let oLocution = null; + + +/* + Technical note: + This worker don’t work as a PromiseWorker (which returns a promise), so when we send request + to this worker, we can’t wait the return of the answer just after the request made. + The answer is received by the background in another function (onmessage). + That’s why the full text to analyze is send in one block, but analyse is returned paragraph + by paragraph. +*/ + +function init (sExtensionPath, dOptions=null, sContext="JavaScript", dInfo={}) { + try { + if (!bInitDone) { + console.log("[Worker] Loading… Extension path: " + sExtensionPath); + conj.init(helpers.loadFile(sExtensionPath + "/grammalecte/fr/conj_data.json")); + phonet.init(helpers.loadFile(sExtensionPath + "/grammalecte/fr/phonet_data.json")); + mfsp.init(helpers.loadFile(sExtensionPath + "/grammalecte/fr/mfsp_data.json")); + //console.log("[Worker] Modules have been initialized…"); + gc_engine.load(sContext, "sCSS", sExtensionPath+"grammalecte/graphspell/_dictionaries"); + oSpellChecker = gc_engine.getSpellChecker(); + oTest = new TestGrammarChecking(gc_engine, sExtensionPath+"/grammalecte/fr/tests_data.json"); + oTokenizer = new Tokenizer("fr"); + oLocution = helpers.loadFile(sExtensionPath + "/grammalecte/fr/locutions_data.json"); + oLxg = new Lexicographe(oSpellChecker, oTokenizer, oLocution); + if (dOptions !== null) { + if (!(dOptions instanceof Map)) { + dOptions = helpers.objectToMap(dOptions); + } + gc_engine.setOptions(dOptions); + } + //tests(); + bInitDone = true; + } else { + console.log("[Worker] Already initialized…") + } + // we always retrieve options from the gc_engine, for setOptions filters obsolete options + dOptions = helpers.mapToObject(gc_engine.getOptions()); + postMessage(createResponse("init", dOptions, dInfo, true)); + } + catch (e) { + console.error(e); + postMessage(createResponse("init", createErrorResult(e, "init failed"), dInfo, true, true)); + } +} + + +function parse (sText, sCountry, bDebug, bContext, dInfo={}) { + sText = sText.replace(/­/g, "").normalize("NFC"); + for (let sParagraph of text.getParagraph(sText)) { + let aGrammErr = gc_engine.parse(sParagraph, sCountry, bDebug, bContext); + postMessage(createResponse("parse", aGrammErr, dInfo, false)); + } + postMessage(createResponse("parse", null, dInfo, true)); +} + +function parseAndSpellcheck (sText, sCountry, bDebug, bContext, dInfo={}) { + let i = 0; + sText = sText.replace(/­/g, "").normalize("NFC"); + for (let sParagraph of text.getParagraph(sText)) { + let aGrammErr = gc_engine.parse(sParagraph, sCountry, bDebug, null, bContext); + let aSpellErr = oSpellChecker.parseParagraph(sParagraph); + postMessage(createResponse("parseAndSpellcheck", {sParagraph: sParagraph, iParaNum: i, aGrammErr: aGrammErr, aSpellErr: aSpellErr}, dInfo, false)); + i += 1; + } + postMessage(createResponse("parseAndSpellcheck", null, dInfo, true)); +} + +function parseAndSpellcheck1 (sParagraph, sCountry, bDebug, bContext, dInfo={}) { + sParagraph = sParagraph.replace(/­/g, "").normalize("NFC"); + let aGrammErr = gc_engine.parse(sParagraph, sCountry, bDebug, null, bContext); + let aSpellErr = oSpellChecker.parseParagraph(sParagraph); + postMessage(createResponse("parseAndSpellcheck1", {sParagraph: sParagraph, aGrammErr: aGrammErr, aSpellErr: aSpellErr}, dInfo, true)); +} + +function parseFull (sText, sCountry, bDebug, bContext, dInfo={}) { + let i = 0; + sText = sText.replace(/­/g, "").normalize("NFC"); + for (let sParagraph of text.getParagraph(sText)) { + let lSentence = gc_engine.parse(sParagraph, sCountry, bDebug, null, bContext, true); + console.log("*", lSentence); + postMessage(createResponse("parseFull", {sParagraph: sParagraph, iParaNum: i, lSentence: lSentence}, dInfo, false)); + i += 1; + } + postMessage(createResponse("parseFull", null, dInfo, true)); +} + +function getListOfTokens (sText, dInfo={}) { + // lexicographer + try { + sText = sText.replace(/­/g, "").normalize("NFC"); + for (let sParagraph of text.getParagraph(sText)) { + if (sParagraph.trim() !== "") { + postMessage(createResponse("getListOfTokens", oLxg.getListOfTokensReduc(sParagraph, true), dInfo, false)); + } + } + postMessage(createResponse("getListOfTokens", null, dInfo, true)); + } + catch (e) { + console.error(e); + postMessage(createResponse("getListOfTokens", createErrorResult(e, "no tokens"), dInfo, true, true)); + } +} + +function getOptions (dInfo={}) { + let dOptions = helpers.mapToObject(gc_engine.getOptions()); + postMessage(createResponse("getOptions", dOptions, dInfo, true)); +} + +function getDefaultOptions (dInfo={}) { + let dOptions = helpers.mapToObject(gc_engine.getDefaultOptions()); + postMessage(createResponse("getDefaultOptions", dOptions, dInfo, true)); +} + +function setOptions (dOptions, dInfo={}) { + if (!(dOptions instanceof Map)) { + dOptions = helpers.objectToMap(dOptions); + } + gc_engine.setOptions(dOptions); + dOptions = helpers.mapToObject(gc_engine.getOptions()); + postMessage(createResponse("setOptions", dOptions, dInfo, true)); +} + +function setOption (sOptName, bValue, dInfo={}) { + console.log(sOptName+": "+bValue); + if (sOptName) { + gc_engine.setOption(sOptName, bValue); + let dOptions = helpers.mapToObject(gc_engine.getOptions()); + postMessage(createResponse("setOption", dOptions, dInfo, true)); + } +} + +function resetOptions (dInfo={}) { + gc_engine.resetOptions(); + let dOptions = helpers.mapToObject(gc_engine.getOptions()); + postMessage(createResponse("resetOptions", dOptions, dInfo, true)); +} + +function tests () { + console.log(conj.getConj("devenir", ":E", ":2s")); + console.log(mfsp.getMasForm("emmerdeuse", true)); + console.log(mfsp.getMasForm("pointilleuse", false)); + console.log(phonet.getSimil("est")); + let aRes = gc_engine.parse("Je suit..."); + for (let oErr of aRes) { + console.log(text.getReadableError(oErr)); + } +} + +function textToTest (sText, sCountry, bDebug, bContext, dInfo={}) { + if (!gc_engine) { + postMessage(createResponse("textToTest", "# Grammar checker not loaded.", dInfo, true)); + return; + } + sText = sText.replace(/­/g, "").normalize("NFC"); + let aGrammErr = gc_engine.parse(sText, sCountry, bDebug, bContext); + let sMsg = ""; + for (let oErr of aGrammErr) { + sMsg += text.getReadableError(oErr) + "\n"; + } + if (sMsg == "") { + sMsg = "Aucune erreur détectée."; + } + postMessage(createResponse("textToTest", sMsg, dInfo, true)); +} + +function fullTests (dInfo={}) { + if (!gc_engine) { + postMessage(createResponse("fullTests", "# Grammar checker not loaded.", dInfo, true)); + return; + } + let dMemoOptions = gc_engine.getOptions(); + let dTestOptions = gc_engine.getDefaultOptions(); + dTestOptions.set("nbsp", true); + dTestOptions.set("esp", true); + dTestOptions.set("unit", true); + dTestOptions.set("num", true); + gc_engine.setOptions(dTestOptions); + let sMsg = ""; + for (let sRes of oTest.testParse()) { + sMsg += sRes + "\n"; + console.log(sRes); + } + gc_engine.setOptions(dMemoOptions); + postMessage(createResponse("fullTests", sMsg, dInfo, true)); +} + + +// SpellChecker + +function setDictionary (sDictionary, oDict, dInfo) { + if (!oSpellChecker) { + postMessage(createResponse("setDictionary", "# Error. SpellChecker not loaded.", dInfo, true)); + return; + } + //console.log("setDictionary", sDictionary); + switch (sDictionary) { + case "main": + oSpellChecker.setMainDictionary(oDict); + break; + case "community": + oSpellChecker.setCommunityDictionary(oDict); + break; + case "personal": + oSpellChecker.setPersonalDictionary(oDict); + break; + default: + console.log("[worker] setDictionary: Unknown dictionary <"+sDictionary+">"); + } + postMessage(createResponse("setDictionary", true, dInfo, true)); +} + +function setDictionaryOnOff (sDictionary, bActivate, dInfo) { + if (!oSpellChecker) { + postMessage(createResponse("setDictionary", "# Error. SpellChecker not loaded.", dInfo, true)); + return; + } + //console.log("setDictionaryOnOff", sDictionary, bActivate); + switch (sDictionary) { + case "community": + if (bActivate) { + oSpellChecker.activateCommunityDictionary(); + } else { + oSpellChecker.deactivateCommunityDictionary(); + } + break; + case "personal": + if (bActivate) { + oSpellChecker.activatePersonalDictionary(); + } else { + oSpellChecker.deactivatePersonalDictionary(); + } + break; + default: + console.log("[worker] setDictionaryOnOff: Unknown dictionary <"+sDictionary+">"); + } + postMessage(createResponse("setDictionaryOnOff", true, dInfo, true)); +} + +function getSpellSuggestions (sWord, dInfo) { + if (!oSpellChecker) { + postMessage(createResponse("getSpellSuggestions", "# Error. SpellChecker not loaded.", dInfo, true)); + return; + } + let i = 0; + for (let aSugg of oSpellChecker.suggest(sWord)) { + postMessage(createResponse("getSpellSuggestions", {sWord: sWord, aSugg: aSugg, iSuggBlock: i}, dInfo, true)); + i += 1; + } +} + + +// Conjugueur + +function getVerb (sWord, bPro, bNeg, bTpsCo, bInt, bFem, dInfo) { + try { + let oVerb = null; + let oConjTable = null; + if (conj.isVerb(sWord)) { + oVerb = new Verb(sWord); + oConjTable = oVerb.createConjTable(bPro, bNeg, bTpsCo, bInt, bFem); + } + postMessage(createResponse("getVerb", { oVerb: oVerb, oConjTable: oConjTable }, dInfo, true)); + } + catch (e) { + console.error(e); + postMessage(createResponse("getVerb", createErrorResult(e, "no verb"), dInfo, true, true)); + } +} ADDED gc_lang/fr/mailext/icon.png Index: gc_lang/fr/mailext/icon.png ================================================================== --- gc_lang/fr/mailext/icon.png +++ gc_lang/fr/mailext/icon.png cannot compute difference between binary files ADDED gc_lang/fr/mailext/manifest.json Index: gc_lang/fr/mailext/manifest.json ================================================================== --- gc_lang/fr/mailext/manifest.json +++ gc_lang/fr/mailext/manifest.json @@ -0,0 +1,26 @@ +{ + "manifest_version": 2, + "applications": { + "gecko": { + "id": "${tb_identifier}", + "strict_min_version": "68.0a1" + } + }, + "name": "${tb_name}", + "description": "${description}", + "version": "${version}", + + "author": "${author}", + "homepage_url": "${link}", + + "background": { + "scripts": [ + "grammalecte-js/graphspell/helpers.js", + "background.js" + ] + }, + + "permissions": [ + "storage" + ] +} Index: helpers.py ================================================================== --- helpers.py +++ helpers.py @@ -34,11 +34,11 @@ if os.path.isdir(spInstall): eraseFolder(spInstall) with zipfile.ZipFile(spfZip) as hZip: hZip.extractall(spDest) else: - print("# folder not found") + print("# folder <" + spDest + "> not found") else: print("path destination is empty") def eraseFolder (sp): @@ -94,9 +94,9 @@ spfDst = (spDst + "/" + sf).strip("/ ") if os.path.isdir(spfSrc): if bRecursive: addFolderToZipAndFileFile(hZip, spfSrc, spfDst, dVars, bRecursive) else: - if spfSrc.endswith((".py", ".js", ".css", ".xcu", ".xul", ".rdf", ".dtd", ".properties")): + if spfSrc.endswith((".py", ".js", ".json", ".css", ".xcu", ".xul", ".rdf", ".dtd", ".properties")): hZip.writestr(spfDst, fileFile(spfSrc, dVars)) else: hZip.write(spfSrc, spfDst) Index: make.py ================================================================== --- make.py +++ make.py @@ -285,11 +285,11 @@ try: buildjs = importlib.import_module("gc_lang."+sLang+".build") except ImportError: print("# No complementary builder in folder gc_lang/"+sLang) else: - buildjs.build(sLang, dVars, spLangPack) + buildjs.build(sLang, dVars) return dVars['version'] def copyGraphspellCore (bJavaScript=False):