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

Compare commits

..

225 Commits

Author SHA1 Message Date
Laurent Cozic
fac9ea3b42 Android 3.0.5 2024-06-19 16:28:45 +01:00
Laurent Cozic
45f8e27d6a Desktop release v3.0.10 2024-06-19 12:38:09 +01:00
Laurent Cozic
c8a478d970 Update translations 2024-06-19 12:37:57 +01:00
pedr
75dfb0af5f Mobile: Fixes #10252 Not able to change notebook when using 'New Note' quick action (#10588) 2024-06-19 12:33:22 +01:00
Mohammad Ashouri
5e592a3096 All: Update farsi/persian translation fa.po (#10634) 2024-06-19 11:00:31 +01:00
Laurent Cozic
84e46ad874 Updating farsi/persian translation (by mimeyn) 2024-06-19 10:59:51 +01:00
XPhyro
0ec917bb96 All: Don't render empty title page for Fountain (#10631) 2024-06-19 10:55:05 +01:00
Henry Heino
818f9f58d1 Desktop: Fixes #10061: Fix paste adds newlines in the Rich Text Editor when certain plugins are enabled (#10635) 2024-06-19 10:54:34 +01:00
renovate[bot]
e1abe0b4cb Update contributor-assistant/github-action action to v2.3.2 (#10633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-18 10:46:09 +01:00
Henry Heino
c972ce223e Mobile: Fixes #10593: Fix plugin list not cached in config screen (#10599)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2024-06-18 10:02:42 +01:00
Henry Heino
d9dadf28cb Mobile: Resolves #10594: Move mobile plugin setting tabs under a separate section (#10600) 2024-06-18 10:02:11 +01:00
Henry Heino
1fb392ff4e Mobile: Fix cmd-i no longer italicizes text (#10604) 2024-06-18 10:02:01 +01:00
pedr
affa620983 Desktop: Fixes: #10030: Prevent application from crashing when the syncInfoCache is corrupted (#10546) 2024-06-18 10:01:35 +01:00
Henry Heino
ed31d8202b Mobile: Fixes #10589: Fix selected note changes on moving to a different folder (#10630) 2024-06-18 09:59:08 +01:00
renovate[bot]
573ea6051c Update dependency @react-native-community/netinfo to v11.3.1 (#10632)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 23:20:07 +01:00
renovate[bot]
f1ec54532f Update dependency jsdom to v23 (#10628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:25:40 +01:00
renovate[bot]
5eb96d71e1 Update dependency sass to v1.71.0 (#10627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:24:56 +01:00
renovate[bot]
73251bac4a Update dependency react-native-webview to v13.8.1 (#10626)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:24:50 +01:00
renovate[bot]
f40a0da195 Update dependency css-loader to v6.10.0 (#10625)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:24:34 +01:00
Laurent Cozic
8dc1ab2cc5 Update renovate.json5 2024-06-17 21:23:55 +01:00
renovate[bot]
1b46c9f5e7 Update dependency chokidar to v3.6.0 (#10623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:23:07 +01:00
renovate[bot]
483ab55a36 Update dependency @react-native-community/netinfo to v11.3.0 (#10622)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:22:56 +01:00
renovate[bot]
502002f9f6 Update dependency style-to-js to v1.1.11 (#10619)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:22:16 +01:00
renovate[bot]
8d8014511f Update dependency turndown to v7.1.3 (#10620)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:22:09 +01:00
renovate[bot]
28569e652e Update dependency react-native-image-picker to v7.1.1 (#10618)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:21:54 +01:00
renovate[bot]
9acf36d802 Update dependency nodemailer to v6.9.12 (#10617)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:21:45 +01:00
renovate[bot]
06d26767ed Update dependency koa to v2.15.1 (#10615)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:21:26 +01:00
renovate[bot]
88858d4413 Update dependency follow-redirects to v1.15.6 (#10614)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 21:21:13 +01:00
github-actions[bot]
27309427a1 @XPhyro has signed the CLA in laurent22/joplin#10631 2024-06-17 19:50:09 +00:00
renovate[bot]
e83a18a907 Update dependency @types/node to v18.19.26 (#10613)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 14:25:46 +00:00
ERYpTION
9bd8b11f67 Update da_DK.po (#10606) 2024-06-17 14:50:34 +01:00
renovate[bot]
3a14c7ce2d Update dependency @types/node to v18.19.25 (#10610)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 09:13:03 +01:00
github-actions[bot]
fe4c9a2401 @kohi9noor has signed the CLA in laurent22/joplin#10607 2024-06-16 08:42:17 +00:00
Arda Kılıçdağı
d2fb19cf6d All: Translation: Update tr_TR.po (#10603) 2024-06-15 14:35:15 -04:00
Laurent Cozic
1f8e3fb620 Update translations 2024-06-15 10:17:54 +01:00
Laurent Cozic
8bbe1d30b4 Update French translation 2024-06-15 10:16:16 +01:00
Laurent Cozic
ec92f716de Chore: Removed unncessary string 2024-06-15 10:15:22 +01:00
Laurent Cozic
ab819d9210 Update translations 2024-06-15 10:06:44 +01:00
Henry Heino
e465b45d6e Mobile: Resolves #10592: Make mobile plugin settings screen UI closer to desktop (#10598) 2024-06-15 10:00:21 +01:00
tiberiusteng
a4a4170d49 Mobile: Resolves #8639: implement callback url (#9803)
Co-authored-by: Tib Teng <661892+tiberiusteng@users.noreply.github.com>
2024-06-15 09:58:23 +01:00
Henry Heino
1dcf528443 Chore: Refactor editor package: Move functions in editorStateUtils into separate files (#10591) 2024-06-14 19:40:07 +01:00
Henry Heino
8cf4ef88b5 Desktop: Fixes #10586: Don't re-order the note list when in search (#10587) 2024-06-14 19:39:26 +01:00
Henry Heino
bf634270be Mobile: Mark plugin support as in beta (#10585) 2024-06-14 19:38:50 +01:00
Henry Heino
56437d3e1b Mobile: Don't show an "expand" arrow by "Installed plugins" when no plugins are installed (#10583)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2024-06-14 19:38:16 +01:00
Henry Heino
d095ab2be7 All: Fixes #10581: English: Use the plural form of a localization for negative and zero items (#10582)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2024-06-14 19:37:26 +01:00
Henry Heino
4751b4dd74 Mobile: Plugin settings screen: Fix plugin states not set correctly when installing multiple plugins at once (#10580)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2024-06-14 19:36:44 +01:00
Henry Heino
ce22d8238c Mobile: Plugin settings: Fix plugins without settings can't be disabled without reinstall (#10579)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2024-06-14 19:36:26 +01:00
pedr
9e2b9e5b8d Desktop: Fixes error when Joplin Cloud login is finished before the settings are saved (#10575) 2024-06-14 19:31:50 +01:00
pedr
4952980e0a Desktop, Mobile: Start synchronisation just after login is complete (#10574) 2024-06-14 14:24:35 +01:00
Joplin Bot
59989d2735 Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-06-13 12:22:09 +00:00
Laurent Cozic
eb7f2855b0 Chore: Trying to fix Android build on CI by using debug keys 2024-06-13 09:01:45 +01:00
Laurent Cozic
a0e3e4fefb Android 3.0.4 2024-06-12 21:41:20 +01:00
Laurent Cozic
de9661448b Chore: Fix Android build for RN 0.74.1 (#10577) 2024-06-12 21:33:44 +01:00
Laurent Cozic
562aabafa1 iOS 13.0.2 2024-06-12 21:29:29 +01:00
Laurent Cozic
a659e45a68 lock files 2024-06-12 21:20:59 +01:00
Laurent Cozic
8e44a15c8d CI: Assemble Android release instead of debug (#10576) 2024-06-12 21:16:18 +01:00
Laurent Cozic
a086358824 Desktop release v3.0.9 2024-06-12 18:31:57 +01:00
pedr
889c395818 Desktop, Mobile: Add Joplin Cloud account information to configuration screen (#10553) 2024-06-12 15:14:32 +01:00
Henry Heino
7d0cc675aa Desktop: Fixes #10236: Fix note disappears while editing during search (#10568) 2024-06-12 15:11:53 +01:00
pedr
73d3f92ae2 Desktop, Mobile: Add button on Synchronization to Joplin Cloud login screen (#10569) 2024-06-12 15:11:30 +01:00
Henry Heino
f5ceb4064c Mobile,Desktop: Upgrade KaTeX to v0.16.10 (#10570) 2024-06-12 15:10:19 +01:00
pedr
53d7bc86ca Desktop, Mobile: Hide links to login after process is successful (#10571) 2024-06-12 15:09:52 +01:00
renovate[bot]
4495fc9a03 Update dependency @types/node to v18.19.24 (#10572)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-12 15:08:38 +01:00
Henry Heino
7ee5cad21e Chore: Mobile: Increase test timeout to try to fix CI failure (#10552) 2024-06-11 07:49:57 +01:00
Henry Heino
940739ce12 Desktop: Fixes #10199: Rich text editor: Include "ctrl-click to open" in link tooltips (#10547) 2024-06-11 07:49:28 +01:00
Henry Heino
5730c1efcd Mobile: Settings screen: Show touch feedback when pressing a tab (#10544) 2024-06-11 07:41:50 +01:00
Henry Heino
b17f28ce94 Desktop: Fixes #10538: Fix wrong text selected when adding a link in the beta editor (#10542) 2024-06-11 07:41:41 +01:00
Henry Heino
629e968878 Windows: Fixes #10525: Prevent notes with titles that differ only in case from being overwritten when exporting (#10541) 2024-06-11 07:41:23 +01:00
Henry Heino
47a924ff4e Mobile: Fix plugins not reloaded when the plugin runner reloads (#10540) 2024-06-11 07:40:36 +01:00
Henry Heino
c511fb59c7 Desktop: Fixes #10551: Watch resources for changes when opened from the Rich Text Editor (#10554) 2024-06-10 22:31:38 +01:00
Henry Heino
80aeff6ecd Mobile: Dismiss dialogs on background tap (#10557) 2024-06-10 22:31:06 +01:00
Henry Heino
97d15bb26a Desktop: Rich Text Editor: Allow toggling bulleted and numbered lists from the command palette (#10559) 2024-06-10 22:26:14 +01:00
renovate[bot]
99b36cbff1 Update dependency @types/node to v18.19.23 (#10555)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-10 14:11:06 +00:00
Helmut K. C. Tessarek
74c3d2c9fb Update translations 2024-06-07 14:27:47 -04:00
Helmut K. C. Tessarek
df8c7fd31c All: Translation: Update ko.po 2024-06-07 14:16:43 -04:00
renovate[bot]
3a780b9490 Update dependency @types/node to v18.19.22 (#10543)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-06 11:44:32 +00:00
github-actions[bot]
97ddb67f68 @tushar-coin has signed the CLA in laurent22/joplin#10539 2024-06-04 18:39:24 +00:00
Joplin Bot
f50a27985b Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-06-04 12:21:58 +00:00
Laurent Cozic
061a9d5bff Doc: Add sponsor 2024-06-04 11:22:27 +01:00
Henry Heino
06f42e8246 Mobile: Implement plugin screen redesign (#10465) 2024-06-04 09:57:52 +01:00
pedr
19f0b667b1 Server: Fixes #10118: Missing record validation before trying to add item to user (#10471) 2024-06-04 09:55:57 +01:00
Henry Heino
ac7165461a Chore: AsyncActionQueue: Support changing which tasks can be skipped (#10506) 2024-06-04 09:54:06 +01:00
Henry Heino
efb48e6145 Mobile: Show WebView version in settings (#10518) 2024-06-04 09:53:49 +01:00
Henry Heino
f94c16b22e Mobile: Plugin API: Implement the newNote command (#10524) 2024-06-04 09:52:52 +01:00
Henry Heino
0938dc9d52 Desktop: Fix importing completed tasks (#10528) 2024-06-04 09:52:34 +01:00
Henry Heino
e049698012 Desktop: Beta editor: Fix crash when switching between notes that use CRLF line endings (#10531) 2024-06-04 09:52:09 +01:00
Henry Heino
c9fb06fd0c Desktop: Fixes #10416: Work around checkbox toggle broken when editor is hidden (#10534) 2024-06-04 09:51:59 +01:00
Henry Heino
96850b7b98 Chore: Migrate mime-utils.js to TypeScript (#10536) 2024-06-04 09:50:18 +01:00
Laurent Cozic
32710e44c3 Desktop: Significantly reduces size of exported HTML files in most cases 2024-06-03 23:50:51 +01:00
Joplin Bot
32e16f6e51 Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-06-01 00:43:45 +00:00
Henry Heino
f938d5f489 Chore: Markdown + fontmatter import and export: Extract frontMatter logic into a separate file (#10508)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2024-05-30 08:40:52 +01:00
Henry Heino
99b840da34 Desktop: Fixes #10284: Sort the note list soon after changing a note's title (#10512) 2024-05-30 08:40:32 +01:00
Henry Heino
55c222c577 Desktop: Fixes #10514: Fix focusing the note list doesn't work when the selected note is off screen (#10515) 2024-05-30 08:38:36 +01:00
Henry Heino
418a6e455f Desktop: Fixes #10466: Fix tables missing source map attributes (#10516) 2024-05-30 08:34:52 +01:00
Henry Heino
789d19b18c Chore: Remove unused NoteTypeToggle event (#10521) 2024-05-30 08:31:54 +01:00
renovate[bot]
59b26f2c63 Update dependency @types/node to v18.19.21 (#10517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-30 02:48:06 +00:00
renovate[bot]
f1eeeabdc5 Update dependency @types/node to v18.19.20 (#10513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-29 02:58:46 +00:00
Laurent Cozic
d2a33b006b Desktop: Fixes #10224: Images from behind a login cannot be pasted in RTE 2024-05-28 14:33:23 +01:00
Laurent Cozic
2386f583e8 Mobile: Fixes #10237: Automatically set focus on title or body when creating a new note 2024-05-28 14:18:35 +01:00
Laurent Cozic
70c5448402 lock files 2024-05-28 14:18:33 +01:00
Henry Heino
4e3326b12f Desktop: Fixes #10230: Fix new note and to-do buttons greyed when initial selection is "all notes" or a tag (#10434) 2024-05-28 13:43:33 +01:00
Henry Heino
34092d8491 Desktop: Fixes #10381: Fix plugin settings stored in settings.json are lost on startup (#10458) 2024-05-28 13:42:52 +01:00
Henry Heino
b8caf08fac Desktop: Re-render note when resources are changed (#10459) 2024-05-28 11:30:56 +01:00
Henry Heino
b0d0e641ea Docs: Resolves #10341: Document the drawing option (#10436) 2024-05-28 11:30:22 +01:00
Laurent Cozic
3a1de4e941 Update renovate.json5 2024-05-28 11:28:56 +01:00
Henry Heino
97274c95a5 Chore: Strengthen eventManager types (#10505) 2024-05-28 11:24:20 +01:00
renovate[bot]
300d0e3ca5 Update dependency @types/node to v18.19.19 (#10509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-28 11:13:24 +01:00
Henry Heino
50d08cd178 Chore: Fix spelling of react-native in renovate.json5 (#10502) 2024-05-27 17:16:00 +01:00
Henry Heino
28f3d53b3b Mobile: Improve dialog styling on large and notched screens (#10470) 2024-05-27 09:05:15 +01:00
Henry Heino
768e59938c Chore: Mobile: Fix warnings in NoteExportButton tests (#10472) 2024-05-27 09:01:32 +01:00
adanub
6c7948a087 Doc: Removed outdated RTE info (#10479)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2024-05-27 09:01:18 +01:00
Laurent Cozic
cc2b442519 Update renovate.json5 2024-05-27 08:59:18 +01:00
renovate[bot]
fa285a9404 Update dependency ldapts to v7.0.9 (#10484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:58:34 +01:00
renovate[bot]
84faa7229d Update dependency lint-staged to v15.2.2 (#10485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:58:28 +01:00
renovate[bot]
254747ee78 Update dependency nodemailer to v6.9.10 (#10486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:58:04 +01:00
renovate[bot]
ef167051d6 Update dependency react-native-device-info to v10.12.1 (#10487)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:57:57 +01:00
renovate[bot]
1ccbdc2341 Update dependency react-native-document-picker to v9.1.1 (#10488)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:57:50 +01:00
renovate[bot]
14747b79cd Update dependency terminal-kit to v3.0.2 (#10489)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:57:32 +01:00
renovate[bot]
111385f1ef Update dependency tesseract.js to v5.0.5 (#10490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:57:21 +01:00
renovate[bot]
f36d395a84 Update react monorepo (#10491)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:56:49 +01:00
renovate[bot]
5d997084f7 Update dependency @types/koa to v2.14.0 (#10493)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:56:35 +01:00
renovate[bot]
132548181f Update dependency css-loader to v6.9.1 (#10494)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:56:26 +01:00
renovate[bot]
452c71e8cb Update dependency js-sha512 to v0.9.0 (#10495)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:56:05 +01:00
renovate[bot]
f7ac95f850 Update dependency react-native-paper to v5.12.3 (#10497)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:55:44 +01:00
Laurent Cozic
33286efe9a Update renovate.json5 2024-05-27 08:55:29 +01:00
renovate[bot]
f21a93febe Update dependency sass to v1.70.0 (#10499)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-27 08:54:18 +01:00
Henry Heino
f817c47dc0 Desktop,Mobile: Update Mermaid to v10.9.1 (#10475) 2024-05-27 08:53:57 +01:00
qx100
9ccca16df7 All: Translation: Update zh_CN.po (#10500) 2024-05-27 03:51:00 -04:00
Jonatan
114f5695b7 All: Translation: Update sv.po (#10478) 2024-05-27 03:49:46 -04:00
Laurent Cozic
916fa39012 Server: Print a heartbeat message to log once per minute 2024-05-26 18:27:41 +01:00
github-actions[bot]
db77a51129 @adanub has signed the CLA in laurent22/joplin#10479 2024-05-26 10:19:56 +00:00
Henry Heino
b09d6e8568 Chore: Refactor: Mobile: Rename CustomButton to IconButton (#10473) 2024-05-25 14:41:27 +01:00
pedr
3bf9438a59 Desktop: Resolves #9959: Display description for settings field in the plugin customization screen (#10469) 2024-05-24 22:46:36 +01:00
renovate[bot]
554894e910 Update dependency @types/node to v18.19.18 (#10467)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-24 19:03:14 +00:00
Sunny Thakurwar
51f1e0202f All: Translation: Update da_DK.po (#10463) 2024-05-24 15:01:12 -04:00
github-actions[bot]
8b7758442b @sunny-thakurwar has signed the CLA in laurent22/joplin#10445 2024-05-23 20:04:06 +00:00
Joplin Bot
63bf7694f0 Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-05-23 06:18:52 +00:00
Joplin Bot
df3aaa7dfd Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-05-22 18:19:03 +00:00
Laurent Cozic
826006ce8b Desktop release v3.0.8 2024-05-22 15:00:08 +01:00
Henry Heino
1e085ee619 Mobile: Update js-draw to version 1.20.2 (#10438) 2024-05-22 14:57:53 +01:00
Henry Heino
efb753e229 Desktop: Fixes #8960: Fix cursor jumps to the top of the note editor on sync (#10456) 2024-05-22 14:57:17 +01:00
Henry Heino
faf332a0e8 Chore: Fix CI build for x86 MacOS (#10452) 2024-05-21 14:28:51 +01:00
Laurent Cozic
83308337b5 Desktop release v3.0.7 2024-05-21 10:17:37 +01:00
Henry Heino
73193df120 Desktop: Sidebar: Remove redundant focus indicator (#10443) 2024-05-21 10:14:49 +01:00
Henry Heino
2dd27cdd00 Desktop: Note attachments screen: Allow searching for attachments (#10442) 2024-05-21 10:14:39 +01:00
Henry Heino
c5e3672e9e Desktop, Mobile: Fixes #10439: Maintain cursor position when changing list indentation (#10441) 2024-05-21 10:13:37 +01:00
Henry Heino
366517999f Mobile: Upgrade to React Native 0.74.1 (#10401) 2024-05-21 10:12:20 +01:00
Laurent Cozic
8445ffaa86 Merge branch 'release-2.14' into dev 2024-05-21 10:10:29 +01:00
Laurent Cozic
2a76970461 Desktop release v2.14.21 2024-05-21 10:04:20 +01:00
Henry Heino
9fcaf5bd18 Desktop: Disable eval in pdf.js (#10450) 2024-05-21 10:00:17 +01:00
Henry Heino
652add9af2 Chore: Desktop: Fix eslint issues and strengthen types in NoteEditor.tsx (#10449) 2024-05-21 01:28:19 +01:00
Nitin
c632ea5c48 Doc: Update index.md (#10446) 2024-05-19 12:42:22 +01:00
github-actions[bot]
7ee5f68770 @nitingururajk has signed the CLA in laurent22/joplin#10446 2024-05-19 03:12:49 +00:00
pedr
1040675781 Chore: Improve logs to help debugging (#10432) 2024-05-17 09:42:16 +01:00
Laurent Cozic
24a37e0fef Tools: Add vscode settings 2024-05-16 17:28:06 +01:00
Laurent Cozic
bfe2d262a5 Tools: Add vscode settings 2024-05-16 17:21:25 +01:00
renovate[bot]
8faf5148a6 Update dependency @types/node to v18.19.17 (#10435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-16 11:58:31 +01:00
Henry Heino
27c5dd1852 Mobile: Fixes #10409: Fix accepting encrypted shared notebooks (#10429) 2024-05-16 09:54:24 +01:00
Dmitriy Q
fae51b90a7 fix russian translate (#10428) 2024-05-16 09:51:56 +01:00
pedr
ccd181851c All: Fix logger tests by adding time (#10433) 2024-05-15 15:37:31 +01:00
Laurent Cozic
cd0ff94c0c Server: Use slave database for reports 2024-05-13 14:51:19 +01:00
Laurent Cozic
e9e6d8a69c Server: Add uploaded data size to report 2024-05-13 14:37:02 +01:00
Laurent Cozic
7ad3b34ec3 Server: Added report page 2024-05-13 11:32:53 +01:00
Laurent Cozic
f39021d373 Chore: Make API note.source optional 2024-05-12 11:14:11 +01:00
Laurent Cozic
13116fec76 Server: Allow filtering users with replication 2024-05-12 10:29:12 +01:00
Henry Heino
d49b2ec0e9 Chore: Fixes #10418: Fix plugin spec page crashes documentation (#10419) 2024-05-12 10:01:24 +01:00
Henry Heino
09d088b2b5 Mobile,Desktop: Fix nonbreaking spaces and CRLF break search for adjacent words (#10417) 2024-05-12 10:01:12 +01:00
Henry Heino
3312bd27c9 Mobile: Simplify Dropbox sync workarond (#10415) 2024-05-12 10:01:02 +01:00
Liffindra Angga Zaaldian
453bdb293f Update Indonesian translations (#10422) 2024-05-12 09:58:08 +01:00
Laurent Cozic
6b0e1598ed Chore: Fixed types 2024-05-11 19:45:42 +01:00
Laurent Cozic
56f25d3094 Chore: Removed duplicated tests 2024-05-11 19:05:28 +01:00
Laurent Cozic
3e458c0028 fixed tests 2024-05-11 17:24:51 +01:00
Laurent Cozic
a747828276 Api: Add support for note.source property 2024-05-11 16:21:07 +01:00
Laurent Cozic
a90e3e04a4 Server: Add support for Postgres replication 2024-05-11 16:12:54 +01:00
renovate[bot]
487f01d2ec Update dependency @types/node to v18.19.15 (#10421)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-11 09:34:40 +01:00
Joplin Bot
36c25fdd86 Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-05-09 00:40:49 +00:00
Laurent Cozic
a9fecb31c3 iOS 12.14.8 2024-05-08 14:57:03 +01:00
Laurent Cozic
ca8fd8d7ae iOS 12.14.8 2024-05-08 14:49:45 +01:00
Laurent Cozic
fb345b1317 Merge branch 'release-2.14' of github.com:laurent22/joplin into release-2.14 2024-05-08 14:39:59 +01:00
Laurent Cozic
966fe38ae3 iOS: Fixed app for iOS 12 2024-05-08 14:39:46 +01:00
Henry Heino
3042e615ac iOS: Fixes #10396: Fix Dropbox sync for large file collections (#10411) 2024-05-08 14:25:06 +01:00
ERYpTION
fd2ae51b93 Update da_DK.po (#10413) 2024-05-08 11:37:37 +01:00
Joplin Bot
1227730393 Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-05-08 00:34:30 +00:00
Laurent Cozic
8622bd506f iOS 12.14.7 2024-05-07 22:40:42 +01:00
Laurent Cozic
5d6a39ce51 lock file 2024-05-07 22:39:55 +01:00
Henry Heino
5245c06ed3 Mobile: Fixes #10396: Fix Dropbox sync (#10400) 2024-05-07 22:38:45 +01:00
Henry Heino
3c5977346e iOS: Add Privacy manifest file (#10406) 2024-05-07 22:38:45 +01:00
Laurent Cozic
a3dc9c2721 iOS 12.14.7 2024-05-07 22:30:41 +01:00
Henry Heino
90ec1f5bc6 Chore: Fix failing Dropbox sync test (#10408) 2024-05-07 17:29:23 +01:00
Laurent Cozic
99caa014ca lock file 2024-05-07 17:23:45 +01:00
Laurent Cozic
00d0cd1cf7 Chore: Fix nan 2024-05-07 17:20:29 +01:00
Henry Heino
d6480e50d2 Mobile: Fixes #10396: Fix Dropbox sync (#10400) 2024-05-07 16:49:39 +01:00
Henry Heino
a1a06dd7d0 iOS: Add Privacy manifest file (#10406) 2024-05-07 11:00:06 +01:00
Psy-Q
95b73b5f41 Doc: Fix plural of parenthesis (#10405) 2024-05-07 10:59:06 +01:00
Fabien
cc00cdfa55 Doc: Add Scaleway to the S3 providers (#10404) 2024-05-07 10:57:35 +01:00
LightTreasure
548ba7d712 Desktop: Resolves #1752: Added capability to toggle visibility of the Menu Bar from the View menu (#10324) 2024-05-07 10:57:02 +01:00
Yurt Page
1ea0c56d7b Chore: Fastline i18n (#10402)
Signed-off-by: Yurt Page <yurtpage@gmail.com>
2024-05-07 10:56:09 +01:00
Henry Heino
f764e76f01 Mobile: Share screen: Update headings and labels for consistency with desktop (#10395) 2024-05-07 10:54:31 +01:00
Norman Rauschen
4862c2e8ea Improved German translations (#10398) 2024-05-07 10:54:12 +01:00
github-actions[bot]
cbb4d43981 @psy-q has signed the CLA in laurent22/joplin#10405 2024-05-06 18:57:12 +00:00
Laurent Cozic
87269e6bcd Tools: Fixed nan dependency to build on macOS 14 with node 22 2024-05-06 16:08:47 +01:00
github-actions[bot]
7d19d294a6 @Fabien-jrt has signed the CLA in laurent22/joplin#10404 2024-05-06 14:45:38 +00:00
github-actions[bot]
5f3ac323ff @yurtpage has signed the CLA in laurent22/joplin#10402 2024-05-06 10:43:45 +00:00
Laurent Cozic
0a766d7314 Desktop: Fixed an issue that could cause certain notes not to render when they contain an empty STYLE tag 2024-05-06 11:30:04 +01:00
github-actions[bot]
e73535ace0 @vulpivia has signed the CLA in laurent22/joplin#10398 2024-05-05 08:37:52 +00:00
ERYpTION
8e93f0975f Update da_DK.po (#10397) 2024-05-03 23:40:00 +01:00
Laurent Cozic
57c316a591 Api: Exclude deleted and conflicted notes when calling /notes 2024-05-03 16:14:04 +01:00
Laurent Cozic
f1691b7743 Update translations 2024-05-02 23:12:06 +01:00
qx100
92a025011e Update Simplified Chinese translation (#10394) 2024-05-02 22:33:55 +01:00
Henry Heino
d5fa8d0216 Mobile: Fix plugins aren't visible after switching to a new profile (#10386) 2024-05-02 17:05:25 +01:00
renovate[bot]
1f74a42dfa Update dependency @types/node to v18.19.14 (#10393)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-02 17:05:07 +01:00
Henry Heino
569b567f21 Desktop: Fixes #10382: Fix default values for plugin settings stored in settings.json not applied (#10383) 2024-05-02 15:00:12 +01:00
Henry Heino
85f890e7c5 Mobile: Plugins: Make panel opening/closing more consistent with desktop (#10385) 2024-05-02 14:59:50 +01:00
Henry Heino
4056fc2281 Mobile: Plugins: Show information page before enabling plugin support (#10348) 2024-05-02 14:58:29 +01:00
renovate[bot]
70c2f0a70a Update dependency @types/node to v18.19.12 (#10390)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-02 14:57:57 +01:00
Laurent Cozic
aac8d58372 All: Improves formatting of log statements 2024-05-01 10:36:20 +01:00
Joplin Bot
8ec233f59c Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-05-01 00:41:57 +00:00
renovate[bot]
a0dd7f58ac Update dependency @types/node to v18.19.11 (#10387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-30 17:56:48 +00:00
Laurent Cozic
443e04b369 Doc: Fixed share notebook link 2024-04-27 21:20:59 +01:00
Joplin Bot
cfd9bca4d6 Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-04-27 18:16:50 +00:00
Joplin Bot
f17157f7e2 Doc: Auto-update documentation
Auto-updated using release-website.sh
2024-04-27 12:19:52 +00:00
Laurent Cozic
18b9f5c79b Desktop release v3.0.6 2024-04-27 13:14:03 +01:00
Laurent Cozic
1b060925a4 CI: Trying to fix broken desktop release 2024-04-27 13:13:41 +01:00
Laurent Cozic
00fa618596 Desktop release v3.0.5 2024-04-27 13:00:49 +01:00
Laurent Cozic
131ec9e913 Android 3.0.3 2024-04-27 12:27:53 +01:00
481 changed files with 91861 additions and 59309 deletions

View File

@@ -242,6 +242,7 @@ packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.test.js
packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.js
packages/app-desktop/gui/MainScreen/commands/toggleEditors.js
packages/app-desktop/gui/MainScreen/commands/toggleLayoutMoveMode.js
packages/app-desktop/gui/MainScreen/commands/toggleMenuBar.js
packages/app-desktop/gui/MainScreen/commands/toggleNoteList.js
packages/app-desktop/gui/MainScreen/commands/toggleNoteType.js
packages/app-desktop/gui/MainScreen/commands/toggleNotesSortOrderField.js
@@ -290,6 +291,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/useLinkTooltips.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useWebViewApi.js
packages/app-desktop/gui/NoteEditor/NoteEditor.js
@@ -321,6 +323,8 @@ packages/app-desktop/gui/NoteEditor/utils/useMarkupToHtml.js
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
packages/app-desktop/gui/NoteEditor/utils/useNoteSearchBar.js
packages/app-desktop/gui/NoteEditor/utils/usePluginServiceRegistration.js
packages/app-desktop/gui/NoteEditor/utils/useScheduleSaveCallbacks.js
packages/app-desktop/gui/NoteEditor/utils/useScrollWhenReadyOptions.js
packages/app-desktop/gui/NoteEditor/utils/useSearchMarkers.js
packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
packages/app-desktop/gui/NoteList/NoteList2.js
@@ -452,6 +456,8 @@ packages/app-desktop/integration-tests/models/MainScreen.js
packages/app-desktop/integration-tests/models/NoteEditorScreen.js
packages/app-desktop/integration-tests/models/SettingsScreen.js
packages/app-desktop/integration-tests/models/Sidebar.js
packages/app-desktop/integration-tests/noteList.spec.js
packages/app-desktop/integration-tests/richTextEditor.spec.js
packages/app-desktop/integration-tests/sidebar.spec.js
packages/app-desktop/integration-tests/simpleBackup.spec.js
packages/app-desktop/integration-tests/util/activateMainMenuItem.js
@@ -460,6 +466,7 @@ packages/app-desktop/integration-tests/util/firstNonDevToolsWindow.js
packages/app-desktop/integration-tests/util/setFilePickerResponse.js
packages/app-desktop/integration-tests/util/setMessageBoxResponse.js
packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/playwright.config.js
packages/app-desktop/plugins/GotoAnything.js
packages/app-desktop/services/bridge.js
@@ -500,20 +507,23 @@ packages/app-desktop/utils/restartInSafeModeFromMain.test.js
packages/app-desktop/utils/restartInSafeModeFromMain.js
packages/app-mobile/PluginAssetsLoader.js
packages/app-mobile/commands/index.js
packages/app-mobile/commands/newNote.test.js
packages/app-mobile/commands/newNote.js
packages/app-mobile/commands/openItem.js
packages/app-mobile/commands/openNote.js
packages/app-mobile/commands/scrollToHash.js
packages/app-mobile/commands/util/goToNote.js
packages/app-mobile/components/ActionButton.js
packages/app-mobile/components/BackButtonDialogBox.js
packages/app-mobile/components/BetaChip.js
packages/app-mobile/components/CameraView.js
packages/app-mobile/components/CustomButton.js
packages/app-mobile/components/DismissibleDialog.js
packages/app-mobile/components/Dropdown.test.js
packages/app-mobile/components/Dropdown.js
packages/app-mobile/components/ExtendedWebView.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/Icon.js
packages/app-mobile/components/IconButton.js
packages/app-mobile/components/Modal.js
packages/app-mobile/components/ModalDialog.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
@@ -581,11 +591,14 @@ 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/TextButton.js
packages/app-mobile/components/buttons/index.js
packages/app-mobile/components/getResponsiveValue.test.js
packages/app-mobile/components/getResponsiveValue.js
packages/app-mobile/components/global-style.js
packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.js
packages/app-mobile/components/screens/ConfigScreen/FileSystemPathSelector.js
packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.js
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportDebugReportButton.js
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.js
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.test.js
@@ -598,25 +611,38 @@ packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/expo
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/makeImportExportCacheDirectory.js
packages/app-mobile/components/screens/ConfigScreen/SectionDescription.js
packages/app-mobile/components/screens/ConfigScreen/SectionHeader.js
packages/app-mobile/components/screens/ConfigScreen/SectionSelector.js
packages/app-mobile/components/screens/ConfigScreen/SectionSelector/SectionTab.js
packages/app-mobile/components/screens/ConfigScreen/SectionSelector/index.js
packages/app-mobile/components/screens/ConfigScreen/SettingComponent.js
packages/app-mobile/components/screens/ConfigScreen/SettingItem.js
packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js
packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/ActionButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginInfoButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.js
packages/app-mobile/components/screens/ConfigScreen/plugins/InstalledPluginBox.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChip.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginTitle.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/index.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.installed.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.search.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginToggle.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginUploadButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.js
packages/app-mobile/components/screens/ConfigScreen/plugins/SectionLabel.js
packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/ActionButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/InstallButton.js
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
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/useRepoApi.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/useUpdateState.js
packages/app-mobile/components/screens/ConfigScreen/types.js
packages/app-mobile/components/screens/JoplinCloudLoginScreen.js
packages/app-mobile/components/screens/LogScreen.js
@@ -657,7 +683,9 @@ packages/app-mobile/plugins/PluginRunner/dialogs/hooks/useWebViewSetup.js
packages/app-mobile/plugins/PluginRunner/types.js
packages/app-mobile/plugins/PluginRunner/utils/createOnLogHandler.js
packages/app-mobile/plugins/hooks/usePlugin.js
packages/app-mobile/plugins/loadPlugins.test.js
packages/app-mobile/plugins/loadPlugins.js
packages/app-mobile/plugins/testing/MockPluginRunner.js
packages/app-mobile/root.js
packages/app-mobile/services/AlarmServiceDriver.android.js
packages/app-mobile/services/AlarmServiceDriver.ios.js
@@ -688,6 +716,7 @@ packages/app-mobile/utils/fs-driver/tarExtract.js
packages/app-mobile/utils/fs-driver/testUtil/createFilesFromPathRecord.js
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/initializeCommandService.js
packages/app-mobile/utils/ipc/RNToWebViewMessenger.js
packages/app-mobile/utils/ipc/WebViewToRNMessenger.js
@@ -740,8 +769,9 @@ packages/editor/CodeMirror/markdown/markdownCommands.toggleList.test.js
packages/editor/CodeMirror/markdown/markdownCommands.js
packages/editor/CodeMirror/markdown/markdownMathParser.test.js
packages/editor/CodeMirror/markdown/markdownMathParser.js
packages/editor/CodeMirror/markdown/markdownReformatter.test.js
packages/editor/CodeMirror/markdown/markdownReformatter.js
packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.test.js
packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.js
packages/editor/CodeMirror/markdown/utils/stripBlockquote.js
packages/editor/CodeMirror/pluginApi/PluginLoader.js
packages/editor/CodeMirror/pluginApi/codeMirrorRequire.js
packages/editor/CodeMirror/pluginApi/customEditorCompletion.test.js
@@ -754,8 +784,22 @@ packages/editor/CodeMirror/testUtil/loadLanguages.js
packages/editor/CodeMirror/testUtil/pressReleaseKey.js
packages/editor/CodeMirror/testUtil/typeText.js
packages/editor/CodeMirror/theme.js
packages/editor/CodeMirror/util/isInSyntaxNode.js
packages/editor/CodeMirror/util/setupVim.js
packages/editor/CodeMirror/utils/formatting/RegionSpec.js
packages/editor/CodeMirror/utils/formatting/findInlineMatch.test.js
packages/editor/CodeMirror/utils/formatting/findInlineMatch.js
packages/editor/CodeMirror/utils/formatting/isIndentationEquivalent.js
packages/editor/CodeMirror/utils/formatting/tabsToSpaces.test.js
packages/editor/CodeMirror/utils/formatting/tabsToSpaces.js
packages/editor/CodeMirror/utils/formatting/toggleInlineFormatGlobally.js
packages/editor/CodeMirror/utils/formatting/toggleInlineRegionSurrounded.js
packages/editor/CodeMirror/utils/formatting/toggleInlineSelectionFormat.js
packages/editor/CodeMirror/utils/formatting/toggleRegionFormatGlobally.test.js
packages/editor/CodeMirror/utils/formatting/toggleRegionFormatGlobally.js
packages/editor/CodeMirror/utils/formatting/toggleSelectedLinesStartWith.js
packages/editor/CodeMirror/utils/formatting/types.js
packages/editor/CodeMirror/utils/growSelectionToNode.js
packages/editor/CodeMirror/utils/isInSyntaxNode.js
packages/editor/CodeMirror/utils/setupVim.js
packages/editor/SelectionFormatting.js
packages/editor/events.js
packages/editor/types.js
@@ -781,6 +825,7 @@ packages/generator-joplin/generators/app/templates/src/index.js
packages/generator-joplin/tools/updateCategories.js
packages/htmlpack/src/index.js
packages/lib/ArrayUtils.js
packages/lib/AsyncActionQueue.test.js
packages/lib/AsyncActionQueue.js
packages/lib/BaseApplication.js
packages/lib/BaseModel.js
@@ -870,6 +915,7 @@ packages/lib/markdownUtils.js
packages/lib/markdownUtils2.test.js
packages/lib/markupLanguageUtils.js
packages/lib/migrations/42.js
packages/lib/mime-utils.js
packages/lib/models/Alarm.js
packages/lib/models/BaseItem.test.js
packages/lib/models/BaseItem.js
@@ -919,6 +965,7 @@ packages/lib/ntp.js
packages/lib/onedrive-api.test.js
packages/lib/onedrive-api.js
packages/lib/path-utils.js
packages/lib/reducer.test.js
packages/lib/reducer.js
packages/lib/registry.test.js
packages/lib/registry.js
@@ -1201,10 +1248,12 @@ packages/lib/themes/solarizedLight.js
packages/lib/themes/type.js
packages/lib/time.js
packages/lib/types.js
packages/lib/urlUtils.js
packages/lib/utils/ActionLogger.test.js
packages/lib/utils/ActionLogger.js
packages/lib/utils/credentialFiles.js
packages/lib/utils/focusHandler.js
packages/lib/utils/frontMatter.js
packages/lib/utils/ipc/RemoteMessenger.test.js
packages/lib/utils/ipc/RemoteMessenger.js
packages/lib/utils/ipc/TestMessenger.js
@@ -1215,7 +1264,8 @@ packages/lib/utils/ipc/utils/mergeCallbacksAndSerializable.js
packages/lib/utils/ipc/utils/separateCallbacksFromSerializable.test.js
packages/lib/utils/ipc/utils/separateCallbacksFromSerializable.js
packages/lib/utils/ipc/utils/separateCallbacksFromSerializableArray.js
packages/lib/utils/joplinCloud.js
packages/lib/utils/joplinCloud/index.js
packages/lib/utils/joplinCloud/types.js
packages/lib/utils/processStartFlags.js
packages/lib/utils/replaceUnsupportedCharacters.test.js
packages/lib/utils/replaceUnsupportedCharacters.js
@@ -1287,6 +1337,7 @@ packages/renderer/MdToHtml/rules/mermaid.js
packages/renderer/MdToHtml/rules/sanitize_html.js
packages/renderer/MdToHtml/rules/source_map.js
packages/renderer/MdToHtml/rules/tableHorizontallyScrollable.js
packages/renderer/MdToHtml/rules/utils/defaultRule.js
packages/renderer/MdToHtml/setupLinkify.js
packages/renderer/MdToHtml/validateLinks.js
packages/renderer/assetsToHeaders.js

View File

@@ -16,7 +16,7 @@ jobs:
with:
concurrent_skipping: 'same_content_newer'
BuildAndroidDebug:
AssembleRelease:
needs: pre_job
if: github.repository == 'laurent22/joplin' && needs.pre_job.outputs.should_skip != 'true'
runs-on: ubuntu-latest
@@ -25,6 +25,11 @@ jobs:
run: |
sudo apt-get update || true
sudo apt-get install -y libsecret-1-dev
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '20'
- uses: actions/checkout@v4
@@ -40,7 +45,9 @@ jobs:
- name: Install
run: yarn install
- name: Build Android Release
- name: Assemble Android Release
run: |
cd packages/app-mobile/android && ./gradlew assembleDebug
cd packages/app-mobile/android
sed -i -- 's/signingConfig signingConfigs.release/signingConfig signingConfigs.debug/' app/build.gradle
./gradlew assembleRelease

View File

@@ -13,7 +13,7 @@ jobs:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Beta Release
uses: contributor-assistant/github-action@v2.3.1
uses: contributor-assistant/github-action@v2.3.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret

View File

@@ -23,7 +23,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-latest, ubuntu-20.04, windows-2019]
os: [macos-12, ubuntu-20.04, windows-2019]
steps:
# Trying to fix random networking issues on Windows

76
.gitignore vendored
View File

@@ -10,7 +10,6 @@ _vieux/
!var/sessions/.gitkeep
!var/SymfonyRequirements.php
.DS_Store
.vscode/*
*.map
*.pro.user
*.sublime-workspace
@@ -222,6 +221,7 @@ packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.test.js
packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.js
packages/app-desktop/gui/MainScreen/commands/toggleEditors.js
packages/app-desktop/gui/MainScreen/commands/toggleLayoutMoveMode.js
packages/app-desktop/gui/MainScreen/commands/toggleMenuBar.js
packages/app-desktop/gui/MainScreen/commands/toggleNoteList.js
packages/app-desktop/gui/MainScreen/commands/toggleNoteType.js
packages/app-desktop/gui/MainScreen/commands/toggleNotesSortOrderField.js
@@ -270,6 +270,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/useLinkTooltips.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useWebViewApi.js
packages/app-desktop/gui/NoteEditor/NoteEditor.js
@@ -301,6 +302,8 @@ packages/app-desktop/gui/NoteEditor/utils/useMarkupToHtml.js
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
packages/app-desktop/gui/NoteEditor/utils/useNoteSearchBar.js
packages/app-desktop/gui/NoteEditor/utils/usePluginServiceRegistration.js
packages/app-desktop/gui/NoteEditor/utils/useScheduleSaveCallbacks.js
packages/app-desktop/gui/NoteEditor/utils/useScrollWhenReadyOptions.js
packages/app-desktop/gui/NoteEditor/utils/useSearchMarkers.js
packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
packages/app-desktop/gui/NoteList/NoteList2.js
@@ -432,6 +435,8 @@ packages/app-desktop/integration-tests/models/MainScreen.js
packages/app-desktop/integration-tests/models/NoteEditorScreen.js
packages/app-desktop/integration-tests/models/SettingsScreen.js
packages/app-desktop/integration-tests/models/Sidebar.js
packages/app-desktop/integration-tests/noteList.spec.js
packages/app-desktop/integration-tests/richTextEditor.spec.js
packages/app-desktop/integration-tests/sidebar.spec.js
packages/app-desktop/integration-tests/simpleBackup.spec.js
packages/app-desktop/integration-tests/util/activateMainMenuItem.js
@@ -440,6 +445,7 @@ packages/app-desktop/integration-tests/util/firstNonDevToolsWindow.js
packages/app-desktop/integration-tests/util/setFilePickerResponse.js
packages/app-desktop/integration-tests/util/setMessageBoxResponse.js
packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/playwright.config.js
packages/app-desktop/plugins/GotoAnything.js
packages/app-desktop/services/bridge.js
@@ -480,20 +486,23 @@ packages/app-desktop/utils/restartInSafeModeFromMain.test.js
packages/app-desktop/utils/restartInSafeModeFromMain.js
packages/app-mobile/PluginAssetsLoader.js
packages/app-mobile/commands/index.js
packages/app-mobile/commands/newNote.test.js
packages/app-mobile/commands/newNote.js
packages/app-mobile/commands/openItem.js
packages/app-mobile/commands/openNote.js
packages/app-mobile/commands/scrollToHash.js
packages/app-mobile/commands/util/goToNote.js
packages/app-mobile/components/ActionButton.js
packages/app-mobile/components/BackButtonDialogBox.js
packages/app-mobile/components/BetaChip.js
packages/app-mobile/components/CameraView.js
packages/app-mobile/components/CustomButton.js
packages/app-mobile/components/DismissibleDialog.js
packages/app-mobile/components/Dropdown.test.js
packages/app-mobile/components/Dropdown.js
packages/app-mobile/components/ExtendedWebView.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/Icon.js
packages/app-mobile/components/IconButton.js
packages/app-mobile/components/Modal.js
packages/app-mobile/components/ModalDialog.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
@@ -561,11 +570,14 @@ 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/TextButton.js
packages/app-mobile/components/buttons/index.js
packages/app-mobile/components/getResponsiveValue.test.js
packages/app-mobile/components/getResponsiveValue.js
packages/app-mobile/components/global-style.js
packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.js
packages/app-mobile/components/screens/ConfigScreen/FileSystemPathSelector.js
packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.js
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportDebugReportButton.js
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.js
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.test.js
@@ -578,25 +590,38 @@ packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/expo
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/utils/makeImportExportCacheDirectory.js
packages/app-mobile/components/screens/ConfigScreen/SectionDescription.js
packages/app-mobile/components/screens/ConfigScreen/SectionHeader.js
packages/app-mobile/components/screens/ConfigScreen/SectionSelector.js
packages/app-mobile/components/screens/ConfigScreen/SectionSelector/SectionTab.js
packages/app-mobile/components/screens/ConfigScreen/SectionSelector/index.js
packages/app-mobile/components/screens/ConfigScreen/SettingComponent.js
packages/app-mobile/components/screens/ConfigScreen/SettingItem.js
packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js
packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/ActionButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginInfoButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.js
packages/app-mobile/components/screens/ConfigScreen/plugins/InstalledPluginBox.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChip.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginTitle.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/index.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.installed.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.search.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginToggle.js
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginUploadButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.test.js
packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.js
packages/app-mobile/components/screens/ConfigScreen/plugins/SectionLabel.js
packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/ActionButton.js
packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/InstallButton.js
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
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/useRepoApi.js
packages/app-mobile/components/screens/ConfigScreen/plugins/utils/useUpdateState.js
packages/app-mobile/components/screens/ConfigScreen/types.js
packages/app-mobile/components/screens/JoplinCloudLoginScreen.js
packages/app-mobile/components/screens/LogScreen.js
@@ -637,7 +662,9 @@ packages/app-mobile/plugins/PluginRunner/dialogs/hooks/useWebViewSetup.js
packages/app-mobile/plugins/PluginRunner/types.js
packages/app-mobile/plugins/PluginRunner/utils/createOnLogHandler.js
packages/app-mobile/plugins/hooks/usePlugin.js
packages/app-mobile/plugins/loadPlugins.test.js
packages/app-mobile/plugins/loadPlugins.js
packages/app-mobile/plugins/testing/MockPluginRunner.js
packages/app-mobile/root.js
packages/app-mobile/services/AlarmServiceDriver.android.js
packages/app-mobile/services/AlarmServiceDriver.ios.js
@@ -668,6 +695,7 @@ packages/app-mobile/utils/fs-driver/tarExtract.js
packages/app-mobile/utils/fs-driver/testUtil/createFilesFromPathRecord.js
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/initializeCommandService.js
packages/app-mobile/utils/ipc/RNToWebViewMessenger.js
packages/app-mobile/utils/ipc/WebViewToRNMessenger.js
@@ -720,8 +748,9 @@ packages/editor/CodeMirror/markdown/markdownCommands.toggleList.test.js
packages/editor/CodeMirror/markdown/markdownCommands.js
packages/editor/CodeMirror/markdown/markdownMathParser.test.js
packages/editor/CodeMirror/markdown/markdownMathParser.js
packages/editor/CodeMirror/markdown/markdownReformatter.test.js
packages/editor/CodeMirror/markdown/markdownReformatter.js
packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.test.js
packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.js
packages/editor/CodeMirror/markdown/utils/stripBlockquote.js
packages/editor/CodeMirror/pluginApi/PluginLoader.js
packages/editor/CodeMirror/pluginApi/codeMirrorRequire.js
packages/editor/CodeMirror/pluginApi/customEditorCompletion.test.js
@@ -734,8 +763,22 @@ packages/editor/CodeMirror/testUtil/loadLanguages.js
packages/editor/CodeMirror/testUtil/pressReleaseKey.js
packages/editor/CodeMirror/testUtil/typeText.js
packages/editor/CodeMirror/theme.js
packages/editor/CodeMirror/util/isInSyntaxNode.js
packages/editor/CodeMirror/util/setupVim.js
packages/editor/CodeMirror/utils/formatting/RegionSpec.js
packages/editor/CodeMirror/utils/formatting/findInlineMatch.test.js
packages/editor/CodeMirror/utils/formatting/findInlineMatch.js
packages/editor/CodeMirror/utils/formatting/isIndentationEquivalent.js
packages/editor/CodeMirror/utils/formatting/tabsToSpaces.test.js
packages/editor/CodeMirror/utils/formatting/tabsToSpaces.js
packages/editor/CodeMirror/utils/formatting/toggleInlineFormatGlobally.js
packages/editor/CodeMirror/utils/formatting/toggleInlineRegionSurrounded.js
packages/editor/CodeMirror/utils/formatting/toggleInlineSelectionFormat.js
packages/editor/CodeMirror/utils/formatting/toggleRegionFormatGlobally.test.js
packages/editor/CodeMirror/utils/formatting/toggleRegionFormatGlobally.js
packages/editor/CodeMirror/utils/formatting/toggleSelectedLinesStartWith.js
packages/editor/CodeMirror/utils/formatting/types.js
packages/editor/CodeMirror/utils/growSelectionToNode.js
packages/editor/CodeMirror/utils/isInSyntaxNode.js
packages/editor/CodeMirror/utils/setupVim.js
packages/editor/SelectionFormatting.js
packages/editor/events.js
packages/editor/types.js
@@ -761,6 +804,7 @@ packages/generator-joplin/generators/app/templates/src/index.js
packages/generator-joplin/tools/updateCategories.js
packages/htmlpack/src/index.js
packages/lib/ArrayUtils.js
packages/lib/AsyncActionQueue.test.js
packages/lib/AsyncActionQueue.js
packages/lib/BaseApplication.js
packages/lib/BaseModel.js
@@ -850,6 +894,7 @@ packages/lib/markdownUtils.js
packages/lib/markdownUtils2.test.js
packages/lib/markupLanguageUtils.js
packages/lib/migrations/42.js
packages/lib/mime-utils.js
packages/lib/models/Alarm.js
packages/lib/models/BaseItem.test.js
packages/lib/models/BaseItem.js
@@ -899,6 +944,7 @@ packages/lib/ntp.js
packages/lib/onedrive-api.test.js
packages/lib/onedrive-api.js
packages/lib/path-utils.js
packages/lib/reducer.test.js
packages/lib/reducer.js
packages/lib/registry.test.js
packages/lib/registry.js
@@ -1181,10 +1227,12 @@ packages/lib/themes/solarizedLight.js
packages/lib/themes/type.js
packages/lib/time.js
packages/lib/types.js
packages/lib/urlUtils.js
packages/lib/utils/ActionLogger.test.js
packages/lib/utils/ActionLogger.js
packages/lib/utils/credentialFiles.js
packages/lib/utils/focusHandler.js
packages/lib/utils/frontMatter.js
packages/lib/utils/ipc/RemoteMessenger.test.js
packages/lib/utils/ipc/RemoteMessenger.js
packages/lib/utils/ipc/TestMessenger.js
@@ -1195,7 +1243,8 @@ packages/lib/utils/ipc/utils/mergeCallbacksAndSerializable.js
packages/lib/utils/ipc/utils/separateCallbacksFromSerializable.test.js
packages/lib/utils/ipc/utils/separateCallbacksFromSerializable.js
packages/lib/utils/ipc/utils/separateCallbacksFromSerializableArray.js
packages/lib/utils/joplinCloud.js
packages/lib/utils/joplinCloud/index.js
packages/lib/utils/joplinCloud/types.js
packages/lib/utils/processStartFlags.js
packages/lib/utils/replaceUnsupportedCharacters.test.js
packages/lib/utils/replaceUnsupportedCharacters.js
@@ -1267,6 +1316,7 @@ packages/renderer/MdToHtml/rules/mermaid.js
packages/renderer/MdToHtml/rules/sanitize_html.js
packages/renderer/MdToHtml/rules/source_map.js
packages/renderer/MdToHtml/rules/tableHorizontallyScrollable.js
packages/renderer/MdToHtml/rules/utils/defaultRule.js
packages/renderer/MdToHtml/setupLinkify.js
packages/renderer/MdToHtml/validateLinks.js
packages/renderer/assetsToHeaders.js

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"cSpell.enabled": true
}

View File

@@ -1,8 +1,8 @@
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
index 0f52b73c61625db2a3081c0950b6bdd2b06e3d40..b0fc3de4be0b3a26b638683613c63c783c2739bb 100644
index 8a719ca35af1cc3a4192c5c5f8258fd4f7fea990..5f8831f81cd164a4f627423427ead92fa286b115 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
@@ -38,7 +38,7 @@ import com.facebook.react.uimanager.common.ViewUtil;
@@ -37,7 +37,7 @@ import com.facebook.react.uimanager.common.ViewUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
@@ -11,7 +11,7 @@ index 0f52b73c61625db2a3081c0950b6bdd2b06e3d40..b0fc3de4be0b3a26b638683613c63c78
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -151,7 +151,10 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
@@ -149,7 +149,10 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
}
private class ConcurrentOperationQueue {

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 200 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

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://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.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://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://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.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>
<!-- SPONSORS-ORG -->
* * *

View File

@@ -1,24 +1,58 @@
# For development this compose file starts the database only. The app can then
# be started using `yarn start-dev`, which is useful for development, because
# it means the app Docker file doesn't have to be rebuilt on each change.
#
# Note that log is setup to give as much information as possible, including
# whether it's the master or slave database that is being used for a query.
#
# To setup and test replication, use the following config in Joplin Server. Note
# in particular the different port, which means we access the slave and not the
# master.
#
# DB_USE_SLAVE=true
# SLAVE_POSTGRES_PASSWORD=joplin
# SLAVE_POSTGRES_DATABASE=joplin
# SLAVE_POSTGRES_USER=joplin
# SLAVE_POSTGRES_PORT=5433
# SLAVE_POSTGRES_HOST=localhost
# USERS_WITH_REPLICATION=ID1,ID2,...
version: '3'
version: '2'
services:
db:
image: postgres:16
command: postgres -c work_mem=100000
postgresql-master:
image: 'bitnami/postgresql:16.3.0'
ports:
- "5432:5432"
- '5432:5432'
environment:
- POSTGRES_PASSWORD=joplin
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin
# Use this to specify additional Postgres
# config parameters:
#
# command:
# - "postgres"
# - "-c"
# - "log_min_duration_statement=0"
- POSTGRESQL_PASSWORD=joplin
- POSTGRESQL_USERNAME=joplin
- POSTGRESQL_DATABASE=joplin
- POSTGRESQL_REPLICATION_MODE=master
- POSTGRESQL_REPLICATION_USER=repl_user
- POSTGRESQL_REPLICATION_PASSWORD=repl_password
- POSTGRESQL_LOG_HOSTNAME=true
- POSTGRESQL_PGAUDIT_LOG=READ,WRITE
- POSTGRESQL_EXTRA_FLAGS=-c work_mem=100000 -c log_statement=all
postgresql-slave:
image: 'bitnami/postgresql:16.3.0'
ports:
- '5433:5432'
depends_on:
- postgresql-master
environment:
- POSTGRESQL_REPLICATION_MODE=slave
- POSTGRESQL_REPLICATION_USER=repl_user
- POSTGRESQL_REPLICATION_PASSWORD=repl_password
- POSTGRESQL_MASTER_HOST=postgresql-master
- POSTGRESQL_PASSWORD=joplin
- POSTGRESQL_MASTER_PORT_NUMBER=5432
- POSTGRESQL_LOG_HOSTNAME=true
- POSTGRESQL_PGAUDIT_LOG=READ,WRITE
- POSTGRESQL_EXTRA_FLAGS=-c work_mem=100000 -c log_statement=all

View File

@@ -1 +1,13 @@
<strong>Joplin</strong> is a free, open source note taking and to-do application, which can handle a large number of notes organised into notebooks. The notes are searchable, can be copied, tagged and modified either from the applications directly or from your own text editor. The notes are in <a href="https://joplinapp.org/help/apps/markdown">Markdown format</a>.</p><p>Notes exported from Evernote <a href="https://joplinapp.org/help/apps/import_export">can be imported</a> into Joplin, including the formatted content (which is converted to Markdown), resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.). Plain Markdown files can also be imported.</p><p>Joplin is "offline first", which means you always have all your data on your phone or computer. This ensures that your notes are always accessible, whether you have an internet connection or not.</p><p>The notes can be securely <a href="https://joplinapp.org/help/apps/sync">synchronised</a> using <a href="https://joplinapp.org/help/apps/sync/e2ee">end-to-end encryption</a> with various cloud services including Nextcloud, Dropbox, OneDrive and <a href="https://joplinapp.org/plans/" target="_blank" rel="noopener noreferrer">Joplin Cloud</a>.</p><p>Full text search is available on all platforms to quickly find the information you need. The app can be customised using plugins and themes, and you can also easily create your own.</p><p>The application is available for Windows, Linux, macOS, Android and iOS. A <a href="https://joplinapp.org/help/apps/clipper">Web Clipper</a>, to save web pages and screenshots from your browser, is also available for <a href="https://addons.mozilla.org/firefox/addon/joplin-web-clipper/" target="_blank" rel="noopener noreferrer">Firefox</a> and <a href="https://chrome.google.com/webstore/detail/joplin-web-clipper/alofnhikmmkdbbbgpnglcpdollgjjfek?hl=en-GB" target="_blank" rel="noopener noreferrer">Chrome</a>.</p><div class="top-screenshot"><img loading="lazy" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/home-top-img.png" class="img_node_modules-@docusaurus-theme-classic-lib-theme-MDXComponents-Img-styles-module" style="max-width: 100%; max-height: 35em;">
<strong>Joplin</strong> is a free and open source note taking and to-do application, which can handle a large number of notes organised into notebooks. The notes are searchable, can be copied, tagged and modified either from the applications directly or from your own text editor.
The notes are in <a href="https://joplinapp.org/help/apps/markdown">Markdown format</a>.
Notes exported from Evernote <a href="https://joplinapp.org/help/apps/import_export">can be imported</a> into Joplin, including the formatted content (which is converted to Markdown), resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.). Plain Markdown files can also be imported.
Joplin is "offline first", which means you always have all your data on your phone or computer. This ensures that your notes are always accessible, whether you have an internet connection or not.</p>
The notes can be securely <a href="https://joplinapp.org/help/apps/sync">synchronised</a> using <a href="https://joplinapp.org/help/apps/sync/e2ee">end-to-end encryption</a> with various cloud services including Nextcloud, Dropbox, OneDrive and <a href="https://joplinapp.org/plans/">Joplin Cloud</a>.
Full text search is available on all platforms to quickly find the information you need. The app can be customised using plugins and themes, and you can also easily create your own.
The application is available for Windows, Linux, macOS, Android and iOS. A <a href="https://joplinapp.org/help/apps/clipper">Web Clipper</a>, to save web pages and screenshots from your browser, is also available for <a href="https://addons.mozilla.org/firefox/addon/joplin-web-clipper/">Firefox</a> and <a href="https://chrome.google.com/webstore/detail/joplin-web-clipper/alofnhikmmkdbbbgpnglcpdollgjjfek">Chrome</a>.

View File

@@ -1 +1 @@
a note taking and to-do app with sync between Linux, macOS, Windows, and mobile
A note taking and to-do app with sync between Linux, macOS, Windows, and mobile

View File

@@ -0,0 +1,13 @@
<strong>Joplin</strong> это бесплатное и свободное приложение для создания заметок и списков задач, которое может обрабатывать большое количество заметок, организованных в блокноты. По заметкам есть поиск, их можно копировать, помечать ярлыками и изменять как непосредственно из приложения, так и из вашего собственного текстового редактора.
Заметки представлены в <a href="https://joplinapp.org/help/apps/markdown">формате Markdown</a>.
Заметки экспортированные из Evernote <a href="https://joplinapp.org/help/apps/import_export">могут быть импортированы</a> в Joplin, включая отформатированный контент (который преобразуется в Markdown), ресурсы (изображения, вложения и т.д.) и полные метаданные (геолокация, время обновления, время создания и т.д.). Обычные файлы Markdown также можно импортировать.
Joplin работает "в первую очередь в автономном режиме", что означает, что у вас всегда есть все ваши данные на телефоне или компьютере. Это гарантирует, что ваши заметки всегда будут доступны, независимо от того есть у вас подключение к Интернету или нет.
Заметки могут быть надежно <a href="https://joplinapp.org/help/apps/sync">синхронизированы</a> с помощью <a href="https://joplinapp.org/help/apps/sync/e2ee">сквозного шифрования</a> на различные облачные сервисы, включая Nextcloud, Dropbox, OneDrive и <a href="https://joplinapp.org/plans/">Joplin Cloud</a>.
Полнотекстовый поиск доступен на всех платформах для быстрого поиска нужной вам информации. Приложение можно настроить с помощью плагинов и тем, а также легко создать свои.
Приложение доступно для Windows, Linux, macOS, Android и iOS. A <a href="https://joplinapp.org/help/apps/clipper">Веб-клипер</a> для сохранения веб-страниц и скриншотов из вашего браузера, также доступен для <a href="https://addons.mozilla.org/firefox/addon/joplin-web-clipper/">Firefox</a> и <a href="https://chrome.google.com/webstore/detail/joplin-web-clipper/alofnhikmmkdbbbgpnglcpdollgjjfek">Chrome</a>.

View File

@@ -0,0 +1 @@
Заметки и списки дел с синхронизацией с Linux, macOS, Windows и мобильным

View File

@@ -106,7 +106,6 @@
"./packages/renderer/**/node_modules/": true,
".eslintignore": true,
".gitignore": true,
".vscode/*": true,
".yarn/cache": true,
".yarn/install-state.gz": true,
".yarn/plugins": true,

View File

@@ -40,7 +40,7 @@
"postinstall": "gulp build",
"postPreReleasesToForum": "node ./packages/tools/postPreReleasesToForum",
"publishAll": "git pull && yarn buildParallel && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
"releaseAndroid": "PATH=\"/usr/local/opt/openjdk@11/bin:$PATH\" node packages/tools/release-android.js",
"releaseAndroid": "PATH=\"/usr/local/opt/openjdk@17/bin:$PATH\" node packages/tools/release-android.js",
"releaseAndroidClean": "node packages/tools/release-android.js",
"releaseCli": "node packages/tools/release-cli.js",
"releaseClipper": "node packages/tools/release-clipper.js",
@@ -86,7 +86,7 @@
"gulp": "4.0.2",
"husky": "3.1.0",
"lerna": "3.22.1",
"lint-staged": "15.2.0",
"lint-staged": "15.2.2",
"madge": "6.1.0",
"npm-package-json-lint": "7.1.0",
"typescript": "5.2.2"
@@ -104,11 +104,11 @@
"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.52.0#./.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",
"react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.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",
"@react-native-community/slider": "patch:@react-native-community/slider@npm%3A4.4.4#./.yarn/patches/@react-native-community-slider-npm-4.4.4-d78e472f48.patch",
"husky": "patch:husky@npm%3A3.1.0#./.yarn/patches/husky-npm-3.1.0-5cc13e4e34.patch",
"chokidar@^2.0.0": "3.5.3"
"chokidar@^2.0.0": "3.5.3",
"react-native@0.74.1": "patch:react-native@npm%3A0.74.1#./.yarn/patches/react-native-npm-0.74.1-754c02ae9e.patch"
}
}

View File

@@ -239,11 +239,6 @@ async function fetchAllNotes() {
type: Database.enumId('fieldType', 'text'),
description: 'If an image is provided, you can also specify an optional rectangle that will be used to crop the image. In format `{ x: x, y: y, width: width, height: height }`',
});
// tableFields.push({
// name: 'tags',
// type: Database.enumId('fieldType', 'text'),
// description: 'Comma-separated list of tags. eg. `tag1,tag2`.',
// });
}
lines.push(`## ${toTitleCase(tableName)}`);
@@ -269,6 +264,11 @@ async function fetchAllNotes() {
lines.push('');
}
if (model.type === BaseModel.TYPE_NOTE) {
lines.push('By default, this call will return the all notes **except** the notes in the trash folder and any conflict note. To include these too, you can specify `include_deleted=1` and `include_conflicts=1` as query parameters.');
lines.push('');
}
lines.push(`### GET /${tableName}/:id`);
lines.push('');
lines.push(`Gets ${singular} with ID :id`);

View File

@@ -63,7 +63,7 @@
"string-padding": "1.0.2",
"strip-ansi": "6.0.1",
"tcp-port-used": "1.0.2",
"terminal-kit": "3.0.1",
"terminal-kit": "3.0.2",
"tkwidgets": "0.5.27",
"url-parse": "1.5.10",
"word-wrap": "1.2.5",
@@ -73,7 +73,7 @@
"@joplin/tools": "~3.0",
"@types/fs-extra": "11.0.4",
"@types/jest": "29.5.8",
"@types/node": "18.19.10",
"@types/node": "18.19.26",
"@types/proper-lockfile": "^4.1.2",
"gulp": "4.0.2",
"jest": "29.7.0",

View File

@@ -49,6 +49,8 @@ describe('MdToHtml', () => {
checkboxRenderingType: 2,
},
};
} else if (mdFilename.startsWith('sourcemap_')) {
mdToHtmlOptions.mapsToLine = true;
}
const markdown = await shim.fsDriver().readFile(mdFilePath);

View File

@@ -0,0 +1,21 @@
<div class="joplin-table-wrapper">
<table class="maps-to-line" source-line="0" source-line-end="3">
<thead>
<tr>
<th>This</th>
<th>is</th>
<th>a</th>
<th>test</th>
</tr>
</thead>
<tbody>
<tr>
<td>This</td>
<td>table</td>
<td>has</td>
<td>line numbers</td>
</tr>
</tbody>
</table>
</div>
<p class="maps-to-line" source-line="4" source-line-end="5">When <code class="inline-code">mapsToLine</code> is enabled for this file, the table above should have line numbers that link to the original markdown.</p>

View File

@@ -0,0 +1,5 @@
| This | is | a | test |
|------|----|---|------|
| This | table | has | line numbers |
When `mapsToLine` is enabled for this file, the table above should have line numbers that link to the original markdown.

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -43,9 +43,9 @@ export interface Command {
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
* And | && | "oneNoteSelected && !inConflictFolder"
*
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
* Joplin, unlike VSCode, also supports parentheses, which allows creating
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
* level of parenthesis is possible (nested ones aren't supported).
* level of parentheses is possible (nested ones aren't supported).
*
* Currently the supported context variables aren't documented, but you can
* find the list below:

View File

@@ -0,0 +1,5 @@
---
title: Not a task
---
This is a note.

View File

@@ -0,0 +1,6 @@
---
title: Task
completed?: yes
---
This is a test. This task should import as completed.

View File

@@ -26,6 +26,10 @@ export interface AppStateDialog {
props: Record<string, any>;
}
export interface EditorScrollPercents {
[noteId: string]: number;
}
export interface AppState extends State {
route: AppStateRoute;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
@@ -34,8 +38,7 @@ export interface AppState extends State {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
windowContentSize: any;
watchedNoteFiles: string[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
lastEditorScrollPercents: any;
lastEditorScrollPercents: EditorScrollPercents;
devToolsVisible: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
visibleDialogs: any; // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.

View File

@@ -243,6 +243,24 @@ class ConfigScreenComponent extends React.Component<any, any> {
</div>
);
if (settings['sync.target'] === SyncTargetRegistry.nameToId('joplinCloud')) {
const goToJoplinCloudLogin = () => {
this.props.dispatch({
type: 'NAV_GO',
routeName: 'JoplinCloudLogin',
});
};
settingComps.push(
<div key="connect_to_joplin_cloud_button" style={this.rowStyle_}>
<Button
title={_('Connect to Joplin Cloud')}
level={ButtonLevel.Primary}
onClick={goToJoplinCloudLogin}
/>
</div>,
);
}
settingComps.push(
<div key="check_sync_config_button" style={this.rowStyle_}>
<Button
@@ -596,6 +614,9 @@ class ConfigScreenComponent extends React.Component<any, any> {
size={ButtonSize.Small}
/>
</div>
<div style={{ width: inputStyle.width, minWidth: inputStyle.minWidth }}>
{descriptionComp}
</div>
</div>
</div>
</div>

View File

@@ -38,6 +38,7 @@ interface Props {
function manifestToItem(manifest: PluginManifest): PluginItem {
return {
manifest: manifest,
installed: true,
enabled: true,
deleted: false,
devMode: false,

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import PluginService, { defaultPluginSetting, Plugins, PluginSetting, PluginSettings } from '@joplin/lib/services/plugins/PluginService';
import { _ } from '@joplin/lib/locale';
import styled from 'styled-components';
@@ -83,6 +83,7 @@ function usePluginItems(plugins: Plugins, settings: PluginSettings): PluginItem[
output.push({
manifest: plugin.manifest,
installed: true,
enabled: setting.enabled,
deleted: setting.deleted,
devMode: plugin.devMode,
@@ -213,8 +214,11 @@ export default function(props: Props) {
props.onChange({ value: pluginService.serializePluginSettings(event.value) });
}, [pluginService, props.onChange]);
const onDelete = useOnDeleteHandler(pluginSettings, onPluginSettingsChange, false);
const onUpdate = useOnInstallHandler(setUpdatingPluginIds, pluginSettings, repoApi, onPluginSettingsChange, true);
const pluginSettingsRef = useRef(pluginSettings);
pluginSettingsRef.current = pluginSettings;
const onDelete = useOnDeleteHandler(pluginSettingsRef, onPluginSettingsChange, false);
const onUpdate = useOnInstallHandler(setUpdatingPluginIds, pluginSettingsRef, repoApi, onPluginSettingsChange, true);
const onToolsClick = useCallback(async () => {
const template = [

View File

@@ -40,7 +40,10 @@ export default function(props: Props) {
const [installingPluginsIds, setInstallingPluginIds] = useState<Record<string, boolean>>({});
const [searchResultCount, setSearchResultCount] = useState(null);
const onInstall = useOnInstallHandler(setInstallingPluginIds, props.pluginSettings, props.repoApi, props.onPluginSettingsChange, false);
const pluginSettingsRef = useRef(props.pluginSettings);
pluginSettingsRef.current = props.pluginSettings;
const onInstall = useOnInstallHandler(setInstallingPluginIds, pluginSettingsRef, props.repoApi, props.onPluginSettingsChange, false);
useEffect(() => {
setSearchResultCount(null);

View File

@@ -9,4 +9,25 @@
p {
padding: calc(var(--joplin-font-size) * 0.8);
}
}
.joplin-cloud-account-information {
margin-bottom: var(--joplin-margin);
table {
margin-bottom: var(--joplin-margin);
border: none;
td {
border: none;
border-bottom: 1px solid var(--joplin-border-color4);
padding: var(--joplin-font-size);
}
tr:last-child {
td {
border: none;
}
}
}
}

View File

@@ -4,10 +4,14 @@ import { _ } from '@joplin/lib/locale';
import { clipboard } from 'electron';
import Button from './Button/Button';
import { Fragment } from 'react';
import { accountTypeToString } from '@joplin/lib/utils/joplinCloud/types';
import bridge from '../services/bridge';
type JoplinCloudConfigScreenProps = {
inboxEmail: string;
joplinCloudAccountType: number;
userEmail: string;
joplinCloudWebsite: string;
};
const JoplinCloudConfigScreen = (props: JoplinCloudConfigScreenProps) => {
@@ -17,8 +21,29 @@ const JoplinCloudConfigScreen = (props: JoplinCloudConfigScreenProps) => {
const isEmailToNoteAvailableInAccount = props.joplinCloudAccountType !== 1;
const goToJoplinCloudProfile = async () => {
await bridge().openExternal(`${props.joplinCloudWebsite}/users/me`);
};
return (
<div>
<div className="joplin-cloud-account-information">
<h2>{_('Account information')}</h2>
<table>
<tbody>
<tr>
<td><strong>{_('Account type')}</strong></td>
<td>{accountTypeToString(props.joplinCloudAccountType)}</td>
</tr>
<tr>
<td><strong>{_('Email')}</strong></td>
<td>{props.userEmail}</td>
</tr>
</tbody>
</table>
<Button onClick={goToJoplinCloudProfile} title={_('Go to Joplin Cloud profile')}/>
</div>
<h2>{_('Email to note')}</h2>
<p>{_('Any email sent to this address will be converted into a note and added to your collection. The note will be saved into the Inbox notebook')}</p>
{
@@ -38,6 +63,8 @@ const mapStateToProps = (state: AppState) => {
return {
inboxEmail: state.settings['sync.10.inboxEmail'],
joplinCloudAccountType: state.settings['sync.10.accountType'],
userEmail: state.settings['sync.10.userEmail'],
joplinCloudWebsite: state.settings['sync.10.website'],
};
};

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useReducer, useState } from 'react';
import { Fragment, useEffect, useMemo, useReducer, useState } from 'react';
import ButtonBar from './ConfigScreen/ButtonBar';
import { _ } from '@joplin/lib/locale';
import { clipboard } from 'electron';
@@ -9,6 +9,7 @@ import { Dispatch } from 'redux';
import { reducer, defaultState, generateApplicationConfirmUrl, checkIfLoginWasSuccessful } from '@joplin/lib/services/joplinCloudUtils';
import { AppState } from '../app.reducer';
import Logger from '@joplin/utils/Logger';
import { reg } from '@joplin/lib/registry';
const logger = Logger.create('JoplinCloudLoginScreen');
const { connect } = require('react-redux');
@@ -38,6 +39,7 @@ const JoplinCloudScreenComponent = (props: Props) => {
if (response && response.success) {
dispatch({ type: 'COMPLETED' });
clearInterval(interval);
void reg.scheduleSync(0);
}
} catch (error) {
logger.error(error);
@@ -77,22 +79,26 @@ const JoplinCloudScreenComponent = (props: Props) => {
return (
<div className="login-page">
<div className="page-container">
<p className="text">{_('To allow Joplin to synchronise with Joplin Cloud, please login using this URL:')}</p>
<div className="buttons-container">
<Button
onClick={onAuthorizeClicked}
title={_('Authorise')}
iconName='fa fa-external-link-alt'
level={ButtonLevel.Primary}
/>
<Button
onClick={onCopyToClipboardClicked}
title={_('Copy link to website')}
iconName='fa fa-clone'
level={ButtonLevel.Secondary}
/>
{state.active !== 'COMPLETED' ? (
<Fragment>
<p className="text">{_('To allow Joplin to synchronise with Joplin Cloud, please login using this URL:')}</p>
<div className="buttons-container">
<Button
onClick={onAuthorizeClicked}
title={_('Authorise')}
iconName='fa fa-external-link-alt'
level={ButtonLevel.Primary}
/>
<Button
onClick={onCopyToClipboardClicked}
title={_('Copy link to website')}
iconName='fa fa-clone'
level={ButtonLevel.Secondary}
/>
</div>
</div>
</Fragment>
) : null}
<p className={state.className}>{state.message()}
{state.active === 'ERROR' ? (
<span className={state.className}>{state.errorMessage}</span>

View File

@@ -39,6 +39,7 @@ import * as showShareNoteDialog from './showShareNoteDialog';
import * as showSpellCheckerMenu from './showSpellCheckerMenu';
import * as toggleEditors from './toggleEditors';
import * as toggleLayoutMoveMode from './toggleLayoutMoveMode';
import * as toggleMenuBar from './toggleMenuBar';
import * as toggleNoteList from './toggleNoteList';
import * as toggleNoteType from './toggleNoteType';
import * as toggleNotesSortOrderField from './toggleNotesSortOrderField';
@@ -88,6 +89,7 @@ const index: any[] = [
showSpellCheckerMenu,
toggleEditors,
toggleLayoutMoveMode,
toggleMenuBar,
toggleNoteList,
toggleNoteType,
toggleNotesSortOrderField,

View File

@@ -3,9 +3,10 @@ import shim from '@joplin/lib/shim';
import { _ } from '@joplin/lib/locale';
import bridge from '../../../services/bridge';
import { openItemById } from '../../NoteEditor/utils/contextMenu';
const { parseResourceUrl, urlProtocol } = require('@joplin/lib/urlUtils');
import { fileUrlToResourceUrl, parseResourceUrl, urlProtocol } from '@joplin/lib/urlUtils';
import { fileUriToPath } from '@joplin/utils/url';
const { urlDecode } = require('@joplin/lib/string-utils');
import { urlDecode } from '@joplin/lib/string-utils';
import Setting from '@joplin/lib/models/Setting';
export const declaration: CommandDeclaration = {
name: 'openItem',
@@ -16,6 +17,11 @@ export const runtime = (): CommandRuntime => {
execute: async (context: CommandContext, link: string) => {
if (!link) throw new Error('Link cannot be empty');
const fromFileUrl = fileUrlToResourceUrl(link, Setting.value('resourceDir'));
if (fromFileUrl) {
link = fromFileUrl;
}
if (link.startsWith('joplin://') || link.startsWith(':/')) {
const parsedUrl = parseResourceUrl(link);
if (parsedUrl) {

View File

@@ -0,0 +1,16 @@
import { CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService';
import Setting from '@joplin/lib/models/Setting';
import { _ } from '@joplin/lib/locale';
export const declaration: CommandDeclaration = {
name: 'toggleMenuBar',
label: () => _('Toggle menu bar'),
};
export const runtime = (): CommandRuntime => {
return {
execute: async () => {
Setting.toggle('showMenuBar');
},
};
};

View File

@@ -1,7 +1,6 @@
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
import { _ } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note';
import eventManager, { EventName } from '@joplin/lib/eventManager';
export const declaration: CommandDeclaration = {
name: 'toggleNoteType',
@@ -15,14 +14,7 @@ export const runtime = (): CommandRuntime => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
const newNote = await Note.save(Note.toggleIsTodo(note), { userSideValidation: true });
const eventNote = {
id: newNote.id,
is_todo: newNote.is_todo,
todo_due: newNote.todo_due,
todo_completed: newNote.todo_completed,
};
eventManager.emit(EventName.NoteTypeToggle, { noteId: note.id, note: eventNote });
await Note.save(Note.toggleIsTodo(note), { userSideValidation: true });
}
},
enabledCondition: '!noteIsReadOnly',

View File

@@ -172,6 +172,7 @@ interface Props {
pluginSettings: PluginSettings;
noteListRendererIds: string[];
noteListRendererId: string;
showMenuBar: boolean;
}
const commandNames: string[] = menuCommandNames();
@@ -190,6 +191,15 @@ function menuItemSetEnabled(id: string, enabled: boolean) {
menuItem.enabled = enabled;
}
const applyMenuBarVisibility = (showMenuBar: boolean) => {
// The menu bar cannot be hidden on macOS
if (shim.isMac()) return;
const window = bridge().window();
window.setAutoHideMenuBar(!showMenuBar);
window.setMenuBarVisibility(showMenuBar);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
function useMenuStates(menu: any, props: Props) {
useEffect(() => {
@@ -760,6 +770,7 @@ function useMenu(props: Props) {
menuItemDic.resetLayout,
separator(),
menuItemDic.toggleSideBar,
shim.isMac() ? noItem : menuItemDic.toggleMenuBar,
menuItemDic.toggleNoteList,
menuItemDic.toggleVisiblePanes,
{
@@ -1083,6 +1094,7 @@ function useMenu(props: Props) {
function MenuBar(props: Props): any {
const menu = useMenu(props);
if (menu) Menu.setApplicationMenu(menu);
applyMenuBarVisibility(props.showMenuBar);
return null;
}
@@ -1112,6 +1124,7 @@ const mapStateToProps = (state: AppState) => {
profileConfig: state.profileConfig,
noteListRendererIds: state.noteListRendererIds,
noteListRendererId: state.settings['notes.listRendererId'],
showMenuBar: state.settings.showMenuBar,
};
};

View File

@@ -4,7 +4,7 @@ import KeymapService, { KeymapItem } from '@joplin/lib/services/KeymapService';
import { EditorCommand } from '../../../../utils/types';
import shim from '@joplin/lib/shim';
import { reg } from '@joplin/lib/registry';
import setupVim from '@joplin/editor/CodeMirror/util/setupVim';
import setupVim from '@joplin/editor/CodeMirror/utils/setupVim';
import { EventName } from '@joplin/lib/eventManager';
import normalizeAccelerator from '../../utils/normalizeAccelerator';
import { CodeMirrorVersion } from '../../utils/types';

View File

@@ -352,7 +352,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
return {
language: isHTMLNote ? EditorLanguageType.Html : EditorLanguageType.Markdown,
readOnly: props.disabled || props.visiblePanes.indexOf('editor') < 0,
readOnly: props.disabled,
katexEnabled: Setting.value('markdown.plugin.katex'),
themeData: {
...styles.globalTheme,
@@ -366,8 +366,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
indentWithTabs: true,
};
}, [
props.contentMarkupLanguage, props.disabled, props.visiblePanes,
props.keyboardMode, styles.globalTheme,
props.contentMarkupLanguage, props.disabled, props.keyboardMode, styles.globalTheme,
]);
// Update the editor's value

View File

@@ -8,7 +8,7 @@ import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import { ContentScriptType } from '@joplin/lib/services/plugins/api/types';
import shim from '@joplin/lib/shim';
import PluginService from '@joplin/lib/services/plugins/PluginService';
import setupVim from '@joplin/editor/CodeMirror/util/setupVim';
import setupVim from '@joplin/editor/CodeMirror/utils/setupVim';
import { dirname } from 'path';
import useKeymap from './utils/useKeymap';
import useEditorSearch from '../utils/useEditorSearchExtension';

View File

@@ -12,25 +12,6 @@ import { focus } from '@joplin/lib/utils/focusHandler';
const logger = Logger.create('CodeMirror 6 commands');
const wrapSelectionWithStrings = (editor: CodeMirrorControl, string1: string, string2 = '', defaultText = '') => {
if (editor.somethingSelected()) {
editor.wrapSelections(string1, string2);
} else {
editor.wrapSelections(string1 + defaultText, string2);
// Now select the default text so the user can replace it
const selections = editor.listSelections();
const newSelections = [];
for (let i = 0; i < selections.length; i++) {
const s = selections[i];
const anchor = { line: s.anchor.line, ch: s.anchor.ch + string1.length };
const head = { line: s.head.line, ch: s.head.ch - string2.length };
newSelections.push({ anchor: anchor, head: head });
}
editor.setSelections(newSelections);
}
};
interface Props {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
webviewRef: RefObject<any>;
@@ -92,7 +73,9 @@ const useEditorCommands = (props: Props) => {
textLink: async () => {
const url = await dialogs.prompt(_('Insert Hyperlink'));
focus('useEditorCommands::textLink', editorRef.current);
if (url) wrapSelectionWithStrings(editorRef.current, '[', `](${url})`);
if (url) {
editorRef.current.wrapSelections('[', `](${url})`);
}
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
insertText: (value: any) => editorRef.current.insertText(value),

View File

@@ -32,6 +32,7 @@ import markupRenderOptions from '../../utils/markupRenderOptions';
import { DropHandler } from '../../utils/useDropHandler';
import Logger from '@joplin/utils/Logger';
import useWebViewApi from './utils/useWebViewApi';
import useLinkTooltips from './utils/useLinkTooltips';
import { focus } from '@joplin/lib/utils/focusHandler';
const md5 = require('md5');
const { clipboard } = require('electron');
@@ -363,6 +364,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
}, []);
useWebViewApi(editor);
const { resetModifiedTitles: resetLinkTooltips } = useLinkTooltips(editor);
useEffect(() => {
const theme = themeStyle(props.themeId);
@@ -1048,6 +1050,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
nextOnChangeEventInfo.current = null;
resetLinkTooltips();
const contentMd = await prop_htmlToMarkdownRef.current(info.contentMarkupLanguage, info.editor.getContent(), info.contentOriginalCss);
lastOnChangeEventInfo.current.content = contentMd;

View File

@@ -17,6 +17,8 @@ export const joplinCommandToTinyMceCommands: JoplinCommandToTinyMceCommands = {
'textItalic': { name: 'mceToggleFormat', value: 'italic' },
'textCode': { name: 'mceToggleFormat', value: 'code' },
'textLink': { name: 'mceLink' },
'textBulletedList': { name: 'InsertUnorderedList' },
'textNumberedList': { name: 'InsertOrderedList' },
'search': { name: 'SearchReplace' },
'attachFile': { name: 'joplinAttach' },
'insertDateTime': true,

View File

@@ -0,0 +1,83 @@
import type { Editor } from 'tinymce';
import { useCallback, useEffect } from 'react';
import { _ } from '@joplin/lib/locale';
import shim from '@joplin/lib/shim';
const useLinkTooltips = (editor: Editor|null) => {
const resetModifiedTitles = useCallback(() => {
for (const element of editor.getDoc().querySelectorAll('a[data-joplin-original-title]')) {
element.setAttribute('title', element.getAttribute('data-joplin-original-title') ?? '');
element.removeAttribute('data-joplin-original-title');
}
}, [editor]);
useEffect(() => {
if (!editor) return () => {};
const onMouseOver = (event: MouseEvent) => {
let element = event.target as HTMLElement;
// mouseover events seem to only target the lowest applicable node in the DOM.
// If the user's mouse enters <a><strong></strong></a>, the mouseover event will
// target the <strong></strong>. As such, the parent nodes need to be checked:
let counter = 0;
while (element.tagName !== 'A' || !('href' in element)) {
element = element.parentElement;
counter++;
if (!element || counter > 4) {
return;
}
}
if (!element.hasAttribute('data-joplin-original-title')) {
element.setAttribute('data-joplin-original-title', element.title);
}
// Avoid showing internal HREFs for note links.
if (element.hasAttribute('data-resource-id') && !element.title) {
if (shim.isMac()) {
element.title = _('Cmd-click to open');
} else {
element.title = _('Ctrl-click to open');
}
} else {
if (shim.isMac()) {
element.title = _('Cmd-click to open: %s', element.title || element.href);
} else {
element.title = _('Ctrl-click to open: %s', element.title || element.href);
}
}
const onMouseLeave = () => {
resetModifiedTitles();
element.removeEventListener('mouseleave', onMouseLeave);
};
element.addEventListener('mouseleave', onMouseLeave);
};
const clearRootEventListeners = () => {
editor.getDoc().removeEventListener('mouseover', onMouseOver);
};
const setUpRootEventListeners = () => {
clearRootEventListeners();
editor.getDoc().addEventListener('mouseover', onMouseOver);
};
setUpRootEventListeners();
editor.on('SetContent', setUpRootEventListeners);
editor.on('keyup', resetModifiedTitles);
editor.on('click', resetModifiedTitles);
return () => {
resetModifiedTitles();
editor.off('SetContent', setUpRootEventListeners);
editor.off('keyup', resetModifiedTitles);
editor.off('click', resetModifiedTitles);
clearRootEventListeners();
};
}, [editor, resetModifiedTitles]);
return { resetModifiedTitles };
};
export default useLinkTooltips;

View File

@@ -3,19 +3,18 @@ import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import TinyMCE from './NoteBody/TinyMCE/TinyMCE';
import { connect } from 'react-redux';
import MultiNoteActions from '../MultiNoteActions';
import { htmlToMarkdown, formNoteToNote } from './utils';
import { htmlToMarkdown } from './utils';
import useSearchMarkers from './utils/useSearchMarkers';
import useNoteSearchBar from './utils/useNoteSearchBar';
import useMessageHandler from './utils/useMessageHandler';
import useWindowCommandHandler from './utils/useWindowCommandHandler';
import useDropHandler from './utils/useDropHandler';
import useMarkupToHtml from './utils/useMarkupToHtml';
import useFormNote, { OnLoadEvent } from './utils/useFormNote';
import useFormNote, { OnLoadEvent, OnSetFormNote } from './utils/useFormNote';
import useEffectiveNoteId from './utils/useEffectiveNoteId';
import useFolder from './utils/useFolder';
import styles_ from './styles';
import { NoteEditorProps, FormNote, ScrollOptions, ScrollOptionTypes, OnChangeEvent, NoteBodyEditorProps, AllAssetsOptions, NoteBodyEditorRef } from './utils/types';
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
import { NoteEditorProps, FormNote, OnChangeEvent, NoteBodyEditorProps, AllAssetsOptions, NoteBodyEditorRef } from './utils/types';
import CommandService from '@joplin/lib/services/CommandService';
import ToolbarButton from '../ToolbarButton/ToolbarButton';
import Button, { ButtonLevel } from '../Button/Button';
@@ -26,7 +25,6 @@ import { _, _n } from '@joplin/lib/locale';
import TagList from '../TagList';
import NoteTitleBar from './NoteTitle/NoteTitleBar';
import markupLanguageUtils from '../../utils/markupLanguageUtils';
import usePrevious from '../hooks/usePrevious';
import Setting from '@joplin/lib/models/Setting';
import stateToWhenClauseContext from '../../services/commands/stateToWhenClauseContext';
import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher';
@@ -37,7 +35,7 @@ import NoteSearchBar from '../NoteSearchBar';
import { reg } from '@joplin/lib/registry';
import Note from '@joplin/lib/models/Note';
import Folder from '@joplin/lib/models/Folder';
const bridge = require('@electron/remote').require('./bridge').default;
import bridge from '../../services/bridge';
import NoteRevisionViewer from '../NoteRevisionViewer';
import { parseShareCache } from '@joplin/lib/services/share/reducer';
import useAsyncEffect from '@joplin/lib/hooks/useAsyncEffect';
@@ -51,6 +49,9 @@ import CodeMirror5 from './NoteBody/CodeMirror/v5/CodeMirror';
import { openItemById } from './utils/contextMenu';
import getPluginSettingValue from '@joplin/lib/services/plugins/utils/getPluginSettingValue';
import { MarkupLanguage } from '@joplin/renderer';
import useScrollWhenReadyOptions from './utils/useScrollWhenReadyOptions';
import useScheduleSaveCallbacks from './utils/useScheduleSaveCallbacks';
const debounce = require('debounce');
const commands = [
require('./commands/showRevisions'),
@@ -61,20 +62,21 @@ const toolbarButtonUtils = new ToolbarButtonUtils(CommandService.instance());
function NoteEditor(props: NoteEditorProps) {
const [showRevisions, setShowRevisions] = useState(false);
const [titleHasBeenManuallyChanged, setTitleHasBeenManuallyChanged] = useState(false);
const [scrollWhenReady, setScrollWhenReady] = useState<ScrollOptions>(null);
const [isReadOnly, setIsReadOnly] = useState<boolean>(false);
const editorRef = useRef<NoteBodyEditorRef>();
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const titleInputRef = useRef<any>();
const titleInputRef = useRef<HTMLInputElement>();
const isMountedRef = useRef(true);
const noteSearchBarRef = useRef(null);
const setFormNoteRef = useRef<OnSetFormNote>();
const { saveNoteIfWillChange, scheduleSaveNote } = useScheduleSaveCallbacks({
setFormNote: setFormNoteRef, dispatch: props.dispatch, editorRef,
});
const formNote_beforeLoad = useCallback(async (event: OnLoadEvent) => {
await saveNoteIfWillChange(event.formNote);
setShowRevisions(false);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
}, [saveNoteIfWillChange]);
const formNote_afterLoad = useCallback(async () => {
setTitleHasBeenManuallyChanged(false);
@@ -92,7 +94,7 @@ function NoteEditor(props: NoteEditorProps) {
onBeforeLoad: formNote_beforeLoad,
onAfterLoad: formNote_afterLoad,
});
setFormNoteRef.current = setFormNote;
const formNoteRef = useRef<FormNote>();
formNoteRef.current = { ...formNote };
@@ -116,53 +118,6 @@ function NoteEditor(props: NoteEditorProps) {
const styles = styles_(props);
function scheduleSaveNote(formNote: FormNote) {
if (!formNote.saveActionQueue) throw new Error('saveActionQueue is not set!!'); // Sanity check
// reg.logger().debug('Scheduling...', formNote);
const makeAction = (formNote: FormNote) => {
return async function() {
const note = await formNoteToNote(formNote);
reg.logger().debug('Saving note...', note);
const savedNote = await Note.save(note);
setFormNote((prev: FormNote) => {
return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false };
});
void ExternalEditWatcher.instance().updateNoteFile(savedNote);
props.dispatch({
type: 'EDITOR_NOTE_STATUS_REMOVE',
id: formNote.id,
});
eventManager.emit(EventName.NoteContentChange, { note: savedNote });
};
};
formNote.saveActionQueue.push(makeAction(formNote));
}
async function saveNoteIfWillChange(formNote: FormNote) {
if (!formNote.id || !formNote.bodyWillChangeId) return;
const body = await editorRef.current.content();
scheduleSaveNote({
...formNote,
body: body,
bodyWillChangeId: 0,
bodyChangeId: 0,
});
}
async function saveNoteAndWait(formNote: FormNote) {
await saveNoteIfWillChange(formNote);
return formNote.saveActionQueue.waitForAllDone();
}
const whiteBackgroundNoteRendering = formNote.markup_language === MarkupLanguage.Html;
const markupToHtml = useMarkupToHtml({
@@ -201,29 +156,18 @@ function NoteEditor(props: NoteEditorProps) {
id: formNote.id,
});
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.isProvisional, formNote.id]);
}, [props.isProvisional, formNote.id, props.dispatch]);
const previousNoteId = usePrevious(formNote.id);
useEffect(() => {
if (formNote.id === previousNoteId) return;
if (editorRef.current) {
editorRef.current.resetScroll();
}
setScrollWhenReady({
type: props.selectedNoteHash ? ScrollOptionTypes.Hash : ScrollOptionTypes.Percent,
value: props.selectedNoteHash ? props.selectedNoteHash : props.lastEditorScrollPercents[formNote.id] || 0,
});
void ResourceEditWatcher.instance().stopWatchingAll();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [formNote.id, previousNoteId]);
const scheduleNoteListResort = useMemo(() => {
return debounce(() => {
// Although the note list will update automatically, it may take some time. This
// forces an immediate update.
props.dispatch({ type: 'NOTE_SORT' });
}, 100);
}, [props.dispatch]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const onFieldChange = useCallback((field: string, value: any, changeId = 0) => {
const onFieldChange = useCallback(async (field: string, value: any, changeId = 0) => {
if (!isMountedRef.current) {
// When the component is unmounted, various actions can happen which can
// trigger onChange events, for example the textarea might be cleared.
@@ -263,19 +207,23 @@ function NoteEditor(props: NoteEditorProps) {
// The previously loaded note, that was modified, will be saved via saveNoteIfWillChange()
} else {
setFormNote(newNote);
scheduleSaveNote(newNote);
await scheduleSaveNote(newNote);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [handleProvisionalFlag, formNote, isNewNote, titleHasBeenManuallyChanged]);
if (field === 'title') {
// Scheduling a resort needs to be:
// - called after scheduleSaveNote so that the new note title is used for sorting
// - debounced because many calls to scheduleSaveNote can resolve at once
scheduleNoteListResort();
}
}, [handleProvisionalFlag, formNote, setFormNote, isNewNote, titleHasBeenManuallyChanged, scheduleNoteListResort, scheduleSaveNote]);
useWindowCommandHandler({
dispatch: props.dispatch,
formNote,
setShowLocalSearch,
noteSearchBarRef,
editorRef,
titleInputRef,
saveNoteAndWait,
setFormNote,
});
@@ -339,10 +287,15 @@ function NoteEditor(props: NoteEditorProps) {
id: formNote.id,
status: 'saving',
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [formNote, handleProvisionalFlag]);
}, [formNote, setFormNote, handleProvisionalFlag, props.dispatch]);
const onMessage = useMessageHandler(scrollWhenReady, setScrollWhenReady, editorRef, setLocalSearchResultCount, props.dispatch, formNote, htmlToMarkdown, markupToHtml);
const { scrollWhenReady, clearScrollWhenReady } = useScrollWhenReadyOptions({
noteId: formNote.id,
selectedNoteHash: props.selectedNoteHash,
lastEditorScrollPercents: props.lastEditorScrollPercents,
editorRef,
});
const onMessage = useMessageHandler(scrollWhenReady, clearScrollWhenReady, editorRef, setLocalSearchResultCount, props.dispatch, formNote, htmlToMarkdown, markupToHtml);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const externalEditWatcher_noteChange = useCallback((event: any) => {
@@ -355,8 +308,7 @@ function NoteEditor(props: NoteEditorProps) {
setFormNote(newFormNote);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [formNote]);
}, [formNote, setFormNote]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const onNotePropertyChange = useCallback((event: any) => {
@@ -373,8 +325,7 @@ function NoteEditor(props: NoteEditorProps) {
return newFormNote;
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
}, [setFormNote]);
useEffect(() => {
eventManager.on(EventName.AlarmChange, onNotePropertyChange);
@@ -409,8 +360,7 @@ function NoteEditor(props: NoteEditorProps) {
});
}, [props.dispatch]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
function renderNoNotes(rootStyle: any) {
function renderNoNotes(rootStyle: React.CSSProperties) {
const emptyDivStyle = {
backgroundColor: 'black',
opacity: 0.1,
@@ -493,7 +443,7 @@ function NoteEditor(props: NoteEditorProps) {
}
const onRichTextReadMoreLinkClick = useCallback(() => {
bridge().openExternal('https://joplinapp.org/help/apps/rich_text_editor');
void bridge().openExternal('https://joplinapp.org/help/apps/rich_text_editor');
}, []);
const onRichTextDismissLinkClick = useCallback(() => {
@@ -521,8 +471,7 @@ function NoteEditor(props: NoteEditorProps) {
if (showRevisions) {
const theme = themeStyle(props.themeId);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const revStyle: any = {
const revStyle: React.CSSProperties = {
// ...props.style,
display: 'inline-flex',
padding: theme.margin,

View File

@@ -36,8 +36,7 @@ interface Props {
noteTitle: string;
noteIsTodo: number;
isProvisional: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
titleInputRef: any;
titleInputRef: React.RefObject<HTMLInputElement>;
onTitleChange(event: ChangeEvent<HTMLInputElement>): void;
disabled: boolean;
}

View File

@@ -6,7 +6,7 @@ import Resource from '@joplin/lib/models/Resource';
const bridge = require('@electron/remote').require('./bridge').default;
import ResourceFetcher from '@joplin/lib/services/ResourceFetcher';
import htmlUtils from '@joplin/lib/htmlUtils';
import rendererHtmlUtils, { extractHtmlBody } from '@joplin/renderer/htmlUtils';
import rendererHtmlUtils, { extractHtmlBody, removeWrappingParagraphAndTrailingEmptyElements } from '@joplin/renderer/htmlUtils';
import Logger from '@joplin/utils/Logger';
import { fileUriToPath } from '@joplin/utils/url';
import { MarkupLanguage } from '@joplin/renderer';
@@ -15,7 +15,7 @@ import markupRenderOptions from './markupRenderOptions';
import { fileExtension, filename, safeFileExtension, safeFilename } from '@joplin/utils/path';
const joplinRendererUtils = require('@joplin/renderer').utils;
const { clipboard } = require('electron');
const mimeUtils = require('@joplin/lib/mime-utils.js').mime;
import * as mimeUtils from '@joplin/lib/mime-utils';
const md5 = require('md5');
const path = require('path');
@@ -220,6 +220,13 @@ export async function processPastedHtml(html: string, htmlToMd: HtmlToMarkdownHa
if (htmlToMd && mdToHtml) {
const md = await htmlToMd(MarkupLanguage.Markdown, html, '');
html = (await mdToHtml(MarkupLanguage.Markdown, md, markupRenderOptions({ bodyOnly: true }))).html;
// When plugins that add to the end of rendered content are installed, bodyOnly can
// fail to remove the wrapping paragraph. This works around that issue by removing
// the wrapping paragraph in more cases. See issue #10061.
if (!md.trim().includes('\n')) {
html = removeWrappingParagraphAndTrailingEmptyElements(html);
}
}
return extractHtmlBody(rendererHtmlUtils.sanitizeHtml(html, {

View File

@@ -1,7 +1,9 @@
import Note from '@joplin/lib/models/Note';
import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
import { renderHook } from '@testing-library/react-hooks';
import { act, renderHook } from '@testing-library/react-hooks';
import useFormNote, { HookDependencies } from './useFormNote';
import shim from '@joplin/lib/shim';
import Resource from '@joplin/lib/models/Resource';
const defaultFormNoteProps: HookDependencies = {
syncStarted: false,
@@ -75,6 +77,8 @@ describe('useFormNote', () => {
title: 'Test Note!',
});
});
formNote.unmount();
});
// It seems this test is crashing the worker on CI (out of memory), so disabling it for now.
@@ -109,4 +113,43 @@ describe('useFormNote', () => {
// });
// });
test('should refresh resource infos when changed outside the editor', async () => {
let note = await Note.save({});
note = await shim.attachFileToNote(note, __filename);
const resourceIds = Note.linkedItemIds(note.body);
const resource = await Resource.load(resourceIds[0]);
const makeFormNoteProps = (syncStarted: boolean, decryptionStarted: boolean): HookDependencies => {
return {
...defaultFormNoteProps,
syncStarted,
decryptionStarted,
noteId: note.id,
};
};
const formNote = renderHook(props => useFormNote(props), {
initialProps: makeFormNoteProps(true, false),
});
await formNote.waitFor(() => {
return Object.values(formNote.result.current.resourceInfos).length > 0;
});
const initialResourceInfos = formNote.result.current.resourceInfos;
expect(initialResourceInfos).toMatchObject({
[resource.id]: { item: { id: resource.id } },
});
await act(async () => {
await Resource.save({ ...resource, filename: 'test.ts' });
});
await formNote.waitFor(() => {
const resourceInfo = formNote.result.current.resourceInfos[resource.id];
expect(resourceInfo.item).toMatchObject({
id: resource.id, filename: 'test.ts',
});
});
formNote.unmount();
});
});

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from 'react';
import { useState, useEffect, useCallback, RefObject, useRef } from 'react';
import { FormNote, defaultFormNote, ResourceInfos } from './types';
import { clearResourceCache, attachedResources } from './resourceHandling';
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
@@ -6,15 +6,17 @@ import { handleResourceDownloadMode } from './resourceHandling';
import { splitHtml } from '@joplin/renderer/HtmlToHtml';
import Setting from '@joplin/lib/models/Setting';
import usePrevious from '../../hooks/usePrevious';
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
const { MarkupToHtml } = require('@joplin/renderer');
import { MarkupToHtml } from '@joplin/renderer';
import Note from '@joplin/lib/models/Note';
import { reg } from '@joplin/lib/registry';
import ResourceFetcher from '@joplin/lib/services/ResourceFetcher';
import DecryptionWorker from '@joplin/lib/services/DecryptionWorker';
import { NoteEntity } from '@joplin/lib/services/database/types';
import { focus } from '@joplin/lib/utils/focusHandler';
import Logger from '@joplin/utils/Logger';
import eventManager, { EventName } from '@joplin/lib/eventManager';
import DecryptionWorker from '@joplin/lib/services/DecryptionWorker';
const logger = Logger.create('useFormNote');
export interface OnLoadEvent {
formNote: FormNote;
@@ -25,28 +27,28 @@ export interface HookDependencies {
decryptionStarted: boolean;
noteId: string;
isProvisional: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
titleInputRef: any;
titleInputRef: RefObject<HTMLInputElement>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
editorRef: any;
onBeforeLoad(event: OnLoadEvent): void;
onAfterLoad(event: OnLoadEvent): void;
}
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
function installResourceChangeHandler(onResourceChangeHandler: Function) {
type MapFormNoteCallback = (previousFormNote: FormNote)=> FormNote;
export type OnSetFormNote = (newFormNote: FormNote|MapFormNoteCallback)=> void;
function installResourceChangeHandler(onResourceChangeHandler: ()=> void) {
ResourceFetcher.instance().on('downloadComplete', onResourceChangeHandler);
ResourceFetcher.instance().on('downloadStarted', onResourceChangeHandler);
DecryptionWorker.instance().on('resourceDecrypted', onResourceChangeHandler);
ResourceEditWatcher.instance().on('resourceChange', onResourceChangeHandler);
eventManager.on(EventName.ResourceChange, onResourceChangeHandler);
}
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
function uninstallResourceChangeHandler(onResourceChangeHandler: Function) {
function uninstallResourceChangeHandler(onResourceChangeHandler: ()=> void) {
ResourceFetcher.instance().off('downloadComplete', onResourceChangeHandler);
ResourceFetcher.instance().off('downloadStarted', onResourceChangeHandler);
DecryptionWorker.instance().off('resourceDecrypted', onResourceChangeHandler);
ResourceEditWatcher.instance().off('resourceChange', onResourceChangeHandler);
eventManager.off(EventName.ResourceChange, onResourceChangeHandler);
}
function resourceInfosChanged(a: ResourceInfos, b: ResourceInfos): boolean {
@@ -77,11 +79,14 @@ export default function useFormNote(dependencies: HookDependencies) {
const previousNoteId = usePrevious(formNote.id);
const [resourceInfos, setResourceInfos] = useState<ResourceInfos>({});
const formNoteRef = useRef(formNote);
formNoteRef.current = formNote;
// Increasing the value of this counter cancels any ongoing note refreshes and starts
// a new refresh.
const [formNoteRefreshScheduled, setFormNoteRefreshScheduled] = useState<number>(0);
async function initNoteState(n: NoteEntity) {
const initNoteState = useCallback(async (n: NoteEntity, isNewNote: boolean) => {
let originalCss = '';
if (n.markup_language === MarkupToHtml.MARKUP_LANGUAGE_HTML) {
@@ -106,22 +111,39 @@ export default function useFormNote(dependencies: HookDependencies) {
encryption_applied: n.encryption_applied,
};
logger.debug('Initializing note state');
// Note that for performance reason,the call to setResourceInfos should
// be first because it loads the resource infos in an async way. If we
// swap them, the formNote will be updated first and rendered, then the
// the resources will load, and the note will be re-rendered.
setResourceInfos(await attachedResources(n.body));
const resources = await attachedResources(n.body);
// If the user changes the note while resources are loading, this can lead to
// a note being incorrectly marked as "unchanged".
if (!isNewNote && formNoteRef.current?.hasChanged) {
logger.info('Cancelled note refresh -- form note changed while loading attached resources.');
return null;
}
setResourceInfos(resources);
setFormNote(newFormNote);
logger.debug('Resource info and form note set.');
await handleResourceDownloadMode(n.body);
return newFormNote;
}
}, []);
useEffect(() => {
if (formNoteRefreshScheduled <= 0) return () => {};
if (formNoteRef.current.hasChanged) {
logger.info('Form note changed between scheduling a refresh and the refresh itself. Cancelling the refresh.');
return () => {};
}
reg.logger().info('Sync has finished and note has never been changed - reloading it');
logger.info('Sync has finished and note has never been changed - reloading it');
let cancelled = false;
@@ -133,11 +155,12 @@ export default function useFormNote(dependencies: HookDependencies) {
// it would not have been loaded in the editor (due to note selection changing
// on delete)
if (!n) {
reg.logger().warn('Trying to reload note that has been deleted:', noteId);
logger.warn('Trying to reload note that has been deleted:', noteId);
return;
}
await initNoteState(n);
await initNoteState(n, false);
setFormNoteRefreshScheduled(0);
};
@@ -146,7 +169,7 @@ export default function useFormNote(dependencies: HookDependencies) {
return () => {
cancelled = true;
};
}, [formNoteRefreshScheduled, noteId]);
}, [formNoteRefreshScheduled, noteId, initNoteState]);
const refreshFormNote = useCallback(() => {
// Increase the counter to cancel any ongoing refresh attempts
@@ -163,7 +186,9 @@ export default function useFormNote(dependencies: HookDependencies) {
const syncJustEnded = prevSyncStarted && !syncStarted;
if (!decryptionJustEnded && !syncJustEnded) return;
if (formNote.hasChanged) return;
if (formNoteRef.current.hasChanged) return;
logger.debug('Sync or decryption finished with an unchanged formNote.');
// Refresh the form note.
// This is kept separate from the above logic so that when prevSyncStarted is changed
@@ -172,7 +197,7 @@ export default function useFormNote(dependencies: HookDependencies) {
}, [
prevSyncStarted, syncStarted,
prevDecryptionStarted, decryptionStarted,
formNote.hasChanged, refreshFormNote,
refreshFormNote,
]);
useEffect(() => {
@@ -185,7 +210,7 @@ export default function useFormNote(dependencies: HookDependencies) {
let cancelled = false;
reg.logger().debug('Loading existing note', noteId);
logger.debug('Loading existing note', noteId);
function handleAutoFocus(noteIsTodo: boolean) {
if (!isProvisional) return;
@@ -205,11 +230,11 @@ export default function useFormNote(dependencies: HookDependencies) {
const n = await Note.load(noteId);
if (cancelled) return;
if (!n) throw new Error(`Cannot find note with ID: ${noteId}`);
reg.logger().debug('Loaded note:', n);
logger.debug('Loaded note:', n);
await onBeforeLoad({ formNote });
const newFormNote = await initNoteState(n);
const newFormNote = await initNoteState(n, true);
setIsNewNote(isProvisional);
@@ -231,7 +256,8 @@ export default function useFormNote(dependencies: HookDependencies) {
const resourceIds = await Note.linkedResourceIds(formNote.body);
if (!event || resourceIds.indexOf(event.id) >= 0) {
clearResourceCache();
setResourceInfos(await attachedResources(formNote.body));
const newResourceInfos = await attachedResources(formNote.body);
setResourceInfos(newResourceInfos);
}
}, [formNote.body]);
@@ -266,5 +292,24 @@ export default function useFormNote(dependencies: HookDependencies) {
};
}, [formNote.body]);
return { isNewNote, formNote, setFormNote, resourceInfos };
// Currently, useFormNote relies on formNoteRef being up-to-date immediately after the editor
// changes, with no delay during which async code can run. Even a small delay (e.g. that introduced
// by a setState -> useEffect) can lead to a race condition. See https://github.com/laurent22/joplin/issues/8960.
const onSetFormNote: OnSetFormNote = useCallback(newFormNote => {
if (typeof newFormNote === 'function') {
const newNote = newFormNote(formNoteRef.current);
formNoteRef.current = newNote;
setFormNote(newNote);
} else {
formNoteRef.current = newFormNote;
setFormNote(newFormNote);
}
}, [setFormNote]);
return {
isNewNote,
formNote,
setFormNote: onSetFormNote,
resourceInfos,
};
}

View File

@@ -25,7 +25,6 @@ export default function useMarkupToHtml(deps: HookDependencies) {
resourceBaseUrl: `file://${Setting.value('resourceDir')}/`,
customCss: customCss || '',
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [plugins, customCss]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
@@ -63,6 +62,5 @@ export default function useMarkupToHtml(deps: HookDependencies) {
});
return result;
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [themeId, customCss, markupToHtml, whiteBackgroundNoteRendering]);
}, [themeId, markupToHtml, whiteBackgroundNoteRendering, deps.settingValue]);
}

View File

@@ -1,5 +1,5 @@
import { useCallback } from 'react';
import { FormNote, HtmlToMarkdownHandler, MarkupToHtmlHandler } from './types';
import { FormNote, HtmlToMarkdownHandler, MarkupToHtmlHandler, ScrollOptions } from './types';
import contextMenu from './contextMenu';
import CommandService from '@joplin/lib/services/CommandService';
import PostMessageService from '@joplin/lib/services/PostMessageService';
@@ -8,7 +8,7 @@ import { reg } from '@joplin/lib/registry';
const bridge = require('@electron/remote').require('./bridge').default;
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied
export default function useMessageHandler(scrollWhenReady: any, setScrollWhenReady: Function, editorRef: any, setLocalSearchResultCount: Function, dispatch: Function, formNote: FormNote, htmlToMd: HtmlToMarkdownHandler, mdToHtml: MarkupToHtmlHandler) {
export default function useMessageHandler(scrollWhenReady: ScrollOptions|null, clearScrollWhenReady: ()=> void, editorRef: any, setLocalSearchResultCount: Function, dispatch: Function, formNote: FormNote, htmlToMd: HtmlToMarkdownHandler, mdToHtml: MarkupToHtmlHandler) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
return useCallback(async (event: any) => {
const msg = event.channel ? event.channel : '';
@@ -25,7 +25,7 @@ export default function useMessageHandler(scrollWhenReady: any, setScrollWhenRea
} else if (msg === 'noteRenderComplete') {
if (scrollWhenReady) {
const options = { ...scrollWhenReady };
setScrollWhenReady(null);
clearScrollWhenReady();
editorRef.current.scrollTo(options);
}
} else if (msg === 'setMarkerCount') {

View File

@@ -0,0 +1,66 @@
import Logger from '@joplin/utils/Logger';
import { RefObject, useCallback } from 'react';
import { FormNote, NoteBodyEditorRef } from './types';
import { formNoteToNote } from '.';
import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher';
import Note from '@joplin/lib/models/Note';
import type { Dispatch } from 'redux';
import eventManager, { EventName } from '@joplin/lib/eventManager';
import type { OnSetFormNote } from './useFormNote';
const logger = Logger.create('useScheduleSaveCallbacks');
interface Props {
setFormNote: RefObject<OnSetFormNote>;
dispatch: Dispatch;
editorRef: RefObject<NoteBodyEditorRef>;
}
const useScheduleSaveCallbacks = (props: Props) => {
const scheduleSaveNote = useCallback((formNote: FormNote) => {
if (!formNote.saveActionQueue) throw new Error('saveActionQueue is not set!!'); // Sanity check
// reg.logger().debug('Scheduling...', formNote);
const makeAction = (formNote: FormNote) => {
return async function() {
const note = await formNoteToNote(formNote);
logger.debug('Saving note...', note);
const savedNote = await Note.save(note);
props.setFormNote.current((prev: FormNote) => {
return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false };
});
void ExternalEditWatcher.instance().updateNoteFile(savedNote);
props.dispatch({
type: 'EDITOR_NOTE_STATUS_REMOVE',
id: formNote.id,
});
eventManager.emit(EventName.NoteContentChange, { note: savedNote });
};
};
formNote.saveActionQueue.push(makeAction(formNote));
return formNote.saveActionQueue.waitForAllDone();
}, [props.dispatch, props.setFormNote]);
const saveNoteIfWillChange = useCallback(async (formNote: FormNote) => {
if (!formNote.id || !formNote.bodyWillChangeId) return;
const body = await props.editorRef.current.content();
void scheduleSaveNote({
...formNote,
body: body,
bodyWillChangeId: 0,
bodyChangeId: 0,
});
}, [scheduleSaveNote, props.editorRef]);
return { saveNoteIfWillChange, scheduleSaveNote };
};
export default useScheduleSaveCallbacks;

View File

@@ -0,0 +1,44 @@
import { RefObject, useCallback, useEffect, useRef, useState } from 'react';
import { NoteBodyEditorRef, ScrollOptions, ScrollOptionTypes } from './types';
import usePrevious from '@joplin/lib/hooks/usePrevious';
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher';
import type { EditorScrollPercents } from '../../../app.reducer';
interface Props {
noteId: string;
selectedNoteHash: string;
lastEditorScrollPercents: EditorScrollPercents;
editorRef: RefObject<NoteBodyEditorRef>;
}
const useScrollWhenReadyOptions = ({ noteId, selectedNoteHash, lastEditorScrollPercents, editorRef }: Props) => {
const [scrollWhenReady, setScrollWhenReady] = useState<ScrollOptions|null>(null);
const previousNoteId = usePrevious(noteId);
const lastScrollPercentsRef = useRef<EditorScrollPercents>();
lastScrollPercentsRef.current = lastEditorScrollPercents;
useEffect(() => {
if (noteId === previousNoteId) return;
if (editorRef.current) {
editorRef.current.resetScroll();
}
const lastScrollPercent = lastScrollPercentsRef.current[noteId] || 0;
setScrollWhenReady({
type: selectedNoteHash ? ScrollOptionTypes.Hash : ScrollOptionTypes.Percent,
value: selectedNoteHash ? selectedNoteHash : lastScrollPercent,
});
void ResourceEditWatcher.instance().stopWatchingAll();
}, [noteId, previousNoteId, selectedNoteHash, editorRef]);
const clearScrollWhenReady = useCallback(() => {
setScrollWhenReady(null);
}, []);
return { scrollWhenReady, clearScrollWhenReady };
};
export default useScrollWhenReadyOptions;

View File

@@ -15,7 +15,6 @@ const commandsWithDependencies = [
type SetFormNoteCallback = (callback: (prev: FormNote)=> FormNote)=> void;
interface HookDependencies {
formNote: FormNote;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
setShowLocalSearch: Function;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
@@ -23,10 +22,7 @@ interface HookDependencies {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
noteSearchBarRef: any;
editorRef: RefObject<NoteBodyEditorRef>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
titleInputRef: any;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
saveNoteAndWait: Function;
titleInputRef: RefObject<HTMLInputElement>;
setFormNote: SetFormNoteCallback;
}
@@ -109,6 +105,5 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
CommandService.instance().unregisterRuntime(command.declaration.name);
}
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [editorRef, setShowLocalSearch, noteSearchBarRef, titleInputRef]);
}, [editorRef, setShowLocalSearch, noteSearchBarRef, titleInputRef, setFormNote]);
}

View File

@@ -65,7 +65,7 @@ const NoteList = (props: Props) => {
props.notes.length,
);
const focusNote = useFocusNote(itemRefs);
const focusNote = useFocusNote(itemRefs, props.notes, makeItemIndexVisible);
const moveNote = useMoveNote(
props.notesParentType,

View File

@@ -1,19 +1,31 @@
import shim from '@joplin/lib/shim';
import { useRef, useCallback, MutableRefObject } from 'react';
import { focus } from '@joplin/lib/utils/focusHandler';
import { NoteEntity } from '@joplin/lib/services/database/types';
export type FocusNote = (noteId: string)=> void;
type ItemRefs = MutableRefObject<Record<string, HTMLDivElement>>;
type OnMakeIndexVisible = (i: number)=> void;
const useFocusNote = (itemRefs: MutableRefObject<Record<string, HTMLDivElement>>) => {
const useFocusNote = (itemRefs: ItemRefs, notes: NoteEntity[], makeItemIndexVisible: OnMakeIndexVisible) => {
const focusItemIID = useRef(null);
const notesRef = useRef(notes);
notesRef.current = notes;
const focusNote: FocusNote = useCallback((noteId: string) => {
// - We need to focus the item manually otherwise focus might be lost when the
// list is scrolled and items within it are being rebuilt.
// - We need to use an interval because when leaving the arrow pressed, the rendering
// of items might lag behind and so the ref is not yet available at this point.
// - We need to use an interval because when leaving the arrow pressed or scrolling
// offscreen items into view, the rendering of items might lag behind and so the
// ref is not yet available at this point.
if (!itemRefs.current[noteId]) {
const targetIndex = notesRef.current.findIndex(note => note.id === noteId);
if (targetIndex > -1) {
makeItemIndexVisible(targetIndex);
}
if (focusItemIID.current) shim.clearInterval(focusItemIID.current);
focusItemIID.current = shim.setInterval(() => {
if (itemRefs.current[noteId]) {
@@ -26,7 +38,7 @@ const useFocusNote = (itemRefs: MutableRefObject<Record<string, HTMLDivElement>>
if (focusItemIID.current) shim.clearInterval(focusItemIID.current);
focus('useFocusNote2', itemRefs.current[noteId]);
}
}, [itemRefs]);
}, [itemRefs, makeItemIndexVisible]);
return focusNote;
};

View File

@@ -7,6 +7,7 @@ const { themeStyle } = require('@joplin/lib/theme');
import bridge from '../services/bridge';
const prettyBytes = require('pretty-bytes');
import Resource from '@joplin/lib/models/Resource';
import { LoadOptions } from '@joplin/lib/models/utils/types';
interface Style {
width: number;
@@ -31,6 +32,7 @@ interface State {
resources: InnerResource[] | undefined;
sorting: ActiveSorting;
isLoading: boolean;
filter: string;
}
interface ResourceTable {
@@ -42,6 +44,7 @@ interface ResourceTable {
onResourceDelete: (resource: InnerResource)=> any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onToggleSorting: (order: SortingOrder)=> any;
filter: string;
themeId: number;
style: Style;
}
@@ -89,6 +92,10 @@ const ResourceTableComp = (props: ResourceTable) => {
fontWeight: 'bold',
};
const filteredResources = props.resources.filter(
(resource: InnerResource) => !props.filter || resource.title?.includes(props.filter) || resource.id.includes(props.filter),
);
return (
<table style={{ width: '100%' }}>
<thead>
@@ -100,7 +107,7 @@ const ResourceTableComp = (props: ResourceTable) => {
</tr>
</thead>
<tbody>
{props.resources.map((resource: InnerResource, index: number) =>
{filteredResources.map((resource: InnerResource, index: number) =>
<tr key={index}>
<td style={titleCellStyle} className="titleCell">
<a
@@ -136,13 +143,15 @@ const getNextSortingOrderType = (s: SortingType): SortingType => {
}
};
const MAX_RESOURCES = 10000;
const defaultMaxResources = 10000;
const searchMaxResources = 1000;
class ResourceScreenComponent extends React.Component<Props, State> {
public constructor(props: Props) {
super(props);
this.state = {
resources: undefined,
filter: '',
sorting: {
type: 'asc',
order: 'name',
@@ -151,22 +160,57 @@ class ResourceScreenComponent extends React.Component<Props, State> {
};
}
public async reloadResources(sorting: ActiveSorting) {
private get maxResources() {
// Use a smaller maximum when searching for performance -- results update
// when the search input changes.
if (this.state.filter) {
return searchMaxResources;
} else {
return defaultMaxResources;
}
}
private reloadResourcesCounter = 0;
public async reloadResources() {
this.setState({ isLoading: true });
this.reloadResourcesCounter ++;
const currentCounterValue = this.reloadResourcesCounter;
let searchOptions: Partial<LoadOptions> = {};
if (this.state.filter) {
const search = `%${this.state.filter}%`;
searchOptions = {
where: 'id LIKE ? OR title LIKE ?',
whereParams: [search, search],
};
}
const resources = await Resource.all({
order: [{
by: getSortingOrderColumn(sorting.order),
dir: sorting.type,
by: getSortingOrderColumn(this.state.sorting.order),
dir: this.state.sorting.type,
caseInsensitive: true,
}],
limit: MAX_RESOURCES,
limit: this.maxResources,
fields: ['title', 'id', 'size', 'file_extension'],
...searchOptions,
});
const cancelled = currentCounterValue !== this.reloadResourcesCounter;
if (cancelled) return;
this.setState({ resources, isLoading: false });
}
public componentDidMount() {
void this.reloadResources(this.state.sorting);
void this.reloadResources();
}
public componentDidUpdate(_prevProps: Props, prevState: State) {
if (prevState.sorting !== this.state.sorting || prevState.filter !== this.state.filter) {
void this.reloadResources();
}
}
public onResourceDelete(resource: InnerResource) {
@@ -185,7 +229,7 @@ class ResourceScreenComponent extends React.Component<Props, State> {
})
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
.finally(() => {
void this.reloadResources(this.state.sorting);
void this.reloadResources();
});
}
@@ -208,9 +252,12 @@ class ResourceScreenComponent extends React.Component<Props, State> {
};
}
this.setState({ sorting: newSorting });
void this.reloadResources(newSorting);
}
public onFilterUpdate = (updateEvent: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ filter: updateEvent.target.value });
};
public render() {
const style = this.props.style;
const theme = themeStyle(this.props.themeId);
@@ -236,20 +283,30 @@ class ResourceScreenComponent extends React.Component<Props, State> {
<div style={{ ...theme.notificationBox, marginBottom: 10 }}>{
_('This is an advanced tool to show the attachments that are linked to your notes. Please be careful when deleting one of them as they cannot be restored afterwards.')
}</div>
<div style={{ float: 'right' }}>
<input
style={theme.inputStyle}
type="search"
value={this.state.filter}
onChange={this.onFilterUpdate}
placeholder={_('Search...')}
/>
</div>
{this.state.isLoading && <div>{_('Please wait...')}</div>}
{!this.state.isLoading && <div>
{!this.state.resources && <div>
{_('No resources!')}
</div>
}
{this.state.resources && this.state.resources.length === MAX_RESOURCES &&
<div>{_('Warning: not all resources shown for performance reasons (limit: %s).', MAX_RESOURCES)}</div>
{this.state.resources && this.state.resources.length === this.maxResources &&
<div>{_('Warning: not all resources shown for performance reasons (limit: %s).', this.maxResources)}</div>
}
{this.state.resources && <ResourceTableComp
themeId={this.props.themeId}
style={style}
resources={this.state.resources}
sorting={this.state.sorting}
filter={this.state.filter}
onToggleSorting={(order) => this.onToggleSortOrder(order)}
onResourceClick={(resource) => this.openResource(resource)}
onResourceDelete={(resource) => this.onResourceDelete(resource)}

View File

@@ -84,6 +84,11 @@ export const StyledListItemAnchor = styled.a`
align-items: center;
user-select: none;
height: 100%;
/* A different background color is already used to indicate focus for sidebar list items. */
&:focus-visible {
outline: none;
}
`;
export const StyledShareIcon = styled.i`

View File

@@ -34,6 +34,7 @@ export default function() {
'toggleExternalEditing',
'toggleLayoutMoveMode',
'resetLayout',
'toggleMenuBar',
'toggleNoteList',
'toggleNotesSortOrderField',
'toggleNotesSortOrderReverse',

View File

@@ -207,7 +207,7 @@
for (const [assetId, asset] of Object.entries(pluginAssetsAdded_)) {
if (!processedAssetIds.includes(assetId)) {
try {
asset.element.remove();
if (asset?.element) asset.element.remove();
} catch (error) {
// We don't throw an exception but we log it since
// it shouldn't happen

View File

@@ -1,6 +1,5 @@
import { utils as pluginUtils, PluginStates } from '@joplin/lib/services/plugins/reducer';
import CommandService from '@joplin/lib/services/CommandService';
import eventManager, { EventName } from '@joplin/lib/eventManager';
import InteropService from '@joplin/lib/services/interop/InteropService';
import MenuUtils from '@joplin/lib/services/commands/MenuUtils';
import InteropServiceHelper from '../../InteropServiceHelper';
@@ -78,7 +77,6 @@ export default class NoteListUtils {
const newNote = Note.changeNoteType(note, type);
if (newNote === note) continue;
await Note.save(newNote, { userSideValidation: true });
eventManager.emit(EventName.NoteTypeToggle, { noteId: note.id });
}
};

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