1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00

Android: Fixes #10152: Fix broken plugin API: editor.execCommand (#10153)

This commit is contained in:
Henry Heino 2024-03-20 03:58:42 -07:00 committed by GitHub
parent 32141d4e23
commit 44e8950f1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 78 additions and 20 deletions

View File

@ -531,6 +531,7 @@ packages/app-mobile/components/NoteEditor/NoteEditor.js
packages/app-mobile/components/NoteEditor/SearchPanel.js
packages/app-mobile/components/NoteEditor/commandDeclarations.js
packages/app-mobile/components/NoteEditor/hooks/useCodeMirrorPlugins.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.test.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.js
packages/app-mobile/components/NoteEditor/hooks/useKeyboardVisible.js
packages/app-mobile/components/NoteEditor/types.js

1
.gitignore vendored
View File

@ -511,6 +511,7 @@ packages/app-mobile/components/NoteEditor/NoteEditor.js
packages/app-mobile/components/NoteEditor/SearchPanel.js
packages/app-mobile/components/NoteEditor/commandDeclarations.js
packages/app-mobile/components/NoteEditor/hooks/useCodeMirrorPlugins.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.test.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.js
packages/app-mobile/components/NoteEditor/hooks/useKeyboardVisible.js
packages/app-mobile/components/NoteEditor/types.js

View File

@ -14,3 +14,22 @@ module.exports = () => {
global.console = jestConsole;
});
};
// jsdom extensions
if (typeof document !== 'undefined') {
// Prevents the CodeMirror error "getClientRects is undefined".
// See https://github.com/jsdom/jsdom/issues/3002#issue-652790925
document.createRange = () => {
const range = new Range();
range.getBoundingClientRect = jest.fn();
range.getClientRects = () => {
return {
length: 0,
item: () => null,
[Symbol.iterator]: jest.fn(),
};
};
return range;
};
}

View File

@ -0,0 +1,36 @@
import CommandService from '@joplin/lib/services/CommandService';
import useEditorCommandHandler from './useEditorCommandHandler';
import commandDeclarations from '../commandDeclarations';
import createTestEditorControl from '@joplin/editor/CodeMirror/testUtil/createEditorControl';
import { renderHook } from '@testing-library/react-native';
import { defaultState } from '@joplin/lib/reducer';
describe('useEditorCommandHandler', () => {
beforeAll(() => {
const storeMock = { getState: () => defaultState, dispatch: jest.fn() };
CommandService.instance().initialize(storeMock, false, ()=>({}));
for (const declaration of commandDeclarations) {
CommandService.instance().registerDeclaration(declaration);
}
});
it('should support running custom commands with editor.execCommand', async () => {
const editor = createTestEditorControl('Test.');
renderHook(() => useEditorCommandHandler(editor));
const testCommandCallback = jest.fn();
editor.registerCommand('myCommand', testCommandCallback);
expect(testCommandCallback).not.toHaveBeenCalled();
// Should support running commands with arguments
await CommandService.instance().execute('editor.execCommand', { name: 'myCommand', args: ['a', 'b', 'c'] });
expect(testCommandCallback).toHaveBeenCalledTimes(1);
expect(testCommandCallback).toHaveBeenLastCalledWith('a', 'b', 'c');
// Should support running commands without arguments
await CommandService.instance().execute('editor.execCommand', { name: 'myCommand' });
expect(testCommandCallback).toHaveBeenCalledTimes(2);
expect(testCommandCallback).toHaveBeenLastCalledWith();
});
});

View File

@ -1,5 +1,5 @@
import CommandService, { CommandContext, CommandDeclaration } from '@joplin/lib/services/CommandService';
import { EditorControl } from '../types';
import { EditorControl } from '@joplin/editor/types';
import { useEffect } from 'react';
import commandDeclarations, { enabledCondition } from '../commandDeclarations';
import Logger from '@joplin/utils/Logger';
@ -12,9 +12,13 @@ const commandRuntime = (declaration: CommandDeclaration, editor: EditorControl)
// Many editor CodeMirror commands are missing the editor. prefix.
let commandName = declaration.name.replace(/^editor\./, '');
if (declaration.name === 'editor.execCommand') {
commandName = args[0];
args = args.slice(1);
if (commandName === 'execCommand') {
commandName = args[0]?.name;
args = args[0]?.args ?? [];
if (!commandName) {
throw new Error('editor.execCommand is missing the name of the command to execute');
}
}
if (!(await editor.supportsCommand(commandName))) {

View File

@ -171,4 +171,16 @@ describe('CodeMirror5Emulation', () => {
expect(testExtensionFn1).toHaveBeenCalledTimes(1);
expect(testExtensionFn2).toHaveBeenCalledTimes(1);
});
it('defineExtension should register an extension where this points to the editor', () => {
const codeMirror = makeCodeMirrorEmulation('Test...');
let lastThis = null;
codeMirror.defineExtension('testExtension', function() {
lastThis = this;
});
codeMirror.execCommand('testExtension');
expect(lastThis).toBe(codeMirror);
});
});

View File

@ -503,7 +503,7 @@ export default class CodeMirror5Emulation extends BaseCodeMirror5Emulation {
if (name in CodeMirror5Emulation.commands) {
return CodeMirror5Emulation.commands[name as (keyof typeof CodeMirror5Emulation.commands)](this);
} else if (typeof this._userExtensions[name] === 'function') {
return this._userExtensions[name](...args);
return this._userExtensions[name].call(this, ...args);
}
}
}

View File

@ -1,17 +1,2 @@
require('../../jest.base-setup.js')();
// Prevents the CodeMirror error "getClientRects is undefined".
// See https://github.com/jsdom/jsdom/issues/3002#issue-652790925
document.createRange = () => {
const range = new Range();
range.getBoundingClientRect = jest.fn();
range.getClientRects = () => {
return {
length: 0,
item: () => null,
[Symbol.iterator]: jest.fn(),
};
};
return range;
};