OK
AJAX error!

Les forumsGrammalectePropositions pour JavaScript

Propositions pour JavaScript

Bonjour,

J'aurais quelques propositions à faire sur des modifications de code (la partie JS), comment vous les faire ?

Merci d'avance de votre réponse !
le 05 août 2017 à 13:24
Bonjour,

Si vous voulez faire des changements sur le code JS, vous devez faire votre branche à partir de la branche webext2… Car le code JS sur trunk va finir par être remplacé.
Dans webext2, j’ai refondu l’organisation des modules pour être utilisable par WebExtension (qui ne reconnaît pas les modules).
Le code doit fonctionner pour :
— WebExtension pour Firefox.
— Addon-SDK pour Firefox (du moins jusqu’en novembre 2017 où ça deviendra obsolète).
— XUL pour Thunderbird.

Ce qui oblige à faire des contorsions assez étranges. Et c’est long et chiant à tester.
Cela dit, maintenant, ça ne devrait plus poser de problème.

Par ailleurs, quand les déclarations import/export seront acceptées par défaut dans Firefox/Thunderbird, c’est ce qui sera utilisé. On pourra peut-être enfin se débarrasser de tout ce merdier avec les require et les objets substituts de modules…

Qu’est-ce que vous voulez faire ?
le 06 août 2017 à 00:12
J'ai bien commencé les modification sur le webext2 :)

Pour le moment j'ai juste fait une petite review du code :

* Correction de quelques ; manquants ou superflus

* Remplacement des compréhensions de tableau par du javascript plus conventionnel : ça permettra que le code puisse fonctionner sur chrome / nodejs / nwjs / ...

* Dans le fichier gc_lang/fr/modules-js/conj.js, il y a eu quelques "conj." devant "getConj" qui ont été oubliés

* Dans gc_core/js/lang_core/gc_engine.js, vu que le helpers est déjà mis dans les require j'ai remplacé le echo par des helpers.echo. Je pense que ce n'est pas vraiment utile d'inclure le echo du helpers en plus


Et sinon quelques réflexions et tests que je faits:

- Je me demande si ça ne simplifierait pas les choses si un fichier unique contenant tout Grammalecte (sauf le French.json pour les autre *data.json je ne sais pas trop s'il faut les mettre aussi dedans) était généré. Ça simplifierait grandement les problèmes de require et d'export et du chargement des datas.

- Si les *data.json ne sont pas inclus dans le js unique, unifier leur chargement en faisant faire plus de travail par le helper.loadFile() comme la distinction de l’URL de changement, ce qui permettra de juste faire un helper.loadFile('fr/conj_data.json') et il complétera l'URL comme il faut, s'il est dans Firefox ou Thunderbird. Ça limitera la duplication de code.

- Pour les "exports." je me demande s'il sera pas plus judicieux d'exporter les objets et classes au lieu des fonctions individuelles.

- Pour le build, je me demande s'il ne faudrait pas que les répertoires "grammalecte" et "grammalecte-js" soient plutôt mis dans le répertoire "_build"

- Je pense aussi que les sources du cli et du serveur auraient plus leur place dans "gc_core/py/outils"

Voilà, j'ai dû faire un peu le tour.
le 06 août 2017 à 02:02
Veuillez m'excuser, je m'étais trompé de branche de départ, donc j'ai un peu pollué le timeline...
Donc j'ai refermé la branche que j'avais créé ou j'étais parti sur le mauvais point de départ.
le 06 août 2017 à 03:38

* Correction de quelques ; manquant ou superflu


OK, merci.

* Remplacement des compréhensions de tableau par du javascript plus conventionnel : ça permettra que le code puisse fonctionner sur chrome / nodejs / nwjs / ...


J’aimais bien les compréhensions de tableau… Mais si c’est nécessaire, qu’il en soit ainsi.

* Dans le fichier gc_lang/fr/modules-js/conj.js il il y a eut quelques "conj." devant "getConj" qui ont été oublié


Bien vu. Merci.

* Dans gc_core/js/lang_core/gc_engine.js vu que le helpers est déjà mis dans les require j'ai remplacer le echo par des helpers.echo je pense que ce n'est pas vraiment utile d'inclure le echo du helpers en plus


C’était en effet nécessaire puisque echo n’est plus disponible par défaut si require n’existe pas.
En revanche, il faut bien mettre une fonction echo directement accessible dans gc_engine.
Car il est parfois nécessaire de faire appel directement à la fonction echo lors du déroulé des règles de la correction grammaticale. Vous verrez que echo renvoie toujours True, ce qui permet de faire appel à elle dans les conditions des règles du correcteur. Dans rules.grx, vous pouvez écrire :

<<- morph(\1, ":N") and echo(\1) and morph(\2, ":A") and echo(\2) ->> suggestion

Ça permet d’afficher des motifs d’une expression régulière ou de vérifier les groupes capturés. Ça ne sert que pour certains cas de débogage, mais c’est indispensable.


- Je me demande si ça ne simplifiais pas les choses si un fichier unique contenant tout Grammalecte (sauf le French.json pour les autre *data.json je ne sais pas trop s'il faut les mettre aussi dedans) était généré ça simplifierait grandement les problèmes de require et d'export et du chargement des datas.


Réponse courte :
Mozilla ne sera pas d’accord.

Réponse longue :
À l’origine, les fichiers .json n’existaient pas. C’était des méga-objets directement écrits en JS, facilement importables via require. Mais Mozilla n’était pas content, et on m’a demandé de mettre tout ça dans des fichiers JSON, au nom des «bonnes pratiques»…
Ils voudraient aussi que je transforme le fichier gc_rules.js en JSON, mais avec des milliers de regex à compiler au démarrage si on fait ça, ils ont accepté de laisser les choses comme ça.
Par ailleurs, ils trouvent aussi que mes fichiers sont déjà trop gros. Que gc_engine.js, gc_rules.js fassent plusieurs milliers de lignes, ça les ennuie.
Apparemment, le fond du problème, c’est que leur outil de revue de code a beaucoup de mal à gérer les gros fichiers.

Dans le Addon-SDK et XUL, les require fonctionnent bien… Je m’en sers depuis le début. Mais la mauvaise surprise de WebExtension, c’est qu’il n’y a aucune possibilité d’importation. Sauf dans un Worker qui propose une sorte de solution bizarre avec importScripts, mais tel que je le comprends, ça fait une sorte de copier-coller, ce ne sont pas des modules à proprement parler qu’on importe.
C’est pourquoi on a cette solution bâtarde bien casse-pieds.

La généralisation de import/export est ce que j’attends avec le plus d’impatience… et c’est ce qui sera utilisé quand ça existera.

- Si les *data.json ne sont pas inclus dans le js unique unifier leur chargement en faisant faire plus de travail par le helper.loadFile() comme la distinction de L’URL de changement se qui permettra de juste faire un helper.loadFile('fr/conj_data.json') et il complétera l'URL comme il faut s'il est dans Firefox ou Thunderbird. Ça limitera la duplication de code.


Pas possible. Le cœur du correcteur grammatical fonctionne dans un Worker (un thread séparé) qui n’a pas accès à la fonction browser.extension.getURL qui permet de récupérer l’URL de l’extension.

- Pour les "exports." je me demande s'il sera pas plus judicieux d'exporter les objets et classes aux lieux des fonctions individuelles.


Oui, pourquoi pas…
À noter qu’actuellement il faut exporter aussi les fonctions et attributs privés sinon ça ne fonctionne pas.
C’est de toute façon une solution bâtarde faite pour concilier des fonctionnements différents.

- Pour le build je me demande s'il ne faudrait pas que les répertoires "grammalecte" et "grammalecte-js" ne soit pas plutôt mis dans le répertoire "_build"
- Je pense aussi que les sources du cli et du serveur aurrais plus leur place dans "gc_core/py/outils"


Non et non.
Il est vrai que le dossier grammalecte-js n’a pas d’utilité tel quel (sauf éventuellement à vérifier le code généré), mais grammalecte est un module Python parfaitement fonctionnel tel quel, et il sert en partie à la compilation de lui-même (cf. build_data.py)
Le dossier _build est pour les fichiers binaires et temporaires.
le 06 août 2017 à 09:28

C’était en effet nécessaire puisque echo n’est plus disponible par défaut si require n’existe pas.
En revanche, il faut bien mettre une fonction echo directement accessible dans gc_engine.
Car il est parfois nécessaire de faire appel directement à la fonction echo lors du déroulé des règles de la correction grammaticale. Vous verrez que echo renvoie toujours True, ce qui permet de faire appel à elle dans les conditions des règles du correcteur. Dans rules.grx, vous pouvez écrire :

<<- morph(\1, ":N") and echo(\1) and morph(\2, ":A") and echo(\2) ->> suggestion



donc on pourrait faire par exemple pour éviter le double require :

if (typeof(require) !== 'undefined') {
var helpers = require("<a href="grammalecte… "="">grammalecte…</a>);
var gc_options = require("<a href="grammalecte… "="">grammalecte…</a>);
var gc_rules = require("<a href="grammalecte… "="">grammalecte…</a>);
var cregex = require("<a href="grammalecte… "="">grammalecte…</a>);
var text = require("<a href="grammalecte… "="">grammalecte…</a>);
var echo = helpers.echo;
}

le 06 août 2017 à 11:27
Quand vous faites des modifications, testez, s’il vous plaît.
L’une des conversions des compréhensions de tableau était erronée et provoquait environ 600 erreurs dans les tests. J’ai passé pas mal de temps à retrouver l’origine du problème. Un seul caractère erroné, mais c’était important : code.grammalecte.net…

Edit: Cela dit, mea culpa, si vous utilisiez Linux, vous ne pouviez pas tester. Je viens d’ajouter les chemins pour lancer Firefox Nightly et Developper, selon que vous mettiez l’option -we ou -fx.

var echo = helpers.echo;


Effectivement, ça ne servait à rien de faire deux require.
Mais ça ne suffit pas, car il faut que echo soit présent, même lorsque require est absent.
Je vais m’en occuper.
le 06 août 2017 à 13:32
Merci.
J’ai fusionné votre branche, mais elle est toujours ouverte pour la suite si vous n’êtes pas trop rebuté. :)
le 06 août 2017 à 14:35
Je m'excuse pour le bug que j'ai introduit.

Si je comprends bien, la principale difficulté avec les extensions est :
* Pour Firefox et Thunderbird quand c'est dans un worker, le require est disponible.
* Dans WebExt, le require ne fonctionne pas, il faut donc utiliser importScripts.

Avec le importScripts, ça inclut le contenu du fichier tel quel, alors qu'avec require il n'y a que les fonctions exportés qui sont accessible.

J'ai pas encore testé, mais pour résoudre cette difficulté d'une manière universelle, je pensais à un code de ce type :
nouveau fichier grammalecte.js


var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
var ENVIRONMENT_IS_WEB = typeof window === 'object';
var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';

function loadScript(scriptName){
if ( ENVIRONMENT_IS_WORKER ) {
exports = {};
importScripts(scriptName);
return exports;
} else {
return require(scriptName);
}
}

var Grammalecte = {};
Grammalecte.helpers = loadScript("grammalecte/helpers.js");
Grammalecte.str_transform = loadScript("grammalecte/str_transform.js");
Grammalecte.ibdawg = loadScript("grammalecte/ibdawg.js");
...

/*Code repris du worker de webext et ajusté*/
let oDict = null;
let oTokenizer = null;
let oLxg = null;
let oTest = null;

function loadGrammarChecker (sExtensionPath, sGCOptions="", sContext="JavaScript") {
try {
console.log("Loading… Extension path: " + sExtensionPath);
Grammalecte.conj.init(Grammalecte.helpers.loadFile(sExtensionPath + "/grammalecte/fr/conj_data.json"));
Grammalecte.phonet.init(Grammalecte.helpers.loadFile(sExtensionPath + "/grammalecte/fr/phonet_data.json"));
Grammalecte.mfsp.init(Grammalecte.helpers.loadFile(sExtensionPath + "/grammalecte/fr/mfsp_data.json"));
console.log("Modules have been initialized…");
Grammalecte.gc_engine.load(sContext, sExtensionPath+"grammalecte/_dictionaries");
oDict = Grammalecte.gc_engine.getDictionary();
oTest = new Grammalecte.tests(gc_engine, sExtensionPath+"/grammalecte/fr/tests_data.json");
oLxg = new Grammalecte.lexicographe(oDict);
if (sGCOptions !== "") {
Grammalecte.gc_engine.setOptions(Grammalecte.helpers.objectToMap(JSON.parse(sGCOptions)));
}
oTokenizer = new Grammalecte.tokenizer("fr");
tests();
// we always retrieve options from the gc_engine, for setOptions filters obsolete options
if ( ENVIRONMENT_IS_WORKER ) {
postMessage(["options", Grammalecte.gc_engine.getOptions().gl_toString()]);
} else {
return Grammalecte.gc_engine.getOptions().gl_toString();
}
}
catch (e) {
console.error(e.fileName + "\n" + e.name + "\nline: " + e.lineNumber + "\n" + e.message);
if ( ENVIRONMENT_IS_WORKER ) {
postMessage(["error", e.message]);
} else {
return e.message;
}
}
}
...
if ( ENVIRONMENT_IS_WORKER ) {
onmessage = function (e) {
let oParam = e.data[1];
switch (e.data[0]) {
case "init":
loadGrammarChecker(oParam.sExtensionPath, oParam.sOptions, oParam.sContext);
break;
...
}
};
}



Ceci permet d'avoir un accès à Grammalecte d'un haut niveau et qui permettrait d'être universel et d'être utilisé aussi bien dans un worker de tous types d'extensions que dans le contexte d'une page html ou voire un script nodejs.

Qu'en pensez-vous ?
le 06 août 2017 à 15:52
En fait, c’est un peu plus compliqué que ça… :)

Il y a trois types d’extensions :
— WebExtension, pour Firefox, en cours de conception, qui utilise un Worker.
— Addon-SDK, l’extension actuelle pour Firefox, qui utilise un PromiseWorker.
— XUL, pour Thunderbird, qui utilise un PromiseWorker.

Addon-SDK et XUL ont des interfaces différentes, mais partagent le même PromiseWorker : code.grammalecte.net…
Lorsque l’extension pour Thunderbird est créée, make.py copie le script pour Firefox tel quel.

Dans WebExtension, tout est différent. Il n’y a pas de PromiseWorker.
J’utilise un simple Worker : code.grammalecte.net…

Le Worker et le PromiseWorker ne fonctionnent pas de la même manière.
Et dans le second cas, il faut déclarer les ressources qu’on importe dans un “chrome.manifest”.

Donc, voilà, c’est le bordel. Il n’y a pas de cohérence globale, ce sont des systèmes incompatibles.

À la mi-novembre 2017, Addon-SDK va périr, mais XUL va encore rester pour un temps indéterminé chez Thunberbird.

Quant à NodeJS, je n’y connais rien.

Bref, je ne suis pas sûr que mélanger tout ça dans un même script d’initialisation nous soit tellement utile.
Je n’y suis pas opposé si ça a du sens, notez bien… L’astuce avec loadScript() est intéressante.
le 06 août 2017 à 20:24
J’ai séparé la discussion sur JavaScript et la gestion du dépôt.
L’autre fil est ici : www.dicollecte.org…
le 06 août 2017 à 21:39
Depuis hier, j'ai fait pas mal de tests sous Firefox, nwjs sans Worker, nwjs avec Worker et effectivement c'est le bordel dans les différents contextes de chaque élément (Worker. Global...)

Donc dans la branche que j'avais créée :
* Dans un premier temps, je fais faire quelques petites modifications. Par exemple, j'ai remarqué qu'à certains endroits avant les requires il y a des

if (typeof(exports) !== 'undefined') {

alors que ça devrait être des

if (typeof(require) !== 'undefined') {


* Puis je vais essayer de rendre le cœur de Grammalecte (le dossier généré grammalecte-js) indépendant du type de contexte afin de simplifier au maximum le futur travail pour les différents types d'application.

Sinon puis-je modifier un peu le make afin de changer la partie qui remplace les ${...} pour que ça remplace les /*${...}*/ et donc répercuter ses changements dans les différents fichiers? Ces changements permettraient que JSHint crie pas sur ses lignes qui sont bien sûr pas valides en javascript pour plusieurs raisons (j'ai même l'impression que ça fait que JSHint ne sais plus trop ou il en est) grâce à ce petit changement, ça fera que tout simplement /*${...}*/ soit ignoré.

Pour l'astuce du loader, avec une petite modification, ça fonctionne à merveille ;)

En ce qui concerne le script d’initialisation les avantages que je vois sans trop réfléchir :
* la possibilité de l'utiliser directement comme Worker / PromiseWorker
* dans une application un simple require de ce fichier permet d'avoir les fonctionnalités de Grammalecte
* unification des noms fonctions exportées et des réponses aux messages dans un Worker. Si on a un

Grammalecte.parse

on aura l'équivalent en

Worker.postMessage(["parse", {})

donc le passage de l'un vers l'autre dans un front-end sera simplifié.
* faire des fonctions de plus haut niveau qui sont souvent utilisées.
le 07 août 2017 à 16:26

if (typeof(exports) !== 'undefined') {


Comme exports n’était défini que si require existait, ce n’était pas incohérent.
Avant seul exports était testé. J’ai modifié pour mettre require quand je suis tombé dessus, mais je n’ai pas parcouru tout le code à la recherche de ça.
OK, pour la modif.

* Puis je vais essayer de rendre le coeur de Grammalecte ( le dossier généré grammalecte-js ) indépendant du type de contexte affin de simplifier au maximum le futur travail pour les différente type d'application.


Bon courage…

les avantages que je voie sans trop réfléchir


Oui, c’est bien.
Mais il faudrait quand même que ce script ne soit pas trop indigeste… si possible. :)

Pour ma part, maintenant, j’ai ce dont j’ai besoin : ça fonctionne sur les extensions de Firefox (WebExtension et Addon-SDK) ainsi que sur Thunderbird.

Je ne veux pas vous empêcher d’avoir ce dont vous avez besoin, mais il faut, si vous voulez que ça devienne le standard, que ça fonctionne impérativement avec Firefox (WebExtension) et Thunderbird.
Pour Firefox (Addon-SDK), si ça ne fonctionne pas, ce n’est pas grave, puisque cette extension est appelée à être remplacée par la nouvelle au plus tard en novembre 2017 (et avant ça, j’espère).

Je vous suggère de faire dans la branche webext2_fix:
fossil merge webext2

S’il n’y a pas de conflit:
fossil commit -m "[fx] merge webext2" --tag fx

Ça permettra d’avoir une branche fonctionnelle.
En faisant:
make.py fr -js -we
vous pourrez vérifier que les tests fonctionnent (dans le panneau TST). Ça prend environ 15 secondes sur mon PC.

Mais il serait peut-être plus judicieux de créer une autre branche à partir de webext2 pour ce que vous voulez faire. Un branche qui pourrait s’appeler js_wrapper par exemple.

Sinon puis-je modifier un peux le make afin de changer la partie qui remplace les ${...} pour que ça remplace les /*${...}*/ et donc répercuté ses changement dans les différents fichier? C'est changement permettrais que JSHint crie pas sur ses lignes qui sont bien sur pas valide en javascript pour plusieurs raisons (j'ai même l'impression que ça fait que JSHint ne sais plus trop ou il en est) gràce a se petit changement ça fera que tout simplement /*${...}*/ soit ignoré.


Je ne comprends pas ce que vous voulez faire.
A priori, ça ne fonctionnera pas sans ça, puisque ça sert à injecter le code qui étend les objets de la lib standard.
Pourquoi ne pas lancer JSHint sur le dossier grammalecte-js ? Ce dossier ne contient plus ces ${…}. S’il en contient encore, c’est qu’il y a un problème.

Le mieux, c’est de vous créer une branche dédiée où vous pourrez casser ce que bon vous semble.

Note : on pourrait peut-être se tutoyer… ?
le 07 août 2017 à 18:29
Pas de problème pour le tutoiement.

Je continue mes tests actuellement et dès que je serais satisfait de toutes mes solutions je commencerais donc une nouvelle branche.

Pour le problème avec JSHINT vu qu'il est intégré à mon éditeur (comme la plupart des éditeur actuelle) c'est pour permettre d'avoir un javascript valide sans avoir besoin de construire et donc pouvoir repérer les éventuelles erreur plus tôt.

Je m'explique mieux sur ce que je veux faire.

Donc actuellement le fichier mfsp.js commence comme ceci :

// Grammalecte - Conjugueur
// License: GPL 3

"use strict";

${map}

....



Donc se que je voudrais faire, c'est qu'il commence comme ceci :

// Grammalecte - Conjugueur
// License: GPL 3

"use strict";

/*${map}*/



Et donc que le make, au lieu de changer le ${map} avec le fichier jsex_map.js, changera le /*${map}*/ ce qui dans l'absolu revient au même... mais avec l'avantage dit précédemment.
le 07 août 2017 à 21:01
On ne peut pas faire ça.

Actuellement, make.py se sert du moteur de Template de Python (docs.python.org…) qui remplace automatiquement les variables ${var} par le contenu d’un dictionnaire passé en paramètre.

${myvar} indique de placer la valeur contenue dans le dictionnaire à la clé myvar.

Si vous écrivez /* ${myvar} */, ce sera simplement mis en commentaire. Le moteur de Template ne sait pas qu’il devrait ôter les commentaires.

En revanche, on peut écrire $myvar au lieu de ${myvar}. JSHint s’accommoderait peut-être plus facilement de cette notation ?
le 08 août 2017 à 08:16
Je pense avoir fini ce que je pensais faire pour la branche webext2_fix.

Le commit b89dc82bc4139068a8580a17f8711f84676f5d045802c780e47dd4aa38724c27 permet que JSHint ne signale pas les erreurs dues a l'utilisation de l'ES6 et permet de signaler quelques variables globales et donc évite de signaler que telle variable n'est pas déclarée. Ce commit n'est pas nécessaire dans l'absolu, c'est juste pour un confort d'utilisation. Par contre pourrais-tu me dire si tu vas le merger pour savoir à partir de quoi je commence le travail sur le js_wapper ?

Le commit ccebd25f43df0aa0481a823183573f14e96c98c8ee009a6636f8026126185507 est juste que je force le mimetype des réponses de la lecture des *_data.json car j'ai vu passer parfois dans la console de débogage de la WebExtension qu'il essayait de l'interpréter en tant que xml. Je n'ai pas réussi à savoir exactement comment le reproduire...

Sinon les commits avant sont pour être sûr que les objets conj, mfsp et phonet ne sont initialisés qu'une seule fois dans un contexte donné. C'est suite à mes tests que j'ai remarqué qu'ils pouvaient être initialisés plusieurs fois ce qui est complètement inutile.

Voilà, la prochaine étape le js_wapper avec les changements pour que tout le "grammalecte-js" puisse fonctionner aussi bien en WebExtension, Thunderbird, NwJS et NodeJS (et surement aussi sous Chrome) !
le 08 août 2017 à 22:21
OK, merci, j’ai fusionné la branche.

J’en suis toujours à la phase des tests sur webext2. J’expérimente ce qui est possible avec WebExtension.

Cela dit, le Worker ne devrait plus beaucoup changer.
le 09 août 2017 à 08:58
Sinon je pensais pour la WebExtension est que ça serait bien de faire la correction en 2 étapes visuelles (si nécessaire).

La première étape (s'il y a des fautes d'orthographe) est de présenter le texte avec les fautes d'orthographe et que donc la personne puisse les faire. Avec un bouton "suivant".

La deuxième étape (s'il n'y a pas de faute, c'est la seule étape mais avec le texte original) est donc reprendre le texte où la personne a modifié l'orthographe et exécuté la correction grammaticale.

Ça permettrait à Grammalecte de mieux se retrouver quand il y a des erreurs orthographiques, vu que sinon il vaut mieux passer le correcteur grammatical une autre fois après la correction de l'orthographe.

Sinon voici une extension chrome (donc des WebExtension) qui pourra peut être vous inspirer pour le fonctionnement:
chrome.google.com…
Leur site officiel : www.gingersoftware.com… (il me semble qu'il ont aussi une extension Firefox)
le 09 août 2017 à 11:12
Deux étapes pour l’utilisateur, ce n’est pas nécessaire, on peut souligner tout en même temps. Ce qu’il faudrait, c’est rafraîchir la correction à mesure que des modifications sont faites par l’utilisateur.

L’interface de Ginger est intéressante, je me demande vraiment comment ils font. Idem pour Grammaly sur Firefox.

Mais je n’en suis pas encore là.
le 09 août 2017 à 11:47
Ah oui il y a aussi la solution de réanalyser à chaque modification.

Je pense que le fonctionnement est du type (je vais peut être me tromper dans les thermes des élément de la WebExtension :
* Avec un Content_script il accède à la page pour détecter les textareas, inputs et les contents éditables.
* Création d'un élément content éditable qui le copie la case originale
* La case originale est cachée et le content éditable le remplace (pour que ce soit invisible à l'utilisateur)
* Ajout du bouton pour lancer l’analyse en superposition positionné en bas du nouvel content éditable (ou de celui réutilisé)
* Sur le clic du bouton créé, ça lance l’analyse et remplace le texte ou il y a des erreurs par des <span class="...">l'erreur</span>
=> sur le span créé un gestionnaire qui permet de faire les différentes actions sur l'erreur surement un div placé comme un contex_menu avec les différentes informations.
* A chaque modification de l'utilisateur synchronisation du content éditable avec la case originale

Voilà se que je pense pour la théorie du fonctionnement de ces WebExtensions (j'ai du code de côté à adapter qui pourrait faire une partie de ce travail (qui fonctionne sur un site et oui normalement je suis webmaster) ).

Mais il vaut mieux je pense dans un premier temps garder plus ou moins le fonctionnement de la première extension (ça évitera que les utilisateurs râlent et oui ils n'aiment pas les moindres changements).

Et puis faire par la suite une nouvelle Extension Grammalecte² avec un tout nouveau fonctionnement...
le 09 août 2017 à 12:37

* Création d'un élément content éditable qui le copie la case originale
* La case originale est cachée et le content éditable le remplace (pour que ce soit invisible à l'utilisateur)


Ça, c’est la solution que j’envisageais, mais je pensais qu’ils faisaient autrement, avec des couches et de la transparence, ou quelque chose de ce genre.

* Sur le clic du bouton créé, ça lance l’analyse et remplace le texte ou il y a des erreurs par des <span class="...">l'erreur</span>
=> sur le span créé un gestionnaire qui permet de faire les différentes actions sur l'erreur surement un div placé comme un contex_menu avec les différentes informations.


C’est ce que je fais avec l’extension actuelle.

Mais il vaut mieux je pense dans un premier temps garder plus ou moins le fonctionnement de la première extension (ça évitera que les utilisateurs râlent et oui ils n'aiment pas les moindres changements).


Ça ne va pas être possible.
WebExtension a beaucoup de contraintes et moins de possibilités. Il faut déjà faire autrement.
J’ai perdu beaucoup de temps à fouiller la doc à la recherche de solutions, mais rien, j’ai arrêté de chercher…

J’envisage d’utiliser un SharedWorker au lieu d’un Worker. Mais je n’arrive pas à appeler le SharedWorker depuis un content-script, je ne sais pas pourquoi. J’y parviens depuis le background, mais j’ai une erreur non explicitée à partir du content-script. C’est pourquoi je déteste JS avec ces messages d’erreur obscurs, et c’est pire quand il n’y a aucune explication, juste “ça marche pas”… J’ai horreur des devinettes.
Que de temps perdu. :(
le 09 août 2017 à 19:20
Et encore je trouve que le débogage de javascript s'est beaucoup amélioré ses dernières années. Le pire c'est que parfois ça ne fonctionne pas, car il y a un point virgule oublié et donc il comprend la commande avec la ligne suivante :s

Quel est l’intérêt de sharedworker à la place du worker ?

Je pense avoir corrigé l’initialisation ;) et j'ai publié direct dans votre branche...
le 09 août 2017 à 21:34
Si vous avez un compte skype, mon pseudo est le même qu'ici ;) (je ferai attention à être connecté vu que je ne l'utilise presque jamais)
le 09 août 2017 à 21:36
Ah non, peut-être pas c'est bizarre car quand je désactive et réactive l’extension ça ne fait pas l'erreur mais quand je ferme complètement Firefox et que je le redémarre il semble qu'une erreur persiste (mais en désactivant et réactivant l'extension ça fonctionne :s).
le 09 août 2017 à 22:11
Après quelques heures de tests, j'ai pas réussi à faire que ça fonctionne même après le redémarrage de Firefox.

Je me demande si c'est possible d’ailleurs... Le content_script modifie les page internet consultée donc ça ferait créer pas mal de sharedworker si la personne a l'habitude d'avoir plusieurs onglets / pages ouvertes en même temps.

Sinon pourquoi veux-tu qu'il y ait un worker dans le content_script ?
le 10 août 2017 à 03:19
Merci pour la correction.
Chez moi, ça ne fonctionne pas du tout. Mais au moins, j’ai un message d’erreur qui veut dire quelque chose :

Erreur de sécurité : le contenu situé à http:xxxxxx ne peut pas charger de données à partir de moz-extension://42511385-7f26-454d-aef9-a4313f7630fe/gce_sharedworker.js.


Ce qui suggère que ce n’est pas possible de charger un SharedWorker depuis un content-script. Ce qui est bien dommage, mais tout de même curieux.

L’intérêt du SharedWorker, c’est justement de le partager entre plusieurs scripts.
Ça offre l’avantage d’un accès direct au Worker sans avoir à transiter par le background. Et, sauf erreur de ma part, ça ne consomme pas plus de mémoire, attendu qu’il est partagé.

developer.mozilla.org…
Dans notre Exemple basique d'un worker partagé (lancer le worker partagé), nous avons deux pages HTML, qui chacune utilise du code JavaScript pour réaliser un calcul simple. Les différents scripts utilisent le même worker pour effectuer ce calcul — ils peuvent tous les deux y accéder, même si leurs pages s'exécutent à l'intérieur de fenêtres différentes.



Le problème du Worker dans le background, c’est que ce n’est pas un PromiseWorker, ce qui est bien moins pratique, attendu que la fonction qui se connecte au Worker ne peut pas attendre le résultat du travail du Worker. La réponse est envoyée ailleurs. Ce qui est dommage, car du coup, le content-script qui envoie la demande ne peut recevoir la réponse via la fonction de réponse dédiée (qui renvoie, elle, une Promise).

Je n’ai pas de compte Skype, ni de webcam, ni de smartphone… Je suis plutôt low-tech en dehors du PC. De surcroît, je déteste le téléphone.
le 10 août 2017 à 07:31
Je viens de comprendre l’origine du problème. En voulant ajouter une image de l’extension dans le content-script, ça a généré la même erreur.

Il s’agit d’un bug de Firefox (bugzilla.mozilla.org…)

En gros, ça dit que les content-scripts ne peuvent pas pointer des fichiers contenus dans l’extension, quels qu’ils soient.
CSP signifie « content-script policy ».
le 10 août 2017 à 09:43
Dans un sens c'est logique... ça ouvre une grosse faille de sécurité si c'était permis.

Peut être que pour contourner ce problème la procédure à suivre est :
Le content_script insert une iframe :

var f = document.createElement('iframe');
f.src = browser.extentsion.getURL('comunicate.html');
f.hidden = true;
document.body.appendChild(f);



Donc il faut dans l'extension le fichier comunicate.html (permet d'être dans le contexte de l'extension) du style

<html><head>
<script src="comunicate.js"></script>
</head><body></body></html>



Et le fichier comunicate.js contiendrait le code de création du SharedWorker et donc de renvoi de la réponse.

Et donc par message entre l'iframe et le content script on devrait pouvoir échanger des données... (Peut être que le blog devrait aussi injecter dans la page Web le un script de communication avec un blod entre l'iframe et la page web)

J'ai pas testé cette solution (je vais le faire de ce pas) mais je pense que ça devrait fonctionner.

Note: je dois avoir la même haine envers le tel que vous. Pour la webcam, j'en ai une mais en 10ans elle a dû servir grand maximum 30 min. Je te proposais mon skype au cas où car ça aurait pu être utile pour des échanges d'idées (par écrit) quand tu bloques quelque part.
le 10 août 2017 à 12:15

Dans un sens c'est logique... ça ouvre une grosse faille de sécurité si c'était permis.


Non, c’est bien un problème. Et ça sera corrigé, un jour, mais apparemment, ce n’est pas facile à faire. Donc, on se passera de SharedWorker en attendant que ce soit possible.

f.src = browser.extentsion.getURL('comunicate.html');


Justement, non, ça ne marchera pas.
Tu peux récupérer une URL de ton extension, mais si tu l’injectes dans le HTML produit, la politique de sécurité va te bloquer.

C’est comme ça que j’ai inséré le lien vers une image et ça n’est pas passé.
le 10 août 2017 à 12:36
J'ai réussi à mettre le SharedWorker fonctionnel dans une iframe qui est elle-même insérée dans la page.

Donc ça fait que la communication se fait :
La page web -> l'iframe qui envoie à son tour au SharedWorker.
Le SharedWorker fait son travail, envoie les réponses à iframe.
Et l'iframe le renvoie à la page web :)

Je fais encore deux trois test et j'ouvre une branche pour que tu puisses analyser le code ;)
le 10 août 2017 à 15:20
C'est posté ! J'ai mis pas mal de console.log et essayé de mettre un max de commentaires pour la compréhension.
le 10 août 2017 à 16:29
Voilà la politique de sécurité est contournée pour pouvoir mettre des images ;)
J'ai ajouté une petite fonction qui permet d’insérer l'image dans un élément ayant une classe donné.
Veux-tu que je fasse une bidouille aussi pour injecter un CSS, ça évitera tous les styles inline...
le 10 août 2017 à 19:03
Ah oui, j'allais oublier, la méthode de mettre les textareas dans un wapper peut casser le fonctionnement de certaines pages...
Je pense qu'il vaut mieux les laisser tels quels et d'ajouter la barre après.
le 10 août 2017 à 19:29
Bravo pour l’astuce de l’iframe. Je n’aurais pas été capable de faire ça. Je ne connaissais pas assez le sujet…

Cela dit, je ne suis pas sûr qu’on y gagne au change. À l’origine, ce qui m’intéressait dans le SharedWorker, c’était de pouvoir communiquer sans intermédiaire.

Je voulais :
content-scripts <====================> SharedWorker

au lieu de :
content-scripts <==========> background <==========> Worker

Et ce qu’on a avec les iframes, c’est :
content-scripts <==========> iframe <==========> SharedWorker

Du coup, on se retrouve avec la même problématique de double processus de communication.

Bon, on comparera, on verra.

Désolé, je n’étais pas là hier après-midi et soir pour répondre plus tôt.
le 11 août 2017 à 08:33
Je vois un avantage, vu que le Shareworker apparemment partage un même contexte, c'est genre de pouvoir partager le changement de configuration en live à tous les onglets ouverts (ou du background => le content_script). Faudrait donc juste faire des modifications mineures pour garder la liste des ports et faire une fonction pour envoyer à tous les ports sauf celui de réception.

Il y a aussi l'uniformisation de comment on accède au core de Grammalecte se qui évite de devoir réintroduire un fichier du core dans divers endroits et donc permet un débogage plus simple. Il y a une bonne séparation Front-end / Core.

On gagne aussi peut être en mémoire (mais là je ne connais pas assez pour en être certain).

Après ça démontre à tous les Anglais qui disaient que c'était pas possible qu' "Impossible n'est pas français" mdr

J'avais pensé à 2-3 autres avantages, mais je ne tape pas au clavier assez rapidement et je les ai oubliés :s

Note : Je me demande s'il faudrait pas ouvrir une section Codage sur le forum, vu que ça ne doit pas intéresser 99% des visiteurs du forum.

PS: a partir de ce soir (ou demain matin) jusqu’à la fin de la semaine prochaine, je n’aurai sans doute pas le temps de coder mais j'essayerai de passer quand même ici.
le 11 août 2017 à 10:05

Je vois un avantage, vu que le Shareworker apparemment partage un même contexte, c'est genre de pouvoir partager le changement de configuration en live à tous les onglets ouverts (ou du background => le content_script).


Ça aurait été aussi le cas avec un Worker. Le Worker n’est pas partagé directement, mais indirectement quand même via le background, et il est unique lui aussi.

Il y a aussi l'uniformisation de comment on accède au core de Grammalecte se qui évite de devoir réintroduire un fichier du core dans divers endroits et donc permet un débogage plus simple.


Non, c’est pareil avec le Worker. Il est instancié une fois dans le background, et tout le monde y accède aussi de la même manière.

Il y a une bonne séparation Front-end / Core.


Idem avec le Worker.

La seule chose qui change c’est l’intermédiaire qui fait la communication : un iframe par content-script, ou le background pour tous les scripts.

En revanche, il y a des différences sur la manière dont la communication se fait. Et c’est là que je ne suis pas sûr de ce qui est le plus avantageux. À vue de nez, passer par les iframes me semble moins ambigu, bien que ce soit de la magouille. :)
Pour l’instant, je vais suivre cette idée, et on verra.
le 11 août 2017 à 10:26
C'est sûr, c'est de la méga bidouille ;)

N'ayant encore jamais pris le temps de faire une extension, je découvre un peu.

Je pense qu'il faut que ça puisse répondre à plusieurs cas :
* Le cas où l'origine du message dois avoir une réponse pour lui
* Le cas où l'origine envoie un message pour une réponse à tous les autres (onglet(s), background...)
* Le cas où l'origine envoie un message pour tout le monde y compris lui ;)

Donc c'est à voir par quelle méthode c'est le plus avantageux (et le moins contraignant)
le 11 août 2017 à 11:01
Bon, ça ne fonctionne pas comme il faut avec le SharedWorker. Il n’est pas partagé. Chaque fois qu’on ouvre un nouvel onglet, même sur la même page, c’est un nouveau SharedWorker qui est créé. Ces workers n’ont donc rien de “shared”.
le 11 août 2017 à 13:25
C'est ce que j'ai remarqué avec mon test d'ajout des fonctions pour envoyer aux différents ports...
Il doit y avoir une petite erreur quelque part, j'essaie de trouver... mais je sens que ça ne sera pas évident.
le 11 août 2017 à 14:04
Bon, je n'arrive pas à comprendre le pourquoi ça ne fonctionne pas comme il faut, surtout qu'il n'y a aucune erreur signalée...

Je crois que la réponse à la question pour savoir s'il faut ou non utiliser un Sharedworker va s'imposer d'elle-même.

J'avais crié victoire trop tôt...
le 11 août 2017 à 18:45
J'abandonne temporairement au moins les recherches sur pourquoi le Sharedworker n'est pas shared.
Toutes les conditions pour que ça fonctionne me semblent pourtant présentes.

Par contre, pour le moment, peux-tu laisser la branche ouverte au cas où je trouve une solution plus tard...
Et oui, j'aime pas ne pas trouver de solution à un problème informatique ou au moins savoir pourquoi ça ne fonctionne pas.
le 11 août 2017 à 20:16
Pas de problème, je laisse tes branches ouvertes.
le 11 août 2017 à 20:33
Après réflexion même si on arrive à faire fonctionner les ShareWorkers, je ne pense pas que ce soit une bonne solution car normalement ça ne crée qu'un seul processus pour renvoyer les réponses. Donc ça veut dire que si une page demande une longue analyse, et bien sûr une autre page on ne pourrait avoir le résultat d'une deuxième analyse qu'après que la première soit terminée :s

Donc, je pense qu'il vaut mieux gérer une liste de Workers simple par le background, donc quand un content_script fait son insertion ça crée un nouveau Worker et donc les messages de ce content-script sont gérés par ce Worker. Ça permettra de limiter les risques d'attente en cas d’analyse longue sur plusieurs pages. (On peut même pousser la logique par textarea de la page.)

(Edit: ou on garde le système de l'iframe mais avec des Worker normaux. Comme ça il se détruisent tout seul au changement ou rafraîchissement de la page.)

Voilà ma dernière pensée avant que je sois obligé de partir pour 1 semaine je pense (ou je pourrais sûrement passer de temps en temps ici, mais pas trop de temps pour coder)...
le 11 août 2017 à 22:08

Après réflexion même si on arrive à faire fonctionner les ShareWorkers, je ne pense pas que ce soit une bonne solution car normalement ça ne crée qu'un seul processus pour renvoyer les réponses. Donc ça veut dire que si une page demande une longue analyse, et bien sûr une autre page on ne pourrait avoir le résultat d'une deuxième analyse qu'après que la première soit terminée :s


Il n’y a pas besoin de plus d’un worker dans l’extension pour Firefox.
Sur mon PC, il faut 15 secondes pour passer tous les tests (6300), ce qui inclut deux nouvelles entières (le Horla de Maupassant, et le Double assassinat de la rue Morgue, d’Edgar Poe).
Personne ne peut écrire aussi vite. Personne ne peut analyser la somme des résultats envoyés par le correcteur aussi vite. De très loin. Quel serait l’intérêt de lancer l’analyse de plusieurs de textes en même temps ? Aucun. Et même si l’utilisateur le faisait, ça irait assez vite malgré tout.

Donc, je pense qu'il vaut mieux gérer une liste de Workers simple par le background, donc quand un content_script fait son insertion ça crée un nouveau Worker et donc les messages de ce content-script sont gérés par ce Worker. Ça permettra de limiter les risques d'attente en cas d’analyse longue sur plusieurs pages. (On peut même pousser la logique par textarea de la page.)


La question d’avoir plusieurs workers ne se pose que si on fait un serveur grammatical répondant à de nombreuses demandes en ligne. Mais, dans ce cas, créer un worker par demande serait une erreur. Ça consommerait bien trop de ressources, ne serait-ce qu’en initialisation. Et surtout en mémoire.

Je ne sais pas combien de mémoire Grammalecte consomme, mais à vue de nez au moins 10 Mo par worker à l’initialisation, je pense.

Si tu veux répondre à des demandes intensives, il faut :
— Dresser un “pool” de workers en fonction de la puissance de calcul que tu peux allouer.
— Recueillir les demandes dans une liste d’attente FIFO.
— Passer les demandes aux workers au fur et à mesure que ceux-ci sont libérés de leur tâche.

C’est ce que je ferai avec le serveur en Python quand j’aurai le temps.
le 12 août 2017 à 09:04
Quand je lance le correcteur grammatical en Python et fais tous les tests, ça consomme environ 45 Mo.

D’après Firefox, ça en prend 77 Mo (si je comprends bien ce que ça me raconte). Mais quand je lance les tests, Windows me montre que la consommation de mémoire de Firefox bondit de 140 Mo.

Python consomme donc environ 3 fois moins de mémoire que JavaScript (mais est environ 3 fois plus lent pour faire les mêmes tests).

À mon avis, pour le pool de workers, si tu veux te lancer là-dedans, il faut en faire au maximum (nombre de cœurs du processeur - 1) si la mémoire peut digérer ça.
le 12 août 2017 à 12:28

Notification par e-mail    1