From 0fff6336c7ca5a066164eee2df219cdc485b28e5 Mon Sep 17 00:00:00 2001 From: Manav Mehta Date: Thu, 18 Jun 2020 18:14:23 +0530 Subject: [PATCH] spellchecker: Use Electron 8 built-in spellchecker. * Using electron built-in spellchecker * Added the custom context menu Co-authored-by: Anders Kaseorg Fixes: #504 --- app/main/index.ts | 4 +- app/renderer/js/components/context-menu.ts | 102 +++++++ app/renderer/js/components/webview.ts | 12 +- app/renderer/js/injected.ts | 4 +- app/renderer/js/main.ts | 3 + .../js/pages/preference/general-section.ts | 87 +++++- app/renderer/js/preload.ts | 15 +- app/renderer/js/spellchecker.ts | 61 ----- app/renderer/preference.html | 2 + package-lock.json | 250 +++--------------- package.json | 9 +- typings.d.ts | 2 + 12 files changed, 248 insertions(+), 303 deletions(-) create mode 100644 app/renderer/js/components/context-menu.ts delete mode 100644 app/renderer/js/spellchecker.ts diff --git a/app/main/index.ts b/app/main/index.ts index 782258cf3..e8499b3d4 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -167,7 +167,9 @@ app.on('activate', () => { app.on('ready', () => { const ses = session.fromPartition('persist:webviewsession'); ses.setUserAgent(`ZulipElectron/${app.getVersion()} ${ses.getUserAgent()}`); - + ipcMain.on('set-spellcheck-langs', () => { + ses.setSpellCheckerLanguages(ConfigUtil.getConfigItem('spellcheckerLanguages')); + }); AppMenu.setMenu({ tabs: [] }); diff --git a/app/renderer/js/components/context-menu.ts b/app/renderer/js/components/context-menu.ts new file mode 100644 index 000000000..f8369e702 --- /dev/null +++ b/app/renderer/js/components/context-menu.ts @@ -0,0 +1,102 @@ +import {remote, ContextMenuParams} from 'electron'; +import * as t from '../utils/translation-util'; +const {clipboard, Menu} = remote; + +export const contextMenu = (webContents: Electron.WebContents, event: Event, props: ContextMenuParams) => { + const isText = Boolean(props.selectionText.length); + const isLink = Boolean(props.linkURL); + + const makeSuggestion = (suggestion: string) => ({ + label: suggestion, + visible: true, + async click() { + await webContents.insertText(suggestion); + } + }); + + let menuTemplate: Electron.MenuItemConstructorOptions[] = [{ + label: t.__('Add to Dictionary'), + visible: props.isEditable && isText && props.misspelledWord.length !== 0, + click(_item) { + webContents.session.addWordToSpellCheckerDictionary(props.misspelledWord); + } + }, { + type: 'separator' + }, { + label: `${t.__('Look Up')} "${props.selectionText}"`, + visible: process.platform === 'darwin' && isText, + click(_item) { + webContents.showDefinitionForSelection(); + } + }, { + type: 'separator' + }, { + label: t.__('Cut'), + visible: isText, + enabled: props.isEditable, + accelerator: 'CommandOrControl+X', + click(_item) { + webContents.cut(); + } + }, { + label: t.__('Copy'), + accelerator: 'CommandOrControl+C', + click(_item) { + webContents.copy(); + } + }, { + label: t.__('Paste'), // Bug: Paste replaces text + accelerator: 'CommandOrControl+V', + enabled: props.isEditable, + click() { + webContents.paste(); + } + }, { + type: 'separator' + }, { + label: t.__('Copy Link'), + visible: isText && isLink, + click(_item) { + clipboard.write({ + bookmark: props.linkText, + text: props.linkURL + }); + } + }, { + label: t.__('Copy Image'), + visible: props.mediaType === 'image', + click(_item) { + webContents.copyImageAt(props.x, props.y); + } + }, { + label: t.__('Copy Image URL'), + visible: props.mediaType === 'image', + click(_item) { + clipboard.write({ + bookmark: props.srcURL, + text: props.srcURL + }); + } + }, { + type: 'separator' + }, { + label: t.__('Services'), + visible: process.platform === 'darwin', + role: 'services' + }]; + + if (props.misspelledWord) { + if (props.dictionarySuggestions.length > 0) { + const suggestions: Electron.MenuItemConstructorOptions[] = props.dictionarySuggestions.map((suggestion: string) => makeSuggestion(suggestion)); + menuTemplate = suggestions.concat(menuTemplate); + } else { + menuTemplate.unshift({ + label: t.__('No Suggestion Found'), + enabled: false + }); + } + } + + const menu = Menu.buildFromTemplate(menuTemplate); + menu.popup(); +}; diff --git a/app/renderer/js/components/webview.ts b/app/renderer/js/components/webview.ts index debde1b79..f0fd8f3d9 100644 --- a/app/renderer/js/components/webview.ts +++ b/app/renderer/js/components/webview.ts @@ -6,6 +6,7 @@ import * as ConfigUtil from '../utils/config-util'; import * as SystemUtil from '../utils/system-util'; import BaseComponent from './base'; import handleExternalLink from './handle-external-link'; +import {contextMenu} from './context-menu'; const {app, dialog} = remote; @@ -57,7 +58,11 @@ export default class WebView extends BaseComponent { ${this.props.preload ? 'preload="js/preload.js"' : ''} partition="persist:webviewsession" name="${this.props.name}" - webpreferences="${this.props.nodeIntegration ? '' : 'contextIsolation, '}javascript=yes"> + webpreferences=" + ${this.props.nodeIntegration ? '' : 'contextIsolation,'} + ${ConfigUtil.getConfigItem('enableSpellchecker') ? 'spellcheck,' : ''} + javascript + "> `; } @@ -117,6 +122,11 @@ export default class WebView extends BaseComponent { }); this.$el.addEventListener('dom-ready', () => { + const webContents = remote.webContents.fromId(this.$el.getWebContentsId()); + webContents.addListener('context-menu', (event, menuParameters) => { + contextMenu(webContents, event, menuParameters); + }); + if (this.props.role === 'server') { this.$el.classList.add('onload'); } diff --git a/app/renderer/js/injected.ts b/app/renderer/js/injected.ts index ebcdd63ac..984293c8a 100644 --- a/app/renderer/js/injected.ts +++ b/app/renderer/js/injected.ts @@ -52,9 +52,7 @@ interface CompatElectronBridge extends ElectronBridge { const {page_params} = zulipWindow; if (page_params) { - electron_bridge.send_event('zulip-loaded', { - serverLanguage: page_params.default_language - }); + electron_bridge.send_event('zulip-loaded'); } })(); diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index c2551b3bc..fcd14ef1c 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -50,6 +50,7 @@ interface SettingsOptions extends DNDSettings { quitOnClose: boolean; promptDownload: boolean; dockBouncing?: boolean; + spellcheckerLanguages?: string[]; } const logger = new Logger({ @@ -137,6 +138,7 @@ class ServerManagerView { await this.initTabs(); this.initActions(); this.registerIpcs(); + ipcRenderer.send('set-spellcheck-langs'); } async loadProxy(): Promise { @@ -214,6 +216,7 @@ class ServerManagerView { if (process.platform !== 'darwin') { settingOptions.autoHideMenubar = false; + settingOptions.spellcheckerLanguages = ['en-US']; } for (const [setting, value] of Object.entries(settingOptions)) { diff --git a/app/renderer/js/pages/preference/general-section.ts b/app/renderer/js/pages/preference/general-section.ts index 8957c3b5d..b24366c4e 100644 --- a/app/renderer/js/pages/preference/general-section.ts +++ b/app/renderer/js/pages/preference/general-section.ts @@ -3,7 +3,7 @@ import {ipcRenderer, remote, OpenDialogOptions} from 'electron'; import path from 'path'; import fs from 'fs-extra'; -const {app, dialog} = remote; +const {app, dialog, session} = remote; const currentBrowserWindow = remote.getCurrentWindow(); import BaseSection from './base-section'; @@ -11,6 +11,8 @@ import * as ConfigUtil from '../../utils/config-util'; import * as EnterpriseUtil from '../../utils/enterprise-util'; import * as t from '../../utils/translation-util'; import supportedLocales from '../../../../translations/supported-locales.json'; +import Tagify from '@yaireo/tagify'; +import ISO6391 from 'iso-639-1'; interface GeneralSectionProps { $root: Element; @@ -93,7 +95,10 @@ export default class GeneralSection extends BaseSection {
${t.__('Enable spellchecker (requires restart)')}
+
+
+
${t.__('Advanced')}
@@ -171,6 +176,7 @@ export default class GeneralSection extends BaseSection { this.updatePromptDownloadOption(); this.enableErrorReporting(); this.setLocale(); + this.initSpellChecker(); // Platform specific settings @@ -356,6 +362,10 @@ export default class GeneralSection extends BaseSection { const newValue = !ConfigUtil.getConfigItem('enableSpellchecker'); ConfigUtil.setConfigItem('enableSpellchecker', newValue); this.enableSpellchecker(); + const spellcheckerLanguageInput: HTMLElement = document.querySelector('#spellcheck-langs'); + const spellcheckerNote: HTMLElement = document.querySelector('#note'); + spellcheckerLanguageInput.style.display = spellcheckerLanguageInput.style.display === 'none' ? '' : 'none'; + spellcheckerNote.style.display = spellcheckerNote.style.display === 'none' ? '' : 'none'; } }); } @@ -493,4 +503,79 @@ export default class GeneralSection extends BaseSection { await this.factoryResetSettings(); }); } + + initSpellChecker(): void { + // The elctron API is a no-op on macOS and macOS default spellchecker is used. + if (process.platform === 'darwin') { + const note: HTMLElement = document.querySelector('#note'); + note.append(t.__('On macOS, the OS spellchecker is used.')); + note.append(document.createElement('br')); + note.append(t.__('Change the language from System Preferences → Keyboard → Text → Spelling.')); + } else { + const note: HTMLElement = document.querySelector('#note'); + note.append(t.__('You can select a maximum of 3 languages for spellchecking.')); + const spellDiv: HTMLElement = document.querySelector('#spellcheck-langs'); + spellDiv.innerHTML += ` +
${t.__('Spellchecker Languages')}
+ `; + + const availableLanguages = session.fromPartition('persist:webviewsession').availableSpellCheckerLanguages; + let languagePairs: Map = new Map(); + availableLanguages.forEach((l: string) => { + if (ISO6391.validate(l)) { + languagePairs.set(ISO6391.getName(l), l); + } + }); + + // Manually set names for languages not available in ISO6391 + languagePairs.set('English (AU)', 'en-AU'); + languagePairs.set('English (CA)', 'en-CA'); + languagePairs.set('English (GB)', 'en-GB'); + languagePairs.set('English (US)', 'en-US'); + languagePairs.set('Spanish (Latin America)', 'es-419'); + languagePairs.set('Spanish (Argentina)', 'es-AR'); + languagePairs.set('Spanish (Mexico)', 'es-MX'); + languagePairs.set('Spanish (US)', 'es-US'); + languagePairs.set('Portuguese (Brazil)', 'pt-BR'); + languagePairs.set('Portuguese (Portugal)', 'pt-PT'); + languagePairs.set('Serbo-Croatian', 'sh'); + + languagePairs = new Map([...languagePairs].sort((a, b) => ((a[0] < b[0]) ? -1 : 1))); + + const tagField: HTMLElement = document.querySelector('input[name=spellcheck]'); + const tagify = new Tagify(tagField, { + whitelist: [...languagePairs.keys()], + enforceWhitelist: true, + maxTags: 3, + dropdown: { + enabled: 0, + maxItems: Infinity, + closeOnSelect: false, + highlightFirst: true + } + }); + + const configuredLanguages: string[] = ConfigUtil.getConfigItem('spellcheckerLanguages').map((code: string) => [...languagePairs].filter(pair => (pair[1] === code))[0][0]); + tagify.addTags(configuredLanguages); + + tagField.addEventListener('change', event => { + if ((event.target as HTMLInputElement).value.length === 0) { + ConfigUtil.setConfigItem('spellcheckerLanguages', []); + ipcRenderer.send('set-spellcheck-langs'); + } else { + const spellLangs: string[] = [...JSON.parse((event.target as HTMLInputElement).value).values()].map(elt => languagePairs.get(elt.value)); + ConfigUtil.setConfigItem('spellcheckerLanguages', spellLangs); + ipcRenderer.send('set-spellcheck-langs'); + } + }); + } + + // Do not display the spellchecker input and note if it is disabled + if (!ConfigUtil.getConfigItem('enableSpellchecker')) { + const spellcheckerLanguageInput: HTMLElement = document.querySelector('#spellcheck-langs'); + const spellcheckerNote: HTMLElement = document.querySelector('#note'); + spellcheckerLanguageInput.style.display = 'none'; + spellcheckerNote.style.display = 'none'; + } + } } diff --git a/app/renderer/js/preload.ts b/app/renderer/js/preload.ts index acbdc497d..e71041f85 100644 --- a/app/renderer/js/preload.ts +++ b/app/renderer/js/preload.ts @@ -1,6 +1,5 @@ import {contextBridge, ipcRenderer, webFrame} from 'electron'; import fs from 'fs'; -import * as SetupSpellChecker from './spellchecker'; import isDev from 'electron-is-dev'; @@ -54,13 +53,7 @@ ipcRenderer.on('show-notification-settings', () => { }, 100); }); -electron_bridge.once('zulip-loaded', ({serverLanguage}) => { - // Get the default language of the server - if (serverLanguage) { - // Init spellchecker - SetupSpellChecker.init(serverLanguage); - } - +electron_bridge.once('zulip-loaded', () => { // Redirect users to network troubleshooting page const getRestartButton = document.querySelector('.restart_get_events_button'); if (getRestartButton) { @@ -70,12 +63,6 @@ electron_bridge.once('zulip-loaded', ({serverLanguage}) => { } }); -// Clean up spellchecker events after you navigate away from this page; -// otherwise, you may experience errors -window.addEventListener('beforeunload', (): void => { - SetupSpellChecker.unsubscribeSpellChecker(); -}); - window.addEventListener('load', (event: any): void => { if (!event.target.URL.includes('app/renderer/network.html')) { return; diff --git a/app/renderer/js/spellchecker.ts b/app/renderer/js/spellchecker.ts deleted file mode 100644 index 649d58716..000000000 --- a/app/renderer/js/spellchecker.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type {Subject} from 'rxjs'; -import {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} from 'electron-spellchecker'; - -import * as ConfigUtil from './utils/config-util'; -import Logger from './utils/logger-util'; - -declare module 'electron-spellchecker' { - interface SpellCheckHandler { - currentSpellcheckerChanged: Subject; - currentSpellcheckerLanguage: string; - } -} - -const logger = new Logger({ - file: 'errors.log', - timestamp: true -}); - -let spellCheckHandler: SpellCheckHandler; -let contextMenuListener: ContextMenuListener; - -export function init(serverLanguage: string): void { - if (ConfigUtil.getConfigItem('enableSpellchecker')) { - enableSpellChecker(); - } - - enableContextMenu(serverLanguage); -} - -function enableSpellChecker(): void { - try { - spellCheckHandler = new SpellCheckHandler(); - } catch (error) { - logger.error(error); - } -} - -function enableContextMenu(serverLanguage: string): void { - if (spellCheckHandler) { - spellCheckHandler.attachToInput(); - spellCheckHandler.switchLanguage(serverLanguage); - spellCheckHandler.currentSpellcheckerChanged.subscribe(() => { - spellCheckHandler.switchLanguage(spellCheckHandler.currentSpellcheckerLanguage); - }); - } - - const contextMenuBuilder = new ContextMenuBuilder(spellCheckHandler); - contextMenuListener = new ContextMenuListener(info => { - contextMenuBuilder.showPopupMenu(info); - }); -} - -export function unsubscribeSpellChecker(): void { - if (spellCheckHandler) { - spellCheckHandler.unsubscribe(); - } - - if (contextMenuListener) { - contextMenuListener.unsubscribe(); - } -} diff --git a/app/renderer/preference.html b/app/renderer/preference.html index 6c32294a6..6e8e25a16 100644 --- a/app/renderer/preference.html +++ b/app/renderer/preference.html @@ -5,6 +5,7 @@ Zulip - Settings +
@@ -13,6 +14,7 @@
diff --git a/package-lock.json b/package-lock.json index eee324709..dd51f4d41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,39 +10,6 @@ "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", "dev": true }, - "@aabuhijleh/electron-remote": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@aabuhijleh/electron-remote/-/electron-remote-1.4.0.tgz", - "integrity": "sha512-EG4ZXxqbFY4lpX55vctwz14mFrEOcOHFCMLH5z5lOl6fiviTqscy86tSlKwEE3/o3ExtdPr2tECgCogYYL7d+g==", - "requires": { - "debug": "^2.5.1", - "hashids": "^1.1.1", - "lodash.get": "^4.4.2", - "pify": "^2.3.0", - "rxjs": "^5.0.0-beta.12", - "xmlhttprequest": "^1.8.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, "@babel/code-frame": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", @@ -419,14 +386,6 @@ } } }, - "@felixrieseberg/spellchecker": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@felixrieseberg/spellchecker/-/spellchecker-4.0.12.tgz", - "integrity": "sha512-jLAPnRALB1I6Un8ldHVJfJid7m2R1qXoafFF/95sdm7R5VPOsZ3xTreZ/wLKO5x9AdsD2t9zpOcjDFTsCf3VzQ==", - "requires": { - "nan": "^2.14.0" - } - }, "@istanbuljs/load-nyc-config": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", @@ -659,15 +618,6 @@ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", "dev": true }, - "@types/electron-spellchecker": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/electron-spellchecker/-/electron-spellchecker-1.1.2.tgz", - "integrity": "sha512-rVPuBtBf6C5Sh8ixkx3MfpvNiI+/sBtrin79+dGhG1kCUxvajX+5L9gWePGhqO6AuHLyRQ06et6WVWtgtWoY4g==", - "dev": true, - "requires": { - "electron": ">=1.6.10" - } - }, "@types/escape-html": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-0.0.20.tgz", @@ -868,6 +818,11 @@ } } }, + "@yaireo/tagify": { + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-3.10.2.tgz", + "integrity": "sha512-gIQinTUz/dVJ650FNFuSyCeYlxi+T/6RJobYAeMKNXZTmr2hrEPLs5LHFo05Kt/S3T81ru6ZtQw3vbROEHpzqA==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1566,7 +1521,8 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", @@ -1629,11 +1585,6 @@ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, - "bcp47": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz", - "integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4=" - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -1726,7 +1677,8 @@ "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2190,54 +2142,6 @@ } } }, - "cld": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/cld/-/cld-2.6.0.tgz", - "integrity": "sha512-2U8Uiv7Bvl1v4fNWFGB3RYtPvhUWXQJ1MoNKJNVuoALfandEt9oVqK64S+3ZLvQPjDiYjsohtTep/wIs0xOXkw==", - "requires": { - "glob": "^5.0.10", - "node-addon-api": "*", - "rimraf": "^2.4.0", - "underscore": "^1.6.0" - }, - "dependencies": { - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - } - } - }, "clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -2475,7 +2379,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-stream": { "version": "1.6.2", @@ -3478,25 +3383,6 @@ "mime": "^2.4.4" } }, - "electron-spellchecker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/electron-spellchecker/-/electron-spellchecker-2.2.1.tgz", - "integrity": "sha512-IqxJmYq/5qyTNo9ONxHr9D/9UxiXVvDbl01s2f71S3aAHtDIc7I7qqEycvNUlFGR1WVBgFc/VzV4+deQwxgikA==", - "requires": { - "@aabuhijleh/electron-remote": "^1.4.0", - "@felixrieseberg/spellchecker": "^4.0.12", - "bcp47": "^1.1.2", - "cld": "^2.5.1", - "debug": "^4.1.1", - "keyboard-layout": "^2.0.16", - "lru-cache": "^5.1.1", - "mkdirp": "^0.5.1", - "pify": "^4.0.1", - "rxjs": "^5.0.1", - "rxjs-serial-subscription": "^0.1.1", - "spawn-rx": "^2.0.7" - } - }, "electron-to-chromium": { "version": "1.3.427", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.427.tgz", @@ -4765,11 +4651,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "event-kit": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz", - "integrity": "sha512-b7Qi1JNzY4BfAYfnIRanLk0DOD1gdkWHT4GISIn8Q2tAf3LpU8SP2CMwWaq40imYoKWbtN4ZhbSRxvsnikooZQ==" - }, "event-target-shim": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-1.1.1.tgz", @@ -5443,7 +5324,8 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "1.2.12", @@ -6674,11 +6556,6 @@ } } }, - "hashids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/hashids/-/hashids-1.2.2.tgz", - "integrity": "sha512-dEHCG2LraR6PNvSGxosZHIRgxF5sNLOIBFEHbj8lfP9WWmu/PWPMzsip1drdVSOFi51N2pU7gZavrgn7sbGFuw==" - }, "highlight.js": { "version": "9.18.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", @@ -7003,6 +6880,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -7011,7 +6889,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "1.3.5", @@ -7531,6 +7410,11 @@ "unc-path-regex": "^0.1.2" } }, + "iso-639-1": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/iso-639-1/-/iso-639-1-2.1.3.tgz", + "integrity": "sha512-2auwfdxdHbqDk/RqEAhYlR+dUHnfD2u2T20mb10gVg07FNqWdCTFTwObA2BNSCk4cZ6hmniyFKwERHP+ZiMoWA==" + }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", @@ -7932,15 +7816,6 @@ "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", "dev": true }, - "keyboard-layout": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/keyboard-layout/-/keyboard-layout-2.0.16.tgz", - "integrity": "sha512-eGrxmlV6jbm/mbPEOpYGuH53XEC7wIUj9ZxKcT2z9QHJ/RwrT9iVkvxka9zRxqHZHwQzcffgsa5OxoVAKnhK9w==", - "requires": { - "event-kit": "^2.0.0", - "nan": "^2.13.2" - } - }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -8104,11 +7979,6 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" - }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", @@ -8118,7 +7988,8 @@ "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true }, "lodash.isequal": { "version": "4.5.0", @@ -8224,6 +8095,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "requires": { "yallist": "^3.0.2" } @@ -8525,7 +8397,8 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8662,11 +8535,6 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, - "node-addon-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz", - "integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==" - }, "node-json-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/node-json-db/-/node-json-db-1.1.0.tgz", @@ -9242,6 +9110,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -9639,7 +9508,8 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true }, "pinkie": { "version": "2.0.4", @@ -10868,22 +10738,6 @@ "rx-lite": "*" } }, - "rxjs": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", - "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", - "requires": { - "symbol-observable": "1.0.1" - } - }, - "rxjs-serial-subscription": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/rxjs-serial-subscription/-/rxjs-serial-subscription-0.1.1.tgz", - "integrity": "sha1-pCsdsL8QlLCSMRkeJ3jKP8+e0Uc=", - "requires": { - "rxjs": "^5.0.0-beta.12" - } - }, "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", @@ -11306,31 +11160,6 @@ "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", "dev": true }, - "spawn-rx": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz", - "integrity": "sha512-gOPXiQQFQ9lTOLuys0iMn3jfxxv9c7zzwhbYLOEbQGvEShHVJ5sSR1oD3Daj88os7jKArDYT7rbOKdvNhe7iEg==", - "requires": { - "debug": "^2.5.1", - "lodash.assign": "^4.2.0", - "rxjs": "^5.1.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, "spawn-sync": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", @@ -12036,11 +11865,6 @@ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", "dev": true }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" - }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -12583,11 +12407,6 @@ } } }, - "underscore": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", - "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==" - }, "undertaker": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", @@ -13288,7 +13107,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write": { "version": "1.0.3", @@ -13330,11 +13150,6 @@ "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", "dev": true }, - "xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" - }, "xo": { "version": "0.30.0", "resolved": "https://registry.npmjs.org/xo/-/xo-0.30.0.tgz", @@ -13785,7 +13600,8 @@ "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true }, "yaml": { "version": "1.9.2", diff --git a/package.json b/package.json index 7da0b8430..8c8b6889f 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,7 @@ "**/*.node" ], "files": [ - "app/**/*", - "!**/node_modules/cld/deps/cld" + "app/**/*" ], "copyright": "©2019 Kandra Labs, Inc.", "mac": { @@ -148,20 +147,21 @@ "dependencies": { "@electron-elements/send-feedback": "^2.0.3", "@sentry/electron": "^1.3.0", + "@yaireo/tagify": "^3.10.2", "adm-zip": "^0.4.14", "auto-launch": "^5.0.5", "backoff": "^2.5.0", "electron-is-dev": "^1.2.0", "electron-log": "^4.1.2", - "electron-spellchecker": "^2.2.1", "electron-updater": "^4.3.1", "electron-window-state": "^5.0.3", "escape-html": "^1.0.3", "fs-extra": "^9.0.0", "i18n": "^0.9.1", + "iso-639-1": "^2.1.3", + "nan": "^2.14.0", "node-json-db": "^1.1.0", "request": "^2.88.2", - "rxjs": "^5.5.12", "semver": "^7.3.2" }, "optionalDependencies": { @@ -171,7 +171,6 @@ "@types/adm-zip": "^0.4.33", "@types/auto-launch": "^5.0.1", "@types/backoff": "^2.5.1", - "@types/electron-spellchecker": "^1.1.2", "@types/escape-html": "0.0.20", "@types/fs-extra": "^8.1.0", "@types/i18n": "^0.8.6", diff --git a/typings.d.ts b/typings.d.ts index c553abeb6..195ff34c7 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -16,6 +16,8 @@ declare module '@electron-elements/send-feedback' { declare module 'node-mac-notifier'; +declare module '@yaireo/tagify'; + interface ClipboardDecrypter { version: number; key: Uint8Array;