Grammalecte  Check-in [5c14b1c9e0]

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | gcerw
Files: files | file ages | folders
SHA3-256: 5c14b1c9e029f509832e2639c2e2a833568f641afd7c784527e01166fdbd5e6d
User & Date: olr on 2020-04-08 14:07:34
Other Links: branch diff | manifest | tags
Context
2020-04-08
15:00
[graphspell][py] rename lexicographer file check-in: 635140d716 user: olr tags: graphspell, gcerw
14:07
merge trunk check-in: 5c14b1c9e0 user: olr tags: gcerw
13:50
[fx] text area button: don’t show it for editable node that aren’t <p> or <div> check-in: dc0a47993e user: olr tags: trunk, fx
2020-04-06
20:43
[tb][js] update gce_worker check-in: 9fd78a9ee5 user: olr tags: tb, gcerw
Changes

Modified doc/API_web.md from [db743ee983] to [7922180e3c].

65
66
67
68
69
70
71
72
73


74
75
76
77
78
79
80
65
66
67
68
69
70
71


72
73
74
75
76
77
78
79
80







-
-
+
+







### Open the Grammalecte panel for a node

If you have disabled the spinning button, you can launch the Grammalecte panel with your custom button.

    oGrammalecteAPI.openPanelForNode("node_id")
    oGrammalecteAPI.openPanelForNode(node)

The node can be a textarea, an editable node or an iframe.
If the node is an iframe, the content won’t be modified by Grammalecte.
The node can be a textarea, an editable node or an iframe. **The node must have an identifier**.
If the node is an iframe, the content won’t be modified by Grammalecte, but events with results may be received (see below).


### Prevent Grammalecte to modify the node content

If you don’t want Grammalecte to modify directly the node content, add the property: `data-grammalecte_result_via_event="true"`.

With this property, Grammalecte will send an event to the node each times the text is modified within the panel.
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133







-
+







-
+


















-

+








### Open the Grammalecte panel for any text

    oGrammalecteAPI.openPanelForText("your text")
    oGrammalecteAPI.openPanelForText("your text", "node_id")
    oGrammalecteAPI.openPanelForText("your text", node)

With the second parameter, Grammalecte will send an event to the node each times the text is modified within the panel.
With the second parameter, Grammalecte will send an event to the node each times the text is modified within the panel. **The node must have an identifier**.


### Parse a node and get errors

    oGrammalecteAPI.parseNode("node_id")
    oGrammalecteAPI.parseNode(node)

The node can be a textarea, an editable node or an iframe. The node must have an identifier.
The node can be a textarea, an editable node or an iframe. **The node must have an identifier**.
Results (for each paragraph) will be sent in a succession of events at the node.

    node.addEventListener("GrammalecteResult", function (event) {
        const detail = (typeof(event.detail) === 'string') && JSON.parse(event.detail);
        if (detail.sType  &&  detail.sType == "proofreading") {
            let oResult = detail.oResult; // null when the text parsing is finished
            ...
        }
    }

For the last event, `oResult` will be `null`.


### Parse text and get errors

    oGrammalecteAPI.parseText("your text", "node_id")
    oGrammalecteAPI.parseText("your text", node)

The node must have an identifier.
Like with `oGrammalecteAPI.parseNode()`, results (for each paragraph) will be sent in a succession of events at the node.
**The node must have an identifier**.



### Get spelling suggestions

    oGrammalecteAPI.getSpellingSuggestions(word, destination)
    oGrammalecteAPI.getSpellingSuggestions(word, destination, request_identifier)

Modified gc_lang/fr/build.py from [5f4b392f44] to [43a9cad18e].

1
2
3
4
5



6
7
8
9
10
11
12
13

14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
29
30



















31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76





+
+
+








+






-
+









-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
















-
+







# Builder for French language

import os
import platform
import zipfile
import shutil
import json
import traceback
from distutils import dir_util, file_util

import helpers


def build (sLang, dVars):
    "complementary build launched from make.py"
    createWebExtension(sLang, dVars)
    convertWebExtensionForChrome(sLang, dVars)
    createMailExtension(sLang, dVars)
    createNodeJSPackage(sLang)


def createWebExtension (sLang, dVars):
    "create Web-extension"
    print("Building WebExtension")
    print("> Building WebExtension for Firefox")
    helpers.createCleanFolder("_build/webext/"+sLang)
    dir_util.copy_tree("gc_lang/"+sLang+"/webext/", "_build/webext/"+sLang)
    dir_util.copy_tree("grammalecte-js", "_build/webext/"+sLang+"/grammalecte")
    dVars['webextOptionsHTML'] = _createOptionsForWebExtension(dVars)
    helpers.copyAndFileTemplate("_build/webext/"+sLang+"/manifest.json", "_build/webext/"+sLang+"/manifest.json", dVars)
    helpers.copyAndFileTemplate("_build/webext/"+sLang+"/panel/main.html", "_build/webext/"+sLang+"/panel/main.html", dVars)
    with helpers.CD("_build/webext/"+sLang):
        os.system("web-ext build")
    # Copy Firefox zip extension to _build
    helpers.moveFolderContent("_build/webext/"+sLang+"/web-ext-artifacts", "_build", "fx-"+sLang+"-", True)
    helpers.moveFolderContent("_build/webext/"+sLang+"/web-ext-artifacts", "_build", "firefox-", True)


def convertWebExtensionForChrome (sLang, dVars):
    "Create the extension for Chrome"
    print("> Converting WebExtension for Chrome")
    try:
        with open(f"_build/webext/{sLang}/manifest.json", "r", encoding="utf-8") as hSrc:
            dManifest = json.load(hSrc)
            if "applications" in dManifest:
                del dManifest["applications"]
            if "chrome_settings_overrides" in dManifest:
                del dManifest["chrome_settings_overrides"]
        with open(f"_build/webext/{sLang}/manifest.json", "w", encoding="utf-8") as hDst:
            json.dump(dManifest, hDst, ensure_ascii=True, indent=2)
        shutil.make_archive(f"_build/chrome-grammalecte-{sLang}-v{dVars['version']}", 'zip', "_build/webext/"+sLang)
    except:
        traceback.print_exc()
        print("  Error. Converting the WebExtension for Chrome failed.")


def _createOptionsForWebExtension (dVars):
    sHTML = ""
    sLang = dVars['sDefaultUILang']
    for sSection, lOpt in dVars['lStructOpt']:
        sHTML += f'\n<div id="subsection_{sSection}" class="opt_subsection">\n  <h2 data-l10n-id="option_{sSection}">{dVars["dOptLabel"][sLang][sSection][0]}</h2>\n'
        for lLineOpt in lOpt:
            for sOpt in lLineOpt:
                sHTML += f'  <p><input type="checkbox" id="option_{sOpt}" class="gc_option" data-option="{sOpt}"/><label id="option_label_{sOpt}" for="option_{sOpt}" data-l10n-id="option_{sOpt}">{dVars["dOptLabel"][sLang][sOpt][0]}</label></p>\n'
        sHTML += '</div>\n'
    return sHTML


def createMailExtension (sLang, dVars):
    "create extension for Thunderbird (as MailExtension)"
    print("Building extension for Thunderbird (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)

Modified gc_lang/fr/rules.grx from [21c94a6458] to [6a36715a8b].

1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502






1503
1504
1505
1506
1507
1508
1509
1488
1489
1490
1491
1492
1493
1494




1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511







-
-
-
-




+
+
+
+
+
+









## Caractères rares
__<s>/ocr(ocr_caractères_rares)__
    \w*[{}<>&*#£^|]+\w*
        <<- \0 != "<" and \0 != ">" ->> _                                                           # Erreur de numérisation ? Cette chaîne contient un caractère de fréquence rare.

__<s>/ocr(ocr_doublons_caractères_rares)__
    [\]\[({}][\]\[({}]+
        <<- ->> _                                                                                   # Erreur de numérisation ? Succession douteuse de caractères.

TEST: __ocr__ trouve {{l£}} temps
TEST: __ocr__ elle s’{{avance*}} sur le seuil
TEST: __ocr__ {{e||e}} vient
TEST: __ocr__ par beaucoup d’argent ? {{{Il}} débouche le Jack Daniels


__<s>/ocr(ocr_doublons_caractères_rares)__
    [\]\[({}][\]\[({}]+
        <<- ->> _                                                                                   # Erreur de numérisation ? Succession douteuse de caractères.

TEST: __ocr__ {{[[}}voyons celà].
TEST: __ocr__ {{((}}voyons ceci).


## Mélange chiffres/lettres
__[i]/ocr(ocr_le_la_les_regex)__
    [1[\]][easrnxiocuwàéè]
4162
4163
4164
4165
4166
4167
4168
4169

4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185












4186
4187
4188
4189
4190
4191
4192
4164
4165
4166
4167
4168
4169
4170

4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206







-
+
















+
+
+
+
+
+
+
+
+
+
+
+







    >arrière >petit >neveu
        <<- /tu/ ->> arrière-petit-neveu|arrière-petits-neveux      # Mettez des traits d’union.

    >arrière >petit >nièce
        <<- /tu/ ->> arrière-petite-nièce|arrière-petites-nièces    # Mettez des traits d’union.

    [basket|volley] ball
        <<- /tu/ ->> \1-ball                                    # Il manque un trait d’union.
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    bas [>côté|coté|cotés]
        <<- /tu/ morph(<1 , ":D") ->> bas-côté|bas-côtés        # Il manque un trait d’union.

    [les|des|aux] beaux arts
        <<- /tu/ -2:3>> beaux-arts                              # Il manque un trait d’union.

    bouche à [bouche|>oreille]
        <<- /tu/ morph(<1, ":D") ->> \1-\2-\3                   # Il manque les traits d’union.

    >centre >ville
        <<- /tu/ ->> centre-ville|centres-villes                # Il manque un trait d’union.

    [chassé+ses] [croisé+ses]
        <<- /tu/ ->> chassé-croisé|chassés-croisés              # Il manque un trait d’union.

    château fort
        <<- /tu/ not morph(>1, ":A.*:[me]:[si]") ->> \1-\2      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/ch%C3%A2teau-fort

    châteaux forts
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/ch%C3%A2teau-fort

    coffre fort
        <<- /tu/ not morph(>1, ":A.*:[me]:[si]") ->> \1-\2      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/coffre-fort

    coffres forts
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/coffre-fort

    >chef lieu
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    >chef d’ œuvre
        <<- /tu/ ->> \1-\2\3                                    # Il manque un trait d’union.

    [auto|moto] >club
4202
4203
4204
4205
4206
4207
4208
4209

4210
4211
4212
4213
4214
4215
4216
4216
4217
4218
4219
4220
4221
4222

4223
4224
4225
4226
4227
4228
4229
4230







-
+








    face [a|à] face
        <<- /tu/ morph(<1, ":D") ->> face-à-face                # Si vous employez cette locution comme un nom, mettez des traits d’union.|https://fr.wiktionary.org/wiki/face-%C3%A0-face

    gagne >pain
        <<- /tu/ not morph(<1, ":O[sv]") ->> gagne-pain         # Il manque un trait d’union.

    [grand|grands] [>père|>mère]
    [grand+s] [>père|>mère]
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    lèse majesté
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    n [ième+s|ieme+s|ème+s|eme+s]
        <<- /tu/ ->> n-ième|n-ièmes                             # Il manque un trait d’union.
4326
4327
4328
4329
4330
4331
4332




4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357







+
+
+
+







TEST: sur le {{bas côté}}
TEST: les {{beaux arts}}
TEST: {{le}} {{bouche à oreille}}
TEST: {{chef lieu}} de ce canton
TEST: un {{chassé croisé}}
TEST: ne vois-tu pas que c’est un {{chef d’œuvre}} ?
TEST: ils sont allés au {{centre ville}}.
TEST: un {{château fort}} n’est pas une demeure confortable
TEST: des {{châteaux forts}}
TEST: un {{coffre fort}}
TEST: des {{coffres forts}}
TEST: Le {{moto club}} était sur le point de faire faillite.
TEST: J’ai beaucoup de {{déjà vu}}.
TEST: L’{{état major}} n’a pas encore tranché la question.
TEST: Le {{face à face}} entre les forces de l’ordre et les manifestants se poursuit devant l’hôtel de ville à Bordeaux depuis environ 1h30.
TEST: {{gagne pain}} de merde
TEST: mes deux {{grands pères}} sont décédés
TEST: un crime de {{lèse majesté}}
7464
7465
7466
7467
7468
7469
7470
7471

7472
7473
7474
7475
7476
7477
7478
7482
7483
7484
7485
7486
7487
7488

7489
7490
7491
7492
7493
7494
7495
7496







-
+







    les ([elle+s]) [de|des|du|d’]
    [sous|sur] leurs ([elle+s]) [<end>|,|$:R]
        <<- /conf/ -1>> ailes
        # Confusion probable : “elle” est un pronom personnel féminin. Pour les oiseaux, les avions ou les parties d’un bâtiment ou d’une armée, écrivez “aile”.|https://fr.wiktionary.org/wiki/aile

    [elle+s] ?[droite|gauche]¿ du [château|palais|bâtiment|manoir]
    [elle+s] ?[droite|gauche]¿ [de|d’] la [maison|ferme]
        <<- /conf/ -1>> aile|ailes
        <<- /conf/ morph(<1, "<start>|,|:D") -1>> aile|ailes
        # Confusion probable : “elle” est un pronom personnel féminin. Pour les oiseaux, les avions ou les parties d’un bâtiment ou d’une armée, écrivez “aile”.|https://fr.wiktionary.org/wiki/aile

TEST: l’{{elle}} est en feu.
TEST: sous l’{{elle}} de sa mère, il ne craint rien
TEST: sur son {{elle}} droite
TEST: des {{elles}} enduites de pétrole
TEST: De l’autre côté du mur, dans l’{{elle}} réservée aux femmes, il y a des jeunes filles dont nul n’a parlé
8009
8010
8011
8012
8013
8014
8015
8016

8017
8018
8019

8020
8021
8022
8023
8024
8025
8026
8027
8028
8029
8030
8031
8032
8033

8034
8035
8036

8037
8038
8039
8040
8041
8042
8043
8044







-
+


-
+








TEST: ce sont des durs à {{cuir}}
TEST: Quelle dure {{a}} {{cuir}}, celle-là.


# dans / d’en
__conf_dans_dan_d_en__
    d’ en [le|la|l’|les|de|d’|des|du|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces]
    d’ en [le|la|l’|les|de|d’|des|du|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces|chacun|plusieurs|quelques|certains|certaines]
        <<- /conf/ not (\3 == "ce" and value(>1, "|moment|")) -1:2>> dans           # Confusion. Utilisez “dans” pour dire “à l’intérieur de quelque chose”.

    <start>  [>dent|dan]  [le|la|l’|les|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces]
    <start>  [>dent|dan]  [le|la|l’|les|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces|chacun|plusieurs|quelques|certains|certaines]
        <<- /conf/ -2>> dans                                                        # Confusion. Utilisez “dans” pour dire “à l’intérieur de quelque chose”.

TEST: {{dan}} la voiture
TEST: ils sont partis {{d’en}} une direction différente
TEST: {{dents}} les montagnes au loin.
TEST: Dents de la mer.
TEST: Un pauvre, ça doit consommer, bosser, et bien fermer sa gueule. Tout l’inverse d’en ce moment.
11564
11565
11566
11567
11568
11569
11570
11571
11572
11573
11574
11575
11576
11577
11578
11579
11580










11581
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591
11592










11593
11594
11595
11596
11597
11598
11599
11582
11583
11584
11585
11586
11587
11588










11589
11590
11591
11592
11593
11594
11595
11596
11597
11598
11599
11600










11601
11602
11603
11604
11605
11606
11607
11608
11609
11610
11611
11612
11613
11614
11615
11616
11617







-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+


-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+







    mois        [après|par]     mois
    décennie    [après|par]     décennie
    année       [après|par]     année
    siècle      [après|par]     siècle
    génération  [après|par]     génération
        <<- ~>> *

    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   [du|ce]  [matin|soir]
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   de  l’ après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   cet  après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   [du|ce]  [matin|soir]
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   de  l’ après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   cet  après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   [demain|hier]  ?[matin|soir|après-midi]¿
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [du|ce]  [matin|soir]
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   de  l’ après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   cet  après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [du|ce]  [matin|soir]
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   de  l’ après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   cet  après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [demain|hier]  ?[matin|soir|après-midi]¿
        <<- ~>> *

    [à|de]      *HOUR
    [à|de]      *HOUR  [du|ce]  [matin|soir]
    [à|de]      *HOUR  de  l’ après-midi
    [à|de]      *HOUR  cet  après-midi
    [à|de]      *HOUR  [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    *HOUR
    jusqu’ à    *HOUR  [du|ce]  [matin|soir]
    jusqu’ à    *HOUR  de  l’ après-midi
    jusqu’ à    *HOUR  cet  après-midi
    jusqu’ à    *HOUR  [demain|hier]  ?[matin|soir|après-midi]¿
    [à|de]      *HOUR  ?[tapantes|pétantes]¿
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  [du|ce]  [matin|soir]
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  de  l’ après-midi
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  cet  après-midi
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  [du|ce]  [matin|soir]
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  de  l’ après-midi
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  cet  après-midi
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  [demain|hier]  ?[matin|soir|après-midi]¿
        <<- ~>> *

TEST: Le train de 2 h 47 {{arriveraient}} en retard.
TEST: Le train de 2 h 47 du matin {{arriveraient}} en retard.
TEST: Le train de 2h47 du matin {{arriveraient}} en retard.


13455
13456
13457
13458
13459
13460
13461

13462
13463
13464
13465
13466
13467
13468
13473
13474
13475
13476
13477
13478
13479
13480
13481
13482
13483
13484
13485
13486
13487







+







    >chasseur [de|d’] primes
    >chemin [de|d’] [traverse|fer]
    >chemise [de|d’] nuit
    >chemise sans >manche
    >chèque sans provision
    >chili con carne
    >chou à la crème ?[fouettée|diplomate|mousseline|patissière|pralinée]¿
    >cité u
    >clair comme [de|d’] l’ eau [de|d’] [boudin|roche|source]
    >clair comme du cristal
    >clair comme jus [de|d’] [boudin|>chaussette|chique]
    >classement sans suite
    [>clé|>clef] à molette
    >clin d’ œil
    >clause [de|d’] [confidentialité|non-concurrence]
13703
13704
13705
13706
13707
13708
13709

13710
13711
13712
13713
13714
13715
13716
13722
13723
13724
13725
13726
13727
13728
13729
13730
13731
13732
13733
13734
13735
13736







+







    [réglé+ses] comme du papier à musique
    >règlement [de|d’] comptes
    [remis+es] à plat
    >requête en nullité
    >requête en non [conciliation|inscription|lieu]
    >requête en non révocation [de|d’] sursis
    >responsable qualité
    [>resto|>restau] u
    >retour à la case départ
    >rivière à sec
    >robe [de|d’] [chambre|soirée]
    >robe du soir
    >robe sans >manche
    >roman à l’ eau [de|d’] rose
    >roue [avant|arrière]
18887
18888
18889
18890
18891
18892
18893
18894

18895
18896
18897
18898
18899
18900



18901
18902
18903
18904
18905
18906
18907
18908
18909
18910
18911
18912
18913
18914

18915
18916
18917

18918
18919
18920
18921
18922
18923
18924
18907
18908
18909
18910
18911
18912
18913

18914
18915
18916
18917
18918
18919
18920
18921
18922
18923
18924
18925
18926
18927
18928
18929
18930
18931
18932
18933
18934
18935
18936
18937
18938
18939
18940
18941
18942
18943
18944
18945
18946
18947
18948
18949







-
+






+
+
+














+



+







__conf_pâte_patte_pat__
    [>patte|pat] [>alimentaire|>alsacien|>chinois|>feuilleté|>italien|>thermique]
    [>patte|pat] au [basilic|beurre|saumon|pesto|poulet|thon]
    [>patte|pat] [à|a] [>pain|>crêpe|>gaufre|>pizza|>tarte|>modeler|>tartiner]
    [>patte|pat] [d’|de] [>amande|>amende|>fruit]
        <<- /conf/ -1>> pâte|pâtes                              # Confusion. La patte est le membre d’un animal (ou d’une table…). La matière pâteuse s’écrit “pâte”.

    >mettre ?[pas|jamais]¿ la main à la [>patte|pat]
    >mettre la main à [la|cette] [>patte|pat]
    >coq en [>patte|pat]
        <<- /conf/ --1>> pâte                                   # Confusion. La patte est le membre d’un animal (ou d’une table…). La matière pâteuse s’écrit “pâte”.

    >coup de [>pâte|pat]
        <<- /conf/ -3>> patte                                   # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

    >montrer [>pâte|pat] [blanche+s]
        <<- /conf/ -2:3>> patte blanche                         # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

    >retomber sur [mes|tes|ses|ces|nos|vos|leur|leurs] [>pâte|pat]
        <<- /conf/ --1>> pattes                                 # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

    >court sur [>pâte|pat]
        <<- /conf/ --1>> pattes                                 # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

TEST: Prépare la {{patte}} à tarte.
TEST: Ils mangent souvent des {{pattes}} au thon.
TEST: Des {{pattes}} alimentaires.
TEST: Elles ont acheté de la {{patte}} à tartiner.
TEST: La {{patte}} à pizza est plus épaisse que la pâte à crêpes.
TEST: Elle adore la {{patte}} d’amande.
TEST: Il est comme un coq en {{pattes}} là.
TEST: Elle n’a jamais mis la main à la {{patte}}.
TEST: ne mets jamais la main à la {{patte}}
TEST: donne-moi un coup de {{pâte}}
TEST: elle retombe toujours sur ses {{pâtes}}.
TEST: il est court sur {{pâtes}}
TEST: elle va montrer {{pâte blanche}} et tout ira bien.


# péché / pêcher
__conf_péché_pêcher2__
    >pêcher par excès [de|d’]
    >pêcher par [insuffisance|omission|orgueil]
        <<- /conf/ -1>> pécher                                  # Confusion : pêcher (capturer des poissons) ≠ pécher (faire un écart de conduite).|https://fr.wiktionary.org/wiki/p%C3%A9cher
19234
19235
19236
19237
19238
19239
19240


















19241
19242
19243
19244
19245
19246
19247
19259
19260
19261
19262
19263
19264
19265
19266
19267
19268
19269
19270
19271
19272
19273
19274
19275
19276
19277
19278
19279
19280
19281
19282
19283
19284
19285
19286
19287
19288
19289
19290







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








    [>être|>demeurer|>rester|>devenir]  >septique
        <<- /conf/ not morph(<1, ">plaie/") -2>> =\2.replace("sep", "scep")     # Confusion possible. Septique = corrompu, infecté. Sceptique = ayant des doutes.

TEST: cette fosse {{sceptique}} est pleine.
TEST: Je suis {{septique}} !


## se / ce
__conf_ce_se_nom__
    [de|par|pour|sans]  se  *WORD
        <<- /conf/ analyse(\3, ":N.*:[me]:[si]", ":Y") -2>> ce                  # Confusion probable. Si “\-1” est bien un nom ou un adjectif, alors écrivez “ce”.

    <start>  se  *WORD  [ne|n’|me|m’|te|t’|se|s’]
    <start>  se  *WORD  [le|la|l’|les|en|nous|vous|lui|leur|y]  @:(?:[123][sp]|P)¬:G
    <start>  se  *WORD  [nous|vous]     [le|la|l’|les|en|y]     @:(?:[123][sp]|P)
    <start>  se  *WORD  [le|la|l’|les]  [lui|leur|en|y]         @:(?:[123][sp]|P)
    <start>  se  *WORD  [lui|leur|y]    en                      @:(?:[123][sp]|P)
    <start>  se  *WORD  @:(?:[123][sp]|P)¬:G
        <<- /conf/ analyse(\3, ":[NA]", ":Y") -2>> ce                           # Confusion probable. Si “\3” est bien un nom ou un adjectif, alors écrivez “ce”.

TEST: que sais-tu de {{se}} {{type}}
TEST: {{se}} type nous emmerde.                                         ->> ce
TEST: se doit d’être fort, ce con, sinon c’est la fin pour lui.


## soit / soie / soi
__conf_aller_de_soi__
    >aller de [sois|>soie]
        <<- /conf/ -3>> soi                                 # Confusion.|https://fr.wiktionary.org/wiki/aller_de_soi

    >aller ?[pas|jamais|guère]¿ de soit
19307
19308
19309
19310
19311
19312
19313















19314
19315
19316
19317
19318
19319
19320
19321


19322
19323
19324
19325
19326
19327
19328
19350
19351
19352
19353
19354
19355
19356
19357
19358
19359
19360
19361
19362
19363
19364
19365
19366
19367
19368
19369
19370
19371
19372
19373
19374
19375
19376
19377
19378
19379
19380
19381
19382
19383
19384
19385
19386
19387
19388







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








+
+







    >tacher  [de|d’]  ?[le|la|l’|les|en|nous|vous|lui|leur|y]¿  $:Y
    >tacher  [de|d’]  [nous|vous]     [le|la|l’|les|en|y]       $:Y
    >tacher  [de|d’]  [le|la|l’|les]  [lui|leur|en|y]           $:Y
    >tacher  [de|d’]  [lui|leur]      en                        $:Y
        <<- /conf/ -1>> =\1.replace("a", "â").replace("A", "Â")
        # Confusion. Tache signifie faire une salissure, une altération, une marque, une coloration… Pour parler de l’accomplissement d’un travail, écrivez “tâcher”.

    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [ne|n’|me|m’|te|t’|se|s’]
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [le|la|l’|les|en|nous|vous|lui|leur|y]  @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [nous|vous]     [le|la|l’|les|en|y]     @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [le|la|l’|les]  [lui|leur|en|y]         @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [lui|leur|y]    en                      @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [ne|n’|me|m’|te|t’|se|s’]
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [le|la|l’|les|en|nous|vous|lui|leur|y]  @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [nous|vous]     [le|la|l’|les|en|y]     @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [le|la|l’|les]  [lui|leur|en|y]         @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [lui|leur|y]    en                      @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    @:(?:Y|V1.*:Q)
        <<- /conf/ morph(\2, ":D", ":R") -3>> =\3.replace("ach", "âch").replace("ACH", "ÂCH")
        # Confusion. Une tache est une salissure, une altération, une marque, une coloration… Pour parler d’un travail à accomplir, écrivez “tâche”.

TEST: Quelle {{tache}} ingrate.
TEST: Une {{tache}} valorisante.
TEST: Elle se tue à la {{tache}}.
TEST: Il a accompli la {{tache}} facilement.
TEST: {{Tache}} de partir tôt.
TEST: {{Tachez}} d’arriver à l’heure.
TEST: {{Tache}} de ne pas faire trop de bruit.
TEST: se tuer à la {{tache}}
TEST: leur {{tache}} consiste à obéir et à fermer leur gueule
TEST: ma {{tache}} est d’accomplir ce que personne d’autre ne peut faire.
TEST: une tâche dévalorisante.
TEST: peiner à la tâche.


# taule / tôle
__conf_taule_tôle2__
    [>aller|>finir] en [>tôle|>tole]
23065
23066
23067
23068
23069
23070
23071

23072

23073
23074
23075
23076
23077

23078

23079
23080
23081
23082
23083
23084
23085
23125
23126
23127
23128
23129
23130
23131
23132

23133
23134
23135
23136
23137
23138
23139

23140
23141
23142
23143
23144
23145
23146
23147







+
-
+





+
-
+








    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  [ne|n’|me|m’|te|s’|se|s’]
    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  [le|la|l’|les|leur]  @:[123][sp]¬:[QNAG]
    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  ?[nous|vous]¿        @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[pi]", True)                                   # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.

    [<start>|,|(] certains        @:V¬:[NAY]  [me|m’|te|s’|se|s’]
    [<start>|,|(] certains        @:V¬:[NAY]  [ne|n’|me|m’|te|s’|se|s’]
    [<start>|,|(] certains        @:V¬:[NAY]  [ne|n’]                     @:[123][sp]
    [<start>|,|(] certains        @:V¬:[NAY]  [le|la|l’|les|leur]         @:[123][sp]¬:[QNAG]
    [<start>|,|(] certains        @:V¬:[NAY]  ?[nous|vous]¿               @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[me]:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[me]:[pi]", True)                              # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.

    [<start>|,|(] certaines       @:V¬:[NAY]  [me|m’|te|s’|se|s’]
    [<start>|,|(] certaines       @:V¬:[NAY]  [ne|n’|me|m’|te|s’|se|s’]
    [<start>|,|(] certaines       @:V¬:[NAY]  [ne|n’]                     @:[123][sp]
    [<start>|,|(] certaines       @:V¬:[NAY]  [le|la|l’|les|leur]         @:[123][sp]¬:[QNAG]
    [<start>|,|(] certaines       @:V¬:[NAY]  ?[nous|vous]¿               @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[fe]:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[fe]:[pi]", True)                              # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.

TEST: Un {{défie}} se définit par la difficulté                 ->> défi
TEST: Le {{défit}} ne l’enthousiasmait pas.                     ->> défi
23095
23096
23097
23098
23099
23100
23101

23102
23103
23104
23105
23106
23107
23108
23157
23158
23159
23160
23161
23162
23163
23164
23165
23166
23167
23168
23169
23170
23171







+







TEST: Les amener n’apportait que des problèmes.
TEST: Le prendre par surprise était difficile.
TEST: La consigner devenait une obligation.
TEST: Les reconnaître semblait nécessaire.
TEST: Son ministre du Budget, Gérald Darmanin, l’avait dit plus crûment sur RTL
TEST: Certains jouent la carte de la dérision
TEST: Certains font grève tous les vendredis pour soutenir cette cause.
TEST: Certains confient ne pas avoir mangé depuis deux ou trois jours


__conf_suj_verbe_det_verbe_nom__
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   ?[le|la|l’|les|en|me|m’|te|t’|se|s’|nous|vous|lui|leur|y]¿  @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [me|m’|te|t’|se|s’|nous|vous]   [le|la|l’|les|en|y]         @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [le|la|l’|les]                  [lui|leur|en|y]             @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [lui|leur]                      en                          @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]

Modified gc_lang/fr/webext/content_scripts/api.js from [184dcb850a] to [0dfb85fb05].

1
2
3
4
5
6
7
8
9
10






11
12
13
14
15



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36



37
38
39
40
41
42
43
44
45
46
47
48
49



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65



66
67
68
69
70
71
72
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74


75
76
77
78
79
80
81
82
83
84










+
+
+
+
+
+



-
-
+
+
+















-
-
+
+




+
+
+











-
-
+
+
+














-
-
+
+
+







// JavaScript

"use strict";


const oGrammalecteAPI = {
    // functions callable from within pages
    // to be sent to the content-cript via an event “GrammalecteCall”

    sVersion: "1.0",

    generateNodeId: function (xNode) {
        xNode.id = "grammalecte_generated_id_" + Date.now().toString(36) + "_" + (Math.floor(Math.random() * (1000000))).toString(36);
        console.log("[Grammalecte API] generated id:", xNode.id);
        return xNode.id;
    },

    openPanelForNode: function (vNode) {
        //  Parameter: a HTML node or the identifier of a HTML node
        if (vNode instanceof HTMLElement && vNode.id) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForNode", sNodeId: vNode.id}) });
        if (vNode instanceof HTMLElement) {
            let sNodeId = vNode.id || this.generateNodeId(vNode);
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForNode", sNodeId: sNodeId}) });
            document.dispatchEvent(xEvent);
        }
        else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForNode", sNodeId: vNode}) });
            document.dispatchEvent(xEvent);
        }
        else {
            console.log("[Grammalecte API] Error: parameter is not a HTML node with an identifier.");
        }
    },

    openPanelForText: function (sText, vNode=null) {
        //  Parameter: text to analyze, and optionaly a node to send results to.
        if (typeof(sText) === "string") {
            let sNodeId = "";
            if (vNode instanceof HTMLElement && vNode.id) {
                sNodeId = vNode.id;
            if (vNode instanceof HTMLElement) {
                sNodeId = vNode.id || this.generateNodeId(vNode);
            }
            else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
                sNodeId = vNode;
            }
            else {
                console.log("[Grammalecte API] No node identifier. No event, no result will be sent.")
            }
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForText", sText: sText, sNodeId: sNodeId}) });
            document.dispatchEvent(xEvent);
        } else {
            console.log("[Grammalecte API] Error: parameter is not a text.");
        }
    },

    parseNode: function (vNode) {
        /*  Parameter: a HTML node (with a identifier) or the identifier of a HTML node.
            The result will be sent as an event “GrammalecteResult” to the node.
        */
        if (vNode instanceof HTMLElement  &&  vNode.id) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseNode", sNodeId: vNode.id}) });
        if (vNode instanceof HTMLElement) {
            let sNodeId = vNode.id || this.generateNodeId(vNode);
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseNode", sNodeId: sNodeId}) });
            document.dispatchEvent(xEvent);
        }
        else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseNode", sNodeId: vNode}) });
            document.dispatchEvent(xEvent);
        }
        else {
            console.log("[Grammalecte API] Error: parameter is not a HTML node with an identifier.");
        }
    },

    parseText: function (sText, vNode) {
        //  Parameter: text to analyze, and a node to send results to.
        if (typeof(sText) === "string") {
            if (vNode instanceof HTMLElement  &&  vNode.id) {
                let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseText", sText: sText, sNodeId: vNode.id}) });
            if (vNode instanceof HTMLElement) {
                let sNodeId = vNode.id || this.generateNodeId(vNode);
                let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseText", sText: sText, sNodeId: sNodeId}) });
                document.dispatchEvent(xEvent);
            }
            else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
                let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseText", sText: sText, sNodeId: vNode}) });
                document.dispatchEvent(xEvent);
            }
            else {

Modified gc_lang/fr/webext/content_scripts/init.js from [d05c6e1179] to [56313a38a6].

468
469
470
471
472
473
474

475
476






477
478
479
480
481
482
483
468
469
470
471
472
473
474
475


476
477
478
479
480
481
482
483
484
485
486
487
488







+
-
-
+
+
+
+
+
+







        switch (oCommand.sCommand) {
            case "openPanelForNode":
                if (oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    oGrammalecte.startGCPanel(document.getElementById(oCommand.sNodeId));
                }
                break;
            case "openPanelForText":
                if (oCommand.sText) {
                if (oCommand.sText && oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    oGrammalecte.startGCPanel(oCommand.sText, document.getElementById(oCommand.sNodeId));
                    if (oCommand.sText && oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                        oGrammalecte.startGCPanel(oCommand.sText, document.getElementById(oCommand.sNodeId));
                    }
                    else {
                        oGrammalecte.startGCPanel(oCommand.sText);
                    }
                }
                break;
            case "parseNode":
                if (oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    let xNode = document.getElementById(oCommand.sNodeId);
                    if (xNode.tagName == "TEXTAREA"  ||  xNode.tagName == "INPUT") {
                        oGrammalecteBackgroundPort.parseAndSpellcheck(xNode.value, oCommand.sNodeId);

Modified gc_lang/fr/webext/content_scripts/menu.js from [562aee0f70] to [1c8166f9c8].

1
2
3
4
5
6
7

8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15







+







// JavaScript

/* jshint esversion:6, -W097 */
/* jslint esversion:6 */
/* global oGrammalecte, showError, window, document */

"use strict";


class GrammalecteButton {

    constructor () {
        // the pearl button
        this.xButton = oGrammalecte.createNode("div", { className: "grammalecte_menu_main_button", textContent: " " });
        this.xButton.onclick = () => {
35
36
37
38
39
40
41

42
43
44
45

46
47
48
49
50
51




52
53
54
55
56
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72








73
74
75
76
77
78
79
36
37
38
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67



68

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90







+



-
+






+
+
+
+










-
-
-
+
-







+
+
+
+
+
+
+
+







            this._bEditableNode = oOptions.ui_options.editablenode;
        }
    }

    examineNode (xNode) {
        if (xNode && xNode instanceof HTMLElement) {
            if (xNode === this.xTextNode) {
                this.move();
                return;
            }
            if ( ( (xNode.tagName == "TEXTAREA" && this._bTextArea && xNode.getAttribute("spellcheck") !== "false")
                    || (xNode.isContentEditable && this._bEditableNode)
                    || ( (xNode.tagName == "P" || xNode.tagName == "DIV") && xNode.isContentEditable && this._bEditableNode )
                    || (xNode.tagName == "IFRAME" && this._bIframe) )
                    && xNode.style.display !== "none" && xNode.style.visibility !== "hidden"
                    && !(xNode.dataset.grammalecte_button  &&  xNode.dataset.grammalecte_button == "false") ) {
                this.xTextNode = xNode;
                this.show()
            }
            else {
                this.xTextNode = null;
                this.hide();
            }
        }
        else {
            this.xTextNode = null;
            this.hide();
        }
    }

    show () {
        if (this.xTextNode) {
            this.xButton.style.display = "none"; // we hide it before showing it again to relaunch the animation
            let oCoord = oGrammalecte.getElementCoord(this.xTextNode);
            //console.log("top:", oCoord.left, "bottom:", oCoord.top, "left:", oCoord.bottom, "right:", oCoord.right);
            this.xButton.style.top = `${oCoord.bottom}px`;
            this.move();
            this.xButton.style.left = `${oCoord.left}px`;
            this.xButton.style.display = "block";
        }
    }

    hide () {
        this.xButton.style.display = "none";
    }

    move () {
        if (this.xTextNode) {
            let oCoord = oGrammalecte.getElementCoord(this.xTextNode);
            this.xButton.style.top = `${oCoord.bottom}px`;
            this.xButton.style.left = `${oCoord.left}px`;
        }
    }

    insertIntoPage () {
        this.bShadow = document.body.createShadowRoot || document.body.attachShadow;
        if (this.bShadow) {
            this.xShadowBtn = oGrammalecte.createNode("div", { style: "display:none; position:absolute; width:0; height:0;" });
            this.xShadowBtnNode = this.xShadowBtn.attachShadow({ mode: "open" });
            oGrammalecte.createStyle("content_scripts/menu.css", null, this.xShadowBtnNode);

Modified gc_lang/fr/webext/content_scripts/panel.js from [98261d40f5] to [8de62f65f5].

15
16
17
18
19
20
21

22
23
24
25
26
27
28
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29







+







        this.nWidth = nWidth;
        this.nHeight = nHeight;
        this.bFlexible = bFlexible;
        this.bHorizStrech = false;
        this.bVertStrech = false;
        this.nPositionX = 2;
        this.nPositionY = 2;
        this.bOpened = false;
        this.bWorking = false;

        this.bShadow = document.body.createShadowRoot || document.body.attachShadow;
        if (this.bShadow) {
            this.xShadowPanel = oGrammalecte.createNode("div", {id: this.sId+"_shadow", style: "width:0;height:0;"});
            this.xShadow = this.xShadowPanel.attachShadow({mode: "open"});
            this.xParent = this.xShadow;
140
141
142
143
144
145
146

147
148
149
150

151
152
153
154
155
156
157
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160







+




+







            }
            document.body.appendChild(this.xPanel);
        }
    }

    show () {
        this.xPanel.style.display = "flex";
        this.bOpened = true;
    }

    hide () {
        this.xPanel.style.display = "none";
        this.bOpened = false;
    }

    center () {
        this.nPosition = 5;
        this.setSizeAndPosition();
    }

Modified gc_lang/fr/webext/content_scripts/panel_gc.js from [e6011e0390] to [a5deafa9f3].

271
272
273
274
275
276
277



278
279
280
281


282
283
284
285
286
287
288



289
290
291
292
293
294
295
271
272
273
274
275
276
277
278
279
280
281
282
283

284
285
286


287
288
289
290
291
292
293
294
295
296
297
298
299
300







+
+
+



-
+
+

-
-




+
+
+







    }

    endTimer () {
        window.clearTimeout(this.nTimer);
    }

    recheckParagraph (iParaNum) {
        if (!this.bOpened) {
            return;
        }
        let sParagraphId = "grammalecte_paragraph" + iParaNum;
        let xParagraph = this.xParent.getElementById(sParagraphId);
        this._blockParagraph(xParagraph);
        let sText = this.purgeText(xParagraph.textContent);
        //let sText = this.purgeText(xParagraph.textContent);
        let sText = this.oTextControl.getParagraph(iParaNum);
        oGrammalecteBackgroundPort.parseAndSpellcheck1(sText, "__GrammalectePanel__", sParagraphId);
        this.oTextControl.setParagraph(iParaNum, sText);
        this.oTextControl.write();
    }

    refreshParagraph (sParagraphId, oResult) {
        // function called when results are sent by the Worker
        if (!this.bOpened) {
            return;
        }
        try {
            let xParagraph = this.xParent.getElementById(sParagraphId);
            // save caret position
            let [nStart, nEnd] = oGrammalecte.getCaretPosition(xParagraph);
            xParagraph.dataset.caret_position_start = nStart;
            xParagraph.dataset.caret_position_end = nEnd;
            // erase texte
401
402
403
404
405
406
407



408
409

410
411
412
413
414
415
416
406
407
408
409
410
411
412
413
414
415
416

417
418
419
420
421
422
423
424







+
+
+

-
+







        try {
            let sErrorId = this.xParent.getElementById(sNodeSuggId).dataset.error_id;
            //let sParaNum = sErrorId.slice(0, sErrorId.indexOf("-"));
            let xNodeErr = this.xParent.getElementById("grammalecte_err" + sErrorId);
            xNodeErr.textContent = this.xParent.getElementById(sNodeSuggId).textContent;
            xNodeErr.className = "grammalecte_error_corrected";
            xNodeErr.removeAttribute("style");
            let iParaNum = parseInt(sErrorId.slice(0, sErrorId.indexOf("-")), 10);
            this.oTextControl.setParagraph(iParaNum, this.purgeText(this.xParent.getElementById("grammalecte_paragraph" + iParaNum).textContent));
            this.oTextControl.write();
            this.oTooltip.hide();
            this.recheckParagraph(parseInt(sErrorId.slice(0, sErrorId.indexOf("-")), 10));
            this.recheckParagraph(iParaNum);
        }
        catch (e) {
            showError(e);
        }
    }

    ignoreError (sIgnoreButtonId) {  // ignore
1024
1025
1026
1027
1028
1029
1030




1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043

1044
1045
1046

1047
1048
1049
1050
1051

1052
1053
1054
1055

1056

1057
1058
1059
1060
1061
1062

1063
1064
1065
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054

1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077

1078
1079
1080
1081







+
+
+
+












-
+



+





+




+

+





-
+



    getText () {
        return [...this.dParagraph.values()].join("\n").normalize("NFC");
    }

    setParagraph (iParagraph, sText) {
        this.dParagraph.set(iParagraph, sText);
    }

    getParagraph (iParaNum) {
        return this.dParagraph.get(iParaNum);
    }

    eraseNodeContent () {
        while (this.xNode.firstChild) {
            this.xNode.removeChild(this.xNode.firstChild);
        }
    }

    write () {
        if (this.xNode !== null) {
            if (this.bResultInEvent) {
                const xEvent = new CustomEvent("GrammalecteResult", { detail: JSON.stringify({ sType: "text", sText: this.getText() }) });
                this.xNode.dispatchEvent(xEvent);
                //console.log("Text to xNode:", xEvent.detail);
                console.log("[Grammalecte debug] Text sent to xNode via event:", xEvent.detail);
            }
            else if (this.bTextArea) {
                this.xNode.value = this.getText();
                console.log("[Grammalecte debug] text written in textarea:", this.getText());
            }
            else if (this.bIframe) {
                //console.log(this.getText());
            }
            else {
                let sText = "";
                this.eraseNodeContent();
                this.dParagraph.forEach((val, key) => {
                    this.xNode.appendChild(document.createTextNode(val.normalize("NFC")));
                    this.xNode.appendChild(document.createElement("br"));
                    sText += val.normalize("NFC") + "\n";
                });
                console.log("[Grammalecte debug] text written in editable node:", sText);
            }
        }
        else if (this.xResultNode !== null) {
            const xEvent = new CustomEvent("GrammalecteResult", { detail: JSON.stringify({ sType: "text", sText: this.getText() }) });
            this.xResultNode.dispatchEvent(xEvent);
            //console.log("Text to xResultNode:", xEvent.detail);
            console.log("[Grammalecte debug] Text sent to xResultNode via event:", xEvent.detail);
        }
    }
}

Modified graphspell-js/char_player.js from [53774aa734] to [14e0bd8318].

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80










81
82
83
84
85
86
87
64
65
66
67
68
69
70










71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87







-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+







    aConsonant: new Set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ"),
    aDouble: new Set("bcdfjklmnprstzBCDFJKLMNPRSTZ"),  // letters that may be used twice successively


    // Similar chars

    d1to1: new Map([
        ["1", "liîLIÎ"],
        ["2", "zZ"],
        ["3", "eéèêEÉÈÊ"],
        ["4", "aàâAÀÂ"],
        ["5", "sgSG"],
        ["6", "bdgBDG"],
        ["7", "ltLT"],
        ["8", "bB"],
        ["9", "gbdGBD"],
        ["0", "oôOÔ"],
        ["1", "1liîLIÎ"],
        ["2", "2zZ"],
        ["3", "3eéèêEÉÈÊ"],
        ["4", "4aàâAÀÂ"],
        ["5", "5sgSG"],
        ["6", "6bdgBDG"],
        ["7", "7ltLT"],
        ["8", "8bB"],
        ["9", "9gbdGBD"],
        ["0", "0oôOÔ"],

        ["a", "aAàÀâÂáÁäÄāĀæÆ"],
        ["A", "AaÀàÂâÁáÄäĀāÆæ"],
        ["à", "aAàÀâÂáÁäÄāĀæÆ"],
        ["À", "AaÀàÂâÁáÄäĀāÆæ"],
        ["â", "aAàÀâÂáÁäÄāĀæÆ"],
        ["Â", "AaÀàÂâÁáÄäĀāÆæ"],
285
286
287
288
289
290
291


292
293
294
295
296
297
298
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300







+
+







        ["AE", ["Æ", "É"]],
        ["ai", ["ei", "é", "è", "ê", "ë"]],
        ["AI", ["EI", "É", "È", "Ê", "Ë"]],
        ["ei", ["ai", "é", "è", "ê", "ë"]],
        ["EI", ["AI", "É", "È", "Ê", "Ë"]],
        ["ch", ["sh", "c", "ss"]],
        ["CH", ["SH", "C", "SS"]],
        ["ck", ["qu", "q"]],
        ["CK", ["QU", "Q"]],
        ["ct", ["x", "cc"]],
        ["CT", ["X", "CC"]],
        ["oa", ["oi",]],
        ["OA", ["OI",]],
        ["oe", ["œ",]],
        ["OE", ["Œ",]],
        ["oi", ["oa", "oie"]],

Modified graphspell-js/suggest.js from [b9786704df] to [64a0045832].

26
27
28
29
30
31
32


33
34
35
36
37
38
39
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41







+
+







        ["mns", "min"],
        ["parce-que", "parce que"],
        ["pcq", "parce que"],
        ["pd", "pendant|pédé"],
        ["pdq", "pendant que"],
        ["pdt", "pendant"],
        ["pdtq", "pendant que"],
        ["pécunier", "pécuniaire"],
        ["pécuniers", "pécuniaires"],
        ["pk", "pourquoi"],
        ["pkoi", "pourquoi"],
        ["pq", "pourquoi|PQ"],
        ["prq", "presque"],
        ["prsq", "presque"],
        ["qcq", "quiconque"],
        ["qd", "quand"],

Modified graphspell/char_player.py from [820a4d128a] to [56f265c6d5].

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67










68
69
70
71
72
73
74
51
52
53
54
55
56
57










58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74







-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+







aConsonant = set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ")
aDouble = set("bcdfjklmnprstzBCDFJKLMNPRSTZ")  # letters that may be used twice successively


# Similar chars

d1to1 = {
    "1": "liîLIÎ",
    "2": "zZ",
    "3": "eéèêEÉÈÊ",
    "4": "aàâAÀÂ",
    "5": "sgSG",
    "6": "bdgBDG",
    "7": "ltLT",
    "8": "bB",
    "9": "gbdGBD",
    "0": "oôOÔ",
    "1": "1liîLIÎ",
    "2": "2zZ",
    "3": "3eéèêEÉÈÊ",
    "4": "4aàâAÀÂ",
    "5": "5sgSG",
    "6": "6bdgBDG",
    "7": "7ltLT",
    "8": "8bB",
    "9": "9gbdGBD",
    "0": "0oôOÔ",

    "a": "aAàÀâÂáÁäÄāĀæÆ",
    "A": "AaÀàÂâÁáÄäĀāÆæ",
    "à": "aAàÀâÂáÁäÄāĀæÆ",
    "À": "AaÀàÂâÁáÄäĀāÆæ",
    "â": "aAàÀâÂáÁäÄāĀæÆ",
    "Â": "AaÀàÂâÁáÄäĀāÆæ",
273
274
275
276
277
278
279


280
281
282
283
284
285
286
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288







+
+







    "AE": ("Æ", "É"),
    "ai": ("ei", "é", "è", "ê", "ë"),
    "AI": ("EI", "É", "È", "Ê", "Ë"),
    "ei": ("ai", "é", "è", "ê", "ë"),
    "EI": ("AI", "É", "È", "Ê", "Ë"),
    "ch": ("sh", "c", "ss"),
    "CH": ("SH", "C", "SS"),
    "ck": ("qu", "q"),
    "CK": ("QU", "Q"),
    "ct": ("x", "cc"),
    "CT": ("X", "CC"),
    "gg": ("gu",),
    "GG": ("GU",),
    "gu": ("gg",),
    "GU": ("GG",),
    "oa": ("oi",),

Modified graphspell/fr.py from [f127f4b49a] to [358150069c].

39
40
41
42
43
44
45


46
47
48
49
50
51
52
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54







+
+







    "mns": "min",
    "parce-que": "parce que",
    "pcq": "parce que",
    "pd": "pendant",
    "pdq": "pendant que",
    "pdt": "pendant",
    "pdtq": "pendant que",
    "pécunier": "pécuniaire",
    "pécuniers": "pécuniaires",
    "pk": "pourquoi",
    "pkoi": "pourquoi",
    "pq": "pourquoi|PQ",
    "prq": "presque",
    "prsq": "presque",
    "qcq": "quiconque",
    "qd": "quand",

Modified helpers.py from [9aa31c58b5] to [f66c7bb7d2].

97
98
99
100
101
102
103
104
105


106
107
108
109
110
111
112
97
98
99
100
101
102
103


104
105
106
107
108
109
110
111
112







-
-
+
+







def fileFile (spf, dVars):
    "return file <spf> as a text filed with variables from <dVars>"
    return Template(open(spf, "r", encoding="utf-8").read()).safe_substitute(dVars)


def copyAndFileTemplate (spfSrc, spfDst, dVars):
    "write file <spfSrc> as <spfDst> with variables filed with <dVars>"
    s = Template(open(spfSrc, "r", encoding="utf-8").read()).safe_substitute(dVars)
    open(spfDst, "w", encoding="utf-8", newline="\n").write(s)
    sText = Template(open(spfSrc, "r", encoding="utf-8").read()).safe_substitute(dVars)
    open(spfDst, "w", encoding="utf-8", newline="\n").write(sText)


def addFolderToZipAndFileFile (hZip, spSrc, spDst, dVars, bRecursive):
    "add folder content to zip archive and file files with <dVars>"
    # recursive function
    spSrc = spSrc.strip("/ ")
    spDst = spDst.strip("/ ")