From 82ad22c5c305fd1b0ca58e3311689ac812707b09 Mon Sep 17 00:00:00 2001 From: Malcolm Lalkaka Date: Mon, 10 Jun 2019 17:22:34 -0700 Subject: [PATCH] Add support for Electron 5 and above Starting with Electron 5.0.0, the function `webFrame.setSpellCheckProvider` has a different signature, in order to support asynchronous spell checkers. For more information on this change in Electron, see https://github.com/electron/electron/pull/14032. This diff updates `SpellCheckHandler` to use the new interface if running on Electron 5.0.0 and above. However, it still checks the spelling synchronously like before. If running on Electron versions below 5.0.0, the `SpellCheckHandler` still works. Closes #144. --- src/spell-check-handler.js | 76 +++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 17 deletions(-) diff --git a/src/spell-check-handler.js b/src/spell-check-handler.js index dc09ccc..dcb01e6 100644 --- a/src/spell-check-handler.js +++ b/src/spell-check-handler.js @@ -140,11 +140,9 @@ module.exports = class SpellCheckHandler { this.currentSpellchecker = new Spellchecker(); this.currentSpellcheckerLanguage = 'en-US'; + d('DEBUG: Settings Spell Check Provider...'); if (webFrame) { - webFrame.setSpellCheckProvider( - this.currentSpellcheckerLanguage, - this.shouldAutoCorrect, - { spellCheck: this.handleElectronSpellCheck.bind(this) }); + this.setSpellCheckProvider(webFrame); } return; } @@ -255,9 +253,9 @@ module.exports = class SpellCheckHandler { } let contentToCheck = Observable.merge( - this.spellingErrorOccurred, - initialInputText, - possiblySwitchedCharacterSets) + this.spellingErrorOccurred, + initialInputText, + possiblySwitchedCharacterSets) .mergeMap(() => { if (lastInputText.length < 8) return Observable.empty(); return Observable.of(lastInputText); @@ -295,16 +293,13 @@ module.exports = class SpellCheckHandler { let prevSpellCheckLanguage; disp.add(this.currentSpellcheckerChanged - .startWith(true) + .startWith(true) .filter(() => this.currentSpellcheckerLanguage) .subscribe(() => { if (prevSpellCheckLanguage === this.currentSpellcheckerLanguage) return; d('Actually installing spell check provider to Electron'); - webFrame.setSpellCheckProvider( - this.currentSpellcheckerLanguage, - this.shouldAutoCorrect, - { spellCheck: this.handleElectronSpellCheck.bind(this) }); + this.setSpellCheckProvider(webFrame); prevSpellCheckLanguage = this.currentSpellcheckerLanguage; })); @@ -388,7 +383,7 @@ module.exports = class SpellCheckHandler { let dict = null; this.isMisspelledCache.reset(); - + // Set language on macOS if (isMac && this.currentSpellchecker) { d(`Setting current spellchecker to ${langCode}`); @@ -449,7 +444,7 @@ module.exports = class SpellCheckHandler { return await Observable.of(...alternatives) .concatMap((l) => { return Observable.defer(() => - Observable.fromPromise(this.dictionarySync.loadDictionaryForLanguage(l, cacheOnly))) + Observable.fromPromise(this.dictionarySync.loadDictionaryForLanguage(l, cacheOnly))) .map((d) => ({language: l, dictionary: d})) .do(({language}) => { alternatesTable[langCode] = language; @@ -463,10 +458,34 @@ module.exports = class SpellCheckHandler { } /** - * The actual callout called by Electron to handle spellchecking + * Sets the SpellCheckProvider on the given WebFrame. Handles API differences + * in Electron. + * @private + * @param {*} webFrame + */ + setSpellCheckProvider(webFrame) { + if (process.versions.electron >= '5.0.0') { + d('DEBUG: Setting provider for Electron 5'); + // Electron 5 and above: + webFrame.setSpellCheckProvider( + this.currentSpellcheckerLanguage, + { spellCheck: this.handleElectronSpellCheck.bind(this) }); + } else { + d('DEBUG: Setting provider for Electron 4'); + // Electron 4 and below: + webFrame.setSpellCheckProvider( + this.currentSpellcheckerLanguage, + this.shouldAutoCorrect, + { spellCheck: this.handleElectron4SpellCheck.bind(this) }); + } + } + + /** + * The actual callout called by Electron version 4 and below to handle + * spellchecking * @private */ - handleElectronSpellCheck(text) { + handleElectron4SpellCheck(text) { if (!this.currentSpellchecker) return true; if (isMac) { @@ -480,6 +499,29 @@ module.exports = class SpellCheckHandler { return !result; } + /** + * The actual callout called by Electron version 5 and above to handle + * spellchecking. + * @private + */ + handleElectronSpellCheck(words, callback) { + if (!this.currentSpellchecker) { + callback([]); + return; + } + + let misspelled = words.filter(w => this.isMisspelled(w)); + + if (isMac) { + callback(misspelled); + return; + } + + this.spellCheckInvoked.next(true); + + misspelled.forEach(w => this.spellingErrorOccurred.next(w)); + } + /** * Calculates whether a word is missspelled, using an LRU cache to memoize * the callout to the actual spell check code. @@ -652,4 +694,4 @@ module.exports = class SpellCheckHandler { d(`Result: ${JSON.stringify(ret)}`); return ret; } -} +};