1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-30 20:39:46 +02:00

Compare commits

...

135 Commits

Author SHA1 Message Date
Laurent Cozic
f7917d42c3 test 2021-01-19 22:51:47 +00:00
Laurent Cozic
db785f7aee update 2021-01-19 22:38:42 +00:00
Laurent Cozic
4ed9bd1bc6 update 2021-01-19 18:10:54 +00:00
Laurent Cozic
fcec52122f Merge branch 'dev' into plugin_repo_update 2021-01-19 17:12:29 +00:00
Laurent Cozic
63e30f6ccb Plugins: Updated types 2021-01-19 16:48:13 +00:00
Laurent Cozic
0e5a31b9d4 update 2021-01-19 16:47:08 +00:00
Laurent Cozic
aafd30f92f updaet 2021-01-19 16:02:11 +00:00
Laurent Cozic
9c718baf61 Merge branch 'dev' of github.com:laurent22/joplin into dev 2021-01-18 20:11:17 +00:00
Laurent Cozic
e8ae29adf2 Tools: Clean up and fix tool dependencies 2021-01-18 20:09:11 +00:00
eresytter
0c67805626 All: Translation: Update id_ID.po (#4387) 2021-01-18 14:16:58 -05:00
Laurent Cozic
e91c94baca Added version command 2021-01-18 15:12:21 +00:00
Laurent Cozic
aa74d05b24 Releasing sub-packages 2021-01-18 15:00:00 +00:00
Laurent Cozic
9a1f7f227d Build before publish 2021-01-18 14:59:16 +00:00
Laurent Cozic
40779d09c0 Releasing sub-packages 2021-01-18 14:49:39 +00:00
Laurent Cozic
351d8d94c5 Set version numbers 2021-01-18 14:49:14 +00:00
Laurent Cozic
6addd52ba4 Fix script 2021-01-18 14:48:42 +00:00
Laurent Cozic
ea5849855f Releasing sub-packages 2021-01-18 14:42:40 +00:00
Laurent Cozic
c81529dc45 Fix repo builder package.json 2021-01-18 14:42:23 +00:00
Laurent Cozic
b6d7971691 Set version numbers on sub-packages 2021-01-18 14:40:39 +00:00
Laurent Cozic
446db2d688 Releasing sub-packages 2021-01-18 14:38:23 +00:00
Laurent Cozic
52da072f9a Plugins: Updated plugin repo script 2021-01-18 14:37:27 +00:00
Laurent Cozic
0d2bf6d787 Server: Improved config and support for Docker 2021-01-18 10:13:26 +00:00
Roman Musin
59fe4a2193 Mobile: When attaching a file to a note set correct title and extension (#4373) 2021-01-17 11:40:24 +00:00
Caleb John
df6d146c84 SideBar -> Sidebar in app.ts (#4375) 2021-01-17 11:34:37 +00:00
Laurent Cozic
eb3493f648 Server: Fixed tests and clean up 2021-01-15 22:02:36 +00:00
Laurent Cozic
7fd4c28a5b Plugin Generator release v1.7.3 2021-01-15 17:04:18 +00:00
Laurent Cozic
d1b55aeceb Generator: Fixes #4360: Scripts were no longer being compiled 2021-01-15 17:03:38 +00:00
Laurent Cozic
413ec1a933 Server: Refactored to use Router class 2021-01-14 22:36:46 +00:00
Laurent Cozic
7ad29577f9 Server: Improved how routes can be defined 2021-01-14 18:27:59 +00:00
Laurent Cozic
7652a5a0a0 Server: Added tests for logout and fixed transaction deadlock 2021-01-14 17:18:27 +00:00
Laurent Cozic
105189fc57 Plugin Generator release v1.7.2 2021-01-14 15:48:10 +00:00
Laurent Cozic
e559999aa4 Generator: Fixed crash when no external script needs to be compiled 2021-01-14 15:47:34 +00:00
Laurent Cozic
4a230d7cd5 Server: Removed all controller
These controllers were mostly here to allow testing the business logic.
However now that the routes are tested directly they are no longer
necessary. And testing the routes significantly increase the test
coverage.
2021-01-14 14:28:20 +00:00
Laurent Cozic
9b2e5e2959 Server: Removed the need for session controller 2021-01-14 13:29:03 +00:00
Laurent Cozic
3c5ac1ecc5 Server: Removed the need for file controller 2021-01-14 13:07:38 +00:00
Laurent Cozic
03dc1bbfe1 Server: Removed the need for profile controller 2021-01-14 12:50:45 +00:00
Laurent Cozic
80580ba54d Server: Clean up test units 2021-01-14 11:55:27 +00:00
Laurent Cozic
6a80b2ae9e Merge branch 'dev' of github.com:laurent22/joplin into dev 2021-01-13 23:26:02 +00:00
Laurent Cozic
f14ea46f0b Server: Moved controller tests to route and model 2021-01-13 23:20:45 +00:00
Laurent Cozic
247bd9bfd9 Server: Moved session tests to route 2021-01-13 22:06:47 +00:00
Laurent Cozic
fc58db5d1a Server: Removed controller dependency from route 2021-01-13 21:50:43 +00:00
Robin Opletal
466cd836d7 Add support for the sway desktop environment (#4357)
Many sway users set $XDG_CURRENT_DESKTOP to sway. This could be detected.
2021-01-13 20:50:32 +00:00
Laurent Cozic
66a09e5068 Server: Moved file API tests to route 2021-01-13 18:11:35 +00:00
jibedoubleve
b53e475f99 Update French translation + fix a typo (#4349) 2021-01-13 12:39:59 +00:00
Laurent Cozic
ecb6134828 Plugin Generator release v1.7.1 2021-01-13 12:19:36 +00:00
Laurent Cozic
4b2bb1168b Setup new release version 1.7 2021-01-13 12:19:12 +00:00
Laurent Cozic
4743b0b5ce Plugins: Updated types 2021-01-13 12:17:54 +00:00
Laurent Cozic
3abf21d4ae Generator: Fixed issue that could result in an invalid JPL file 2021-01-13 12:16:36 +00:00
Laurent Cozic
6cdb16c8ab Server: Started moving controller tests to routes 2021-01-12 22:03:31 +00:00
rnbastos
b7bfa2b997 Updated pt_BR translation (#4344) 2021-01-12 21:27:16 +00:00
Laurent Cozic
eab2371206 Server: Add test units for sessions route 2021-01-12 18:08:14 +00:00
Laurent Cozic
63615ffbaf Server: Unit test request routing 2021-01-12 17:33:14 +00:00
Laurent Cozic
59fa51c5bf Server: Added test units for user login 2021-01-12 17:14:09 +00:00
Laurent Cozic
c70f023fe0 Server: Added test units for notification handler 2021-01-12 16:49:39 +00:00
Laurent Cozic
fb5eb1a47b Server: Dismiss admin password notification when password has been changed 2021-01-12 16:02:44 +00:00
Laurent Cozic
5aa5089ae0 Plugins: Add support for "keywords" manifest field 2021-01-12 15:34:59 +00:00
Laurent Cozic
4413e6a1ee Tools: Handle obsolete packages on plugin repo 2021-01-12 15:29:08 +00:00
Laurent Cozic
309a97fb5b Fixed publishing toggleSidebars plugin 2021-01-12 12:36:15 +00:00
Laurent Cozic
1b5b2342fc Move plugin under joplin namespace 2021-01-12 12:30:45 +00:00
Laurent Cozic
0f23277bfc Chore: SideBar => Sidebar 2021-01-12 12:28:55 +00:00
Laurent Cozic
e595e19c0d Typo 2021-01-12 02:27:56 +00:00
Laurent Cozic
79dde365f0 Doc: Updated doc and tests for plugin postMessage() update 2021-01-11 23:34:06 +00:00
Laurent Cozic
2489409abb Plugins: Added support for bi-directional messages in content scripts and webview scripts using postMessage 2021-01-11 23:33:10 +00:00
Laurent Cozic
cbad3b1190 Merge branch 'release-1.6' into dev 2021-01-11 22:41:26 +00:00
Laurent Cozic
b74b849830 Desktop release v1.6.7 2021-01-11 22:18:24 +00:00
Caleb John
63a331c82f Desktop: Fixes #4338: Some commands were no longer working (#4343) 2021-01-11 22:17:55 +00:00
Caleb John
b7313568de Desktop: Fixes #4338: Some commands were no longer working (#4343) 2021-01-11 22:17:34 +00:00
Laurent Cozic
25341858d5 Tools: Fixed plugin repo table and sort by name 2021-01-11 12:46:21 +00:00
Laurent Cozic
dc6ae90113 Tools: Auto-update README when building plugin repo 2021-01-11 12:42:11 +00:00
Laurent Cozic
3c8d79975c Update website 2021-01-11 12:19:14 +00:00
Laurent Cozic
7530d2e4bc CLI v1.6.3 2021-01-11 11:52:17 +00:00
Laurent Cozic
f678434411 Fixed deps 2021-01-11 11:51:53 +00:00
Laurent Cozic
9d547a58c9 CLI v1.6.2 2021-01-11 11:42:17 +00:00
Laurent Cozic
aa4905ab45 Releasing sub-packages 2021-01-11 11:40:56 +00:00
Laurent Cozic
b24eb5d09c ios-v10.6.2 2021-01-11 11:16:46 +00:00
Laurent Cozic
1bc56d0fa9 ios-v10.6.1 2021-01-11 11:16:17 +00:00
Laurent Cozic
a77d500bfa CLI v1.6.1 2021-01-11 11:10:58 +00:00
Laurent Cozic
8fea9ba193 Android release v1.6.6 2021-01-10 00:53:26 +00:00
Laurent Cozic
3fdcd3aaa6 Android release v1.6.5 2021-01-10 00:14:36 +00:00
Laurent
0629cb394c Doc: Resolves #4329: Mentioned that vim and emacs mode are not supported in Rich Text editor 2021-01-09 19:58:41 +00:00
Laurent Cozic
f58b7563e6 Desktop release v1.6.6 2021-01-09 13:17:23 +00:00
Laurent Cozic
d434723244 Desktop: Add way to install plugin from file 2021-01-09 13:14:39 +00:00
Laurent Cozic
fca8f71f4a Desktop release v1.6.5 2021-01-08 22:22:44 +00:00
Laurent Cozic
023170548f Plugins: Added joplin.settings.onChange event 2021-01-08 22:20:59 +00:00
Laurent Cozic
d75adc3740 Desktop: Fixed attaching local files that contain spaces in path
Ref: https://discourse.joplinapp.org/t/a-minor-bug-on-linking-to-local-files/13654
2021-01-08 18:33:22 +00:00
Laurent Cozic
0bf3531f51 Plugins: Fixes #4308: Fixed "exportFolders" command when exporting JEX file 2021-01-08 18:06:33 +00:00
Laurent Cozic
c9f40ea23f Desktop, Cli: Resolves #4310: Do not display error message when fixing ENEX resource mime type 2021-01-08 17:49:53 +00:00
Laurent Cozic
c8755839be Desktop, Cli: Resolves #4316: Improved support for bold and italic format when importing ENEX file 2021-01-08 17:40:18 +00:00
Laurent Cozic
c3e696db5a Merge branch 'release-1.5' into dev 2021-01-08 17:27:41 +00:00
Laurent Cozic
a0134005b7 Plugin Generator release v1.6.11 2021-01-08 16:45:44 +00:00
Laurent Cozic
b66d90bbcc Tools: Fixed config of demo plugins 2021-01-08 16:44:11 +00:00
Laurent Cozic
41edf5b2da Plugins: Updated types 2021-01-08 16:36:48 +00:00
Caleb John
c484c88715 Desktop: Fix issue that was preventing editor context menu from being refreshed (#4303) 2021-01-08 16:35:23 +00:00
Laurent Cozic
4a0fb124a7 Merge branch 'dev' of github.com:laurent22/joplin into dev 2021-01-08 16:32:11 +00:00
Laurent Cozic
ebbaa5177b Generator: Better handling of external scripts 2021-01-08 16:31:11 +00:00
Jonathan Heard
5d1dc224ca All: Fixes #4313: Fixed OneDrive issue that would require a full resync every time (#4324) 2021-01-08 16:07:03 +00:00
Helmut K. C. Tessarek
3626714403 actually toggle something ;-) (#4309)
* actually toggle something ;-)

* make ids a bit longer
2021-01-08 10:36:37 -05:00
JackGruber
3884ada760 Doc: Fix typo on json array (#4322) 2021-01-08 00:36:38 -05:00
Laurent Cozic
16788d1437 Tools: Setup server tests 2021-01-07 22:15:41 +00:00
Laurent Cozic
b1908756d4 Tools: Disable tsc compile when committing - too slow 2021-01-07 22:10:35 +00:00
Laurent Cozic
ccf5271584 Desktop: Handle case where a command is sent to an editor that is gone 2021-01-07 22:03:13 +00:00
Laurent Cozic
df3e6a6219 Desktop: Fixed context menu not being displayed on high DPI screens 2021-01-07 21:44:31 +00:00
Laurent Cozic
f43ec71d9a Tools: Increase Jest timeout on server tests 2021-01-07 21:34:07 +00:00
Laurent Cozic
32dab88054 Tools: Fixed validatePluginId test 2021-01-07 19:30:29 +00:00
Laurent Cozic
1b5868a7c5 Desktop release v1.6.4 2021-01-07 17:05:31 +00:00
Laurent Cozic
72712e71eb Desktop release v1.6.3 2021-01-07 17:05:21 +00:00
Laurent Cozic
ec29f791ba Merge branch 'dev' of github.com:laurent22/joplin into dev 2021-01-07 17:04:04 +00:00
Darshani Audhish
40c2e59394 Doc: Update order of the plugin list in documentation (#4321) 2021-01-07 17:03:34 +00:00
Caleb John
98cbb237b5 Desktop: Fixes: #4317: Spell checker inserts correction at wrong location (#4318) 2021-01-07 17:01:44 +00:00
Jan Blunck
826dda5a75 Mobile: Fixes #4268: Fix "Not implemented" error when downloading resources with S3 sync target (#4279)
Since the RNFetchBlob API doesn't support writing binary data directly
it creates a custom Writable which is doing the base64 encoding per 
chunk.

This also fixes a problem with the S3 synchronization code using the
shim.fsDriver().writeBinaryFile().

Tested with AVD Android 10.0 target.

Signed-off-by: Jan Blunck <jblunck@users.noreply.github.com>
2021-01-07 16:36:07 +00:00
Laurent Cozic
6dc5a816e5 Desktop: Add support for searching and installing plugins from repository 2021-01-07 16:30:53 +00:00
Laurent Cozic
1700b29f7d Merge branch 'dev' of github.com:laurent22/joplin into dev 2021-01-07 16:30:13 +00:00
Jerry Zhao
7a6966405c All: Support natural sorting by title (#4272) 2021-01-07 16:29:53 +00:00
Max S. Test
9cb576889f Doc: Update clipper.md (#4319)
Spelling fix
2021-01-06 19:18:21 -05:00
JackGruber
047846a552 Doc: Add Synology WebDAV Server to WebDAV-compatible services (#4315) 2021-01-06 19:17:13 -05:00
Gen Neko
99fb578db4 All: Translation: Update ja_JP.po (#4307) 2021-01-06 19:15:02 -05:00
Laurent Cozic
7114228fd6 Validate plugin ID 2021-01-06 20:27:04 +00:00
Laurent Cozic
8d4d438136 Tools: Updated script to build plugin repository 2021-01-06 20:23:23 +00:00
Laurent Cozic
420ac8359c Tools: Updated script to build plugin repository 2021-01-06 19:43:05 +00:00
Laurent Cozic
fe7691d786 Plugin Generator release v1.6.10 2021-01-05 21:59:41 +00:00
Laurent Cozic
db4f35b936 Generator: Added "npm run update" command 2021-01-05 21:59:16 +00:00
Laurent Cozic
72aabf71f3 Plugin Generator release v1.6.9 2021-01-05 21:49:37 +00:00
Laurent Cozic
d145ce1876 Generator: Fixed package name conversion and added test units 2021-01-05 21:49:08 +00:00
Laurent Cozic
ab6f02a949 Plugin Generator release v1.6.8 2021-01-05 18:28:36 +00:00
Laurent Cozic
1339414443 Generator: Merge ignore files when updating plugin 2021-01-05 18:28:12 +00:00
Laurent Cozic
732ca53b70 Plugin Generator release v1.6.7 2021-01-05 18:20:00 +00:00
Laurent Cozic
fa749d6d2a Generator: Merge ignore files when updating plugin 2021-01-05 18:18:40 +00:00
Laurent Cozic
6e69343bb6 Plugin Generator release v1.6.6 2021-01-05 18:02:35 +00:00
Laurent Cozic
520454affb Generator: Do not overwrite README.md when updating 2021-01-05 17:57:42 +00:00
Laurent Cozic
734514b6d8 Tools: Add script to build plugin repository 2021-01-05 15:25:15 +00:00
Laurent Cozic
ceb252b9ad Add "plugins" sub-package to group official Joplin plugins 2021-01-05 13:38:38 +00:00
Laurent Cozic
f121245e40 Plugin Generator release v1.6.5 2021-01-05 13:27:41 +00:00
Laurent Cozic
215a1e0240 Generator: Cleaned up prompts 2021-01-05 12:09:43 +00:00
Laurent Cozic
9e076bf194 Desktop release v1.5.14 2020-12-30 00:18:46 +00:00
Laurent Cozic
74a797b410 Desktop, Cli: Fixed importing ENEX files that contain hidden sections 2020-12-30 00:17:15 +00:00
488 changed files with 37852 additions and 6865 deletions

View File

@@ -6,4 +6,5 @@ packages/app-desktop
packages/app-cli
packages/app-mobile
packages/app-clipper
packages/generator-joplin
packages/generator-joplin
packages/plugin-repo-cli

View File

@@ -1,9 +1,26 @@
# Example of local config, for development:
# =============================================================================
# PRODUCTION CONFIG EXAMPLE
# -----------------------------------------------------------------------------
# By default it will use SQLite, but that's mostly to test and evaluate the
# server. So you'll want to specify db connection settings to use Postgres.
# =============================================================================
#
# JOPLIN_BASE_URL=http://localhost:22300
# JOPLIN_PORT=22300
# APP_BASE_URL=https://example.com/joplin
# APP_PORT=22300
#
# DB_CLIENT=pg
# POSTGRES_PASSWORD=joplin
# POSTGRES_DATABASE=joplin
# POSTGRES_USER=joplin
# POSTGRES_PORT=5432
# POSTGRES_HOST=localhost
# Example of config for production:
# =============================================================================
# DEV CONFIG EXAMPLE
# -----------------------------------------------------------------------------
# Example of local config, for development. In dev mode, you would usually use
# SQLite so database settings are not needed.
# =============================================================================
#
# JOPLIN_BASE_URL=https://example.com/joplin
# JOPLIN_PORT=22300
# APP_BASE_URL=http://localhost:22300
# APP_PORT=22300

View File

@@ -6,6 +6,7 @@ _releases/
**/node_modules/
Assets/
docs/
packages/plugins/**/dist
packages/server/dist/
highlight.pack.js
Modules/TinyMCE/IconPack/postinstall.js
@@ -110,6 +111,12 @@ packages/app-cli/tests/models_Note.js.map
packages/app-cli/tests/models_Setting.d.ts
packages/app-cli/tests/models_Setting.js
packages/app-cli/tests/models_Setting.js.map
packages/app-cli/tests/services/plugins/RepositoryApi.d.ts
packages/app-cli/tests/services/plugins/RepositoryApi.js
packages/app-cli/tests/services/plugins/RepositoryApi.js.map
packages/app-cli/tests/services/plugins/api/JoplinSettings.d.ts
packages/app-cli/tests/services/plugins/api/JoplinSettings.js
packages/app-cli/tests/services/plugins/api/JoplinSettings.js.map
packages/app-cli/tests/services/plugins/api/JoplinViewMenuItem.d.ts
packages/app-cli/tests/services/plugins/api/JoplinViewMenuItem.js
packages/app-cli/tests/services/plugins/api/JoplinViewMenuItem.js.map
@@ -221,6 +228,15 @@ packages/app-cli/tests/support/plugins/multi_selection/api/types.js.map
packages/app-cli/tests/support/plugins/multi_selection/src/index.d.ts
packages/app-cli/tests/support/plugins/multi_selection/src/index.js
packages/app-cli/tests/support/plugins/multi_selection/src/index.js.map
packages/app-cli/tests/support/plugins/post_messages/api/index.d.ts
packages/app-cli/tests/support/plugins/post_messages/api/index.js
packages/app-cli/tests/support/plugins/post_messages/api/index.js.map
packages/app-cli/tests/support/plugins/post_messages/api/types.d.ts
packages/app-cli/tests/support/plugins/post_messages/api/types.js
packages/app-cli/tests/support/plugins/post_messages/api/types.js.map
packages/app-cli/tests/support/plugins/post_messages/src/index.d.ts
packages/app-cli/tests/support/plugins/post_messages/src/index.js
packages/app-cli/tests/support/plugins/post_messages/src/index.js.map
packages/app-cli/tests/support/plugins/register_command/api/index.d.ts
packages/app-cli/tests/support/plugins/register_command/api/index.js
packages/app-cli/tests/support/plugins/register_command/api/index.js.map
@@ -323,12 +339,21 @@ packages/app-desktop/gui/ConfigScreen/ButtonBar.js.map
packages/app-desktop/gui/ConfigScreen/ConfigScreen.d.ts
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js.map
packages/app-desktop/gui/ConfigScreen/SideBar.d.ts
packages/app-desktop/gui/ConfigScreen/SideBar.js
packages/app-desktop/gui/ConfigScreen/SideBar.js.map
packages/app-desktop/gui/ConfigScreen/controls/PluginsStates.d.ts
packages/app-desktop/gui/ConfigScreen/controls/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/PluginsStates.js.map
packages/app-desktop/gui/ConfigScreen/Sidebar.d.ts
packages/app-desktop/gui/ConfigScreen/Sidebar.js
packages/app-desktop/gui/ConfigScreen/Sidebar.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js.map
packages/app-desktop/gui/DropboxLoginScreen.d.ts
packages/app-desktop/gui/DropboxLoginScreen.js
packages/app-desktop/gui/DropboxLoginScreen.js.map
@@ -656,21 +681,18 @@ packages/app-desktop/gui/Root_UpgradeSyncTarget.js.map
packages/app-desktop/gui/SearchBar/SearchBar.d.ts
packages/app-desktop/gui/SearchBar/SearchBar.js
packages/app-desktop/gui/SearchBar/SearchBar.js.map
packages/app-desktop/gui/SearchBar/styles/index.d.ts
packages/app-desktop/gui/SearchBar/styles/index.js
packages/app-desktop/gui/SearchBar/styles/index.js.map
packages/app-desktop/gui/ShareNoteDialog.d.ts
packages/app-desktop/gui/ShareNoteDialog.js
packages/app-desktop/gui/ShareNoteDialog.js.map
packages/app-desktop/gui/SideBar/SideBar.d.ts
packages/app-desktop/gui/SideBar/SideBar.js
packages/app-desktop/gui/SideBar/SideBar.js.map
packages/app-desktop/gui/SideBar/commands/focusElementSideBar.d.ts
packages/app-desktop/gui/SideBar/commands/focusElementSideBar.js
packages/app-desktop/gui/SideBar/commands/focusElementSideBar.js.map
packages/app-desktop/gui/SideBar/styles/index.d.ts
packages/app-desktop/gui/SideBar/styles/index.js
packages/app-desktop/gui/SideBar/styles/index.js.map
packages/app-desktop/gui/Sidebar/Sidebar.d.ts
packages/app-desktop/gui/Sidebar/Sidebar.js
packages/app-desktop/gui/Sidebar/Sidebar.js.map
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.d.ts
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js.map
packages/app-desktop/gui/Sidebar/styles/index.d.ts
packages/app-desktop/gui/Sidebar/styles/index.js
packages/app-desktop/gui/Sidebar/styles/index.js.map
packages/app-desktop/gui/StatusScreen/StatusScreen.d.ts
packages/app-desktop/gui/StatusScreen/StatusScreen.js
packages/app-desktop/gui/StatusScreen/StatusScreen.js.map
@@ -707,6 +729,9 @@ packages/app-desktop/gui/hooks/usePrevious.js.map
packages/app-desktop/gui/hooks/usePropsDebugger.d.ts
packages/app-desktop/gui/hooks/usePropsDebugger.js
packages/app-desktop/gui/hooks/usePropsDebugger.js.map
packages/app-desktop/gui/lib/SearchInput/SearchInput.d.ts
packages/app-desktop/gui/lib/SearchInput/SearchInput.js
packages/app-desktop/gui/lib/SearchInput/SearchInput.js.map
packages/app-desktop/gui/lib/ToggleButton/ToggleButton.d.ts
packages/app-desktop/gui/lib/ToggleButton/ToggleButton.js
packages/app-desktop/gui/lib/ToggleButton/ToggleButton.js.map
@@ -1004,6 +1029,9 @@ packages/lib/services/KeymapService_keysRegExp.js.map
packages/lib/services/KvStore.d.ts
packages/lib/services/KvStore.js
packages/lib/services/KvStore.js.map
packages/lib/services/PostMessageService.d.ts
packages/lib/services/PostMessageService.js
packages/lib/services/PostMessageService.js.map
packages/lib/services/ResourceEditWatcher/index.d.ts
packages/lib/services/ResourceEditWatcher/index.js
packages/lib/services/ResourceEditWatcher/index.js.map
@@ -1121,6 +1149,9 @@ packages/lib/services/plugins/Plugin.js.map
packages/lib/services/plugins/PluginService.d.ts
packages/lib/services/plugins/PluginService.js
packages/lib/services/plugins/PluginService.js.map
packages/lib/services/plugins/RepositoryApi.d.ts
packages/lib/services/plugins/RepositoryApi.js
packages/lib/services/plugins/RepositoryApi.js.map
packages/lib/services/plugins/ToolbarButtonController.d.ts
packages/lib/services/plugins/ToolbarButtonController.js
packages/lib/services/plugins/ToolbarButtonController.js.map
@@ -1139,6 +1170,9 @@ packages/lib/services/plugins/api/Joplin.js.map
packages/lib/services/plugins/api/JoplinCommands.d.ts
packages/lib/services/plugins/api/JoplinCommands.js
packages/lib/services/plugins/api/JoplinCommands.js.map
packages/lib/services/plugins/api/JoplinContentScripts.d.ts
packages/lib/services/plugins/api/JoplinContentScripts.js
packages/lib/services/plugins/api/JoplinContentScripts.js.map
packages/lib/services/plugins/api/JoplinData.d.ts
packages/lib/services/plugins/api/JoplinData.js
packages/lib/services/plugins/api/JoplinData.js.map
@@ -1205,6 +1239,12 @@ packages/lib/services/plugins/utils/mapEventHandlersToIds.js.map
packages/lib/services/plugins/utils/types.d.ts
packages/lib/services/plugins/utils/types.js
packages/lib/services/plugins/utils/types.js.map
packages/lib/services/plugins/utils/validatePluginId.d.ts
packages/lib/services/plugins/utils/validatePluginId.js
packages/lib/services/plugins/utils/validatePluginId.js.map
packages/lib/services/plugins/utils/validatePluginId.test.d.ts
packages/lib/services/plugins/utils/validatePluginId.test.js
packages/lib/services/plugins/utils/validatePluginId.test.js.map
packages/lib/services/rest/Api.d.ts
packages/lib/services/rest/Api.js
packages/lib/services/rest/Api.js.map
@@ -1334,6 +1374,21 @@ packages/lib/uuid.js.map
packages/lib/versionInfo.d.ts
packages/lib/versionInfo.js
packages/lib/versionInfo.js.map
packages/plugin-repo-cli/dummy.test.d.ts
packages/plugin-repo-cli/dummy.test.js
packages/plugin-repo-cli/dummy.test.js.map
packages/plugin-repo-cli/index.d.ts
packages/plugin-repo-cli/index.js
packages/plugin-repo-cli/index.js.map
packages/plugins/ToggleSidebars/api/index.d.ts
packages/plugins/ToggleSidebars/api/index.js
packages/plugins/ToggleSidebars/api/index.js.map
packages/plugins/ToggleSidebars/api/types.d.ts
packages/plugins/ToggleSidebars/api/types.js
packages/plugins/ToggleSidebars/api/types.js.map
packages/plugins/ToggleSidebars/src/index.d.ts
packages/plugins/ToggleSidebars/src/index.js
packages/plugins/ToggleSidebars/src/index.js.map
packages/renderer/HtmlToHtml.d.ts
packages/renderer/HtmlToHtml.js
packages/renderer/HtmlToHtml.js.map
@@ -1415,78 +1470,24 @@ packages/renderer/utils.js.map
packages/server/src/app.d.ts
packages/server/src/app.js
packages/server/src/app.js.map
packages/server/src/config-base.d.ts
packages/server/src/config-base.js
packages/server/src/config-base.js.map
packages/server/src/config-buildTypes.d.ts
packages/server/src/config-buildTypes.js
packages/server/src/config-buildTypes.js.map
packages/server/src/config-dev.d.ts
packages/server/src/config-dev.js
packages/server/src/config-dev.js.map
packages/server/src/config-prod.d.ts
packages/server/src/config-prod.js
packages/server/src/config-prod.js.map
packages/server/src/config-tests.d.ts
packages/server/src/config-tests.js
packages/server/src/config-tests.js.map
packages/server/src/config.d.ts
packages/server/src/config.js
packages/server/src/config.js.map
packages/server/src/controllers/BaseController.d.ts
packages/server/src/controllers/BaseController.js
packages/server/src/controllers/BaseController.js.map
packages/server/src/controllers/api/FileController.d.ts
packages/server/src/controllers/api/FileController.js
packages/server/src/controllers/api/FileController.js.map
packages/server/src/controllers/api/FileController.test.d.ts
packages/server/src/controllers/api/FileController.test.js
packages/server/src/controllers/api/FileController.test.js.map
packages/server/src/controllers/api/OAuthController.d.ts
packages/server/src/controllers/api/OAuthController.js
packages/server/src/controllers/api/OAuthController.js.map
packages/server/src/controllers/api/SessionController.d.ts
packages/server/src/controllers/api/SessionController.js
packages/server/src/controllers/api/SessionController.js.map
packages/server/src/controllers/api/SessionController.test.d.ts
packages/server/src/controllers/api/SessionController.test.js
packages/server/src/controllers/api/SessionController.test.js.map
packages/server/src/controllers/api/UserController.d.ts
packages/server/src/controllers/api/UserController.js
packages/server/src/controllers/api/UserController.js.map
packages/server/src/controllers/api/UserController.test.d.ts
packages/server/src/controllers/api/UserController.test.js
packages/server/src/controllers/api/UserController.test.js.map
packages/server/src/controllers/factory.d.ts
packages/server/src/controllers/factory.js
packages/server/src/controllers/factory.js.map
packages/server/src/controllers/index/FileController.d.ts
packages/server/src/controllers/index/FileController.js
packages/server/src/controllers/index/FileController.js.map
packages/server/src/controllers/index/HomeController.d.ts
packages/server/src/controllers/index/HomeController.js
packages/server/src/controllers/index/HomeController.js.map
packages/server/src/controllers/index/LoginController.d.ts
packages/server/src/controllers/index/LoginController.js
packages/server/src/controllers/index/LoginController.js.map
packages/server/src/controllers/index/NotificationController.d.ts
packages/server/src/controllers/index/NotificationController.js
packages/server/src/controllers/index/NotificationController.js.map
packages/server/src/controllers/index/ProfileController.d.ts
packages/server/src/controllers/index/ProfileController.js
packages/server/src/controllers/index/ProfileController.js.map
packages/server/src/controllers/index/UserController.d.ts
packages/server/src/controllers/index/UserController.js
packages/server/src/controllers/index/UserController.js.map
packages/server/src/db.d.ts
packages/server/src/db.js
packages/server/src/db.js.map
packages/server/src/middleware/notificationHandler.d.ts
packages/server/src/middleware/notificationHandler.js
packages/server/src/middleware/notificationHandler.js.map
packages/server/src/middleware/notificationHandler.test.d.ts
packages/server/src/middleware/notificationHandler.test.js
packages/server/src/middleware/notificationHandler.test.js.map
packages/server/src/middleware/ownerHandler.d.ts
packages/server/src/middleware/ownerHandler.js
packages/server/src/middleware/ownerHandler.js.map
packages/server/src/middleware/ownerHandler.test.d.ts
packages/server/src/middleware/ownerHandler.test.js
packages/server/src/middleware/ownerHandler.test.js.map
packages/server/src/middleware/routeHandler.d.ts
packages/server/src/middleware/routeHandler.js
packages/server/src/middleware/routeHandler.js.map
@@ -1529,6 +1530,9 @@ packages/server/src/models/SessionModel.js.map
packages/server/src/models/UserModel.d.ts
packages/server/src/models/UserModel.js
packages/server/src/models/UserModel.js.map
packages/server/src/models/UserModel.test.d.ts
packages/server/src/models/UserModel.test.js
packages/server/src/models/UserModel.test.js.map
packages/server/src/models/factory.d.ts
packages/server/src/models/factory.js
packages/server/src/models/factory.js.map
@@ -1541,15 +1545,21 @@ packages/server/src/models/utils/pagination.test.js.map
packages/server/src/routes/api/files.d.ts
packages/server/src/routes/api/files.js
packages/server/src/routes/api/files.js.map
packages/server/src/routes/api/index.d.ts
packages/server/src/routes/api/index.js
packages/server/src/routes/api/index.js.map
packages/server/src/routes/api/files.test.d.ts
packages/server/src/routes/api/files.test.js
packages/server/src/routes/api/files.test.js.map
packages/server/src/routes/api/ping.d.ts
packages/server/src/routes/api/ping.js
packages/server/src/routes/api/ping.js.map
packages/server/src/routes/api/ping.test.d.ts
packages/server/src/routes/api/ping.test.js
packages/server/src/routes/api/ping.test.js.map
packages/server/src/routes/api/sessions.d.ts
packages/server/src/routes/api/sessions.js
packages/server/src/routes/api/sessions.js.map
packages/server/src/routes/api/sessions.test.d.ts
packages/server/src/routes/api/sessions.test.js
packages/server/src/routes/api/sessions.test.js.map
packages/server/src/routes/default.d.ts
packages/server/src/routes/default.js
packages/server/src/routes/default.js.map
@@ -1559,24 +1569,33 @@ packages/server/src/routes/index/files.js.map
packages/server/src/routes/index/home.d.ts
packages/server/src/routes/index/home.js
packages/server/src/routes/index/home.js.map
packages/server/src/routes/index/home.test.d.ts
packages/server/src/routes/index/home.test.js
packages/server/src/routes/index/home.test.js.map
packages/server/src/routes/index/login.d.ts
packages/server/src/routes/index/login.js
packages/server/src/routes/index/login.js.map
packages/server/src/routes/index/login.test.d.ts
packages/server/src/routes/index/login.test.js
packages/server/src/routes/index/login.test.js.map
packages/server/src/routes/index/logout.d.ts
packages/server/src/routes/index/logout.js
packages/server/src/routes/index/logout.js.map
packages/server/src/routes/index/logout.test.d.ts
packages/server/src/routes/index/logout.test.js
packages/server/src/routes/index/logout.test.js.map
packages/server/src/routes/index/notifications.d.ts
packages/server/src/routes/index/notifications.js
packages/server/src/routes/index/notifications.js.map
packages/server/src/routes/index/profile.d.ts
packages/server/src/routes/index/profile.js
packages/server/src/routes/index/profile.js.map
packages/server/src/routes/index/user.d.ts
packages/server/src/routes/index/user.js
packages/server/src/routes/index/user.js.map
packages/server/src/routes/index/notifications.test.d.ts
packages/server/src/routes/index/notifications.test.js
packages/server/src/routes/index/notifications.test.js.map
packages/server/src/routes/index/users.d.ts
packages/server/src/routes/index/users.js
packages/server/src/routes/index/users.js.map
packages/server/src/routes/index/users.test.d.ts
packages/server/src/routes/index/users.test.js
packages/server/src/routes/index/users.test.js.map
packages/server/src/routes/oauth2/authorize.d.ts
packages/server/src/routes/oauth2/authorize.js
packages/server/src/routes/oauth2/authorize.js.map
@@ -1595,6 +1614,9 @@ packages/server/src/tools/dbTools.js.map
packages/server/src/tools/generate-types.d.ts
packages/server/src/tools/generate-types.js
packages/server/src/tools/generate-types.js.map
packages/server/src/utils/Router.d.ts
packages/server/src/utils/Router.js
packages/server/src/utils/Router.js.map
packages/server/src/utils/TransactionHandler.d.ts
packages/server/src/utils/TransactionHandler.js
packages/server/src/utils/TransactionHandler.js.map
@@ -1628,12 +1650,24 @@ packages/server/src/utils/routeUtils.js.map
packages/server/src/utils/routeUtils.test.d.ts
packages/server/src/utils/routeUtils.test.js
packages/server/src/utils/routeUtils.test.js.map
packages/server/src/utils/testUtils.d.ts
packages/server/src/utils/testUtils.js
packages/server/src/utils/testUtils.js.map
packages/server/src/utils/testing/apiUtils.d.ts
packages/server/src/utils/testing/apiUtils.js
packages/server/src/utils/testing/apiUtils.js.map
packages/server/src/utils/testing/koa/FakeCookies.d.ts
packages/server/src/utils/testing/koa/FakeCookies.js
packages/server/src/utils/testing/koa/FakeCookies.js.map
packages/server/src/utils/testing/koa/FakeRequest.d.ts
packages/server/src/utils/testing/koa/FakeRequest.js
packages/server/src/utils/testing/koa/FakeRequest.js.map
packages/server/src/utils/testing/koa/FakeResponse.d.ts
packages/server/src/utils/testing/koa/FakeResponse.js
packages/server/src/utils/testing/koa/FakeResponse.js.map
packages/server/src/utils/testing/testRouters.d.ts
packages/server/src/utils/testing/testRouters.js
packages/server/src/utils/testing/testRouters.js.map
packages/server/src/utils/testing/testUtils.d.ts
packages/server/src/utils/testing/testUtils.js
packages/server/src/utils/testing/testUtils.js.map
packages/server/src/utils/time.d.ts
packages/server/src/utils/time.js
packages/server/src/utils/time.js.map
@@ -1646,7 +1680,13 @@ packages/server/src/utils/urlUtils.js.map
packages/server/src/utils/uuidgen.d.ts
packages/server/src/utils/uuidgen.js
packages/server/src/utils/uuidgen.js.map
packages/tools/lerna-add.d.ts
packages/tools/lerna-add.js
packages/tools/lerna-add.js.map
packages/tools/release-server.d.ts
packages/tools/release-server.js
packages/tools/release-server.js.map
packages/tools/tool-utils.d.ts
packages/tools/tool-utils.js
packages/tools/tool-utils.js.map
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD

219
.gitignore vendored
View File

@@ -99,6 +99,12 @@ packages/app-cli/tests/models_Note.js.map
packages/app-cli/tests/models_Setting.d.ts
packages/app-cli/tests/models_Setting.js
packages/app-cli/tests/models_Setting.js.map
packages/app-cli/tests/services/plugins/RepositoryApi.d.ts
packages/app-cli/tests/services/plugins/RepositoryApi.js
packages/app-cli/tests/services/plugins/RepositoryApi.js.map
packages/app-cli/tests/services/plugins/api/JoplinSettings.d.ts
packages/app-cli/tests/services/plugins/api/JoplinSettings.js
packages/app-cli/tests/services/plugins/api/JoplinSettings.js.map
packages/app-cli/tests/services/plugins/api/JoplinViewMenuItem.d.ts
packages/app-cli/tests/services/plugins/api/JoplinViewMenuItem.js
packages/app-cli/tests/services/plugins/api/JoplinViewMenuItem.js.map
@@ -210,6 +216,15 @@ packages/app-cli/tests/support/plugins/multi_selection/api/types.js.map
packages/app-cli/tests/support/plugins/multi_selection/src/index.d.ts
packages/app-cli/tests/support/plugins/multi_selection/src/index.js
packages/app-cli/tests/support/plugins/multi_selection/src/index.js.map
packages/app-cli/tests/support/plugins/post_messages/api/index.d.ts
packages/app-cli/tests/support/plugins/post_messages/api/index.js
packages/app-cli/tests/support/plugins/post_messages/api/index.js.map
packages/app-cli/tests/support/plugins/post_messages/api/types.d.ts
packages/app-cli/tests/support/plugins/post_messages/api/types.js
packages/app-cli/tests/support/plugins/post_messages/api/types.js.map
packages/app-cli/tests/support/plugins/post_messages/src/index.d.ts
packages/app-cli/tests/support/plugins/post_messages/src/index.js
packages/app-cli/tests/support/plugins/post_messages/src/index.js.map
packages/app-cli/tests/support/plugins/register_command/api/index.d.ts
packages/app-cli/tests/support/plugins/register_command/api/index.js
packages/app-cli/tests/support/plugins/register_command/api/index.js.map
@@ -312,12 +327,21 @@ packages/app-desktop/gui/ConfigScreen/ButtonBar.js.map
packages/app-desktop/gui/ConfigScreen/ConfigScreen.d.ts
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js
packages/app-desktop/gui/ConfigScreen/ConfigScreen.js.map
packages/app-desktop/gui/ConfigScreen/SideBar.d.ts
packages/app-desktop/gui/ConfigScreen/SideBar.js
packages/app-desktop/gui/ConfigScreen/SideBar.js.map
packages/app-desktop/gui/ConfigScreen/controls/PluginsStates.d.ts
packages/app-desktop/gui/ConfigScreen/controls/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/PluginsStates.js.map
packages/app-desktop/gui/ConfigScreen/Sidebar.d.ts
packages/app-desktop/gui/ConfigScreen/Sidebar.js
packages/app-desktop/gui/ConfigScreen/Sidebar.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js.map
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.d.ts
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js.map
packages/app-desktop/gui/DropboxLoginScreen.d.ts
packages/app-desktop/gui/DropboxLoginScreen.js
packages/app-desktop/gui/DropboxLoginScreen.js.map
@@ -645,21 +669,18 @@ packages/app-desktop/gui/Root_UpgradeSyncTarget.js.map
packages/app-desktop/gui/SearchBar/SearchBar.d.ts
packages/app-desktop/gui/SearchBar/SearchBar.js
packages/app-desktop/gui/SearchBar/SearchBar.js.map
packages/app-desktop/gui/SearchBar/styles/index.d.ts
packages/app-desktop/gui/SearchBar/styles/index.js
packages/app-desktop/gui/SearchBar/styles/index.js.map
packages/app-desktop/gui/ShareNoteDialog.d.ts
packages/app-desktop/gui/ShareNoteDialog.js
packages/app-desktop/gui/ShareNoteDialog.js.map
packages/app-desktop/gui/SideBar/SideBar.d.ts
packages/app-desktop/gui/SideBar/SideBar.js
packages/app-desktop/gui/SideBar/SideBar.js.map
packages/app-desktop/gui/SideBar/commands/focusElementSideBar.d.ts
packages/app-desktop/gui/SideBar/commands/focusElementSideBar.js
packages/app-desktop/gui/SideBar/commands/focusElementSideBar.js.map
packages/app-desktop/gui/SideBar/styles/index.d.ts
packages/app-desktop/gui/SideBar/styles/index.js
packages/app-desktop/gui/SideBar/styles/index.js.map
packages/app-desktop/gui/Sidebar/Sidebar.d.ts
packages/app-desktop/gui/Sidebar/Sidebar.js
packages/app-desktop/gui/Sidebar/Sidebar.js.map
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.d.ts
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js.map
packages/app-desktop/gui/Sidebar/styles/index.d.ts
packages/app-desktop/gui/Sidebar/styles/index.js
packages/app-desktop/gui/Sidebar/styles/index.js.map
packages/app-desktop/gui/StatusScreen/StatusScreen.d.ts
packages/app-desktop/gui/StatusScreen/StatusScreen.js
packages/app-desktop/gui/StatusScreen/StatusScreen.js.map
@@ -696,6 +717,9 @@ packages/app-desktop/gui/hooks/usePrevious.js.map
packages/app-desktop/gui/hooks/usePropsDebugger.d.ts
packages/app-desktop/gui/hooks/usePropsDebugger.js
packages/app-desktop/gui/hooks/usePropsDebugger.js.map
packages/app-desktop/gui/lib/SearchInput/SearchInput.d.ts
packages/app-desktop/gui/lib/SearchInput/SearchInput.js
packages/app-desktop/gui/lib/SearchInput/SearchInput.js.map
packages/app-desktop/gui/lib/ToggleButton/ToggleButton.d.ts
packages/app-desktop/gui/lib/ToggleButton/ToggleButton.js
packages/app-desktop/gui/lib/ToggleButton/ToggleButton.js.map
@@ -993,6 +1017,9 @@ packages/lib/services/KeymapService_keysRegExp.js.map
packages/lib/services/KvStore.d.ts
packages/lib/services/KvStore.js
packages/lib/services/KvStore.js.map
packages/lib/services/PostMessageService.d.ts
packages/lib/services/PostMessageService.js
packages/lib/services/PostMessageService.js.map
packages/lib/services/ResourceEditWatcher/index.d.ts
packages/lib/services/ResourceEditWatcher/index.js
packages/lib/services/ResourceEditWatcher/index.js.map
@@ -1110,6 +1137,9 @@ packages/lib/services/plugins/Plugin.js.map
packages/lib/services/plugins/PluginService.d.ts
packages/lib/services/plugins/PluginService.js
packages/lib/services/plugins/PluginService.js.map
packages/lib/services/plugins/RepositoryApi.d.ts
packages/lib/services/plugins/RepositoryApi.js
packages/lib/services/plugins/RepositoryApi.js.map
packages/lib/services/plugins/ToolbarButtonController.d.ts
packages/lib/services/plugins/ToolbarButtonController.js
packages/lib/services/plugins/ToolbarButtonController.js.map
@@ -1128,6 +1158,9 @@ packages/lib/services/plugins/api/Joplin.js.map
packages/lib/services/plugins/api/JoplinCommands.d.ts
packages/lib/services/plugins/api/JoplinCommands.js
packages/lib/services/plugins/api/JoplinCommands.js.map
packages/lib/services/plugins/api/JoplinContentScripts.d.ts
packages/lib/services/plugins/api/JoplinContentScripts.js
packages/lib/services/plugins/api/JoplinContentScripts.js.map
packages/lib/services/plugins/api/JoplinData.d.ts
packages/lib/services/plugins/api/JoplinData.js
packages/lib/services/plugins/api/JoplinData.js.map
@@ -1194,6 +1227,12 @@ packages/lib/services/plugins/utils/mapEventHandlersToIds.js.map
packages/lib/services/plugins/utils/types.d.ts
packages/lib/services/plugins/utils/types.js
packages/lib/services/plugins/utils/types.js.map
packages/lib/services/plugins/utils/validatePluginId.d.ts
packages/lib/services/plugins/utils/validatePluginId.js
packages/lib/services/plugins/utils/validatePluginId.js.map
packages/lib/services/plugins/utils/validatePluginId.test.d.ts
packages/lib/services/plugins/utils/validatePluginId.test.js
packages/lib/services/plugins/utils/validatePluginId.test.js.map
packages/lib/services/rest/Api.d.ts
packages/lib/services/rest/Api.js
packages/lib/services/rest/Api.js.map
@@ -1323,6 +1362,21 @@ packages/lib/uuid.js.map
packages/lib/versionInfo.d.ts
packages/lib/versionInfo.js
packages/lib/versionInfo.js.map
packages/plugin-repo-cli/dummy.test.d.ts
packages/plugin-repo-cli/dummy.test.js
packages/plugin-repo-cli/dummy.test.js.map
packages/plugin-repo-cli/index.d.ts
packages/plugin-repo-cli/index.js
packages/plugin-repo-cli/index.js.map
packages/plugins/ToggleSidebars/api/index.d.ts
packages/plugins/ToggleSidebars/api/index.js
packages/plugins/ToggleSidebars/api/index.js.map
packages/plugins/ToggleSidebars/api/types.d.ts
packages/plugins/ToggleSidebars/api/types.js
packages/plugins/ToggleSidebars/api/types.js.map
packages/plugins/ToggleSidebars/src/index.d.ts
packages/plugins/ToggleSidebars/src/index.js
packages/plugins/ToggleSidebars/src/index.js.map
packages/renderer/HtmlToHtml.d.ts
packages/renderer/HtmlToHtml.js
packages/renderer/HtmlToHtml.js.map
@@ -1404,78 +1458,24 @@ packages/renderer/utils.js.map
packages/server/src/app.d.ts
packages/server/src/app.js
packages/server/src/app.js.map
packages/server/src/config-base.d.ts
packages/server/src/config-base.js
packages/server/src/config-base.js.map
packages/server/src/config-buildTypes.d.ts
packages/server/src/config-buildTypes.js
packages/server/src/config-buildTypes.js.map
packages/server/src/config-dev.d.ts
packages/server/src/config-dev.js
packages/server/src/config-dev.js.map
packages/server/src/config-prod.d.ts
packages/server/src/config-prod.js
packages/server/src/config-prod.js.map
packages/server/src/config-tests.d.ts
packages/server/src/config-tests.js
packages/server/src/config-tests.js.map
packages/server/src/config.d.ts
packages/server/src/config.js
packages/server/src/config.js.map
packages/server/src/controllers/BaseController.d.ts
packages/server/src/controllers/BaseController.js
packages/server/src/controllers/BaseController.js.map
packages/server/src/controllers/api/FileController.d.ts
packages/server/src/controllers/api/FileController.js
packages/server/src/controllers/api/FileController.js.map
packages/server/src/controllers/api/FileController.test.d.ts
packages/server/src/controllers/api/FileController.test.js
packages/server/src/controllers/api/FileController.test.js.map
packages/server/src/controllers/api/OAuthController.d.ts
packages/server/src/controllers/api/OAuthController.js
packages/server/src/controllers/api/OAuthController.js.map
packages/server/src/controllers/api/SessionController.d.ts
packages/server/src/controllers/api/SessionController.js
packages/server/src/controllers/api/SessionController.js.map
packages/server/src/controllers/api/SessionController.test.d.ts
packages/server/src/controllers/api/SessionController.test.js
packages/server/src/controllers/api/SessionController.test.js.map
packages/server/src/controllers/api/UserController.d.ts
packages/server/src/controllers/api/UserController.js
packages/server/src/controllers/api/UserController.js.map
packages/server/src/controllers/api/UserController.test.d.ts
packages/server/src/controllers/api/UserController.test.js
packages/server/src/controllers/api/UserController.test.js.map
packages/server/src/controllers/factory.d.ts
packages/server/src/controllers/factory.js
packages/server/src/controllers/factory.js.map
packages/server/src/controllers/index/FileController.d.ts
packages/server/src/controllers/index/FileController.js
packages/server/src/controllers/index/FileController.js.map
packages/server/src/controllers/index/HomeController.d.ts
packages/server/src/controllers/index/HomeController.js
packages/server/src/controllers/index/HomeController.js.map
packages/server/src/controllers/index/LoginController.d.ts
packages/server/src/controllers/index/LoginController.js
packages/server/src/controllers/index/LoginController.js.map
packages/server/src/controllers/index/NotificationController.d.ts
packages/server/src/controllers/index/NotificationController.js
packages/server/src/controllers/index/NotificationController.js.map
packages/server/src/controllers/index/ProfileController.d.ts
packages/server/src/controllers/index/ProfileController.js
packages/server/src/controllers/index/ProfileController.js.map
packages/server/src/controllers/index/UserController.d.ts
packages/server/src/controllers/index/UserController.js
packages/server/src/controllers/index/UserController.js.map
packages/server/src/db.d.ts
packages/server/src/db.js
packages/server/src/db.js.map
packages/server/src/middleware/notificationHandler.d.ts
packages/server/src/middleware/notificationHandler.js
packages/server/src/middleware/notificationHandler.js.map
packages/server/src/middleware/notificationHandler.test.d.ts
packages/server/src/middleware/notificationHandler.test.js
packages/server/src/middleware/notificationHandler.test.js.map
packages/server/src/middleware/ownerHandler.d.ts
packages/server/src/middleware/ownerHandler.js
packages/server/src/middleware/ownerHandler.js.map
packages/server/src/middleware/ownerHandler.test.d.ts
packages/server/src/middleware/ownerHandler.test.js
packages/server/src/middleware/ownerHandler.test.js.map
packages/server/src/middleware/routeHandler.d.ts
packages/server/src/middleware/routeHandler.js
packages/server/src/middleware/routeHandler.js.map
@@ -1518,6 +1518,9 @@ packages/server/src/models/SessionModel.js.map
packages/server/src/models/UserModel.d.ts
packages/server/src/models/UserModel.js
packages/server/src/models/UserModel.js.map
packages/server/src/models/UserModel.test.d.ts
packages/server/src/models/UserModel.test.js
packages/server/src/models/UserModel.test.js.map
packages/server/src/models/factory.d.ts
packages/server/src/models/factory.js
packages/server/src/models/factory.js.map
@@ -1530,15 +1533,21 @@ packages/server/src/models/utils/pagination.test.js.map
packages/server/src/routes/api/files.d.ts
packages/server/src/routes/api/files.js
packages/server/src/routes/api/files.js.map
packages/server/src/routes/api/index.d.ts
packages/server/src/routes/api/index.js
packages/server/src/routes/api/index.js.map
packages/server/src/routes/api/files.test.d.ts
packages/server/src/routes/api/files.test.js
packages/server/src/routes/api/files.test.js.map
packages/server/src/routes/api/ping.d.ts
packages/server/src/routes/api/ping.js
packages/server/src/routes/api/ping.js.map
packages/server/src/routes/api/ping.test.d.ts
packages/server/src/routes/api/ping.test.js
packages/server/src/routes/api/ping.test.js.map
packages/server/src/routes/api/sessions.d.ts
packages/server/src/routes/api/sessions.js
packages/server/src/routes/api/sessions.js.map
packages/server/src/routes/api/sessions.test.d.ts
packages/server/src/routes/api/sessions.test.js
packages/server/src/routes/api/sessions.test.js.map
packages/server/src/routes/default.d.ts
packages/server/src/routes/default.js
packages/server/src/routes/default.js.map
@@ -1548,24 +1557,33 @@ packages/server/src/routes/index/files.js.map
packages/server/src/routes/index/home.d.ts
packages/server/src/routes/index/home.js
packages/server/src/routes/index/home.js.map
packages/server/src/routes/index/home.test.d.ts
packages/server/src/routes/index/home.test.js
packages/server/src/routes/index/home.test.js.map
packages/server/src/routes/index/login.d.ts
packages/server/src/routes/index/login.js
packages/server/src/routes/index/login.js.map
packages/server/src/routes/index/login.test.d.ts
packages/server/src/routes/index/login.test.js
packages/server/src/routes/index/login.test.js.map
packages/server/src/routes/index/logout.d.ts
packages/server/src/routes/index/logout.js
packages/server/src/routes/index/logout.js.map
packages/server/src/routes/index/logout.test.d.ts
packages/server/src/routes/index/logout.test.js
packages/server/src/routes/index/logout.test.js.map
packages/server/src/routes/index/notifications.d.ts
packages/server/src/routes/index/notifications.js
packages/server/src/routes/index/notifications.js.map
packages/server/src/routes/index/profile.d.ts
packages/server/src/routes/index/profile.js
packages/server/src/routes/index/profile.js.map
packages/server/src/routes/index/user.d.ts
packages/server/src/routes/index/user.js
packages/server/src/routes/index/user.js.map
packages/server/src/routes/index/notifications.test.d.ts
packages/server/src/routes/index/notifications.test.js
packages/server/src/routes/index/notifications.test.js.map
packages/server/src/routes/index/users.d.ts
packages/server/src/routes/index/users.js
packages/server/src/routes/index/users.js.map
packages/server/src/routes/index/users.test.d.ts
packages/server/src/routes/index/users.test.js
packages/server/src/routes/index/users.test.js.map
packages/server/src/routes/oauth2/authorize.d.ts
packages/server/src/routes/oauth2/authorize.js
packages/server/src/routes/oauth2/authorize.js.map
@@ -1584,6 +1602,9 @@ packages/server/src/tools/dbTools.js.map
packages/server/src/tools/generate-types.d.ts
packages/server/src/tools/generate-types.js
packages/server/src/tools/generate-types.js.map
packages/server/src/utils/Router.d.ts
packages/server/src/utils/Router.js
packages/server/src/utils/Router.js.map
packages/server/src/utils/TransactionHandler.d.ts
packages/server/src/utils/TransactionHandler.js
packages/server/src/utils/TransactionHandler.js.map
@@ -1617,12 +1638,24 @@ packages/server/src/utils/routeUtils.js.map
packages/server/src/utils/routeUtils.test.d.ts
packages/server/src/utils/routeUtils.test.js
packages/server/src/utils/routeUtils.test.js.map
packages/server/src/utils/testUtils.d.ts
packages/server/src/utils/testUtils.js
packages/server/src/utils/testUtils.js.map
packages/server/src/utils/testing/apiUtils.d.ts
packages/server/src/utils/testing/apiUtils.js
packages/server/src/utils/testing/apiUtils.js.map
packages/server/src/utils/testing/koa/FakeCookies.d.ts
packages/server/src/utils/testing/koa/FakeCookies.js
packages/server/src/utils/testing/koa/FakeCookies.js.map
packages/server/src/utils/testing/koa/FakeRequest.d.ts
packages/server/src/utils/testing/koa/FakeRequest.js
packages/server/src/utils/testing/koa/FakeRequest.js.map
packages/server/src/utils/testing/koa/FakeResponse.d.ts
packages/server/src/utils/testing/koa/FakeResponse.js
packages/server/src/utils/testing/koa/FakeResponse.js.map
packages/server/src/utils/testing/testRouters.d.ts
packages/server/src/utils/testing/testRouters.js
packages/server/src/utils/testing/testRouters.js.map
packages/server/src/utils/testing/testUtils.d.ts
packages/server/src/utils/testing/testUtils.js
packages/server/src/utils/testing/testUtils.js.map
packages/server/src/utils/time.d.ts
packages/server/src/utils/time.js
packages/server/src/utils/time.js.map
@@ -1635,7 +1668,13 @@ packages/server/src/utils/urlUtils.js.map
packages/server/src/utils/uuidgen.d.ts
packages/server/src/utils/uuidgen.js
packages/server/src/utils/uuidgen.js.map
packages/tools/lerna-add.d.ts
packages/tools/lerna-add.js
packages/tools/lerna-add.js.map
packages/tools/release-server.d.ts
packages/tools/release-server.js
packages/tools/release-server.js.map
packages/tools/tool-utils.d.ts
packages/tools/tool-utils.js
packages/tools/tool-utils.js.map
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD

View File

@@ -22,7 +22,8 @@ module.exports = {
return `joplin.${camelCaseToDots(p)
.replace(/menu\.items/, 'menuItems')
.replace(/toolbar\.buttons/, 'toolbarButtons')}`;
.replace(/toolbar\.buttons/, 'toolbarButtons')
.replace(/content\.scripts/, 'contentScripts')}`;
},
jpIsAllowedGroup: function(name) {

View File

@@ -1,3 +0,0 @@
FROM postgres:13.1
EXPOSE 5432

View File

@@ -16,8 +16,15 @@ WORKDIR /home/$user
RUN mkdir /home/$user/logs
# Install the root scripts but don't run postinstall (which would bootstrap
# and build TypeScript files, but we don't have the TypeScript files at
# this point)
COPY --chown=$user:$user package*.json ./
RUN npm install --ignore-scripts
# To take advantage of the Docker cache, we first copy all the package.json
# and package-lock.json files, as they rarely change? and then bootstrap
# and package-lock.json files, as they rarely change, and then bootstrap
# all the packages.
#
# Note that bootstrapping the packages will run all the postinstall
@@ -27,19 +34,10 @@ RUN mkdir /home/$user/logs
# We can't run boostrap with "--ignore-scripts" because that would
# prevent certain sub-packages, such as sqlite3, from being built
COPY --chown=$user:$user package*.json ./
# Install the root scripts but don't run postinstall (which would bootstrap
# and build TypeScript files, but we don't have the TypeScript files at
# this point)
RUN npm install --ignore-scripts
COPY --chown=$user:$user packages/fork-sax/package*.json ./packages/fork-sax/
COPY --chown=$user:$user packages/lib/package*.json ./packages/lib/
COPY --chown=$user:$user packages/renderer/package*.json ./packages/renderer/
COPY --chown=$user:$user packages/tools/package*.json ./packages/tools/
COPY --chown=$user:$user packages/server/package*.json ./packages/server/
COPY --chown=$user:$user packages/lib/package*.json ./packages/lib/
COPY --chown=$user:$user lerna.json .
COPY --chown=$user:$user tsconfig.json .
@@ -50,22 +48,29 @@ COPY --chown=$user:$user packages/turndown ./packages/turndown
COPY --chown=$user:$user packages/turndown-plugin-gfm ./packages/turndown-plugin-gfm
COPY --chown=$user:$user packages/fork-htmlparser2 ./packages/fork-htmlparser2
RUN ls -la /home/$user
# Then bootstrap only, without compiling the TypeScript files
RUN npm run bootstrap
# We have a separate step for the server files because they are more likely to
# change.
COPY --chown=$user:$user packages/server/package*.json ./packages/server/
RUN npm run bootstrapServerOnly
# Now copy the source files. Put lib and server last as they are more likely to change.
COPY --chown=$user:$user packages/fork-sax ./packages/fork-sax
COPY --chown=$user:$user packages/lib ./packages/lib
COPY --chown=$user:$user packages/renderer ./packages/renderer
COPY --chown=$user:$user packages/tools ./packages/tools
COPY --chown=$user:$user packages/lib ./packages/lib
COPY --chown=$user:$user packages/server ./packages/server
# Finally build everything, in particular the TypeScript files.
RUN npm run build
EXPOSE ${JOPLIN_PORT}
ENV RUNNING_IN_DOCKER=1
EXPOSE ${APP_PORT}
CMD [ "npm", "--prefix", "packages/server", "start" ]

View File

@@ -162,7 +162,7 @@ DESKTOP=${DESKTOP,,} # convert to lower case
#-----------------------------------------------------
echo 'Create Desktop icon...'
if [[ $DESKTOP =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*x-cinnamon.*|.*deepin.*|.*pantheon.*|.*lxde.*|.*i3.* ]]
if [[ $DESKTOP =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*x-cinnamon.*|.*deepin.*|.*pantheon.*|.*lxde.*|.*i3.*|.*sway.* ]]
then
# Only delete the desktop file if it will be replaced
rm -f ~/.local/share/applications/appimagekit-joplin.desktop

View File

@@ -20,11 +20,11 @@ Three types of applications are available: for the **desktop** (Windows, macOS a
Operating System | Download
---|---
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-Setup-1.5.11.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a>
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a>
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a>
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/Joplin-Setup-1.6.6.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a>
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/Joplin-1.6.6.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a>
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/Joplin-1.6.6.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a>
**On Windows**, you may also use the <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/JoplinPortable.exe'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
**On Windows**, you may also use the <a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/JoplinPortable.exe'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
**On Linux**, the recommended way is to use the following installation script as it will handle the desktop icon too:
@@ -235,6 +235,7 @@ WebDAV-compatible services that are known to work with Joplin:
- [OwnCloud](https://owncloud.org/)
- [Seafile](https://www.seafile.com/)
- [Stack](https://www.transip.nl/stack/)
- [Synology WebDAV Server](https://www.synology.com/en-us/dsm/packages/WebDAVServer)
- [WebDAV Nav](https://www.schimera.com/products/webdav-nav-server/), a macOS server.
- [Zimbra](https://www.zimbra.com/)

15
docker-compose.db-dev.yml Normal file
View File

@@ -0,0 +1,15 @@
# For development this compose file starts the database only. The app can then
# be started using `npm run start-dev`, which is useful for development, because
# it means the app Docker file doesn't have to be rebuilt on each change.
version: '3'
services:
db:
image: postgres:13.1
ports:
- "5432:5432"
environment:
- POSTGRES_PASSWORD=joplin
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin

View File

@@ -1,28 +1,27 @@
# For development, the easiest might be to only start the Postgres container and
# run the app directly with `npm start`. Or use sqlite3.
# This compose file can be used in development to run both the database and app
# within Docker.
version: '3'
services:
# app:
# build:
# context: .
# dockerfile: Dockerfile.server-dev
# ports:
# - "22300:22300"
# # volumes:
# # - ./packages/server/:/var/www/joplin/packages/server/
# # - /var/www/joplin/packages/server/node_modules/
db:
app:
build:
context: .
dockerfile: Dockerfile.db
dockerfile: Dockerfile.server
ports:
- "22300:22300"
environment:
- DB_CLIENT=pg
- POSTGRES_PASSWORD=joplin
- POSTGRES_DATABASE=joplin
- POSTGRES_USER=joplin
- POSTGRES_PORT=5432
- POSTGRES_HOST=localhost
db:
image: postgres:13.1
ports:
- "5432:5432"
environment:
# TODO: Considering the database is only exposed to the
# application, and not to the outside world, is there a need to
# pick a secure password?
- POSTGRES_PASSWORD=joplin
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin
- POSTGRES_DB=joplin

View File

@@ -1,40 +1,34 @@
# This is a sample docker-compose file that can be used to run Joplin Server
# along with a PostgreSQL server.
#
# All environment variables are optional. If you don't set them, you will get a
# warning from docker-compose, however the app should use working defaults.
version: '3'
services:
app:
environment:
- JOPLIN_BASE_URL=${JOPLIN_BASE_URL}
- JOPLIN_PORT=${JOPLIN_PORT}
restart: unless-stopped
build:
context: .
dockerfile: Dockerfile.server
ports:
- "${JOPLIN_PORT}:${JOPLIN_PORT}"
# volumes:
# # Mount the server directory so that it's possible to edit file
# # while the container is running. However don't mount the
# # node_modules directory which will be specific to the Docker
# # image (eg native modules will be built for Ubuntu, while the
# # container might be running in Windows)
# # https://stackoverflow.com/a/37898591/561309
# - ./packages/server:/home/joplin/packages/server
# - /home/joplin/packages/server/node_modules/
db:
restart: unless-stopped
# By default, the Postgres image saves the data to a Docker volume,
# so it persists whenever the server is restarted using
# `docker-compose up`. Note that it would however be deleted when
# running `docker-compose down`.
build:
context: .
dockerfile: Dockerfile.db
image: postgres:13.1
ports:
- "5432:5432"
restart: unless-stopped
environment:
# TODO: Considering the database is only exposed to the
# application, and not to the outside world, is there a need to
# pick a secure password?
- POSTGRES_PASSWORD=joplin
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin
- APP_PORT=22300
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_DB=${POSTGRES_DATABASE}
app:
image: joplin/server:latest
depends_on:
- db
ports:
- "22300:22300"
restart: unless-stopped
environment:
- APP_BASE_URL=${APP_BASE_URL}
- DB_CLIENT=pg
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DATABASE=${POSTGRES_DATABASE}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PORT=${POSTGRES_PORT}
- POSTGRES_HOST=db

File diff suppressed because one or more lines are too long

View File

@@ -102,6 +102,7 @@
<h3>Accessors</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-get-signature tsd-parent-kind-class"><a href="joplin.html#commands" class="tsd-kind-icon">commands</a></li>
<li class="tsd-kind-get-signature tsd-parent-kind-class"><a href="joplin.html#contentscripts" class="tsd-kind-icon">content<wbr>Scripts</a></li>
<li class="tsd-kind-get-signature tsd-parent-kind-class"><a href="joplin.html#data" class="tsd-kind-icon">data</a></li>
<li class="tsd-kind-get-signature tsd-parent-kind-class"><a href="joplin.html#interop" class="tsd-kind-icon">interop</a></li>
<li class="tsd-kind-get-signature tsd-parent-kind-class"><a href="joplin.html#plugins" class="tsd-kind-icon">plugins</a></li>
@@ -131,6 +132,24 @@
<h4 class="tsd-returns-title">Returns <a href="joplincommands.html" class="tsd-signature-type">joplin.commands</a></h4>
-->
</li>
</ul>
</section>
<section class="tsd-panel tsd-member tsd-kind-get-signature tsd-parent-kind-class">
<a name="contentscripts" class="tsd-anchor"></a>
<h3>content<wbr>Scripts</h3>
<ul class="tsd-signatures tsd-kind-get-signature tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">get</span> contentScripts<span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><a href="joplincontentscripts.html" class="tsd-signature-type">joplin.contentScripts</a></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<aside class="tsd-sources">
</aside>
<!-- JOPLINCHANGE
<h4 class="tsd-returns-title">Returns <a href="joplincontentscripts.html" class="tsd-signature-type">joplin.contentScripts</a></h4>
-->
</li>
</ul>
@@ -268,6 +287,9 @@
<li class=" tsd-kind-get-signature tsd-parent-kind-class">
<a href="joplin.html#commands" class="tsd-kind-icon">commands</a>
</li>
<li class=" tsd-kind-get-signature tsd-parent-kind-class">
<a href="joplin.html#contentscripts" class="tsd-kind-icon">content<wbr>Scripts</a>
</li>
<li class=" tsd-kind-get-signature tsd-parent-kind-class">
<a href="joplin.html#data" class="tsd-kind-icon">data</a>
</li>

View File

@@ -0,0 +1,256 @@
<!doctype html>
<html class="default no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>joplin.contentScripts | Joplin Plugin API Documentation</title>
<meta name="description" content="Documentation for Joplin Plugin API Documentation">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../assets/css/main.css">
</head>
<body>
<header>
<div class="tsd-page-toolbar">
<div class="container">
<div class="table-wrap">
<div class="table-cell" id="tsd-search" data-index="../assets/js/search.json" data-base="..">
<div class="field">
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
<input id="tsd-search-field" type="text" />
</div>
<ul class="results">
<li class="state loading">Preparing search index...</li>
<li class="state failure">The search index is not available</li>
</ul>
<a href="joplin.html" class="title">Joplin Plugin API Documentation</a>
</div>
<div class="table-cell" id="tsd-widgets">
<div id="tsd-filter">
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
<div class="tsd-filter-group">
<div class="tsd-select" id="tsd-filter-visibility">
<span class="tsd-select-label">All</span>
<ul class="tsd-select-list">
<li data-value="public">Public</li>
<li data-value="protected">Public/Protected</li>
<li data-value="private" class="selected">All</li>
</ul>
</div>
<input type="checkbox" id="tsd-filter-inherited" checked />
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
</div>
</div>
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
</div>
</div>
</div>
</div>
<div class="tsd-page-title">
<div class="container">
<ul class="tsd-breadcrumb">
<!--
<li>
<a href="../globals.html">Globals</a>
</li>
-->
<li>
<a href="joplincontentscripts.html">joplin.contentScripts</a>
</li>
</ul>
<h1><!-- Class -->joplin.contentScripts</h1>
</div>
</div>
</header>
<div class="container container-main">
<div class="row">
<div class="col-8 col-content">
<!--
<section class="tsd-panel tsd-hierarchy">
<h3>Hierarchy</h3>
<ul class="tsd-hierarchy">
<li>
<span class="target">JoplinContentScripts</span>
</li>
</ul>
</section>
-->
<section class="tsd-panel-group tsd-index-group">
<h2>Index</h2>
<section class="tsd-panel tsd-index-panel">
<div class="tsd-index-content">
<section class="tsd-index-section ">
</section>
<section class="tsd-index-section ">
<h3>Methods</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplincontentscripts.html#onmessage" class="tsd-kind-icon">on<wbr>Message</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplincontentscripts.html#register" class="tsd-kind-icon">register</a></li>
</ul>
</section>
</div>
</section>
</section>
<section class="tsd-panel-group tsd-member-group ">
</section>
<section class="tsd-panel-group tsd-member-group ">
<h2>Methods</h2>
<section class="tsd-panel tsd-member tsd-kind-method tsd-parent-kind-class">
<a name="onmessage" class="tsd-anchor"></a>
<h3>on<wbr>Message</h3>
<ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon">on<wbr>Message<span class="tsd-signature-symbol">(</span>contentScriptId<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, callback<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Listens to a messages sent from the content script using postMessage().
See <a href="../enums/contentscripttype.html">ContentScriptType</a> for more information as well as the
<a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages">postMessage
demo</a></p>
</div>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>contentScriptId: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>callback: <span class="tsd-signature-type">any</span></h5>
</li>
</ul>
<!-- JOPLINCHANGE
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h4>
-->
</li>
</ul>
</section>
<section class="tsd-panel tsd-member tsd-kind-method tsd-parent-kind-class">
<a name="register" class="tsd-anchor"></a>
<h3>register</h3>
<ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon">register<span class="tsd-signature-symbol">(</span>type<span class="tsd-signature-symbol">: </span><a href="../enums/contentscripttype.html" class="tsd-signature-type">ContentScriptType</a>, id<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, scriptPath<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>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.</p>
</div>
<p>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.</p>
<p>The plugin generator provides a way to build any content script you might
want to package as well as its dependencies. See the <a href="https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md">Plugin Generator
doc</a>
for more information.</p>
<ul>
<li><a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script">View the renderer demo plugin</a></li>
<li><a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">View the editor demo plugin</a></li>
</ul>
<p>See also the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages">postMessage demo</a></p>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>type: <a href="../enums/contentscripttype.html" class="tsd-signature-type">ContentScriptType</a></h5>
<div class="tsd-comment tsd-typography">
<p>Defines how the script will be used. See the type definition for more information about each supported type.</p>
</div>
</li>
<li>
<h5>id: <span class="tsd-signature-type">string</span></h5>
<div class="tsd-comment tsd-typography">
<p>A unique ID for the content script.</p>
</div>
</li>
<li>
<h5>scriptPath: <span class="tsd-signature-type">string</span></h5>
<div class="tsd-comment tsd-typography">
<p>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 <code>scriptPath</code> to <code>&quot;./content_script.js</code>.</p>
</div>
</li>
</ul>
<!-- JOPLINCHANGE
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h4>
-->
</li>
</ul>
</section>
</section>
</div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
<!--
<nav class="tsd-navigation primary">
<ul>
<li class="globals ">
<a href="../globals.html"><em>Globals</em></a>
</li>
</ul>
</nav>
-->
<nav class="tsd-navigation secondary menu-sticky">
<ul class="before-current">
</ul>
<ul class="current">
<li class="current tsd-kind-class">
<a href="joplincontentscripts.html" class="tsd-kind-icon">joplin.contentScripts</a>
<ul>
<li class=" tsd-kind-constructor tsd-parent-kind-class">
<a href="joplincontentscripts.html#constructor" class="tsd-kind-icon">constructor</a>
</li>
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplincontentscripts.html#onmessage" class="tsd-kind-icon">on<wbr>Message</a>
</li>
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplincontentscripts.html#register" class="tsd-kind-icon">register</a>
</li>
</ul>
</li>
</ul>
<ul class="after-current">
</ul>
</nav>
</div>
</div>
</div>
<!-- JOPLINCHANGE
<footer class="with-border-bottom">
<div class="container">
<h2>Legend</h2>
<div class="tsd-legend-group">
<ul class="tsd-legend">
<li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li>
<li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
<li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li>
</ul>
</div>
</div>
</footer>
<div class="container tsd-generator">
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
</div>
-->
<div class="overlay"></div>
<script src="../assets/js/main.js"></script>
</body>
</html>

View File

@@ -149,45 +149,22 @@
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>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.</p>
</div>
<p>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.</p>
<p>The plugin generator provides a way to build any content script you might
want to package as well as its dependencies. See the <a href="https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md">Plugin Generator
doc</a>
for more information.</p>
<ul>
<li><a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script">View the renderer demo plugin</a></li>
<li><a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">View the editor demo plugin</a></li>
</ul>
<dl class="tsd-comment-tags">
<dt>deprecated</dt>
<dd><p>Use joplin.contentScripts.register()</p>
</dd>
</dl>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>type: <a href="../enums/contentscripttype.html" class="tsd-signature-type">ContentScriptType</a></h5>
<div class="tsd-comment tsd-typography">
<p>Defines how the script will be used. See the type definition for more information about each supported type.</p>
</div>
</li>
<li>
<h5>id: <span class="tsd-signature-type">string</span></h5>
<div class="tsd-comment tsd-typography">
<p>A unique ID for the content script.</p>
</div>
</li>
<li>
<h5>scriptPath: <span class="tsd-signature-type">string</span></h5>
<div class="tsd-comment tsd-typography">
<p>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 <code>scriptPath</code> to <code>&quot;./content_script.js</code>.</p>
</div>
</li>
</ul>
<!-- JOPLINCHANGE

View File

@@ -96,6 +96,7 @@
<h3>Methods</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinsettings.html#globalvalue" class="tsd-kind-icon">global<wbr>Value</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinsettings.html#onchange" class="tsd-kind-icon">on<wbr>Change</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinsettings.html#registersection" class="tsd-kind-icon">register<wbr>Section</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinsettings.html#registersetting" class="tsd-kind-icon">register<wbr>Setting</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinsettings.html#setvalue" class="tsd-kind-icon">set<wbr>Value</a></li>
@@ -136,6 +137,39 @@
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">&gt;</span></h4>
-->
</li>
</ul>
</section>
<section class="tsd-panel tsd-member tsd-kind-method tsd-parent-kind-class">
<a name="onchange" class="tsd-anchor"></a>
<h3>on<wbr>Change</h3>
<ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon">on<wbr>Change<span class="tsd-signature-symbol">(</span>handler<span class="tsd-signature-symbol">: </span><a href="../globals.html#changehandler" class="tsd-signature-type">ChangeHandler</a><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Called when one or multiple settings of your plugin have been changed.</p>
<ul>
<li>For performance reasons, this event is triggered with a delay.</li>
<li>You will only get events for your own plugin settings.</li>
</ul>
</div>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>handler: <a href="../globals.html#changehandler" class="tsd-signature-type">ChangeHandler</a></h5>
</li>
</ul>
<!-- JOPLINCHANGE
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h4>
-->
</li>
</ul>
@@ -293,6 +327,9 @@
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplinsettings.html#globalvalue" class="tsd-kind-icon">global<wbr>Value</a>
</li>
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplinsettings.html#onchange" class="tsd-kind-icon">on<wbr>Change</a>
</li>
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplinsettings.html#registersection" class="tsd-kind-icon">register<wbr>Section</a>
</li>

View File

@@ -217,6 +217,16 @@
<div class="lead">
<p>Called when a message is sent from the webview (using postMessage).</p>
</div>
<p>To post a message from the webview to the plugin use:</p>
<pre><code class="language-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> webviewApi.postMessage(message);</code></pre>
<ul>
<li><code>message</code> can be any JavaScript object, string or number</li>
<li><code>response</code> is whatever was returned by the <code>onMessage</code> handler</li>
</ul>
<p>Using this mechanism, you can have two-way communication between the
plugin and webview.</p>
<p>See the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages">postMessage
demo</a> for more details.</p>
</div>
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">

View File

@@ -102,6 +102,7 @@
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinworkspace.html#onnoteselectionchange" class="tsd-kind-icon">on<wbr>Note<wbr>Selection<wbr>Change</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinworkspace.html#onsynccomplete" class="tsd-kind-icon">on<wbr>Sync<wbr>Complete</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinworkspace.html#onsyncstart" class="tsd-kind-icon">on<wbr>Sync<wbr>Start</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinworkspace.html#selectedfolder" class="tsd-kind-icon">selected<wbr>Folder</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinworkspace.html#selectednote" class="tsd-kind-icon">selected<wbr>Note</a></li>
<li class="tsd-kind-method tsd-parent-kind-class"><a href="joplinworkspace.html#selectednoteids" class="tsd-kind-icon">selected<wbr>Note<wbr>Ids</a></li>
</ul>
@@ -288,6 +289,32 @@
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><a href="../interfaces/disposable.html" class="tsd-signature-type">Disposable</a><span class="tsd-signature-symbol">&gt;</span></h4>
-->
</li>
</ul>
</section>
<section class="tsd-panel tsd-member tsd-kind-method tsd-parent-kind-class">
<a name="selectedfolder" class="tsd-anchor"></a>
<h3>selected<wbr>Folder</h3>
<ul class="tsd-signatures tsd-kind-method tsd-parent-kind-class">
<li class="tsd-signature tsd-kind-icon">selected<wbr>Folder<span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">FolderEntity</span><span class="tsd-signature-symbol">&gt;</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Gets the currently selected folder. In some cases, for example during
search or when viewing a tag, no folder is actually selected in the user
interface. In that case, that function would return the last selected
folder.</p>
</div>
</div>
<!-- JOPLINCHANGE
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">FolderEntity</span><span class="tsd-signature-symbol">&gt;</span></h4>
-->
</li>
</ul>
@@ -378,6 +405,9 @@
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplinworkspace.html#onsyncstart" class="tsd-kind-icon">on<wbr>Sync<wbr>Start</a>
</li>
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplinworkspace.html#selectedfolder" class="tsd-kind-icon">selected<wbr>Folder</a>
</li>
<li class=" tsd-kind-method tsd-parent-kind-class">
<a href="joplinworkspace.html#selectednote" class="tsd-kind-icon">selected<wbr>Note</a>
</li>

View File

@@ -108,42 +108,56 @@
}
}</code></pre>
<ul>
<li><p>The <code>context</code> 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.</p>
<li><p>The <code>context</code> 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.</p>
</li>
<li><p>The <code>plugin</code> key is your CodeMirror plugin. This is where you can
register new commands with CodeMirror or interact with the
CodeMirror instance as needed.</p>
register new commands with CodeMirror or interact with the CodeMirror
instance as needed.</p>
</li>
<li><p>The <code>codeMirrorResources</code> 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&#39;s to enable clojure highlighting in code blocks.
<code>codeMirrorResources</code> would be set to <code>[&#39;mode/clojure/clojure&#39;]</code>.</p>
<li><p>The <code>codeMirrorResources</code> 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&#39;s to
enable clojure highlighting in code blocks. <code>codeMirrorResources</code> would
be set to <code>[&#39;mode/clojure/clojure&#39;]</code>.</p>
</li>
<li><p>The <code>codeMirrorOptions</code> key contains all the
<a href="https://codemirror.net/doc/manual.html#config">CodeMirror</a>
options that will be set or changed by this plugin. New options
can alse be declared via
<a href="https://codemirror.net/doc/manual.html#config">CodeMirror</a> options
that will be set or changed by this plugin. New options can alse be
declared via
<a href="https://codemirror.net/doc/manual.html#defineOption"><code>CodeMirror.defineOption</code></a>,
and then have their value set here. For example, a plugin that
enables line numbers would set <code>codeMirrorOptions</code> to
<code>{&#39;lineNumbers&#39;: true}</code>.</p>
and then have their value set here. For example, a plugin that enables
line numbers would set <code>codeMirrorOptions</code> to <code>{&#39;lineNumbers&#39;: true}</code>.</p>
</li>
<li><p>Using the <strong>optional</strong> <code>assets</code> key you may specify <strong>only</strong> CSS
assets that should be loaded in the rendered HTML document. Check
for example the Joplin [Mermaid
<li><p>Using the <strong>optional</strong> <code>assets</code> key you may specify <strong>only</strong> CSS assets
that should be loaded in the rendered HTML document. Check for example
the Joplin [Mermaid
plugin](<a href="https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts">https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts</a>)
to see how the data should be structured.</p>
</li>
</ul>
<p>One of the <code>plugin</code>, <code>codeMirrorResources</code>, or <code>codeMirrorOptions</code>
keys must be provided for the plugin to be valid. Having multiple or
all provided is also okay.</p>
<p>See the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">demo
<p>One of the <code>plugin</code>, <code>codeMirrorResources</code>, or <code>codeMirrorOptions</code> keys
must be provided for the plugin to be valid. Having multiple or all
provided is also okay.</p>
<p>See also the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">demo
plugin</a>
for an example of all these keys being used in one plugin.</p>
<a href="#posting-messages-from-the-content-script-to-your-plugin" id="posting-messages-from-the-content-script-to-your-plugin" style="color: inherit; text-decoration: none;">
<h2>Posting messages from the content script to your plugin</h2>
</a>
<p>In order to post messages to the plugin, you can use the postMessage
function passed to the <a href="../interfaces/contentscriptcontext.html">context</a>.</p>
<pre><code class="language-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> context.postMessage(<span class="hljs-string">&#x27;messageFromCodeMirrorContentScript&#x27;</span>);</code></pre>
<p>When you post a message, the plugin can send back a <code>response</code> thus
allowing two-way communication:</p>
<pre><code class="language-javascript"><span class="hljs-keyword">await</span> joplin.contentScripts.onMessage(contentScriptId, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
<span class="hljs-comment">// Process message</span>
<span class="hljs-keyword">return</span> response; <span class="hljs-comment">// Can be any object, string or number</span>
});</code></pre>
<p>See <a href="../classes/joplincontentscripts.html#onmessage">JoplinContentScripts.onMessage</a> for more details, as well as
the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages">postMessage
demo</a>.</p>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
@@ -176,43 +190,51 @@
<h2>Exported members</h2>
</a>
<ul>
<li><p>The <code>context</code> 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.</p>
<li><p>The <code>context</code> 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.</p>
</li>
<li><p>The <strong>required</strong> <code>plugin</code> key is the actual Markdown-It plugin -
check the [official
doc](<a href="https://github.com/markdown-it/markdown-it">https://github.com/markdown-it/markdown-it</a>) for more
<li><p>The <strong>required</strong> <code>plugin</code> key is the actual Markdown-It plugin - check
the <a href="https://github.com/markdown-it/markdown-it">official doc</a> for more
information. The <code>options</code> parameter is of type
<a href="https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts">RuleOptions</a>,
which contains a number of options, mostly useful for Joplin&#39;s
internal code.</p>
which contains a number of options, mostly useful for Joplin&#39;s internal
code.</p>
</li>
<li><p>Using the <strong>optional</strong> <code>assets</code> 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
<li><p>Using the <strong>optional</strong> <code>assets</code> 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](<a href="https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts">https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts</a>)
to see how the data should be structured.</p>
</li>
</ul>
<a href="#passing-messages-from-the-content-script-to-your-plugin" id="passing-messages-from-the-content-script-to-your-plugin" style="color: inherit; text-decoration: none;">
<h2>Passing messages from the content script to your plugin</h2>
<a href="#posting-messages-from-the-content-script-to-your-plugin" id="posting-messages-from-the-content-script-to-your-plugin" style="color: inherit; text-decoration: none;">
<h2>Posting messages from the content script to your plugin</h2>
</a>
<p>The application provides the following function to allow executing
commands from the rendered HTML code:</p>
<p><code>webviewApi.executeCommand(commandName, ...args)</code></p>
<p>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
<code>joplin.commands.register</code>, then you would call this command using
the <code>webviewApi</code> object. See again <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script">the
demo</a>
to see how this can be done.</p>
<pre><code class="language-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> webviewApi.postMessage(contentScriptId, message);</code></pre>
<ul>
<li><code>contentScriptId</code> is the ID you&#39;ve defined when you registered the
content script. You can retrieve it from the
<a href="../interfaces/contentscriptcontext.html">context</a>.</li>
<li><code>message</code> can be any basic JavaScript type (number, string, plain
object), but it cannot be a function or class instance.</li>
</ul>
<p>When you post a message, the plugin can send back a <code>response</code> thus
allowing two-way communication:</p>
<pre><code class="language-javascript"><span class="hljs-keyword">await</span> joplin.contentScripts.onMessage(contentScriptId, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
<span class="hljs-comment">// Process message</span>
<span class="hljs-keyword">return</span> response; <span class="hljs-comment">// Can be any object, string or number</span>
});</code></pre>
<p>See <a href="../classes/joplincontentscripts.html#onmessage">JoplinContentScripts.onMessage</a> for more details, as well as
the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages">postMessage
demo</a>.</p>
<a href="#registering-an-existing-markdown-it-plugin" id="registering-an-existing-markdown-it-plugin" style="color: inherit; text-decoration: none;">
<h2>Registering an existing Markdown-it plugin</h2>
</a>
<p>To include a regular Markdown-It plugin, that doesn&#39;t make use of
any Joplin-specific features, you would simply create a file such as
this:</p>
<p>To include a regular Markdown-It plugin, that doesn&#39;t make use of any
Joplin-specific features, you would simply create a file such as this:</p>
<pre><code class="language-javascript"><span class="hljs-built_in">module</span>.exports = {
<span class="hljs-attr">default</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{
<span class="hljs-keyword">return</span> {

View File

@@ -82,6 +82,7 @@
<ul class="tsd-index-list">
<li class="tsd-kind-class"><a href="classes/joplin.html" class="tsd-kind-icon">Joplin</a></li>
<li class="tsd-kind-class"><a href="classes/joplincommands.html" class="tsd-kind-icon">Joplin<wbr>Commands</a></li>
<li class="tsd-kind-class"><a href="classes/joplincontentscripts.html" class="tsd-kind-icon">Joplin<wbr>Content<wbr>Scripts</a></li>
<li class="tsd-kind-class"><a href="classes/joplindata.html" class="tsd-kind-icon">Joplin<wbr>Data</a></li>
<li class="tsd-kind-class"><a href="classes/joplininterop.html" class="tsd-kind-icon">Joplin<wbr>Interop</a></li>
<li class="tsd-kind-class"><a href="classes/joplinplugins.html" class="tsd-kind-icon">Joplin<wbr>Plugins</a></li>
@@ -99,7 +100,9 @@
<h3>Interfaces</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-interface"><a href="interfaces/buttonspec.html" class="tsd-kind-icon">Button<wbr>Spec</a></li>
<li class="tsd-kind-interface"><a href="interfaces/changeevent.html" class="tsd-kind-icon">Change<wbr>Event</a></li>
<li class="tsd-kind-interface"><a href="interfaces/command.html" class="tsd-kind-icon">Command</a></li>
<li class="tsd-kind-interface"><a href="interfaces/contentscriptcontext.html" class="tsd-kind-icon">Content<wbr>Script<wbr>Context</a></li>
<li class="tsd-kind-interface"><a href="interfaces/createmenuitemoptions.html" class="tsd-kind-icon">Create<wbr>Menu<wbr>Item<wbr>Options</a></li>
<li class="tsd-kind-interface"><a href="interfaces/dialogresult.html" class="tsd-kind-icon">Dialog<wbr>Result</a></li>
<li class="tsd-kind-interface"><a href="interfaces/disposable.html" class="tsd-kind-icon">Disposable</a></li>
@@ -121,8 +124,10 @@
<h3>Type aliases</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-type-alias"><a href="globals.html#buttonid" class="tsd-kind-icon">Button<wbr>Id</a></li>
<li class="tsd-kind-type-alias"><a href="globals.html#changehandler" class="tsd-kind-icon">Change<wbr>Handler</a></li>
<li class="tsd-kind-type-alias"><a href="globals.html#itemchangehandler" class="tsd-kind-icon">Item<wbr>Change<wbr>Handler</a></li>
<li class="tsd-kind-type-alias"><a href="globals.html#path" class="tsd-kind-icon">Path</a></li>
<li class="tsd-kind-type-alias"><a href="globals.html#postmessagehandler" class="tsd-kind-icon">Post<wbr>Message<wbr>Handler</a></li>
<li class="tsd-kind-type-alias"><a href="globals.html#syncstarthandler" class="tsd-kind-icon">Sync<wbr>Start<wbr>Handler</a></li>
<li class="tsd-kind-type-alias"><a href="globals.html#viewhandle" class="tsd-kind-icon">View<wbr>Handle</a></li>
</ul>
@@ -151,6 +156,38 @@
<aside class="tsd-sources">
</aside>
</section>
<section class="tsd-panel tsd-member tsd-kind-type-alias">
<a name="changehandler" class="tsd-anchor"></a>
<h3>Change<wbr>Handler</h3>
<div class="tsd-signature tsd-kind-icon">Change<wbr>Handler<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span>event<span class="tsd-signature-symbol">: </span><a href="interfaces/changeevent.html" class="tsd-signature-type">ChangeEvent</a><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">void</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-type-declaration">
<h4>Type declaration</h4>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-alias">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>event<span class="tsd-signature-symbol">: </span><a href="interfaces/changeevent.html" class="tsd-signature-type">ChangeEvent</a><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">void</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>event: <a href="interfaces/changeevent.html" class="tsd-signature-type">ChangeEvent</a></h5>
</li>
</ul>
<!-- JOPLINCHANGE
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4>
-->
</li>
</ul>
</li>
</ul>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-type-alias">
<a name="itemchangehandler" class="tsd-anchor"></a>
<h3>Item<wbr>Change<wbr>Handler</h3>
@@ -200,6 +237,41 @@
</ul>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-type-alias">
<a name="postmessagehandler" class="tsd-anchor"></a>
<h3>Post<wbr>Message<wbr>Handler</h3>
<div class="tsd-signature tsd-kind-icon">Post<wbr>Message<wbr>Handler<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span>id<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, message<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol"> =&gt; </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">&gt;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-type-declaration">
<h4>Type declaration</h4>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-alias">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span>id<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, message<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">&gt;</span></li>
</ul>
<ul class="tsd-descriptions">
<li class="tsd-description">
<h4 class="tsd-parameters-title">Parameters</h4>
<ul class="tsd-parameters">
<li>
<h5>id: <span class="tsd-signature-type">string</span></h5>
</li>
<li>
<h5>message: <span class="tsd-signature-type">any</span></h5>
</li>
</ul>
<!-- JOPLINCHANGE
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">&gt;</span></h4>
-->
</li>
</ul>
</li>
</ul>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-type-alias">
<a name="syncstarthandler" class="tsd-anchor"></a>
<h3>Sync<wbr>Start<wbr>Handler</h3>
@@ -317,6 +389,9 @@
<li class=" tsd-kind-class">
<a href="classes/joplincommands.html" class="tsd-kind-icon">joplin.commands</a>
</li>
<li class=" tsd-kind-class">
<a href="classes/joplincontentscripts.html" class="tsd-kind-icon">joplin.contentScripts</a>
</li>
<li class=" tsd-kind-class">
<a href="classes/joplindata.html" class="tsd-kind-icon">joplin.data</a>
</li>
@@ -353,9 +428,15 @@
<li class=" tsd-kind-interface">
<a href="interfaces/buttonspec.html" class="tsd-kind-icon">ButtonSpec</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/changeevent.html" class="tsd-kind-icon">ChangeEvent</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/command.html" class="tsd-kind-icon">Command</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/contentscriptcontext.html" class="tsd-kind-icon">ContentScriptContext</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/createmenuitemoptions.html" class="tsd-kind-icon">CreateMenuItemOptions</a>
</li>
@@ -404,12 +485,18 @@
<li class=" tsd-kind-type-alias">
<a href="globals.html#buttonid" class="tsd-kind-icon">ButtonId</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#changehandler" class="tsd-kind-icon">ChangeHandler</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#itemchangehandler" class="tsd-kind-icon">ItemChangeHandler</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#path" class="tsd-kind-icon">Path</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#postmessagehandler" class="tsd-kind-icon">PostMessageHandler</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#syncstarthandler" class="tsd-kind-icon">SyncStartHandler</a>
</li>

View File

@@ -107,6 +107,9 @@
<li class=" tsd-kind-class">
<a href="classes/joplincommands.html" class="tsd-kind-icon">joplin.commands</a>
</li>
<li class=" tsd-kind-class">
<a href="classes/joplincontentscripts.html" class="tsd-kind-icon">joplin.contentScripts</a>
</li>
<li class=" tsd-kind-class">
<a href="classes/joplindata.html" class="tsd-kind-icon">joplin.data</a>
</li>
@@ -143,9 +146,15 @@
<li class=" tsd-kind-interface">
<a href="interfaces/buttonspec.html" class="tsd-kind-icon">ButtonSpec</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/changeevent.html" class="tsd-kind-icon">ChangeEvent</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/command.html" class="tsd-kind-icon">Command</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/contentscriptcontext.html" class="tsd-kind-icon">ContentScriptContext</a>
</li>
<li class=" tsd-kind-interface">
<a href="interfaces/createmenuitemoptions.html" class="tsd-kind-icon">CreateMenuItemOptions</a>
</li>
@@ -194,12 +203,18 @@
<li class=" tsd-kind-type-alias">
<a href="globals.html#buttonid" class="tsd-kind-icon">ButtonId</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#changehandler" class="tsd-kind-icon">ChangeHandler</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#itemchangehandler" class="tsd-kind-icon">ItemChangeHandler</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#path" class="tsd-kind-icon">Path</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#postmessagehandler" class="tsd-kind-icon">PostMessageHandler</a>
</li>
<li class=" tsd-kind-type-alias">
<a href="globals.html#syncstarthandler" class="tsd-kind-icon">SyncStartHandler</a>
</li>

View File

@@ -0,0 +1,161 @@
<!doctype html>
<html class="default no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>ChangeEvent | Joplin Plugin API Documentation</title>
<meta name="description" content="Documentation for Joplin Plugin API Documentation">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../assets/css/main.css">
</head>
<body>
<header>
<div class="tsd-page-toolbar">
<div class="container">
<div class="table-wrap">
<div class="table-cell" id="tsd-search" data-index="../assets/js/search.json" data-base="..">
<div class="field">
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
<input id="tsd-search-field" type="text" />
</div>
<ul class="results">
<li class="state loading">Preparing search index...</li>
<li class="state failure">The search index is not available</li>
</ul>
<a href="../classes/joplin.html" class="title">Joplin Plugin API Documentation</a>
</div>
<div class="table-cell" id="tsd-widgets">
<div id="tsd-filter">
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
<div class="tsd-filter-group">
<div class="tsd-select" id="tsd-filter-visibility">
<span class="tsd-select-label">All</span>
<ul class="tsd-select-list">
<li data-value="public">Public</li>
<li data-value="protected">Public/Protected</li>
<li data-value="private" class="selected">All</li>
</ul>
</div>
<input type="checkbox" id="tsd-filter-inherited" checked />
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
</div>
</div>
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
</div>
</div>
</div>
</div>
<div class="tsd-page-title">
<div class="container">
<ul class="tsd-breadcrumb">
<!--
<li>
<a href="../globals.html">Globals</a>
</li>
-->
<li>
<a href="changeevent.html">ChangeEvent</a>
</li>
</ul>
<h1><!-- Interface -->ChangeEvent</h1>
</div>
</div>
</header>
<div class="container container-main">
<div class="row">
<div class="col-8 col-content">
<!--
<section class="tsd-panel tsd-hierarchy">
<h3>Hierarchy</h3>
<ul class="tsd-hierarchy">
<li>
<span class="target">ChangeEvent</span>
</li>
</ul>
</section>
-->
<section class="tsd-panel-group tsd-index-group">
<h2>Index</h2>
<section class="tsd-panel tsd-index-panel">
<div class="tsd-index-content">
<section class="tsd-index-section ">
<h3>Properties</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="changeevent.html#keys" class="tsd-kind-icon">keys</a></li>
</ul>
</section>
</div>
</section>
</section>
<section class="tsd-panel-group tsd-member-group ">
<h2>Properties</h2>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-interface">
<a name="keys" class="tsd-anchor"></a>
<h3>keys</h3>
<div class="tsd-signature tsd-kind-icon">keys<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span><span class="tsd-signature-symbol">[]</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Setting keys that have been changed</p>
</div>
</div>
</section>
</section>
</div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
<!--
<nav class="tsd-navigation primary">
<ul>
<li class="globals ">
<a href="../globals.html"><em>Globals</em></a>
</li>
</ul>
</nav>
-->
<nav class="tsd-navigation secondary menu-sticky">
<ul class="before-current">
</ul>
<ul class="current">
<li class="current tsd-kind-interface">
<a href="changeevent.html" class="tsd-kind-icon">ChangeEvent</a>
<ul>
<li class=" tsd-kind-property tsd-parent-kind-interface">
<a href="changeevent.html#keys" class="tsd-kind-icon">keys</a>
</li>
</ul>
</li>
</ul>
<ul class="after-current">
</ul>
</nav>
</div>
</div>
</div>
<!-- JOPLINCHANGE
<footer class="with-border-bottom">
<div class="container">
<h2>Legend</h2>
<div class="tsd-legend-group">
<ul class="tsd-legend">
<li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li>
<li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
<li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li>
</ul>
</div>
</div>
</footer>
<div class="container tsd-generator">
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
</div>
-->
<div class="overlay"></div>
<script src="../assets/js/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,200 @@
<!doctype html>
<html class="default no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>ContentScriptContext | Joplin Plugin API Documentation</title>
<meta name="description" content="Documentation for Joplin Plugin API Documentation">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../assets/css/main.css">
</head>
<body>
<header>
<div class="tsd-page-toolbar">
<div class="container">
<div class="table-wrap">
<div class="table-cell" id="tsd-search" data-index="../assets/js/search.json" data-base="..">
<div class="field">
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
<input id="tsd-search-field" type="text" />
</div>
<ul class="results">
<li class="state loading">Preparing search index...</li>
<li class="state failure">The search index is not available</li>
</ul>
<a href="../classes/joplin.html" class="title">Joplin Plugin API Documentation</a>
</div>
<div class="table-cell" id="tsd-widgets">
<div id="tsd-filter">
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
<div class="tsd-filter-group">
<div class="tsd-select" id="tsd-filter-visibility">
<span class="tsd-select-label">All</span>
<ul class="tsd-select-list">
<li data-value="public">Public</li>
<li data-value="protected">Public/Protected</li>
<li data-value="private" class="selected">All</li>
</ul>
</div>
<input type="checkbox" id="tsd-filter-inherited" checked />
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
</div>
</div>
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
</div>
</div>
</div>
</div>
<div class="tsd-page-title">
<div class="container">
<ul class="tsd-breadcrumb">
<!--
<li>
<a href="../globals.html">Globals</a>
</li>
-->
<li>
<a href="contentscriptcontext.html">ContentScriptContext</a>
</li>
</ul>
<h1><!-- Interface -->ContentScriptContext</h1>
</div>
</div>
</header>
<div class="container container-main">
<div class="row">
<div class="col-8 col-content">
<section class="tsd-panel tsd-comment">
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>When a content script is initialised, it receives a <code>context</code> object.</p>
</div>
</div>
</section>
<!--
<section class="tsd-panel tsd-hierarchy">
<h3>Hierarchy</h3>
<ul class="tsd-hierarchy">
<li>
<span class="target">ContentScriptContext</span>
</li>
</ul>
</section>
-->
<section class="tsd-panel-group tsd-index-group">
<h2>Index</h2>
<section class="tsd-panel tsd-index-panel">
<div class="tsd-index-content">
<section class="tsd-index-section ">
<h3>Properties</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="contentscriptcontext.html#contentscriptid" class="tsd-kind-icon">content<wbr>Script<wbr>Id</a></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="contentscriptcontext.html#pluginid" class="tsd-kind-icon">plugin<wbr>Id</a></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><a href="contentscriptcontext.html#postmessage" class="tsd-kind-icon">post<wbr>Message</a></li>
</ul>
</section>
</div>
</section>
</section>
<section class="tsd-panel-group tsd-member-group ">
<h2>Properties</h2>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-interface">
<a name="contentscriptid" class="tsd-anchor"></a>
<h3>content<wbr>Script<wbr>Id</h3>
<div class="tsd-signature tsd-kind-icon">content<wbr>Script<wbr>Id<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>The content script ID, which may be necessary to post messages</p>
</div>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-interface">
<a name="pluginid" class="tsd-anchor"></a>
<h3>plugin<wbr>Id</h3>
<div class="tsd-signature tsd-kind-icon">plugin<wbr>Id<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>The plugin ID that registered this content script</p>
</div>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-interface">
<a name="postmessage" class="tsd-anchor"></a>
<h3>post<wbr>Message</h3>
<div class="tsd-signature tsd-kind-icon">post<wbr>Message<span class="tsd-signature-symbol">:</span> <a href="../globals.html#postmessagehandler" class="tsd-signature-type">PostMessageHandler</a></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Can be used by CodeMirror content scripts to post a message to the plugin</p>
</div>
</div>
</section>
</section>
</div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
<!--
<nav class="tsd-navigation primary">
<ul>
<li class="globals ">
<a href="../globals.html"><em>Globals</em></a>
</li>
</ul>
</nav>
-->
<nav class="tsd-navigation secondary menu-sticky">
<ul class="before-current">
</ul>
<ul class="current">
<li class="current tsd-kind-interface">
<a href="contentscriptcontext.html" class="tsd-kind-icon">ContentScriptContext</a>
<ul>
<li class=" tsd-kind-property tsd-parent-kind-interface">
<a href="contentscriptcontext.html#contentscriptid" class="tsd-kind-icon">content<wbr>Script<wbr>Id</a>
</li>
<li class=" tsd-kind-property tsd-parent-kind-interface">
<a href="contentscriptcontext.html#pluginid" class="tsd-kind-icon">plugin<wbr>Id</a>
</li>
<li class=" tsd-kind-property tsd-parent-kind-interface">
<a href="contentscriptcontext.html#postmessage" class="tsd-kind-icon">post<wbr>Message</a>
</li>
</ul>
</li>
</ul>
<ul class="after-current">
</ul>
</nav>
</div>
</div>
</div>
<!-- JOPLINCHANGE
<footer class="with-border-bottom">
<div class="container">
<h2>Legend</h2>
<div class="tsd-legend-group">
<ul class="tsd-legend">
<li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li>
<li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
<li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li>
</ul>
</div>
</div>
</footer>
<div class="container tsd-generator">
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
</div>
-->
<div class="overlay"></div>
<script src="../assets/js/main.js"></script>
</body>
</html>

View File

@@ -455,12 +455,6 @@ https://github.com/laurent22/joplin/blob/dev/readme/api/references/plugin_manife
<td>No</td>
<td>Homepage URL of the plugin. It can also be, for example, a link to a GitHub repository.</td>
</tr>
<tr>
<td><code>content_scripts</code></td>
<td>string[]</td>
<td>No</td>
<td>List of <a href="https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md#content-scripts">content scripts</a> used by the plugin.</td>
</tr>
</tbody>
</table>
<h2>Manifest example<a name="manifest-example" href="#manifest-example" class="heading-anchor">🔗</a></h2>

View File

@@ -402,6 +402,59 @@ https://github.com/laurent22/joplin/blob/dev/readme/changelog.md
<div class="main">
<h1>Joplin changelog<a name="joplin-changelog" href="#joplin-changelog" class="heading-anchor">🔗</a></h1>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.6.6">v1.6.6</a> - 2021-01-09T16:15:31Z<a name="v1-6-6-https-github-com-laurent22-joplin-releases-tag-v1-6-6-2021-01-09t16-15-31z" href="#v1-6-6-https-github-com-laurent22-joplin-releases-tag-v1-6-6-2021-01-09t16-15-31z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add way to install plugin from file</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.5.14">v1.5.14</a> - 2020-12-30T01:48:46Z<a name="v1-5-14-https-github-com-laurent22-joplin-releases-tag-v1-5-14-2020-12-30t01-48-46z" href="#v1-5-14-https-github-com-laurent22-joplin-releases-tag-v1-5-14-2020-12-30t01-48-46z" class="heading-anchor">🔗</a></h2>
<ul>
<li>Fixed: Fixed importing ENEX files that contain hidden sections</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.5.13">v1.5.13</a> - 2020-12-29T18:29:15Z<a name="v1-5-13-https-github-com-laurent22-joplin-releases-tag-v1-5-13-2020-12-29t18-29-15z" href="#v1-5-13-https-github-com-laurent22-joplin-releases-tag-v1-5-13-2020-12-29t18-29-15z" class="heading-anchor">🔗</a></h2>
<ul>
<li>Improved: Improve support for SVG images when importing ENEX files</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.5.12">v1.5.12</a> - 2020-12-28T15:14:08Z<a name="v1-5-12-https-github-com-laurent22-joplin-releases-tag-v1-5-12-2020-12-28t15-14-08z" href="#v1-5-12-https-github-com-laurent22-joplin-releases-tag-v1-5-12-2020-12-28t15-14-08z" class="heading-anchor">🔗</a></h2>
<p>Fixed ENEX import regression: Fix issue when importing ENEX file that contains invalid list elements</p>
<ul>
<li>New: Add support for media players (video, audio and PDF)</li>
<li>New: Add table captions when importing ENEX files</li>
<li>New: Added doc about Rich Text editor and added way to dismiss warning banner</li>
<li>New: MacOS: Notarize application</li>
<li>New: Plugins: Add support for content script asset files, for Markdown-it plugins</li>
<li>New: Plugins: Add support for context menu items on notebooks and tags</li>
<li>New: Plugins: Add support for workspace.onSyncStart event</li>
<li>New: Plugins: Added a way to execute commands from Markdown-it content scripts</li>
<li>Fixed: Fix End key behavior with Codemirror spellcheck (<a href="https://github.com/laurent22/joplin/issues/4215">#4215</a> by Caleb John)</li>
<li>Fixed: Fixed basic search when executing a query in Chinese (<a href="https://github.com/laurent22/joplin/issues/4034">#4034</a> by Naveen M V)</li>
<li>Fixed: Fixed context menu when the UI is zoomed in or out (<a href="https://github.com/laurent22/joplin/issues/4201">#4201</a>)</li>
<li>Fixed: Fixed importing certain code blocks from ENEX</li>
<li>Fixed: Fixed importing ENEX files that contain empty resources</li>
<li>Fixed: Fixed importing ENEX files that contain resources with invalid mime type</li>
<li>Fixed: Fixed issue when searching for text that contains diacritic (<a href="https://github.com/laurent22/joplin/issues/4152">#4152</a>) (<a href="https://github.com/laurent22/joplin/issues/4025">#4025</a> by Roman Musin)</li>
<li>Fixed: Fixed issue with attachment paths being invalid when user has spaces in home directory path.</li>
<li>Fixed: Fixed issue with note not being saved when a column is added or remove from Rich Text editor</li>
<li>Fixed: Fixed issues when importing hidden tables within hidden sections in Enex files</li>
<li>Fixed: Fixed numbered list bug in markdown editor (<a href="https://github.com/laurent22/joplin/issues/4116">#4116</a>) (<a href="https://github.com/laurent22/joplin/issues/3917">#3917</a> by <a href="https://github.com/MichBoi">@MichBoi</a>)</li>
<li>Fixed: Fixed potential crash when watching note files or resources</li>
<li>Fixed: Fixed title input field width on small windows</li>
<li>Fixed: Focus editor after pressing toolbar buttons (<a href="https://github.com/laurent22/joplin/issues/4037">#4037</a>) (<a href="https://github.com/laurent22/joplin/issues/4036">#4036</a> by <a href="https://github.com/CalebJohn">@CalebJohn</a>)</li>
<li>Fixed: Plugins: Fixed disabling plugin files that start with &quot;_&quot;</li>
<li>Fixed: Prevent double paste when using Shift+Ctrl+V (<a href="https://github.com/laurent22/joplin/issues/4243">#4243</a>)</li>
<li>Fixed: Prevents crash when invalid spell checker language is selected, and provide fallback for invalid language codes (<a href="https://github.com/laurent22/joplin/issues/4146">#4146</a>)</li>
<li>Fixed: Register Markdown editor commands with the Keyboard Shortcut editor (<a href="https://github.com/laurent22/joplin/issues/4136">#4136</a>) (<a href="https://github.com/laurent22/joplin/issues/4130">#4130</a> by Caleb John)</li>
<li>Improved: Display Katex parsing errors</li>
<li>Improved: Improved warning banner colors</li>
<li>Improved: Plugins: Commands would not show up in keymap editor when no shortcut was associated with them</li>
<li>Improved: Plugins: Improved note change event handling.</li>
<li>Improved: Removed warning for Markdown editor spell checking</li>
<li>Improved: Restrict auto-detection of links, and added option to toggle linkify (<a href="https://github.com/laurent22/joplin/issues/4205">#4205</a>)</li>
<li>Improved: Rich Text: Do not converts to markdown links URLs that would be linkified</li>
<li>Improved: Translation: Update zh_CN (<a href="https://github.com/laurent22/joplin/issues/4195">#4195</a> by Zhang YANG)</li>
<li>Improved: Update macOS icon for macOS Big Sur</li>
<li>Improved: Update Mermaid: 8.8.1 -&gt; 8.8.4 (<a href="https://github.com/laurent22/joplin/issues/4193">#4193</a> by Helmut K. C. Tessarek)</li>
<li>Improved: Use plugins whenever printing or exporting notes</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.5.11">v1.5.11</a> - 2020-12-27T19:54:07Z<a name="v1-5-11-https-github-com-laurent22-joplin-releases-tag-v1-5-11-2020-12-27t19-54-07z" href="#v1-5-11-https-github-com-laurent22-joplin-releases-tag-v1-5-11-2020-12-27t19-54-07z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add support for media players (video, audio and PDF)</li>

View File

@@ -402,6 +402,28 @@ https://github.com/laurent22/joplin/blob/dev/readme/changelog_cli.md
<div class="main">
<h1>Joplin terminal app changelog<a name="joplin-terminal-app-changelog" href="#joplin-terminal-app-changelog" class="heading-anchor">🔗</a></h1>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.6.3">cli-v1.6.3</a> - 2021-01-11T11:52:11Z<a name="cli-v1-6-3-https-github-com-laurent22-joplin-releases-tag-cli-v1-6-3-2021-01-11t11-52-11z" href="#cli-v1-6-3-https-github-com-laurent22-joplin-releases-tag-cli-v1-6-3-2021-01-11t11-52-11z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add more log info when a revision cannot be deleted due to still-encrypted itel</li>
<li>Improved: Do not display error message when fixing ENEX resource mime type (#4310)</li>
<li>Improved: Improve support for SVG images when importing ENEX files</li>
<li>Improved: Improved support for bold and italic format when importing ENEX file (#4316)</li>
<li>Improved: Support natural sorting by title (#4272 by <a href="https://github.com/volatilevar">@volatilevar</a>)</li>
<li>Improved: Upload Big Notes to Onedrive (#4120) (#3528 by Jonathan Heard)</li>
<li>Fixed: Fixed OneDrive issue that would require a full resync every time (#4324) (#4313 by Jonathan Heard)</li>
<li>Fixed: Fixed importing ENEX files that contain hidden sections</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.6.2">cli-v1.6.2</a> - 2021-01-11T11:41:56Z<a name="cli-v1-6-2-https-github-com-laurent22-joplin-releases-tag-cli-v1-6-2-2021-01-11t11-41-56z" href="#cli-v1-6-2-https-github-com-laurent22-joplin-releases-tag-cli-v1-6-2-2021-01-11t11-41-56z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add more log info when a revision cannot be deleted due to still-encrypted item</li>
<li>Improved: Do not display error message when fixing ENEX resource mime type (#4310)</li>
<li>Improved: Improve support for SVG images when importing ENEX files</li>
<li>Improved: Improved support for bold and italic format when importing ENEX file (#4316)</li>
<li>Improved: Support natural sorting by title (#4272 by <a href="https://github.com/volatilevar">@volatilevar</a>)</li>
<li>Improved: Upload Big Notes to Onedrive (#4120) (#3528 by Jonathan Heard)</li>
<li>Fixed: Fixed OneDrive issue that would require a full resync every time (#4324) (#4313 by Jonathan Heard)</li>
<li>Fixed: Fixed importing ENEX files that contain hidden sections</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.5.1">cli-v1.5.1</a> - 2020-12-26T00:46:31Z<a name="cli-v1-5-1-https-github-com-laurent22-joplin-releases-tag-cli-v1-5-1-2020-12-26t00-46-31z" href="#cli-v1-5-1-https-github-com-laurent22-joplin-releases-tag-cli-v1-5-1-2020-12-26t00-46-31z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add table captions when importing ENEX files</li>

View File

@@ -406,7 +406,7 @@ https://github.com/laurent22/joplin/blob/dev/readme/clipper.md
<img src="https://joplinapp.org/images/WebExtensionScreenshot.png" style="max-width: 50%; border: 1px solid gray;">
<h1>Troubleshooting the web clipper service<a name="troubleshooting-the-web-clipper-service" href="#troubleshooting-the-web-clipper-service" class="heading-anchor">🔗</a></h1>
<p>The web clipper extension and the Joplin application communicates via a service, which is started by the Joplin desktop app.</p>
<p>However certain things can interfer with this service and prevent it from being accessible or from starting. If something does not work, check the following:</p>
<p>However certain things can interfere with this service and prevent it from being accessible or from starting. If something does not work, check the following:</p>
<ul>
<li>Check that the service is started. You can check this in the Web clipper options in the desktop app.</li>
<li>Check that the port used by the service is not blocked by a firewall. You can find the port number in the Web clipper options in the desktop Joplin application.</li>

View File

@@ -421,19 +421,19 @@ https://github.com/laurent22/joplin/blob/dev/README.md
<tbody>
<tr>
<td>Windows (32 and 64-bit)</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-Setup-1.5.11.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/Joplin-Setup-1.6.6.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a></td>
</tr>
<tr>
<td>macOS</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/Joplin-1.6.6.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a></td>
</tr>
<tr>
<td>Linux</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/Joplin-1.6.6.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a></td>
</tr>
</tbody>
</table>
<p><strong>On Windows</strong>, you may also use the <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/JoplinPortable.exe'>Portable version</a>. The <a href="https://en.wikipedia.org/wiki/Portable_application">portable application</a> allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called &quot;JoplinProfile&quot; next to the executable file.</p>
<p><strong>On Windows</strong>, you may also use the <a href='https://github.com/laurent22/joplin/releases/download/v1.6.6/JoplinPortable.exe'>Portable version</a>. The <a href="https://en.wikipedia.org/wiki/Portable_application">portable application</a> allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called &quot;JoplinProfile&quot; next to the executable file.</p>
<p><strong>On Linux</strong>, the recommended way is to use the following installation script as it will handle the desktop icon too:</p>
<pre><code style="word-break: break-all">wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh | bash</code></pre>
<h2>Mobile applications<a name="mobile-applications" href="#mobile-applications" class="heading-anchor">🔗</a></h2>
@@ -612,6 +612,7 @@ https://github.com/laurent22/joplin/blob/dev/README.md
<li><a href="https://owncloud.org/">OwnCloud</a></li>
<li><a href="https://www.seafile.com/">Seafile</a></li>
<li><a href="https://www.transip.nl/stack/">Stack</a></li>
<li><a href="https://www.synology.com/en-us/dsm/packages/WebDAVServer">Synology WebDAV Server</a></li>
<li><a href="https://www.schimera.com/products/webdav-nav-server/">WebDAV Nav</a>, a macOS server.</li>
<li><a href="https://www.zimbra.com/">Zimbra</a></li>
</ul>

View File

@@ -642,6 +642,20 @@ graph TD;
<td><a href="https://joplinapp.org/images/md_plugins/katex_plugin.jpg">View</a></td>
</tr>
<tr>
<td><a href="https://fountain.io">Fountain</a></td>
<td><code>```fountain</code><br/>Your screenplay...<br/><code>```</code></td>
<td>Adds support for the Fountain markup language, a plain text markup language for screenwriting</td>
<td>no</td>
<td><a href="https://joplinapp.org/images/md_plugins/fountain_plugin.jpg">View</a></td>
</tr>
<tr>
<td><a href="https://mermaid-js.github.io/mermaid/">Mermaid</a></td>
<td><code>```mermaid</code><br/>mermaid syntax...<br/><code>```</code></td>
<td>See <a href="https://mermaid-js.github.io/mermaid/#/examples">plugin page</a> for full description</td>
<td>no</td>
<td><a href="https://joplinapp.org/images/md_plugins/mermaid.jpg">View</a></td>
</tr>
<tr>
<td><a href="https://github.com/markdown-it/markdown-it-mark">Mark</a></td>
<td><code>==marked==</code></td>
<td>Transforms into <code>&lt;mark&gt;marked&lt;/mark&gt;</code> (highlighted)</td>
@@ -711,20 +725,6 @@ graph TD;
<td>no</td>
<td><a href="https://joplinapp.org/images/md_plugins/multitable_plugin.jpg">View</a></td>
</tr>
<tr>
<td><a href="https://fountain.io">Fountain</a></td>
<td><code>```fountain</code><br/>Your screenplay...<br/><code>```</code></td>
<td>Adds support for the Fountain markup language, a plain text markup language for screenwriting</td>
<td>no</td>
<td><a href="https://joplinapp.org/images/md_plugins/fountain_plugin.jpg">View</a></td>
</tr>
<tr>
<td><a href="https://mermaid-js.github.io/mermaid/">Mermaid</a></td>
<td><code>```mermaid</code><br/>mermaid syntax...<br/><code>```</code></td>
<td>See <a href="https://mermaid-js.github.io/mermaid/#/examples">plugin page</a> for full description</td>
<td>no</td>
<td><a href="https://joplinapp.org/images/md_plugins/mermaid.jpg">View</a></td>
</tr>
</tbody>
</table>

View File

@@ -419,6 +419,9 @@ https://github.com/laurent22/joplin/blob/dev/readme/rich_text_editor.md
<li>
<p>All items in a list must be of the same type, so for example all checkboxes, or all bullet points. If you require two different types, you should create two different lists separated by an horizontal rule or similar.</p>
</li>
<li>
<p>Special keyboard modes &quot;vim&quot; and &quot;emacs&quot; are not supported.</p>
</li>
</ul>
<p>Those are the known limitations but if you notice any other issue not listed here, please let us know <a href="https://discourse.joplinapp.org/">in the forum</a>.</p>

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,15 @@
module.exports = {
'**/*.ts?(x)': () => 'npm run tsc',
// Don't compile when committing as it will process all TS files in the
// monorepo, which is too slow. Errors should be checked during development
// using `npm run watch`.
//
// Or if we add this back, we could do something like this:
// https://stackoverflow.com/a/44748041/561309
//
// The script would check where the TS file is located, then use the right
// tsconfig.json file along with the tsconfig override.
//
// '**/*.ts?(x)': () => 'npm run tsc',
'*.{js,jsx,ts,tsx}': [
'npm run linter-precommit',
'git add',

View File

@@ -8,6 +8,7 @@
"license": "MIT",
"scripts": {
"bootstrap": "lerna bootstrap --no-ci",
"bootstrapServerOnly": "lerna bootstrap --no-ci --include-dependents --include-dependencies --scope @joplin/server",
"bootstrapIgnoreScripts": "lerna bootstrap --ignore-scripts --no-ci",
"build": "lerna run build && npm run tsc",
"buildApiDoc": "npm start --prefix=packages/app-cli -- apidoc ../../readme/api/references/rest_api.md",
@@ -24,8 +25,9 @@
"linter-precommit": "./node_modules/.bin/eslint --resolve-plugins-relative-to . --fix --ext .js --ext .jsx --ext .ts --ext .tsx",
"linter": "./node_modules/.bin/eslint --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
"postinstall": "npm run bootstrap --no-ci && npm run build",
"publishAll": "git pull && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
"releaseAndroid": "node packages/tools/release-android.js",
"publishAll": "git pull && npm run build && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
"releaseAndroidClean": "node packages/tools/release-android.js",
"releaseAndroid": "export PATH=\"/usr/local/opt/openjdk@11/bin:$PATH\" && node packages/tools/release-android.js",
"releaseCli": "node packages/tools/release-cli.js",
"releaseClipper": "node packages/tools/release-clipper.js",
"releaseDesktop": "node packages/tools/release-electron.js",

View File

@@ -1,22 +1,8 @@
const gulp = require('gulp');
const fs = require('fs-extra');
const utils = require('@joplin/tools/gulp/utils');
const { setPackagePrivateField } = require('@joplin/tools/tool-utils');
const tasks = {
// compileExtensions: {
// fn: require('../Tools/gulp/tasks/compileExtensions.js'),
// },
// copyLib: require('../Tools/gulp/tasks/copyLib'),
// tsc: require('../Tools/gulp/tasks/tsc'),
// updateIgnoredTypeScriptBuild: require('../Tools/gulp/tasks/updateIgnoredTypeScriptBuild'),
};
// async function makePackagePublic(filePath) {
// const text = await fs.readFile(filePath, 'utf8');
// const obj = JSON.parse(text);
// delete obj.private;
// await fs.writeFile(filePath, JSON.stringify(obj), 'utf8');
// }
const tasks = {};
tasks.prepareBuild = {
fn: async () => {
@@ -26,8 +12,7 @@ tasks.prepareBuild = {
});
await utils.copyFile(`${__dirname}/package.json`, `${buildDir}/package.json`);
// await makePackagePublic(`${buildDir}/package.json`);
await setPackagePrivateField(`${buildDir}/package.json`, false);
await utils.setPackagePrivateField(`${buildDir}/package.json`, false);
await utils.copyFile(`${__dirname}/package-lock.json`, `${buildDir}/package-lock.json`);
await utils.copyFile(`${__dirname}/gulpfile.js`, `${buildDir}/gulpfile.js`);
@@ -50,14 +35,6 @@ tasks.prepareTestBuild = {
],
});
// const rootDir = utils.rootDir();
// await utils.copyDir(`${rootDir}/packages/app-mobile/lib`, `${testBuildDir}/lib`, {
// excluded: [
// `${rootDir}/packages/renderer/node_modules`,
// ],
// });
// await utils.copyDir(`${rootDir}/packages/app-mobile/locales`, `${testBuildDir}/locales`);
await fs.mkdirp(`${testBuildDir}/data`);
},
};
@@ -67,12 +44,4 @@ utils.registerGulpTasks(gulp, tasks);
gulp.task('build', gulp.series([
'prepareBuild',
// 'compileExtensions',
// 'copyLib',
]));
// gulp.task('buildTests', gulp.series([
// // 'prepareTestBuild',
// // 'compileExtensions',
// // 'copyLib',
// ]));

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "1.5.1",
"version": "1.6.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -31,7 +31,7 @@
],
"owner": "Laurent Cozic"
},
"version": "1.6.0",
"version": "1.7.0",
"bin": {
"joplin": "./main.js"
},
@@ -39,8 +39,8 @@
"node": ">=10.0.0"
},
"dependencies": {
"@joplin/lib": "^1.0.9",
"@joplin/renderer": "^1.0.17",
"@joplin/lib": "*",
"@joplin/renderer": "*",
"aws-sdk": "^2.588.0",
"chalk": "^4.1.0",
"clean-html": "^1.5.0",

View File

@@ -27,17 +27,22 @@ describe('InMemoryCache', function() {
await time.msleep(510);
expect(cache.value('test')).toBe(undefined);
// Check that the TTL is reset every time setValue is called
cache.setValue('test', 'something', 300);
await time.msleep(100);
cache.setValue('test', 'something', 300);
await time.msleep(100);
cache.setValue('test', 'something', 300);
await time.msleep(100);
cache.setValue('test', 'something', 300);
await time.msleep(100);
// This test can sometimes fail in some cases, probably because it
// sleeps for more than 100ms (when the computer is slow). Changing this
// to use higher values would slow down the test unit too much, so let's
// disable it for now.
expect(cache.value('test')).toBe('something');
// Check that the TTL is reset every time setValue is called
// cache.setValue('test', 'something', 300);
// await time.msleep(100);
// cache.setValue('test', 'something', 300);
// await time.msleep(100);
// cache.setValue('test', 'something', 300);
// await time.msleep(100);
// cache.setValue('test', 'something', 300);
// await time.msleep(100);
// expect(cache.value('test')).toBe('something');
});
it('should delete old records', async () => {

View File

@@ -1,4 +1,6 @@
This is visible
This too<div style="display: none;">This is hidden
and this sub-tag **too**
</div>This is visible again
</div>
This is visible again

View File

@@ -9,3 +9,9 @@
<div><span style="font-weight: bold;">singleline bold text with span style font-weight: bold; and with trailing space </span>next to normal text.</div><div><br/></div>
<div><span style="font-weight: bold;">singleline bold text with span style font-weight: bold;</span><span style="font-weight: bold;"> next to more bold text with span style font-weight: bold; and with leading space.</span></div><div><br/></div>
<div><span style="font-weight: bold;">singleline bold text with span style font-weight: bold; and with trailing space </span><span style="font-weight: bold;">next to more bold text with span style font-weight: bold;.</span></div>
<div><span style="font-weight:bold;">bold no space</span></div>
<div><span style="font-weight:700;">bold 700</span></div>
<div><span style="font-weight:800;">bold 800</span></div>
<div><span style="font-weight:900;">bold 900</span></div>
<div><span style="font-weight:500;">not bold</span></div>

View File

@@ -12,4 +12,10 @@
**singleline bold text with span style font-weight: bold;**** next to more bold text with span style font-weight: bold; and with leading space.**
**singleline bold text with span style font-weight: bold; and with trailing space ****next to more bold text with span style font-weight: bold;.**
**singleline bold text with span style font-weight: bold; and with trailing space ****next to more bold text with span style font-weight: bold;.**
**bold no space**
**bold 700**
**bold 800**
**bold 900**
not bold

View File

@@ -271,4 +271,48 @@ describe('models_Note', function() {
expect(result).toBe(`[](:/${note1.id})`);
}));
it('should perform natural sorting', (async () => {
const folder1 = await Folder.save({});
const sortedNotes = await Note.previews(folder1.id, {
fields: ['id', 'title'],
order: [{ by: 'title', dir: 'ASC' }],
});
expect(sortedNotes.length).toBe(0);
const note0 = await Note.save({ title: 'A3', parent_id: folder1.id, is_todo: false });
const note1 = await Note.save({ title: 'A20', parent_id: folder1.id, is_todo: false });
const note2 = await Note.save({ title: 'A100', parent_id: folder1.id, is_todo: false });
const note3 = await Note.save({ title: 'égalité', parent_id: folder1.id, is_todo: false });
const note4 = await Note.save({ title: 'z', parent_id: folder1.id, is_todo: false });
const sortedNotes2 = await Note.previews(folder1.id, {
fields: ['id', 'title'],
order: [{ by: 'title', dir: 'ASC' }],
});
expect(sortedNotes2.length).toBe(5);
expect(sortedNotes2[0].id).toBe(note0.id);
expect(sortedNotes2[1].id).toBe(note1.id);
expect(sortedNotes2[2].id).toBe(note2.id);
expect(sortedNotes2[3].id).toBe(note3.id);
expect(sortedNotes2[4].id).toBe(note4.id);
const todo3 = Note.changeNoteType(note3, 'todo');
const todo4 = Note.changeNoteType(note4, 'todo');
await Note.save(todo3);
await Note.save(todo4);
const sortedNotes3 = await Note.previews(folder1.id, {
fields: ['id', 'title'],
order: [{ by: 'title', dir: 'ASC' }],
uncompletedTodosOnTop: true,
});
expect(sortedNotes3.length).toBe(5);
expect(sortedNotes3[0].id).toBe(note3.id);
expect(sortedNotes3[1].id).toBe(note4.id);
expect(sortedNotes3[2].id).toBe(note0.id);
expect(sortedNotes3[3].id).toBe(note1.id);
expect(sortedNotes3[4].id).toBe(note2.id);
}));
});

View File

@@ -66,14 +66,14 @@ describe('pathUtils', function() {
it('should create correct fileURL syntax', (async () => {
const testCases_win32 = [
['C:\\handle\\space test', 'file:///C:/handle/space+test'],
['C:\\handle\\space test', 'file:///C:/handle/space%20test'],
['C:\\escapeplus\\+', 'file:///C:/escapeplus/%2B'],
['C:\\handle\\single quote\'', 'file:///C:/handle/single+quote%27'],
['C:\\handle\\single quote\'', 'file:///C:/handle/single%20quote%27'],
];
const testCases_unixlike = [
['/handle/space test', 'file:///handle/space+test'],
['/handle/space test', 'file:///handle/space%20test'],
['/escapeplus/+', 'file:///escapeplus/%2B'],
['/handle/single quote\'', 'file:///handle/single+quote%27'],
['/handle/single quote\'', 'file:///handle/single%20quote%27'],
];
for (let i = 0; i < testCases_win32.length; i++) {

View File

@@ -0,0 +1,56 @@
import RepositoryApi from '@joplin/lib/services/plugins/RepositoryApi';
import shim from '@joplin/lib/shim';
import { setupDatabaseAndSynchronizer, switchClient, supportDir, createTempDir } from '../../test-utils';
async function newRepoApi(): Promise<RepositoryApi> {
const repo = new RepositoryApi(`${supportDir}/pluginRepo`, await createTempDir());
await repo.loadManifests();
return repo;
}
describe('services_plugins_RepositoryApi', function() {
beforeEach(async (done: Function) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
it('should get the manifests', (async () => {
const api = await newRepoApi();
const manifests = await api.manifests();
expect(!!manifests.find(m => m.id === 'joplin.plugin.ambrt.backlinksToNote')).toBe(true);
expect(!!manifests.find(m => m.id === 'org.joplinapp.plugins.ToggleSidebars')).toBe(true);
}));
it('should search', (async () => {
const api = await newRepoApi();
{
const results = await api.search('to');
expect(results.length).toBe(2);
expect(!!results.find(m => m.id === 'joplin.plugin.ambrt.backlinksToNote')).toBe(true);
expect(!!results.find(m => m.id === 'org.joplinapp.plugins.ToggleSidebars')).toBe(true);
}
{
const results = await api.search('backlink');
expect(results.length).toBe(1);
expect(!!results.find(m => m.id === 'joplin.plugin.ambrt.backlinksToNote')).toBe(true);
}
}));
it('should download a plugin', (async () => {
const api = await newRepoApi();
const pluginPath = await api.downloadPlugin('org.joplinapp.plugins.ToggleSidebars');
expect(await shim.fsDriver().exists(pluginPath)).toBe(true);
}));
it('should tell if a plugin can be updated', (async () => {
const api = await newRepoApi();
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.0')).toBe(true);
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.2')).toBe(false);
expect(await api.pluginCanBeUpdated('does.not.exist', '1.0.0')).toBe(false);
}));
});

View File

@@ -0,0 +1,69 @@
import Setting from '@joplin/lib/models/Setting';
import PluginService from '@joplin/lib/services/plugins/PluginService';
const { waitForFolderCount, newPluginService, newPluginScript, setupDatabaseAndSynchronizer, switchClient, afterEachCleanUp } = require('../../../test-utils');
const Folder = require('@joplin/lib/models/Folder');
describe('JoplinSettings', () => {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
afterEach(async () => {
await afterEachCleanUp();
});
test('should listen to setting change event', async () => {
const service = new newPluginService() as PluginService;
const pluginScript = newPluginScript(`
joplin.plugins.register({
onStart: async function() {
await joplin.settings.registerSetting('myCustomSetting1', {
value: 1,
type: 1,
public: true,
label: 'My Custom Setting 1',
});
await joplin.settings.registerSetting('myCustomSetting2', {
value: 2,
type: 1,
public: true,
label: 'My Custom Setting 2',
});
joplin.settings.onChange((event) => {
joplin.data.post(['folders'], null, { title: JSON.stringify(event.keys) });
});
},
});
`);
const plugin = await service.loadPluginFromJsBundle('', pluginScript);
await service.runPlugin(plugin);
Setting.setValue('plugin-org.joplinapp.plugins.PluginTest.myCustomSetting1', 111);
Setting.setValue('plugin-org.joplinapp.plugins.PluginTest.myCustomSetting2', 222);
// Also change a global setting, to verify that the plugin doesn't get
// notifications for non-plugin related events.
Setting.setValue('locale', 'fr_FR');
Setting.emitScheduledChangeEvent();
await waitForFolderCount(1);
const folder = (await Folder.all())[0];
const settingNames: string[] = JSON.parse(folder.title);
settingNames.sort();
expect(settingNames.join(',')).toBe('myCustomSetting1,myCustomSetting2');
await service.destroy();
});
});

View File

@@ -192,7 +192,7 @@ describe('services_PluginService', function() {
joplin.plugins.register({
onStart: async function() {
await joplin.plugins.registerContentScript('markdownItPlugin', 'justtesting', './markdownItTestPlugin.js');
await joplin.contentScripts.register('markdownItPlugin', 'justtesting', './markdownItTestPlugin.js');
},
});
`);

View File

@@ -0,0 +1,25 @@
# Joplin Plugin Repository
This is the official Joplin Plugin Repository
## Installation
To install any of these plugins, open the desktop application, then go to the "Plugins" section in the Configuration screen. You can then search for any plugin and install it from there.
## Plugins
This repository contains the following plugins:
<!-- PLUGIN_LIST -->
&nbsp; | Name | Version | Description | Author
--- | --- | --- | --- | ---
[🏠](https://discourse.joplinapp.org/t/insert-referencing-notes-backlinks-plugin/13632) | Backlinks to note | 1.0.4 | Creates backlinks to opened note | a
[🏠](https://github.com/JackGruber/joplin-plugin-combine-notes) | Combine notes | 0.2.1 | Combine one or more notes | JackGruber
[🏠](https://github.com/JackGruber/joplin-plugin-copytags) | Copy Tags | 0.3.2 | Plugin to extend the Joplin tagging menu with a coppy all tags and tagging list with more control. | JackGruber
[🏠](https://discourse.joplinapp.org/t/go-to-note-tag-or-notebook-via-highlighting-text-in-editor/12731) | Create and go to #tags and @notebooks | 1.3.4 | Go to tag,notebook or note via links or via text | a
[🏠](https://github.com/benji300/joplin-favorites) | Favorites | 1.0.0 | Save any notebook, note, to-do, tag, or search as favorite in an extra panel view for quick access. (v1.0.0) | Benji300
[🏠](https://github.com/laurent22/joplin/tree/dev/packages/plugins/ToggleSidebars) | Note list and side bar toggle buttons | 1.0.2 | Adds buttons to toggle note list and sidebar | Laurent Cozic
[🏠](https://github.com/JackGruber/joplin-plugin-note-overview) | Note overview | 1.0.0 | A note overview is created based on the defined search and the specified fields | JackGruber
[🏠](https://github.com/benji300/joplin-note-tabs) | Note Tabs | 1.1.1 | Allows to open several notes at once in tabs and pin them. (v1.1.1) | Benji300
[🏠](https://github.com/JackGruber/joplin-plugin-backup) | Simple Backup | 0.3.0 | Plugin to create manual and automatic backups | JackGruber
<!-- PLUGIN_LIST -->

View File

@@ -0,0 +1,29 @@
{
"joplin.plugin.ambrt.backlinksToNote": {
"manifest_version": 1,
"id": "joplin.plugin.ambrt.backlinksToNote",
"app_min_version": "1.5",
"version": "1.0.4",
"name": "Backlinks to note",
"description": "Creates backlinks to opened note",
"author": "a",
"homepage_url": "https://discourse.joplinapp.org/t/insert-referencing-notes-backlinks-plugin/13632",
"_publish_hash": "sha256:ab9c9bc776e167a3b1a9ec40a4927d93da14514c0508f46dd6e5ea3f8a3a6c3b",
"_publish_commit": "master:5b74f93c687463572c46200292fa911e0ba96033",
"_npm_package_name": "joplin-plugin-backlinks"
},
"org.joplinapp.plugins.ToggleSidebars": {
"manifest_version": 1,
"id": "org.joplinapp.plugins.ToggleSidebars",
"app_min_version": "1.6",
"version": "1.0.2",
"name": "Note list and side bar toggle buttons",
"description": "Adds buttons to toggle note list and sidebar",
"author": "Laurent Cozic",
"homepage_url": "https://github.com/laurent22/joplin/tree/dev/packages/plugins/ToggleSidebars",
"repository_url": "https://github.com/laurent22/joplin/tree/dev/packages/plugins/ToggleSidebars",
"_publish_hash": "sha256:e0d833b7ef1bb8f02ee4cb861ef1989621358c45a5614911071302dc0527a3b4",
"_publish_commit": "dev:1b5b2342fc25717b77ad9f1627c1a334e5bbae54",
"_npm_package_name": "@joplin/joplin-plugin-toggle-sidebars"
}
}

View File

@@ -0,0 +1,13 @@
{
"manifest_version": 1,
"id": "joplin.plugin.ambrt.backlinksToNote",
"app_min_version": "1.5",
"version": "1.0.4",
"name": "Backlinks to note",
"description": "Creates backlinks to opened note",
"author": "a",
"homepage_url": "https://discourse.joplinapp.org/t/insert-referencing-notes-backlinks-plugin/13632",
"_publish_hash": "sha256:ab9c9bc776e167a3b1a9ec40a4927d93da14514c0508f46dd6e5ea3f8a3a6c3b",
"_publish_commit": "master:5b74f93c687463572c46200292fa911e0ba96033",
"_npm_package_name": "joplin-plugin-backlinks"
}

View File

@@ -0,0 +1,14 @@
{
"manifest_version": 1,
"id": "org.joplinapp.plugins.ToggleSidebars",
"app_min_version": "1.6",
"version": "1.0.2",
"name": "Note list and side bar toggle buttons",
"description": "Adds buttons to toggle note list and sidebar",
"author": "Laurent Cozic",
"homepage_url": "https://github.com/laurent22/joplin/tree/dev/packages/plugins/ToggleSidebars",
"repository_url": "https://github.com/laurent22/joplin/tree/dev/packages/plugins/ToggleSidebars",
"_publish_hash": "sha256:e0d833b7ef1bb8f02ee4cb861ef1989621358c45a5614911071302dc0527a3b4",
"_publish_commit": "dev:1b5b2342fc25717b77ad9f1627c1a334e5bbae54",
"_npm_package_name": "@joplin/joplin-plugin-toggle-sidebars"
}

View File

@@ -1,3 +1,10 @@
dist/
node_modules/
publish/
dist/*
*.jpl

View File

@@ -29,6 +29,8 @@ The main two files you will want to look at are:
- `/src/index.ts`, which contains the entry point for the plugin source code.
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
The file `/plugin.config.json` could also be useful if you intend to use [external scripts](#external-script-files), such as content scripts or webview scripts.
## Building the plugin
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
@@ -49,44 +51,21 @@ In general all this is done automatically by the plugin generator, which will se
## Updating the plugin framework
To update the plugin framework, run `yo joplin --update`
To update the plugin framework, run `npm run update`.
Keep in mind that doing so will overwrite all the framework-related files **outside of the "src/" directory** (your source code will not be touched). So if you have modified any of the framework-related files, such as package.json or .gitignore, make sure your code is under version control so that you can check the diff and re-apply your changes.
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
For that reason, it's generally best not to change any of the framework files or to do so in a way that minimises the number of changes. For example, if you want to modify the Webpack config, create a new separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
## Content scripts
## External script files
A plugin that uses [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) must declare them under the `content_scripts` key of [manifest.json](https://joplinapp.org/api/references/plugin_manifest/).
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:
Each entry must be a path **relative to /src**, and **without extension**. The extension should not be included because it might change once the script is compiled. Each of these scripts will then be compiled to JavaScript and packaged into the plugin file. The content script files can be TypeScript (.ts or .tsx) or JavaScript.
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
For example, assuming these files:
- The script requires modules you've added to package.json. In that case, the script, whether JS or TS, must be compiled so that the dependencies are bundled with the JPL file.
```bash
/src
index.ts # Main plugin script
myContentScript.js # One content script (JS)
otherContentScript.ts # Another content script (TypeScript)
vendor/
test.ts # Sub-directories are also supported
```
The `manifest.json` file would be:
```json
{
"manifest_version": 1,
"name": "Testing Content Scripts",
content_scripts: [
"myContentScript",
"otherContentScript",
"vendor/test"
]
}
```
Note in particular how the file path is relative to /src and the extensions removed.
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
## License

View File

@@ -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
*

View File

@@ -0,0 +1,40 @@
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)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*
* @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<void>;
/**
* Listens to a messages sent from the content script using postMessage().
* See {@link ContentScriptType} for more information as well as the
* [postMessage
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*/
onMessage(contentScriptId: string, callback: any): Promise<void>;
}

View File

@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise<void>;
/**
* 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<void>;
}

View File

@@ -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<any>;
/**
* 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<void>;
}

View File

@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* 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<void>;
/**

View File

@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
// Plugins type
// Content Script types
// =================================================================
export type PostMessageHandler = (id: string, message: any)=> Promise<any>;
/**
* 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 JoplinContentScripts.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 JoplinContentScripts.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',
}

View File

@@ -701,14 +701,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": {
@@ -3442,12 +3467,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": {
@@ -3749,6 +3782,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",
@@ -3768,6 +3812,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"
}
}
}
},
@@ -4395,6 +4448,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",

View File

@@ -3,10 +3,13 @@
"version": "1.0.0",
"description": "",
"scripts": {
"dist": "webpack",
"prepare": "npm run dist"
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
"prepare": "npm run dist",
"update": "npm install -g generator-joplin && yo joplin --update"
},
"keywords": ["joplin-plugin"],
"keywords": [
"joplin-plugin"
],
"license": "MIT",
"devDependencies": {
"@types/node": "^14.0.14",
@@ -19,6 +22,7 @@
"typescript": "^3.9.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"chalk": "^4.1.0"
"chalk": "^4.1.0",
"yargs": "^16.2.0"
}
}

View File

@@ -0,0 +1,3 @@
{
"extraScripts": []
}

View File

@@ -1,13 +1,24 @@
import joplin from 'api';
import { ContentScriptType } from 'api/types';
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'
);
await joplin.commands.register({
name: 'editor.printSomething',
label: 'Print some random string',
execute: async () => {
alert('mathMode.printSomething not implemented by Editor yet');
},
});
await joplin.views.menuItems.create('printSomethingButton', 'editor.printSomething', MenuItemLocation.Tools, { accelerator: 'Ctrl+Alt+Shift+U' });
},
});

View File

@@ -6,5 +6,5 @@
"version": "1.0.0",
"author": "CalebJohn",
"app_min_version": "1.4",
"homepage_url": "inmoth.ca"
"homepage_url": "joplinapp.org"
}

View File

@@ -1,3 +1,11 @@
// -----------------------------------------------------------------------------
// 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');
@@ -9,20 +17,22 @@ 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) {
@@ -68,13 +78,7 @@ function createPluginArchive(sourceDir, destPath) {
const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true })
.map(f => f.substr(sourceDir.length + 1));
if (!distFiles.length) {
// Usually means there's an error, which is going to be printed by
// webpack
console.warn(chalk.yellow('Plugin archive was not created because the "dist" directory is empty'));
return;
}
if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
fs.removeSync(destPath);
tar.create(
@@ -100,9 +104,14 @@ function createPluginInfo(manifestPath, destPath, jplFilePath) {
}
function onBuildCompleted() {
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
try {
fs.removeSync(path.resolve(publishDir, 'index.js'));
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
} catch (error) {
console.error(chalk.red(error.message));
}
}
const baseConfig = {
@@ -132,9 +141,6 @@ const pluginConfig = Object.assign({}, baseConfig, {
filename: 'index.js',
path: distDir,
},
});
const lastStepConfig = {
plugins: [
new CopyPlugin({
patterns: [
@@ -148,23 +154,15 @@ const lastStepConfig = {
// already copied into /dist so we don't copy them.
'**/*.ts',
'**/*.tsx',
// Currently we don't support JS files for the main
// plugin script. We support it for content scripts,
// but they should be declared in manifest.json,
// and then they are also compiled and copied to
// /dist. So wse also don't need to copy JS files.
'**/*.js',
],
},
},
],
}),
new WebpackOnBuildPlugin(onBuildCompleted),
],
};
});
const contentScriptConfig = Object.assign({}, baseConfig, {
const extraScriptConfig = Object.assign({}, baseConfig, {
resolve: {
alias: {
api: path.resolve(__dirname, 'api'),
@@ -173,42 +171,46 @@ const contentScriptConfig = Object.assign({}, baseConfig, {
},
});
function resolveContentScriptPaths(name) {
if (['.js', '.ts', '.tsx'].includes(path.extname(name).toLowerCase())) {
throw new Error(`Content script path must not include file extension: ${name}`);
}
const createArchiveConfig = {
stats: 'errors-only',
entry: './dist/index.js',
output: {
filename: 'index.js',
path: publishDir,
},
plugins: [new WebpackOnBuildPlugin(onBuildCompleted)],
};
const pathsToTry = [
`./src/${name}.ts`,
`${'./src/' + '/'}${name}.js`,
];
function resolveExtraScriptPath(name) {
const relativePath = `./src/${name}`;
for (const pathToTry of pathsToTry) {
if (fs.pathExistsSync(`${rootDir}/${pathToTry}`)) {
return {
entry: pathToTry,
output: {
filename: `${name}.js`,
path: distDir,
library: 'default',
libraryTarget: 'commonjs',
libraryExport: 'default',
},
};
}
}
const fullPath = path.resolve(`${rootDir}/${relativePath}`);
if (!fs.pathExistsSync(fullPath)) throw new Error(`Could not find extra script: "${name}" at "${fullPath}"`);
throw new Error(`Could not find content script "${name}" at locations ${JSON.stringify(pathsToTry)}`);
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 createContentScriptConfigs() {
if (!manifest.content_scripts) return [];
function buildExtraScriptConfigs(userConfig) {
if (!userConfig.extraScripts.length) return [];
const output = [];
for (const contentScriptName of manifest.content_scripts) {
const scriptPaths = resolveContentScriptPaths(contentScriptName);
output.push(Object.assign({}, contentScriptConfig, {
for (const scriptName of userConfig.extraScripts) {
const scriptPaths = resolveExtraScriptPath(scriptName);
output.push(Object.assign({}, extraScriptConfig, {
entry: scriptPaths.entry,
output: scriptPaths.output,
}));
@@ -217,8 +219,61 @@ function createContentScriptConfigs() {
return output;
}
const exportedConfigs = [pluginConfig].concat(createContentScriptConfigs());
function main(processArgv) {
const yargs = require('yargs/yargs');
const argv = yargs(processArgv).argv;
exportedConfigs[exportedConfigs.length - 1] = Object.assign({}, exportedConfigs[exportedConfigs.length - 1], lastStepConfig);
const configName = argv['joplin-plugin-config'];
if (!configName) throw new Error('A config file must be specified via the --joplin-plugin-config flag');
// Webpack configurations run in parallel, while we need them to run in
// sequence, and to do that it seems the only way is to run webpack multiple
// times, with different config each time.
const configs = {
// Builds the main src/index.ts and copy the extra content from /src to
// /dist including scripts, CSS and any other asset.
buildMain: [pluginConfig],
// Builds the extra scripts as defined in plugin.config.json. When doing
// so, some JavaScript files that were copied in the previous might be
// overwritten here by the compiled version. This is by design. The
// result is that JS files that don't need compilation, are simply
// copied to /dist, while those that do need it are correctly compiled.
buildExtraScripts: buildExtraScriptConfigs(userConfig),
// Ths config is for creating the .jpl, which is done via the plugin, so
// it doesn't actually need an entry and output, however webpack won't
// run without this. So we give it an entry that we know is going to
// exist and output in the publish dir. Then the plugin will delete this
// temporary file before packaging the plugin.
createArchive: [createArchiveConfig],
};
// If we are running the first config step, we clean up and create the build
// directories.
if (configName === 'buildMain') {
fs.removeSync(distDir);
fs.removeSync(publishDir);
fs.mkdirpSync(publishDir);
}
return configs[configName];
}
let exportedConfigs = [];
try {
exportedConfigs = main(process.argv);
} catch (error) {
console.error(chalk.red(error.message));
process.exit(1);
}
if (!exportedConfigs.length) {
// Nothing to do - for example where there are no external scripts to
// compile.
process.exit(0);
}
module.exports = exportedConfigs;

View File

@@ -29,6 +29,8 @@ The main two files you will want to look at are:
- `/src/index.ts`, which contains the entry point for the plugin source code.
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
The file `/plugin.config.json` could also be useful if you intend to use [external scripts](#external-script-files), such as content scripts or webview scripts.
## Building the plugin
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
@@ -49,44 +51,21 @@ In general all this is done automatically by the plugin generator, which will se
## Updating the plugin framework
To update the plugin framework, run `yo joplin --update`
To update the plugin framework, run `npm run update`.
Keep in mind that doing so will overwrite all the framework-related files **outside of the "src/" directory** (your source code will not be touched). So if you have modified any of the framework-related files, such as package.json or .gitignore, make sure your code is under version control so that you can check the diff and re-apply your changes.
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
For that reason, it's generally best not to change any of the framework files or to do so in a way that minimises the number of changes. For example, if you want to modify the Webpack config, create a new separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
## Content scripts
## External script files
A plugin that uses [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) must declare them under the `content_scripts` key of [manifest.json](https://joplinapp.org/api/references/plugin_manifest/).
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:
Each entry must be a path **relative to /src**, and **without extension**. The extension should not be included because it might change once the script is compiled. Each of these scripts will then be compiled to JavaScript and packaged into the plugin file. The content script files can be TypeScript (.ts or .tsx) or JavaScript.
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
For example, assuming these files:
- The script requires modules you've added to package.json. In that case, the script, whether JS or TS, must be compiled so that the dependencies are bundled with the JPL file.
```bash
/src
index.ts # Main plugin script
myContentScript.js # One content script (JS)
otherContentScript.ts # Another content script (TypeScript)
vendor/
test.ts # Sub-directories are also supported
```
The `manifest.json` file would be:
```json
{
"manifest_version": 1,
"name": "Testing Content Scripts",
content_scripts: [
"myContentScript",
"otherContentScript",
"vendor/test"
]
}
```
Note in particular how the file path is relative to /src and the extensions removed.
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
## License

View File

@@ -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
*

View File

@@ -0,0 +1,40 @@
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)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*
* @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<void>;
/**
* Listens to a messages sent from the content script using postMessage().
* See {@link ContentScriptType} for more information as well as the
* [postMessage
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*/
onMessage(contentScriptId: string, callback: any): Promise<void>;
}

View File

@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise<void>;
/**
* 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<void>;
}

View File

@@ -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<any>;
/**
* 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<void>;
}

View File

@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* 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<void>;
/**

View File

@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
// Plugins type
// Content Script types
// =================================================================
export type PostMessageHandler = (id: string, message: any)=> Promise<any>;
/**
* 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 JoplinContentScripts.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 JoplinContentScripts.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',
}

View File

@@ -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",

View File

@@ -3,10 +3,13 @@
"version": "1.0.0",
"description": "",
"scripts": {
"dist": "webpack",
"prepare": "npm run dist"
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
"prepare": "npm run dist",
"update": "npm install -g generator-joplin && yo joplin --update"
},
"keywords": ["joplin-plugin"],
"keywords": [
"joplin-plugin"
],
"license": "MIT",
"devDependencies": {
"@types/node": "^14.0.14",
@@ -19,7 +22,8 @@
"typescript": "^3.9.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"chalk": "^4.1.0"
"chalk": "^4.1.0",
"yargs": "^16.2.0"
},
"dependencies": {
"left-pad": "^1.3.0"

View File

@@ -0,0 +1,5 @@
{
"extraScripts": [
"markdownItTestPlugin.ts"
]
}

View File

@@ -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';
});
},
});

View File

@@ -6,8 +6,5 @@
"description": "",
"version": "1.0.0",
"author": "",
"homepage_url": "",
"content_scripts": [
"markdownItTestPlugin"
]
"homepage_url": ""
}

View File

@@ -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 `
<div class="just-testing">
<p>JUST TESTING: <pre>${leftPad(token.content.trim(), 10, 'x')}</pre></p>
<p><a href="#" onclick="webviewApi.executeCommand('testCommand', 'one', 'two'); return false;">Click to send "testCommand" to plugin</a></p>
<p><a href="#" onclick="webviewApi.executeCommand('testCommandNoArgs'); return false;">Click to send "testCommandNoArgs" to plugin</a></p>
</div>
`;
};
}
export default function(_context) {
export default function(context) {
return {
plugin: plugin,
plugin: function(markdownIt, _options) {
const pluginId = context.pluginId;
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);
const postMessageWithResponseTest = `
webviewApi.postMessage('${pluginId}', 'justtesting').then(function(response) {
console.info('Got response in content script: ' + response);
});
return false;
`;
return `
<div class="just-testing">
<p>JUST TESTING: <pre>${leftPad(token.content.trim(), 10, 'x')}</pre></p>
<p><a href="#" onclick="${postMessageWithResponseTest.replace(/\n/g, ' ')}">Click to post a message "justtesting" to plugin and check the response in the console</a></p>
</div>
`;
};
},
assets: function() {
return [
{ name: 'markdownItTestPlugin.css' }

View File

@@ -1,3 +1,11 @@
// -----------------------------------------------------------------------------
// 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');
@@ -9,20 +17,22 @@ 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) {
@@ -68,13 +78,7 @@ function createPluginArchive(sourceDir, destPath) {
const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true })
.map(f => f.substr(sourceDir.length + 1));
if (!distFiles.length) {
// Usually means there's an error, which is going to be printed by
// webpack
console.warn(chalk.yellow('Plugin archive was not created because the "dist" directory is empty'));
return;
}
if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
fs.removeSync(destPath);
tar.create(
@@ -100,9 +104,14 @@ function createPluginInfo(manifestPath, destPath, jplFilePath) {
}
function onBuildCompleted() {
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
try {
fs.removeSync(path.resolve(publishDir, 'index.js'));
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
} catch (error) {
console.error(chalk.red(error.message));
}
}
const baseConfig = {
@@ -132,9 +141,6 @@ const pluginConfig = Object.assign({}, baseConfig, {
filename: 'index.js',
path: distDir,
},
});
const lastStepConfig = {
plugins: [
new CopyPlugin({
patterns: [
@@ -148,23 +154,15 @@ const lastStepConfig = {
// already copied into /dist so we don't copy them.
'**/*.ts',
'**/*.tsx',
// Currently we don't support JS files for the main
// plugin script. We support it for content scripts,
// but they should be declared in manifest.json,
// and then they are also compiled and copied to
// /dist. So wse also don't need to copy JS files.
'**/*.js',
],
},
},
],
}),
new WebpackOnBuildPlugin(onBuildCompleted),
],
};
});
const contentScriptConfig = Object.assign({}, baseConfig, {
const extraScriptConfig = Object.assign({}, baseConfig, {
resolve: {
alias: {
api: path.resolve(__dirname, 'api'),
@@ -173,42 +171,46 @@ const contentScriptConfig = Object.assign({}, baseConfig, {
},
});
function resolveContentScriptPaths(name) {
if (['.js', '.ts', '.tsx'].includes(path.extname(name).toLowerCase())) {
throw new Error(`Content script path must not include file extension: ${name}`);
}
const createArchiveConfig = {
stats: 'errors-only',
entry: './dist/index.js',
output: {
filename: 'index.js',
path: publishDir,
},
plugins: [new WebpackOnBuildPlugin(onBuildCompleted)],
};
const pathsToTry = [
`./src/${name}.ts`,
`${'./src/' + '/'}${name}.js`,
];
function resolveExtraScriptPath(name) {
const relativePath = `./src/${name}`;
for (const pathToTry of pathsToTry) {
if (fs.pathExistsSync(`${rootDir}/${pathToTry}`)) {
return {
entry: pathToTry,
output: {
filename: `${name}.js`,
path: distDir,
library: 'default',
libraryTarget: 'commonjs',
libraryExport: 'default',
},
};
}
}
const fullPath = path.resolve(`${rootDir}/${relativePath}`);
if (!fs.pathExistsSync(fullPath)) throw new Error(`Could not find extra script: "${name}" at "${fullPath}"`);
throw new Error(`Could not find content script "${name}" at locations ${JSON.stringify(pathsToTry)}`);
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 createContentScriptConfigs() {
if (!manifest.content_scripts) return [];
function buildExtraScriptConfigs(userConfig) {
if (!userConfig.extraScripts.length) return [];
const output = [];
for (const contentScriptName of manifest.content_scripts) {
const scriptPaths = resolveContentScriptPaths(contentScriptName);
output.push(Object.assign({}, contentScriptConfig, {
for (const scriptName of userConfig.extraScripts) {
const scriptPaths = resolveExtraScriptPath(scriptName);
output.push(Object.assign({}, extraScriptConfig, {
entry: scriptPaths.entry,
output: scriptPaths.output,
}));
@@ -217,8 +219,61 @@ function createContentScriptConfigs() {
return output;
}
const exportedConfigs = [pluginConfig].concat(createContentScriptConfigs());
function main(processArgv) {
const yargs = require('yargs/yargs');
const argv = yargs(processArgv).argv;
exportedConfigs[exportedConfigs.length - 1] = Object.assign({}, exportedConfigs[exportedConfigs.length - 1], lastStepConfig);
const configName = argv['joplin-plugin-config'];
if (!configName) throw new Error('A config file must be specified via the --joplin-plugin-config flag');
// Webpack configurations run in parallel, while we need them to run in
// sequence, and to do that it seems the only way is to run webpack multiple
// times, with different config each time.
const configs = {
// Builds the main src/index.ts and copy the extra content from /src to
// /dist including scripts, CSS and any other asset.
buildMain: [pluginConfig],
// Builds the extra scripts as defined in plugin.config.json. When doing
// so, some JavaScript files that were copied in the previous might be
// overwritten here by the compiled version. This is by design. The
// result is that JS files that don't need compilation, are simply
// copied to /dist, while those that do need it are correctly compiled.
buildExtraScripts: buildExtraScriptConfigs(userConfig),
// Ths config is for creating the .jpl, which is done via the plugin, so
// it doesn't actually need an entry and output, however webpack won't
// run without this. So we give it an entry that we know is going to
// exist and output in the publish dir. Then the plugin will delete this
// temporary file before packaging the plugin.
createArchive: [createArchiveConfig],
};
// If we are running the first config step, we clean up and create the build
// directories.
if (configName === 'buildMain') {
fs.removeSync(distDir);
fs.removeSync(publishDir);
fs.mkdirpSync(publishDir);
}
return configs[configName];
}
let exportedConfigs = [];
try {
exportedConfigs = main(process.argv);
} catch (error) {
console.error(chalk.red(error.message));
process.exit(1);
}
if (!exportedConfigs.length) {
// Nothing to do - for example where there are no external scripts to
// compile.
process.exit(0);
}
module.exports = exportedConfigs;

View File

@@ -29,6 +29,8 @@ The main two files you will want to look at are:
- `/src/index.ts`, which contains the entry point for the plugin source code.
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
The file `/plugin.config.json` could also be useful if you intend to use [external scripts](#external-script-files), such as content scripts or webview scripts.
## Building the plugin
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
@@ -49,44 +51,21 @@ In general all this is done automatically by the plugin generator, which will se
## Updating the plugin framework
To update the plugin framework, run `yo joplin --update`
To update the plugin framework, run `npm run update`.
Keep in mind that doing so will overwrite all the framework-related files **outside of the "src/" directory** (your source code will not be touched). So if you have modified any of the framework-related files, such as package.json or .gitignore, make sure your code is under version control so that you can check the diff and re-apply your changes.
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
For that reason, it's generally best not to change any of the framework files or to do so in a way that minimises the number of changes. For example, if you want to modify the Webpack config, create a new separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
## Content scripts
## External script files
A plugin that uses [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) must declare them under the `content_scripts` key of [manifest.json](https://joplinapp.org/api/references/plugin_manifest/).
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:
Each entry must be a path **relative to /src**, and **without extension**. The extension should not be included because it might change once the script is compiled. Each of these scripts will then be compiled to JavaScript and packaged into the plugin file. The content script files can be TypeScript (.ts or .tsx) or JavaScript.
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
For example, assuming these files:
- The script requires modules you've added to package.json. In that case, the script, whether JS or TS, must be compiled so that the dependencies are bundled with the JPL file.
```bash
/src
index.ts # Main plugin script
myContentScript.js # One content script (JS)
otherContentScript.ts # Another content script (TypeScript)
vendor/
test.ts # Sub-directories are also supported
```
The `manifest.json` file would be:
```json
{
"manifest_version": 1,
"name": "Testing Content Scripts",
content_scripts: [
"myContentScript",
"otherContentScript",
"vendor/test"
]
}
```
Note in particular how the file path is relative to /src and the extensions removed.
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
## License

View File

@@ -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
*

View File

@@ -0,0 +1,40 @@
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)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*
* @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<void>;
/**
* Listens to a messages sent from the content script using postMessage().
* See {@link ContentScriptType} for more information as well as the
* [postMessage
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*/
onMessage(contentScriptId: string, callback: any): Promise<void>;
}

View File

@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise<void>;
/**
* 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<void>;
}

View File

@@ -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<any>;
/**
* 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<void>;
}

View File

@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* 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<void>;
/**

View File

@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
// Plugins type
// Content Script types
// =================================================================
export type PostMessageHandler = (id: string, message: any)=> Promise<any>;
/**
* 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 JoplinContentScripts.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 JoplinContentScripts.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',
}

View File

@@ -3,10 +3,13 @@
"version": "1.0.0",
"description": "",
"scripts": {
"dist": "webpack",
"prepare": "npm run dist"
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
"prepare": "npm run dist",
"update": "npm install -g generator-joplin && yo joplin --update"
},
"keywords": ["joplin-plugin"],
"keywords": [
"joplin-plugin"
],
"license": "MIT",
"devDependencies": {
"@types/node": "^14.0.14",
@@ -19,6 +22,7 @@
"typescript": "^3.9.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"chalk": "^4.1.0"
"chalk": "^4.1.0",
"yargs": "^16.2.0"
}
}

View File

@@ -0,0 +1,3 @@
{
"extraScripts": []
}

View File

@@ -1,3 +1,11 @@
// -----------------------------------------------------------------------------
// 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');
@@ -9,20 +17,22 @@ 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) {
@@ -68,13 +78,7 @@ function createPluginArchive(sourceDir, destPath) {
const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true })
.map(f => f.substr(sourceDir.length + 1));
if (!distFiles.length) {
// Usually means there's an error, which is going to be printed by
// webpack
console.warn(chalk.yellow('Plugin archive was not created because the "dist" directory is empty'));
return;
}
if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
fs.removeSync(destPath);
tar.create(
@@ -100,9 +104,14 @@ function createPluginInfo(manifestPath, destPath, jplFilePath) {
}
function onBuildCompleted() {
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
try {
fs.removeSync(path.resolve(publishDir, 'index.js'));
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
} catch (error) {
console.error(chalk.red(error.message));
}
}
const baseConfig = {
@@ -132,9 +141,6 @@ const pluginConfig = Object.assign({}, baseConfig, {
filename: 'index.js',
path: distDir,
},
});
const lastStepConfig = {
plugins: [
new CopyPlugin({
patterns: [
@@ -148,23 +154,15 @@ const lastStepConfig = {
// already copied into /dist so we don't copy them.
'**/*.ts',
'**/*.tsx',
// Currently we don't support JS files for the main
// plugin script. We support it for content scripts,
// but they should be declared in manifest.json,
// and then they are also compiled and copied to
// /dist. So wse also don't need to copy JS files.
'**/*.js',
],
},
},
],
}),
new WebpackOnBuildPlugin(onBuildCompleted),
],
};
});
const contentScriptConfig = Object.assign({}, baseConfig, {
const extraScriptConfig = Object.assign({}, baseConfig, {
resolve: {
alias: {
api: path.resolve(__dirname, 'api'),
@@ -173,42 +171,46 @@ const contentScriptConfig = Object.assign({}, baseConfig, {
},
});
function resolveContentScriptPaths(name) {
if (['.js', '.ts', '.tsx'].includes(path.extname(name).toLowerCase())) {
throw new Error(`Content script path must not include file extension: ${name}`);
}
const createArchiveConfig = {
stats: 'errors-only',
entry: './dist/index.js',
output: {
filename: 'index.js',
path: publishDir,
},
plugins: [new WebpackOnBuildPlugin(onBuildCompleted)],
};
const pathsToTry = [
`./src/${name}.ts`,
`${'./src/' + '/'}${name}.js`,
];
function resolveExtraScriptPath(name) {
const relativePath = `./src/${name}`;
for (const pathToTry of pathsToTry) {
if (fs.pathExistsSync(`${rootDir}/${pathToTry}`)) {
return {
entry: pathToTry,
output: {
filename: `${name}.js`,
path: distDir,
library: 'default',
libraryTarget: 'commonjs',
libraryExport: 'default',
},
};
}
}
const fullPath = path.resolve(`${rootDir}/${relativePath}`);
if (!fs.pathExistsSync(fullPath)) throw new Error(`Could not find extra script: "${name}" at "${fullPath}"`);
throw new Error(`Could not find content script "${name}" at locations ${JSON.stringify(pathsToTry)}`);
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 createContentScriptConfigs() {
if (!manifest.content_scripts) return [];
function buildExtraScriptConfigs(userConfig) {
if (!userConfig.extraScripts.length) return [];
const output = [];
for (const contentScriptName of manifest.content_scripts) {
const scriptPaths = resolveContentScriptPaths(contentScriptName);
output.push(Object.assign({}, contentScriptConfig, {
for (const scriptName of userConfig.extraScripts) {
const scriptPaths = resolveExtraScriptPath(scriptName);
output.push(Object.assign({}, extraScriptConfig, {
entry: scriptPaths.entry,
output: scriptPaths.output,
}));
@@ -217,8 +219,61 @@ function createContentScriptConfigs() {
return output;
}
const exportedConfigs = [pluginConfig].concat(createContentScriptConfigs());
function main(processArgv) {
const yargs = require('yargs/yargs');
const argv = yargs(processArgv).argv;
exportedConfigs[exportedConfigs.length - 1] = Object.assign({}, exportedConfigs[exportedConfigs.length - 1], lastStepConfig);
const configName = argv['joplin-plugin-config'];
if (!configName) throw new Error('A config file must be specified via the --joplin-plugin-config flag');
// Webpack configurations run in parallel, while we need them to run in
// sequence, and to do that it seems the only way is to run webpack multiple
// times, with different config each time.
const configs = {
// Builds the main src/index.ts and copy the extra content from /src to
// /dist including scripts, CSS and any other asset.
buildMain: [pluginConfig],
// Builds the extra scripts as defined in plugin.config.json. When doing
// so, some JavaScript files that were copied in the previous might be
// overwritten here by the compiled version. This is by design. The
// result is that JS files that don't need compilation, are simply
// copied to /dist, while those that do need it are correctly compiled.
buildExtraScripts: buildExtraScriptConfigs(userConfig),
// Ths config is for creating the .jpl, which is done via the plugin, so
// it doesn't actually need an entry and output, however webpack won't
// run without this. So we give it an entry that we know is going to
// exist and output in the publish dir. Then the plugin will delete this
// temporary file before packaging the plugin.
createArchive: [createArchiveConfig],
};
// If we are running the first config step, we clean up and create the build
// directories.
if (configName === 'buildMain') {
fs.removeSync(distDir);
fs.removeSync(publishDir);
fs.mkdirpSync(publishDir);
}
return configs[configName];
}
let exportedConfigs = [];
try {
exportedConfigs = main(process.argv);
} catch (error) {
console.error(chalk.red(error.message));
process.exit(1);
}
if (!exportedConfigs.length) {
// Nothing to do - for example where there are no external scripts to
// compile.
process.exit(0);
}
module.exports = exportedConfigs;

View File

@@ -29,6 +29,8 @@ The main two files you will want to look at are:
- `/src/index.ts`, which contains the entry point for the plugin source code.
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
The file `/plugin.config.json` could also be useful if you intend to use [external scripts](#external-script-files), such as content scripts or webview scripts.
## Building the plugin
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
@@ -49,44 +51,21 @@ In general all this is done automatically by the plugin generator, which will se
## Updating the plugin framework
To update the plugin framework, run `yo joplin --update`
To update the plugin framework, run `npm run update`.
Keep in mind that doing so will overwrite all the framework-related files **outside of the "src/" directory** (your source code will not be touched). So if you have modified any of the framework-related files, such as package.json or .gitignore, make sure your code is under version control so that you can check the diff and re-apply your changes.
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
For that reason, it's generally best not to change any of the framework files or to do so in a way that minimises the number of changes. For example, if you want to modify the Webpack config, create a new separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
## Content scripts
## External script files
A plugin that uses [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinplugins.html#registercontentscript) must declare them under the `content_scripts` key of [manifest.json](https://joplinapp.org/api/references/plugin_manifest/).
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:
Each entry must be a path **relative to /src**, and **without extension**. The extension should not be included because it might change once the script is compiled. Each of these scripts will then be compiled to JavaScript and packaged into the plugin file. The content script files can be TypeScript (.ts or .tsx) or JavaScript.
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
For example, assuming these files:
- The script requires modules you've added to package.json. In that case, the script, whether JS or TS, must be compiled so that the dependencies are bundled with the JPL file.
```bash
/src
index.ts # Main plugin script
myContentScript.js # One content script (JS)
otherContentScript.ts # Another content script (TypeScript)
vendor/
test.ts # Sub-directories are also supported
```
The `manifest.json` file would be:
```json
{
"manifest_version": 1,
"name": "Testing Content Scripts",
content_scripts: [
"myContentScript",
"otherContentScript",
"vendor/test"
]
}
```
Note in particular how the file path is relative to /src and the extensions removed.
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
## License

View File

@@ -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
*

View File

@@ -0,0 +1,40 @@
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)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*
* @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<void>;
/**
* Listens to a messages sent from the content script using postMessage().
* See {@link ContentScriptType} for more information as well as the
* [postMessage
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*/
onMessage(contentScriptId: string, callback: any): Promise<void>;
}

View File

@@ -20,28 +20,7 @@ export default class JoplinPlugins {
*/
register(script: Script): Promise<void>;
/**
* 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<void>;
}

View File

@@ -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<any>;
/**
* 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<void>;
}

View File

@@ -28,6 +28,22 @@ export default class JoplinViewsPanels {
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* 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<void>;
/**

View File

@@ -366,9 +366,31 @@ export interface SettingSection {
export type Path = string[];
// =================================================================
// Plugins type
// Content Script types
// =================================================================
export type PostMessageHandler = (id: string, message: any)=> Promise<any>;
/**
* 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 JoplinContentScripts.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 JoplinContentScripts.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',
}

View File

@@ -3,10 +3,13 @@
"version": "1.0.0",
"description": "",
"scripts": {
"dist": "webpack",
"prepare": "npm run dist"
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
"prepare": "npm run dist",
"update": "npm install -g generator-joplin && yo joplin --update"
},
"keywords": ["joplin-plugin"],
"keywords": [
"joplin-plugin"
],
"license": "MIT",
"devDependencies": {
"@types/node": "^14.0.14",
@@ -19,6 +22,7 @@
"typescript": "^3.9.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"chalk": "^4.1.0"
"chalk": "^4.1.0",
"yargs": "^16.2.0"
}
}

View File

@@ -0,0 +1,3 @@
{
"extraScripts": []
}

View File

@@ -1,3 +1,11 @@
// -----------------------------------------------------------------------------
// 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');
@@ -9,20 +17,22 @@ 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) {
@@ -68,13 +78,7 @@ function createPluginArchive(sourceDir, destPath) {
const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true })
.map(f => f.substr(sourceDir.length + 1));
if (!distFiles.length) {
// Usually means there's an error, which is going to be printed by
// webpack
console.warn(chalk.yellow('Plugin archive was not created because the "dist" directory is empty'));
return;
}
if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
fs.removeSync(destPath);
tar.create(
@@ -100,9 +104,14 @@ function createPluginInfo(manifestPath, destPath, jplFilePath) {
}
function onBuildCompleted() {
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
try {
fs.removeSync(path.resolve(publishDir, 'index.js'));
createPluginArchive(distDir, pluginArchiveFilePath);
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
validatePackageJson();
} catch (error) {
console.error(chalk.red(error.message));
}
}
const baseConfig = {
@@ -132,9 +141,6 @@ const pluginConfig = Object.assign({}, baseConfig, {
filename: 'index.js',
path: distDir,
},
});
const lastStepConfig = {
plugins: [
new CopyPlugin({
patterns: [
@@ -148,23 +154,15 @@ const lastStepConfig = {
// already copied into /dist so we don't copy them.
'**/*.ts',
'**/*.tsx',
// Currently we don't support JS files for the main
// plugin script. We support it for content scripts,
// but they should be declared in manifest.json,
// and then they are also compiled and copied to
// /dist. So wse also don't need to copy JS files.
'**/*.js',
],
},
},
],
}),
new WebpackOnBuildPlugin(onBuildCompleted),
],
};
});
const contentScriptConfig = Object.assign({}, baseConfig, {
const extraScriptConfig = Object.assign({}, baseConfig, {
resolve: {
alias: {
api: path.resolve(__dirname, 'api'),
@@ -173,42 +171,46 @@ const contentScriptConfig = Object.assign({}, baseConfig, {
},
});
function resolveContentScriptPaths(name) {
if (['.js', '.ts', '.tsx'].includes(path.extname(name).toLowerCase())) {
throw new Error(`Content script path must not include file extension: ${name}`);
}
const createArchiveConfig = {
stats: 'errors-only',
entry: './dist/index.js',
output: {
filename: 'index.js',
path: publishDir,
},
plugins: [new WebpackOnBuildPlugin(onBuildCompleted)],
};
const pathsToTry = [
`./src/${name}.ts`,
`${'./src/' + '/'}${name}.js`,
];
function resolveExtraScriptPath(name) {
const relativePath = `./src/${name}`;
for (const pathToTry of pathsToTry) {
if (fs.pathExistsSync(`${rootDir}/${pathToTry}`)) {
return {
entry: pathToTry,
output: {
filename: `${name}.js`,
path: distDir,
library: 'default',
libraryTarget: 'commonjs',
libraryExport: 'default',
},
};
}
}
const fullPath = path.resolve(`${rootDir}/${relativePath}`);
if (!fs.pathExistsSync(fullPath)) throw new Error(`Could not find extra script: "${name}" at "${fullPath}"`);
throw new Error(`Could not find content script "${name}" at locations ${JSON.stringify(pathsToTry)}`);
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 createContentScriptConfigs() {
if (!manifest.content_scripts) return [];
function buildExtraScriptConfigs(userConfig) {
if (!userConfig.extraScripts.length) return [];
const output = [];
for (const contentScriptName of manifest.content_scripts) {
const scriptPaths = resolveContentScriptPaths(contentScriptName);
output.push(Object.assign({}, contentScriptConfig, {
for (const scriptName of userConfig.extraScripts) {
const scriptPaths = resolveExtraScriptPath(scriptName);
output.push(Object.assign({}, extraScriptConfig, {
entry: scriptPaths.entry,
output: scriptPaths.output,
}));
@@ -217,8 +219,61 @@ function createContentScriptConfigs() {
return output;
}
const exportedConfigs = [pluginConfig].concat(createContentScriptConfigs());
function main(processArgv) {
const yargs = require('yargs/yargs');
const argv = yargs(processArgv).argv;
exportedConfigs[exportedConfigs.length - 1] = Object.assign({}, exportedConfigs[exportedConfigs.length - 1], lastStepConfig);
const configName = argv['joplin-plugin-config'];
if (!configName) throw new Error('A config file must be specified via the --joplin-plugin-config flag');
// Webpack configurations run in parallel, while we need them to run in
// sequence, and to do that it seems the only way is to run webpack multiple
// times, with different config each time.
const configs = {
// Builds the main src/index.ts and copy the extra content from /src to
// /dist including scripts, CSS and any other asset.
buildMain: [pluginConfig],
// Builds the extra scripts as defined in plugin.config.json. When doing
// so, some JavaScript files that were copied in the previous might be
// overwritten here by the compiled version. This is by design. The
// result is that JS files that don't need compilation, are simply
// copied to /dist, while those that do need it are correctly compiled.
buildExtraScripts: buildExtraScriptConfigs(userConfig),
// Ths config is for creating the .jpl, which is done via the plugin, so
// it doesn't actually need an entry and output, however webpack won't
// run without this. So we give it an entry that we know is going to
// exist and output in the publish dir. Then the plugin will delete this
// temporary file before packaging the plugin.
createArchive: [createArchiveConfig],
};
// If we are running the first config step, we clean up and create the build
// directories.
if (configName === 'buildMain') {
fs.removeSync(distDir);
fs.removeSync(publishDir);
fs.mkdirpSync(publishDir);
}
return configs[configName];
}
let exportedConfigs = [];
try {
exportedConfigs = main(process.argv);
} catch (error) {
console.error(chalk.red(error.message));
process.exit(1);
}
if (!exportedConfigs.length) {
// Nothing to do - for example where there are no external scripts to
// compile.
process.exit(0);
}
module.exports = exportedConfigs;

Some files were not shown because too many files have changed in this diff Show More