Listens to a messages sent from the content script using postMessage().
+ See ContentScriptType for more information as well as the
+ postMessage
+ demo
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.
+
The plugin generator provides a way to build any content script you might
+ want to package as well as its dependencies. See the Plugin Generator
+ doc
+ for more information.
Defines how the script will be used. See the type definition for more information about each supported type.
+
+
+
+
id: string
+
+
A unique ID for the content script.
+
+
+
+
scriptPath: string
+
+
Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set scriptPath to "./content_script.js.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/api/references/plugin_api/classes/joplinplugins.html b/docs/api/references/plugin_api/classes/joplinplugins.html
index 159cac5c8..c4eb16c95 100644
--- a/docs/api/references/plugin_api/classes/joplinplugins.html
+++ b/docs/api/references/plugin_api/classes/joplinplugins.html
@@ -149,45 +149,22 @@
-
-
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.
-
The plugin generator provides a way to build any content script you might
- want to package as well as its dependencies. See the Plugin Generator
- doc
- for more information.
Defines how the script will be used. See the type definition for more information about each supported type.
-
id: string
-
-
A unique ID for the content script.
-
scriptPath: string
-
-
Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set scriptPath to "./content_script.js.
Can be used by CodeMirror content scripts to post a message to the plugin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/.gitignore b/packages/app-cli/tests/support/plugins/codemirror_content_script/.gitignore
index 847e39a46..a9c428d62 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/.gitignore
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/.gitignore
@@ -3,5 +3,8 @@ node_modules/
publish/
+
+
+
dist/*
*.jpl
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/.npmignore b/packages/app-cli/tests/support/plugins/codemirror_content_script/.npmignore
index 79fcfe8d9..8df5d12d4 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/.npmignore
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/.npmignore
@@ -8,3 +8,6 @@ tsconfig.json
webpack.config.js
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/GENERATOR_DOC.md b/packages/app-cli/tests/support/plugins/codemirror_content_script/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/GENERATOR_DOC.md
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/Joplin.d.ts b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/Joplin.d.ts
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinContentScripts.d.ts b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinPlugins.d.ts b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinPlugins.d.ts
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinSettings.d.ts b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinSettings.d.ts
index d725ea47b..ab9254e9e 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinSettings.d.ts
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinViewsPanels.d.ts b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinViewsPanels.d.ts
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/types.ts b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/api/types.ts
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/package.json b/packages/app-cli/tests/support/plugins/codemirror_content_script/package.json
index 4c4435bb8..00ab0179d 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/package.json
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/package.json
@@ -24,4 +24,4 @@
"webpack-cli": "^3.3.11",
"chalk": "^4.1.0"
}
-}
+}
\ No newline at end of file
diff --git a/packages/app-cli/tests/support/plugins/codemirror_content_script/src/index.ts b/packages/app-cli/tests/support/plugins/codemirror_content_script/src/index.ts
index 9c84f5450..61655d5ac 100644
--- a/packages/app-cli/tests/support/plugins/codemirror_content_script/src/index.ts
+++ b/packages/app-cli/tests/support/plugins/codemirror_content_script/src/index.ts
@@ -5,7 +5,7 @@ import { MenuItemLocation } from 'api/types';
joplin.plugins.register({
onStart: async function() {
console.info('Match Highlighter started!');
- await joplin.plugins.registerContentScript(
+ await joplin.contentScripts.register(
ContentScriptType.CodeMirrorPlugin,
'matchHighlighter',
'./joplinMatchHighlighter.js'
diff --git a/packages/app-cli/tests/support/plugins/content_script/.gitignore b/packages/app-cli/tests/support/plugins/content_script/.gitignore
index bad13dc9f..7a4fea3fe 100644
--- a/packages/app-cli/tests/support/plugins/content_script/.gitignore
+++ b/packages/app-cli/tests/support/plugins/content_script/.gitignore
@@ -2,3 +2,6 @@ dist/
node_modules/
publish/
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/content_script/.npmignore b/packages/app-cli/tests/support/plugins/content_script/.npmignore
index c7302012e..3f18d39bd 100644
--- a/packages/app-cli/tests/support/plugins/content_script/.npmignore
+++ b/packages/app-cli/tests/support/plugins/content_script/.npmignore
@@ -7,3 +7,6 @@
tsconfig.json
webpack.config.js
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/content_script/GENERATOR_DOC.md b/packages/app-cli/tests/support/plugins/content_script/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/app-cli/tests/support/plugins/content_script/GENERATOR_DOC.md
+++ b/packages/app-cli/tests/support/plugins/content_script/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/app-cli/tests/support/plugins/content_script/api/Joplin.d.ts b/packages/app-cli/tests/support/plugins/content_script/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/app-cli/tests/support/plugins/content_script/api/Joplin.d.ts
+++ b/packages/app-cli/tests/support/plugins/content_script/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/app-cli/tests/support/plugins/content_script/api/JoplinContentScripts.d.ts b/packages/app-cli/tests/support/plugins/content_script/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/content_script/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/app-cli/tests/support/plugins/content_script/api/JoplinPlugins.d.ts b/packages/app-cli/tests/support/plugins/content_script/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/app-cli/tests/support/plugins/content_script/api/JoplinPlugins.d.ts
+++ b/packages/app-cli/tests/support/plugins/content_script/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/content_script/api/JoplinSettings.d.ts b/packages/app-cli/tests/support/plugins/content_script/api/JoplinSettings.d.ts
index d725ea47b..ab9254e9e 100644
--- a/packages/app-cli/tests/support/plugins/content_script/api/JoplinSettings.d.ts
+++ b/packages/app-cli/tests/support/plugins/content_script/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/content_script/api/JoplinViewsPanels.d.ts b/packages/app-cli/tests/support/plugins/content_script/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/app-cli/tests/support/plugins/content_script/api/JoplinViewsPanels.d.ts
+++ b/packages/app-cli/tests/support/plugins/content_script/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/app-cli/tests/support/plugins/content_script/api/types.ts b/packages/app-cli/tests/support/plugins/content_script/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/app-cli/tests/support/plugins/content_script/api/types.ts
+++ b/packages/app-cli/tests/support/plugins/content_script/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/app-cli/tests/support/plugins/content_script/package-lock.json b/packages/app-cli/tests/support/plugins/content_script/package-lock.json
index 0b80a1420..92ea44135 100644
--- a/packages/app-cli/tests/support/plugins/content_script/package-lock.json
+++ b/packages/app-cli/tests/support/plugins/content_script/package-lock.json
@@ -711,14 +711,39 @@
"dev": true
},
"chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ }
}
},
"chokidar": {
@@ -3471,12 +3496,20 @@
}
},
"supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
- "has-flag": "^3.0.0"
+ "has-flag": "^4.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ }
}
},
"tapable": {
@@ -3778,6 +3811,17 @@
"semver": "^6.0.0"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
@@ -3797,6 +3841,15 @@
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
}
}
},
@@ -4428,6 +4481,28 @@
"yargs": "^13.3.2"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
diff --git a/packages/app-cli/tests/support/plugins/content_script/src/index.ts b/packages/app-cli/tests/support/plugins/content_script/src/index.ts
index 1fb7038fb..3576d09b4 100644
--- a/packages/app-cli/tests/support/plugins/content_script/src/index.ts
+++ b/packages/app-cli/tests/support/plugins/content_script/src/index.ts
@@ -19,10 +19,14 @@ joplin.plugins.register({
},
});
- await joplin.plugins.registerContentScript(
+ await joplin.contentScripts.register(
ContentScriptType.MarkdownItPlugin,
'justtesting',
'./markdownItTestPlugin.js'
);
+
+ await joplin.contentScripts.onMessage('justtesting', (message:any) => {
+ return message + '+response';
+ });
},
});
diff --git a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts
index 76ba868dd..5348eb212 100644
--- a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts
+++ b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts
@@ -1,26 +1,33 @@
const leftPad = require('left-pad');
-function plugin(markdownIt, _options) {
- const defaultRender = markdownIt.renderer.rules.fence || function(tokens, idx, options, env, self) {
- return self.renderToken(tokens, idx, options, env, self);
- };
-
- 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 `
-
');
+ await panels.addScript(view, './webview.js');
+ await panels.addScript(view, './webview.css');
+
+ panels.onMessage(view, (message:any) => {
+ console.info('PostMessagePlugin (Webview): Got message from webview:', message);
+ const response = message + '+responseFromWebviewPanel';
+ console.info('PostMessagePlugin (Webview): Responding with:', response);
+ return response;
+ });
+}
+
+joplin.plugins.register({
+ onStart: async function() {
+ await setupContentScriptMarkdownIt();
+ await setContentScriptCodeMirror();
+ await setupWebviewPanel();
+ },
+});
diff --git a/packages/app-cli/tests/support/plugins/post_messages/src/manifest.json b/packages/app-cli/tests/support/plugins/post_messages/src/manifest.json
new file mode 100644
index 000000000..0fd503227
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/post_messages/src/manifest.json
@@ -0,0 +1,11 @@
+{
+ "manifest_version": 1,
+ "id": "org.joplinapp.plugins.PostMessageDemo",
+ "app_min_version": "1.6",
+ "version": "1.0.0",
+ "name": "PostMessage demo",
+ "description": "",
+ "author": "",
+ "homepage_url": "",
+ "repository_url": ""
+}
\ No newline at end of file
diff --git a/packages/app-cli/tests/support/plugins/post_messages/src/webview.js b/packages/app-cli/tests/support/plugins/post_messages/src/webview.js
new file mode 100644
index 000000000..fde9ed56f
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/post_messages/src/webview.js
@@ -0,0 +1,10 @@
+document.addEventListener('click', async (event) => {
+ const element = event.target;
+ if (element.className === 'webview-test-link') {
+ event.preventDefault();
+
+ console.info('webview.js: sending message');
+ const response = await webviewApi.postMessage('testingWebviewMessage');
+ console.info('webiew.js: got response:', response);
+ }
+})
\ No newline at end of file
diff --git a/packages/app-cli/tests/support/plugins/post_messages/tsconfig.json b/packages/app-cli/tests/support/plugins/post_messages/tsconfig.json
new file mode 100644
index 000000000..4474cab3d
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/post_messages/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "outDir": "./dist/",
+ "module": "commonjs",
+ "target": "es2015",
+ "jsx": "react",
+ "allowJs": true,
+ "baseUrl": "."
+ }
+}
diff --git a/packages/app-cli/tests/support/plugins/post_messages/webpack.config.js b/packages/app-cli/tests/support/plugins/post_messages/webpack.config.js
new file mode 100644
index 000000000..35538a529
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/post_messages/webpack.config.js
@@ -0,0 +1,233 @@
+// -----------------------------------------------------------------------------
+// This file is used to build the plugin file (.jpl) and plugin info (.json). It
+// is recommended not to edit this file as it would be overwritten when updating
+// the plugin framework. If you do make some changes, consider using an external
+// JS file and requiring it here to minimize the changes. That way when you
+// update, you can easily restore the functionality you've added.
+// -----------------------------------------------------------------------------
+
+const path = require('path');
+const crypto = require('crypto');
+const fs = require('fs-extra');
+const chalk = require('chalk');
+const CopyPlugin = require('copy-webpack-plugin');
+const WebpackOnBuildPlugin = require('on-build-webpack');
+const tar = require('tar');
+const glob = require('glob');
+const execSync = require('child_process').execSync;
+
+const rootDir = path.resolve(__dirname);
+const userConfigFilename = './plugin.config.json';
+const userConfigPath = path.resolve(rootDir, userConfigFilename);
+const distDir = path.resolve(rootDir, 'dist');
+const srcDir = path.resolve(rootDir, 'src');
+const publishDir = path.resolve(rootDir, 'publish');
+
+const userConfig = Object.assign({}, {
+ extraScripts: [],
+}, fs.pathExistsSync(userConfigPath) ? require(userConfigFilename) : {});
+
+const manifestPath = `${srcDir}/manifest.json`;
+const packageJsonPath = `${rootDir}/package.json`;
+const manifest = readManifest(manifestPath);
+const pluginArchiveFilePath = path.resolve(publishDir, `${manifest.id}.jpl`);
+const pluginInfoFilePath = path.resolve(publishDir, `${manifest.id}.json`);
+
+fs.removeSync(distDir);
+fs.removeSync(publishDir);
+fs.mkdirpSync(publishDir);
+
+function validatePackageJson() {
+ const content = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
+ if (!content.name || content.name.indexOf('joplin-plugin-') !== 0) {
+ console.warn(chalk.yellow(`WARNING: To publish the plugin, the package name should start with "joplin-plugin-" (found "${content.name}") in ${packageJsonPath}`));
+ }
+
+ if (!content.keywords || content.keywords.indexOf('joplin-plugin') < 0) {
+ console.warn(chalk.yellow(`WARNING: To publish the plugin, the package keywords should include "joplin-plugin" (found "${JSON.stringify(content.keywords)}") in ${packageJsonPath}`));
+ }
+
+ if (content.scripts && content.scripts.postinstall) {
+ console.warn(chalk.yellow(`WARNING: package.json contains a "postinstall" script. It is recommended to use a "prepare" script instead so that it is executed before publish. In ${packageJsonPath}`));
+ }
+}
+
+function fileSha256(filePath) {
+ const content = fs.readFileSync(filePath);
+ return crypto.createHash('sha256').update(content).digest('hex');
+}
+
+function currentGitInfo() {
+ try {
+ let branch = execSync('git rev-parse --abbrev-ref HEAD', { stdio: 'pipe' }).toString().trim();
+ const commit = execSync('git rev-parse HEAD', { stdio: 'pipe' }).toString().trim();
+ if (branch === 'HEAD') branch = 'master';
+ return `${branch}:${commit}`;
+ } catch (error) {
+ const messages = error.message ? error.message.split('\n') : [''];
+ console.info(chalk.cyan('Could not get git commit (not a git repo?):', messages[0].trim()));
+ console.info(chalk.cyan('Git information will not be stored in plugin info file'));
+ return '';
+ }
+}
+
+function readManifest(manifestPath) {
+ const content = fs.readFileSync(manifestPath, 'utf8');
+ const output = JSON.parse(content);
+ if (!output.id) throw new Error(`Manifest plugin ID is not set in ${manifestPath}`);
+ return output;
+}
+
+function createPluginArchive(sourceDir, destPath) {
+ const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true })
+ .map(f => f.substr(sourceDir.length + 1));
+
+ if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
+ fs.removeSync(destPath);
+
+ tar.create(
+ {
+ strict: true,
+ portable: true,
+ file: destPath,
+ cwd: sourceDir,
+ sync: true,
+ },
+ distFiles
+ );
+
+ console.info(chalk.cyan(`Plugin archive has been created in ${destPath}`));
+}
+
+function createPluginInfo(manifestPath, destPath, jplFilePath) {
+ const contentText = fs.readFileSync(manifestPath, 'utf8');
+ const content = JSON.parse(contentText);
+ content._publish_hash = `sha256:${fileSha256(jplFilePath)}`;
+ content._publish_commit = currentGitInfo();
+ fs.writeFileSync(destPath, JSON.stringify(content, null, '\t'), 'utf8');
+}
+
+function onBuildCompleted() {
+ try {
+ createPluginArchive(distDir, pluginArchiveFilePath);
+ createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
+ validatePackageJson();
+ } catch (error) {
+ console.error(chalk.red(error.message));
+ }
+}
+
+const baseConfig = {
+ mode: 'production',
+ target: 'node',
+ stats: 'errors-only',
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: 'ts-loader',
+ exclude: /node_modules/,
+ },
+ ],
+ },
+};
+
+const pluginConfig = Object.assign({}, baseConfig, {
+ entry: './src/index.ts',
+ resolve: {
+ alias: {
+ api: path.resolve(__dirname, 'api'),
+ },
+ extensions: ['.tsx', '.ts', '.js'],
+ },
+ output: {
+ filename: 'index.js',
+ path: distDir,
+ },
+ plugins: [
+ new CopyPlugin({
+ patterns: [
+ {
+ from: '**/*',
+ context: path.resolve(__dirname, 'src'),
+ to: path.resolve(__dirname, 'dist'),
+ globOptions: {
+ ignore: [
+ // All TypeScript files are compiled to JS and
+ // already copied into /dist so we don't copy them.
+ '**/*.ts',
+ '**/*.tsx',
+ ],
+ },
+ },
+ ],
+ }),
+ ],
+});
+
+const extraScriptConfig = Object.assign({}, baseConfig, {
+ resolve: {
+ alias: {
+ api: path.resolve(__dirname, 'api'),
+ },
+ extensions: ['.tsx', '.ts', '.js'],
+ },
+});
+
+function resolveExtraScriptPath(name) {
+ const relativePath = `./src/${name}`;
+
+ const fullPath = path.resolve(`${rootDir}/${relativePath}`);
+ if (!fs.pathExistsSync(fullPath)) throw new Error(`Could not find extra script: "${name}" at "${fullPath}"`);
+
+ const s = name.split('.');
+ s.pop();
+ const nameNoExt = s.join('.');
+
+ return {
+ entry: relativePath,
+ output: {
+ filename: `${nameNoExt}.js`,
+ path: distDir,
+ library: 'default',
+ libraryTarget: 'commonjs',
+ libraryExport: 'default',
+ },
+ };
+}
+
+function addExtraScriptConfigs(baseConfig, userConfig) {
+ if (!userConfig.extraScripts.length) return baseConfig;
+
+ const output = [];
+
+ for (const scriptName of userConfig.extraScripts) {
+ const scriptPaths = resolveExtraScriptPath(scriptName);
+ output.push(Object.assign({}, extraScriptConfig, {
+ entry: scriptPaths.entry,
+ output: scriptPaths.output,
+ }));
+ }
+
+ return baseConfig.concat(output);
+}
+
+function addLastConfigStep(config) {
+ const lastConfig = config[config.length - 1];
+ if (!lastConfig.plugins) lastConfig.plugins = [];
+ lastConfig.plugins.push(new WebpackOnBuildPlugin(onBuildCompleted));
+ config[config.length - 1] = lastConfig;
+ return config;
+}
+
+let exportedConfigs = [pluginConfig];
+
+try {
+ exportedConfigs = addExtraScriptConfigs(exportedConfigs, userConfig);
+ exportedConfigs = addLastConfigStep(exportedConfigs);
+} catch (error) {
+ console.error(chalk.red(error.message));
+ process.exit(1);
+}
+
+module.exports = exportedConfigs;
diff --git a/packages/app-cli/tests/support/plugins/register_command/.gitignore b/packages/app-cli/tests/support/plugins/register_command/.gitignore
index bad13dc9f..7a4fea3fe 100644
--- a/packages/app-cli/tests/support/plugins/register_command/.gitignore
+++ b/packages/app-cli/tests/support/plugins/register_command/.gitignore
@@ -2,3 +2,6 @@ dist/
node_modules/
publish/
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/register_command/.npmignore b/packages/app-cli/tests/support/plugins/register_command/.npmignore
index c7302012e..3f18d39bd 100644
--- a/packages/app-cli/tests/support/plugins/register_command/.npmignore
+++ b/packages/app-cli/tests/support/plugins/register_command/.npmignore
@@ -7,3 +7,6 @@
tsconfig.json
webpack.config.js
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/register_command/GENERATOR_DOC.md b/packages/app-cli/tests/support/plugins/register_command/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/app-cli/tests/support/plugins/register_command/GENERATOR_DOC.md
+++ b/packages/app-cli/tests/support/plugins/register_command/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/app-cli/tests/support/plugins/register_command/api/Joplin.d.ts b/packages/app-cli/tests/support/plugins/register_command/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/app-cli/tests/support/plugins/register_command/api/Joplin.d.ts
+++ b/packages/app-cli/tests/support/plugins/register_command/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/app-cli/tests/support/plugins/register_command/api/JoplinContentScripts.d.ts b/packages/app-cli/tests/support/plugins/register_command/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/register_command/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/app-cli/tests/support/plugins/register_command/api/JoplinPlugins.d.ts b/packages/app-cli/tests/support/plugins/register_command/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/app-cli/tests/support/plugins/register_command/api/JoplinPlugins.d.ts
+++ b/packages/app-cli/tests/support/plugins/register_command/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/register_command/api/JoplinSettings.d.ts b/packages/app-cli/tests/support/plugins/register_command/api/JoplinSettings.d.ts
index d725ea47b..ab9254e9e 100644
--- a/packages/app-cli/tests/support/plugins/register_command/api/JoplinSettings.d.ts
+++ b/packages/app-cli/tests/support/plugins/register_command/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/register_command/api/JoplinViewsPanels.d.ts b/packages/app-cli/tests/support/plugins/register_command/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/app-cli/tests/support/plugins/register_command/api/JoplinViewsPanels.d.ts
+++ b/packages/app-cli/tests/support/plugins/register_command/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/app-cli/tests/support/plugins/register_command/api/types.ts b/packages/app-cli/tests/support/plugins/register_command/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/app-cli/tests/support/plugins/register_command/api/types.ts
+++ b/packages/app-cli/tests/support/plugins/register_command/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/app-cli/tests/support/plugins/selected_text/.gitignore b/packages/app-cli/tests/support/plugins/selected_text/.gitignore
index bad13dc9f..7a4fea3fe 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/.gitignore
+++ b/packages/app-cli/tests/support/plugins/selected_text/.gitignore
@@ -2,3 +2,6 @@ dist/
node_modules/
publish/
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/selected_text/.npmignore b/packages/app-cli/tests/support/plugins/selected_text/.npmignore
index c7302012e..3f18d39bd 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/.npmignore
+++ b/packages/app-cli/tests/support/plugins/selected_text/.npmignore
@@ -7,3 +7,6 @@
tsconfig.json
webpack.config.js
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/selected_text/GENERATOR_DOC.md b/packages/app-cli/tests/support/plugins/selected_text/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/GENERATOR_DOC.md
+++ b/packages/app-cli/tests/support/plugins/selected_text/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/app-cli/tests/support/plugins/selected_text/api/Joplin.d.ts b/packages/app-cli/tests/support/plugins/selected_text/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/api/Joplin.d.ts
+++ b/packages/app-cli/tests/support/plugins/selected_text/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/app-cli/tests/support/plugins/selected_text/api/JoplinContentScripts.d.ts b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/app-cli/tests/support/plugins/selected_text/api/JoplinPlugins.d.ts b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/api/JoplinPlugins.d.ts
+++ b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/selected_text/api/JoplinSettings.d.ts b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinSettings.d.ts
index d725ea47b..ab9254e9e 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/api/JoplinSettings.d.ts
+++ b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/selected_text/api/JoplinViewsPanels.d.ts b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/api/JoplinViewsPanels.d.ts
+++ b/packages/app-cli/tests/support/plugins/selected_text/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/app-cli/tests/support/plugins/selected_text/api/types.ts b/packages/app-cli/tests/support/plugins/selected_text/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/app-cli/tests/support/plugins/selected_text/api/types.ts
+++ b/packages/app-cli/tests/support/plugins/selected_text/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/app-cli/tests/support/plugins/settings/.gitignore b/packages/app-cli/tests/support/plugins/settings/.gitignore
index bad13dc9f..7a4fea3fe 100644
--- a/packages/app-cli/tests/support/plugins/settings/.gitignore
+++ b/packages/app-cli/tests/support/plugins/settings/.gitignore
@@ -2,3 +2,6 @@ dist/
node_modules/
publish/
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/settings/.npmignore b/packages/app-cli/tests/support/plugins/settings/.npmignore
index c7302012e..3f18d39bd 100644
--- a/packages/app-cli/tests/support/plugins/settings/.npmignore
+++ b/packages/app-cli/tests/support/plugins/settings/.npmignore
@@ -7,3 +7,6 @@
tsconfig.json
webpack.config.js
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/settings/GENERATOR_DOC.md b/packages/app-cli/tests/support/plugins/settings/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/app-cli/tests/support/plugins/settings/GENERATOR_DOC.md
+++ b/packages/app-cli/tests/support/plugins/settings/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/app-cli/tests/support/plugins/settings/api/Joplin.d.ts b/packages/app-cli/tests/support/plugins/settings/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/app-cli/tests/support/plugins/settings/api/Joplin.d.ts
+++ b/packages/app-cli/tests/support/plugins/settings/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/app-cli/tests/support/plugins/settings/api/JoplinContentScripts.d.ts b/packages/app-cli/tests/support/plugins/settings/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/settings/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/app-cli/tests/support/plugins/settings/api/JoplinPlugins.d.ts b/packages/app-cli/tests/support/plugins/settings/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/app-cli/tests/support/plugins/settings/api/JoplinPlugins.d.ts
+++ b/packages/app-cli/tests/support/plugins/settings/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/settings/api/JoplinSettings.d.ts b/packages/app-cli/tests/support/plugins/settings/api/JoplinSettings.d.ts
index d725ea47b..ab9254e9e 100644
--- a/packages/app-cli/tests/support/plugins/settings/api/JoplinSettings.d.ts
+++ b/packages/app-cli/tests/support/plugins/settings/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/settings/api/JoplinViewsPanels.d.ts b/packages/app-cli/tests/support/plugins/settings/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/app-cli/tests/support/plugins/settings/api/JoplinViewsPanels.d.ts
+++ b/packages/app-cli/tests/support/plugins/settings/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/app-cli/tests/support/plugins/settings/api/types.ts b/packages/app-cli/tests/support/plugins/settings/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/app-cli/tests/support/plugins/settings/api/types.ts
+++ b/packages/app-cli/tests/support/plugins/settings/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/app-cli/tests/support/plugins/toc/.gitignore b/packages/app-cli/tests/support/plugins/toc/.gitignore
index bad13dc9f..7a4fea3fe 100644
--- a/packages/app-cli/tests/support/plugins/toc/.gitignore
+++ b/packages/app-cli/tests/support/plugins/toc/.gitignore
@@ -2,3 +2,6 @@ dist/
node_modules/
publish/
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/toc/.npmignore b/packages/app-cli/tests/support/plugins/toc/.npmignore
index c7302012e..3f18d39bd 100644
--- a/packages/app-cli/tests/support/plugins/toc/.npmignore
+++ b/packages/app-cli/tests/support/plugins/toc/.npmignore
@@ -7,3 +7,6 @@
tsconfig.json
webpack.config.js
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/toc/GENERATOR_DOC.md b/packages/app-cli/tests/support/plugins/toc/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/app-cli/tests/support/plugins/toc/GENERATOR_DOC.md
+++ b/packages/app-cli/tests/support/plugins/toc/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/app-cli/tests/support/plugins/toc/api/Joplin.d.ts b/packages/app-cli/tests/support/plugins/toc/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/app-cli/tests/support/plugins/toc/api/Joplin.d.ts
+++ b/packages/app-cli/tests/support/plugins/toc/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/app-cli/tests/support/plugins/toc/api/JoplinContentScripts.d.ts b/packages/app-cli/tests/support/plugins/toc/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/toc/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/app-cli/tests/support/plugins/toc/api/JoplinPlugins.d.ts b/packages/app-cli/tests/support/plugins/toc/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/app-cli/tests/support/plugins/toc/api/JoplinPlugins.d.ts
+++ b/packages/app-cli/tests/support/plugins/toc/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/toc/api/JoplinSettings.d.ts b/packages/app-cli/tests/support/plugins/toc/api/JoplinSettings.d.ts
index d725ea47b..ab9254e9e 100644
--- a/packages/app-cli/tests/support/plugins/toc/api/JoplinSettings.d.ts
+++ b/packages/app-cli/tests/support/plugins/toc/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/toc/api/JoplinViewsPanels.d.ts b/packages/app-cli/tests/support/plugins/toc/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/app-cli/tests/support/plugins/toc/api/JoplinViewsPanels.d.ts
+++ b/packages/app-cli/tests/support/plugins/toc/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/app-cli/tests/support/plugins/toc/api/types.ts b/packages/app-cli/tests/support/plugins/toc/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/app-cli/tests/support/plugins/toc/api/types.ts
+++ b/packages/app-cli/tests/support/plugins/toc/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/app-cli/tests/support/plugins/toc/package-lock.json b/packages/app-cli/tests/support/plugins/toc/package-lock.json
index fbd7a1145..0545ceecc 100644
--- a/packages/app-cli/tests/support/plugins/toc/package-lock.json
+++ b/packages/app-cli/tests/support/plugins/toc/package-lock.json
@@ -742,23 +742,52 @@
"dev": true
},
"chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
},
"dependencies": {
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
- "has-flag": "^3.0.0"
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
}
}
}
@@ -3922,6 +3951,17 @@
"fill-range": "^7.0.1"
}
},
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -3953,6 +3993,15 @@
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -4339,6 +4388,28 @@
"yargs": "13.2.4"
},
"dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
"emojis-list": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
diff --git a/packages/app-cli/tests/support/plugins/updatePlugins.sh b/packages/app-cli/tests/support/plugins/updatePlugins.sh
index 76487354c..2ee4efdfc 100755
--- a/packages/app-cli/tests/support/plugins/updatePlugins.sh
+++ b/packages/app-cli/tests/support/plugins/updatePlugins.sh
@@ -17,3 +17,4 @@ cd "$SCRIPT_DIR/selected_text/" && yo joplin --update --skip-install --silent
cd "$SCRIPT_DIR/settings/" && yo joplin --update --skip-install --silent
cd "$SCRIPT_DIR/toc/" && yo joplin --update --skip-install --silent
cd "$SCRIPT_DIR/withExternalModules/" && yo joplin --update --skip-install --silent
+cd "$SCRIPT_DIR/post_messages/" && yo joplin --update --skip-install --silent
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/.gitignore b/packages/app-cli/tests/support/plugins/withExternalModules/.gitignore
index bad13dc9f..7a4fea3fe 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/.gitignore
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/.gitignore
@@ -2,3 +2,6 @@ dist/
node_modules/
publish/
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/.npmignore b/packages/app-cli/tests/support/plugins/withExternalModules/.npmignore
index c7302012e..3f18d39bd 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/.npmignore
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/.npmignore
@@ -7,3 +7,6 @@
tsconfig.json
webpack.config.js
+
+
+
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/GENERATOR_DOC.md b/packages/app-cli/tests/support/plugins/withExternalModules/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/GENERATOR_DOC.md
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/api/Joplin.d.ts b/packages/app-cli/tests/support/plugins/withExternalModules/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/api/Joplin.d.ts
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinContentScripts.d.ts b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinPlugins.d.ts b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinPlugins.d.ts
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinSettings.d.ts b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinSettings.d.ts
index d725ea47b..ab9254e9e 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinSettings.d.ts
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinViewsPanels.d.ts b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinViewsPanels.d.ts
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/app-cli/tests/support/plugins/withExternalModules/api/types.ts b/packages/app-cli/tests/support/plugins/withExternalModules/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/app-cli/tests/support/plugins/withExternalModules/api/types.ts
+++ b/packages/app-cli/tests/support/plugins/withExternalModules/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/generator-joplin/README.md b/packages/generator-joplin/README.md
index 50a915023..80e70e0b3 100644
--- a/packages/generator-joplin/README.md
+++ b/packages/generator-joplin/README.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/generator-joplin/generators/app/templates/GENERATOR_DOC.md b/packages/generator-joplin/generators/app/templates/GENERATOR_DOC.md
index 50a915023..80e70e0b3 100644
--- a/packages/generator-joplin/generators/app/templates/GENERATOR_DOC.md
+++ b/packages/generator-joplin/generators/app/templates/GENERATOR_DOC.md
@@ -59,7 +59,7 @@ The file that may cause problem is "webpack.config.js" because it's going to be
## External script files
-By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
+By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
diff --git a/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts b/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts
index fc09aeeaa..2d5ee2cf9 100644
--- a/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts
+++ b/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts
@@ -7,6 +7,7 @@ import JoplinCommands from './JoplinCommands';
import JoplinViews from './JoplinViews';
import JoplinInterop from './JoplinInterop';
import JoplinSettings from './JoplinSettings';
+import JoplinContentScripts from './JoplinContentScripts';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
@@ -31,10 +32,12 @@ export default class Joplin {
private views_;
private interop_;
private settings_;
+ private contentScripts_;
constructor(implementation: any, plugin: Plugin, store: any);
get data(): JoplinData;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
+ get contentScripts(): JoplinContentScripts;
/**
* @ignore
*
diff --git a/packages/generator-joplin/generators/app/templates/api/JoplinContentScripts.d.ts b/packages/generator-joplin/generators/app/templates/api/JoplinContentScripts.d.ts
new file mode 100644
index 000000000..09ad5178a
--- /dev/null
+++ b/packages/generator-joplin/generators/app/templates/api/JoplinContentScripts.d.ts
@@ -0,0 +1,32 @@
+import Plugin from '../Plugin';
+import { ContentScriptType } from './types';
+export default class JoplinContentScripts {
+ private plugin;
+ constructor(plugin: 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.
+ *
+ * The plugin generator provides a way to build any content script you might
+ * want to package as well as its dependencies. See the [Plugin Generator
+ * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
+ * for more information.
+ *
+ * * [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.
+ * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ */
+ register(type: ContentScriptType, id: string, scriptPath: string): Promise;
+ onMessage(id: string, callback: any): Promise;
+}
diff --git a/packages/generator-joplin/generators/app/templates/api/JoplinPlugins.d.ts b/packages/generator-joplin/generators/app/templates/api/JoplinPlugins.d.ts
index 72cbe0774..56e7e8d02 100644
--- a/packages/generator-joplin/generators/app/templates/api/JoplinPlugins.d.ts
+++ b/packages/generator-joplin/generators/app/templates/api/JoplinPlugins.d.ts
@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise;
/**
- * 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.
- *
- * The plugin generator provides a way to build any content script you might
- * want to package as well as its dependencies. See the [Plugin Generator
- * doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
- * for more information.
- *
- * * [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.
- * @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
+ * @deprecated Use joplin.contentScripts.register()
*/
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise;
}
diff --git a/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts b/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts
index d725ea47b..82e4ab311 100644
--- a/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts
+++ b/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts
@@ -1,5 +1,12 @@
import Plugin from '../Plugin';
import { SettingItem, SettingSection } from './types';
+export interface ChangeEvent {
+ /**
+ * Setting keys that have been changed
+ */
+ keys: string[];
+}
+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.
*
@@ -12,6 +19,7 @@ import { SettingItem, SettingSection } from './types';
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
+ private get keyPrefix();
private namespacedKey;
/**
* Registers a new setting. Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@@ -40,4 +48,10 @@ export default class JoplinSettings {
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
*/
globalValue(key: string): Promise;
+ /**
+ * Called when one or multiple settings of your plugin have been changed.
+ * - For performance reasons, this event is triggered with a delay.
+ * - You will only get events for your own plugin settings.
+ */
+ onChange(handler: ChangeHandler): Promise;
}
diff --git a/packages/generator-joplin/generators/app/templates/api/JoplinViewsPanels.d.ts b/packages/generator-joplin/generators/app/templates/api/JoplinViewsPanels.d.ts
index 956ddb7b3..20d3e1264 100644
--- a/packages/generator-joplin/generators/app/templates/api/JoplinViewsPanels.d.ts
+++ b/packages/generator-joplin/generators/app/templates/api/JoplinViewsPanels.d.ts
@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise;
/**
* Called when a message is sent from the webview (using postMessage).
+ *
+ * To post a message from the webview to the plugin use:
+ *
+ * ```javascript
+ * const response = await webviewApi.postMessage(message);
+ * ```
+ *
+ * - `message` can be any JavaScript object, string or number
+ * - `response` is whatever was returned by the `onMessage` handler
+ *
+ * Using this mechanism, you can have two-way communication between the
+ * plugin and webview.
+ *
+ * See the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
+ *
*/
onMessage(handle: ViewHandle, callback: Function): Promise;
/**
diff --git a/packages/generator-joplin/generators/app/templates/api/types.ts b/packages/generator-joplin/generators/app/templates/api/types.ts
index d14c63b49..bc3219ac2 100644
--- a/packages/generator-joplin/generators/app/templates/api/types.ts
+++ b/packages/generator-joplin/generators/app/templates/api/types.ts
@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
-// Plugins type
+// Content Script types
// =================================================================
+export type PostMessageHandler = (id: string, message: any)=> Promise;
+
+/**
+ * When a content script is initialised, it receives a `context` object.
+ */
+export interface ContentScriptContext {
+ /**
+ * The plugin ID that registered this content script
+ */
+ pluginId: string;
+
+ /**
+ * The content script ID, which may be necessary to post messages
+ */
+ contentScriptId: string;
+
+ /**
+ * Can be used by CodeMirror content scripts to post a message to the plugin
+ */
+ postMessage: PostMessageHandler;
+}
+
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@@ -394,43 +416,56 @@ export enum ContentScriptType {
*
* ## Exported members
*
- * - 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 **required** `plugin` key is the actual Markdown-It plugin -
- * check the [official
- * doc](https://github.com/markdown-it/markdown-it) for more
+ * - 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.
+ * which contains a number of options, mostly useful for Joplin's internal
+ * code.
*
- * - 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
+ * - 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
+ * ## Posting 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)`
+ * ```javascript
+ * const response = await webviewApi.postMessage(contentScriptId, message);
+ * ```
*
- * 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.
+ * - `contentScriptId` is the ID you've defined when you registered the
+ * content script. You can retrieve it from the
+ * {@link ContentScriptContext | context}.
+ * - `message` can be any basic JavaScript type (number, string, plain
+ * object), but it cannot be a function or class instance.
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
*
* ## 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:
+ * 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 = {
@@ -443,6 +478,7 @@ export enum ContentScriptType {
* ```
*/
MarkdownItPlugin = 'markdownItPlugin',
+
/**
* Registers a new CodeMirror plugin, which should follow the template
* below.
@@ -466,42 +502,65 @@ 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.
+ * 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](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}`.
+ * 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
+ * - 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
+ * See also 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.
+ *
+ * ## Posting messages from the content script to your plugin
+ *
+ * In order to post messages to the plugin, you can use the postMessage
+ * function passed to the {@link ContentScriptContext | context}.
+ *
+ * ```javascript
+ * const response = await context.postMessage('messageFromCodeMirrorContentScript');
+ * ```
+ *
+ * When you post a message, the plugin can send back a `response` thus
+ * allowing two-way communication:
+ *
+ * ```javascript
+ * await joplin.contentScripts.onMessage(contentScriptId, (message) => {
+ * // Process message
+ * return response; // Can be any object, string or number
+ * });
+ * ```
+ *
+ * See {@link JoplinContentScript.onMessage} for more details, as well as
+ * the [postMessage
+ * demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
+ *
*/
CodeMirrorPlugin = 'codeMirrorPlugin',
}
diff --git a/packages/generator-joplin/package.json b/packages/generator-joplin/package.json
index 8cf17bc75..d91f4cbf2 100644
--- a/packages/generator-joplin/package.json
+++ b/packages/generator-joplin/package.json
@@ -34,4 +34,4 @@
"repository": "https://github.com/laurent22/generator-joplin",
"license": "MIT",
"private": true
-}
\ No newline at end of file
+}
Listens to a messages sent from the content script using postMessage(). + See ContentScriptType for more information as well as the + postMessage + demo
+