1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-01-20 00:46:28 +02:00

Compare commits

...

511 Commits

Author SHA1 Message Date
Laurent Cozic
c5d9646908 Desktop release v3.6.2 2026-01-18 11:33:16 +00:00
Henry Heino
876ec80911 Desktop: Fixes #14084: .onepkg import: Fix Unicode issues, support Linux and MacOS (#14094)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-18 11:31:48 +00:00
mrjo118
4051f88ce7 Chore: Fix intermittent Synchronizer.revisions test failure (#14096)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-18 11:31:42 +00:00
Laurent Cozic
f194c111e4 All: Fixes #14144: Application crashes when profile database has been analyzed 2026-01-18 11:30:05 +00:00
Henry Heino
e386246bc9 Chore: Sync fuzzer: Improve error logging (#14108)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-18 11:29:32 +00:00
Henry Heino
292b269f1d Desktop: Resolves #14086: Accessibility: Include accessibility information in exported PDFs (#14111)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-18 11:29:25 +00:00
renovate[bot]
b2fc43da2b Update dependency short-uuid to v4.2.2 (#14114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-18 11:29:17 +00:00
Henry Heino
4a23a1ed3e Desktop: Fixes #14092: Built-in plugins: Upgrade Freehand Drawing to v4.3.0 (#14123)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-18 11:29:07 +00:00
Henry Heino
c8878a18bf Desktop, Mobile: Editor: Inline rendering: Render inline HTML (colorized text, superscript, subscript, strikethrough) (#14133) 2026-01-18 11:28:15 +00:00
Henry Heino
340fba7af5 Server: Fixes #14107: Fix warning when unsharing folder (#14134) 2026-01-18 11:25:52 +00:00
Henry Heino
271c4f4a2a Server: Fixes #14131: Allow changing the password for the admin account when SAML is enabled (#14135) 2026-01-18 11:25:38 +00:00
Henry Heino
c9dba20f59 Chore: Sync fuzzer: Allow specifying a set of initial actions (#14136)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-18 11:25:07 +00:00
renovate[bot]
b474cc206a Update dependency dotenv to v17 (#14138)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-18 11:24:46 +00:00
Milo Ivir
9d4df8cc6e All: Translation: Update hr_HR.po (#14140) 2026-01-17 20:57:39 -05:00
Joplin Bot
a4ddfe1f58 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-01-17 18:38:35 +00:00
renovate[bot]
7d15215e66 Update dependency react-native-device-info to v14.1.1 (#14132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-17 14:23:02 +00:00
Laurent Cozic
5b74e206ed Desktop release v3.6.1 2026-01-17 11:19:55 +00:00
Laurent Cozic
9873d02b0b Chore: Setup new release 3.6 2026-01-17 11:19:43 +00:00
Laurent Cozic
57b7d98d8a Merge branch 'release-3.5' into dev 2026-01-17 11:18:39 +00:00
Laurent Cozic
f075b561a2 All: Add more error information when the profile is corrupted 2026-01-17 11:17:43 +00:00
renovate[bot]
483d051de0 Update dependency rate-limiter-flexible to v7.3.2 (#14130)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-16 15:59:43 +00:00
renovate[bot]
106cd2778f Update dependency rate-limiter-flexible to v7.3.1 (#14128)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-16 13:57:49 +00:00
Eric Duarte
c3aea2db80 All: Translation: Update ca.po (#14129) 2026-01-16 08:10:45 -05:00
Liffindra Angga Zaaldian
3f067b0f77 All: Translation: Update id_ID.po (#14127)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-16 08:08:49 -05:00
Laurent Cozic
15cf025bc2 All: Resolves #14106: Improve Fountain notes exported as PDF (#14120) 2026-01-16 11:30:54 +00:00
Henry Heino
4677586e3b Desktop: Rich Text Editor: Fix cut, copy, paste, and select all menu items (#14125) 2026-01-16 11:30:39 +00:00
Laurent Cozic
b8c5b7a153 Doc: Added Contribution Scope Policy 2026-01-16 10:19:32 +00:00
renovate[bot]
e46e634c2e Update dependency style-to-js to v1.1.18 (#14118)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-16 09:44:18 +00:00
Henry Heino
b3cf4e5a35 Chore: Fix CI (#14124) 2026-01-16 09:43:30 +00:00
Laurent Cozic
8589e10d6e Chore: Trying to fix CI 2026-01-15 14:23:00 +00:00
renovate[bot]
18942f0d6a Update dependency babel-plugin-react-native-web to v0.21.2 (#14104)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-15 13:25:14 +00:00
Eric Duarte
3be354cdcb All: Translation: Update es_ES.po (#14117) 2026-01-15 08:22:26 -05:00
renovate[bot]
0575f1aa3e Update dependency react-native-web to v0.21.2 (#14113)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-15 05:12:54 +00:00
renovate[bot]
caa9baa460 Update dependency react-native-localize to v3.5.4 (#14112)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-15 02:04:45 +00:00
renovate[bot]
b5284804d8 Update dependency qrcode to v1.5.4 (#14109)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-15 00:07:22 +00:00
renovate[bot]
6053b4296c Update dependency esbuild to v0.25.11 (#14101)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-14 13:56:24 +00:00
renovate[bot]
615fec1d2c Update dependency @rollup/plugin-node-resolve to v16.0.3 (#14100)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-14 13:54:35 +00:00
Laurent Cozic
0bbcd9a59b All: Add support for external embeds, eg. YouTube videos (#14012) 2026-01-14 13:52:17 +00:00
renovate[bot]
6931b32f17 Update dependency @rollup/plugin-commonjs to v28.0.8 (#14099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-14 12:09:18 +00:00
renovate[bot]
17ac501ddb Update dependency @types/serviceworker to v0.0.158 (#14060)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-14 09:32:41 +00:00
renovate[bot]
94161c5f93 Update dependency @types/react to v18.3.26 (#14050)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2026-01-14 09:32:34 +00:00
Jozef Gaal
196255e960 All: Translation: Update sk_SK.po (#14095) 2026-01-13 19:55:13 -05:00
Self Not Found
f936390ee4 All: Translation: Update zh_CN.po (#14091) 2026-01-13 16:48:20 -05:00
Laurent Cozic
5638c4b812 Chore: Fixed various typo and grammar mistakes 2026-01-13 16:28:24 +00:00
Linkosred
4222caa423 Docs : Add video tutorial link for several pages of the documentation (#14068) 2026-01-13 16:20:52 +00:00
Henry Heino
bc705acc5c Windows: Fixes #13430: Experimental auto-updater: Fix application crash on update failure (#14083) 2026-01-13 16:19:51 +00:00
Laurent Cozic
f1c968c19a Chore: Remove usage of watchman when running Jest tests (#14087) 2026-01-13 15:40:53 +00:00
Laurent Cozic
26c5a6181e Chore: Retry Apple Silicon test build when it fails (#14088) 2026-01-13 15:40:36 +00:00
Laurent Cozic
a3bf0cfdeb Server: Add support for MFA (#14081) 2026-01-13 14:14:46 +00:00
Joplin Bot
606b397326 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-01-13 01:53:11 +00:00
krevad
fbd157283d All: Translation: Update sv.po (#14082) 2026-01-12 19:38:43 -05:00
Laurent Cozic
2e879f65fc Chore: Fixed Markdown filename 2026-01-12 19:32:54 +00:00
Joplin Bot
c727156a46 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-01-12 18:43:05 +00:00
Laurent Cozic
4e31f1918d Doc: Added instructions on how to create a custom profile for deployments 2026-01-12 16:18:17 +00:00
Laurent Cozic
a1cdf67779 Chore: Also release pkg files for macOS 2026-01-12 16:08:56 +00:00
Laurent Cozic
5cb1db197f Doc: Add release notes 3.5 2026-01-12 15:12:18 +00:00
Joplin Bot
05c3065c72 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-01-10 12:49:51 +00:00
Laurent Cozic
25a5be09bf Merge branch 'release-3.5' into dev 2026-01-10 10:16:56 +00:00
Laurent Cozic
f0a3f73ddb iOS 13.5.3 2026-01-10 10:09:40 +00:00
Laurent Cozic
1bb5d9ade5 Android 3.5.8 2026-01-10 10:09:18 +00:00
Laurent Cozic
e75875c1b0 Desktop release v3.5.11 2026-01-10 10:01:41 +00:00
mrjo118
cce4b76e3f Mobile: Fixes #13544: Fixed keyboard input issue in note title (#14070) 2026-01-10 09:53:21 +00:00
Henry Heino
b310bfd0c2 iOS: Fixes #14063: Fix icon rendering (#14071) 2026-01-10 09:44:23 +00:00
Henry Heino
e19e1ac040 Desktop: OneNote importer: Simplify error report (#14074) 2026-01-10 09:44:09 +00:00
ERYpTION
3bba2f6b2a All: Translation: Update da_DK.po (#14073) 2026-01-09 17:22:08 -05:00
summoner
ca9addcda0 ALL: Translation: Update hu-HU.po (#14069) 2026-01-09 16:16:33 -05:00
Nick
c42a49c1cf All: Translation: Update sv.po (#14064) 2026-01-09 15:58:20 -05:00
Laurent Cozic
a1e056670d Chore: Ignore .watchman-cookie- files 2026-01-09 17:45:27 +00:00
Laurent Cozic
6d7a70c21a Chore: Update translations 2026-01-09 10:06:42 +00:00
Henry Heino
14fd3c66c1 Chore: Fix CI (#14061) 2026-01-09 09:26:17 +00:00
Joplin Bot
376f44a0ce Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-01-09 01:56:03 +00:00
Laurent Cozic
4d81ee4c7f Chore: Exclude katex and mermaid from Renovate 2026-01-08 19:44:50 +00:00
Laurent Cozic
d9011800b2 iOS 13.5.2 2026-01-08 19:43:11 +00:00
Laurent Cozic
e64f141b28 Android 3.5.7 2026-01-08 19:42:31 +00:00
Laurent Cozic
8bba68d920 Chore: Katex build files 2026-01-08 19:42:23 +00:00
Laurent Cozic
e342f2d572 Desktop release v3.5.10 2026-01-08 19:21:20 +00:00
Henry Heino
5951a66fef Desktop, Mobile: Resolves #13753: Markdown editor: Make header styles more closely match the note viewer (#14053) 2026-01-08 09:24:00 +00:00
Henry Heino
04f9bda128 Desktop: OneNote import: Fix all imported notes have the language marked as "English" (#14054) 2026-01-08 09:23:35 +00:00
Henry Heino
7a8a94f557 Mobile: Rich Text Editor: Add shortcuts for inserting code blocks (#14055) 2026-01-08 09:22:19 +00:00
Henry Heino
ad000fb521 Desktop,Mobile: Fixes #14049: Fix ABC Sheet Music setting includes "Translation error" in description (#14058) 2026-01-08 09:21:55 +00:00
Henry Heino
435b896142 Desktop, Mobile: Accessibility: In-editor rendering: Fix rendered checkboxes are very small on mobile (#14056) 2026-01-08 09:19:56 +00:00
renovate[bot]
b12f31c802 Update dependency katex to v0.16.23 (#14018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-07 16:43:31 +00:00
Laurent Cozic
ddb6d7a677 Desktop: Fixes #14040: Rich Text Editor: ABC sheet music options lost on edit 2026-01-07 12:14:54 +00:00
AlterWill
f0a1d05284 Chore: Fixes #13629: Fix focusHandler warning when navigating (#13973) 2026-01-07 11:56:45 +00:00
Alejandro Saucedo
27f7cb7ca6 Cli: Added keymap command to print existing keybinds in CLI and TUI (#13984)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2026-01-07 11:56:06 +00:00
Alejandro Saucedo
9e43ebcf43 Chore: Fixes #13983: Remove conflicting macos dependency for devbox (#13985) 2026-01-07 11:54:33 +00:00
Ahmed Idani
05cc0fa798 Desktop, Mobile: Fixes #13229: Insert time command not respecting locale settings (#13994) 2026-01-07 11:48:15 +00:00
Henry Heino
ee5b631d13 Desktop: Built-in plugins: Update Freehand Drawing to v4.2.0 (#14002) 2026-01-07 11:47:46 +00:00
Henry Heino
e4b6b34d37 Desktop: Built-in plugins: Update Backup to v1.5.1 (#14003) 2026-01-07 11:47:38 +00:00
Gerd Naschenweng
6f1280f0f5 Doc: Add Mailbox.org WebDAV to sync options (#14016) 2026-01-07 11:44:03 +00:00
bwat47
4c9015dab4 Desktop, Mobile: Fixes #13963: Images sometimes don't render until you click somewhere in the note (#14019) 2026-01-07 11:39:58 +00:00
Henry Heino
1adcafce9d Desktop, Mobile: Fixes #14030: Fix "Check synchronization configuration" button (#14031) 2026-01-07 11:37:35 +00:00
Henry Heino
cc9f55e115 Chore: Refactoring: Improve ObjectUtils types (#14032) 2026-01-07 11:36:43 +00:00
Henry Heino
e8b3b039df Desktop: Accessibility: Make sidebar "jump to next match" case insensitive (#14033) 2026-01-07 11:36:30 +00:00
Henry Heino
d9295a69d1 Chore: OneNote importer: Don't require IS_CONTINUOUS_INTEGRATION for a dev build (#14034) 2026-01-07 11:36:11 +00:00
Henry Heino
b92743b068 Desktop: Resolves #14004: OneNote import: Improve ID resolution (#14035) 2026-01-07 11:35:53 +00:00
Henry Heino
03f65a3fb1 Windows: Fixes #13549: Importing from OneNote: Fix badly encoded accents in notebook titles (#14037) 2026-01-07 11:35:42 +00:00
Henry Heino
32a22174f7 Desktop, Mobile: Resolves #13159: Markdown editor: Prevent layout shift when hiding/showing rendered checkboxes (#14044) 2026-01-07 11:34:51 +00:00
Henry Heino
d154ef4f5c Chore: Desktop: Fix "net::ERR_FILE_NOT_FOUND" logged to stdout when an invalid resource is requested from the note viewer (#14045) 2026-01-07 11:34:40 +00:00
Henry Heino
b8dd660c28 Desktop: OneNote import: Fix video embeds aren't imported: Import video embeds as links (#14046) 2026-01-07 11:34:31 +00:00
Henry Heino
2b20315bf5 Desktop: OneNote import: Simplify imported HTML (#14047) 2026-01-07 11:34:23 +00:00
nickprotop
93b9108832 All: Translation: Update el_GR.po (#14036) 2026-01-06 19:20:52 -05:00
renovate[bot]
0538bf0720 Update dependency @rollup/plugin-node-resolve to v16.0.2 (#14023)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-02 20:29:47 +00:00
renovate[bot]
54018c3a94 Update dependency @types/serviceworker to v0.0.157 (#14020)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-02 09:35:32 +00:00
renovate[bot]
0cb120c321 Update dependency @types/serviceworker to v0.0.156 (#14010)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-01 09:52:01 +00:00
Joplin Bot
0dab436420 Doc: Auto-update documentation
Auto-updated using release-website.sh
2026-01-01 02:03:48 +00:00
renovate[bot]
77331ca471 Update dependency @types/react to v18.3.25 (#13999)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 11:45:37 +00:00
krevad
d467205b91 All: Translation: Update sv.po (#13997) 2025-12-28 23:47:32 -05:00
renovate[bot]
7a2f686228 Update dependency @types/nodemailer to v6.4.20 (#13998)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-28 23:26:56 +00:00
Joplin Bot
fa37b87c98 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-12-28 02:03:41 +00:00
Laurent Cozic
0eed352684 Android 3.5.6 2025-12-27 20:38:40 +00:00
Laurent Cozic
6ab281d299 Revert "All: Apache Tomcat WebDAV compatibility for sync (#13614)"
Trying to fix #13992

This reverts commit 5be124b54a.
2025-12-27 20:26:36 +00:00
Laurent Cozic
5b94e0d470 Chore: CI: Disable mobile tests on macOS (#13987) 2025-12-27 01:28:15 +00:00
Joplin Bot
5372eeb64a Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-12-26 12:52:51 +00:00
Laurent Cozic
f6baf036dc Android 3.5.5 2025-12-26 10:53:47 +00:00
Henry Heino
610f00029f Mobile: Update js-draw to v1.33.0 (#13990) 2025-12-26 10:19:30 +00:00
renovate[bot]
10be1a0240 Update dependency @types/serviceworker to v0.0.154 (#13991)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 09:41:24 +00:00
Laurent Cozic
99a9be535c Update renovate.json5 2025-12-25 18:47:55 +00:00
renovate[bot]
614a95abb8 Update dependency react-native-webview to v13.16.0 (#13982)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-24 12:16:03 +00:00
Henry Heino
7cbaae3847 Mobile: Editor: Fix search/replace UI is partially offscreen on small-screen devices (#13978) 2025-12-24 10:11:23 +00:00
Henry Heino
9e2a6d22ea Chore: Mobile: Allow disabling features known to be incompatible with small screens at build time (#13980) 2025-12-24 10:10:56 +00:00
Henry Heino
f576e116a8 Mobile: Feature flags: Fix "voice typing" feature flag (#13981) 2025-12-24 10:10:12 +00:00
Joplin Bot
b0e912157b Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-12-24 01:52:27 +00:00
Laurent Cozic
c5598242f9 Android 3.5.4 2025-12-23 21:06:18 +00:00
Laurent Cozic
57980ae916 Lock files and prebuild assets 2025-12-23 19:44:54 +00:00
renovate[bot]
9d1720b6e1 Update dependency sass to v1.93.2 (#13972)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-23 19:41:31 +00:00
Henry Heino
c4e0ed18eb Android: Attempt to fix application hang when opening the camera (#13974) 2025-12-23 19:41:13 +00:00
Henry Heino
150f6c9a3f Android: Fix react-native-vector-icons error when opening a note (#13975) 2025-12-23 19:40:44 +00:00
Henry Heino
6f3781f27a Mobile: Toolbar editor: Fix toolbar editor dismiss button is rendered outside the dialog on small screens (#13976) 2025-12-23 19:40:38 +00:00
Henry Heino
37c3d24650 Chore: Android: Allow disabling the voice typing feature at build time (#13977) 2025-12-23 19:40:29 +00:00
renovate[bot]
bcb3f69d15 Update dependency expo to v53.0.23 (#13968)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-23 13:00:10 +00:00
renovate[bot]
70ffb29af4 Update dependency @playwright/test to v1.55.1 (#13970)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-23 12:59:49 +00:00
Henry Heino
5f61bee712 Mobile: Resolves #520: Viewer, Rich Text Editor: Save/restore the cursor and scroll position when switching notes (#13962) 2025-12-23 11:51:15 +00:00
Henry Heino
496d007f74 Mobile: Rich Text Editor: Fix indent/de-indent buttons do nothing when not in a list (#13961) 2025-12-23 11:50:26 +00:00
renovate[bot]
5a9b389504 Update dependency sass to v1.93.1 (#13969)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-22 04:56:42 +00:00
Henry Heino
107290177e Web: Note viewer: Fix assets from development plugins don't load (#13954) 2025-12-21 10:16:28 +00:00
renovate[bot]
5055c9af3e Update dependency @react-native-documents/picker to v10.1.7 (#13964)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-20 15:30:20 +00:00
renovate[bot]
2ed6650136 Update bitnamilegacy/postgresql Docker tag to v17.6.0 (#13966)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-20 15:30:07 +00:00
Laurent Cozic
e80db6afb5 Server v3.5.2 2025-12-19 21:28:55 +00:00
renovate[bot]
6a06922633 Update dependency @playwright/test to v1.55.0 (#13945)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-12-19 17:36:07 +00:00
renovate[bot]
fd02d88739 Update dependency node-gyp to v11.4.2 (#13953)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-18 22:56:07 +00:00
renovate[bot]
dacd460f64 Update dependency node-gyp to v11.4.0 (#13950)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-18 19:41:16 +00:00
Henry Heino
3279485f44 Mobile: Fixes #13081: Rich Text Editor: Fix checklists saved with extra space (#13951) 2025-12-18 19:41:03 +00:00
Henry Heino
eaf8d15be7 Mobile: Rich Text Editor: Set the default math/code block content to the selection (#13952) 2025-12-18 19:40:48 +00:00
Henry Heino
6b186b965a Chore: Fix CI (#13948) 2025-12-18 17:56:09 +00:00
cedecode
7a8ac14c99 All: Translation: Update de_DE.po (#13937) 2025-12-18 12:12:53 -05:00
renovate[bot]
73291fa355 Update dependency mermaid to v11.10.1 (#13930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-18 02:41:28 +00:00
Henry Heino
27ff8be432 Desktop: OneNote import: Fix certain embedded files are positioned under the header (#13898)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-12-18 01:12:35 +00:00
Linkosred
0904838311 Docs: Add video tutorial link for publish notes documentation (#13902) 2025-12-18 01:12:27 +00:00
Henry Heino
2798cc6027 Mobile: Fixes #13854: Fix some icons are invisible: Upgrade react-native-vector-icons to v12 (#13905) 2025-12-18 01:12:14 +00:00
Linkosred
1ede5bc499 Docs: Add video tutorial link for importing and exporting documentation (#13914) 2025-12-18 01:11:58 +00:00
Henry Heino
418a660a66 Chore: Allow specifying a custom API key at build time (#13917) 2025-12-18 01:11:29 +00:00
Linkosred
5bc073e888 Docs: Add section and video tutorial link about Rich text editor on mobile for Rich text documentation (#13921) 2025-12-18 01:10:50 +00:00
Henry Heino
87b443e051 Mobile: Accessibility: Dark mode: Improve contrast of conflicts notebook title, error messages in "Logs" (#13925) 2025-12-18 01:09:47 +00:00
Henry Heino
8e36644068 Desktop: OneNote importer: Add partial support for importing internal links (#13926) 2025-12-18 01:09:30 +00:00
Henry Heino
1833de789a Desktop: Fix search markers vanish when moving focus to a secondary window (#13927) 2025-12-18 01:09:09 +00:00
Henry Heino
0b18fd988b Desktop: Editor plugins: Fix error logged when pressing enter and a plugin-created input is focused (#13932) 2025-12-18 00:55:34 +00:00
Henry Heino
2ce65b9315 Clipper: Support importing math from Wikipedia and other websites (#13934) 2025-12-18 00:54:58 +00:00
renovate[bot]
8f4f0ee321 Update dependency sharp to v0.34.4 (#13923)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-17 10:25:11 +00:00
renovate[bot]
6a83cc95ee Update dependency mermaid to v11.10.0 (#13929)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-17 10:24:42 +00:00
renovate[bot]
5134b63075 Update dependency esbuild to v0.25.10 (#13924)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-16 21:43:32 +00:00
renovate[bot]
74527d7006 Update dependency dompurify to v3.2.7 (#13922)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-16 19:43:18 +00:00
renovate[bot]
ad909ac6f0 Update dependency @types/serviceworker to v0.0.153 (#13919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-16 08:55:40 +00:00
summoner
5ff0285b85 ALL: Translation: Update hu_HU.po (#13915) 2025-12-15 13:11:08 -05:00
renovate[bot]
bcb509a965 Update dependency @react-native-documents/picker to v10.1.6 (#13911)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 11:00:15 +00:00
renovate[bot]
075c98175e Update dependency fs-extra to v11.3.2 (#13910)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 00:48:20 +00:00
Joplin Bot
212112d4b6 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-12-14 18:38:22 +00:00
renovate[bot]
74bf0cb655 Update dependency @react-native-community/datetimepicker to v8.4.5 (#13900)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-14 17:46:57 +00:00
Laurent Cozic
b2bdf84f06 Add 'yargs' to renovate.json5 dependencies 2025-12-14 15:36:37 +00:00
Laurent Cozic
a2156a0548 Add yargs-parser to renovate.json5 dependencies 2025-12-14 14:41:48 +00:00
Laurent Cozic
620afdaab1 Android 3.5.3 2025-12-14 13:48:19 +00:00
Laurent Cozic
3f8928000e Chore: Clean up Android release script 2025-12-14 13:37:22 +00:00
Laurent Cozic
5caec161f2 Mobile: Add a link to the list of open-source licenses 2025-12-13 00:03:26 +00:00
Laurent Cozic
daab2223e7 Chore: Fix CI 2025-12-12 16:46:53 +00:00
Laurent Cozic
f96071870c All: Fixes #12172: Markdown import incorrectly parses a link as a file path 2025-12-12 14:53:35 +00:00
Laurent Cozic
5e08abb7a9 Desktop: Fixes #12367: When using RTE, switching to a note from go to anything search results with keyboard immediately updates note last modified date 2025-12-12 14:31:50 +00:00
Laurent Cozic
2c71557d88 All: Fixes #12770: Import Error: Note date incorrect when import notes with import MD - Markdown + Front Matter 2025-12-12 12:35:38 +00:00
Laurent Cozic
d551963669 All: Fixes #13008: Importing MD + frontmatter fails on empty variable 2025-12-12 11:53:03 +00:00
Laurent Cozic
7dae90c9f3 Linux: Fixes #13038: Do not suggest downgrading the app when a version has been unpublished 2025-12-12 11:29:40 +00:00
Laurent Cozic
46820fb21b Server: Fixes #13059: Confusing error message if a published note has not been synced to the server 2025-12-12 10:56:22 +00:00
Laurent Cozic
a18e49ab54 Chore: Fixes #13358: Fix randomly failing test on app/command-rmnote.test 2025-12-12 10:27:25 +00:00
Laurent Cozic
2c6eaca442 Desktop: Fixes #13814: Remove architecture warning on Windows ARM with Apple silicon 2025-12-12 10:05:37 +00:00
Laurent Cozic
44de1246d9 Desktop: Fixes #13880: Warning logged on startup when ABC Sheet Music plugin is not installed 2025-12-12 09:49:57 +00:00
renovate[bot]
ab3a0ab69f Update dependency pg-boss to v10.3.3 (#13894)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-12 04:13:14 +00:00
Laurent Cozic
896f0e0bc5 Doc: Clarify difference between JS and JSB 2025-12-11 18:29:56 +00:00
Henry Heino
e2c933db82 Chore: Resolves #13866: Create a tool that lists dependencies of a package and its licenses (#13874) 2025-12-11 15:16:41 +00:00
Henry Heino
30c5031611 Mobile: Rich Text Editor: Fix table delete row/delete column buttons can't remove the last row/column from a table (#13877) 2025-12-11 15:16:13 +00:00
Henry Heino
e7f14a0995 Desktop: Fixes #13872: Fix importing HTML links with multi-line titles as Markdown (#13876) 2025-12-11 15:15:28 +00:00
Henry Heino
319bf79bc1 Mobile: Upgrade js-draw to v1.32.0 (#13875) 2025-12-11 08:17:37 +00:00
renovate[bot]
02f94adb96 Update dependency nodejs to v24.5.0 (#13890)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-10 16:25:17 +00:00
Laurent Cozic
2370c12129 Revert "Update dependency @react-native/babel-preset to v0.81.0" (#13888) 2025-12-10 12:56:15 +00:00
Laurent Cozic
8d074a563b Update renovate.json5 2025-12-10 12:55:48 +00:00
renovate[bot]
1014edfdeb Update dependency @react-native/babel-preset to v0.81.0 (#13886)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-10 12:54:43 +00:00
Laurent Cozic
364bdd9bb0 Chore: Allow specifying a custom API key at build time 2025-12-09 15:33:07 +00:00
Laurent Cozic
8d6b219191 lock file 2025-12-09 15:07:45 +00:00
Laurent Cozic
2455245f86 Chore: Allow creating a custom build of the Android app 2025-12-09 15:07:28 +00:00
Laurent Cozic
c669a3986e Tools: Allow generating Android images using generate-imgae script 2025-12-09 10:53:57 +00:00
Laurent Cozic
5f1a1e50d9 Doc: Add forum background images 2025-12-09 00:06:48 +00:00
Self Not Found
819a591cc0 Desktop: Add CJK characters counter in statistics panel (#13840) 2025-12-08 18:52:09 +00:00
mrjo118
421b82c86d Mobile: Add the ability to rename and delete tags (#13731) 2025-12-08 10:15:34 +00:00
Henry Heino
16169b2780 Server: Periodically delete old backups for archived accounts (#13741) 2025-12-08 10:15:18 +00:00
Charlie Arehart
49ed4ae920 Docs: add links to clarify "plugins" references (#13763)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-12-08 10:11:26 +00:00
mrjo118
13777d261c Desktop: Replace the edit profile config menu option with a gui to manage profiles (#13771) 2025-12-08 10:08:58 +00:00
Henry Heino
1c7b0e6266 Mac: Fixes #13214: Markdown editor: Don't open links on ctrl-click (#13792) 2025-12-08 10:07:41 +00:00
Henry Heino
4589670126 Chore: Server: Debug: Add debug benchmarkDeltaPerformance API (#13801) 2025-12-08 10:07:25 +00:00
marph91
b6ab6e0b46 Desktop: Use the "--no-sandbox" flag for Tuxedo OS (#13810) 2025-12-08 10:06:42 +00:00
mrjo118
9b28b618bb Desktop, Mobile: Do no re-use the 'Restored Notes' folder if it is trashed (#13813) 2025-12-08 10:06:25 +00:00
Bartolomeo
bf7cc6be03 Desktop: Resolves: #13804: Change search Resources feature to case insensitive (#13824) 2025-12-08 10:04:31 +00:00
mrjo118
e5e5b342a7 Mobile: Fixes #13825: Fix incompatible plugins cannot be uninstalled (#13828) 2025-12-08 10:03:23 +00:00
Henry Heino
9709721a73 Desktop: OneNote importer: Fix missing content in imported notebooks, improve math formula import (#13829) 2025-12-08 09:59:58 +00:00
Henry Heino
a34010ef62 Chore: Tests: Make renderBlockImages.test.ts less likely to fail in CI (#13835) 2025-12-08 09:59:50 +00:00
Henry Heino
9a6043e6a6 Chore: Desktop: Migrate the "Share note" dialog to RSCSS (#13842) 2025-12-08 09:53:15 +00:00
Henry Heino
992bf683c4 Chore: Server: Create more realistic test data (#13843) 2025-12-08 09:53:05 +00:00
Henry Heino
b40c2b8a41 Desktop: Fixes #13844: OneNote importer: Fix wrong page version imported (#13850) 2025-12-08 09:52:51 +00:00
Henry Heino
8dcd08e21d Server: Ensure that shared items are processed in the correct order (#13858) 2025-12-08 09:52:39 +00:00
mrjo118
cb2b32520d Mobile: Prevent opening the edit / delete dialog when long pressing the conflicts notebook (#13860) 2025-12-08 09:51:12 +00:00
Henry Heino
315b1d8275 Desktop: Markdown Editor: Collapse selection to a single cursor when pressing "escape" (#13864) 2025-12-08 09:49:50 +00:00
renovate[bot]
8018f1269a Update dependency react-native-share to v12.2.0 (#13861)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-07 10:17:21 +00:00
renovate[bot]
c2d186188b Update dependency react-native-safe-area-context to v5.6.1 (#13868)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-06 11:05:56 +00:00
renovate[bot]
d5798e558b Update dependency react-native-safe-area-context to v5.6.0 (#13865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-06 09:37:17 +00:00
renovate[bot]
224bcd54f1 Update dependency fs-extra to v11.3.1 (#13849)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 23:45:31 +00:00
Laurent Cozic
1a3d572498 Server v3.5.1 2025-12-03 11:56:50 +00:00
Laurent Cozic
848a2c986a Chore: Remove the need for yarn when bumping version number
Since "yarn version patch" also performs "yarn install" which is usually unnecessary
2025-12-03 11:56:04 +00:00
renovate[bot]
fc61a2bc6a Update dependency raw-body to v3.0.1 (#13846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 06:55:14 +00:00
Henry Heino
f9d58742c0 Desktop: Support converting multiple notes from HTML to Markdown at once (#13802) 2025-12-01 18:52:01 +00:00
renovate[bot]
5ba8cefe7c Update dependency nodejs to v24.4.1 (#13833)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 18:51:35 +00:00
renovate[bot]
74484f194e Update Node.js to v24 (#13834)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 18:51:30 +00:00
renovate[bot]
eae569aff8 Update dependency lint-staged to v16.1.6 (#13831)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 13:58:57 +00:00
renovate[bot]
8734bc8467 Update dependency nodejs to v24 (#13832)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 13:58:50 +00:00
renovate[bot]
612d09d16f Update dependency lint-staged to v16.1.2 (#13822)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 12:07:32 +00:00
Joplin Bot
eb2e9419b9 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-12-01 02:04:54 +00:00
renovate[bot]
17935458e6 Update dependency react-native-web to v0.21.1 (#13823)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 01:24:20 +00:00
renovate[bot]
a69a5d98ee Update dependency react-native-web to v0.21.0 (#13819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 19:10:02 +00:00
renovate[bot]
48c9c1112c Update dependency lint-staged to v16 (#13820)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 19:09:41 +00:00
Kachelkaiser
a6585a67d0 All: Translation: Update de_DE.po (#13815) 2025-11-30 13:16:12 -05:00
renovate[bot]
959e1522d4 Update dependency babel-plugin-react-native-web to v0.21.1 (#13818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 18:12:52 +00:00
renovate[bot]
8605e5aad5 Update dependency ts-loader to v9.5.4 (#13808)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 16:02:04 +00:00
renovate[bot]
88af5208f5 Update dependency babel-plugin-react-native-web to v0.21.0 (#13811)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 16:01:48 +00:00
renovate[bot]
bef73dbbf5 Update dependency rate-limiter-flexible to v7.2.0 (#13817)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 16:01:41 +00:00
renovate[bot]
b23c50cc7d Update dependency node-gyp to v11.3.0 (#13812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 12:41:42 +00:00
Joplin Bot
3e90a9392d Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-11-29 18:37:14 +00:00
renovate[bot]
e2a32c5993 Update dependency git to v2.50.1 (#13807)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 16:59:17 +00:00
renovate[bot]
759761086d Update dependency dayjs to v1.11.18 (#13806)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 16:57:30 +00:00
Laurent Cozic
ca29ed94cc Chore: Updated CLA signatures and consent record 2025-11-29 14:07:08 +00:00
Laurent Cozic
f815933ad0 Chore: Improved saveClaConsentRecords script to display any mistake in data 2025-11-29 14:06:46 +00:00
Laurent Cozic
67af879d38 Chore: Updated signatures.json 2025-11-29 13:51:23 +00:00
Laurent Cozic
2e310e0f79 iOS 13.5.1 2025-11-29 12:56:34 +00:00
Laurent Cozic
e63041766f Android 3.5.1 2025-11-29 12:45:14 +00:00
renovate[bot]
93997277b6 Update dependency @types/serviceworker to v0.0.152 (#13805)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 12:29:27 +00:00
Laurent Cozic
4afac412ce Desktop release v3.5.9 2025-11-29 12:27:27 +00:00
Laurent Cozic
b79bf11680 Chore: Fixed version patching 2025-11-29 12:25:58 +00:00
Laurent Cozic
10d727f183 Desktop release 3.5.8 2025-11-29 12:14:40 +00:00
Laurent Cozic
50e2dc7749 Chore: Replaced npm version patch by yarn version patch
`npm version patch` now seems to run `npm install` too and messes up the repository
2025-11-29 12:14:05 +00:00
Laurent Cozic
5108fe5b24 Chore: lock files 2025-11-29 11:41:19 +00:00
Laurent Cozic
3536a68cfe Chore: lock files 2025-11-29 10:58:53 +00:00
Henry Heino
d94d057f1d Desktop: Plugins: Add an "importFrom" command to allow importing notes and notebooks (#13534) 2025-11-29 10:53:58 +00:00
mrjo118
8ec11bddc2 Mobile: Extend notebook selection dropdowns when the dropdown is opened (#13726) 2025-11-29 10:51:56 +00:00
mrjo118
4813c79b35 Mobile: Add the ability to search on the tag list screen (#13733) 2025-11-29 10:49:39 +00:00
renovate[bot]
7778a68764 Update dependency git to v2.50.0 (#13759)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 10:42:37 +00:00
renovate[bot]
503e748ca8 Update dependency react-native-vector-icons to v10.3.0 (#13760)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 10:42:26 +00:00
Henry Heino
b6297b609e Chore: Refactor: Make custom MultiTouchableOpacity component closer to a drop-in-replacement for TouchableOpacity (#13762) 2025-11-29 10:28:05 +00:00
Henry Heino
31d37b30b0 Docs: Fix lower half of Markdown documentation is marked as a code block (#13766) 2025-11-29 10:26:56 +00:00
Henry Heino
0ccd7e474d Desktop: Upgrade to Electron 39.2.3 (#13767) 2025-11-29 10:26:47 +00:00
renovate[bot]
046cfece32 Update dependency ldapts to v8.0.9 (#13768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 10:26:39 +00:00
bwat47
0280bb80b9 Desktop,Mobile: Hide backslash escapes when "Markdown editor: Render markup in editor" is enabled (#13773) 2025-11-29 10:05:13 +00:00
Henry Heino
8a61f4ec54 Mobile: Rich Text Editor: Support inserting code blocks (#13776) 2025-11-29 10:04:28 +00:00
Henry Heino
d7dd16aac1 Desktop: OneNote importer: Change source label from ZIP to ONE (#13778) 2025-11-29 10:04:13 +00:00
Henry Heino
e1ed573c33 Chore: Mobile plugin IPC: Fix possible error format issue (#13780) 2025-11-29 10:03:36 +00:00
Henry Heino
b6c8347549 Chore: Renderer: Convert resourceId to a string in a safer way (#13781) 2025-11-29 10:03:28 +00:00
Henry Heino
b150d6453d Mobile: Rich Text Editor: Improve support for ABC sheet music and Mermaid code blocks (#13784) 2025-11-29 10:03:22 +00:00
Henry Heino
9feba9345d Mobile: Rich Text Editor: Fix error when pressing enter (#13788) 2025-11-29 10:03:15 +00:00
Henry Heino
7fa3a3b545 Desktop: OneNote importer: Handle the case where an entity GUID is missing (#13789) 2025-11-29 10:02:57 +00:00
Henry Heino
fed2438bc3 Docs: OneNote import: Update import documentation (#13790)
Co-authored-by: Linkosed <linkosed@users.noreply.github.com>
2025-11-29 09:58:22 +00:00
Henry Heino
31cb404854 Desktop: Fixes #13745: Prevent cut events from being merged with other actions in the undo history (#13791) 2025-11-29 09:57:46 +00:00
Henry Heino
dba3a3f68f Desktop: Add loading indicator to the sync status screen (#13796) 2025-11-29 09:55:00 +00:00
Henry Heino
14f8f51cd1 Desktop: Accessibility: Disable the loading animation when 'reduce motion' is enabled (#13797) 2025-11-29 09:54:47 +00:00
Henry Heino
2240cf77b5 Chore: Server: Debug: Add debug populateDatabase API (#13800) 2025-11-29 09:54:05 +00:00
Milo Ivir
599f7a24ce All: Translation: Update hr_HR.po (#13769) 2025-11-26 17:33:21 -05:00
Henry Heino
f177563c4a Chore: Mobile: Fix test warnings (#13798) 2025-11-26 22:11:50 +00:00
Laurent Cozic
a0bdc1fa9b Doc: Update donate links 2025-11-22 16:11:16 +00:00
Joplin Bot
f566e5c336 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-11-22 12:45:34 +00:00
renovate[bot]
87d07eff4a Update dependency ldapts to v8 (#13765)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-22 12:41:50 +00:00
github-actions[bot]
3caf41984f @carehart has signed the CLA in laurent22/joplin#13763 2025-11-22 05:01:45 +00:00
Laurent Cozic
7a31f1f156 Desktop release v3.5.7 2025-11-21 19:32:11 +00:00
Henry Heino
090c1d9706 Desktop: Accessibility: Fix last items in note actions menu cannot be accessed on small screens (#13756) 2025-11-21 19:28:33 +00:00
Henry Heino
5e2b79557c Server: Fix report service fails when there are a very large number of items to be processed (#13721) 2025-11-21 19:28:10 +00:00
Henry Heino
74fa2a6eb9 Server: Slightly improve delta performance (#13730) 2025-11-21 19:27:28 +00:00
Henry Heino
791668455e Desktop: Resolves #13464: OneNote importer: Don't stop the import process when a page fails to render (#13736) 2025-11-21 19:26:14 +00:00
renovate[bot]
91aedc5efa Update bitnamilegacy/postgresql Docker tag to v17.5.0 (#13737)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-21 19:26:07 +00:00
Henry Heino
6b2d9ba5ec Server: Save and query less data when creating and updating items (#13739) 2025-11-21 19:25:47 +00:00
bwat47
d8920840f2 Desktop: Fixes #13707: Fix text contrast issues with Aritim, Dracula, and Nord themes (#13740) 2025-11-21 19:24:18 +00:00
bwat47
bf571c5961 Desktop,Mobile: Add support for rendering html images when "Markdown editor: Render images" is enabled (#13743) 2025-11-21 19:19:19 +00:00
Henry Heino
a7b22edbc4 Chore: Remove unused type definition dependency (#13747) 2025-11-21 19:18:37 +00:00
Henry Heino
f4904d8155 Chore: Remove no-longer-necessary Promise polyfill (#13748) 2025-11-21 19:18:28 +00:00
Henry Heino
fab633bbb4 Cli: Fix startup failure (#13749) 2025-11-21 19:17:20 +00:00
Henry Heino
cda4073bfc Chore: Cli: Run integration tests in CI (#13750) 2025-11-21 19:17:13 +00:00
Henry Heino
903edb8fa2 Chore: Desktop: Remove unused dependency (#13752) 2025-11-21 19:16:49 +00:00
Laurent Cozic
f3409600e1 All: Allow using share permission with Joplin Server Business 2025-11-21 19:14:00 +00:00
Laurent Cozic
9f36b44842 All: Fix issue with shared notebooks and SAML sync 2025-11-21 18:21:28 +00:00
Laurent Cozic
6f41234db3 Doc: Improve SAML doc 2025-11-21 18:20:27 +00:00
Laurent Cozic
2feebf504e Doc: Update donate page 2025-11-21 16:09:39 +00:00
Laurent Cozic
3312e96b0d Doc: Update donate page 2025-11-21 15:24:11 +00:00
renovate[bot]
af5108d702 Update dependency @fortawesome/react-fontawesome to v0.2.6 (#13744)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 08:24:51 +00:00
Henry Heino
0f4877f263 Chore: Sync fuzzer: Allow generating large amounts of test data for Joplin Server (#13636)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-11-18 22:53:44 +00:00
Henry Heino
46c22fffb9 Desktop,Mobile: Resolves #12959: Remove image height limit in Markdown editor (#13717) 2025-11-18 22:53:14 +00:00
renovate[bot]
ae5bc1b849 Update dependency @types/nodemailer to v6.4.19 (#13728)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 21:47:40 +00:00
Henry Heino
907da6caa9 Desktop: OneNote importer: Don't stop the import process if a style object can't be found (#13719) 2025-11-18 21:40:49 +00:00
renovate[bot]
57a4a687d1 Update dependency @fortawesome/react-fontawesome to v0.2.5 (#13723)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 16:10:04 +00:00
github-actions[bot]
865d39d657 @Wohlstand has signed the CLA in laurent22/joplin#13727 2025-11-18 15:23:06 +00:00
Henry Heino
00aecd63d4 Desktop: Resolves #1556: Support selecting multiple notebooks (#13612) 2025-11-17 22:14:28 +00:00
Henry Heino
bd569b9d8d Mobile: Rich Text Editor: Add button for creating tables (#13645) 2025-11-17 22:06:42 +00:00
Henry Heino
ad4a8aa76d Server: Improve error message when font file cannot be loaded (#13682) 2025-11-17 22:01:34 +00:00
Self Not Found
c67dcebbbe All: Fix text highlighting in basic search mode (#13703) 2025-11-17 22:01:22 +00:00
renovate[bot]
0e135adbe2 Update dependency mermaid to v11.9.0 (#13708)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-11-17 21:27:33 +00:00
Laurent Cozic
43e83e7cee Chore: Improve error message when an asset cannot be removed 2025-11-16 22:53:02 +00:00
renovate[bot]
d1dcc6ced5 Update dependency @types/serviceworker to v0.0.150 (#13710)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-16 19:27:52 +00:00
Laurent Cozic
8425f195f8 Doc: Suggest log level in CLI install command 2025-11-16 15:54:21 +00:00
renovate[bot]
055177f726 Update dependency turndown to v7.2.1 (#13690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-11-16 09:41:21 +00:00
Liffindra Angga Zaaldian
1674df2c0f All: Translation: Update id_ID.po (#13706) 2025-11-15 10:29:06 -05:00
renovate[bot]
29fa117d36 Update dependency react-native-localize to v3.5.2 (#13705)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 14:40:27 +00:00
renovate[bot]
f08eaae7ed Update dependency @types/nodemailer to v6.4.18 (#13704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 14:38:03 +00:00
Joplin Bot
9573bb6af7 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-11-15 12:46:15 +00:00
Henry Heino
cb6bafcac6 Chore: Update js-yaml to v4.1.1 (#13702)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-11-15 11:17:18 +00:00
Henry Heino
d89aae5371 Server: Upgrade NodeJS to v24 (#13701)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-11-15 11:17:06 +00:00
Henry Heino
0b0ffe06d4 Desktop: Fixes #13561: Upgrade to Electron 39 (#13567) 2025-11-15 09:21:18 +00:00
mrjo118
2ab720ff87 Desktop, Mobile: Fixes #13258: Prevent new notes from being created in trashed or missing notebooks in certain cases (#13575) 2025-11-15 09:21:00 +00:00
Henry Heino
b9b07790d7 Chore: Desktop: Editor: Don't update the global Redux state on cursor motion (#13580) 2025-11-15 09:16:36 +00:00
Laurent Cozic
3dca34952b Desktop: Move ABC rendering from plugin to main app (#13599) 2025-11-15 09:11:29 +00:00
horvatkm
5be124b54a All: Apache Tomcat WebDAV compatibility for sync (#13614) 2025-11-15 09:07:39 +00:00
mrjo118
51dd0d3fdc Chore: Fix intermittent revision test failure attempt 2 (#13622) 2025-11-15 09:06:46 +00:00
horvatkm
7955f15298 Desktop: Resolves #13625: Skip over unsupported image formats during processing paste event (#13630) 2025-11-15 09:03:27 +00:00
renovate[bot]
fdf6091006 Update dependency react-native-localize to v3.5.1 (#13651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-11-15 09:02:45 +00:00
mrjo118
bb1c5792cc Mobile: Fixes #13637: Fix incorrect zebra striping on tables in the rich text editor (#13663) 2025-11-15 09:02:36 +00:00
Henry Heino
75544c943c Mobile: Hide Markdown-editor-only buttons in the Rich Text Editor (#13664) 2025-11-15 09:02:15 +00:00
Henry Heino
db9967d4fd Server: Performance: Improve performance of requests-per-minute logger (#13670) 2025-11-15 09:02:02 +00:00
Saturn&Eric
07a66ca62c Server: Update @aws-sdk/client-s3 to v3.928.0 (#13673) 2025-11-15 09:01:49 +00:00
renovate[bot]
3e3dc4392c Update dependency esbuild to v0.25.9 (#13677)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 09:01:14 +00:00
Henry Heino
57504a1795 Server: Database: Adjust connection pool configuration, make connection pool size configurable (#13681) 2025-11-15 09:00:24 +00:00
Henry Heino
9e9d2699b5 Server: Improve error when attempting to load certain routes that do not exist (#13683) 2025-11-15 08:58:36 +00:00
Henry Heino
4a0d9220ba Server: Fixes #13686: Fix items can be incorrectly unshared on conflicting update (#13691) 2025-11-15 08:58:16 +00:00
Henry Heino
86a7771d5b Desktop: Fixes #13694: Fix settings aren't saved before opening the SAML login screen (#13696) 2025-11-15 08:58:06 +00:00
Henry Heino
d792a6b3a9 Desktop: Fixes #13549: OneNote importer: Support converting checklists to Markdown (#13698) 2025-11-15 08:56:44 +00:00
mrjo118
e8a083b7bd Web: Fix find and replace toolbar in note editor is too squashed on small mobile screens (#13697) 2025-11-15 08:56:32 +00:00
Henry Heino
41ed6ab364 Chore: CI: Upgrade NodeJS to v24 (#13700) 2025-11-15 08:55:45 +00:00
Henry Heino
b587e9ad37 Chore: Fix CI (#13699) 2025-11-15 08:54:36 +00:00
Laurent Cozic
e3f9fafcdf Revert "Chore: Resolves #13643: Update Esperanto translation (Credit: @paleid)"
This reverts commit aef9429f21.
2025-11-14 01:08:29 +00:00
Joplin Bot
c0ba743d70 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-11-13 12:53:26 +00:00
Joplin Bot
523660006d Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-11-13 06:41:07 +00:00
Laurent Cozic
aef9429f21 Chore: Resolves #13643: Update Esperanto translation (Credit: @paleid) 2025-11-12 22:29:37 +00:00
renovate[bot]
58e2bba1ed Update dependency esbuild to v0.25.9 (#13676)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 04:49:37 +00:00
renovate[bot]
cee44bcdc3 Update dependency @adobe/css-tools to v4.4.4 (#13667)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-11 22:51:42 +00:00
renovate[bot]
9a120bc0d5 Update dependency react-native-dropdownalert to v5.2.0 (#13657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-11 22:51:20 +00:00
Henry Heino
d1415a318c Server: Performance: Improve performance of updating shared items, generating reports (#13674) 2025-11-11 22:49:24 +00:00
github-actions[bot]
d701b9b1bd @Kallemakela has signed the CLA in laurent22/joplin#13675 2025-11-11 22:09:54 +00:00
github-actions[bot]
f8fe143809 @saturneric has signed the CLA in laurent22/joplin#13673 2025-11-11 21:06:32 +00:00
Jason Lewis
e626db3b8c Doc: Resolves #13665: Remind users not to use the Nextcloud desktop client for syncing. (#13666)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-11-11 09:44:53 +00:00
github-actions[bot]
9e0491ef2f @jasonblewis has signed the CLA in laurent22/joplin#13666 2025-11-11 01:09:38 +00:00
Frank Fesevur
053bd91984 All: Translation: Update nl_NL.po (#13653) 2025-11-08 20:22:03 -05:00
Laurent Cozic
c76059cf7f Server: Optimise delta query (#13650) 2025-11-08 22:57:29 +01:00
ERYpTION
6d6bc78d53 All: Translation: Update da_DK.po (#13652) 2025-11-08 16:56:23 -05:00
renovate[bot]
8855495822 Update dependency react-native-localize to v3.5.0 (#13647)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-08 13:12:17 +01:00
renovate[bot]
3491fea313 Update dependency @playwright/test to v1.54.2 (#13649)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-08 13:12:06 +01:00
renovate[bot]
66f5e2fbc3 Update dependency @playwright/test to v1.54.0 (#13641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-08 11:47:07 +01:00
renovate[bot]
3640bf8ae7 Update dependency nan to v2.23.0 (#13642)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-08 11:46:57 +01:00
Laurent Cozic
977edf6e5d Server: Fix slow delta queries (#13639) 2025-11-08 11:02:55 +01:00
renovate[bot]
e8f067a0b2 Update dependency @crowdin/cli to v4.9.0 (#13638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-07 14:41:44 +01:00
Henry Heino
f971e2aa4c Server: Upgrade koa to v2.16.3 (#13626) 2025-11-07 10:42:15 +01:00
renovate[bot]
b15b92d161 Update dependency git to v2.49.0 (#13635)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-07 10:41:47 +01:00
renovate[bot]
1c5f66b5a9 Update dependency @react-native-community/datetimepicker to v8.4.4 (#13634)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 23:48:24 +00:00
github-actions[bot]
1f77357c7d @Bappoz has signed the CLA in laurent22/joplin#13588 2025-11-06 20:55:57 +00:00
Laurent Cozic
aaeb5db3c7 Server: Optimise delta sub-query (#13633) 2025-11-06 20:27:47 +01:00
Laurent Cozic
996a0894ae Chore: Fixed Postgres tool path for new Homebrew version 2025-11-06 17:50:59 +01:00
Laurent Cozic
66fa3fc808 Server: Remove query optimisation that now seems to be slower with newer versions of Postgres 2025-11-06 17:12:45 +01:00
renovate[bot]
dab55daf95 Update dependency prosemirror-model to v1.25.3 (#13623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 02:16:07 +00:00
summoner
7f1c31e03f All: Translation: Update hu_HU.po (#13620) 2025-11-04 15:42:36 -05:00
cedecode
0a8255f091 All: Translation: Update de_DE.po (#13618) 2025-11-04 15:41:04 -05:00
Helmut K. C. Tessarek
9f3e6650a9 Update translations 2025-11-03 17:23:28 -05:00
mrjo118
4a17da3df5 All: Fixes #13531: When creating a conflict, ensure the latest note contents are used to create the conflict (#13552) 2025-11-03 20:21:05 +01:00
Henry Heino
2c4f0d4d8c Desktop: Fixes #13574: Fix crash when opening the legacy Markdown editor (#13576) 2025-11-03 20:12:39 +01:00
Henry Heino
9c1c2fb0d4 Chore: Desktop: Enable source maps for error reporting by default (#13577) 2025-11-03 20:12:24 +01:00
Henry Heino
2332e4bf62 Desktop: Fixes #13579: Rich Text Editor: Make cursor jump during editing less likely (#13581) 2025-11-03 20:11:45 +01:00
Henry Heino
a488ac1b27 Desktop: Fixes #13177: Location: Remove geoplugin.net from location providers (#13583) 2025-11-03 20:11:37 +01:00
Henry Heino
6daa41ca66 All: Fixes #13291: Improve performance of item deserialization (#13585) 2025-11-03 20:11:21 +01:00
Henry Heino
cc9517f1a2 Desktop: Resolves #13586: Preserve scroll when switching between Markdown and Rich Text Editors (#13587) 2025-11-03 20:11:12 +01:00
github-actions[bot]
c53d18e068 @horvatkm has signed the CLA in laurent22/joplin#13613 2025-11-03 17:08:09 +00:00
Henry Heino
200a471e55 Chore: OneNote importer: Remove unused dependency (#13590) 2025-11-03 12:21:03 +01:00
renovate[bot]
c21d37bd91 Update dependency @types/serviceworker to v0.0.149 (#13604)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 12:20:50 +01:00
renovate[bot]
e36cd0e60b Update dependency mermaid to v11.8.1 (#13607)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-02 21:16:04 +00:00
VortexP
871f55bf11 All: Translation: Update fi_FI.po (#13605) 2025-11-02 16:13:27 -05:00
renovate[bot]
22c9fed663 Update dependency mermaid to v11.8.0 (#13589)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-02 20:14:11 +01:00
renovate[bot]
ea362d7a82 Update dependency @electron/remote to v2.1.3 (#13594)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-02 20:13:54 +01:00
renovate[bot]
9ae9347f89 Update eslint (#13597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-01 20:28:29 +00:00
Joplin Bot
ae8bb902f9 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-11-01 01:50:23 +00:00
renovate[bot]
90eeec23de Update eslint (#13595)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-01 01:49:05 +00:00
github-actions[bot]
fe8ad1fa74 @mariadenis has signed the CLA in laurent22/joplin#13593 2025-10-31 22:47:47 +00:00
github-actions[bot]
dfc0a96567 @HarmonicSoldier has signed the CLA in laurent22/joplin#13592 2025-10-31 21:57:08 +00:00
Henry Heino
474fd094c4 Chore: Update licenses.md (#13582) 2025-10-31 10:28:04 +01:00
renovate[bot]
937d8fa4f7 Update dependency react-native-share to v12.1.2 (#13570)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 12:10:11 +01:00
renovate[bot]
45c9844616 Update dependency @types/serviceworker to v0.0.148 (#13568)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 10:49:02 +01:00
Joplin Bot
12b8ef5a54 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-10-29 18:41:30 +00:00
mrjo118
18f72c224e Mobile: Fixes #13151: Reset the state of undo and redo buttons when switching editor (#13505) 2025-10-29 18:22:56 +01:00
mrjo118
7ca3aaa83f Web: Fixes #13241: Find and replace toolbar in the note editor is not sized correctly (#13559) 2025-10-29 18:21:30 +01:00
mrjo118
04b1443e5a Mobile: Make title field work with very long text (#13566) 2025-10-29 18:20:56 +01:00
mrjo118
c461741778 All: Fixes #13319: Treat unclosed quotes as fully quoted search terms, to prevent malformed match expression error (#13564) 2025-10-29 18:19:38 +01:00
renovate[bot]
2865b0a803 Update dependency follow-redirects to v1.15.11 (#13565)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 17:58:37 +01:00
Laurent Cozic
21e49be22f Doc: Fixed order of tags in spellcheck document 2025-10-29 17:56:40 +01:00
Laurent Cozic
fef761cbab Doc: Added documentation to setup Joplin Server with Keycloak to test SAML auth 2025-10-29 17:55:07 +01:00
renovate[bot]
c15a353dc2 Update dependency react-native-safe-area-context to v5.5.2 (#13496)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-29 14:00:36 +01:00
Laurent Cozic
ffb32766c1 Desktop release v3.5.6 2025-10-29 13:45:27 +01:00
Henry Heino
038908550e Chore: Desktop: Share folder dialog: Remove duplicate "refreshShares" call (#13535) 2025-10-29 13:43:56 +01:00
Henry Heino
42f59134ae Desktop: Fixes #13549: OneNote importer: Task lists: Fix checkbox sizes and accessibility (#13558) 2025-10-29 13:43:48 +01:00
Laurent Cozic
fc0014c0b5 All: Open the connection screen when a SAML session has expired 2025-10-29 13:42:11 +01:00
Laurent Cozic
42d8df3036 Desktop, Cli, Mobile: Ensure that sync process ends up properly when Joplin Server shares cannot be accessed 2025-10-29 13:42:11 +01:00
Frank Fesevur
1fad9ca1cc All: Translation: Update nl_NL.po (#13556) 2025-10-28 17:37:04 -04:00
Laurent Cozic
ae289be77a Server: Add support for DELETE_EXPIRED_SESSIONS_SCHEDULE to prevent auto-logout when using SAML login 2025-10-28 17:37:38 +01:00
Laurent Cozic
7f6bfe9c6e Doc: Clarifies that SAML does not support the API_BASE_URL 2025-10-28 17:21:57 +01:00
Laurent Cozic
ead4001b7a Revert "Server: Fix SAML routes to prevent cookie issues on redirect (#13557)"
This reverts commit a4556bf598.
2025-10-28 17:05:27 +01:00
Laurent Cozic
7b95ef72a0 Server: Fixes #13368: Cannot login with SAML when already logged in on the browser 2025-10-28 16:59:42 +01:00
Laurent Cozic
a4556bf598 Server: Fix SAML routes to prevent cookie issues on redirect (#13557) 2025-10-28 16:58:11 +01:00
mrjo118
8d6268dc92 Chore: Fix intermittent revision test failure (#13458) 2025-10-28 11:35:07 +01:00
Henry Heino
7ffcbdf60a Server: Fixes #13490: Make server less likely to generate non-unique SSO codes (#13501) 2025-10-28 11:34:22 +01:00
mrjo118
76989ddc45 Mobile: Fixes #13120: Fix truncated buttons on tag association screen (#13502) 2025-10-28 11:33:52 +01:00
mrjo118
1db1254617 Mobile: Fixes #12957: Avoid dismissing the keyboard when tapping markdown toolbar buttons with the title in focus (#13504) 2025-10-28 11:33:36 +01:00
mrjo118
9810bffddc Mobile: Fixes #11468: Ensure note list is re-ordered after updating a note opened via a search (#13506) 2025-10-28 11:28:59 +01:00
Henry Heino
b25e18107b Desktop,Mobile,Cli: Fixes #13522: Fix "cannot add an item as a child of a read-only item" error when updating share IDs (#13523) 2025-10-28 11:28:37 +01:00
Henry Heino
edc5fe5d1b Desktop: Allow adding and removing users from a share while a sync is in progress (#13529) 2025-10-28 11:26:46 +01:00
Henry Heino
7ffb44b3a4 Desktop: Fixes #13537: Fix adding a new user to a share creates an unused E2EE key (#13538) 2025-10-28 11:23:02 +01:00
Henry Heino
32f4c33140 Desktop: Disallow unsharing a folder while sharing is in progress (#13551) 2025-10-28 11:22:13 +01:00
renovate[bot]
1a7b09c91c Update dependency koa to v2.16.2 (#13554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-28 09:40:08 +00:00
renovate[bot]
e5bf8e0e58 Update dependency @types/node-fetch to v2.6.13 (#13553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-28 09:38:10 +00:00
renovate[bot]
94725c533c Update dependency @react-native-community/datetimepicker to v8.4.3 (#13547)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-26 14:46:31 +00:00
Jozef Gaal
359c92b64f All: Translation: Update sk_SK.po (#13542) 2025-10-25 16:28:26 -04:00
renovate[bot]
8f8b8ad943 Update dependency dotenv to v16.6.1 (#13543)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-25 14:36:57 +00:00
renovate[bot]
dd2f329fd5 Update dependency @types/serviceworker to v0.0.147 (#13541)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-25 14:34:38 +00:00
mrjo118
813f594cb4 Mobile: Increase height of tag association screen to cater for a larger tag list area (#13521) 2025-10-25 14:13:15 +02:00
mrjo118
0e0ce49867 Mobile: Fixes #13108: Markdown toolbar overlaps with the gesture bar (#13533) 2025-10-25 14:12:37 +02:00
Henry Heino
e485d318b7 Desktop: Accessibility: Improve dialog keyboard handling (#13536) 2025-10-25 14:09:10 +02:00
renovate[bot]
4e82d81df1 Update dependency dotenv to v16.6.0 (#13539)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-25 14:04:29 +02:00
Frank Fesevur
d5dbda201b All: Translation: Update nl_NL.po (#13519) 2025-10-23 15:29:45 -04:00
Joplin Bot
831258506b Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-10-23 12:52:21 +00:00
renovate[bot]
67f3329ecb Update dependency rate-limiter-flexible to v7.1.1 (#13517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-23 14:32:35 +02:00
renovate[bot]
ed7e6751f0 Update dependency react-native-share to v12.1.1 (#13516)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-23 14:32:03 +02:00
mrjo118
35e69486d3 Mobile: Fixes #13457: Prevent toggling of multiline mode from clearing the title field on iOS (#13515) 2025-10-23 11:40:50 +02:00
Henry Heino
918c8830e0 Mobile: Fixes #13193: Fix Markdown toolbar (#13514) 2025-10-23 11:40:28 +02:00
renovate[bot]
c3b4a4b955 Update dependency rate-limiter-flexible to v7 (#13513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-23 11:38:21 +02:00
Laurent Cozic
44a14fabbd Doc: Updated sponsors 2025-10-23 10:19:53 +02:00
Frank Fesevur
49399cd1fa All: Translation: Update nl_NL.po (#13510) 2025-10-22 14:39:24 -04:00
github-actions[bot]
2eb70be937 @ffes has signed the CLA in laurent22/joplin#13510 2025-10-22 12:11:13 +00:00
Bartolomeo
fc4cd2e942 Server: Resolves #13147: Add LOG_LEVEL env var to control logging verbosity (#13503) 2025-10-22 12:26:02 +02:00
Arman Saga
cd6e457dc5 All: Translation: Update ru_RU.po (#13507) 2025-10-22 00:31:23 -04:00
github-actions[bot]
3ef138c9fe @Asagat has signed the CLA in laurent22/joplin#13507 2025-10-22 04:28:53 +00:00
Eric Duarte
2e9bf3a4e5 All: Translation: Update ca.po and es_ES.po (#13499) 2025-10-21 18:27:12 -04:00
Eric Duarte
547ceea4b0 All: Translation: Update es_ES.po (#13498) 2025-10-21 18:11:53 -04:00
renovate[bot]
776ff5e7ea Update dependency @fortawesome/react-fontawesome to v0.2.3 (#13500)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-21 23:22:49 +02:00
Joplin Bot
2b3bac0d43 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-10-21 18:39:58 +00:00
github-actions[bot]
4e21643bbe @bhorbowicz has signed the CLA in laurent22/joplin#13503 2025-10-21 18:06:20 +00:00
Henry Heino
e48efe2e8d Desktop: OneNote importer: Resolve possible import failure related to unsupported formatting (#13495) 2025-10-21 17:19:56 +02:00
Laurent Cozic
5f6382fbc0 Merge branch 'release-3.4' into dev 2025-10-21 16:36:53 +02:00
Laurent Cozic
3d5d82081a iOS 13.4.4 2025-10-21 16:17:15 +02:00
Laurent Cozic
cff96b1306 iOS: Removed donation link since Apple is blocking the release because of this 2025-10-21 16:08:02 +02:00
Henry Heino
98c5a9c096 Desktop: Fixes #13481: Accessibility: Prevent sidebar header text from moving: Don't change the header icon on hover (#13482) 2025-10-21 00:46:52 +02:00
Henry Heino
e92430b3ed Desktop: Accessibility: Fix global keyboard shortcuts are ignored when the sidebar has focus (#13485) 2025-10-21 00:46:36 +02:00
renovate[bot]
848d1bfe64 Update dependency react-native-safe-area-context to v5.5.0 (#13487)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-21 00:45:52 +02:00
Henry Heino
a386283530 Docs: Update OneNote import workflow (#13494) 2025-10-21 00:45:33 +02:00
Greg Oledzki
6101031269 Chore: Replace if with it in one of the tests (#13489) 2025-10-20 21:18:07 +02:00
Henry Heino
2fc3431f46 Web: Accessibility: Fix focus indicator is invisible for sync wizard options (#13492) 2025-10-20 21:12:06 +02:00
renovate[bot]
361fa2c768 Update dependency @types/serviceworker to v0.0.146 (#13484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-20 16:07:56 +00:00
github-actions[bot]
d9d9946faf @greg-at-moderne has signed the CLA in laurent22/joplin#13489 2025-10-20 08:59:01 +00:00
Helmut K. C. Tessarek
f4a0a2466b Update translations 2025-10-19 14:42:12 -04:00
summoner
dbf225d6ad All: Translation: Update hu_HU.po (#13486) 2025-10-19 14:36:40 -04:00
Helmut K. C. Tessarek
4773a3831c fix: remove \r escape sequence from hu_HU.po 2025-10-18 15:46:49 -04:00
Mihai Vasiliu
6a19690581 All: Translation: Update ro_RO.po and ro_MD.po (#13479) 2025-10-18 15:24:06 -04:00
Arda Kılıçdağı
b7a771d58d All: Translation: Update tr_TR.po (#13478) 2025-10-18 15:23:53 -04:00
Jozef Gaal
e3daefb81a All: Translation: Update sk_SK.po (#13477) 2025-10-18 15:23:41 -04:00
Joplin Bot
b4253dace8 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-10-18 12:46:07 +00:00
renovate[bot]
fcf3be1be1 Update dependency esbuild to v0.25.8 (#13473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-18 12:41:05 +01:00
renovate[bot]
99aebbad81 Update dependency mermaid to v11.7.0 (#13476)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-18 12:40:51 +01:00
Laurent Cozic
81b695a2a9 Chore: Exclude translation updates from changelog 2025-10-18 11:30:24 +01:00
Laurent Cozic
2dbba27357 Plugin Repo CLI v3.5.3 2025-10-18 10:12:33 +01:00
github-actions[bot]
032dfa949d @k-santos has signed the CLA in laurent22/joplin#13448 2025-10-16 01:40:36 +00:00
github-actions[bot]
7e703ed405 @WhiskerLogic has signed the CLA in laurent22/joplin#13429 2025-10-12 08:10:48 +00:00
github-actions[bot]
3b0cc08e6b @shania-codes has signed the CLA in laurent22/joplin#13418 2025-10-11 11:39:38 +00:00
github-actions[bot]
8961a4a10d @manuerwin has signed the CLA in laurent22/joplin#13383 2025-10-05 21:48:55 +00:00
github-actions[bot]
fed580ae18 @GordonRamsay-689 has signed the CLA in laurent22/joplin#13381 2025-10-05 17:34:50 +00:00
Laurent Cozic
97fa85a3f7 Desktop release v3.4.13 2025-10-02 09:35:36 +01:00
Laurent Cozic
defe36bba1 Server: Enable publish and share notebook for SAML login 2025-10-02 09:34:51 +01:00
github-actions[bot]
f036869f53 @filbert-wijaya has signed the CLA in laurent22/joplin#13339 2025-10-01 01:38:50 +00:00
github-actions[bot]
3a1b36d594 @Om7035 has signed the CLA in laurent22/joplin#13287 2025-09-29 14:59:37 +00:00
github-actions[bot]
b9ba747327 @yingli-lab has signed the CLA in laurent22/joplin#13311 2025-09-26 22:50:39 +00:00
github-actions[bot]
5631e1d57b @Sid0004 has signed the CLA in laurent22/joplin#13307 2025-09-26 17:46:01 +00:00
github-actions[bot]
740a5628dd @carica has signed the CLA in laurent22/joplin#13306 2025-09-26 17:13:02 +00:00
github-actions[bot]
0a758561f3 @trap000d has signed the CLA in laurent22/joplin#13299 2025-09-25 21:51:03 +00:00
github-actions[bot]
4986b1f084 @chadcrum has signed the CLA in laurent22/joplin#13286 2025-09-24 17:55:16 +00:00
github-actions[bot]
7aaad4e7f3 @bsavant has signed the CLA in laurent22/joplin#13281 2025-09-23 18:40:43 +00:00
github-actions[bot]
b0497bfa07 @kimar has signed the CLA in laurent22/joplin#13275 2025-09-23 07:22:52 +00:00
Henry Heino
711d214741 Android: Fixes #13193: Fix Markdown toolbar buttons sometimes don't work (#13233) 2025-09-18 12:05:57 +01:00
pedr
0795c67354 All: Fixes #12249: Change default content-type for Webdav connector to application/octet-stream (#13053) 2025-09-13 14:13:27 +01:00
github-actions[bot]
2d0f02cb8a @maggie897 has signed the CLA in laurent22/joplin#13190 2025-09-11 22:00:38 +00:00
Laurent Cozic
e9a9f68568 Desktop release v3.4.12 2025-09-09 15:36:24 +01:00
github-actions[bot]
1ae72235fc @pplulee has signed the CLA in laurent22/joplin#13137 2025-09-06 11:15:42 +00:00
github-actions[bot]
86f2a3a7d0 @VortexP has signed the CLA in laurent22/joplin#12971 2025-08-15 19:29:31 +00:00
github-actions[bot]
5b106d4827 @yuudi has signed the CLA in laurent22/joplin#12948 2025-08-13 20:45:52 +00:00
github-actions[bot]
3bf2eb0399 @prashant1177 has signed the CLA in laurent22/joplin#12940 2025-08-13 11:25:48 +00:00
github-actions[bot]
8302afda19 @miguelammatos has signed the CLA in laurent22/joplin#12718 2025-08-10 23:26:18 +00:00
github-actions[bot]
ba970ac7a5 @laurent22 has signed the CLA in laurent22/joplin#12902 2025-08-06 12:04:36 +00:00
github-actions[bot]
89018e497f @klaas0 has signed the CLA in laurent22/joplin#12895 2025-08-05 21:46:31 +00:00
github-actions[bot]
53a05eb781 @JZou-Code has signed the CLA in laurent22/joplin#12868 2025-08-04 11:57:37 +00:00
github-actions[bot]
7637915bed @PanWor has signed the CLA in laurent22/joplin#12857 2025-08-02 20:09:21 +00:00
github-actions[bot]
d5dd55a813 @w568w has signed the CLA in laurent22/joplin#12839 2025-08-01 15:31:56 +00:00
github-actions[bot]
e80a0c39f8 @laurent22 has signed the CLA in laurent22/joplin#12798 2025-07-27 14:57:46 +00:00
github-actions[bot]
357199658f @bwat47 has signed the CLA in laurent22/joplin#12805 2025-07-27 13:42:23 +00:00
819 changed files with 146590 additions and 95640 deletions

View File

@@ -6,6 +6,7 @@ _releases/
*.min.js
**/commands/index.ts
**/node_modules/
**/abcjs-basic-min.js
packages/generator-joplin/generators/app/templates/api/
Assets/
docs/
@@ -96,7 +97,7 @@ packages/onenote-converter/renderer/pkg/*
packages/app-cli/app/LinkSelector.js
packages/app-cli/app/app.js
packages/app-cli/app/base-command.js
packages/app-cli/app/cli-integration-tests.js
packages/app-cli/app/cli-integration-tests.test.js
packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js
@@ -114,6 +115,7 @@ packages/app-cli/app/command-export.js
packages/app-cli/app/command-geoloc.js
packages/app-cli/app/command-help.js
packages/app-cli/app/command-import.js
packages/app-cli/app/command-keymap.js
packages/app-cli/app/command-ls.js
packages/app-cli/app/command-mkbook.test.js
packages/app-cli/app/command-mkbook.js
@@ -164,8 +166,6 @@ packages/app-desktop/app.reducer.js
packages/app-desktop/app.js
packages/app-desktop/bridge.js
packages/app-desktop/checkForUpdates.js
packages/app-desktop/commands/convertNoteToMarkdown.test.js
packages/app-desktop/commands/convertNoteToMarkdown.js
packages/app-desktop/commands/copyDevCommand.js
packages/app-desktop/commands/copyToClipboard.js
packages/app-desktop/commands/editProfileConfig.js
@@ -182,6 +182,7 @@ packages/app-desktop/commands/openProfileDirectory.js
packages/app-desktop/commands/openSecondaryAppInstance.js
packages/app-desktop/commands/replaceMisspelling.js
packages/app-desktop/commands/restoreNoteRevision.js
packages/app-desktop/commands/showProfileEditor.js
packages/app-desktop/commands/startExternalEditing.js
packages/app-desktop/commands/stopExternalEditing.js
packages/app-desktop/commands/switchProfile.js
@@ -206,7 +207,6 @@ packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
packages/app-desktop/gui/ConversionNotification/ConversionNotification.js
packages/app-desktop/gui/Dialog.js
packages/app-desktop/gui/DialogButtonRow.js
packages/app-desktop/gui/DialogButtonRow/useKeyboardHandler.js
@@ -392,6 +392,7 @@ packages/app-desktop/gui/PopupNotification/NotificationItem.js
packages/app-desktop/gui/PopupNotification/PopupNotificationList.js
packages/app-desktop/gui/PopupNotification/PopupNotificationProvider.js
packages/app-desktop/gui/PopupNotification/types.js
packages/app-desktop/gui/ProfileEditor.js
packages/app-desktop/gui/PromptDialog.js
packages/app-desktop/gui/ResizableLayout/LayoutItemContainer.js
packages/app-desktop/gui/ResizableLayout/MoveButtons.js
@@ -424,10 +425,11 @@ packages/app-desktop/gui/Sidebar/Sidebar.js
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js
packages/app-desktop/gui/Sidebar/commands/index.js
packages/app-desktop/gui/Sidebar/hooks/useFocusHandler.js
packages/app-desktop/gui/Sidebar/hooks/useOnItemClick.js
packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.js
packages/app-desktop/gui/Sidebar/hooks/useOnRenderListWrapper.js
packages/app-desktop/gui/Sidebar/hooks/useOnSidebarKeyDownHandler.js
packages/app-desktop/gui/Sidebar/hooks/useSelectedSidebarIndex.js
packages/app-desktop/gui/Sidebar/hooks/useSelectedSidebarIndexes.js
packages/app-desktop/gui/Sidebar/hooks/useSidebarCommandHandler.js
packages/app-desktop/gui/Sidebar/hooks/useSidebarListData.js
packages/app-desktop/gui/Sidebar/hooks/utils/toggleHeader.js
@@ -468,6 +470,7 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/editAlarm.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/exportPdf.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/gotoAnything.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/hideModalMessage.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/importFrom.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/index.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/linkToNote.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.js
@@ -510,6 +513,7 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleSideBar.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleVisiblePanes.js
packages/app-desktop/gui/WindowCommandsAndDialogs/types.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/appDialogs.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/showFolderPicker.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/usePrintToCallback.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useSyncDialogState.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowCommands.js
@@ -561,6 +565,7 @@ packages/app-desktop/integration-tests/util/evaluateWithRetry.js
packages/app-desktop/integration-tests/util/extendedExpect.js
packages/app-desktop/integration-tests/util/getImageSourceSize.js
packages/app-desktop/integration-tests/util/getMainWindow.js
packages/app-desktop/integration-tests/util/mockClipboard.js
packages/app-desktop/integration-tests/util/retryOnFailure.js
packages/app-desktop/integration-tests/util/setDarkMode.js
packages/app-desktop/integration-tests/util/setFilePickerResponse.js
@@ -701,6 +706,7 @@ packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.js
packages/app-mobile/components/NoteEditor/ImageEditor/autosave.js
packages/app-mobile/components/NoteEditor/ImageEditor/isEditableResource.js
packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.js
packages/app-mobile/components/NoteEditor/MarkdownEditor.test.js
packages/app-mobile/components/NoteEditor/MarkdownEditor.js
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
packages/app-mobile/components/NoteEditor/NoteEditor.js
@@ -848,6 +854,7 @@ packages/app-mobile/components/screens/NoteTagsDialog.js
packages/app-mobile/components/screens/Notes/NewNoteButton.test.js
packages/app-mobile/components/screens/Notes/NewNoteButton.js
packages/app-mobile/components/screens/Notes/Notes.js
packages/app-mobile/components/screens/SearchScreen/SearchBar.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
packages/app-mobile/components/screens/SearchScreen/index.js
@@ -953,6 +960,7 @@ packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js
packages/app-mobile/utils/getPackageInfo.js
packages/app-mobile/utils/getVersionInfoText.js
packages/app-mobile/utils/hooks/useBackHandler.js
packages/app-mobile/utils/hooks/useDebounced.js
packages/app-mobile/utils/hooks/useIsScreenReaderEnabled.js
packages/app-mobile/utils/hooks/useKeyboardState.js
packages/app-mobile/utils/hooks/useOnLongPressProps.js
@@ -1004,6 +1012,7 @@ packages/editor/CodeMirror/CodeMirrorControl.js
packages/editor/CodeMirror/configFromSettings.js
packages/editor/CodeMirror/createEditor.test.js
packages/editor/CodeMirror/createEditor.js
packages/editor/CodeMirror/editorCommands/cutOrCopyText.js
packages/editor/CodeMirror/editorCommands/duplicateLine.test.js
packages/editor/CodeMirror/editorCommands/duplicateLine.js
packages/editor/CodeMirror/editorCommands/editorCommands.js
@@ -1023,6 +1032,7 @@ packages/editor/CodeMirror/editorCommands/supportsCommand.js
packages/editor/CodeMirror/extensions/biDirectionalTextExtension.js
packages/editor/CodeMirror/extensions/ctrlClickActionExtension.js
packages/editor/CodeMirror/extensions/ctrlClickCheckboxExtension.js
packages/editor/CodeMirror/extensions/editorSettingsExtension.js
packages/editor/CodeMirror/extensions/highlightActiveLineExtension.js
packages/editor/CodeMirror/extensions/keyUpHandlerExtension.js
packages/editor/CodeMirror/extensions/links/ctrlClickLinksExtension.js
@@ -1046,10 +1056,13 @@ packages/editor/CodeMirror/extensions/rendering/addFormattingClasses.js
packages/editor/CodeMirror/extensions/rendering/renderBlockImages.test.js
packages/editor/CodeMirror/extensions/rendering/renderBlockImages.js
packages/editor/CodeMirror/extensions/rendering/renderingExtension.js
packages/editor/CodeMirror/extensions/rendering/replaceBackslashEscapes.js
packages/editor/CodeMirror/extensions/rendering/replaceBulletLists.js
packages/editor/CodeMirror/extensions/rendering/replaceCheckboxes.js
packages/editor/CodeMirror/extensions/rendering/replaceDividers.js
packages/editor/CodeMirror/extensions/rendering/replaceFormatCharacters.js
packages/editor/CodeMirror/extensions/rendering/replaceInlineHtml.test.js
packages/editor/CodeMirror/extensions/rendering/replaceInlineHtml.js
packages/editor/CodeMirror/extensions/rendering/types.js
packages/editor/CodeMirror/extensions/rendering/utils/makeBlockReplaceExtension.js
packages/editor/CodeMirror/extensions/rendering/utils/makeInlineReplaceExtension.js
@@ -1090,6 +1103,7 @@ packages/editor/CodeMirror/utils/getSearchState.js
packages/editor/CodeMirror/utils/growSelectionToNode.js
packages/editor/CodeMirror/utils/handleLinkEditRequests.js
packages/editor/CodeMirror/utils/handlePasteEvent.js
packages/editor/CodeMirror/utils/htmlNodeInfo.js
packages/editor/CodeMirror/utils/isCursorAtBeginning.js
packages/editor/CodeMirror/utils/isInSyntaxNode.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/allLanguages.js
@@ -1105,6 +1119,7 @@ packages/editor/CodeMirror/vendor/announceSearchMatch.js
packages/editor/ProseMirror/commands/commands.test.js
packages/editor/ProseMirror/commands/commands.js
packages/editor/ProseMirror/commands/focusEditor.js
packages/editor/ProseMirror/commands/selectDocumentEnd.js
packages/editor/ProseMirror/createEditor.js
packages/editor/ProseMirror/index.js
packages/editor/ProseMirror/plugins/detailsPlugin.test.js
@@ -1112,10 +1127,12 @@ packages/editor/ProseMirror/plugins/detailsPlugin.js
packages/editor/ProseMirror/plugins/imagePlugin.test.js
packages/editor/ProseMirror/plugins/imagePlugin.js
packages/editor/ProseMirror/plugins/inputRulesPlugin.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/createEditorDialog.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/joplinEditablePlugin.test.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/joplinEditablePlugin.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/postProcessRenderedHtml.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/showCreateEditablePrompt.test.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/showCreateEditablePrompt.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/utils/createEditorDialog.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/utils/postProcessRenderedHtml.js
packages/editor/ProseMirror/plugins/joplinEditorApiPlugin.js
packages/editor/ProseMirror/plugins/keymapPlugin.js
packages/editor/ProseMirror/plugins/linkTooltipPlugin.test.js
@@ -1130,10 +1147,12 @@ packages/editor/ProseMirror/schema.js
packages/editor/ProseMirror/styles.js
packages/editor/ProseMirror/testing/createTestEditor.js
packages/editor/ProseMirror/testing/createTestEditorWithSerializer.js
packages/editor/ProseMirror/testing/mockEditorApi.js
packages/editor/ProseMirror/types.js
packages/editor/ProseMirror/utils/SelectableNodeView.js
packages/editor/ProseMirror/utils/UndoStackSynchronizer.js
packages/editor/ProseMirror/utils/canReplaceSelectionWith.js
packages/editor/ProseMirror/utils/clampPointToDocument.js
packages/editor/ProseMirror/utils/computeSelectionFormatting.js
packages/editor/ProseMirror/utils/dom/createButton.js
packages/editor/ProseMirror/utils/dom/createTextArea.js
@@ -1143,6 +1162,8 @@ packages/editor/ProseMirror/utils/dom/showModal.js
packages/editor/ProseMirror/utils/extractSelectedLinesTo.test.js
packages/editor/ProseMirror/utils/extractSelectedLinesTo.js
packages/editor/ProseMirror/utils/forEachHeading.js
packages/editor/ProseMirror/utils/getTextBetween.js
packages/editor/ProseMirror/utils/insertRenderedMarkdown.js
packages/editor/ProseMirror/utils/jumpToHash.js
packages/editor/ProseMirror/utils/makeLinksClickableInElement.js
packages/editor/ProseMirror/utils/postprocessEditorOutput.test.js
@@ -1210,6 +1231,7 @@ packages/lib/InMemoryCache.js
packages/lib/JoplinDatabase.js
packages/lib/JoplinError.js
packages/lib/JoplinServerApi.js
packages/lib/ObjectUtils.test.js
packages/lib/ObjectUtils.js
packages/lib/PerformanceLogger.test.js
packages/lib/PerformanceLogger.js
@@ -1232,6 +1254,8 @@ packages/lib/callbackUrlUtils.js
packages/lib/clipperUtils.js
packages/lib/commands/convertHtmlToMarkdown.test.js
packages/lib/commands/convertHtmlToMarkdown.js
packages/lib/commands/convertNoteToMarkdown.test.js
packages/lib/commands/convertNoteToMarkdown.js
packages/lib/commands/deleteNote.js
packages/lib/commands/historyBackward.js
packages/lib/commands/historyForward.js
@@ -1360,6 +1384,7 @@ packages/lib/models/utils/getCanBeCollapsedFolderIds.js
packages/lib/models/utils/getCollator.js
packages/lib/models/utils/getConflictFolderId.js
packages/lib/models/utils/isItemId.js
packages/lib/models/utils/isJoplinServerVariant.js
packages/lib/models/utils/itemCanBeEncrypted.js
packages/lib/models/utils/onFolderDrop.test.js
packages/lib/models/utils/onFolderDrop.js
@@ -1395,6 +1420,7 @@ packages/lib/services/KeymapService_keysRegExp.js
packages/lib/services/KvStore.js
packages/lib/services/MigrationService.js
packages/lib/services/NavService.js
packages/lib/services/NotePositionService.js
packages/lib/services/PostMessageService.js
packages/lib/services/ReportService.test.js
packages/lib/services/ReportService.js
@@ -1410,6 +1436,7 @@ packages/lib/services/UndoRedoService.js
packages/lib/services/WhenClause.test.js
packages/lib/services/WhenClause.js
packages/lib/services/commands/MenuUtils.js
packages/lib/services/commands/ToolbarButtonUtils.test.js
packages/lib/services/commands/ToolbarButtonUtils.js
packages/lib/services/commands/commandsToMarkdownTable.js
packages/lib/services/commands/focusEditorIfEditorCommand.js
@@ -1643,6 +1670,7 @@ packages/lib/services/synchronizer/Synchronizer.sharing.test.js
packages/lib/services/synchronizer/Synchronizer.tags.test.js
packages/lib/services/synchronizer/Synchronizer.tools.test.js
packages/lib/services/synchronizer/gui/useSyncTargetUpgrade.js
packages/lib/services/synchronizer/handleConflictAction.test.js
packages/lib/services/synchronizer/migrations/1.js
packages/lib/services/synchronizer/migrations/2.js
packages/lib/services/synchronizer/migrations/3.js
@@ -1777,8 +1805,10 @@ packages/renderer/MdToHtml/createEventHandlingAttrs.js
packages/renderer/MdToHtml/linkReplacement.test.js
packages/renderer/MdToHtml/linkReplacement.js
packages/renderer/MdToHtml/renderMedia.js
packages/renderer/MdToHtml/rules/abc.js
packages/renderer/MdToHtml/rules/checkbox.js
packages/renderer/MdToHtml/rules/code_inline.js
packages/renderer/MdToHtml/rules/externalEmbed.js
packages/renderer/MdToHtml/rules/fence.js
packages/renderer/MdToHtml/rules/fountain.js
packages/renderer/MdToHtml/rules/highlight_keywords.js
@@ -1814,6 +1844,7 @@ packages/tools/checkIgnoredFiles.js
packages/tools/checkLibPaths.test.js
packages/tools/checkLibPaths.js
packages/tools/convertThemesToCss.js
packages/tools/fuzzer/ActionRunner.js
packages/tools/fuzzer/ActionTracker.js
packages/tools/fuzzer/Client.js
packages/tools/fuzzer/ClientPool.js
@@ -1822,16 +1853,22 @@ packages/tools/fuzzer/constants.js
packages/tools/fuzzer/model/FolderRecord.js
packages/tools/fuzzer/sync-fuzzer.js
packages/tools/fuzzer/types.js
packages/tools/fuzzer/utils/ProgressBar.js
packages/tools/fuzzer/utils/SeededRandom.js
packages/tools/fuzzer/utils/diffSortedStringArrays.test.js
packages/tools/fuzzer/utils/diffSortedStringArrays.js
packages/tools/fuzzer/utils/getNumberProperty.js
packages/tools/fuzzer/utils/getProperty.js
packages/tools/fuzzer/utils/getStringProperty.js
packages/tools/fuzzer/utils/logDiffDebug.js
packages/tools/fuzzer/utils/openDebugSession.js
packages/tools/fuzzer/utils/randomString.js
packages/tools/fuzzer/utils/retryWithCount.js
packages/tools/generate-database-types.js
packages/tools/generate-images.js
packages/tools/git-changelog.test.js
packages/tools/git-changelog.js
packages/tools/licenses/buildReport.js
packages/tools/licenses/getLicenses.js
packages/tools/licenses/licenseChecker.js
packages/tools/licenses/licenseOverrides/fontAwesomeOverride/index.js

View File

@@ -21,19 +21,24 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: '18'
node-version: '24'
cache: 'yarn'
- uses: dtolnay/rust-toolchain@stable
- name: Install Yarn
run: |
corepack enable
- name: Install
run: yarn install
env:
SKIP_ONENOTE_CONVERTER_BUILD: 1
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
- name: Assemble Android Release
run: |

View File

@@ -9,11 +9,9 @@ jobs:
- uses: actions/checkout@v4
- uses: olegtarasov/get-tag@v2.1.4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
# We need to pin the version to 18.15, because 18.16+ fails with this error:
# https://github.com/facebook/react-native/issues/36440
node-version: '18.20.8'
node-version: '24'
cache: 'yarn'
- name: Install Yarn
@@ -50,6 +48,7 @@ jobs:
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
IS_CONTINUOUS_INTEGRATION: 1
BUILD_SEQUENCIAL: 1
PUBLISH_ENABLED: ${{ env.PUBLISH_ENABLED }}
@@ -59,25 +58,38 @@ jobs:
yarn install
cd packages/app-desktop
npm pkg set 'build.mac.artifactName'='${productName}-${version}-${arch}.${ext}'
npm pkg delete 'build.mac.target'
npm pkg set 'build.mac.target[0].target'='dmg'
npm pkg set 'build.mac.target[0].arch[0]'='arm64'
npm pkg set 'build.mac.target[1].target'='zip'
npm pkg set 'build.mac.target[1].arch[0]'='arm64'
if [[ "$PUBLISH_ENABLED" == "true" ]]; then
echo "Building and publishing desktop application..."
PYTHON_PATH=$(which python) USE_HARD_LINKS=false yarn dist --mac --arm64
# Only enable pkg build in the main repository CI. As of 01/15/2026, pkg
# build fails when running on external pull requests.
if [[ "$GITHUB_EVENT_NAME" != "pull_request" ]]; then
npm pkg set 'build.mac.target[2].target'='pkg'
npm pkg set 'build.mac.target[2].arch[0]'='arm64'
fi
yarn modifyReleaseAssets --repo="$GH_REPO" --tag="$GIT_TAG_NAME" --token="$GITHUB_TOKEN"
else
echo "Building but *not* publishing desktop application..."
build_dist() {
if [[ "$PUBLISH_ENABLED" == "true" ]]; then
echo "Building and publishing desktop application..."
PYTHON_PATH=$(which python) USE_HARD_LINKS=false yarn dist --mac --arm64
# We also want to disable signing the app in this case, because
# it doesn't work and we don't need it.
# https://www.electron.build/code-signing#how-to-disable-code-signing-during-the-build-process-on-macos
yarn modifyReleaseAssets --repo="$GH_REPO" --tag="$GIT_TAG_NAME" --token="$GITHUB_TOKEN"
else
echo "Building but *not* publishing desktop application..."
export CSC_IDENTITY_AUTO_DISCOVERY=false
npm pkg set 'build.mac.identity'=null --json
# We also want to disable signing the app in this case, because
# it doesn't work and we don't need it.
# https://www.electron.build/code-signing#how-to-disable-code-signing-during-the-build-process-on-macos
PYTHON_PATH=$(which python) USE_HARD_LINKS=false yarn dist --mac --arm64 --publish=never
fi
export CSC_IDENTITY_AUTO_DISCOVERY=false
npm pkg set 'build.mac.identity'=null --json
PYTHON_PATH=$(which python) USE_HARD_LINKS=false yarn dist --mac --arm64 --publish=never
fi
}
build_dist || build_dist

View File

@@ -147,9 +147,9 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: '18'
node-version: '24'
- name: Free disk space
if: runner.os == 'Linux'

View File

@@ -51,9 +51,9 @@ runs:
- uses: dtolnay/rust-toolchain@stable
if: ${{ runner.os != 'Windows' }}
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: '18.20.8'
node-version: '24'
# Disable the cache on ARM runners. For now, we don't run "yarn install" on these
# environments and this breaks actions/setup-node.
# See https://github.com/laurent22/joplin/commit/47d0d3eb9e89153a609fb5441344da10904c6308#commitcomment-159577783.

52
.gitignore vendored
View File

@@ -1,6 +1,7 @@
_mydocs
_releases
_vieux/
.claude
!/var/cache
!/var/logs
!/var/sessions
@@ -52,6 +53,7 @@ lerna-debug.log
docs/**/*.mustache
.idea
/readme/i18n
.watchman-cookie-*
# Yarn stuff
# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
@@ -69,7 +71,7 @@ docs/**/*.mustache
packages/app-cli/app/LinkSelector.js
packages/app-cli/app/app.js
packages/app-cli/app/base-command.js
packages/app-cli/app/cli-integration-tests.js
packages/app-cli/app/cli-integration-tests.test.js
packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js
@@ -87,6 +89,7 @@ packages/app-cli/app/command-export.js
packages/app-cli/app/command-geoloc.js
packages/app-cli/app/command-help.js
packages/app-cli/app/command-import.js
packages/app-cli/app/command-keymap.js
packages/app-cli/app/command-ls.js
packages/app-cli/app/command-mkbook.test.js
packages/app-cli/app/command-mkbook.js
@@ -137,8 +140,6 @@ packages/app-desktop/app.reducer.js
packages/app-desktop/app.js
packages/app-desktop/bridge.js
packages/app-desktop/checkForUpdates.js
packages/app-desktop/commands/convertNoteToMarkdown.test.js
packages/app-desktop/commands/convertNoteToMarkdown.js
packages/app-desktop/commands/copyDevCommand.js
packages/app-desktop/commands/copyToClipboard.js
packages/app-desktop/commands/editProfileConfig.js
@@ -155,6 +156,7 @@ packages/app-desktop/commands/openProfileDirectory.js
packages/app-desktop/commands/openSecondaryAppInstance.js
packages/app-desktop/commands/replaceMisspelling.js
packages/app-desktop/commands/restoreNoteRevision.js
packages/app-desktop/commands/showProfileEditor.js
packages/app-desktop/commands/startExternalEditing.js
packages/app-desktop/commands/stopExternalEditing.js
packages/app-desktop/commands/switchProfile.js
@@ -179,7 +181,6 @@ packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
packages/app-desktop/gui/ConversionNotification/ConversionNotification.js
packages/app-desktop/gui/Dialog.js
packages/app-desktop/gui/DialogButtonRow.js
packages/app-desktop/gui/DialogButtonRow/useKeyboardHandler.js
@@ -365,6 +366,7 @@ packages/app-desktop/gui/PopupNotification/NotificationItem.js
packages/app-desktop/gui/PopupNotification/PopupNotificationList.js
packages/app-desktop/gui/PopupNotification/PopupNotificationProvider.js
packages/app-desktop/gui/PopupNotification/types.js
packages/app-desktop/gui/ProfileEditor.js
packages/app-desktop/gui/PromptDialog.js
packages/app-desktop/gui/ResizableLayout/LayoutItemContainer.js
packages/app-desktop/gui/ResizableLayout/MoveButtons.js
@@ -397,10 +399,11 @@ packages/app-desktop/gui/Sidebar/Sidebar.js
packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.js
packages/app-desktop/gui/Sidebar/commands/index.js
packages/app-desktop/gui/Sidebar/hooks/useFocusHandler.js
packages/app-desktop/gui/Sidebar/hooks/useOnItemClick.js
packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.js
packages/app-desktop/gui/Sidebar/hooks/useOnRenderListWrapper.js
packages/app-desktop/gui/Sidebar/hooks/useOnSidebarKeyDownHandler.js
packages/app-desktop/gui/Sidebar/hooks/useSelectedSidebarIndex.js
packages/app-desktop/gui/Sidebar/hooks/useSelectedSidebarIndexes.js
packages/app-desktop/gui/Sidebar/hooks/useSidebarCommandHandler.js
packages/app-desktop/gui/Sidebar/hooks/useSidebarListData.js
packages/app-desktop/gui/Sidebar/hooks/utils/toggleHeader.js
@@ -441,6 +444,7 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/editAlarm.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/exportPdf.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/gotoAnything.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/hideModalMessage.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/importFrom.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/index.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/linkToNote.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.js
@@ -483,6 +487,7 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleSideBar.js
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleVisiblePanes.js
packages/app-desktop/gui/WindowCommandsAndDialogs/types.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/appDialogs.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/showFolderPicker.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/usePrintToCallback.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useSyncDialogState.js
packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowCommands.js
@@ -534,6 +539,7 @@ packages/app-desktop/integration-tests/util/evaluateWithRetry.js
packages/app-desktop/integration-tests/util/extendedExpect.js
packages/app-desktop/integration-tests/util/getImageSourceSize.js
packages/app-desktop/integration-tests/util/getMainWindow.js
packages/app-desktop/integration-tests/util/mockClipboard.js
packages/app-desktop/integration-tests/util/retryOnFailure.js
packages/app-desktop/integration-tests/util/setDarkMode.js
packages/app-desktop/integration-tests/util/setFilePickerResponse.js
@@ -674,6 +680,7 @@ packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.js
packages/app-mobile/components/NoteEditor/ImageEditor/autosave.js
packages/app-mobile/components/NoteEditor/ImageEditor/isEditableResource.js
packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.js
packages/app-mobile/components/NoteEditor/MarkdownEditor.test.js
packages/app-mobile/components/NoteEditor/MarkdownEditor.js
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
packages/app-mobile/components/NoteEditor/NoteEditor.js
@@ -821,6 +828,7 @@ packages/app-mobile/components/screens/NoteTagsDialog.js
packages/app-mobile/components/screens/Notes/NewNoteButton.test.js
packages/app-mobile/components/screens/Notes/NewNoteButton.js
packages/app-mobile/components/screens/Notes/Notes.js
packages/app-mobile/components/screens/SearchScreen/SearchBar.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
packages/app-mobile/components/screens/SearchScreen/index.js
@@ -926,6 +934,7 @@ packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js
packages/app-mobile/utils/getPackageInfo.js
packages/app-mobile/utils/getVersionInfoText.js
packages/app-mobile/utils/hooks/useBackHandler.js
packages/app-mobile/utils/hooks/useDebounced.js
packages/app-mobile/utils/hooks/useIsScreenReaderEnabled.js
packages/app-mobile/utils/hooks/useKeyboardState.js
packages/app-mobile/utils/hooks/useOnLongPressProps.js
@@ -977,6 +986,7 @@ packages/editor/CodeMirror/CodeMirrorControl.js
packages/editor/CodeMirror/configFromSettings.js
packages/editor/CodeMirror/createEditor.test.js
packages/editor/CodeMirror/createEditor.js
packages/editor/CodeMirror/editorCommands/cutOrCopyText.js
packages/editor/CodeMirror/editorCommands/duplicateLine.test.js
packages/editor/CodeMirror/editorCommands/duplicateLine.js
packages/editor/CodeMirror/editorCommands/editorCommands.js
@@ -996,6 +1006,7 @@ packages/editor/CodeMirror/editorCommands/supportsCommand.js
packages/editor/CodeMirror/extensions/biDirectionalTextExtension.js
packages/editor/CodeMirror/extensions/ctrlClickActionExtension.js
packages/editor/CodeMirror/extensions/ctrlClickCheckboxExtension.js
packages/editor/CodeMirror/extensions/editorSettingsExtension.js
packages/editor/CodeMirror/extensions/highlightActiveLineExtension.js
packages/editor/CodeMirror/extensions/keyUpHandlerExtension.js
packages/editor/CodeMirror/extensions/links/ctrlClickLinksExtension.js
@@ -1019,10 +1030,13 @@ packages/editor/CodeMirror/extensions/rendering/addFormattingClasses.js
packages/editor/CodeMirror/extensions/rendering/renderBlockImages.test.js
packages/editor/CodeMirror/extensions/rendering/renderBlockImages.js
packages/editor/CodeMirror/extensions/rendering/renderingExtension.js
packages/editor/CodeMirror/extensions/rendering/replaceBackslashEscapes.js
packages/editor/CodeMirror/extensions/rendering/replaceBulletLists.js
packages/editor/CodeMirror/extensions/rendering/replaceCheckboxes.js
packages/editor/CodeMirror/extensions/rendering/replaceDividers.js
packages/editor/CodeMirror/extensions/rendering/replaceFormatCharacters.js
packages/editor/CodeMirror/extensions/rendering/replaceInlineHtml.test.js
packages/editor/CodeMirror/extensions/rendering/replaceInlineHtml.js
packages/editor/CodeMirror/extensions/rendering/types.js
packages/editor/CodeMirror/extensions/rendering/utils/makeBlockReplaceExtension.js
packages/editor/CodeMirror/extensions/rendering/utils/makeInlineReplaceExtension.js
@@ -1063,6 +1077,7 @@ packages/editor/CodeMirror/utils/getSearchState.js
packages/editor/CodeMirror/utils/growSelectionToNode.js
packages/editor/CodeMirror/utils/handleLinkEditRequests.js
packages/editor/CodeMirror/utils/handlePasteEvent.js
packages/editor/CodeMirror/utils/htmlNodeInfo.js
packages/editor/CodeMirror/utils/isCursorAtBeginning.js
packages/editor/CodeMirror/utils/isInSyntaxNode.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/allLanguages.js
@@ -1078,6 +1093,7 @@ packages/editor/CodeMirror/vendor/announceSearchMatch.js
packages/editor/ProseMirror/commands/commands.test.js
packages/editor/ProseMirror/commands/commands.js
packages/editor/ProseMirror/commands/focusEditor.js
packages/editor/ProseMirror/commands/selectDocumentEnd.js
packages/editor/ProseMirror/createEditor.js
packages/editor/ProseMirror/index.js
packages/editor/ProseMirror/plugins/detailsPlugin.test.js
@@ -1085,10 +1101,12 @@ packages/editor/ProseMirror/plugins/detailsPlugin.js
packages/editor/ProseMirror/plugins/imagePlugin.test.js
packages/editor/ProseMirror/plugins/imagePlugin.js
packages/editor/ProseMirror/plugins/inputRulesPlugin.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/createEditorDialog.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/joplinEditablePlugin.test.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/joplinEditablePlugin.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/postProcessRenderedHtml.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/showCreateEditablePrompt.test.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/showCreateEditablePrompt.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/utils/createEditorDialog.js
packages/editor/ProseMirror/plugins/joplinEditablePlugin/utils/postProcessRenderedHtml.js
packages/editor/ProseMirror/plugins/joplinEditorApiPlugin.js
packages/editor/ProseMirror/plugins/keymapPlugin.js
packages/editor/ProseMirror/plugins/linkTooltipPlugin.test.js
@@ -1103,10 +1121,12 @@ packages/editor/ProseMirror/schema.js
packages/editor/ProseMirror/styles.js
packages/editor/ProseMirror/testing/createTestEditor.js
packages/editor/ProseMirror/testing/createTestEditorWithSerializer.js
packages/editor/ProseMirror/testing/mockEditorApi.js
packages/editor/ProseMirror/types.js
packages/editor/ProseMirror/utils/SelectableNodeView.js
packages/editor/ProseMirror/utils/UndoStackSynchronizer.js
packages/editor/ProseMirror/utils/canReplaceSelectionWith.js
packages/editor/ProseMirror/utils/clampPointToDocument.js
packages/editor/ProseMirror/utils/computeSelectionFormatting.js
packages/editor/ProseMirror/utils/dom/createButton.js
packages/editor/ProseMirror/utils/dom/createTextArea.js
@@ -1116,6 +1136,8 @@ packages/editor/ProseMirror/utils/dom/showModal.js
packages/editor/ProseMirror/utils/extractSelectedLinesTo.test.js
packages/editor/ProseMirror/utils/extractSelectedLinesTo.js
packages/editor/ProseMirror/utils/forEachHeading.js
packages/editor/ProseMirror/utils/getTextBetween.js
packages/editor/ProseMirror/utils/insertRenderedMarkdown.js
packages/editor/ProseMirror/utils/jumpToHash.js
packages/editor/ProseMirror/utils/makeLinksClickableInElement.js
packages/editor/ProseMirror/utils/postprocessEditorOutput.test.js
@@ -1183,6 +1205,7 @@ packages/lib/InMemoryCache.js
packages/lib/JoplinDatabase.js
packages/lib/JoplinError.js
packages/lib/JoplinServerApi.js
packages/lib/ObjectUtils.test.js
packages/lib/ObjectUtils.js
packages/lib/PerformanceLogger.test.js
packages/lib/PerformanceLogger.js
@@ -1205,6 +1228,8 @@ packages/lib/callbackUrlUtils.js
packages/lib/clipperUtils.js
packages/lib/commands/convertHtmlToMarkdown.test.js
packages/lib/commands/convertHtmlToMarkdown.js
packages/lib/commands/convertNoteToMarkdown.test.js
packages/lib/commands/convertNoteToMarkdown.js
packages/lib/commands/deleteNote.js
packages/lib/commands/historyBackward.js
packages/lib/commands/historyForward.js
@@ -1333,6 +1358,7 @@ packages/lib/models/utils/getCanBeCollapsedFolderIds.js
packages/lib/models/utils/getCollator.js
packages/lib/models/utils/getConflictFolderId.js
packages/lib/models/utils/isItemId.js
packages/lib/models/utils/isJoplinServerVariant.js
packages/lib/models/utils/itemCanBeEncrypted.js
packages/lib/models/utils/onFolderDrop.test.js
packages/lib/models/utils/onFolderDrop.js
@@ -1368,6 +1394,7 @@ packages/lib/services/KeymapService_keysRegExp.js
packages/lib/services/KvStore.js
packages/lib/services/MigrationService.js
packages/lib/services/NavService.js
packages/lib/services/NotePositionService.js
packages/lib/services/PostMessageService.js
packages/lib/services/ReportService.test.js
packages/lib/services/ReportService.js
@@ -1383,6 +1410,7 @@ packages/lib/services/UndoRedoService.js
packages/lib/services/WhenClause.test.js
packages/lib/services/WhenClause.js
packages/lib/services/commands/MenuUtils.js
packages/lib/services/commands/ToolbarButtonUtils.test.js
packages/lib/services/commands/ToolbarButtonUtils.js
packages/lib/services/commands/commandsToMarkdownTable.js
packages/lib/services/commands/focusEditorIfEditorCommand.js
@@ -1616,6 +1644,7 @@ packages/lib/services/synchronizer/Synchronizer.sharing.test.js
packages/lib/services/synchronizer/Synchronizer.tags.test.js
packages/lib/services/synchronizer/Synchronizer.tools.test.js
packages/lib/services/synchronizer/gui/useSyncTargetUpgrade.js
packages/lib/services/synchronizer/handleConflictAction.test.js
packages/lib/services/synchronizer/migrations/1.js
packages/lib/services/synchronizer/migrations/2.js
packages/lib/services/synchronizer/migrations/3.js
@@ -1750,8 +1779,10 @@ packages/renderer/MdToHtml/createEventHandlingAttrs.js
packages/renderer/MdToHtml/linkReplacement.test.js
packages/renderer/MdToHtml/linkReplacement.js
packages/renderer/MdToHtml/renderMedia.js
packages/renderer/MdToHtml/rules/abc.js
packages/renderer/MdToHtml/rules/checkbox.js
packages/renderer/MdToHtml/rules/code_inline.js
packages/renderer/MdToHtml/rules/externalEmbed.js
packages/renderer/MdToHtml/rules/fence.js
packages/renderer/MdToHtml/rules/fountain.js
packages/renderer/MdToHtml/rules/highlight_keywords.js
@@ -1787,6 +1818,7 @@ packages/tools/checkIgnoredFiles.js
packages/tools/checkLibPaths.test.js
packages/tools/checkLibPaths.js
packages/tools/convertThemesToCss.js
packages/tools/fuzzer/ActionRunner.js
packages/tools/fuzzer/ActionTracker.js
packages/tools/fuzzer/Client.js
packages/tools/fuzzer/ClientPool.js
@@ -1795,16 +1827,22 @@ packages/tools/fuzzer/constants.js
packages/tools/fuzzer/model/FolderRecord.js
packages/tools/fuzzer/sync-fuzzer.js
packages/tools/fuzzer/types.js
packages/tools/fuzzer/utils/ProgressBar.js
packages/tools/fuzzer/utils/SeededRandom.js
packages/tools/fuzzer/utils/diffSortedStringArrays.test.js
packages/tools/fuzzer/utils/diffSortedStringArrays.js
packages/tools/fuzzer/utils/getNumberProperty.js
packages/tools/fuzzer/utils/getProperty.js
packages/tools/fuzzer/utils/getStringProperty.js
packages/tools/fuzzer/utils/logDiffDebug.js
packages/tools/fuzzer/utils/openDebugSession.js
packages/tools/fuzzer/utils/randomString.js
packages/tools/fuzzer/utils/retryWithCount.js
packages/tools/generate-database-types.js
packages/tools/generate-images.js
packages/tools/git-changelog.test.js
packages/tools/git-changelog.js
packages/tools/licenses/buildReport.js
packages/tools/licenses/getLicenses.js
packages/tools/licenses/licenseChecker.js
packages/tools/licenses/licenseOverrides/fontAwesomeOverride/index.js

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@@ -1,4 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Mon, 22 Sep 2025 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate><item><title><![CDATA[What's new in Joplin 3.4]]></title><description><![CDATA[<p>Joplin 3.4 includes many bug fixes and improvements, with a focus on the mobile app.</p>
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Sun, 11 Jan 2026 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><item><title><![CDATA[What's new in Joplin 3.5]]></title><description><![CDATA[<h2>Improvements across desktop and mobile<a name="improvements-across-desktop-and-mobile" href="#improvements-across-desktop-and-mobile" class="heading-anchor">🔗</a></h2>
<h3>More stable and consistent Markdown editing<a name="more-stable-and-consistent-markdown-editing" href="#more-stable-and-consistent-markdown-editing" class="heading-anchor">🔗</a></h3>
<p>The Markdown editor has been refined to feel more stable and closer to the final rendered view. Headings in the editor now more closely match how they appear when viewing a note, reducing the visual jump between editing and reading. Layout issues have also been addressed so elements like rendered checkboxes and images no longer cause the editor to shift unexpectedly while typing.</p>
<p>The ABC music notation plugin appeared to be popular but had some limitations. With this new version, ABC is now part of the app, which means it can now work from published notes, and from the Rich Text editor!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260111-abc.png" alt="ABC music notation rendered directly in Joplin, showing a short musical phrase displayed from plain-text ABC syntax"></p>
<h3>Smoother switching between notes<a name="smoother-switching-between-notes" href="#smoother-switching-between-notes" class="heading-anchor">🔗</a></h3>
<p>Switching between notes is now less disruptive. Joplin restores cursor position and scroll location more reliably, making it easier to move back and forth between notes—especially when working with longer documents or comparing content—without losing your place.</p>
<h3>Case insensitive tags<a name="case-insensitive-tags" href="#case-insensitive-tags" class="heading-anchor">🔗</a></h3>
<p>Tags are now treated in a case-insensitive way, which helps prevent duplicate tags caused by differences in capitalisation, while still allowing mixed-case tag names. All this time we were hoping that @dpoulton <a href="https://discourse.joplinapp.org/t/tags-lower-case-only/4220/106">would just get used to lowercase tags</a>, but 5 years later it looks like it's not happening ;) So thank you @mrjo118 for implementing it!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260111-lowercase-tags.png" alt="Joplin tag list demonstrating case-insensitive tags, with mixed-case tag names merged into a single tag."></p>
<h3>More reliable syncing and sharing<a name="more-reliable-syncing-and-sharing" href="#more-reliable-syncing-and-sharing" class="heading-anchor">🔗</a></h3>
<p>Syncing and sharing have been made more robust in everyday use. Joplin now handles repeated syncs more efficiently, avoids unnecessary data usage, and is better at detecting and syncing all changes, particularly when using WebDAV and S3 sync targets.</p>
<p>Moreover filesystem synchronisation is now more reliable, in particular when used alongside tools like SyncThing on both mobile and desktop.</p>
<h3>Accessibility and readability improvements<a name="accessibility-and-readability-improvements" href="#accessibility-and-readability-improvements" class="heading-anchor">🔗</a></h3>
<p>Accessibility has seen further refinements in this release. Dark mode readability has been improved, common editor elements are clearer, and animations are reduced or disabled when system “reduce motion” settings are enabled, making the app more comfortable to use for a wider range of users. Keyboard navigation has also been improved on the desktop application.</p>
<h2>Desktop-specific improvements<a name="desktop-specific-improvements" href="#desktop-specific-improvements" class="heading-anchor">🔗</a></h2>
<h3>Easier profile management<a name="easier-profile-management" href="#easier-profile-management" class="heading-anchor">🔗</a></h3>
<p>Managing multiple profiles on desktop is now simpler thanks to a new, more user-friendly profile management interface. This removes the need to manually edit configuration files and makes switching between different setups easier and safer.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260111-profiles.png" alt="Desktop profile management screen in Joplin showing multiple profiles with options to rename or delete them."></p>
<h3>Significantly improved OneNote import<a name="significantly-improved-onenote-import" href="#significantly-improved-onenote-import" class="heading-anchor">🔗</a></h3>
<p>Importing content from OneNote is now more reliable and accurate. Support has been expanded to cover more OneNote file formats, and many edge cases have been addressed so imported notes more closely match their original structure and content. This makes migrating from OneNote to Joplin smoother and more trustworthy.</p>
<h3>Better tools for organising large note collections<a name="better-tools-for-organising-large-note-collections" href="#better-tools-for-organising-large-note-collections" class="heading-anchor">🔗</a></h3>
<p>Desktop users can now select multiple notebooks at once, making it easier to reorganise notebook structures, move groups of notes, or clean up larger collections without working notebook by notebook.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260111-multi-select.png" alt="Joplin desktop sidebar with several notebooks selected at the same time for bulk organisation."></p>
<h3>Polished editing experience on desktop<a name="polished-editing-experience-on-desktop" href="#polished-editing-experience-on-desktop" class="heading-anchor">🔗</a></h3>
<p>Both the Markdown and Rich Text editors have been further refined. Cursor behaviour is more predictable, visual consistency between editing and viewing has improved, and several layout and rendering issues have been fixed to reduce interruptions while writing.</p>
<h3>More reliable search and navigation<a name="more-reliable-search-and-navigation" href="#more-reliable-search-and-navigation" class="heading-anchor">🔗</a></h3>
<p>Search and navigation on desktop have been improved with fixes that ensure search results behave consistently and remain visible when moving between windows or views.</p>
<h3>Improved math support in WebClipper<a name="improved-math-support-in-webclipper" href="#improved-math-support-in-webclipper" class="heading-anchor">🔗</a></h3>
<p>The WebClipper is not forgotten in this release - clipping certain math formulas, in particular from Wikipedia but also other websites, has been improved. Additionally, certain scientific articles are now also better handled by the WebClipper.</p>
<h2>Mobile-specific improvements<a name="mobile-specific-improvements" href="#mobile-specific-improvements" class="heading-anchor">🔗</a></h2>
<h3>A more powerful Rich Text Editor on mobile<a name="a-more-powerful-rich-text-editor-on-mobile" href="#a-more-powerful-rich-text-editor-on-mobile" class="heading-anchor">🔗</a></h3>
<p>The mobile Rich Text Editor continues to improve, with new and expanded support for tables, code blocks, and other structured content. These changes make it easier to create and edit more complex notes directly on mobile devices.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260111-rte1.png" alt="Joplin mobile Rich Text Editor showing table editing controls and an embedded code block inside a note."></p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260111-rte2.png" alt="Mobile code block editor in Joplin with a Python code snippet displayed in an editable dialog."></p>
<h3>Easier tag management on mobile<a name="easier-tag-management-on-mobile" href="#easier-tag-management-on-mobile" class="heading-anchor">🔗</a></h3>
<p>Managing tags on mobile is now more practical. You can rename and delete tags directly from the app, and searching through tags is easier, helping keep large tag lists organised over time.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20260111-mobile-tags.png" alt="Joplin mobile tag management screen showing a tag options menu with rename and delete actions."></p>
<h3>Improved stability and usability on mobile devices<a name="improved-stability-and-usability-on-mobile-devices" href="#improved-stability-and-usability-on-mobile-devices" class="heading-anchor">🔗</a></h3>
<p>Several fixes improve overall stability and usability on mobile, particularly on smaller screens. Issues causing UI elements to appear off-screen have been addressed, and the app behaves more consistently in situations that previously caused hangs or visual glitches.</p>
<h2>Bug fixes and security fixes across platforms<a name="bug-fixes-and-security-fixes-across-platforms" href="#bug-fixes-and-security-fixes-across-platforms" class="heading-anchor">🔗</a></h2>
<h3>A large number of stability, correctness and security fixes<a name="a-large-number-of-stability-correctness-and-security-fixes" href="#a-large-number-of-stability-correctness-and-security-fixes" class="heading-anchor">🔗</a></h3>
<p>Joplin 3.5 includes about 114 bug fixes across desktop and mobile, addressing issues in editing, syncing, importing, rendering, and general stability. Many fixes target edge cases that could lead to crashes, inconsistent behaviour, or rare data loss scenarios. Moreover, this version includes several vulnerability fixes to make the applications more secure.</p>
]]></description><link>https://joplinapp.org/news/20260111-release-3-5</link><guid isPermaLink="false">20260111-release-3-5</guid><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[What's new in Joplin 3.4]]></title><description><![CDATA[<p>Joplin 3.4 includes many bug fixes and improvements, with a focus on the mobile app.</p>
<h2>Mobile<a name="mobile" href="#mobile" class="heading-anchor">🔗</a></h2>
<h3>Rich Text Editor<a name="rich-text-editor" href="#rich-text-editor" class="heading-anchor">🔗</a></h3>
<p>The mobile app now includes a beta <a href="https://joplinapp.org/help/apps/rich_text_editor">Rich Text Editor</a>! The new editor renders formatting/math/images within the editor:</p>
@@ -481,42 +524,4 @@ sys 0m38.013s</p>
<p>This is a bit of an extra constraint but it is hard to avoid. Contributor License Agreements are very common for GPL or AGPL projects. For example Apache, Canonical or Python all require their contributors to sign a CLA.</p>
<h2>Questions?<a name="questions" href="#questions" class="heading-anchor">🔗</a></h2>
<p>If you have any questions please let us know. Overall we believe this is a positive improvements for Joplin as it means any work derives from it will also benefit the project.</p>
]]></description><link>https://joplinapp.org/news/20221221-agpl</link><guid isPermaLink="false">20221221-agpl</guid><pubDate>Wed, 21 Dec 2022 00:00:00 GMT</pubDate><twitter-text>Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0)</twitter-text></item><item><title><![CDATA[What's new in Joplin 2.9]]></title><description><![CDATA[<h2>Proxy support<a name="proxy-support" href="#proxy-support" class="heading-anchor">🔗</a></h2>
<p>Both the desktop and mobile application now support proxies thanks to the work of Jason Williams. This will allow you to use the apps in particular when you are behind a company proxy.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20221216-proxy-support.png" alt=""></p>
<h2>New PDF viewer<a name="new-pdf-viewer" href="#new-pdf-viewer" class="heading-anchor">🔗</a></h2>
<p>The desktop application now features a new PDF viewer thanks to the work of Asrient during GSoC.</p>
<p>The main advantage for now is that this viewer preserves the last PDF page that was read. In the next version, the viewer will also include a way to annotate PDF files.</p>
<h2>Multi-language spell checking<a name="multi-language-spell-checking" href="#multi-language-spell-checking" class="heading-anchor">🔗</a></h2>
<p>The desktop app include a multi-language spell checking features, which allows you, for example, to spell-check notes in your native language and in English.</p>
<h2>New mobile text editor<a name="new-mobile-text-editor" href="#new-mobile-text-editor" class="heading-anchor">🔗</a></h2>
<p>Writing formatted notes on mobile has always been cumbersome due to the need to enter special format characters like <code>*</code> or <code>[</code>, etc.</p>
<p>Thanks to the work of Henry Heino during GSoC, writing notes on the go is now easier thanks to an improved Markdown editor.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20221216-mobile-beta-editor.png" alt=""></p>
<p>The most visible feature is the addition of a toolbar, which helps input those special characters, like on desktop.</p>
<p>Moreover Henry made a lot of subtle but useful improvements to the editor, for example to improve the note appearance, to improve list continuation, etc. Search within a note is now also supported as well as spell-checking.</p>
<p>At a more technical level, Henry also added many test units to ensure that the editor remains robust and reliable.</p>
<p>To enable the feature, go to the configuration screen and selected &quot;Opt-in to the editor beta&quot;. It is already very stable so we will probably promote it to be the main editor from the next version.</p>
<h2>Improved alignment of notebook icons<a name="improved-alignment-of-notebook-icons" href="#improved-alignment-of-notebook-icons" class="heading-anchor">🔗</a></h2>
<p>Previously, when you would assign an icon to a notebook, it would shift the title to the right, but notebook without an icon would not. It means that notebooks with and without an icon would not be vertically aligned.</p>
<p>To tidy things up, this new version adds a default icons to notebooks without an explicitly assigned icon. This result in the notebook titles being correctly vertically aligned.</p>
<p>Note that this feature is only enabled if you use custom icons - otherwise it will simply display the notebook titles without any default icons, as before.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20221216-notebook-icons.png" alt=""></p>
<h2>Improved handling of file attachments<a name="improved-handling-of-file-attachments" href="#improved-handling-of-file-attachments" class="heading-anchor">🔗</a></h2>
<p>Self Not Found made a number of small but useful improvements to attachment handling, including increasing the maximum size to 200MB, adding support for attaching multiple files, and fixing issues with synchronising attachments via proxy.</p>
<h2>Fixed filesystem sync on mobile<a name="fixed-filesystem-sync-on-mobile" href="#fixed-filesystem-sync-on-mobile" class="heading-anchor">🔗</a></h2>
<p>This was a long and complex change due to the need to support new Android APIs but hopefully that should now be working again, thanks to the work of jd1378.</p>
<p>So you can now sync again your notes with Syncthing and other file-based synchronisation systems.</p>
<h2>And more...<a name="and-more" href="#and-more" class="heading-anchor">🔗</a></h2>
<p>In total this new desktop version includes 36 improvements, bug fixes, and security fixes.</p>
<p>As always, a lot of work went into the Android and iOS app too, which include 37 improvements, bug fixes, and security fixes.</p>
<p>See here for the changelogs:</p>
<ul>
<li><a href="https://joplinapp.org/help/about/changelog/desktop">Desktop app changelog</a></li>
<li><a href="https://joplinapp.org/help/about/changelog/android/">Android app changelog</a></li>
</ul>
<h2>About the Android version<a name="about-the-android-version" href="#about-the-android-version" class="heading-anchor">🔗</a></h2>
<p>Unfortunately we cannot publish the Android version because it is based on a framework version that Google does not accept. To upgrade the app a lot of changes are needed and another round of pre-releases, and therefore there will not be a 2.9 version for Google Play. You may however download the official APK directly from there: <a href="https://github.com/laurent22/joplin-android/releases/tag/android-v2.9.8">Android 2.9 Official Release</a></p>
<p>This is the reality of app stores in general - small developers being imposed never ending new requirements by all-powerful companies, and by the time a version is finally ready we can't even publish it because yet more requirements are in place.</p>
<p>For the record the current 2.9 app works perfectly fine. It targets Android 11, which is only 2 years old and is still supported (and installed on millions of phones). Google requires us to target Android 12 which only came out last year.</p>
]]></description><link>https://joplinapp.org/news/20221216-release-2-9</link><guid isPermaLink="false">20221216-release-2-9</guid><pubDate>Fri, 16 Dec 2022 00:00:00 GMT</pubDate><twitter-text>What&apos;s new in Joplin 2.9</twitter-text></item></channel></rss>
]]></description><link>https://joplinapp.org/news/20221221-agpl</link><guid isPermaLink="false">20221221-agpl</guid><pubDate>Wed, 21 Dec 2022 00:00:00 GMT</pubDate><twitter-text>Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0)</twitter-text></item></channel></rss>

View File

@@ -2,7 +2,7 @@
# Build stage
# =============================================================================
FROM node:18 AS builder
FROM node:24 AS builder
RUN apt-get update \
&& apt-get install -y \
@@ -58,7 +58,7 @@ RUN --mount=type=cache,target=/build/.yarn/cache --mount=type=cache,target=/buil
# from a smaller base image.
# =============================================================================
FROM node:18-slim
FROM node:24-slim
ARG user=joplin
RUN useradd --create-home --shell /bin/bash $user

View File

@@ -1,4 +1,4 @@
FROM node:18-bullseye
FROM node:24-bullseye
RUN apt-get update \
&& apt-get install -y \

View File

@@ -67,6 +67,45 @@ showHelp() {
fi
}
# Accepts two versions in symver (a.b.c).
# Echos -1 if the first version is less than the second,
# 0 if they're equal,
# 1 if the first version is greater than second.
compareVersions() {
V_MAJOR1=$(echo "$1"|cut -d. -f1)
V_MAJOR2=$(echo "$2"|cut -d. -f1)
if [[ $V_MAJOR1 -lt $V_MAJOR2 ]] ; then
echo -1
return
elif [[ $V_MAJOR1 -gt $V_MAJOR2 ]] ; then
echo 1
return
fi
V_MINOR1=$(echo "$1"|cut -d. -f2)
V_MINOR2=$(echo "$2"|cut -d. -f2)
if [[ $V_MINOR1 -lt $V_MINOR2 ]] ; then
echo -1
return
elif [[ $V_MINOR1 -gt $V_MINOR2 ]] ; then
echo 1
return
fi
V_PATCH1=$(echo "$1"|cut -d. -f3)
V_PATCH2=$(echo "$2"|cut -d. -f3)
if [[ $V_PATCH1 -lt $V_PATCH2 ]] ; then
echo -1
elif [[ $V_PATCH1 -gt $V_PATCH2 ]] ; then
echo 1
else
echo 0
fi
}
#-----------------------------------------------------
# Setup Download Helper: DL
#-----------------------------------------------------
@@ -159,12 +198,21 @@ else
fi
# Check if it's in the latest version
if [[ -e "${INSTALL_DIR}/VERSION" ]] && [[ $(< "${INSTALL_DIR}/VERSION") == "${RELEASE_VERSION}" ]]; then
print "${COLOR_GREEN}You already have the latest version${COLOR_RESET} ${RELEASE_VERSION} ${COLOR_GREEN}installed.${COLOR_RESET}"
([[ "$FORCE" == true ]] && print "Forcing installation...") || exit 0
if [[ -e "${INSTALL_DIR}/VERSION" ]]; then
CURRENT_VERSION=$(< "${INSTALL_DIR}/VERSION")
VERSION_COMPARISON=$(compareVersions "$CURRENT_VERSION" "$RELEASE_VERSION")
if [[ "$VERSION_COMPARISON" == "0" ]]; then
print "${COLOR_GREEN}You already have the latest version${COLOR_RESET} ${RELEASE_VERSION} ${COLOR_GREEN}installed.${COLOR_RESET}"
([[ "$FORCE" == true ]] && print "Forcing installation...") || exit 0
elif [[ "$VERSION_COMPARISON" == "1" ]]; then
print "${COLOR_YELLOW}You have version ${CURRENT_VERSION} installed, which is newer than the latest published version ${RELEASE_VERSION}.${COLOR_RESET}"
print "${COLOR_YELLOW}Skipping installation to avoid downgrade.${COLOR_RESET}"
else
print "The latest version is ${RELEASE_VERSION}, but you have ${CURRENT_VERSION} installed."
fi
else
[[ -e "${INSTALL_DIR}/VERSION" ]] && CURRENT_VERSION=$(< "${INSTALL_DIR}/VERSION")
print "The latest version is ${RELEASE_VERSION}, but you have ${CURRENT_VERSION:-no version} installed."
print "The latest version is ${RELEASE_VERSION}, but you have no version installed."
fi
# Check if it's an update or a new install
@@ -236,7 +284,7 @@ if command -v lsb_release &> /dev/null; then
# without writing the AppImage to a non-user-writable location (without invalidating other security
# controls). See https://discourse.joplinapp.org/t/possible-future-requirement-for-no-sandbox-flag-for-ubuntu-23-10/.
HAS_USERNS_RESTRICTIONS=false
if [[ "$DISTVER" =~ ^Ubuntu && $DISTMAJOR -ge 23 ]]; then
if [[ "$DISTVER" =~ ^(Ubuntu|Tuxedo) && $DISTMAJOR -ge 23 ]]; then
HAS_USERNS_RESTRICTIONS=true
fi
@@ -258,6 +306,15 @@ fi
if [[ $DESKTOP =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*x-cinnamon.*|.*deepin.*|.*pantheon.*|.*lxde.*|.*i3.*|.*sway.* ]] || [[ `command -v update-desktop-database` ]]; then
DATA_HOME=${XDG_DATA_HOME:-~/.local/share}
DESKTOP_FILE_LOCATION="$DATA_HOME/applications"
# Only later versions of Joplin default to Wayland
IS_WAYLAND_BY_DEFAULT=$(compareVersions "$RELEASE_VERSION" "3.5.6")
# Joplin has a different startup WM class on Wayland and X11:
STARTUP_WM_CLASS=Joplin
if [[ $XDG_SESSION_TYPE != "x11" && $IS_WAYLAND_BY_DEFAULT == "1" ]]; then
STARTUP_WM_CLASS=@joplin/app-desktop
fi
# Only delete the desktop file if it will be replaced
rm -f "$DESKTOP_FILE_LOCATION/appimagekit-joplin.desktop"
@@ -272,7 +329,9 @@ Name=Joplin
Comment=Joplin for Desktop
Exec=env APPIMAGELAUNCHER_DISABLE=TRUE "${INSTALL_DIR}/Joplin.AppImage" ${SANDBOXPARAM} %u
Icon=joplin
StartupWMClass=Joplin
# This will be different between Wayland and X11. On Wayland, the startup
# WM class is "@joplin/app-desktop". On X11, it's "Joplin".
StartupWMClass=${STARTUP_WM_CLASS}
Type=Application
Categories=Office;
MimeType=x-scheme-handler/joplin;

View File

@@ -1,5 +1,5 @@
<!-- DONATELINKS -->
[![Donate using PayPal](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-PayPal-green.svg)](https://www.paypal.com/donate/?business=E8JMYD2LQ8MMA&no_recurring=0&item_name=I+rely+on+donations+to+maintain+and+improve+the+Joplin+open+source+project.+Thank+you+for+your+help+-+it+makes+a+difference%21&currency_code=EUR) [![Sponsor on GitHub](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/GitHub-Badge.svg)](https://github.com/sponsors/laurent22/) [![Become a patron](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Patreon-Badge.svg)](https://www.patreon.com/joplin) [![Donate using IBAN](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-IBAN.svg)](https://joplinapp.org/donate/#donations)
[![Donate using PayPal](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-PayPal-green.svg)](https://www.paypal.com/donate/?hosted_button_id=WQCERTSSLCC7U) [![Sponsor on GitHub](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/GitHub-Badge.svg)](https://github.com/sponsors/laurent22/) [![Become a patron](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Patreon-Badge.svg)](https://www.patreon.com/joplin) [![Donate using IBAN](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-IBAN.svg)](https://joplinapp.org/donate/#donations)
<!-- DONATELINKS -->
<img width="64" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/LinuxIcons/256x256.png" align="left" style="margin-right:15px"/>
@@ -31,7 +31,7 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
# Sponsors
<!-- SPONSORS-ORG -->
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a> <a href="https://sorted.travel/?utm_source=joplinapp"><img title="Sorted Travel" width="256" src="https://joplinapp.org/images/sponsors/SortedTravel.png"/></a> <a href="https://celebian.com"><img title="Celebian" width="256" src="https://joplinapp.org/images/sponsors/Celebian.png"/></a> <a href="https://bestkru.com"><img title="BestKru" width="256" src="https://joplinapp.org/images/sponsors/BestKru.png"/></a> <a href="https://www.socialfollowers.uk/buy-tiktok-followers/"><img title="Social Followers" width="256" src="https://joplinapp.org/images/sponsors/SocialFollowers.png"/></a> <a href="https://stormlikes.com/"><img title="Stormlikes" width="256" src="https://joplinapp.org/images/sponsors/Stormlikes.png"/></a> <a href="https://route4me.com"><img title="Route4Me" width="256" src="https://joplinapp.org/images/sponsors/Route4Me.png"/></a> <a href="https://topagency.webflow.io"><img title="WebDesignAgency" width="256" src="https://joplinapp.org/images/sponsors/WebDesignAgency.png" alt="topagency"/></a> <a href="https://www.slotozilla.com/nz/no-deposit-bonus"><img title="casino without making any upfront cost" width="256" src="https://joplinapp.org/images/sponsors/Slotozilla.png" alt="casino without making any upfront cost"/></a> <a href="https://writepaper.com/"><img title="best service to write my paper for me" width="256" src="https://joplinapp.org/images/sponsors/WritePaper.png" alt="best service to write my paper for me"/></a> <a href="https://paperwriter.com/"><img title="high-quality paper writing service PaperWriter" width="256" src="https://joplinapp.org/images/sponsors/PaperWriter.png" alt="high-quality paper writing service PaperWriter"/></a> <a href="https://www.bestetf.net/"><img title="BestETF" width="256" src="https://joplinapp.org/images/sponsors/BestEtf.png" alt="BestETF"/></a> <a href="https://freespinny.io/free-spins-no-deposit/"><img title="Freespinny.io Free Spins Bonus site" width="256" src="https://joplinapp.org/images/sponsors/Freespinny.png" alt="Freespinny.io Free Spins Bonus site"/></a> <a href="https://essayshark.com"><img title="EssayShark - essay writers for hire" width="256" src="https://joplinapp.org/images/sponsors/EssayShark.png" alt="EssayShark - essay writers for hire"/></a> <a href="https://pokieslab1.com/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/PokiesLab.png" alt="Australian Real Money Pokies"/></a> <a href="https://pokiesman1.net/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/Pokiesman.png" alt="Australian Real Money Pokies"/></a> <a href="https://domyessay.com"><img title="Essay writers DoMyEssay are dedicated to providing top-notch, custom-written papers that meet your academic requirements" width="256" src="https://joplinapp.org/images/sponsors/DoMyEssay.png" alt="DoMyEssay"/></a> <a href="https://essaypro.com/"><img title="best essay writing service" width="256" src="https://joplinapp.org/images/sponsors/EssayPro.png" alt="best essay writing service"/></a> <a href="https://socialkings.online"><img title="Boost your reach and buy real followers" width="256" src="https://joplinapp.org/images/sponsors/SocialKings.png" alt="Boost your reach and buy real followers"/></a> <a href="https://uk.notgamstop.com/bonuses/free-spins-no-deposit-no-gamstop/"><img title="free spins no deposit at NotGamstop" width="256" src="https://joplinapp.org/images/sponsors/NotGamStop.jpg" alt="free spins no deposit at NotGamstop"/></a> <a href="https://www.writemyessay.com/"><img title="writing service for students WriteMyEssay" width="256" src="https://joplinapp.org/images/sponsors/WriteMyEssay.png" alt="writing service for students WriteMyEssay"/></a>
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a> <a href="https://sorted.travel/?utm_source=joplinapp"><img title="Sorted Travel" width="256" src="https://joplinapp.org/images/sponsors/SortedTravel.png"/></a> <a href="https://celebian.com"><img title="Celebian" width="256" src="https://joplinapp.org/images/sponsors/Celebian.png"/></a> <a href="https://bestkru.com"><img title="BestKru" width="256" src="https://joplinapp.org/images/sponsors/BestKru.png"/></a> <a href="https://www.socialfollowers.uk/buy-tiktok-followers/"><img title="Social Followers" width="256" src="https://joplinapp.org/images/sponsors/SocialFollowers.png"/></a> <a href="https://stormlikes.com/"><img title="Stormlikes" width="256" src="https://joplinapp.org/images/sponsors/Stormlikes.png"/></a> <a href="https://route4me.com"><img title="Route4Me" width="256" src="https://joplinapp.org/images/sponsors/Route4Me.png"/></a> <a href="https://topagency.webflow.io"><img title="WebDesignAgency" width="256" src="https://joplinapp.org/images/sponsors/WebDesignAgency.png" alt="topagency"/></a> <a href="https://www.slotozilla.com/nz/no-deposit-bonus"><img title="casino without making any upfront cost" width="256" src="https://joplinapp.org/images/sponsors/Slotozilla.png" alt="casino without making any upfront cost"/></a> <a href="https://writepaper.com/"><img title="best service to write my paper for me" width="256" src="https://joplinapp.org/images/sponsors/WritePaper.png" alt="best service to write my paper for me"/></a> <a href="https://paperwriter.com/"><img title="high-quality paper writing service PaperWriter" width="256" src="https://joplinapp.org/images/sponsors/PaperWriter.png" alt="high-quality paper writing service PaperWriter"/></a> <a href="https://www.bestetf.net/"><img title="BestETF" width="256" src="https://joplinapp.org/images/sponsors/BestEtf.png" alt="BestETF"/></a> <a href="https://freespinny.io/free-spins-no-deposit/"><img title="Freespinny.io Free Spins Bonus site" width="256" src="https://joplinapp.org/images/sponsors/Freespinny.png" alt="Freespinny.io Free Spins Bonus site"/></a> <a href="https://essayshark.com"><img title="EssayShark - essay writers for hire" width="256" src="https://joplinapp.org/images/sponsors/EssayShark.png" alt="EssayShark - essay writers for hire"/></a> <a href="https://pokieslab1.com/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/PokiesLab.png" alt="Australian Real Money Pokies"/></a> <a href="https://pokiesman1.net/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/Pokiesman.png" alt="Australian Real Money Pokies"/></a> <a href="https://domyessay.com"><img title="Essay writers DoMyEssay are dedicated to providing top-notch, custom-written papers that meet your academic requirements" width="256" src="https://joplinapp.org/images/sponsors/DoMyEssay.png" alt="DoMyEssay"/></a> <a href="https://essaypro.com/"><img title="best essay writing service" width="256" src="https://joplinapp.org/images/sponsors/EssayPro.png" alt="best essay writing service"/></a> <a href="https://socialkings.online"><img title="Boost your reach and buy real followers" width="256" src="https://joplinapp.org/images/sponsors/SocialKings.png" alt="Boost your reach and buy real followers"/></a> <a href="https://uk.notgamstop.com/bonuses/free-spins-no-deposit-no-gamstop/"><img title="free spins no deposit at NotGamstop" width="256" src="https://joplinapp.org/images/sponsors/NotGamStop.jpg" alt="free spins no deposit at NotGamstop"/></a> <a href="https://www.writemyessay.com/"><img title="writing service for students WriteMyEssay" width="256" src="https://joplinapp.org/images/sponsors/WriteMyEssay.png" alt="writing service for students WriteMyEssay"/></a> <a href="https://essayservice.com/"><img title="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines" width="256" src="https://joplinapp.org/images/sponsors/EssayService.png" alt="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines"/></a>
<!-- SPONSORS-ORG -->
* * *

View File

@@ -9,20 +9,15 @@
"vips.dev": {
"platforms": ["aarch64-darwin"],
},
"nodejs": "23.11.0",
"nodejs": "24.5.0",
"pkg-config": "latest",
"darwin.apple_sdk.frameworks.Foundation": { // satisfies missing CoreText/CoreText.h
// https://github.com/NixOS/nixpkgs/blob/master/pkgs/os-specific/darwin/apple-sdk/default.nix
"version": "",
"platforms": ["aarch64-darwin", "x86_64-darwin"],
},
"python": "3.13.3",
"bat": "latest",
"electron": {
"version": "latest",
"excluded_platforms": ["aarch64-darwin", "x86_64-darwin"],
},
"git": "2.48.1",
"git": "2.50.1",
},
"shell": {
"init_hook": [

View File

@@ -19,7 +19,7 @@
services:
postgresql-master:
image: 'bitnamilegacy/postgresql:17.4.0'
image: 'bitnamilegacy/postgresql:17.6.0'
ports:
- '5432:5432'
environment:
@@ -36,7 +36,7 @@ services:
- POSTGRESQL_EXTRA_FLAGS=-c work_mem=100000 -c log_statement=all
postgresql-slave:
image: 'bitnamilegacy/postgresql:17.4.0'
image: 'bitnamilegacy/postgresql:17.6.0'
ports:
- '5433:5432'
depends_on:

6
jest.config.base.js Normal file
View File

@@ -0,0 +1,6 @@
// This is the base Jest configuration - all
// jest.config.js files should inherit from it.
module.exports = {
watchman: false,
};

View File

@@ -16,6 +16,7 @@
"./packages/app-cli/**/*.mo": true,
"./packages/app-cli/**/build/": true,
"./packages/app-cli/**/config.json": true,
"**/.watchman-cookie-*": true,
"./packages/app-cli/**/linkToLocal.sh": true,
"./packages/app-cli/**/node_modules/": true,
"./packages/app-cli/**/out.txt": true,

View File

@@ -76,17 +76,17 @@
"cspell": "5.21.2",
"eslint": "8.57.1",
"eslint-interactive": "10.8.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-jest": "27.9.0",
"eslint-plugin-promise": "6.6.0",
"eslint-plugin-react": "7.37.5",
"execa": "5.1.1",
"fs-extra": "11.2.0",
"fs-extra": "11.3.2",
"glob": "11.0.3",
"gulp": "4.0.2",
"husky": "9.1.7",
"lerna": "3.22.1",
"lint-staged": "15.5.2",
"lint-staged": "16.1.6",
"madge": "8.0.0",
"npm-package-json-lint": "8.0.0",
"typescript": "5.8.3"
@@ -95,7 +95,7 @@
"@types/fs-extra": "11.0.4",
"eslint-plugin-github": "4.10.2",
"http-server": "14.1.1",
"node-gyp": "11.2.0",
"node-gyp": "11.4.2",
"nodemon": "3.1.10"
},
"packageManager": "yarn@4.9.2",

View File

@@ -0,0 +1,270 @@
import * as fs from 'fs-extra';
import Logger, { TargetType } from '@joplin/utils/Logger';
import { dirname } from '@joplin/lib/path-utils';
const { DatabaseDriverNode } = require('@joplin/lib/database-driver-node.js');
import JoplinDatabase from '@joplin/lib/JoplinDatabase';
import BaseModel from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
import Note from '@joplin/lib/models/Note';
import Setting from '@joplin/lib/models/Setting';
import { node } from 'execa';
import { splitCommandString } from '@joplin/utils';
const nodeSqlite = require('sqlite3');
const { loadKeychainServiceAndSettings } = require('@joplin/lib/services/SettingUtils');
const { default: shimInitCli } = require('./utils/shimInitCli');
const baseDir = `${dirname(__dirname)}/tests/cli-integration`;
const joplinAppPath = `${__dirname}/main.js`;
shimInitCli({ nodeSqlite, appVersion: () => require('../package.json').version, keytar: null });
require('@joplin/lib/testing/test-utils');
interface Client {
id: number;
profileDir: string;
}
function createClient(id: number): Client {
return {
id: id,
profileDir: `${baseDir}/client${id}`,
};
}
async function execCommand(client: Client, command: string) {
const result = await node(
joplinAppPath,
['--update-geolocation-disabled', '--env', 'dev', '--profile', client.profileDir, ...splitCommandString(command)],
);
if (result.exitCode !== 0) {
throw new Error(`Command failed: ${command}:\nstderr: ${result.stderr}\nstdout: ${result.stdout}`);
}
return result.stdout;
}
async function clearDatabase(db: JoplinDatabase) {
await db.transactionExecBatch(['DELETE FROM folders', 'DELETE FROM notes', 'DELETE FROM tags', 'DELETE FROM note_tags', 'DELETE FROM resources', 'DELETE FROM deleted_items']);
}
describe('cli-integration-tests', () => {
let client: Client;
let db: JoplinDatabase;
beforeAll(async () => {
await fs.remove(baseDir);
await fs.mkdir(baseDir);
client = createClient(1);
// Initialize the database by running a client command and exiting.
await execCommand(client, 'version');
const dbLogger = new Logger();
dbLogger.addTarget(TargetType.Console);
dbLogger.setLevel(Logger.LEVEL_WARN);
db = new JoplinDatabase(new DatabaseDriverNode());
db.setLogger(dbLogger);
await db.open({ name: `${client.profileDir}/database.sqlite` });
BaseModel.setDb(db);
Setting.setConstant('rootProfileDir', client.profileDir);
Setting.setConstant('profileDir', client.profileDir);
await loadKeychainServiceAndSettings([]);
});
beforeEach(async () => {
await clearDatabase(db);
});
it.each([
'version',
'help',
])('should run command %j without crashing', async (command) => {
await execCommand(client, command);
});
it('should support the \'ls\' command', async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote note1');
await execCommand(client, 'mknote note2');
const r = await execCommand(client, 'ls');
expect(r.indexOf('note1') >= 0).toBe(true);
expect(r.indexOf('note2') >= 0).toBe(true);
});
it('should support the \'mv\' command', async () => {
await execCommand(client, 'mkbook nb2');
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote n1');
await execCommand(client, 'mv n1 nb2');
const f1 = await Folder.loadByTitle('nb1');
const f2 = await Folder.loadByTitle('nb2');
let notes1 = await Note.previews(f1.id);
let notes2 = await Note.previews(f2.id);
expect(notes1.length).toBe(0);
expect(notes2.length).toBe(1);
await execCommand(client, 'mknote note1');
await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3');
await execCommand(client, 'mknote blabla');
notes1 = await Note.previews(f1.id);
notes2 = await Note.previews(f2.id);
expect(notes1.length).toBe(4);
expect(notes2.length).toBe(1);
await execCommand(client, 'mv \'note*\' nb2');
notes2 = await Note.previews(f2.id);
notes1 = await Note.previews(f1.id);
expect(notes1.length).toBe(1);
expect(notes2.length).toBe(4);
});
it('should support the \'use\' command', async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mkbook nb2');
await execCommand(client, 'mknote n1');
await execCommand(client, 'mknote n2');
const f1 = await Folder.loadByTitle('nb1');
const f2 = await Folder.loadByTitle('nb2');
let notes1 = await Note.previews(f1.id);
let notes2 = await Note.previews(f2.id);
expect(notes1.length).toBe(0);
expect(notes2.length).toBe(2);
await execCommand(client, 'use nb1');
await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3');
notes1 = await Note.previews(f1.id);
notes2 = await Note.previews(f2.id);
expect(notes1.length).toBe(2);
});
it('should support creating and removing folders', async () => {
await execCommand(client, 'mkbook nb1');
let folders = await Folder.all();
expect(folders.length).toBe(1);
expect(folders[0].title).toBe('nb1');
await execCommand(client, 'mkbook nb1');
folders = await Folder.all();
expect(folders.length).toBe(2);
expect(folders[0].title).toBe('nb1');
expect(folders[1].title).toBe('nb1');
await execCommand(client, 'rmbook -p -f nb1');
folders = await Folder.all();
expect(folders.length).toBe(1);
await execCommand(client, 'rmbook -p -f nb1');
folders = await Folder.all();
expect(folders.length).toBe(0);
});
it('should support creating and removing notes', async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote n1');
let notes = await Note.all();
expect(notes.length).toBe(1);
expect(notes[0].title).toBe('n1');
await execCommand(client, 'rmnote -p -f n1');
notes = await Note.all();
expect(notes.length).toBe(0);
await execCommand(client, 'mknote n1');
await execCommand(client, 'mknote n2');
notes = await Note.all();
expect(notes.length).toBe(2);
// Should fail to delete a non-existent note
let failed = false;
try {
await execCommand(client, 'rmnote -f \'blabla*\'');
} catch (error) {
failed = true;
}
expect(failed).toBe(true);
notes = await Note.all();
expect(notes.length).toBe(2);
await execCommand(client, 'rmnote -f -p \'n*\'');
notes = await Note.all();
expect(notes.length).toBe(0);
});
it('should support listing the contents of notes', async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote mynote');
const folder = await Folder.loadByTitle('nb1');
const note = await Note.loadFolderNoteByField(folder.id, 'title', 'mynote');
let r = await execCommand(client, 'cat mynote');
expect(r).toContain('mynote');
expect(r).not.toContain(note.id);
r = await execCommand(client, 'cat -v mynote');
expect(r).toContain(note.id);
});
it('should support changing settings with config', async () => {
await execCommand(client, 'config editor vim');
await Setting.reset();
await Setting.load();
expect(Setting.value('editor')).toBe('vim');
await execCommand(client, 'config editor subl');
await Setting.reset();
await Setting.load();
expect(Setting.value('editor')).toBe('subl');
const r = await execCommand(client, 'config');
expect(r.indexOf('editor') >= 0).toBe(true);
expect(r.indexOf('subl') >= 0).toBe(true);
});
it('should support copying folders with cp', async () => {
await execCommand(client, 'mkbook nb2');
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote n1');
await execCommand(client, 'cp n1');
const f1 = await Folder.loadByTitle('nb1');
const f2 = await Folder.loadByTitle('nb2');
let notes = await Note.previews(f1.id);
expect(notes.length).toBe(2);
await execCommand(client, 'cp n1 nb2');
const notesF1 = await Note.previews(f1.id);
expect(notesF1.length).toBe(2);
notes = await Note.previews(f2.id);
expect(notes.length).toBe(1);
expect(notes[0].title).toBe(notesF1[0].title);
});
});

View File

@@ -1,300 +0,0 @@
'use strict';
/* eslint-disable no-console */
import * as fs from 'fs-extra';
import Logger, { TargetType } from '@joplin/utils/Logger';
import { dirname } from '@joplin/lib/path-utils';
const { DatabaseDriverNode } = require('@joplin/lib/database-driver-node.js');
import JoplinDatabase from '@joplin/lib/JoplinDatabase';
import BaseModel from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
import Note from '@joplin/lib/models/Note';
import Setting from '@joplin/lib/models/Setting';
const { sprintf } = require('sprintf-js');
const exec = require('child_process').exec;
const nodeSqlite = require('sqlite3');
const { loadKeychainServiceAndSettings } = require('@joplin/lib/services/SettingUtils');
const { default: shimInitCli } = require('./utils/shimInitCli');
const baseDir = `${dirname(__dirname)}/tests/cli-integration`;
const joplinAppPath = `${__dirname}/main.js`;
shimInitCli({ nodeSqlite, appVersion: () => require('../package.json').version, keytar: null });
require('@joplin/lib/testing/test-utils');
const logger = new Logger();
logger.addTarget(TargetType.Console);
logger.setLevel(Logger.LEVEL_ERROR);
const dbLogger = new Logger();
dbLogger.addTarget(TargetType.Console);
dbLogger.setLevel(Logger.LEVEL_INFO);
const db = new JoplinDatabase(new DatabaseDriverNode());
db.setLogger(dbLogger);
interface Client {
id: number;
profileDir: string;
}
function createClient(id: number): Client {
return {
id: id,
profileDir: `${baseDir}/client${id}`,
};
}
const client = createClient(1);
function execCommand(client: Client, command: string) {
const exePath = `node ${joplinAppPath}`;
const cmd = `${exePath} --update-geolocation-disabled --env dev --profile ${client.profileDir} ${command}`;
logger.info(`${client.id}: ${command}`);
return new Promise<string>((resolve, reject) => {
exec(cmd, (error: string, stdout: string, stderr: string) => {
if (error) {
logger.error(stderr);
reject(error);
} else {
resolve(stdout.trim());
}
});
});
}
function assertTrue(v: unknown) {
if (!v) throw new Error(sprintf('Expected "true", got "%s"."', v));
process.stdout.write('.');
}
function assertFalse(v: unknown) {
if (v) throw new Error(sprintf('Expected "false", got "%s"."', v));
process.stdout.write('.');
}
function assertEquals(expected: unknown, real: unknown) {
if (expected !== real) throw new Error(sprintf('Expecting "%s", got "%s"', expected, real));
process.stdout.write('.');
}
async function clearDatabase() {
await db.transactionExecBatch(['DELETE FROM folders', 'DELETE FROM notes', 'DELETE FROM tags', 'DELETE FROM note_tags', 'DELETE FROM resources', 'DELETE FROM deleted_items']);
}
const testUnits: Record<string, ()=> Promise<void>> = {};
testUnits.testFolders = async () => {
await execCommand(client, 'mkbook nb1');
let folders = await Folder.all();
assertEquals(1, folders.length);
assertEquals('nb1', folders[0].title);
await execCommand(client, 'mkbook nb1');
folders = await Folder.all();
assertEquals(2, folders.length);
assertEquals('nb1', folders[0].title);
assertEquals('nb1', folders[1].title);
await execCommand(client, 'rmbook -p -f nb1');
folders = await Folder.all();
assertEquals(1, folders.length);
await execCommand(client, 'rmbook -p -f nb1');
folders = await Folder.all();
assertEquals(0, folders.length);
};
testUnits.testNotes = async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote n1');
let notes = await Note.all();
assertEquals(1, notes.length);
assertEquals('n1', notes[0].title);
await execCommand(client, 'rmnote -p -f n1');
notes = await Note.all();
assertEquals(0, notes.length);
await execCommand(client, 'mknote n1');
await execCommand(client, 'mknote n2');
notes = await Note.all();
assertEquals(2, notes.length);
// Should fail to delete a non-existent note
let failed = false;
try {
await execCommand(client, 'rmnote -f \'blabla*\'');
} catch (error) {
failed = true;
}
assertEquals(failed, true);
notes = await Note.all();
assertEquals(2, notes.length);
await execCommand(client, 'rmnote -f -p \'n*\'');
notes = await Note.all();
assertEquals(0, notes.length);
};
testUnits.testCat = async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote mynote');
const folder = await Folder.loadByTitle('nb1');
const note = await Note.loadFolderNoteByField(folder.id, 'title', 'mynote');
let r = await execCommand(client, 'cat mynote');
assertTrue(r.indexOf('mynote') >= 0);
assertFalse(r.indexOf(note.id) >= 0);
r = await execCommand(client, 'cat -v mynote');
assertTrue(r.indexOf(note.id) >= 0);
};
testUnits.testConfig = async () => {
await execCommand(client, 'config editor vim');
await Setting.reset();
await Setting.load();
assertEquals('vim', Setting.value('editor'));
await execCommand(client, 'config editor subl');
await Setting.reset();
await Setting.load();
assertEquals('subl', Setting.value('editor'));
const r = await execCommand(client, 'config');
assertTrue(r.indexOf('editor') >= 0);
assertTrue(r.indexOf('subl') >= 0);
};
testUnits.testCp = async () => {
await execCommand(client, 'mkbook nb2');
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote n1');
await execCommand(client, 'cp n1');
const f1 = await Folder.loadByTitle('nb1');
const f2 = await Folder.loadByTitle('nb2');
let notes = await Note.previews(f1.id);
assertEquals(2, notes.length);
await execCommand(client, 'cp n1 nb2');
const notesF1 = await Note.previews(f1.id);
assertEquals(2, notesF1.length);
notes = await Note.previews(f2.id);
assertEquals(1, notes.length);
assertEquals(notesF1[0].title, notes[0].title);
};
testUnits.testLs = async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote note1');
await execCommand(client, 'mknote note2');
const r = await execCommand(client, 'ls');
assertTrue(r.indexOf('note1') >= 0);
assertTrue(r.indexOf('note2') >= 0);
};
testUnits.testMv = async () => {
await execCommand(client, 'mkbook nb2');
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mknote n1');
await execCommand(client, 'mv n1 nb2');
const f1 = await Folder.loadByTitle('nb1');
const f2 = await Folder.loadByTitle('nb2');
let notes1 = await Note.previews(f1.id);
let notes2 = await Note.previews(f2.id);
assertEquals(0, notes1.length);
assertEquals(1, notes2.length);
await execCommand(client, 'mknote note1');
await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3');
await execCommand(client, 'mknote blabla');
notes1 = await Note.previews(f1.id);
notes2 = await Note.previews(f2.id);
assertEquals(4, notes1.length);
assertEquals(1, notes2.length);
await execCommand(client, 'mv \'note*\' nb2');
notes2 = await Note.previews(f2.id);
notes1 = await Note.previews(f1.id);
assertEquals(1, notes1.length);
assertEquals(4, notes2.length);
};
testUnits.testUse = async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mkbook nb2');
await execCommand(client, 'mknote n1');
await execCommand(client, 'mknote n2');
const f1 = await Folder.loadByTitle('nb1');
const f2 = await Folder.loadByTitle('nb2');
let notes1 = await Note.previews(f1.id);
let notes2 = await Note.previews(f2.id);
assertEquals(0, notes1.length);
assertEquals(2, notes2.length);
await execCommand(client, 'use nb1');
await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3');
notes1 = await Note.previews(f1.id);
notes2 = await Note.previews(f2.id);
assertEquals(2, notes1.length);
assertEquals(2, notes2.length);
};
async function main() {
await fs.remove(baseDir);
logger.info(await execCommand(client, 'version'));
await db.open({ name: `${client.profileDir}/database.sqlite` });
BaseModel.setDb(db);
Setting.setConstant('rootProfileDir', client.profileDir);
Setting.setConstant('profileDir', client.profileDir);
await loadKeychainServiceAndSettings([]);
let onlyThisTest = 'testMv';
onlyThisTest = '';
for (const n in testUnits) {
if (!testUnits.hasOwnProperty(n)) continue;
if (onlyThisTest && n !== onlyThisTest) continue;
await clearDatabase();
const testName = n.substr(4).toLowerCase();
process.stdout.write(`${testName}: `);
await testUnits[n]();
console.info('');
}
}
main().catch(error => {
console.info('');
logger.error(error);
});

View File

@@ -0,0 +1,49 @@
import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
const { cliUtils } = require('./cli-utils.js');
interface Args { }
class Command extends BaseCommand {
public override usage() {
return 'keymap';
}
public override description() {
return _('Displays the configured keyboard shortcuts.');
}
public override compatibleUis() {
return ['cli', 'gui'];
}
public override async action(_args: Args) {
const keymaps = await app().loadKeymaps();
this.stdout(_('Configured keyboard shortcuts:'));
this.stdout('\n');
const rows = [];
const padding = ' ';
rows.push([`${padding}${_('KEYS')}`, _('TYPE'), _('COMMAND')]);
rows.push([`${padding}----`, '----', '-------']);
for (const item of keymaps) {
const formattedKeys = item.keys
.map((k: string) => (k === ' ' ? `(${_('SPACE')})` : k))
.join(', ');
rows.push([padding + formattedKeys, item.type, item.command]);
}
cliUtils.printArray(this.stdout.bind(this), rows);
if (app().gui() && !app().gui().isDummy()) {
app().gui().showConsole();
app().gui().maximizeConsole();
}
}
}
module.exports = Command;

View File

@@ -107,6 +107,7 @@ class Command extends BaseCommand {
userContentBaseUrl: () => joplinServerAuth.userContentBaseUrl,
username: () => joplinServerAuth.email,
password: () => joplinServerAuth.password,
apiKey: () => '',
session: (): Session => null,
});

View File

@@ -12,7 +12,7 @@ class Command extends BaseCommand {
}
public override async action() {
this.stdout(versionInfo(require('./package.json'), {}).message);
this.stdout(versionInfo(require('../package.json'), {}).message);
}
}

View File

@@ -2,6 +2,7 @@ import app from '../app';
import Folder from '@joplin/lib/models/Folder';
import BaseCommand from '../base-command';
import setupCommand from '../setupCommand';
import Setting from '@joplin/lib/models/Setting';
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied
export const setupCommandForTesting = (CommandClass: any, stdout: Function = null): BaseCommand => {
@@ -18,4 +19,9 @@ export const setupApplication = async () => {
// Some tests also need access to the Redux store
app().initRedux();
// Since the settings need to be loaded before the store is created, it will never
// receive the SETTING_UPDATE_ALL event, which means state.settings will not be
// initialised. So we manually call dispatchUpdateAll() to force an update.
Setting.dispatchUpdateAll();
};

View File

@@ -24,9 +24,21 @@
// 4. Remove tests one by one to narrow it down to the one with the async
// call that's causing problem.
const baseConfig = require('../../jest.config.base.js');
module.exports = {
...baseConfig,
testMatch: [
'**/tests/**/*.js',
'**/tests/HtmlToHtml.js',
'**/tests/HtmlToMd.js',
'**/tests/MarkupToHtml.js',
'**/tests/MdToHtml.js',
'**/tests/feature_NoteHistory.js',
'**/tests/feature_NoteList.js',
'**/tests/feature_ShowAllNotes.js',
'**/tests/feature_TagList.js',
'**/tests/services/**/*.js',
'**/*.test.js',
],

View File

@@ -1,5 +1,5 @@
const { afterEachCleanUp } = require('@joplin/lib/testing/test-utils.js');
const { shimInit } = require('@joplin/lib/shim-init-node.js');
const { default: shimInitCli } = require('./app/utils/shimInitCli');
const shim = require('@joplin/lib/shim').default;
const sharp = require('sharp');
const nodeSqlite = require('sqlite3');
@@ -13,7 +13,7 @@ try {
keytar = null;
}
shimInit({ sharp, keytar, nodeSqlite });
shimInitCli({ sharp, nodeSqlite, appVersion: () => require('./package.json').version, keytar });
global.afterEach(async () => {
await afterEachCleanUp();

View File

@@ -7,7 +7,7 @@
"scripts": {
"test": "jest --verbose=false --config=jest.config.js --bail --forceExit",
"test-one": "jest --verbose=false --config=jest.config.js --bail --forceExit",
"test-ci": "jest --config=jest.config.js --forceExit",
"test-ci": "jest --config=jest.config.js --forceExit --testPathIgnorePatterns=cli-integration-tests.test",
"build": "gulp build",
"start": "gulp build -L && node \"build/main.js\" --stack-trace-enabled --log-level debug --env dev",
"start-no-build": "node \"build/main.js\" --stack-trace-enabled --log-level debug --env dev",
@@ -35,20 +35,20 @@
],
"owner": "Laurent Cozic"
},
"version": "3.5.1",
"version": "3.6.0",
"bin": "./main.js",
"engines": {
"node": ">=10.0.0"
},
"dependencies": {
"@joplin/lib": "~3.5",
"@joplin/renderer": "~3.5",
"@joplin/utils": "~3.5",
"@joplin/lib": "~3.6",
"@joplin/renderer": "~3.6",
"@joplin/utils": "~3.6",
"aws-sdk": "2.1340.0",
"chalk": "4.1.2",
"compare-version": "0.1.2",
"file-type": "16.5.4",
"fs-extra": "11.2.0",
"fs-extra": "11.3.2",
"html-entities": "1.4.0",
"keytar": "7.9.0",
"md5": "2.3.0",
@@ -57,7 +57,7 @@
"proper-lockfile": "4.1.2",
"redux": "4.2.1",
"server-destroy": "1.0.1",
"sharp": "0.34.3",
"sharp": "0.34.4",
"sprintf-js": "1.1.3",
"sqlite3": "5.1.6",
"string-padding": "1.0.2",
@@ -70,7 +70,7 @@
"yargs-parser": "21.1.1"
},
"devDependencies": {
"@joplin/tools": "~3.5",
"@joplin/tools": "~3.6",
"@types/fs-extra": "11.0.4",
"@types/jest": "29.5.14",
"@types/node": "18.19.130",

View File

@@ -52,7 +52,7 @@ describe('MarkupToHtml', () => {
pluginAssets: [],
};
expect(await service.render(MarkupLanguage.Html, testString, {}, {})).toMatchObject(expectedOutput);
expect(await service.render(MarkupLanguage.Markdown, testString, {}, {})).toMatchObject(expectedOutput);
expect(await service.render(MarkupLanguage.Html, testString, {}, { })).toMatchObject(expectedOutput);
expect(await service.render(MarkupLanguage.Markdown, testString, {}, { })).toMatchObject(expectedOutput);
});
});

View File

@@ -0,0 +1,11 @@
<ul>
<li><a href="https://example.com/" title="This
is a test title
testing!
Test...">Test!</a></li>
<li><a href="http://example.com" title="
Test
">Another test...</a></li>
</ul>

View File

@@ -0,0 +1,5 @@
- [Test!](https://example.com/ "This
is a test title
testing!
Test...")
- [Another test...](http://example.com "Test")

View File

@@ -0,0 +1,74 @@
<!-- From https://en.wikipedia.org/wiki/Collatz_conjecture -->
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML" alttext="{\displaystyle f(n)={\begin{cases}n/2&amp;{\text{if }}n\equiv 0{\pmod {2}},\\3n+1&amp;{\text{if }}n\equiv 1{\pmod {2}}.\end{cases}}}">
<semantics>
<mrow class="MJX-TeXAtom-ORD">
<mstyle displaystyle="true" scriptlevel="0">
<mi>f</mi>
<mo stretchy="false">(</mo>
<mi>n</mi>
<mo stretchy="false">)</mo>
<mo>=</mo>
<mrow class="MJX-TeXAtom-ORD">
<mrow>
<mo>{</mo>
<mtable columnalign="left left" rowspacing=".2em" columnspacing="1em" displaystyle="false">
<mtr>
<mtd>
<mi>n</mi>
<mrow class="MJX-TeXAtom-ORD">
<mo>/</mo>
</mrow>
<mn>2</mn>
</mtd>
<mtd>
<mrow class="MJX-TeXAtom-ORD">
<mtext>if&nbsp;</mtext>
</mrow>
<mi>n</mi>
<mo>\u2261</mo>
<mn>0</mn>
<mrow class="MJX-TeXAtom-ORD">
<mspace width="0.444em"></mspace>
<mo stretchy="false">(</mo>
<mi>mod</mi>
<mspace width="0.333em"></mspace>
<mn>2</mn>
<mo stretchy="false">)</mo>
</mrow>
<mo>,</mo>
</mtd>
</mtr>
<mtr>
<mtd>
<mn>3</mn>
<mi>n</mi>
<mo>+</mo>
<mn>1</mn>
</mtd>
<mtd>
<mrow class="MJX-TeXAtom-ORD">
<mtext>if&nbsp;</mtext>
</mrow>
<mi>n</mi>
<mo>\u2261</mo>
<mn>1</mn>
<mrow class="MJX-TeXAtom-ORD">
<mspace width="0.444em"></mspace>
<mo stretchy="false">(</mo>
<mi>mod</mi>
<mspace width="0.333em"></mspace>
<mn>2</mn>
<mo stretchy="false">)</mo>
</mrow>
<mo>.</mo>
</mtd>
</mtr>
</mtable>
<mo fence="true" stretchy="true" symmetric="true"></mo>
</mrow>
</mrow>
</mstyle>
</mrow>
<annotation encoding="application/x-tex">{\displaystyle f(n)={\begin{cases}n/2&amp;{\text{if }}n\equiv 0{\pmod {2}},\\3n+1&amp;{\text{if }}n\equiv 1{\pmod {2}}.\end{cases}}}</annotation>
</semantics>
</math></span><img src="/some/src/here" class="mwe-math-fallback-image-display mw-invert skin-invert" aria-hidden="true" style="vertical-align: -3.171ex; width:45.735ex; height:7.509ex;"/>

View File

@@ -0,0 +1 @@
${\displaystyle f(n)={\begin{cases}n/2&{\text{if }}n\equiv 0{\pmod {2}},\\3n+1&{\text{if }}n\equiv 1{\pmod {2}}.\end{cases}}}$

View File

@@ -0,0 +1,10 @@
<div class="joplin-editable joplin-abc-notation">
<pre class="joplin-source" data-abc-options="{&quot;responsive&quot;:&quot;resize&quot;}" data-joplin-language="abc" data-joplin-source-open="```abc&#10;" data-joplin-source-close="&#10;```&#10;">{responsive:'resize'}
---
K:F
!f!(fgag-g2c2)|</pre>
<pre class="joplin-rendered joplin-abc-notation-rendered">K:F
!f!(fgag-g2c2)|</pre>
</div>

View File

@@ -0,0 +1,6 @@
```abc
{ responsive: 'resize' }
---
K:F
!f!(fgag-g2c2)|
```

View File

@@ -0,0 +1,8 @@
<div class="joplin-editable">
<span class="joplin-source" data-joplin-source-open="" data-joplin-source-close="">https://www.youtube.com/watch?v=iJqe9pC-z-Y</span>
<div class="joplin-youtube-player-rendered">
<iframe src="https://www.youtube-nocookie.com/embed/iJqe9pC-z-Y" title="YouTube video player" frameborder="0" allowfullscreen></iframe>
</div>
</div>

View File

@@ -0,0 +1 @@
https://www.youtube.com/watch?v=iJqe9pC-z-Y

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
# test for joplin import
[https://l.facebook.com/l.php?u=https%3A%2F%2Fix.sk%2FNiBZH%3Futm\_source%3DYouTube%2520Instagram%26utm\_medium%3D2HIqFSGVVB2mFsVTJClrQ7ZnuGJaUt6hu1MNH0vUMjcrgWnUsK%26utm\_campaign%3D%25F0%259F%2598%25A9%25F0%259F%2598%258E%25F0%259F%2598%25BF%25F0%259F%25A4%2594%25F0%259F%2598%25A9%25F0%259F%2599%2583%25F0%259F%25A4%25AF%25F0%259F%25A5%25B0%25F0%259F%2598%25AB%25F0%259F%2598%25BA%26utm\_id%3D%25F0%259F%2598%258B%25F0%259F%2598%25A5%25F0%259F%25A4%25A1%25F0%259F%2598%25A0%25F0%259F%2598%2587%25F0%259F%25A5%25B4%25F0%259F%25A7%2590%25F0%259F%2598%258E%25F0%259F%2598%2582%25F0%259F%2598%259E%26utm\_term%3D%25F0%259F%2598%2584%25F0%259F%25A4%25A9%25F0%259F%2599%2580%25F0%259F%2598%2593%25F0%259F%25A4%25AF%25F0%259F%25A4%25A5%25F0%259F%2591%25BE%25F0%259F%2591%25BF%25F0%259F%2598%25BD%25F0%259F%25A4%25A5%26utm\_content%3D%25F0%259F%2591%25BD%25F0%259F%2598%25AB%25F0%259F%2591%25BF%25F0%259F%2598%25BD%25F0%259F%2598%25A9%25F0%259F%2599%2589%26fbclid%3DIwAR0I3l5DBLypLaTjDTCGPQ1i1MmPB2-pE8iqrxrgUK9Kkvq3OX5Mjejibzw&h=AT3nNxW4G-9nAkhXU1EVN-aVGl1o\_-DzDAaWFx9xbprpN3JRBOh17lCQQHNAlIMv6iE4P2vobBAAivLvdzy00K8xqIqb-CvGj6YnnBX6R9wwtj5Y&\_\_tn\_\_=H-y-R&c[0]=AT0eE6OXx\_t9HzpPmMgTdOWAw2ZRNPRDIHJWf699NZYkYzugbWS6g3rOndhPA8fwrCIgk1zn2D1To7phLW9wXkqfgZU1ayT3887\_dxrfN-x822Pos0lCjTIhoQcxfBl516pTz1XrRG\_MbtPpLzUFAGu4nw5W86UR1EkBCZhustNbgTX4wVReiVSuwAWu7Sp1yiWvUm5JXlo76663333hhsgsu](<https://l.facebook.com/l.php?u=https%3A%2F%2Fix.sk%2FNiBZH%3Futm_source%3DYouTube%2520Instagram%26utm_medium%3D2HIqFSGVVB2mFsVTJClrQ7ZnuGJaUt6hu1MNH0vUMjcrgWnUsK%26utm_campaign%3D%25F0%259F%2598%25A9%25F0%259F%2598%258E%25F0%259F%2598%25BF%25F0%259F%25A4%2594%25F0%259F%2598%25A9%25F0%259F%2599%2583%25F0%259F%25A4%25AF%25F0%259F%25A5%25B0%25F0%259F%2598%25AB%25F0%259F%2598%25BA%26utm_id%3D%25F0%259F%2598%258B%25F0%259F%2598%25A5%25F0%259F%25A4%25A1%25F0%259F%2598%25A0%25F0%259F%2598%2587%25F0%259F%25A5%25B4%25F0%259F%25A7%2590%25F0%259F%2598%258E%25F0%259F%2598%2582%25F0%259F%2598%259E%26utm_term%3D%25F0%259F%2598%2584%25F0%259F%25A4%25A9%25F0%259F%2599%2580%25F0%259F%2598%2593%25F0%259F%25A4%25AF%25F0%259F%25A4%25A5%25F0%259F%2591%25BE%25F0%259F%2591%25BF%25F0%259F%2598%25BD%25F0%259F%25A4%25A5%26utm_content%3D%25F0%259F%2591%25BD%25F0%259F%2598%25AB%25F0%259F%2591%25BF%25F0%259F%2598%25BD%25F0%259F%2598%25A9%25F0%259F%2599%2589%26fbclid%3DIwAR0I3l5DBLypLaTjDTCGPQ1i1MmPB2-pE8iqrxrgUK9Kkvq3OX5Mjejibzw&h=AT3nNxW4G-9nAkhXU1EVN-aVGl1o_-DzDAaWFx9xbprpN3JRBOh17lCQQHNAlIMv6iE4P2vobBAAivLvdzy00K8xqIqb-CvGj6YnnBX6R9wwtj5Y&__tn__=H-y-R&c[0]=AT0eE6OXx_t9HzpPmMgTdOWAw2ZRNPRDIHJWf699NZYkYzugbWS6g3rOndhPA8fwrCIgk1zn2D1To7phLW9wXkqfgZU1ayT3887_dxrfN-x822Pos0lCjTIhoQcxfBl516pTz1XrRG_MbtPpLzUFAGu4nw5W86UR1EkBCZhustNbgTX4wVReiVSuwAWu7Sp1yiWvUm5JXlo>)

View File

@@ -0,0 +1,9 @@
---
id: 20250821081408
date: 2025-08-21
keywords:
---
# A test file for Joplin importer
Test

View File

@@ -0,0 +1,7 @@
---
title: test
created: 2025-07-22 17:30:44Z
updated: 2025-07-22 17:37:48Z
---
test

View File

@@ -1,7 +1,7 @@
---
title: "Frontmatter test"
created_at: 01-01-2024 01:23 AM
updated_at: 02-01-2024 04:56 AM
updated_at: 01-01-2024 04:56 AM
---
# Frontmatter test

View File

@@ -165,6 +165,10 @@
if (a && a.toLowerCase().indexOf('math/tex') >= 0) isVisible = true;
}
if (nodeName === 'annotation') {
if (node.getAttribute('encoding') === 'application/x-tex') isVisible = true;
}
if (nodeName === 'source' && nodeParentName === 'picture') {
isVisible = false;
}

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Joplin Web Clipper [DEV]",
"version": "3.5.0",
"version": "3.6.0",
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
"homepage_url": "https://joplinapp.org",
"content_security_policy": {

View File

@@ -23,6 +23,7 @@ import { defaultWindowId } from '@joplin/lib/reducer';
import { msleep, Second } from '@joplin/utils/time';
import determineBaseAppDirs from '@joplin/lib/determineBaseAppDirs';
import getAppName from '@joplin/lib/getAppName';
import { execCommand } from '@joplin/utils';
interface RendererProcessQuitReply {
canClose: boolean;
@@ -259,6 +260,15 @@ export default class ElectronAppWrapper {
require('@electron/remote/main').enable(this.win_.webContents);
// Add Referer header for YouTube embeds to fix Error 153
this.win_.webContents.session.webRequest.onBeforeSendHeaders(
{ urls: ['*://*.youtube.com/*', '*://*.youtube-nocookie.com/*'] },
(details, callback) => {
details.requestHeaders['Referer'] = 'https://joplinapp.org/';
callback({ requestHeaders: details.requestHeaders });
},
);
if (!screen.getDisplayMatching(this.win_.getBounds())) {
const { width: windowWidth, height: windowHeight } = this.win_.getBounds();
const { width: primaryDisplayWidth, height: primaryDisplayHeight } = screen.getPrimaryDisplay().workArea;
@@ -810,6 +820,33 @@ export default class ElectronAppWrapper {
return this.customProtocolHandler_;
}
private async fixLinuxAccessibility_() {
if (this.electronApp().accessibilitySupportEnabled) return;
const isOrcaRunning = async () => {
if (!shim.isLinux()) return false;
try {
const matchingProcesses = await execCommand(['ps', '--no-headers', '-C', 'orca'], { quiet: true });
return matchingProcesses.trim().length > 0;
} catch (error) {
if (error.stderr || error.exitCode !== 1) {
// eslint-disable-next-line no-console -- The main logger is not available at this point.
console.error('Failed to check for and enable accessibility support:', error.stderr);
}
return false;
}
};
// Work around https://issues.chromium.org/issues/431257156 by force-enabling accessibility
// when Orca (a screen reader) is running:
if (await isOrcaRunning()) {
// eslint-disable-next-line no-console -- The main logger is not available at this point.
console.log('Linux accessibility: Enabling full accessibility support.');
this.electronApp().setAccessibilitySupportEnabled(true);
}
}
public async start() {
// Since we are doing other async things before creating the window, we might miss
// the "ready" event. So we use the function below to make sure that the app is ready.
@@ -818,6 +855,8 @@ export default class ElectronAppWrapper {
const alreadyRunning = await this.ensureSingleInstance();
if (alreadyRunning) return;
await this.fixLinuxAccessibility_();
this.customProtocolHandler_ = handleCustomProtocols();
this.createWindow();

View File

@@ -11,7 +11,7 @@ import Setting from '@joplin/lib/models/Setting';
import Note from '@joplin/lib/models/Note';
const { friendlySafeFilename } = require('@joplin/lib/path-utils');
import time from '@joplin/lib/time';
import { BrowserWindow } from 'electron';
import { BrowserWindow, BrowserWindowConstructorOptions } from 'electron';
const md5 = require('md5');
const url = require('url');
@@ -62,8 +62,10 @@ export default class InteropServiceHelper {
htmlFile = await this.exportNoteToHtmlFile(noteId, exportOptions);
const windowOptions = {
show: false,
const windowOptions: BrowserWindowConstructorOptions = {
// Work around a printing issue: As of Electron 39, if the window is initially hidden, printing crashes the app.
// This only seems to be necessary on Linux.
show: shim.isLinux(),
};
win = bridge().newBrowserWindow(windowOptions);
@@ -93,6 +95,9 @@ export default class InteropServiceHelper {
// Allows users to override the CSS page size.
// See https://github.com/laurent22/joplin/issues/13096
preferCSSPageSize: true,
// Include accessibility information in the output:
generateTaggedPDF: true,
});
resolve(data);
} catch (error) {
@@ -120,6 +125,9 @@ export default class InteropServiceHelper {
//
// 2025-05-03: Windows and MacOS also need the window.print() workaround.
// See https://github.com/electron/electron/pull/46937.
//
// 2025-10-30: window.print() now causes a crash on Linux -- switch back to the
// other method.
const applyWorkaround = true;
if (applyWorkaround) {

View File

@@ -52,7 +52,7 @@ describe('app.reducer', () => {
...createAppDefaultState({}),
backgroundWindows: {
testWindow: {
...createAppDefaultWindowState(null),
...createAppDefaultWindowState(),
windowId: 'testWindow',
visibleDialogs: {

View File

@@ -30,17 +30,6 @@ export interface NoteIdToScrollPercent {
[noteId: string]: number;
}
type RichTextEditorSelectionBookmark = unknown;
export interface EditorCursorLocations {
readonly richText?: RichTextEditorSelectionBookmark;
readonly markdown?: number;
}
export interface NoteIdToEditorCursorLocations {
[noteId: string]: EditorCursorLocations;
}
export interface VisibleDialogs {
[dialogKey: string]: boolean;
}
@@ -53,9 +42,6 @@ export interface AppWindowState extends WindowState {
devToolsVisible: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
watchedResources: any;
lastEditorScrollPercents: NoteIdToScrollPercent;
lastEditorCursorLocations: NoteIdToEditorCursorLocations;
}
interface BackgroundWindowStates {
@@ -79,7 +65,7 @@ export interface AppState extends State, AppWindowState {
isResettingLayout: boolean;
}
export const createAppDefaultWindowState = (globalState: AppState|null): AppWindowState => {
export const createAppDefaultWindowState = (): AppWindowState => {
return {
...defaultWindowState,
visibleDialogs: {},
@@ -88,12 +74,6 @@ export const createAppDefaultWindowState = (globalState: AppState|null): AppWind
editorCodeView: true,
devToolsVisible: false,
watchedResources: {},
// Maintain the scroll and cursor location for secondary windows separate from the
// main window. This prevents scrolling in a secondary window from changing/resetting
// the default scroll position in the main window:
lastEditorCursorLocations: globalState?.lastEditorCursorLocations ?? {},
lastEditorScrollPercents: globalState?.lastEditorScrollPercents ?? {},
};
};
@@ -101,7 +81,7 @@ export const createAppDefaultWindowState = (globalState: AppState|null): AppWind
export function createAppDefaultState(resourceEditWatcherDefaultState: any): AppState {
return {
...defaultState,
...createAppDefaultWindowState(null),
...createAppDefaultWindowState(),
route: {
type: 'NAV_GO',
routeName: 'Main',
@@ -307,28 +287,6 @@ export default function(state: AppState, action: any) {
}
break;
case 'EDITOR_SCROLL_PERCENT_SET':
{
newState = { ...state };
const newPercents = { ...newState.lastEditorScrollPercents };
newPercents[action.noteId] = action.percent;
newState.lastEditorScrollPercents = newPercents;
}
break;
case 'EDITOR_CURSOR_POSITION_SET':
{
newState = { ...state };
const newCursorLocations = { ...newState.lastEditorCursorLocations };
newCursorLocations[action.noteId] = {
...(newCursorLocations[action.noteId] ?? {}),
...action.location,
};
newState.lastEditorCursorLocations = newCursorLocations;
}
break;
case 'NOTE_DEVTOOLS_TOGGLE':
newState = { ...state };
newState.devToolsVisible = !newState.devToolsVisible;

View File

@@ -280,6 +280,18 @@ class Application extends BaseApplication {
Setting.setValue('plugins.states', pluginSettings);
}
// As of Joplin 3.5.7, the ABC rendering is part of the app so we automatically disable the plugin
if (pluginSettings['org.joplinapp.plugins.AbcSheetMusic']) {
pluginSettings = {
...pluginSettings,
['org.joplinapp.plugins.AbcSheetMusic']: {
enabled: false,
deleted: false,
hasBeenUpdated: false,
},
};
}
try {
if (await shim.fsDriver().exists(Setting.value('pluginDir'))) {
await service.loadAndRunPlugins(Setting.value('pluginDir'), pluginSettings);

View File

@@ -1,52 +0,0 @@
import { _ } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note';
import { stateUtils } from '@joplin/lib/reducer';
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
import { MarkupLanguage } from '@joplin/renderer';
import { runtime as convertHtmlToMarkdown } from '@joplin/lib/commands/convertHtmlToMarkdown';
import bridge from '../services/bridge';
export const declaration: CommandDeclaration = {
name: 'convertNoteToMarkdown',
label: () => _('Convert note to Markdown'),
};
export const runtime = (): CommandRuntime => {
return {
execute: async (context: CommandContext, noteId: string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
const note = await Note.load(noteId);
if (!note) return;
try {
const markdownBody = await convertHtmlToMarkdown().execute(context, note.body);
const newNote = await Note.duplicate(note.id);
newNote.body = markdownBody;
newNote.markup_language = MarkupLanguage.Markdown;
await Note.save(newNote);
await Note.delete(note.id, { toTrash: true });
context.dispatch({
type: 'NOTE_HTML_TO_MARKDOWN_DONE',
value: note.id,
});
context.dispatch({
type: 'NOTE_SELECT',
id: newNote.id,
});
} catch (error) {
bridge().showErrorMessageBox(_('Could not convert note to Markdown: %s', error.message));
}
},
enabledCondition: 'oneNoteSelected && noteIsHtml && !noteIsReadOnly',
};
};

View File

@@ -1,5 +1,4 @@
// AUTO-GENERATED using `gulp buildScriptIndexes`
import * as convertNoteToMarkdown from './convertNoteToMarkdown';
import * as copyDevCommand from './copyDevCommand';
import * as copyToClipboard from './copyToClipboard';
import * as editProfileConfig from './editProfileConfig';
@@ -14,6 +13,7 @@ import * as openProfileDirectory from './openProfileDirectory';
import * as openSecondaryAppInstance from './openSecondaryAppInstance';
import * as replaceMisspelling from './replaceMisspelling';
import * as restoreNoteRevision from './restoreNoteRevision';
import * as showProfileEditor from './showProfileEditor';
import * as startExternalEditing from './startExternalEditing';
import * as stopExternalEditing from './stopExternalEditing';
import * as switchProfile from './switchProfile';
@@ -25,7 +25,6 @@ import * as toggleSafeMode from './toggleSafeMode';
import * as toggleTabMovesFocus from './toggleTabMovesFocus';
const index: any[] = [
convertNoteToMarkdown,
copyDevCommand,
copyToClipboard,
editProfileConfig,
@@ -40,6 +39,7 @@ const index: any[] = [
openSecondaryAppInstance,
replaceMisspelling,
restoreNoteRevision,
showProfileEditor,
startExternalEditing,
stopExternalEditing,
switchProfile,

View File

@@ -2,7 +2,7 @@ import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/
import { _ } from '@joplin/lib/locale';
import { stateUtils } from '@joplin/lib/reducer';
import Note from '@joplin/lib/models/Note';
import { AppState, createAppDefaultWindowState } from '../app.reducer';
import { createAppDefaultWindowState } from '../app.reducer';
import Setting from '@joplin/lib/models/Setting';
export const declaration: CommandDeclaration = {
@@ -25,7 +25,7 @@ export const runtime = (): CommandRuntime => {
folderId: note.parent_id,
windowId: `window-${noteId}-${idCounter++}`,
defaultAppWindowState: {
...createAppDefaultWindowState(context.state as AppState),
...createAppDefaultWindowState(),
noteVisiblePanes: Setting.value('noteVisiblePanes'),
editorCodeView: Setting.value('editor.codeView'),
},

View File

@@ -0,0 +1,20 @@
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
import { _ } from '@joplin/lib/locale';
export const declaration: CommandDeclaration = {
name: 'showProfileEditor',
label: () => _('Manage profiles'),
};
export const runtime = (): CommandRuntime => {
return {
execute: async (context: CommandContext) => {
context.dispatch({
type: 'NAV_GO',
routeName: 'ProfileEditor',
});
},
enabledCondition: 'hasMultiProfiles',
};
};

View File

@@ -261,7 +261,10 @@ class ConfigScreenComponent extends React.Component<any, any> {
if (settings['sync.target'] === SyncTargetRegistry.nameToId('joplinServerSaml')) {
const server = settings['sync.11.path'] as string;
const goToSamlLogin = () => {
const goToSamlLogin = async () => {
// Save settings to allow SAML auth with the correct URL.
await shared.saveSettings(this);
this.props.dispatch({
type: 'NAV_GO',
routeName: 'JoplinServerSamlLogin',

View File

@@ -1,28 +0,0 @@
import * as React from 'react';
import { useContext, useEffect } from 'react';
import { _ } from '@joplin/lib/locale';
import { Dispatch } from 'redux';
import { PopupNotificationContext } from '../PopupNotification/PopupNotificationProvider';
import { NotificationType } from '../PopupNotification/types';
interface Props {
noteId: string;
dispatch: Dispatch;
}
export default (props: Props) => {
const popupManager = useContext(PopupNotificationContext);
useEffect(() => {
if (!props.noteId || props.noteId === '') return;
props.dispatch({ type: 'NOTE_HTML_TO_MARKDOWN_DONE', value: '' });
const notification = popupManager.createPopup(() => (
<div>{_('The note has been converted to Markdown and the original note has been moved to the trash')}</div>
), { type: NotificationType.Success });
notification.scheduleDismiss();
}, [props.dispatch, popupManager, props.noteId]);
return <div style={{ display: 'none' }}/>;
};

View File

@@ -7,6 +7,7 @@ import useKeyboardHandler from './DialogButtonRow/useKeyboardHandler';
export interface ButtonSpec {
name: string;
label: string;
disabled?: boolean;
}
export interface ClickEvent {
@@ -51,21 +52,29 @@ export default function DialogButtonRow(props: Props) {
if (props.onClick) props.onClick(event);
}, [props.onClick]);
const onKeyDown = useKeyboardHandler({ onOkButtonClick, onCancelButtonClick });
const okButtonShow = props.okButtonShow ?? true;
const cancelButtonShow = props.cancelButtonShow ?? true;
const canClickOk = okButtonShow && !props.okButtonDisabled;
const canClickCancel = cancelButtonShow && !props.cancelButtonDisabled;
const onKeyDown = useKeyboardHandler({
onOkButtonClick: canClickOk ? onOkButtonClick : null,
onCancelButtonClick: canClickCancel ? onCancelButtonClick : null,
});
const buttonComps = [];
if (props.customButtons) {
for (const b of props.customButtons) {
buttonComps.push(
<button key={b.name} style={buttonStyle} onClick={() => onCustomButtonClick({ buttonName: b.name })} onKeyDown={onKeyDown}>
<button key={b.name} style={buttonStyle} onClick={() => onCustomButtonClick({ buttonName: b.name })} disabled={b.disabled} onKeyDown={onKeyDown}>
{b.label}
</button>,
);
}
}
if (props.okButtonShow !== false) {
if (okButtonShow) {
buttonComps.push(
<button disabled={props.okButtonDisabled} key="ok" style={buttonStyle} onClick={onOkButtonClick} ref={props.okButtonRef} onKeyDown={onKeyDown}>
{props.okButtonLabel ? props.okButtonLabel : _('OK')}
@@ -73,7 +82,7 @@ export default function DialogButtonRow(props: Props) {
);
}
if (props.cancelButtonShow !== false) {
if (cancelButtonShow) {
buttonComps.push(
<button disabled={props.cancelButtonDisabled} key="cancel" style={{ ...buttonStyle }} onClick={onCancelButtonClick}>
{props.cancelButtonLabel ? props.cancelButtonLabel : _('Cancel')}

View File

@@ -2,11 +2,10 @@ import * as React from 'react';
import { useEffect, useState, useRef, useCallback } from 'react';
import { isInsideContainer } from '@joplin/lib/dom';
type OnButtonClick = ()=> void;
interface Props {
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
onOkButtonClick: Function;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
onCancelButtonClick: Function;
onOkButtonClick: null|OnButtonClick;
onCancelButtonClick: null|OnButtonClick;
}
const globalKeydownHandlers: string[] = [];
@@ -48,15 +47,17 @@ export default (props: Props) => {
if (!isTopDialog() || isInSubModal(event.target)) return;
if (event.keyCode === 13) {
if (event.keyCode === 13 && props.onOkButtonClick) {
if ('nodeName' in event.target && event.target.nodeName === 'INPUT') {
const target = event.target as HTMLInputElement;
if (target.type !== 'button' && target.type !== 'checkbox') {
event.preventDefault();
props.onOkButtonClick();
}
}
} else if (event.keyCode === 27) {
} else if (event.keyCode === 27 && props.onCancelButtonClick) {
event.preventDefault();
props.onCancelButtonClick();
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied

View File

@@ -106,7 +106,7 @@ const JoplinCloudScreenComponent = (props: Props) => {
<span className={state.className}>{state.errorMessage}</span>
) : null}
</p>
{state.active === 'LINK_USED' ? <div id="loading-animation" /> : null}
{state.active === 'LINK_USED' ? <div className="loading-animation" /> : null}
<JoplinCloudSignUpCallToAction />
</div>
<ButtonBar onCancelClick={() => props.dispatch({ type: 'NAV_BACK' })} />

View File

@@ -38,14 +38,12 @@ import restart from '../services/restart';
import { connect } from 'react-redux';
import { NoteListColumns } from '@joplin/lib/services/plugins/api/noteListType';
import validateColumns from './NoteListHeader/utils/validateColumns';
import ConversionNotification from './ConversionNotification/ConversionNotification';
import TrashNotification from './TrashNotification/TrashNotification';
import UpdateNotification from './UpdateNotification/UpdateNotification';
import NoteEditor from './NoteEditor/NoteEditor';
import PluginNotification from './PluginNotification/PluginNotification';
import { Toast } from '@joplin/lib/services/plugins/api/types';
import PluginService from '@joplin/lib/services/plugins/PluginService';
import { Dispatch } from 'redux';
const ipcRenderer = require('electron').ipcRenderer;
@@ -86,7 +84,6 @@ interface Props {
showInvalidJoplinCloudCredential: boolean;
toast: Toast;
shouldSwitchToAppleSiliconVersion: boolean;
noteHtmlToMarkdownDone: string;
}
interface ShareFolderDialogOptions {
@@ -800,10 +797,6 @@ class MainScreenComponent extends React.Component<Props, State> {
return (
<div style={style}>
<ConversionNotification
noteId={this.props.noteHtmlToMarkdownDone}
dispatch={this.props.dispatch as Dispatch}
/>
<TrashNotification
lastDeletion={this.props.lastDeletion}
lastDeletionNotificationTime={this.props.lastDeletionNotificationTime}
@@ -859,8 +852,7 @@ const mapStateToProps = (state: AppState) => {
notesColumns: validateColumns(state.settings['notes.columns']),
showInvalidJoplinCloudCredential: state.settings['sync.target'] === 10 && state.mustAuthenticate,
toast: state.toast,
shouldSwitchToAppleSiliconVersion: shim.isAppleSilicon() && process.arch !== 'arm64',
noteHtmlToMarkdownDone: state.noteHtmlToMarkdownDone,
shouldSwitchToAppleSiliconVersion: shim.isAppleSilicon() && shim.isMac() && process.arch !== 'arm64',
};
};

View File

@@ -9,7 +9,6 @@ import { PluginStates, utils as pluginUtils } from '@joplin/lib/services/plugins
import shim from '@joplin/lib/shim';
import Setting from '@joplin/lib/models/Setting';
import versionInfo, { PackageInfo } from '@joplin/lib/versionInfo';
import makeDiscourseDebugUrl from '@joplin/lib/makeDiscourseDebugUrl';
import { ImportModule } from '@joplin/lib/services/interop/Module';
import InteropServiceHelper from '../InteropServiceHelper';
import { _ } from '@joplin/lib/locale';
@@ -29,6 +28,8 @@ import { EventName } from '@joplin/lib/eventManager';
import { ipcRenderer } from 'electron';
import NavService from '@joplin/lib/services/NavService';
import Logger from '@joplin/utils/Logger';
import { ImportCommandOptions } from './WindowCommandsAndDialogs/commands/importFrom';
import { FileSystemItem } from '@joplin/lib/services/interop/types';
const logger = Logger.create('MenuBar');
@@ -116,7 +117,7 @@ const useSwitchProfileMenuItems = (profileConfig: ProfileConfig, menuItemDic: an
switchProfileMenuItems.push({ type: 'separator' });
switchProfileMenuItems.push(menuItemDic.addProfile);
switchProfileMenuItems.push(menuItemDic.editProfileConfig);
switchProfileMenuItems.push(menuItemDic.showProfileEditor);
return switchProfileMenuItems;
}, [profileConfig, menuItemDic]);
@@ -304,83 +305,16 @@ function useMenu(props: Props) {
void CommandService.instance().execute(commandName);
}, []);
const onImportModuleClick = useCallback(async (module: ImportModule, moduleSource: string) => {
let path = null;
if (moduleSource === 'file') {
path = await bridge().showOpenDialog({
filters: [{ name: module.description, extensions: module.fileExtensions }],
});
} else {
path = await bridge().showOpenDialog({
properties: ['openDirectory', 'createDirectory'],
});
}
if (!path || (Array.isArray(path) && !path.length)) return;
if (Array.isArray(path)) path = path[0];
const modalMessage = _('Importing from "%s" as "%s" format. Please wait...', path, module.format);
void CommandService.instance().execute('showModalMessage', modalMessage);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const errors: any[] = [];
const importOptions = {
path,
format: module.format,
outputFormat: module.outputFormat,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProgress: (status: any) => {
const statusStrings: string[] = Object.keys(status).map((key: string) => {
return `${key}: ${status[key]}`;
});
void CommandService.instance().execute('showModalMessage', `${modalMessage}\n\n${statusStrings.join('\n')}`);
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onError: (error: any) => {
errors.push(error);
console.warn(error);
},
const onImportModuleClick = useCallback(async (module: ImportModule, moduleSource: FileSystemItem) => {
const options: ImportCommandOptions = {
destinationFolderId: !module.isNoteArchive && moduleSource === 'file' ? props.selectedFolderId : null,
sourcePath: undefined, // Show a file picker
sourceType: moduleSource,
importFormat: module.format,
outputFormat: module.outputFormat,
};
const service = InteropService.instance();
try {
const result = await service.import(importOptions);
// eslint-disable-next-line no-console
console.info('Import result: ', result);
} catch (error) {
bridge().showErrorMessageBox(error.message);
}
void CommandService.instance().execute('hideModalMessage');
if (errors.length) {
const response = bridge().showErrorMessageBox('There was some errors importing the notes - check the console for more details.\n\nPlease consider sending a bug report to the forum!', {
buttons: [_('Close'), _('Send bug report')],
});
props.dispatch({ type: 'NOTE_DEVTOOLS_SET', value: true });
if (response === 1) {
const url = makeDiscourseDebugUrl(
`Error importing notes from format: ${module.format}`,
`- Input format: ${module.format}\n- Output format: ${module.outputFormat}`,
errors,
packageInfo,
PluginService.instance(),
props.pluginSettings,
);
void bridge().openExternal(url);
}
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.selectedFolderId, props.pluginSettings]);
await CommandService.instance().execute('importFrom', options);
}, [props.selectedFolderId]);
const onMenuItemClickRef = useRef(null);
onMenuItemClickRef.current = onMenuItemClick;

View File

@@ -22,12 +22,6 @@ interface MultiNoteActionsProps {
function styles_(props: MultiNoteActionsProps) {
return buildStyle('MultiNoteActions', props.themeId, (theme: ThemeStyle) => {
return {
root: {
display: 'inline-flex',
justifyContent: 'center',
paddingTop: theme.marginTop,
width: '100%',
},
itemList: {
display: 'flex',
flexDirection: 'column',
@@ -90,7 +84,7 @@ export default function MultiNoteActions(props: MultiNoteActionsProps) {
}
return (
<div style={styles.root}>
<div style={styles.root} className='multi-note-actions'>
<div style={styles.itemList}>{itemComps}</div>
</div>
);

View File

@@ -31,13 +31,15 @@ function markupToHtml() {
}
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
function countElements(text: string, wordSetter: Function, characterSetter: Function, characterNoSpaceSetter: Function, lineSetter: Function) {
function countElements(text: string, wordSetter: Function, characterSetter: Function, characterNoSpaceSetter: Function, cjkCharacterSetter: React.Dispatch<React.SetStateAction<number>>, lineSetter: Function) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
Countable.count(text, (counter: any) => {
wordSetter(counter.words);
characterSetter(counter.all);
characterNoSpaceSetter(counter.characters);
});
const cjkMatches = text.match(/[\p{Script=Han}\p{Script=Bopomofo}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/gu);
cjkCharacterSetter(cjkMatches ? cjkMatches.length : 0);
lineSetter(text === '' ? 0 : text.split('\n').length);
}
@@ -58,23 +60,25 @@ export default function NoteContentPropertiesDialog(props: NoteContentProperties
const [words, setWords] = useState<number>(0);
const [characters, setCharacters] = useState<number>(0);
const [charactersNoSpace, setCharactersNoSpace] = useState<number>(0);
const [cjkCharacters, setCjkCharacters] = useState<number>(0);
// For source with Markdown syntax stripped out
const [strippedLines, setStrippedLines] = useState<number>(0);
const [strippedWords, setStrippedWords] = useState<number>(0);
const [strippedCharacters, setStrippedCharacters] = useState<number>(0);
const [strippedCharactersNoSpace, setStrippedCharactersNoSpace] = useState<number>(0);
const [strippedCjkCharacters, setStrippedCjkCharacters] = useState<number>(0);
const [strippedReadTime, setStrippedReadTime] = useState<number>(0);
// This amount based on the following paper:
// https://www.researchgate.net/publication/332380784_How_many_words_do_we_read_per_minute_A_review_and_meta-analysis_of_reading_rate
const wordsPerMinute = 250;
useEffect(() => {
countElements(props.text, setWords, setCharacters, setCharactersNoSpace, setLines);
countElements(props.text, setWords, setCharacters, setCharactersNoSpace, setCjkCharacters, setLines);
}, [props.text]);
useEffect(() => {
const strippedText: string = markupToHtml().stripMarkup(props.markupLanguage, props.text);
countElements(strippedText, setStrippedWords, setStrippedCharacters, setStrippedCharactersNoSpace, setStrippedLines);
countElements(strippedText, setStrippedWords, setStrippedCharacters, setStrippedCharactersNoSpace, setStrippedCjkCharacters, setStrippedLines);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.text]);
@@ -88,6 +92,7 @@ export default function NoteContentPropertiesDialog(props: NoteContentProperties
words: words,
characters: characters,
charactersNoSpace: charactersNoSpace,
cjkCharacters: cjkCharacters,
};
const strippedTextProperties: TextPropertiesMap = {
@@ -99,12 +104,14 @@ export default function NoteContentPropertiesDialog(props: NoteContentProperties
words: strippedWords,
characters: strippedCharacters,
charactersNoSpace: strippedCharactersNoSpace,
cjkCharacters: strippedCjkCharacters,
};
const keyToLabel: KeyToLabelMap = {
words: _('Words'),
characters: _('Characters'),
charactersNoSpace: _('Characters excluding spaces'),
cjkCharacters: _('Chinese/Japanese/Korean characters'),
lines: _('Lines'),
};
@@ -147,6 +154,7 @@ export default function NoteContentPropertiesDialog(props: NoteContentProperties
);
for (const key in textProperties) {
if (key === 'cjkCharacters' && textProperties[key] === 0 && strippedTextProperties[key] === 0) continue;
const comp = createTableBodyRow(key, textProperties[key], strippedTextProperties[key]);
tableBodyComps.push(comp);
}
@@ -172,7 +180,12 @@ export default function NoteContentPropertiesDialog(props: NoteContentProperties
<div style={{ ...labelCompStyle, marginTop: 10 }}>
{readTimeLabel}
</div>
<DialogButtonRow themeId={props.themeId} onClick={buttonRow_click} okButtonShow={false} cancelButtonLabel={_('Close')}/>
<DialogButtonRow
themeId={props.themeId}
onClick={buttonRow_click}
okButtonShow={false}
cancelButtonLabel={_('Close')}
/>
</Dialog>
);
}

View File

@@ -8,7 +8,36 @@ const logger = Logger.create('useEditorSearch');
// Registers a helper CodeMirror extension to be used with
// useEditorSearchHandler.
export default function useEditorSearchExtension(CodeMirror: CodeMirror5Emulation) {
interface SetMarkersOptions {
selectedIndex: number;
searchTimestamp: number;
showEditorMarkers?: boolean;
withSelection?: boolean;
}
type Keyword = { value: string };
export type OnSetMarkers = (cm: CodeMirror5Emulation, keywords: Keyword[], options: SetMarkersOptions)=> number;
// Modified from codemirror/addons/search/search.js
const searchOverlay = (query: RegExp) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
return { token: function(stream: any) {
query.lastIndex = stream.pos;
const match = query.exec(stream.string);
if (match && match.index === stream.pos) {
stream.pos += match[0].length || 1;
return 'search-marker';
} else if (match) {
stream.pos = match.index;
} else {
stream.skipToEnd();
}
return null;
} };
};
export default function useEditorSearchExtension() {
const [markers, setMarkers] = useState([]);
const [overlay, setOverlay] = useState(null);
@@ -48,23 +77,6 @@ export default function useEditorSearchExtension(CodeMirror: CodeMirror5Emulatio
setOverlayTimeout(null);
}, [scrollbarMarks, overlay, overlayTimeout]);
// Modified from codemirror/addons/search/search.js
const searchOverlay = useCallback((query: RegExp) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
return { token: function(stream: any) {
query.lastIndex = stream.pos;
const match = query.exec(stream.string);
if (match && match.index === stream.pos) {
stream.pos += match[0].length || 1;
return 'search-marker';
} else if (match) {
stream.pos = match.index;
} else {
stream.skipToEnd();
}
return null;
} };
}, []);
// Highlights the currently active found work
// It's possible to get tricky with this functions and just use findNext/findPrev
@@ -115,16 +127,17 @@ export default function useEditorSearchExtension(CodeMirror: CodeMirror5Emulatio
};
}, []);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
CodeMirror?.defineExtension('setMarkers', function(keywords: any, options: any) {
const onSetMarkers: OnSetMarkers = (cm, keywords, options) => {
// Pass arguments in via options to allow the extension to work if multiple editors are open simultaneously
// See https://github.com/laurent22/joplin/issues/13399.
if (!options) {
options = { selectedIndex: 0, searchTimestamp: 0 };
}
if (options.showEditorMarkers === false) {
clearMarkers();
clearOverlay(this);
return;
clearOverlay(cm);
return 0;
}
clearMarkers();
@@ -145,7 +158,7 @@ export default function useEditorSearchExtension(CodeMirror: CodeMirror5Emulatio
const scrollTo = i === 0 && (previousKeywordValue !== keyword.value || previousIndex !== options.selectedIndex || options.searchTimestamp !== previousSearchTimestamp);
try {
const match = highlightSearch(this, searchTerm, options.selectedIndex, scrollTo, !!options.withSelection);
const match = highlightSearch(cm, searchTerm, options.selectedIndex, scrollTo, !!options.withSelection);
if (match) marks.push(match);
} catch (error) {
if (error.name !== 'SyntaxError') {
@@ -165,7 +178,7 @@ export default function useEditorSearchExtension(CodeMirror: CodeMirror5Emulatio
// SEARCHOVERLAY
// We only want to highlight all matches when there is only 1 search term
if (keywords.length !== 1 || keywords[0].value === '') {
clearOverlay(this);
clearOverlay(cm);
const prev = keywords.length > 1 ? keywords[0].value : '';
setPreviousKeywordValue(prev);
return 0;
@@ -175,22 +188,22 @@ export default function useEditorSearchExtension(CodeMirror: CodeMirror5Emulatio
// Determine the number of matches in the source, this is passed on
// to the NoteEditor component
const regexMatches = this.getValue().match(searchTerm);
const regexMatches = cm.getValue().match(searchTerm);
const nMatches = regexMatches ? regexMatches.length : 0;
// Don't bother clearing and re-calculating the overlay if the search term
// hasn't changed
if (keywords[0].value === previousKeywordValue) return nMatches;
clearOverlay(this);
clearOverlay(cm);
setPreviousKeywordValue(keywords[0].value);
// These operations are pretty slow, so we won't add use them until the user
// has finished typing, 500ms is probably enough time
const timeout = shim.setTimeout(() => {
const scrollMarks = this.showMatchesOnScrollbar?.(searchTerm, true, 'cm-search-marker-scrollbar');
const scrollMarks = cm.showMatchesOnScrollbar?.(searchTerm, true, 'cm-search-marker-scrollbar');
const overlay = searchOverlay(searchTerm);
this.addOverlay(overlay);
cm.addOverlay(overlay);
setOverlay(overlay);
setScrollbarMarks(scrollMarks);
}, 500);
@@ -199,5 +212,9 @@ export default function useEditorSearchExtension(CodeMirror: CodeMirror5Emulatio
overlayTimeoutRef.current = timeout;
return nMatches;
});
};
const onSetMarkersRef = useRef(onSetMarkers);
onSetMarkersRef.current = onSetMarkers;
return { onSetMarkersRef };
}

View File

@@ -2,6 +2,8 @@ import { RefObject, useEffect, useMemo, useRef } from 'react';
import usePrevious from '../../../../hooks/usePrevious';
import { RenderedBody } from './types';
import { SearchMarkers } from '../../../utils/useSearchMarkers';
import CodeMirror5Emulation from '@joplin/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation';
import useEditorSearchExtension from './useEditorSearchExtension';
const debounce = require('debounce');
interface Props {
@@ -10,8 +12,7 @@ interface Props {
searchMarkers: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
webviewRef: RefObject<any>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
editorRef: RefObject<any>;
editorRef: RefObject<CodeMirror5Emulation>;
noteContent: string;
renderedBody: RenderedBody;
@@ -23,6 +24,8 @@ const useEditorSearchHandler = (props: Props) => {
webviewRef, editorRef, renderedBody, noteContent, searchMarkers, showEditorMarkers,
} = props;
const { onSetMarkersRef } = useEditorSearchExtension();
const previousContent = usePrevious(noteContent);
const previousRenderedBody = usePrevious(renderedBody);
const previousSearchMarkers = usePrevious(searchMarkers);
@@ -31,15 +34,15 @@ const useEditorSearchHandler = (props: Props) => {
// Fixes https://github.com/laurent22/joplin/issues/7565
const debouncedMarkers = useMemo(() => debounce((searchMarkers: SearchMarkers) => {
if (!editorRef.current) return;
if (!onSetMarkersRef.current) return;
if (showEditorMarkersRef.current) {
const matches = editorRef.current.setMarkers(searchMarkers.keywords, searchMarkers.options);
const matches = onSetMarkersRef.current(editorRef.current, searchMarkers.keywords, searchMarkers.options);
props.setLocalSearchResultCount(matches);
} else {
editorRef.current.setMarkers(searchMarkers.keywords, { ...searchMarkers.options, showEditorMarkers: false });
onSetMarkersRef.current(editorRef.current, searchMarkers.keywords, { ...searchMarkers.options, showEditorMarkers: false });
}
}, 50), [editorRef, props.setLocalSearchResultCount]);
}, 50), [editorRef, onSetMarkersRef, props.setLocalSearchResultCount]);
useEffect(() => {
if (!searchMarkers) return () => {};
@@ -59,7 +62,7 @@ const useEditorSearchHandler = (props: Props) => {
}
return () => {};
}, [
editorRef,
onSetMarkersRef,
webviewRef,
searchMarkers,
previousSearchMarkers,
@@ -71,6 +74,10 @@ const useEditorSearchHandler = (props: Props) => {
debouncedMarkers,
]);
return {
// Returned to allow quickly setting the initial search markers just after the editor loads.
onSetInitialMarkersRef: onSetMarkersRef,
};
};
export default useEditorSearchHandler;

View File

@@ -695,7 +695,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [renderedBody, webviewReady]);
useEditorSearchHandler({
const { onSetInitialMarkersRef } = useEditorSearchHandler({
setLocalSearchResultCount: props.setLocalSearchResultCount,
searchMarkers: props.searchMarkers,
webviewRef,
@@ -737,6 +737,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
<Editor
value={props.content}
searchMarkers={props.searchMarkers}
onSetMarkersRef={onSetInitialMarkersRef}
ref={editorRef}
mode={props.contentMarkupLanguage === MarkupToHtml.MARKUP_LANGUAGE_HTML ? 'xml' : 'joplin-markdown'}
codeMirrorTheme={styles.editor.codeMirrorTheme}

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { useEffect, useImperativeHandle, useState, useRef, useCallback, forwardRef } from 'react';
import { useEffect, useImperativeHandle, useState, useRef, useCallback, forwardRef, RefObject } from 'react';
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import CodeMirror from 'codemirror';
@@ -16,7 +16,7 @@ import useListIdent from './utils/useListIdent';
import useScrollUtils from './utils/useScrollUtils';
import useCursorUtils from './utils/useCursorUtils';
import useLineSorting from './utils/useLineSorting';
import useEditorSearch from '../utils/useEditorSearchExtension';
import { OnSetMarkers } from '../utils/useEditorSearchExtension';
import useJoplinMode from './utils/useJoplinMode';
import useKeymap from './utils/useKeymap';
import useExternalPlugins from './utils/useExternalPlugins';
@@ -77,6 +77,7 @@ export interface EditorProps {
value: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
searchMarkers: any;
onSetMarkersRef: RefObject<OnSetMarkers>;
mode: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
style: any;
@@ -119,7 +120,6 @@ function Editor(props: EditorProps, ref: any) {
useScrollUtils(CodeMirror);
useCursorUtils(CodeMirror);
useLineSorting(CodeMirror);
useEditorSearch(CodeMirror);
useJoplinMode(CodeMirror);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const pluginOptions: any = useExternalPlugins(CodeMirror, props.plugins);
@@ -228,7 +228,7 @@ function Editor(props: EditorProps, ref: any) {
// It's possible for searchMarkers to be available before the editor
// In these cases we set the markers asap so the user can see them as
// soon as the editor is ready
if (props.searchMarkers) { cm.setMarkers(props.searchMarkers.keywords, props.searchMarkers.options); }
if (props.searchMarkers) { props.onSetMarkersRef.current(cm, props.searchMarkers.keywords, props.searchMarkers.options); }
return () => {
// Clean up codemirror

View File

@@ -13,7 +13,7 @@ import { _ } from '@joplin/lib/locale';
import bridge from '../../../../../services/bridge';
import shim from '@joplin/lib/shim';
import { MarkupToHtml } from '@joplin/renderer';
const { clipboard } = require('electron');
import { clipboard } from 'electron';
import { reg } from '@joplin/lib/registry';
import ErrorBoundary from '../../../../ErrorBoundary';
import { EditorKeymap, EditorLanguageType, EditorSettings, SearchState, UserEventSource } from '@joplin/editor/types';
@@ -32,6 +32,7 @@ import useRefocusOnVisiblePaneChange from './utils/useRefocusOnVisiblePaneChange
import { WindowIdContext } from '../../../../NewWindowOrIFrame';
import eventManager, { EventName, ResourceChangeEvent } from '@joplin/lib/eventManager';
import useSyncEditorValue from './utils/useSyncEditorValue';
import { getGlobalSettings } from '@joplin/renderer/types';
const logger = Logger.create('CodeMirror6');
const logDebug = (message: string) => logger.debug(message);
@@ -93,41 +94,13 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
const editorCutText = useCallback(() => {
if (editorRef.current) {
const selections = editorRef.current.getSelections();
if (selections.length > 0 && selections[0]) {
clipboard.writeText(selections[0]);
// Easy way to wipe out just the first selection
selections[0] = '';
editorRef.current.replaceSelections(selections);
} else {
const cursor = editorRef.current.getCursor();
const line = editorRef.current.getLine(cursor.line);
clipboard.writeText(`${line}\n`);
const startLine = editorRef.current.getCursor('head');
startLine.ch = 0;
const endLine = {
line: startLine.line + 1,
ch: 0,
};
editorRef.current.replaceRange('', startLine, endLine);
}
editorRef.current.cutText(text => clipboard.writeText(text));
}
}, []);
const editorCopyText = useCallback(() => {
if (editorRef.current) {
const selections = editorRef.current.getSelections();
// Handle the case when there is a selection - copy the selection to the clipboard
// When there is no selection, the selection array contains an empty string.
if (selections.length > 0 && selections[0]) {
clipboard.writeText(selections[0]);
} else {
// This is the case when there is no selection - copy the current line to the clipboard
const cursor = editorRef.current.getCursor();
const line = editorRef.current.getLine(cursor.line);
clipboard.writeText(line);
}
editorRef.current.copyText(text => clipboard.writeText(text));
}
}, []);
@@ -248,6 +221,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
useCustomPdfViewer: props.useCustomPdfViewer,
noteId: props.noteId,
vendorDir: bridge().vendorDir(),
globalSettings: getGlobalSettings(Setting),
}));
if (cancelled) return;
@@ -392,6 +366,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
ignoreModifiers: true,
spellcheckEnabled: Setting.value('editor.spellcheckBeta'),
keymap: keyboardMode,
preferMacShortcuts: shim.isMac(),
indentWithTabs: true,
tabMovesFocus: props.tabMovesFocus,
editorLabel: _('Markdown editor'),

View File

@@ -11,7 +11,6 @@ import PluginService from '@joplin/lib/services/plugins/PluginService';
import setupVim from '@joplin/editor/CodeMirror/utils/setupVim';
import { dirname } from 'path';
import useKeymap from './utils/useKeymap';
import useEditorSearch from '../utils/useEditorSearchExtension';
import CommandService from '@joplin/lib/services/CommandService';
import { SearchMarkers } from '../../../utils/useSearchMarkers';
import localisation from './utils/localisation';
@@ -44,8 +43,6 @@ const Editor = (props: Props, ref: ForwardedRef<CodeMirrorControl>) => {
onLogMessageRef.current = props.onLogMessage;
}, [props.onEvent, props.onLogMessage]);
useEditorSearch(editor);
useEffect(() => {
if (!editor) {
return () => {};

View File

@@ -742,7 +742,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
'media-src \'self\' blob: data: *', // Audio and video players
// Disallow certain unused features
'child-src \'none\'', // Should not contain sub-frames
'child-src https://*.youtube.com https://*.youtube-nocookie.com', // Allow YouTube embeds
'object-src \'none\'', // Objects can be used for script injection
'form-action \'none\'', // No submitting forms
@@ -919,8 +919,6 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
editor.on('SetContent', () => {
preprocessContent();
props_onMessage.current({ channel: 'noteRenderComplete' });
});
},
});
@@ -1047,12 +1045,13 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
return true;
}
const { onInitialContentSet } = useCursorPositioning({
const { onRestoreCursorPosition } = useCursorPositioning({
initialCursorLocation: props.initialCursorLocation.richText as Bookmark,
onCursorUpdate: props.onCursorMotion,
editor,
});
const noteChangeTimeRef = useRef(Date.now());
const lastNoteIdRef = useRef(props.noteId);
useEffect(() => {
if (!editor) return () => {};
@@ -1070,6 +1069,9 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
// Use nextOnChangeEventInfo's noteId -- lastOnChangeEventInfo can be slightly out-of-date.
const differentNoteId = lastNoteIdRef.current !== props.noteId;
const differentContent = lastOnChangeEventInfo.current.content !== props.content;
if (differentNoteId) noteChangeTimeRef.current = Date.now();
if (differentNoteId || differentContent || !resourcesEqual) {
const result = await props.markupToHtml(
props.contentMarkupLanguage,
@@ -1120,8 +1122,12 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
// times would result in an empty note.
// https://github.com/laurent22/joplin/issues/3534
editor.undoManager.reset();
// Only restore the cursor position from the global state when switching notes.
// See https://github.com/laurent22/joplin/issues/13579
onRestoreCursorPosition();
} else {
// Restore the cursor location
// Restore the cursor location from the current note
editor.selection.bookmarkManager.moveToBookmark(bookmark);
}
@@ -1130,6 +1136,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
resourceInfos: props.resourceInfos,
contentKey: props.contentKey,
};
props_onMessage.current({ channel: 'noteRenderComplete' });
}
const allAssetsOptions: NoteStyleOptions = {
@@ -1143,7 +1150,6 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
await loadDocumentAssets(props.themeId, editor, allAssets);
dispatchDidUpdate(editor);
onInitialContentSet();
};
void loadContent();
@@ -1338,7 +1344,15 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: Ref<NoteBodyEditorRef>) => {
// keep it this way for now.
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
function onKeyUp(event: any) {
if (['Backspace', 'Delete', 'Enter', 'Tab'].includes(event.key)) {
const timeSinceNoteChange = Date.now() - noteChangeTimeRef.current;
// A key that is pressed before the editor is opened, and that is released after it is
// opened is going to be processed here. For example if the user presses Enter in
// GotoAnything to arrive here. But in that case, we don't want the change handler to be
// activated, because that would change the note timestamp. So we take into account how
// long the note has been loaded before we process the key. Fixes
// https://github.com/laurent22/joplin/issues/12367
if (['Backspace', 'Delete', 'Enter', 'Tab'].includes(event.key) && timeSinceNoteChange > 200) {
onChangeHandler();
}
}

View File

@@ -22,4 +22,8 @@ export const joplinCommandToTinyMceCommands: JoplinCommandToTinyMceCommands = {
'search': { name: 'SearchReplace' },
'attachFile': { name: 'joplinAttach' },
'insertDateTime': true,
'textCopy': true,
'textCut': true,
'textPaste': true,
'textSelectAll': true,
};

View File

@@ -13,7 +13,7 @@ const useCursorPositioning = ({ initialCursorLocation, editor, onCursorUpdate }:
initialCursorLocationRef.current = initialCursorLocation;
const appliedInitialCursorLocationRef = useRef(false);
const onInitialContentSet = useCallback(() => {
const onRestoreCursorPosition = useCallback(() => {
if (editor) {
if (initialCursorLocationRef.current) {
editor.selection.moveToBookmark(initialCursorLocationRef.current);
@@ -26,8 +26,6 @@ const useCursorPositioning = ({ initialCursorLocation, editor, onCursorUpdate }:
useEffect(() => {
if (!editor) return () => {};
editor.on('ContentSet', onInitialContentSet);
const onSelectionChange = () => {
// Wait until the initial cursor position has been set. This avoids resetting
// the initial cursor position to zero when the editor first loads.
@@ -44,12 +42,11 @@ const useCursorPositioning = ({ initialCursorLocation, editor, onCursorUpdate }:
editor.on('SelectionChange', onSelectionChange);
return () => {
editor.off('ContentSet', onInitialContentSet);
editor.off('SelectionChange', onSelectionChange);
};
}, [editor, onCursorUpdate, onInitialContentSet]);
}, [editor, onCursorUpdate, onRestoreCursorPosition]);
return { onInitialContentSet };
return { onRestoreCursorPosition };
};
export default useCursorPositioning;

View File

@@ -5,6 +5,8 @@ import { MarkupToHtmlHandler } from '../../../utils/types';
import { _ } from '@joplin/lib/locale';
import enableTextAreaTab, { TextAreaTabHandler } from './enableTextAreaTab';
import { MarkupToHtml } from '@joplin/renderer';
import { getGlobalSettings } from '@joplin/renderer/types';
import Setting from '@joplin/lib/models/Setting';
interface Props {
editor: Editor;
@@ -90,7 +92,7 @@ function openEditDialog(
onSubmit: async (dialogApi: any) => {
const newSource = newBlockSource(dialogApi.getData().languageInput, dialogApi.getData().codeTextArea, source);
const md = `${newSource.openCharacters}${newSource.content}${newSource.closeCharacters}`;
const result = await markupToHtml.current(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, md, { bodyOnly: true });
const result = await markupToHtml.current(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, md, { bodyOnly: true, globalSettings: getGlobalSettings(Setting) });
// markupToHtml will return the complete editable HTML, but we only
// want to update the inner HTML, so as not to break additional props that

View File

@@ -18,7 +18,7 @@ import { NoteEditorProps, FormNote, OnChangeEvent, AllAssetsOptions, NoteBodyEdi
import CommandService from '@joplin/lib/services/CommandService';
import Button, { ButtonLevel } from '../Button/Button';
import eventManager, { EventName } from '@joplin/lib/eventManager';
import { AppState, EditorCursorLocations } from '../../app.reducer';
import { AppState } from '../../app.reducer';
import ToolbarButtonUtils, { ToolbarButtonInfo } from '@joplin/lib/services/commands/ToolbarButtonUtils';
import { _, _n } from '@joplin/lib/locale';
import NoteTitleBar from './NoteTitle/NoteTitleBar';
@@ -50,7 +50,7 @@ import WarningBanner from './WarningBanner/WarningBanner';
import UserWebview from '../../services/plugins/UserWebview';
import Logger from '@joplin/utils/Logger';
import usePluginEditorView from './utils/usePluginEditorView';
import { stateUtils } from '@joplin/lib/reducer';
import { defaultWindowId, stateUtils } from '@joplin/lib/reducer';
import { WindowIdContext } from '../NewWindowOrIFrame';
import useResourceUnwatcher from './utils/useResourceUnwatcher';
import StatusBar from './StatusBar';
@@ -58,6 +58,7 @@ import useVisiblePluginEditorViewIds from '@joplin/lib/hooks/plugins/useVisibleP
import useConnectToEditorPlugin from './utils/useConnectToEditorPlugin';
import getResourceBaseUrl from './utils/getResourceBaseUrl';
import useInitialCursorLocation from './utils/useInitialCursorLocation';
import NotePositionService, { EditorCursorLocations } from '@joplin/lib/services/NotePositionService';
const debounce = require('debounce');
@@ -333,8 +334,8 @@ function NoteEditorContent(props: NoteEditorProps) {
const { scrollWhenReadyRef, clearScrollWhenReady } = useScrollWhenReadyOptions({
noteId: formNote.id,
selectedNoteHash: props.selectedNoteHash,
lastEditorScrollPercents: props.lastEditorScrollPercents,
editorRef,
editorName: props.bodyEditor,
});
const onMessage = useMessageHandler(scrollWhenReadyRef, clearScrollWhenReady, windowId, editorRef, setLocalSearchResultCount, props.dispatch, formNote, htmlToMarkdown, markupToHtml);
@@ -400,23 +401,14 @@ function NoteEditorContent(props: NoteEditorProps) {
}, [setShowRevisions]);
const onScroll = useCallback((event: { percent: number }) => {
props.dispatch({
type: 'EDITOR_SCROLL_PERCENT_SET',
// In callbacks of setTimeout()/setInterval(), props/state cannot be used
// to refer the current value, since they would be one or more generations old.
// For the purpose, useRef value should be used.
noteId: formNoteRef.current.id,
percent: event.percent,
});
}, [props.dispatch]);
const noteId = formNoteRef.current.id;
NotePositionService.instance().updateScrollPosition(noteId, windowId, event.percent);
}, [windowId]);
const onCursorMotion = useCallback((location: EditorCursorLocations) => {
props.dispatch({
type: 'EDITOR_CURSOR_POSITION_SET',
noteId: formNoteRef.current.id,
location,
});
}, [props.dispatch]);
const noteId = formNoteRef.current.id;
NotePositionService.instance().updateCursorPosition(noteId, windowId, location);
}, [windowId]);
function renderNoNotes(rootStyle: React.CSSProperties) {
const emptyDivStyle = {
@@ -429,7 +421,7 @@ function NoteEditorContent(props: NoteEditorProps) {
const searchMarkers = useSearchMarkers(showLocalSearch, localSearchMarkerOptions, props.searches, props.selectedSearchId, props.highlightedWords);
const initialCursorLocation = useInitialCursorLocation({
lastEditorCursorLocations: props.lastEditorCursorLocations, noteId: props.noteId,
noteId: props.noteId,
});
const markupLanguage = formNote.markup_language;
@@ -730,6 +722,8 @@ const mapStateToProps = (state: AppState, ownProps: ConnectProps) => {
bodyEditor = 'CodeMirror5';
}
const mainWindowState = stateUtils.windowStateById(state, defaultWindowId);
return {
noteId,
bodyEditor,
@@ -742,15 +736,15 @@ const mapStateToProps = (state: AppState, ownProps: ConnectProps) => {
watchedNoteFiles: state.watchedNoteFiles,
notesParentType: windowState.notesParentType,
selectedNoteTags: windowState.selectedNoteTags,
lastEditorScrollPercents: state.lastEditorScrollPercents,
lastEditorCursorLocations: state.lastEditorCursorLocations,
selectedNoteHash: windowState.selectedNoteHash,
searches: state.searches,
selectedSearchId: windowState.selectedSearchId,
customCss: state.customViewerCss,
noteVisiblePanes: windowState.noteVisiblePanes,
watchedResources: windowState.watchedResources,
highlightedWords: state.highlightedWords,
// For now, only the main window has search UI. Show the same search markers in all
// windows:
highlightedWords: mainWindowState.highlightedWords,
plugins: state.pluginService.plugins,
pluginHtmlContents: state.pluginService.pluginHtmlContents,
toolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons([

View File

@@ -17,19 +17,19 @@ describe('editorCommandDeclarations', () => {
test.each([
[
{},
true,
{ textBold: true },
],
[
{
markdownEditorPaneVisible: false,
},
false,
{ textBold: false },
],
[
{
noteIsReadOnly: true,
},
false,
{ textBold: false },
],
[
// In the Markdown editor, but only the viewer is visible
@@ -37,7 +37,7 @@ describe('editorCommandDeclarations', () => {
markdownEditorPaneVisible: false,
richTextEditorVisible: false,
},
false,
{ textBold: false },
],
[
// In the Markdown editor, and the viewer is visible
@@ -45,7 +45,7 @@ describe('editorCommandDeclarations', () => {
markdownEditorPaneVisible: true,
richTextEditorVisible: false,
},
true,
{ textBold: true },
],
[
// In the RT editor
@@ -53,7 +53,7 @@ describe('editorCommandDeclarations', () => {
markdownEditorPaneVisible: false,
richTextEditorVisible: true,
},
true,
{ textBold: true },
],
[
// In the Markdown editor, and the command palette is visible
@@ -63,14 +63,57 @@ describe('editorCommandDeclarations', () => {
gotoAnythingVisible: true,
modalDialogVisible: true,
},
true,
{ textBold: true },
],
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
])('should create the enabledCondition', (context: Record<string, any>, expected: boolean) => {
const condition = enabledCondition('textBold');
const wc = new WhenClause(condition);
const actual = wc.evaluate({ ...baseContext, ...context });
expect(actual).toBe(expected);
[
// In the Markdown editor, and the command palette is visible
{
markdownEditorPaneVisible: true,
richTextEditorVisible: false,
gotoAnythingVisible: true,
modalDialogVisible: true,
},
{ textBold: true },
],
[
// Rich Text Editor, HTML note
{
markdownEditorPaneVisible: false,
richTextEditorVisible: true,
noteIsMarkdown: false,
},
{
textCopy: true,
textPaste: true,
textSelectAll: true,
},
],
[
// Rich Text Editor, read-only note
{
markdownEditorPaneVisible: false,
richTextEditorVisible: true,
noteIsReadOnly: true,
},
{
textBold: false,
textPaste: false,
// TODO: textCopy should be enabled in read-only notes:
// textCopy: false,
},
],
])('should correctly determine whether command is enabled (case %#)', (context, expectedStates) => {
const actualStates = [];
for (const commandName of Object.keys(expectedStates)) {
const condition = enabledCondition(commandName);
const wc = new WhenClause(condition);
const actual = wc.evaluate({ ...baseContext, ...context });
actualStates.push([commandName, actual]);
}
const expectedStatesArray = Object.entries(expectedStates);
expect(actualStates).toEqual(expectedStatesArray);
});
});

View File

@@ -4,6 +4,10 @@ import { joplinCommandToTinyMceCommands } from './NoteBody/TinyMCE/utils/joplinC
const workWithHtmlNotes = [
'attachFile',
'textCopy',
'textCut',
'textPaste',
'textSelectAll',
];
export const enabledCondition = (commandName: string) => {

View File

@@ -1,7 +1,15 @@
import { LinkRenderingType } from '@joplin/renderer/MdToHtml';
import { MarkupToHtmlOptions } from './types';
import { getGlobalSettings, ResourceInfos } from '@joplin/renderer/types';
import Setting from '@joplin/lib/models/Setting';
export default (override: MarkupToHtmlOptions = null): MarkupToHtmlOptions => {
interface OptionOverride {
bodyOnly: boolean;
resourceInfos?: ResourceInfos;
allowedFilePrefixes?: string[];
}
export default (override: OptionOverride = null): MarkupToHtmlOptions => {
return {
plugins: {
checkbox: {
@@ -12,6 +20,7 @@ export default (override: MarkupToHtmlOptions = null): MarkupToHtmlOptions => {
},
},
replaceResourceInternalToExternalLinks: true,
globalSettings: getGlobalSettings(Setting),
...override,
};
};

View File

@@ -98,6 +98,10 @@ export async function getResourcesFromPasteEvent(event: any) {
const formatType = format.split('/')[0];
if (formatType === 'image') {
// writeImageToFile can process only image/jpeg, image/jpg or image/png mime types
if (['image/png', 'image/jpg', 'image/jpeg'].indexOf(format) < 0) {
continue;
}
if (event) event.preventDefault();
const image = clipboard.readImage();

View File

@@ -14,7 +14,7 @@ import { ScrollbarSize } from '@joplin/lib/models/settings/builtInMetadata';
import { RefObject, SetStateAction } from 'react';
import * as React from 'react';
import { ResourceEntity, ResourceLocalStateEntity } from '@joplin/lib/services/database/types';
import { EditorCursorLocations, NoteIdToEditorCursorLocations, NoteIdToScrollPercent } from '../../../app.reducer';
import { EditorCursorLocations } from '@joplin/lib/services/NotePositionService';
export interface AllAssetsOptions {
contentMaxWidthTarget?: string;
@@ -41,8 +41,6 @@ export interface NoteEditorProps {
notesParentType: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
selectedNoteTags: any[];
lastEditorScrollPercents: NoteIdToScrollPercent;
lastEditorCursorLocations: NoteIdToEditorCursorLocations;
selectedNoteHash: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
searches: any[];

View File

@@ -1,17 +1,17 @@
import { useMemo } from 'react';
import { EditorCursorLocations, NoteIdToEditorCursorLocations } from '../../../app.reducer';
import { useContext, useMemo } from 'react';
import { WindowIdContext } from '../../NewWindowOrIFrame';
import NotePositionService from '@joplin/lib/services/NotePositionService';
interface Props {
lastEditorCursorLocations: NoteIdToEditorCursorLocations;
noteId: string;
}
const useInitialCursorLocation = ({ noteId, lastEditorCursorLocations }: Props) => {
const lastCursorLocation = lastEditorCursorLocations[noteId];
const useInitialCursorLocation = ({ noteId }: Props) => {
const windowId = useContext(WindowIdContext);
return useMemo((): EditorCursorLocations => {
return lastCursorLocation ?? { };
}, [lastCursorLocation]);
return useMemo(() => {
return NotePositionService.instance().getCursorPosition(noteId, windowId);
}, [noteId, windowId]);
};
export default useInitialCursorLocation;

View File

@@ -1,38 +1,43 @@
import { RefObject, useCallback, useRef } from 'react';
import { RefObject, useCallback, useContext, useRef } from 'react';
import { NoteBodyEditorRef, ScrollOptions, ScrollOptionTypes } from './types';
import usePrevious from '@joplin/lib/hooks/usePrevious';
import type { NoteIdToScrollPercent } from '../../../app.reducer';
import NotePositionService from '@joplin/lib/services/NotePositionService';
import useNowEffect from '@joplin/lib/hooks/useNowEffect';
import { WindowIdContext } from '../../NewWindowOrIFrame';
interface Props {
noteId: string;
editorName: string;
selectedNoteHash: string;
lastEditorScrollPercents: NoteIdToScrollPercent;
editorRef: RefObject<NoteBodyEditorRef>;
}
const useScrollWhenReadyOptions = ({ noteId, selectedNoteHash, lastEditorScrollPercents, editorRef }: Props) => {
const useScrollWhenReadyOptions = ({ noteId, editorName, selectedNoteHash, editorRef }: Props) => {
const scrollWhenReadyRef = useRef<ScrollOptions|null>(null);
const previousNoteId = usePrevious(noteId);
const lastScrollPercentsRef = useRef<NoteIdToScrollPercent>(null);
lastScrollPercentsRef.current = lastEditorScrollPercents;
const previousEditor = usePrevious(editorName);
const windowId = useContext(WindowIdContext);
// This needs to be a nowEffect to prevent race conditions
useNowEffect(() => {
if (noteId === previousNoteId) return () => {};
const editorChanged = editorName !== previousEditor;
const noteIdChanged = noteId !== previousNoteId;
if (!editorChanged && !noteIdChanged) return () => {};
const lastScrollPercent = NotePositionService.instance().getScrollPercent(noteId, windowId) || 0;
scrollWhenReadyRef.current = {
type: selectedNoteHash ? ScrollOptionTypes.Hash : ScrollOptionTypes.Percent,
value: selectedNoteHash ? selectedNoteHash : lastScrollPercent,
};
if (editorRef.current) {
editorRef.current.resetScroll();
}
const lastScrollPercent = lastScrollPercentsRef.current[noteId] || 0;
scrollWhenReadyRef.current = {
type: selectedNoteHash ? ScrollOptionTypes.Hash : ScrollOptionTypes.Percent,
value: selectedNoteHash ? selectedNoteHash : lastScrollPercent,
};
return () => {};
}, [noteId, previousNoteId, selectedNoteHash, editorRef]);
}, [editorName, previousEditor, noteId, previousNoteId, selectedNoteHash, editorRef, windowId]);
const clearScrollWhenReady = useCallback(() => {
scrollWhenReadyRef.current = null;

View File

@@ -2,7 +2,7 @@ import { RefObject, Dispatch, SetStateAction, useEffect } from 'react';
import { WindowCommandDependencies, NoteBodyEditorRef, OnChangeEvent, ScrollOptionTypes } from './types';
import editorCommandDeclarations, { enabledCondition } from '../editorCommandDeclarations';
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext, RegisteredRuntime } from '@joplin/lib/services/CommandService';
import time from '@joplin/lib/time';
import { formatMsToLocal } from '@joplin/utils/time';
import { reg } from '@joplin/lib/registry';
import getWindowCommandPriority from './getWindowCommandPriority';
@@ -50,7 +50,7 @@ function editorCommandRuntime(
if (declaration.name === 'insertDateTime') {
return editorRef.current.execCommand({
name: 'insertText',
value: time.formatMsToLocal(new Date().getTime()),
value: formatMsToLocal(Date.now()),
});
} else if (declaration.name === 'scrollToHash') {
return editorRef.current.scrollTo({

View File

@@ -501,7 +501,12 @@ class NotePropertiesDialog extends React.Component<Props, State> {
<div role='table' aria-labelledby='note-properties-dialog-title'>
{noteComps}
</div>
<DialogButtonRow themeId={this.props.themeId} okButtonShow={!this.isReadOnly()} okButtonRef={this.okButton} onClick={this.buttonRow_click}/>
<DialogButtonRow
themeId={this.props.themeId}
okButtonShow={!this.isReadOnly()}
okButtonRef={this.okButton}
onClick={this.buttonRow_click}
/>
</Dialog>
);
}

View File

@@ -25,6 +25,8 @@ import useAsyncEffect from '@joplin/lib/hooks/useAsyncEffect';
import { ScrollbarSize } from '@joplin/lib/models/settings/builtInMetadata';
import { focus } from '@joplin/lib/utils/focusHandler';
import useDeleteHistoryClick from '@joplin/lib/components/shared/NoteRevisionViewer/useDeleteHistoryClick';
import { getGlobalSettings } from '@joplin/renderer/types';
import Setting from '@joplin/lib/models/Setting';
interface Props {
themeId: number;
@@ -72,6 +74,7 @@ const useNoteContent = (
const result = await markupToHtml(markupLanguage, noteBody, {
resources: await shared.attachedResources(noteBody),
whiteBackgroundNoteRendering: markupLanguage === MarkupLanguage.Html,
globalSettings: getGlobalSettings(Setting),
});
viewerRef.current.setHtml(result.html, {

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