Commit 2103136a authored by Tasso Evangelista's avatar Tasso Evangelista

Merge branch 'hotfix/2.17.6'

parents 4341da1d ee5e4c7f
## [2.17.6](https://github.com/RocketChat/Rocket.Chat.Electron/compare/2.17.5...2.17.6) (2020-02-11)
### Bug Fixes
* Rollback to plain-text Hunspell dictionaries ([#1514](https://github.com/RocketChat/Rocket.Chat.Electron/issues/1514)) ([0f16d32](https://github.com/RocketChat/Rocket.Chat.Electron/commit/0f16d32845faf5b9a9b475db3c34420d982cb6bc))
## [2.17.5](https://github.com/RocketChat/Rocket.Chat.Electron/compare/2.17.4...2.17.5) (2020-02-04)
......
This diff is collapsed.
This diff is collapsed.
SET UTF-8
TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
ICONV 1
ICONV ’ '
NOSUGGEST !
# ordinal numbers
COMPOUNDMIN 1
# only in compounds: 1th, 2th, 3th
ONLYINCOMPOUND c
# compound rules:
# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.)
# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.)
COMPOUNDRULE 2
COMPOUNDRULE n*1t
COMPOUNDRULE n*mp
WORDCHARS 0123456789
PFX A Y 1
PFX A 0 re .
PFX I Y 1
PFX I 0 in .
PFX U Y 1
PFX U 0 un .
PFX C Y 1
PFX C 0 de .
PFX E Y 1
PFX E 0 dis .
PFX F Y 1
PFX F 0 con .
PFX K Y 1
PFX K 0 pro .
SFX V N 2
SFX V e ive e
SFX V 0 ive [^e]
SFX N Y 3
SFX N e ion e
SFX N y ication y
SFX N 0 en [^ey]
SFX X Y 3
SFX X e ions e
SFX X y ications y
SFX X 0 ens [^ey]
SFX H N 2
SFX H y ieth y
SFX H 0 th [^y]
SFX Y Y 1
SFX Y 0 ly .
SFX G Y 2
SFX G e ing e
SFX G 0 ing [^e]
SFX J Y 2
SFX J e ings e
SFX J 0 ings [^e]
SFX D Y 4
SFX D 0 d e
SFX D y ied [^aeiou]y
SFX D 0 ed [^ey]
SFX D 0 ed [aeiou]y
SFX T N 4
SFX T 0 st e
SFX T y iest [^aeiou]y
SFX T 0 est [aeiou]y
SFX T 0 est [^ey]
SFX R Y 4
SFX R 0 r e
SFX R y ier [^aeiou]y
SFX R 0 er [aeiou]y
SFX R 0 er [^ey]
SFX Z Y 4
SFX Z 0 rs e
SFX Z y iers [^aeiou]y
SFX Z 0 ers [aeiou]y
SFX Z 0 ers [^ey]
SFX S Y 4
SFX S y ies [^aeiou]y
SFX S 0 s [aeiou]y
SFX S 0 es [sxzh]
SFX S 0 s [^sxzhy]
SFX P Y 3
SFX P y iness [^aeiou]y
SFX P 0 ness [aeiou]y
SFX P 0 ness [^y]
SFX M Y 1
SFX M 0 's .
SFX B Y 3
SFX B 0 able [^aeiou]
SFX B 0 able ee
SFX B e able [^aeiou]e
SFX L Y 1
SFX L 0 ment .
REP 90
REP a ei
REP ei a
REP a ey
REP ey a
REP ai ie
REP ie ai
REP alot a_lot
REP are air
REP are ear
REP are eir
REP air are
REP air ere
REP ere air
REP ere ear
REP ere eir
REP ear are
REP ear air
REP ear ere
REP eir are
REP eir ere
REP ch te
REP te ch
REP ch ti
REP ti ch
REP ch tu
REP tu ch
REP ch s
REP s ch
REP ch k
REP k ch
REP f ph
REP ph f
REP gh f
REP f gh
REP i igh
REP igh i
REP i uy
REP uy i
REP i ee
REP ee i
REP j di
REP di j
REP j gg
REP gg j
REP j ge
REP ge j
REP s ti
REP ti s
REP s ci
REP ci s
REP k cc
REP cc k
REP k qu
REP qu k
REP kw qu
REP o eau
REP eau o
REP o ew
REP ew o
REP oo ew
REP ew oo
REP ew ui
REP ui ew
REP oo ui
REP ui oo
REP ew u
REP u ew
REP oo u
REP u oo
REP u oe
REP oe u
REP u ieu
REP ieu u
REP ue ew
REP ew ue
REP uff ough
REP oo ieu
REP ieu oo
REP ier ear
REP ear ier
REP ear air
REP air ear
REP w qu
REP qu w
REP z ss
REP ss z
REP shun tion
REP shun sion
REP shun cion
REP size cise
This diff is collapsed.
SET UTF-8
TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
ICONV 1
ICONV ’ '
NOSUGGEST !
# ordinal numbers
COMPOUNDMIN 1
# only in compounds: 1th, 2th, 3th
ONLYINCOMPOUND c
# compound rules:
# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.)
# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.)
COMPOUNDRULE 2
COMPOUNDRULE n*1t
COMPOUNDRULE n*mp
WORDCHARS 0123456789
PFX A Y 1
PFX A 0 re .
PFX I Y 1
PFX I 0 in .
PFX U Y 1
PFX U 0 un .
PFX C Y 1
PFX C 0 de .
PFX E Y 1
PFX E 0 dis .
PFX F Y 1
PFX F 0 con .
PFX K Y 1
PFX K 0 pro .
SFX V N 2
SFX V e ive e
SFX V 0 ive [^e]
SFX N Y 3
SFX N e ion e
SFX N y ication y
SFX N 0 en [^ey]
SFX X Y 3
SFX X e ions e
SFX X y ications y
SFX X 0 ens [^ey]
SFX H N 2
SFX H y ieth y
SFX H 0 th [^y]
SFX Y Y 1
SFX Y 0 ly .
SFX G Y 2
SFX G e ing e
SFX G 0 ing [^e]
SFX J Y 2
SFX J e ings e
SFX J 0 ings [^e]
SFX D Y 4
SFX D 0 d e
SFX D y ied [^aeiou]y
SFX D 0 ed [^ey]
SFX D 0 ed [aeiou]y
SFX T N 4
SFX T 0 st e
SFX T y iest [^aeiou]y
SFX T 0 est [aeiou]y
SFX T 0 est [^ey]
SFX R Y 4
SFX R 0 r e
SFX R y ier [^aeiou]y
SFX R 0 er [aeiou]y
SFX R 0 er [^ey]
SFX Z Y 4
SFX Z 0 rs e
SFX Z y iers [^aeiou]y
SFX Z 0 ers [aeiou]y
SFX Z 0 ers [^ey]
SFX S Y 4
SFX S y ies [^aeiou]y
SFX S 0 s [aeiou]y
SFX S 0 es [sxzh]
SFX S 0 s [^sxzhy]
SFX P Y 3
SFX P y iness [^aeiou]y
SFX P 0 ness [aeiou]y
SFX P 0 ness [^y]
SFX M Y 1
SFX M 0 's .
SFX B Y 3
SFX B 0 able [^aeiou]
SFX B 0 able ee
SFX B e able [^aeiou]e
SFX L Y 1
SFX L 0 ment .
REP 90
REP a ei
REP ei a
REP a ey
REP ey a
REP ai ie
REP ie ai
REP alot a_lot
REP are air
REP are ear
REP are eir
REP air are
REP air ere
REP ere air
REP ere ear
REP ere eir
REP ear are
REP ear air
REP ear ere
REP eir are
REP eir ere
REP ch te
REP te ch
REP ch ti
REP ti ch
REP ch tu
REP tu ch
REP ch s
REP s ch
REP ch k
REP k ch
REP f ph
REP ph f
REP gh f
REP f gh
REP i igh
REP igh i
REP i uy
REP uy i
REP i ee
REP ee i
REP j di
REP di j
REP j gg
REP gg j
REP j ge
REP ge j
REP s ti
REP ti s
REP s ci
REP ci s
REP k cc
REP cc k
REP k qu
REP qu k
REP kw qu
REP o eau
REP eau o
REP o ew
REP ew o
REP oo ew
REP ew oo
REP ew ui
REP ui ew
REP oo ui
REP ui oo
REP ew u
REP u ew
REP oo u
REP u oo
REP u oe
REP oe u
REP u ieu
REP ieu u
REP ue ew
REP ew ue
REP uff ough
REP oo ieu
REP ieu oo
REP ier ear
REP ear ier
REP ear air
REP air ear
REP w qu
REP qu w
REP z ss
REP ss z
REP shun tion
REP shun sion
REP shun cion
REP size cise
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -18,7 +18,7 @@
"mas"
],
"icon": "build/icon.icns",
"bundleVersion": "65",
"bundleVersion": "66",
"helperBundleId": "chat.rocket.electron.helper",
"type": "distribution",
"artifactName": "rocketchat-${version}.${ext}",
......
{
"name": "rocketchat",
"description": "Official OSX, Windows, and Linux Desktop Clients for Rocket.Chat",
"version": "2.17.5",
"version": "2.17.6",
"author": "Rocket.Chat Support <support@rocket.chat>",
"copyright": "© 2019, Rocket.Chat",
"homepage": "https://rocket.chat",
......@@ -31,9 +31,9 @@
},
"dependencies": {
"@bugsnag/js": "^6.3.2",
"@felixrieseberg/spellchecker": "^4.0.12",
"debug": "^4.1.1",
"electron-fetch": "^1.4.0",
"electron-hunspell": "^1.1.2",
"electron-reload": "^1.5.0",
"electron-updater": "^4.0.6",
"fs-jetpack": "^2.2.0",
......
......@@ -25,7 +25,7 @@ const createSpellCheckingMenuTemplate = ({
title: t('dialog.loadDictionary.title'),
defaultPath: dictionariesPath,
filters: [
{ name: t('dialog.loadDictionary.dictionaries'), extensions: ['bdic'] },
{ name: t('dialog.loadDictionary.dictionaries'), extensions: ['dic', 'aff'] },
{ name: t('dialog.loadDictionary.allFiles'), extensions: ['*'] },
],
properties: ['openFile', 'multiSelections'],
......
......@@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' data: filesystem: about: blob: ws: wss:">
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval' data: filesystem: about: blob: ws: wss:">
<title>Rocket.Chat</title>
<link rel="stylesheet" href="../stylesheets/main.css" />
</head>
......
......@@ -2,27 +2,21 @@ import fs from 'fs';
import path from 'path';
import { remote } from 'electron';
import mem from 'mem';
import { SpellCheckerProvider } from 'electron-hunspell';
const { Spellchecker, getAvailableDictionaries } = remote.require('@felixrieseberg/spellchecker');
let provider;
let dictionaries = [];
let dictionariesPath = null;
const spellCheckers = new Map();
let availableDictionaries = new Map();
let userDictionariesPath = null;
export const isMisspelled = mem((text) => {
if (!text || spellCheckers.size === 0) {
export const isMisspelled = async (text) => {
if (!text || (await provider.getAvailableDictionaries()).length === 0) {
return false;
}
for (const spellChecker of spellCheckers.values()) {
if (!spellChecker.isMisspelled(text)) {
return false;
}
}
return true;
});
return !(await provider.getAvailableDictionaries())
.some((dictionaryName) => provider.spellCheckerTable[dictionaryName].spellChecker.spell(text));
};
function filterDictionaries(dictionariesToFilter) {
return dictionariesToFilter
......@@ -32,106 +26,136 @@ function filterDictionaries(dictionariesToFilter) {
? [`${ matches[1] }_${ matches[2] }`, `${ matches[1] }-${ matches[2] }`, matches[1]]
: [dictionary];
})
.filter((dictionary) => dictionaries.includes(dictionary));
.filter((dictionary) => availableDictionaries.has(dictionary));
}
export const getSpellCheckingDictionaries = () => dictionaries;
export const getSpellCheckingDictionaries = () => Array.from(availableDictionaries.keys());
export const getSpellCheckingDictionariesPath = () => dictionariesPath;
export const getSpellCheckingDictionariesPath = () => userDictionariesPath;
export const getEnabledSpellCheckingDictionaries = () => Array.from(spellCheckers.keys());
export const getEnabledSpellCheckingDictionaries = () => provider.getAvailableDictionaries();
export const installSpellCheckingDictionaries = async (filePaths) => {
if (process.platform === 'darwin') {
return;
}
await Promise.all(filePaths.map(async (filePath) => {
const name = path.basename(filePath, path.extname(filePath));
const extension = path.extname(filePath);
const name = path.basename(filePath, extension);
const basename = path.basename(filePath);
const newPath = path.join(dictionariesPath, basename);
const newPath = path.join(userDictionariesPath, basename);
await fs.promises.copyFile(filePath, newPath);
if (!dictionaries.includes(name)) {
dictionaries.push(name);
if (!availableDictionaries.has(name)) {
availableDictionaries.set(name, { [extension.slice(1).toLowerCase()]: newPath });
} else {
availableDictionaries.get(name)[extension.slice(1).toLowerCase()] = newPath;
}
}));
};
export const getMisspelledWords = (words) => words.filter(isMisspelled);
export const getMisspelledWords = async (words) => {
const misspelledWords = [];
export const getSpellCheckingCorrections = (text) => {
for (const word of words) {
// eslint-disable-next-line no-await-in-loop
if (await isMisspelled(word)) {
misspelledWords.push(word);
}
}
return misspelledWords;
};
export const getSpellCheckingCorrections = async (text) => {
text = text.trim();
if (!isMisspelled(text)) {
if (!await isMisspelled(text)) {
return null;
}
return Array.from(spellCheckers.values()).flatMap((spellChecker) => spellChecker.getCorrectionsForMisspelling(text));
return (await provider.getAvailableDictionaries())
.flatMap((dictionaryName) => provider.spellCheckerTable[dictionaryName].spellChecker.suggest(text));
};
const registerSpellCheckingDictionary = async (dictionary) => {
let args;
try {
const dictionaryPath = path.join(dictionariesPath, `${ dictionary.replace(/_/g, '-') }.bdic`);
args = [dictionary, await fs.promises.readFile(dictionaryPath)];
} catch (error) {
args = [dictionary];
}
const registerSpellCheckingDictionary = async (dictionaryName) => {
try {
const spellChecker = new Spellchecker();
if (spellChecker.setDictionary(...args)) {
spellCheckers.set(dictionary, spellChecker);
}
const { dic: dicPath, aff: affPath } = availableDictionaries.get(dictionaryName);
const [dicBuffer, affBuffer] = await Promise.all([
fs.promises.readFile(dicPath),
fs.promises.readFile(affPath),
]);
await provider.loadDictionary(dictionaryName, dicBuffer, affBuffer);
} catch (error) {
spellCheckers.delete(dictionary);
console.error(error);
await provider.unloadDictionary(dictionaryName);
}
};
export const enableSpellCheckingDictionaries = async (...dictionaries) => {
const filteredDictionaries = filterDictionaries(dictionaries);
export const enableSpellCheckingDictionaries = async (...dictionaryNames) => {
const filteredDictionaries = filterDictionaries(dictionaryNames);
await Promise.all(filteredDictionaries.map(registerSpellCheckingDictionary));
mem.clear(isMisspelled);
localStorage.setItem('spellcheckerDictionaries', JSON.stringify(await provider.getAvailableDictionaries()));
localStorage.setItem('spellcheckerDictionaries', JSON.stringify(Array.from(spellCheckers.keys())));
return spellCheckers.size > 0;
return (await provider.getAvailableDictionaries()).length > 0;
};
export const disableSpellCheckingDictionaries = (...dictionaries) => {
const filteredDictionaries = filterDictionaries(dictionaries);
export const disableSpellCheckingDictionaries = async (...dictionaryNames) => {
const filteredDictionaries = filterDictionaries(dictionaryNames);
for (const dictionary of filteredDictionaries) {
spellCheckers.delete(dictionary);
}
filteredDictionaries.forEach((dictionary) => {
provider.unloadDictionary(dictionary);
});
mem.clear(isMisspelled);
localStorage.setItem('spellcheckerDictionaries', JSON.stringify(await provider.getAvailableDictionaries()));
};
localStorage.setItem('spellcheckerDictionaries', JSON.stringify(Array.from(spellCheckers.keys())));
const getPairsOfDictionaryFiles = async (directoryPath) => {
try {
return Object.entries(
(await fs.promises.readdir(directoryPath, { encoding: 'utf8' }))