Skip to content

Commit c648f19

Browse files
committed
Desktop: Added support for Menu API for plugins
1 parent 2caaf8e commit c648f19

37 files changed

+5561
-34
lines changed

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,13 @@ ReactNativeClient/lib/services/plugins/api/JoplinSettings.js
264264
ReactNativeClient/lib/services/plugins/api/JoplinViews.js
265265
ReactNativeClient/lib/services/plugins/api/JoplinViewsDialogs.js
266266
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenuItems.js
267+
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenus.js
267268
ReactNativeClient/lib/services/plugins/api/JoplinViewsPanels.js
268269
ReactNativeClient/lib/services/plugins/api/JoplinViewsToolbarButtons.js
269270
ReactNativeClient/lib/services/plugins/api/JoplinWorkspace.js
270271
ReactNativeClient/lib/services/plugins/api/types.js
271272
ReactNativeClient/lib/services/plugins/BasePluginRunner.js
273+
ReactNativeClient/lib/services/plugins/MenuController.js
272274
ReactNativeClient/lib/services/plugins/MenuItemController.js
273275
ReactNativeClient/lib/services/plugins/Plugin.js
274276
ReactNativeClient/lib/services/plugins/PluginService.js

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,13 @@ ReactNativeClient/lib/services/plugins/api/JoplinSettings.js
258258
ReactNativeClient/lib/services/plugins/api/JoplinViews.js
259259
ReactNativeClient/lib/services/plugins/api/JoplinViewsDialogs.js
260260
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenuItems.js
261+
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenus.js
261262
ReactNativeClient/lib/services/plugins/api/JoplinViewsPanels.js
262263
ReactNativeClient/lib/services/plugins/api/JoplinViewsToolbarButtons.js
263264
ReactNativeClient/lib/services/plugins/api/JoplinWorkspace.js
264265
ReactNativeClient/lib/services/plugins/api/types.js
265266
ReactNativeClient/lib/services/plugins/BasePluginRunner.js
267+
ReactNativeClient/lib/services/plugins/MenuController.js
266268
ReactNativeClient/lib/services/plugins/MenuItemController.js
267269
ReactNativeClient/lib/services/plugins/Plugin.js
268270
ReactNativeClient/lib/services/plugins/PluginService.js
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dist/*
2+
node_modules/
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Joplin Plugin
2+
3+
This is a template to create a new Joplin plugin.
4+
5+
The main two files you will want to look at are:
6+
7+
- `/src/index.ts`, which contains the entry point for the plugin source code.
8+
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
9+
10+
The plugin is built using webpack, which create the compiled code in `/dist`. The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
11+
12+
## Building the plugin
13+
14+
To build the plugin, simply run `npm run dist`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Plugin from '../Plugin';
2+
import Joplin from './Joplin';
3+
import Logger from 'lib/Logger';
4+
/**
5+
* @ignore
6+
*/
7+
export default class Global {
8+
private joplin_;
9+
private requireWhiteList_;
10+
constructor(logger: Logger, implementation: any, plugin: Plugin, store: any);
11+
get joplin(): Joplin;
12+
private requireWhiteList;
13+
require(filePath: string): any;
14+
get process(): any;
15+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Plugin from '../Plugin';
2+
import JoplinData from './JoplinData';
3+
import JoplinPlugins from './JoplinPlugins';
4+
import JoplinWorkspace from './JoplinWorkspace';
5+
import JoplinFilters from './JoplinFilters';
6+
import JoplinCommands from './JoplinCommands';
7+
import JoplinViews from './JoplinViews';
8+
import JoplinInterop from './JoplinInterop';
9+
import JoplinSettings from './JoplinSettings';
10+
import Logger from 'lib/Logger';
11+
/**
12+
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
13+
*/
14+
export default class Joplin {
15+
private data_;
16+
private plugins_;
17+
private workspace_;
18+
private filters_;
19+
private commands_;
20+
private views_;
21+
private interop_;
22+
private settings_;
23+
constructor(logger: Logger, implementation: any, plugin: Plugin, store: any);
24+
get data(): JoplinData;
25+
get plugins(): JoplinPlugins;
26+
get workspace(): JoplinWorkspace;
27+
/**
28+
* @ignore
29+
*
30+
* Not sure if it's the best way to hook into the app
31+
* so for now disable filters.
32+
*/
33+
get filters(): JoplinFilters;
34+
get commands(): JoplinCommands;
35+
get views(): JoplinViews;
36+
get interop(): JoplinInterop;
37+
get settings(): JoplinSettings;
38+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Command } from './types';
2+
/**
3+
* This class allows executing or registering new Joplin commands. Commands can be executed or associated with
4+
* {@link JoplinViewsToolbarButtons | toolbar buttons} or {@link JoplinViewsMenuItems | menu items}.
5+
*
6+
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/CliClient/tests/support/plugins/register_command)
7+
*
8+
* ## Executing Joplin's internal commands
9+
*
10+
* It is also possible to execute internal Joplin's commands which, as of now, are not well documented.
11+
* You can find the list directly on GitHub though at the following locations:
12+
*
13+
* https://github.com/laurent22/joplin/tree/dev/ElectronClient/gui/MainScreen/commands
14+
* https://github.com/laurent22/joplin/tree/dev/ElectronClient/commands
15+
* https://github.com/laurent22/joplin/tree/dev/ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.ts
16+
*
17+
* To view what arguments are supported, you can open any of these files and look at the `execute()` command.
18+
*/
19+
export default class JoplinCommands {
20+
/**
21+
* <span class="platform-desktop">desktop</span> Executes the given command.
22+
* The `props` are the arguments passed to the command, and they vary based on the command
23+
*
24+
* ```typescript
25+
* // Create a new note in the current notebook:
26+
* await joplin.commands.execute('newNote');
27+
*
28+
* // Create a new sub-notebook under the provided notebook
29+
* // Note: internally, notebooks are called "folders".
30+
* await joplin.commands.execute('newFolder', { parent_id: "SOME_FOLDER_ID" });
31+
* ```
32+
*/
33+
execute(commandName: string, props?: any): Promise<any>;
34+
/**
35+
* <span class="platform-desktop">desktop</span> Registers a new command.
36+
*
37+
* ```typescript
38+
* // Register a new commmand called "testCommand1"
39+
*
40+
* await joplin.commands.register({
41+
* name: 'testCommand1',
42+
* label: 'My Test Command 1',
43+
* iconName: 'fas fa-music',
44+
* execute: () => {
45+
* alert('Testing plugin command 1');
46+
* },
47+
* });
48+
* ```
49+
*/
50+
register(command: Command): Promise<void>;
51+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Path } from './types';
2+
/**
3+
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
4+
* This is the main way to retrieve data, such as notes, notebooks, tags, etc.
5+
* or to update them or delete them.
6+
*
7+
* This is also what you would use to search notes, via the `search` endpoint.
8+
*
9+
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/CliClient/tests/support/plugins/simple)
10+
*
11+
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
12+
* And each method takes these parameters:
13+
*
14+
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
15+
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
16+
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
17+
* * `files`: (Optional) Used to create new resources and associate them with files.
18+
*
19+
* Please refer to the [Joplin API documentation](https://joplinapp.org/api/references/rest_api/) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
20+
*
21+
* For example:
22+
*
23+
* ```typescript
24+
* // Get a note ID, title and body
25+
* const noteId = 'some_note_id';
26+
* const note = await joplin.data.get(['notes', noteId], { fields: ['id', 'title', 'body'] });
27+
*
28+
* // Get all folders
29+
* const folders = await joplin.data.get(['folders']);
30+
*
31+
* // Set the note body
32+
* await joplin.data.put(['notes', noteId], null, { body: "New note body" });
33+
*
34+
* // Create a new note under one of the folders
35+
* await joplin.data.post(['notes'], null, { body: "my new note", title: "some title", parent_id: folders[0].id });
36+
* ```
37+
*/
38+
export default class JoplinData {
39+
private api_;
40+
private pathSegmentRegex_;
41+
private serializeApiBody;
42+
private pathToString;
43+
get(path: Path, query?: any): Promise<any>;
44+
post(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
45+
put(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
46+
delete(path: Path, query?: any): Promise<any>;
47+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* @ignore
3+
*
4+
* Not sure if it's the best way to hook into the app
5+
* so for now disable filters.
6+
*/
7+
export default class JoplinFilters {
8+
on(name: string, callback: Function): Promise<void>;
9+
off(name: string, callback: Function): Promise<void>;
10+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ExportModule, ImportModule } from './types';
2+
/**
3+
* Provides a way to create modules to import external data into Joplin or to export notes into any arbitrary format.
4+
*
5+
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/CliClient/tests/support/plugins/json_export)
6+
*
7+
* To implement an import or export module, you would simply define an object with various event handlers that are called
8+
* by the application during the import/export process.
9+
*
10+
* See the documentation of the [[ExportModule]] and [[ImportModule]] for more information.
11+
*
12+
* 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/
13+
*/
14+
export default class JoplinInterop {
15+
registerExportModule(module: ExportModule): Promise<void>;
16+
registerImportModule(module: ImportModule): Promise<void>;
17+
}

0 commit comments

Comments
 (0)