1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-03-15 10:06:37 +02:00

Compare commits

...

247 Commits

Author SHA1 Message Date
Laurent Cozic
bfae770b19 Testing adding type to plugin framework 2020-10-06 19:08:33 +01:00
Laurent Cozic
e570f7a226 Disable filters for now 2020-10-06 18:23:15 +01:00
Laurent Cozic
9b28a8995f Open plugin dev tool window 2020-10-06 18:14:46 +01:00
Laurent Cozic
197f509f5d Increase version to 1.3 2020-10-06 14:04:21 +01:00
Laurent Cozic
4c83d7aa75 Fixed sidebar resize issue 2020-10-06 12:03:15 +01:00
Laurent Cozic
17e053b358 Handle module change event 2020-10-06 11:33:13 +01:00
Laurent Cozic
a29c93634d Converted locale file to TS 2020-10-06 10:27:43 +01:00
Laurent Cozic
a5f5bfcfec clean up 2020-10-06 10:16:18 +01:00
Laurent Cozic
b509329383 Convert interopservicehelper to TS 2020-10-06 10:14:54 +01:00
Laurent Cozic
91c7abed42 Added back support for keymap on command service 2020-10-06 09:55:23 +01:00
Laurent Cozic
54fda6ac97 Refactored menu bar 2020-10-05 19:29:53 +01:00
Laurent Cozic
341eefebaf Converted BaseApplication to TypeScripy 2020-10-05 14:44:56 +01:00
Laurent Cozic
af714cbdac Optimize command state handling 2020-10-05 13:20:23 +01:00
Laurent Cozic
6a0bf15c28 Clean up 2020-10-03 18:24:44 +01:00
Laurent Cozic
5a2bdad348 Cleaned up toolbar code to improve rendering 2020-10-03 18:22:39 +01:00
Laurent Cozic
fd08bfdd86 Better way to create buttonToolbarInfos 2020-10-03 17:49:28 +01:00
Laurent Cozic
1a5cead659 Added @typescript-eslint/explicit-member-accessibility rule 2020-10-03 15:45:32 +01:00
Laurent Cozic
85df133386 Added command service tests and a way to get multiple toolbar buttons 2020-10-03 15:36:23 +01:00
Laurent Cozic
869d11e113 Added way to parse when-clauses for commands 2020-10-03 14:40:12 +01:00
Laurent Cozic
d7a01d3965 Fixed issue with state that was accidentally mutated 2020-10-02 20:06:52 +01:00
Laurent Cozic
989036241d Fixed toolbar button label 2020-10-02 20:03:14 +01:00
Laurent Cozic
433cef1827 Fixed encryption config screen password save logic 2020-10-02 19:59:36 +01:00
Laurent Cozic
433d34f62b Resize app content when banner is added on top 2020-10-02 19:40:12 +01:00
Laurent Cozic
e7ec33bbf9 Added event tests 2020-10-02 18:48:25 +01:00
Laurent Cozic
a29f42d78d Converted synchronizer to TypeScript 2020-10-02 18:03:29 +01:00
Laurent Cozic
74ed234ab9 Added support for onAlarmTrigger event 2020-10-02 17:41:18 +01:00
Laurent Cozic
86b76ccb77 Fixed setting plugin 2020-10-02 16:49:39 +01:00
Laurent Cozic
29aedf8480 Fixed toc demo 2020-10-02 16:21:32 +01:00
Laurent Cozic
9486f5e0d2 Simplify plugin 2020-10-02 16:07:04 +01:00
Laurent Cozic
9a458431b8 Fixed sandbox proxy namespace logic 2020-10-02 15:56:34 +01:00
Laurent Cozic
2c9db9d18c Fixed dialog plugin API 2020-10-02 15:21:58 +01:00
Laurent Cozic
ae9c535842 Improved setting API 2020-10-02 13:02:39 +01:00
Laurent Cozic
a518da587e Fixed demo 2020-10-02 12:52:05 +01:00
Laurent Cozic
92e6e00d9e Fixed commands 2020-10-02 12:49:40 +01:00
Laurent Cozic
b64c9cf18a Finished refactoring interop service 2020-10-02 12:42:25 +01:00
Laurent Cozic
275d6e230d Converted shim to TypeScript 2020-10-02 11:38:04 +01:00
Laurent Cozic
ab8ce15c33 Fixed command api 2020-10-02 10:42:03 +01:00
Laurent Cozic
3fb6179587 lonter 2020-10-02 01:03:39 +01:00
Laurent Cozic
28cc38064c Fixed interop plugin API to work with multi-process arch and cleaned up interop service 2020-10-02 00:44:42 +01:00
Laurent Cozic
1fa5ab2b96 Refactoring and got ipc messages to work 2020-10-01 23:42:49 +01:00
Laurent Cozic
15f4e635d9 Minor tweaks 2020-10-01 15:10:59 +01:00
Laurent Cozic
7a79d7ef7e Refactoring and got ipc messages to work 2020-10-01 14:47:38 +01:00
Laurent Cozic
776e7dfe3f renaming logger 2020-10-01 10:31:01 +01:00
Laurent Cozic
790b622cbc Updated doc 2020-09-30 23:38:28 +01:00
Laurent Cozic
89117b4ee9 Renamed 2020-09-30 23:36:27 +01:00
Laurent Cozic
c245517e0f Renamed to PlatformImplementation 2020-09-30 23:31:27 +01:00
Laurent Cozic
31db95d0c4 Cleaned up plugin API names 2020-09-30 23:17:18 +01:00
Laurent Cozic
2cd50de065 Moved plugin classes under /plugins namespace 2020-09-30 23:07:46 +01:00
Laurent Cozic
6dcb7e2605 Added doc 2020-09-30 17:19:34 +01:00
Laurent Cozic
9c9bd4ba51 Changed plugin system architecture to allow using one process per plugin 2020-09-30 16:56:41 +01:00
Laurent Cozic
71e6964945 Added proxy class 2020-09-30 10:24:15 +01:00
Laurent Cozic
97dc2fa6bd Fixed tests 2020-09-29 16:42:32 +01:00
Laurent Cozic
161e112e7b Added support for getting selected notes and adding a context menu item 2020-09-29 16:28:25 +01:00
Laurent Cozic
c93a6f86cd Added way to add a custom Markdown plugin 2020-09-29 15:29:11 +01:00
Laurent Cozic
9bb178b9d9 Fixed broken merge 2020-09-29 15:28:12 +01:00
Laurent Cozic
8087bc5280 Merge branch 'dev' into plugin_system 2020-09-29 14:30:33 +01:00
Laurent Cozic
26f5a606e0 Merge branch 'release-1.2' into dev 2020-09-29 14:29:38 +01:00
Laurent Cozic
9ebb574059 Merge branch 'release-1.2' of github.com:laurent22/joplin into release-1.2 2020-09-29 14:27:33 +01:00
Laurent Cozic
d29c3c2466 Desktop: Regression: Sidebar toggle button did not work anymore 2020-09-29 14:26:05 +01:00
Laurent Cozic
a71f1c19ec Android release v1.2.2 2020-09-29 12:40:46 +01:00
Laurent Cozic
485921d879 CLI v1.2.2 2020-09-29 12:34:42 +01:00
Laurent Cozic
15de7572c0 Electron release v1.2.3 2020-09-29 12:32:24 +01:00
Laurent Cozic
09f41dd50e Desktop: Make global search field wider when it has focus 2020-09-29 12:31:19 +01:00
Laurent Cozic
7b8ee467a0 Desktop: Improved rendering of All Notes item in sidebar 2020-09-29 11:49:51 +01:00
Laurent Cozic
99a496d684 Desktop: Always label "Click to add tags" 2020-09-29 11:33:22 +01:00
Laurent Cozic
100aaab58d Refactor reducer to TypeScript and using immerjs 2020-09-29 11:16:01 +01:00
Laurent Cozic
126c7b5a75 Merge branch 'dev' into reducer_refactor 2020-09-29 11:00:31 +01:00
Laurent Cozic
d448ea3a02 Merge branch 'dev' into plugin_system 2020-09-29 10:59:55 +01:00
Laurent Cozic
9d6975a9e2 Merge branch 'dev' of github.com:laurent22/joplin into dev 2020-09-29 10:57:34 +01:00
Laurent Cozic
555727e5fe Refactor reducer 2020-09-29 10:56:33 +01:00
Laurent Cozic
f43ee123d8 Tools: Fixed tests 2020-09-29 10:54:31 +01:00
Laurent Cozic
f42fb1b871 Changed tag label 2020-09-29 10:51:47 +01:00
Laurent Cozic
cf2442c5b2 Desktop: Fixes #3835: Prevent crash in rare case when opening the config screen 2020-09-29 08:40:14 +01:00
Laurent Cozic
e0e4735b03 Desktop: Fixes #3754: Refresh search results when searching by tag and when a tag is changed 2020-09-29 08:11:52 +01:00
osso73
138faa2aae All: Translation: Update ca.po (#3844) 2020-09-29 02:06:23 -04:00
Laurent Cozic
8bd58c9608 Merge branch 'release-1.2' of github.com:laurent22/joplin into release-1.2 2020-09-28 19:19:52 +01:00
Laurent Cozic
215a725ded Mobile: Fixes #3834: Fixed search highlights 2020-09-28 19:19:21 +01:00
Naveen M V
12c0a05af0 Desktop: Keep search fuzzy scores between 0 and 2 (#3812) 2020-09-28 18:58:19 +01:00
Caleb John
a7fa119041 Desktop: Extend functionality of codemirror vim (#3823)
add swapLine(Up/Down)
have `o` use the more complex list indent
enable sync initializing from vim (and maybe emacs)
split keymap stuff into it's own file
2020-09-28 18:57:17 +01:00
Laurent Cozic
7fb52b8b0e Desktop: Fix issue with highlighted search terms in CodeMirror viewer 2020-09-28 18:44:21 +01:00
Laurent Cozic
3e86ae4a82 Desktop: Disable fuzzy search for now due to performance issues 2020-09-28 18:41:16 +01:00
Laurent Cozic
77eceea426 Ensure plugin settings are within their own namespaces 2020-09-28 18:11:53 +01:00
Laurent Cozic
a09c6f152c Added support for plugin dialogs 2020-09-28 17:26:22 +01:00
Laurent Cozic
3830195752 Allow creating new section from plugin 2020-09-27 13:45:08 +01:00
Laurent Cozic
c9594065c3 Refactor Settings 2020-09-27 13:31:45 +01:00
Laurent Cozic
360d3bbff9 Allow creating new settings from plugin 2020-09-27 13:03:37 +01:00
Laurent Cozic
6fde8dfe52 Refactored Settings into TypeScript 2020-09-26 18:14:00 +01:00
Laurent Cozic
de2ccfbfe0 Added explanation for shim timers and implemented RN side 2020-09-26 12:42:44 +01:00
Laurent Cozic
31f53b12fd Move timers to shim 2020-09-26 12:19:13 +01:00
Laurent Cozic
d45b280ada Done text selection plugin 2020-09-25 11:18:06 +01:00
Ji-Hyeon Gim
ca46590ff3 All: Translation: Update ko.po (#3813)
Signed-off-by: Ji-Hyeon Gim <potatogim@potatogim.net>
2020-09-24 21:17:53 -04:00
Laurent Cozic
b5a137545e Add support getting and replacing editor selection 2020-09-24 18:35:20 +01:00
Laurent Cozic
4e80dbb7a7 Allow tagging desktop-only feature in plugin doc 2020-09-24 15:53:37 +01:00
Laurent Cozic
90b0c99806 Merge branch 'release-1.2' into plugin_system 2020-09-24 14:50:20 +01:00
Laurent Cozic
947d81d96d Desktop: Optimised sidebar rendering speed 2020-09-24 14:30:20 +01:00
Laurent Cozic
6ca640d2ed Desktop: Fix: Fade out checked items in Rich Text editor too 2020-09-23 17:49:25 +01:00
Laurent Cozic
c8c0c3af46 Changed to node-slug 2020-09-23 17:34:58 +01:00
Laurent Cozic
110de50bf9 Allow setting custom shortcuts and saving/loading them 2020-09-23 17:26:30 +01:00
Laurent Cozic
b7e110d888 Converted eventManager to TypeScript 2020-09-23 16:25:00 +01:00
Laurent Cozic
f1c557cb43 Converted app to TypeScript 2020-09-23 15:51:31 +01:00
Laurent Cozic
43e9fc92c9 Adding support for custom menu items 2020-09-23 15:24:42 +01:00
Laurent Cozic
10fa331731 Define plugin state types 2020-09-23 15:18:45 +01:00
Laurent Cozic
cc8e122de3 Added support for custom commands and toolbar buttons 2020-09-23 15:10:31 +01:00
Laurent Cozic
bca5fd8db9 gitignore 2020-09-23 14:10:02 +01:00
Laurent Cozic
13101f7d9b Merge branch 'dev' into plugin_system 2020-09-23 14:09:21 +01:00
Laurent Cozic
6aca233b21 CLI v1.2.1 2020-09-23 12:16:58 +01:00
Laurent Cozic
2200be697e Cli: Fixed crash due to missing spellfix extension 2020-09-23 12:14:17 +01:00
Laurent Cozic
25ab3c323b Desktop: Fixes #3801: Fixed editor font size 2020-09-23 11:39:36 +01:00
Laurent Cozic
5bf30a9586 Merge branch 'release-1.2' into dev 2020-09-23 10:24:55 +01:00
Laurent Cozic
b6779a8074 Desktop: Fixes #3810: Only disable relevant toolbar buttons when editor is read-only 2020-09-23 10:21:24 +01:00
Caleb John
59599d318c Desktop: Adjust the codemirror code block colors for the dark theme (#3794) 2020-09-23 09:34:39 +01:00
Arda Kılıçdağı
538600fd6c All: Translation: Update tr_TR.po (#3798) 2020-09-22 21:12:31 -04:00
Ji-Hyeon Gim
63264ba471 All: Translation: Update ko.po (#3778)
This patch includes the translation of missing strings, the improvement of the existing translation

Signed-off-by: Ji-Hyeon Gim <potatogim@potatogim.net>
2020-09-22 21:11:55 -04:00
Laurent Cozic
95e7f3df7d Electron release v1.2.2 2020-09-22 16:39:18 +01:00
Laurent Cozic
366fd2a333 Fixed desktop build 2020-09-22 16:38:47 +01:00
Laurent Cozic
5be99a4a16 Merge branch 'release-1.2' of github.com:laurent22/joplin into release-1.2 2020-09-22 16:37:23 +01:00
Laurent Cozic
d86f6a1fbd Tools: Require setting type flag for new Android releases 2020-09-22 16:36:46 +01:00
Laurent Cozic
7d68208cb4 Android release v1.2.1 2020-09-22 16:17:11 +01:00
Laurent Cozic
e9de9d9128 Electron release v1.2.1 2020-09-22 16:02:51 +01:00
Laurent Cozic
1af16d9f0b Tools: Update package locks 2020-09-22 16:02:22 +01:00
Laurent Cozic
8e11eababa Android: Fixes #3797: Disable beta editor even if it was already enabled 2020-09-22 16:01:00 +01:00
Laurent Cozic
4ec9faadd5 Desktop: Disable auto-update by default 2020-09-22 15:41:25 +01:00
Laurent Cozic
5cf462c885 Tools: Increase release version to 1.2 2020-09-22 15:31:32 +01:00
Laurent Cozic
f7ef0a2b1e Tools: Added script to automatically increase major and minor version numbers on new releases 2020-09-22 15:30:20 +01:00
Laurent Cozic
870f55a6c5 Merge branch 'release-1.2' of github.com:laurent22/joplin into release-1.2 2020-09-22 14:37:34 +01:00
Caleb John
7f7e38b434 Desktop, Mobile: Resolves #3740: Upgrade Mermaid to v8.8.0 (#3745)
Co-authored-by: Laurent <laurent22@users.noreply.github.com>
2020-09-22 13:21:35 +01:00
Caleb John
460a07b1a3 Desktop: Fix missed highlighting when using the global search (#3717) 2020-09-22 13:17:51 +01:00
Caleb John
48c9b86d2b Desktop: Fixes #3791: Add stricter rules for katex blocks (#3795) 2020-09-22 13:16:37 +01:00
Caleb John
7202066c1f Desktop: Fix bug where editor would scroll to focus global search (#3787) 2020-09-22 13:12:22 +01:00
Carlos Eduardo
5226f0019b Desktop: Add frequently used languages to markdown editor (#3786) 2020-09-22 13:11:12 +01:00
Laurent Cozic
26ac745419 Deskop, Cli: Fixes #3780: Fixed link generation when exporting to PDF or HTML 2020-09-22 12:56:56 +01:00
Laurent Cozic
b3f2bbee5b Desktop, Cli: Fixes #3760: Improved handling of special characters when exporting to Markdown 2020-09-22 12:06:19 +01:00
Laurent Cozic
56c6cfc785 Update website 2020-09-21 17:53:14 +01:00
Laurent Cozic
1db4932573 Merge branch 'release-1.2' into dev 2020-09-21 17:52:25 +01:00
Laurent Cozic
a2873ebbc5 Merge branch 'release-1.1' into dev 2020-09-21 17:52:19 +01:00
Laurent Cozic
f652011d59 Desktop: Fixes #3748: Fixed issue when switching from search to "All notes" 2020-09-21 17:50:59 +01:00
Laurent Cozic
27c572b2f5 Desktop: Fixes #3700: Disable editor shortcuts when a dialog, such as GotoAnything, is visible 2020-09-21 17:31:25 +01:00
Laurent Cozic
7a4c97618d Desktop: Improved menu enabled states when not in main screen 2020-09-21 17:09:57 +01:00
Laurent Cozic
3ac4fbeee5 Desktop, Mobile: Fixes #3698: Always use light theme for notes in HTML mode 2020-09-21 16:41:24 +01:00
Laurent Cozic
9e05fa553c Desktop: Fixes #3684: Allow Read Time label to be translated 2020-09-21 16:16:28 +01:00
Laurent Cozic
d4f0d2423d CLI v1.1.8 2020-09-21 13:03:33 +01:00
Laurent Cozic
abdd7e3256 Tools: Improved git changelog 2020-09-21 13:01:46 +01:00
Laurent Cozic
f3ea476f27 Merge branch 'release-1.1' of github.com:laurent22/joplin into release-1.1 2020-09-21 12:40:28 +01:00
Laurent Cozic
aa22af443c Tools: Clean up after spellfix build 2020-09-21 12:35:20 +01:00
Laurent Cozic
ce3bd2a47d Tools: Fixed Cli version handling 2020-09-21 12:16:05 +01:00
Laurent Cozic
a9b26246e6 Merge branch 'dev' into release-1.2 2020-09-21 11:56:32 +01:00
Laurent Cozic
cc1e941dd9 Merge branch 'release-1.1' into dev 2020-09-21 11:55:47 +01:00
Laurent Cozic
9610b7e6bd Electron release v1.1.4 2020-09-21 11:42:26 +01:00
Laurent Cozic
4f2884a0f7 Started adding support for registering commands 2020-09-21 11:38:09 +01:00
Laurent Cozic
4872f1419c Also add placeholder for JSON import 2020-09-20 16:57:17 +01:00
Laurent Cozic
fdcaab3caf Got JSON export working as a plugin 2020-09-20 16:19:37 +01:00
Laurent Cozic
9f2c4b938f Added complete lib to plugin doc 2020-09-20 15:36:30 +01:00
Laurent Cozic
8be65acf7d Testing interop plugin 2020-09-20 12:09:32 +01:00
Marc BOUVIER
ad85a12535 All: Translation: Update fr_FR.po (#3776) 2020-09-19 13:35:05 -04:00
Ji-Hyeon Gim
b825346829 All: Translation: Update ko.po (#3771)
Update ko.po translations.

Signed-off-by: Ji-Hyeon Gim <potatogim@potatogim.net>
2020-09-19 13:32:37 -04:00
Ettore Atalan
bd4cbaf93d All: Translation: Update de_DE.po (#3770)
This patch includes the translation of missing strings, the improvement of the existing translation and the replacement of Anglicisms by German words.
2020-09-19 13:31:25 -04:00
Laurent Cozic
e05aa433e4 Allow creating custom exporters 2020-09-19 15:50:46 +01:00
Laurent Cozic
ccfb0b43d6 Refactor 2020-09-19 14:56:49 +01:00
Laurent Cozic
4211e962c6 Merge branch 'release-1.2' into plugin_system 2020-09-19 14:22:24 +01:00
Laurent Cozic
9af2a19bdf Merge branch 'dev' into release-1.2 2020-09-19 14:22:02 +01:00
Laurent Cozic
d3fa906a9a Merge branch 'dev' of github.com:laurent22/joplin into dev 2020-09-19 14:20:02 +01:00
Laurent Cozic
6b54c4244b Refactored 2020-09-19 14:19:09 +01:00
Laurent Cozic
1d5a4bd381 Simplified interop interface 2020-09-19 12:20:01 +01:00
Laurent Cozic
86a1103a64 Remove JSON exporter 2020-09-19 11:13:49 +01:00
Laurent Cozic
45edaaa96f Converted interop service to TypeScript 2020-09-19 11:04:29 +01:00
Laurent Cozic
b7b158aa94 Fixed doc title 2020-09-18 15:53:25 +01:00
Laurent Cozic
e6bc55b6f8 Update plugin doc 2020-09-18 15:46:25 +01:00
Laurent Cozic
111092791c Updated plugin doc 2020-09-18 13:10:47 +01:00
Laurent Cozic
4e91e01ddc Updated plugin doc 2020-09-18 13:08:01 +01:00
Laurent Cozic
44dce6c6c3 Fixed frozen state issue 2020-09-18 10:10:26 +01:00
Laurent Cozic
b25ad50a1b Add more doc 2020-09-18 09:59:22 +01:00
Gen Neko
22679641ee All: Translation: Update ja_JP.po (#3761) 2020-09-18 01:56:18 -04:00
Laurent Cozic
e2e3be66ee doc 2020-09-17 18:02:57 +01:00
Laurent Cozic
4b3119ebba Finished tutorial 2020-09-17 17:39:15 +01:00
Laurent Cozic
1712a67e2e Doc draft 2020-09-17 16:19:25 +01:00
Laurent Cozic
cd563b050c Bottom border on user views 2020-09-17 15:41:05 +01:00
Laurent Cozic
4426f2dbec Make sure plugin views can be resized 2020-09-17 15:08:43 +01:00
Laurent Cozic
0fbbf2eee0 Remember plugin view sizes 2020-09-17 14:51:50 +01:00
Laurent Cozic
0ca7457000 Electron release v1.1.3 2020-09-17 10:19:25 +01:00
Laurent Cozic
c84e49c71c All: Fixes #3696: Increased file extension limit to 20 to prevent issue when using external editors 2020-09-17 10:17:45 +01:00
Laurent Cozic
07ab0e986d Merge branch 'release-1.1' of github.com:laurent22/joplin into release-1.1 2020-09-17 10:00:30 +01:00
Laurent Cozic
17957f5da4 Desktop, Cli: Do not prevent export when one item is still encrypted 2020-09-17 10:00:13 +01:00
Naveen M V
a7b5d43e69 Desktop: Fix: Creating a note after backward redirection places it in a wrong notebook (#3759) 2020-09-17 09:32:52 +01:00
Caleb John
38eda3f151 Desktop: Fixes #3749: Use joplin list handling in emacs mode (#3758) 2020-09-17 09:29:19 +01:00
Laurent Cozic
2fdad2fe80 Make sure user views have a stable ID 2020-09-17 09:22:03 +01:00
Laurent Cozic
0249ff48ca Removed obsolete handlers 2020-09-17 08:51:12 +01:00
Laurent Cozic
142fc02f9c Simplified UserWebview component 2020-09-16 17:57:30 +01:00
Laurent Cozic
842b123285 Fixed slub 2020-09-16 17:30:39 +01:00
Laurent Cozic
a4aca68b85 Support for theme in webview 2020-09-16 17:27:13 +01:00
Laurent Cozic
1397af0692 User webviews 2020-09-16 16:19:33 +01:00
Laurent Cozic
5da760dd0c Added a way to load a plugin for development 2020-09-15 17:49:43 +01:00
Laurent Cozic
511d58d3af Various improvements 2020-09-15 17:02:02 +01:00
Laurent Cozic
a1c9e675ad Improve plugin build 2020-09-15 16:56:48 +01:00
Laurent Cozic
0349ad0b80 Merge branch 'release-1.2' into plugin_system 2020-09-15 14:41:47 +01:00
Laurent
056285deda Desktop: UI update (#3586) 2020-09-15 14:01:07 +01:00
Laurent Cozic
9d8411a25e Add TOC plugin demo 2020-09-15 13:47:47 +01:00
Laurent Cozic
754ba2267a Merge branch 'dev' into plugin_system 2020-09-15 13:41:57 +01:00
Laurent Cozic
bdedf69439 Tools: Remove console statement 2020-09-15 12:13:29 +01:00
Laurent Cozic
c9451d8675 Electron release v1.1.2 2020-09-15 12:12:16 +01:00
Laurent Cozic
c38834b04c Updated French translation 2020-09-15 12:08:49 +01:00
Laurent Cozic
851eee1500 Fixed and simplified translations 2020-09-15 12:08:25 +01:00
Laurent Cozic
4cdac308d1 Wraps console calls 2020-09-15 10:36:32 +01:00
Laurent Cozic
c0d5c7c282 Merge branch 'dev' into plugin_system 2020-09-14 14:06:21 +01:00
Laurent
f9296992bf Merge branch 'dev' into plugin_system 2020-08-01 18:58:08 +01:00
Laurent Cozic
5b06ebde1e Updated 2020-08-01 18:38:43 +01:00
Laurent Cozic
d309c75974 Merge branch 'dev' into plugin_system 2020-08-01 18:35:05 +01:00
Laurent Cozic
807c89a42f Added way to get dev mode command line 2020-07-05 18:55:21 +01:00
Laurent Cozic
0b8350e9ea Adding plugin doc 2020-07-05 17:58:24 +01:00
Laurent Cozic
49e7be8924 Ignored files 2020-07-05 17:24:20 +01:00
Laurent Cozic
810c63e3b2 Update doc 2020-07-04 18:38:12 +01:00
Laurent Cozic
d917ca5551 Added plugin doc auto-generation 2020-07-04 18:27:47 +01:00
Laurent Cozic
ec642300ab Moved sandbox to sub-folder 2020-07-04 17:56:21 +01:00
Laurent Cozic
9034d646bf Moved sandbox to a class 2020-07-04 17:02:32 +01:00
Laurent Cozic
96f6bbb035 Allow executing commands from plugin 2020-07-04 16:05:02 +01:00
Laurent Cozic
e14ed655d2 Freeze state in dev mode 2020-07-04 15:32:24 +01:00
Laurent Cozic
54e5323f54 Fixed another issue due to modifying state data 2020-07-04 15:24:53 +01:00
Laurent Cozic
ef58affed1 Fix tests 2020-07-04 15:09:14 +01:00
Laurent Cozic
76fa87d878 Fixed test issue due modification of immutable state 2020-07-04 14:52:55 +01:00
Laurent Cozic
2db2225788 Merge branch 'master' into plugin_system 2020-07-04 14:31:54 +01:00
Laurent Cozic
425c1763f4 Desktop: Fixed GotoAnything rendering issue with HTML notes 2020-07-04 12:57:19 +01:00
Laurent Cozic
044f2eac6a Improved view support 2020-06-28 17:10:34 +01:00
Laurent Cozic
281f135125 Improved view support 2020-06-28 17:08:38 +01:00
Laurent Cozic
6c88f8b8ae Merge branch 'plugin_system' of github.com:laurent22/joplin into plugin_system 2020-06-28 16:57:28 +01:00
Laurent Cozic
832abcddf0 Add support for state watch 2020-06-27 11:54:42 +01:00
Laurent Cozic
e6c481f45c Fixed tests 2020-06-27 01:05:40 +01:00
Laurent Cozic
11fecfb83a Cleaned up naming and types 2020-06-26 23:03:20 +01:00
Laurent Cozic
2facc9868e Renamed control to view 2020-06-26 22:52:40 +01:00
Laurent Cozic
7b9ad9d1c3 Moved listener to view itself 2020-06-26 22:46:45 +01:00
Laurent Cozic
3b96a99f3e Allow sending messages from webview script to plugin 2020-06-26 18:13:00 +01:00
Laurent Cozic
575ce5128b Added reducer 2020-06-26 16:14:59 +01:00
Laurent Cozic
dece28da35 Better integration of custom webviews 2020-06-25 22:15:31 +01:00
Laurent Cozic
2ffc429971 Merge branch 'master' into plugin_system 2020-06-25 20:27:38 +01:00
Laurent Cozic
8baa125842 Refactored to save plugin state in Redux store 2020-06-25 20:25:50 +01:00
Laurent Cozic
6b6092ffc7 Merge branch 'master' into plugin_system 2020-06-24 23:14:16 +01:00
Laurent Cozic
714c912aff Added support for plugin webview 2020-06-24 23:10:19 +01:00
Laurent Cozic
ebf8b744e1 Tools: Fixed build issues 2020-06-24 16:33:35 +01:00
Laurent Cozic
1039e98396 Only load plugins if dir present 2020-06-23 17:25:35 +01:00
Laurent Cozic
8f00538cb1 Merge branch 'master' into plugin_system 2020-06-22 23:07:12 +01:00
Laurent Cozic
2b530a3ff9 Merge branch 'master' into plugin_system 2020-06-21 21:37:58 +00:00
Laurent Cozic
d089511aa6 Added support filters and custom views 2020-06-21 21:30:07 +00:00
Laurent Cozic
450c8dbf22 Added support for setting and getting runtime preferences and done CodeMirror plugin test 2020-06-18 00:49:32 +01:00
Laurent Cozic
94d87285dc Merge branch 'master' into plugin_system 2020-06-17 23:50:12 +01:00
Laurent Cozic
ffeb7d0ecd Add support for TypeScript in plugins 2020-05-25 18:04:15 +01:00
Laurent Cozic
aba92857cb Load plugins from directory 2020-05-25 17:28:32 +01:00
Laurent Cozic
5918c81dbb Merge branch 'master' into plugin_system 2020-05-25 16:56:04 +01:00
Laurent Cozic
819d9fd977 Added more tests 2020-05-23 10:40:10 +01:00
Laurent Cozic
ad80e074de Started plugin system 2020-05-21 23:51:51 +00:00
1361 changed files with 113004 additions and 10386 deletions

View File

@@ -59,18 +59,54 @@ Tools/node_modules
Tools/PortableAppsLauncher
Modules/TinyMCE/IconPack/postinstall.js
Modules/TinyMCE/langs/
CliClient/build/
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
CliClient/app/LinkSelector.js
CliClient/build/LinkSelector.js
CliClient/app/services/plugins/PluginRunner.js
CliClient/tests/models_Setting.js
CliClient/tests/services_CommandService.js
CliClient/tests/services_InteropService.js
CliClient/tests/services_PluginService.js
CliClient/tests/services/plugins/sandboxProxy.js
CliClient/tests/support/plugins/codemirror_test/global.d.js
CliClient/tests/support/plugins/codemirror_test/src/index.js
CliClient/tests/support/plugins/dialog/global.d.js
CliClient/tests/support/plugins/dialog/src/index.js
CliClient/tests/support/plugins/events/global.d.js
CliClient/tests/support/plugins/events/src/index.js
CliClient/tests/support/plugins/json_export/global.d.js
CliClient/tests/support/plugins/json_export/src/index.js
CliClient/tests/support/plugins/markdown_plugin/global.d.js
CliClient/tests/support/plugins/markdown_plugin/src/index.js
CliClient/tests/support/plugins/multi_selection/global.d.js
CliClient/tests/support/plugins/multi_selection/src/index.js
CliClient/tests/support/plugins/register_command/global.d.js
CliClient/tests/support/plugins/register_command/src/index.js
CliClient/tests/support/plugins/selected_text/global.d.js
CliClient/tests/support/plugins/selected_text/src/index.js
CliClient/tests/support/plugins/settings/global.d.js
CliClient/tests/support/plugins/settings/src/index.js
CliClient/tests/support/plugins/toc/global.d.js
CliClient/tests/support/plugins/toc/src/index.js
CliClient/tests/support/plugins/withExternalModules/global.d.js
CliClient/tests/support/plugins/withExternalModules/src/index.js
CliClient/tests/synchronizer_LockHandler.js
CliClient/tests/synchronizer_MigrationHandler.js
ElectronClient/app.js
ElectronClient/bridge.js
ElectronClient/commands/copyDevCommand.js
ElectronClient/commands/focusElement.js
ElectronClient/commands/startExternalEditing.js
ElectronClient/commands/stopExternalEditing.js
ElectronClient/ElectronAppWrapper.js
ElectronClient/global.d.js
ElectronClient/gui/Button/Button.js
ElectronClient/gui/ConfigScreen/ButtonBar.js
ElectronClient/gui/ConfigScreen/ConfigScreen.js
ElectronClient/gui/ConfigScreen/SideBar.js
ElectronClient/gui/DropboxLoginScreen.js
ElectronClient/gui/ErrorBoundary.js
ElectronClient/gui/Header/commands/focusSearch.js
ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js
ElectronClient/gui/KeymapConfig/ShortcutRecorder.js
ElectronClient/gui/KeymapConfig/styles/index.js
@@ -81,8 +117,8 @@ ElectronClient/gui/MainScreen/commands/editAlarm.js
ElectronClient/gui/MainScreen/commands/exportPdf.js
ElectronClient/gui/MainScreen/commands/hideModalMessage.js
ElectronClient/gui/MainScreen/commands/moveToFolder.js
ElectronClient/gui/MainScreen/commands/newFolder.js
ElectronClient/gui/MainScreen/commands/newNote.js
ElectronClient/gui/MainScreen/commands/newNotebook.js
ElectronClient/gui/MainScreen/commands/newTodo.js
ElectronClient/gui/MainScreen/commands/print.js
ElectronClient/gui/MainScreen/commands/renameFolder.js
@@ -94,9 +130,12 @@ ElectronClient/gui/MainScreen/commands/showModalMessage.js
ElectronClient/gui/MainScreen/commands/showNoteContentProperties.js
ElectronClient/gui/MainScreen/commands/showNoteProperties.js
ElectronClient/gui/MainScreen/commands/showShareNoteDialog.js
ElectronClient/gui/MainScreen/commands/toggleEditors.js
ElectronClient/gui/MainScreen/commands/toggleNoteList.js
ElectronClient/gui/MainScreen/commands/toggleSidebar.js
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
ElectronClient/gui/MainScreen/MainScreen.js
ElectronClient/gui/MenuBar.js
ElectronClient/gui/MultiNoteActions.js
ElectronClient/gui/NoteContentPropertiesDialog.js
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
@@ -113,9 +152,11 @@ ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useJoplinMode.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useLineSorting.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
ElectronClient/gui/NoteEditor/NoteEditor.js
@@ -125,41 +166,138 @@ ElectronClient/gui/NoteEditor/utils/index.js
ElectronClient/gui/NoteEditor/utils/resourceHandling.js
ElectronClient/gui/NoteEditor/utils/types.js
ElectronClient/gui/NoteEditor/utils/useDropHandler.js
ElectronClient/gui/NoteEditor/utils/useFolder.js
ElectronClient/gui/NoteEditor/utils/useFormNote.js
ElectronClient/gui/NoteEditor/utils/useMarkupToHtml.js
ElectronClient/gui/NoteEditor/utils/useMessageHandler.js
ElectronClient/gui/NoteEditor/utils/useNoteSearchBar.js
ElectronClient/gui/NoteEditor/utils/usePluginServiceRegistration.js
ElectronClient/gui/NoteEditor/utils/useSearchMarkers.js
ElectronClient/gui/NoteEditor/utils/useWindowCommandHandler.js
ElectronClient/gui/NoteList/commands/focusElementNoteList.js
ElectronClient/gui/NoteList/NoteList.js
ElectronClient/gui/NoteListControls/commands/focusSearch.js
ElectronClient/gui/NoteListControls/NoteListControls.js
ElectronClient/gui/NoteListItem.js
ElectronClient/gui/NoteTextViewer.js
ElectronClient/gui/NoteToolbar/NoteToolbar.js
ElectronClient/gui/OneDriveLoginScreen.js
ElectronClient/gui/ResizableLayout/hooks/useLayoutItemSizes.js
ElectronClient/gui/ResizableLayout/hooks/useWindowResizeEvent.js
ElectronClient/gui/ResizableLayout/ResizableLayout.js
ElectronClient/gui/ResourceScreen.js
ElectronClient/gui/Root_UpgradeSyncTarget.js
ElectronClient/gui/Root.js
ElectronClient/gui/SearchBar/hooks/useSearch.js
ElectronClient/gui/SearchBar/SearchBar.js
ElectronClient/gui/SearchBar/styles/index.js
ElectronClient/gui/ShareNoteDialog.js
ElectronClient/gui/SideBar/commands/focusElementSideBar.js
ElectronClient/gui/SideBar/SideBar.js
ElectronClient/gui/SideBar/styles/index.js
ElectronClient/gui/StatusScreen/StatusScreen.js
ElectronClient/gui/style/StyledInput.js
ElectronClient/gui/style/StyledTextInput.js
ElectronClient/gui/ToggleEditorsButton/styles/index.js
ElectronClient/gui/ToggleEditorsButton/ToggleEditorsButton.js
ElectronClient/gui/ToolbarBase.js
ElectronClient/gui/ToolbarButton/styles/index.js
ElectronClient/gui/ToolbarButton/ToolbarButton.js
ElectronClient/gui/utils/NoteListUtils.js
ElectronClient/InteropServiceHelper.js
ElectronClient/services/bridge.js
ElectronClient/services/plugins/hooks/useThemeCss.js
ElectronClient/services/plugins/hooks/useViewIsReady.js
ElectronClient/services/plugins/PlatformImplementation.js
ElectronClient/services/plugins/PluginRunner.js
ElectronClient/services/plugins/UserWebview.js
ElectronClient/services/plugins/UserWebviewDialog.js
ElectronClient/services/plugins/UserWebviewDialogButtonBar.js
ReactNativeClient/lib/AsyncActionQueue.js
ReactNativeClient/lib/BaseApplication.js
ReactNativeClient/lib/checkPermissions.js
ReactNativeClient/lib/commands/historyBackward.js
ReactNativeClient/lib/commands/historyForward.js
ReactNativeClient/lib/commands/synchronize.js
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
ReactNativeClient/lib/eventManager.js
ReactNativeClient/lib/hooks/useEffectDebugger.js
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
ReactNativeClient/lib/hooks/usePrevious.js
ReactNativeClient/lib/hooks/usePropsDebugger.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
ReactNativeClient/lib/JoplinServerApi.js
ReactNativeClient/lib/locale.js
ReactNativeClient/lib/Logger.js
ReactNativeClient/lib/models/Alarm.js
ReactNativeClient/lib/models/Setting.js
ReactNativeClient/lib/ntpDate.js
ReactNativeClient/lib/reducer.js
ReactNativeClient/lib/services/AlarmService.js
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
ReactNativeClient/lib/services/AlarmServiceDriver.ios.js
ReactNativeClient/lib/services/AlarmServiceDriverNode.js
ReactNativeClient/lib/services/BaseService.js
ReactNativeClient/lib/services/BooleanExpression.js
ReactNativeClient/lib/services/commands/MenuUtils.js
ReactNativeClient/lib/services/commands/propsHaveChanged.js
ReactNativeClient/lib/services/commands/ToolbarButtonUtils.js
ReactNativeClient/lib/services/CommandService.js
ReactNativeClient/lib/services/contextkey/contextkey.js
ReactNativeClient/lib/services/debug/populateDatabase.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Base.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Custom.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Html.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Jex.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Md.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Raw.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Base.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Custom.js
ReactNativeClient/lib/services/interop/InteropService_Importer_EnexToHtml.js
ReactNativeClient/lib/services/interop/InteropService_Importer_EnexToMd.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Jex.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Md.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Raw.js
ReactNativeClient/lib/services/interop/InteropService.js
ReactNativeClient/lib/services/interop/types.js
ReactNativeClient/lib/services/keychain/KeychainService.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.dummy.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.mobile.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.node.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriverBase.js
ReactNativeClient/lib/services/KeymapService.js
ReactNativeClient/lib/services/plugins/api/Global.js
ReactNativeClient/lib/services/plugins/api/Joplin.js
ReactNativeClient/lib/services/plugins/api/JoplinCommands.js
ReactNativeClient/lib/services/plugins/api/JoplinData.js
ReactNativeClient/lib/services/plugins/api/JoplinFilters.js
ReactNativeClient/lib/services/plugins/api/JoplinInterop.js
ReactNativeClient/lib/services/plugins/api/JoplinPlugins.js
ReactNativeClient/lib/services/plugins/api/JoplinSettings.js
ReactNativeClient/lib/services/plugins/api/JoplinUtils.js
ReactNativeClient/lib/services/plugins/api/JoplinViews.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsDialogs.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenuItems.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsPanels.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsToolbarButtons.js
ReactNativeClient/lib/services/plugins/api/JoplinWorkspace.js
ReactNativeClient/lib/services/plugins/BasePluginRunner.js
ReactNativeClient/lib/services/plugins/MenuItemController.js
ReactNativeClient/lib/services/plugins/Plugin.js
ReactNativeClient/lib/services/plugins/PluginService.js
ReactNativeClient/lib/services/plugins/reducer.js
ReactNativeClient/lib/services/plugins/sandboxProxy.js
ReactNativeClient/lib/services/plugins/ToolbarButtonController.js
ReactNativeClient/lib/services/plugins/utils/createViewHandle.js
ReactNativeClient/lib/services/plugins/utils/executeSandboxCall.js
ReactNativeClient/lib/services/plugins/utils/manifestFromObject.js
ReactNativeClient/lib/services/plugins/utils/mapEventHandlersToIds.js
ReactNativeClient/lib/services/plugins/utils/types.js
ReactNativeClient/lib/services/plugins/ViewController.js
ReactNativeClient/lib/services/plugins/WebviewController.js
ReactNativeClient/lib/services/ResourceEditWatcher/index.js
ReactNativeClient/lib/services/ResourceEditWatcher/reducer.js
ReactNativeClient/lib/services/rest/actionApi.desktop.js
@@ -176,6 +314,19 @@ ReactNativeClient/lib/services/synchronizer/utils/types.js
ReactNativeClient/lib/services/UndoRedoService.js
ReactNativeClient/lib/ShareExtension.js
ReactNativeClient/lib/shareHandler.js
ReactNativeClient/lib/shim.js
ReactNativeClient/lib/Synchronizer.js
ReactNativeClient/lib/theme.js
ReactNativeClient/lib/themes/aritimDark.js
ReactNativeClient/lib/themes/dark.js
ReactNativeClient/lib/themes/dracula.js
ReactNativeClient/lib/themes/light.js
ReactNativeClient/lib/themes/nord.js
ReactNativeClient/lib/themes/oledDark.js
ReactNativeClient/lib/themes/solarizedDark.js
ReactNativeClient/lib/themes/solarizedLight.js
ReactNativeClient/lib/themes/type.js
ReactNativeClient/lib/uuid.js
ReactNativeClient/lib/versionInfo.js
ReactNativeClient/PluginAssetsLoader.js
ReactNativeClient/setUpQuickActions.js

View File

@@ -48,8 +48,9 @@ module.exports = {
// -------------------------------
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'no-unused-vars': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'no-unused-vars': ['error', { 'argsIgnorePattern': '^_' }],
'@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': '^_' }],
'@typescript-eslint/explicit-member-accessibility': 'off',
'no-constant-condition': 0,
'no-prototype-builtins': 0,
// This error is always a false positive so far since it detects
@@ -121,4 +122,15 @@ module.exports = {
'react-hooks',
'import',
],
'overrides': [
{
// enable the rule specifically for TypeScript files
'files': ['*.ts', '*.tsx'],
'rules': {
// Warn only because it would make it difficult to convert JS classes to TypeScript, unless we
// make everything public which is not great. New code however should specify member accessibility.
'@typescript-eslint/explicit-member-accessibility': ['warn'],
},
},
],
};

161
.gitignore vendored
View File

@@ -50,20 +50,56 @@ joplin-webclipper-source.zip
Tools/commit_hook.txt
.vscode/*
*.map
ReactNativeClient/lib/sql-extensions/
!ReactNativeClient/lib/sql-extensions/spellfix.dll
ReactNativeClient/lib/sql-extensions/spellfix.so
ReactNativeClient/lib/sql-extensions/spellfix.dylib
CliClient/build/
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
CliClient/app/LinkSelector.js
CliClient/build/LinkSelector.js
CliClient/app/services/plugins/PluginRunner.js
CliClient/tests/models_Setting.js
CliClient/tests/services_CommandService.js
CliClient/tests/services_InteropService.js
CliClient/tests/services_PluginService.js
CliClient/tests/services/plugins/sandboxProxy.js
CliClient/tests/support/plugins/codemirror_test/global.d.js
CliClient/tests/support/plugins/codemirror_test/src/index.js
CliClient/tests/support/plugins/dialog/global.d.js
CliClient/tests/support/plugins/dialog/src/index.js
CliClient/tests/support/plugins/events/global.d.js
CliClient/tests/support/plugins/events/src/index.js
CliClient/tests/support/plugins/json_export/global.d.js
CliClient/tests/support/plugins/json_export/src/index.js
CliClient/tests/support/plugins/markdown_plugin/global.d.js
CliClient/tests/support/plugins/markdown_plugin/src/index.js
CliClient/tests/support/plugins/multi_selection/global.d.js
CliClient/tests/support/plugins/multi_selection/src/index.js
CliClient/tests/support/plugins/register_command/global.d.js
CliClient/tests/support/plugins/register_command/src/index.js
CliClient/tests/support/plugins/selected_text/global.d.js
CliClient/tests/support/plugins/selected_text/src/index.js
CliClient/tests/support/plugins/settings/global.d.js
CliClient/tests/support/plugins/settings/src/index.js
CliClient/tests/support/plugins/toc/global.d.js
CliClient/tests/support/plugins/toc/src/index.js
CliClient/tests/support/plugins/withExternalModules/global.d.js
CliClient/tests/support/plugins/withExternalModules/src/index.js
CliClient/tests/synchronizer_LockHandler.js
CliClient/tests/synchronizer_MigrationHandler.js
ElectronClient/app.js
ElectronClient/bridge.js
ElectronClient/commands/copyDevCommand.js
ElectronClient/commands/focusElement.js
ElectronClient/commands/startExternalEditing.js
ElectronClient/commands/stopExternalEditing.js
ElectronClient/ElectronAppWrapper.js
ElectronClient/global.d.js
ElectronClient/gui/Button/Button.js
ElectronClient/gui/ConfigScreen/ButtonBar.js
ElectronClient/gui/ConfigScreen/ConfigScreen.js
ElectronClient/gui/ConfigScreen/SideBar.js
ElectronClient/gui/DropboxLoginScreen.js
ElectronClient/gui/ErrorBoundary.js
ElectronClient/gui/Header/commands/focusSearch.js
ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js
ElectronClient/gui/KeymapConfig/ShortcutRecorder.js
ElectronClient/gui/KeymapConfig/styles/index.js
@@ -74,8 +110,8 @@ ElectronClient/gui/MainScreen/commands/editAlarm.js
ElectronClient/gui/MainScreen/commands/exportPdf.js
ElectronClient/gui/MainScreen/commands/hideModalMessage.js
ElectronClient/gui/MainScreen/commands/moveToFolder.js
ElectronClient/gui/MainScreen/commands/newFolder.js
ElectronClient/gui/MainScreen/commands/newNote.js
ElectronClient/gui/MainScreen/commands/newNotebook.js
ElectronClient/gui/MainScreen/commands/newTodo.js
ElectronClient/gui/MainScreen/commands/print.js
ElectronClient/gui/MainScreen/commands/renameFolder.js
@@ -87,9 +123,12 @@ ElectronClient/gui/MainScreen/commands/showModalMessage.js
ElectronClient/gui/MainScreen/commands/showNoteContentProperties.js
ElectronClient/gui/MainScreen/commands/showNoteProperties.js
ElectronClient/gui/MainScreen/commands/showShareNoteDialog.js
ElectronClient/gui/MainScreen/commands/toggleEditors.js
ElectronClient/gui/MainScreen/commands/toggleNoteList.js
ElectronClient/gui/MainScreen/commands/toggleSidebar.js
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
ElectronClient/gui/MainScreen/MainScreen.js
ElectronClient/gui/MenuBar.js
ElectronClient/gui/MultiNoteActions.js
ElectronClient/gui/NoteContentPropertiesDialog.js
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
@@ -106,9 +145,11 @@ ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useJoplinMode.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useLineSorting.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
ElectronClient/gui/NoteEditor/NoteEditor.js
@@ -118,41 +159,138 @@ ElectronClient/gui/NoteEditor/utils/index.js
ElectronClient/gui/NoteEditor/utils/resourceHandling.js
ElectronClient/gui/NoteEditor/utils/types.js
ElectronClient/gui/NoteEditor/utils/useDropHandler.js
ElectronClient/gui/NoteEditor/utils/useFolder.js
ElectronClient/gui/NoteEditor/utils/useFormNote.js
ElectronClient/gui/NoteEditor/utils/useMarkupToHtml.js
ElectronClient/gui/NoteEditor/utils/useMessageHandler.js
ElectronClient/gui/NoteEditor/utils/useNoteSearchBar.js
ElectronClient/gui/NoteEditor/utils/usePluginServiceRegistration.js
ElectronClient/gui/NoteEditor/utils/useSearchMarkers.js
ElectronClient/gui/NoteEditor/utils/useWindowCommandHandler.js
ElectronClient/gui/NoteList/commands/focusElementNoteList.js
ElectronClient/gui/NoteList/NoteList.js
ElectronClient/gui/NoteListControls/commands/focusSearch.js
ElectronClient/gui/NoteListControls/NoteListControls.js
ElectronClient/gui/NoteListItem.js
ElectronClient/gui/NoteTextViewer.js
ElectronClient/gui/NoteToolbar/NoteToolbar.js
ElectronClient/gui/OneDriveLoginScreen.js
ElectronClient/gui/ResizableLayout/hooks/useLayoutItemSizes.js
ElectronClient/gui/ResizableLayout/hooks/useWindowResizeEvent.js
ElectronClient/gui/ResizableLayout/ResizableLayout.js
ElectronClient/gui/ResourceScreen.js
ElectronClient/gui/Root_UpgradeSyncTarget.js
ElectronClient/gui/Root.js
ElectronClient/gui/SearchBar/hooks/useSearch.js
ElectronClient/gui/SearchBar/SearchBar.js
ElectronClient/gui/SearchBar/styles/index.js
ElectronClient/gui/ShareNoteDialog.js
ElectronClient/gui/SideBar/commands/focusElementSideBar.js
ElectronClient/gui/SideBar/SideBar.js
ElectronClient/gui/SideBar/styles/index.js
ElectronClient/gui/StatusScreen/StatusScreen.js
ElectronClient/gui/style/StyledInput.js
ElectronClient/gui/style/StyledTextInput.js
ElectronClient/gui/ToggleEditorsButton/styles/index.js
ElectronClient/gui/ToggleEditorsButton/ToggleEditorsButton.js
ElectronClient/gui/ToolbarBase.js
ElectronClient/gui/ToolbarButton/styles/index.js
ElectronClient/gui/ToolbarButton/ToolbarButton.js
ElectronClient/gui/utils/NoteListUtils.js
ElectronClient/InteropServiceHelper.js
ElectronClient/services/bridge.js
ElectronClient/services/plugins/hooks/useThemeCss.js
ElectronClient/services/plugins/hooks/useViewIsReady.js
ElectronClient/services/plugins/PlatformImplementation.js
ElectronClient/services/plugins/PluginRunner.js
ElectronClient/services/plugins/UserWebview.js
ElectronClient/services/plugins/UserWebviewDialog.js
ElectronClient/services/plugins/UserWebviewDialogButtonBar.js
ReactNativeClient/lib/AsyncActionQueue.js
ReactNativeClient/lib/BaseApplication.js
ReactNativeClient/lib/checkPermissions.js
ReactNativeClient/lib/commands/historyBackward.js
ReactNativeClient/lib/commands/historyForward.js
ReactNativeClient/lib/commands/synchronize.js
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
ReactNativeClient/lib/eventManager.js
ReactNativeClient/lib/hooks/useEffectDebugger.js
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
ReactNativeClient/lib/hooks/usePrevious.js
ReactNativeClient/lib/hooks/usePropsDebugger.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
ReactNativeClient/lib/JoplinServerApi.js
ReactNativeClient/lib/locale.js
ReactNativeClient/lib/Logger.js
ReactNativeClient/lib/models/Alarm.js
ReactNativeClient/lib/models/Setting.js
ReactNativeClient/lib/ntpDate.js
ReactNativeClient/lib/reducer.js
ReactNativeClient/lib/services/AlarmService.js
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
ReactNativeClient/lib/services/AlarmServiceDriver.ios.js
ReactNativeClient/lib/services/AlarmServiceDriverNode.js
ReactNativeClient/lib/services/BaseService.js
ReactNativeClient/lib/services/BooleanExpression.js
ReactNativeClient/lib/services/commands/MenuUtils.js
ReactNativeClient/lib/services/commands/propsHaveChanged.js
ReactNativeClient/lib/services/commands/ToolbarButtonUtils.js
ReactNativeClient/lib/services/CommandService.js
ReactNativeClient/lib/services/contextkey/contextkey.js
ReactNativeClient/lib/services/debug/populateDatabase.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Base.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Custom.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Html.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Jex.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Md.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Raw.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Base.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Custom.js
ReactNativeClient/lib/services/interop/InteropService_Importer_EnexToHtml.js
ReactNativeClient/lib/services/interop/InteropService_Importer_EnexToMd.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Jex.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Md.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Raw.js
ReactNativeClient/lib/services/interop/InteropService.js
ReactNativeClient/lib/services/interop/types.js
ReactNativeClient/lib/services/keychain/KeychainService.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.dummy.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.mobile.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.node.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriverBase.js
ReactNativeClient/lib/services/KeymapService.js
ReactNativeClient/lib/services/plugins/api/Global.js
ReactNativeClient/lib/services/plugins/api/Joplin.js
ReactNativeClient/lib/services/plugins/api/JoplinCommands.js
ReactNativeClient/lib/services/plugins/api/JoplinData.js
ReactNativeClient/lib/services/plugins/api/JoplinFilters.js
ReactNativeClient/lib/services/plugins/api/JoplinInterop.js
ReactNativeClient/lib/services/plugins/api/JoplinPlugins.js
ReactNativeClient/lib/services/plugins/api/JoplinSettings.js
ReactNativeClient/lib/services/plugins/api/JoplinUtils.js
ReactNativeClient/lib/services/plugins/api/JoplinViews.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsDialogs.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenuItems.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsPanels.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsToolbarButtons.js
ReactNativeClient/lib/services/plugins/api/JoplinWorkspace.js
ReactNativeClient/lib/services/plugins/BasePluginRunner.js
ReactNativeClient/lib/services/plugins/MenuItemController.js
ReactNativeClient/lib/services/plugins/Plugin.js
ReactNativeClient/lib/services/plugins/PluginService.js
ReactNativeClient/lib/services/plugins/reducer.js
ReactNativeClient/lib/services/plugins/sandboxProxy.js
ReactNativeClient/lib/services/plugins/ToolbarButtonController.js
ReactNativeClient/lib/services/plugins/utils/createViewHandle.js
ReactNativeClient/lib/services/plugins/utils/executeSandboxCall.js
ReactNativeClient/lib/services/plugins/utils/manifestFromObject.js
ReactNativeClient/lib/services/plugins/utils/mapEventHandlersToIds.js
ReactNativeClient/lib/services/plugins/utils/types.js
ReactNativeClient/lib/services/plugins/ViewController.js
ReactNativeClient/lib/services/plugins/WebviewController.js
ReactNativeClient/lib/services/ResourceEditWatcher/index.js
ReactNativeClient/lib/services/ResourceEditWatcher/reducer.js
ReactNativeClient/lib/services/rest/actionApi.desktop.js
@@ -169,6 +307,19 @@ ReactNativeClient/lib/services/synchronizer/utils/types.js
ReactNativeClient/lib/services/UndoRedoService.js
ReactNativeClient/lib/ShareExtension.js
ReactNativeClient/lib/shareHandler.js
ReactNativeClient/lib/shim.js
ReactNativeClient/lib/Synchronizer.js
ReactNativeClient/lib/theme.js
ReactNativeClient/lib/themes/aritimDark.js
ReactNativeClient/lib/themes/dark.js
ReactNativeClient/lib/themes/dracula.js
ReactNativeClient/lib/themes/light.js
ReactNativeClient/lib/themes/nord.js
ReactNativeClient/lib/themes/oledDark.js
ReactNativeClient/lib/themes/solarizedDark.js
ReactNativeClient/lib/themes/solarizedLight.js
ReactNativeClient/lib/themes/type.js
ReactNativeClient/lib/uuid.js
ReactNativeClient/lib/versionInfo.js
ReactNativeClient/PluginAssetsLoader.js
ReactNativeClient/setUpQuickActions.js

View File

@@ -11,6 +11,7 @@ Note that all the applications share the same library, which, for historical rea
- macOS, Linux: Install rsync - https://nodejs.org/en/
- macOS: Install Cocoapods - `brew install cocoapods`
- Windows: Install Windows Build Tools - `npm install -g windows-build-tools`
- Linux: Install dependencies - `sudo apt install libnss3 libsecret-1-dev`
## Building
@@ -25,6 +26,8 @@ Then you can test the various applications:
cd ElectronClient
npm start
You can also run it under WSL 2. To do so, [follow these instructions](https://www.beekeeperstudio.io/blog/building-electron-windows-ubuntu-wsl2) to setup your environment.
## Testing the Terminal application
cd CliClient

View File

@@ -1,4 +1,4 @@
const { Logger } = require('lib/logger.js');
const Logger = require('lib/Logger').default;
const { netUtils } = require('lib/net-utils.js');
const http = require('http');

View File

@@ -1,15 +1,17 @@
const { Logger } = require('lib/logger.js');
const Logger = require('lib/Logger').default;
const Folder = require('lib/models/Folder.js');
const BaseItem = require('lib/models/BaseItem.js');
const Tag = require('lib/models/Tag.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const Resource = require('lib/models/Resource.js');
const Setting = require('lib/models/Setting.js');
const { reducer, defaultState } = require('lib/reducer.js');
const Setting = require('lib/models/Setting').default;
const reducer = require('lib/reducer').default;
const { defaultState } = require('lib/reducer');
const { splitCommandString } = require('lib/string-utils.js');
const { reg } = require('lib/registry.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const shim = require('lib/shim').default;
const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = new Entities().encode;
@@ -477,7 +479,7 @@ class AppGui {
this.linkSelector_.noteX + cursorOffsetX,
this.linkSelector_.noteY + cursorOffsetY
);
setTimeout(() => this.term_.term().inverse(this.linkSelector_.link), 50);
shim.setTimeout(() => this.term_.term().inverse(this.linkSelector_.link), 50);
}
} else if (cmd === 'open_link') {
if (this.widget('noteText').hasFocus) {

View File

@@ -1,4 +1,4 @@
const { BaseApplication } = require('lib/BaseApplication');
const BaseApplication = require('lib/BaseApplication').default;
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
const ResourceService = require('lib/services/ResourceService');
const BaseModel = require('lib/BaseModel.js');
@@ -6,14 +6,15 @@ const Folder = require('lib/models/Folder.js');
const BaseItem = require('lib/models/BaseItem.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const { reg } = require('lib/registry.js');
const { fileExtension } = require('lib/path-utils.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const fs = require('fs-extra');
const { cliUtils } = require('./cli-utils.js');
const Cache = require('lib/Cache');
const RevisionService = require('lib/services/RevisionService');
const shim = require('lib/shim').default;
class Application extends BaseApplication {
constructor() {
@@ -161,7 +162,7 @@ class Application extends BaseApplication {
};
// Give it a few seconds to cancel otherwise exit anyway
setTimeout(async () => {
shim.setTimeout(async () => {
await doExit();
}, 5000);

View File

@@ -1,4 +1,4 @@
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const { reg } = require('lib/registry.js');
class BaseCommand {

View File

@@ -1,7 +1,7 @@
const fs = require('fs-extra');
const { fileExtension, dirname } = require('lib/path-utils.js');
const wrap_ = require('word-wrap');
const { languageCode } = require('lib/locale.js');
const { languageCode } = require('lib/locale');
const rootDir = dirname(dirname(__dirname));
const MAX_WIDTH = 78;

View File

@@ -1,14 +1,14 @@
'use strict';
const fs = require('fs-extra');
const { Logger } = require('lib/logger.js');
const Logger = require('lib/Logger').default;
const { dirname } = require('lib/path-utils.js');
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
const { JoplinDatabase } = require('lib/joplin-database.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const { sprintf } = require('sprintf-js');
const exec = require('child_process').exec;

View File

@@ -1,8 +1,8 @@
const yargParser = require('yargs-parser');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const { time } = require('lib/time-utils.js');
const stringPadding = require('string-padding');
const { Logger } = require('lib/logger.js');
const Logger = require('lib/Logger').default;
const cliUtils = {};

View File

@@ -1,8 +1,8 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim.js');
const shim = require('lib/shim').default;
class Command extends BaseCommand {
usage() {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const BaseItem = require('lib/models/BaseItem.js');
const Note = require('lib/models/Note.js');

View File

@@ -1,8 +1,8 @@
const { BaseCommand } = require('./base-command.js');
const { _, setLocale } = require('lib/locale.js');
const { _, setLocale } = require('lib/locale');
const { app } = require('./app.js');
const fs = require('fs-extra');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
class Command extends BaseCommand {
usage() {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');

View File

@@ -1,10 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const EncryptionService = require('lib/services/EncryptionService');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const BaseItem = require('lib/models/BaseItem');
const Setting = require('lib/models/Setting.js');
const { shim } = require('lib/shim');
const Setting = require('lib/models/Setting').default;
const shim = require('lib/shim').default;
const pathUtils = require('lib/path-utils.js');
const imageType = require('image-type');
const readChunk = require('read-chunk');
@@ -38,7 +38,7 @@ class Command extends BaseCommand {
this.stdout(_('Operation cancelled'));
return false;
}
Setting.setObjectKey('encryption.passwordCache', masterKeyId, password);
Setting.setObjectValue('encryption.passwordCache', masterKeyId, password);
await EncryptionService.instance().loadMasterKeysFromSettings();
return true;
};

View File

@@ -1,11 +1,11 @@
const fs = require('fs-extra');
const { BaseCommand } = require('./base-command.js');
const { splitCommandString } = require('lib/string-utils.js');
const { uuid } = require('lib/uuid.js');
const uuid = require('lib/uuid').default;
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const BaseModel = require('lib/BaseModel.js');
class Command extends BaseCommand {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
class Command extends BaseCommand {
usage() {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const { ReportService } = require('lib/services/report.js');
const fs = require('fs-extra');

View File

@@ -1,8 +1,8 @@
const { BaseCommand } = require('./base-command.js');
const InteropService = require('lib/services/InteropService.js');
const InteropService = require('lib/services/interop/InteropService').default;
const BaseModel = require('lib/BaseModel.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
class Command extends BaseCommand {
usage() {
@@ -14,7 +14,7 @@ class Command extends BaseCommand {
}
options() {
const service = new InteropService();
const service = InteropService.instance();
const formats = service
.modules()
.filter(m => m.type === 'exporter' && m.format !== 'html')
@@ -41,7 +41,7 @@ class Command extends BaseCommand {
exportOptions.sourceFolderIds = folders.map(n => n.id);
}
const service = new InteropService();
const service = InteropService.instance();
const result = await service.export(exportOptions);
result.warnings.map(w => this.stdout(w));

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');

View File

@@ -1,7 +1,7 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { renderCommandHelp } = require('./help-utils.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {

View File

@@ -1,9 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const InteropService = require('lib/services/InteropService.js');
const InteropService = require('lib/services/interop/InteropService').default;
const BaseModel = require('lib/BaseModel.js');
const { cliUtils } = require('./cli-utils.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
class Command extends BaseCommand {
usage() {
@@ -15,7 +15,7 @@ class Command extends BaseCommand {
}
options() {
const service = new InteropService();
const service = InteropService.instance();
const formats = service
.modules()
.filter(m => m.type === 'importer')
@@ -63,7 +63,7 @@ class Command extends BaseCommand {
app().gui().showConsole();
this.stdout(_('Importing notes...'));
const service = new InteropService();
const service = InteropService.instance();
const result = await service.import(importOptions);
result.warnings.map(w => this.stdout(w));
cliUtils.redrawDone();

View File

@@ -1,9 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const Note = require('lib/models/Note.js');
const { sprintf } = require('sprintf-js');
const { time } = require('lib/time-utils.js');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const Folder = require('lib/models/Folder.js');
class Command extends BaseCommand {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const Folder = require('lib/models/Folder.js');
const BaseModel = require('lib/BaseModel.js');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');

View File

@@ -1,8 +1,8 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const { uuid } = require('lib/uuid.js');
const uuid = require('lib/uuid').default;
class Command extends BaseCommand {
usage() {

View File

@@ -1,8 +1,8 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const Setting = require('lib/models/Setting.js');
const { Logger } = require('lib/logger.js');
const { shim } = require('lib/shim');
const { _ } = require('lib/locale');
const Setting = require('lib/models/Setting').default;
const Logger = require('lib/Logger').default;
const shim = require('lib/shim').default;
class Command extends BaseCommand {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const { Database } = require('lib/database.js');
const Note = require('lib/models/Note.js');

View File

@@ -1,7 +1,7 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const Setting = require('lib/models/Setting.js');
const { _ } = require('lib/locale.js');
const Setting = require('lib/models/Setting').default;
const { _ } = require('lib/locale');
const { ReportService } = require('lib/services/report.js');
class Command extends BaseCommand {

View File

@@ -1,10 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const { OneDriveApiNodeUtils } = require('lib/onedrive-api-node-utils.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const ResourceFetcher = require('lib/services/ResourceFetcher');
const { Synchronizer } = require('lib/synchronizer.js');
const Synchronizer = require('lib/Synchronizer').default;
const { reg } = require('lib/registry.js');
const { cliUtils } = require('./cli-utils.js');
const md5 = require('md5');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const Tag = require('lib/models/Tag.js');
const BaseModel = require('lib/BaseModel.js');
const { time } = require('lib/time-utils.js');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');

View File

@@ -1,5 +1,5 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const CommandDone = require('./command-done.js');

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const BaseModel = require('lib/BaseModel.js');
class Command extends BaseCommand {

View File

@@ -1,6 +1,6 @@
const { BaseCommand } = require('./base-command.js');
const Setting = require('lib/models/Setting.js');
const { _ } = require('lib/locale.js');
const Setting = require('lib/models/Setting').default;
const { _ } = require('lib/locale');
class Command extends BaseCommand {
usage() {

View File

@@ -1,7 +1,7 @@
'use strict';
const { time } = require('lib/time-utils.js');
const { Logger } = require('lib/logger.js');
const Logger = require('lib/Logger').default;
const Resource = require('lib/models/Resource.js');
const { dirname } = require('lib/path-utils.js');
const { FsDriverNode } = require('./fs-driver-node.js');

View File

@@ -2,7 +2,7 @@ const Folder = require('lib/models/Folder.js');
const Tag = require('lib/models/Tag.js');
const BaseModel = require('lib/BaseModel.js');
const ListWidget = require('tkwidgets/ListWidget.js');
const _ = require('lib/locale.js')._;
const _ = require('lib/locale')._;
class FolderListWidget extends ListWidget {
constructor() {

View File

@@ -1,6 +1,6 @@
const Note = require('lib/models/Note.js');
const TextWidget = require('tkwidgets/TextWidget.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
class NoteWidget extends TextWidget {
constructor() {

View File

@@ -1,6 +1,6 @@
const { wrap } = require('lib/string-utils.js');
const Setting = require('lib/models/Setting.js');
const { _ } = require('lib/locale.js');
const Setting = require('lib/models/Setting').default;
const { _ } = require('lib/locale');
const MAX_WIDTH = 78;
const INDENT = ' ';

View File

@@ -21,12 +21,12 @@ const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const NoteTag = require('lib/models/NoteTag.js');
const MasterKey = require('lib/models/MasterKey');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const Revision = require('lib/models/Revision.js');
const { Logger } = require('lib/logger.js');
const Logger = require('lib/Logger').default;
const { FsDriverNode } = require('lib/fs-driver-node.js');
const { shimInit } = require('lib/shim-init-node.js');
const { _ } = require('lib/locale.js');
const { _ } = require('lib/locale');
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
const EncryptionService = require('lib/services/EncryptionService');
const envFromArgs = require('lib/envFromArgs');

View File

@@ -0,0 +1,68 @@
import * as vm from 'vm';
import Plugin from 'lib/services/plugins/Plugin';
import sandboxProxy from 'lib/services/plugins/sandboxProxy';
import BasePluginRunner from 'lib/services/plugins/BasePluginRunner';
import executeSandboxCall from 'lib/services/plugins/utils/executeSandboxCall';
import Global from 'lib/services/plugins/api/Global';
import mapEventHandlersToIds, { EventHandlers } from 'lib/services/plugins/utils/mapEventHandlersToIds';
function createConsoleWrapper(pluginId:string) {
const wrapper:any = {};
for (const n in console) {
if (!console.hasOwnProperty(n)) continue;
wrapper[n] = (...args:any[]) => {
const newArgs = args.slice();
newArgs.splice(0, 0, `Plugin "${pluginId}":`);
return (console as any)[n](...newArgs);
};
}
return wrapper;
}
// The CLI plugin runner is more complex than it needs to be because it more or less emulates
// how it would work in a multi-process architecture, as in the desktop app (and probably how
// it would work in the mobile app too). This is mainly to allow doing integration testing.
//
// For example, all plugin calls go through a proxy, however they could made directly since
// the plugin script is running within the same process as the main app.
export default class PluginRunner extends BasePluginRunner {
private eventHandlers_:EventHandlers = {};
constructor() {
super();
this.eventHandler = this.eventHandler.bind(this);
}
private async eventHandler(eventHandlerId:string, args:any[]) {
const cb = this.eventHandlers_[eventHandlerId];
return cb(...args);
}
private newSandboxProxy(pluginId:string, sandbox:Global) {
const target = async (path:string, args:any[]) => {
return executeSandboxCall(pluginId, sandbox, `joplin.${path}`, mapEventHandlersToIds(args, this.eventHandlers_), this.eventHandler);
};
return {
joplin: sandboxProxy(target),
console: createConsoleWrapper(pluginId),
};
}
async run(plugin:Plugin, sandbox:Global) {
const vmSandbox = vm.createContext(this.newSandboxProxy(plugin.id, sandbox));
try {
vm.runInContext(plugin.scriptText, vmSandbox);
} catch (error) {
this.logger().error(`In plugin ${plugin.id}:`, error);
return;
}
}
}

View File

@@ -46,8 +46,14 @@ tasks.prepareTestBuild = {
],
});
await utils.copyDir(`${__dirname}/../ReactNativeClient/lib`, `${testBuildDir}/lib`);
await utils.copyDir(`${__dirname}/../ReactNativeClient/locales`, `${testBuildDir}/locales`);
const rootDir = utils.rootDir();
await utils.copyDir(`${rootDir}/ReactNativeClient/lib`, `${testBuildDir}/lib`, {
excluded: [
`${rootDir}/ReactNativeClient/lib/joplin-renderer/node_modules`,
],
});
await utils.copyDir(`${rootDir}/ReactNativeClient/locales`, `${testBuildDir}/locales`);
await fs.mkdirp(`${testBuildDir}/data`);
},
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -13,8 +13,10 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.3.1\n"
"X-Generator: Poedit 2.4.1\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
#: CliClient/app/command-cp.js:13
msgid ""
@@ -104,9 +106,9 @@ msgid "Do not ask for confirmation."
msgstr "Ne pas demander de confirmation."
#: CliClient/app/command-import.js:27
#, fuzzy, javascript-format
#, javascript-format
msgid "Output format: %s"
msgstr "Format de la source : %s"
msgstr "Format de la sortie : %s"
#: CliClient/app/command-import.js:47 ElectronClient/gui/ImportScreen.min.js:69
#, javascript-format
@@ -317,7 +319,7 @@ msgstr ""
#: CliClient/app/command-sync.js:35
msgid "Upgrade the sync target to the latest version."
msgstr ""
msgstr "Mettre à jour la cible de synchronisation."
#: CliClient/app/command-sync.js:81 CliClient/app/command-sync.js:95
#: ElectronClient/gui/OneDriveLoginScreen.min.js:40
@@ -376,7 +378,6 @@ msgid "Synchronisation target: %s (%s)"
msgstr "Cible de la synchronisation : %s (%s)"
#: CliClient/app/command-sync.js:177
#, fuzzy
msgid "Cannot initialise synchroniser."
msgstr "Impossible d'initialiser la synchronisation."
@@ -813,14 +814,16 @@ msgstr "Annuler"
msgid ""
"The app is now going to close. Please relaunch it to complete the process."
msgstr ""
"L'application va maintenance fermer. Veuillez la relancer pour terminer "
"l'opération."
#: ElectronClient/plugins/GotoAnything.min.js:446
msgid ""
"Type a note title or part of its content to jump to it. Or type # followed "
"by a tag name, or @ followed by a notebook name."
msgstr ""
"Entrez le titre d’une note, ou entrez # suivit du nom d’une étiquette, ou @ "
"suivit du nom d’un carnet."
"Entrez le titre d’une note, ou entrez # suivi du nom d’une étiquette, ou @ "
"suivi du nom d’un carnet."
#: ElectronClient/plugins/GotoAnything.min.js:486
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:20
@@ -1021,7 +1024,6 @@ msgid "strong text"
msgstr "texte en gras"
#: ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.js:147
#, fuzzy
msgid "emphasised text"
msgstr "texte en italique"
@@ -1176,13 +1178,14 @@ msgstr "Création de %s..."
#: ElectronClient/gui/NoteEditor/NoteEditor.js:344
msgid "The following attachments are being watched for changes:"
msgstr ""
msgstr "Les changements sur les éléments suivants sont monitorés :"
#: ElectronClient/gui/NoteEditor/NoteEditor.js:347
msgid ""
"The attachments will no longer be watched when you switch to a different "
"note."
msgstr ""
"Les pièces jointes ne seront plus monitorées lorsque vous changerez de note."
#: ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js:25
msgid "Select all"
@@ -1308,12 +1311,11 @@ msgstr "Importer"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:125
msgid "Command"
msgstr ""
msgstr "Commande"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:126
#, fuzzy
msgid "Keyboard Shortcut"
msgstr "Mode de clavier"
msgstr "Raccourci"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:14
#: ElectronClient/app.js:690
@@ -1336,9 +1338,8 @@ msgid "Website and documentation"
msgstr "Documentation en ligne"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:24
#, fuzzy
msgid "Hide Joplin"
msgstr "A propos de Joplin"
msgstr "Cacher Joplin"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:26
#: ElectronClient/app.js:703
@@ -1346,9 +1347,8 @@ msgid "Close Window"
msgstr "Fermer la fenêtre"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#, fuzzy
msgid "Preferences"
msgstr "Préférences"
msgstr "Préférences"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#: ElectronClient/gui/Root.min.js:92 ElectronClient/app.js:572
@@ -1357,13 +1357,15 @@ msgstr "Options"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid "Press the shortcut"
msgstr ""
msgstr "Taper le raccourci"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid ""
"Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the "
"shortcut."
msgstr ""
"Tapez le raccourci et appuyez sur ENTREE. Ou, appuyez sur la touche de "
"retour arrière pour supprimer le raccourci."
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
#: ElectronClient/gui/EncryptionConfigScreen.min.js:95
@@ -1377,11 +1379,13 @@ msgid ""
"may take a few minutes to complete and the app needs to be restarted. To "
"proceed please click on the link."
msgstr ""
"La cible de synchronisation doit être mise à jour. L'opération peut prendre "
"plusieurs minutes et l'application devra être re-démarrée. Pour continuer, "
"veuillez cliquer sur le lien."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:306
#, fuzzy
msgid "Restart and upgrade"
msgstr "Clefs maîtres qui peuvent être mise à niveau"
msgstr "Redémarrer et mettre à jour"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:313
msgid "Some items cannot be synchronised."
@@ -1406,12 +1410,10 @@ msgid "Set the password"
msgstr "Définir le mot de passe"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:349
#, fuzzy
msgid "One of your master keys use an obsolete encryption method."
msgstr "L'une des clefs maîtres requiert un mot de passe."
msgstr "L'une des clefs maîtres utilise une méthode de chiffrement obsolète."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:361
#, fuzzy
msgid ""
"The default encryption method has been changed, you should re-encrypt your "
"data."
@@ -1420,7 +1422,6 @@ msgstr ""
"l'appliquer à vos données."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:366
#, fuzzy
msgid "More info"
msgstr "Plus d'information"
@@ -1761,9 +1762,8 @@ msgid "Icon"
msgstr "Icône"
#: ElectronClient/gui/FolderPropertiesDialog.min.js:272
#, fuzzy
msgid "Notebook properties"
msgstr "Propriétés de la note"
msgstr "Propriétés du carnet"
#: ElectronClient/gui/NoteText.min.js:781
#, javascript-format
@@ -1936,7 +1936,7 @@ msgstr "Statistiques"
#: ElectronClient/gui/NoteContentPropertiesDialog.js:111
#, javascript-format
msgid "Read time: %s min"
msgstr ""
msgstr "Temps de lecture : %s min"
#: ElectronClient/gui/NoteContentPropertiesDialog.js:112
#: ElectronClient/gui/ShareNoteDialog.js:175
@@ -2151,9 +2151,8 @@ msgid "Templates"
msgstr "Modèles"
#: ElectronClient/app.js:668
#, fuzzy
msgid "Export all"
msgstr "Exporter"
msgstr "Tout exporter"
#: ElectronClient/app.js:683
#, javascript-format
@@ -2253,7 +2252,7 @@ msgstr "Paramètre inconnu : %s"
#: ReactNativeClient/lib/SyncTargetAmazonS3.js:28
msgid "AWS S3"
msgstr ""
msgstr "AWS S3"
#: ReactNativeClient/lib/SyncTargetDropbox.js:25
msgid "Dropbox"
@@ -2397,15 +2396,15 @@ msgstr "WebDAV : Mot de passe"
#: ReactNativeClient/lib/models/Setting.js:195
msgid "AWS S3 bucket"
msgstr ""
msgstr "AWS S3: bucket"
#: ReactNativeClient/lib/models/Setting.js:206
msgid "AWS key"
msgstr ""
msgstr "AWS : Clef"
#: ReactNativeClient/lib/models/Setting.js:216
msgid "AWS secret"
msgstr ""
msgstr "AWS : Secret"
#: ReactNativeClient/lib/models/Setting.js:230
msgid "Attachment download behaviour"
@@ -2626,7 +2625,6 @@ msgid "Editor font family"
msgstr "Police de l'éditeur"
#: ReactNativeClient/lib/models/Setting.js:553
#, fuzzy
msgid ""
"This should be a *monospace* font or some elements will render incorrectly. "
"If the font is incorrect or empty, it will default to a generic monospace "
@@ -2867,9 +2865,8 @@ msgid "Web Clipper"
msgstr "Web Clipper"
#: ReactNativeClient/lib/models/Setting.js:1259
#, fuzzy
msgid "Keyboard Shortcuts"
msgstr "Mode de clavier"
msgstr "Raccourcis clavier"
#: ReactNativeClient/lib/models/Setting.js:1264
msgid ""
@@ -3025,6 +3022,8 @@ msgstr "Certains objets ne peuvent être synchronisés."
#: ReactNativeClient/lib/components/screen-header.js:453
msgid "The sync target needs to be upgraded. Press this banner to proceed."
msgstr ""
"La cible de synchronisation doit être mise à jour. Veuillez appuyer sur "
"cette bannière pour commencer."
#: ReactNativeClient/lib/components/side-menu-content.js:126
#, javascript-format
@@ -3151,7 +3150,7 @@ msgstr "Rafraîchir"
#: ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js:42
msgid "Sync Target Upgrade"
msgstr ""
msgstr "Mise à jour de la cible de synchro"
#: ReactNativeClient/lib/components/screens/NoteTagsDialog.js:163
msgid "New tags:"
@@ -3553,7 +3552,6 @@ msgid "Forward"
msgstr "Vers l'avant"
#: ReactNativeClient/lib/commands/synchronize.js:17
#, fuzzy
msgid "Synchronize"
msgstr "Synchroniser"
@@ -3793,9 +3791,11 @@ msgid "Directory"
msgstr "Dossier"
#: ReactNativeClient/lib/services/InteropService.js:174
#, fuzzy, javascript-format
#, javascript-format
msgid "Cannot load \"%s\" module for format \"%s\" and output \"%s\""
msgstr "Impossible de charger module \"%s\" pour le format \"%s\""
msgstr ""
"Impossible de charger module \"%s\" pour le format d'entrée \"%s\" et de "
"sortie \"%s\""
#: ReactNativeClient/lib/services/InteropService.js:232
#, javascript-format

View File

@@ -15,6 +15,8 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.4\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
#: CliClient/app/command-cp.js:13
msgid ""
@@ -312,7 +314,7 @@ msgstr "指定のターゲットと同期します。(標準: sync.targetの
#: CliClient/app/command-sync.js:35
msgid "Upgrade the sync target to the latest version."
msgstr ""
msgstr "同期先を最新バージョンにアップグレード。"
#: CliClient/app/command-sync.js:81 CliClient/app/command-sync.js:95
#: ElectronClient/gui/OneDriveLoginScreen.min.js:40
@@ -796,6 +798,8 @@ msgstr "キャンセル"
msgid ""
"The app is now going to close. Please relaunch it to complete the process."
msgstr ""
"まもなくアプリケーションは終了します。もう一度起動して処理を完了させてくださ"
"い。"
#: ElectronClient/plugins/GotoAnything.min.js:446
msgid ""
@@ -1157,13 +1161,13 @@ msgstr "新しい %s を作成中..."
#: ElectronClient/gui/NoteEditor/NoteEditor.js:344
msgid "The following attachments are being watched for changes:"
msgstr ""
msgstr "下記の添付ファイルが変更されたかどうかを監視中です。"
#: ElectronClient/gui/NoteEditor/NoteEditor.js:347
msgid ""
"The attachments will no longer be watched when you switch to a different "
"note."
msgstr ""
msgstr "添付ファイルの監視は他のノートに移動すると終了します。"
#: ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js:25
msgid "Select all"
@@ -1274,7 +1278,7 @@ msgstr "ノートのプロパティ"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:62
msgid "An unexpected error occured while importing the keymap!"
msgstr ""
msgstr "キーマップのインポート中に予期しないエラーが発生しました!"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:119
#: ElectronClient/gui/MainScreen/MainScreen.min.js:437
@@ -1289,12 +1293,11 @@ msgstr "インポート"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:125
msgid "Command"
msgstr ""
msgstr "コマンド"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:126
#, fuzzy
msgid "Keyboard Shortcut"
msgstr "キーバインド"
msgstr "ショートカットキー"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:14
#: ElectronClient/app.js:690
@@ -1317,9 +1320,8 @@ msgid "Website and documentation"
msgstr "Webサイトとドキュメント"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:24
#, fuzzy
msgid "Hide Joplin"
msgstr "Joplinについて"
msgstr "Joplinを隠す"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:26
#: ElectronClient/app.js:703
@@ -1327,7 +1329,6 @@ msgid "Close Window"
msgstr "ウィンドウを閉じる"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#, fuzzy
msgid "Preferences"
msgstr "環境設定"
@@ -1338,13 +1339,15 @@ msgstr "オプション"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid "Press the shortcut"
msgstr ""
msgstr "ショートカットキーを押してください"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid ""
"Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the "
"shortcut."
msgstr ""
"ショートカットキーに続けてENTERを押すことで設定します。ショートカットを削除す"
"るにはBACKSPACEを押してください。"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
#: ElectronClient/gui/EncryptionConfigScreen.min.js:95
@@ -1358,11 +1361,13 @@ msgid ""
"may take a few minutes to complete and the app needs to be restarted. To "
"proceed please click on the link."
msgstr ""
"同期するには同期先をアップグレードする必要があります。アップグレードには数分"
"かかるかもしれません。またアプリケーションの再起動が必要です。アップグレード"
"するにはリンクをクリックしてください。"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:306
#, fuzzy
msgid "Restart and upgrade"
msgstr "アップグレードが必要なマスターキー"
msgstr "再起動してアップグレード"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:313
msgid "Some items cannot be synchronised."
@@ -2114,9 +2119,8 @@ msgid "Templates"
msgstr "テンプレート"
#: ElectronClient/app.js:668
#, fuzzy
msgid "Export all"
msgstr "エクスポート"
msgstr "すべてをエクスポート"
#: ElectronClient/app.js:683
#, javascript-format
@@ -2215,7 +2219,7 @@ msgstr "不明なレベルID: %s"
#: ReactNativeClient/lib/SyncTargetAmazonS3.js:28
msgid "AWS S3"
msgstr ""
msgstr "AWS S3"
#: ReactNativeClient/lib/SyncTargetDropbox.js:25
msgid "Dropbox"
@@ -2360,15 +2364,15 @@ msgstr "WevDAV パスワード"
#: ReactNativeClient/lib/models/Setting.js:195
msgid "AWS S3 bucket"
msgstr ""
msgstr "AWS S3 バケット"
#: ReactNativeClient/lib/models/Setting.js:206
msgid "AWS key"
msgstr ""
msgstr "AWS アクセスキーID"
#: ReactNativeClient/lib/models/Setting.js:216
msgid "AWS secret"
msgstr ""
msgstr "AWS シークレットアクセスキー"
#: ReactNativeClient/lib/models/Setting.js:230
msgid "Attachment download behaviour"
@@ -2823,9 +2827,8 @@ msgid "Web Clipper"
msgstr "Webクリッパー"
#: ReactNativeClient/lib/models/Setting.js:1259
#, fuzzy
msgid "Keyboard Shortcuts"
msgstr "キーバインド"
msgstr "キーボードショートカット"
#: ReactNativeClient/lib/models/Setting.js:1264
msgid ""
@@ -2980,6 +2983,8 @@ msgstr "いくつかの項目は同期されませんでした。詳細はクリ
#: ReactNativeClient/lib/components/screen-header.js:453
msgid "The sync target needs to be upgraded. Press this banner to proceed."
msgstr ""
"同期先をアップグレードする必要があります。アップグレードするにはバナーをク"
"リックしてください。"
#: ReactNativeClient/lib/components/side-menu-content.js:126
#, javascript-format
@@ -3024,8 +3029,8 @@ msgid ""
"Error. Please check that URL, username, password, etc. are correct and that "
"the sync target is accessible. The reported error was:"
msgstr ""
"エラーです。URL、ユーザー名、パスワードなどを修正し、同期するターゲットにアク"
"セスできるかを確認してください。次が報告されたエラーです:"
"エラーです。URL、ユーザー名、パスワードなどを修正し、同期先にアクセスできるか"
"を確認してください。次が報告されたエラーです:"
#: ReactNativeClient/lib/components/shared/dropbox-login-shared.js:39
msgid "The application has been authorised!"
@@ -3102,7 +3107,7 @@ msgstr "更新"
#: ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js:42
msgid "Sync Target Upgrade"
msgstr ""
msgstr "同期先のアップグレード"
#: ReactNativeClient/lib/components/screens/NoteTagsDialog.js:163
msgid "New tags:"
@@ -3151,10 +3156,10 @@ msgid ""
"password as, for security purposes, this will be the *only* way to decrypt "
"the data! To enable encryption, please enter your password below."
msgstr ""
"暗号化を有効にするとは、*すべて*のノートや添付ファイルを再同期し、同期ター"
"ゲットに暗号化した状態で送ることを意味します。パスワードはなくさないようにし"
"てください。セキュリティ上、このパスワードがデータを復号する*唯一*の方法にな"
"るためです! 暗号化を有効にするには、下にパスワードを入力してください。"
"暗号化を有効にするとは、*すべて*のノートや添付ファイルを再同期し、同期先に暗"
"号化した状態で送ることを意味します。パスワードはなくさないようにしてくださ"
"い。セキュリティ上、このパスワードがデータを復号する*唯一*の方法になるためで"
"す! 暗号化を有効にするには、下にパスワードを入力してください。"
#: ReactNativeClient/lib/components/screens/encryption-config.js:177
msgid "Enable"
@@ -3546,32 +3551,35 @@ msgstr "ノートをどのノートブックにインポートするのか指定
#: ReactNativeClient/lib/services/KeymapService.js:124
#, javascript-format
msgid "Error loading the keymap from file: %s"
msgstr ""
msgstr "キーマップ読み込みエラー(ファイル: %s)"
#: ReactNativeClient/lib/services/KeymapService.js:141
#, javascript-format
msgid "Error saving the keymap to file: %s"
msgstr ""
msgstr "キーマップ書き出しエラー(ファイル: %s)"
#: ReactNativeClient/lib/services/KeymapService.js:204
#, javascript-format
msgid "Keymap item %s is missing the required \"command\" property."
msgstr ""
"キーマップアイテム %s は必須の \"command\" プロパティを持っていません。"
#: ReactNativeClient/lib/services/KeymapService.js:207
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid command."
msgstr ""
msgstr "キーマップアイテム %s は %s が有効なコマンドでないため無効です。"
#: ReactNativeClient/lib/services/KeymapService.js:210
#, javascript-format
msgid "Keymap item %s is missing the required \"accelerator\" property."
msgstr ""
"キーマップアイテム %s は必須の \"accelerator\" プロパティを持っていません。"
#: ReactNativeClient/lib/services/KeymapService.js:217
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid accelerator."
msgstr ""
"キーマップアイテム %s は %s が有効なショートカットキーでないため無効です。"
#: ReactNativeClient/lib/services/KeymapService.js:235
#, javascript-format
@@ -3579,11 +3587,13 @@ msgid ""
"Accelerator \"%s\" is used for \"%s\" and \"%s\" commands. This may lead to "
"unexpected behaviour."
msgstr ""
"ショートカットキー \"%s\" は \"%s\" コマンドと \"%s\" コマンドで使われていま"
"す。これにより予想外の動作が起こる可能性があります。"
#: ReactNativeClient/lib/services/KeymapService.js:260
#, javascript-format
msgid "Accelerator \"%s\" is not valid."
msgstr ""
msgstr "ショートカットキー \"%s\" は無効です。"
#: ReactNativeClient/lib/services/report.js:121
msgid "Items that cannot be synchronised"

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,9 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.3.1\n"
"X-Generator: Poedit 2.4.1\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
#: CliClient/app/command-cp.js:13
msgid ""
@@ -319,7 +321,7 @@ msgstr ""
#: CliClient/app/command-sync.js:35
msgid "Upgrade the sync target to the latest version."
msgstr ""
msgstr "Senkronizasyon hedefini en son sürüme yükseltin"
#: CliClient/app/command-sync.js:81 CliClient/app/command-sync.js:95
#: ElectronClient/gui/OneDriveLoginScreen.min.js:40
@@ -813,6 +815,8 @@ msgstr "İptal et"
msgid ""
"The app is now going to close. Please relaunch it to complete the process."
msgstr ""
"Uygulama şimdi kapanacak. İşlemi tamamlamak için lütfen uygulamayı "
"kapandıktan sonar yeniden çalıştırın."
#: ElectronClient/plugins/GotoAnything.min.js:446
msgid ""
@@ -1173,13 +1177,13 @@ msgstr "Yeni %s oluşturuluyor..."
#: ElectronClient/gui/NoteEditor/NoteEditor.js:344
msgid "The following attachments are being watched for changes:"
msgstr ""
msgstr "Şu ek dosyaları değişiklikler için izlenmekte:"
#: ElectronClient/gui/NoteEditor/NoteEditor.js:347
msgid ""
"The attachments will no longer be watched when you switch to a different "
"note."
msgstr ""
msgstr "Eğer başka bir not'a geçerseniz ek dosyalar artık izlenmeyecek."
#: ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js:25
msgid "Select all"
@@ -1290,7 +1294,7 @@ msgstr "Not özellikleri"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:62
msgid "An unexpected error occured while importing the keymap!"
msgstr ""
msgstr "Tuş dizimini içe aktarırken bir hata oluştu!"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:119
#: ElectronClient/gui/MainScreen/MainScreen.min.js:437
@@ -1305,12 +1309,11 @@ msgstr "İçe aktar"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:125
msgid "Command"
msgstr ""
msgstr "Komut"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:126
#, fuzzy
msgid "Keyboard Shortcut"
msgstr "Klavye modu"
msgstr "Klavye Kısayolu"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:14
#: ElectronClient/app.js:690
@@ -1333,9 +1336,8 @@ msgid "Website and documentation"
msgstr "Web sitesi ve dökümanlar"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:24
#, fuzzy
msgid "Hide Joplin"
msgstr "Joplin hakkında"
msgstr "Joplin'i Gizle"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:26
#: ElectronClient/app.js:703
@@ -1343,9 +1345,8 @@ msgid "Close Window"
msgstr "Pencereyi Kapat"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#, fuzzy
msgid "Preferences"
msgstr "Tercihler..."
msgstr "Tercihler"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#: ElectronClient/gui/Root.min.js:92 ElectronClient/app.js:572
@@ -1354,13 +1355,15 @@ msgstr "Seçenekler"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid "Press the shortcut"
msgstr ""
msgstr "Kısayolu girin"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid ""
"Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the "
"shortcut."
msgstr ""
"Kısayolu girin ve ardından ENTER tuşuna basın. Veya BACKSPACE tuşuna basarak "
"kısayolu temizleyin."
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
#: ElectronClient/gui/EncryptionConfigScreen.min.js:95
@@ -1374,11 +1377,14 @@ msgid ""
"may take a few minutes to complete and the app needs to be restarted. To "
"proceed please click on the link."
msgstr ""
"Senkronizasyon hedefi'nin Joplin senkronizasyona yeniden başlamadan once "
"güncellenmesi gerekir. Bu işlem notlarınızıın yoğunluğuna göre birkaç dakika "
"sürebilir, ve de bu işlem ardından uygulama yeniden başlatılacaktır. Bu "
"işlemi başlatmak için lütfen linke tıklayın."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:306
#, fuzzy
msgid "Restart and upgrade"
msgstr "Ana anahtarların güncellenmesi lazım"
msgstr "Yeniden başlat ve güncelle"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:313
msgid "Some items cannot be synchronised."
@@ -2138,9 +2144,8 @@ msgid "Templates"
msgstr "Şablonlar"
#: ElectronClient/app.js:668
#, fuzzy
msgid "Export all"
msgstr "Dışa aktar"
msgstr "Tümünü dışa aktar"
#: ElectronClient/app.js:683
#, javascript-format
@@ -2241,7 +2246,7 @@ msgstr "Bilinmeyen ID seviyesi: %s"
#: ReactNativeClient/lib/SyncTargetAmazonS3.js:28
msgid "AWS S3"
msgstr ""
msgstr "AWS S3"
#: ReactNativeClient/lib/SyncTargetDropbox.js:25
msgid "Dropbox"
@@ -2384,15 +2389,15 @@ msgstr "WebDAV şifresi"
#: ReactNativeClient/lib/models/Setting.js:195
msgid "AWS S3 bucket"
msgstr ""
msgstr "AWS S3 deposu"
#: ReactNativeClient/lib/models/Setting.js:206
msgid "AWS key"
msgstr ""
msgstr "AWS anahtarı"
#: ReactNativeClient/lib/models/Setting.js:216
msgid "AWS secret"
msgstr ""
msgstr "AWS gizli anahtarı"
#: ReactNativeClient/lib/models/Setting.js:230
msgid "Attachment download behaviour"
@@ -2850,9 +2855,8 @@ msgid "Web Clipper"
msgstr "Web Alıntılayıcısı"
#: ReactNativeClient/lib/models/Setting.js:1259
#, fuzzy
msgid "Keyboard Shortcuts"
msgstr "Klavye modu"
msgstr "Klavye Kısayolları"
#: ReactNativeClient/lib/models/Setting.js:1264
msgid ""
@@ -3008,6 +3012,8 @@ msgstr "Bazı öğeler senkronize edilemiyor. Detayları için tıklayın."
#: ReactNativeClient/lib/components/screen-header.js:453
msgid "The sync target needs to be upgraded. Press this banner to proceed."
msgstr ""
"Senkronizasyon hedefinin güncellenmesi gerekmekte. Bu banner'a tıklayarak "
"devam edebilirsiniz."
#: ReactNativeClient/lib/components/side-menu-content.js:126
#, javascript-format
@@ -3129,7 +3135,7 @@ msgstr "Yenile"
#: ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js:42
msgid "Sync Target Upgrade"
msgstr ""
msgstr "Senkronizasyon Hedefi Güncellemesi"
#: ReactNativeClient/lib/components/screens/NoteTagsDialog.js:163
msgid "New tags:"
@@ -3578,32 +3584,37 @@ msgstr "Lütfen notların alınacağı not defterini belirtin."
#: ReactNativeClient/lib/services/KeymapService.js:124
#, javascript-format
msgid "Error loading the keymap from file: %s"
msgstr ""
msgstr "%s dosyasından tuş haritası yüklenemedi"
#: ReactNativeClient/lib/services/KeymapService.js:141
#, javascript-format
msgid "Error saving the keymap to file: %s"
msgstr ""
msgstr "%s dosyasına tuş haritası kaydedilemedi"
#: ReactNativeClient/lib/services/KeymapService.js:204
#, javascript-format
msgid "Keymap item %s is missing the required \"command\" property."
msgstr ""
"%s tuş haritası, işlemler için gerekli olan \"command\" özelliğini "
"barındırmıyor."
#: ReactNativeClient/lib/services/KeymapService.js:207
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid command."
msgstr ""
msgstr "%s tuş haritası geçersizdir, çünkü %s geçerli bir komut değildir."
#: ReactNativeClient/lib/services/KeymapService.js:210
#, javascript-format
msgid "Keymap item %s is missing the required \"accelerator\" property."
msgstr ""
"%s tuş haritası, işlemler için gerekli olan \"accelerator\" özelliğini "
"barındırmıyor."
#: ReactNativeClient/lib/services/KeymapService.js:217
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid accelerator."
msgstr ""
"%s tuş haritası geçersizdir, çünkü %s geçerli bir accelerator değildir."
#: ReactNativeClient/lib/services/KeymapService.js:235
#, javascript-format
@@ -3611,11 +3622,13 @@ msgid ""
"Accelerator \"%s\" is used for \"%s\" and \"%s\" commands. This may lead to "
"unexpected behaviour."
msgstr ""
"Kısayol \"%s\", \"%s\" ve \"%s\" komutları için kullanılıyor. Bu beklenmeyen "
"sonuçlara sebep verebilir."
#: ReactNativeClient/lib/services/KeymapService.js:260
#, javascript-format
msgid "Accelerator \"%s\" is not valid."
msgstr ""
msgstr "Kısayol \"%s\" geçersiz."
#: ReactNativeClient/lib/services/report.js:121
msgid "Items that cannot be synchronised"
@@ -3949,7 +3962,7 @@ msgstr ""
#~ "Şu anda not defteriniz yok. (+) butonuna tıklayarak bir tane oluşturun."
#~ msgid "Welcome"
#~ msgstr "Hoşgeldiniz"
#~ msgstr "Hoş Geldiniz"
#~ msgid "Separate each tag by a comma."
#~ msgstr "Her etiketi virgülle ayırın."

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "1.0.168",
"version": "1.2.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -606,6 +606,11 @@
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"builtin-modules": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
"integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw=="
},
"cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@@ -4344,6 +4349,11 @@
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
},
"nanoid": {
"version": "3.1.12",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz",
"integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A=="
},
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -5250,6 +5260,11 @@
}
}
},
"re-reselect": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/re-reselect/-/re-reselect-4.0.0.tgz",
"integrity": "sha512-wuygyq8TXUlSdVXv2kigXxQNOgdb9m7LbIjwfTNGSpaY1riLd5e+VeQjlQMyUtrk0oiyhi1AqIVynworl3qxHA=="
},
"read-chunk": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz",
@@ -5610,6 +5625,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"reselect": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
},
"resolve": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
@@ -5880,6 +5900,11 @@
"is-fullwidth-code-point": "^2.0.0"
}
},
"slug": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/slug/-/slug-3.3.4.tgz",
"integrity": "sha512-VpHbtRCEWmgaZsrZcTsVl/Dhw98lcrOYDO17DNmJCNpppI6s3qJvnNu2Q3D4L84/2bi6vkW40mjNQI9oGQsflg=="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -6742,11 +6767,6 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
},
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA=="
},
"unpack-string": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz",
@@ -6849,14 +6869,6 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
"uslug": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz",
"integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=",
"requires": {
"unorm": ">= 1.0.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

View File

@@ -28,7 +28,7 @@
],
"owner": "Laurent Cozic"
},
"version": "1.0.168",
"version": "1.3.0",
"bin": {
"joplin": "./main.js"
},
@@ -41,6 +41,7 @@
"aws-sdk": "^2.588.0",
"base-64": "^0.1.0",
"base64-stream": "^1.0.0",
"builtin-modules": "^3.1.0",
"clean-html": "^1.5.0",
"compare-version": "^0.1.2",
"diacritics": "^1.3.0",
@@ -83,6 +84,7 @@
"mime": "^2.0.3",
"moment": "^2.24.0",
"multiparty": "^4.2.1",
"nanoid": "^3.1.12",
"node-emoji": "^1.8.1",
"node-fetch": "^1.7.1",
"node-persist": "^2.1.0",
@@ -91,13 +93,16 @@
"promise": "^7.1.1",
"proper-lockfile": "^2.0.1",
"query-string": "4.3.4",
"re-reselect": "^4.0.0",
"read-chunk": "^2.1.0",
"redux": "^3.7.2",
"relative": "^3.0.2",
"request": "^2.88.0",
"reselect": "^4.0.0",
"sax": "^1.2.4",
"server-destroy": "^1.0.1",
"sharp": "^0.23.2",
"slug": "^3.3.4",
"sprintf-js": "^1.1.1",
"sqlite3": "^4.1.1",
"string-padding": "^1.0.2",
@@ -109,7 +114,6 @@
"terminal-kit": "^1.30.0",
"tkwidgets": "^0.5.26",
"url-parse": "^1.4.7",
"uslug": "^1.0.4",
"uuid": "^3.0.1",
"valid-url": "^1.0.9",
"word-wrap": "^1.2.3",

View File

@@ -1,7 +1,7 @@
require('app-module-path').addPath(__dirname);
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
const { enexXmlToHtml } = require('lib/import-enex-html-gen.js');
process.on('unhandledRejection', (reason, p) => {

View File

@@ -9,7 +9,7 @@ const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
const { enexXmlToMd } = require('lib/import-enex-md-gen.js');
process.on('unhandledRejection', (reason, p) => {

View File

@@ -9,7 +9,7 @@ const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
const HtmlToHtml = require('lib/joplin-renderer/HtmlToHtml');
const { enexXmlToMd } = require('lib/import-enex-md-gen.js');

View File

@@ -9,7 +9,7 @@ const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
const HtmlToMd = require('lib/HtmlToMd');
const { enexXmlToMd } = require('lib/import-enex-md-gen.js');

View File

@@ -9,7 +9,7 @@ const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
const MdToHtml = require('lib/joplin-renderer/MdToHtml');
const { enexXmlToMd } = require('lib/import-enex-md-gen.js');
const { themeStyle } = require('lib/theme');

View File

@@ -1,4 +1,4 @@
const mdImporterService = require('lib/services/InteropService_Importer_Md');
const mdImporterService = require('lib/services/interop/InteropService_Importer_Md').default;
const Note = require('lib/models/Note.js');
const { setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');

View File

@@ -6,10 +6,10 @@ const { time } = require('lib/time-utils.js');
const { sortedIds, createNTestNotes, asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const BaseModel = require('lib/BaseModel.js');
const ArrayUtils = require('lib/ArrayUtils.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -0,0 +1,121 @@
'use strict';
require('app-module-path').addPath(__dirname);
const { asyncTest,checkThrow } = require('test-utils.js');
const eventManager = require('lib/eventManager').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
describe('eventManager', function() {
beforeEach(async (done) => {
eventManager.reset();
done();
});
afterEach(async (done) => {
eventManager.reset();
done();
});
it('should watch state props', asyncTest(async () => {
let localStateName = '';
let callCount = 0;
function nameWatch(event) {
callCount++;
localStateName = event.value;
}
const globalState = {
name: 'john',
};
eventManager.appStateOn('name', nameWatch);
eventManager.appStateEmit(globalState);
expect(localStateName).toBe('john');
globalState.name = 'paul';
eventManager.appStateEmit(globalState);
expect(localStateName).toBe('paul');
expect(callCount).toBe(2);
eventManager.appStateEmit(globalState);
expect(callCount).toBe(2);
}));
it('should unwatch state props', asyncTest(async () => {
let localStateName = '';
function nameWatch(event) {
localStateName = event.value;
}
const globalState = {
name: 'john',
};
eventManager.appStateOn('name', nameWatch);
eventManager.appStateOff('name', nameWatch);
eventManager.appStateEmit(globalState);
expect(localStateName).toBe('');
}));
it('should watch nested props', asyncTest(async () => {
let localStateName = '';
function nameWatch(event) {
localStateName = event.value;
}
const globalState = {
user: {
name: 'john',
},
};
eventManager.appStateOn('user.name', nameWatch);
eventManager.appStateEmit(globalState);
expect(localStateName).toBe('john');
globalState.user.name = 'paul';
eventManager.appStateEmit(globalState);
expect(localStateName).toBe('paul');
}));
it('should not be possible to modify state props', asyncTest(async () => {
let localUser = {};
function userWatch(event) {
// Normally, the user should not keep a reference to the whole object
// but make a copy. However, if they do keep a reference and try to
// modify it, it should throw an exception as that would be an attempt
// to directly modify the Redux state.
localUser = event.value;
}
const globalState = {
user: {
name: 'john',
},
};
eventManager.appStateOn('user', userWatch);
eventManager.appStateEmit(globalState);
expect(checkThrow(() => localUser.name = 'paul')).toBe(true);
}));
});

View File

@@ -1,7 +1,7 @@
require('app-module-path').addPath(__dirname);
const { asyncTest, id, ids, createNTestFolders, sortedIds, createNTestNotes, TestApp } = require('test-utils.js');
const BaseModel = require('lib/BaseModel.js');
const { uuid } = require('lib/uuid.js');
const uuid = require('lib/uuid').default;
const Note = require('lib/models/Note.js');
const Folder = require('lib/models/Folder.js');

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-unused-vars */
require('app-module-path').addPath(__dirname);
const { setupDatabaseAndSynchronizer, switchClient, asyncTest, createNTestFolders, createNTestNotes, createNTestTags, TestApp } = require('test-utils.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-unused-vars */
require('app-module-path').addPath(__dirname);
const { setupDatabaseAndSynchronizer, switchClient, asyncTest, id, ids, sortedIds, at, createNTestFolders, createNTestNotes, createNTestTags, TestApp } = require('test-utils.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-unused-vars */
require('app-module-path').addPath(__dirname);
const { setupDatabaseAndSynchronizer, switchClient, asyncTest, createNTestFolders, createNTestNotes, createNTestTags, TestApp } = require('test-utils.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');

View File

@@ -2,12 +2,12 @@
require('app-module-path').addPath(__dirname);
const { uuid } = require('lib/uuid.js');
const uuid = require('lib/uuid').default;
const { time } = require('lib/time-utils.js');
const { asyncTest, sleep, fileApi, fileContentEqual, checkThrowAsync } = require('test-utils.js');
const { shim } = require('lib/shim.js');
const shim = require('lib/shim').default;
const fs = require('fs-extra');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -9,7 +9,7 @@ const Note = require('lib/models/Note.js');
const BaseItem = require('lib/models/BaseItem.js');
const Resource = require('lib/models/Resource.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -7,7 +7,7 @@ const { createNTestNotes, asyncTest, fileContentEqual, setupDatabase, setupDatab
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -8,7 +8,7 @@ const SearchEngine = require('lib/services/searchengine/SearchEngine');
const ResourceService = require('lib/services/ResourceService');
const ItemChangeUtils = require('lib/services/ItemChangeUtils');
const Note = require('lib/models/Note');
const Setting = require('lib/models/Setting');
const Setting = require('lib/models/Setting').default;
const ItemChange = require('lib/models/ItemChange');
process.on('unhandledRejection', (reason, p) => {

View File

@@ -6,10 +6,10 @@ const { time } = require('lib/time-utils.js');
const { sortedIds, createNTestNotes, asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const BaseModel = require('lib/BaseModel.js');
const ArrayUtils = require('lib/ArrayUtils.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -6,10 +6,10 @@ const { time } = require('lib/time-utils.js');
const { sortedIds, createNTestNotes, asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const BaseModel = require('lib/BaseModel.js');
const ArrayUtils = require('lib/ArrayUtils.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -8,7 +8,7 @@ const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Resource = require('lib/models/Resource.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -10,7 +10,7 @@ const NoteTag = require('lib/models/NoteTag.js');
const Tag = require('lib/models/Tag.js');
const Revision = require('lib/models/Revision.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -1,37 +0,0 @@
/* eslint-disable no-unused-vars */
require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const { shim } = require('lib/shim');
const Setting = require('lib/models/Setting.js');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
describe('models_Setting', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
it('should return only sub-values', asyncTest(async () => {
const settings = {
'sync.5.path': 'http://example.com',
'sync.5.username': 'testing',
};
let output = Setting.subValues('sync.5', settings);
expect(output['path']).toBe('http://example.com');
expect(output['username']).toBe('testing');
output = Setting.subValues('sync.4', settings);
expect('path' in output).toBe(false);
expect('username' in output).toBe(false);
}));
});

View File

@@ -0,0 +1,135 @@
import Setting from 'lib/models/Setting';
require('app-module-path').addPath(__dirname);
const { asyncTest, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('test-utils.js');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
describe('models_Setting', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
it('should return only sub-values', asyncTest(async () => {
const settings = {
'sync.5.path': 'http://example.com',
'sync.5.username': 'testing',
};
let output = Setting.subValues('sync.5', settings);
expect(output['path']).toBe('http://example.com');
expect(output['username']).toBe('testing');
output = Setting.subValues('sync.4', settings);
expect('path' in output).toBe(false);
expect('username' in output).toBe(false);
}));
it('should allow registering new settings dynamically', asyncTest(async () => {
await expectThrow(async () => Setting.setValue('myCustom', '123'));
await Setting.registerSetting('myCustom', {
public: true,
value: 'default',
type: Setting.TYPE_STRING,
});
await expectNotThrow(async () => Setting.setValue('myCustom', '123'));
expect(Setting.value('myCustom')).toBe('123');
}));
it('should not clear old custom settings', asyncTest(async () => {
// In general the following should work:
//
// - Plugin register a new setting
// - User set new value for setting
// - Settings are saved
// - => App restart
// - Plugin does not register setting again
// - Settings are loaded
// - Settings are saved
// - Plugin register setting again
// - Previous value set by user should still be there.
//
// In other words, once a custom setting has been set we don't clear it
// even if registration doesn't happen immediately. That allows for example
// to delay setting registration without a risk for the custom setting to be deleted.
await Setting.registerSetting('myCustom', {
public: true,
value: 'default',
type: Setting.TYPE_STRING,
});
Setting.setValue('myCustom', '123');
await Setting.saveAll();
await Setting.reset();
await Setting.load();
await Setting.registerSetting('myCustom', {
public: true,
value: 'default',
type: Setting.TYPE_STRING,
});
await Setting.saveAll();
expect(Setting.value('myCustom')).toBe('123');
}));
it('should return values with correct type for custom settings', asyncTest(async () => {
await Setting.registerSetting('myCustom', {
public: true,
value: 123,
type: Setting.TYPE_INT,
});
Setting.setValue('myCustom', 456);
await Setting.saveAll();
await Setting.reset();
await Setting.load();
await Setting.registerSetting('myCustom', {
public: true,
value: 123,
type: Setting.TYPE_INT,
});
expect(typeof Setting.value('myCustom')).toBe('number');
expect(Setting.value('myCustom')).toBe(456);
}));
it('should validate registered keys', asyncTest(async () => {
const md = {
public: true,
value: 'default',
type: Setting.TYPE_STRING,
};
await expectThrow(async () => await Setting.registerSetting('', md));
await expectThrow(async () => await Setting.registerSetting('no spaces', md));
await expectThrow(async () => await Setting.registerSetting('nospecialcharacters!!!', md));
await expectThrow(async () => await Setting.registerSetting('Robert\'); DROP TABLE Students;--', md));
await expectNotThrow(async () => await Setting.registerSetting('numbersareok123', md));
await expectNotThrow(async () => await Setting.registerSetting('so-ARE-dashes_123', md));
}));
it('should register new sections', asyncTest(async () => {
await Setting.registerSection('mySection', {
label: 'My section',
});
expect(Setting.sectionNameToLabel('mySection')).toBe('My section');
}));
});

View File

@@ -9,7 +9,7 @@ const Note = require('lib/models/Note.js');
const NoteTag = require('lib/models/NoteTag.js');
const Tag = require('lib/models/Tag.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -5,7 +5,8 @@ const { setupDatabaseAndSynchronizer, switchClient, asyncTest, createNTestNotes,
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const { reducer, defaultState, stateUtils, MAX_HISTORY } = require('lib/reducer.js');
const reducer = require('lib/reducer').default;
const { defaultState, stateUtils, MAX_HISTORY } = require('lib/reducer');
function initTestState(folders, selectedFolderIndex, notes, selectedNoteIndexes, tags = null, selectedTagIndex = null) {
let state = defaultState;
@@ -87,7 +88,7 @@ function getIds(items, indexes = null) {
let insideBeforeEach = false;
describe('Reducer', function() {
describe('reducer', function() {
beforeEach(async (done) => {
insideBeforeEach = true;

View File

@@ -0,0 +1,58 @@
import sandboxProxy, { Target } from 'lib/services/plugins/sandboxProxy';
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
describe('services_plugins_sandboxProxy', function() {
beforeEach(async (done:Function) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
it('should create a new sandbox proxy', asyncTest(async () => {
interface Result {
path: string,
args: any[],
}
const results:Result[] = [];
const target:Target = (path:string, args:any[]) => {
results.push({ path, args });
};
const proxy = sandboxProxy(target);
proxy.testing.bla.test('hello', '123');
proxy.testing.test2();
expect(results[0].path).toBe('testing.bla.test');
expect(results[0].args.join('_')).toBe('hello_123');
expect(results[1].path).toBe('testing.test2');
expect(results[1].args.join('_')).toBe('');
}));
it('should allow importing a namespace', asyncTest(async () => {
interface Result {
path: string,
args: any[],
}
const results:Result[] = [];
const target:Target = (path:string, args:any[]) => {
results.push({ path, args });
};
const proxy = sandboxProxy(target);
const ns = proxy.testing.blabla;
ns.test();
ns.test2();
expect(results[0].path).toBe('testing.blabla.test');
expect(results[1].path).toBe('testing.blabla.test2');
}));
});

View File

@@ -0,0 +1,278 @@
import MenuUtils from 'lib/services/commands/MenuUtils';
import ToolbarButtonUtils from 'lib/services/commands/ToolbarButtonUtils';
import CommandService, { CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
interface TestCommand {
declaration: CommandDeclaration,
runtime: CommandRuntime,
}
function newService():CommandService {
const service = new CommandService();
service.initialize({});
return service;
}
function createCommand(name:string, options:any):TestCommand {
const declaration:CommandDeclaration = {
name: name,
};
const runtime:CommandRuntime = {
execute: options.execute,
};
if (options.mapStateToProps) runtime.mapStateToProps = options.mapStateToProps;
if (options.isEnabled) runtime.isEnabled = options.isEnabled;
return { declaration, runtime };
}
function registerCommand(service:CommandService, cmd:TestCommand) {
service.registerDeclaration(cmd.declaration);
service.registerRuntime(cmd.declaration.name, cmd.runtime);
}
describe('services_CommandService', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
it('should create toolbar button infos from commands', asyncTest(async () => {
const service = newService();
const toolbarButtonUtils = new ToolbarButtonUtils(service);
const executedCommands:string[] = [];
registerCommand(service, createCommand('test1', {
execute: () => {
executedCommands.push('test1');
},
}));
registerCommand(service, createCommand('test2', {
execute: () => {
executedCommands.push('test2');
},
}));
const toolbarInfos = toolbarButtonUtils.commandsToToolbarButtons({}, ['test1', 'test2']);
await toolbarInfos[0].onClick();
await toolbarInfos[1].onClick();
expect(executedCommands.join('_')).toBe('test1_test2');
expect(toolbarInfos[0].enabled).toBe(true);
expect(toolbarInfos[1].enabled).toBe(true);
}));
it('should enable and disable toolbar buttons depending on state', asyncTest(async () => {
const service = newService();
const toolbarButtonUtils = new ToolbarButtonUtils(service);
registerCommand(service, createCommand('test1', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedNoteId: state.selectedNoteId,
selectedFolderId: state.selectedFolderId,
};
},
isEnabled: (props:any) => {
return props.selectedNoteId === 'abc';
},
}));
registerCommand(service, createCommand('test2', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedNoteId: state.selectedNoteId,
selectedFolderId: state.selectedFolderId,
};
},
isEnabled: (props:any) => {
return props.selectedNoteId === '123';
},
}));
const toolbarInfos = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: '123',
selectedFolderId: 'aaa',
}, ['test1', 'test2']);
expect(toolbarInfos[0].enabled).toBe(false);
expect(toolbarInfos[1].enabled).toBe(true);
}));
it('should return the same toolbarButtons array if nothing has changed', asyncTest(async () => {
const service = newService();
const toolbarButtonUtils = new ToolbarButtonUtils(service);
registerCommand(service, createCommand('test1', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedNoteId: state.selectedNoteId,
};
},
isEnabled: (props:any) => {
return props.selectedNoteId === 'ok';
},
}));
registerCommand(service, createCommand('test2', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedFolderId: state.selectedFolderId,
};
},
isEnabled: (props:any) => {
return props.selectedFolderId === 'ok';
},
}));
const toolbarInfos1 = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', 'test2']);
const toolbarInfos2 = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', 'test2']);
expect(toolbarInfos1).toBe(toolbarInfos2);
expect(toolbarInfos1[0] === toolbarInfos2[0]).toBe(true);
expect(toolbarInfos1[1] === toolbarInfos2[1]).toBe(true);
const toolbarInfos3 = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'ok',
}, ['test1', 'test2']);
expect(toolbarInfos2 === toolbarInfos3).toBe(false);
expect(toolbarInfos2[0] === toolbarInfos3[0]).toBe(true);
expect(toolbarInfos2[1] === toolbarInfos3[1]).toBe(false);
{
expect(toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', '-', 'test2'])).toBe(toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', '-', 'test2']));
}
}));
it('should create menu items from commands', asyncTest(async () => {
const service = newService();
const utils = new MenuUtils(service);
registerCommand(service, createCommand('test1', {
execute: () => {},
}));
registerCommand(service, createCommand('test2', {
execute: () => {},
}));
const clickedCommands:string[] = [];
const onClick = (commandName:string) => {
clickedCommands.push(commandName);
};
const menuItems = utils.commandsToMenuItems(['test1', 'test2'], onClick);
menuItems.test1.click();
menuItems.test2.click();
expect(clickedCommands.join('_')).toBe('test1_test2');
// Also check that the same commands always return strictly the same menu
expect(utils.commandsToMenuItems(['test1', 'test2'], onClick)).toBe(utils.commandsToMenuItems(['test1', 'test2'], onClick));
}));
it('should give menu item props from state', asyncTest(async () => {
const service = newService();
const utils = new MenuUtils(service);
registerCommand(service, createCommand('test1', {
mapStateToProps: (state:any) => {
return {
isOk: state.test1 === 'ok',
};
},
execute: () => {},
}));
registerCommand(service, createCommand('test2', {
mapStateToProps: (state:any) => {
return {
isOk: state.test2 === 'ok',
};
},
execute: () => {},
}));
{
const menuItemProps = utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'notok',
}, ['test1', 'test2']);
expect(menuItemProps.test1.isOk).toBe(true);
expect(menuItemProps.test2.isOk).toBe(false);
}
{
const menuItemProps = utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'ok',
}, ['test1', 'test2']);
expect(menuItemProps.test1.isOk).toBe(true);
expect(menuItemProps.test2.isOk).toBe(true);
}
expect(utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'ok',
}, ['test1', 'test2'])).toBe(utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'ok',
}, ['test1', 'test2']));
}));
it('should create stateful menu items', asyncTest(async () => {
const service = newService();
const utils = new MenuUtils(service);
let propValue = null;
registerCommand(service, createCommand('test1', {
mapStateToProps: (state:any) => {
return {
isOk: state.test1 === 'ok',
};
},
execute: (props:any) => {
propValue = props.isOk;
},
}));
const menuItem = utils.commandToStatefulMenuItem('test1', { isOk: 'hello' });
menuItem.click();
expect(propValue).toBe('hello');
}));
});

View File

@@ -8,7 +8,7 @@ const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const { Database } = require('lib/database.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const BaseItem = require('lib/models/BaseItem.js');
const BaseModel = require('lib/BaseModel.js');
const MasterKey = require('lib/models/MasterKey');
@@ -289,35 +289,4 @@ describe('services_EncryptionService', function() {
const plainText = await service.decryptString(cipherText);
expect(plainText).toBe('🐶🐶🐶'.substr(0,5));
}));
// it('should upgrade master key encryption mode', asyncTest(async () => {
// let masterKey = await service.generateMasterKey('123456', {
// encryptionMethod: EncryptionService.METHOD_SJCL_2,
// });
// masterKey = await MasterKey.save(masterKey);
// Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
// Setting.setValue('encryption.activeMasterKeyId', masterKey.id);
// await sleep(0.01);
// await service.loadMasterKeysFromSettings();
// masterKeyNew = await MasterKey.load(masterKey.id);
// // Check that the master key has been upgraded
// expect(masterKeyNew.created_time).toBe(masterKey.created_time);
// expect(masterKeyNew.updated_time === masterKey.updated_time).toBe(false);
// expect(masterKeyNew.content === masterKey.content).toBe(false);
// expect(masterKeyNew.encryption_method === masterKey.encryption_method).toBe(false);
// expect(masterKeyNew.checksum === masterKey.checksum).toBe(false);
// expect(masterKeyNew.encryption_method).toBe(service.defaultMasterKeyEncryptionMethod_);
// // Check that encryption still works
// const cipherText = await service.encryptString('some secret');
// const plainText = await service.decryptString(cipherText);
// expect(plainText).toBe('some secret');
// }));
});

View File

@@ -1,19 +1,16 @@
/* eslint-disable no-unused-vars */
import InteropService from 'lib/services/interop/InteropService';
import { CustomExportContext, CustomImportContext, Module, ModuleType } from 'lib/services/interop/types';
import shim from 'lib/shim';
require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, fileContentEqual, expectNotThrow, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const InteropService = require('lib/services/InteropService.js');
const { asyncTest, fileContentEqual, setupDatabaseAndSynchronizer, switchClient, checkThrowAsync } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const NoteTag = require('lib/models/NoteTag.js');
const Resource = require('lib/models/Resource.js');
const fs = require('fs-extra');
const ArrayUtils = require('lib/ArrayUtils');
const ObjectUtils = require('lib/ObjectUtils');
const { shim } = require('lib/shim.js');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
@@ -23,7 +20,7 @@ function exportDir() {
return `${__dirname}/export`;
}
function fieldsEqual(model1, model2, fieldNames) {
function fieldsEqual(model1:any, model2:any, fieldNames:string[]) {
for (let i = 0; i < fieldNames.length; i++) {
const f = fieldNames[i];
expect(model1[f]).toBe(model2[f], `For key ${f}`);
@@ -43,7 +40,7 @@ describe('services_InteropService', function() {
});
it('should export and import folders', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
let folder1 = await Folder.save({ title: 'folder1' });
folder1 = await Folder.load(folder1.id);
const filePath = `${exportDir()}/test.jex`;
@@ -78,7 +75,7 @@ describe('services_InteropService', function() {
}));
it('should import folders and de-duplicate titles when needed', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const folder1 = await Folder.save({ title: 'folder' });
const folder2 = await Folder.save({ title: 'folder' });
const filePath = `${exportDir()}/test.jex`;
@@ -90,15 +87,15 @@ describe('services_InteropService', function() {
await service.import({ path: filePath });
const allFolders = await Folder.all();
expect(allFolders.map(f => f.title).sort().join(' - ')).toBe('folder - folder (1)');
expect(allFolders.map((f:any) => f.title).sort().join(' - ')).toBe('folder - folder (1)');
}));
it('should import folders, and only de-duplicate titles when needed', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const folder1 = await Folder.save({ title: 'folder1' });
const folder2 = await Folder.save({ title: 'folder2' });
const sub1 = await Folder.save({ title: 'Sub', parent_id: folder1.id });
const sub2 = await Folder.save({ title: 'Sub', parent_id: folder2.id });
await Folder.save({ title: 'Sub', parent_id: folder1.id });
await Folder.save({ title: 'Sub', parent_id: folder2.id });
const filePath = `${exportDir()}/test.jex`;
await service.export({ path: filePath });
@@ -117,7 +114,7 @@ describe('services_InteropService', function() {
}));
it('should export and import folders and notes', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const folder1 = await Folder.save({ title: 'folder1' });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
note1 = await Note.load(note1.id);
@@ -156,7 +153,7 @@ describe('services_InteropService', function() {
}));
it('should export and import notes to specific folder', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const folder1 = await Folder.save({ title: 'folder1' });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
note1 = await Note.load(note1.id);
@@ -175,7 +172,7 @@ describe('services_InteropService', function() {
}));
it('should export and import tags', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const filePath = `${exportDir()}/test.jex`;
const folder1 = await Folder.save({ title: 'folder1' });
const note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
@@ -215,7 +212,7 @@ describe('services_InteropService', function() {
}));
it('should export and import resources', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const filePath = `${exportDir()}/test.jex`;
const folder1 = await Folder.save({ title: 'folder1' });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
@@ -251,7 +248,7 @@ describe('services_InteropService', function() {
}));
it('should export and import single notes', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const filePath = `${exportDir()}/test.jex`;
const folder1 = await Folder.save({ title: 'folder1' });
const note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
@@ -271,7 +268,7 @@ describe('services_InteropService', function() {
}));
it('should export and import single folders', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const filePath = `${exportDir()}/test.jex`;
const folder1 = await Folder.save({ title: 'folder1' });
const note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
@@ -292,7 +289,7 @@ describe('services_InteropService', function() {
it('should export and import folder and its sub-folders', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const filePath = `${exportDir()}/test.jex`;
const folder1 = await Folder.save({ title: 'folder1' });
const folder2 = await Folder.save({ title: 'folder2', parent_id: folder1.id });
@@ -326,7 +323,7 @@ describe('services_InteropService', function() {
}));
it('should export and import links to notes', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const filePath = `${exportDir()}/test.jex`;
const folder1 = await Folder.save({ title: 'folder1' });
const note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
@@ -349,43 +346,21 @@ describe('services_InteropService', function() {
expect(note2_2.body.indexOf(note1_2.id) >= 0).toBe(true);
}));
it('should export into json format', asyncTest(async () => {
const service = new InteropService();
const folder1 = await Folder.save({ title: 'folder1' });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
note1 = await Note.load(note1.id);
const filePath = exportDir();
await service.export({ path: filePath, format: 'json' });
// verify that the json files exist and can be parsed
const items = [folder1, note1];
for (let i = 0; i < items.length; i++) {
const jsonFile = `${filePath}/${items[i].id}.json`;
const json = await fs.readFile(jsonFile, 'utf-8');
const obj = JSON.parse(json);
expect(obj.id).toBe(items[i].id);
expect(obj.type_).toBe(items[i].type_);
expect(obj.title).toBe(items[i].title);
expect(obj.body).toBe(items[i].body);
}
}));
it('should export selected notes in md format', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const folder1 = await Folder.save({ title: 'folder1' });
let note11 = await Note.save({ title: 'title note11', parent_id: folder1.id });
note11 = await Note.load(note11.id);
let note12 = await Note.save({ title: 'title note12', parent_id: folder1.id });
note12 = await Note.load(note12.id);
const note12 = await Note.save({ title: 'title note12', parent_id: folder1.id });
await Note.load(note12.id);
let folder2 = await Folder.save({ title: 'folder2', parent_id: folder1.id });
folder2 = await Folder.load(folder2.id);
let note21 = await Note.save({ title: 'title note21', parent_id: folder2.id });
note21 = await Note.load(note21.id);
let folder3 = await Folder.save({ title: 'folder3', parent_id: folder1.id });
folder3 = await Folder.load(folder2.id);
await Folder.save({ title: 'folder3', parent_id: folder1.id });
await Folder.load(folder2.id);
const outDir = exportDir();
@@ -401,16 +376,16 @@ describe('services_InteropService', function() {
}));
it('should export MD with unicode filenames', asyncTest(async () => {
const service = new InteropService();
const service = InteropService.instance();
const folder1 = await Folder.save({ title: 'folder1' });
const folder2 = await Folder.save({ title: 'ジョプリン' });
const note1 = await Note.save({ title: '生活', parent_id: folder1.id });
const note2 = await Note.save({ title: '生活', parent_id: folder1.id });
const note2b = await Note.save({ title: '生活', parent_id: folder1.id });
const note3 = await Note.save({ title: '', parent_id: folder1.id });
const note4 = await Note.save({ title: '', parent_id: folder1.id });
const note5 = await Note.save({ title: 'salut, ça roule ?', parent_id: folder1.id });
const note6 = await Note.save({ title: 'ジョプリン', parent_id: folder2.id });
await Note.save({ title: '生活', parent_id: folder1.id });
await Note.save({ title: '生活', parent_id: folder1.id });
await Note.save({ title: '生活', parent_id: folder1.id });
await Note.save({ title: '', parent_id: folder1.id });
await Note.save({ title: '', parent_id: folder1.id });
await Note.save({ title: 'salut, ça roule ?', parent_id: folder1.id });
await Note.save({ title: 'ジョプリン', parent_id: folder2.id });
const outDir = exportDir();
@@ -430,7 +405,7 @@ describe('services_InteropService', function() {
await Note.save({ title: 'textexportnote1', parent_id: folder1.id });
await Note.save({ title: 'textexportnote2', parent_id: folder1.id });
const service = new InteropService();
const service = InteropService.instance();
await service.export({
path: exportDir(),
@@ -454,7 +429,7 @@ describe('services_InteropService', function() {
await Folder.save({ title: 'orphan', parent_id: '0c5bbd8a1b5a48189484a412a7e534cc' });
const service = new InteropService();
const service = InteropService.instance();
const result = await service.export({
path: exportDir(),
@@ -464,4 +439,99 @@ describe('services_InteropService', function() {
expect(result.warnings.length).toBe(0);
}));
it('should allow registering new import modules', asyncTest(async () => {
const testImportFilePath = `${exportDir()}/testImport${Math.random()}.test`;
await shim.fsDriver().writeFile(testImportFilePath, 'test', 'utf8');
const result = {
hasBeenExecuted: false,
sourcePath: '',
};
const module:Module = {
type: ModuleType.Importer,
description: 'Test Import Module',
format: 'testing',
fileExtensions: ['test'],
isCustom: true,
onExec: async (context:CustomImportContext) => {
result.hasBeenExecuted = true;
result.sourcePath = context.sourcePath;
},
};
const service = InteropService.instance();
service.registerModule(module);
await service.import({
format: 'testing',
path: testImportFilePath,
});
expect(result.hasBeenExecuted).toBe(true);
expect(result.sourcePath).toBe(testImportFilePath);
}));
it('should allow registering new export modules', asyncTest(async () => {
const folder1 = await Folder.save({ title: 'folder1' });
const note1 = await Note.save({ title: 'note1', parent_id: folder1.id });
await Note.save({ title: 'note2', parent_id: folder1.id });
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
const filePath = `${exportDir()}/example.test`;
const result:any = {
destPath: '',
itemTypes: [],
items: [],
resources: [],
filePaths: [],
closeCalled: false,
};
const module:Module = {
type: ModuleType.Exporter,
description: 'Test Export Module',
format: 'testing',
fileExtensions: ['test'],
isCustom: true,
onInit: async (context:CustomExportContext) => {
result.destPath = context.destPath;
},
onProcessItem: async (_context:CustomExportContext, itemType:number, item:any) => {
result.itemTypes.push(itemType);
result.items.push(item);
},
onProcessResource: async (_context:CustomExportContext, resource:any, filePath:string) => {
result.resources.push(resource);
result.filePaths.push(filePath);
},
onClose: async (_context:CustomExportContext) => {
result.closeCalled = true;
},
};
const service = InteropService.instance();
service.registerModule(module);
await service.export({
format: 'testing',
path: filePath,
});
expect(result.destPath).toBe(filePath);
expect(result.itemTypes.sort().join('_')).toBe('1_1_2_4');
expect(result.items.length).toBe(4);
expect(result.items.map((o:any) => o.title).sort().join('_')).toBe('folder1_note1_note2_photo.jpg');
expect(result.resources.length).toBe(1);
expect(result.resources[0].title).toBe('photo.jpg');
expect(result.filePaths.length).toBe(1);
expect(!!result.filePaths[0]).toBe(true);
expect(result.closeCalled).toBe(true);
}));
});

View File

@@ -4,12 +4,12 @@ require('app-module-path').addPath(__dirname);
const fs = require('fs-extra');
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
const InteropService_Exporter_Md = require('lib/services/InteropService_Exporter_Md.js');
const InteropService_Exporter_Md = require('lib/services/interop/InteropService_Exporter_Md').default;
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Resource = require('lib/models/Resource.js');
const Note = require('lib/models/Note.js');
const { shim } = require('lib/shim.js');
const shim = require('lib/shim').default;
const exportDir = `${__dirname}/export`;
@@ -67,8 +67,8 @@ describe('services_InteropService_Exporter_Md', function() {
expect(!exporter.context() && !(exporter.context().notePaths || Object.keys(exporter.context().notePaths).length)).toBe(false, 'Context should be empty before processing.');
await exporter.processItem(Folder, folder1);
await exporter.processItem(Folder, folder2);
await exporter.processItem(Folder.modelType(), folder1);
await exporter.processItem(Folder.modelType(), folder2);
await exporter.prepareForProcessingItemType(BaseModel.TYPE_NOTE, itemsToExport);
expect(Object.keys(exporter.context().notePaths).length).toBe(3, 'There should be 3 note paths in the context.');
@@ -96,7 +96,7 @@ describe('services_InteropService_Exporter_Md', function() {
queueExportItem(BaseModel.TYPE_NOTE, note1);
queueExportItem(BaseModel.TYPE_NOTE, note1_2);
await exporter.processItem(Folder, folder1);
await exporter.processItem(Folder.modelType(), folder1);
await exporter.prepareForProcessingItemType(BaseModel.TYPE_NOTE, itemsToExport);
expect(Object.keys(exporter.context().notePaths).length).toBe(2, 'There should be 2 note paths in the context.');
@@ -121,7 +121,7 @@ describe('services_InteropService_Exporter_Md', function() {
queueExportItem(BaseModel.TYPE_FOLDER, folder1.id);
queueExportItem(BaseModel.TYPE_NOTE, note1);
await exporter.processItem(Folder, folder1);
await exporter.processItem(Folder.modelType(), folder1);
// Create a file with the path of note1 before processing note1
await shim.fsDriver().writeFile(`${exportDir}/folder1/note1.md`, 'Note content', 'utf-8');
@@ -189,10 +189,10 @@ describe('services_InteropService_Exporter_Md', function() {
const folder3 = await Folder.save({ title: 'folder3', parent_id: folder1.id });
queueExportItem(BaseModel.TYPE_FOLDER, folder3.id);
await exporter.processItem(Folder, folder2);
await exporter.processItem(Folder, folder3);
await exporter.processItem(Folder.modelType(), folder2);
await exporter.processItem(Folder.modelType(), folder3);
await exporter.prepareForProcessingItemType(BaseModel.TYPE_NOTE, itemsToExport);
await exporter.processItem(Note, note2);
await exporter.processItem(Note.modelType(), note2);
expect(await shim.fsDriver().exists(`${exportDir}/folder1`)).toBe(true, 'Folder should be created in filesystem.');
expect(await shim.fsDriver().exists(`${exportDir}/folder1/folder2`)).toBe(true, 'Folder should be created in filesystem.');
@@ -227,9 +227,9 @@ describe('services_InteropService_Exporter_Md', function() {
queueExportItem(BaseModel.TYPE_NOTE, note3);
await exporter.prepareForProcessingItemType(BaseModel.TYPE_NOTE, itemsToExport);
await exporter.processItem(Note, note1);
await exporter.processItem(Note, note2);
await exporter.processItem(Note, note3);
await exporter.processItem(Note.modelType(), note1);
await exporter.processItem(Note.modelType(), note2);
await exporter.processItem(Note.modelType(), note3);
expect(await shim.fsDriver().exists(`${exportDir}/${exporter.context().notePaths[note1.id]}`)).toBe(true, 'File should be saved in filesystem.');
expect(await shim.fsDriver().exists(`${exportDir}/${exporter.context().notePaths[note2.id]}`)).toBe(true, 'File should be saved in filesystem.');
@@ -262,8 +262,8 @@ describe('services_InteropService_Exporter_Md', function() {
queueExportItem(BaseModel.TYPE_NOTE, note2);
const resource2 = await Resource.load((await Note.linkedResourceIds(note2.body))[0]);
await exporter.processItem(Folder, folder1);
await exporter.processItem(Folder, folder2);
await exporter.processItem(Folder.modelType(), folder1);
await exporter.processItem(Folder.modelType(), folder2);
await exporter.prepareForProcessingItemType(BaseModel.TYPE_NOTE, itemsToExport);
const context = {
resourcePaths: {},
@@ -271,8 +271,8 @@ describe('services_InteropService_Exporter_Md', function() {
context.resourcePaths[resource1.id] = 'resource1.jpg';
context.resourcePaths[resource2.id] = 'resource2.jpg';
exporter.updateContext(context);
await exporter.processItem(Note, note1);
await exporter.processItem(Note, note2);
await exporter.processItem(Note.modelType(), note1);
await exporter.processItem(Note.modelType(), note2);
const note1_body = await shim.fsDriver().readFile(`${exportDir}/${exporter.context().notePaths[note1.id]}`);
const note2_body = await shim.fsDriver().readFile(`${exportDir}/${exporter.context().notePaths[note2.id]}`);
@@ -315,13 +315,13 @@ describe('services_InteropService_Exporter_Md', function() {
queueExportItem(BaseModel.TYPE_NOTE, note2);
queueExportItem(BaseModel.TYPE_NOTE, note3);
await exporter.processItem(Folder, folder1);
await exporter.processItem(Folder, folder2);
await exporter.processItem(Folder, folder3);
await exporter.processItem(Folder.modelType(), folder1);
await exporter.processItem(Folder.modelType(), folder2);
await exporter.processItem(Folder.modelType(), folder3);
await exporter.prepareForProcessingItemType(BaseModel.TYPE_NOTE, itemsToExport);
await exporter.processItem(Note, note1);
await exporter.processItem(Note, note2);
await exporter.processItem(Note, note3);
await exporter.processItem(Note.modelType(), note1);
await exporter.processItem(Note.modelType(), note2);
await exporter.processItem(Note.modelType(), note3);
const note1_body = await shim.fsDriver().readFile(`${exportDir}/${exporter.context().notePaths[note1.id]}`);
const note2_body = await shim.fsDriver().readFile(`${exportDir}/${exporter.context().notePaths[note2.id]}`);
@@ -351,10 +351,10 @@ describe('services_InteropService_Exporter_Md', function() {
queueExportItem(BaseModel.TYPE_NOTE, note1);
queueExportItem(BaseModel.TYPE_NOTE, note2);
await exporter.processItem(Folder, folder1);
await exporter.processItem(Folder.modelType(), folder1);
await exporter.prepareForProcessingItemType(BaseModel.TYPE_NOTE, itemsToExport);
await exporter.processItem(Note, note1);
await exporter.processItem(Note, note2);
await exporter.processItem(Note.modelType(), note1);
await exporter.processItem(Note.modelType(), note2);
const note2_body = await shim.fsDriver().readFile(`${exportDir}/${exporter.context().notePaths[note2.id]}`);
expect(note2_body).toContain('[link](../folder%20with%20space1/note1%20name%20with%20space.md)', 'Whitespace in URL should be encoded');

View File

@@ -1,5 +1,6 @@
require('app-module-path').addPath(__dirname);
const { tempFilePath } = require('test-utils.js');
const KeymapService = require('lib/services/KeymapService').default;
const keymapService = KeymapService.instance();
@@ -76,6 +77,31 @@ describe('services_KeymapService', () => {
});
});
describe('registerCommandAccelerator', () => {
beforeEach(() => keymapService.initialize());
it('should allow registering new commands', async () => {
keymapService.initialize('linux');
keymapService.registerCommandAccelerator('myCustomCommand', 'Ctrl+Shift+Alt+B');
expect(keymapService.getAccelerator('myCustomCommand')).toEqual('Ctrl+Shift+Alt+B');
// Check that macOS key conversion is working
keymapService.initialize('darwin');
keymapService.registerCommandAccelerator('myCustomCommand', 'CmdOrCtrl+Shift+Alt+B');
expect(keymapService.getAccelerator('myCustomCommand')).toEqual('Cmd+Shift+Option+B');
keymapService.setAccelerator('myCustomCommand', 'Cmd+Shift+Option+X');
// Check that the new custom shortcut is being saved and loaded
const keymapFilePath = tempFilePath('json');
await keymapService.saveCustomKeymap(keymapFilePath);
keymapService.initialize('darwin');
await keymapService.loadCustomKeymap(keymapFilePath);
expect(keymapService.getAccelerator('myCustomCommand')).toEqual('Cmd+Shift+Option+X');
});
});
describe('getAccelerator', () => {
beforeEach(() => keymapService.initialize());
@@ -254,15 +280,15 @@ describe('services_KeymapService', () => {
expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
});
it('should throw when the provided commands are invalid', () => {
const customKeymapItems = [
{ command: 'totallyInvalidCommand', accelerator: 'Ctrl+Shift+G' },
{ command: 'print', accelerator: 'Alt+P' },
{ command: 'focusElementNoteTitle', accelerator: 'Ctrl+Alt+Shift+J' },
];
// it('should throw when the provided commands are invalid', () => {
// const customKeymapItems = [
// { command: 'totallyInvalidCommand', accelerator: 'Ctrl+Shift+G' },
// { command: 'print', accelerator: 'Alt+P' },
// { command: 'focusElementNoteTitle', accelerator: 'Ctrl+Alt+Shift+J' },
// ];
expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
});
// expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
// });
it('should throw when duplicate accelerators are provided', () => {
const customKeymaps_Darwin = [

View File

@@ -0,0 +1,93 @@
import PluginRunner from '../app/services/plugins/PluginRunner';
import PluginService from 'lib/services/plugins/PluginService';
require('app-module-path').addPath(__dirname);
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
const Note = require('lib/models/Note');
const Folder = require('lib/models/Folder');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
const testPluginDir = `${__dirname}/../tests/support/plugins`;
function newPluginService() {
const runner = new PluginRunner();
const service = new PluginService();
service.initialize(
{
joplin: {
workspace: {},
},
},
runner,
{
dispatch: () => {},
getState: () => {},
}
);
return service;
}
describe('services_PluginService', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
it('should load and run a simple plugin', asyncTest(async () => {
const service = newPluginService();
const plugin = await service.loadPlugin(`${testPluginDir}/simple`);
await service.runPlugin(plugin);
const allFolders = await Folder.all();
expect(allFolders.length).toBe(1);
expect(allFolders[0].title).toBe('my plugin folder');
const allNotes = await Note.all();
expect(allNotes.length).toBe(1);
expect(allNotes[0].title).toBe('testing plugin!');
expect(allNotes[0].parent_id).toBe(allFolders[0].id);
}));
it('should load and run a plugin that uses external packages', asyncTest(async () => {
const service = newPluginService();
const plugin = await service.loadPlugin(`${testPluginDir}/withExternalModules`);
expect(plugin.id).toBe('withexternalmodules');
await service.runPlugin(plugin);
const allFolders = await Folder.all();
expect(allFolders.length).toBe(1);
expect(allFolders[0].title).toBe(' foo');
}));
it('should load multiple plugins from a directory', asyncTest(async () => {
const service = newPluginService();
await service.loadAndRunPlugins(`${testPluginDir}/multi_plugins`);
const plugin1 = service.pluginById('simple1');
const plugin2 = service.pluginById('simple2');
expect(!!plugin1).toBe(true);
expect(!!plugin2).toBe(true);
const allFolders = await Folder.all();
expect(allFolders.length).toBe(2);
expect(allFolders.map((f:any) => f.title).sort().join(', ')).toBe('multi - simple1, multi - simple2');
}));
// it('should translate calls from plugin process to sandbox', asyncTest(async () => {
// const service = newPluginService();
// const plugin = await service.loadPlugin(`${testPluginDir}/simple`);
// await service.runPlugin(plugin);
// const folder = await Folder.save({ title: 'folder' });
// const folderFromApi = await service.executeSandboxCall(plugin.id, 'joplin.data.get', ['folders/' + folder.id]);
// expect(folder.id).toBe(folderFromApi.id);
// expect(folder.title).toBe(folderFromApi.title);
// }));
});

View File

@@ -4,7 +4,7 @@ require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, resourceService, decryptionWorker, encryptionService, loadEncryptionMasterKey, allSyncTargetItemsEncrypted, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const InteropService = require('lib/services/InteropService.js');
const InteropService = require('lib/services/interop/InteropService').default;
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
@@ -16,7 +16,7 @@ const ResourceService = require('lib/services/ResourceService.js');
const fs = require('fs-extra');
const ArrayUtils = require('lib/ArrayUtils');
const ObjectUtils = require('lib/ObjectUtils');
const { shim } = require('lib/shim.js');
const shim = require('lib/shim').default;
const SearchEngine = require('lib/services/searchengine/SearchEngine');
process.on('unhandledRejection', (reason, p) => {

View File

@@ -5,7 +5,7 @@ require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, fileContentEqual, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Setting = require('lib/models/Setting.js');
const Setting = require('lib/models/Setting').default;
const Note = require('lib/models/Note.js');
const NoteTag = require('lib/models/NoteTag.js');
const ItemChange = require('lib/models/ItemChange.js');
@@ -13,7 +13,7 @@ const Tag = require('lib/models/Tag.js');
const Revision = require('lib/models/Revision.js');
const BaseModel = require('lib/BaseModel.js');
const RevisionService = require('lib/services/RevisionService.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -8,7 +8,7 @@ const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, asyncTest
const SearchEngine = require('lib/services/searchengine/SearchEngine');
const Note = require('lib/models/Note');
const ItemChange = require('lib/models/ItemChange');
const Setting = require('lib/models/Setting');
const Setting = require('lib/models/Setting').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -10,9 +10,9 @@ const Note = require('lib/models/Note');
const Folder = require('lib/models/Folder');
const Tag = require('lib/models/Tag');
const ItemChange = require('lib/models/ItemChange');
const Setting = require('lib/models/Setting');
const Setting = require('lib/models/Setting').default;
const Resource = require('lib/models/Resource.js');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
const ResourceService = require('lib/services/ResourceService.js');

View File

@@ -1,163 +1,162 @@
/* eslint-disable no-unused-vars */
/* eslint prefer-const: 0*/
require('app-module-path').addPath(__dirname);
// require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, asyncTest, db, synchronizer, fileApi, sleep, createNTestNotes, switchClient, createNTestFolders } = require('test-utils.js');
const SearchEngine = require('lib/services/searchengine/SearchEngine');
const Note = require('lib/models/Note');
const Folder = require('lib/models/Folder');
const Tag = require('lib/models/Tag');
const ItemChange = require('lib/models/ItemChange');
const Setting = require('lib/models/Setting');
const Resource = require('lib/models/Resource.js');
const { shim } = require('lib/shim');
const ResourceService = require('lib/services/ResourceService.js');
// const { time } = require('lib/time-utils.js');
// const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, asyncTest, db, synchronizer, fileApi, sleep, createNTestNotes, switchClient, createNTestFolders } = require('test-utils.js');
// const SearchEngine = require('lib/services/searchengine/SearchEngine');
// const Note = require('lib/models/Note');
// const Folder = require('lib/models/Folder');
// const Tag = require('lib/models/Tag');
// const ItemChange = require('lib/models/ItemChange');
// const Setting = require('lib/models/Setting');
// const Resource = require('lib/models/Resource.js');
// const shim = require('lib/shim').default;
// const ResourceService = require('lib/services/ResourceService.js');
// process.on('unhandledRejection', (reason, p) => {
// console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// });
// let engine = null;
// const ids = (array) => array.map(a => a.id);
// describe('services_SearchFuzzy', function() {
// beforeEach(async (done) => {
// await setupDatabaseAndSynchronizer(1);
// await switchClient(1);
// engine = new SearchEngine();
// engine.setDb(db());
// Setting.setValue('db.fuzzySearchEnabled', 1);
// done();
// });
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
// it('should return note almost matching title', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'If It Ain\'t Baroque, Don\'t Fix It' });
// const n2 = await Note.save({ title: 'Important note' });
let engine = null;
// await engine.syncTables();
// rows = await engine.search('Broke', { fuzzy: false });
// expect(rows.length).toBe(0);
const ids = (array) => array.map(a => a.id);
describe('services_SearchFuzzy', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
engine = new SearchEngine();
engine.setDb(db());
Setting.setValue('db.fuzzySearchEnabled', 1);
done();
});
// rows = await engine.search('Broke', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
it('should return note almost matching title', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'If It Ain\'t Baroque, Don\'t Fix It' });
const n2 = await Note.save({ title: 'Important note' });
// rows = await engine.search('title:Broke', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
await engine.syncTables();
rows = await engine.search('Broke', { fuzzy: false });
expect(rows.length).toBe(0);
// rows = await engine.search('title:"Broke"', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
rows = await engine.search('Broke', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('Imprtant', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n2.id);
// }));
rows = await engine.search('title:Broke', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
// it('should order results by min fuzziness', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'I demand you take me to him' });
// const n2 = await Note.save({ title: 'He demanded an answer' });
// const n3 = await Note.save({ title: 'Don\'t you make demands of me' });
// const n4 = await Note.save({ title: 'No drama for me' });
// const n5 = await Note.save({ title: 'Just minding my own business' });
rows = await engine.search('title:"Broke"', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
rows = await engine.search('Imprtant', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n2.id);
}));
// await engine.syncTables();
// rows = await engine.search('demand', { fuzzy: false });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
it('should order results by min fuzziness', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'I demand you take me to him' });
const n2 = await Note.save({ title: 'He demanded an answer' });
const n3 = await Note.save({ title: 'Don\'t you make demands of me' });
const n4 = await Note.save({ title: 'No drama for me' });
const n5 = await Note.save({ title: 'Just minding my own business' });
// rows = await engine.search('demand', { fuzzy: true });
// expect(rows.length).toBe(3);
// expect(rows[0].id).toBe(n1.id);
// expect(rows[1].id).toBe(n3.id);
// expect(rows[2].id).toBe(n2.id);
// }));
await engine.syncTables();
rows = await engine.search('demand', { fuzzy: false });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
// it('should consider any:1', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'cat' });
// const n2 = await Note.save({ title: 'cats' });
// const n3 = await Note.save({ title: 'cot' });
// const n4 = await Note.save({ title: 'defenestrate' });
// const n5 = await Note.save({ title: 'defenstrate' });
// const n6 = await Note.save({ title: 'defenestrated' });
rows = await engine.search('demand', { fuzzy: true });
expect(rows.length).toBe(3);
expect(rows[0].id).toBe(n1.id);
expect(rows[1].id).toBe(n3.id);
expect(rows[2].id).toBe(n2.id);
}));
// const n7 = await Note.save({ title: 'he defenestrated the cat' });
it('should consider any:1', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'cat' });
const n2 = await Note.save({ title: 'cats' });
const n3 = await Note.save({ title: 'cot' });
// await engine.syncTables();
const n4 = await Note.save({ title: 'defenestrate' });
const n5 = await Note.save({ title: 'defenstrate' });
const n6 = await Note.save({ title: 'defenestrated' });
// rows = await engine.search('defenestrated cat', { fuzzy: true });
// expect(rows.length).toBe(1);
const n7 = await Note.save({ title: 'he defenestrated the cat' });
// rows = await engine.search('any:1 defenestrated cat', { fuzzy: true });
// expect(rows.length).toBe(7);
// }));
await engine.syncTables();
// it('should leave phrase searches alone', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'abc def' });
// const n2 = await Note.save({ title: 'def ghi' });
// const n3 = await Note.save({ title: 'ghi jkl' });
// const n4 = await Note.save({ title: 'def abc' });
// const n5 = await Note.save({ title: 'mno pqr ghi jkl' });
rows = await engine.search('defenestrated cat', { fuzzy: true });
expect(rows.length).toBe(1);
// await engine.syncTables();
rows = await engine.search('any:1 defenestrated cat', { fuzzy: true });
expect(rows.length).toBe(7);
}));
// rows = await engine.search('abc def', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n1.id);
// expect(rows.map(r=>r.id)).toContain(n4.id);
it('should leave phrase searches alone', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'abc def' });
const n2 = await Note.save({ title: 'def ghi' });
const n3 = await Note.save({ title: 'ghi jkl' });
const n4 = await Note.save({ title: 'def abc' });
const n5 = await Note.save({ title: 'mno pqr ghi jkl' });
// rows = await engine.search('"abc def"', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows.map(r=>r.id)).toContain(n1.id);
await engine.syncTables();
// rows = await engine.search('"ghi jkl"', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n5.id);
rows = await engine.search('abc def', { fuzzy: true });
expect(rows.length).toBe(2);
expect(rows.map(r=>r.id)).toContain(n1.id);
expect(rows.map(r=>r.id)).toContain(n4.id);
// rows = await engine.search('"ghi jkl" mno', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows.map(r=>r.id)).toContain(n5.id);
rows = await engine.search('"abc def"', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows.map(r=>r.id)).toContain(n1.id);
// rows = await engine.search('any:1 "ghi jkl" mno', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n5.id);
// }));
rows = await engine.search('"ghi jkl"', { fuzzy: true });
expect(rows.length).toBe(2);
expect(rows.map(r=>r.id)).toContain(n3.id);
expect(rows.map(r=>r.id)).toContain(n5.id);
// it('should leave wild card searches alone', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'abc def' });
// const n2 = await Note.save({ title: 'abcc ghi' });
// const n3 = await Note.save({ title: 'abccc ghi' });
// const n4 = await Note.save({ title: 'abcccc ghi' });
// const n5 = await Note.save({ title: 'wxy zzz' });
rows = await engine.search('"ghi jkl" mno', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows.map(r=>r.id)).toContain(n5.id);
// await engine.syncTables();
rows = await engine.search('any:1 "ghi jkl" mno', { fuzzy: true });
expect(rows.length).toBe(2);
expect(rows.map(r=>r.id)).toContain(n3.id);
expect(rows.map(r=>r.id)).toContain(n5.id);
}));
// rows = await engine.search('abc*', { fuzzy: true });
it('should leave wild card searches alone', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'abc def' });
const n2 = await Note.save({ title: 'abcc ghi' });
const n3 = await Note.save({ title: 'abccc ghi' });
const n4 = await Note.save({ title: 'abcccc ghi' });
const n5 = await Note.save({ title: 'wxy zzz' });
// expect(rows.length).toBe(4);
// expect(rows.map(r=>r.id)).toContain(n1.id);
// expect(rows.map(r=>r.id)).toContain(n2.id);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n4.id);
// }));
await engine.syncTables();
rows = await engine.search('abc*', { fuzzy: true });
expect(rows.length).toBe(4);
expect(rows.map(r=>r.id)).toContain(n1.id);
expect(rows.map(r=>r.id)).toContain(n2.id);
expect(rows.map(r=>r.id)).toContain(n3.id);
expect(rows.map(r=>r.id)).toContain(n4.id);
}));
});
// });

View File

@@ -1,84 +0,0 @@
// /* eslint-disable no-unused-vars */
// require('app-module-path').addPath(__dirname);
// const { asyncTest, fileContentEqual, setupDatabase, checkThrow, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
// const KvStore = require('lib/services/KvStore.js');
// const UndoRedoService = require('lib/services/UndoRedoService.js').default;
// process.on('unhandledRejection', (reason, p) => {
// console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// });
// describe('services_UndoRedoService', function() {
// beforeEach(async (done) => {
// await setupDatabaseAndSynchronizer(1);
// await switchClient(1);
// done();
// });
// it('should undo and redo', asyncTest(async () => {
// const service = new UndoRedoService();
// expect(service.canUndo).toBe(false);
// expect(service.canRedo).toBe(false);
// service.push('test');
// expect(service.canUndo).toBe(true);
// expect(service.canRedo).toBe(false);
// service.push('test 2');
// service.push('test 3');
// expect(service.undo()).toBe('test 3');
// expect(service.canRedo).toBe(true);
// expect(service.undo()).toBe('test 2');
// expect(service.undo()).toBe('test');
// expect(checkThrow(() => service.undo())).toBe(true);
// expect(service.canUndo).toBe(false);
// expect(service.canRedo).toBe(true);
// expect(service.redo()).toBe('test');
// expect(service.canUndo).toBe(true);
// expect(service.redo()).toBe('test 2');
// expect(service.redo()).toBe('test 3');
// expect(service.canRedo).toBe(false);
// expect(checkThrow(() => service.redo())).toBe(true);
// }));
// it('should clear the redo stack when undoing', asyncTest(async () => {
// const service = new UndoRedoService();
// service.push('test');
// service.push('test 2');
// service.push('test 3');
// service.undo();
// expect(service.canRedo).toBe(true);
// service.push('test 4');
// expect(service.canRedo).toBe(false);
// expect(service.undo()).toBe('test 4');
// expect(service.undo()).toBe('test 2');
// }));
// it('should limit the size of the undo stack', asyncTest(async () => {
// const service = new UndoRedoService();
// for (let i = 0; i < 30; i++) {
// service.push(`test${i}`);
// }
// for (let i = 0; i < 20; i++) {
// service.undo();
// }
// expect(service.canUndo).toBe(false);
// }));
// });

View File

@@ -3,8 +3,8 @@
require('app-module-path').addPath(__dirname);
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const { shim } = require('lib/shim');
const Setting = require('lib/models/Setting');
const shim = require('lib/shim').default;
const Setting = require('lib/models/Setting').default;
const KeychainService = require('lib/services/keychain/KeychainService').default;
process.on('unhandledRejection', (reason, p) => {
@@ -50,7 +50,7 @@ describeIfCompatible('services_KeychainService', function() {
}));
it('should save and load secure settings', asyncTest(async () => {
Setting.setObjectKey('encryption.passwordCache', 'testing', '123456');
Setting.setObjectValue('encryption.passwordCache', 'testing', '123456');
await Setting.saveAll();
await Setting.load();
const passwords = Setting.value('encryption.passwordCache');

View File

@@ -9,7 +9,7 @@ const Resource = require('lib/models/Resource');
const Note = require('lib/models/Note');
const Tag = require('lib/models/Tag');
const NoteTag = require('lib/models/NoteTag');
const { shim } = require('lib/shim');
const shim = require('lib/shim').default;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);

View File

@@ -2,6 +2,7 @@
"spec_dir": "tests-build",
"spec_files": [
"*.js",
"services/plugins/*.js",
"!test-utils.js"
],
"stopSpecOnExpectationFailure": false,

View File

@@ -0,0 +1 @@
!function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e){var n=this&&this.__assign||function(){return(n=Object.assign||function(t){for(var e,n=1,r=arguments.length;n<r;n++)for(var o in e=arguments[n])Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t}).apply(this,arguments)},r=this&&this.__awaiter||function(t,e,n,r){return new(n||(n=Promise))((function(o,i){function u(t){try{a(r.next(t))}catch(t){i(t)}}function l(t){try{a(r.throw(t))}catch(t){i(t)}}function a(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(u,l)}a((r=r.apply(t,e||[])).next())}))},o=this&&this.__generator||function(t,e){var n,r,o,i,u={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:l(0),throw:l(1),return:l(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function l(i){return function(l){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;u;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return u.label++,{value:i[1],done:!1};case 5:u.label++,r=i[1],i=[0];continue;case 7:i=u.ops.pop(),u.trys.pop();continue;default:if(!(o=u.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){u=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]<o[3])){u.label=i[1];break}if(6===i[0]&&u.label<o[1]){u.label=o[1],o=i;break}if(o&&u.label<o[2]){u.label=o[2],u.ops.push(i);break}o[2]&&u.ops.pop(),u.trys.pop();continue}i=e.call(t,u)}catch(t){i=[6,t],r=0}finally{n=o=0}if(5&i[0])throw i[1];return{value:i[0]?i[1]:void 0,done:!0}}([i,l])}}};joplin.plugins.register({run:function(){return r(this,void 0,void 0,(function(){return o(this,(function(t){return joplin.filters.on("codeMirrorOptions",(function(t){return n(n({},t),{lineNumbers:!0})})),[2]}))}))}})}]);

View File

@@ -0,0 +1,9 @@
{
"manifest_version": 1,
"name": "To test setting preferences on CodeMirror editor",
"version": "1.0.0",
"homepage_url": "https://joplinapp.org",
"permissions": [
"model"
]
}

View File

@@ -0,0 +1 @@
declare var joplin:any;

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