Use Electron Spellchecker
This commit is contained in:
parent
42152be4af
commit
4a8f5db0a4
15 changed files with 195 additions and 381 deletions
|
@ -147,6 +147,14 @@
|
|||
"message": "Set Up as Standalone Device",
|
||||
"description": "Only available on development modes, menu option to open up the standalone device setup sequence"
|
||||
},
|
||||
"contextMenuCopyLink": {
|
||||
"message": "Copy Link",
|
||||
"description": "Shown in the context menu for a link to indicate that the user can copy the link"
|
||||
},
|
||||
"contextMenuNoSuggestions": {
|
||||
"message": "No Suggestions",
|
||||
"description": "Shown in the context menu for a misspelled word to indicate that there are no suggestions to replace the misspelled word"
|
||||
},
|
||||
"avatarMenuViewArchive": {
|
||||
"message": "View Archive",
|
||||
"description": "One of the menu options available in the Avatar Popup menu"
|
||||
|
@ -1080,6 +1088,10 @@
|
|||
"message": "Enable spell check of text entered in message composition box",
|
||||
"description": "Description of the media permission description"
|
||||
},
|
||||
"spellCheckDirty": {
|
||||
"message": "You must restart Signal to apply your new settings",
|
||||
"description": "Shown when the user changes their spellcheck setting to indicate that they must restart Signal."
|
||||
},
|
||||
"clearDataHeader": {
|
||||
"message": "Clear Data",
|
||||
"description": "Header in the settings dialog for the section dealing with data deletion"
|
||||
|
|
102
app/spell_check.js
Normal file
102
app/spell_check.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
/* global exports, require */
|
||||
/* eslint-disable strict */
|
||||
|
||||
const { Menu, clipboard } = require('electron');
|
||||
const osLocale = require('os-locale');
|
||||
|
||||
exports.setup = (browserWindow, messages) => {
|
||||
const { session } = browserWindow.webContents;
|
||||
const userLocale = osLocale.sync().replace(/_/g, '-');
|
||||
const userLocales = [userLocale, userLocale.split('-')[0]];
|
||||
const available = session.availableSpellCheckerLanguages;
|
||||
const languages = userLocales.filter(l => available.includes(l));
|
||||
console.log(`spellcheck: user locale: ${userLocale}`);
|
||||
console.log('spellcheck: available spellchecker languages: ', available);
|
||||
console.log('spellcheck: setting languages to: ', languages);
|
||||
session.setSpellCheckerLanguages(languages);
|
||||
|
||||
browserWindow.webContents.on('context-menu', (_event, params) => {
|
||||
const { editFlags } = params;
|
||||
const isMisspelled = Boolean(params.misspelledWord);
|
||||
const isLink = Boolean(params.linkURL);
|
||||
const showMenu = params.isEditable || editFlags.canCopy || isLink;
|
||||
|
||||
// Popup editor menu
|
||||
if (showMenu) {
|
||||
const template = [];
|
||||
|
||||
if (isMisspelled) {
|
||||
if (params.dictionarySuggestions.length > 0) {
|
||||
template.push(
|
||||
...params.dictionarySuggestions.map(label => ({
|
||||
label,
|
||||
click: () => {
|
||||
browserWindow.webContents.replaceMisspelling(label);
|
||||
},
|
||||
}))
|
||||
);
|
||||
} else {
|
||||
template.push({
|
||||
label: messages.contextMenuNoSuggestions.message,
|
||||
enabled: false,
|
||||
});
|
||||
}
|
||||
template.push({ type: 'separator' });
|
||||
}
|
||||
|
||||
if (params.isEditable) {
|
||||
if (editFlags.canUndo) {
|
||||
template.push({ label: messages.editMenuUndo.message, role: 'undo' });
|
||||
}
|
||||
// This is only ever `true` if undo was triggered via the context menu
|
||||
// (not ctrl/cmd+z)
|
||||
if (editFlags.canRedo) {
|
||||
template.push({ label: messages.editMenuRedo.message, role: 'redo' });
|
||||
}
|
||||
if (editFlags.canUndo || editFlags.canRedo) {
|
||||
template.push({ type: 'separator' });
|
||||
}
|
||||
if (editFlags.canCut) {
|
||||
template.push({ label: messages.editMenuCut.message, role: 'cut' });
|
||||
}
|
||||
}
|
||||
|
||||
if (editFlags.canCopy || isLink) {
|
||||
template.push({
|
||||
label: isLink
|
||||
? messages.contextMenuCopyLink.message
|
||||
: messages.editMenuCopy.message,
|
||||
role: isLink ? undefined : 'copy',
|
||||
click: isLink
|
||||
? () => {
|
||||
clipboard.writeText(params.linkURL);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (editFlags.canPaste) {
|
||||
template.push({ label: messages.editMenuPaste.message, role: 'paste' });
|
||||
}
|
||||
|
||||
if (editFlags.canPaste) {
|
||||
template.push({
|
||||
label: messages.editMenuPasteAndMatchStyle.message,
|
||||
role: 'pasteAndMatchStyle',
|
||||
});
|
||||
}
|
||||
|
||||
// Only enable select all in editors because select all in non-editors
|
||||
// results in all the UI being selected
|
||||
if (editFlags.canSelectAll && params.isEditable) {
|
||||
template.push({
|
||||
label: messages.editMenuSelectAll.message,
|
||||
role: 'selectall',
|
||||
});
|
||||
}
|
||||
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
menu.popup(browserWindow);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -334,7 +334,6 @@
|
|||
getSpellCheck: () => storage.get('spell-check', true),
|
||||
setSpellCheck: value => {
|
||||
storage.put('spell-check', value);
|
||||
startSpellCheck();
|
||||
},
|
||||
|
||||
// eslint-disable-next-line eqeqeq
|
||||
|
@ -545,19 +544,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
const startSpellCheck = () => {
|
||||
if (!window.enableSpellCheck || !window.disableSpellCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.Events.getSpellCheck()) {
|
||||
window.enableSpellCheck();
|
||||
} else {
|
||||
window.disableSpellCheck();
|
||||
}
|
||||
};
|
||||
startSpellCheck();
|
||||
|
||||
try {
|
||||
await Promise.all([
|
||||
ConversationController.load(),
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
/* global require, process, _ */
|
||||
|
||||
/* eslint-disable strict */
|
||||
|
||||
const electron = require('electron');
|
||||
|
||||
const Typo = require('typo-js');
|
||||
const osLocale = require('os-locale');
|
||||
|
||||
const { remote, webFrame } = electron;
|
||||
|
||||
// `remote.require` since `Menu` is a main-process module.
|
||||
const buildEditorContextMenu = remote.require('electron-editor-context-menu');
|
||||
|
||||
const EN_VARIANT = /^en/;
|
||||
|
||||
// Prevent the spellchecker from showing contractions as errors.
|
||||
const ENGLISH_SKIP_WORDS = [
|
||||
'ain',
|
||||
'couldn',
|
||||
'didn',
|
||||
'doesn',
|
||||
'hadn',
|
||||
'hasn',
|
||||
'mightn',
|
||||
'mustn',
|
||||
'needn',
|
||||
'oughtn',
|
||||
'shan',
|
||||
'shouldn',
|
||||
'wasn',
|
||||
'weren',
|
||||
'wouldn',
|
||||
];
|
||||
|
||||
function setupLinux(locale) {
|
||||
if (EN_VARIANT.test(locale)) {
|
||||
window.log.info('Detected English locale on Linux. Enabling spell check.');
|
||||
|
||||
return new Typo(locale);
|
||||
}
|
||||
|
||||
window.log.info(
|
||||
'Detected non-English locale on Linux. Disabling spell check.'
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// We load locale this way and not via app.getLocale() because this call returns
|
||||
// 'es_ES' and not just 'es.' And hunspell requires the fully-qualified locale.
|
||||
const locale = osLocale.sync().replace('-', '_');
|
||||
|
||||
// The LANG environment variable is how node spellchecker finds its default language:
|
||||
// https://github.com/atom/node-spellchecker/blob/59d2d5eee5785c4b34e9669cd5d987181d17c098/lib/spellchecker.js#L29
|
||||
if (!process.env.LANG) {
|
||||
process.env.LANG = locale;
|
||||
}
|
||||
|
||||
let spellchecker = null;
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
spellchecker = setupLinux(locale);
|
||||
} else {
|
||||
spellchecker = new Typo(locale);
|
||||
// OSX and Windows 8+ have OS-level spellcheck APIs
|
||||
window.log.info(
|
||||
'Using OS-level spell check API with locale',
|
||||
process.env.LANG
|
||||
);
|
||||
}
|
||||
|
||||
const simpleChecker = {
|
||||
spellCheck(words, callback) {
|
||||
const mispelled = words.filter(word => this.isMisspelled(word));
|
||||
callback(mispelled);
|
||||
},
|
||||
isMisspelled(word) {
|
||||
if (!spellchecker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const misspelled = !spellchecker.check(word);
|
||||
|
||||
// The idea is to make this as fast as possible. For the many, many calls which
|
||||
// don't result in the red squiggly, we minimize the number of checks.
|
||||
if (!misspelled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only if we think we've found an error do we check the locale and skip list.
|
||||
if (locale.match(EN_VARIANT) && _.contains(ENGLISH_SKIP_WORDS, word)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
getSuggestions(text) {
|
||||
if (!spellchecker) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return spellchecker.suggest(text);
|
||||
},
|
||||
add() {},
|
||||
};
|
||||
|
||||
const dummyChecker = {
|
||||
spellCheck(words, callback) {
|
||||
callback([]);
|
||||
},
|
||||
isMisspelled() {
|
||||
return false;
|
||||
},
|
||||
getSuggestions() {
|
||||
return [];
|
||||
},
|
||||
add() {
|
||||
// nothing
|
||||
},
|
||||
};
|
||||
|
||||
window.spellChecker = simpleChecker;
|
||||
window.disableSpellCheck = () => {
|
||||
window.removeEventListener('contextmenu', spellCheckHandler);
|
||||
window.addEventListener('contextmenu', defaultContextMenuHandler);
|
||||
webFrame.setSpellCheckProvider('en-US', dummyChecker);
|
||||
};
|
||||
|
||||
window.enableSpellCheck = () => {
|
||||
webFrame.setSpellCheckProvider('en-US', simpleChecker);
|
||||
window.addEventListener('contextmenu', spellCheckHandler);
|
||||
window.removeEventListener('contextmenu', defaultContextMenuHandler);
|
||||
};
|
||||
|
||||
const defaultContextMenuHandler = e => {
|
||||
// Only show the context menu in text editors.
|
||||
if (!e.target.closest('textarea, input, [contenteditable="true"]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const menu = buildEditorContextMenu({});
|
||||
|
||||
// @see js/spell_check.js:177
|
||||
setTimeout(() => {
|
||||
menu.popup(remote.getCurrentWindow());
|
||||
}, 30);
|
||||
};
|
||||
|
||||
const spellCheckHandler = e => {
|
||||
// Only show the context menu in text editors.
|
||||
if (!e.target.closest('textarea, input, [contenteditable="true"]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedText = window.getSelection().toString();
|
||||
const isMisspelled = selectedText && simpleChecker.isMisspelled(selectedText);
|
||||
const spellingSuggestions =
|
||||
isMisspelled && simpleChecker.getSuggestions(selectedText).slice(0, 5);
|
||||
const menu = buildEditorContextMenu({
|
||||
isMisspelled,
|
||||
spellingSuggestions,
|
||||
});
|
||||
|
||||
// The 'contextmenu' event is emitted after 'selectionchange' has fired
|
||||
// but possibly before the visible selection has changed. Try to wait
|
||||
// to show the menu until after that, otherwise the visible selection
|
||||
// will update after the menu dismisses and look weird.
|
||||
setTimeout(() => {
|
||||
menu.popup(remote.getCurrentWindow());
|
||||
}, 30);
|
||||
};
|
|
@ -106,7 +106,17 @@
|
|||
el: this.$('.spell-check-setting'),
|
||||
name: 'spell-check-setting',
|
||||
value: window.initialData.spellCheck,
|
||||
setFn: window.setSpellCheck,
|
||||
setFn: val => {
|
||||
const $msg = this.$('.spell-check-setting-message');
|
||||
if (val !== window.appStartInitialSpellcheckSetting) {
|
||||
$msg.show();
|
||||
$msg.attr('aria-hidden', false);
|
||||
} else {
|
||||
$msg.hide();
|
||||
$msg.attr('aria-hidden', true);
|
||||
}
|
||||
window.setSpellCheck(val);
|
||||
},
|
||||
});
|
||||
if (Settings.isHideMenuBarSupported()) {
|
||||
new CheckboxView({
|
||||
|
@ -131,6 +141,10 @@
|
|||
'click .clear-data': 'onClearData',
|
||||
},
|
||||
render_attributes() {
|
||||
const spellCheckDirty =
|
||||
window.initialData.spellCheck !==
|
||||
window.appStartInitialSpellcheckSetting;
|
||||
|
||||
return {
|
||||
deviceNameLabel: i18n('deviceName'),
|
||||
deviceName: window.initialData.deviceName,
|
||||
|
@ -157,6 +171,9 @@
|
|||
mediaPermissionsDescription: i18n('mediaPermissionsDescription'),
|
||||
generalHeader: i18n('general'),
|
||||
spellCheckDescription: i18n('spellCheckDescription'),
|
||||
spellCheckHidden: spellCheckDirty ? 'false' : 'true',
|
||||
spellCheckDisplay: spellCheckDirty ? 'inherit' : 'none',
|
||||
spellCheckDirtyText: i18n('spellCheckDirty'),
|
||||
};
|
||||
},
|
||||
onClose() {
|
||||
|
|
25
main.js
25
main.js
|
@ -16,6 +16,7 @@ const electron = require('electron');
|
|||
|
||||
const packageJson = require('./package.json');
|
||||
const GlobalErrors = require('./app/global_errors');
|
||||
const { setup: setupSpellChecker } = require('./app/spell_check');
|
||||
|
||||
GlobalErrors.addHandler();
|
||||
|
||||
|
@ -94,6 +95,19 @@ const {
|
|||
} = require('./app/protocol_filter');
|
||||
const { installPermissionsHandler } = require('./app/permissions');
|
||||
|
||||
let appStartInitialSpellcheckSetting = true;
|
||||
|
||||
async function getSpellCheckSetting() {
|
||||
const json = await sql.getItemById('spell-check');
|
||||
|
||||
// Default to `true` if setting doesn't exist yet
|
||||
if (!json) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return json.value;
|
||||
}
|
||||
|
||||
function showWindow() {
|
||||
if (!mainWindow) {
|
||||
return;
|
||||
|
@ -182,6 +196,7 @@ function prepareURL(pathSegments, moreKeys) {
|
|||
contentProxyUrl: config.contentProxyUrl,
|
||||
importMode: importMode ? true : undefined, // for stringify()
|
||||
serverTrustRoot: config.get('serverTrustRoot'),
|
||||
appStartInitialSpellcheckSetting,
|
||||
...moreKeys,
|
||||
},
|
||||
});
|
||||
|
@ -240,7 +255,7 @@ function isVisible(window, bounds) {
|
|||
);
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
async function createWindow() {
|
||||
const { screen } = electron;
|
||||
const windowOptions = Object.assign(
|
||||
{
|
||||
|
@ -260,6 +275,7 @@ function createWindow() {
|
|||
contextIsolation: false,
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
nativeWindowOpen: true,
|
||||
spellcheck: await getSpellCheckSetting(),
|
||||
},
|
||||
icon: path.join(__dirname, 'images', 'icon_256.png'),
|
||||
},
|
||||
|
@ -296,6 +312,7 @@ function createWindow() {
|
|||
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow(windowOptions);
|
||||
setupSpellChecker(mainWindow, locale.messages);
|
||||
if (!usingTrayIcon && windowConfig && windowConfig.maximized) {
|
||||
mainWindow.maximize();
|
||||
}
|
||||
|
@ -525,7 +542,7 @@ function showAbout() {
|
|||
}
|
||||
|
||||
let settingsWindow;
|
||||
async function showSettingsWindow() {
|
||||
function showSettingsWindow() {
|
||||
if (settingsWindow) {
|
||||
settingsWindow.show();
|
||||
return;
|
||||
|
@ -621,10 +638,12 @@ async function showStickerCreator() {
|
|||
contextIsolation: false,
|
||||
preload: path.join(__dirname, 'sticker-creator/preload.js'),
|
||||
nativeWindowOpen: true,
|
||||
spellcheck: await getSpellCheckSetting(),
|
||||
},
|
||||
};
|
||||
|
||||
stickerCreatorWindow = new BrowserWindow(options);
|
||||
setupSpellChecker(stickerCreatorWindow, locale.messages);
|
||||
|
||||
handleCommonWindowEvents(stickerCreatorWindow);
|
||||
|
||||
|
@ -797,6 +816,8 @@ app.on('ready', async () => {
|
|||
console.log('sql.initialize was unsuccessful; returning early');
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line more/no-then
|
||||
appStartInitialSpellcheckSetting = await getSpellCheckSetting();
|
||||
await sqlChannels.initialize();
|
||||
|
||||
try {
|
||||
|
|
|
@ -75,8 +75,6 @@
|
|||
"copy-text-to-clipboard": "2.1.0",
|
||||
"curve25519-n": "https://github.com/scottnonnenberg-signal/node-curve25519.git#3e94f60bc54b2426476520d8d1a0aa835c25f5cc",
|
||||
"draft-js": "0.10.5",
|
||||
"electron-context-menu": "0.11.0",
|
||||
"electron-editor-context-menu": "1.1.1",
|
||||
"electron-mocha": "8.1.1",
|
||||
"electron-notarize": "0.1.1",
|
||||
"emoji-datasource": "5.0.1",
|
||||
|
@ -139,7 +137,6 @@
|
|||
"tmp": "0.0.33",
|
||||
"to-arraybuffer": "1.0.1",
|
||||
"typeface-inter": "3.10.0",
|
||||
"typo-js": "1.1.0",
|
||||
"underscore": "1.9.0",
|
||||
"uuid": "3.3.2",
|
||||
"websocket": "1.0.28"
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
diff --git a/node_modules/typo-js/typo.js b/node_modules/typo-js/typo.js
|
||||
index 68c285b..95ebc6c 100644
|
||||
--- a/node_modules/typo-js/typo.js
|
||||
+++ b/node_modules/typo-js/typo.js
|
||||
@@ -431,7 +431,7 @@ Typo.prototype = {
|
||||
dictionaryTable[word] = null;
|
||||
}
|
||||
|
||||
- if (rules.length > 0) {
|
||||
+ if (rules && rules.length > 0) {
|
||||
if (dictionaryTable[word] === null) {
|
||||
dictionaryTable[word] = [];
|
||||
}
|
||||
@@ -546,6 +546,7 @@ Typo.prototype = {
|
||||
else if (this.flags.FLAG === "num") {
|
||||
return textCodes.split(",");
|
||||
}
|
||||
+ return [];
|
||||
},
|
||||
|
||||
/**
|
24
preload.js
24
preload.js
|
@ -395,23 +395,17 @@ try {
|
|||
window.Signal.Debug = require('./js/modules/debug');
|
||||
window.Signal.Logs = require('./js/modules/logs');
|
||||
|
||||
// Add right-click listener for selected text and urls
|
||||
const contextMenu = require('electron-context-menu');
|
||||
|
||||
contextMenu({
|
||||
showInspectElement: false,
|
||||
shouldShowMenu: (event, params) =>
|
||||
Boolean(
|
||||
!params.isEditable &&
|
||||
params.mediaType === 'none' &&
|
||||
(params.linkURL || params.selectionText)
|
||||
),
|
||||
window.addEventListener('contextmenu', e => {
|
||||
const editable = e.target.closest(
|
||||
'textarea, input, [contenteditable="true"]'
|
||||
);
|
||||
const link = e.target.closest('a');
|
||||
const selection = Boolean(window.getSelection().toString());
|
||||
if (!editable && !selection && !link) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// We pull this in last, because the native module involved appears to be sensitive to
|
||||
// /tmp mounted as noexec on Linux.
|
||||
require('./js/spell_check');
|
||||
|
||||
if (config.environment === 'test') {
|
||||
/* eslint-disable global-require, import/no-extraneous-dependencies */
|
||||
window.test = {
|
||||
|
|
|
@ -100,6 +100,9 @@
|
|||
<div class='spell-check-setting'>
|
||||
<input type='checkbox' name='spell-check-setting' id='spell-check-setting' />
|
||||
<label for='spell-check-setting'>{{ spellCheckDescription }}</label>
|
||||
<p class='spell-check-setting-message' style='display: {{ spellCheckDisplay }};' aria-hidden='{{ spellCheckHidden }}'>
|
||||
{{ spellCheckDirtyText }}
|
||||
</p>
|
||||
</div>
|
||||
<hr>
|
||||
<div class='permissions-setting'>
|
||||
|
|
|
@ -14,6 +14,8 @@ const { nativeTheme } = remote.require('electron');
|
|||
window.platform = process.platform;
|
||||
window.theme = config.theme;
|
||||
window.i18n = i18n.setup(locale, localeMessages);
|
||||
window.appStartInitialSpellcheckSetting =
|
||||
config.appStartInitialSpellcheckSetting === 'true';
|
||||
|
||||
function setSystemTheme() {
|
||||
window.systemTheme = nativeTheme.shouldUseDarkColors ? 'dark' : 'light';
|
||||
|
|
|
@ -407,7 +407,6 @@
|
|||
<script type="text/javascript" src="crypto_test.js"></script>
|
||||
<script type="text/javascript" src="database_test.js"></script>
|
||||
<script type="text/javascript" src="i18n_test.js"></script>
|
||||
<script type="text/javascript" src="spellcheck_test.js"></script>
|
||||
|
||||
<!-- Comment out to turn off code coverage. Useful for getting real callstacks. -->
|
||||
<!-- NOTE: blanket doesn't support modern syntax and will choke until we find a replacement. :0( -->
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
describe('spellChecker', () => {
|
||||
it('should work', () => {
|
||||
let result = null;
|
||||
|
||||
window.spellChecker.spellCheck(['correct'], answer => {
|
||||
result = answer;
|
||||
});
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
window.spellChecker.spellCheck(['fhqwgads'], answer => {
|
||||
result = answer;
|
||||
});
|
||||
assert.deepEqual(result, ['fhqwgads']);
|
||||
});
|
||||
});
|
|
@ -883,73 +883,81 @@
|
|||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " el: this.$('.menu-bar-setting'),",
|
||||
"lineNumber": 113,
|
||||
"line": " const $msg = this.$('.spell-check-setting-message');",
|
||||
"lineNumber": 110,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2019-04-08T18:24:35.255Z",
|
||||
"updated": "2020-03-19T16:06:32.598Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " el: this.$('.menu-bar-setting'),",
|
||||
"lineNumber": 123,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-20T16:47:14.450Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " el: this.$('.media-permissions'),",
|
||||
"lineNumber": 120,
|
||||
"lineNumber": 130,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"updated": "2020-03-20T16:47:14.450Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " this.$('.sync-setting').append(syncView.el);",
|
||||
"lineNumber": 126,
|
||||
"lineNumber": 136,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"updated": "2020-03-20T16:47:14.450Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-append(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " this.$('.sync-setting').append(syncView.el);",
|
||||
"lineNumber": 126,
|
||||
"lineNumber": 136,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T18:13:29.628Z",
|
||||
"updated": "2020-03-20T16:47:14.450Z",
|
||||
"reasonDetail": "Interacting with already-existing DOM nodes"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " this.$('.sync').text(i18n('syncNow'));",
|
||||
"lineNumber": 181,
|
||||
"lineNumber": 198,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"updated": "2020-03-20T19:55:50.800Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " this.$('.sync').attr('disabled', 'disabled');",
|
||||
"lineNumber": 185,
|
||||
"lineNumber": 202,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"updated": "2020-03-20T19:55:50.800Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " this.$('.synced_at').hide();",
|
||||
"lineNumber": 197,
|
||||
"lineNumber": 214,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"updated": "2020-03-20T19:55:50.800Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/settings_view.js",
|
||||
"line": " this.$('.sync_failed').hide();",
|
||||
"lineNumber": 202,
|
||||
"lineNumber": 219,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"updated": "2020-03-20T19:55:50.800Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
|
@ -3141,22 +3149,6 @@
|
|||
"reasonCategory": "falseMatch",
|
||||
"updated": "2018-09-19T18:13:29.628Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-prepend(",
|
||||
"path": "node_modules/electron-context-menu/index.js",
|
||||
"line": "\t\t\tconst result = options.prepend(props, win);",
|
||||
"lineNumber": 122,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2019-04-10T19:08:25.356Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-append(",
|
||||
"path": "node_modules/electron-context-menu/index.js",
|
||||
"line": "\t\t\tconst result = options.append(props, win);",
|
||||
"lineNumber": 130,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2019-04-10T19:08:25.356Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-load(",
|
||||
"path": "node_modules/electron-download/node_modules/debug/src/browser.js",
|
||||
|
@ -11816,4 +11808,4 @@
|
|||
"reasonCategory": "falseMatch",
|
||||
"updated": "2020-02-07T19:52:28.522Z"
|
||||
}
|
||||
]
|
||||
]
|
103
yarn.lock
103
yarn.lock
|
@ -6181,23 +6181,6 @@ electron-chromedriver@~3.0.0:
|
|||
electron-download "^4.1.0"
|
||||
extract-zip "^1.6.5"
|
||||
|
||||
electron-context-menu@0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-context-menu/-/electron-context-menu-0.11.0.tgz#3ecefb0231151add474c9b0df2fb66fde3ad5731"
|
||||
integrity sha512-sgDIGqjgazUQ5fbfz0ObRkmODAsw00eylQprp5q4jyuL6dskd27yslhoJTrjLbFGErfVVYzRXPW2rQPJxARKmg==
|
||||
dependencies:
|
||||
electron-dl "^1.2.0"
|
||||
electron-is-dev "^1.0.1"
|
||||
|
||||
electron-dl@^1.2.0:
|
||||
version "1.14.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-dl/-/electron-dl-1.14.0.tgz#1466f1b945664ca3d784268307c2b935728177bf"
|
||||
integrity sha512-4okyei42a1mLsvLK7hLrIfd20EQzB18nIlLTwBV992aMSmTGLUEFRTmO1MfSslGNrzD8nuPuy1l/VxO8so4lig==
|
||||
dependencies:
|
||||
ext-name "^5.0.0"
|
||||
pupa "^1.0.0"
|
||||
unused-filename "^1.0.0"
|
||||
|
||||
electron-download@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845"
|
||||
|
@ -6212,17 +6195,6 @@ electron-download@^4.1.0:
|
|||
semver "^5.3.0"
|
||||
sumchecker "^2.0.1"
|
||||
|
||||
electron-editor-context-menu@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-editor-context-menu/-/electron-editor-context-menu-1.1.1.tgz#dc30098e0dfb37f62628e43303124c7f3379572d"
|
||||
integrity sha1-3DAJjg37N/YmKOQzAxJMfzN5Vy0=
|
||||
dependencies:
|
||||
lodash.clonedeep "^4.3.0"
|
||||
lodash.defaults "^4.0.1"
|
||||
lodash.isarray "^4.0.0"
|
||||
lodash.isempty "^4.1.2"
|
||||
lodash.isfunction "^3.0.8"
|
||||
|
||||
electron-icon-maker@0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/electron-icon-maker/-/electron-icon-maker-0.0.3.tgz#bcd2e91896d7200f84fcc6652aed924fdaaa8307"
|
||||
|
@ -6232,11 +6204,6 @@ electron-icon-maker@0.0.3:
|
|||
icon-gen "^1.0.7"
|
||||
jimp "^0.2.27"
|
||||
|
||||
electron-is-dev@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-1.0.1.tgz#6e0a184736fe7aea77d18210b0b0f6a02402c4bc"
|
||||
integrity sha512-iwM3EotA9HTXqMGpQRkR/kT8OZqBbdfHTnlwcxsjSLYqY8svvsq0MuujsWCn3/vtgRmDv/PC/gKUUpoZvi5C1w==
|
||||
|
||||
electron-mocha@8.1.1:
|
||||
version "8.1.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-mocha/-/electron-mocha-8.1.1.tgz#e540e7d9ba80a024007a18533ae491c18f9a0ce2"
|
||||
|
@ -6950,21 +6917,6 @@ express@^4.17.0, express@^4.17.1:
|
|||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
ext-list@^2.0.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
|
||||
integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
|
||||
dependencies:
|
||||
mime-db "^1.28.0"
|
||||
|
||||
ext-name@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6"
|
||||
integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==
|
||||
dependencies:
|
||||
ext-list "^2.0.0"
|
||||
sort-keys-length "^1.0.0"
|
||||
|
||||
extend-shallow@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
|
||||
|
@ -10264,10 +10216,6 @@ lodash.camelcase@^4.3.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
|
||||
|
||||
lodash.clonedeep@^4.3.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
|
||||
lodash.cond@^4.3.0:
|
||||
version "4.5.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5"
|
||||
|
@ -10277,26 +10225,10 @@ lodash.debounce@^4.0.8:
|
|||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
|
||||
|
||||
lodash.defaults@^4.0.1:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
|
||||
lodash.isarray@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-4.0.0.tgz#2aca496b28c4ca6d726715313590c02e6ea34403"
|
||||
|
||||
lodash.isempty@^4.1.2:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
|
||||
|
||||
lodash.isfunction@^3.0.8:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz#4db709fc81bc4a8fd7127a458a5346c5cdce2c6b"
|
||||
|
||||
lodash.memoize@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
|
@ -10804,11 +10736,6 @@ mime-db@1.40.0, "mime-db@>= 1.40.0 < 2":
|
|||
version "1.33.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
|
||||
|
||||
mime-db@^1.28.0:
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.39.0.tgz#f95a20275742f7d2ad0429acfe40f4233543780e"
|
||||
integrity sha512-DTsrw/iWVvwHH+9Otxccdyy0Tgiil6TWK/xhfARJZF/QFhwOgZgOIvA2/VIGpM8U7Q8z5nDmdDWC6tuVMJNibw==
|
||||
|
||||
mime-db@~1.27.0:
|
||||
version "1.27.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
|
||||
|
@ -11104,11 +11031,6 @@ mocha@~6.2.0:
|
|||
yargs-parser "13.0.0"
|
||||
yargs-unparser "1.5.0"
|
||||
|
||||
modify-filename@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/modify-filename/-/modify-filename-1.1.0.tgz#9a2dec83806fbb2d975f22beec859ca26b393aa1"
|
||||
integrity sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE=
|
||||
|
||||
moment@2.21.0:
|
||||
version "2.21.0"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.21.0.tgz#2a114b51d2a6ec9e6d83cf803f838a878d8a023a"
|
||||
|
@ -13156,11 +13078,6 @@ punycode@^2.1.0:
|
|||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
|
||||
|
||||
pupa@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pupa/-/pupa-1.0.0.tgz#9a9568a5af7e657b8462a6e9d5328743560ceff6"
|
||||
integrity sha1-mpVopa9+ZXuEYqbp1TKHQ1YM7/Y=
|
||||
|
||||
pupa@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.0.1.tgz#dbdc9ff48ffbea4a26a069b6f9f7abb051008726"
|
||||
|
@ -15312,13 +15229,6 @@ socks@~2.2.0:
|
|||
ip "^1.1.5"
|
||||
smart-buffer "^4.0.1"
|
||||
|
||||
sort-keys-length@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"
|
||||
integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=
|
||||
dependencies:
|
||||
sort-keys "^1.0.0"
|
||||
|
||||
sort-keys@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
|
||||
|
@ -16622,11 +16532,6 @@ typescript@3.7.4:
|
|||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19"
|
||||
integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==
|
||||
|
||||
typo-js@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.1.0.tgz#a5a9f592bcb453666bf70c9694da58705d025ed8"
|
||||
integrity sha512-W3kLbx+ML9PBl5Bzso/lTvVxk4BCveSNAtQeht59FEtxCdGThmn6wSHA4Xq3eQYAK24NHdisMM4JmsK0GFy/pg==
|
||||
|
||||
ua-parser-js@^0.7.18:
|
||||
version "0.7.19"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b"
|
||||
|
@ -16855,14 +16760,6 @@ unset-value@^1.0.0:
|
|||
has-value "^0.3.1"
|
||||
isobject "^3.0.0"
|
||||
|
||||
unused-filename@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unused-filename/-/unused-filename-1.0.0.tgz#d340880f71ae2115ebaa1325bef05cc6684469c6"
|
||||
integrity sha1-00CID3GuIRXrqhMlvvBcxmhEacY=
|
||||
dependencies:
|
||||
modify-filename "^1.1.0"
|
||||
path-exists "^3.0.0"
|
||||
|
||||
unzip-response@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
|
||||
|
|
Loading…
Reference in a new issue