From 9794439336e2b9130a5dc6cfd8f26c66405ac8ea Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Sun, 18 Sep 2022 07:06:40 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20native=20dictionary=20optionally=20?= =?UTF-8?q?used=20for=20spell=20checking=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc Nuri --- src/spell-check/__tests__/index.test.js | 125 ++++++++++++++++-- src/spell-check/index.js | 52 +++++--- src/tab-manager/__tests__/index.test.js | 56 ++++++-- .../__tests__/preload.spell-check.test.js | 70 +++++++--- src/tab-manager/__tests__/preload.test.js | 29 +++- src/tab-manager/index.js | 25 +++- src/tab-manager/preload.js | 9 +- src/tab-manager/preload.spell-check.js | 16 ++- 8 files changed, 306 insertions(+), 76 deletions(-) diff --git a/src/spell-check/__tests__/index.test.js b/src/spell-check/__tests__/index.test.js index dea62d3d..3a4e2c08 100644 --- a/src/spell-check/__tests__/index.test.js +++ b/src/spell-check/__tests__/index.test.js @@ -19,19 +19,22 @@ describe('Spell-check module test suite', () => { let mockSettings; let spellCheck; beforeEach(() => { + jest.resetModules(); mockBrowserWindow = { + destroy: jest.fn(), loadURL: jest.fn() }; mockIpc = { - handle: jest.fn() + handle: jest.fn(), + removeHandler: jest.fn() }; mockSettings = { enabledDictionaries: [] }; - jest.resetModules(); jest.mock('electron', () => ({ BrowserWindow: jest.fn(() => mockBrowserWindow), - ipcMain: mockIpc + ipcMain: mockIpc, + MenuItem: jest.fn(({label, click}) => ({label, click})) })); jest.mock('../../settings', () => ({ loadSettings: jest.fn(() => mockSettings) @@ -46,11 +49,115 @@ describe('Spell-check module test suite', () => { // Then expect(result).toEqual(['13-37']); }); - test('loadDictionaries', () => { - // When - spellCheck.loadDictionaries(); - // Then - expect(mockBrowserWindow.loadURL).toHaveBeenCalledWith(expect.stringMatching(/\/dictionary.renderer\/index.html$/)); - expect(mockIpc.handle).toHaveBeenCalledWith('dictionaryGetMisspelled', expect.any(Function)); + describe('loadDictionaries', () => { + test('should destroy existing previous fakeRenderer', () => { + // Given + spellCheck.loadDictionaries(); + // When + spellCheck.loadDictionaries(); + // Then + expect(mockBrowserWindow.destroy).toHaveBeenCalledTimes(1); + }); + test('should not destroy non-existing previous fakeRenderer', () => { + // When + spellCheck.loadDictionaries(); + // Then + expect(mockBrowserWindow.destroy).not.toHaveBeenCalled(); + }); + test('should remove and then add handler', () => { + // When + spellCheck.loadDictionaries(); + // Then + expect(mockIpc.handle).toHaveBeenCalledAfter(mockIpc.removeHandler); + }); + test('should remove dictionaryGetMisspelled handler', () => { + // When + spellCheck.loadDictionaries(); + // Then + expect(mockIpc.removeHandler).toHaveBeenCalledWith('dictionaryGetMisspelled'); + }); + test('should handle dictionaryGetMisspelled', () => { + // When + spellCheck.loadDictionaries(); + // Then + expect(mockIpc.handle).toHaveBeenCalledWith('dictionaryGetMisspelled', expect.any(Function)); + }); + test('should load dictionary.renderer URL', () => { + // When + spellCheck.loadDictionaries(); + // Then + expect(mockBrowserWindow.loadURL) + .toHaveBeenCalledWith(expect.stringMatching(/\/dictionary.renderer\/index.html$/)); + }); + }); + describe('Context Menu handlers', () => { + let params; + let webContents; + beforeEach(() => { + params = {}; + webContents = {}; + mockBrowserWindow.webContents = webContents; + spellCheck.loadDictionaries(); + }); + describe('contextMenuHandler', () => { + test('with no misspelled word, should return empty array', async () => { + // When + const result = await spellCheck.contextMenuHandler({}, params, webContents); + // Then + expect(result).toEqual([]); + }); + describe('with misspelled word', () => { + beforeEach(() => { + params.misspelledWord = 'the-word'; + }); + test('and no suggestions, should return empty array', async () => { + // Given + mockBrowserWindow.webContents.executeJavaScript = jest.fn(async () => []); + // When + const result = await spellCheck.contextMenuHandler({}, params, webContents); + // Then + expect(result).toEqual([]); + }); + test('and suggestions, should return array of MenuItems', async () => { + // Given + mockBrowserWindow.webContents.executeJavaScript = jest.fn(async () => ['the-suggestion']); + // When + const result = await spellCheck.contextMenuHandler({}, params, webContents); + // Then + expect(result).toEqual([ + expect.objectContaining({label: 'the-suggestion'}) + ]); + }); + }); + }); + describe('contextMenuNativeHandler', () => { + test('with no misspelled word, should return empty array', () => { + // When + const result = spellCheck.contextMenuNativeHandler({}, params, webContents); + // Then + expect(result).toEqual([]); + }); + describe('with misspelled word', () => { + beforeEach(() => { + params.misspelledWord = 'the-word'; + }); + test('and no suggestions, should return empty array', () => { + // When + const result = spellCheck.contextMenuNativeHandler({}, params, webContents); + // Then + expect(result).toEqual([]); + }); + test('and suggestions, should return array of MenuItems', async () => { + // Given + params.dictionarySuggestions = ['the-suggestion']; + // When + const result = spellCheck.contextMenuNativeHandler({}, params, webContents); + // Then + expect(result).toEqual([ + expect.objectContaining({label: 'the-suggestion'}) + ]); + }); + }); + }); }); }); diff --git a/src/spell-check/index.js b/src/spell-check/index.js index d1a54921..b525e0ef 100644 --- a/src/spell-check/index.js +++ b/src/spell-check/index.js @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const {BrowserWindow, ipcMain} = require('electron'); +const {BrowserWindow, MenuItem, ipcMain} = require('electron'); const {APP_EVENTS} = require('../constants'); const {loadSettings} = require('../settings'); @@ -87,48 +87,60 @@ const getAvailableNativeDictionaries = () => const handleGetMisspelled = async (_event, words) => fakeRendererWorker.webContents.executeJavaScript(`getMisspelled(${JSON.stringify(words)})`); +const getUseNativeSpellChecker = () => loadSettings().useNativeSpellChecker; + const getEnabledDictionaries = () => loadSettings().enabledDictionaries; const loadDictionaries = () => { - if (!fakeRendererWorker) { - fakeRendererWorker = new BrowserWindow({ - show: false, - webPreferences: { - contextIsolation: false, - nativeWindowOpen: true, - nodeIntegration: true - } - }); - ipcMain.handle(APP_EVENTS.dictionaryGetMisspelled, handleGetMisspelled); + if (fakeRendererWorker) { + fakeRendererWorker.destroy(); } + fakeRendererWorker = new BrowserWindow({ + show: false, + webPreferences: { + contextIsolation: false, + nativeWindowOpen: true, + nodeIntegration: true + } + }); fakeRendererWorker.loadURL(`file://${__dirname}/dictionary.renderer/index.html`); + ipcMain.removeHandler(APP_EVENTS.dictionaryGetMisspelled); + ipcMain.handle(APP_EVENTS.dictionaryGetMisspelled, handleGetMisspelled); // Uncomment to debug problems with dictionaries // fakeRendererWorker.webContents.openDevTools(); }; +const menuItem = ({webContents, suggestion}) => new MenuItem({ + label: suggestion, + click: () => { + webContents.replaceMisspelling(suggestion); + } +}); + const contextMenuHandler = async (_event, {misspelledWord}, webContents) => { - const {MenuItem} = require('electron'); const ret = []; if (misspelledWord && misspelledWord.length > 0) { const suggestions = await fakeRendererWorker.webContents.executeJavaScript(`getSuggestions('${misspelledWord}')`); - suggestions.forEach(suggestion => - ret.push(new MenuItem({ - label: suggestion, - click: () => { - webContents.replaceMisspelling(suggestion); - } - })) - ); + suggestions.forEach(suggestion => ret.push(menuItem({webContents, suggestion}))); } return ret; }; +const contextMenuNativeHandler = (_event, {misspelledWord, dictionarySuggestions = []}, webContents) => { + const ret = []; + if (misspelledWord && misspelledWord.length > 0) { + dictionarySuggestions.forEach(suggestion => ret.push(menuItem({webContents, suggestion}))); + } + return ret; +}; module.exports = { AVAILABLE_DICTIONARIES, contextMenuHandler, + contextMenuNativeHandler, getAvailableDictionaries, getAvailableNativeDictionaries, getEnabledDictionaries, + getUseNativeSpellChecker, loadDictionaries }; diff --git a/src/tab-manager/__tests__/index.test.js b/src/tab-manager/__tests__/index.test.js index ba72b75d..b56fb7c0 100644 --- a/src/tab-manager/__tests__/index.test.js +++ b/src/tab-manager/__tests__/index.test.js @@ -25,6 +25,7 @@ describe('Tab Manager module test suite', () => { mockBrowserView = { setAutoResize: jest.fn(), webContents: { + session: {}, executeJavaScript: jest.fn(async () => {}), on: jest.fn(), loadURL: jest.fn(), @@ -198,7 +199,7 @@ describe('Tab Manager module test suite', () => { mockMenu.append = jest.fn(); mockMenu.popup = jest.fn(); }); - test('No spelling suggestions, should open a Menu with DevTools entry', async () => { + test('should open a Menu with DevTools entry', async () => { // Given spellChecker.contextMenuHandler.mockImplementationOnce(() => []); // When @@ -208,26 +209,55 @@ describe('Tab Manager module test suite', () => { expect(electron.MenuItem).toHaveBeenCalledTimes(1); expect(electron.MenuItem).toHaveBeenCalledWith(expect.objectContaining({label: 'DevTools'})); expect(mockMenu.append).toHaveBeenCalledTimes(1); - expect(mockMenu.popup).toHaveBeenCalledTimes(1); - expect(mockMenu.popup).toHaveBeenCalledWith({x: 13, y: 37}); }); - test('Spelling suggestions, should open a Menu with all suggestions, a sperator and DevTools entry', async () => { + test('should open a Menu at the specified location', async () => { // Given - spellChecker.contextMenuHandler.mockImplementationOnce(() => [ - new electron.MenuItem({label: 'suggestion 1'}), - new electron.MenuItem({label: 'suggestion 2'}) - ]); + spellChecker.contextMenuHandler.mockImplementationOnce(() => []); // When await events['context-menu'](new Event(''), {x: 13, y: 37}); // Then - expect(electron.Menu).toHaveBeenCalledTimes(1); - expect(electron.MenuItem).toHaveBeenCalledTimes(4); - expect(electron.MenuItem).toHaveBeenCalledWith({type: 'separator'}); - expect(electron.MenuItem).toHaveBeenCalledWith(expect.objectContaining({label: 'DevTools'})); - expect(mockMenu.append).toHaveBeenCalledTimes(4); expect(mockMenu.popup).toHaveBeenCalledTimes(1); expect(mockMenu.popup).toHaveBeenCalledWith({x: 13, y: 37}); }); + describe('with native spellcheck disabled', () => { + beforeEach(() => { + mockBrowserView.webContents.session.spellcheck = false; + }); + test('Spelling suggestions, should open a Menu with all suggestions, a separator and DevTools entry', async () => { + // Given + spellChecker.contextMenuHandler.mockImplementationOnce(() => [ + new electron.MenuItem({label: 'suggestion 1'}), + new electron.MenuItem({label: 'suggestion 2'}) + ]); + // When + await events['context-menu'](new Event(''), {x: 13, y: 37}); + // Then + expect(electron.Menu).toHaveBeenCalledTimes(1); + expect(electron.MenuItem).toHaveBeenCalledTimes(4); + expect(electron.MenuItem).toHaveBeenCalledWith({type: 'separator'}); + expect(electron.MenuItem).toHaveBeenCalledWith(expect.objectContaining({label: 'DevTools'})); + expect(mockMenu.append).toHaveBeenCalledTimes(4); + }); + }); + describe('with native spellcheck enabled', () => { + beforeEach(() => { + mockBrowserView.webContents.session.spellcheck = true; + }); + test('Spelling suggestions, should open a Menu with all suggestions, a separator and DevTools entry', async () => { + // Given + spellChecker.contextMenuNativeHandler.mockImplementationOnce(() => [ + new electron.MenuItem({label: 'suggestion 1'}) + ]); + // When + await events['context-menu'](new Event(''), {x: 13, y: 37}); + // Then + expect(electron.Menu).toHaveBeenCalledTimes(1); + expect(electron.MenuItem).toHaveBeenCalledTimes(3); + expect(electron.MenuItem).toHaveBeenCalledWith({type: 'separator'}); + expect(electron.MenuItem).toHaveBeenCalledWith(expect.objectContaining({label: 'DevTools'})); + expect(mockMenu.append).toHaveBeenCalledTimes(3); + }); + }); }); }); }); diff --git a/src/tab-manager/__tests__/preload.spell-check.test.js b/src/tab-manager/__tests__/preload.spell-check.test.js index 4f50f9b3..d9dec916 100644 --- a/src/tab-manager/__tests__/preload.spell-check.test.js +++ b/src/tab-manager/__tests__/preload.spell-check.test.js @@ -13,36 +13,74 @@ See the License for the specific language governing permissions and limitations under the License. */ +const {waitFor} = require('@testing-library/dom'); + describe('Browser Spell Check test suite', () => { let mockIpcRenderer; + let mockWebFrame; let browserSpellCheck; beforeEach(() => { - global.APP_EVENTS = { - dictionaryGetMisspelled: 'dictionaryGetMisspelled' - }; + jest.resetModules(); + global.APP_EVENTS = require('../../constants').APP_EVENTS; mockIpcRenderer = { - invoke: jest.fn() + invoke: jest.fn(async () => ({useNativeSpellChecker: false})) + }; + mockWebFrame = { + setSpellCheckProvider: jest.fn() }; - jest.resetModules(); jest.mock('electron', () => ({ - ipcRenderer: mockIpcRenderer + ipcRenderer: mockIpcRenderer, + webFrame: mockWebFrame })); browserSpellCheck = require('../preload.spell-check'); }); - test('initSpellChecker, should set spell checker in provided webFrame', async () => { + describe('initSpellChecker', () => { + test('not-native, should load settings and set SpellCheckProvider in webFrame for navigator language', async () => { + // Given + Object.defineProperty(navigator, 'language', {value: 'eo'}); + // When + browserSpellCheck.initSpellChecker(); + // Then + await waitFor(() => expect(mockWebFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1)); + expect(mockWebFrame.setSpellCheckProvider).toHaveBeenCalledWith('eo', expect.any(Object)); + expect(mockIpcRenderer.invoke).toHaveBeenCalledTimes(1); + expect(mockIpcRenderer.invoke).toHaveBeenCalledWith('settingsLoad'); + }); + test('native, should load settings and skip processing', async () => { + // Given + mockIpcRenderer.invoke = jest.fn(async () => ({useNativeSpellChecker: true})); + // When + await browserSpellCheck.initSpellChecker(); + // Then + expect(mockWebFrame.setSpellCheckProvider).not.toHaveBeenCalled(); + expect(mockIpcRenderer.invoke).toHaveBeenCalledTimes(1); + expect(mockIpcRenderer.invoke).toHaveBeenCalledWith('settingsLoad'); + }); + test('retries in case of failure', async () => { + // Given + mockIpcRenderer.invoke = jest.fn() + .mockImplementationOnce(async () => { + throw new Error('failed'); + }) + .mockImplementationOnce(async () => ({useNativeSpellChecker: false})); + // When + browserSpellCheck.initSpellChecker(); + // Then + await waitFor(() => expect(mockWebFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1)); + expect(mockIpcRenderer.invoke).toHaveBeenCalledTimes(2); + expect(mockIpcRenderer.invoke).toHaveBeenCalledWith('settingsLoad'); + }); + }); + test('spellCheck, should invoke dictionaryGetMisspelled and trigger callback', async () => { // Given const callback = jest.fn(); - Object.defineProperty(navigator, 'language', {value: 'eo'}); - const webFrame = { - setSpellCheckProvider: jest.fn() - }; - browserSpellCheck.initSpellChecker(webFrame); + browserSpellCheck.initSpellChecker(); + await waitFor(() => expect(mockWebFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1)); // When - await webFrame.setSpellCheckProvider.mock.calls[0][1].spellCheck([], callback); + await mockWebFrame.setSpellCheckProvider.mock.calls[0][1].spellCheck([], callback); // Then - expect(webFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1); - expect(webFrame.setSpellCheckProvider).toHaveBeenCalledWith('eo', expect.any(Object)); - expect(mockIpcRenderer.invoke).toHaveBeenCalledTimes(1); + expect(mockIpcRenderer.invoke).toHaveBeenCalledTimes(2); + expect(mockIpcRenderer.invoke).toHaveBeenCalledWith('dictionaryGetMisspelled', []); expect(callback).toHaveBeenCalledTimes(1); }); }); diff --git a/src/tab-manager/__tests__/preload.test.js b/src/tab-manager/__tests__/preload.test.js index 9c106a47..04d96b6b 100644 --- a/src/tab-manager/__tests__/preload.test.js +++ b/src/tab-manager/__tests__/preload.test.js @@ -13,11 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. */ +/* eslint-disable no-console */ +const {waitFor} = require('@testing-library/dom'); + describe('Tab Manager Module preload test suite', () => { let mockElectron; beforeEach(() => { mockElectron = { - webFrame: {setSpellCheckProvider: jest.fn()} + webFrame: {setSpellCheckProvider: jest.fn()}, + ipcRenderer: {invoke: async () => ({useNativeSpellChecker: false})} }; jest.resetModules(); jest.mock('electron', () => mockElectron); @@ -31,29 +35,42 @@ describe('Tab Manager Module preload test suite', () => { jest.spyOn(require('../preload.keyboard-shortcuts'), 'initKeyboardShortcuts'); jest.spyOn(require('../preload.spell-check'), 'initSpellChecker'); }); - test('adds required libraries', () => { + test('adds required libraries', async () => { // When require('../preload'); // Then expect(window.Notification).toEqual(expect.any(Function)); expect(window.navigator.mediaDevices.getDisplayMedia).toEqual(expect.any(Function)); expect(require('../preload.keyboard-shortcuts').initKeyboardShortcuts).toHaveBeenCalledTimes(1); - expect(mockElectron.webFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1); + await waitFor(() => expect(mockElectron.webFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1)); expect(require('../preload.spell-check').initSpellChecker).toHaveBeenCalledTimes(1); - expect(require('../preload.spell-check').initSpellChecker).toHaveBeenCalledWith(mockElectron.webFrame); + }); + test('logs error if can\'t initialize spell checker', async () => { + // Given + jest.mock('../preload.spell-check', () => ({ + initSpellChecker: async () => { + throw new Error('Error initializing spell checker'); + } + })); + jest.spyOn(console, 'error').mockImplementationOnce(() => {}); + // When + require('../preload'); + // Then + await waitFor(() => expect(console.error).toHaveBeenCalledTimes(1)); + expect(console.error).toHaveBeenCalledWith('Error initializing spell check', expect.any(Error)); }); }); describe('preload.bundle', () => { beforeEach(() => { window.addEventListener = jest.fn(); }); - test('adds required libraries', () => { + test('adds required libraries', async () => { // When require('../../../bundles/tab-manager.preload'); // Then expect(window.Notification).toEqual(expect.any(Function)); expect(window.navigator.mediaDevices.getDisplayMedia).toEqual(expect.any(Function)); - expect(mockElectron.webFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1); + await waitFor(() => expect(mockElectron.webFrame.setSpellCheckProvider).toHaveBeenCalledTimes(1)); expect(window.addEventListener).toHaveBeenCalledTimes(2); expect(window.addEventListener).toHaveBeenCalledWith('keyup', expect.any(Function)); expect(window.addEventListener).toHaveBeenCalledWith('load', expect.any(Function)); diff --git a/src/tab-manager/index.js b/src/tab-manager/index.js index 99c61a95..11949b20 100644 --- a/src/tab-manager/index.js +++ b/src/tab-manager/index.js @@ -17,7 +17,7 @@ const {app, BrowserView, Menu, MenuItem, session} = require('electron'); const path = require('path'); const {APP_EVENTS} = require('../constants'); const settings = require('../settings'); -const {contextMenuHandler} = require('../spell-check'); +const {contextMenuHandler, contextMenuNativeHandler, getEnabledDictionaries, getUseNativeSpellChecker} = require('../spell-check'); const {userAgentForView, addUserAgentInterceptor} = require('../user-agent'); const {handleRedirect} = require('./redirect'); @@ -58,8 +58,12 @@ const handlePageFaviconUpdated = (browserView, ipcSender, tabId) => async (_e, f const handleContextMenu = browserView => async (event, params) => { const {webContents} = browserView; const menu = new Menu(); - - const spellingSuggestions = await contextMenuHandler(event, params, webContents); + let spellingSuggestions; + if (webContents.session.spellcheck) { + spellingSuggestions = contextMenuNativeHandler(event, params, webContents); + } else { + spellingSuggestions = await contextMenuHandler(event, params, webContents); + } if (spellingSuggestions.length > 0) { spellingSuggestions.forEach(mi => menu.append(mi)); menu.append(new MenuItem({type: 'separator'})); @@ -79,6 +83,8 @@ const cleanUserAgent = browserView => { }; const addTabs = ipcSender => tabsMetadata => { + const useNativeSpellChecker = getUseNativeSpellChecker(); + const enabledDictionaries = getEnabledDictionaries(); tabsMetadata.forEach(({id, url, sandboxed = false}) => { const tabPreferences = {...webPreferences}; if (sandboxed) { @@ -87,6 +93,19 @@ const addTabs = ipcSender => tabsMetadata => { tabPreferences.session = session.defaultSession; } addUserAgentInterceptor(tabPreferences.session); + + tabPreferences.session.spellcheck = useNativeSpellChecker; + if (useNativeSpellChecker) { + tabPreferences.session.setSpellCheckerEnabled(true); + tabPreferences.session.setSpellCheckerLanguages(tabPreferences.session.availableSpellCheckerLanguages + .filter(lang => enabledDictionaries.includes(lang))); + } + + + tabPreferences.experiment = false; + if (tabPreferences.experiment) { // USE NATIVE SPELL CHECKER + tabPreferences.session.setSpellCheckerDictionaryDownloadURL('file:///home/user/00-MN/projects/manusa/electronim/dictionaries/'); + } const tab = new BrowserView({webPreferences: tabPreferences}); tab.setAutoResize({width: true, height: true}); diff --git a/src/tab-manager/preload.js b/src/tab-manager/preload.js index 5a408da4..b69f4087 100644 --- a/src/tab-manager/preload.js +++ b/src/tab-manager/preload.js @@ -13,11 +13,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -const {webFrame} = require('electron'); require('./preload.notification-shim'); require('./preload.mediadevices-shim'); -const {initKeyboardShortcuts} = require('./preload.keyboard-shortcuts'); -const {initSpellChecker} = require('./preload.spell-check'); +require('./preload.keyboard-shortcuts').initKeyboardShortcuts(); +require('./preload.spell-check').initSpellChecker() + // eslint-disable-next-line no-console + .catch(err => console.error('Error initializing spell check', err)); -initKeyboardShortcuts(); -initSpellChecker(webFrame); diff --git a/src/tab-manager/preload.spell-check.js b/src/tab-manager/preload.spell-check.js index 32573031..55ae083e 100644 --- a/src/tab-manager/preload.spell-check.js +++ b/src/tab-manager/preload.spell-check.js @@ -13,7 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -const {ipcRenderer} = require('electron'); +/* eslint-disable no-undef */ +const {ipcRenderer, webFrame} = require('electron'); const spellCheckFunction = async (words, callback) => { // eslint-disable-next-line no-undef @@ -21,8 +22,15 @@ const spellCheckFunction = async (words, callback) => { callback(misspelled); }; -const initSpellChecker = webFrame => { - webFrame.setSpellCheckProvider(navigator.language, {spellCheck: spellCheckFunction}); -}; +const initSpellChecker = () => new Promise(resolve => { + ipcRenderer.invoke(APP_EVENTS.settingsLoad) + .then(settings => { + if (!settings.useNativeSpellChecker) { + webFrame.setSpellCheckProvider(navigator.language, {spellCheck: spellCheckFunction}); + } + resolve(); + }) + .catch(initSpellChecker); +}); module.exports = {initSpellChecker};