You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-23 23:33:01 +02:00
Compare commits
32 Commits
external_r
...
commonmark
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05be96e0a6 | ||
|
|
351ae3d47f | ||
|
|
6d2bad01e6 | ||
|
|
3847831d80 | ||
|
|
44462f4d71 | ||
|
|
4d20589773 | ||
|
|
52140ec1a9 | ||
|
|
08c2a7ad64 | ||
|
|
d19796f14c | ||
|
|
e4f53a48d2 | ||
|
|
154163bd6c | ||
|
|
4502414934 | ||
|
|
86c471afcd | ||
|
|
db7d467ddc | ||
|
|
e2698aaead | ||
|
|
5f2d90b7e4 | ||
|
|
8cfe4b0f82 | ||
|
|
fd90a490c0 | ||
|
|
16c5ffadc7 | ||
|
|
4a184721e4 | ||
|
|
1e3bd937ed | ||
|
|
0f6932f1e8 | ||
|
|
cab98776db | ||
|
|
fbc1e3ed3b | ||
|
|
805d16abda | ||
|
|
f133229287 | ||
|
|
8f4031572a | ||
|
|
d25fa796c0 | ||
|
|
9491d81f5c | ||
|
|
442b7ce0d3 | ||
|
|
6bdeddaa1d | ||
|
|
301adaa7d0 |
@@ -126,6 +126,7 @@ ElectronClient/gui/MainScreen/commands/toggleSideBar.js
|
||||
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
|
||||
ElectronClient/gui/MainScreen/MainScreen.js
|
||||
ElectronClient/gui/MenuBar.js
|
||||
ElectronClient/gui/menuCommandNames.js
|
||||
ElectronClient/gui/MultiNoteActions.js
|
||||
ElectronClient/gui/NoteContentPropertiesDialog.js
|
||||
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -120,6 +120,7 @@ ElectronClient/gui/MainScreen/commands/toggleSideBar.js
|
||||
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
|
||||
ElectronClient/gui/MainScreen/MainScreen.js
|
||||
ElectronClient/gui/MenuBar.js
|
||||
ElectronClient/gui/menuCommandNames.js
|
||||
ElectronClient/gui/MultiNoteActions.js
|
||||
ElectronClient/gui/NoteContentPropertiesDialog.js
|
||||
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
|
||||
|
||||
1
.ignore
1
.ignore
@@ -69,6 +69,7 @@ ElectronClient/gui/MainScreen/commands/toggleSideBar.js
|
||||
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
|
||||
ElectronClient/gui/MainScreen/MainScreen.js
|
||||
ElectronClient/gui/MenuBar.js
|
||||
ElectronClient/gui/menuCommandNames.js
|
||||
ElectronClient/gui/MultiNoteActions.js
|
||||
ElectronClient/gui/NoteContentPropertiesDialog.js
|
||||
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
|
||||
|
||||
@@ -45,10 +45,12 @@ class Command extends BaseCommand {
|
||||
|
||||
const startDecryption = async () => {
|
||||
this.stdout(_('Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.'));
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const result = await DecryptionWorker.instance().start();
|
||||
|
||||
if (result.error) throw result.error;
|
||||
|
||||
const line = [];
|
||||
line.push(_('Decrypted items: %d', result.decryptedItemCount));
|
||||
if (result.skippedItemCount) line.push(_('Skipped items: %d (use --retry-failed-items to retry decrypting them)', result.skippedItemCount));
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -38,33 +38,33 @@ locales['tr_TR'] = require('./tr_TR.json');
|
||||
locales['vi'] = require('./vi.json');
|
||||
locales['zh_CN'] = require('./zh_CN.json');
|
||||
locales['zh_TW'] = require('./zh_TW.json');
|
||||
stats['ar'] = {"percentDone":79};
|
||||
stats['ar'] = {"percentDone":78};
|
||||
stats['eu'] = {"percentDone":33};
|
||||
stats['bs_BA'] = {"percentDone":82};
|
||||
stats['bg_BG'] = {"percentDone":65};
|
||||
stats['ca'] = {"percentDone":95};
|
||||
stats['hr_HR'] = {"percentDone":27};
|
||||
stats['cs_CZ'] = {"percentDone":99};
|
||||
stats['da_DK'] = {"percentDone":73};
|
||||
stats['cs_CZ'] = {"percentDone":98};
|
||||
stats['da_DK'] = {"percentDone":72};
|
||||
stats['de_DE'] = {"percentDone":97};
|
||||
stats['et_EE'] = {"percentDone":65};
|
||||
stats['en_GB'] = {"percentDone":100};
|
||||
stats['en_US'] = {"percentDone":100};
|
||||
stats['es_ES'] = {"percentDone":99};
|
||||
stats['es_ES'] = {"percentDone":98};
|
||||
stats['eo'] = {"percentDone":37};
|
||||
stats['fr_FR'] = {"percentDone":98};
|
||||
stats['gl_ES'] = {"percentDone":42};
|
||||
stats['id_ID'] = {"percentDone":92};
|
||||
stats['it_IT'] = {"percentDone":98};
|
||||
stats['nl_BE'] = {"percentDone":33};
|
||||
stats['nl_NL'] = {"percentDone":94};
|
||||
stats['nl_BE'] = {"percentDone":33};
|
||||
stats['nb_NO'] = {"percentDone":87};
|
||||
stats['fa'] = {"percentDone":82};
|
||||
stats['pl_PL'] = {"percentDone":97};
|
||||
stats['pt_PT'] = {"percentDone":98};
|
||||
stats['pt_BR'] = {"percentDone":95};
|
||||
stats['pt_BR'] = {"percentDone":96};
|
||||
stats['ro'] = {"percentDone":77};
|
||||
stats['sl_SI'] = {"percentDone":42};
|
||||
stats['sl_SI'] = {"percentDone":41};
|
||||
stats['sv'] = {"percentDone":70};
|
||||
stats['th_TH'] = {"percentDone":52};
|
||||
stats['vi'] = {"percentDone":84};
|
||||
@@ -74,6 +74,6 @@ stats['ru_RU'] = {"percentDone":94};
|
||||
stats['sr_RS'] = {"percentDone":70};
|
||||
stats['zh_CN'] = {"percentDone":95};
|
||||
stats['zh_TW'] = {"percentDone":94};
|
||||
stats['ja_JP'] = {"percentDone":97};
|
||||
stats['ja_JP'] = {"percentDone":99};
|
||||
stats['ko'] = {"percentDone":99};
|
||||
module.exports = { locales: locales, stats: stats };
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
import MdToHtml from 'lib/joplin-renderer/MdToHtml';
|
||||
const os = require('os');
|
||||
const { filename } = require('lib/path-utils');
|
||||
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
|
||||
const shim = require('lib/shim').default;
|
||||
const MdToHtml = require('lib/joplin-renderer/MdToHtml').default;
|
||||
const { themeStyle } = require('lib/theme');
|
||||
|
||||
function newTestMdToHtml(options:any = null) {
|
||||
@@ -120,23 +120,54 @@ describe('MdToHtml', function() {
|
||||
it('should return the rendered body only', asyncTest(async () => {
|
||||
const mdToHtml = newTestMdToHtml();
|
||||
|
||||
// In this case, the HTML contains only the rendered markdown,
|
||||
// with no wrapper and no style.
|
||||
// The style is instead in the cssStrings property.
|
||||
const result = await mdToHtml.render('just **testing**', null, { bodyOnly: true });
|
||||
expect(result.cssStrings.length).toBeGreaterThan(0);
|
||||
expect(result.html.trim()).toBe('just <strong>testing</strong>');
|
||||
// In this case, the HTML contains only the rendered markdown, with
|
||||
// no wrapper and no style. The style is instead in the cssStrings
|
||||
// property.
|
||||
{
|
||||
const result = await mdToHtml.render('just **testing**', null, { bodyOnly: true });
|
||||
expect(result.cssStrings.length).toBeGreaterThan(0);
|
||||
expect(result.html.trim()).toBe('just <strong>testing</strong>');
|
||||
}
|
||||
|
||||
// But it should not remove the wrapping <p> tags if there's more
|
||||
// than one line
|
||||
{
|
||||
const result = await mdToHtml.render('one\n\ntwo', null, { bodyOnly: true });
|
||||
expect(result.html.trim()).toBe('<p>one</p>\n<p>two</p>');
|
||||
}
|
||||
}));
|
||||
|
||||
it('should split HTML and CSS', asyncTest(async () => {
|
||||
const mdToHtml = newTestMdToHtml();
|
||||
|
||||
// It is similar to the bodyOnly option, excepts that
|
||||
// the rendered Markdown is wrapped in a DIV
|
||||
// It is similar to the bodyOnly option, excepts that the rendered
|
||||
// Markdown is wrapped in a DIV
|
||||
const result = await mdToHtml.render('just **testing**', null, { splitted: true });
|
||||
expect(result.cssStrings.length).toBeGreaterThan(0);
|
||||
expect(result.html.trim()).toBe('<div id="rendered-md"><p>just <strong>testing</strong></p>\n</div>');
|
||||
}));
|
||||
|
||||
it('should render links correctly', asyncTest(async () => {
|
||||
const mdToHtml = newTestMdToHtml();
|
||||
|
||||
const testCases = [
|
||||
// None of these should result in a link
|
||||
['https://example.com', 'https://example.com'],
|
||||
['file://C:\\AUTOEXEC.BAT', 'file://C:\\AUTOEXEC.BAT'],
|
||||
['example.com', 'example.com'],
|
||||
['oo.ps', 'oo.ps'],
|
||||
['test@example.com', 'test@example.com'],
|
||||
|
||||
// Those should be converted to links
|
||||
['<https://example.com>', '<a data-from-md title=\'https://example.com\' href=\'https://example.com\'>https://example.com</a>'],
|
||||
['[ok](https://example.com)', '<a data-from-md title=\'https://example.com\' href=\'https://example.com\'>ok</a>'],
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
const [input, expected] = testCase;
|
||||
const actual = await mdToHtml.render(input, null, { bodyOnly: true, plainResourceRendering: true });
|
||||
expect(actual.html).toBe(expected);
|
||||
}
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ require('app-module-path').addPath(__dirname);
|
||||
const { tempFilePath } = require('test-utils.js');
|
||||
const KeymapService = require('lib/services/KeymapService').default;
|
||||
const keymapService = KeymapService.instance();
|
||||
keymapService.initialize([]);
|
||||
|
||||
describe('services_KeymapService', () => {
|
||||
describe('validateAccelerator', () => {
|
||||
@@ -31,7 +32,7 @@ describe('services_KeymapService', () => {
|
||||
};
|
||||
|
||||
Object.entries(testCases).forEach(([platform, accelerators]) => {
|
||||
keymapService.initialize(platform);
|
||||
keymapService.initialize([], platform);
|
||||
accelerators.forEach(accelerator => {
|
||||
expect(() => keymapService.validateAccelerator(accelerator)).not.toThrow();
|
||||
});
|
||||
@@ -69,7 +70,7 @@ describe('services_KeymapService', () => {
|
||||
};
|
||||
|
||||
Object.entries(testCases).forEach(([platform, accelerators]) => {
|
||||
keymapService.initialize(platform);
|
||||
keymapService.initialize([], platform);
|
||||
accelerators.forEach(accelerator => {
|
||||
expect(() => keymapService.validateAccelerator(accelerator)).toThrow();
|
||||
});
|
||||
@@ -81,12 +82,12 @@ describe('services_KeymapService', () => {
|
||||
beforeEach(() => keymapService.initialize());
|
||||
|
||||
it('should allow registering new commands', async () => {
|
||||
keymapService.initialize('linux');
|
||||
keymapService.initialize([], 'linux');
|
||||
keymapService.registerCommandAccelerator('myCustomCommand', 'Ctrl+Shift+Alt+B');
|
||||
expect(keymapService.getAccelerator('myCustomCommand')).toEqual('Ctrl+Shift+Alt+B');
|
||||
|
||||
// Check that macOS key conversion is working
|
||||
keymapService.initialize('darwin');
|
||||
keymapService.initialize([], 'darwin');
|
||||
keymapService.registerCommandAccelerator('myCustomCommand', 'CmdOrCtrl+Shift+Alt+B');
|
||||
expect(keymapService.getAccelerator('myCustomCommand')).toEqual('Cmd+Shift+Option+B');
|
||||
keymapService.setAccelerator('myCustomCommand', 'Cmd+Shift+Option+X');
|
||||
@@ -95,7 +96,7 @@ describe('services_KeymapService', () => {
|
||||
const keymapFilePath = tempFilePath('json');
|
||||
await keymapService.saveCustomKeymap(keymapFilePath);
|
||||
|
||||
keymapService.initialize('darwin');
|
||||
keymapService.initialize([], 'darwin');
|
||||
await keymapService.loadCustomKeymap(keymapFilePath);
|
||||
|
||||
expect(keymapService.getAccelerator('myCustomCommand')).toEqual('Cmd+Shift+Option+X');
|
||||
@@ -106,17 +107,17 @@ describe('services_KeymapService', () => {
|
||||
beforeEach(() => keymapService.initialize());
|
||||
|
||||
it('should return the platform-specific default Accelerator', () => {
|
||||
keymapService.initialize('darwin');
|
||||
keymapService.initialize([], 'darwin');
|
||||
expect(keymapService.getAccelerator('newNote')).toEqual('Cmd+N');
|
||||
expect(keymapService.getAccelerator('synchronize')).toEqual('Cmd+S');
|
||||
expect(keymapService.getAccelerator('textSelectAll')).toEqual('Cmd+A');
|
||||
expect(keymapService.getAccelerator('textBold')).toEqual('Cmd+B');
|
||||
|
||||
keymapService.initialize('linux');
|
||||
keymapService.initialize([], 'linux');
|
||||
expect(keymapService.getAccelerator('newNote')).toEqual('Ctrl+N');
|
||||
expect(keymapService.getAccelerator('synchronize')).toEqual('Ctrl+S');
|
||||
|
||||
keymapService.initialize('win32');
|
||||
keymapService.initialize([], 'win32');
|
||||
expect(keymapService.getAccelerator('textSelectAll')).toEqual('Ctrl+A');
|
||||
expect(keymapService.getAccelerator('textBold')).toEqual('Ctrl+B');
|
||||
});
|
||||
@@ -130,7 +131,7 @@ describe('services_KeymapService', () => {
|
||||
beforeEach(() => keymapService.initialize());
|
||||
|
||||
it('should update the Accelerator', () => {
|
||||
keymapService.initialize('darwin');
|
||||
keymapService.initialize(['print'], 'darwin');
|
||||
const testCases_Darwin = [
|
||||
{ command: 'newNote', accelerator: 'Ctrl+Option+Shift+N' },
|
||||
{ command: 'synchronize', accelerator: 'F11' },
|
||||
@@ -147,7 +148,7 @@ describe('services_KeymapService', () => {
|
||||
expect(keymapService.getAccelerator(command)).toEqual(accelerator);
|
||||
});
|
||||
|
||||
keymapService.initialize('linux');
|
||||
keymapService.initialize(['print'], 'linux');
|
||||
const testCases_Linux = [
|
||||
{ command: 'newNote', accelerator: 'Ctrl+Alt+Shift+N' },
|
||||
{ command: 'synchronize', accelerator: 'F15' },
|
||||
@@ -167,7 +168,7 @@ describe('services_KeymapService', () => {
|
||||
});
|
||||
|
||||
describe('getDefaultAccelerator', () => {
|
||||
beforeEach(() => keymapService.initialize());
|
||||
beforeEach(() => keymapService.initialize(['print', 'linux']));
|
||||
|
||||
it('should return the default accelerator', () => {
|
||||
const testCases = [
|
||||
@@ -196,7 +197,7 @@ describe('services_KeymapService', () => {
|
||||
beforeEach(() => keymapService.initialize());
|
||||
|
||||
it('should update the keymap', () => {
|
||||
keymapService.initialize('darwin');
|
||||
keymapService.initialize([], 'darwin');
|
||||
const customKeymapItems_Darwin = [
|
||||
{ command: 'newNote', accelerator: 'Option+Shift+Cmd+N' },
|
||||
{ command: 'synchronize', accelerator: 'Ctrl+F11' },
|
||||
@@ -217,7 +218,7 @@ describe('services_KeymapService', () => {
|
||||
expect(keymapService.getAccelerator(command)).toEqual(accelerator);
|
||||
});
|
||||
|
||||
keymapService.initialize('win32');
|
||||
keymapService.initialize([], 'win32');
|
||||
const customKeymapItems_Win32 = [
|
||||
{ command: 'newNote', accelerator: 'Ctrl+Alt+Shift+N' },
|
||||
{ command: 'synchronize', accelerator: 'Ctrl+F11' },
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Joplin Web Clipper [DEV]",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.1",
|
||||
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
|
||||
"homepage_url": "https://joplinapp.org",
|
||||
"content_security_policy": "script-src 'self'; object-src 'self'",
|
||||
|
||||
@@ -14,6 +14,7 @@ import Setting from 'lib/models/Setting';
|
||||
import actionApi from 'lib/services/rest/actionApi.desktop';
|
||||
import BaseApplication from 'lib/BaseApplication';
|
||||
import { _, setLocale } from 'lib/locale';
|
||||
import menuCommandNames from './gui/menuCommandNames';
|
||||
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
@@ -495,14 +496,6 @@ class Application extends BaseApplication {
|
||||
const filename = Setting.custom_css_files.JOPLIN_APP;
|
||||
await CssUtils.injectCustomStyles(`${dir}/${filename}`);
|
||||
|
||||
const keymapService = KeymapService.instance();
|
||||
|
||||
try {
|
||||
await keymapService.loadCustomKeymap(`${dir}/keymap-desktop.json`);
|
||||
} catch (err) {
|
||||
reg.logger().error(err.message);
|
||||
}
|
||||
|
||||
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
||||
AlarmService.setLogger(reg.logger());
|
||||
|
||||
@@ -533,9 +526,21 @@ class Application extends BaseApplication {
|
||||
CommandService.instance().registerDeclaration(declaration);
|
||||
}
|
||||
|
||||
// Since the settings need to be loaded before the store is created, it will never
|
||||
// receive the SETTING_UPDATE_ALL even, which mean state.settings will not be
|
||||
// initialised. So we manually call dispatchUpdateAll() to force an update.
|
||||
const keymapService = KeymapService.instance();
|
||||
// We only add the commands that appear in the menu because only
|
||||
// those can have a shortcut associated with them.
|
||||
keymapService.initialize(menuCommandNames());
|
||||
|
||||
try {
|
||||
await keymapService.loadCustomKeymap(`${dir}/keymap-desktop.json`);
|
||||
} catch (error) {
|
||||
reg.logger().error(error);
|
||||
}
|
||||
|
||||
// Since the settings need to be loaded before the store is
|
||||
// created, it will never receive the SETTING_UPDATE_ALL even,
|
||||
// which mean state.settings will not be initialised. So we
|
||||
// manually call dispatchUpdateAll() to force an update.
|
||||
Setting.dispatchUpdateAll();
|
||||
|
||||
await FoldersScreenUtils.refreshFolders();
|
||||
|
||||
@@ -5,7 +5,7 @@ import { _ } from 'lib/locale';
|
||||
|
||||
const commandService = CommandService.instance();
|
||||
|
||||
const getLabel = (commandName: string) => {
|
||||
const getLabel = (commandName: string):string => {
|
||||
if (commandService.exists(commandName)) return commandService.label(commandName, true);
|
||||
|
||||
// Some commands are not registered in CommandService at the moment
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import KeymapService, { KeymapItem } from 'lib/services/KeymapService';
|
||||
import getLabel from './getLabel';
|
||||
|
||||
const keymapService = KeymapService.instance();
|
||||
|
||||
// This custom hook provides a synchronized snapshot of the keymap residing at KeymapService
|
||||
// All the logic regarding altering and interacting with the keymap is isolated from the components
|
||||
|
||||
function allKeymapItems() {
|
||||
const output = keymapService.getKeymapItems().slice();
|
||||
|
||||
output.sort((a:KeymapItem, b:KeymapItem) => {
|
||||
return getLabel(a.command).toLocaleLowerCase() < getLabel(b.command).toLocaleLowerCase() ? -1 : +1;
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
const useKeymap = (): [
|
||||
KeymapItem[],
|
||||
Error,
|
||||
@@ -13,7 +24,7 @@ const useKeymap = (): [
|
||||
(commandName: string, accelerator: string) => void,
|
||||
(commandName: string) => void
|
||||
] => {
|
||||
const [keymapItems, setKeymapItems] = useState<KeymapItem[]>(() => keymapService.getKeymapItems());
|
||||
const [keymapItems, setKeymapItems] = useState<KeymapItem[]>(() => allKeymapItems());
|
||||
const [keymapError, setKeymapError] = useState<Error>(null);
|
||||
const [mustSave, setMustSave] = useState(false);
|
||||
|
||||
@@ -42,7 +53,7 @@ const useKeymap = (): [
|
||||
|
||||
const overrideKeymapItems = (customKeymapItems: KeymapItem[]) => {
|
||||
const oldKeymapItems = [...customKeymapItems];
|
||||
keymapService.initialize(); // Start with a fresh keymap
|
||||
keymapService.resetKeymap(); // Start with a fresh keymap
|
||||
|
||||
try {
|
||||
// First, try to update the in-memory keymap of KeymapService
|
||||
|
||||
@@ -14,6 +14,7 @@ import InteropServiceHelper from '../InteropServiceHelper';
|
||||
import { _ } from 'lib/locale';
|
||||
import { MenuItem, MenuItemLocation } from 'lib/services/plugins/api/types';
|
||||
import stateToWhenClauseContext from 'lib/services/commands/stateToWhenClauseContext';
|
||||
import menuCommandNames from './menuCommandNames';
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
const { reg } = require('lib/registry.js');
|
||||
@@ -86,39 +87,7 @@ interface Props {
|
||||
pluginMenus: any[],
|
||||
}
|
||||
|
||||
const commandNames:string[] = [
|
||||
'focusElementSideBar',
|
||||
'focusElementNoteList',
|
||||
'focusElementNoteTitle',
|
||||
'focusElementNoteBody',
|
||||
'exportPdf',
|
||||
'newNote',
|
||||
'newTodo',
|
||||
'newFolder',
|
||||
'newSubFolder',
|
||||
'print',
|
||||
'synchronize',
|
||||
'textCopy',
|
||||
'textCut',
|
||||
'textPaste',
|
||||
'textSelectAll',
|
||||
'textBold',
|
||||
'textItalic',
|
||||
'textLink',
|
||||
'textCode',
|
||||
'insertDateTime',
|
||||
'attachFile',
|
||||
'focusSearch',
|
||||
'showLocalSearch',
|
||||
'toggleSideBar',
|
||||
'toggleNoteList',
|
||||
'toggleVisiblePanes',
|
||||
'toggleExternalEditing',
|
||||
'setTags',
|
||||
'showNoteContentProperties',
|
||||
'copyDevCommand',
|
||||
'openProfileDirectory',
|
||||
];
|
||||
const commandNames:string[] = menuCommandNames();
|
||||
|
||||
function menuItemSetChecked(id:string, checked:boolean) {
|
||||
const menu = Menu.getApplicationMenu();
|
||||
@@ -249,10 +218,8 @@ function useMenu(props:Props) {
|
||||
menuItemDic.focusElementNoteBody,
|
||||
];
|
||||
|
||||
let toolsItems:any[] = [];
|
||||
const importItems = [];
|
||||
const exportItems = [];
|
||||
const toolsItemsFirst = [];
|
||||
const templateItems:any[] = [];
|
||||
const ioService = InteropService.instance();
|
||||
const ioModules = ioService.modules();
|
||||
@@ -299,16 +266,18 @@ function useMenu(props:Props) {
|
||||
},
|
||||
};
|
||||
|
||||
const separator = () => {
|
||||
return {
|
||||
type: 'separator',
|
||||
};
|
||||
};
|
||||
|
||||
const newNoteItem = menuItemDic.newNote;
|
||||
const newTodoItem = menuItemDic.newTodo;
|
||||
const newFolderItem = menuItemDic.newFolder;
|
||||
const newSubFolderItem = menuItemDic.newSubFolder;
|
||||
const printItem = menuItemDic.print;
|
||||
|
||||
toolsItemsFirst.push(syncStatusItem, {
|
||||
type: 'separator',
|
||||
});
|
||||
|
||||
templateItems.push({
|
||||
label: _('Create note from template'),
|
||||
click: () => {
|
||||
@@ -342,18 +311,22 @@ function useMenu(props:Props) {
|
||||
},
|
||||
});
|
||||
|
||||
let toolsItems:any[] = [];
|
||||
|
||||
// we need this workaround, because on macOS the menu is different
|
||||
const toolsItemsWindowsLinux:any[] = toolsItemsFirst.concat([{
|
||||
label: _('Options'),
|
||||
visible: !shim.isMac(),
|
||||
accelerator: !shim.isMac() && keymapService.getAccelerator('config'),
|
||||
click: () => {
|
||||
props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Config',
|
||||
});
|
||||
const toolsItemsWindowsLinux:any[] = [
|
||||
{
|
||||
label: _('Options'),
|
||||
accelerator: keymapService.getAccelerator('config'),
|
||||
click: () => {
|
||||
props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Config',
|
||||
});
|
||||
},
|
||||
},
|
||||
} as any]);
|
||||
separator(),
|
||||
];
|
||||
|
||||
// the following menu items will be available for all OS under Tools
|
||||
const toolsItemsAll = [{
|
||||
@@ -451,9 +424,7 @@ function useMenu(props:Props) {
|
||||
|
||||
menuItemDic.synchronize,
|
||||
|
||||
shim.isMac() ? syncStatusItem : noItem, {
|
||||
type: 'separator',
|
||||
}, shim.isMac() ? noItem : printItem, {
|
||||
shim.isMac() ? noItem : printItem, {
|
||||
type: 'separator',
|
||||
platforms: ['darwin'],
|
||||
},
|
||||
@@ -518,12 +489,6 @@ function useMenu(props:Props) {
|
||||
});
|
||||
}
|
||||
|
||||
const separator = () => {
|
||||
return {
|
||||
type: 'separator',
|
||||
};
|
||||
};
|
||||
|
||||
const rootMenus:any = {
|
||||
edit: {
|
||||
id: 'edit',
|
||||
@@ -586,11 +551,6 @@ function useMenu(props:Props) {
|
||||
},
|
||||
},
|
||||
separator(),
|
||||
{
|
||||
label: _('Focus'),
|
||||
submenu: focusItems,
|
||||
},
|
||||
separator(),
|
||||
{
|
||||
label: _('Actual Size'),
|
||||
click: () => {
|
||||
@@ -623,6 +583,18 @@ function useMenu(props:Props) {
|
||||
accelerator: 'CommandOrControl+-',
|
||||
}],
|
||||
},
|
||||
go: {
|
||||
label: _('&Go'),
|
||||
submenu: [
|
||||
menuItemDic.historyBackward,
|
||||
menuItemDic.historyForward,
|
||||
separator(),
|
||||
{
|
||||
label: _('Focus'),
|
||||
submenu: focusItems,
|
||||
},
|
||||
],
|
||||
},
|
||||
note: {
|
||||
label: _('&Note'),
|
||||
submenu: [
|
||||
@@ -655,6 +627,8 @@ function useMenu(props:Props) {
|
||||
click: () => _checkForUpdates(),
|
||||
},
|
||||
separator(),
|
||||
syncStatusItem,
|
||||
separator(),
|
||||
{
|
||||
id: 'help:toggleDevTools',
|
||||
label: _('Toggle development tools'),
|
||||
@@ -709,6 +683,7 @@ function useMenu(props:Props) {
|
||||
const pluginMenuItems = PluginManager.instance().menuItems();
|
||||
for (const item of pluginMenuItems) {
|
||||
const itemParent = rootMenus[item.parent] ? rootMenus[item.parent] : 'tools';
|
||||
itemParent.submenu.push(separator());
|
||||
itemParent.submenu.push(item);
|
||||
}
|
||||
}
|
||||
@@ -741,6 +716,7 @@ function useMenu(props:Props) {
|
||||
rootMenus.file,
|
||||
rootMenus.edit,
|
||||
rootMenus.view,
|
||||
rootMenus.go,
|
||||
rootMenus.note,
|
||||
rootMenus.tools,
|
||||
rootMenus.help,
|
||||
@@ -748,46 +724,6 @@ function useMenu(props:Props) {
|
||||
|
||||
if (shim.isMac()) template.splice(0, 0, rootMenus.macOsApp);
|
||||
|
||||
// TODO
|
||||
|
||||
// function isEmptyMenu(template:any[]) {
|
||||
// for (let i = 0; i < template.length; i++) {
|
||||
// const t = template[i];
|
||||
// if (t.type !== 'separator') return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// function removeUnwantedItems(template:any[], screen:string) {
|
||||
// const platform = shim.platformName();
|
||||
|
||||
// let output = [];
|
||||
// for (let i = 0; i < template.length; i++) {
|
||||
// const t = Object.assign({}, template[i]);
|
||||
// if (t.screens && t.screens.indexOf(screen) < 0) continue;
|
||||
// if (t.platforms && t.platforms.indexOf(platform) < 0) continue;
|
||||
// if (t.submenu) t.submenu = removeUnwantedItems(t.submenu, screen);
|
||||
// if (('submenu' in t) && isEmptyMenu(t.submenu)) continue;
|
||||
// output.push(t);
|
||||
// }
|
||||
|
||||
// // Remove empty separator for now empty sections
|
||||
// const temp = [];
|
||||
// let previous = null;
|
||||
// for (let i = 0; i < output.length; i++) {
|
||||
// const t = Object.assign({}, output[i]);
|
||||
// if (t.type === 'separator') {
|
||||
// if (!previous) continue;
|
||||
// if (previous.type === 'separator') continue;
|
||||
// }
|
||||
// temp.push(t);
|
||||
// previous = t;
|
||||
// }
|
||||
// output = temp;
|
||||
|
||||
// return output;
|
||||
// }
|
||||
|
||||
if (props.routeName !== 'Main') {
|
||||
setMenu(Menu.buildFromTemplate([
|
||||
{
|
||||
|
||||
37
ElectronClient/gui/menuCommandNames.ts
Normal file
37
ElectronClient/gui/menuCommandNames.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
export default function() {
|
||||
return [
|
||||
'attachFile',
|
||||
'copyDevCommand',
|
||||
'exportPdf',
|
||||
'focusElementNoteBody',
|
||||
'focusElementNoteList',
|
||||
'focusElementNoteTitle',
|
||||
'focusElementSideBar',
|
||||
'focusSearch',
|
||||
'historyBackward',
|
||||
'historyForward',
|
||||
'insertDateTime',
|
||||
'newFolder',
|
||||
'newNote',
|
||||
'newSubFolder',
|
||||
'newTodo',
|
||||
'openProfileDirectory',
|
||||
'print',
|
||||
'setTags',
|
||||
'showLocalSearch',
|
||||
'showNoteContentProperties',
|
||||
'synchronize',
|
||||
'textBold',
|
||||
'textCode',
|
||||
'textCopy',
|
||||
'textCut',
|
||||
'textItalic',
|
||||
'textLink',
|
||||
'textPaste',
|
||||
'textSelectAll',
|
||||
'toggleExternalEditing',
|
||||
'toggleNoteList',
|
||||
'toggleSideBar',
|
||||
'toggleVisiblePanes',
|
||||
];
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user