Index: gc_lang/fr/webext/content_scripts/init.js ================================================================== --- gc_lang/fr/webext/content_scripts/init.js +++ gc_lang/fr/webext/content_scripts/init.js @@ -54,10 +54,18 @@ this.lMenu.push(new GrammalecteMenu(this.nMenu, xNode)); this.nMenu += 1; } } }, + + createMenus2 () { + let lNode = document.querySelectorAll("[contenteditable]"); + for (let xNode of lNode) { + this.lMenu.push(new GrammalecteMenu(this.nMenu, xNode)); + this.nMenu += 1; + } + }, rescanPage: function () { if (this.oTFPanel !== null) { this.oTFPanel.hide(); } if (this.oLxgPanel !== null) { this.oLxgPanel.hide(); } if (this.oGCPanel !== null) { this.oGCPanel.hide(); } @@ -104,10 +112,20 @@ showError(e); } } } + +/* + Node where a right click is done + Bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=1325814 +*/ +let xRightClickedNode = null; +document.addEventListener('contextmenu', function (xEvent) { + xRightClickedNode = xEvent.target; +}, true); + /* Connexion to the background */ let xGrammalectePort = browser.runtime.connect({name: "content-script port"}); @@ -161,5 +179,6 @@ /* Start */ oGrammalecte.createMenus(); +oGrammalecte.createMenus2(); Index: gc_lang/fr/webext/content_scripts/menu.css ================================================================== --- gc_lang/fr/webext/content_scripts/menu.css +++ gc_lang/fr/webext/content_scripts/menu.css @@ -18,11 +18,11 @@ border-radius: 50%; text-align: center; cursor: pointer; box-shadow: 0 0 0 0 hsla(210, 50%, 50%, .5); z-index: 2147483640; /* maximum is 2147483647: https://stackoverflow.com/questions/491052/minimum-and-maximum-value-of-z-index */ - animation: grammalecte-spin 2s ease 3; + animation: grammalecte-spin 2s ease 1; } .grammalecte_menu_main_button:hover { border: 4px solid hsla(210, 80%, 35%, .5); background-color: hsla(210, 80%, 55%, .5); animation: grammalecte-spin .5s linear infinite; Index: gc_lang/fr/webext/content_scripts/menu.js ================================================================== --- gc_lang/fr/webext/content_scripts/menu.js +++ gc_lang/fr/webext/content_scripts/menu.js @@ -3,81 +3,83 @@ "use strict"; class GrammalecteMenu { - constructor (nMenu, xTextArea) { + constructor (nMenu, xNode) { this.sMenuId = "grammalecte_menu" + nMenu; this.xButton = oGrammalecte.createNode("div", {className: "grammalecte_menu_main_button", textContent: " "}); this.xButton.onclick = () => { this.switchMenu(); }; - this.xMenu = this._createMenu(xTextArea); - this._insertAfter(this.xButton, xTextArea); - this._insertAfter(this.xMenu, xTextArea); + this.xMenu = this._createMenu(xNode); + this._insertAfter(this.xButton, xNode); + this._insertAfter(this.xMenu, xNode); } _insertAfter (xNewNode, xReferenceNode) { xReferenceNode.parentNode.insertBefore(xNewNode, xReferenceNode.nextSibling); } - _createMenu (xTextArea) { + _createMenu (xNode) { try { + let sText = (xNode.tagName == "TEXTAREA") ? xNode.value : xNode.textContent; let xMenu = oGrammalecte.createNode("div", {id: this.sMenuId, className: "grammalecte_menu"}); + xMenu.appendChild(oGrammalecte.createNode("div", {className: "grammalecte_menu_header", textContent: "GRAMMALECTE"})); // Text formatter - let xTFButton = oGrammalecte.createNode("div", {className: "grammalecte_menu_item", textContent: "Formateur de texte"}); - xTFButton.onclick = () => { - this.switchMenu(); - oGrammalecte.createTFPanel(); - oGrammalecte.oTFPanel.start(xTextArea); - oGrammalecte.oTFPanel.show(); - }; + if (xNode.tagName == "TEXTAREA") { + let xTFButton = oGrammalecte.createNode("div", {className: "grammalecte_menu_item", textContent: "Formateur de texte"}); + xTFButton.onclick = () => { + this.switchMenu(); + oGrammalecte.createTFPanel(); + oGrammalecte.oTFPanel.start(xNode); + oGrammalecte.oTFPanel.show(); + }; + xMenu.appendChild(xTFButton); + } // lexicographe let xLxgButton = oGrammalecte.createNode("div", {className: "grammalecte_menu_item", textContent: "Lexicographe"}); xLxgButton.onclick = () => { - this.switchMenu(); + this.switchMenu(); oGrammalecte.createLxgPanel(); oGrammalecte.oLxgPanel.clear(); oGrammalecte.oLxgPanel.show(); oGrammalecte.oLxgPanel.startWaitIcon(); xGrammalectePort.postMessage({ sCommand: "getListOfTokens", - dParam: {sText: xTextArea.value}, - dInfo: {sTextAreaId: xTextArea.id} + dParam: {sText: sText}, + dInfo: {sTextAreaId: xNode.id} }); }; + xMenu.appendChild(xLxgButton); // Grammar checker let xGCButton = oGrammalecte.createNode("div", {className: "grammalecte_menu_item", textContent: "Correction grammaticale"}); xGCButton.onclick = () => { - this.switchMenu(); + this.switchMenu(); oGrammalecte.createGCPanel(); - oGrammalecte.oGCPanel.start(xTextArea); + oGrammalecte.oGCPanel.start(xNode); oGrammalecte.oGCPanel.show(); oGrammalecte.oGCPanel.startWaitIcon(); xGrammalectePort.postMessage({ sCommand: "parseAndSpellcheck", - dParam: {sText: xTextArea.value, sCountry: "FR", bDebug: false, bContext: false}, - dInfo: {sTextAreaId: xTextArea.id} + dParam: {sText: sText, sCountry: "FR", bDebug: false, bContext: false}, + dInfo: {sTextAreaId: xNode.id} }); }; + xMenu.appendChild(xGCButton); // Conjugation tool let xConjButton = oGrammalecte.createNode("div", {className: "grammalecte_menu_item_block", textContent: "Conjugueur"}); let xConjButtonTab = oGrammalecte.createNode("div", {className: "grammalecte_menu_button", textContent: "Onglet"}); xConjButtonTab.onclick = () => { - this.switchMenu(); - xGrammalectePort.postMessage({sCommand: "openConjugueurTab", dParam: null, dInfo: null}); + this.switchMenu(); + xGrammalectePort.postMessage({sCommand: "openConjugueurTab", dParam: null, dInfo: null}); }; let xConjButtonWin = oGrammalecte.createNode("div", {className: "grammalecte_menu_button", textContent: "Fenêtre"}); xConjButtonWin.onclick = () => { - this.switchMenu(); - xGrammalectePort.postMessage({sCommand: "openConjugueurWindow", dParam: null, dInfo: null}); + this.switchMenu(); + xGrammalectePort.postMessage({sCommand: "openConjugueurWindow", dParam: null, dInfo: null}); }; xConjButton.appendChild(xConjButtonTab); xConjButton.appendChild(xConjButtonWin); - // Create - xMenu.appendChild(oGrammalecte.createNode("div", {className: "grammalecte_menu_header", textContent: "GRAMMALECTE"})); - xMenu.appendChild(xTFButton); - xMenu.appendChild(xLxgButton); - xMenu.appendChild(xGCButton); xMenu.appendChild(xConjButton); //xMenu.appendChild(oGrammalecte.createNode("img", {scr: browser.extension.getURL("img/logo-16.png")})); // can’t work, due to content-script policy: https://bugzilla.mozilla.org/show_bug.cgi?id=1267027 xMenu.appendChild(oGrammalecte.createNode("div", {className: "grammalecte_menu_footer"})); return xMenu; @@ -91,9 +93,9 @@ this.xMenu.parentNode.removeChild(this.xMenu); this.xButton.parentNode.removeChild(this.xButton); } switchMenu () { - let xMenu = document.getElementById(this.sMenuId); + let xMenu = document.getElementById(this.sMenuId); xMenu.style.display = (xMenu.style.display == "block") ? "none" : "block"; } } Index: gc_lang/fr/webext/content_scripts/panel_gc.js ================================================================== --- gc_lang/fr/webext/content_scripts/panel_gc.js +++ gc_lang/fr/webext/content_scripts/panel_gc.js @@ -53,15 +53,15 @@ this.oTooltip = new GrammalecteTooltip(this.xContentNode); this.xPanelContent.appendChild(this.xContentNode); this.oTAC = new GrammalecteTextAreaControl(); } - start (xTextArea=null) { + start (xNode=null) { this.oTooltip.hide(); this.clear(); - if (xTextArea) { - this.oTAC.setTextArea(xTextArea); + if (xNode && xNode.tagName == "TEXTAREA") { + this.oTAC.setTextArea(xNode); } } clear () { while (this.xParagraphList.firstChild) { @@ -448,11 +448,11 @@ this._dParagraph.set(i, sText.slice(iStart, iEnd)); i++; iStart = iEnd+1; } this._dParagraph.set(i, sText.slice(iStart)); - console.log("Paragraphs number: " + (i+1)); + //console.log("Paragraphs number: " + (i+1)); } write () { if (this._xTextArea !== null) { let sText = ""; DELETED gc_lang/fr/webext/gce_sharedworker.js Index: gc_lang/fr/webext/gce_sharedworker.js ================================================================== --- gc_lang/fr/webext/gce_sharedworker.js +++ gc_lang/fr/webext/gce_sharedworker.js @@ -1,271 +0,0 @@ -/* - 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("GC Engine SharedWorker [start]"); -//console.log(self); - -importScripts("grammalecte/helpers.js"); -importScripts("grammalecte/str_transform.js"); -importScripts("grammalecte/ibdawg.js"); -importScripts("grammalecte/text.js"); -importScripts("grammalecte/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_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”. -*/ - - -/* - Message Event Object - https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent -*/ - -let xPort = null; - -function createResponse (sActionDone, result, dInfo, bError=false) { - return { - "sActionDone": sActionDone, - "result": result, // can be of any type - "dInfo": dInfo, - "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]); - } -} - -onconnect = function (e) { - console.log("[Sharedworker] START CONNECTION"); - xPort = e.ports[0]; - - xPort.onmessage = function (e) { - console.log("[Sharedworker] ONMESSAGE"); - let {sCommand, dParam, dInfo} = e.data; - console.log(e.data); - switch (sCommand) { - case "init": - init(dParam.sExtensionPath, dParam.sOptions, 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 "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('{"nbsp":true, "esp":true, "unit":true, "num":true}', dInfo); - break; - case "getListOfTokens": - getListOfTokens(dParam.sText, dInfo); - break; - default: - console.log("Unknown command: " + sCommand); - showData(e.data); - } - } - //xPort.start(); -} - -let bInitDone = false; - -let oDict = null; -let oTokenizer = null; -let oLxg = null; -let oTest = null; - - -function init (sExtensionPath, sGCOptions="", sContext="JavaScript", dInfo={}) { - try { - if (!bInitDone) { - console.log("[Sharedworker] 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("[Sharedworker] Modules have been initialized…"); - gc_engine.load(sContext, sExtensionPath+"grammalecte/_dictionaries"); - oDict = gc_engine.getDictionary(); - oTest = new TestGrammarChecking(gc_engine, sExtensionPath+"/grammalecte/fr/tests_data.json"); - oLxg = new Lexicographe(oDict); - if (sGCOptions !== "") { - gc_engine.setOptions(helpers.objectToMap(JSON.parse(sGCOptions))); - } - oTokenizer = new Tokenizer("fr"); - //tests(); - bInitDone = true; - } else { - console.log("[Sharedworker] Already initialized…") - } - // we always retrieve options from the gc_engine, for setOptions filters obsolete options - xPort.postMessage(createResponse("init", gc_engine.getOptions().gl_toString(), dInfo)); - } - catch (e) { - helpers.logerror(e); - xPort.postMessage(createResponse("init", createErrorResult(e, "init failed"), dInfo, true)); - } -} - -function parse (sText, sCountry, bDebug, bContext, dInfo={}) { - let aGrammErr = gc_engine.parse(sText, sCountry, bDebug, bContext); - xPort.postMessage({sActionDone: "parse", result: aGrammErr, dInfo: dInfo}); -} - -function parseAndSpellcheck (sText, sCountry, bDebug, bContext, dInfo={}) { - let aGrammErr = gc_engine.parse(sText, sCountry, bDebug, bContext); - let aSpellErr = oTokenizer.getSpellingErrors(sText, oDict); - xPort.postMessage(createResponse("parseAndSpellcheck", {aGrammErr: aGrammErr, aSpellErr: aSpellErr}, dInfo)); -} - -function getOptions (dInfo={}) { - xPort.postMessage(createResponse("getOptions", gc_engine.getOptions().gl_toString(), dInfo)); -} - -function getDefaultOptions (dInfo={}) { - xPort.postMessage(createResponse("getDefaultOptions", gc_engine.getDefaultOptions().gl_toString(), dInfo)); -} - -function setOptions (sGCOptions, dInfo={}) { - gc_engine.setOptions(helpers.objectToMap(JSON.parse(sGCOptions))); - xPort.postMessage(createResponse("setOptions", gc_engine.getOptions().gl_toString(), dInfo)); -} - -function setOption (sOptName, bValue, dInfo={}) { - gc_engine.setOptions(new Map([ [sOptName, bValue] ])); - xPort.postMessage(createResponse("setOption", gc_engine.getOptions().gl_toString(), dInfo)); -} - -function resetOptions (dInfo={}) { - gc_engine.resetOptions(); - xPort.postMessage(createResponse("resetOptions", gc_engine.getOptions().gl_toString(), dInfo)); -} - -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 || !oDict) { - xPort.postMessage(createResponse("textToTest", "# Grammar checker or dictionary not loaded.", dInfo)); - return; - } - let aGrammErr = gc_engine.parse(sText, sCountry, bDebug, bContext); - let sMsg = ""; - for (let oErr of aGrammErr) { - sMsg += text.getReadableError(oErr) + "\n"; - } - xPort.postMessage(createResponse("textToTest", sMsg, dInfo)); -} - -function fullTests (sGCOptions="", dInfo={}) { - if (!gc_engine || !oDict) { - xPort.postMessage(createResponse("fullTests", "# Grammar checker or dictionary not loaded.", dInfo)); - return; - } - let dMemoOptions = gc_engine.getOptions(); - if (sGCOptions) { - gc_engine.setOptions(helpers.objectToMap(JSON.parse(sGCOptions))); - } - let sMsg = ""; - for (let sRes of oTest.testParse()) { - sMsg += sRes + "\n"; - console.log(sRes); - } - gc_engine.setOptions(dMemoOptions); - xPort.postMessage(createResponse("fullTests", sMsg, dInfo)); -} - - -// Lexicographer - -function getListOfTokens (sText, dInfo={}) { - try { - let aElem = []; - let aRes = null; - for (let oToken of oTokenizer.genTokens(sText)) { - aRes = oLxg.getInfoForToken(oToken); - if (aRes) { - aElem.push(aRes); - } - } - xPort.postMessage(createResponse("getListOfTokens", aElem, dInfo)); - } - catch (e) { - helpers.logerror(e); - xPort.postMessage(createResponse("getListOfTokens", createErrorResult(e, "no tokens"), dInfo, true)); - } -} Index: gc_lang/fr/webext/panel/main.html ================================================================== --- gc_lang/fr/webext/panel/main.html +++ gc_lang/fr/webext/panel/main.html @@ -15,13 +15,13 @@ @@ -49,11 +49,11 @@

-

AIDE

+

INTERFACE

Grammalecte affiche un bouton d’accès au menu en bas à gauche des zones de texte usuelles pour accéder aux fonctionnalités existantes.

Pour les autres zones de texte (HTML éditable), il faut sélectionner le texte et utiliser le menu contextuel.