use electron 8 spellchecker instead of electron-spellchecker, WIP

This commit is contained in:
zadam 2020-02-28 22:07:08 +01:00
parent a2d6a5c3e9
commit 16f42dd4ab
30 changed files with 98 additions and 74 deletions

View File

@ -1,4 +1,4 @@
FROM node:12.16.0-alpine
FROM node:12.16.1-alpine
# Create app directory
WORKDIR /usr/src/app

View File

@ -11,11 +11,9 @@ echo "Copying required linux-x64 binaries"
rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
cp -r bin/deps/linux-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/linux-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/linux-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite

View File

@ -13,15 +13,11 @@ rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
rm -r $SRC_DIR/node_modules/mozjpeg/vendor/*
rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
rm -r $SRC_DIR/node_modules/giflossy/vendor/*
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
rm -r $SRC_DIR/node_modules/keyboard-layout/build/Release/*
cp -r bin/deps/mac-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/mac-x64/image/cjpeg $SRC_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/mac-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/mac-x64/image/gifsicle $SRC_DIR/node_modules/giflossy/vendor/
cp bin/deps/mac-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
cp bin/deps/mac-x64/keyboard-layout-manager.node $SRC_DIR/node_modules/keyboard-layout/build/Release/
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=images/app-icons/mac/icon.icns

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=12.16.0
NODE_VERSION=12.16.1
if [ "$1" != "DONTCOPY" ]
then

View File

@ -13,16 +13,11 @@ rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
rm -r $SRC_DIR/node_modules/mozjpeg/vendor/*
rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
rm -r $SRC_DIR/node_modules/giflossy/vendor/*
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
rm -r $SRC_DIR/node_modules/keyboard-layout/build/Release/*
rm -r $SRC_DIR/node_modules/cld/build/Release/*
cp -r bin/deps/win-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/win-x64/image/cjpeg.exe $SRC_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/win-x64/image/pngquant.exe $SRC_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/win-x64/image/gifsicle.exe $SRC_DIR/node_modules/giflossy/vendor/
cp bin/deps/win-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
cp bin/deps/win-x64/keyboard-layout-manager.node $SRC_DIR/node_modules/keyboard-layout/build/Release/
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico

View File

@ -26,7 +26,4 @@ cp -r electron.js $DIR/
# run in subshell (so we return to original dir)
(cd $DIR && npm install --only=prod)
rm -r $DIR/node_modules/cld/deps
find $DIR/libraries -name "*.map" -type f -delete
find $DIR/libraries -name "hunspell.lib" -type f -delete

6
package-lock.json generated
View File

@ -2669,9 +2669,9 @@
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
},
"electron": {
"version": "9.0.0-beta.3",
"resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.3.tgz",
"integrity": "sha512-se2XiC3sc6o8EUL/uE7bOknW7/gh37mQ+7uX8idugfYyK1oCISfr5CqtVXOMNTwMtx0opdFQ1HFC+W2ckNiPXg==",
"version": "9.0.0-beta.4",
"resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.4.tgz",
"integrity": "sha512-XznzkZ8nWTclg7B/Bue8PgXPyaYygZvtIqiNSmI3mgJ710F69RO2IrM3Rs1ULS3qWA3sTDY6PO0UPyUeTxhP7g==",
"dev": true,
"requires": {
"@electron/get": "^1.0.1",

View File

@ -33,7 +33,6 @@
"electron-debug": "3.0.1",
"electron-dl": "3.0.0",
"electron-find": "1.0.6",
"electron-spellchecker": "2.2.1",
"electron-window-state": "5.0.3",
"express": "4.17.1",
"express-session": "1.17.0",
@ -75,7 +74,7 @@
"ws": "7.2.1"
},
"devDependencies": {
"electron": "9.0.0-beta.3",
"electron": "9.0.0-beta.4",
"electron-builder": "22.3.2",
"electron-packager": "14.2.1",
"electron-rebuild": "1.10.0",

View File

@ -66,6 +66,7 @@ import RenderTypeWidget from "./widgets/type_widgets/render.js";
import RelationMapTypeWidget from "./widgets/type_widgets/relation_map.js";
import ProtectedSessionTypeWidget from "./widgets/type_widgets/protected_session.js";
import BookTypeWidget from "./widgets/type_widgets/book.js";
import contextMenuService from "./services/context_menu.js";
if (utils.isElectron()) {
require('electron').ipcRenderer.on('globalShortcut', async function(event, actionName) {
@ -84,3 +85,43 @@ appContext.start();
noteTooltipService.setupGlobalTooltip();
noteAutocompleteService.init();
if (utils.isElectron()) {
const {webContents} = require('electron').remote.getCurrentWindow();
webContents.on('context-menu', (event, params) => {
const items = [
{title: "Hello", cmd: "openNoteInNewTab", uiIcon: "arrow-up-right"}
];
if (params.misspelledWord) {
items.push({
title: `Misspelled "<strong>${params.misspelledWord}</strong>"`,
cmd: "openNoteInNewTab",
uiIcon: ""
});
for (const suggestion of params.dictionarySuggestions) {
items.push({
title: suggestion,
command: "replaceMisspelling",
spellingSuggestion: suggestion,
uiIcon: ""
});
}
}
contextMenuService.initContextMenu({
x: params.x,
y: params.y,
items,
selectContextMenuItem: (e, {command, spellingSuggestion}) => {
if (command === 'replaceMisspelling') {
console.log("Replacing missspeling", spellingSuggestion);
require('electron').remote.getCurrentWindow().webContents.insertText(spellingSuggestion);
}
}
});
});
}

View File

@ -16,11 +16,11 @@ const TPL = `
<br/>
<div class="form-group">
<label for="spell-check-language-code">Language code</label>
<label for="spell-check-language-code">Language code(s)</label>
<input type="text" class="form-control" id="spell-check-language-code" placeholder="for example &quot;en-US&quot;, &quot;de-AT&quot;">
</div>
<p>Changes to the spell check options will take effect after application restart.</p>
<p>Multiple languages can be separated by comman. Changes to the spell check options will take effect after application restart.</p>
</div>
<div>

View File

@ -21,9 +21,7 @@ function initAttributeNameAutocomplete({ $el, attributeType, open }) {
const type = typeof attributeType === "function" ? attributeType() : attributeType;
const names = await server.get(`attributes/names/?type=${type}&query=${encodeURIComponent(term)}`);
const result = names.map(name => {
return {name};
});
const result = names.map(name => ({name}));
cb(result);
}
@ -44,7 +42,7 @@ async function initLabelValueAutocomplete({ $el, open }) {
}
const attributeValues = (await server.get('attributes/values/' + encodeURIComponent(attributeName)))
.map(attribute => { return { value: attribute }; });
.map(attribute => ({ value: attribute }));
if (attributeValues.length === 0) {
return;

View File

@ -3,15 +3,7 @@ const $contextMenuContainer = $("#context-menu-container");
let dateContextMenuOpenedMs = 0;
/**
* @param event - originating click event (used to get coordinates to display menu at position)
* @param {object} contextMenu - needs to have getContextMenuItems() and selectContextMenuItem(e, cmd)
*/
async function initContextMenu(event, contextMenu) {
event.stopPropagation();
$contextMenuContainer.empty();
async function initContextMenu(options) {
function addItems($parent, items) {
for (const item of items) {
if (item.title === '----') {
@ -33,15 +25,14 @@ async function initContextMenu(event, contextMenu) {
const $item = $("<li>")
.addClass("dropdown-item")
.append($link)
.attr("data-cmd", item.cmd)
.on('click', function (e) {
const cmd = $(e.target).closest(".dropdown-item").attr("data-cmd");
.on('mousedown', function (e) {
e.stopPropagation();
hideContextMenu();
e.originalTarget = event.target;
contextMenu.selectContextMenuItem(e, cmd);
hideContextMenu();
options.selectContextMenuItem(e, item);
// it's important to stop the propagation especially for sub-menus, otherwise the event
// might be handled again by top-level menu
@ -68,21 +59,22 @@ async function initContextMenu(event, contextMenu) {
}
}
addItems($contextMenuContainer, await contextMenu.getContextMenuItems());
$contextMenuContainer.empty();
addItems($contextMenuContainer, options.items);
keyboardActionService.updateDisplayedShortcuts($contextMenuContainer);
// code below tries to detect when dropdown would overflow from page
// in such case we'll position it above click coordinates so it will fit into client
const clickPosition = event.pageY;
const clientHeight = document.documentElement.clientHeight;
const contextMenuHeight = $contextMenuContainer.outerHeight() + 30;
let top;
if (clickPosition + contextMenuHeight > clientHeight) {
if (options.y + contextMenuHeight > clientHeight) {
top = clientHeight - contextMenuHeight - 10;
} else {
top = event.pageY - 10;
top = options.y - 10;
}
dateContextMenuOpenedMs = Date.now();
@ -90,7 +82,7 @@ async function initContextMenu(event, contextMenu) {
$contextMenuContainer.css({
display: "block",
top: top,
left: event.pageX - 20
left: options.x - 20
}).addClass("show");
}

View File

@ -1,6 +1,6 @@
import options from "./options.js";
export async function initSpellCheck() {
export async function initSpellCheck() {return;
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
const {remote, shell} = require('electron');

View File

@ -120,10 +120,10 @@ export default class NoteTreeWidget extends TabAwareWidget {
node.setSelected(true);
const notes = this.getSelectedNodes().map(node => { return {
const notes = this.getSelectedNodes().map(node => ({
noteId: node.data.noteId,
title: node.title
}});
}));
data.dataTransfer.setData("text", JSON.stringify(notes));

View File

@ -125,7 +125,7 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
return;
}
attributeValues = attributeValues.map(attribute => { return { value: attribute }; });
attributeValues = attributeValues.map(attribute => ({ value: attribute }));
$input.autocomplete({
appendTo: document.querySelector('body'),

View File

@ -114,12 +114,10 @@ export default class TextTypeWidget extends TypeWidget {
const codeBlockLanguages =
(await mimeTypesService.getMimeTypes())
.filter(mt => mt.enabled)
.map(mt => {
return {
.map(mt => ({
language: mt.mime.toLowerCase().replace(/[\W_]+/g,"-"),
label: mt.title
}
});
}));
// CKEditor since version 12 needs the element to be visible before initialization. At the same time
// we want to avoid flicker - i.e. show editor only once everything is ready. That's why we have separate

View File

@ -43,6 +43,7 @@ body {
min-height: 0;
padding-left: 10px;
width: 100%;
height: 100%;
}
.dropdown-menu {

View File

@ -133,12 +133,12 @@ async function getRelationMap(req) {
resp.relations = resp.relations.concat((await note.getRelations())
.filter(relation => noteIds.includes(relation.value))
.map(relation => { return {
.map(relation => ({
attributeId: relation.attributeId,
sourceNoteId: relation.noteId,
targetNoteId: relation.value,
name: relation.name
}; }));
})));
for (const relationDefinition of await note.getRelationDefinitions()) {
if (relationDefinition.value.inverseRelation) {

View File

@ -121,15 +121,13 @@ async function exportToTar(taskContext, branch, format, res) {
type: note.type,
mime: note.mime,
// we don't export utcDateCreated and utcDateModified of any entity since that would be a bit misleading
attributes: (await note.getOwnedAttributes()).map(attribute => {
return {
attributes: (await note.getOwnedAttributes()).map(attribute => ({
type: attribute.type,
name: attribute.name,
value: attribute.value,
isInheritable: attribute.isInheritable,
position: attribute.position
};
})
}))
};
taskContext.increaseProgressCount();

View File

@ -102,13 +102,11 @@ async function initStartupOptions() {
function getKeyboardDefaultOptions() {
return keyboardActions.DEFAULT_KEYBOARD_ACTIONS
.filter(ka => !!ka.actionName)
.map(ka => {
return {
.map(ka => ({
name: "keyboardShortcuts" + ka.actionName.charAt(0).toUpperCase() + ka.actionName.slice(1),
value: JSON.stringify(ka.defaultShortcuts),
isSynced: false
};
});
}));
}
module.exports = {

View File

@ -23,6 +23,8 @@ async function createMainWindow() {
defaultHeight: 800
});
const spellcheckEnabled = await optionService.getOptionBool('spellCheckEnabled');
const {BrowserWindow} = require('electron'); // should not be statically imported
mainWindow = new BrowserWindow({
x: mainWindowState.x,
@ -31,7 +33,8 @@ async function createMainWindow() {
height: mainWindowState.height,
title: 'Trilium Notes',
webPreferences: {
nodeIntegration: true
nodeIntegration: true,
spellcheck: spellcheckEnabled
},
frame: await optionService.getOptionBool('nativeTitleBarVisible'),
icon: getIcon()
@ -43,15 +46,17 @@ async function createMainWindow() {
mainWindow.loadURL('http://127.0.0.1:' + await port);
mainWindow.on('closed', () => mainWindow = null);
mainWindow.webContents.on('new-window', (e, url) => {
if (url !== mainWindow.webContents.getURL()) {
const {webContents} = mainWindow;
webContents.on('new-window', (e, url) => {
if (url !== webContents.getURL()) {
e.preventDefault();
require('electron').shell.openExternal(url);
}
});
// prevent drag & drop to navigate away from trilium
mainWindow.webContents.on('will-navigate', (ev, targetUrl) => {
webContents.on('will-navigate', (ev, targetUrl) => {
const parsedUrl = url.parse(targetUrl);
// we still need to allow internal redirects from setup and migration pages
@ -59,6 +64,14 @@ async function createMainWindow() {
ev.preventDefault();
}
});
if (spellcheckEnabled) {
const languageCodes = (await optionService.getOption('spellCheckLanguageCode'))
.split('/')
.map(code => code.trim());
webContents.session.setSpellCheckerLanguages(languageCodes);
}
}
function getIcon() {