1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-26 22:41:17 +02:00

Desktop: Fix returning form data from plugin dialogs (#12092)

This commit is contained in:
Henry Heino
2025-04-13 11:28:56 -07:00
committed by GitHub
parent a8b18e9ab0
commit 3d15e64762
4 changed files with 76 additions and 4 deletions

View File

@@ -23,6 +23,27 @@ test.describe('pluginApi', () => {
await editor.expectToHaveText('PASS');
});
test('should return form data from the dialog API', async ({ startAppWithPlugins }) => {
const { app, mainWindow } = await startAppWithPlugins(['resources/test-plugins/dialogs.js']);
const mainScreen = await new MainScreen(mainWindow).setup();
await mainScreen.createNewNote('First note');
const editor = mainScreen.noteEditor;
await editor.expectToHaveText('');
await mainScreen.goToAnything.runCommand(app, 'showTestDialog');
// Wait for the iframe to load
const dialogContent = mainScreen.dialog.locator('iframe').contentFrame();
await dialogContent.locator('form').waitFor();
// Submitting the dialog should include form data in the output
await mainScreen.dialog.getByRole('button', { name: 'Okay' }).click();
await editor.expectToHaveText(JSON.stringify({
id: 'ok',
hasFormData: true,
}));
});
test('should be possible to create multiple toasts with the same text from a plugin', async ({ startAppWithPlugins }) => {
const { app, mainWindow } = await startAppWithPlugins(['resources/test-plugins/showToast.js']);
const mainScreen = await new MainScreen(mainWindow).setup();

View File

@@ -0,0 +1,51 @@
// Allows referencing the Joplin global:
/* eslint-disable no-undef */
// Allows the `joplin-manifest` block comment:
/* eslint-disable multiline-comment-style */
/* joplin-manifest:
{
"id": "org.joplinapp.plugins.example.dialogs",
"manifest_version": 1,
"app_min_version": "3.1",
"name": "JS Bundle test",
"description": "JS Bundle Test plugin",
"version": "1.0.0",
"author": "",
"homepage_url": "https://joplinapp.org"
}
*/
joplin.plugins.register({
onStart: async function() {
const dialogs = joplin.views.dialogs;
const dialogHandle = await dialogs.create('test-dialog');
await dialogs.setHtml(
dialogHandle,
`
<form name="main-form">
<label>Test: <input type="checkbox" name="test" checked/></label>
</form>
`,
);
await dialogs.setButtons(dialogHandle, [
{
id: 'ok',
title: 'Okay',
},
]);
await joplin.commands.register({
name: 'showTestDialog',
label: 'showTestDialog',
iconName: 'fas fa-drum',
execute: async () => {
const result = await joplin.views.dialogs.open(dialogHandle);
await joplin.commands.execute('editor.setText', JSON.stringify({
id: result.id,
hasFormData: !!result.formData,
}));
},
});
},
});

View File

@@ -46,9 +46,9 @@ export default function UserWebviewDialog(props: Props) {
const buttons: ButtonSpec[] = (props.buttons ? props.buttons : defaultButtons()).map((b: ButtonSpec) => {
return {
...b,
onClick: () => {
onClick: async () => {
const response: DialogResult = { id: b.id };
const formData = webviewRef.current.formData();
const formData = await webviewRef.current.formData();
if (formData && Object.keys(formData).length) response.formData = formData;
viewController().closeWithResponse(response);
},

View File

@@ -17,7 +17,7 @@ const useFormData = (viewRef: RefObject<HTMLIFrameElement>, postMessage: PostMes
const listeners = [...formDataListenersRef.current];
formDataListenersRef.current = [];
for (const listener of listeners) {
listener(event.data.formData);
listener(formData);
}
}
});
@@ -26,7 +26,7 @@ const useFormData = (viewRef: RefObject<HTMLIFrameElement>, postMessage: PostMes
return {
getFormData: () => {
return new Promise<FormDataRecord>(resolve => {
postMessage('getFormData', null);
postMessage('serializeForms', null);
formDataListenersRef.current.push((data) => {
resolve(data);
});