Index: gc_core/js/char_player.js ================================================================== --- gc_core/js/char_player.js +++ gc_core/js/char_player.js @@ -2,321 +2,331 @@ // useful for suggestion mechanism ${map} -function distanceDamerauLevenshtein (s1, s2) { - // distance of Damerau-Levenshtein between and - // https://fr.wikipedia.org/wiki/Distance_de_Damerau-Levenshtein - let d = new Map(); - let nLen1 = s1.length; - let nLen2 = s2.length; - for (let i = -1; i <= nLen1; i++) { - d.set([i, -1], i + 1); - } - for (let j = -1; i <= nLen2; i++) { - d.set([-1, j], j + 1); - } - for (let i = 0; i < nLen1; i++) { - for (let j =0; j < nLen2; i++) { - let nCost = (s1[i] === s2[j]) ? 0 : 1; - d.set([i, j], Math.min( - d.get([i-1, j]) + 1, // Deletion - d.get([i, j-1]) + 1, // Insertion - d.get([i-1, j-1]) + nCost, // Substitution - )); - if (i && j && s1[i] == s2[j-1] && s1[i-1] == s2[j]) { - d.set([i, j], Math.min(d.get([i, j]), d.get([i-2, j-2]) + nCost)); // Transposition - } - } - } - return d.get([nLen1-1, nLen2-1]); -} - - -// Method: Remove Useless Chars - -const aVovels = new Set([ - 'a', 'e', 'i', 'o', 'u', 'y', - 'à', 'é', 'î', 'ô', 'û', 'ÿ', - 'â', 'è', 'ï', 'ö', 'ù', 'ŷ', - 'ä', 'ê', 'í', 'ó', 'ü', 'ý', - 'á', 'ë', 'ì', 'ò', 'ú', 'ỳ', - 'ā', 'ē', 'ī', 'ō', 'ū', 'ȳ', - 'h', 'œ', 'æ' -]); - - -function clearWord (sWord) { - // remove vovels and h - let sRes = ""; - for (let cChar of sWord.slice(1)) { - if (!aVovels.has(cChar)) { - sRes += cChar; - } - } - return sWord.slice(0, 1).replace("h", "") + sRes; -} - - -// Similar chars - -const 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Ô"], - - ["a", "aàâáäæ"], - ["A", "AÀÂÁÄÆ"], - ["à", "aàâáäæ"], - ["À", "AÀÂÁÄÆ"], - ["â", "aàâáäæ"], - ["Â", "AÀÂÁÄÆ"], - ["á", "aàâáäæ"], - ["Á", "AÀÂÁÄÆ"], - ["ä", "aàâáäæ"], - ["Ä", "AÀÂÁÄÆ"], - - ["æ", "æéa"], - ["Æ", "ÆÉA"], - - ["c", "cçskqśŝ"], - ["C", "CÇSKQŚŜ"], - ["ç", "cçskqśŝ"], - ["Ç", "CÇSKQŚŜ"], - - ["e", "eéèêëœ"], - ["E", "EÉÈÊËŒ"], - ["é", "eéèêëœ"], - ["É", "EÉÈÊËŒ"], - ["ê", "eéèêëœ"], - ["Ê", "EÉÈÊËŒ"], - ["è", "eéèêëœ"], - ["È", "EÉÈÊËŒ"], - ["ë", "eéèêëœ"], - ["Ë", "EÉÈÊËŒ"], - - ["g", "gj"], - ["G", "GJ"], - - ["i", "iîïyíìÿ"], - ["I", "IÎÏYÍÌŸ"], - ["î", "iîïyíìÿ"], - ["Î", "IÎÏYÍÌŸ"], - ["ï", "iîïyíìÿ"], - ["Ï", "IÎÏYÍÌŸ"], - ["í", "iîïyíìÿ"], - ["Í", "IÎÏYÍÌŸ"], - ["ì", "iîïyíìÿ"], - ["Ì", "IÎÏYÍÌŸ"], - - ["j", "jg"], - ["J", "JG"], - - ["k", "kcq"], - ["K", "KCQ"], - - ["n", "nñ"], - ["N", "NÑ"], - - ["o", "oôóòöœ"], - ["O", "OÔÓÒÖŒ"], - ["ô", "oôóòöœ"], - ["Ô", "OÔÓÒÖŒ"], - ["ó", "oôóòöœ"], - ["Ó", "OÔÓÒÖŒ"], - ["ò", "oôóòöœ"], - ["Ò", "OÔÓÒÖŒ"], - ["ö", "oôóòöœ"], - ["Ö", "OÔÓÒÖŒ"], - - ["œ", "œoôeéèêë"], - ["Œ", "ŒOÔEÉÈÊË"], - - ["q", "qck"], - ["Q", "QCK"], - - ["s", "sśŝcç"], - ["S", "SŚŜCÇ"], - ["ś", "sśŝcç"], - ["Ś", "SŚŜCÇ"], - ["ŝ", "sśŝcç"], - ["Ŝ", "SŚŜCÇ"], - - ["u", "uûùüú"], - ["U", "UÛÙÜÚ"], - ["û", "uûùüú"], - ["Û", "UÛÙÜÚ"], - ["ù", "uûùüú"], - ["Ù", "UÛÙÜÚ"], - ["ü", "uûùüú"], - ["Ü", "UÛÙÜÚ"], - ["ú", "uûùüú"], - ["Ú", "UÛÙÜÚ"], - - ["v", "vw"], - ["V", "VW"], - - ["w", "wv"], - ["W", "WV"], - - ["x", "xck"], - ["X", "XCK"], - - ["y", "yÿiîŷýỳ"], - ["Y", "YŸIÎŶÝỲ"], - ["ÿ", "yÿiîŷýỳ"], - ["Ÿ", "YŸIÎŶÝỲ"], - ["ŷ", "yÿiîŷýỳ"], - ["Ŷ", "YŸIÎŶÝỲ"], - ["ý", "yÿiîŷýỳ"], - ["Ý", "YŸIÎŶÝỲ"], - ["ỳ", "yÿiîŷýỳ"], - ["Ỳ", "YŸIÎŶÝỲ"], - - ["z", "zs"], - ["Z", "ZS"], -]); - -const d1toX = new Map([ - ["æ", ["ae",]], - ["Æ", ["AE",]], - ["b", ["bb",]], - ["B", ["BB",]], - ["c", ["cc", "ss", "qu", "ch"]], - ["C", ["CC", "SS", "QU", "CH"]], - ["ç", ["ss", "cc", "qh", "ch"]], - ["Ç", ["SS", "CC", "QH", "CH"]], - ["d", ["dd",]], - ["D", ["DD",]], - ["f", ["ff", "ph"]], - ["F", ["FF", "PH"]], - ["g", ["gu", "ge", "gg", "gh"]], - ["G", ["GU", "GE", "GG", "GH"]], - ["i", ["ii",]], - ["I", ["II",]], - ["j", ["jj", "dj"]], - ["J", ["JJ", "DJ"]], - ["k", ["qu", "ck", "ch", "cu", "kk", "kh"]], - ["K", ["QU", "CK", "CH", "CU", "KK", "KH"]], - ["l", ["ll",]], - ["L", ["LL",]], - ["m", ["mm", "mn"]], - ["M", ["MM", "MN"]], - ["n", ["nn", "nm", "mn"]], - ["N", ["NN", "NM", "MN"]], - ["o", ["au", "eau", "aut"]], - ["O", ["AU", "EAU", "AUT"]], - ["œ", ["oe", "eu"]], - ["Œ", ["OE", "EU"]], - ["p", ["pp", "ph"]], - ["P", ["PP", "PH"]], - ["q", ["qu", "ch", "cq", "ck", "kk"]], - ["Q", ["QU", "CH", "CQ", "CK", "KK"]], - ["r", ["rr",]], - ["R", ["RR",]], - ["s", ["ss", "sh"]], - ["S", ["SS", "SH"]], - ["t", ["tt", "th"]], - ["T", ["TT", "TH"]], - ["x", ["cc", "ct", "xx"]], - ["X", ["CC", "CT", "XX"]], - ["z", ["ss", "zh"]], - ["Z", ["SS", "ZH"]], -]); - -const d2toX = new Map([ - ["an", ["en",]], - ["AN", ["EN",]], - ["en", ["an",]], - ["EN", ["AN",]], - ["ai", ["ei", "é", "è", "ê", "ë"]], - ["AI", ["EI", "É", "È", "Ê", "Ë"]], - ["ei", ["ai", "é", "è", "ê", "ë"]], - ["EI", ["AI", "É", "È", "Ê", "Ë"]], - ["ch", ["sh", "c", "ss"]], - ["CH", ["SH", "C", "SS"]], - ["ct", ["x", "cc"]], - ["CT", ["X", "CC"]], - ["oa", ["oi",]], - ["OA", ["OI",]], - ["oi", ["oa", "oie"]], - ["OI", ["OA", "OIE"]], - ["qu", ["q", "cq", "ck", "c", "k"]], - ["QU", ["Q", "CQ", "CK", "C", "K"]], - ["ss", ["c", "ç"]], - ["SS", ["C", "Ç"]], -]); - - -// End of word - -const dFinal1 = new Map([ - ["a", ["as", "at", "ant", "ah"]], - ["A", ["AS", "AT", "ANT", "AH"]], - ["c", ["ch",]], - ["C", ["CH",]], - ["e", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait", "ent", "eh"]], - ["E", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT", "ENT", "EH"]], - ["é", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], - ["É", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], - ["è", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], - ["È", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], - ["ê", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], - ["Ê", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], - ["ë", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], - ["Ë", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], - ["g", ["gh",]], - ["G", ["GH",]], - ["i", ["is", "it", "ie", "in"]], - ["I", ["IS", "IT", "IE", "IN"]], - ["n", ["nt", "nd", "ns", "nh"]], - ["N", ["NT", "ND", "NS", "NH"]], - ["o", ["aut", "ot", "os"]], - ["O", ["AUT", "OT", "OS"]], - ["ô", ["aut", "ot", "os"]], - ["Ô", ["AUT", "OT", "OS"]], - ["ö", ["aut", "ot", "os"]], - ["Ö", ["AUT", "OT", "OS"]], - ["p", ["ph",]], - ["P", ["PH",]], - ["s", ["sh",]], - ["S", ["SH",]], - ["t", ["th",]], - ["T", ["TH",]], - ["u", ["ut", "us", "uh"]], - ["U", ["UT", "US", "UH"]], -]); - -const dFinal2 = new Map([ - ["ai", ["aient", "ais", "et"]], - ["AI", ["AIENT", "AIS", "ET"]], - ["an", ["ant", "ent"]], - ["AN", ["ANT", "ENT"]], - ["en", ["ent", "ant"]], - ["EN", ["ENT", "ANT"]], - ["ei", ["ait", "ais"]], - ["EI", ["AIT", "AIS"]], - ["on", ["ons", "ont"]], - ["ON", ["ONS", "ONT"]], - ["oi", ["ois", "oit", "oix"]], - ["OI", ["OIS", "OIT", "OIX"]], -]); - - -// Préfixes - -aPfx1 = new Set([ - "anti", "archi", "contre", "hyper", "mé", "méta", "im", "in", "ir", "par", "proto", - "pseudo", "pré", "re", "ré", "sans", "sous", "supra", "sur", "ultra" -]); - -aPfx2 = new Set([ - "belgo", "franco", "génito", "gynéco", "médico", "russo" -]); +var char_player = { + + distanceDamerauLevenshtein: function (s1, s2) { + // distance of Damerau-Levenshtein between and + // https://fr.wikipedia.org/wiki/Distance_de_Damerau-Levenshtein + try { + let d = new Map(); + let nLen1 = s1.length; + let nLen2 = s2.length; + for (let i = -1; i <= nLen1; i++) { + d.set([i, -1], i + 1); + } + for (let j = -1; j <= nLen2; j++) { + d.set([-1, j], j + 1); + } + for (let i = 0; i < nLen1; i++) { + for (let j = 0; j < nLen2; j++) { + let nCost = (s1[i] === s2[j]) ? 0 : 1; + d.set([i, j], Math.min( + d.get([i-1, j]) + 1, // Deletion + d.get([i, j-1]) + 1, // Insertion + d.get([i-1, j-1]) + nCost, // Substitution + )); + if (i && j && s1[i] == s2[j-1] && s1[i-1] == s2[j]) { + d.set([i, j], Math.min(d.get([i, j]), d.get([i-2, j-2]) + nCost)); // Transposition + } + } + } + return d.get([nLen1-1, nLen2-1]); + } + catch (e) { + helpers.logerror(e); + } + }, + + + // Method: Remove Useless Chars + + aVovels: new Set([ + 'a', 'e', 'i', 'o', 'u', 'y', + 'à', 'é', 'î', 'ô', 'û', 'ÿ', + 'â', 'è', 'ï', 'ö', 'ù', 'ŷ', + 'ä', 'ê', 'í', 'ó', 'ü', 'ý', + 'á', 'ë', 'ì', 'ò', 'ú', 'ỳ', + 'ā', 'ē', 'ī', 'ō', 'ū', 'ȳ', + 'h', 'œ', 'æ' + ]), + + clearWord: function (sWord) { + // remove vovels and h + let sRes = ""; + for (let cChar of sWord.slice(1)) { + if (!this.aVovels.has(cChar)) { + sRes += cChar; + } + } + return sWord.slice(0, 1).replace("h", "") + sRes; + }, + + + // 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Ô"], + + ["a", "aàâáäæ"], + ["A", "AÀÂÁÄÆ"], + ["à", "aàâáäæ"], + ["À", "AÀÂÁÄÆ"], + ["â", "aàâáäæ"], + ["Â", "AÀÂÁÄÆ"], + ["á", "aàâáäæ"], + ["Á", "AÀÂÁÄÆ"], + ["ä", "aàâáäæ"], + ["Ä", "AÀÂÁÄÆ"], + + ["æ", "æéa"], + ["Æ", "ÆÉA"], + + ["c", "cçskqśŝ"], + ["C", "CÇSKQŚŜ"], + ["ç", "cçskqśŝ"], + ["Ç", "CÇSKQŚŜ"], + + ["e", "eéèêëœ"], + ["E", "EÉÈÊËŒ"], + ["é", "eéèêëœ"], + ["É", "EÉÈÊËŒ"], + ["ê", "eéèêëœ"], + ["Ê", "EÉÈÊËŒ"], + ["è", "eéèêëœ"], + ["È", "EÉÈÊËŒ"], + ["ë", "eéèêëœ"], + ["Ë", "EÉÈÊËŒ"], + + ["g", "gj"], + ["G", "GJ"], + + ["i", "iîïyíìÿ"], + ["I", "IÎÏYÍÌŸ"], + ["î", "iîïyíìÿ"], + ["Î", "IÎÏYÍÌŸ"], + ["ï", "iîïyíìÿ"], + ["Ï", "IÎÏYÍÌŸ"], + ["í", "iîïyíìÿ"], + ["Í", "IÎÏYÍÌŸ"], + ["ì", "iîïyíìÿ"], + ["Ì", "IÎÏYÍÌŸ"], + + ["j", "jg"], + ["J", "JG"], + + ["k", "kcq"], + ["K", "KCQ"], + + ["n", "nñ"], + ["N", "NÑ"], + + ["o", "oôóòöœ"], + ["O", "OÔÓÒÖŒ"], + ["ô", "oôóòöœ"], + ["Ô", "OÔÓÒÖŒ"], + ["ó", "oôóòöœ"], + ["Ó", "OÔÓÒÖŒ"], + ["ò", "oôóòöœ"], + ["Ò", "OÔÓÒÖŒ"], + ["ö", "oôóòöœ"], + ["Ö", "OÔÓÒÖŒ"], + + ["œ", "œoôeéèêë"], + ["Œ", "ŒOÔEÉÈÊË"], + + ["q", "qck"], + ["Q", "QCK"], + + ["s", "sśŝcç"], + ["S", "SŚŜCÇ"], + ["ś", "sśŝcç"], + ["Ś", "SŚŜCÇ"], + ["ŝ", "sśŝcç"], + ["Ŝ", "SŚŜCÇ"], + + ["u", "uûùüú"], + ["U", "UÛÙÜÚ"], + ["û", "uûùüú"], + ["Û", "UÛÙÜÚ"], + ["ù", "uûùüú"], + ["Ù", "UÛÙÜÚ"], + ["ü", "uûùüú"], + ["Ü", "UÛÙÜÚ"], + ["ú", "uûùüú"], + ["Ú", "UÛÙÜÚ"], + + ["v", "vw"], + ["V", "VW"], + + ["w", "wv"], + ["W", "WV"], + + ["x", "xck"], + ["X", "XCK"], + + ["y", "yÿiîŷýỳ"], + ["Y", "YŸIÎŶÝỲ"], + ["ÿ", "yÿiîŷýỳ"], + ["Ÿ", "YŸIÎŶÝỲ"], + ["ŷ", "yÿiîŷýỳ"], + ["Ŷ", "YŸIÎŶÝỲ"], + ["ý", "yÿiîŷýỳ"], + ["Ý", "YŸIÎŶÝỲ"], + ["ỳ", "yÿiîŷýỳ"], + ["Ỳ", "YŸIÎŶÝỲ"], + + ["z", "zs"], + ["Z", "ZS"], + ]), + + d1toX: new Map([ + ["æ", ["ae",]], + ["Æ", ["AE",]], + ["b", ["bb",]], + ["B", ["BB",]], + ["c", ["cc", "ss", "qu", "ch"]], + ["C", ["CC", "SS", "QU", "CH"]], + ["ç", ["ss", "cc", "qh", "ch"]], + ["Ç", ["SS", "CC", "QH", "CH"]], + ["d", ["dd",]], + ["D", ["DD",]], + ["f", ["ff", "ph"]], + ["F", ["FF", "PH"]], + ["g", ["gu", "ge", "gg", "gh"]], + ["G", ["GU", "GE", "GG", "GH"]], + ["i", ["ii",]], + ["I", ["II",]], + ["j", ["jj", "dj"]], + ["J", ["JJ", "DJ"]], + ["k", ["qu", "ck", "ch", "cu", "kk", "kh"]], + ["K", ["QU", "CK", "CH", "CU", "KK", "KH"]], + ["l", ["ll",]], + ["L", ["LL",]], + ["m", ["mm", "mn"]], + ["M", ["MM", "MN"]], + ["n", ["nn", "nm", "mn"]], + ["N", ["NN", "NM", "MN"]], + ["o", ["au", "eau", "aut"]], + ["O", ["AU", "EAU", "AUT"]], + ["œ", ["oe", "eu"]], + ["Œ", ["OE", "EU"]], + ["p", ["pp", "ph"]], + ["P", ["PP", "PH"]], + ["q", ["qu", "ch", "cq", "ck", "kk"]], + ["Q", ["QU", "CH", "CQ", "CK", "KK"]], + ["r", ["rr",]], + ["R", ["RR",]], + ["s", ["ss", "sh"]], + ["S", ["SS", "SH"]], + ["t", ["tt", "th"]], + ["T", ["TT", "TH"]], + ["x", ["cc", "ct", "xx"]], + ["X", ["CC", "CT", "XX"]], + ["z", ["ss", "zh"]], + ["Z", ["SS", "ZH"]], + ]), + + d2toX: new Map([ + ["an", ["en",]], + ["AN", ["EN",]], + ["en", ["an",]], + ["EN", ["AN",]], + ["ai", ["ei", "é", "è", "ê", "ë"]], + ["AI", ["EI", "É", "È", "Ê", "Ë"]], + ["ei", ["ai", "é", "è", "ê", "ë"]], + ["EI", ["AI", "É", "È", "Ê", "Ë"]], + ["ch", ["sh", "c", "ss"]], + ["CH", ["SH", "C", "SS"]], + ["ct", ["x", "cc"]], + ["CT", ["X", "CC"]], + ["oa", ["oi",]], + ["OA", ["OI",]], + ["oi", ["oa", "oie"]], + ["OI", ["OA", "OIE"]], + ["qu", ["q", "cq", "ck", "c", "k"]], + ["QU", ["Q", "CQ", "CK", "C", "K"]], + ["ss", ["c", "ç"]], + ["SS", ["C", "Ç"]], + ]), + + // End of word + dFinal1: new Map([ + ["a", ["as", "at", "ant", "ah"]], + ["A", ["AS", "AT", "ANT", "AH"]], + ["c", ["ch",]], + ["C", ["CH",]], + ["e", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait", "ent", "eh"]], + ["E", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT", "ENT", "EH"]], + ["é", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], + ["É", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], + ["è", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], + ["È", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], + ["ê", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], + ["Ê", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], + ["ë", ["et", "er", "ets", "ée", "ez", "ai", "ais", "ait"]], + ["Ë", ["ET", "ER", "ETS", "ÉE", "EZ", "AI", "AIS", "AIT"]], + ["g", ["gh",]], + ["G", ["GH",]], + ["i", ["is", "it", "ie", "in"]], + ["I", ["IS", "IT", "IE", "IN"]], + ["n", ["nt", "nd", "ns", "nh"]], + ["N", ["NT", "ND", "NS", "NH"]], + ["o", ["aut", "ot", "os"]], + ["O", ["AUT", "OT", "OS"]], + ["ô", ["aut", "ot", "os"]], + ["Ô", ["AUT", "OT", "OS"]], + ["ö", ["aut", "ot", "os"]], + ["Ö", ["AUT", "OT", "OS"]], + ["p", ["ph",]], + ["P", ["PH",]], + ["s", ["sh",]], + ["S", ["SH",]], + ["t", ["th",]], + ["T", ["TH",]], + ["u", ["ut", "us", "uh"]], + ["U", ["UT", "US", "UH"]], + ]), + + dFinal2: new Map([ + ["ai", ["aient", "ais", "et"]], + ["AI", ["AIENT", "AIS", "ET"]], + ["an", ["ant", "ent"]], + ["AN", ["ANT", "ENT"]], + ["en", ["ent", "ant"]], + ["EN", ["ENT", "ANT"]], + ["ei", ["ait", "ais"]], + ["EI", ["AIT", "AIS"]], + ["on", ["ons", "ont"]], + ["ON", ["ONS", "ONT"]], + ["oi", ["ois", "oit", "oix"]], + ["OI", ["OIS", "OIT", "OIX"]], + ]), + + + // Préfixes + aPfx1: new Set([ + "anti", "archi", "contre", "hyper", "mé", "méta", "im", "in", "ir", "par", "proto", + "pseudo", "pré", "re", "ré", "sans", "sous", "supra", "sur", "ultra" + ]), + + aPfx2: new Set([ + "belgo", "franco", "génito", "gynéco", "médico", "russo" + ]) + +} + + + + + Index: gc_core/js/ibdawg.js ================================================================== --- gc_core/js/ibdawg.js +++ gc_core/js/ibdawg.js @@ -6,10 +6,11 @@ if (typeof(require) !== 'undefined') { var str_transform = require("resource://grammalecte/str_transform.js"); var helpers = require("resource://grammalecte/helpers.js"); + var char_player = require("resource://grammalecte/char_player.js"); } // Don’t remove . Necessary in TB. ${string} @@ -171,27 +172,31 @@ } return l; } suggest (sWord, nMaxSugg=10) { - // returns a set of suggestions for - let aSugg = this._suggest(sWord, nMaxDel=Math.floor(sWord.length / 5)); + // returns a array of suggestions for + let aSugg = this._suggest(sWord, Math.floor(sWord.length / 5)); if (sWord.gl_isTitle()) { - aSugg.gl_update(this._suggest(sWord.lower(), nMaxDel=Math.floor(sWord.length / 5))); - aSugg = new Set(aSugg.map((sSugg) => { return sSugg.title(); })); + aSugg.gl_update(this._suggest(sWord.toLowerCase(), Math.floor(sWord.length / 5))); } else if (sWord.gl_isLowerCase()) { - aSugg.gl_update(this._suggest(sWord.title(), nMaxDel=Math.floor(sWord.length / 5))); + aSugg.gl_update(this._suggest(sWord.gl_toCapitalize(), Math.floor(sWord.length / 5))); } if (aSugg.size == 0) { - aSugg.gl_update(this._suggestWithCrushedUselessChars(cp.clearWord(sWord))); + aSugg.gl_update(this._suggestWithCrushedUselessChars(char_player.clearWord(sWord))); } + // Set to Array + aSugg = Array.from(aSugg); aSugg = aSugg.filter((sSugg) => { return !sSugg.endsWith("è") && !sSugg.endsWith("È"); }); // fr language - return aSugg.sort((sSugg) => { return cp.distanceDamerauLevenshtein(sWord, sSugg); }).slice(0, nMaxSugg); + if (sWord.gl_isTitle()) { + aSugg = aSugg.map((sSugg) => { return sSugg.gl_toCapitalize(); }); + } + return aSugg.sort((sSugg) => { return char_player.distanceDamerauLevenshtein(sWord, sSugg); }).slice(0, nMaxSugg); } - _suggest (sRemain, nMaxDel=0, nDeep=0, iAddr=0, sNewWord="", bAvoidLoop=False) { + _suggest (sRemain, nMaxDel=0, nDeep=0, iAddr=0, sNewWord="", bAvoidLoop=false) { // returns a set of suggestions // recursive function //show(nDeep, sNewWord + ":" + sRemain) let aSugg = new Set(); if (sRemain == "") { @@ -220,35 +225,35 @@ if (nMaxDel > 0) { aSugg.gl_update(this._suggest(sRemain.slice(1), nMaxDel-1, nDeep+1, iAddr, sNewWord, true)); } } // Replacements - for (let sRepl of cp.d1toX.gl_get(cCurrent, [])) { + for (let sRepl of char_player.d1toX.gl_get(cCurrent, [])) { aSugg.gl_update(this._suggest(sRepl + sRemain.slice(1), nMaxDel, nDeep+1, iAddr, sNewWord, true)); } - for (let sRepl of cp.d2toX.gl_get(sRemain[0:2], [])) { + for (let sRepl of char_player.d2toX.gl_get(sRemain.slice(0, 2), [])) { aSugg.gl_update(this._suggest(sRepl + sRemain.slice(2), nMaxDel, nDeep+1, iAddr, sNewWord, true)); } // end of word if (sRemain.length == 2) { - for (let sRepl of cp.dFinal2.gl_get(sRemain, [])) { + for (let sRepl of char_player.dFinal2.gl_get(sRemain, [])) { aSugg.gl_update(this._suggest(sRepl, nMaxDel, nDeep+1, iAddr, sNewWord, true)); } } else if (sRemain.length == 1) { aSugg.gl_update(this._suggest("", nMaxDel, nDeep+1, iAddr, sNewWord, true)); // remove last char and go on - for (let sRepl of cp.dFinal1.gl_get(sRemain, [])) { + for (let sRepl of char_player.dFinal1.gl_get(sRemain, [])) { aSugg.gl_update(this._suggest(sRepl, nMaxDel, nDeep+1, iAddr, sNewWord, true)); } } } return aSugg; } * _getSimilarArcs (cChar, iAddr) { // generator: yield similar char of and address of the following node - for (let c of cp.d1to1.gl_get(cChar, [cChar])) { + for (let c of char_player.d1to1.gl_get(cChar, [cChar])) { if (this.dChar.has(c)) { let jAddr = this._lookupArcNode(this.dChar.get(c), iAddr); if (jAddr) { yield [c, jAddr]; } @@ -260,21 +265,21 @@ // return a list of suffixes ending at a distance of from let aTails = new Set(); for (let [nVal, jAddr] of this._getArcs(iAddr)) { if (nVal < this.nChar) { if (this._convBytesToInteger(this.byDic.slice(jAddr, jAddr+this.nBytesArc)) & this._finalNodeMask) { - aTails.add(sTail + this.dCharVal.get(nVal)); + aTails.add(sTail + this.dChar.get(nVal)); } if (n && aTails.size == 0) { - aTails.update(this._getTails(jAddr, sTail+this.dCharVal.get(nVal), n-1)); + aTails.gl_update(this._getTails(jAddr, sTail+this.dChar.get(nVal), n-1)); } } } return aTails; } - _suggestWithCrushedUselessChars (sWord, nDeep=0, iAddr=0, sNewWord="", bAvoidLoop=False) { + _suggestWithCrushedUselessChars (sWord, nDeep=0, iAddr=0, sNewWord="", bAvoidLoop=false) { let aSugg = new Set(); if (sWord.length == 0) { if (this._convBytesToInteger(this.byDic.slice(iAddr, iAddr+this.nBytesArc)) & this._finalNodeMask) { show(nDeep, "!!! " + sNewWord + " !!!"); aSugg.add(sNewWord); @@ -282,20 +287,20 @@ return aSugg; } let cCurrent = sWord.slice(0, 1); for (let [cChar, jAddr] of this._getSimilarArcsAndCrushedChars(cCurrent, iAddr)) { show(nDeep, cChar); - aSugg.gl_update(this._suggestWithCrushedUselessChars(sWord[1:], nDeep+1, jAddr, sNewWord+cChar)); + aSugg.gl_update(this._suggestWithCrushedUselessChars(sWord.slice(1), nDeep+1, jAddr, sNewWord+cChar)); } return aSugg; } * _getSimilarArcsAndCrushedChars (cChar, iAddr) { // generator: yield similar char of and address of the following node for (let [nVal, jAddr] of this._getArcs(iAddr)) { - if (this.dCharVal.get(nVal, null) in cp.aVovels) { - yield [this.dCharVal[nVal], jAddr]; + if (this.dChar.get(nVal, null) in char_player.aVovels) { + yield [this.dChar[nVal], jAddr]; } } yield* this._getSimilarArcs(cChar, iAddr); } @@ -391,11 +396,11 @@ iAddr = iEndArcAddr + this.nBytesNodeAddress; } } } - _getArcs1 (iAddr) { + * _getArcs1 (iAddr) { "generator: return all arcs at as tuples of (nVal, iAddr)" while (true) { let iEndArcAddr = iAddr+this.nBytesArc; let nRawArc = this._convBytesToInteger(this.byDic.slice(iAddr, iEndArcAddr)); yield [nRawArc & this._arcMask, this._convBytesToInteger(this.byDic.slice(iEndArcAddr, iEndArcAddr+this.nBytesNodeAddress))]; Index: gc_lang/fr/webext/background.js ================================================================== --- gc_lang/fr/webext/background.js +++ gc_lang/fr/webext/background.js @@ -23,10 +23,11 @@ break; case "parse": case "parseAndSpellcheck": case "parseAndSpellcheck1": case "getListOfTokens": + case "getSpellSuggestions": // send result to content script if (typeof(dInfo.iReturnPort) === "number") { let xPort = dConnx.get(dInfo.iReturnPort); xPort.postMessage(e.data); } else { @@ -130,10 +131,11 @@ switch (sCommand) { case "parse": case "parseAndSpellcheck": case "parseAndSpellcheck1": case "getListOfTokens": + case "getSpellSuggestions": oRequest.dInfo.iReturnPort = iPortId; // we pass the id of the return port to receive answer xGCEWorker.postMessage(oRequest); break; case "openURL": browser.tabs.create({url: dParam.sURL}); Index: gc_lang/fr/webext/content_scripts/init.js ================================================================== --- gc_lang/fr/webext/content_scripts/init.js +++ gc_lang/fr/webext/content_scripts/init.js @@ -108,10 +108,13 @@ oGrammalecte.oLxgPanel.addListOfTokens(result); } else { oGrammalecte.oLxgPanel.stopWaitIcon(); } break; + case "getSpellSuggestions": + oGrammalecte.oGCPanel.oTooltip.setSpellSuggestionsFor(result.sWord, result.aSugg, dInfo.sErrorId); + break; // Design WTF: context menus are made in background, not in content-script. // Commands from context menu received here to initialize panels case "openGCPanel": oGrammalecte.createGCPanel(); oGrammalecte.oGCPanel.clear(); Index: gc_lang/fr/webext/content_scripts/panel_gc.js ================================================================== --- gc_lang/fr/webext/content_scripts/panel_gc.js +++ gc_lang/fr/webext/content_scripts/panel_gc.js @@ -276,10 +276,11 @@ class GrammalecteTooltip { constructor (xContentNode) { + this.sErrorId = null; this.xTooltip = createNode("div", {id: "grammalecte_tooltip"}); this.xTooltipArrow = createNode("img", { id: "grammalecte_tooltip_arrow", src: " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwAAADsABataJCQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAAnSURBVChTY/j//z8cq/kW/wdhZDEMSXRFWCVhGKwAmwQyHngFxf8B5fOGYfeFpYoAAAAASUVORK5CYII=", alt: "^", @@ -300,10 +301,11 @@ } show (sNodeErrorId) { // err try { let xNodeErr = document.getElementById(sNodeErrorId); + this.sErrorId = xNodeErr.dataset.error_id; // we store error_id here to know if spell_suggestions are given to the right word. let nLimit = 500 - 330; // paragraph width - tooltip width this.xTooltipArrow.style.top = (xNodeErr.offsetTop + 16) + "px"; this.xTooltipArrow.style.left = (xNodeErr.offsetLeft + Math.floor((xNodeErr.offsetWidth / 2))-4) + "px"; // 4 is half the width of the arrow. this.xTooltip.style.top = (xNodeErr.offsetTop + 20) + "px"; this.xTooltip.style.left = (xNodeErr.offsetLeft > nLimit) ? nLimit + "px" : xNodeErr.offsetLeft + "px"; @@ -325,40 +327,46 @@ document.getElementById("grammalecte_tooltip_url").dataset.url = ""; document.getElementById("grammalecte_tooltip_url").style.display = "none"; } document.getElementById("grammalecte_tooltip_ignore").dataset.error_id = xNodeErr.dataset.error_id; let iSugg = 0; - let xGCSugg = document.getElementById("grammalecte_tooltip_sugg_block"); - xGCSugg.textContent = ""; + this.clearSuggestionBlock(); if (xNodeErr.dataset.suggestions.length > 0) { for (let sSugg of xNodeErr.dataset.suggestions.split("|")) { - xGCSugg.appendChild(this._createSuggestion(xNodeErr.dataset.error_id, iSugg, sSugg)); - xGCSugg.appendChild(document.createTextNode(" ")); + this.xTooltipSuggBlock.appendChild(this._createSuggestion(xNodeErr.dataset.error_id, iSugg, sSugg)); + this.xTooltipSuggBlock.appendChild(document.createTextNode(" ")); iSugg += 1; } } else { - xGCSugg.textContent = "Aucune."; + this.xTooltipSuggBlock.textContent = "Aucune."; } } - this.xTooltipArrow.style.display = "block"; - this.xTooltip.style.display = "block"; if (xNodeErr.dataset.error_type === "spelling") { // spelling mistake document.getElementById("grammalecte_tooltip_message").textContent = "Mot inconnu du dictionnaire."; document.getElementById("grammalecte_tooltip_ignore").dataset.error_id = xNodeErr.dataset.error_id; - while (this.xTooltipSuggBlock.firstChild) { - this.xTooltipSuggBlock.removeChild(this.xTooltipSuggBlock.firstChild); - } - //console.log("getSuggFor: " + xNodeErr.textContent.trim() + " // error_id: " + xNodeErr.dataset.error_id); - //self.port.emit("getSuggestionsForTo", xNodeErr.textContent.trim(), xNodeErr.dataset.error_id); - this.setSpellSuggestionsFor(xNodeErr.textContent.trim(), "", xNodeErr.dataset.error_id); + this.clearSuggestionBlock(); + this.xTooltipSuggBlock.textContent = "Recherche de graphies possibles…"; + xGrammalectePort.postMessage({ + sCommand: "getSpellSuggestions", + dParam: {sWord: xNodeErr.textContent}, + dInfo: {sErrorId: xNodeErr.dataset.error_id} + }); } + this.xTooltipArrow.style.display = "block"; + this.xTooltip.style.display = "block"; } catch (e) { showError(e); } } + + clearSuggestionBlock () { + while (this.xTooltipSuggBlock.firstChild) { + this.xTooltipSuggBlock.removeChild(this.xTooltipSuggBlock.firstChild); + } + } setTooltipColor () { // todo } @@ -365,40 +373,39 @@ hide () { this.xTooltipArrow.style.display = "none"; this.xTooltip.style.display = "none"; } - _createSuggestion (sErrId, iSugg, sSugg) { + _createSuggestion (sErrorId, iSugg, sSugg) { let xNodeSugg = document.createElement("div"); - xNodeSugg.id = "grammalecte_sugg" + sErrId + "--" + iSugg.toString(); + xNodeSugg.id = "grammalecte_sugg" + sErrorId + "--" + iSugg.toString(); xNodeSugg.className = "grammalecte_tooltip_sugg"; - xNodeSugg.dataset.error_id = sErrId; + xNodeSugg.dataset.error_id = sErrorId; xNodeSugg.textContent = sSugg; return xNodeSugg; } - setSpellSuggestionsFor (sWord, sSuggestions, sErrId) { + setSpellSuggestionsFor (sWord, aSugg, sErrorId) { // spell checking suggestions try { - // console.log("setSuggestionsFor: " + sWord + " > " + sSuggestions + " // " + sErrId); - let xSuggBlock = document.getElementById("grammalecte_tooltip_sugg_block"); - xSuggBlock.textContent = ""; - if (sSuggestions === "") { - xSuggBlock.appendChild(document.createTextNode("Aucune.")); - } else if (sSuggestions.startsWith("#")) { - xSuggBlock.appendChild(document.createTextNode(sSuggestions)); - } else { - let lSugg = sSuggestions.split("|"); - let iSugg = 0; - for (let sSugg of lSugg) { - xSuggBlock.appendChild(this._createSuggestion(sErrId, iSugg, sSugg)); - xSuggBlock.appendChild(document.createTextNode(" ")); - iSugg += 1; + if (sErrorId === this.sErrorId) { + let xSuggBlock = document.getElementById("grammalecte_tooltip_sugg_block"); + xSuggBlock.textContent = ""; + if (!aSugg || aSugg.length == 0) { + xSuggBlock.appendChild(document.createTextNode("Aucune.")); + } else { + let iSugg = 0; + for (let sSugg of aSugg) { + xSuggBlock.appendChild(this._createSuggestion(sErrorId, iSugg, sSugg)); + xSuggBlock.appendChild(document.createTextNode(" ")); + iSugg += 1; + } } } } catch (e) { + xSuggBlock.appendChild(document.createTextNode("# Oups. Le mécanisme de suggestion orthographique a rencontré un bug… (Ce module est encore en phase β.)")); showError(e); } } } Index: gc_lang/fr/webext/gce_worker.js ================================================================== --- gc_lang/fr/webext/gce_worker.js +++ gc_lang/fr/webext/gce_worker.js @@ -32,10 +32,11 @@ //console.log("[Worker] GC Engine Worker [start]"); //console.log(self); importScripts("grammalecte/helpers.js"); importScripts("grammalecte/str_transform.js"); +importScripts("grammalecte/char_player.js"); importScripts("grammalecte/ibdawg.js"); importScripts("grammalecte/text.js"); importScripts("grammalecte/tokenizer.js"); importScripts("grammalecte/fr/conj.js"); importScripts("grammalecte/fr/mfsp.js"); @@ -117,10 +118,13 @@ textToTest(dParam.sText, dParam.sCountry, dParam.bDebug, dParam.bContext, dInfo); break; case "fullTests": fullTests(dInfo); break; + case "getSpellSuggestions": + getSpellSuggestions(dParam.sWord, dInfo); + break; case "getListOfTokens": getListOfTokens(dParam.sText, dInfo); break; default: console.log("[Worker] Unknown command: " + sCommand); @@ -237,12 +241,12 @@ console.log(text.getReadableError(oErr)); } } function textToTest (sText, sCountry, bDebug, bContext, dInfo={}) { - if (!gc_engine || !oDict) { - postMessage(createResponse("textToTest", "# Grammar checker or dictionary not loaded.", dInfo, true)); + if (!gc_engine) { + postMessage(createResponse("textToTest", "# Grammar checker not loaded.", dInfo, true)); return; } let aGrammErr = gc_engine.parse(sText, sCountry, bDebug, bContext); let sMsg = ""; for (let oErr of aGrammErr) { @@ -253,12 +257,12 @@ } postMessage(createResponse("textToTest", sMsg, dInfo, true)); } function fullTests (dInfo={}) { - if (!gc_engine || !oDict) { - postMessage(createResponse("fullTests", "# Grammar checker or dictionary not loaded.", dInfo, true)); + if (!gc_engine) { + postMessage(createResponse("fullTests", "# Grammar checker not loaded.", dInfo, true)); return; } let dMemoOptions = gc_engine.getOptions(); let dTestOptions = gc_engine.getDefaultOptions(); dTestOptions.set("nbsp", true); @@ -273,10 +277,22 @@ } gc_engine.setOptions(dMemoOptions); postMessage(createResponse("fullTests", sMsg, dInfo, true)); } + +// Spellchecker + +function getSpellSuggestions (sWord, dInfo) { + if (!oDict) { + postMessage(createResponse("getSpellSuggestions", "# Error. Dictionary not loaded.", dInfo, true)); + return; + } + let aSugg = oDict.suggest(sWord); + console.log(aSugg); + postMessage(createResponse("getSpellSuggestions", {sWord: sWord, aSugg: aSugg}, dInfo, true)); +} // Lexicographer function getListOfTokens (sText, dInfo={}) {