1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-11 18:24:43 +02:00

Plugins: Added a way to execute commands from Markdown-it content scripts

This commit is contained in:
Laurent Cozic 2020-12-11 12:00:24 +00:00
parent bc76e4a918
commit 65cc6853bd
7 changed files with 136 additions and 24 deletions

View File

@ -3,6 +3,22 @@ import { ContentScriptType } from 'api/types';
joplin.plugins.register({
onStart: async function() {
await joplin.commands.register({
name: 'testCommand',
label: 'My Test Command',
execute: async (...args) => {
alert('Got command "testCommand" with args: ' + JSON.stringify(args));
},
});
await joplin.commands.register({
name: 'testCommandNoArgs',
label: 'My Test Command (no args)',
execute: async () => {
alert('Got command "testCommandNoArgs"');
},
});
await joplin.plugins.registerContentScript(
ContentScriptType.MarkdownItPlugin,
'justtesting',

View File

@ -1,4 +1,9 @@
.just-testing {
background-color: red;
color: yellow;
background-color: rgb(202, 255, 255);
color: rgb(82, 0, 78);
}
.just-testing a {
background-color: rgb(202, 255, 255);
color: rgb(10, 0, 104);
}

View File

@ -6,7 +6,13 @@ function plugin(markdownIt, _options) {
markdownIt.renderer.rules.fence = function(tokens, idx, options, env, self) {
const token = tokens[idx];
if (token.info !== 'justtesting') return defaultRender(tokens, idx, options, env, self);
return `<div class="just-testing">JUST TESTING: ${token.content}</div>`;
return `
<div class="just-testing">
<p>JUST TESTING: ${token.content}</p>
<p><a href="#" onclick="webviewApi.executeCommand('testCommand', 'one', 'two'); return false;">Click to send "testCommand" to plugin</a></p>
<p><a href="#" onclick="webviewApi.executeCommand('testCommandNoArgs'); return false;">Click to send "testCommandNoArgs" to plugin</a></p>
</div>
`;
};
}

View File

@ -3,6 +3,7 @@ import { FormNote } from './types';
import contextMenu from './contextMenu';
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
import { _ } from '@joplin/lib/locale';
import CommandService from '@joplin/lib/services/CommandService';
const BaseItem = require('@joplin/lib/models/BaseItem');
const BaseModel = require('@joplin/lib/BaseModel').default;
const Resource = require('@joplin/lib/models/Resource.js');
@ -90,6 +91,10 @@ export default function useMessageHandler(scrollWhenReady: any, setScrollWhenRea
}
} else if (msg.indexOf('#') === 0) {
// This is an internal anchor, which is handled by the WebView so skip this case
} else if (msg === 'contentScriptExecuteCommand') {
const commandName = arg0.name;
const commandArgs = arg0.args || [];
void CommandService.instance().execute(commandName, ...commandArgs);
} else {
bridge().showErrorMessageBox(_('Unsupported link or message: %s', msg));
}

View File

@ -49,10 +49,24 @@
<script src="./lib.js"></script>
<script>
// This is function used internally to send message from the webview to
// the host.
const ipcProxySendToHost = (methodName, arg) => {
window.postMessage({ target: 'main', name: methodName, args: [ arg ] }, '*');
}
// This function is reserved for plugin, currently only to allow
// executing a command, but more features could be added to the object
// later on.
const webviewApi = {
executeCommand: function (commandName, ...args) {
return ipcProxySendToHost('contentScriptExecuteCommand', {
name: commandName,
args: args,
});
}
}
let pluginAssetsAdded_ = {};
try {

View File

@ -51,14 +51,20 @@ export default class JoplinPlugins {
}
/**
* Registers a new content script. Unlike regular plugin code, which runs in a separate process, content scripts run within the main process code
* and thus allow improved performances and more customisations in specific cases. It can be used for example to load a Markdown or editor plugin.
* Registers a new content script. Unlike regular plugin code, which
* runs in a separate process, content scripts run within the main
* process code and thus allow improved performances and more
* customisations in specific cases. It can be used for example to load
* a Markdown or editor plugin.
*
* Note that registering a content script in itself will do nothing - it will only be loaded in specific cases by the relevant app modules
* (eg. the Markdown renderer or the code editor). So it is not a way to inject and run arbitrary code in the app, which for safety and performance reasons is not supported.
* Note that registering a content script in itself will do nothing -
* it will only be loaded in specific cases by the relevant app modules
* (eg. the Markdown renderer or the code editor). So it is not a way
* to inject and run arbitrary code in the app, which for safety and
* performance reasons is not supported.
*
* [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* * [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* * [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
*
* @param type Defines how the script will be used. See the type definition for more information about each supported type.
* @param id A unique ID for the content script.

View File

@ -334,7 +334,8 @@ export type Path = string[];
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template below.
* Registers a new Markdown-It plugin, which should follow the template
* below.
*
* ```javascript
* module.exports = {
@ -350,14 +351,49 @@ export enum ContentScriptType {
* }
* }
* ```
* See [the
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* for a simple Markdown-it plugin example.
*
* - The `context` argument is currently unused but could be used later on to provide access to your own plugin so that the content script and plugin can communicate.
* ## Exported members
*
* - The **required** `plugin` key is the actual Markdown-It plugin - check the [official doc](https://github.com/markdown-it/markdown-it) for more information. The `options` parameter is of type [RuleOptions](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts), which contains a number of options, mostly useful for Joplin's internal code.
* - The `context` argument is currently unused but could be used later
* on to provide access to your own plugin so that the content script
* and plugin can communicate.
*
* - Using the **optional** `assets` key you may specify assets such as JS or CSS that should be loaded in the rendered HTML document. Check for example the Joplin [Mermaid plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts) to see how the data should be structured.
* - The **required** `plugin` key is the actual Markdown-It plugin -
* check the [official
* doc](https://github.com/markdown-it/markdown-it) for more
* information. The `options` parameter is of type
* [RuleOptions](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts),
* which contains a number of options, mostly useful for Joplin's
* internal code.
*
* To include a regular Markdown-It plugin, that doesn't make use of any Joplin-specific features, you would simply create a file such as this:
* - Using the **optional** `assets` key you may specify assets such as
* JS or CSS that should be loaded in the rendered HTML document.
* Check for example the Joplin [Mermaid
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
* to see how the data should be structured.
*
* ## Passing messages from the content script to your plugin
*
* The application provides the following function to allow executing
* commands from the rendered HTML code:
*
* `webviewApi.executeCommand(commandName, ...args)`
*
* So you can use this mechanism to pass messages from the note viewer
* to your own plugin. To do so you would define a command, using
* `joplin.commands.register`, then you would call this command using
* the `webviewApi` object. See again [the
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* to see how this can be done.
*
* ## Registering an existing Markdown-it plugin
*
* To include a regular Markdown-It plugin, that doesn't make use of
* any Joplin-specific features, you would simply create a file such as
* this:
*
* ```javascript
* module.exports = {
@ -371,7 +407,8 @@ export enum ContentScriptType {
*/
MarkdownItPlugin = 'markdownItPlugin',
/**
* Registers a new CodeMirror plugin, which should follow the template below.
* Registers a new CodeMirror plugin, which should follow the template
* below.
*
* ```javascript
* module.exports = {
@ -382,8 +419,8 @@ export enum ContentScriptType {
* },
* codeMirrorResources: [],
* codeMirrorOptions: {
* // ...
* },
* // ...
* },
* assets: {
* // ...
* },
@ -392,19 +429,42 @@ export enum ContentScriptType {
* }
* ```
*
* - The `context` argument is currently unused but could be used later on to provide access to your own plugin so that the content script and plugin can communicate.
* - The `context` argument is currently unused but could be used later
* on to provide access to your own plugin so that the content script
* and plugin can communicate.
*
* - The `plugin` key is your CodeMirror plugin. This is where you can register new commands with CodeMirror or interact with the CodeMirror instance as needed.
* - The `plugin` key is your CodeMirror plugin. This is where you can
* register new commands with CodeMirror or interact with the
* CodeMirror instance as needed.
*
* - The `codeMirrorResources` key is an array of CodeMirror resources that will be loaded and attached to the CodeMirror module. These are made up of addons, keymaps, and modes. For example, for a plugin that want's to enable clojure highlighting in code blocks. `codeMirrorResources` would be set to `['mode/clojure/clojure']`.
* - The `codeMirrorResources` key is an array of CodeMirror resources
* that will be loaded and attached to the CodeMirror module. These
* are made up of addons, keymaps, and modes. For example, for a
* plugin that want's to enable clojure highlighting in code blocks.
* `codeMirrorResources` would be set to `['mode/clojure/clojure']`.
*
* - The `codeMirrorOptions` key contains all the [CodeMirror](https://codemirror.net/doc/manual.html#config) options that will be set or changed by this plugin. New options can alse be declared via [`CodeMirror.defineOption`](https://codemirror.net/doc/manual.html#defineOption), and then have their value set here. For example, a plugin that enables line numbers would set `codeMirrorOptions` to `{'lineNumbers': true}`.
* - The `codeMirrorOptions` key contains all the
* [CodeMirror](https://codemirror.net/doc/manual.html#config)
* options that will be set or changed by this plugin. New options
* can alse be declared via
* [`CodeMirror.defineOption`](https://codemirror.net/doc/manual.html#defineOption),
* and then have their value set here. For example, a plugin that
* enables line numbers would set `codeMirrorOptions` to
* `{'lineNumbers': true}`.
*
* - Using the **optional** `assets` key you may specify **only** CSS assets that should be loaded in the rendered HTML document. Check for example the Joplin [Mermaid plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts) to see how the data should be structured.
* - Using the **optional** `assets` key you may specify **only** CSS
* assets that should be loaded in the rendered HTML document. Check
* for example the Joplin [Mermaid
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
* to see how the data should be structured.
*
* One of the `plugin`, `codeMirrorResources`, or `codeMirrorOptions` keys must be provided for the plugin to be valid. Having multiple or all provided is also okay.
* One of the `plugin`, `codeMirrorResources`, or `codeMirrorOptions`
* keys must be provided for the plugin to be valid. Having multiple or
* all provided is also okay.
*
* See the [demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script) for an example of all these keys being used in one plugin.
* See the [demo
* plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}