1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-29 22:48:10 +02:00

Merge branch 'dev' of github.com:laurent22/joplin into dev

This commit is contained in:
Laurent Cozic
2020-12-19 22:17:48 +00:00
10 changed files with 232 additions and 64 deletions

View File

@@ -164,6 +164,18 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
replaceSelection: (value: any) => {
return editorRef.current.replaceSelection(value);
},
textCopy: () => {
editorCopyText();
},
textCut: () => {
editorCutText();
},
textPaste: () => {
editorPaste();
},
textSelectAll: () => {
return editorRef.current.execCommand('selectAll');
},
textBold: () => wrapSelectionWithStrings('**', '**', _('strong text')),
textItalic: () => wrapSelectionWithStrings('*', '*', _('emphasised text')),
textLink: async () => {
@@ -210,6 +222,8 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
if (commands[cmd.name]) {
commandOutput = commands[cmd.name](cmd.value);
} else if (editorRef.current.supportsCommand(cmd)) {
commandOutput = editorRef.current.execCommandFromJoplinCommand(cmd);
} else {
reg.logger().warn('CodeMirror: unsupported Joplin command: ', cmd);
}
@@ -255,6 +269,17 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
}
}, []);
const editorPaste = useCallback(() => {
const clipboardText = clipboard.readText();
if (clipboardText) {
editorPasteText();
} else {
// To handle pasting images
void onEditorPaste();
}
}, [editorPasteText, onEditorPaste]);
const loadScript = async (script: any) => {
return new Promise((resolve) => {
let element: any = document.createElement('script');
@@ -598,7 +623,6 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
const menu = new Menu();
const hasSelectedText = editorRef.current && !!editorRef.current.getSelection() ;
const clipboardText = clipboard.readText();
menu.append(
new MenuItem({
@@ -625,12 +649,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
label: _('Paste'),
enabled: true,
click: async () => {
if (clipboardText) {
editorPasteText();
} else {
// To handle pasting images
void onEditorPaste();
}
editorPaste();
},
})
);

View File

@@ -105,8 +105,8 @@ function Editor(props: EditorProps, ref: any) {
useLineSorting(CodeMirror);
useEditorSearch(CodeMirror);
useJoplinMode(CodeMirror);
useKeymap(CodeMirror);
const pluginOptions: any = useExternalPlugins(CodeMirror, props.plugins);
useKeymap(CodeMirror);
useImperativeHandle(ref, () => {
return editor;

View File

@@ -1,6 +1,9 @@
import { useEffect } from 'react';
import CommandService from '@joplin/lib/services/CommandService';
import KeymapService, { KeymapItem } from '@joplin/lib/services/KeymapService';
import { EditorCommand } from '../../../utils/types';
import shim from '@joplin/lib/shim';
const { reg } = require('@joplin/lib/registry.js');
export default function useKeymap(CodeMirror: any) {
@@ -23,6 +26,77 @@ export default function useKeymap(CodeMirror: any) {
CodeMirror.Vim.mapCommand('o', 'action', 'insertListElement', { after: true }, { context: 'normal', isEdit: true, interlaceInsertRepeat: true });
}
function isEditorCommand(command: string) {
return command.startsWith('editor.');
}
// Converts a command of the form editor.command to just command
function editorCommandToCodeMirror(command: String) {
return command.slice(7); // 7 is the length of editor.
}
// CodeMirror and Electron register accelerators slightly different
// CodeMirror requires a - between keys while Electron want's a +
// CodeMirror doesn't recognize Option (it uses Alt instead)
// This function uses simple regex to translate the Electron
// accelerator to a CodeMirror accelerator
function normalizeAccelerator(accelerator: String) {
return accelerator.replace(/\+/g, '-').replace('Option', 'Alt');
}
// Because there is sometimes a clash between these keybindings and the Joplin window ones
// (This specifically can happen with the Ctrl-B and Ctrl-I keybindings when
// codemirror is in contenteditable mode)
// we will register all keypresses with the codemirror editor to guarentee they
// work no matter where the focus is
function registerJoplinCommand(key: KeymapItem) {
if (!key.command || !key.accelerator) return;
let command = '';
if (isEditorCommand(key.command)) {
command = editorCommandToCodeMirror(key.command);
} else {
// We need to register Joplin commands with codemirror
command = `joplin${key.command}`;
// Not all commands are registered with the command service
// (for example, the Quit command)
// This check will ensure that codemirror only takesover the commands that are
// see gui/KeymapConfig/getLabel.ts for more information
const commandNames = CommandService.instance().commandNames();
if (commandNames.includes(key.command)) {
CodeMirror.commands[command] = () => {
void CommandService.instance().execute(key.command);
};
}
}
// CodeMirror and Electron have slightly different formats for defining accelerators
const acc = normalizeAccelerator(key.accelerator);
CodeMirror.keyMap.default[acc] = command;
}
// Called on initialization, and whenever the keymap changes
function registerKeymap() {
const keymapItems = KeymapService.instance().getKeymapItems();
// Register all commands with the codemirror editor
keymapItems.forEach((key) => { registerJoplinCommand(key); });
}
CodeMirror.defineExtension('supportsCommand', function(cmd: EditorCommand) {
return isEditorCommand(cmd.name) && editorCommandToCodeMirror(cmd.name) in CodeMirror.commands;
});
// Used when an editor command is executed using the CommandService.instance().execute
// function (rather than being initiated by a keypress in the editor)
CodeMirror.defineExtension('execCommandFromJoplin', function(cmd: EditorCommand) {
if (cmd.value) {
reg.logger().warn('CodeMirror commands cannot accept a value:', cmd);
}
return this.execCommand(editorCommandToCodeMirror(cmd.name));
});
useEffect(() => {
// This enables the special modes (emacs and vim) to initiate sync by the save action
CodeMirror.commands.save = save;
@@ -46,61 +120,57 @@ export default function useKeymap(CodeMirror: any) {
'Esc': 'singleSelection',
};
// Some keybindings are added here and not to the global registry because users
// often expect multiple keys to bind to the same command for example, redo is mapped to
// both Ctrl+Shift+Z AND Ctrl+Y
// Doing this mapping here will make those commands available but will allow users to
// override them using the KeymapService
CodeMirror.keyMap.default = {
// Windows / Linux
'Ctrl-Z': 'undo',
'Shift-Ctrl-Z': 'redo',
'Ctrl-Y': 'redo',
'Ctrl-Up': 'goLineUp',
'Ctrl-Down': 'go,ineDown',
'Ctrl+Home': 'goDocStart',
'Ctrl+End': 'goDocEnd',
'Ctrl+Left': 'goGroupLeft',
'Ctrl+Right': 'goGroupRight',
'Alt+Left': 'goLineStart',
'Alt+Right': 'goLineEnd',
'Ctrl+Backspace': 'delGroupBefore',
'Ctrl+Delete': 'delGroupAfter',
'fallthrough': 'basic',
};
if (shim.isMac()) {
CodeMirror.keyMap.default = {
// MacOS
'Cmd-A': 'selectAll',
'Cmd-D': 'deleteLine',
'Cmd-Z': 'undo',
'Shift-Cmd-Z': 'redo',
'Cmd-Y': 'redo',
'Cmd-Home': 'goDocStart',
'Cmd-Up': 'goDocStart',
'Cmd-End': 'goDocEnd',
'Cmd-Down': 'goDocEnd',
'Cmd-Left': 'goLineLeft',
'Cmd-Right': 'goLineRight',
'Alt-Left': 'goGroupLeft',
'Alt-Right': 'goGroupRight',
'Alt-Backspace': 'delGroupBefore',
'Alt-Delete': 'delGroupAfter',
'Cmd-[': 'indentLess',
'Cmd-]': 'indentMore',
'Cmd-/': 'toggleComment',
'Cmd-Opt-S': 'sortSelectedLines',
'Opt-Up': 'swapLineUp',
'Opt-Down': 'swapLineDown',
'fallthrough': 'basic',
};
} else {
CodeMirror.keyMap.default = {
// Windows/linux
'Ctrl-A': 'selectAll',
'Ctrl-D': 'deleteLine',
'Ctrl-Z': 'undo',
'Shift-Ctrl-Z': 'redo',
'Ctrl-Y': 'redo',
'Ctrl-Home': 'goDocStart',
'Ctrl-End': 'goDocEnd',
'Ctrl-Up': 'goLineUp',
'Ctrl-Down': 'goLineDown',
'Ctrl-Left': 'goGroupLeft',
'Ctrl-Right': 'goGroupRight',
'Alt-Left': 'goLineStart',
'Alt-Right': 'goLineEnd',
'Ctrl-Backspace': 'delGroupBefore',
'Ctrl-Delete': 'delGroupAfter',
'Ctrl-[': 'indentLess',
'Ctrl-]': 'indentMore',
'Ctrl-/': 'toggleComment',
'Ctrl-Alt-S': 'sortSelectedLines',
'Alt-Up': 'swapLineUp',
'Alt-Down': 'swapLineDown',
'Cmd-Home': 'goDocStart',
'Cmd-Up': 'goDocStart',
'Ctrl-D': 'delCharAfter',
'Cmd+Home': 'goDocStart',
'Cmd+End': 'goDocEnd',
'Cmd+Left': 'goGroupLeft',
'Cmd+Right': 'goGroupRight',
'Ctrl+A': 'goLineStart',
'Ctrl+E': 'goLineEnd',
'Alt+Backspace': 'delGroupBefore',
'Alt+Delete': 'delGroupAfter',
'fallthrough': 'basic',
};
}
const keymapService = KeymapService.instance();
registerKeymap();
keymapService.on('keymapChange', registerKeymap);
setupEmacs();
setupVim();
}, []);

View File

@@ -83,6 +83,42 @@ const declarations: CommandDeclaration[] = [
label: () => _('Insert Date Time'),
iconName: 'icon-add-date',
},
{
name: 'editor.deleteLine',
label: _('Delete line'),
},
{
name: 'editor.undo',
label: _('Undo'),
},
{
name: 'editor.redo',
label: _('Redo'),
},
{
name: 'editor.indentLess',
label: _('Indent less'),
},
{
name: 'editor.indentMore',
label: _('Indent more'),
},
{
name: 'editor.toggleComment',
label: _('Toggle comment'),
},
{
name: 'editor.sortSelectedLines',
label: _('Sort selected lines'),
},
{
name: 'editor.swapLineUp',
label: _('Swap line up'),
},
{
name: 'editor.swapLineDown',
label: _('Swap line down'),
},
{
name: 'selectedText',
},