1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-06-15 23:00:36 +02:00

Desktop: Undo changes introduced in #4303 (#4406)

This commit is contained in:
Caleb John
2021-02-06 09:01:06 -07:00
committed by GitHub
parent 11c8bf7e6e
commit 33e1214ef6
18 changed files with 82 additions and 117 deletions

View File

@ -21,7 +21,7 @@ import { Command } from './types';
* and look at the `execute()` command. * and look at the `execute()` command.
*/ */
export default class JoplinCommands { export default class JoplinCommands {
/** /**
* <span class="platform-desktop">desktop</span> Executes the given * <span class="platform-desktop">desktop</span> Executes the given
* command. * command.
* *
@ -40,8 +40,8 @@ export default class JoplinCommands {
* await joplin.commands.execute('newFolder', "SOME_FOLDER_ID"); * await joplin.commands.execute('newFolder', "SOME_FOLDER_ID");
* ``` * ```
*/ */
execute(commandName: string, ...args: any[]): Promise<any | void>; execute(commandName: string, ...args: any[]): Promise<any | void>;
/** /**
* <span class="platform-desktop">desktop</span> Registers a new command. * <span class="platform-desktop">desktop</span> Registers a new command.
* *
* ```typescript * ```typescript
@ -57,5 +57,5 @@ export default class JoplinCommands {
* }); * });
* ``` * ```
*/ */
register(command: Command): Promise<void>; register(command: Command): Promise<void>;
} }

View File

@ -5,6 +5,6 @@
* so for now disable filters. * so for now disable filters.
*/ */
export default class JoplinFilters { export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>; on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>; off(name: string, callback: Function): Promise<void>;
} }

View File

@ -12,6 +12,6 @@ import { ExportModule, ImportModule } from './types';
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/api/references/rest_api/ * You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/api/references/rest_api/
*/ */
export default class JoplinInterop { export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>; registerExportModule(module: ExportModule): Promise<void>;
registerImportModule(module: ImportModule): Promise<void>; registerImportModule(module: ImportModule): Promise<void>;
} }

View File

@ -6,7 +6,7 @@ export interface ChangeEvent {
*/ */
keys: string[]; keys: string[];
} }
export declare type ChangeHandler = (event: ChangeEvent) => void; export declare type ChangeHandler = (event: ChangeEvent)=> void;
/** /**
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user. * This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
* *

View File

@ -3,7 +3,7 @@ import { Disposable } from './types';
declare enum ItemChangeEventType { declare enum ItemChangeEventType {
Create = 1, Create = 1,
Update = 2, Update = 2,
Delete = 3 Delete = 3,
} }
interface ItemChangeEvent { interface ItemChangeEvent {
id: string; id: string;
@ -12,8 +12,8 @@ interface ItemChangeEvent {
interface SyncStartEvent { interface SyncStartEvent {
withErrors: boolean; withErrors: boolean;
} }
declare type ItemChangeHandler = (event: ItemChangeEvent) => void; declare type ItemChangeHandler = (event: ItemChangeEvent)=> void;
declare type SyncStartHandler = (event: SyncStartEvent) => void; declare type SyncStartHandler = (event: SyncStartEvent)=> void;
/** /**
* The workspace service provides access to all the parts of Joplin that * The workspace service provides access to all the parts of Joplin that
* are being worked on - i.e. the currently selected notes or notebooks as * are being worked on - i.e. the currently selected notes or notebooks as

View File

@ -330,57 +330,16 @@ export enum SettingItemType {
export interface SettingItem { export interface SettingItem {
value: any; value: any;
type: SettingItemType; type: SettingItemType;
label: string;
description?: string;
/**
* A public setting will appear in the Configuration screen and will be
* modifiable by the user. A private setting however will not appear there,
* and can only be changed programmatically. You may use this to store some
* values that you do not want to directly expose.
*/
public: boolean; public: boolean;
label: string;
/** description?: string;
* You would usually set this to a section you would have created
* specifically for the plugin.
*/
section?: string;
/**
* To create a setting with multiple options, set this property to `true`.
* That setting will render as a dropdown list in the configuration screen.
*/
isEnum?: boolean; isEnum?: boolean;
section?: string;
/** options?: any;
* This property is required when `isEnum` is `true`. In which case, it
* should contain a map of value => label.
*/
options?: Record<any, any>;
/**
* Reserved property. Not used at the moment.
*/
appTypes?: string[]; appTypes?: string[];
/**
* Set this to `true` to store secure data, such as passwords. Any such
* setting will be stored in the system keychain if one is available.
*/
secure?: boolean; secure?: boolean;
/**
* An advanced setting will be moved under the "Advanced" button in the
* config screen.
*/
advanced?: boolean; advanced?: boolean;
/**
* Set the min, max and step values if you want to restrict an int setting
* to a particular range.
*/
minimum?: number; minimum?: number;
maximum?: number; maximum?: number;
step?: number; step?: number;

View File

@ -12,13 +12,16 @@ joplin.plugins.register({
); );
await joplin.commands.register({ await joplin.commands.register({
name: 'editor.printSomething', name: 'printSomething',
label: 'Print some random string', label: 'Print some random string',
execute: async () => { execute: async () => {
alert('mathMode.printSomething not implemented by Editor yet'); await joplin.commands.execute('editor.execCommand', {
name: 'printSomething',
args: ['Anything']
});
}, },
}); });
await joplin.views.menuItems.create('printSomethingButton', 'editor.printSomething', MenuItemLocation.Tools, { accelerator: 'Ctrl+Alt+Shift+U' }); await joplin.views.menuItems.create('printSomethingButton', 'printSomething', MenuItemLocation.Tools, { accelerator: 'Ctrl+Alt+Shift+U' });
}, },
}); });

View File

@ -6,9 +6,9 @@ function plugin(CodeMirror) {
// Once created here it can be called by any other codemirror command // Once created here it can be called by any other codemirror command
// using cm.execCommand(stringName) or register a joplin command called 'editor.printSomething' // using cm.execCommand(stringName) or register a joplin command called 'editor.printSomething'
// through the joplin.commands api // through the joplin.commands api
CodeMirror.commands.printSomething = function(cm) { CodeMirror.defineExtension('printSomething', function(something) {
console.log("Something"); console.log(something);
} });
} }
module.exports = { module.exports = {

View File

@ -4,7 +4,7 @@
"name": "joplin-match-highlighter", "name": "joplin-match-highlighter",
"description": "Adds support for the Codemirror match highlighter to the Joplin CodeView editor.", "description": "Adds support for the Codemirror match highlighter to the Joplin CodeView editor.",
"version": "1.0.0", "version": "1.0.0",
"author": "CalebJohn", "author": "JoplinTeam",
"app_min_version": "1.4", "app_min_version": "1.7",
"homepage_url": "joplinapp.org" "homepage_url": "joplinapp.org"
} }

View File

@ -5,6 +5,7 @@ import { useState, useEffect, useRef, forwardRef, useCallback, useImperativeHand
import { EditorCommand, NoteBodyEditorProps } from '../../utils/types'; import { EditorCommand, NoteBodyEditorProps } from '../../utils/types';
import { commandAttachFileToBody, handlePasteEvent } from '../../utils/resourceHandling'; import { commandAttachFileToBody, handlePasteEvent } from '../../utils/resourceHandling';
import { ScrollOptions, ScrollOptionTypes } from '../../utils/types'; import { ScrollOptions, ScrollOptionTypes } from '../../utils/types';
import { CommandValue } from '../../utils/types';
import { useScrollHandler, usePrevious, cursorPositionToTextOffset, useRootSize } from './utils'; import { useScrollHandler, usePrevious, cursorPositionToTextOffset, useRootSize } from './utils';
import Toolbar from './Toolbar'; import Toolbar from './Toolbar';
import styles_ from './styles'; import styles_ from './styles';
@ -218,6 +219,15 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
textCheckbox: () => addListItem('- [ ] ', _('List item')), textCheckbox: () => addListItem('- [ ] ', _('List item')),
textHeading: () => addListItem('## ', ''), textHeading: () => addListItem('## ', ''),
textHorizontalRule: () => addListItem('* * *'), textHorizontalRule: () => addListItem('* * *'),
'editor.execCommand': (value: CommandValue) => {
if (editorRef.current[value.name]) {
if (!('args' in value)) value.args = [];
editorRef.current[value.name](...value.args);
} else {
reg.logger().warn('CodeMirror execCommand: unsupported command: ', value.name);
}
},
}; };
if (commands[cmd.name]) { if (commands[cmd.name]) {

View File

@ -25,6 +25,9 @@ export default function useKeymap(CodeMirror: any) {
CodeMirror.Vim.defineAction('insertListElement', CodeMirror.commands.vimInsertListElement); CodeMirror.Vim.defineAction('insertListElement', CodeMirror.commands.vimInsertListElement);
CodeMirror.Vim.mapCommand('o', 'action', 'insertListElement', { after: true }, { context: 'normal', isEdit: true, interlaceInsertRepeat: true }); 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 // Converts a command of the form editor.command to just command
function editorCommandToCodeMirror(command: String) { function editorCommandToCodeMirror(command: String) {
@ -91,7 +94,7 @@ export default function useKeymap(CodeMirror: any) {
CodeMirror.defineExtension('supportsCommand', function(cmd: EditorCommand) { CodeMirror.defineExtension('supportsCommand', function(cmd: EditorCommand) {
return CommandService.isEditorCommand(cmd.name) && editorCommandToCodeMirror(cmd.name) in CodeMirror.commands; return isEditorCommand(cmd.name) && editorCommandToCodeMirror(cmd.name) in CodeMirror.commands;
}); });
// Used when an editor command is executed using the CommandService.instance().execute // Used when an editor command is executed using the CommandService.instance().execute

View File

@ -249,6 +249,12 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
editor.insertContent(result.html); editor.insertContent(result.html);
} else if (cmd.name === 'editor.focus') { } else if (cmd.name === 'editor.focus') {
editor.focus(); editor.focus();
} else if (cmd.name === 'editor.execCommand') {
if (!('ui' in cmd.value)) cmd.value.ui = false;
if (!('value' in cmd.value)) cmd.value.value = null;
if (!('args' in cmd.value)) cmd.value.args = {};
editor.execCommand(cmd.value.name, cmd.value.ui, cmd.value.value, cmd.value.args);
} else if (cmd.name === 'dropItems') { } else if (cmd.name === 'dropItems') {
if (cmd.value.type === 'notes') { if (cmd.value.type === 'notes') {
const result = await markupToHtml.current(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, cmd.value.markdownTags.join('\n'), markupRenderOptions({ bodyOnly: true })); const result = await markupToHtml.current(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, cmd.value.markdownTags.join('\n'), markupRenderOptions({ bodyOnly: true }));

View File

@ -233,7 +233,6 @@ function NoteEditor(props: NoteEditorProps) {
useWindowCommandHandler({ useWindowCommandHandler({
dispatch: props.dispatch, dispatch: props.dispatch,
plugins: props.plugins,
formNote, formNote,
setShowLocalSearch, setShowLocalSearch,
noteSearchBarRef, noteSearchBarRef,

View File

@ -131,6 +131,9 @@ const declarations: CommandDeclaration[] = [
{ {
name: 'editor.focus', name: 'editor.focus',
}, },
{
name: 'editor.execCommand',
},
]; ];
export default declarations; export default declarations;

View File

@ -159,3 +159,10 @@ export interface EditorCommand {
name: string; name: string;
value: any; value: any;
} }
export interface CommandValue {
name: string;
args?: any; // Should be an array for CodeMirror or an object for TinyMCE
ui?: boolean; // For TinyMCE only
value?: any; // For TinyMCE only
}

View File

@ -1,5 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { FormNote, ScrollOptionTypes } from './types'; import { FormNote, ScrollOptionTypes } from './types';
import editorCommandDeclarations from '../commands/editorCommandDeclarations';
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService'; import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService';
import time from '@joplin/lib/time'; import time from '@joplin/lib/time';
import { reg } from '@joplin/lib/registry'; import { reg } from '@joplin/lib/registry';
@ -19,7 +20,6 @@ interface HookDependencies {
titleInputRef: any; titleInputRef: any;
saveNoteAndWait: Function; saveNoteAndWait: Function;
setFormNote: Function; setFormNote: Function;
plugins: any;
} }
function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, setFormNote: Function): CommandRuntime { function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, setFormNote: Function): CommandRuntime {
@ -61,10 +61,10 @@ function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, s
} }
export default function useWindowCommandHandler(dependencies: HookDependencies) { export default function useWindowCommandHandler(dependencies: HookDependencies) {
const { setShowLocalSearch, noteSearchBarRef, editorRef, titleInputRef, setFormNote, plugins } = dependencies; const { setShowLocalSearch, noteSearchBarRef, editorRef, titleInputRef, setFormNote } = dependencies;
useEffect(() => { useEffect(() => {
for (const declaration of CommandService.instance().editorCommandDeclarations()) { for (const declaration of editorCommandDeclarations) {
CommandService.instance().registerRuntime(declaration.name, editorCommandRuntime(declaration, editorRef, setFormNote)); CommandService.instance().registerRuntime(declaration.name, editorCommandRuntime(declaration, editorRef, setFormNote));
} }
@ -80,7 +80,7 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
} }
return () => { return () => {
for (const declaration of CommandService.instance().editorCommandDeclarations()) { for (const declaration of editorCommandDeclarations) {
CommandService.instance().unregisterRuntime(declaration.name); CommandService.instance().unregisterRuntime(declaration.name);
} }
@ -88,5 +88,5 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
CommandService.instance().unregisterRuntime(command.declaration.name); CommandService.instance().unregisterRuntime(command.declaration.name);
} }
}; };
}, [editorRef, setShowLocalSearch, noteSearchBarRef, titleInputRef, plugins]); }, [editorRef, setShowLocalSearch, noteSearchBarRef, titleInputRef]);
} }

View File

@ -309,40 +309,4 @@ export default class CommandService extends BaseService {
const command = this.commandByName(commandName, { mustExist: false }); const command = this.commandByName(commandName, { mustExist: false });
return !!command; return !!command;
} }
public static isEditorCommand(commandName: string) {
return (commandName.indexOf('editor.') === 0 ||
// These commands are grandfathered in, but in the future
// all editor commands should start with "editor."
commandName === 'insertText' ||
commandName === 'scrollToHash' ||
commandName === 'textCopy' ||
commandName === 'textCut' ||
commandName === 'textPaste' ||
commandName === 'textSelectAll' ||
commandName === 'textBold' ||
commandName === 'textItalic' ||
commandName === 'textLink' ||
commandName === 'textCode' ||
commandName === 'attachFile' ||
commandName === 'textNumberedList' ||
commandName === 'textBulletedList' ||
commandName === 'textCheckbox' ||
commandName === 'textHeading' ||
commandName === 'textHorizontalRule' ||
commandName === 'insertDateTime' ||
commandName === 'selectedText' ||
commandName === 'replaceSelection'
);
}
public editorCommandDeclarations(): CommandDeclaration[] {
const output = [];
for (const name in this.commands_) {
if (CommandService.isEditorCommand(name)) { output.push(this.commands_[name].declaration); }
}
return output;
}
} }

View File

@ -33,16 +33,27 @@ export default class ToolbarButtonUtils {
return this.service_; return this.service_;
} }
// Editor commands will focus the editor after they're executed
private isEditorCommand(commandName: string) { private isEditorCommand(commandName: string) {
return CommandService.isEditorCommand(commandName) && !( return (commandName.indexOf('editor.') === 0 ||
// These commands are attached to the editor runtime, // These commands are grandfathered in, but in the future
// but they either handle focus themselves or don't need // all editor commands should start with "editor."
// to focus the editor // WARNING: Some commands such as textLink are not defined here
commandName === 'textLink' || // because they are more complex and handle focus manually
commandName === 'insertText' || commandName === 'textCopy' ||
commandName === 'scrollToHash' || commandName === 'textCut' ||
commandName === 'selectedText' || commandName === 'textPaste' ||
commandName === 'replaceSelection' commandName === 'textSelectAll' ||
commandName === 'textBold' ||
commandName === 'textItalic' ||
commandName === 'textCode' ||
commandName === 'attachFile' ||
commandName === 'textNumberedList' ||
commandName === 'textBulletedList' ||
commandName === 'textCheckbox' ||
commandName === 'textHeading' ||
commandName === 'textHorizontalRule' ||
commandName === 'insertDateTime'
); );
} }