1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-12-08 23:07:32 +02:00

Compare commits

...

533 Commits

Author SHA1 Message Date
Laurent Cozic
8713cd2fd8 CLI v3.5.1 2025-10-18 10:11:50 +01:00
Laurent Cozic
d0fc4ea21b Lock file 2025-10-18 10:11:18 +01:00
Laurent Cozic
8bd62800ef Releasing sub-packages 2025-10-18 10:10:42 +01:00
Laurent Cozic
00f9e932e6 Desktop release v3.5.5 2025-10-18 09:53:34 +01:00
Helmut K. C. Tessarek
b8b55e4a55 Chore: Fix generated file line ending (#13459) 2025-10-18 09:50:37 +01:00
renovate[bot]
ef5be2ded3 Update dependency @types/node to v18.19.130 (#13463)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-18 09:49:19 +01:00
Henry Heino
00702dde00 Desktop: OneNote importer: Improve file header validation (#13467) 2025-10-18 09:48:51 +01:00
Henry Heino
2a6af9bed9 Desktop: Accessibility: Allow jumping to notebooks by typing the initial letter or Home/End (#13469) 2025-10-18 09:48:44 +01:00
Henry Heino
c26fe0960b Web: Show sync wizard on first start (#13470) 2025-10-18 09:48:13 +01:00
Henry Heino
ab9d36fc08 Chore: Windows: Tests: Fix Rust OneNote importer tests fail (#13471) 2025-10-18 09:48:03 +01:00
Henry Heino
28eb53bd9f Desktop: OneNote importer: Support directly importing .one files and, on Windows, .onepkg files (#13474)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-18 09:47:35 +01:00
Laurent Cozic
3097c3e589 Desktop, Cli: Correctly import Evernote resources that do not have the encoding specified 2025-10-18 09:44:35 +01:00
renovate[bot]
08371ef718 Update dependency @types/serviceworker to v0.0.144 (#13475)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-18 08:19:27 +00:00
Laurent Cozic
561716efea Desktop, Cli: Fixed importing certain Evernote images that have invalid dimension attributes (#13472) 2025-10-18 09:17:22 +01:00
renovate[bot]
0d457d1bde Update dependency esbuild to v0.25.7 (#13461)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-17 09:18:57 +01:00
renovate[bot]
8c11f17c93 Update dependency @types/node to v18.19.120 (#13460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-17 09:18:50 +01:00
renovate[bot]
f7a90ee1d2 Update dependency @types/serviceworker to v0.0.143 (#13449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-17 09:18:08 +01:00
Eric Duarte
8822409f7c All: Translation: Update ca.po (#13462) 2025-10-17 03:54:42 -04:00
Eric Duarte
cd3e7f485a All: Translation: Update es_ES.po (#13454) 2025-10-16 17:25:46 -04:00
summoner
8d42b01d4f All: Translation: Update hu_HU.po (#13451) 2025-10-16 17:25:34 -04:00
Henry Heino
2c37197641 Desktop: Resolves #520: Save and restore the cursor position when switching between notes (#13447) 2025-10-16 14:56:38 +01:00
Henry Heino
c2c37b3741 Desktop: Fixes #13411: Fix header links only work if the note viewer is visible (#13442) 2025-10-16 12:10:01 +01:00
Henry Heino
3e770300dc Chore: Desktop: Add tool for resolving stack traces based on source maps (#13427) 2025-10-16 12:09:02 +01:00
Henry Heino
683291d5df Chore: Transcribe: Make logic for starting transcription workers safer (#13425) 2025-10-16 12:08:52 +01:00
Henry Heino
d239035417 Mobile: Resolves #13067: Rich Text Editor: Improve table support (#13413)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-16 12:08:44 +01:00
Henry Heino
5ef37d9de0 Desktop: Support importing .one files from OneNote 2016 (#13391) 2025-10-16 12:08:35 +01:00
mrjo118
1111bde017 All: Fixes #6517: Prevent Joplin from missing changes when syncing with file system or WebDAV (#13054) 2025-10-16 12:06:48 +01:00
Laurent Cozic
468cf00d77 Chore: Clean-up exclusion list in buildTranslation 2025-10-16 11:20:05 +01:00
Laurent Cozic
3c5b41b992 Chore: Fixed CI 2025-10-16 11:19:44 +01:00
Helmut K. C. Tessarek
5f66c51dba All: Update translations 2025-10-15 23:34:40 -04:00
k-santos
bfeaa67ec4 All: Translation: Update pt_BR.po (#13448) 2025-10-15 23:30:16 -04:00
renovate[bot]
348fd0333f Update dependency react-native-share to v12.1.0 (#13446)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 21:19:13 +01:00
Henry Heino
51c4d6d6ef Desktop: Upgrade to Electron v37.7.0 (#13445) 2025-10-15 20:39:26 +01:00
Laurent Cozic
09d77a65e8 Plugin Repo CLI v3.5.1 2025-10-15 20:03:29 +01:00
Laurent Cozic
d1aec4a9f7 Plugin Generator release v3.5.1 2025-10-15 20:02:14 +01:00
Henry Heino
cab1525589 Chore: Plugin repository script: Fix certain plugins are not being published (#13443) 2025-10-15 20:00:29 +01:00
Henry Heino
a52f3fea9e Mobile: Resolves: #12823: Disable auto-search for 1-2 character searches (#13444)
Co-authored-by: pedr <pedr@users.noreply.github.com>
2025-10-15 20:00:02 +01:00
renovate[bot]
dfbd5eb8ed Update dependency expo to v53.0.20 (#13441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 14:18:13 +01:00
Laurent Cozic
3131f36033 Chore: Trying to fix random CI failure 2025-10-15 12:55:40 +01:00
renovate[bot]
dc5b2cfa21 Update dependency form-data to v4.0.4 (#13439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 09:42:15 +00:00
renovate[bot]
cad0f35fcc Update dependency expo-camera to v16.1.11 (#13438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 02:43:03 +00:00
renovate[bot]
38ea92ff57 Update dependency axios to v1.10.0 (#13431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 14:35:53 +01:00
renovate[bot]
830deada22 Update dependency @types/serviceworker to v0.0.142 (#13434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 18:47:47 +01:00
renovate[bot]
38cd4033ea Update dependency @types/node to v18.19.119 (#13435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 13:36:57 +00:00
Shania
02900752d9 Doc: Missing hashtag in rich_text_editor.md (#13418) 2025-10-11 12:56:26 +01:00
renovate[bot]
091e9813b5 Update dependency @react-native/babel-preset to v0.80.1 (#13426)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-11 01:23:33 +01:00
renovate[bot]
e61e5ac32a Update dependency @react-native/babel-preset to v0.80.0 (#13423)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-10 21:28:24 +01:00
Joplin Bot
414970c9a1 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-10-10 18:39:00 +00:00
Laurent Cozic
d4ed49ff23 Doc: Clarify how to disable spellchecking on Markdown files 2025-10-10 17:48:37 +01:00
Laurent Cozic
8751d5d152 Doc: Add documentation for LDAP and SAML support in Joplin Server 2025-10-10 17:47:28 +01:00
Laurent Cozic
2e846fe15d Desktop release v3.5.4 2025-10-10 15:48:13 +01:00
Laurent Cozic
e54b7696d9 Chore: Prevent sign tool from being added to the Windows app 2025-10-10 15:48:01 +01:00
Laurent Cozic
553c61d628 Desktop release v3.5.3 2025-10-10 12:12:32 +01:00
Laurent Cozic
6a15db3a36 Chore: Implement SSL eSigner for Windows app signing (#13397) 2025-10-10 11:18:43 +01:00
Laurent Cozic
6f1d0a4b90 Chore: Disable time drift check on Joplin Server tests (#13420) 2025-10-10 11:18:18 +01:00
renovate[bot]
33b995672c Update dependency @playwright/test to v1.53.2 (#13421)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-10 11:18:04 +01:00
mrjo118
8ee46bb4e7 All: Avoid excessive data usage when automatically triggering another sync (#13261) 2025-10-10 09:36:42 +01:00
renovate[bot]
b35d9a64cf Update dependency @playwright/test to v1.53.0 (#13410)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-09 22:36:48 +01:00
renovate[bot]
64ef74dd01 Update dependency @types/node to v18.19.118 (#13412)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-09 22:36:39 +01:00
mrjo118
53035839a5 Desktop, Mobile: Fix historic issue whereby the first revision created for a note does not contain the original contents (#12674)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-09 22:35:08 +01:00
Henry Heino
af5287de99 Desktop: OCR: Fully disable the handwriting transcription backend when disabled in settings (#13072) 2025-10-09 22:21:49 +01:00
mrjo118
45a7554774 All: Fixes #11902: Ensure notebook conflicts do not delete child notes and notebooks when resolved (#13167)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-09 22:21:14 +01:00
Henry Heino
b06ffe3d25 Mobile,Desktop: Resolves #12343: Markdown editor search: Auto-scroll to the next match when the search changes (#13242)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-09 22:20:34 +01:00
mrjo118
53ea51b758 All: Fixes 12810: Ensure the sync shows an error when the server is down, when using a local WebDAV server (#13301) 2025-10-09 21:59:58 +01:00
Tom Chedmail
820acdc1f0 All: Fixes #13328: Implement the config check for Joplin Server with SAML enabled (#13360) 2025-10-09 21:49:18 +01:00
Henry Heino
ef0a79666e Desktop: OneNote importer: Simplify reporting import issues to the forum (#13409) 2025-10-09 21:47:31 +01:00
Henry Heino
d096a90c0e Chore: shim.mobilePlatform: Use a stronger return type (#13415) 2025-10-09 21:46:04 +01:00
renovate[bot]
191775310e Update dependency react-select to v5.10.2 (#13417)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-09 20:42:35 +00:00
renovate[bot]
4fc351b861 Update dependency @react-native-documents/picker to v10.1.5 (#13416)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-09 04:55:42 +00:00
renovate[bot]
396decd26c Update dependency sharp to v0.34.3 (#13404)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-08 13:45:43 +01:00
yingli-lab
01f8fa7bef Desktop: Fixes #13267: Fixed image load failure when path contains '#' (13267) (#13375) 2025-10-08 09:34:52 +01:00
Henry Heino
c40856ac7e Docs: Mobile: Add documentation for the mobile document scanner (#13387) 2025-10-08 09:33:45 +01:00
Henry Heino
d869cce413 Mobile: Document scanner: Add "Recognise text" checkbox (#13398) 2025-10-08 09:33:05 +01:00
Henry Heino
a83e8311d8 Server: Fixes #13400: Fix password fields are always disabled (#13401) 2025-10-08 09:32:24 +01:00
renovate[bot]
aa884fcb39 Update dependency @react-native-documents/picker to v10.1.4 (#13403)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-08 06:58:50 +00:00
Henry Heino
be2a4c3e24 Chore: Correct license information for packages/onenote-converter (#13392) 2025-10-07 10:01:52 +01:00
renovate[bot]
520eec555b Update dependency @types/node to v18.19.117 (#13395)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-07 05:08:10 +00:00
renovate[bot]
1281fdb9d2 Update dependency @types/node to v18.19.116 (#13394)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-07 00:55:38 +01:00
renovate[bot]
6029353fd1 Update dependency react-native-webview to v13.15.0 (#13388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-06 17:49:23 +01:00
Laurent Cozic
8d1d1be79e Doc: Resolves #13370: Add documentation for user profiles (#13377) 2025-10-06 09:45:22 +01:00
bwat47
fd180ae0b4 Desktop: Add write() method to Plugin Clipboard API (#13348) 2025-10-06 09:31:27 +01:00
Laurent Cozic
6fdfd6eae6 Desktop: Resolves #13371: Open the Joplin Plugin web page when clicking on a plugin name (#13376) 2025-10-06 09:30:04 +01:00
Laurent Cozic
cd5bb575c8 Server: Resolves #13369: SAML users cannot modify their own profile at all (#13378) 2025-10-06 09:29:53 +01:00
Laurent Cozic
2df56530ae All: Remove Beta mention for Joplin Server (#13367) 2025-10-06 09:28:24 +01:00
Laurent Cozic
7987137470 Chore: Trying to migrate to macOS 15 on CI (#13366) 2025-10-06 09:28:13 +01:00
Manu Erwin
a1dcd2fd8f Doc: Update trash.md (#13383) 2025-10-06 08:40:10 +01:00
renovate[bot]
7826dc064a Update dependency @types/serviceworker to v0.0.141 (#13385)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-06 08:39:30 +01:00
renovate[bot]
eedf083bfd Update dependency esbuild to v0.25.6 (#13380)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-05 20:53:13 +00:00
renovate[bot]
d4aa1f8f8d Update dependency pg-boss to v10.3.2 (#13353)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-05 17:57:51 +01:00
Henry Heino
738e749d51 Desktop: Fixes #13346: Fix startup error when a non-English locale is selected (#13347) 2025-10-04 16:08:23 +01:00
renovate[bot]
8fe818c0b0 Update dependency samlify to v2.10.1 (#13362)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-04 09:25:20 +01:00
maggie897
e603452fad Desktop: Fixes #13088: Hide 'Start application minimised' unless tray icon is enabled (#13340) 2025-10-03 14:42:45 +01:00
mrjo118
3827637b54 Mobile: Make the conflicts folder text use the error colour, like is done on desktop (#13343) 2025-10-03 14:41:55 +01:00
Henry Heino
1da7c54e5f Chore: Add test for joplinServerConnected condition (#13352) 2025-10-03 14:32:57 +01:00
Henry Heino
e24ebffba6 Desktop: Resolves #12803: Upgrade tesseract.js to v6 (#13345)
Co-authored-by: pedr <pedr@users.noreply.github.com>
2025-10-03 14:32:15 +01:00
Laurent Cozic
e5bd77836a Desktop release v3.5.2 2025-10-02 09:14:44 +01:00
Henry Heino
8f5e628303 Chore: Fix CI (#13344) 2025-10-02 09:14:14 +01:00
Laurent Cozic
6850c8128b Desktop release v3.5.1 2025-10-02 09:13:48 +01:00
Laurent Cozic
8a797fdf23 Server: Enable publish and share notebook for SAML login 2025-10-02 09:13:29 +01:00
Laurent Cozic
1ae550c0aa Chore: Setup new release 3.5 2025-10-02 09:12:11 +01:00
maggie897
e7e0529f52 Desktop: Resolves #12292: Add hover + expanded arrow behavior for Notebook/Tags header (#13190)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-01 23:20:33 +01:00
Henry Heino
2381e44c7f Chore: OneNote importer: Upgrade to Rust 2024 (#13298)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-10-01 10:22:33 +01:00
renovate[bot]
a59e975f73 Update dependency sharp to v0.34.2 (#13336)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 09:35:07 +01:00
Henry Heino
2d703b6292 Mobile: Resolves #13123: Add sync wizard (#13234) 2025-10-01 09:34:18 +01:00
renovate[bot]
b8db70f707 Update eslint (#13337)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 04:17:48 +00:00
Filbert Wijaya
c91513b6b5 All: Translation: Update ja_JP.po (#13339) 2025-10-01 00:15:56 -04:00
Joplin Bot
a57ada97ef Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-10-01 01:51:34 +00:00
Laurent Cozic
d8677a70dd Transcribe: Resolves #12874: Downscale images before storing (#13333) 2025-09-30 23:17:01 +01:00
renovate[bot]
15839a19fd Update dependency rate-limiter-flexible to v6.2.1 (#13334)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-30 23:10:14 +01:00
renovate[bot]
8f1d55c1fc Update dependency rate-limiter-flexible to v6 (#13325)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-30 20:03:59 +01:00
JZou-Code
98c18711f7 Desktop: Fixes #12531: Fix the order of attached images (#12531) (#12868) 2025-09-30 17:44:38 +01:00
Henry Heino
24ff4612fb Mobile: Resolves #13104: Accessibility: Allow changing the ALT text of images from the mobile Rich Text Editor (#13169)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-30 17:34:03 +01:00
Henry Heino
f832eb38ff Mobile: Improve inline search performance in large documents (#13259) 2025-09-30 17:22:55 +01:00
Henry Heino
91dc23c23f Android: Plugins: Fix inspecting note editor WebViews (#13272) 2025-09-30 17:17:34 +01:00
Henry Heino
d1913493ab Desktop: Fix "insecure content security policy" warning (#13288)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-30 17:08:48 +01:00
trap000d
fd2b22ed68 Desktop: Resolves #12572: Click on systray icon will show/hide Joplin main window (#13299)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-30 17:05:44 +01:00
Henry Heino
14b56f19df Chore: OneNote converter: Refactor to allow debugging the import process, reduce use of "unsafe" (#13300) 2025-09-30 17:03:38 +01:00
renovate[bot]
0b082a985b Update dependency @react-native-clipboard/clipboard to v1.16.3 (#13304)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-30 16:50:29 +01:00
mrjo118
53dcac22d0 Mobile: For notes over 100,000 characters, make the share note function share them as a file (#13305) 2025-09-30 16:49:54 +01:00
Henry Heino
2c721a76b7 Chore: Fix transcription server build (#13310) 2025-09-30 16:45:16 +01:00
yingli-lab
b68cfd6d9e Desktop: Fixes #13196: Fixed red close button not working on macOS 26 (#13311) 2025-09-30 16:43:58 +01:00
JZou-Code
affebedc4b Desktop: Fixes #12763: skip copy event in TinyMCE if no content is selected. (#13313) 2025-09-30 16:37:44 +01:00
JZou-Code
a714ef4807 Desktop: Fixes #13314: skip cut action in TinyMCE editor if no content is selected. (#13315) 2025-09-30 16:35:38 +01:00
renovate[bot]
596f99aad3 Update dependency @types/node to v18.19.115 (#13332)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-30 16:32:47 +01:00
renovate[bot]
c530d35b36 Update dependency @react-native/metro-config to v0.79.5 (#13331)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-30 02:49:10 +00:00
renovate[bot]
5a5c734e2a Update dependency @react-native/babel-preset to v0.79.5 (#13329)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 21:56:41 +00:00
renovate[bot]
f7eb483d9a Update dependency react-native-webview to v13.14.2 (#13327)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 17:10:00 +01:00
Laurent Cozic
7f3c7e807c Desktop: Use plugin repository URL when homepage URL is not available in config screen (#13318) 2025-09-29 14:35:55 +01:00
renovate[bot]
a50fc02b32 Update dependency react-native-webview to v13.14.0 (#13324)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 14:35:39 +01:00
renovate[bot]
63702e9e34 Update dependency @types/serviceworker to v0.0.140 (#13321)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 02:48:55 +00:00
renovate[bot]
92c67aab4e Update dependency @types/node to v18.19.113 (#13320)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 02:46:26 +00:00
renovate[bot]
91535870a2 Update dependency react-native-localize to v3.4.2 (#13289)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-28 21:48:19 +01:00
renovate[bot]
d4bb277417 Update dependency pg to v8.16.3 (#13296)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-28 21:48:06 +01:00
krevad
90f87d1496 All: Translation: Update sv.po (#13316) 2025-09-28 14:44:42 -04:00
Joplin Bot
b07752b3ab Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-28 12:47:37 +00:00
Laurent Cozic
98effef4c5 Server: Improve SAML login error handling and add doc regarding email and displayName attributes 2025-09-28 12:48:56 +01:00
Laurent Cozic
32a919eb81 Chore: Remove obsolete "version" parameter from docker-compose files 2025-09-28 12:44:00 +01:00
Laurent Cozic
e124fd5c9f Chore: Set URLs to absolute ones on release notes and tweak title 2025-09-28 10:23:56 +01:00
Joplin Bot
c5f9290402 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-27 10:41:21 +00:00
Henry Heino
c80cdadc99 Doc: Add release notes for v3.4 (#13273) 2025-09-27 10:20:31 +01:00
Laurent Cozic
d96dcef109 Chore: Trying to fix GitHub Actions size issue (#13290) 2025-09-25 23:33:02 +01:00
Henry Heino
33b889ca38 Chore: Fix APK alignment check in CI (#13294) 2025-09-25 20:48:56 +01:00
Laurent Cozic
fa78ea0173 Server v3.4.4 2025-09-25 14:19:26 +01:00
Laurent Cozic
6705712f80 Server: Use "lax" cookies when using external authentication like SAML or LDAP 2025-09-25 12:12:14 +01:00
renovate[bot]
2785b7f7d9 Update dependency @react-native-community/datetimepicker to v8.4.2 (#13285)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-24 14:10:36 +01:00
Laurent Cozic
f04831406e Server: Trying to make logging more robust 2025-09-24 12:37:49 +01:00
renovate[bot]
fdffc81834 Update dependency @react-native-community/datetimepicker to v8.4.1 (#13279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-24 11:13:51 +01:00
Henry Heino
6f113df2d6 Chore: Sync fuzzer: Fix failures related to publishing/unpublishing notes (#13282) 2025-09-24 11:12:58 +01:00
Henry Heino
8b8b6fbe36 Desktop: Accessibility: Disable sync icon animation when reduce motion is enabled (#13283) 2025-09-24 11:12:38 +01:00
Laurent Cozic
1ef8fd529b Server: Provide more logging information for each request to help debugging issues 2025-09-24 10:46:24 +01:00
Marcus Kida
9547a459cb All: Translation: Update de_DE.po (#13275) 2025-09-23 11:11:34 -04:00
Joplin Bot
be1d092cab Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-23 01:32:34 +00:00
Laurent Cozic
517669ee27 Doc: Update sponsors 2025-09-22 22:29:54 +01:00
Laurent Cozic
72fc97116f Chore: Update renovate.json5 - ignore @react-native-community/cli-platform-ios package 2025-09-22 17:46:53 +01:00
Laurent Cozic
77ca6b3447 Chore: Update renovate.json5 - ignore @react-native-community/cli* packages 2025-09-22 17:46:21 +01:00
renovate[bot]
b227d337d0 Update dependency sass to v1.93.0 (#13255)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 17:44:44 +01:00
Henry Heino
a6e671d45b Android: Improve location permission request (#13248) 2025-09-20 10:00:15 +01:00
Henry Heino
47c82a7e75 Chore: Mobile: Fix expo-related warnings in tests (#13260) 2025-09-20 01:25:49 +01:00
summoner
bafa1576f2 All: Translations: Update hu_HU.po (#13256) 2025-09-19 16:11:45 -04:00
Henry Heino
48956df439 Chore: Fix web app build (#13257) 2025-09-19 17:37:28 +01:00
renovate[bot]
4716065295 Update dependency pg to v8.16.2 (#13236)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-19 09:24:41 +01:00
renovate[bot]
f801bbfb27 Update dependency sass to v1.89.2 (#13237)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-19 09:24:24 +01:00
Henry Heino
4a043f68ad Chore: Web: Fix build (#13250) 2025-09-19 09:22:22 +01:00
renovate[bot]
cac93e9f9c Update dependency react-native-paper to v5.14.5 (#13230)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-18 14:25:08 +01:00
mrjo118
e1e5c9aeb0 Mobile: Remove expandable title field on Web client and fix icon alignment (#13240)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-18 14:24:49 +01:00
Henry Heino
382cb257ab Web: Fix multi-page document creation action fails for non-JPEG images (#13244)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-18 14:23:57 +01:00
Laurent Cozic
6f375be8b9 Server: Pin pm2-logrotate version to prevent supply chain attacks (#13235) 2025-09-18 12:03:57 +01:00
Laurent Cozic
a118615e06 Chore: Remove bitnami repository (#13239) 2025-09-18 10:34:01 +01:00
Joplin Bot
912bf7463f Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-17 18:38:33 +00:00
Laurent Cozic
cfc29832a2 Doc: Update sponsors 2025-09-17 18:07:34 +01:00
renovate[bot]
737fd132e3 Update dependency sass to v1.89.0 (#13231)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 16:53:56 +01:00
renovate[bot]
9fc76f4e4c Update dependency pg to v8.16.0 (#13223)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 16:27:13 +01:00
renovate[bot]
981f15d85c Update dependency node-mocks-http to v1.17.2 (#13221)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 16:26:43 +01:00
renovate[bot]
a59594db3b Update dependency nodejs to v23.11.0 (#13222)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 16:26:35 +01:00
JZou-Code
8c8190e2e9 Desktop: Fixes #12239: Prevent the default cut action handler to avoid double deletion (#13208) 2025-09-16 13:22:26 +01:00
Henry Heino
d7e7ff77e8 Chore: Mobile: Add additional logging to help debug toolbar issue (#13224)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-16 13:18:12 +01:00
Henry Heino
e33c142c5a Chore: Web: Skip secondary single-instance check in dev mode (#13225)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-16 12:52:43 +01:00
Laurent Cozic
97d3a8243d Chore: Fix CI (#13227) 2025-09-16 08:50:28 +01:00
renovate[bot]
f1716a3edb Update dependency @pmmmwh/react-refresh-webpack-plugin to ^0.6.0 (#13219)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 18:39:20 +01:00
renovate[bot]
1436f5867d Update dependency androidx.documentfile:documentfile to v1.1.0 (#13220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 18:37:53 +01:00
renovate[bot]
d754b8fe0c Update dependency @rollup/plugin-commonjs to v28.0.6 (#13218)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 17:05:58 +01:00
renovate[bot]
4f58055cc1 Update dependency @react-native/metro-config to v0.79.4 (#13217)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 16:38:15 +01:00
renovate[bot]
98697e1db4 Update dependency style-to-js to v1.1.17 (#13209)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-15 16:30:10 +01:00
renovate[bot]
8ac65a08c1 Update dependency @react-native/babel-preset to v0.79.4 (#13213)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 15:06:33 +01:00
renovate[bot]
2b86d83290 Update dependency @babel/plugin-transform-export-namespace-from to v7.27.1 (#13212)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 13:18:34 +01:00
renovate[bot]
09cafe99d1 Update bitnami/postgresql Docker tag to v17.4.0 (#13211)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 11:33:22 +01:00
renovate[bot]
6fce844cbf Update dependency webpack-dev-server to v5.2.2 (#13210)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 09:01:07 +01:00
renovate[bot]
52de8c071f Update dependency glob to v11.0.3 (#13205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-15 09:00:01 +01:00
renovate[bot]
537543cc8a Update dependency react-native-zip-archive to v7.0.2 (#13207)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 00:29:44 +00:00
renovate[bot]
ff16453299 Update dependency js-draw to v1.30.1 (#13206)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 00:27:57 +00:00
renovate[bot]
210deec495 Update dependency form-data to v4.0.3 (#13203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-14 19:03:16 +01:00
renovate[bot]
e96baea005 Update dependency @types/tar-stream to v3.1.4 (#13202)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-14 19:03:05 +01:00
renovate[bot]
ae24b91f25 Update dependency @types/node to v18.19.112 (#13204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-14 19:02:56 +01:00
renovate[bot]
f2e5118bf5 Update dependency @types/serviceworker to v0.0.139 (#13201)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-14 12:36:40 +00:00
renovate[bot]
72698ec573 Update dependency @react-native/metro-config to v0.79.3 (#13198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-14 09:35:05 +01:00
renovate[bot]
68abc27c6a Update dependency @types/react to v18.3.23 (#13200)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-14 09:34:56 +01:00
renovate[bot]
1acb3d0726 Update dependency @rollup/plugin-commonjs to v28.0.5 (#13199)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-14 09:34:48 +01:00
Joplin Bot
5bf97dc3b8 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-14 01:38:57 +00:00
Laurent Cozic
e0e04fbc91 Chore: Fixed type error 2025-09-14 00:44:36 +01:00
Laurent Cozic
625cd1221c Doc: Update sponsors 2025-09-14 00:41:03 +01:00
Henry Heino
110d5bde2d Desktop: Fix error dialogs fail to appear in certain cases (#13179) 2025-09-13 14:21:38 +01:00
renovate[bot]
93a85b3207 Update dependency @types/node to v18.19.111 (#13165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-13 14:18:04 +01:00
renovate[bot]
ff305f42fd Update dependency @js-draw/material-icons to v1.30.1 (#13164)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-13 14:17:50 +01:00
Henry Heino
99ba854ee1 Chore: Cli: Fix CLI app integration tests (#13089) 2025-09-13 14:17:40 +01:00
mrjo118
38b368e997 Mobile: Resolves #12936: Allow expanding and collapsing the title field across multiple lines (#13016) 2025-09-13 14:08:31 +01:00
Henry Heino
f9ffe6c4e6 Desktop,Mobile,Cli: Fix notes are moved to the conflict folder when a folder is unshared (#12993)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-13 14:08:19 +01:00
pedr
5adc0170fc All: Resolves #8718: Delete all note revisions when the note is permanently deleted (#12609) 2025-09-13 14:06:56 +01:00
mrjo118
f54c364b4d Desktop, Mobile: Automatically retrigger the sync if there are more unsynced outgoing changes when sync completes (#12989) 2025-09-13 14:05:31 +01:00
mrjo118
9f541b9b9d Desktop, Mobile: Add support for mixed case tags (#12931)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2025-09-13 14:01:33 +01:00
Henry Heino
bd0af08c57 Docs: REST API: Add descriptions for "is_shared" and "share_id" (#13186) 2025-09-13 13:52:46 +01:00
Henry Heino
ac06c6750d Android: Fixes #13113: Fix compatibility with 16-KB-page-size devices: Remove Vosk (#13189) 2025-09-13 13:52:12 +01:00
renovate[bot]
23b07094b7 Update dependency @react-native/babel-preset to v0.79.3 (#13195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-13 13:48:57 +01:00
Joplin Bot
7eefc016de Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-13 12:45:33 +00:00
Laurent Cozic
c002be76cd Doc: Update sponsors 2025-09-13 12:00:32 +01:00
renovate[bot]
2cd29aaaea Update dependency react-native-image-picker to v8.2.1 (#13002)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-09-12 22:48:44 +01:00
Laurent Cozic
4cb6b01c71 Server: Clean-up SAML login section 2025-09-12 15:14:22 +01:00
Joplin Bot
91c79b9488 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-10 12:42:24 +00:00
Henry Heino
fc516d05b3 Docs: Update the Rich Text Editor documentation (#13171) 2025-09-10 10:44:29 +01:00
Henry Heino
2769c9586c Mobile: Fixes #13138: Rich Text Editor: Fix image size lost on change (#13172) 2025-09-10 10:06:40 +01:00
Henry Heino
fd15d5a6d3 Mobile: Rich Text Editor: Accessibility: Fix font size setting not respected (#13174) 2025-09-10 10:05:51 +01:00
krevad
7237d7faa7 All: Translation: Update sv.po (#13170)
Co-authored-by: Helmut K. C. Tessarek <tessarek@evermeet.cx>
2025-09-09 19:37:19 -04:00
Henry Heino
3025d62568 Chore: Fix CI (#13168) 2025-09-09 22:31:55 +01:00
renovate[bot]
5b5dcf34a1 Update dependency @axe-core/playwright to v4.10.2 (#13162)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-09 09:54:36 +01:00
Laurent Cozic
9e8500c148 Server v3.4.3 2025-09-09 09:47:29 +01:00
Laurent Cozic
4f1999f921 Merge branch 'release-3.4' into dev 2025-09-09 09:46:39 +01:00
Laurent Cozic
6ee9571069 iOS 13.4.3 2025-09-09 09:25:40 +01:00
krevad
10663b1494 All: Translation: Update sv.po (#13163) 2025-09-09 04:15:15 -04:00
Laurent Cozic
f25db9bbd7 Android 3.4.7 2025-09-09 09:14:11 +01:00
Laurent Cozic
44ac261304 Desktop release v3.4.11 2025-09-09 09:05:11 +01:00
renovate[bot]
eac995a209 Update dependency esbuild to v0.25.5 (#13040)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2025-09-09 00:32:19 +01:00
Henry Heino
15c973e885 Chore: Mobile: Add additional plugin panel integration tests (#13152) 2025-09-09 00:31:12 +01:00
Henry Heino
1762f9485f Web: Fixes #13153: Fix installing certain plugins (#13154) 2025-09-09 00:30:48 +01:00
Henry Heino
7777f8428f Desktop: Upgrade to Electron 37.4.0 (#13156) 2025-09-09 00:30:06 +01:00
Henry Heino
948aa9db4f Mobile: Upgrade react-native-quick-crypto to v0.7.17 (#13155) 2025-09-09 00:07:29 +01:00
Henry Heino
fdde04ee85 Desktop,Mobile,Cli: Support accepting shares with a new key format (#12829) 2025-09-08 23:56:40 +01:00
Laurent Cozic
f77a20f5d5 Merge branch 'release-3.4' into dev 2025-09-08 23:55:24 +01:00
Henry Heino
d43aa2a3e6 Web: Update the beta notice (#13150) 2025-09-08 23:47:19 +01:00
Henry Heino
04d5ce13c2 Chore: Android: Compile Whisper with support for 16 KB pages (#13118) 2025-09-08 16:50:48 +01:00
Laurent Cozic
3b764ba06a Server: Remove the need to install pm2-logrotate on startup so that image can work in a closed environment (#13149) 2025-09-08 16:37:35 +01:00
Henry Heino
5492ce55fa Server: Fixes #12984: Improve handling of concurrent deletion requests for the same item (#13092) 2025-09-08 12:03:20 +01:00
Henry Heino
f6b3f9860c Cli: Fix last change sometimes lost when not in TUI mode (#13090) 2025-09-08 12:03:13 +01:00
Henry Heino
88f687ba6a Chore: Sync fuzzer: Add actions for publishing and unpublishing notes (#13062) 2025-09-08 12:02:53 +01:00
Henry Heino
1f0a98999f Desktop, Mobile: Fixes #12987: Fix images rendered in the Markdown editor don't reload when downloaded (#13045) 2025-09-08 12:01:54 +01:00
mrjo118
69135c3bea Mobile: Fixes #12956: Resize the notes menu to the viewport when the keyboard is open (#13035) 2025-09-08 12:01:24 +01:00
pedr
c27d542a4b Desktop: Fixes #12049: Fix files without extension not being imported properly (#12974)
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
2025-09-08 11:46:36 +01:00
mrjo118
bd1c2534c5 Mobile: Fixes #13095: Fix long note title doesn’t wrap properly for To Do type note (#13099) 2025-09-08 11:05:19 +01:00
mrjo118
72513b520c Android: Fixes #13079: Fix dropdown menus are offset on Android 15+ (#13106) 2025-09-08 11:04:46 +01:00
Henry Heino
ec0f9ef9bc Server: Fix unique constraint error when multiple createSharedFolderUserItems are run concurrently (#13112) 2025-09-08 11:03:28 +01:00
Henry Heino
818bc3218a Mobile: Improve tag dialog performance with long tags and many tags (#13117) 2025-09-08 11:03:01 +01:00
Henry Heino
82760a5b6a Web: Show a "Give feedback" banner and link to a survey (#13125) 2025-09-08 10:59:40 +01:00
mrjo118
5ba9a16cfd Mobile: Fixes #13116: Fix tag association screen no longer searches case insensitively or searches tag endings (#13128) 2025-09-08 10:59:01 +01:00
Henry Heino
68fc91fdc7 Desktop: Resolves #13096: Prefer user-specified CSS page sizing when printing to PDF (#13130) 2025-09-08 10:58:16 +01:00
Henry Heino
bdc4687327 Chore: Refactor WebViewController (#13133) 2025-09-08 10:56:51 +01:00
Henry Heino
3a9f57e13f Cli: Fixes #13086: Fix "use" command when not in TUI mode (#13091) 2025-09-08 10:56:08 +01:00
Henry Heino
b72c48c693 Mobile, Desktop: Fixes #13103: Fix error when saving in-editor rendering-related settings (#13105) 2025-09-08 10:56:01 +01:00
Henry Heino
f1e42f3bac iOS: Fixes #13111: Fix "scan notebook" tool on iOS (#13114) 2025-09-08 10:55:48 +01:00
Henry Heino
93c908286d Mobile: Plugins: Fix renderer plugins that use the settingValue API (#13131) 2025-09-08 10:55:42 +01:00
Henry Heino
4eb8777ed0 Mobile: Fix light bar shown above header in dark mode (#13132) 2025-09-08 10:55:15 +01:00
summoner
5e1909cee0 All: Translation: Update hu_HU.po (#13142) 2025-09-08 00:34:54 -04:00
pplulee
2e7b312415 All: Translation: Update zh_CN.po (#13137) 2025-09-06 17:02:31 -04:00
Joplin Bot
7735a59fc1 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-04 18:26:55 +00:00
Laurent Cozic
41d6e912a7 Doc: Updated sponsors 2025-09-04 17:43:49 +02:00
Joplin Bot
4c2fae8423 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-03 01:00:02 +00:00
Laurent Cozic
b72c134890 Doc: Update sponsors 2025-09-02 23:01:06 +02:00
Joplin Bot
58a9c229bb Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-01 18:25:20 +00:00
Laurent Cozic
d8c203bb8a Merge branch 'release-3.4' into dev 2025-09-01 14:48:55 +02:00
Laurent Cozic
9020c07825 lock files 2025-09-01 14:48:51 +02:00
Laurent Cozic
e884da8312 Android 3.4.6 2025-09-01 14:48:38 +02:00
Joplin Bot
d134ea8bfe Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-01 12:33:37 +00:00
Henry Heino
faa44468f3 Mobile: Plugins: Improve handling of invalid toolbar button enabled conditions (#13076) 2025-09-01 13:50:59 +02:00
Laurent Cozic
85585d16d2 Desktop release v3.4.10 2025-09-01 13:50:43 +02:00
Joplin Bot
b9c5b8f187 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-09-01 01:12:51 +00:00
Henry Heino
da8e638359 Chore: Mobile: Add test to verify that content scripts load in the note viewer (#13093) 2025-08-31 00:32:10 +02:00
Henry Heino
6482ab5a4e Mobile: Plugin API: Fix compatibility with certain plugins targetting the desktop app (#13077) 2025-08-29 23:28:45 +02:00
Henry Heino
ec74abe754 Mobile: Plugin API: Fix certain renderer plugins fail to load (#13078) 2025-08-29 23:28:39 +02:00
Henry Heino
859bc8d88e Mobile: Plugins: Fix plugin panel buttons are offscreen on recent versions of Android (#13080) 2025-08-29 23:28:22 +02:00
Henry Heino
56ed471a2f Chore: Rich Text Editor: Refactor editor dialog to simplify toggling the dialog from external commands (#13082) 2025-08-29 23:28:11 +02:00
Henry Heino
650594ecea Chore: Sync fuzzer: Add action for deleting notes (#13083) 2025-08-29 23:28:00 +02:00
Henry Heino
3e9bb914e5 Android: Fixes #13015: Fix "edit profile" button is partially offscreen (#13084) 2025-08-29 23:27:51 +02:00
Henry Heino
f75e911a4e Docs: Update the privacy policy (#13087) 2025-08-29 23:27:44 +02:00
Eric Duarte
78fb07d4c7 All: Translation: Update ca.po (#13065) 2025-08-28 17:50:34 -04:00
Henry Heino
6390ef43ed Desktop: Clarify handwritten text transcription setting (#13073)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-28 09:20:55 +03:00
Henry Heino
78c5c4d7c3 Android: Accessibility: Fix tag search input loses focus when submitted by pressing "enter" (#13070) 2025-08-28 09:20:10 +03:00
Henry Heino
0d1d50768b Android: Fix shadow shown above the screen header (#13074) 2025-08-28 09:04:10 +03:00
Henry Heino
57093b35ea Android: Fixes #12960: Rich Text Editor: Fix pressing enter does nothing in some cases (#13075) 2025-08-28 09:03:37 +03:00
Laurent Cozic
cba5cf660b Desktop release v3.4.9 2025-08-27 22:09:47 +03:00
Laurent Cozic
0024722c79 Desktop: Clarified that handwritten transcription may not always work 2025-08-27 22:09:26 +03:00
Henry Heino
bc2832e78f Chore: Desktop: Allow access to more Joplin APIs from the desktop development tools in dev mode (#13052) 2025-08-27 22:05:52 +03:00
Henry Heino
424cc96d36 Chore: Sync fuzzer: Fix incorrect expected state after removing the last user from a share (#13061) 2025-08-27 22:03:17 +03:00
Henry Heino
56fd5d828f Android: Fixes #12952: External keyboard: Fix adding tags by pressing enter on certain Android devices (#13069) 2025-08-27 22:02:48 +03:00
Henry Heino
03843b087a Desktop: Fixes #12816: Accessibility: Fix dismissing the alarm dialog by pressing escape (#13068) 2025-08-27 22:02:34 +03:00
Henry Heino
b179509dd3 Desktop: Fixes #12855: Legacy editor: Fix plugin support (#13066) 2025-08-27 22:02:09 +03:00
Joplin Bot
f6851314d2 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-27 18:26:06 +00:00
Laurent Cozic
eaec45cb3f Doc: Update sponsors 2025-08-27 18:38:56 +03:00
Laurent Cozic
9be954496c Doc: Update sponsors 2025-08-27 17:45:40 +03:00
Laurent Cozic
ac289c5198 Desktop: Clarified that handwritten transcription may not always work 2025-08-27 17:22:06 +03:00
Joplin Bot
98ef5e619b Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-27 12:33:13 +00:00
Laurent Cozic
62faa48aac lock files 2025-08-27 10:15:15 +03:00
Laurent Cozic
5daa7a1f4c Chore: By default, create new releases as pre-releases when publishing desktop app 2025-08-27 09:54:06 +03:00
Laurent Cozic
32be071601 CLI v3.4.1 2025-08-27 09:50:10 +03:00
Laurent Cozic
0dc63dd306 Lock file 2025-08-27 09:47:17 +03:00
Laurent Cozic
78ed58187a Releasing sub-packages 2025-08-27 09:46:45 +03:00
Laurent Cozic
b8b8dd8011 iOS 13.4.2 2025-08-27 09:33:18 +03:00
Laurent Cozic
0bc72b45be Android 3.4.5 2025-08-27 09:28:51 +03:00
Laurent Cozic
c52523134d Desktop release v3.4.8 2025-08-27 09:23:04 +03:00
Henry Heino
aff871eee6 Desktop, Mobile: Markdown editor: Fix image rendering is disabled unless markup rendering is also enabled (#13056) 2025-08-27 09:21:26 +03:00
Henry Heino
a5a68a2238 Cli: Add commands for publishing and unpublishing notes with Joplin Server (#13060) 2025-08-27 09:21:10 +03:00
Henry Heino
e066b8f9bc Desktop: Fixes #13043: OCR: Fix processing resources with an invalid ocr_driver_id (#13051) 2025-08-27 09:20:00 +03:00
Henry Heino
e7827a3a64 Mobile: Remove the "beta" warning from the plugin settings screen (#13063) 2025-08-27 09:19:21 +03:00
Henry Heino
4ceca647dc Desktop, Mobile: Resolves #13048: Auto-disable plugin settings when conflicting built-in settings are enabled (#13055) 2025-08-27 09:19:07 +03:00
Henry Heino
4185afebdb Chore: Fix build (#13050) 2025-08-26 18:40:26 +03:00
Henry Heino
c530b07f45 Desktop, Mobile: Disable in-editor Markdown rendering by default (can be re-enabled in settings > note) (#13022) 2025-08-26 10:56:53 +03:00
Henry Heino
0ed7daaed8 Linux, Windows: Fixes #12991, #12733: Fix notifications (#13007) 2025-08-26 10:56:42 +03:00
Henry Heino
2eb107c716 Desktop, Mobile: Add a "highlight active line" setting (#12967) 2025-08-26 10:49:59 +03:00
Henry Heino
c99780db1b Mobile: Rich Text Editor: Avoid rendering links with unknown protocols (#12943)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-26 10:49:26 +03:00
Henry Heino
ac05b7d389 Mobile: Rich Text Editor: Fix additional blank lines added around list items on save (#12935) 2025-08-26 10:46:00 +03:00
Henry Heino
9719d82c47 Desktop: Fixes #13024: OCR: Fix infinite loop (#13025) 2025-08-26 10:45:27 +03:00
Henry Heino
48694a585f Mobile: Fixes #12953: Allow the tag dialog to scroll when little screen space is available (#13028) 2025-08-26 10:44:32 +03:00
Henry Heino
b577a27887 Mobile: Fixes #13027: Fix additional space added around app content in landscape mode (#13030) 2025-08-26 10:44:06 +03:00
Helmut K. C. Tessarek
9f649c9fc2 All: Update translations 2025-08-25 19:40:33 -04:00
Eric Duarte
8c9c5d13bd All: Translation: Update es_ES.po (#13041) 2025-08-25 19:32:14 -04:00
renovate[bot]
96692de93c Update dependency @types/react to v18.3.23 (#13042)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-25 13:44:38 +00:00
Joplin Bot
3d8e1dd146 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-24 18:26:08 +00:00
Joplin Bot
227e41b69a Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-24 12:31:05 +00:00
renovate[bot]
a616e26a0f Update dependency react-native-safe-area-context to v5.4.1 (#13000)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-24 13:02:03 +03:00
Joplin Bot
ba0e7e2226 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-23 12:30:39 +00:00
Laurent Cozic
b5a4ba554d Doc: Add sponsor 2025-08-23 13:14:58 +03:00
Arda Kılıçdağı
9037da8f2d All: Translation: Update tr_TR.po (#13019) 2025-08-22 16:07:31 -04:00
renovate[bot]
6998606ec9 Update dependency pg to v8.15.6 (#13021)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-22 17:00:30 +00:00
Laurent Cozic
66d52c90a3 Desktop release v3.4.7 2025-08-22 13:19:27 +03:00
renovate[bot]
f6fb1f7fbf Update dependency pg to v8.15.5 (#13001)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-22 13:14:06 +03:00
Henry Heino
3aac6043da Chore: Sync fuzzer: Support testing Joplin Cloud readonly shares (#13003) 2025-08-22 11:33:54 +03:00
Henry Heino
ae170e0aa0 Desktop: Fixes #12998: Fix error logged when rendering a non-existent resource (#13004) 2025-08-22 11:33:16 +03:00
Henry Heino
371f027a24 MacOS: Fix startup failure when unable to access the keychain (#13006) 2025-08-22 11:32:59 +03:00
Henry Heino
37422f316e Desktop: Downgrade to Electron 35.7.5 (#13013) 2025-08-22 11:30:39 +03:00
Henry Heino
a9f284ae45 Desktop: Fixes #13009: Fix custom root CA support (#13018) 2025-08-22 11:29:54 +03:00
Milo Ivir
fd2f69cc73 All: Translation: Update hr_HR.po (#13011) 2025-08-21 18:45:39 -04:00
Joplin Bot
c4eab3c79c Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-21 01:03:33 +00:00
renovate[bot]
a0b9c6376e Update dependency react-native-image-picker to v8 (#12997)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-20 23:37:39 +03:00
Henry Heino
e2fc056369 Desktop,Mobile,Cli: Fixes #12648: Fix unshare action requires two syncs to be reflected locally (#12999) 2025-08-20 23:36:47 +03:00
renovate[bot]
453b4705b1 Update dependency @types/node to v18.19.103 (#12985)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-20 19:25:54 +00:00
Laurent Cozic
4128061e40 Desktop release v3.4.6 2025-08-20 22:22:42 +03:00
Joplin Bot
432b0ca870 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-20 12:32:59 +00:00
renovate[bot]
c484cd2e48 Update dependency sass to v1.87.0 (#12995)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-20 15:06:57 +03:00
Laurent Cozic
58f0725c6b Doc: Add sponsor 2025-08-20 15:05:28 +03:00
Henry Heino
bf8fbec0cd Chore: Sync fuzzer: Add support for adding and removing share participants (#12988) 2025-08-20 09:46:23 +03:00
pedr
f1d452f130 Server: Fixes #12983: Not handling correctly non JSON error responses from Transcribe (#12986) 2025-08-20 09:46:15 +03:00
Henry Heino
26012cd7d5 Cli,Mobile,Desktop: Shared folders: Fix moving shared subfolder to toplevel briefly marks it as a toplevel share (#12964) 2025-08-20 09:39:39 +03:00
mrjo118
a414241541 Mobile: Improve tag screen usability to allow add or remove tag with a single press, when the keyboard is open (#12954) 2025-08-20 09:33:31 +03:00
Henry Heino
0f13bf9d51 Mobile: Rich Text Editor: Support rendering subscript, superscript, and highlighted formatting (#12944) 2025-08-20 09:33:13 +03:00
Henry Heino
c142c5c5c0 Desktop,Mobile: Markdown editor: Toggle checkboxes on ctrl-click (#12927) 2025-08-20 09:32:16 +03:00
Henry Heino
af5c0135dc Mobile: Rich Text Editor: Enable syntax highlighting and auto-indent in the code block editor (#12909) 2025-08-20 09:29:30 +03:00
pedr
8a811b9e78 Doc: Resolves #12861: Add end point documentation for Transcribe (#12870)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-20 09:29:12 +03:00
Henry Heino
602484f143 Desktop: Upgrade to Electron v37.3.0 (#12951) 2025-08-20 08:53:50 +03:00
renovate[bot]
dc84db1657 Update dependency sharp to v0.34.2 (#12982)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-20 08:33:29 +03:00
Henry Heino
f5882ecfcc Chore: Improve type safety (#12992) 2025-08-20 08:33:10 +03:00
Laurent Cozic
30000c34ec Cli: If no notebook is provided when importing a file, use the default one 2025-08-19 23:33:52 +03:00
renovate[bot]
6e3df1bd90 Update dependency @types/react to v18.3.22 (#12990)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 18:59:17 +03:00
Joplin Bot
67196ac0b2 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-19 12:33:44 +00:00
Laurent Cozic
69646b5522 Doc: Update sponsors 2025-08-19 12:31:13 +03:00
Laurent Cozic
9147afce9a Server v3.4.2 2025-08-18 19:54:35 +03:00
Henry Heino
c92701c52f iOS: Rich Text Editor: Fix the "edit" button for code blocks (#12924) 2025-08-18 18:46:02 +03:00
pedr
ab3e9d1a3e Transcribe: Fixes: Use latest version of joplin/htr-cli available (#12875) 2025-08-18 18:45:52 +03:00
Henry Heino
f9cab8843b Chore: Fix tsc (#12981) 2025-08-18 18:40:58 +03:00
yuudi
c36289c024 Server: Fixes #12947 Skip CORS check for SAML callback (#12948)
Co-authored-by: yuudi <yuudi@users.noreply.github.com>
2025-08-18 16:10:20 +03:00
Henry Heino
60b6db8cd4 Mobile: Rich Text Editor: Add basic support for collapsible <details> blocks (#12946) 2025-08-18 16:10:00 +03:00
Henry Heino
bbd8f6f40e Mobile: Rich Text Editor: Fix adding headings moves the cursor to the next line (#12934) 2025-08-18 16:07:55 +03:00
Henry Heino
34b7f4e1f8 Chore: Sync fuzzer: Fix "DecryptionWorker: Cannot start because..." warning (#12925) 2025-08-18 16:04:26 +03:00
Henry Heino
06b681d897 Chore: Sync fuzzer: Add new possible actions: Adding and syncing a new temporary client on an existing account (#12741) 2025-08-18 15:57:44 +03:00
pedr
f02a94bef5 Transcribe: Fixes #12766: Remove processed files and clean up after a retention period (#12827) 2025-08-18 15:57:34 +03:00
Miguel Matos
ae6b57c5a5 CLI: Add collapsible notebooks functionality (#12718) 2025-08-18 15:55:55 +03:00
Henry Heino
88ab916008 Mobile: Rich Text Editor: Support rendering table of contents blocks (#12949) 2025-08-18 11:35:48 +03:00
pedr
97b0ffc263 Transcribe: #12883: Disable JobProcessor tests by default (#12955) 2025-08-18 11:34:26 +03:00
pedr
ff8848d138 Desktop: Fixes #12315: Clicking Edit URL button in Note properties does not focus in url field (#12970) 2025-08-18 11:20:54 +03:00
renovate[bot]
2b686e6318 Update dependency @playwright/test to v1.52.0 (#12972)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 11:17:35 +03:00
renovate[bot]
b913d18882 Update dependency @adobe/css-tools to v4.4.3 (#12979)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-17 22:02:58 +00:00
renovate[bot]
a2c9a01722 Update dependency @types/node to v18.19.101 (#12978)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-17 05:42:21 +00:00
Milo Ivir
000d23c20f All: Translation: Update hr_HR.po (#12961) 2025-08-16 21:46:55 -04:00
Liffindra Angga Zaaldian
9e9f2f2930 All: Translation: Update id_ID.po (#12977) 2025-08-16 20:42:49 -04:00
VortexP
c5a1a759c7 All: Translation: Update fi_FI.po (#12971) 2025-08-15 18:15:58 -04:00
cedecode
0b6a1c75ba All: Translation: Update de_DE.po (#12966) 2025-08-14 22:09:33 -04:00
renovate[bot]
53a0f8ddbc Update dependency python to v3.13.3 (#12965)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-15 01:08:28 +02:00
Laurent Cozic
67eabb5038 Doc: Update recommended Postgres for JSB 2025-08-14 22:32:00 +02:00
Laurent Cozic
983fced410 Doc: Fixed Transcribe graph 2025-08-14 22:32:00 +02:00
Jozef Gaal
4f5bbc1132 All: Translation: Update sk_SK.po (#12950) 2025-08-14 00:22:49 -04:00
ERYpTION
2f10235ecb All: Translation: Update da_DK.po (#12945) 2025-08-13 17:22:50 -04:00
Joplin Bot
cfa7d6cb31 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-13 18:27:34 +00:00
renovate[bot]
f5d62a50fe Update dependency @types/serviceworker to v0.0.135 (#12937)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-13 10:12:25 +00:00
Laurent Cozic
b52f5435aa Doc: Add Transcribe System Architecture documentation 2025-08-12 19:24:27 +01:00
renovate[bot]
bfd5bfc004 Update dependency git to v2.48.1 (#12921)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 15:32:53 +01:00
renovate[bot]
82965fe991 Update dependency jsdom to v26.1.0 (#12922)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 15:32:45 +01:00
summoner
b2c162c25b All: Translation: Update hu_HU.po (#12918) 2025-08-10 16:05:34 -04:00
Mihai Vasiliu
022e76fe8d All: Translation: Update ro_RO.po and ro_MD.po (#12917) 2025-08-10 16:04:28 -04:00
Joplin Bot
4b2d1895fd Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-10 18:26:11 +00:00
Joplin Bot
534507a31f Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-10 12:32:07 +00:00
Laurent Cozic
5b4a300c81 iOS 13.4.1 2025-08-10 10:41:49 +01:00
Laurent Cozic
1de0a59313 Chore: Fix iOS IPHONEOS_DEPLOYMENT_TARGET 2025-08-10 10:41:25 +01:00
Laurent Cozic
f4dff92d2e Android 3.4.4 2025-08-10 10:34:02 +01:00
Laurent Cozic
a5d37a0dca Desktop release v3.4.5 2025-08-10 10:26:53 +01:00
Laurent Cozic
75ef418b39 Update translations 2025-08-10 10:26:37 +01:00
Henry Heino
6bd702ae24 Mobile: Resolves #12843: Rich Text Editor: Improve support for HTML notes (#12912) 2025-08-10 09:32:42 +01:00
Laurent Cozic
9ea1808766 Update translations 2025-08-10 09:31:13 +01:00
Suchith
59f8dd36a6 Desktop: Fixes #12358: Selected emoji for new notebooks display too large until Joplin is restarted (#12888) 2025-08-10 09:30:42 +01:00
Henry Heino
ea1d2e4878 Desktop, Mobile: Move several features from Extra Markdown Editor Settings into the main app (#12747) 2025-08-10 09:17:12 +01:00
Henry Heino
46ab00bfe4 Chore: Sync fuzzer: Re-use the same CLI process for commands run on the same client (#12913) 2025-08-10 09:14:25 +01:00
renovate[bot]
07465dd349 Update dependency dotenv to v16.5.0 (#12914)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-09 10:46:41 +01:00
renovate[bot]
a288ffe338 Update dependency @types/node to v18.19.100 (#12904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-08 21:20:11 +00:00
renovate[bot]
dba62386b6 Update dependency @types/serviceworker to v0.0.134 (#12907)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-07 12:12:36 +01:00
Henry Heino
6704ab0d13 Mobile: Resolves #12841: Allow editing code blocks from the Rich Text Editor (#12906) 2025-08-07 10:18:09 +01:00
Arda Kılıçdağı
0312f2213d All: Translation: Update tr_TR.po (#12905) 2025-08-06 20:23:39 -04:00
Chaitanya Gupta
2ac0b66ef6 Doc: Fix link to E2EE spec (#12902) 2025-08-06 13:05:42 +01:00
Henry Heino
639b261ee4 Mobile: Fixes #12844: Rich Text Editor: Make initial search behavior match the Markdown editor (#12878) 2025-08-06 11:10:14 +01:00
mrjo118
82bc819a21 Mobile: Fixes #12822: Fix switching between note and todo on mobile (#12849) 2025-08-06 11:09:05 +01:00
w568w
72f8ebe4ff Desktop: Fixes #11871: Put crash dump files at the platform-compliant locations (#12839) 2025-08-06 11:08:29 +01:00
pedr
8c8a38e704 Desktop: Resolves #2059: Add option to transform HTML notes into Markdown (#12730)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-06 11:02:13 +01:00
mrjo118
358134038c Desktop, Mobile: Fixes #12104: Ensure merges to revisions during cleaning are synced to the target (#12444) 2025-08-06 10:52:28 +01:00
Henry Heino
1f4b32a241 Desktop: Fixes #12235: Fix switching to the Markdown editor after pasting links (#12241) 2025-08-06 10:50:17 +01:00
Henry Heino
2a216f1e61 Server: Fix notebooks remain shared after being permanently deleted by the share owner (#12583) 2025-08-06 10:37:38 +01:00
pedr
3f75d770f7 Desktop: Resolves #12224: Add an option to enable or disable search in OCR text (#12578) 2025-08-06 10:37:20 +01:00
Henry Heino
b6d32831c6 Mobile: Fixes #12880: Fix plugin support (#12890) 2025-08-06 10:23:40 +01:00
Henry Heino
788033cb5f Mobile: Fixes #12891: Fix error logged when opening the Markdown editor (#12892) 2025-08-06 10:23:07 +01:00
klaas0
4e685ec687 Mobile: Resolves #12858: Fixed missing filename when a file is shared with the app (#12895) 2025-08-06 10:22:47 +01:00
renovate[bot]
c60b703b9c Update dependency ldapts to v7.4.0 (#12900)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-06 10:19:03 +01:00
renovate[bot]
f23e10a975 Update dependency @types/node to v18.19.99 (#12899)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-06 06:25:58 +00:00
renovate[bot]
b9a71c0c3d Update dependency sharp to v0.34.1 (#12898)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-06 04:43:57 +00:00
renovate[bot]
f525c4179f Update dependency react-native-share to v12.0.11 (#12897)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-06 02:34:38 +00:00
renovate[bot]
1dd0ec619f Update dependency lint-staged to v15.5.2 (#12896)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-06 02:32:29 +00:00
renovate[bot]
d2ee5411d0 Update dependency @types/react to v18.3.21 (#12884)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 22:56:45 +00:00
krevad
a2472cb3b7 All: Translation: Update sv.po (#12893) 2025-08-05 18:55:12 -04:00
renovate[bot]
ca8415f74a Update dependency esbuild to v0.25.4 (#12889)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 20:34:24 +00:00
renovate[bot]
853b792367 Update dependency @types/node to v18.19.98 (#12881)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 20:31:35 +00:00
renovate[bot]
56d477f1c1 Update dependency esbuild to v0.25.4 (#12887)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 16:37:20 +00:00
Laurent Cozic
020ba10c56 Update renovate.json5 2025-08-05 13:35:34 +01:00
pedr
be09873c58 Desktop: Resolves #12087: Add shortcut to toggle between editors (#12869) 2025-08-05 12:43:58 +01:00
renovate[bot]
4d8a16bda7 Update dependency @types/mustache to v4.2.6 (#12867)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 12:28:03 +01:00
pedr
f725d3895f Transcribe: Resolves #12862: Add log statement signaling that the startup has finished (#12876) 2025-08-05 12:26:10 +01:00
pedr
0e19dce0d1 Transcribe: Fixes #12863: Improve error handling (#12873) 2025-08-05 10:53:42 +01:00
Joplin Bot
31c5058d5e Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-04 18:29:30 +00:00
Laurent Cozic
4d760303bc Android 3.4.3 2025-08-04 18:39:19 +01:00
Laurent Cozic
23e63e5fec Desktop release v3.4.4 2025-08-04 18:33:28 +01:00
renovate[bot]
3880352f53 Update dependency @react-native-documents/picker to v10.1.3 (#12865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-03 20:34:46 +00:00
summoner
42a3c40702 All: Translation: Update hu_HU.po (#12864) 2025-08-03 12:56:34 -04:00
mrjo118
8e585640e7 Android: Fixes #12821: Fix on screen keyboard covers the markdown toolbar and contents on Android 15+ (#12838) 2025-08-03 17:30:15 +01:00
renovate[bot]
cd3fb4e7ad Update dependency sharp to v0.34.0 (#12854)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-03 17:27:35 +01:00
Laurent Cozic
702b5b3c63 Server: Trying to fix a request parsing error that can potentially crash the error (#12860) 2025-08-03 15:04:54 +01:00
PanWor
a80406dcb7 All: Translation: Update Polish pl_PL.po (#12857) 2025-08-02 17:06:09 -04:00
renovate[bot]
ea8b6485d8 Update dependency pg-boss to v10.2.0 (#12850)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-02 13:17:06 +01:00
renovate[bot]
1a2ef78726 Update dependency babel-plugin-react-native-web to v0.20.0 (#12848)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-02 09:23:47 +01:00
renovate[bot]
63d5ffc796 Update dependency @types/serviceworker to v0.0.133 (#12846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-02 09:23:28 +01:00
renovate[bot]
15918a57aa Update dependency react-refresh to v0.17.0 (#12847)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-02 09:23:13 +01:00
renovate[bot]
032e8b5596 Update dependency @types/react-dom to v18.3.7 (#12845)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-01 20:14:16 +01:00
Laurent Cozic
ee091ede52 Update renovate.json5 2025-08-01 17:51:06 +01:00
Henry Heino
763e3f7479 Chore: Resolves #12814: Add additional logging to DecryptionWorker and EncryptionService (#12824) 2025-08-01 17:39:37 +01:00
Laurent Cozic
0089c62493 Transcribe v3.4.9 2025-08-01 17:32:56 +01:00
Laurent Cozic
20d6d56c02 Doc: Hide "Edit this page" link when printing 2025-08-01 17:32:33 +01:00
pedr
8b999f8dc6 Transcribe: Resolves #12831: Add support for transcribe server to the server docker compose configuration (#12832)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-01 17:31:59 +01:00
Laurent Cozic
0067ac126d Doc: Added technical info to JSB page 2025-08-01 16:28:01 +01:00
renovate[bot]
c6f47a9084 Update eslint (#12833)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-08-01 14:46:54 +01:00
Laurent Cozic
22817317f1 Transcribe v3.4.8 2025-08-01 13:30:54 +01:00
Laurent Cozic
9ba1c0db4e Chore: Also build ARM64 image for Transcribe 2025-08-01 13:30:34 +01:00
renovate[bot]
70d6c1225c Update types (#12834)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-01 12:50:46 +01:00
Laurent Cozic
b1f013a8c2 Transcribe v3.4.7 2025-08-01 12:14:32 +01:00
Laurent Cozic
8c66349907 Chore: Fixed credential for Transcribe release 2025-08-01 12:14:09 +01:00
Laurent Cozic
86b4f713ee Chore: Trying to disable Renovate React monorepo rule 2025-08-01 12:08:20 +01:00
Henry Heino
f50dc6a536 Chore: Work around test failure in newer NodeJS versions (#12830) 2025-08-01 11:45:09 +01:00
Henry Heino
825ce51a3c Chore: Resolves #12813: Move performance logger file labels to the corresponding log statements (#12820) 2025-08-01 11:43:05 +01:00
mrjo118
c5b6f0bca1 Mobile: Fixes #12783: Improve usability of inline search in notes (#12791) 2025-08-01 11:39:07 +01:00
Laurent Cozic
86934d502e Transcribe v3.4.6 2025-08-01 11:14:18 +01:00
Laurent Cozic
c63ad17f98 Chore: Fixed Transcribe Docker image 2025-08-01 11:13:57 +01:00
Joplin Bot
c746b5fdc2 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-08-01 01:19:23 +00:00
Laurent Cozic
949fb85755 Transcribe v3.4.5 2025-07-31 21:36:35 +01:00
Laurent Cozic
0f94cb8c17 Chore: Updated script to allow deploying Transcribe server (#12828) 2025-07-31 21:35:03 +01:00
Joplin Bot
7ba61bb585 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-07-31 18:28:37 +00:00
Henry Heino
00e4657a39 Desktop: Resolves #12714: Make more settings per-profile (application layout, note list style, and note list order) (#12825) 2025-07-31 17:12:31 +01:00
pedr
cbdc98553a Desktop, Server: Add transcribe functionality to Desktop though Joplin Server (#12670) 2025-07-31 16:42:03 +01:00
Laurent Cozic
e3c2589a12 Doc: Allow setting the initial hosting type on the Plans page 2025-07-31 14:48:25 +01:00
Henry Heino
56b3cc3dc2 Android: Fixes #12782: Fix save button is invisible in release builds (#12826) 2025-07-31 13:59:25 +01:00
Suchith
d59a09fd29 Desktop: Fixes #12233: Add tooltips to sidebar buttons (#12798) 2025-07-30 15:42:08 +01:00
Laurent Cozic
5a64222276 Desktop: Fixes #12816: Date/Time dialog button not visible in dark mode 2025-07-30 15:22:34 +01:00
Henry Heino
012297d52a Android: Fixes #12781: Fix editor becomes blank after dismissing search (#12818) 2025-07-30 10:53:12 +01:00
Henry Heino
5e70bce2c3 Mobile: Performance: Improve Rich Text Editor startup performance (#12819) 2025-07-30 10:52:57 +01:00
Henry Heino
4c3eca1f18 Mobile: Add a Rich Text Editor (#12748) 2025-07-29 20:25:43 +01:00
Henry Heino
c899f63a41 Chore: Resolves #12088: Desktop: Add performance logging statements to the startup code (#12812) 2025-07-29 19:57:12 +01:00
Liffindra Angga Zaaldian
c838b86413 All: Translation: Update id_ID.po (#12815) 2025-07-29 06:57:18 -04:00
pedr
90d6d1747a Transcribe: Fixes #12765: Removes file from temporary folder after storing it (#12795) 2025-07-28 18:32:10 +01:00
renovate[bot]
6e8ba8a536 Update dependency jsdom to v26 (#12809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 12:24:57 +01:00
bwat47
ffeb5f887a Doc: Update s3.md for provider Cloudflare R2 (#12805) 2025-07-27 15:54:10 +01:00
Laurent Cozic
65bde86263 Doc: Added documentation for the CLA consent records tool and archives 2025-07-27 10:00:33 +01:00
Laurent Cozic
1c236ca73c Doc: Update CLA consent records 2025-07-27 09:36:28 +01:00
Laurent Cozic
2881280100 Merge branch 'cla_signatures' into dev 2025-07-27 09:33:50 +01:00
Laurent Cozic
954b48b779 Merge branch 'dev' into cla_signatures 2025-07-27 09:33:24 +01:00
Laurent Cozic
53e7b672b0 Chore: Recorded CLA consent documents 2025-07-27 09:33:22 +01:00
krevad
ceaaab77e8 All: Translation: Update sv.po (#12800) 2025-07-26 18:00:43 -04:00
Eric Duarte
c29bbe96f7 All: Translation: Update es_ES.po and ca.po (#12760) 2025-07-26 17:03:20 -04:00
Mihai Vasiliu
db323ac585 All: Translation: Update ro_RO.po and ro_MD.po (#12799) 2025-07-26 16:54:55 -04:00
krevad
dc8e3242f3 All: Translation: Update sv.po (#12797) 2025-07-26 11:00:38 -04:00
github-actions[bot]
9705941538 @krevad has signed the CLA in laurent22/joplin#12797 2025-07-26 09:58:22 +00:00
Joplin Bot
0cf9981ac7 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-07-26 01:09:51 +00:00
Laurent Cozic
b93ee3469b Desktop release v3.4.3 2025-07-25 19:22:30 +01:00
Laurent Cozic
73e5bc74a5 Android 3.4.2 2025-07-25 19:21:50 +01:00
Henry Heino
6c761b3fb4 Desktop,Mobile: Fixes #12573: Markdown editor: Make list indentation size equivalent to four spaces (#12794) 2025-07-25 19:18:14 +01:00
Henry Heino
e13985a952 Desktop: Fixes #12790: Plugins: Fix importing sqlite3 (#12792) 2025-07-25 19:17:40 +01:00
Laurent Cozic
8b912b22cf Chore: Fixed bad merge 2025-07-25 09:25:17 +01:00
Henry Heino
4c90cd62fe Chore: Mobile: Log startup performance information (#12776)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2025-07-25 09:20:38 +01:00
Henry Heino
999ec8c11f Android: Fix title bar is partially hidden by the screen header (#12785) 2025-07-25 09:19:23 +01:00
Henry Heino
d8e73f3141 Chore: Mobile: Fix warning (#12786) 2025-07-25 09:19:11 +01:00
renovate[bot]
3b1a4e8209 Update dependency react-native-paper to v5.13.5 (#12784)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-24 23:33:23 +00:00
renovate[bot]
1ff0f0f1c8 Update dependency @types/node to v18.19.87 (#12779)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-24 13:48:29 +01:00
Joplin Bot
68863db4bd Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-07-24 12:36:28 +00:00
Laurent Cozic
f6b8462a5b Android 3.4.1 2025-07-24 12:04:31 +01:00
Laurent Cozic
f8d09ce847 Chore: Trying to fix Android build 2025-07-24 11:52:40 +01:00
Laurent Cozic
f541618ed4 Chore: Build files 2025-07-24 11:44:36 +01:00
renovate[bot]
b023ddc4db Update dependency nodemon to v3.1.10 (#12769)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-24 02:03:07 +00:00
Henry Heino
3289b2ba30 Chore: Desktop: Migrate entrypoint to TypeScript (#12773) 2025-07-23 22:24:49 +01:00
renovate[bot]
0c52ac424d Update dependency mermaid to v11.6.0 (#12775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-23 18:29:26 +01:00
renovate[bot]
56529a1433 Update dependency glob to v11.0.2 (#12772)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 22:05:49 +00:00
renovate[bot]
65981e5e8b Update dependency @types/serviceworker to v0.0.132 (#12768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 14:35:01 +01:00
summoner
798064b004 All: Translations: Update hu_HU.po (#12764) 2025-07-21 17:54:56 -04:00
Laurent Cozic
e5ffb7df4d Chore: Trying to fix Android build 2025-07-21 22:40:44 +01:00
github-actions[bot]
83f1fcc228 @jordanhandy has signed the CLA in laurent22/joplin#12701 2025-07-11 13:05:02 +00:00
github-actions[bot]
b03e370d2b @khemarato has signed the CLA in laurent22/joplin#12696 2025-07-11 06:21:31 +00:00
github-actions[bot]
4ddd5c4558 @laurent22 has signed the CLA in laurent22/joplin#12571 2025-07-04 16:36:54 +00:00
github-actions[bot]
7746694dca @SAYAN02-DEV has signed the CLA in laurent22/joplin#12666 2025-07-03 07:56:53 +00:00
github-actions[bot]
f1ac95a1c7 @bekemax has signed the CLA in laurent22/joplin#12586 2025-06-27 17:11:39 +00:00
github-actions[bot]
78e9ced96c @jhult has signed the CLA in laurent22/joplin#12567 2025-06-20 14:38:18 +00:00
github-actions[bot]
bba6ede569 @Robin-Sch has signed the CLA in laurent22/joplin#12563 2025-06-18 21:52:29 +00:00
github-actions[bot]
7a26d4f336 @Gustavo-V-F has signed the CLA in laurent22/joplin#12537 2025-06-15 20:44:49 +00:00
github-actions[bot]
04a976e459 @ShawnZhang31 has signed the CLA in laurent22/joplin#12345 2025-05-27 01:28:32 +00:00
github-actions[bot]
ecfef1a9da @NBA2K1 has signed the CLA in laurent22/joplin#12316 2025-05-18 07:40:04 +00:00
github-actions[bot]
e422a88bb0 @eyaaba has signed the CLA in laurent22/joplin#12260 2025-05-10 11:48:28 +00:00
github-actions[bot]
74ef89d25b @SilviaAC has signed the CLA in laurent22/joplin#12256 2025-05-09 09:43:31 +00:00
github-actions[bot]
28b7251e16 @yatishgoel has signed the CLA in laurent22/joplin#12185 2025-04-29 09:12:38 +00:00
github-actions[bot]
9218c7df1f @BellezaEmporium has signed the CLA in laurent22/joplin#12161 2025-04-28 09:42:54 +00:00
1020 changed files with 102779 additions and 52900 deletions

View File

@@ -15,6 +15,23 @@
# POSTGRES_PORT=5432
# POSTGRES_HOST=localhost
# =============================================================================
# TRANSCRIBE CONFIG EXAMPLE
# -----------------------------------------------------------------------------
# This service is not required, and it will be ignored by using --profile server
# when running docker-compose. If you want to use it, you need to set the
# following environment variables.
# =============================================================================
# TRANSCRIBE_API_KEY=secret_string_shared_between_server_and_transcribe
# TRANSCRIBE_ENABLED=true
# QUEUE_DATABASE_NAME=transcribe
# QUEUE_DATABASE_USER=transcribe
# QUEUE_DATABASE_PASSWORD=transcribe
# QUEUE_DATABASE_PORT=5431
# HTR_CLI_IMAGES_FOLDER=/home/user/images_storage
# =============================================================================
# DEV CONFIG EXAMPLE
# -----------------------------------------------------------------------------

View File

@@ -9,14 +9,18 @@ API_KEY=random-string
QUEUE_TTL=900000
QUEUE_RETRY_COUNT=2
QUEUE_MAINTENANCE_INTERVAL=30000
IMAGE_MAX_DIMENSION=400
HTR_CLI_DOCKER_IMAGE=joplin/htr-cli:0.0.2
# Fullpath to images folder
HTR_CLI_IMAGES_FOLDER=/home/user/joplin/packages/transcribe/images
HTR_CLI_DOCKER_IMAGE=joplin/htr-cli:latest
# Fullpath to images folder e.g.:
#HTR_CLI_IMAGES_FOLDER=/home/user/joplin/packages/transcribe/images
HTR_CLI_IMAGES_FOLDER=
QUEUE_DRIVER=pg
# QUEUE_DRIVER=sqlite
FILE_STORAGE_MAINTENANCE_INTERVAL=3600000
FILE_STORAGE_TTL=604800000 # one week
# =============================================================================
# Queue driver
@@ -27,4 +31,5 @@ QUEUE_DRIVER=pg
QUEUE_DATABASE_NAME=transcribe
QUEUE_DATABASE_USER=transcribe
QUEUE_DATABASE_PASSWORD=transcribe
QUEUE_DATABASE_PORT=5432
QUEUE_DATABASE_PORT=5432
QUEUE_DATABASE_HOST=localhost

View File

@@ -55,6 +55,7 @@ packages/app-desktop/vendor/lib/
packages/app-mobile/packageInfo.js
packages/app-mobile/android
packages/app-mobile/**/*.bundle.js
packages/app-mobile/**/*.bundle.css
packages/app-mobile/web/public/pluginAssets/**/*
packages/app-mobile/ios
packages/app-mobile/lib/rnInjectedJs/
@@ -74,6 +75,7 @@ packages/lib/services/database/types.ts
packages/lib/vendor/
packages/lib/vendor/fountain.min.js
packages/lib/welcomeAssets.js
packages/editor/*/vendor/
packages/plugins/**/api
packages/plugins/**/dist
packages/server/dist/
@@ -88,14 +90,16 @@ plugin_types/
readme/
packages/react-native-vosk/lib/
packages/lib/countable/Countable.js
packages/onenote-converter/pkg/onenote_converter.js
packages/onenote-converter/renderer/pkg/*
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
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/command-apidoc.js
packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js
packages/app-cli/app/command-cat.js
packages/app-cli/app/command-config.js
packages/app-cli/app/command-cp.js
@@ -114,6 +118,8 @@ packages/app-cli/app/command-ls.js
packages/app-cli/app/command-mkbook.test.js
packages/app-cli/app/command-mkbook.js
packages/app-cli/app/command-mv.js
packages/app-cli/app/command-publish.test.js
packages/app-cli/app/command-publish.js
packages/app-cli/app/command-ren.js
packages/app-cli/app/command-restore.js
packages/app-cli/app/command-rmbook.test.js
@@ -126,6 +132,8 @@ packages/app-cli/app/command-share.test.js
packages/app-cli/app/command-share.js
packages/app-cli/app/command-sync.js
packages/app-cli/app/command-testing.js
packages/app-cli/app/command-unpublish.test.js
packages/app-cli/app/command-unpublish.js
packages/app-cli/app/command-use.js
packages/app-cli/app/command-version.js
packages/app-cli/app/gui/FolderListWidget.js
@@ -133,6 +141,7 @@ packages/app-cli/app/gui/StatusBarWidget.js
packages/app-cli/app/services/plugins/PluginRunner.js
packages/app-cli/app/setupCommand.js
packages/app-cli/app/utils/initializeCommandService.js
packages/app-cli/app/utils/iterateStdin.js
packages/app-cli/app/utils/shimInitCli.js
packages/app-cli/app/utils/testUtils.js
packages/app-cli/tests/HtmlToMd.js
@@ -155,6 +164,8 @@ 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
@@ -195,6 +206,7 @@ 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
@@ -258,6 +270,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useKeymap.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useRefocusOnVisiblePaneChange.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useSyncEditorValue.js
packages/app-desktop/gui/NoteEditor/NoteBody/PlainEditor/PlainEditor.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
@@ -268,6 +281,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useCursorPositioning.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useEditDialog.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useEditDialogEventListeners.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useKeyboardRefocusHandler.js
@@ -296,6 +310,7 @@ packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.js
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.js
packages/app-desktop/gui/NoteEditor/utils/contextMenu.js
packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.js
packages/app-desktop/gui/NoteEditor/utils/getResourceBaseUrl.js
packages/app-desktop/gui/NoteEditor/utils/getWindowCommandPriority.js
packages/app-desktop/gui/NoteEditor/utils/index.js
packages/app-desktop/gui/NoteEditor/utils/markupRenderOptions.js
@@ -308,6 +323,7 @@ packages/app-desktop/gui/NoteEditor/utils/useEffectiveNoteId.js
packages/app-desktop/gui/NoteEditor/utils/useFolder.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.test.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.js
packages/app-desktop/gui/NoteEditor/utils/useInitialCursorLocation.js
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
packages/app-desktop/gui/NoteEditor/utils/useNoteSearchBar.js
packages/app-desktop/gui/NoteEditor/utils/usePluginEditorView.test.js
@@ -553,6 +569,8 @@ packages/app-desktop/integration-tests/util/setSettingValue.js
packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/integration-tests/wcag.spec.js
packages/app-desktop/main-html.js
packages/app-desktop/main.js
packages/app-desktop/playwright.config.js
packages/app-desktop/plugins/GotoAnything.js
packages/app-desktop/services/autoUpdater/AutoUpdaterService.test.js
@@ -589,6 +607,7 @@ packages/app-desktop/tools/generateLatestArm64Yml.js
packages/app-desktop/tools/githubReleasesUtils.js
packages/app-desktop/tools/modifyReleaseAssets.js
packages/app-desktop/tools/notarizeMacApp.js
packages/app-desktop/tools/resolveSourceMap.js
packages/app-desktop/utils/7zip/getPathToExecutable7Zip.js
packages/app-desktop/utils/7zip/pathToBundled7Zip.js
packages/app-desktop/utils/checkForUpdatesUtils.test.js
@@ -661,6 +680,9 @@ packages/app-mobile/components/ExtendedWebView/index.jest.js
packages/app-mobile/components/ExtendedWebView/index.js
packages/app-mobile/components/ExtendedWebView/index.web.js
packages/app-mobile/components/ExtendedWebView/types.js
packages/app-mobile/components/ExtendedWebView/utils/useCss.js
packages/app-mobile/components/FeedbackBanner.test.js
packages/app-mobile/components/FeedbackBanner.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/Icon.js
packages/app-mobile/components/IconButton.js
@@ -669,48 +691,34 @@ packages/app-mobile/components/ModalDialog.js
packages/app-mobile/components/NestableFlatList.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.test.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/Renderer.test.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/Renderer.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/noteBodyViewerBundle.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/types.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/utils/addPluginAssets.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/utils/makeResourceModel.js
packages/app-mobile/components/NoteBodyViewer/hooks/useContentScripts.js
packages/app-mobile/components/NoteBodyViewer/hooks/useEditPopup.test.js
packages/app-mobile/components/NoteBodyViewer/hooks/useEditPopup.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnMessage.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
packages/app-mobile/components/NoteBodyViewer/hooks/useRenderer.js
packages/app-mobile/components/NoteBodyViewer/hooks/useRerenderHandler.js
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js
packages/app-mobile/components/NoteBodyViewer/types.js
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.js
packages/app-mobile/components/NoteEditor/EditLinkDialog.js
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/js-draw/applyTemplateToEditor.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/createJsDrawEditor.test.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/createJsDrawEditor.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/polyfills.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/startAutosaveLoop.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/types.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/watchEditorForTemplateChanges.js
packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.js
packages/app-mobile/components/NoteEditor/ImageEditor/utils/useEditorMessenger.js
packages/app-mobile/components/NoteEditor/MarkdownEditor.js
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
packages/app-mobile/components/NoteEditor/NoteEditor.js
packages/app-mobile/components/NoteEditor/RichTextEditor.test.js
packages/app-mobile/components/NoteEditor/RichTextEditor.js
packages/app-mobile/components/NoteEditor/SearchPanel.js
packages/app-mobile/components/NoteEditor/WarningBanner.js
packages/app-mobile/components/NoteEditor/commandDeclarations.js
packages/app-mobile/components/NoteEditor/hooks/useCodeMirrorPlugins.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.test.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.js
packages/app-mobile/components/NoteEditor/testing/createTestEditorProps.js
packages/app-mobile/components/NoteEditor/types.js
packages/app-mobile/components/NoteItem.js
packages/app-mobile/components/NoteList.js
packages/app-mobile/components/ProfileSwitcher/ProfileEditor.js
packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.js
packages/app-mobile/components/ProfileSwitcher/useProfileConfig.js
packages/app-mobile/components/SafeAreaView.js
packages/app-mobile/components/ScreenHeader/Menu.js
packages/app-mobile/components/ScreenHeader/WarningBanner.test.js
packages/app-mobile/components/ScreenHeader/WarningBanner.js
@@ -721,6 +729,8 @@ packages/app-mobile/components/SearchInput.js
packages/app-mobile/components/SelectDateTimeDialog.js
packages/app-mobile/components/SideMenu.js
packages/app-mobile/components/SideMenuContentNote.js
packages/app-mobile/components/SyncWizard/JoplinCloudIcon.js
packages/app-mobile/components/SyncWizard/SyncWizard.js
packages/app-mobile/components/TagEditor.test.js
packages/app-mobile/components/TagEditor.js
packages/app-mobile/components/TextInput.js
@@ -737,6 +747,7 @@ packages/app-mobile/components/base-screen.js
packages/app-mobile/components/biometrics/BiometricPopup.js
packages/app-mobile/components/biometrics/biometricAuthenticate.js
packages/app-mobile/components/biometrics/sensorInfo.js
packages/app-mobile/components/buttons/CardButton.js
packages/app-mobile/components/buttons/FloatingActionButton.js
packages/app-mobile/components/buttons/LabelledIconButton.js
packages/app-mobile/components/buttons/MultiTouchableOpacity.js
@@ -747,6 +758,7 @@ packages/app-mobile/components/getResponsiveValue.js
packages/app-mobile/components/global-style.js
packages/app-mobile/components/plugins/PluginNotification.js
packages/app-mobile/components/plugins/PluginRunner.js
packages/app-mobile/components/plugins/PluginRunnerWebView.test.js
packages/app-mobile/components/plugins/PluginRunnerWebView.js
packages/app-mobile/components/plugins/backgroundPage/initializeDialogWebView.js
packages/app-mobile/components/plugins/backgroundPage/initializePluginBackgroundIframe.js
@@ -811,7 +823,6 @@ packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/InstallButto
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/WrappedPluginStates.js
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/mockRepositoryApiConstructor.js
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/newRepoApi.js
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/pluginServiceSetup.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/openWebsiteForPlugin.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/usePluginCallbacks.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/usePluginItem.js
@@ -837,6 +848,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/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
packages/app-mobile/components/screens/SearchScreen/index.js
packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.js
@@ -858,6 +870,38 @@ packages/app-mobile/components/voiceTyping/AudioRecordingBanner.js
packages/app-mobile/components/voiceTyping/RecordingControls.js
packages/app-mobile/components/voiceTyping/SpeechToTextBanner.js
packages/app-mobile/components/voiceTyping/types.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/applyTemplateToEditor.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/index.test.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/index.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/startAutosaveLoop.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/types.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/watchEditorForTemplateChanges.js
packages/app-mobile/contentScripts/imageEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/imageEditorBundle/utils/useEditorMessenger.js
packages/app-mobile/contentScripts/markdownEditorBundle/contentScript.js
packages/app-mobile/contentScripts/markdownEditorBundle/types.js
packages/app-mobile/contentScripts/markdownEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/markdownEditorBundle/utils/useCodeMirrorPlugins.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.test.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/index.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/types.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/addPluginAssets.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/afterFullPageRender.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/makeResourceModel.js
packages/app-mobile/contentScripts/rendererBundle/types.js
packages/app-mobile/contentScripts/rendererBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/rendererBundle/utils/useContentScripts.js
packages/app-mobile/contentScripts/rendererBundle/utils/useEditPopup.test.js
packages/app-mobile/contentScripts/rendererBundle/utils/useEditPopup.js
packages/app-mobile/contentScripts/richTextEditorBundle/contentScript/convertHtmlToMarkdown.js
packages/app-mobile/contentScripts/richTextEditorBundle/contentScript/index.js
packages/app-mobile/contentScripts/richTextEditorBundle/types.js
packages/app-mobile/contentScripts/richTextEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/types.js
packages/app-mobile/contentScripts/utils/polyfills.js
packages/app-mobile/contentScripts/utils/readFileToBase64.js
packages/app-mobile/contentScripts/utils/setUpLogger.js
packages/app-mobile/gulpfile.js
packages/app-mobile/index.web.js
packages/app-mobile/root.js
@@ -867,20 +911,19 @@ packages/app-mobile/services/AlarmServiceDriver.web.js
packages/app-mobile/services/BackButtonService.js
packages/app-mobile/services/commands/stateToWhenClauseContext.js
packages/app-mobile/services/e2ee/RSA.react-native.js
packages/app-mobile/services/e2ee/RSA.react-native.web.js
packages/app-mobile/services/e2ee/crypto.js
packages/app-mobile/services/plugins/PlatformImplementation.js
packages/app-mobile/services/profiles/index.js
packages/app-mobile/services/voiceTyping/VoiceTyping.js
packages/app-mobile/services/voiceTyping/utils/unzip.android.js
packages/app-mobile/services/voiceTyping/utils/unzip.js
packages/app-mobile/services/voiceTyping/vosk.android.js
packages/app-mobile/services/voiceTyping/vosk.js
packages/app-mobile/services/voiceTyping/whisper.test.js
packages/app-mobile/services/voiceTyping/whisper.js
packages/app-mobile/setupQuickActions.js
packages/app-mobile/tools/buildInjectedJs/BundledFile.js
packages/app-mobile/tools/buildInjectedJs/constants.js
packages/app-mobile/tools/buildInjectedJs/copyJs.js
packages/app-mobile/tools/buildInjectedJs/copyAssets.js
packages/app-mobile/tools/buildInjectedJs/gulpTasks.js
packages/app-mobile/tools/copyAssets.js
packages/app-mobile/utils/ShareExtension.js
@@ -888,7 +931,9 @@ packages/app-mobile/utils/ShareUtils.test.js
packages/app-mobile/utils/ShareUtils.js
packages/app-mobile/utils/TlsUtils.js
packages/app-mobile/utils/appDefaultState.js
packages/app-mobile/utils/appReducer.js
packages/app-mobile/utils/autodetectTheme.js
packages/app-mobile/utils/buildStartupTasks.js
packages/app-mobile/utils/checkPermissions.js
packages/app-mobile/utils/createRootStyle.js
packages/app-mobile/utils/database-driver-react-native.js
@@ -908,6 +953,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/useIsScreenReaderEnabled.js
packages/app-mobile/utils/hooks/useKeyboardState.js
packages/app-mobile/utils/hooks/useOnLongPressProps.js
packages/app-mobile/utils/hooks/useReduceMotionEnabled.js
@@ -916,7 +962,6 @@ packages/app-mobile/utils/image/fileToImage.web.js
packages/app-mobile/utils/image/getImageDimensions.js
packages/app-mobile/utils/image/resizeImage.js
packages/app-mobile/utils/initializeCommandService.js
packages/app-mobile/utils/injectedJs.js
packages/app-mobile/utils/ipc/RNToWebViewMessenger.js
packages/app-mobile/utils/ipc/WebViewToRNMessenger.js
packages/app-mobile/utils/lockToSingleInstance.js
@@ -926,6 +971,7 @@ packages/app-mobile/utils/pickDocument.js
packages/app-mobile/utils/polyfills/bufferPolyfill.js
packages/app-mobile/utils/polyfills/crypto-polyfill/index.js
packages/app-mobile/utils/polyfills/index.js
packages/app-mobile/utils/polyfills/index.web.js
packages/app-mobile/utils/setupNotifications.js
packages/app-mobile/utils/shareFile.js
packages/app-mobile/utils/shareHandler.js
@@ -936,6 +982,7 @@ packages/app-mobile/utils/shim-init-react/shimInitShared.js
packages/app-mobile/utils/testing/createMockReduxStore.js
packages/app-mobile/utils/testing/getWebViewDomById.js
packages/app-mobile/utils/testing/getWebViewWindowById.js
packages/app-mobile/utils/testing/mockPluginServiceSetup.js
packages/app-mobile/utils/testing/setupGlobalStore.js
packages/app-mobile/utils/testing/testingLibrary.js
packages/app-mobile/utils/types.js
@@ -974,24 +1021,49 @@ packages/editor/CodeMirror/editorCommands/sortSelectedLines.test.js
packages/editor/CodeMirror/editorCommands/sortSelectedLines.js
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/highlightActiveLineExtension.js
packages/editor/CodeMirror/extensions/keyUpHandlerExtension.js
packages/editor/CodeMirror/extensions/links/ctrlClickLinksExtension.js
packages/editor/CodeMirror/extensions/links/followLinkTooltipExtension.test.js
packages/editor/CodeMirror/extensions/links/followLinkTooltipExtension.js
packages/editor/CodeMirror/extensions/links/referenceLinksStateField.js
packages/editor/CodeMirror/extensions/links/utils/findLineMatchingLink.test.js
packages/editor/CodeMirror/extensions/links/utils/findLineMatchingLink.js
packages/editor/CodeMirror/extensions/links/utils/getUrlAtPosition.js
packages/editor/CodeMirror/extensions/links/utils/openLink.js
packages/editor/CodeMirror/extensions/markdownDecorationExtension.test.js
packages/editor/CodeMirror/extensions/markdownDecorationExtension.js
packages/editor/CodeMirror/extensions/markdownHighlightExtension.test.js
packages/editor/CodeMirror/extensions/markdownHighlightExtension.js
packages/editor/CodeMirror/extensions/markdownMathExtension.test.js
packages/editor/CodeMirror/extensions/markdownMathExtension.js
packages/editor/CodeMirror/extensions/modifierKeyCssExtension.js
packages/editor/CodeMirror/extensions/overwriteModeExtension.test.js
packages/editor/CodeMirror/extensions/overwriteModeExtension.js
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/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/types.js
packages/editor/CodeMirror/extensions/rendering/utils/makeBlockReplaceExtension.js
packages/editor/CodeMirror/extensions/rendering/utils/makeInlineReplaceExtension.js
packages/editor/CodeMirror/extensions/rendering/utils/nodeIntersectsSelection.js
packages/editor/CodeMirror/extensions/searchExtension.test.js
packages/editor/CodeMirror/extensions/searchExtension.js
packages/editor/CodeMirror/extensions/selectedNoteIdExtension.js
packages/editor/CodeMirror/getScrollFraction.js
packages/editor/CodeMirror/index.js
packages/editor/CodeMirror/pluginApi/PluginLoader.js
packages/editor/CodeMirror/pluginApi/codeMirrorRequire.js
packages/editor/CodeMirror/pluginApi/customEditorCompletion.test.js
packages/editor/CodeMirror/pluginApi/customEditorCompletion.js
packages/editor/CodeMirror/testing/createEditorControl.js
packages/editor/CodeMirror/testing/createEditorSettings.js
packages/editor/CodeMirror/testing/createTestEditor.js
packages/editor/CodeMirror/testing/findNodesWithName.js
packages/editor/CodeMirror/testing/forceFullParse.js
@@ -1023,13 +1095,78 @@ packages/editor/CodeMirror/utils/isInSyntaxNode.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/allLanguages.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/defaultLanguage.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/lookUpLanguage.js
packages/editor/CodeMirror/utils/markdown/getCheckboxAtPosition.js
packages/editor/CodeMirror/utils/markdown/renumberSelectedLists.test.js
packages/editor/CodeMirror/utils/markdown/renumberSelectedLists.js
packages/editor/CodeMirror/utils/markdown/stripBlockquote.js
packages/editor/CodeMirror/utils/markdown/toggleCheckboxAt.js
packages/editor/CodeMirror/utils/setupVim.js
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/createEditor.js
packages/editor/ProseMirror/index.js
packages/editor/ProseMirror/plugins/detailsPlugin.test.js
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/joplinEditorApiPlugin.js
packages/editor/ProseMirror/plugins/keymapPlugin.js
packages/editor/ProseMirror/plugins/linkTooltipPlugin.test.js
packages/editor/ProseMirror/plugins/linkTooltipPlugin.js
packages/editor/ProseMirror/plugins/listPlugin.js
packages/editor/ProseMirror/plugins/originalMarkupPlugin.js
packages/editor/ProseMirror/plugins/searchPlugin.js
packages/editor/ProseMirror/plugins/tablePlugin.js
packages/editor/ProseMirror/plugins/utils/createExternalEditorPlugin.js
packages/editor/ProseMirror/plugins/utils/createFloatingButtonPlugin.js
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/types.js
packages/editor/ProseMirror/utils/SelectableNodeView.js
packages/editor/ProseMirror/utils/UndoStackSynchronizer.js
packages/editor/ProseMirror/utils/canReplaceSelectionWith.js
packages/editor/ProseMirror/utils/computeSelectionFormatting.js
packages/editor/ProseMirror/utils/dom/createButton.js
packages/editor/ProseMirror/utils/dom/createTextArea.js
packages/editor/ProseMirror/utils/dom/createTextNode.js
packages/editor/ProseMirror/utils/dom/createUniqueId.js
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/jumpToHash.js
packages/editor/ProseMirror/utils/makeLinksClickableInElement.js
packages/editor/ProseMirror/utils/postprocessEditorOutput.test.js
packages/editor/ProseMirror/utils/postprocessEditorOutput.js
packages/editor/ProseMirror/utils/preprocessEditorInput.test.js
packages/editor/ProseMirror/utils/preprocessEditorInput.js
packages/editor/ProseMirror/utils/sanitizeHtml.js
packages/editor/ProseMirror/utils/selectFirstInstanceOfNode.js
packages/editor/ProseMirror/utils/trimEmptyParagraphs.js
packages/editor/ProseMirror/vendor/changedDescendants.js
packages/editor/ProseMirror/vendor/icons/addColumnRight.js
packages/editor/ProseMirror/vendor/icons/addRowBelow.js
packages/editor/ProseMirror/vendor/icons/icon.js
packages/editor/ProseMirror/vendor/icons/removeColumn.js
packages/editor/ProseMirror/vendor/icons/removeRow.js
packages/editor/ProseMirror/vendor/icons/types.js
packages/editor/ProseMirror/vendor/splitBlockAs.js
packages/editor/SelectionFormatting.js
packages/editor/events.js
packages/editor/polyfills.js
packages/editor/testing/createEditorSettings.js
packages/editor/testing/setUpLogger.js
packages/editor/types.js
packages/editor/utils/getFileFromPasteEvent.js
packages/fork-htmlparser2/src/CollectingHandler.js
packages/fork-htmlparser2/src/FeedHandler.spec.js
packages/fork-htmlparser2/src/FeedHandler.js
@@ -1074,6 +1211,8 @@ packages/lib/JoplinDatabase.js
packages/lib/JoplinError.js
packages/lib/JoplinServerApi.js
packages/lib/ObjectUtils.js
packages/lib/PerformanceLogger.test.js
packages/lib/PerformanceLogger.js
packages/lib/PoorManIntervals.js
packages/lib/RotatingLogs.test.js
packages/lib/RotatingLogs.js
@@ -1091,6 +1230,8 @@ packages/lib/array.js
packages/lib/callbackUrlUtils.test.js
packages/lib/callbackUrlUtils.js
packages/lib/clipperUtils.js
packages/lib/commands/convertHtmlToMarkdown.test.js
packages/lib/commands/convertHtmlToMarkdown.js
packages/lib/commands/deleteNote.js
packages/lib/commands/historyBackward.js
packages/lib/commands/historyForward.js
@@ -1107,6 +1248,8 @@ packages/lib/commands/toggleAllFolders.js
packages/lib/commands/toggleEditorPlugin.js
packages/lib/components/EncryptionConfigScreen/utils.test.js
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextDismissLinkClick.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextReadMoreLinkClick.js
packages/lib/components/shared/NoteList/getEmptyFolderMessage.js
packages/lib/components/shared/NoteRevisionViewer/getHelpMessage.js
packages/lib/components/shared/NoteRevisionViewer/useDeleteHistoryClick.js
@@ -1283,20 +1426,27 @@ packages/lib/services/database/migrations/44.js
packages/lib/services/database/migrations/45.js
packages/lib/services/database/migrations/46.js
packages/lib/services/database/migrations/47.js
packages/lib/services/database/migrations/48.js
packages/lib/services/database/migrations/49.js
packages/lib/services/database/migrations/index.js
packages/lib/services/database/sqlStringToLines.js
packages/lib/services/database/types.js
packages/lib/services/debug/populateDatabase.js
packages/lib/services/e2ee/EncryptionService.test.js
packages/lib/services/e2ee/EncryptionService.js
packages/lib/services/e2ee/RSA.node.js
packages/lib/services/e2ee/crypto.test.js
packages/lib/services/e2ee/crypto.js
packages/lib/services/e2ee/cryptoShared.js
packages/lib/services/e2ee/cryptoTestUtils.js
packages/lib/services/e2ee/ppk.test.js
packages/lib/services/e2ee/ppk.js
packages/lib/services/e2ee/ppkTestUtils.js
packages/lib/services/e2ee/ppk/RSA.node.js
packages/lib/services/e2ee/ppk/ppk.test.js
packages/lib/services/e2ee/ppk/ppk.js
packages/lib/services/e2ee/ppk/ppkTestUtils.js
packages/lib/services/e2ee/ppk/webCrypto/LongDataWrapper.js
packages/lib/services/e2ee/ppk/webCrypto/StringToBufferWrapper.js
packages/lib/services/e2ee/ppk/webCrypto/WebCryptoRsa.js
packages/lib/services/e2ee/ppk/webCrypto/buildRsaCryptoProvider.test.js
packages/lib/services/e2ee/ppk/webCrypto/buildRsaCryptoProvider.js
packages/lib/services/e2ee/types.js
packages/lib/services/e2ee/utils.test.js
packages/lib/services/e2ee/utils.js
@@ -1351,6 +1501,8 @@ packages/lib/services/ocr/OcrDriverBase.js
packages/lib/services/ocr/OcrService.test.js
packages/lib/services/ocr/OcrService.js
packages/lib/services/ocr/drivers/OcrDriverTesseract.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.test.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.js
packages/lib/services/ocr/utils/filterOcrText.test.js
packages/lib/services/ocr/utils/filterOcrText.js
packages/lib/services/ocr/utils/types.js
@@ -1399,6 +1551,7 @@ packages/lib/services/plugins/utils/createViewHandle.js
packages/lib/services/plugins/utils/executeSandboxCall.js
packages/lib/services/plugins/utils/getActivePluginEditorView.js
packages/lib/services/plugins/utils/getActivePluginEditorViews.js
packages/lib/services/plugins/utils/getPluginHelpUrl.js
packages/lib/services/plugins/utils/getPluginIssueReportUrl.test.js
packages/lib/services/plugins/utils/getPluginIssueReportUrl.js
packages/lib/services/plugins/utils/getPluginNamespacedSettingKey.js
@@ -1520,6 +1673,7 @@ packages/lib/shim-init-node.js
packages/lib/shim.js
packages/lib/string-utils.test.js
packages/lib/string-utils.js
packages/lib/testing/plugins/createTestPlugin.js
packages/lib/testing/share/makeMockShareInvitation.js
packages/lib/testing/share/mockShareService.js
packages/lib/testing/syncTargetUtils.js
@@ -1602,6 +1756,7 @@ packages/plugin-repo-cli/lib/gitCompareUrl.test.js
packages/plugin-repo-cli/lib/gitCompareUrl.js
packages/plugin-repo-cli/lib/overrideUtils.test.js
packages/plugin-repo-cli/lib/overrideUtils.js
packages/plugin-repo-cli/lib/searchPlugins.js
packages/plugin-repo-cli/lib/types.js
packages/plugin-repo-cli/lib/updateReadme.test.js
packages/plugin-repo-cli/lib/updateReadme.js
@@ -1664,12 +1819,14 @@ packages/tools/fuzzer/Client.js
packages/tools/fuzzer/ClientPool.js
packages/tools/fuzzer/Server.js
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/SeededRandom.js
packages/tools/fuzzer/utils/getNumberProperty.js
packages/tools/fuzzer/utils/getProperty.js
packages/tools/fuzzer/utils/getStringProperty.js
packages/tools/fuzzer/utils/openDebugSession.js
packages/tools/fuzzer/utils/retryWithCount.js
packages/tools/generate-database-types.js
packages/tools/generate-images.js
@@ -1701,6 +1858,7 @@ packages/tools/release-electron.js
packages/tools/release-ios.js
packages/tools/release-plugin-repo-cli.js
packages/tools/release-server.js
packages/tools/release-transcribe.js
packages/tools/saveClaConsentRecords.js
packages/tools/setupNewRelease.js
packages/tools/spellcheck.js
@@ -1714,6 +1872,8 @@ packages/tools/updateMarkdownDoc.js
packages/tools/utils/discourse.test.js
packages/tools/utils/discourse.js
packages/tools/utils/loadSponsors.js
packages/tools/utils/parsePluralLocalizationForm.js
packages/tools/utils/parsePlurallLocalizationForm.test.js
packages/tools/utils/translation.js
packages/tools/validateFilenames.js
packages/tools/website/build.js

View File

@@ -23,6 +23,7 @@ module.exports = {
'FileSystemCreateWritableOptions': 'readonly',
'FileSystemHandle': 'readonly',
'IDBTransactionMode': 'readonly',
'FlatArray': 'readonly',
'BigInt': 'readonly',
'globalThis': 'readonly',

View File

@@ -7,9 +7,13 @@
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
ROOT_DIR="$SCRIPT_DIR/../.."
TRANSCRIBE_TAG_PREFIX=transcribe
TRANSCRIBE_REPOSITORY=joplin/transcribe
IS_PULL_REQUEST=0
IS_DESKTOP_RELEASE=0
IS_SERVER_RELEASE=0
IS_TRANSCRIBE_RELEASE=0
IS_LINUX=0
IS_MACOS=0
@@ -23,6 +27,10 @@ if [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
IS_SERVER_RELEASE=1
fi
if [[ $GIT_TAG_NAME = $TRANSCRIBE_TAG_PREFIX-* ]]; then
IS_TRANSCRIBE_RELEASE=1
fi
if [[ $GIT_TAG_NAME = v* ]]; then
IS_DESKTOP_RELEASE=1
fi
@@ -41,15 +49,17 @@ DOCKER_IMAGE_PLATFORM="linux/amd64"
# a release
RUN_TESTS=0
if [ "$IS_SERVER_RELEASE" = 0 ] && [ "$IS_DESKTOP_RELEASE" = 0 ]; then
if [ "$IS_SERVER_RELEASE" = 0 ] && [ "$IS_DESKTOP_RELEASE" = 0 ] && [ "$IS_TRANSCRIBE_RELEASE" = 0 ]; then
RUN_TESTS=1
fi
if [ "$RUNNER_ARCH" == "ARM64" ] && [ "$IS_SERVER_RELEASE" == "0" ]; then
# We exit now because nothing works properly with the ARM64 architecture.
# We only proceed if building the server image.
echo "Running on ARM64 and not trying to build server image - early exit"
exit 0
if [ "$RUNNER_ARCH" == "ARM64" ]; then
if [ "$IS_SERVER_RELEASE" == "0" ] && [ "$IS_TRANSCRIBE_RELEASE" == "0" ]; then
# We exit now because nothing works properly with the ARM64 architecture.
# We only proceed if building the server image.
echo "Running on ARM64 and not trying to build server image - early exit"
exit 0
fi
fi
if [ "$RUNNER_ARCH" == "ARM64" ]; then
@@ -80,12 +90,14 @@ echo "GIT_TAG_NAME=$GIT_TAG_NAME"
echo "BUILD_SEQUENCIAL=$BUILD_SEQUENCIAL"
echo "SERVER_REPOSITORY=$SERVER_REPOSITORY"
echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX"
echo "TRANSCRIBE_TAG_PREFIX=$TRANSCRIBE_TAG_PREFIX"
echo "DOCKER_IMAGE_PLATFORM=$DOCKER_IMAGE_PLATFORM"
echo "IS_CONTINUOUS_INTEGRATION=$IS_CONTINUOUS_INTEGRATION"
echo "IS_PULL_REQUEST=$IS_PULL_REQUEST"
echo "IS_DESKTOP_RELEASE=$IS_DESKTOP_RELEASE"
echo "IS_SERVER_RELEASE=$IS_SERVER_RELEASE"
echo "IS_TRANSCRIBE_RELEASE=$IS_TRANSCRIBE_RELEASE"
echo "RUN_TESTS=$RUN_TESTS"
echo "IS_LINUX=$IS_LINUX"
echo "IS_MACOS=$IS_MACOS"
@@ -301,9 +313,13 @@ if [ "$IS_DESKTOP_RELEASE" == "1" ]; then
USE_HARD_LINKS=false yarn dist
fi
elif [[ $IS_LINUX = 1 ]] && [ "$IS_SERVER_RELEASE" == "1" ]; then
echo "Step: Building Docker Image..."
echo "Step: Building Joplin Server Docker Image..."
cd "$ROOT_DIR"
yarn buildServerDocker --platform $DOCKER_IMAGE_PLATFORM --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY
yarn buildServerDocker --docker-file Dockerfile.server --platform $DOCKER_IMAGE_PLATFORM --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY
elif [[ $IS_LINUX = 1 ]] && [ "$IS_TRANSCRIBE_RELEASE" == "1" ]; then
echo "Step: Building Joplin Transcribe Docker Image..."
cd "$ROOT_DIR"
yarn buildServerDocker --docker-file Dockerfile.transcribe --platform $DOCKER_IMAGE_PLATFORM --tag-name $GIT_TAG_NAME --push-images --repository $TRANSCRIBE_REPOSITORY
else
echo "Step: Building but *not* publishing desktop application..."

View File

@@ -40,4 +40,29 @@ jobs:
cd packages/app-mobile/android
sed -i -- 's/signingConfig signingConfigs.release/signingConfig signingConfigs.debug/' app/build.gradle
./gradlew assembleRelease
- name: Verify alignment
run: |
cd packages/app-mobile/android/app
APK_FILE="./build/outputs/apk/release/app-release.apk"
if test ! -f "$APK_FILE" ; then
echo "APK file not found."
exit 1
else
echo "APK file found at: $APK_FILE"
fi
BUILD_TOOLS_PATH="$ANDROID_HOME/build-tools/"
if test ! -d "$BUILD_TOOLS_PATH" ; then
echo "Build tools not found at $BUILD_TOOLS_PATH ($ANDROID_HOME, $BUILD_TOOLS_VERSION)"
exit 1
fi
# The build-tools/ directory contains different subdirectories
# for each build tools version. As a result, there may be multiple
# zipalign tools. Select the most recent (biggest two-digit version number):
ZIPALIGN_PATH="$(find $BUILD_TOOLS_PATH -name "zipalign" -print | sort | tail -n1)"
if test ! -x "$ZIPALIGN_PATH" ; then
echo "zipalign not found (searching in $BUILD_TOOLS_PATH, candidate: $ZIPALIGN_PATH)"
exit 1
fi
"$ZIPALIGN_PATH" -c -P 16 -v 4 "$APK_FILE"

View File

@@ -9,7 +9,7 @@ jobs:
matrix:
# Do not use unbuntu-latest because it causes `The operation was canceled` failures:
# https://github.com/actions/runner-images/issues/6709
os: [macos-13, ubuntu-22.04, windows-2025, ubuntu-22.04-arm]
os: [macos-15-intel, ubuntu-22.04, windows-2025, ubuntu-22.04-arm]
steps:
- uses: actions/checkout@v4
@@ -17,7 +17,6 @@ jobs:
uses: ./.github/workflows/shared/setup-build-environment
- name: Install Docker Engine
# if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v')
if: runner.os == 'Linux'
run: |
sudo apt-get install -y apt-transport-https
@@ -32,15 +31,41 @@ jobs:
sudo apt-get update || true
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin
- name: Free disk space
if: runner.os == 'Linux'
run: |
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
docker system prune -af || true
docker builder prune -af || true
sudo rm -rf /var/lib/docker/tmp/* || true
# Login to Docker only if we're on a server release tag. If we run this on
# a pull request it will fail because the PR doesn't have access to
# secrets
- uses: docker/login-action@v3
if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v')
if: runner.os == 'Linux' && (startsWith(github.ref, 'refs/tags/server-v') || startsWith(github.ref, 'refs/tags/transcribe-v'))
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# - name: Test Windows app signing
# if: runner.os == 'Windows'
# env:
# GH_TOKEN: ${{ secrets.GH_TOKEN }}
# IS_CONTINUOUS_INTEGRATION: 1
# BUILD_SEQUENCIAL: 1
# SSL_ESIGNER_USER_NAME: ${{ secrets.SSL_ESIGNER_USER_NAME }}
# SSL_ESIGNER_USER_PASSWORD: ${{ secrets.SSL_ESIGNER_USER_PASSWORD }}
# SSL_ESIGNER_CREDENTIAL_ID: ${{ secrets.SSL_ESIGNER_CREDENTIAL_ID }}
# SSL_ESIGNER_USER_TOTP: ${{ secrets.SSL_ESIGNER_USER_TOTP }}
# SIGN_APPLICATION: 1
# # To ensure that the operations stop on failure, all commands
# # should be on one line with "&&" in between.
# run: |
# yarn install && cd packages/app-desktop && yarn dist
- name: Run tests, build and publish Linux and macOS apps
if: runner.os == 'Linux' || runner.os == 'macOs'
env:
@@ -62,11 +87,14 @@ jobs:
- name: Build and publish Windows app
if: runner.os == 'Windows' && startsWith(github.ref, 'refs/tags/v')
env:
CSC_KEY_PASSWORD: ${{ secrets.WINDOWS_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.WINDOWS_CSC_LINK }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
IS_CONTINUOUS_INTEGRATION: 1
BUILD_SEQUENCIAL: 1
SSL_ESIGNER_USER_NAME: ${{ secrets.SSL_ESIGNER_USER_NAME }}
SSL_ESIGNER_USER_PASSWORD: ${{ secrets.SSL_ESIGNER_USER_PASSWORD }}
SSL_ESIGNER_CREDENTIAL_ID: ${{ secrets.SSL_ESIGNER_CREDENTIAL_ID }}
SSL_ESIGNER_USER_TOTP: ${{ secrets.SSL_ESIGNER_USER_TOTP }}
SIGN_APPLICATION: 1
# To ensure that the operations stop on failure, all commands
# should be on one line with "&&" in between.
run: |
@@ -123,6 +151,16 @@ jobs:
with:
node-version: '18'
- name: Free disk space
if: runner.os == 'Linux'
run: |
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
docker system prune -af || true
docker builder prune -af || true
sudo rm -rf /var/lib/docker/tmp/* || true
- name: Install Yarn
run: |
# https://yarnpkg.com/getting-started/install
@@ -141,7 +179,7 @@ jobs:
echo "DOCKER_IMAGE_PLATFORM=$DOCKER_IMAGE_PLATFORM"
yarn install
yarn buildServerDocker --platform $DOCKER_IMAGE_PLATFORM --tag-name server-v0.0.0 --repository joplin/server
yarn buildServerDocker --docker-file Dockerfile.server --platform $DOCKER_IMAGE_PLATFORM --tag-name server-v0.0.0 --repository joplin/server
# Basic test to ensure that the created build is valid. It should exit with
# code 0 if it works.
@@ -150,7 +188,7 @@ jobs:
- name: Check HTTP request
run: |
# Need to pass environment variables:
docker run -p 22300:22300 joplin/server:$(dpkg --print-architecture)-0.0.0 node dist/app.js --env dev &
docker run --env MAX_TIME_DRIFT=0 --publish 22300:22300 joplin/server:$(dpkg --print-architecture)-0.0.0 node dist/app.js --env dev &
# Wait for server to start
sleep 120
@@ -176,5 +214,4 @@ jobs:
if [[ "$actual_body" != "$expected_body" ]]; then
echo 'Failed while checking the body response after request to /api/ping'
exit 1;
fi
fi

218
.gitignore vendored
View File

@@ -69,8 +69,10 @@ 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/command-apidoc.js
packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js
packages/app-cli/app/command-cat.js
packages/app-cli/app/command-config.js
packages/app-cli/app/command-cp.js
@@ -89,6 +91,8 @@ packages/app-cli/app/command-ls.js
packages/app-cli/app/command-mkbook.test.js
packages/app-cli/app/command-mkbook.js
packages/app-cli/app/command-mv.js
packages/app-cli/app/command-publish.test.js
packages/app-cli/app/command-publish.js
packages/app-cli/app/command-ren.js
packages/app-cli/app/command-restore.js
packages/app-cli/app/command-rmbook.test.js
@@ -101,6 +105,8 @@ packages/app-cli/app/command-share.test.js
packages/app-cli/app/command-share.js
packages/app-cli/app/command-sync.js
packages/app-cli/app/command-testing.js
packages/app-cli/app/command-unpublish.test.js
packages/app-cli/app/command-unpublish.js
packages/app-cli/app/command-use.js
packages/app-cli/app/command-version.js
packages/app-cli/app/gui/FolderListWidget.js
@@ -108,6 +114,7 @@ packages/app-cli/app/gui/StatusBarWidget.js
packages/app-cli/app/services/plugins/PluginRunner.js
packages/app-cli/app/setupCommand.js
packages/app-cli/app/utils/initializeCommandService.js
packages/app-cli/app/utils/iterateStdin.js
packages/app-cli/app/utils/shimInitCli.js
packages/app-cli/app/utils/testUtils.js
packages/app-cli/tests/HtmlToMd.js
@@ -130,6 +137,8 @@ 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
@@ -170,6 +179,7 @@ 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
@@ -233,6 +243,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useKeymap.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useRefocusOnVisiblePaneChange.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/useSyncEditorValue.js
packages/app-desktop/gui/NoteEditor/NoteBody/PlainEditor/PlainEditor.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
@@ -243,6 +254,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useCursorPositioning.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useEditDialog.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useEditDialogEventListeners.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useKeyboardRefocusHandler.js
@@ -271,6 +283,7 @@ packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.js
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.js
packages/app-desktop/gui/NoteEditor/utils/contextMenu.js
packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.js
packages/app-desktop/gui/NoteEditor/utils/getResourceBaseUrl.js
packages/app-desktop/gui/NoteEditor/utils/getWindowCommandPriority.js
packages/app-desktop/gui/NoteEditor/utils/index.js
packages/app-desktop/gui/NoteEditor/utils/markupRenderOptions.js
@@ -283,6 +296,7 @@ packages/app-desktop/gui/NoteEditor/utils/useEffectiveNoteId.js
packages/app-desktop/gui/NoteEditor/utils/useFolder.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.test.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.js
packages/app-desktop/gui/NoteEditor/utils/useInitialCursorLocation.js
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
packages/app-desktop/gui/NoteEditor/utils/useNoteSearchBar.js
packages/app-desktop/gui/NoteEditor/utils/usePluginEditorView.test.js
@@ -528,6 +542,8 @@ packages/app-desktop/integration-tests/util/setSettingValue.js
packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/integration-tests/wcag.spec.js
packages/app-desktop/main-html.js
packages/app-desktop/main.js
packages/app-desktop/playwright.config.js
packages/app-desktop/plugins/GotoAnything.js
packages/app-desktop/services/autoUpdater/AutoUpdaterService.test.js
@@ -564,6 +580,7 @@ packages/app-desktop/tools/generateLatestArm64Yml.js
packages/app-desktop/tools/githubReleasesUtils.js
packages/app-desktop/tools/modifyReleaseAssets.js
packages/app-desktop/tools/notarizeMacApp.js
packages/app-desktop/tools/resolveSourceMap.js
packages/app-desktop/utils/7zip/getPathToExecutable7Zip.js
packages/app-desktop/utils/7zip/pathToBundled7Zip.js
packages/app-desktop/utils/checkForUpdatesUtils.test.js
@@ -636,6 +653,9 @@ packages/app-mobile/components/ExtendedWebView/index.jest.js
packages/app-mobile/components/ExtendedWebView/index.js
packages/app-mobile/components/ExtendedWebView/index.web.js
packages/app-mobile/components/ExtendedWebView/types.js
packages/app-mobile/components/ExtendedWebView/utils/useCss.js
packages/app-mobile/components/FeedbackBanner.test.js
packages/app-mobile/components/FeedbackBanner.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/Icon.js
packages/app-mobile/components/IconButton.js
@@ -644,48 +664,34 @@ packages/app-mobile/components/ModalDialog.js
packages/app-mobile/components/NestableFlatList.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.test.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/Renderer.test.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/Renderer.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/noteBodyViewerBundle.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/types.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/utils/addPluginAssets.js
packages/app-mobile/components/NoteBodyViewer/bundledJs/utils/makeResourceModel.js
packages/app-mobile/components/NoteBodyViewer/hooks/useContentScripts.js
packages/app-mobile/components/NoteBodyViewer/hooks/useEditPopup.test.js
packages/app-mobile/components/NoteBodyViewer/hooks/useEditPopup.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnMessage.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
packages/app-mobile/components/NoteBodyViewer/hooks/useRenderer.js
packages/app-mobile/components/NoteBodyViewer/hooks/useRerenderHandler.js
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js
packages/app-mobile/components/NoteBodyViewer/types.js
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.js
packages/app-mobile/components/NoteEditor/EditLinkDialog.js
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/js-draw/applyTemplateToEditor.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/createJsDrawEditor.test.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/createJsDrawEditor.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/polyfills.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/startAutosaveLoop.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/types.js
packages/app-mobile/components/NoteEditor/ImageEditor/js-draw/watchEditorForTemplateChanges.js
packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.js
packages/app-mobile/components/NoteEditor/ImageEditor/utils/useEditorMessenger.js
packages/app-mobile/components/NoteEditor/MarkdownEditor.js
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
packages/app-mobile/components/NoteEditor/NoteEditor.js
packages/app-mobile/components/NoteEditor/RichTextEditor.test.js
packages/app-mobile/components/NoteEditor/RichTextEditor.js
packages/app-mobile/components/NoteEditor/SearchPanel.js
packages/app-mobile/components/NoteEditor/WarningBanner.js
packages/app-mobile/components/NoteEditor/commandDeclarations.js
packages/app-mobile/components/NoteEditor/hooks/useCodeMirrorPlugins.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.test.js
packages/app-mobile/components/NoteEditor/hooks/useEditorCommandHandler.js
packages/app-mobile/components/NoteEditor/testing/createTestEditorProps.js
packages/app-mobile/components/NoteEditor/types.js
packages/app-mobile/components/NoteItem.js
packages/app-mobile/components/NoteList.js
packages/app-mobile/components/ProfileSwitcher/ProfileEditor.js
packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.js
packages/app-mobile/components/ProfileSwitcher/useProfileConfig.js
packages/app-mobile/components/SafeAreaView.js
packages/app-mobile/components/ScreenHeader/Menu.js
packages/app-mobile/components/ScreenHeader/WarningBanner.test.js
packages/app-mobile/components/ScreenHeader/WarningBanner.js
@@ -696,6 +702,8 @@ packages/app-mobile/components/SearchInput.js
packages/app-mobile/components/SelectDateTimeDialog.js
packages/app-mobile/components/SideMenu.js
packages/app-mobile/components/SideMenuContentNote.js
packages/app-mobile/components/SyncWizard/JoplinCloudIcon.js
packages/app-mobile/components/SyncWizard/SyncWizard.js
packages/app-mobile/components/TagEditor.test.js
packages/app-mobile/components/TagEditor.js
packages/app-mobile/components/TextInput.js
@@ -712,6 +720,7 @@ packages/app-mobile/components/base-screen.js
packages/app-mobile/components/biometrics/BiometricPopup.js
packages/app-mobile/components/biometrics/biometricAuthenticate.js
packages/app-mobile/components/biometrics/sensorInfo.js
packages/app-mobile/components/buttons/CardButton.js
packages/app-mobile/components/buttons/FloatingActionButton.js
packages/app-mobile/components/buttons/LabelledIconButton.js
packages/app-mobile/components/buttons/MultiTouchableOpacity.js
@@ -722,6 +731,7 @@ packages/app-mobile/components/getResponsiveValue.js
packages/app-mobile/components/global-style.js
packages/app-mobile/components/plugins/PluginNotification.js
packages/app-mobile/components/plugins/PluginRunner.js
packages/app-mobile/components/plugins/PluginRunnerWebView.test.js
packages/app-mobile/components/plugins/PluginRunnerWebView.js
packages/app-mobile/components/plugins/backgroundPage/initializeDialogWebView.js
packages/app-mobile/components/plugins/backgroundPage/initializePluginBackgroundIframe.js
@@ -786,7 +796,6 @@ packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/InstallButto
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/WrappedPluginStates.js
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/mockRepositoryApiConstructor.js
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/newRepoApi.js
packages/app-mobile/components/screens/ConfigScreen/plugins/testUtils/pluginServiceSetup.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/openWebsiteForPlugin.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/usePluginCallbacks.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/usePluginItem.js
@@ -812,6 +821,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/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
packages/app-mobile/components/screens/SearchScreen/index.js
packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.js
@@ -833,6 +843,38 @@ packages/app-mobile/components/voiceTyping/AudioRecordingBanner.js
packages/app-mobile/components/voiceTyping/RecordingControls.js
packages/app-mobile/components/voiceTyping/SpeechToTextBanner.js
packages/app-mobile/components/voiceTyping/types.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/applyTemplateToEditor.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/index.test.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/index.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/startAutosaveLoop.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/types.js
packages/app-mobile/contentScripts/imageEditorBundle/contentScript/watchEditorForTemplateChanges.js
packages/app-mobile/contentScripts/imageEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/imageEditorBundle/utils/useEditorMessenger.js
packages/app-mobile/contentScripts/markdownEditorBundle/contentScript.js
packages/app-mobile/contentScripts/markdownEditorBundle/types.js
packages/app-mobile/contentScripts/markdownEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/markdownEditorBundle/utils/useCodeMirrorPlugins.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.test.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/Renderer.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/index.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/types.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/addPluginAssets.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/afterFullPageRender.js
packages/app-mobile/contentScripts/rendererBundle/contentScript/utils/makeResourceModel.js
packages/app-mobile/contentScripts/rendererBundle/types.js
packages/app-mobile/contentScripts/rendererBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/rendererBundle/utils/useContentScripts.js
packages/app-mobile/contentScripts/rendererBundle/utils/useEditPopup.test.js
packages/app-mobile/contentScripts/rendererBundle/utils/useEditPopup.js
packages/app-mobile/contentScripts/richTextEditorBundle/contentScript/convertHtmlToMarkdown.js
packages/app-mobile/contentScripts/richTextEditorBundle/contentScript/index.js
packages/app-mobile/contentScripts/richTextEditorBundle/types.js
packages/app-mobile/contentScripts/richTextEditorBundle/useWebViewSetup.js
packages/app-mobile/contentScripts/types.js
packages/app-mobile/contentScripts/utils/polyfills.js
packages/app-mobile/contentScripts/utils/readFileToBase64.js
packages/app-mobile/contentScripts/utils/setUpLogger.js
packages/app-mobile/gulpfile.js
packages/app-mobile/index.web.js
packages/app-mobile/root.js
@@ -842,20 +884,19 @@ packages/app-mobile/services/AlarmServiceDriver.web.js
packages/app-mobile/services/BackButtonService.js
packages/app-mobile/services/commands/stateToWhenClauseContext.js
packages/app-mobile/services/e2ee/RSA.react-native.js
packages/app-mobile/services/e2ee/RSA.react-native.web.js
packages/app-mobile/services/e2ee/crypto.js
packages/app-mobile/services/plugins/PlatformImplementation.js
packages/app-mobile/services/profiles/index.js
packages/app-mobile/services/voiceTyping/VoiceTyping.js
packages/app-mobile/services/voiceTyping/utils/unzip.android.js
packages/app-mobile/services/voiceTyping/utils/unzip.js
packages/app-mobile/services/voiceTyping/vosk.android.js
packages/app-mobile/services/voiceTyping/vosk.js
packages/app-mobile/services/voiceTyping/whisper.test.js
packages/app-mobile/services/voiceTyping/whisper.js
packages/app-mobile/setupQuickActions.js
packages/app-mobile/tools/buildInjectedJs/BundledFile.js
packages/app-mobile/tools/buildInjectedJs/constants.js
packages/app-mobile/tools/buildInjectedJs/copyJs.js
packages/app-mobile/tools/buildInjectedJs/copyAssets.js
packages/app-mobile/tools/buildInjectedJs/gulpTasks.js
packages/app-mobile/tools/copyAssets.js
packages/app-mobile/utils/ShareExtension.js
@@ -863,7 +904,9 @@ packages/app-mobile/utils/ShareUtils.test.js
packages/app-mobile/utils/ShareUtils.js
packages/app-mobile/utils/TlsUtils.js
packages/app-mobile/utils/appDefaultState.js
packages/app-mobile/utils/appReducer.js
packages/app-mobile/utils/autodetectTheme.js
packages/app-mobile/utils/buildStartupTasks.js
packages/app-mobile/utils/checkPermissions.js
packages/app-mobile/utils/createRootStyle.js
packages/app-mobile/utils/database-driver-react-native.js
@@ -883,6 +926,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/useIsScreenReaderEnabled.js
packages/app-mobile/utils/hooks/useKeyboardState.js
packages/app-mobile/utils/hooks/useOnLongPressProps.js
packages/app-mobile/utils/hooks/useReduceMotionEnabled.js
@@ -891,7 +935,6 @@ packages/app-mobile/utils/image/fileToImage.web.js
packages/app-mobile/utils/image/getImageDimensions.js
packages/app-mobile/utils/image/resizeImage.js
packages/app-mobile/utils/initializeCommandService.js
packages/app-mobile/utils/injectedJs.js
packages/app-mobile/utils/ipc/RNToWebViewMessenger.js
packages/app-mobile/utils/ipc/WebViewToRNMessenger.js
packages/app-mobile/utils/lockToSingleInstance.js
@@ -901,6 +944,7 @@ packages/app-mobile/utils/pickDocument.js
packages/app-mobile/utils/polyfills/bufferPolyfill.js
packages/app-mobile/utils/polyfills/crypto-polyfill/index.js
packages/app-mobile/utils/polyfills/index.js
packages/app-mobile/utils/polyfills/index.web.js
packages/app-mobile/utils/setupNotifications.js
packages/app-mobile/utils/shareFile.js
packages/app-mobile/utils/shareHandler.js
@@ -911,6 +955,7 @@ packages/app-mobile/utils/shim-init-react/shimInitShared.js
packages/app-mobile/utils/testing/createMockReduxStore.js
packages/app-mobile/utils/testing/getWebViewDomById.js
packages/app-mobile/utils/testing/getWebViewWindowById.js
packages/app-mobile/utils/testing/mockPluginServiceSetup.js
packages/app-mobile/utils/testing/setupGlobalStore.js
packages/app-mobile/utils/testing/testingLibrary.js
packages/app-mobile/utils/types.js
@@ -949,24 +994,49 @@ packages/editor/CodeMirror/editorCommands/sortSelectedLines.test.js
packages/editor/CodeMirror/editorCommands/sortSelectedLines.js
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/highlightActiveLineExtension.js
packages/editor/CodeMirror/extensions/keyUpHandlerExtension.js
packages/editor/CodeMirror/extensions/links/ctrlClickLinksExtension.js
packages/editor/CodeMirror/extensions/links/followLinkTooltipExtension.test.js
packages/editor/CodeMirror/extensions/links/followLinkTooltipExtension.js
packages/editor/CodeMirror/extensions/links/referenceLinksStateField.js
packages/editor/CodeMirror/extensions/links/utils/findLineMatchingLink.test.js
packages/editor/CodeMirror/extensions/links/utils/findLineMatchingLink.js
packages/editor/CodeMirror/extensions/links/utils/getUrlAtPosition.js
packages/editor/CodeMirror/extensions/links/utils/openLink.js
packages/editor/CodeMirror/extensions/markdownDecorationExtension.test.js
packages/editor/CodeMirror/extensions/markdownDecorationExtension.js
packages/editor/CodeMirror/extensions/markdownHighlightExtension.test.js
packages/editor/CodeMirror/extensions/markdownHighlightExtension.js
packages/editor/CodeMirror/extensions/markdownMathExtension.test.js
packages/editor/CodeMirror/extensions/markdownMathExtension.js
packages/editor/CodeMirror/extensions/modifierKeyCssExtension.js
packages/editor/CodeMirror/extensions/overwriteModeExtension.test.js
packages/editor/CodeMirror/extensions/overwriteModeExtension.js
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/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/types.js
packages/editor/CodeMirror/extensions/rendering/utils/makeBlockReplaceExtension.js
packages/editor/CodeMirror/extensions/rendering/utils/makeInlineReplaceExtension.js
packages/editor/CodeMirror/extensions/rendering/utils/nodeIntersectsSelection.js
packages/editor/CodeMirror/extensions/searchExtension.test.js
packages/editor/CodeMirror/extensions/searchExtension.js
packages/editor/CodeMirror/extensions/selectedNoteIdExtension.js
packages/editor/CodeMirror/getScrollFraction.js
packages/editor/CodeMirror/index.js
packages/editor/CodeMirror/pluginApi/PluginLoader.js
packages/editor/CodeMirror/pluginApi/codeMirrorRequire.js
packages/editor/CodeMirror/pluginApi/customEditorCompletion.test.js
packages/editor/CodeMirror/pluginApi/customEditorCompletion.js
packages/editor/CodeMirror/testing/createEditorControl.js
packages/editor/CodeMirror/testing/createEditorSettings.js
packages/editor/CodeMirror/testing/createTestEditor.js
packages/editor/CodeMirror/testing/findNodesWithName.js
packages/editor/CodeMirror/testing/forceFullParse.js
@@ -998,13 +1068,78 @@ packages/editor/CodeMirror/utils/isInSyntaxNode.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/allLanguages.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/defaultLanguage.js
packages/editor/CodeMirror/utils/markdown/codeBlockLanguages/lookUpLanguage.js
packages/editor/CodeMirror/utils/markdown/getCheckboxAtPosition.js
packages/editor/CodeMirror/utils/markdown/renumberSelectedLists.test.js
packages/editor/CodeMirror/utils/markdown/renumberSelectedLists.js
packages/editor/CodeMirror/utils/markdown/stripBlockquote.js
packages/editor/CodeMirror/utils/markdown/toggleCheckboxAt.js
packages/editor/CodeMirror/utils/setupVim.js
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/createEditor.js
packages/editor/ProseMirror/index.js
packages/editor/ProseMirror/plugins/detailsPlugin.test.js
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/joplinEditorApiPlugin.js
packages/editor/ProseMirror/plugins/keymapPlugin.js
packages/editor/ProseMirror/plugins/linkTooltipPlugin.test.js
packages/editor/ProseMirror/plugins/linkTooltipPlugin.js
packages/editor/ProseMirror/plugins/listPlugin.js
packages/editor/ProseMirror/plugins/originalMarkupPlugin.js
packages/editor/ProseMirror/plugins/searchPlugin.js
packages/editor/ProseMirror/plugins/tablePlugin.js
packages/editor/ProseMirror/plugins/utils/createExternalEditorPlugin.js
packages/editor/ProseMirror/plugins/utils/createFloatingButtonPlugin.js
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/types.js
packages/editor/ProseMirror/utils/SelectableNodeView.js
packages/editor/ProseMirror/utils/UndoStackSynchronizer.js
packages/editor/ProseMirror/utils/canReplaceSelectionWith.js
packages/editor/ProseMirror/utils/computeSelectionFormatting.js
packages/editor/ProseMirror/utils/dom/createButton.js
packages/editor/ProseMirror/utils/dom/createTextArea.js
packages/editor/ProseMirror/utils/dom/createTextNode.js
packages/editor/ProseMirror/utils/dom/createUniqueId.js
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/jumpToHash.js
packages/editor/ProseMirror/utils/makeLinksClickableInElement.js
packages/editor/ProseMirror/utils/postprocessEditorOutput.test.js
packages/editor/ProseMirror/utils/postprocessEditorOutput.js
packages/editor/ProseMirror/utils/preprocessEditorInput.test.js
packages/editor/ProseMirror/utils/preprocessEditorInput.js
packages/editor/ProseMirror/utils/sanitizeHtml.js
packages/editor/ProseMirror/utils/selectFirstInstanceOfNode.js
packages/editor/ProseMirror/utils/trimEmptyParagraphs.js
packages/editor/ProseMirror/vendor/changedDescendants.js
packages/editor/ProseMirror/vendor/icons/addColumnRight.js
packages/editor/ProseMirror/vendor/icons/addRowBelow.js
packages/editor/ProseMirror/vendor/icons/icon.js
packages/editor/ProseMirror/vendor/icons/removeColumn.js
packages/editor/ProseMirror/vendor/icons/removeRow.js
packages/editor/ProseMirror/vendor/icons/types.js
packages/editor/ProseMirror/vendor/splitBlockAs.js
packages/editor/SelectionFormatting.js
packages/editor/events.js
packages/editor/polyfills.js
packages/editor/testing/createEditorSettings.js
packages/editor/testing/setUpLogger.js
packages/editor/types.js
packages/editor/utils/getFileFromPasteEvent.js
packages/fork-htmlparser2/src/CollectingHandler.js
packages/fork-htmlparser2/src/FeedHandler.spec.js
packages/fork-htmlparser2/src/FeedHandler.js
@@ -1049,6 +1184,8 @@ packages/lib/JoplinDatabase.js
packages/lib/JoplinError.js
packages/lib/JoplinServerApi.js
packages/lib/ObjectUtils.js
packages/lib/PerformanceLogger.test.js
packages/lib/PerformanceLogger.js
packages/lib/PoorManIntervals.js
packages/lib/RotatingLogs.test.js
packages/lib/RotatingLogs.js
@@ -1066,6 +1203,8 @@ packages/lib/array.js
packages/lib/callbackUrlUtils.test.js
packages/lib/callbackUrlUtils.js
packages/lib/clipperUtils.js
packages/lib/commands/convertHtmlToMarkdown.test.js
packages/lib/commands/convertHtmlToMarkdown.js
packages/lib/commands/deleteNote.js
packages/lib/commands/historyBackward.js
packages/lib/commands/historyForward.js
@@ -1082,6 +1221,8 @@ packages/lib/commands/toggleAllFolders.js
packages/lib/commands/toggleEditorPlugin.js
packages/lib/components/EncryptionConfigScreen/utils.test.js
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextDismissLinkClick.js
packages/lib/components/shared/NoteEditor/WarningBanner/onRichTextReadMoreLinkClick.js
packages/lib/components/shared/NoteList/getEmptyFolderMessage.js
packages/lib/components/shared/NoteRevisionViewer/getHelpMessage.js
packages/lib/components/shared/NoteRevisionViewer/useDeleteHistoryClick.js
@@ -1258,20 +1399,27 @@ packages/lib/services/database/migrations/44.js
packages/lib/services/database/migrations/45.js
packages/lib/services/database/migrations/46.js
packages/lib/services/database/migrations/47.js
packages/lib/services/database/migrations/48.js
packages/lib/services/database/migrations/49.js
packages/lib/services/database/migrations/index.js
packages/lib/services/database/sqlStringToLines.js
packages/lib/services/database/types.js
packages/lib/services/debug/populateDatabase.js
packages/lib/services/e2ee/EncryptionService.test.js
packages/lib/services/e2ee/EncryptionService.js
packages/lib/services/e2ee/RSA.node.js
packages/lib/services/e2ee/crypto.test.js
packages/lib/services/e2ee/crypto.js
packages/lib/services/e2ee/cryptoShared.js
packages/lib/services/e2ee/cryptoTestUtils.js
packages/lib/services/e2ee/ppk.test.js
packages/lib/services/e2ee/ppk.js
packages/lib/services/e2ee/ppkTestUtils.js
packages/lib/services/e2ee/ppk/RSA.node.js
packages/lib/services/e2ee/ppk/ppk.test.js
packages/lib/services/e2ee/ppk/ppk.js
packages/lib/services/e2ee/ppk/ppkTestUtils.js
packages/lib/services/e2ee/ppk/webCrypto/LongDataWrapper.js
packages/lib/services/e2ee/ppk/webCrypto/StringToBufferWrapper.js
packages/lib/services/e2ee/ppk/webCrypto/WebCryptoRsa.js
packages/lib/services/e2ee/ppk/webCrypto/buildRsaCryptoProvider.test.js
packages/lib/services/e2ee/ppk/webCrypto/buildRsaCryptoProvider.js
packages/lib/services/e2ee/types.js
packages/lib/services/e2ee/utils.test.js
packages/lib/services/e2ee/utils.js
@@ -1326,6 +1474,8 @@ packages/lib/services/ocr/OcrDriverBase.js
packages/lib/services/ocr/OcrService.test.js
packages/lib/services/ocr/OcrService.js
packages/lib/services/ocr/drivers/OcrDriverTesseract.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.test.js
packages/lib/services/ocr/drivers/OcrDriverTranscribe.js
packages/lib/services/ocr/utils/filterOcrText.test.js
packages/lib/services/ocr/utils/filterOcrText.js
packages/lib/services/ocr/utils/types.js
@@ -1374,6 +1524,7 @@ packages/lib/services/plugins/utils/createViewHandle.js
packages/lib/services/plugins/utils/executeSandboxCall.js
packages/lib/services/plugins/utils/getActivePluginEditorView.js
packages/lib/services/plugins/utils/getActivePluginEditorViews.js
packages/lib/services/plugins/utils/getPluginHelpUrl.js
packages/lib/services/plugins/utils/getPluginIssueReportUrl.test.js
packages/lib/services/plugins/utils/getPluginIssueReportUrl.js
packages/lib/services/plugins/utils/getPluginNamespacedSettingKey.js
@@ -1495,6 +1646,7 @@ packages/lib/shim-init-node.js
packages/lib/shim.js
packages/lib/string-utils.test.js
packages/lib/string-utils.js
packages/lib/testing/plugins/createTestPlugin.js
packages/lib/testing/share/makeMockShareInvitation.js
packages/lib/testing/share/mockShareService.js
packages/lib/testing/syncTargetUtils.js
@@ -1577,6 +1729,7 @@ packages/plugin-repo-cli/lib/gitCompareUrl.test.js
packages/plugin-repo-cli/lib/gitCompareUrl.js
packages/plugin-repo-cli/lib/overrideUtils.test.js
packages/plugin-repo-cli/lib/overrideUtils.js
packages/plugin-repo-cli/lib/searchPlugins.js
packages/plugin-repo-cli/lib/types.js
packages/plugin-repo-cli/lib/updateReadme.test.js
packages/plugin-repo-cli/lib/updateReadme.js
@@ -1639,12 +1792,14 @@ packages/tools/fuzzer/Client.js
packages/tools/fuzzer/ClientPool.js
packages/tools/fuzzer/Server.js
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/SeededRandom.js
packages/tools/fuzzer/utils/getNumberProperty.js
packages/tools/fuzzer/utils/getProperty.js
packages/tools/fuzzer/utils/getStringProperty.js
packages/tools/fuzzer/utils/openDebugSession.js
packages/tools/fuzzer/utils/retryWithCount.js
packages/tools/generate-database-types.js
packages/tools/generate-images.js
@@ -1676,6 +1831,7 @@ packages/tools/release-electron.js
packages/tools/release-ios.js
packages/tools/release-plugin-repo-cli.js
packages/tools/release-server.js
packages/tools/release-transcribe.js
packages/tools/saveClaConsentRecords.js
packages/tools/setupNewRelease.js
packages/tools/spellcheck.js
@@ -1689,6 +1845,8 @@ packages/tools/updateMarkdownDoc.js
packages/tools/utils/discourse.test.js
packages/tools/utils/discourse.js
packages/tools/utils/loadSponsors.js
packages/tools/utils/parsePluralLocalizationForm.js
packages/tools/utils/parsePlurallLocalizationForm.test.js
packages/tools/utils/translation.js
packages/tools/validateFilenames.js
packages/tools/website/build.js

View File

@@ -0,0 +1,36 @@
# Patch to remove eval. This allows using depd in an environment with
# a strict Content-Security-Policy.
# Ref: https://github.com/dougwilson/nodejs-depd/pull/33
diff --git a/index.js b/index.js
index d758d3c8f58a60bf27ef377ad77639bf10ce7854..2bad40d4eeba553d3bcfb206873eac059067ae3b 100644
--- a/index.js
+++ b/index.js
@@ -399,19 +399,20 @@ function wrapfunction (fn, message) {
throw new TypeError('argument fn must be a function')
}
- var args = createArgumentsString(fn.length)
- var deprecate = this // eslint-disable-line no-unused-vars
var stack = getStack()
var site = callSiteLocation(stack[1])
site.name = fn.name
- // eslint-disable-next-line no-eval
- var deprecatedfn = eval('(function (' + args + ') {\n' +
- '"use strict"\n' +
- 'log.call(deprecate, message, site)\n' +
- 'return fn.apply(this, arguments)\n' +
- '})')
+ var deprecatedfn
+ var self = this
+ deprecatedfn = function () {
+ 'use strict'
+ log.call(self, message, site)
+ return fn.apply(this, arguments)
+ }
+ Object.defineProperty(deprecatedfn, 'length', { value: fn.length })
+ Object.defineProperty(deprecatedfn, 'name', { value: fn.name })
return deprecatedfn
}

View File

@@ -0,0 +1,35 @@
# Patch to remove eval. This allows using depd in an environment with
# a strict Content-Security-Policy.
# Ref: https://github.com/dougwilson/nodejs-depd/pull/33
diff --git a/index.js b/index.js
index 1bf2fcfdeffc984e5ad792eec08744c29d4a4590..1b24aa2414458bc651abfdded81b103c131efeaa 100644
--- a/index.js
+++ b/index.js
@@ -415,19 +415,19 @@ function wrapfunction (fn, message) {
throw new TypeError('argument fn must be a function')
}
- var args = createArgumentsString(fn.length)
var stack = getStack()
var site = callSiteLocation(stack[1])
site.name = fn.name
- // eslint-disable-next-line no-new-func
- var deprecatedfn = new Function('fn', 'log', 'deprecate', 'message', 'site',
- '"use strict"\n' +
- 'return function (' + args + ') {' +
- 'log.call(deprecate, message, site)\n' +
- 'return fn.apply(this, arguments)\n' +
- '}')(fn, log, this, message, site)
+ var self = this
+ var deprecatedfn = function () {
+ 'use strict'
+ log.call(self, message, site)
+ return fn.apply(this, arguments)
+ }
+ Object.defineProperty(deprecatedfn, 'length', { value: fn.length })
+ Object.defineProperty(deprecatedfn, 'name', { value: fn.name })
return deprecatedfn
}

View File

@@ -1,209 +0,0 @@
diff --git a/android/build.gradle b/android/build.gradle
index 6afcbbf0cc8ca2d69dd78077d61e59a90b2136bb..9f8d72b4ec5b2b3d290975d6a255917c95300854 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -67,19 +67,19 @@ repositories {
}
// Generate UUIDs for each models contained in android/src/main/assets/
-tasks.register('genUUID') {
- doLast {
- fileTree(dir: "$rootDir/app/src/main/assets", exclude: ['*/*']).visit { fileDetails ->
- if (fileDetails.directory) {
- def odir = file("$rootDir/app/src/main/assets/$fileDetails.relativePath")
- def ofile = file("$odir/uuid")
- mkdir odir
- ofile.text = UUID.randomUUID().toString()
- }
- }
- }
-}
-preBuild.dependsOn genUUID
+// tasks.register('genUUID') {
+// doLast {
+// fileTree(dir: "$rootDir/app/src/main/assets", exclude: ['*/*']).visit { fileDetails ->
+// if (fileDetails.directory) {
+// def odir = file("$rootDir/app/src/main/assets/$fileDetails.relativePath")
+// def ofile = file("$odir/uuid")
+// mkdir odir
+// ofile.text = UUID.randomUUID().toString()
+// }
+// }
+// }
+// }
+// preBuild.dependsOn genUUID
def kotlin_version = getExtOrDefault('kotlinVersion')
diff --git a/android/src/main/java/com/reactnativevosk/VoskModule.kt b/android/src/main/java/com/reactnativevosk/VoskModule.kt
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4e3ff404a 100644
--- a/android/src/main/java/com/reactnativevosk/VoskModule.kt
+++ b/android/src/main/java/com/reactnativevosk/VoskModule.kt
@@ -19,13 +19,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
return "Vosk"
}
+ @ReactMethod
+ fun addListener(type: String?) {
+ // Keep: Required for RN built in Event Emitter Calls.
+ }
+
+ @ReactMethod
+ fun removeListeners(type: Int?) {
+ // Keep: Required for RN built in Event Emitter Calls.
+ }
+
override fun onResult(hypothesis: String) {
// Get text data from string object
val text = getHypothesisText(hypothesis)
// Stop recording if data found
if (text != null && text.isNotEmpty()) {
- cleanRecognizer();
+ // Don't auto-stop the recogniser - we want to do that when the user
+ // presses on "stop" only.
+ // cleanRecognizer();
sendEvent("onResult", text)
}
}
@@ -93,12 +105,11 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
@ReactMethod
fun loadModel(path: String, promise: Promise) {
cleanModel();
- StorageService.unpack(context, path, "models",
- { model: Model? ->
- this.model = model
- promise.resolve("Model successfully loaded")
- }
- ) { e: IOException ->
+
+ try {
+ this.model = Model(path);
+ promise.resolve("Model successfully loaded")
+ } catch (e: IOException) {
this.model = null
promise.reject(e)
}
@@ -153,6 +164,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
cleanRecognizer();
}
+ @ReactMethod
+ fun stopOnly() {
+ if (speechService != null) {
+ speechService!!.stop()
+ }
+ }
+
+ @ReactMethod
+ fun cleanup() {
+ if (speechService != null) {
+ speechService!!.shutdown();
+ speechService = null
+ }
+ if (recognizer != null) {
+ recognizer!!.close();
+ recognizer = null;
+ }
+ }
+
@ReactMethod
fun unload() {
cleanRecognizer();
diff --git a/lib/typescript/index.d.ts b/lib/typescript/index.d.ts
index 441e41cc402cca3a60b34978ef4fea976076259c..a173acebb4b314402550442ad471e0f7c706e3c4 100644
--- a/lib/typescript/index.d.ts
+++ b/lib/typescript/index.d.ts
@@ -10,6 +10,8 @@ export default class Vosk {
currentRegisteredEvents: EmitterSubscription[];
start: (grammar?: string[] | null) => Promise<String>;
stop: () => void;
+ stopOnly: () => void;
+ cleanup: () => void;
unload: () => void;
onResult: (onResult: (e: VoskEvent) => void) => EventSubscription;
onFinalResult: (onFinalResult: (e: VoskEvent) => void) => EventSubscription;
diff --git a/package.json b/package.json
index 707eddb8d68007f93071ac659c5b087c935c5f01..90ebe20f224eeec472c377df1fef9b15f2ff8200 100644
--- a/package.json
+++ b/package.json
@@ -11,12 +11,9 @@
"src",
"lib",
"android",
- "ios",
"cpp",
- "react-native-vosk.podspec",
"!lib/typescript/example",
"!android/build",
- "!ios/build",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__"
diff --git a/react-native-vosk.podspec b/react-native-vosk.podspec
deleted file mode 100644
index e3d41b90c5eef890c7a5108aaf16ac07d34a698b..0000000000000000000000000000000000000000
--- a/react-native-vosk.podspec
+++ /dev/null
@@ -1,41 +0,0 @@
-require "json"
-
-package = JSON.parse(File.read(File.join(__dir__, "package.json")))
-folly_version = '2021.06.28.00-v2'
-folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
-
-Pod::Spec.new do |s|
- s.name = "react-native-vosk"
- s.version = package["version"]
- s.summary = package["description"]
- s.homepage = package["homepage"]
- s.license = package["license"]
- s.authors = package["author"]
-
- s.platforms = { :ios => "10.0" }
- s.source = { :git => "https://github.com/riderodd/react-native-vosk.git", :tag => "#{s.version}" }
-
- s.source_files = "ios/**/*.{h,m,mm,swift}"
- s.resource_bundles = { 'Vosk' => ['ios/Vosk/*'] }
-
- s.dependency "React-Core"
- s.frameworks = "Accelerate"
- s.library = "c++"
- s.vendored_frameworks = "ios/libvosk.xcframework"
- s.requires_arc = true
-
- # Don't install the dependencies when we run `pod install` in the old architecture.
- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
- s.pod_target_xcconfig = {
- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
- }
-
- s.dependency "React-Codegen"
- s.dependency "RCT-Folly", folly_version
- s.dependency "RCTRequired"
- s.dependency "RCTTypeSafety"
- s.dependency "ReactCommon/turbomodule/core"
- end
-end
diff --git a/src/index.tsx b/src/index.tsx
index d9f90c921d89b1b4d85e145443ed3376546a368a..29e4068dbd7500828a73145bd25497a52c9bf638 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -69,6 +69,15 @@ export default class Vosk {
VoskModule.stop();
};
+ stopOnly = () => {
+ VoskModule.stopOnly();
+ };
+
+ cleanup = () => {
+ this.cleanListeners();
+ VoskModule.cleanup();
+ };
+
unload = () => {
this.cleanListeners();
VoskModule.unload();

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -0,0 +1,215 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Milo Ivir <mail@mivirtype.de>\n"
"Language-Team: \n"
"Language: hr_HR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.6\n"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:13
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:9
msgid "/month"
msgstr "/mjesec"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:19
msgid "/year"
msgstr "/godina"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:8
msgid ""
"<a href=\"https://joplincloud.com\">Joplin Cloud</a> allows you to "
"synchronise your notes across devices. It also lets you publish notes, and "
"collaborate on notebooks with your friends, family or colleagues."
msgstr ""
"<a href=\"https://joplincloud.com\">Joplin Cloud</a> omogućuje "
"sinkronizaciju bilješki na različitim uređajima. Omogućuje i objavljivanje "
"bilješki i suradnju na bilježnicama s prijateljima, obitelji ili kolegama."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:205
msgid "<span class=\"frame-bg frame-bg-yellow-lg\">Customise</span> it"
msgstr "<span class=\"frame-bg frame-bg-yellow-lg\">Prilagodi</span> uslugu"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:104
msgid "<span class=\"frame-bg frame-bg-yellow\">Multimedia</span> notes"
msgstr "<span class=\"frame-bg frame-bg-yellow\">Multimedijske</span> bilješke"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:256
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
msgstr "100 % <span class=\"frame-bg frame-bg-yellow-lg\">tvoji podaci</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:298
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
msgstr ""
"<span class=\"frame-bg frame-bg-yellow-lg\">Francuska</span> alternativa"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:236
msgid ""
"Access your notes from your computer, phone or tablet by synchronising with "
"various services, including Joplin Cloud, Dropbox and OneDrive. The app is "
"available on Windows, macOS, Linux, Android and iOS. A terminal app is also "
"available!"
msgstr ""
"Pristupi svojim bilješkama s računala, mobitela ili tableta sinkronizacijom "
"s raznim uslugama, uključujući Joplin Cloud, Dropbox i OneDrive. Program je "
"dostupan za Windows, macOS, Linux, Android i iOS sustave. Dostupan je i "
"program za terminal!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
msgid ""
"Already have a Joplin Cloud account? <a href=\"https://"
"joplincloud.com\">Login now</a>"
msgstr ""
"Već imaš Joplin Cloud račun? <a href=\"https://joplincloud.com\">Prijavi se "
"sada</a>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:208
msgid ""
"Customise the app with plugins, custom themes and multiple text editors "
"(Rich Text or Markdown). Or create your own scripts and plugins using the "
"Extension API."
msgstr ""
"Prilagodi program pomoću dodataka, prilagođenih tema i uređivača teksta "
"(formatirani tekst ili Markdown). Ili izradi vlastita skripta i dodatke "
"pomoću API-ja za proširenja."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:242
msgid "Download it now"
msgstr "Preuzmi sada"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:112
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:63
msgid "Download the app"
msgstr "Preuzmi program"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:213
msgid "Find out more"
msgstr "Saznaj više"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:54
msgid "Free your <span class=\"frame-bg frame-bg-blue\">notes</span>"
msgstr "Oslobodi svoje <span class=\"frame-bg frame-bg-blue\">bilješke</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:175
msgid "Get the clipper"
msgstr "Nabavi Clipper"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:107
msgid ""
"Images, videos, PDFs and audio files are supported. Create math expressions "
"and diagrams directly from the app. Take photos with the mobile app and save "
"them to a note."
msgstr ""
"Podržane su slike, videozapisi, PDF-ovi i audio datoteke. Stvori matematičke "
"izraze i dijagrame izravno iz programa. Snimaj fotografije s programom za "
"mobitel i spremi ih u bilješku."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:327
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
msgstr "<span class=\"frame-bg frame-bg-yellow\">Recenzije</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:5
msgid "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">plans</span>"
msgstr "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">tarife</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
msgid ""
"Joplin Cloud is based in France. This means your data is protected by strict "
"European Union privacy laws. In addition, Joplin Cloud implements strong end-"
"to-end encryption so that not even us can have access to your data."
msgstr ""
"Joplin Cloud ima sjedište u Francuskoj. To znači da su tvoji podaci "
"zaštićeni strogim zakonima o privatnosti Europske unije. Osim toga, Joplin "
"Cloud implementira snažno sveobuhvatno šifriranje (end-to-end encryption) "
"tako da čak ni mi ne možemo pristupiti tvojim podacima."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
msgid ""
"Joplin is an open source note-taking app. Capture your thoughts and securely "
"access them from any device."
msgstr ""
"Joplin je program za bilješke otvorenog koda. Zabilježi svoje misli i "
"sigurno im pristupi s bilo kojeg uređaja."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:262
msgid "More about E2EE"
msgstr "Više o E2EE"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:391
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
msgstr "Naši <span class=\"frame-bg frame-bg-blue-lg\">sponzori</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:23
msgid "Pay Monthly"
msgstr "Plaćaj mjesečno"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:30
msgid "Pay Yearly"
msgstr "Plaćaj godišnje"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:167
msgid ""
"Save <span class=\"frame-bg frame-bg-blue\">web pages</span> <br>as notes"
msgstr ""
"Spremaj <span class=\"frame-bg frame-bg-blue\">web stranice</span> <br>kao "
"bilješke"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:65
msgid "Sign up with Joplin Cloud"
msgstr "Registriraj se na Joplin Cloud"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:394
msgid "Thank you for your support!"
msgstr "Hvala ti na podršci!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
msgid ""
"The app is open source and your notes are saved to an open format, so you'll "
"always have access to them. Uses End-To-End Encryption (E2EE) to secure your "
"notes and ensure no-one but yourself can access them."
msgstr ""
"Program je otvorenog koda i tvoje se bilješke spremaju u otvorenom formatu, "
"tako da ćeš im uvijek moći pristupiti. Program koristi sveobuhvatno "
"šifriranje – engl. End-To-End Encryption (E2EE) – kako bi zaštitila tvoje "
"bilješke i osigurala da im nitko osim tebe ne može pristupiti."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:144
msgid "Try it now"
msgstr "Isprobaj sada"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:170
msgid ""
"Use the web clipper extension, available on Chrome and Firefox, to save web "
"pages or take screenshots as notes."
msgstr ""
"Koristi proširenje Web Clipper, dostupno za Chrome i Firefox, za spremanje "
"web stranica ili snimanje ekrana kao bilješku."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
msgid ""
"With Joplin Cloud, share your notes with your friends, family or colleagues "
"and collaborate on them."
msgstr ""
"Joplin Cloud ti omogućuje da dijeliš bilješke s prijateljima, obitelji ili "
"kolegama te da na njima surađujete."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:137
msgid "Work <span class=\"frame-bg frame-bg-yellow\">together</span>"
msgstr "<span class=\"frame-bg frame-bg-yellow\">Surađuj</span> s drugima"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:141
msgid ""
"You can also publish a note to the internet and share the URL with others."
msgstr "Bilješke možeš objaviti i na internetu te dijeliti URL s drugima."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:233
msgid ""
"Your notes, <span class=\"frame-bg frame-bg-blue-lg\">everywhere</span> you "
"are"
msgstr ""
"Tvoje bilješke, <span class=\"frame-bg frame-bg-blue-lg\">gdje god</span> se "
"nalaziš"

View File

@@ -1,4 +1,77 @@
<?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, 28 Apr 2025 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Mon, 28 Apr 2025 00:00:00 GMT</pubDate><item><title><![CDATA[What's new in Joplin 3.3]]></title><description><![CDATA[<h2>Desktop application<a name="desktop-application" href="#desktop-application" class="heading-anchor">🔗</a></h2>
<?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>
<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>
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-mobile-rte.png" width="400" alt="screenshot: Mobile Rich Text Editor editing the welcome notes. Images, headings, etc are rendering."/>
<p>To try it, 1) open a note in the default Markdown editor 2) open the note actions menu (the three vertical dots) for the note and 3) click “Edit as Rich Text”.</p>
<p>Be aware that this editor is still in active development and <a href="https://github.com/laurent22/joplin/issues/12840">has a number of known limitations and issues</a>. The Rich Text editor is based on <a href="https://prosemirror.net/">ProseMirror</a> and will behave differently from the desktop Rich Text Editor in many cases.</p>
<h3>Support for publishing notes with Joplin Cloud and Server<a name="support-for-publishing-notes-with-joplin-cloud-and-server" href="#support-for-publishing-notes-with-joplin-cloud-and-server" class="heading-anchor">🔗</a></h3>
<p>It's now possible to <a href="https://joplinapp.org/help/apps/publish_note">publish notes</a> from the mobile app! To do so, open the “Properties” menu for a note, then click “Publish/unpublish”:</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-publish-notes.png" alt="screenshot: A Publish/unpublish note action is shown in the &quot;Note properties&quot; sidebar, just below a &quot;Previous versions&quot; button"></p>
<p>Next, in the “publish note” dialog, click “Copy shareable link”. Notes can later be unpublished by clicking &quot;Unpublish&quot; in the publication dialog.</p>
<h3>Viewing note history<a name="viewing-note-history" href="#viewing-note-history" class="heading-anchor">🔗</a></h3>
<p>It is now possible to view and restore previous note versions from the mobile app. Like the &quot;publish note&quot; feature, previous note versions can be accessed from the note properties menu.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-note-history.png" alt="screenshot: The note history page"></p>
<p>As on desktop, the note history feature can be configured from the “Note History” tab in settings.</p>
<h3>Updated tag dialog<a name="updated-tag-dialog" href="#updated-tag-dialog" class="heading-anchor">🔗</a></h3>
<p>The tag dialog has been redesigned, with a new UI for adding, removing, and creating new tags:<br>
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-tag-editor.png" width="500" alt="screenshot: Tag dialog now consists of three sections: Added tags, Add new tags, Actions."/></p>
<h3>Android: Improved voice typing<a name="android-improved-voice-typing" href="#android-improved-voice-typing" class="heading-anchor">🔗</a></h3>
<p>The voice typing feature on Android has been updated with <a href="https://github.com/laurent22/joplin/pull/12404">improved silence detection</a> and a new “<a href="https://github.com/laurent22/joplin/pull/12370">custom glossary</a>” setting. Voice typing also now <a href="https://github.com/laurent22/joplin/pull/12352">defaults to a more accurate (but somewhat slower) model</a>.</p>
<h3>Quickly creating a note from multiple photos<a name="quickly-creating-a-note-from-multiple-photos" href="#quickly-creating-a-note-from-multiple-photos" class="heading-anchor">🔗</a></h3>
<p>A “scan notebook” action has been added to the “New note” menu:</p>
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-scan-notebook.png" width="500"/>
<p>This action allows quickly creating a new note with multiple pictures taken from the camera.</p>
<h2>Desktop<a name="desktop" href="#desktop" class="heading-anchor">🔗</a></h2>
<h3>More Markdown Editor settings<a name="more-markdown-editor-settings" href="#more-markdown-editor-settings" class="heading-anchor">🔗</a></h3>
<p>The &quot;Note&quot; tab in settings now includes new settings for the Markdown editor, including:</p>
<ul>
<li>An option to render headers, lists, and certain other formatting within the editor.</li>
<li>An option to render images in the editor.</li>
</ul>
<p>When enabled, these settings bring the Markdown editor closer to the Rich Text Editor, without <a href="https://joplinapp.org/help/apps/rich_text_editor">some of the Rich Text Editor's limitations</a>.</p>
<p>These settings are also available on mobile.</p>
<h3>Smaller application size and faster startup<a name="smaller-application-size-and-faster-startup" href="#smaller-application-size-and-faster-startup" class="heading-anchor">🔗</a></h3>
<p>We've made the desktop application roughly 33% smaller! In addition to faster application startup, this means that the desktop app should be faster to download take up less space.</p>
<table class="table">
<thead>
<tr>
<th>Joplin version</th>
<th>Previous size (v3.3.13)</th>
<th>New size (v3.4.12)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Joplin for MacOS (ARM)</td>
<td>211 MB</td>
<td>141 MB</td>
</tr>
<tr>
<td>Joplin for Windows (installer)</td>
<td>321 MB</td>
<td>219 MB</td>
</tr>
<tr>
<td>Joplin for Windows (portable)</td>
<td>320 MB</td>
<td>219 MB</td>
</tr>
<tr>
<td>Joplin for Linux (AppImage)</td>
<td>219 MB</td>
<td>147 MB</td>
</tr>
</tbody>
</table>
<h2>Terminal app<a name="terminal-app" href="#terminal-app" class="heading-anchor">🔗</a></h2>
<h3>Collapsible folders<a name="collapsible-folders" href="#collapsible-folders" class="heading-anchor">🔗</a></h3>
<p>The <a href="https://joplinapp.org/help/apps/terminal/">terminal application</a> now supports expanding and collapsing folders by pressing <kbd>z</kbd>. For additional information, see <a href="https://github.com/laurent22/joplin/pull/12718">the original pull request</a>.</p>
<h3>Managing shared notebooks and published notes<a name="managing-shared-notebooks-and-published-notes" href="#managing-shared-notebooks-and-published-notes" class="heading-anchor">🔗</a></h3>
<p>New commands have been added to the terminal app, including <code>publish</code>, <code>unpublish</code>, and <code>share</code>. This allows the terminal app to manage shared folders and published notes.</p>
<h2>Bug fixes<a name="bug-fixes" href="#bug-fixes" class="heading-anchor">🔗</a></h2>
<p>For the full list of changes, see <a href="https://joplinapp.org/help/about/changelog/desktop/">the desktop changelog</a> and <a href="https://joplinapp.org/help/about/changelog/android/">the mobile changelog</a>.</p>
]]></description><link>https://joplinapp.org/news/20250922-release-3-4</link><guid isPermaLink="false">20250922-release-3-4</guid><pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[What's new in Joplin 3.3]]></title><description><![CDATA[<h2>Desktop application<a name="desktop-application" href="#desktop-application" class="heading-anchor">🔗</a></h2>
<h3>Accessibility improvements<a name="accessibility-improvements" href="#accessibility-improvements" class="heading-anchor">🔗</a></h3>
<p>The Joplin 3.3 release introduces significant accessibility enhancements designed to make the application more inclusive and user-friendly. Users can now benefit from improved keyboard navigation, thanks to newly added shortcuts and clearer labels that streamline interaction across the interface. We've also added a &quot;go to viewer&quot; menu item that moves focus from the note editor to the note viewer. Focus is moved to the location in the viewer corresponding to the location of the cursor in the editor.</p>
<p>Screen reader support has been bolstered, ensuring elements like the note list and sidebar are easier to toggle and interact with. These updates make the application more usable for individuals relying on assistive technologies.</p>
@@ -446,10 +519,4 @@ sys 0m38.013s</p>
<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><item><title><![CDATA[Joplin is hiring!]]></title><description><![CDATA[<p>Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device.</p>
<p>We are looking to hire two JavaScript software developers to work on the desktop, mobile, and server applications. All those are built using modern technologies, including React, React Native and Electron with a strong focus on test units.</p>
<p>You need to demonstrate some experience with at least some of these technologies, and willing to learn more and touch various different projects.</p>
<p>You will be part of a small team, so you will have an opportunity for a high-impact role, targeting hundreds of thousands of users.</p>
<p>If you're interested please contact us at job-AT-joplin.cloud</p>
<p>No agencies please.</p>
]]></description><link>https://joplinapp.org/news/20221209-job</link><guid isPermaLink="false">20221209-job</guid><pubDate>Fri, 09 Dec 2022 00:00:00 GMT</pubDate><twitter-text>Joplin is hiring!</twitter-text></item></channel></rss>
]]></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>

View File

@@ -219,10 +219,7 @@
$('.feature-description-' + featureId).toggle(200);
});
});
</script>
<script>
const setHostingType = (type) => {
const other = type === 'managed' ? 'self' : 'managed';
$('.toggle-button-' + type).addClass('active');
@@ -244,6 +241,7 @@
setHostingType('self');
});
setHostingType('managed');
const initialHostingType = urlQuery.get('hosting') ? urlQuery.get('hosting') : 'managed';
setHostingType(initialHostingType);
</script>
</div>

View File

@@ -63,11 +63,24 @@ FROM node:18-slim
ARG user=joplin
RUN useradd --create-home --shell /bin/bash $user
# Install PM2 and set home directory. Setting the PM2 data dir so modules/config persist regardless
# of user home.
RUN npm i -g pm2@5.4.3 && mkdir -p /opt/pm2 && chown -R $user:$user /opt/pm2
ENV PM2_HOME=/opt/pm2
USER $user
COPY --chown=$user:$user --from=builder /build/packages /home/$user/packages
COPY --chown=$user:$user --from=builder /usr/bin/tini /usr/local/bin/tini
# We download a specific version of the plugin to prevent pm2 from fetching the latest, since it may
# not have been properly audited (that fact was used to spread malware at some point). Ref:
# https://github.com/laurent22/joplin/issues/12754
RUN pm2 install https://registry.npmjs.org/pm2-logrotate/-/pm2-logrotate-3.0.0.tgz \
&& pm2 set pm2-logrotate:max_size 100MB \
&& pm2 set pm2-logrotate:retain 5 \
&& pm2 set pm2-logrotate:compress true
ENV NODE_ENV=production
ENV RUNNING_IN_DOCKER=1
EXPOSE ${APP_PORT}

View File

@@ -23,7 +23,6 @@ RUN corepack enable
WORKDIR /app
COPY .yarn/plugins ./.yarn/plugins
COPY .yarn/releases ./.yarn/releases
COPY .yarn/patches ./.yarn/patches
COPY package.json .

View File

@@ -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://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&amp;mtm_kwd=joplinapp&amp;mtm_source=joplinapp-webseite&amp;mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.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://realgambling.ca/"><img title="RealGambling.ca" width="256" src="https://joplinapp.org/images/sponsors/RealGambling.png" alt="RealGambling.ca"/></a> <a href="https://essaypro.com/"><img title="write an essay online with EssayPro" width="256" src="https://joplinapp.org/images/sponsors/EssayPro.png" alt="write an essay online with EssayPro"/></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://essaywriter.pro"><img title="write my essay services by EssayWriter" width="256" src="https://joplinapp.org/images/sponsors/EssayWriterPro.png" alt="write my essay services by EssayWriter"/></a> <a href="https://essayservice.com"><img title="quick and reliable service to write my paper for me" width="256" src="https://joplinapp.org/images/sponsors/EssayService.png" alt="quick and reliable service to write my paper for me"/></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://homeworkguy.org/someone-to-take-my-online-class"><img title="someone to take my online class" width="256" src="https://joplinapp.org/images/sponsors/HomeworkGuy.png" alt="someone to take my online class"/></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://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>
<!-- SPONSORS-ORG -->
* * *
@@ -40,9 +40,8 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
| | | | |
| :---: | :---: | :---: | :---: |
| <img width="50" src="https://avatars2.githubusercontent.com/u/97193607?s=96&v=4"/></br>[Akhil-CM](https://github.com/Akhil-CM) | <img width="50" src="https://avatars2.githubusercontent.com/u/552452?s=96&v=4"/></br>[andypiper](https://github.com/andypiper) | <img width="50" src="https://avatars2.githubusercontent.com/u/215668?s=96&v=4"/></br>[avanderberg](https://github.com/avanderberg) | <img width="50" src="https://avatars2.githubusercontent.com/u/67130?s=96&v=4"/></br>[chr15m](https://github.com/chr15m) |
| <img width="50" src="https://avatars2.githubusercontent.com/u/1177810?s=96&v=4"/></br>[felixstorm](https://github.com/felixstorm) | <img width="50" src="https://avatars2.githubusercontent.com/u/8030470?s=96&v=4"/></br>[Galliver7](https://github.com/Galliver7) | <img width="50" src="https://avatars2.githubusercontent.com/u/64712218?s=96&v=4"/></br>[Hegghammer](https://github.com/Hegghammer) | <img width="50" src="https://avatars2.githubusercontent.com/u/11947658?s=96&v=4"/></br>[KentBrockman](https://github.com/KentBrockman) |
| <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) | <img width="50" src="https://avatars2.githubusercontent.com/u/1788010?s=96&v=4"/></br>[maxtruxa](https://github.com/maxtruxa) | <img width="50" src="https://avatars2.githubusercontent.com/u/327998?s=96&v=4"/></br>[sif](https://github.com/sif) | <img width="50" src="https://avatars2.githubusercontent.com/u/765564?s=96&v=4"/></br>[taskcruncher](https://github.com/taskcruncher) |
| <img width="50" src="https://avatars2.githubusercontent.com/u/668977?s=96&v=4"/></br>[ugoertz](https://github.com/ugoertz) | | | |
| <img width="50" src="https://avatars2.githubusercontent.com/u/1177810?s=96&v=4"/></br>[felixstorm](https://github.com/felixstorm) | <img width="50" src="https://avatars2.githubusercontent.com/u/11947658?s=96&v=4"/></br>[KentBrockman](https://github.com/KentBrockman) | <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) | <img width="50" src="https://avatars2.githubusercontent.com/u/668977?s=96&v=4"/></br>[ugoertz](https://github.com/ugoertz) |
| | | | |
<!-- SPONSORS-GITHUB -->
# Community

View File

@@ -5,24 +5,24 @@
"version": "latest",
"platforms": ["aarch64-darwin", "x86_64-darwin"],
},
"yarn": "latest",
"yarn": "1.22.19",
"vips.dev": {
"platforms": ["aarch64-darwin"],
},
"nodejs": "23.10.0",
"nodejs": "23.11.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.2",
"python": "3.13.3",
"bat": "latest",
"electron": {
"version": "latest",
"excluded_platforms": ["aarch64-darwin", "x86_64-darwin"],
},
"git": "2.47.2",
"git": "2.48.1",
},
"shell": {
"init_hook": [

View File

@@ -16,12 +16,10 @@
# SLAVE_POSTGRES_PORT=5433
# SLAVE_POSTGRES_HOST=localhost
version: '2'
services:
postgresql-master:
image: 'bitnami/postgresql:17.3.0'
image: 'bitnamilegacy/postgresql:17.4.0'
ports:
- '5432:5432'
environment:
@@ -38,7 +36,7 @@ services:
- POSTGRESQL_EXTRA_FLAGS=-c work_mem=100000 -c log_statement=all
postgresql-slave:
image: 'bitnami/postgresql:17.3.0'
image: 'bitnamilegacy/postgresql:17.4.0'
ports:
- '5433:5432'
depends_on:

View File

@@ -1,8 +1,6 @@
# This compose file can be used in development to run both the database and app
# within Docker.
version: '3'
services:
app:
build:

View File

@@ -15,13 +15,21 @@
# - This would typically be mapped to port to 443 (TLS) with a reverse proxy.
# - If Joplin Server does not need to be accessible over the internet, the port can be mapped to 22300.
version: '3'
networks:
app-network:
transcribe-network:
shared-network:
services:
db:
image: postgres:16
profiles:
- full
- server
volumes:
- ./data/postgres:/var/lib/postgresql/data
networks:
- app-network
ports:
- "5432:5432"
restart: unless-stopped
@@ -31,10 +39,17 @@ services:
- POSTGRES_DB=${POSTGRES_DATABASE}
app:
image: joplin/server:latest
profiles:
- full
- server
depends_on:
- db
- transcribe
ports:
- "22300:22300"
networks:
- app-network
- shared-network
restart: unless-stopped
environment:
- APP_PORT=22300
@@ -45,3 +60,48 @@ services:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PORT=${POSTGRES_PORT}
- POSTGRES_HOST=db
- TRANSCRIBE_API_KEY=${TRANSCRIBE_API_KEY}
- TRANSCRIBE_BASE_URL=http://transcribe:4567
- TRANSCRIBE_ENABLED=${TRANSCRIBE_ENABLED}
transcribe-db:
image: postgres:16
profiles:
- full
volumes:
- ./data/transcribe-postgres:/var/lib/postgresql/data
networks:
- transcribe-network
ports:
- "${QUEUE_DATABASE_PORT}:5432"
restart: unless-stopped
environment:
- POSTGRES_PASSWORD=${QUEUE_DATABASE_PASSWORD}
- POSTGRES_USER=${QUEUE_DATABASE_USER}
- POSTGRES_DB=${QUEUE_DATABASE_NAME}
command: -p ${QUEUE_DATABASE_PORT}
transcribe:
image: joplin/transcribe:latest
profiles:
- full
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${HTR_CLI_IMAGES_FOLDER}:/app/packages/transcribe/images
depends_on:
- transcribe-db
ports:
- "4567:4567"
networks:
- transcribe-network
- shared-network
restart: unless-stopped
environment:
- APP_PORT=4567
- DB_CLIENT=pg
- QUEUE_DATABASE_NAME=${QUEUE_DATABASE_NAME}
- QUEUE_DATABASE_USER=${QUEUE_DATABASE_USER}
- QUEUE_DATABASE_PASSWORD=${QUEUE_DATABASE_PASSWORD}
- QUEUE_DATABASE_PORT=${QUEUE_DATABASE_PORT}
- QUEUE_DATABASE_HOST=transcribe-db
- API_KEY=${TRANSCRIBE_API_KEY}
- HTR_CLI_IMAGES_FOLDER=${HTR_CLI_IMAGES_FOLDER}

View File

@@ -0,0 +1,13 @@
<strong>Joplin</strong> je besplatan program otvorenog koda za bilješke i popis zadataka koji može obraditi veliki broj bilješki organizirane u bilježnice. Bilješke se mogu pretraživati, kopirati, označavati i mijenjati izravno iz programa ili iz vlastitog uređivača teksta.
Bilješke su u <a href="https://joplinapp.org/help/apps/markdown">Markdown formatu</a>.
Iz Evernotea izvezene bilješke <a href="https://joplinapp.org/help/apps/import_export">mogu se uvesti</a> u Joplin, uključujući formatirani sadržaj (koji se pretvara u Markdown), resurse (slike, privitke itd.) i potpune metapodatke (geografski podaci mjesta, vrijeme aktualiziranja, vrijeme stvaranja itd.). Mogu se uvesti i obične Markdown datoteke.
Joplin radi ponajprije s lokalnim podacima (offline first), što znači da uvijek imaš sve svoje podatke na mobitelu ili računalu. To osigurava da su tvoje bilješke uvijek dostupne, bez obzira je li imaš internetsku vezu ili ne.</p>
Bilješke se mogu sigurno <a href="https://joplinapp.org/help/apps/sync">sinkronizirati</a> pomoću <a href="https://joplinapp.org/help/apps/sync/e2ee">sveobuhvatnog šifriranja</a> s raznim uslugama u oblaku, uključujući Nextcloud, Dropbox, OneDrive i <a href="https://joplinapp.org/plans/">Joplin Cloud</a>.
Pretraživanje cijelog teksta dostupno je na svim platformama za brzo pronalaženje potrebnih informacija. Program se može prilagoditi pomoću dodataka i tema, a možeš stvoriti i vlastite.
Program je dostupan za Windows, Linux, macOS, Android i iOS sustave. <a href="https://joplinapp.org/help/apps/clipper">Web Clipper</a>, za spremanje web stranica i snimaka ekrana iz tvog preglednika, je također dostupan za <a href="https://addons.mozilla.org/firefox/addon/joplin-web-clipper/">Firefox</a> i <a href="https://chrome.google.com/webstore/detail/joplin-web-clipper/alofnhikmmkdbbbgpnglcpdollgjjfek">Chrome</a>.

View File

@@ -0,0 +1 @@
Program za bilješke i popis zadataka sa sinkronizacijom između Linuxa, macOS-a, Windowsa i mobitela

View File

@@ -51,6 +51,8 @@
"releasePluginGenerator": "node packages/tools/release-plugin-generator.js",
"releasePluginRepoCli": "node packages/tools/release-plugin-repo-cli.js",
"releaseServer": "node packages/tools/release-server.js",
"releaseTranscribe": "node packages/tools/release-transcribe.js",
"saveClaConsentRecords": "node packages/tools/saveClaConsentRecords.js",
"setupNewRelease": "node ./packages/tools/setupNewRelease",
"spellcheck": "node packages/tools/spellcheck.js",
"tagServerLatest": "node packages/tools/tagServerLatest.js",
@@ -72,35 +74,34 @@
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"cspell": "5.21.2",
"eslint": "8.57.0",
"eslint": "8.57.1",
"eslint-interactive": "10.8.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-jest": "27.9.0",
"eslint-plugin-promise": "6.2.0",
"eslint-plugin-react": "7.34.3",
"eslint-plugin-promise": "6.6.0",
"eslint-plugin-react": "7.37.5",
"execa": "5.1.1",
"fs-extra": "11.2.0",
"glob": "11.0.1",
"glob": "11.0.3",
"gulp": "4.0.2",
"husky": "9.1.7",
"lerna": "3.22.1",
"lint-staged": "15.5.1",
"lint-staged": "15.5.2",
"madge": "8.0.0",
"npm-package-json-lint": "8.0.0",
"typescript": "5.4.5"
"typescript": "5.8.3"
},
"dependencies": {
"@types/fs-extra": "11.0.4",
"eslint-plugin-github": "4.10.2",
"http-server": "14.1.1",
"node-gyp": "11.2.0",
"nodemon": "3.1.9"
"nodemon": "3.1.10"
},
"packageManager": "yarn@4.9.2",
"resolutions": {
"react-native-camera@4.2.1": "patch:react-native-camera@npm%3A4.2.1#./.yarn/patches/react-native-camera-npm-4.2.1-24b2600a7e.patch",
"react-native-vosk@0.1.12": "patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch",
"eslint": "patch:eslint@8.57.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
"eslint": "patch:eslint@8.57.1#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
"app-builder-lib@24.4.0": "patch:app-builder-lib@npm%3A24.4.0#./.yarn/patches/app-builder-lib-npm-24.4.0-05322ff057.patch",
"nanoid": "patch:nanoid@npm%3A3.3.7#./.yarn/patches/nanoid-npm-3.3.7-98824ba130.patch",
"pdfjs-dist": "patch:pdfjs-dist@npm%3A3.11.174#./.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch",
@@ -116,6 +117,12 @@
"pdfjs-dist@*": "patch:pdfjs-dist@npm%3A3.11.174#./.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch",
"pdfjs-dist@3.11.174": "patch:pdfjs-dist@npm%3A3.11.174#./.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch",
"canvas@npm:^2.11.2": "link:./.yarn/joplin-empty-package/",
"node-gyp@npm:^9.0.0": "11.2.0"
"node-gyp@npm:^9.0.0": "11.2.0",
"depd@npm:^2.0.0": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:~2.0.0": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:~1.1.2": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:2.0.0": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:^1.1.2": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch",
"depd@npm:^1.1.0": "patch:depd@npm%3A2.0.0#~/.yarn/patches/depd-npm-2.0.0-b6c51a4b43.patch"
}
}

View File

@@ -380,6 +380,13 @@ class AppGui {
this.widget('noteList').toggleShowIds();
}
toggleFolderCollapse() {
const folderList = this.widget('folderList');
if (folderList && folderList.toggleFolderCollapse) {
folderList.toggleFolderCollapse();
}
}
widget(name) {
if (name === 'root') return this.rootWidget_;
return this.rootWidget_.childByName(name);
@@ -506,6 +513,8 @@ class AppGui {
this.toggleNoteMetadata();
} else if (cmd === 'toggle_ids') {
this.toggleFolderIds();
} else if (cmd === 'toggle_folder_collapse') {
this.toggleFolderCollapse();
} else if (cmd === 'enter_command_line_mode') {
const cmd = await this.widget('statusBar').prompt();
if (!cmd) return;

View File

@@ -9,7 +9,6 @@ import Tag from '@joplin/lib/models/Tag';
import Setting, { Env } from '@joplin/lib/models/Setting';
import { reg } from '@joplin/lib/registry.js';
import { dirname, fileExtension } from '@joplin/lib/path-utils';
import { splitCommandString } from '@joplin/utils';
import { _ } from '@joplin/lib/locale';
import { pathExists, readFile, readdirSync } from 'fs-extra';
import RevisionService from '@joplin/lib/services/RevisionService';
@@ -19,7 +18,6 @@ import { FolderEntity, NoteEntity } from '@joplin/lib/services/database/types';
import initializeCommandService from './utils/initializeCommandService';
const { cliUtils } = require('./cli-utils.js');
const Cache = require('@joplin/lib/Cache');
const { splitCommandBatch } = require('@joplin/lib/string-utils');
class Application extends BaseApplication {
@@ -222,6 +220,7 @@ class Application extends BaseApplication {
return { ...this.commandMetadata_ };
}
public hasGui() {
return this.gui() && !this.gui().isDummy();
}
@@ -332,6 +331,7 @@ class Application extends BaseApplication {
{ keys: ['mb'], type: 'prompt', command: 'mkbook ""', cursorPosition: -2 },
{ keys: ['yn'], type: 'prompt', command: 'cp $n ""', cursorPosition: -2 },
{ keys: ['dn'], type: 'prompt', command: 'mv $n ""', cursorPosition: -2 },
{ keys: ['z'], type: 'function', command: 'toggle_folder_collapse' },
];
// Filter the keymap item by command so that items in keymap.json can override
@@ -381,22 +381,6 @@ class Application extends BaseApplication {
return output;
}
public async commandList(argv: string[]) {
if (argv.length && argv[0] === 'batch') {
const commands = [];
const commandLines = splitCommandBatch(await readFile(argv[1], 'utf-8'));
for (const commandLine of commandLines) {
if (!commandLine.trim()) continue;
const splitted = splitCommandString(commandLine.trim());
commands.push(splitted);
}
return commands;
} else {
return [argv];
}
}
// We need this special case here because by the time the `version` command
// runs, the keychain has already been setup.
public checkIfKeychainEnabled(argv: string[]) {
@@ -433,15 +417,12 @@ class Application extends BaseApplication {
if (argv.length) {
this.gui_ = this.dummyGui();
this.currentFolder_ = await Folder.load(Setting.value('activeFolderId'));
const initialFolder = await Folder.load(Setting.value('activeFolderId'));
await this.switchCurrentFolder(initialFolder);
await this.applySettingsSideEffects();
try {
const commands = await this.commandList(argv);
for (const command of commands) {
await this.execCommand(command);
}
await this.execCommand(argv);
} catch (error) {
if (this.showStackTraces_) {
console.error(error);
@@ -453,6 +434,7 @@ class Application extends BaseApplication {
}
await Setting.saveAll();
await this.database_.close();
// Need to call exit() explicitly, otherwise Node wait for any timeout to complete
// https://stackoverflow.com/questions/18050095

View File

@@ -2,33 +2,44 @@
/* eslint-disable no-console */
const fs = require('fs-extra');
const Logger = require('@joplin/utils/Logger').default;
const { dirname } = require('@joplin/lib/path-utils');
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');
const JoplinDatabase = require('@joplin/lib/JoplinDatabase').default;
const BaseModel = require('@joplin/lib/BaseModel').default;
const Folder = require('@joplin/lib/models/Folder').default;
const Note = require('@joplin/lib/models/Note').default;
const Setting = require('@joplin/lib/models/Setting').default;
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('console');
logger.addTarget(TargetType.Console);
logger.setLevel(Logger.LEVEL_ERROR);
const dbLogger = new Logger();
dbLogger.addTarget('console');
dbLogger.addTarget(TargetType.Console);
dbLogger.setLevel(Logger.LEVEL_INFO);
const db = new JoplinDatabase(new DatabaseDriverNode());
db.setLogger(dbLogger);
function createClient(id) {
interface Client {
id: number;
profileDir: string;
}
function createClient(id: number): Client {
return {
id: id,
profileDir: `${baseDir}/client${id}`,
@@ -37,13 +48,13 @@ function createClient(id) {
const client = createClient(1);
function execCommand(client, command) {
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((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
return new Promise<string>((resolve, reject) => {
exec(cmd, (error: string, stdout: string, stderr: string) => {
if (error) {
logger.error(stderr);
reject(error);
@@ -54,17 +65,17 @@ function execCommand(client, command) {
});
}
function assertTrue(v) {
function assertTrue(v: unknown) {
if (!v) throw new Error(sprintf('Expected "true", got "%s"."', v));
process.stdout.write('.');
}
function assertFalse(v) {
function assertFalse(v: unknown) {
if (v) throw new Error(sprintf('Expected "false", got "%s"."', v));
process.stdout.write('.');
}
function assertEquals(expected, real) {
function assertEquals(expected: unknown, real: unknown) {
if (expected !== real) throw new Error(sprintf('Expecting "%s", got "%s"', expected, real));
process.stdout.write('.');
}
@@ -73,7 +84,7 @@ 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 = {};
const testUnits: Record<string, ()=> Promise<void>> = {};
testUnits.testFolders = async () => {
await execCommand(client, 'mkbook nb1');
@@ -85,10 +96,16 @@ testUnits.testFolders = async () => {
await execCommand(client, 'mkbook nb1');
folders = await Folder.all();
assertEquals(1, folders.length);
assertEquals(2, folders.length);
assertEquals('nb1', folders[0].title);
assertEquals('nb1', folders[1].title);
await execCommand(client, 'rm -r -f nb1');
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);
@@ -102,7 +119,7 @@ testUnits.testNotes = async () => {
assertEquals(1, notes.length);
assertEquals('n1', notes[0].title);
await execCommand(client, 'rm -f n1');
await execCommand(client, 'rmnote -p -f n1');
notes = await Note.all();
assertEquals(0, notes.length);
@@ -112,12 +129,19 @@ testUnits.testNotes = async () => {
notes = await Note.all();
assertEquals(2, notes.length);
await execCommand(client, 'rm -f \'blabla*\'');
// 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, 'rm -f \'n*\'');
await execCommand(client, 'rmnote -f -p \'n*\'');
notes = await Note.all();
assertEquals(0, notes.length);
@@ -140,10 +164,12 @@ testUnits.testCat = async () => {
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'));
@@ -201,15 +227,47 @@ testUnits.testMv = async () => {
await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3');
await execCommand(client, 'mknote blabla');
await execCommand(client, 'mv \'note*\' nb2');
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);
@@ -217,7 +275,9 @@ async function main() {
await db.open({ name: `${client.profileDir}/database.sqlite` });
BaseModel.setDb(db);
await Setting.load();
Setting.setConstant('rootProfileDir', client.profileDir);
Setting.setConstant('profileDir', client.profileDir);
await loadKeychainServiceAndSettings([]);
let onlyThisTest = 'testMv';
onlyThisTest = '';
@@ -234,7 +294,7 @@ async function main() {
}
}
main(process.argv).catch(error => {
main().catch(error => {
console.info('');
logger.error(error);
});

View File

@@ -1,19 +0,0 @@
const BaseCommand = require('./base-command').default;
const { _ } = require('@joplin/lib/locale');
class Command extends BaseCommand {
usage() {
return 'batch <file-path>';
}
description() {
return _('Runs the commands contained in the text file. There should be one command per line.');
}
async action() {
// Implementation is in app.js::commandList()
throw new Error('No implemented');
}
}
module.exports = Command;

View File

@@ -0,0 +1,79 @@
import { splitCommandBatch } from '@joplin/lib/string-utils';
import BaseCommand from './base-command';
import { _ } from '@joplin/lib/locale';
import { splitCommandString } from '@joplin/utils';
import iterateStdin from './utils/iterateStdin';
import { readFile } from 'fs-extra';
import app from './app';
interface Options {
'file-path': string;
options: {
'continue-on-failure': boolean;
};
}
class Command extends BaseCommand {
public usage() {
return 'batch <file-path>';
}
public options() {
return [
// These are present mostly for testing purposes
['--continue-on-failure', 'Continue running commands when one command in the batch fails.'],
];
}
public description() {
return _('Runs the commands contained in the text file. There should be one command per line.');
}
private streamCommands_ = async function*(filePath: string) {
const processLines = function*(lines: string) {
const commandLines = splitCommandBatch(lines);
for (const command of commandLines) {
if (!command.trim()) continue;
yield splitCommandString(command.trim());
}
};
if (filePath === '-') { // stdin
// Iterating over standard input conflicts with the CLI app's GUI.
if (app().hasGui()) {
throw new Error(_('Reading commands from standard input is only available in CLI mode.'));
}
for await (const lines of iterateStdin('command> ')) {
yield* processLines(lines);
}
} else {
const data = await readFile(filePath, 'utf-8');
yield* processLines(data);
}
};
public async action(options: Options) {
let lastError;
for await (const command of this.streamCommands_(options['file-path'])) {
try {
await app().refreshCurrentFolder();
await app().execCommand(command);
} catch (error) {
if (options.options['continue-on-failure']) {
app().stdout(error.message);
lastError = error;
} else {
throw error;
}
}
}
if (lastError) {
throw lastError;
}
}
}
module.exports = Command;

View File

@@ -6,6 +6,7 @@ import app from './app';
import { _ } from '@joplin/lib/locale';
import { ImportOptions } from '@joplin/lib/services/interop/types';
import { unique } from '@joplin/lib/array';
import Folder from '@joplin/lib/models/Folder';
class Command extends BaseCommand {
public override usage() {
@@ -32,14 +33,16 @@ class Command extends BaseCommand {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public override async action(args: any) {
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, args.notebook);
let destinationFolder = await app().loadItem(BaseModel.TYPE_FOLDER, args.notebook);
if (args.notebook && !folder) throw new Error(_('Cannot find "%s".', args.notebook));
if (args.notebook && !destinationFolder) throw new Error(_('Cannot find "%s".', args.notebook));
if (!destinationFolder) destinationFolder = await Folder.defaultFolder();
const importOptions: ImportOptions = {};
importOptions.path = args.path;
importOptions.format = args.options.format ? args.options.format : 'auto';
importOptions.destinationFolderId = folder ? folder.id : null;
importOptions.destinationFolderId = destinationFolder ? destinationFolder.id : null;
let lastProgress = '';

View File

@@ -0,0 +1,104 @@
import ShareService from '@joplin/lib/services/share/ShareService';
import mockShareService from '@joplin/lib/testing/share/mockShareService';
import { createFolderTree, setupDatabaseAndSynchronizer, switchClient, waitFor } from '@joplin/lib/testing/test-utils';
import { setupApplication, setupCommandForTesting } from './utils/testUtils';
import Note from '@joplin/lib/models/Note';
import Folder from '@joplin/lib/models/Folder';
import Setting from '@joplin/lib/models/Setting';
const Command = require('./command-publish');
const setUpCommand = () => {
const onStdout = jest.fn();
const command = setupCommandForTesting(Command, onStdout);
return { command, onStdout };
};
describe('command-publish', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
await setupApplication();
mockShareService({
getShares: async () => {
return { items: [] };
},
postShares: async () => ({ id: 'test-id' }),
getShareInvitations: async () => null,
}, ShareService.instance());
});
test('should publish a note', async () => {
const { command, onStdout } = setUpCommand();
const testFolder = await Folder.save({ title: 'Test' });
const testNote = await Note.save({ title: 'test', parent_id: testFolder.id });
await command.action({
note: testNote.id,
options: {
force: true,
},
});
// Should be shared
await waitFor(async () => {
expect(await Note.load(testNote.id)).toMatchObject({
is_shared: 1,
});
});
// Should have logged the publication URL
expect(onStdout).toHaveBeenCalled();
expect(onStdout.mock.lastCall[0]).toMatch(/Published at URL:/);
});
test('should be enabled for Joplin Server and Cloud sync targets', () => {
const { command } = setUpCommand();
Setting.setValue('sync.target', 1);
expect(command.enabled()).toBe(false);
const supportedSyncTargets = [9, 10, 11];
for (const id of supportedSyncTargets) {
Setting.setValue('sync.target', id);
expect(command.enabled()).toBe(true);
}
});
test('should not ask for confirmation if a note is already published', async () => {
const { command } = setUpCommand();
const promptMock = jest.fn(() => true);
command.setPrompt(promptMock);
await createFolderTree('', [
{
title: 'folder 1',
children: [
{
title: 'note 1',
body: 'test',
},
],
},
]);
const noteId = (await Note.loadByTitle('note 1')).id;
// Should ask for confirmation when first sharing
await command.action({
note: noteId,
options: { },
});
expect(promptMock).toHaveBeenCalledTimes(1);
expect(await Note.load(noteId)).toMatchObject({ is_shared: 1 });
// Should not ask for confirmation if called again for the same note
await command.action({
note: noteId,
options: { },
});
expect(promptMock).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,64 @@
import { _ } from '@joplin/lib/locale';
import BaseCommand from './base-command';
import app from './app';
import Logger from '@joplin/utils/Logger';
import ShareService from '@joplin/lib/services/share/ShareService';
import { ModelType } from '@joplin/lib/BaseModel';
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
import Setting from '@joplin/lib/models/Setting';
import { reg } from '@joplin/lib/registry';
const logger = Logger.create('command-publish');
type Args = {
note: string;
options: {
force?: boolean;
};
};
class Command extends BaseCommand {
public usage() {
return 'publish [note]';
}
public description() {
return _('Publishes a note to Joplin Server or Joplin Cloud');
}
public options() {
return [
['-f, --force', _('Do not ask for user confirmation.')],
];
}
public enabled() {
return SyncTargetRegistry.isJoplinServerOrCloud(Setting.value('sync.target'));
}
public async action(args: Args) {
const targetNote = await app().loadItemOrFail(ModelType.Note, args.note);
const parent = await app().loadItem(ModelType.Folder, targetNote.parent_id);
const force = args.options.force;
const alreadyShared = !!targetNote.is_shared;
const ok = force || alreadyShared ? true : await this.prompt(
_('Publish note "%s" (in notebook "%s")?', targetNote.title, parent.title ?? '<root>'),
{ booleanAnswerDefault: 'n' },
);
if (!ok) return;
logger.info('Share note: ', targetNote.id);
const share = await ShareService.instance().shareNote(targetNote.id, false);
this.stdout(_('Synchronising...'));
await reg.waitForSyncFinishedThenSync();
const userId = ShareService.instance().userId;
const shareUrl = ShareService.instance().shareUrl(userId, share);
this.stdout(_('Published at URL: %s', shareUrl));
}
}
module.exports = Command;

View File

@@ -14,17 +14,25 @@ class Command extends BaseCommand {
return `${_('Start, stop or check the API server. To specify on which port it should run, set the api.port config variable. Commands are (%s).', ['start', 'stop', 'status'].join('|'))} This is an experimental feature - use at your own risks! It is recommended that the server runs off its own separate profile so that no two CLI instances access that profile at the same time. Use --profile to specify the profile path.`;
}
options() {
return [
['--exit-early', 'Allow the command to exit while the server is still running. The server will still stop when the app exits. Valid only for the `start` subcommand.'],
['--quiet', 'Log less information to the console. More verbose logs will still be available through log-clipper.txt.'],
];
}
async action(args) {
const command = args.command;
const ClipperServer = require('@joplin/lib/ClipperServer').default;
ClipperServer.instance().initialize();
const stdoutFn = (...s) => this.stdout(s.join(' '));
const ignoreOutputFn = ()=>{};
const clipperLogger = new Logger();
clipperLogger.addTarget('file', { path: `${Setting.value('profileDir')}/log-clipper.txt` });
clipperLogger.addTarget('console', { console: {
info: stdoutFn,
warn: stdoutFn,
info: args.options.quiet ? ignoreOutputFn : stdoutFn,
warn: args.options.quiet ? ignoreOutputFn : stdoutFn,
error: stdoutFn,
} });
ClipperServer.instance().setDispatch(() => {});
@@ -38,7 +46,11 @@ class Command extends BaseCommand {
this.stdout(_('Server is already running on port %d', runningOnPort));
} else {
await shim.fsDriver().writeFile(pidPath, process.pid.toString(), 'utf-8');
await ClipperServer.instance().start(); // Never exit
const promise = ClipperServer.instance().start();
if (!args.options['exit-early']) {
await promise; // Never exit
}
}
} else if (command === 'status') {
this.stdout(runningOnPort ? _('Server is running on port %d', runningOnPort) : _('Server is not running.'));

View File

@@ -149,6 +149,7 @@ class Command extends BaseCommand {
waiting: invitation.status === ShareUserStatus.Waiting,
rejected: invitation.status === ShareUserStatus.Rejected,
folderId: invitation.share.folder_id,
canWrite: !!invitation.can_write,
fromUser: {
email: invitation.share.user?.email,
},

View File

@@ -0,0 +1,43 @@
import ShareService from '@joplin/lib/services/share/ShareService';
import mockShareService from '@joplin/lib/testing/share/mockShareService';
import { setupDatabaseAndSynchronizer, switchClient, waitFor } from '@joplin/lib/testing/test-utils';
import { setupApplication, setupCommandForTesting } from './utils/testUtils';
import Note from '@joplin/lib/models/Note';
import Folder from '@joplin/lib/models/Folder';
const Command = require('./command-unpublish');
describe('command-unpublish', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
await setupApplication();
mockShareService({
getShares: async () => {
return { items: [{ id: 'test-id' }] };
},
postShares: async () => {
throw new Error('Unexpected call to postShares');
},
getShareInvitations: async () => null,
}, ShareService.instance());
});
test('should unpublish a note', async () => {
const command = setupCommandForTesting(Command, ()=>{});
const testFolder = await Folder.save({ title: 'Test' });
const testNote = await Note.save({ title: 'test', parent_id: testFolder.id, is_shared: 1 });
await command.action({
note: testNote.id,
});
await waitFor(async () => {
expect(await Note.load(testNote.id)).toMatchObject({
is_shared: 0,
});
});
});
});

View File

@@ -0,0 +1,57 @@
import { _ } from '@joplin/lib/locale';
import BaseCommand from './base-command';
import app from './app';
import Logger from '@joplin/utils/Logger';
import ShareService from '@joplin/lib/services/share/ShareService';
import { ModelType } from '@joplin/lib/BaseModel';
import Note from '@joplin/lib/models/Note';
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
import Setting from '@joplin/lib/models/Setting';
import { reg } from '@joplin/lib/registry';
const logger = Logger.create('command-unpublish');
type Args = {
note: string;
};
class Command extends BaseCommand {
public usage() {
return 'publish [note]';
}
public description() {
return _('Publishes a note to Joplin Server or Joplin Cloud');
}
public options() {
return [
['-f, --force', _('Do not ask for user confirmation.')],
];
}
public enabled() {
return SyncTargetRegistry.isJoplinServerOrCloud(Setting.value('sync.target'));
}
public async action(args: Args) {
const targetNote = await app().loadItemOrFail(ModelType.Note, args.note);
if (!targetNote.is_shared) {
throw new Error(_('Note not published: %s', targetNote.title));
}
logger.info('Unshare note: ', targetNote.id);
await ShareService.instance().unshareNote(targetNote.id);
const note = await Note.load(targetNote.id);
if (note.is_shared) {
throw new Error('Assertion failure: The note is still shared.');
}
this.stdout(_('Synchronising...'));
await reg.waitForSyncFinishedThenSync();
}
}
module.exports = Command;

View File

@@ -2,6 +2,7 @@ import BaseCommand from './base-command';
import app from './app';
import { _ } from '@joplin/lib/locale';
import BaseModel from '@joplin/lib/BaseModel';
import Folder from '@joplin/lib/models/Folder';
class Command extends BaseCommand {
public override usage() {
@@ -20,6 +21,18 @@ class Command extends BaseCommand {
public override async action(args: any) {
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, args['notebook']);
if (!folder) throw new Error(_('Cannot find "%s".', args['notebook']));
// Auto-expand parent folders in GUI if present
if (app().gui() && app().gui().widget && app().gui().widget('folderList')) {
const folderListWidget = app().gui().widget('folderList');
if (folderListWidget.expandToFolder) {
// Get all folders to pass to expandToFolder
const folders = await Folder.all();
folderListWidget.folders = folders; // Ensure widget has current folders
folderListWidget.expandToFolder(folder.id);
}
}
app().switchCurrentFolder(folder);
}
}

View File

@@ -4,11 +4,14 @@ import BaseModel from '@joplin/lib/BaseModel';
import Setting from '@joplin/lib/models/Setting';
import { _ } from '@joplin/lib/locale';
import { FolderEntity } from '@joplin/lib/services/database/types';
import { getDisplayParentId, getTrashFolderId } from '@joplin/lib/services/trash';
import {
getDisplayParentId,
getTrashFolderId,
} from '@joplin/lib/services/trash';
const ListWidget = require('tkwidgets/ListWidget.js');
export default class FolderListWidget extends ListWidget {
export default class FolderListWidget extends ListWidget {
private folders_: FolderEntity[] = [];
public constructor() {
@@ -31,7 +34,18 @@ export default class FolderListWidget extends ListWidget {
if (item === '-') {
output.push('-'.repeat(this.innerWidth));
} else if (item.type_ === Folder.modelType()) {
output.push(' '.repeat(this.folderDepth(this.folders, item.id)));
const depth = this.folderDepth(this.folders, item.id);
output.push(' '.repeat(depth));
// Add collapse/expand indicator
const hasChildren = this.folderHasChildren_(this.folders, item.id);
if (hasChildren) {
const collapsedFolders = Setting.value('collapsedFolderIds');
const isCollapsed = collapsedFolders.includes(item.id);
output.push(isCollapsed ? '[+] ' : '[-] ');
} else {
output.push(' '); // Space for alignment
}
if (this.showIds) {
output.push(Folder.shortId(item.id));
@@ -65,7 +79,10 @@ export default class FolderListWidget extends ListWidget {
let output = 0;
while (true) {
const folder = BaseModel.byId(folders, folderId);
const folderParentId = getDisplayParentId(folder, folders.find(f => f.id === folder.parent_id));
const folderParentId = getDisplayParentId(
folder,
folders.find((f) => f.id === folder.parent_id),
);
if (!folder || !folderParentId) return output;
output++;
folderId = folderParentId;
@@ -153,7 +170,10 @@ export default class FolderListWidget extends ListWidget {
public folderHasChildren_(folders: FolderEntity[], folderId: string) {
for (let i = 0; i < folders.length; i++) {
const folder = folders[i];
const folderParentId = getDisplayParentId(folder, folders.find(f => f.id === folder.parent_id));
const folderParentId = getDisplayParentId(
folder,
folders.find((f) => f.id === folder.parent_id),
);
if (folderParentId === folderId) return true;
}
return false;
@@ -161,7 +181,12 @@ export default class FolderListWidget extends ListWidget {
public render() {
if (this.updateItems_) {
this.logger().debug('Rebuilding items...', this.notesParentType, this.selectedJoplinItemId, this.selectedSearchId);
this.logger().debug(
'Rebuilding items...',
this.notesParentType,
this.selectedJoplinItemId,
this.selectedSearchId,
);
const wasSelectedItemId = this.selectedJoplinItemId;
const previousParentType = this.notesParentType;
@@ -170,12 +195,20 @@ export default class FolderListWidget extends ListWidget {
const orderFolders = (parentId: string) => {
for (let i = 0; i < this.folders.length; i++) {
const f = this.folders[i];
const originalParent = this.folders_.find(f => f.id === f.parent_id);
const originalParent = this.folders_.find(
(f) => f.id === f.parent_id,
);
const folderParentId = getDisplayParentId(f, originalParent); // f.parent_id ? f.parent_id : '';
if (folderParentId === parentId) {
newItems.push(f);
if (this.folderHasChildren_(this.folders, f.id)) orderFolders(f.id);
// Only recurse into children if the folder is not collapsed
if (this.folderHasChildren_(this.folders, f.id)) {
const collapsedFolders = Setting.value('collapsedFolderIds');
if (!collapsedFolders.includes(f.id)) {
orderFolders(f.id);
}
}
}
}
};
@@ -221,4 +254,53 @@ export default class FolderListWidget extends ListWidget {
const index = this.itemIndexByKey('id', itemId);
this.currentIndex = index >= 0 ? index : 0;
}
public toggleFolderCollapse() {
const item = this.currentItem;
if (item && item.type_ === Folder.modelType() && this.folderHasChildren_(this.folders, item.id)) {
const collapsedFolders = Setting.value('collapsedFolderIds');
const isCollapsed = collapsedFolders.includes(item.id);
if (isCollapsed) {
const newCollapsed = collapsedFolders.filter((id: string) => id !== item.id);
Setting.setValue('collapsedFolderIds', newCollapsed);
} else {
Setting.setValue('collapsedFolderIds', [...collapsedFolders, item.id]);
}
this.updateItems_ = true;
this.invalidate();
return true;
}
return false;
}
public expandToFolder(folderId: string) {
// Find all parent folders and expand them
const parentsToExpand: string[] = [];
let currentId = folderId;
while (currentId) {
const folder = BaseModel.byId(this.folders, currentId);
if (!folder) break;
const parentId = getDisplayParentId(
folder,
this.folders.find((f) => f.id === folder.parent_id),
);
if (parentId) {
parentsToExpand.unshift(parentId);
currentId = parentId;
} else {
break;
}
}
// Expand all parent folders
const collapsedFolders = Setting.value('collapsedFolderIds');
const newCollapsed = collapsedFolders.filter((id: string) => !parentsToExpand.includes(id));
Setting.setValue('collapsedFolderIds', newCollapsed);
this.updateItems_ = true;
this.invalidate();
}
}

View File

@@ -0,0 +1,54 @@
import { createInterface } from 'readline/promises';
const iterateStdin = async function*(prompt: string) {
let nextLineListeners: (()=> void)[] = [];
const dispatchAllListeners = () => {
const listeners = nextLineListeners;
nextLineListeners = [];
for (const listener of listeners) {
listener();
}
};
const rl = createInterface({
input: process.stdin,
output: process.stdout,
});
rl.setPrompt(prompt);
let buffer: string[] = [];
rl.on('line', (line) => {
buffer.push(line);
dispatchAllListeners();
});
let done = false;
rl.on('close', () => {
done = true;
dispatchAllListeners();
});
const readNextLines = () => {
return new Promise<string|null>(resolve => {
if (done) {
resolve(null);
} else if (buffer.length > 0) {
resolve(buffer.join('\n'));
buffer = [];
} else {
nextLineListeners.push(() => {
resolve(buffer.join('\n'));
buffer = [];
});
}
});
};
while (!done) {
rl.prompt();
const lines = await readNextLines();
yield lines;
}
};
export default iterateStdin;

View File

@@ -9,7 +9,7 @@ const shimInitCli = (options: ShimInitOptions) => {
shim.showMessageBox = async (message: string, options: ShowMessageBoxOptions) => {
const gui = app()?.gui();
let answers = options.buttons ?? [_('Ok'), _('Cancel')];
let answers = options.buttons ?? [_('OK'), _('Cancel')];
if (options.type === 'error' || options.type === 'info') {
answers = [];

View File

@@ -35,15 +35,15 @@
],
"owner": "Laurent Cozic"
},
"version": "3.4.0",
"version": "3.5.1",
"bin": "./main.js",
"engines": {
"node": ">=10.0.0"
},
"dependencies": {
"@joplin/lib": "~3.4",
"@joplin/renderer": "~3.4",
"@joplin/utils": "~3.4",
"@joplin/lib": "~3.5",
"@joplin/renderer": "~3.5",
"@joplin/utils": "~3.5",
"aws-sdk": "2.1340.0",
"chalk": "4.1.2",
"compare-version": "0.1.2",
@@ -57,7 +57,7 @@
"proper-lockfile": "4.1.2",
"redux": "4.2.1",
"server-destroy": "1.0.1",
"sharp": "0.33.5",
"sharp": "0.34.3",
"sprintf-js": "1.1.3",
"sqlite3": "5.1.6",
"string-padding": "1.0.2",
@@ -70,14 +70,14 @@
"yargs-parser": "21.1.1"
},
"devDependencies": {
"@joplin/tools": "~3.4",
"@joplin/tools": "~3.5",
"@types/fs-extra": "11.0.4",
"@types/jest": "29.5.12",
"@types/node": "18.19.86",
"@types/jest": "29.5.14",
"@types/node": "18.19.130",
"@types/proper-lockfile": "^4.1.2",
"gulp": "4.0.2",
"jest": "29.7.0",
"temp": "0.9.4",
"typescript": "5.4.5"
"typescript": "5.8.3"
}
}

View File

@@ -1,6 +1,6 @@
import MarkupToHtml, { MarkupLanguage } from '@joplin/renderer/MarkupToHtml';
import { RenderResult } from '@joplin/renderer/types';
import MarkupToHtml from '@joplin/renderer/MarkupToHtml';
import { RenderResult, MarkupLanguage } from '@joplin/renderer/types';
describe('MarkupToHtml', () => {

View File

@@ -0,0 +1,8 @@
<en-note>
<div>
<en-media style="--en-viewerProps:{};" type="image/jpeg" hash="e2d4887c5a32ab1686276c7c5ae733ef" width="1.125in" />
</div>
<div>
<br />
</div>
</en-note>

View File

@@ -0,0 +1,8 @@
<en-note>
<div>
<img src=":/e2d4887c5a32ab1686276c7c5ae733ef" style="--en-viewerProps:{};" type="image/jpeg" hash="e2d4887c5a32ab1686276c7c5ae733ef" width="108" alt="attachment-image" />
</div>
<div>
<br/>
</div>
</en-note>

View File

@@ -1,6 +1,8 @@
<en-note>
<div><a href=":/21ca2b948f222a38802940ec7e2e5de3" hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:pointer;" alt="attachment-1">attachment-1</a></div>
<div>
<br>
<a href=':/21ca2b948f222a38802940ec7e2e5de3' hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:pointer;" alt="attachment-1"> attachment-1</a>
</div>
<div>
<br/>
</div>
</en-note>

View File

@@ -1,16 +1,11 @@
<en-note>
<div>
<p>For example, consider an exported Evernote list with todo checkboxes like this:</p>
<ul>
<li>
<div><input checked="checked" type="checkbox" onclick="return false;">Foo</div>
</li>
<li>
<div><input type="checkbox" onclick="return false;"><b>Bar</b></div>
</li>
<li>
<div><input type="checkbox" onclick="return false;"><i>Baz</i></div>
</li>
<li><div><input checked="checked" type="checkbox" onclick="return false;" />Foo</div></li>
<li><div><input type="checkbox" onclick="return false;" /><b>Bar</b></div></li>
<li><div><input type="checkbox" onclick="return false;" /><i>Baz</i></div></li>
</ul>
</div>
</en-note>

View File

@@ -1,19 +1,11 @@
<en-note>
<div>
<p>In Evernote a checklist is not the same as a list with checkboxes.</p>
<ul style="--en-todo:true;">
<li style="--en-checked:false;">
<input type="checkbox" onclick="return false;">
<div>One</div>
</li>
<li style="--en-checked:true;">
<input checked="checked" type="checkbox" onclick="return false;">
<div>Two</div>
</li>
<li style="--en-checked:false;">
<input type="checkbox" onclick="return false;">
<div>Three</div>
</li>
<ul STYLE="--en-todo:true;">
<li STYLE="--en-checked:false;"> <input type="checkbox" onclick="return false;" /><div>One</div></li>
<li STYLE="--en-checked:true;"> <input checked="checked" type="checkbox" onclick="return false;" /><div>Two</div>
</li><li STYLE="--en-checked:false;"> <input type="checkbox" onclick="return false;" /><div>Three</div></li>
</ul>
</div>
</en-note>

View File

@@ -1,12 +1 @@
<en-note>
<div>
<audio controls="" preload="none" style="width:480px;">
<source src=":/9168ee833d03c5ea7c730ac6673978c1" type="audio/mp4">
<p>Your browser does not support HTML5 audio.</p>
</audio>
<p><a href=":/9168ee833d03c5ea7c730ac6673978c1">audio test</a></p>
</div>
<div>
<br>
</div>
</en-note>
<en-note><div><audio controls preload="none" style="width:480px;"><source src=":/9168ee833d03c5ea7c730ac6673978c1" type="audio/mp4" /><p>Your browser does not support HTML5 audio.</p></audio><p><a href=":/9168ee833d03c5ea7c730ac6673978c1">audio test</a></p></div><div><br/></div></en-note>

View File

@@ -1,12 +1 @@
<en-note>
<div><input type="checkbox" onclick="return false;">This is a test</div>
<div><input type="checkbox" onclick="return false;">A test for <span style="font-weight: bold;">bold</span></div>
<div>
<input type="checkbox" onclick="return false;">A test for <i>italic</i>
<br>
</div>
<div>
<br>
</div>
<div><i><img src=":/89ce7da62c6b2832929a6964237e98e9" hash="89ce7da62c6b2832929a6964237e98e9" type="image/jpeg" alt=""></i></div>
</en-note>
<en-note><div><input type="checkbox" onclick="return false;" />This is a test</div><div><input type="checkbox" onclick="return false;" />A test for <span STYLE="font-weight: bold;">bold</span></div><div><input type="checkbox" onclick="return false;" />A test for <i>italic</i><br/></div><div><br/></div><div><i><img src=":/89ce7da62c6b2832929a6964237e98e9" hash="89ce7da62c6b2832929a6964237e98e9" type="image/jpeg" alt="" /></i></div></en-note>

View File

@@ -1,3 +1,3 @@
<en-note>
<h1 style="box-sizing:inherit;font-family:&quot;Guardian TextSans Web&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;margin-top:0.2em;margin-bottom:0.35em;font-size:2.125em;font-weight:600;line-height:1.3;">Association Between mRNA Vaccination and COVID-19 Hospitalization and Disease Severity</h1>
<h1 STYLE="box-sizing:inherit;font-family:&quot;Guardian TextSans Web&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;margin-top:0.2em;margin-bottom:0.35em;font-size:2.125em;font-weight:600;line-height:1.3;">Association Between mRNA Vaccination and COVID-19 Hospitalization and Disease Severity</h1>
</en-note>

View File

@@ -1,3 +1,5 @@
<en-note>
<div><img style="margin:0px;padding:0px;outline:0px;width:74px;height:36px;position:absolute;bottom:-5px;left:0px;transform:translate(0px, 100%);stroke-dasharray:90;transition:stroke-dashoffset 0.5s cubic-bezier(0.97, 0.16, 0.62, 0.76) 0s;stroke-dashoffset:0;" src="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' data-evernote-id='97' class='js-evernote-checked'%3e%3cuse xlink:href='https://wordminds.com/wp-content/themes/wordminds/assets/img/hint_left.svg%23hint_left' data-evernote-id='98' class='js-evernote-checked'%3e%3c/use%3e%3c/svg%3e"></div>
<div>
<img STYLE="margin:0px;padding:0px;outline:0px;width:74px;height:36px;position:absolute;bottom:-5px;left:0px;transform:translate(0px, 100%);stroke-dasharray:90;transition:stroke-dashoffset 0.5s cubic-bezier(0.97, 0.16, 0.62, 0.76) 0s;stroke-dashoffset:0;" SRC="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' data-evernote-id='97' class='js-evernote-checked'%3e%3cuse xlink:href='https://wordminds.com/wp-content/themes/wordminds/assets/img/hint_left.svg%23hint_left' data-evernote-id='98' class='js-evernote-checked'%3e%3c/use%3e%3c/svg%3e"/>
</div>
</en-note>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export4.dtd">
<en-export export-date="20230724T173816Z" application="Evernote" version="10.58.8">
<note>
<title>test.json</title>
<content><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><en-media hash="ac91cc691d21261b222681dd38c1e4ad" type="application/json"/></en-note>
]]>
</content>
<created>20191002T075850Z</created>
<updated>20191002T075850Z</updated>
<note-attributes><latitude>48.79547119140625</latitude><longitude>9.809423921920198</longitude><altitude>398.0</altitude><author>Laurent</author><source>desktop.mac</source></note-attributes>
<resource><data>eyAidGVzdCI6IDEyMyB9</data><mime>application/json</mime><width>0</width><height>0</height><resource-attributes><file-name>test.json</file-name><attachment>false</attachment></resource-attributes></resource></note></en-export>

View File

@@ -0,0 +1,13 @@
<p>A task list created by the TipTap editor:</p>
<ul data-type="taskList">
<li><label contenteditable="false"><input type="checkbox"><span></span></label>
<div>
<p>Testing...</p>
</div>
</li>
<li><label contenteditable="false"><input type="checkbox"><span></span></label>
<div>
<p>testing</p>
</div>
</li>
</ul>

View File

@@ -0,0 +1,5 @@
A task list created by the TipTap editor:
- [ ] Testing...
- [ ] testing

View File

@@ -0,0 +1,26 @@
<p>List 1:</p>
<ul>
<li><label><input type="checkbox"/>This</label></li>
<li><label><input type="checkbox" checked/>is a test.</label></li>
</ul>
<p>List 2:</p>
<ul>
<li>
<input type="checkbox" id="checkbox-1"/><label for="checkbox-1">This</label>
</li>
<li>
<input type="checkbox" checked id="checkbox-2"/><label for="checkbox-2">is another test.</label>
</li>
</ul>
<p>List 3:</p>
<ul>
<li>
<input type="checkbox" id="checkbox-a1"/><label for="checkbox-a1">This</label>
</li>
<li>
<input type="checkbox" checked id="checkbox-a2"/><label for="checkbox-a2">is another test.</label>
</li>
<li>
<input type="checkbox" checked id="checkbox-a3"/><label for="checkbox-a3"></label>
</li>
</ul>

View File

@@ -0,0 +1,15 @@
List 1:
- [ ] This
- [x] is a test.
List 2:
- [ ] This
- [x] is another test.
List 3:
- [ ] This
- [x] is another test.
- [x] &nbsp;

View File

@@ -1,7 +1,7 @@
<ul class="joplin-checklist">
<ul class="joplin-checklist" data-is-checklist="1">
<li>Not checked</li>
<li class="checked">Checked!!
<ul class="joplin-checklist">
<ul class="joplin-checklist" data-is-checklist="1">
<li class="checked">Indented, with <strong>bold</strong></li>
<li>Indented, not checked</li>
</ul>

View File

@@ -1,15 +1,15 @@
<div class="not-loaded-resource not-loaded-image-resource resource-status-notDownloaded" data-resource-id="a1test2a1test2a1test2a1test22345" data-original-alt data-original-title="test" contenteditable="false"><img src="data:image/svg+xml;utf8,
<span class="not-loaded-resource not-loaded-image-resource resource-status-notDownloaded" data-resource-id="a1test2a1test2a1test2a1test22345" data-original-alt data-original-title="test" contenteditable="false"><img src="data:image/svg+xml;utf8,
&Tab;&Tab;&lt;svg width=&quot;1700&quot; height=&quot;1536&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
&Tab;&Tab; &lt;path d=&quot;M1280 1344c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm256 0c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm128-224v320c0 53-43 96-96 96H96c-53 0-96-43-96-96v-320c0-53 43-96 96-96h465l135 136c37 36 85 56 136 56s99-20 136-56l136-136h464c53 0 96 43 96 96zm-325-569c10 24 5 52-14 70l-448 448c-12 13-29 19-45 19s-33-6-45-19L339 621c-19-18-24-46-14-70 10-23 33-39 59-39h256V64c0-35 29-64 64-64h256c35 0 64 29 64 64v448h256c26 0 49 16 59 39z&quot;/&gt;
&Tab;&Tab;&lt;/svg&gt;
&Tab;"/></div>
<div class="not-loaded-resource not-loaded-image-resource resource-status-notDownloaded" data-resource-id="a1test2a1test2a1test2a1test22346" data-original-alt="test" data-original-title contenteditable="false"><img src="data:image/svg+xml;utf8,
&Tab;"/></span>
<span class="not-loaded-resource not-loaded-image-resource resource-status-notDownloaded" data-resource-id="a1test2a1test2a1test2a1test22346" data-original-alt="test" data-original-title contenteditable="false"><img src="data:image/svg+xml;utf8,
&Tab;&Tab;&lt;svg width=&quot;1700&quot; height=&quot;1536&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
&Tab;&Tab; &lt;path d=&quot;M1280 1344c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm256 0c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm128-224v320c0 53-43 96-96 96H96c-53 0-96-43-96-96v-320c0-53 43-96 96-96h465l135 136c37 36 85 56 136 56s99-20 136-56l136-136h464c53 0 96 43 96 96zm-325-569c10 24 5 52-14 70l-448 448c-12 13-29 19-45 19s-33-6-45-19L339 621c-19-18-24-46-14-70 10-23 33-39 59-39h256V64c0-35 29-64 64-64h256c35 0 64 29 64 64v448h256c26 0 49 16 59 39z&quot;/&gt;
&Tab;&Tab;&lt;/svg&gt;
&Tab;"/></div>
<div class="not-loaded-resource not-loaded-image-resource resource-status-notDownloaded" data-resource-id="a1test2a1test2a1test2a1test22347" data-original-before=" " data-original-after=" class=&quot;jop-noMdConv&quot;/" contenteditable="false"><img src="data:image/svg+xml;utf8,
&Tab;"/></span>
<span class="not-loaded-resource not-loaded-image-resource resource-status-notDownloaded" data-resource-id="a1test2a1test2a1test2a1test22347" data-original-before=" " data-original-after=" class=&quot;jop-noMdConv&quot;/" contenteditable="false"><img src="data:image/svg+xml;utf8,
&Tab;&Tab;&lt;svg width=&quot;1700&quot; height=&quot;1536&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
&Tab;&Tab; &lt;path d=&quot;M1280 1344c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm256 0c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm128-224v320c0 53-43 96-96 96H96c-53 0-96-43-96-96v-320c0-53 43-96 96-96h465l135 136c37 36 85 56 136 56s99-20 136-56l136-136h464c53 0 96 43 96 96zm-325-569c10 24 5 52-14 70l-448 448c-12 13-29 19-45 19s-33-6-45-19L339 621c-19-18-24-46-14-70 10-23 33-39 59-39h256V64c0-35 29-64 64-64h256c35 0 64 29 64 64v448h256c26 0 49 16 59 39z&quot;/&gt;
&Tab;&Tab;&lt;/svg&gt;
&Tab;"/></div>
&Tab;"/></span>

View File

@@ -2,7 +2,7 @@ import PluginRunner from '../../../app/services/plugins/PluginRunner';
import PluginService, { PluginSettings, defaultPluginSetting } from '@joplin/lib/services/plugins/PluginService';
import { ContentScriptType } from '@joplin/lib/services/plugins/api/types';
import MdToHtml from '@joplin/renderer/MdToHtml';
import shim from '@joplin/lib/shim';
import shim, { MobilePlatform } from '@joplin/lib/shim';
import Setting from '@joplin/lib/models/Setting';
import * as fs from 'fs-extra';
import Note from '@joplin/lib/models/Note';
@@ -310,7 +310,7 @@ describe('services_PluginService', () => {
let resetPlatformMock = () => {};
if (!isDesktop) {
resetPlatformMock = mockMobilePlatform('android').reset;
resetPlatformMock = mockMobilePlatform(MobilePlatform.Android).reset;
}
try {

View File

@@ -0,0 +1,3 @@
1. File without extension and leading `./`: [file1](./file1). Gets imported, but filename is converted to extension, like `<internal_id>.file1`
2. File without extension: [file2](file2). Not imported at all.
3. File with extension: [file3](file3.text). Gets imported properly.

View File

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

View File

@@ -8,7 +8,7 @@ import { FileLocker } from '@joplin/utils/fs';
import { IpcMessageHandler, IpcServer, Message, newHttpError, sendMessage, SendMessageOptions, startServer, stopServer } from '@joplin/utils/ipc';
import { BrowserWindow, Tray, WebContents, screen, App, nativeTheme } from 'electron';
import bridge from './bridge';
const url = require('url');
import * as url from 'url';
const path = require('path');
const { dirname } = require('@joplin/lib/path-utils');
const fs = require('fs-extra');
@@ -407,7 +407,17 @@ export default class ElectronAppWrapper {
isGoingToExit = true;
} else {
event.preventDefault();
this.hide();
const w = this.win_;
if (!w) return;
if (w.isFullScreen()) {
// leave fullscreen, then hide
w.once('leave-full-screen', () => w.hide());
w.setFullScreen(false);
} else {
w.hide();
}
}
} else {
const hasBackgroundWindows = this.secondaryWindows_.size > 0;
@@ -612,7 +622,11 @@ export default class ElectronAppWrapper {
console.warn('The window object was not available during the click event from tray icon');
return;
}
this.mainWindow().show();
if (!this.mainWindow().isVisible()) {
this.mainWindow().show();
} else {
this.mainWindow().hide();
}
});
} catch (error) {
console.error('Cannot create tray', error);

View File

@@ -86,8 +86,14 @@ export default class InteropServiceHelper {
// pdfs.
// https://github.com/laurent22/joplin/issues/6254.
await win.webContents.executeJavaScript('document.querySelectorAll(\'details\').forEach(el=>el.setAttribute(\'open\',\'\'))');
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const data = await win.webContents.printToPDF(options as any);
const data = await win.webContents.printToPDF({
...options,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partially refactored old code before rule was applied
pageSize: options.pageSize as any,
// Allows users to override the CSS page size.
// See https://github.com/laurent22/joplin/issues/13096
preferCSSPageSize: true,
});
resolve(data);
} catch (error) {
reject(error);

View File

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

View File

@@ -26,10 +26,21 @@ export interface AppStateDialog {
props: Record<string, any>;
}
export interface EditorScrollPercents {
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;
}
@@ -42,6 +53,9 @@ 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 {
@@ -55,7 +69,6 @@ export interface AppState extends State, AppWindowState {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
navHistory: any[];
watchedNoteFiles: string[];
lastEditorScrollPercents: EditorScrollPercents;
focusedField: string;
layoutMoveMode: boolean;
startupPluginsLoaded: boolean;
@@ -66,7 +79,7 @@ export interface AppState extends State, AppWindowState {
isResettingLayout: boolean;
}
export const createAppDefaultWindowState = (): AppWindowState => {
export const createAppDefaultWindowState = (globalState: AppState|null): AppWindowState => {
return {
...defaultWindowState,
visibleDialogs: {},
@@ -75,6 +88,12 @@ export const createAppDefaultWindowState = (): AppWindowState => {
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 ?? {},
};
};
@@ -82,7 +101,7 @@ export const createAppDefaultWindowState = (): AppWindowState => {
export function createAppDefaultState(resourceEditWatcherDefaultState: any): AppState {
return {
...defaultState,
...createAppDefaultWindowState(),
...createAppDefaultWindowState(null),
route: {
type: 'NAV_GO',
routeName: 'Main',
@@ -90,7 +109,6 @@ export function createAppDefaultState(resourceEditWatcherDefaultState: any): App
},
navHistory: [],
watchedNoteFiles: [],
lastEditorScrollPercents: {},
visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
focusedField: null,
layoutMoveMode: false,
@@ -299,6 +317,18 @@ export default function(state: AppState, action: any) {
}
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

@@ -55,11 +55,18 @@ import userFetcher, { initializeUserFetcher } from '@joplin/lib/utils/userFetche
import { parseNotesParent } from '@joplin/lib/reducer';
import OcrService from '@joplin/lib/services/ocr/OcrService';
import OcrDriverTesseract from '@joplin/lib/services/ocr/drivers/OcrDriverTesseract';
import OcrDriverTranscribe from '@joplin/lib/services/ocr/drivers/OcrDriverTranscribe';
import SearchEngine from '@joplin/lib/services/search/SearchEngine';
import { PackageInfo } from '@joplin/lib/versionInfo';
import { CustomProtocolHandler } from './utils/customProtocols/handleCustomProtocols';
import { refreshFolders } from '@joplin/lib/folders-screen-utils';
import initializeCommandService from './utils/initializeCommandService';
import OcrDriverBase from '@joplin/lib/services/ocr/OcrDriverBase';
import PerformanceLogger from '@joplin/lib/PerformanceLogger';
import Note from '@joplin/lib/models/Note';
import Resource from '@joplin/lib/models/Resource';
const perfLogger = PerformanceLogger.create();
const pluginClasses = [
require('./plugins/GotoAnything').default,
@@ -67,6 +74,8 @@ const pluginClasses = [
const appDefaultState = createAppDefaultState(resourceEditWatcherDefaultState);
type StartupTask = { label: string; task: ()=> void|Promise<void> };
class Application extends BaseApplication {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
@@ -348,16 +357,19 @@ class Application extends BaseApplication {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const Tesseract = (window as any).Tesseract;
const driver = new OcrDriverTesseract(
const drivers: OcrDriverBase[] = [];
drivers.push(new OcrDriverTesseract(
{ createWorker: Tesseract.createWorker },
{
workerPath: `${bridge().buildDir()}/tesseract.js/worker.min.js`,
corePath: `${bridge().buildDir()}/tesseract.js-core`,
languageDataPath: Setting.value('ocr.languageDataPath') || null,
},
);
));
this.ocrService_ = new OcrService(driver);
drivers.push(new OcrDriverTranscribe());
this.ocrService_ = new OcrService(drivers);
}
void this.ocrService_.runInBackground();
@@ -411,56 +423,53 @@ class Application extends BaseApplication {
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async start(argv: string[], startOptions: StartOptions = null): Promise<any> {
// If running inside a package, the command line, instead of being "node.exe <path> <flags>" is "joplin.exe <flags>" so
// insert an extra argument so that they can be processed in a consistent way everywhere.
if (!bridge().electronIsDev()) argv.splice(1, 0, '.');
private buildStartupTasks_() {
const tasks: StartupTask[] = [];
const addTask = (label: string, task: StartupTask['task']) => {
tasks.push({ label, task });
};
argv = await super.start(argv, startOptions);
addTask('app/set up extra debug logging', () => {
reg.logger().info('app.start: doing regular boot');
const dir: string = Setting.value('profileDir');
await this.setupIntegrationTestUtils();
syncDebugLog.enabled = false;
bridge().setLogFilePath(Logger.globalLogger.logFilePath());
if (dir.endsWith('dev-desktop-2')) {
syncDebugLog.addTarget(TargetType.File, {
path: `${homedir()}/synclog.txt`,
});
syncDebugLog.enabled = true;
syncDebugLog.info(`Profile dir: ${dir}`);
}
});
await this.applySettingsSideEffects();
addTask('app/set up registry', () => {
reg.setDispatch(this.dispatch.bind(this));
reg.setShowErrorMessageBoxHandler((message: string) => { bridge().showErrorMessageBox(message); });
});
if (Setting.value('sync.upgradeState') === Setting.SYNC_UPGRADE_STATE_MUST_DO) {
reg.logger().info('app.start: doing upgradeSyncTarget action');
bridge().mainWindow().show();
return { action: 'upgradeSyncTarget' };
}
addTask('app/set up auto updater', () => {
this.setupAutoUpdaterService();
});
reg.logger().info('app.start: doing regular boot');
const dir: string = Setting.value('profileDir');
syncDebugLog.enabled = false;
if (dir.endsWith('dev-desktop-2')) {
syncDebugLog.addTarget(TargetType.File, {
path: `${homedir()}/synclog.txt`,
});
syncDebugLog.enabled = true;
syncDebugLog.info(`Profile dir: ${dir}`);
}
this.setupAutoUpdaterService();
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
AlarmService.setLogger(reg.logger());
reg.setDispatch(this.dispatch.bind(this));
reg.setShowErrorMessageBoxHandler((message: string) => { bridge().showErrorMessageBox(message); });
addTask('app/set up AlarmService', () => {
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
AlarmService.setLogger(reg.logger());
});
if (Setting.value('flagOpenDevTools')) {
bridge().openDevTools();
addTask('app/openDevTools', () => {
bridge().openDevTools();
});
}
this.protocolHandler_ = bridge().electronApp().getCustomProtocolHandler();
this.protocolHandler_.allowReadAccessToDirectory(__dirname); // App bundle directory
this.protocolHandler_.allowReadAccessToDirectory(Setting.value('cacheDir'));
this.protocolHandler_.allowReadAccessToDirectory(Setting.value('resourceDir'));
addTask('app/set up custom protocol handler', async () => {
this.protocolHandler_ = bridge().electronApp().getCustomProtocolHandler();
this.protocolHandler_.allowReadAccessToDirectory(__dirname); // App bundle directory
this.protocolHandler_.allowReadAccessToDirectory(Setting.value('cacheDir'));
this.protocolHandler_.allowReadAccessToDirectory(Setting.value('resourceDir'));
});
// this.protocolHandler_.allowReadAccessTo(Setting.value('tempDir'));
// For now, this doesn't seem necessary:
// this.protocolHandler_.allowReadAccessTo(Setting.value('profileDir'));
@@ -468,44 +477,52 @@ class Application extends BaseApplication {
// handler, and, as such, it may make sense to also limit permissions of
// allowed pages with a Content Security Policy.
PluginManager.instance().dispatch_ = this.dispatch.bind(this);
PluginManager.instance().setLogger(reg.logger());
PluginManager.instance().register(pluginClasses);
addTask('app/initialize PluginManager, redux, CommandService, and KeymapService', async () => {
PluginManager.instance().dispatch_ = this.dispatch.bind(this);
PluginManager.instance().setLogger(reg.logger());
PluginManager.instance().register(pluginClasses);
this.initRedux();
this.initRedux();
PerFolderSortOrderService.initialize();
initializeCommandService(this.store(), Setting.value('env') === 'dev');
initializeCommandService(this.store(), Setting.value('env') === 'dev');
const keymapService = KeymapService.instance();
// We only add the commands that appear in the menu because only
// those can have a shortcut associated with them.
keymapService.initialize(menuCommandNames());
const keymapService = KeymapService.instance();
// We only add the commands that appear in the menu because only
// those can have a shortcut associated with them.
keymapService.initialize(menuCommandNames());
try {
await keymapService.loadCustomKeymap(`${dir}/keymap-desktop.json`);
} catch (error) {
reg.logger().error(error);
}
// Since the settings need to be loaded before the store is
// created, it will never receive the SETTING_UPDATE_ALL even,
// which mean state.settings will not be initialised. So we
// manually call dispatchUpdateAll() to force an update.
Setting.dispatchUpdateAll();
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
await refreshFolders((action: any) => this.dispatch(action), '');
const tags = await Tag.allWithNotes();
this.dispatch({
type: 'TAG_UPDATE_ALL',
items: tags,
try {
await keymapService.loadCustomKeymap(`${Setting.value('profileDir')}/keymap-desktop.json`);
} catch (error) {
reg.logger().error(error);
}
});
await this.setupCustomCss();
addTask('app/initialize PerFolderSortOrderService', () => {
PerFolderSortOrderService.initialize();
});
addTask('app/dispatch initial settings', () => {
// Since the settings need to be loaded before the store is
// created, it will never receive the SETTING_UPDATE_ALL even,
// which mean state.settings will not be initialised. So we
// manually call dispatchUpdateAll() to force an update.
Setting.dispatchUpdateAll();
});
addTask('app/update folders and tags', async () => {
await refreshFolders((action) => this.dispatch(action), '');
const tags = await Tag.allWithNotes();
this.dispatch({
type: 'TAG_UPDATE_ALL',
items: tags,
});
});
addTask('app/set up custom CSS', async () => {
await this.setupCustomCss();
});
// const masterKeys = await MasterKey.all();
@@ -514,188 +531,242 @@ class Application extends BaseApplication {
// items: masterKeys,
// });
const getNotesParent = async () => {
let notesParent = parseNotesParent(Setting.value('notesParent'), Setting.value('activeFolderId'));
if (notesParent.type === 'Tag' && !(await Tag.load(notesParent.selectedItemId))) {
notesParent = {
type: 'Folder',
selectedItemId: Setting.value('activeFolderId'),
};
addTask('app/send initial selection to redux', async () => {
const getNotesParent = async () => {
let notesParent = parseNotesParent(Setting.value('notesParent'), Setting.value('activeFolderId'));
if (notesParent.type === 'Tag' && !(await Tag.load(notesParent.selectedItemId))) {
notesParent = {
type: 'Folder',
selectedItemId: Setting.value('activeFolderId'),
};
}
return notesParent;
};
const notesParent = await getNotesParent();
if (notesParent.type === 'SmartFilter') {
this.store().dispatch({
type: 'SMART_FILTER_SELECT',
id: notesParent.selectedItemId,
});
} else if (notesParent.type === 'Tag') {
this.store().dispatch({
type: 'TAG_SELECT',
id: notesParent.selectedItemId,
});
} else {
this.store().dispatch({
type: 'FOLDER_SELECT',
id: notesParent.selectedItemId,
});
}
return notesParent;
};
const notesParent = await getNotesParent();
this.store().dispatch({
type: 'FOLDER_SET_COLLAPSED_ALL',
ids: Setting.value('collapsedFolderIds'),
});
if (notesParent.type === 'SmartFilter') {
this.store().dispatch({
type: 'SMART_FILTER_SELECT',
id: notesParent.selectedItemId,
type: 'NOTE_DEVTOOLS_SET',
value: Setting.value('flagOpenDevTools'),
});
} else if (notesParent.type === 'Tag') {
this.store().dispatch({
type: 'TAG_SELECT',
id: notesParent.selectedItemId,
});
} else {
this.store().dispatch({
type: 'FOLDER_SELECT',
id: notesParent.selectedItemId,
});
}
this.store().dispatch({
type: 'FOLDER_SET_COLLAPSED_ALL',
ids: Setting.value('collapsedFolderIds'),
});
this.store().dispatch({
type: 'NOTE_DEVTOOLS_SET',
value: Setting.value('flagOpenDevTools'),
addTask('app/initializeUserFetcher', async () => {
initializeUserFetcher();
shim.setInterval(() => { void userFetcher(); }, 1000 * 60 * 60);
});
// Always disable on Mac for now - and disable too for the few apps that may have the flag enabled.
// At present, it only seems to work on Windows.
if (shim.isMac()) {
Setting.setValue('featureFlag.autoUpdaterServiceEnabled', false);
}
addTask('app/updateTray', () => this.updateTray());
// Note: Auto-update is a misnomer in the code.
// The code below only checks, if a new version is available.
// We only allow Windows and macOS users to automatically check for updates
if (!Setting.value('featureFlag.autoUpdaterServiceEnabled')) {
if (shim.isWindows() || shim.isMac()) {
const runAutoUpdateCheck = () => {
if (Setting.value('autoUpdateEnabled')) {
void checkForUpdates(true, bridge().mainWindow(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
}
};
// Initial check on startup
shim.setTimeout(() => { runAutoUpdateCheck(); }, 5000);
// Then every x hours
shim.setInterval(() => { runAutoUpdateCheck(); }, 12 * 60 * 60 * 1000);
addTask('app/set main window state', () => {
if (Setting.value('startMinimized') && Setting.value('showTrayIcon')) {
bridge().mainWindow().hide();
} else {
bridge().mainWindow().show();
}
}
});
initializeUserFetcher();
shim.setInterval(() => { void userFetcher(); }, 1000 * 60 * 60);
addTask('app/start maintenance tasks', () => {
// Always disable on Mac for now - and disable too for the few apps that may have the flag enabled.
// At present, it only seems to work on Windows.
if (shim.isMac()) {
Setting.setValue('featureFlag.autoUpdaterServiceEnabled', false);
}
this.updateTray();
// Note: Auto-update is a misnomer in the code.
// The code below only checks, if a new version is available.
// We only allow Windows and macOS users to automatically check for updates
if (!Setting.value('featureFlag.autoUpdaterServiceEnabled')) {
if (shim.isWindows() || shim.isMac()) {
const runAutoUpdateCheck = () => {
if (Setting.value('autoUpdateEnabled')) {
void checkForUpdates(true, bridge().mainWindow(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
}
};
shim.setTimeout(() => {
void AlarmService.garbageCollect();
}, 1000 * 60 * 60);
// Initial check on startup
shim.setTimeout(() => { runAutoUpdateCheck(); }, 5000);
// Then every x hours
shim.setInterval(() => { runAutoUpdateCheck(); }, 12 * 60 * 60 * 1000);
}
}
if (Setting.value('startMinimized') && Setting.value('showTrayIcon')) {
bridge().mainWindow().hide();
} else {
bridge().mainWindow().show();
}
shim.setTimeout(() => {
void AlarmService.garbageCollect();
}, 1000 * 60 * 60);
void ShareService.instance().maintenance();
void ShareService.instance().maintenance();
ResourceService.runInBackground();
ResourceService.runInBackground();
if (Setting.value('env') === 'dev') {
void AlarmService.updateAllNotifications();
} else {
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
void reg.scheduleSync(1000).then(() => {
// Wait for the first sync before updating the notifications, since synchronisation
// might change the notifications.
if (Setting.value('env') === 'dev') {
void AlarmService.updateAllNotifications();
} else {
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
void reg.scheduleSync(1000).then(() => {
// Wait for the first sync before updating the notifications, since synchronisation
// might change the notifications.
void AlarmService.updateAllNotifications();
void DecryptionWorker.instance().scheduleStart();
});
}
void DecryptionWorker.instance().scheduleStart();
});
}
const clipperLogger = new Logger();
clipperLogger.addTarget(TargetType.File, { path: `${Setting.value('profileDir')}/log-clipper.txt` });
clipperLogger.addTarget(TargetType.Console);
ClipperServer.instance().initialize(actionApi);
ClipperServer.instance().setEnabled(!Setting.value('altInstanceId'));
ClipperServer.instance().setLogger(clipperLogger);
ClipperServer.instance().setDispatch(this.store().dispatch);
if (ClipperServer.instance().enabled() && Setting.value('clipperServer.autoStart')) {
void ClipperServer.instance().start();
}
ExternalEditWatcher.instance().setLogger(reg.logger());
ExternalEditWatcher.instance().initialize(bridge, this.store().dispatch);
ResourceEditWatcher.instance().initialize(
reg.logger(),
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
(action: any) => { this.store().dispatch(action); },
(path: string) => bridge().openItem(path),
() => this.store().getState().windowId,
);
// Forwards the local event to the global event manager, so that it can
// be picked up by the plugin manager.
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
ResourceEditWatcher.instance().on('resourceChange', (event: any) => {
eventManager.emit(EventName.ResourceChange, event);
RevisionService.instance().runInBackground();
this.startRotatingLogMaintenance(Setting.value('profileDir'));
});
RevisionService.instance().runInBackground();
addTask('app/set up ClipperServer', () => {
const clipperLogger = new Logger();
clipperLogger.addTarget(TargetType.File, { path: `${Setting.value('profileDir')}/log-clipper.txt` });
clipperLogger.addTarget(TargetType.Console);
ClipperServer.instance().initialize(actionApi);
ClipperServer.instance().setEnabled(!Setting.value('altInstanceId'));
ClipperServer.instance().setLogger(clipperLogger);
ClipperServer.instance().setDispatch(this.store().dispatch);
if (ClipperServer.instance().enabled() && Setting.value('clipperServer.autoStart')) {
void ClipperServer.instance().start();
}
});
addTask('app/set up external edit watchers', () => {
ExternalEditWatcher.instance().setLogger(reg.logger());
ExternalEditWatcher.instance().initialize(bridge, this.store().dispatch);
ResourceEditWatcher.instance().initialize(
reg.logger(),
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
(action: any) => { this.store().dispatch(action); },
(path: string) => bridge().openItem(path),
() => this.store().getState().windowId,
);
// Forwards the local event to the global event manager, so that it can
// be picked up by the plugin manager.
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
ResourceEditWatcher.instance().on('resourceChange', (event: any) => {
eventManager.emit(EventName.ResourceChange, event);
});
});
// Make it available to the console window - useful to call revisionService.collectRevisions()
if (Setting.value('env') === 'dev') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
(window as any).joplin = {
revisionService: RevisionService.instance(),
migrationService: MigrationService.instance(),
decryptionWorker: DecryptionWorker.instance(),
commandService: CommandService.instance(),
pluginService: PluginService.instance(),
bridge: bridge(),
debug: new DebugService(reg.db()),
resourceService: ResourceService.instance(),
searchEngine: SearchEngine.instance(),
ocrService: () => this.ocrService_,
};
addTask('app/add debug variables', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
(window as any).joplin = {
revisionService: RevisionService.instance(),
migrationService: MigrationService.instance(),
decryptionWorker: DecryptionWorker.instance(),
commandService: CommandService.instance(),
pluginService: PluginService.instance(),
bridge: bridge(),
debug: new DebugService(reg.db()),
resourceService: ResourceService.instance(),
searchEngine: SearchEngine.instance(),
shim,
Note,
Folder,
Resource,
Setting,
ocrService: () => this.ocrService_,
};
});
}
bridge().addEventListener('nativeThemeUpdated', this.bridge_nativeThemeUpdated);
bridge().setOnAllowedExtensionsChangeListener((newExtensions) => {
Setting.setValue('linking.extraAllowedExtensions', newExtensions);
addTask('app/listen for main process events', () => {
bridge().addEventListener('nativeThemeUpdated', this.bridge_nativeThemeUpdated);
bridge().setOnAllowedExtensionsChangeListener((newExtensions) => {
Setting.setValue('linking.extraAllowedExtensions', newExtensions);
});
ipcRenderer.on('window-focused', (_event, newWindowId) => {
const currentWindowId = this.store().getState().windowId;
if (newWindowId !== currentWindowId) {
this.dispatch({
type: 'WINDOW_FOCUS',
windowId: newWindowId,
lastWindowId: currentWindowId,
});
}
});
});
ipcRenderer.on('window-focused', (_event, newWindowId) => {
const currentWindowId = this.store().getState().windowId;
if (newWindowId !== currentWindowId) {
this.dispatch({
type: 'WINDOW_FOCUS',
windowId: newWindowId,
lastWindowId: currentWindowId,
});
}
addTask('app/initPluginService', () => this.initPluginService());
addTask('app/setupContextMenu', () => {
this.setupContextMenu();
});
await this.initPluginService();
this.setupContextMenu();
await SpellCheckerService.instance().initialize(new SpellCheckerServiceDriverNative());
this.startRotatingLogMaintenance(Setting.value('profileDir'));
await this.setupOcrService();
eventManager.on(EventName.OcrServiceResourcesProcessed, async () => {
await ResourceService.instance().indexNoteResources();
addTask('app/set up SpellCheckerService', async () => {
await SpellCheckerService.instance().initialize(new SpellCheckerServiceDriverNative());
});
eventManager.on(EventName.NoteResourceIndexed, async () => {
SearchEngine.instance().scheduleSyncTables();
addTask('app/listen for resource events', () => {
eventManager.on(EventName.OcrServiceResourcesProcessed, async () => {
await ResourceService.instance().indexNoteResources();
});
eventManager.on(EventName.NoteResourceIndexed, async () => {
SearchEngine.instance().scheduleSyncTables();
});
});
// Used by tests
ipcRenderer.send('startup-finished');
addTask('app/setupOcrService', () => this.setupOcrService());
return tasks;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public async start(argv: string[], startOptions: StartOptions = null): Promise<any> {
const startupTask = perfLogger.taskStart('app/start');
// If running inside a package, the command line, instead of being "node.exe <path> <flags>" is "joplin.exe <flags>" so
// insert an extra argument so that they can be processed in a consistent way everywhere.
if (!bridge().electronIsDev()) argv.splice(1, 0, '.');
argv = await super.start(argv, startOptions);
await this.setupIntegrationTestUtils();
bridge().setLogFilePath(Logger.globalLogger.logFilePath());
await this.applySettingsSideEffects();
if (Setting.value('sync.upgradeState') === Setting.SYNC_UPGRADE_STATE_MUST_DO) {
reg.logger().info('app.start: doing upgradeSyncTarget action');
bridge().mainWindow().show();
startupTask.onEnd();
return { action: 'upgradeSyncTarget' };
}
const startupTasks = this.buildStartupTasks_();
for (const task of startupTasks) {
await perfLogger.track(task.label, async () => task.task());
}
// setTimeout(() => {
// void populateDatabase(reg.db(), {
@@ -749,6 +820,10 @@ class Application extends BaseApplication {
// await runIntegrationTests();
// Used by tests
ipcRenderer.send('startup-finished');
startupTask.onEnd();
return null;
}

View File

@@ -8,8 +8,8 @@ import { urlDecode } from '@joplin/lib/string-utils';
import * as Sentry from '@sentry/electron/main';
import { homedir } from 'os';
import { msleep } from '@joplin/utils/time';
import { pathExists, pathExistsSync, writeFileSync } from 'fs-extra';
import { extname, normalize } from 'path';
import { pathExists, pathExistsSync, writeFileSync, ensureDirSync } from 'fs-extra';
import { extname, normalize, join } from 'path';
import isSafeToOpen from './utils/isSafeToOpen';
import { closeSync, openSync, readSync, statSync } from 'fs';
import { KB } from '@joplin/utils/bytes';
@@ -67,6 +67,30 @@ export class Bridge {
this.logFilePath_ = v;
}
private getCrashDumpDirectory(): string {
try {
const platformName = shim.platformName();
switch (platformName) {
case 'win32':
// Windows: Use %LOCALAPPDATA%\CrashDumps
return join(process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local'), 'CrashDumps');
case 'darwin':
// macOS: Use ~/Library/Logs/DiagnosticReports
return join(homedir(), 'Library', 'Logs', 'DiagnosticReports');
case 'linux':
// Linux: Use XDG_STATE_HOME (for logs) or fallback to ~/.local/state
return join(process.env.XDG_STATE_HOME || join(homedir(), '.local', 'state'), 'joplin');
default:
// For unknown platforms, default to the home directory
return homedir();
}
} catch (error) {
// If we can't get the platform name, fallback to the home directory
return homedir();
}
}
private sentryInit() {
const getLogLines = () => {
try {
@@ -109,7 +133,10 @@ export class Bridge {
log: logAttachment ? logAttachment.data.trim().split('\n') : [],
};
writeFileSync(`${homedir()}/joplin_crash_dump_${date}.json`, JSON.stringify(errorEventWithLog, null, '\t'), 'utf-8');
const crashDumpDir = this.getCrashDumpDirectory();
ensureDirSync(crashDumpDir);
const crashDumpPath = join(crashDumpDir, `joplin_crash_dump_${date}.json`);
writeFileSync(crashDumpPath, JSON.stringify(errorEventWithLog, null, '\t'), 'utf-8');
} catch (error) {
// Ignore the error since we can't handle it here
}

View File

@@ -0,0 +1,96 @@
import * as convertHtmlToMarkdown from './convertNoteToMarkdown';
import { AppState, createAppDefaultState } from '../app.reducer';
import Note from '@joplin/lib/models/Note';
import { MarkupLanguage } from '@joplin/renderer';
import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
import Folder from '@joplin/lib/models/Folder';
import { NoteEntity } from '@joplin/lib/services/database/types';
describe('convertNoteToMarkdown', () => {
let state: AppState = undefined;
beforeEach(async () => {
state = createAppDefaultState({});
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
});
it('should set the original note to be trashed', async () => {
const folder = await Folder.save({ title: 'test_folder' });
const htmlNote = await Note.save({ title: 'test', body: '<p>Hello</p>', parent_id: folder.id, markup_language: MarkupLanguage.Html });
state.selectedNoteIds = [htmlNote.id];
await convertHtmlToMarkdown.runtime().execute({ state, dispatch: () => {} });
const refreshedNote = await Note.load(htmlNote.id);
expect(htmlNote.deleted_time).toBe(0);
expect(refreshedNote.deleted_time).not.toBe(0);
});
it('should recreate a new note that is a clone of the original', async () => {
let noteConvertedToMarkdownId = '';
const dispatchFn = jest.fn()
.mockImplementationOnce(() => {})
.mockImplementationOnce(action => {
noteConvertedToMarkdownId = action.id;
});
const folder = await Folder.save({ title: 'test_folder' });
const htmlNoteProperties = {
title: 'test',
body: '<p>Hello</p>',
parent_id: folder.id,
markup_language: MarkupLanguage.Html,
author: 'test-author',
is_todo: 1,
todo_completed: 1,
};
const htmlNote = await Note.save(htmlNoteProperties);
state.selectedNoteIds = [htmlNote.id];
await convertHtmlToMarkdown.runtime().execute({ state, dispatch: dispatchFn });
expect(dispatchFn).toHaveBeenCalledTimes(2);
expect(noteConvertedToMarkdownId).not.toBe('');
const markdownNote = await Note.load(noteConvertedToMarkdownId);
const fields: (keyof NoteEntity)[] = ['parent_id', 'title', 'author', 'is_todo', 'todo_completed'];
for (const field of fields) {
expect(htmlNote[field]).toEqual(markdownNote[field]);
}
});
it('should generate action to trigger notification', async () => {
let originalHtmlNoteId = '';
let actionType = '';
const dispatchFn = jest.fn()
.mockImplementationOnce(action => {
originalHtmlNoteId = action.value;
actionType = action.type;
})
.mockImplementationOnce(() => {});
const folder = await Folder.save({ title: 'test_folder' });
const htmlNoteProperties = {
title: 'test',
body: '<p>Hello</p>',
parent_id: folder.id,
markup_language: MarkupLanguage.Html,
author: 'test-author',
is_todo: 1,
todo_completed: 1,
};
const htmlNote = await Note.save(htmlNoteProperties);
state.selectedNoteIds = [htmlNote.id];
await convertHtmlToMarkdown.runtime().execute({ state, dispatch: dispatchFn });
expect(dispatchFn).toHaveBeenCalledTimes(2);
expect(originalHtmlNoteId).toBe(htmlNote.id);
expect(actionType).toBe('NOTE_HTML_TO_MARKDOWN_DONE');
});
});

View File

@@ -0,0 +1,52 @@
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,4 +1,5 @@
// 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';
@@ -24,6 +25,7 @@ import * as toggleSafeMode from './toggleSafeMode';
import * as toggleTabMovesFocus from './toggleTabMovesFocus';
const index: any[] = [
convertNoteToMarkdown,
copyDevCommand,
copyToClipboard,
editProfileConfig,

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 { createAppDefaultWindowState } from '../app.reducer';
import { AppState, 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(),
...createAppDefaultWindowState(context.state as AppState),
noteVisiblePanes: Setting.value('noteVisiblePanes'),
editorCodeView: Setting.value('editor.codeView'),
},

View File

@@ -225,7 +225,7 @@ const Button = React.forwardRef(({
animation={iconAnimation}
mr={iconOnly ? '0' : '6px'}
color={color}
className={iconName}
className={`${iconName} icon`}
role='img'
/>;
}

View File

@@ -8,6 +8,7 @@ import { PluginManifest } from '@joplin/lib/services/plugins/utils/types';
import bridge from '../../../../services/bridge';
import { ItemEvent, PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
import PluginService from '@joplin/lib/services/plugins/PluginService';
import getPluginHelpUrl from '@joplin/lib/services/plugins/utils/getPluginHelpUrl';
export enum InstallState {
NotInstalled = 1,
@@ -150,8 +151,7 @@ export default function(props: Props) {
const onNameClick = useCallback(() => {
const manifest = item.manifest;
if (!manifest.homepage_url) return;
void bridge().openExternal(manifest.homepage_url);
void bridge().openExternal(getPluginHelpUrl(manifest.id));
}, [item]);
const onRecommendedClick = useCallback(() => {

View File

@@ -0,0 +1,28 @@
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

@@ -1,4 +1,4 @@
import { useMemo, useRef, useState } from 'react';
import { useMemo, useRef, useState, useCallback } from 'react';
interface Props {
width: number;
@@ -9,40 +9,62 @@ interface Props {
const fontSizeCache_: Record<string, number> = {};
export default (props: Props) => {
const containerRef = useRef(null);
const containerRef = useRef<HTMLDivElement>(null);
const [containerReady, setContainerReady] = useState(false);
const refCallback = useCallback((el: HTMLDivElement | null) => {
if (el && !containerRef.current) {
containerRef.current = el;
requestAnimationFrame(() => {
setContainerReady(true);
});
}
}, []);
const fontSize = useMemo(() => {
if (!containerReady) return props.height;
if (!containerReady || !containerRef.current) {
return Math.min(props.height * 0.7, 14);
}
const cacheKey = [props.width, props.height, props.emoji].join('-');
if (fontSizeCache_[cacheKey]) {
return fontSizeCache_[cacheKey];
}
// Set the emoji font size so that it fits within the specified width
// and height. In fact, currently it only looks at the height.
let spanFontSize = props.height;
const span = document.createElement('span');
span.innerText = props.emoji;
span.style.fontSize = `${spanFontSize}px`;
span.style.visibility = 'hidden';
span.style.position = 'absolute';
span.style.whiteSpace = 'nowrap';
containerRef.current.appendChild(span);
let rect = span.getBoundingClientRect();
while (rect.height > props.height) {
spanFontSize -= .5;
while ((rect.height > props.height || rect.width > props.width) && spanFontSize > 1) {
spanFontSize -= 0.5;
span.style.fontSize = `${spanFontSize}px`;
rect = span.getBoundingClientRect();
}
span.remove();
fontSizeCache_[cacheKey] = spanFontSize;
return spanFontSize;
}, [props.width, props.height, props.emoji, containerReady, containerRef]);
}, [props.width, props.height, props.emoji, containerReady]);
return <div className="emoji-box" ref={el => { containerRef.current = el; setContainerReady(true); }} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: props.width, height: props.height, fontSize }}>{props.emoji}</div>;
return <div
ref={refCallback}
style={{
width: props.width,
height: props.height,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
fontSize,
}}
>
{props.emoji}
</div>;
};

View File

@@ -15,7 +15,7 @@ import { connect } from 'react-redux';
import { AppState } from '../../app.reducer';
import Setting from '@joplin/lib/models/Setting';
import CommandService from '@joplin/lib/services/CommandService';
import { PublicPrivateKeyPair } from '@joplin/lib/services/e2ee/ppk';
import { PublicPrivateKeyPair } from '@joplin/lib/services/e2ee/ppk/ppk';
import ToggleAdvancedSettingsButton from '../ConfigScreen/controls/ToggleAdvancedSettingsButton';
import MacOSMissingPasswordHelpLink from '../ConfigScreen/controls/MissingPasswordHelpLink';

View File

@@ -38,12 +38,14 @@ 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;
@@ -84,6 +86,7 @@ interface Props {
showInvalidJoplinCloudCredential: boolean;
toast: Toast;
shouldSwitchToAppleSiliconVersion: boolean;
noteHtmlToMarkdownDone: string;
}
interface ShareFolderDialogOptions {
@@ -797,6 +800,10 @@ 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}
@@ -853,6 +860,7 @@ const mapStateToProps = (state: AppState) => {
showInvalidJoplinCloudCredential: state.settings['sync.target'] === 10 && state.mustAuthenticate,
toast: state.toast,
shouldSwitchToAppleSiliconVersion: shim.isAppleSilicon() && process.arch !== 'arm64',
noteHtmlToMarkdownDone: state.noteHtmlToMarkdownDone,
};
};

View File

@@ -803,6 +803,7 @@ function useMenu(props: Props) {
menuItemDic.toggleNoteList,
menuItemDic.toggleVisiblePanes,
menuItemDic.toggleEditorPlugin,
menuItemDic.toggleEditors,
{
label: _('Layout button sequence'),
submenu: layoutButtonSequenceMenuItems,
@@ -906,6 +907,7 @@ function useMenu(props: Props) {
separator(),
menuItemDic.setTags,
menuItemDic.showShareNoteDialog,
menuItemDic.convertNoteToMarkdown,
separator(),
menuItemDic.showNoteProperties,
menuItemDic.showNoteContentProperties,

View File

@@ -67,6 +67,11 @@ import 'codemirror/mode/diff/diff';
import 'codemirror/mode/erlang/erlang';
import 'codemirror/mode/sql/sql';
interface ExtendedWindow {
CodeMirror?: unknown;
}
declare const window: ExtendedWindow;
export interface EditorProps {
value: string;
@@ -100,6 +105,14 @@ function Editor(props: EditorProps, ref: any) {
const editorParent = useRef(null);
const lastEditTime = useRef(NaN);
useEffect(() => {
window.CodeMirror = CodeMirror;
return () => {
window.CodeMirror = undefined;
};
}, []);
// Codemirror plugins add new commands to codemirror (or change it's behavior)
// This command adds the smartListIndent function which will be bound to tab
useListIdent(CodeMirror);

View File

@@ -1,5 +1,6 @@
import { useEffect, useState } from 'react';
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import bridge from '../../../../../../services/bridge';
import { contentScriptsToCodeMirrorPlugin } from '@joplin/lib/services/plugins/utils/loadContentScripts';
import { extname } from 'path';
import shim from '@joplin/lib/shim';
@@ -7,6 +8,18 @@ import uuid from '@joplin/lib/uuid';
import { reg } from '@joplin/lib/registry';
const addPluginDependency = (path: string) => {
const id = `content-script-${encodeURIComponent(path)}`;
if (document.getElementById(id)) {
return;
}
const element = document.createElement('script');
element.setAttribute('id', id);
element.setAttribute('src', path);
document.head.appendChild(element);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export default function useExternalPlugins(CodeMirror: any, plugins: PluginStates) {
const [options, setOptions] = useState({});
@@ -23,7 +36,14 @@ export default function useExternalPlugins(CodeMirror: any, plugins: PluginState
if (mod.codeMirrorResources) {
for (const asset of mod.codeMirrorResources) {
try {
require(`codemirror/${asset}`);
let assetPath = shim.fsDriver().resolveRelativePathWithinDir(`${bridge().vendorDir()}/lib/codemirror/`, asset);
// Compatibility with old versions of Joplin, where the file extension was automatically added by require().
if (extname(assetPath) === '') {
assetPath += '.js';
}
addPluginDependency(assetPath);
} catch (error) {
error.message = `${asset} is not a valid CodeMirror asset, keymap or mode. You can find a list of valid assets here: https://codemirror.net/doc/manual.html#addons`;
throw error;

View File

@@ -30,6 +30,8 @@ import useEditorSearchHandler from '../utils/useEditorSearchHandler';
import CommandService from '@joplin/lib/services/CommandService';
import useRefocusOnVisiblePaneChange from './utils/useRefocusOnVisiblePaneChange';
import { WindowIdContext } from '../../../../NewWindowOrIFrame';
import eventManager, { EventName, ResourceChangeEvent } from '@joplin/lib/eventManager';
import useSyncEditorValue from './utils/useSyncEditorValue';
const logger = Logger.create('CodeMirror6');
const logDebug = (message: string) => logger.debug(message);
@@ -166,9 +168,8 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
},
scrollTo: (options: ScrollOptions) => {
if (options.type === ScrollOptionTypes.Hash) {
if (!webviewRef.current) return;
const hash: string = options.value;
webviewRef.current.send('scrollToHash', hash);
webviewRef.current?.send('scrollToHash', hash);
editorRef.current.jumpToHash(hash);
} else if (options.type === ScrollOptionTypes.Percent) {
const percent = options.value as number;
@@ -272,6 +273,17 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
props.noteId, props.useCustomPdfViewer,
]);
useEffect(() => {
const listener = (event: ResourceChangeEvent) => {
editorRef.current?.onResourceChanged(event.id);
};
eventManager.on(EventName.ResourceChange, listener);
return () => {
eventManager.off(EventName.ResourceChange, listener);
};
}, [props.resourceInfos]);
useEffect(() => {
if (!webviewReady) return;
@@ -330,6 +342,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
} else if (event.kind === EditorEventType.Change) {
codeMirror_change(event.value);
} else if (event.kind === EditorEventType.SelectionRangeChange) {
props.onCursorMotion({ markdown: event.from });
setSelectionRange({ from: event.from, to: event.to });
} else if (event.kind === EditorEventType.UpdateSearchDialog) {
if (lastSearchState.current?.searchText !== event.searchState.searchText) {
@@ -340,8 +353,10 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
props.setShowLocalSearch(event.searchState.dialogVisible);
}
lastSearchState.current = event.searchState;
} else if (event.kind === EditorEventType.FollowLink) {
void CommandService.instance().execute('openItem', event.link);
}
}, [editor_scroll, codeMirror_change, props.setLocalSearch, props.setShowLocalSearch]);
}, [editor_scroll, codeMirror_change, props.setLocalSearch, props.setShowLocalSearch, props.onCursorMotion]);
const onSelectPastBeginning = useCallback(() => {
void CommandService.instance().execute('focusElement', 'noteTitle');
@@ -362,6 +377,9 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
readOnly: props.disabled,
markdownMarkEnabled: Setting.value('markdown.plugin.mark'),
katexEnabled: Setting.value('markdown.plugin.katex'),
inlineRenderingEnabled: Setting.value('editor.inlineRendering'),
imageRenderingEnabled: Setting.value('editor.imageRendering'),
highlightActiveLine: Setting.value('editor.highlightActiveLine'),
themeData: {
...styles.globalTheme,
marginLeft: 0,
@@ -383,15 +401,17 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
props.tabMovesFocus,
]);
// Update the editor's value
useEffect(() => {
// Include the noteId in the update props to give plugins access
// to the current note ID.
const updateProps = { noteId: props.noteId };
if (editorRef.current?.updateBody(props.content, updateProps)) {
editorRef.current?.clearHistory();
}
}, [props.content, props.noteId]);
const initialCursorLocationRef = useRef(0);
initialCursorLocationRef.current = props.initialCursorLocation.markdown ?? 0;
useSyncEditorValue({
content: props.content,
visiblePanes: props.visiblePanes,
onMessage: props.onMessage,
editorRef,
noteId: props.noteId,
initialCursorLocationRef,
});
const renderEditor = () => {
return (
@@ -399,6 +419,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
<Editor
style={styles.editor}
initialText={props.content}
initialSelectionRef={initialCursorLocationRef}
initialNoteId={props.noteId}
ref={editorRef}
settings={editorSettings}
@@ -410,6 +431,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
onSelectPastBeginning={onSelectPastBeginning}
externalSearch={props.searchMarkers}
useLocalSearch={props.useLocalSearch}
onLocalize={_}
/>
</div>
);

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { ForwardedRef } from 'react';
import { ForwardedRef, RefObject } from 'react';
import { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react';
import { EditorProps, LogMessageCallback, OnEventCallback, ContentScriptData } from '@joplin/editor/types';
import createEditor from '@joplin/editor/CodeMirror/createEditor';
@@ -15,10 +15,15 @@ import useEditorSearch from '../utils/useEditorSearchExtension';
import CommandService from '@joplin/lib/services/CommandService';
import { SearchMarkers } from '../../../utils/useSearchMarkers';
import localisation from './utils/localisation';
import Resource from '@joplin/lib/models/Resource';
import { parseResourceUrl } from '@joplin/lib/urlUtils';
import { resourceFilename } from '@joplin/lib/models/utils/resourceUtils';
import getResourceBaseUrl from '../../../utils/getResourceBaseUrl';
interface Props extends EditorProps {
style: React.CSSProperties;
pluginStates: PluginStates;
initialSelectionRef: RefObject<number>;
onEditorPaste: (event: Event)=> void;
externalSearch: SearchMarkers;
@@ -104,7 +109,16 @@ const Editor = (props: Props, ref: ForwardedRef<CodeMirrorControl>) => {
onLogMessage: message => onLogMessageRef.current(message),
};
const editor = createEditor(editorContainerRef.current, editorProps);
const editor = createEditor(editorContainerRef.current, {
...editorProps,
resolveImageSrc: async (src, reloadCounter) => {
const url = parseResourceUrl(src);
if (!url.itemId) return null;
const item = await Resource.load(url.itemId);
if (!item) return null;
return `${getResourceBaseUrl()}/${resourceFilename(item)}${reloadCounter ? `?r=${reloadCounter}` : ''}`;
},
});
editor.addStyles({
'.cm-scroller': { overflow: 'auto' },
'&.CodeMirror': {
@@ -114,6 +128,9 @@ const Editor = (props: Props, ref: ForwardedRef<CodeMirrorControl>) => {
direction: 'unset',
},
});
const cursor = props.initialSelectionRef.current;
editor.select(cursor, cursor);
setEditor(editor);
return () => {

View File

@@ -0,0 +1,50 @@
import { useEffect, useRef, RefObject } from 'react';
import { OnMessage } from '../../../../utils/types';
import CodeMirrorControl from '@joplin/editor/CodeMirror/CodeMirrorControl';
interface Props {
content: string;
visiblePanes: string[];
onMessage: OnMessage;
editorRef: RefObject<CodeMirrorControl>;
noteId: string;
initialCursorLocationRef: RefObject<number>;
}
// Updates the editor's value as necessary
const useSyncEditorValue = ({ content, visiblePanes, onMessage, editorRef, noteId, initialCursorLocationRef }: Props) => {
const visiblePanesRef = useRef(visiblePanes);
visiblePanesRef.current = visiblePanes;
const onMessageRef = useRef(onMessage);
onMessageRef.current = onMessage;
const lastNoteIdRef = useRef(noteId);
useEffect(() => {
// Include the noteId in the update props to give plugins access
// to the current note ID.
const updateProps = { noteId: noteId };
if (editorRef.current?.updateBody(content, updateProps)) {
editorRef.current?.clearHistory();
// Only reset the cursor location when switching notes. If, for example,
// the note is updated from a secondary window, the cursor location shouldn't
// reset.
const noteChanged = lastNoteIdRef.current !== noteId;
if (noteChanged) {
const cursorLocation = initialCursorLocationRef.current;
editorRef.current?.select(cursorLocation, cursorLocation);
}
lastNoteIdRef.current = noteId;
// If the viewer isn't visible, the content should be considered rendered
// after the editor has finished updating:
if (!visiblePanesRef.current.includes('viewer')) {
onMessageRef.current({ channel: 'noteRenderComplete' });
}
}
}, [content, noteId, editorRef, initialCursorLocationRef]);
};
export default useSyncEditorValue;

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