Grammalecte  Check-in [6bd3d5409b]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:[fx] grammar checking: autorefresh after edition
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | fx
Files: files | file ages | folders
SHA3-256:6bd3d5409b90406b20cad07ff0bdb61c735c848fc86664886d6b7ddecbbcb21f
User & Date: olr 2019-04-16 14:16:48
Context
2019-04-16
15:58
[fr] faux positifs (ocr) check-in: a052c4803b user: olr tags: fr, trunk
14:16
[fx] grammar checking: autorefresh after edition check-in: 6bd3d5409b user: olr tags: fx, trunk
2019-04-15
20:00
[fr] faux positifs (OCR) et casse check-in: 49dbba531c user: olr tags: fr, trunk
Changes

Changes to gc_lang/fr/webext/content_scripts/init.js.

240
241
242
243
244
245
246























































247
248
249
250
251
252
253
                xNodeToAppendTo.appendChild(xNode);
            }
            return xNode;
        }
        catch (e) {
            showError(e);
        }























































    }
};


/*
    Connexion to the background
*/







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
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
301
302
303
304
305
306
307
308
                xNodeToAppendTo.appendChild(xNode);
            }
            return xNode;
        }
        catch (e) {
            showError(e);
        }
    },

    getCaretPosition (xElement) {
        // JS awfulness again.
        // recepie from https://stackoverflow.com/questions/4811822/get-a-ranges-start-and-end-offsets-relative-to-its-parent-container
        let nCaretOffsetStart = 0;
        let nCaretOffsetEnd = 0;
        let xSelection = window.getSelection();
        if (xSelection.rangeCount > 0) {
            let xRange = xSelection.getRangeAt(0);
            let xPreCaretRange = xRange.cloneRange();
            xPreCaretRange.selectNodeContents(xElement);
            xPreCaretRange.setEnd(xRange.endContainer, xRange.endOffset);
            nCaretOffsetStart = xPreCaretRange.toString().length;
            nCaretOffsetEnd = nCaretOffsetStart + xRange.toString().length;
        }
        return [nCaretOffsetStart, nCaretOffsetEnd];
        // for later: solution with multilines text
        // https://stackoverflow.com/questions/4811822/get-a-ranges-start-and-end-offsets-relative-to-its-parent-container/4812022
    },

    setCaretPosition (xElement, nCaretOffsetStart, nCaretOffsetEnd) {
        // JS awfulness again.
        // recipie from https://stackoverflow.com/questions/6249095/how-to-set-caretcursor-position-in-contenteditable-element-div
        let iChar = 0;
        let xRange = document.createRange();
        xRange.setStart(xElement, 0);
        xRange.collapse(true);

        let lNode = [xElement];
        let xNode;
        let bFoundStart = false;
        let bStop = false;
        while (!bStop && (xNode = lNode.pop())) {
            if (xNode.nodeType == 3) { // Node.TEXT_NODE
                let iNextChar = iChar + xNode.length;
                if (!bFoundStart && nCaretOffsetStart >= iChar && nCaretOffsetStart <= iNextChar) {
                    xRange.setStart(xNode, nCaretOffsetStart - iChar);
                    bFoundStart = true;
                }
                if (bFoundStart && nCaretOffsetEnd >= iChar && nCaretOffsetEnd <= iNextChar) {
                    xRange.setEnd(xNode, nCaretOffsetEnd - iChar);
                    bStop = true;
                }
                iChar = iNextChar;
            } else {
                let i = xNode.childNodes.length;
                while (i--) {
                    lNode.push(xNode.childNodes[i]);
                }
            }
        }
        let xSelection = window.getSelection();
        xSelection.removeAllRanges();
        xSelection.addRange(xRange);
    }
};


/*
    Connexion to the background
*/

Changes to gc_lang/fr/webext/content_scripts/panel_gc.css.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
..
62
63
64
65
66
67
68






69
70
71
72
73
74
75

div.grammalecte_paragraph_block {
    margin: 0 0 5px 0;
}

p.grammalecte_paragraph {
    margin: 0;
    padding: 10px;
    background-color: hsl(0, 0%, 96%);
    border-radius: 2px;
    line-height: normal;
    text-align: left;
    font-size: 14px;
    font-family: "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace;
    color: hsl(0, 0%, 0%);
................................................................................
}
div.grammalecte_paragraph_button:hover {
    background-color: hsl(0, 0%, 40%);
    color: hsl(0, 0%, 100%);
}

div.grammalecte_paragraph_actions .grammalecte_green {
    width: 80px;
    background-color: hsl(120, 30%, 50%);
    color: hsl(0, 0%, 96%);
}
div.grammalecte_paragraph_actions .grammalecte_green:hover {
    background-color: hsl(120, 50%, 40%);
    color: hsl(0, 0%, 100%);
}
................................................................................
    background-color: hsl(0, 30%, 50%);
    color: hsl(0, 0%, 96%);
}
div.grammalecte_paragraph_actions .grammalecte_red:hover {
    background-color: hsl(0, 50%, 40%);
    color: hsl(0, 0%, 100%);
}








/*
    TOOLTIP
*/
img#grammalecte_tooltip_arrow {
    position: absolute;







|







 







<







 







>
>
>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
46
47
48
49
50
51
52

53
54
55
56
57
58
59
..
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

div.grammalecte_paragraph_block {
    margin: 0 0 5px 0;
}

p.grammalecte_paragraph {
    margin: 0;
    padding: 12px;
    background-color: hsl(0, 0%, 96%);
    border-radius: 2px;
    line-height: normal;
    text-align: left;
    font-size: 14px;
    font-family: "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace;
    color: hsl(0, 0%, 0%);
................................................................................
}
div.grammalecte_paragraph_button:hover {
    background-color: hsl(0, 0%, 40%);
    color: hsl(0, 0%, 100%);
}

div.grammalecte_paragraph_actions .grammalecte_green {

    background-color: hsl(120, 30%, 50%);
    color: hsl(0, 0%, 96%);
}
div.grammalecte_paragraph_actions .grammalecte_green:hover {
    background-color: hsl(120, 50%, 40%);
    color: hsl(0, 0%, 100%);
}
................................................................................
    background-color: hsl(0, 30%, 50%);
    color: hsl(0, 0%, 96%);
}
div.grammalecte_paragraph_actions .grammalecte_red:hover {
    background-color: hsl(0, 50%, 40%);
    color: hsl(0, 0%, 100%);
}

@keyframes grammalecte-pulse {
    0% { box-shadow: 0 0 0 1px hsla(0, 100%, 50%, .4); }
    50% { box-shadow: 0 0 0 3px hsla(0, 100%, 50%, .4); }
    100% { box-shadow: 0 0 0 1px hsla(0, 100%, 50%, .4); }
}


/*
    TOOLTIP
*/
img#grammalecte_tooltip_arrow {
    position: absolute;

Changes to gc_lang/fr/webext/content_scripts/panel_gc.js.

84
85
86
87
88
89
90
91
92
93
94
95

96





97
98
99
100
101
102
103
...
195
196
197
198
199
200
201
202
203
204


205
206
207
208



209
210

211
212
213
214
215
216
217
218
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271

    addParagraphResult (oResult) {
        try {
            if (oResult && (oResult.sParagraph.trim() !== "" || oResult.aGrammErr.length > 0 || oResult.aSpellErr.length > 0)) {
                let xNodeDiv = oGrammalecte.createNode("div", {className: "grammalecte_paragraph_block"});
                // actions
                let xActionsBar = oGrammalecte.createNode("div", {className: "grammalecte_paragraph_actions"});
                xActionsBar.appendChild(oGrammalecte.createNode("div", {id: "grammalecte_check" + oResult.iParaNum, className: "grammalecte_paragraph_button grammalecte_green", textContent: "Réanalyser"}, {para_num: oResult.iParaNum}));
                xActionsBar.appendChild(oGrammalecte.createNode("div", {id: "grammalecte_hide" + oResult.iParaNum, className: "grammalecte_paragraph_button grammalecte_red", textContent: "×", style: "font-weight: bold;"}));
                // paragraph
                let xParagraph = oGrammalecte.createNode("p", {id: "grammalecte_paragraph"+oResult.iParaNum, className: "grammalecte_paragraph", lang: "fr", contentEditable: "true"}, {para_num: oResult.iParaNum});
                xParagraph.setAttribute("spellcheck", "false"); // doesn’t seem possible to use “spellcheck” as a common attribute.

                xParagraph.addEventListener("keyup", function (xEvent) {





                    this.oNodeControl.setParagraph(parseInt(xEvent.target.dataset.para_num), this.purgeText(xEvent.target.textContent));
                    this.oNodeControl.write();
                }.bind(this)
                , true);
                this._tagParagraph(xParagraph, oResult.sParagraph, oResult.iParaNum, oResult.aGrammErr, oResult.aSpellErr);
                // creation
                xNodeDiv.appendChild(xActionsBar);
................................................................................
        xNodeErr.className = (this.aIgnoredErrors.has(xNodeErr.dataset.ignored_key)) ? "grammalecte_error_ignored" : "grammalecte_error";
        xNodeErr.style.backgroundColor = (oErr['sType'] === "WORD") ? "hsl(0, 50%, 50%)" : oErr["aColor"];
        return xNodeErr;
    }

    blockParagraph (xParagraph) {
        xParagraph.contentEditable = "false";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).textContent = "Analyse…";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.backgroundColor = "hsl(0, 50%, 50%)";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.boxShadow = "0 0 0 3px hsla(0, 100%, 50%, .2)";


    }

    freeParagraph (xParagraph) {
        xParagraph.contentEditable = "true";



        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).textContent = "Réanalyser";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.backgroundColor = "hsl(120, 30%, 50%)";

        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.boxShadow = "none";
    }

    applySuggestion (sNodeSuggId) { // sugg
        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);
................................................................................
        // recipe from https://github.com/mdn/webextensions-examples/blob/master/context-menu-copy-link-with-types/clipboard-helper.js
        function setClipboardData (xEvent) {
            document.removeEventListener("copy", setClipboardData, true);
            xEvent.stopImmediatePropagation();
            xEvent.preventDefault();
            xEvent.clipboardData.setData("text/plain", sText);
        }

        document.addEventListener("copy", setClipboardData, true);
        document.execCommand("copy");
    }

    copyTextToClipboard () {
        this.startWaitIcon();
        try {







|
|



>
|
>
>
>
>
>







 







|

|
>
>




>
>
>
|

>
|







 







<







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
269
270
271
272
273
274
275

276
277
278
279
280
281
282

    addParagraphResult (oResult) {
        try {
            if (oResult && (oResult.sParagraph.trim() !== "" || oResult.aGrammErr.length > 0 || oResult.aSpellErr.length > 0)) {
                let xNodeDiv = oGrammalecte.createNode("div", {className: "grammalecte_paragraph_block"});
                // actions
                let xActionsBar = oGrammalecte.createNode("div", {className: "grammalecte_paragraph_actions"});
                xActionsBar.appendChild(oGrammalecte.createNode("div", {id: "grammalecte_check" + oResult.iParaNum, className: "grammalecte_paragraph_button grammalecte_green", textContent: "A", title: "Réanalyser"}, {para_num: oResult.iParaNum}));
                xActionsBar.appendChild(oGrammalecte.createNode("div", {id: "grammalecte_hide" + oResult.iParaNum, className: "grammalecte_paragraph_button grammalecte_red", textContent: "×", title: "Cacher", style: "font-weight: bold;"}));
                // paragraph
                let xParagraph = oGrammalecte.createNode("p", {id: "grammalecte_paragraph"+oResult.iParaNum, className: "grammalecte_paragraph", lang: "fr", contentEditable: "true"}, {para_num: oResult.iParaNum});
                xParagraph.setAttribute("spellcheck", "false"); // doesn’t seem possible to use “spellcheck” as a common attribute.
                xParagraph.dataset.timer_id = "0";
                xParagraph.addEventListener("input", function (xEvent) {
                    window.clearTimeout(parseInt(xParagraph.dataset.timer_id));
                    xParagraph.dataset.timer_id = window.setTimeout(this.recheckParagraph.bind(this), 3000, oResult.iParaNum);
                    let [nStart, nEnd] = oGrammalecte.getCaretPosition(xParagraph);
                    xParagraph.dataset.caret_position_start = nStart;
                    xParagraph.dataset.caret_position_end = nEnd;
                    this.oNodeControl.setParagraph(parseInt(xEvent.target.dataset.para_num), this.purgeText(xEvent.target.textContent));
                    this.oNodeControl.write();
                }.bind(this)
                , true);
                this._tagParagraph(xParagraph, oResult.sParagraph, oResult.iParaNum, oResult.aGrammErr, oResult.aSpellErr);
                // creation
                xNodeDiv.appendChild(xActionsBar);
................................................................................
        xNodeErr.className = (this.aIgnoredErrors.has(xNodeErr.dataset.ignored_key)) ? "grammalecte_error_ignored" : "grammalecte_error";
        xNodeErr.style.backgroundColor = (oErr['sType'] === "WORD") ? "hsl(0, 50%, 50%)" : oErr["aColor"];
        return xNodeErr;
    }

    blockParagraph (xParagraph) {
        xParagraph.contentEditable = "false";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).textContent = "!!";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.backgroundColor = "hsl(0, 50%, 50%)";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.boxShadow = "0 0 0 3px hsla(0, 0%, 50%, .2)";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.animation = "grammalecte-pulse 1s linear infinite";

    }

    freeParagraph (xParagraph) {
        xParagraph.contentEditable = "true";
        let nStart = parseInt(xParagraph.dataset.caret_position_start);
        let nEnd = parseInt(xParagraph.dataset.caret_position_end);
        oGrammalecte.setCaretPosition(xParagraph, nStart, nEnd);
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).textContent = "A";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.backgroundColor = "hsl(120, 30%, 50%)";
        this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.animation = "";
        setTimeout(() => { this.xParent.getElementById("grammalecte_check"+xParagraph.dataset.para_num).style.boxShadow = ""; }, 1000);
    }

    applySuggestion (sNodeSuggId) { // sugg
        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);
................................................................................
        // recipe from https://github.com/mdn/webextensions-examples/blob/master/context-menu-copy-link-with-types/clipboard-helper.js
        function setClipboardData (xEvent) {
            document.removeEventListener("copy", setClipboardData, true);
            xEvent.stopImmediatePropagation();
            xEvent.preventDefault();
            xEvent.clipboardData.setData("text/plain", sText);
        }

        document.addEventListener("copy", setClipboardData, true);
        document.execCommand("copy");
    }

    copyTextToClipboard () {
        this.startWaitIcon();
        try {