1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-23 18:53: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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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.
*/
export default class JoplinCommands {
/**
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
*
@ -40,8 +40,8 @@ export default class JoplinCommands {
* 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.
*
* ```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.
*/
export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
on(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/
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;
registerImportModule(module: ImportModule): Promise<void>;
registerExportModule(module: ExportModule): Promise<void>;
registerImportModule(module: ImportModule): Promise<void>;
}

View File

@ -6,7 +6,7 @@ export interface ChangeEvent {
*/
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.
*

View File

@ -3,7 +3,7 @@ import { Disposable } from './types';
declare enum ItemChangeEventType {
Create = 1,
Update = 2,
Delete = 3
Delete = 3,
}
interface ItemChangeEvent {
id: string;
@ -12,8 +12,8 @@ interface ItemChangeEvent {
interface SyncStartEvent {
withErrors: boolean;
}
declare type ItemChangeHandler = (event: ItemChangeEvent) => void;
declare type SyncStartHandler = (event: SyncStartEvent) => void;
declare type ItemChangeHandler = (event: ItemChangeEvent)=> void;
declare type SyncStartHandler = (event: SyncStartEvent)=> void;
/**
* 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

View File

@ -330,57 +330,16 @@ export enum SettingItemType {
export interface SettingItem {
value: any;
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;
label: 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.
*/
description?: string;
isEnum?: boolean;
/**
* 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.
*/
section?: string;
options?: any;
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;
/**
* An advanced setting will be moved under the "Advanced" button in the
* config screen.
*/
advanced?: boolean;
/**
* Set the min, max and step values if you want to restrict an int setting
* to a particular range.
*/
minimum?: number;
maximum?: number;
step?: number;

View File

@ -12,13 +12,16 @@ joplin.plugins.register({
);
await joplin.commands.register({
name: 'editor.printSomething',
name: 'printSomething',
label: 'Print some random string',
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
// using cm.execCommand(stringName) or register a joplin command called 'editor.printSomething'
// through the joplin.commands api
CodeMirror.commands.printSomething = function(cm) {
console.log("Something");
}
CodeMirror.defineExtension('printSomething', function(something) {
console.log(something);
});
}
module.exports = {

View File

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

View File

@ -5,6 +5,7 @@ import { useState, useEffect, useRef, forwardRef, useCallback, useImperativeHand
import { EditorCommand, NoteBodyEditorProps } from '../../utils/types';
import { commandAttachFileToBody, handlePasteEvent } from '../../utils/resourceHandling';
import { ScrollOptions, ScrollOptionTypes } from '../../utils/types';
import { CommandValue } from '../../utils/types';
import { useScrollHandler, usePrevious, cursorPositionToTextOffset, useRootSize } from './utils';
import Toolbar from './Toolbar';
import styles_ from './styles';
@ -218,6 +219,15 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
textCheckbox: () => addListItem('- [ ] ', _('List item')),
textHeading: () => 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]) {

View File

@ -25,6 +25,9 @@ export default function useKeymap(CodeMirror: any) {
CodeMirror.Vim.defineAction('insertListElement', CodeMirror.commands.vimInsertListElement);
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) {
@ -91,7 +94,7 @@ export default function useKeymap(CodeMirror: any) {
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

View File

@ -249,6 +249,12 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
editor.insertContent(result.html);
} else if (cmd.name === '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') {
if (cmd.value.type === 'notes') {
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({
dispatch: props.dispatch,
plugins: props.plugins,
formNote,
setShowLocalSearch,
noteSearchBarRef,

View File

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

View File

@ -159,3 +159,10 @@ export interface EditorCommand {
name: string;
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 { FormNote, ScrollOptionTypes } from './types';
import editorCommandDeclarations from '../commands/editorCommandDeclarations';
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService';
import time from '@joplin/lib/time';
import { reg } from '@joplin/lib/registry';
@ -19,7 +20,6 @@ interface HookDependencies {
titleInputRef: any;
saveNoteAndWait: Function;
setFormNote: Function;
plugins: any;
}
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) {
const { setShowLocalSearch, noteSearchBarRef, editorRef, titleInputRef, setFormNote, plugins } = dependencies;
const { setShowLocalSearch, noteSearchBarRef, editorRef, titleInputRef, setFormNote } = dependencies;
useEffect(() => {
for (const declaration of CommandService.instance().editorCommandDeclarations()) {
for (const declaration of editorCommandDeclarations) {
CommandService.instance().registerRuntime(declaration.name, editorCommandRuntime(declaration, editorRef, setFormNote));
}
@ -80,7 +80,7 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
}
return () => {
for (const declaration of CommandService.instance().editorCommandDeclarations()) {
for (const declaration of editorCommandDeclarations) {
CommandService.instance().unregisterRuntime(declaration.name);
}
@ -88,5 +88,5 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
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 });
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_;
}
// Editor commands will focus the editor after they're executed
private isEditorCommand(commandName: string) {
return CommandService.isEditorCommand(commandName) && !(
// These commands are attached to the editor runtime,
// but they either handle focus themselves or don't need
// to focus the editor
commandName === 'textLink' ||
commandName === 'insertText' ||
commandName === 'scrollToHash' ||
commandName === 'selectedText' ||
commandName === 'replaceSelection'
return (commandName.indexOf('editor.') === 0 ||
// These commands are grandfathered in, but in the future
// all editor commands should start with "editor."
// WARNING: Some commands such as textLink are not defined here
// because they are more complex and handle focus manually
commandName === 'textCopy' ||
commandName === 'textCut' ||
commandName === 'textPaste' ||
commandName === 'textSelectAll' ||
commandName === 'textBold' ||
commandName === 'textItalic' ||
commandName === 'textCode' ||
commandName === 'attachFile' ||
commandName === 'textNumberedList' ||
commandName === 'textBulletedList' ||
commandName === 'textCheckbox' ||
commandName === 'textHeading' ||
commandName === 'textHorizontalRule' ||
commandName === 'insertDateTime'
);
}