1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-24 20:19:10 +02:00

Compare commits

...

685 Commits

Author SHA1 Message Date
Laurent Cozic
7a985c2c8a Android release v1.0.103 2018-03-02 18:15:09 +00:00
Laurent Cozic
b11ad30a31 Updated translations 2018-03-02 18:12:58 +00:00
Laurent Cozic
5914fc97df Merge branch 'master' of github.com:laurent22/joplin 2018-03-02 18:03:28 +00:00
Laurent Cozic
e41ae1832d Minor tweaks 2018-03-02 18:24:02 +00:00
Laurent Cozic
89b50909ed Electron: Resolves #266: Allow setting text editor font family 2018-03-02 18:16:48 +00:00
Laurent Cozic
edccd7412f Merge pull request #265 from jaredcrowe/docs-correct-checkbox-syntax
correct the documentation about adding checkboxes
2018-03-02 17:59:33 +00:00
Jared Crowe
c76beae057 correct the documentation about adding checkboxes 2018-03-02 09:30:27 +11:00
Laurent Cozic
23c5934a7d Electron: Allow exporting only selected notes or notebook 2018-03-01 20:14:06 +00:00
Laurent Cozic
a078947d6d Allow importing and exporting single notes and notebooks 2018-03-01 18:35:17 +00:00
Laurent Cozic
5ba98b4200 CLI v1.0.100 2018-02-28 21:18:27 +00:00
Laurent Cozic
c36513b99d Updated translation 2018-02-28 20:46:15 +00:00
Laurent Cozic
97814531fa Update readme downloads 2018-02-28 20:06:06 +00:00
Laurent Cozic
fd3e335a02 Electron release v1.0.70 2018-02-28 18:57:10 +00:00
Laurent Cozic
e676fa2b57 Trying to fix Electron builder 2018-02-28 18:56:57 +00:00
Laurent Cozic
122cbbf673 Electron release v1.0.69 2018-02-28 18:43:12 +00:00
Laurent Cozic
271793b324 Trying to upgrade Electron Builder 2018-02-28 18:43:03 +00:00
Laurent Cozic
134b31933b Electron release v1.0.68 2018-02-28 18:13:02 +00:00
Laurent Cozic
0ec5518a62 Android release v1.0.102 2018-02-28 18:10:33 +00:00
Laurent Cozic
76931370d7 Updated readme for import/export 2018-02-27 22:15:20 +00:00
Laurent Cozic
8cf0e4517a Merge branch 'master' of github.com:laurent22/joplin 2018-02-28 17:27:06 +00:00
Laurent Cozic
e75c62bf0f Electron: Fix logic of hidding app in macOS 2018-02-27 21:54:40 +00:00
Laurent Cozic
058285e0b9 All: Made scheduled sync delay slightly shorter 2018-02-27 21:19:11 +00:00
Laurent Cozic
795568d8c2 Electron: Fixed note sorting bug 2018-02-27 21:11:53 +00:00
Laurent Cozic
df4933fddd All: Prevent export of encrypted items 2018-02-27 20:51:07 +00:00
Laurent Cozic
4046a51472 Electron: Handle import export 2018-02-27 20:04:38 +00:00
Laurent Cozic
45845f645d Refactored Interop service to make export/import code more modular 2018-02-26 19:25:54 +00:00
Laurent Cozic
d7fd8944f7 Moved Enex import to InteropService 2018-02-26 19:16:01 +00:00
Laurent Cozic
3cee671f25 Done MD importer 2018-02-26 18:43:50 +00:00
Laurent Cozic
8f2e5faff3 Support importing JEX and raw data 2018-02-25 17:01:16 +00:00
Laurent Cozic
39ddd934f6 Changed export format extension to JEX and made it a non-compressed tar file 2018-02-25 21:08:40 +00:00
Laurent Cozic
9f8a46b9d9 All: Added more export options including jpz format 2018-02-23 19:32:19 +00:00
Laurent Cozic
c6698eaea6 Electron: Fixes #256: Check that no other instance of Joplin is running before launching a new one 2018-02-23 17:51:23 +00:00
Laurent Cozic
8a96cf3434 All: Allow sorting notes by various fields 2018-02-22 18:58:15 +00:00
Laurent Cozic
74d255c056 Updated readme 2018-02-21 18:19:22 +00:00
Laurent Cozic
71aa841265 Mobile: Fixes #244: When accessing configuration or encrypt configuration option while making a note and the going back, the note gets erased 2018-02-21 22:08:34 +00:00
Laurent Cozic
14a93a9f26 All: Fixed sync interval sorting order 2018-02-21 19:58:28 +00:00
Laurent Cozic
e1fd9c6922 Clean up 2018-02-21 19:20:33 +00:00
Laurent Cozic
b9db747b5c Minor refactoring to make function purpose clearer 2018-02-21 18:36:29 +00:00
Laurent Cozic
4a56c76901 Electron: Fixes #247: Unreadable error messages when checking for updates 2018-02-20 18:07:31 +00:00
Laurent Cozic
6bb3184a72 macOS: Resolves #243: Added black and white tray icon for macOS 2018-02-20 00:41:52 +00:00
Laurent Cozic
7fb8fbd450 iOS: Added compatibility with iPad 2018-02-19 23:41:53 +00:00
Laurent Cozic
9d5bba472e iOS v1.0.13 2018-02-19 23:41:12 +00:00
Laurent Cozic
e6d821a45f CLI v1.0.99 2018-02-19 22:59:09 +00:00
Laurent Cozic
72f0027e21 Electron release v1.0.67 2018-02-19 21:05:43 +00:00
Laurent Cozic
29a13a9943 Android release v1.0.101 2018-02-19 21:04:27 +00:00
Laurent Cozic
3691ae4d13 Electron: Fixes #217: Display a message when the note has no content and only the note viewer is visible 2018-02-19 18:56:56 +00:00
Laurent Cozic
4dda397c29 Removed es_CR translation as it's unfortunately too incomplete and there's already a 100% Spanish translation 2018-02-19 18:44:41 +00:00
Laurent Cozic
b4b058998d Updated French and Español translation 2018-02-19 18:41:39 +00:00
Laurent Cozic
10919e415e Merge branch 'master' of github.com:laurent22/joplin 2018-02-19 18:38:56 +00:00
Laurent Cozic
4966d74864 All: Fixes #240: Tags should be handled in a case-insensitive way 2018-02-19 18:38:27 +00:00
Laurent Cozic
c70ecb30a5 All: Fixes #241: Ignore response for certain calls. Also re-enabled If-None-Match fix. 2018-02-19 18:37:44 +00:00
Laurent Cozic
acc0d17e0f Minor changes 2018-02-19 18:36:31 +00:00
Laurent Cozic
b509b878bf Merge pull request #238 from fmrtn/master
Improved Spanish translations
2018-02-19 18:02:58 +00:00
Laurent Cozic
322ec2efa1 Android release v1.0.100 2018-02-18 22:58:37 +00:00
Laurent Cozic
1232661b1e Electron release v1.0.66 2018-02-18 22:56:57 +00:00
Laurent Cozic
c46d123503 All: Fixed: Local items were no longer being deleted via sync. Also fixed Nextcloud sync target. 2018-02-18 21:52:07 +00:00
Laurent Cozic
8f4060999f Merge branch 'master' of github.com:laurent22/joplin 2018-02-18 21:16:26 +00:00
Laurent Cozic
0addd86069 iOS: Improved compatbility with some WebDAV services (Seafile) 2018-02-18 21:16:18 +00:00
Fernando
760086307b Improved Spanish translations 2018-02-18 17:15:18 +01:00
Laurent Cozic
fc6558a64c Electron release v1.0.65 2018-02-17 19:29:26 +00:00
Laurent Cozic
eca500880d All: Convert new lines in tables to BR tag, and added support for HTML tags in Markdown viewers 2018-02-17 19:29:10 +00:00
Laurent Cozic
90bcd7c977 Merge pull request #226 from fmrtn/master
Nextcloud typos and Spanish update
2018-02-17 11:05:25 +00:00
Fernando
cca0c6eaf3 Updated Spanish translation 2018-02-17 01:09:32 +01:00
Fernando
b0736002be Fixed several Nextcloud typos 2018-02-17 01:09:00 +01:00
Laurent Cozic
51fc2d8e51 CLI v1.0.98 2018-02-16 23:49:22 +00:00
Laurent Cozic
d87c192ff1 Updated readme and translation 2018-02-16 23:26:31 +00:00
Laurent Cozic
52ccf398a6 Update readme 2018-02-16 23:17:55 +00:00
Laurent Cozic
344d0e2687 Update readme 2018-02-16 23:14:26 +00:00
Laurent Cozic
1bc4d6b423 CLI v1.0.97 2018-02-16 23:08:57 +00:00
Laurent Cozic
baa9ca7ea3 Updated terminal readme 2018-02-16 23:08:04 +00:00
Laurent Cozic
e4d477fb4c CLI: Resolve #63: Allow customizing shortcuts 2018-02-16 22:53:53 +00:00
Laurent Cozic
71319eee28 Also add link to po file in translation table 2018-02-16 21:45:28 +00:00
Laurent Cozic
68b31526f8 Updated translations 2018-02-16 21:39:54 +00:00
Laurent Cozic
0b2b7324d9 Merge pull request #224 from fmrtn/master
Fixed and updated Spanish translation
2018-02-16 20:35:46 +00:00
Fernando
43512cf27b Fixed and updated Spanish translation 2018-02-16 20:36:58 +01:00
Laurent Cozic
4218b65969 Electron: Added several keyboard shortcuts 2018-02-16 18:08:02 +00:00
Laurent Cozic
7244e12b78 Electron: Fixed: Confirmation message boxes, and release notes text 2018-02-16 18:06:02 +00:00
Laurent Cozic
a796ef5c66 All: Fixed: Notify DecryptionWorker when item added due to conflict, to make sure it is decrypted as early as possible 2018-02-16 17:55:50 +00:00
Laurent Cozic
9474a05aaa Update readme 2018-02-16 00:17:05 +00:00
Laurent Cozic
41df355a7e CLI v1.0.96 2018-02-15 23:51:00 +00:00
Laurent Cozic
4f3ab87914 Electron release v1.0.64 2018-02-15 23:21:47 +00:00
Laurent Cozic
5d1a08707c Android release v1.0.98 2018-02-15 23:20:28 +00:00
Laurent Cozic
4f822df80e Merge branch 'master' of github.com:laurent22/joplin 2018-02-15 23:05:34 +00:00
Laurent Cozic
951be5cbf6 Electron: Fixes #201, Fixes #216: Make sure only one update check can run at a time, and improved modal dialog boxes 2018-02-15 23:05:04 +00:00
Laurent Cozic
b6c2341542 Merge pull request #219 from fmrtn/patch-1
Update README.md
2018-02-15 18:33:48 +00:00
Laurent Cozic
a6e6b49a9d Merge branch 'master' of github.com:laurent22/joplin 2018-02-15 18:33:21 +00:00
Laurent Cozic
3a4bbd571e All: Provide Content-Length header for WebDAV for better compatibility with more servers 2018-02-15 18:33:08 +00:00
Laurent Cozic
feccc6150e Merge branch 'master' of github.com:laurent22/joplin 2018-02-15 18:19:11 +00:00
Laurent Cozic
a37b599a6b macOS: Allow copy and paste from config and encryption screen 2018-02-15 18:19:00 +00:00
Laurent Cozic
9347683fe3 All: Fixed Nextcloud sync target ID (which was incorrectly set to WebDAV sync ID) 2018-02-15 18:01:05 +00:00
Laurent Cozic
3551c26e28 Fixed race condition when testing with memory driver and fixed encoding issue 2018-02-15 17:12:09 +00:00
Fernando
cfca0107eb Update README.md 2018-02-15 13:09:59 +01:00
Laurent Cozic
81bc975193 Update readme 2018-02-14 21:54:34 +00:00
Laurent Cozic
7908fda451 Android release v1.0.97 2018-02-14 19:11:35 +00:00
Laurent Cozic
cdbb7c4b0d Merge branch 'master' of github.com:laurent22/joplin 2018-02-14 19:10:42 +00:00
Laurent Cozic
414e57ec55 Electron release v1.0.63 2018-02-14 19:08:24 +00:00
Laurent Cozic
1871123066 All: Improved WebDAV driver compatibility with some services (eg. Seafile) 2018-02-14 19:08:07 +00:00
Laurent Cozic
87bc08bef5 iOS: Fixed resource decryption issue, log page crash and text input rendering issue 2018-02-14 15:28:56 +00:00
Laurent Cozic
214a39c3d3 All: Improved the way settings are changed. Should also fixed issue with sync context being accidentally broken. 2018-02-13 18:26:33 +00:00
Laurent Cozic
ef0cc5e33e Update readme 2018-02-12 20:23:16 +00:00
Laurent Cozic
3a1fa583ab CLI v1.0.95 2018-02-12 18:07:20 +00:00
Laurent Cozic
c1161ae017 Android release v1.0.95 2018-02-12 17:58:55 +00:00
Laurent Cozic
1023ec6206 Electron release v1.0.62 2018-02-12 17:56:42 +00:00
Laurent Cozic
7841421c0d All: Fixes #209: Items with non-ASCII characters end up truncated on Nextcloud 2018-02-12 18:15:22 +00:00
Laurent Cozic
995d8c35dd Updated readme 2018-02-11 20:49:28 +00:00
Laurent Cozic
b179471eff Electron: Fixes #205: Importing Evernote notes while on import page re-imports previous import 2018-02-11 20:31:26 +00:00
Laurent Cozic
19a126ebfe Android release v1.0.94 2018-02-11 17:29:09 +00:00
Laurent Cozic
7e56e5b587 Mobile: Fixes #207: Crash when changing dropdown value in config screen 2018-02-11 17:26:20 +00:00
Laurent Cozic
acf0c79341 Graduated E2EE and WebDAV from beta, and moved to v1.0 2018-02-11 13:50:59 +00:00
Laurent Cozic
9fe7e23ffe Android release v0.10.92 2018-02-11 13:20:32 +00:00
Laurent Cozic
c94cc93971 Fixed translator names 2018-02-10 13:03:01 +00:00
Laurent Cozic
b26094eba8 Fixed Basque flag 2018-02-10 12:52:57 +00:00
Laurent Cozic
89a5ccdf93 Added Basque translation, fixed issue with handling invalid translations. Updated translation FR. 2018-02-10 12:43:45 +00:00
Laurent Cozic
ce2da0e6dc Update readme 2018-02-09 16:03:43 +00:00
Laurent Cozic
f49d644b6a Electron release v0.10.61 2018-02-08 18:15:49 +00:00
Laurent Cozic
02ac0b8593 Removed uneeded created_time property 2018-02-07 20:42:52 +00:00
Laurent Cozic
78e5eaf1e2 Electron: Toolbar button to set tags 2018-02-07 20:35:11 +00:00
Laurent Cozic
fc0d227396 Electron: Allowing opening and saving resource images 2018-02-07 20:23:17 +00:00
Laurent Cozic
f91c52cdf7 Mobile: Update time when app is activated 2018-02-07 19:51:58 +00:00
Laurent Cozic
3f14878d0f All: Improved request repeating mechanism 2018-02-07 19:46:07 +00:00
Laurent Cozic
69fd32e7c6 All: Use mutex when saving model to avoid race conditions when decrypting and syncing at the same time 2018-02-07 19:02:07 +00:00
Laurent Cozic
80801cedf0 Android release v0.10.91 2018-02-07 17:57:08 +00:00
Laurent Cozic
480e4fa94b Merge branch 'master' of github.com:laurent22/joplin 2018-02-07 17:56:36 +00:00
Laurent Cozic
717c789836 Android release v0.10.90 2018-02-07 17:55:54 +00:00
Laurent Cozic
f099376446 Update README.md 2018-02-07 17:55:17 +00:00
Laurent Cozic
41fa9d093e Android release v0.10.89 2018-02-07 17:54:06 +00:00
Laurent Cozic
e2f3f81eb6 Android release v0.10.88 2018-02-07 17:51:31 +00:00
Laurent Cozic
5cab7aeb55 Fixed: Make sure alarms and resources are attached to right note when creating new note 2018-02-06 19:31:22 +00:00
Laurent Cozic
fa5f418c22 All: Added sync config check to config screens 2018-02-06 18:59:36 +00:00
Laurent Cozic
a25fcacace Electron: Display message when creating new note or to-do 2018-02-06 18:12:43 +00:00
Laurent Cozic
727ba7300e All: Also support $ as delimiter for Katex expressoins 2018-02-06 17:58:54 +00:00
Laurent Cozic
d25d9b3f44 CLI v0.10.93 2018-02-06 13:17:10 +00:00
Laurent Cozic
9d762a4319 Android release v0.10.86 2018-02-06 13:01:20 +00:00
Laurent Cozic
18d94c7585 Electron release v0.10.60 2018-02-06 12:57:40 +00:00
Laurent Cozic
af82345eb8 Fixed tray icon and update issue 2018-02-06 13:11:59 +00:00
Laurent Cozic
1e94a22986 Merge branch 'master' of github.com:laurent22/joplin 2018-02-06 13:06:59 +00:00
Laurent Cozic
e19a8a99ff macOS: Fixed startup crash 2018-02-06 13:05:36 +00:00
Laurent Cozic
f975009e24 Update readme 2018-02-05 19:02:11 +00:00
Laurent Cozic
90640fafc7 Merge branch 'master' of github.com:laurent22/joplin 2018-02-05 18:49:58 +00:00
Laurent Cozic
42e0e1e5a5 Updated build instructions 2018-02-06 09:42:20 +00:00
Laurent Cozic
61f64fa933 Added Markdown doc 2018-02-05 22:53:10 +00:00
Laurent Cozic
0d0ffd6d27 Added Markdown doc 2018-02-05 22:50:17 +00:00
Laurent Cozic
023ccffd2e Electron release v0.10.59 2018-02-05 22:20:31 +00:00
Laurent Cozic
bc26098c7d Android release v0.10.85 2018-02-05 22:19:21 +00:00
Laurent Cozic
7257a71a18 Mobile: Fixes #159: Make sure text fields aren't hidden by keyboard on iOS 2018-02-05 18:32:59 +00:00
Laurent Cozic
8ad8b73585 Better error handling for Katex and handling of code blocks and inline 2018-02-05 17:55:35 +00:00
Laurent Cozic
9a06815db9 Electron release v0.10.58 2018-02-05 17:34:39 +00:00
Laurent Cozic
66947d4954 Fixing appveyor script 2018-02-05 17:34:31 +00:00
Laurent Cozic
3ec22185d5 Electron release v0.10.57 2018-02-05 17:32:54 +00:00
Laurent Cozic
0f05c23e26 Fixing deployment script 2018-02-05 17:32:48 +00:00
Laurent Cozic
74493fece0 Android release v0.10.83 2018-02-05 17:32:00 +00:00
Laurent Cozic
557a96e814 Electron release v0.10.56 2018-02-05 17:27:38 +00:00
Laurent Cozic
4b23b419a4 Electron release v0.10.55 2018-02-05 17:27:09 +00:00
Laurent Cozic
8b7f5b1151 Fix scrolling issue in Electron app 2018-02-04 18:45:52 +00:00
Laurent Cozic
29e9ccf216 Electron: Reverted to older Sharp version to fix Ubuntu issue 2018-02-04 18:31:13 +00:00
Laurent Cozic
2c04f5c8bc Improved Android and Electron release process 2018-02-04 18:05:07 +00:00
Laurent Cozic
5430a747e9 Improved Android and Electron release process 2018-02-04 17:55:22 +00:00
Laurent Cozic
13bc185829 Improved Android and Electron release process 2018-02-04 17:51:42 +00:00
Laurent Cozic
ed87581a8a Improved Android and Electron release process 2018-02-04 17:48:29 +00:00
Laurent Cozic
2645ec96a8 Fixed tool utils 2018-02-04 17:44:32 +00:00
Laurent Cozic
d278d830f0 Improved Android and Electron release process 2018-02-04 17:42:33 +00:00
Laurent Cozic
b4dce0ed46 All: Added Katex support 2018-02-04 17:12:24 +00:00
Laurent Cozic
e8416042d4 Merge branch 'master' into math-support 2018-02-02 20:35:32 +00:00
Laurent Cozic
70adbe5e76 Added flags 2018-02-01 20:21:54 +00:00
Laurent Cozic
f66be08d1d Added list of translated languages to README file 2018-02-01 20:15:31 +00:00
Laurent Cozic
fad96f5266 All: Added section to list missing master keys 2018-02-01 19:01:20 +00:00
Laurent Cozic
c33a7f5f47 Updated French translation 2018-02-02 00:08:37 +00:00
Laurent Cozic
28afbcde02 Updated translations 2018-02-02 00:02:47 +00:00
Laurent Cozic
691292d2b3 Merge branch 'master' of github.com:laurent22/joplin 2018-02-01 23:40:15 +00:00
Laurent Cozic
30ff81064f All: Made WebDAV driver more generic to support services other than Nextcloud and added WebDAV sync target 2018-02-01 23:40:05 +00:00
Laurent Cozic
f9f398ad98 Merge pull request #194 from rtmkrlv/russian-locale
Update Russian translation
2018-02-01 15:26:15 +01:00
rtmkrlv
537884bdcd Merge branch 'master' into russian-locale 2018-02-01 15:50:39 +02:00
rtmkrlv
d54400a7cb Updated Russian translation 2018-02-01 15:43:26 +02:00
Laurent Cozic
42c78264fb Update website 2018-01-31 20:21:38 +00:00
Laurent Cozic
c52da82447 Electron: Fix: Don't allow adding notes and to-do to conflict notebook 2018-01-31 20:19:11 +00:00
Laurent Cozic
cca43624e4 Electron: Added tray icon support 2018-01-31 20:10:32 +00:00
Laurent Cozic
dac1cd7668 Mobile: Allow filtering log by warning/error 2018-01-31 19:51:29 +00:00
Laurent Cozic
b4c00db0e3 Electron release v0.10.54 2018-01-31 19:40:40 +00:00
Laurent Cozic
3ce393a8b2 Electron release v0.10.53 2018-01-31 19:34:47 +00:00
Laurent Cozic
2b627fe4ab Fixed auto-update check 2018-01-31 19:34:38 +00:00
Laurent Cozic
fcf8a1649d CLI v0.10.92 2018-01-31 19:28:31 +00:00
Laurent Cozic
8d3b050831 Update website 2018-01-31 19:26:21 +00:00
Laurent Cozic
43297ef0a3 Updated translations 2018-01-31 19:14:32 +00:00
Laurent Cozic
551fabdfc9 Tweak and error handling on auto-update 2018-01-31 19:10:45 +00:00
Laurent Cozic
d6de56b2db All: Fixed crash when having invalid UTF-8 string in text editor 2018-01-31 19:01:11 +00:00
Laurent Cozic
9e979804f3 Electron release v0.10.52 2018-01-31 17:53:18 +00:00
Laurent Cozic
b8e0f182cc Android release v0.10.81 2018-01-31 17:51:22 +00:00
Laurent Cozic
9a41b9e192 Electron: Improved auto-update process to avoid random crashes 2018-01-30 22:35:50 +00:00
Laurent Cozic
9b8f520b9f Electron: Allow focusing either title or body when creating a new note or to-odo 2018-01-30 21:49:22 +00:00
Laurent Cozic
5b6019805c Electron: Fixed auto-title when title is manually entered first 2018-01-30 21:36:54 +00:00
Laurent Cozic
a4106436c4 Fixed delta function when processing many items 2018-01-30 21:10:54 +00:00
Laurent Cozic
f6b4eb511e Add Content-Size header for WebDAV, which is required by some services 2018-01-30 20:24:09 +00:00
Laurent Cozic
eb67ac17a0 Allow decryption to continue even if an item cannot be decrypted 2018-01-30 20:15:05 +00:00
Laurent Cozic
7b760d03ef All: Handle case where file is left half-uploaded on Nextcloud instance (possibly an ocloud.de issue only) 2018-01-30 20:10:36 +00:00
Laurent Cozic
2805ae2acf Fixed crash when calling fetch() with invalid URL in RN app 2018-01-30 19:01:07 +00:00
Laurent Cozic
5cb5ccc781 All: Optimised Nextcloud sync delta functionality 2018-01-29 20:51:14 +00:00
Laurent Cozic
0dba2821b6 Merge pull request #189 from strobeltobias/patch-2
Update German translation
2018-01-29 18:59:20 +00:00
Tobias Strobel
1db7825b22 Update German translation
Grammar and wording fixes, translating new strings.
2018-01-29 14:24:50 +01:00
Laurent Cozic
8a92d6ad70 Update website 2018-01-28 18:47:22 +00:00
Laurent Cozic
138ad9fcad Mobile: Fixes #114: Update geolocation in metadata after it has been set 2018-01-28 18:42:43 +00:00
Laurent Cozic
08cb518c25 Check if current folder exists 2018-01-28 18:19:56 +00:00
Laurent Cozic
6d04eab200 Merge pull request #185 from pf-siedler/autocomp_file_and_item
Autocompletion for files and items
2018-01-28 18:17:01 +00:00
Laurent Cozic
8a8cb51e1b Electron release v0.10.51 2018-01-28 18:07:08 +00:00
Laurent Cozic
5c66042a2d CLI v0.10.91 2018-01-28 17:59:34 +00:00
Laurent Cozic
ae75181b02 Electron release v0.10.50 2018-01-28 17:52:15 +00:00
Laurent Cozic
9dc3238182 Added beta notice 2018-01-28 17:51:38 +00:00
Laurent Cozic
0a68749373 Android release v0.10.79 2018-01-28 17:45:54 +00:00
Laurent Cozic
1519116291 Updated French translation 2018-01-28 17:43:21 +00:00
Laurent Cozic
d023d841e2 Update translations 2018-01-28 17:38:30 +00:00
Laurent Cozic
d7a1465d8e Skip sync report events in log 2018-01-28 17:38:17 +00:00
Laurent Cozic
15848fc696 Closing a resource is async 2018-01-28 17:37:51 +00:00
Laurent Cozic
837ae2c9f2 Send only one NOT_LOADED event per master key 2018-01-28 17:37:29 +00:00
Laurent Cozic
6789b98ead Return fileNotFound error when file cannot be opened so that it is skipped by synchroniser 2018-01-28 17:37:03 +00:00
Laurent Cozic
29f6e74ee3 Convert fs errors to normal errors 2018-01-28 17:36:36 +00:00
Laurent Cozic
2780c38c45 Fixed WebDAV error handling 2018-01-28 17:36:11 +00:00
Laurent Cozic
4531838217 Display stars for secure config value 2018-01-28 17:35:20 +00:00
pf-siedler
7bccf7f65d Implement auto completaion for <item> usage 2018-01-28 23:12:54 +09:00
pf-siedler
c62a24a9cb Implement auto completion for <file> usage
Suggest file names from current directory.
2018-01-28 22:59:58 +09:00
Laurent Cozic
c6830499f7 Fixed Travis 2018-01-28 11:48:29 +00:00
Laurent Cozic
d9f00a2539 Electron release v0.10.49 2018-01-26 17:21:34 +00:00
Laurent Cozic
def83c9119 Merge branch 'master' of github.com:laurent22/joplin 2018-01-26 17:19:58 +00:00
Laurent Cozic
b6cb0056c7 CLI v0.10.90 2018-01-26 17:19:42 +00:00
Laurent Cozic
1669b5258a Fixed detection of encrypted item 2018-01-25 23:01:18 +00:00
Laurent Cozic
5a9e0bfc26 Handle password text input in mobile and desktop 2018-01-25 22:44:09 +00:00
Laurent Cozic
8f3fdb3afe Tweaks to make sure Nextcloud driver passes all test units 2018-01-25 21:15:58 +00:00
Laurent Cozic
7ab135c099 Various tweaks to get Nextcloud working in mobile 2018-01-25 20:48:01 +00:00
Laurent Cozic
1cc27f2509 Got Nextcloud sync to work in Electron 2018-01-25 19:01:14 +00:00
Laurent Cozic
ef700b421c Update CONTRIBUTING.md 2018-01-25 13:35:04 +00:00
Laurent Cozic
b9af5ac052 Update issue_template.md 2018-01-25 13:34:07 +00:00
Laurent Cozic
173f2d421d Update PULL_REQUEST_TEMPLATE 2018-01-25 13:32:19 +00:00
Laurent Cozic
9f82c069c9 Update CONTRIBUTING.md 2018-01-25 13:31:17 +00:00
Laurent Cozic
6ade09c228 Merge branch 'master' into webdav 2018-01-24 17:25:34 +00:00
Laurent Cozic
5393a1399c Finished WebDAV driver 2018-01-23 20:10:20 +00:00
Laurent Cozic
fd29f20b2e Electron: Fix checkbox issue in config screen 2018-01-23 18:31:49 +00:00
Laurent Cozic
c011b53d1f Electron: Upgraded Electron to 1.7.11 to fix security vulnerability 2018-01-23 18:10:30 +00:00
Laurent Cozic
26e3a7b68c Merge branch 'master' of github.com:laurent22/joplin 2018-01-23 17:53:19 +00:00
Laurent Cozic
e70a291698 Merge pull request #174 from gabcoh/fix171
Fix #171
2018-01-23 11:26:11 +00:00
Laurent Cozic
511bd57726 Merge pull request #175 from alexdevero/add-font-size-settings
Add font size settings
2018-01-23 11:25:47 +00:00
Laurent Cozic
c6de8598dc Electron release v0.10.48 2018-01-22 19:10:29 +00:00
Laurent Cozic
7bee25599d Removed uneeded code 2018-01-22 19:06:50 +00:00
Laurent Cozic
773a1ad829 Travis: only build tags 2018-01-21 20:03:40 +00:00
Laurent Cozic
1a1e264fa4 All: Refactored so that memory and file sync target use same delta logic 2018-01-21 19:45:32 +00:00
Laurent Cozic
5b99ecefca Merge branch 'master' into webdav 2018-01-21 19:10:39 +00:00
Laurent Cozic
1bfeed377a All: Optimised file sync logic so that it doesn't fetch the content of
all the items on each sync. Also limit the number of items in a batch
to 1000
2018-01-21 18:54:47 +00:00
Laurent Cozic
86eee376bb All: Handle case where resource blob is missing during sync 2018-01-21 17:48:50 +00:00
Laurent Cozic
6a7d368184 All: Started Nextcloud support 2018-01-21 17:01:37 +00:00
Alex Devero
1da19ae98d Fix indentation 2018-01-19 14:11:40 +01:00
Alex Devero
f52c117b09 Add font size settings 2018-01-19 13:27:44 +01:00
Laurent Cozic
2551f96149 Fixed Readme 2018-01-18 22:43:37 +00:00
Laurent Cozic
c984c19fee Android release v0.10.78 2018-01-18 22:35:05 +00:00
Laurent Cozic
ac8e91e82e Started FAQ 2018-01-18 22:34:27 +00:00
Gabe Cohen
af50d80541 Fix #171 2018-01-18 14:29:13 -06:00
Laurent Cozic
e355f4e49b Fixed license 2018-01-18 20:14:05 +00:00
Laurent Cozic
738ef2b0fa Android release v0.10.75 2018-01-18 17:29:57 +00:00
Laurent Cozic
9746a3964b All: Removed certain log statements so that sensitive info doesn't end up in logs 2018-01-17 21:17:40 +00:00
Laurent Cozic
9efbf74b6f All: Various changes to get filesystem target to work on mobile 2018-01-17 21:01:41 +00:00
Laurent Cozic
c16ea6b237 Typo 2018-01-17 20:19:45 +00:00
Laurent Cozic
b06a3b588f Add APK download link 2018-01-17 20:19:20 +00:00
Laurent Cozic
6ff67e0995 Automate building and deploying Android app 2018-01-17 20:16:13 +00:00
Laurent Cozic
1a5c8d126d All: Refactored filesystem sync driver to support mobile 2018-01-17 18:51:15 +00:00
Laurent Cozic
f632580eed CLI: Display error when cannot open note with editor 2018-01-17 18:10:07 +00:00
Laurent Cozic
1d73f0cdee Simplified and fixed caching issue 2018-01-17 17:59:33 +00:00
Laurent Cozic
99c7111f8c CLI: Fixes #168: Invalid code block would crash app 2018-01-17 17:52:55 +00:00
Laurent Cozic
ae9806561a Added tech spec info 2018-01-16 19:51:37 +00:00
Laurent Cozic
fffdf5b5b7 Fixed link 2018-01-17 00:47:45 +00:00
Laurent Cozic
3de19c3db7 All: Added Dutch translation. Thanks @tcassaert 2018-01-17 00:43:47 +00:00
Laurent Cozic
56e074b4ef Merge branch 'master' of github.com:laurent22/joplin 2018-01-17 00:41:04 +00:00
Laurent Cozic
1a79253780 Update doc 2018-01-17 00:40:35 +00:00
Laurent Cozic
b67908df11 Merge pull request #165 from tcassaert/master
Dutch translation
2018-01-16 17:32:33 +00:00
tcassaert
6a5089f71d Dutch translation
All EN keys are translated to nl_BE.
2018-01-15 22:33:05 +01:00
Laurent Cozic
f710463b67 Electron: Fixes #155: Caret alignment issue with Russian text 2018-01-15 19:01:00 +00:00
Laurent Cozic
6ae0c3aba0 Electron release v0.10.47 2018-01-15 18:41:19 +00:00
Laurent Cozic
07c6347014 Android v0.10.74 2018-01-15 18:40:44 +00:00
Laurent Cozic
b10999e83e All: Update French translation 2018-01-15 18:35:39 +00:00
Laurent Cozic
961b5bfd25 All: Fixes #85: Don't record deleted_items entries for folders deleted via sync 2018-01-15 18:10:14 +00:00
Laurent Cozic
d1f1d1068a Electron release v0.10.46 2018-01-15 12:29:58 +00:00
Laurent Cozic
faade0afe2 All: Fixed model ID issue 2018-01-14 17:11:44 +00:00
Laurent Cozic
a442a49e2f Electron release v0.10.45 2018-01-15 12:27:10 +00:00
Laurent Cozic
7d3fbbcaba Updated translations 2018-01-14 17:07:34 +00:00
Laurent Cozic
d9bb7c3271 Android v0.10.73 2018-01-14 17:05:59 +00:00
Laurent Cozic
4d1dd17fa2 All: Fixed issue with timestamp when saving notes 2018-01-14 17:01:22 +00:00
Laurent Cozic
c5c6c777be Electron release v0.10.44 2018-01-12 18:11:39 +01:00
Laurent Cozic
1fd1a73fda Electron: Improved the way new note are created, and automatically add a title. Made saving and loading notes more reliable. 2018-01-12 19:58:01 +00:00
Laurent Cozic
feeb498a79 All: Fixed OneDrive sync when resync is requested 2018-01-12 19:01:34 +00:00
Laurent Cozic
1d7f30d441 Electron: Fixed logic to save, and make sure scheduled save always happen even when changing note 2018-01-11 21:05:34 +01:00
Laurent Cozic
53da63e371 Trying to add math support 2018-01-11 19:51:01 +00:00
Laurent Cozic
424443a2d8 CLI: Display arrays and objects in settings 2018-01-09 21:25:31 +01:00
Laurent Cozic
08b58f0e4c All: Fixed table font size and family 2018-01-09 21:09:49 +01:00
Laurent Cozic
c2a0d8600f Electron: Move prompt to top to avoid issue with date picker being hidden 2018-01-09 21:06:47 +01:00
Laurent Cozic
ede3c2ce2f Electron: Fixed display of too long notebook titles 2018-01-09 19:34:06 +01:00
Laurent Cozic
0b93515711 Electron: Display URL for links 2018-01-09 19:26:46 +01:00
Laurent Cozic
2f13e689b9 Electron: Don't scroll back to top when note is reloaded via sync 2018-01-09 20:26:20 +00:00
Laurent Cozic
ea135a0d28 Electron: Fixed logic of what note is used when right-clicking one or more notes 2018-01-09 20:16:09 +00:00
Laurent Cozic
f67e4a03e4 CLI: Detect installed Node version 2018-01-09 19:56:38 +00:00
Laurent Cozic
e9268edeff All: Fixes #150: Extra comma causes crash 2018-01-09 19:45:08 +00:00
Laurent Cozic
a8576a55d6 CLI v0.10.87 2018-01-09 09:31:03 +01:00
Laurent Cozic
eb500cdf9e All: Display sync items being fetched 2018-01-08 21:36:00 +01:00
Laurent Cozic
7b9dc66121 All: Schedule sync after enabling or disabling encryption 2018-01-08 21:25:38 +01:00
Laurent Cozic
bba2c68c6f All: Schedule sync only after 30 seconds 2018-01-08 21:05:08 +01:00
Laurent Cozic
c70d8bea78 All: Fixes #129: Tags are case insensitive 2018-01-08 21:04:44 +01:00
Laurent Cozic
176bda66ad Merge branch 'master' of github.com:laurent22/joplin 2018-01-08 20:09:12 +01:00
Laurent Cozic
78ce10ddf0 All: Fixed race condition when a note is being uploaded while it's being modified in the text editor 2018-01-08 20:09:01 +01:00
Laurent Cozic
29f14681a8 Mobile: Fixed mix of tabs and spaces 2018-01-08 19:31:04 +00:00
Laurent Cozic
aaf617e41c iOS v0.10.9 2018-01-08 18:26:30 +01:00
Laurent Cozic
b99146ed7f Merge pull request #111 from marcosvega91/fix_scroll_note_keyboard
Fix scroll note keyboard on IOS
2018-01-08 16:45:58 +00:00
Laurent Cozic
d136161650 Android v0.10.71 2018-01-07 19:29:57 +00:00
Laurent Cozic
39051a27a1 Update website 2018-01-08 11:12:22 +01:00
Laurent Cozic
30bc9dd551 Electron release v0.10.43 2018-01-08 10:57:36 +01:00
Laurent Cozic
cc2f665313 Electron: Undone tests 2018-01-08 10:57:29 +01:00
Laurent Cozic
37c989ed28 Electron release v0.10.42 2018-01-08 10:27:02 +01:00
Laurent Cozic
adc5885980 All: Better handling of null values in settings 2018-01-07 19:20:10 +00:00
Laurent Cozic
8de5b4219d All: Updated translations 2018-01-06 21:05:34 +01:00
Laurent Cozic
e096ddebd4 Merge branch 'master' of github.com:laurent22/joplin 2018-01-06 20:40:47 +01:00
Laurent Cozic
83398dd0bc Mobile: Fixes #139: Crash when creating new notebook 2018-01-06 20:37:42 +01:00
Laurent Cozic
ddc78ebb41 Merge pull request #138 from rtmkrlv/russian-locale
Updated Russian translation
2018-01-06 19:34:02 +00:00
rtmkrlv
70b69eb31e Merge branch 'master' into russian-locale 2018-01-06 14:59:28 +02:00
rtmkrlv
3fa891e136 Merge branch 'master' into russian-locale 2018-01-06 14:54:46 +02:00
rtmkrlv
6f7a9f3295 Updated Russian translation
Added translation of new strings and small corrections
2018-01-06 14:45:30 +02:00
Laurent Cozic
8e8793943b Update README.md 2018-01-06 10:19:50 +01:00
Laurent Cozic
83d9faf2fe Create PULL_REQUEST_TEMPLATE 2018-01-06 10:17:14 +01:00
Laurent Cozic
f45a4fff8b Mobile: Fixes #136, fixes #137: styling issues on E2EE 2018-01-06 10:06:41 +01:00
Laurent Cozic
1e02aa3120 Update website 2018-01-05 21:38:37 +01:00
Laurent Cozic
77fec75f23 CLI v0.10.86 2018-01-05 21:02:23 +01:00
Laurent Cozic
2c9feae20b Merge branch 'master' of github.com:laurent22/joplin 2018-01-05 20:52:41 +01:00
Laurent Cozic
a81788b3fa Electron release v0.10.41 2018-01-05 20:52:22 +01:00
Laurent Cozic
88cfba53a3 Update CONTRIBUTING.md 2018-01-05 20:50:28 +01:00
Laurent Cozic
d659d975cd All: Documentation and minor tweaks for E2EE 2018-01-05 18:40:57 +01:00
marcosvega91
277ad90f72 Indent with tab 2017-12-19 21:14:40 +01:00
marcosvega91
f2e3bedde6 Fix scroll
After fixing the issue on ios, it caused an issue on android that I solved with this commit
2017-12-19 10:28:52 +01:00
marcosvega91
98c0f2315a Fix scroll
Fixed the issue that not permit to view edited text when the keyboard is shown.
2017-12-19 10:08:22 +01:00
Laurent Cozic
0926755635 Create README_debugging.md 2017-12-17 18:54:29 +01:00
Laurent Cozic
75f8234db5 All: Added Russian translation. Thanks @rtmkrlv 2017-12-17 12:34:56 +01:00
Laurent Cozic
b8e85e1587 Merge pull request #106 from rtmkrlv/russian-locale
Russian localisation
2017-12-17 11:33:34 +00:00
Laurent Cozic
b6add857f9 Merge branch 'master' of github.com:laurent22/joplin 2017-12-17 12:30:47 +01:00
Laurent Cozic
4e41731c08 All: Updated translations 2017-12-17 12:30:32 +01:00
rtmkrlv
6ac3b8a8f9 Add files via upload
Russian localisation for Joplin. 100% done, but some corrections may be required.
2017-12-16 20:41:04 +02:00
Laurent Cozic
7ab2b11c9d Update README.md
Updated list of supported languages
2017-12-15 10:07:55 +00:00
Laurent Cozic
1eb1c5914c Merge branch 'master' of github.com:laurent22/joplin 2017-12-15 08:46:39 +00:00
Laurent Cozic
5780951f7d Updated translations 2017-12-15 08:46:30 +00:00
Laurent Cozic
67e790e393 Merge pull request #95 from tbroadley/fix-typos
Fix typos
2017-12-15 07:21:26 +00:00
Thomas Broadley
0d472486ca Fix typos 2017-12-14 19:10:47 -05:00
Laurent Cozic
2d218904d0 Merge branch 'master' of github.com:laurent22/joplin 2017-12-11 21:20:57 +00:00
Laurent Cozic
c3fbcb8feb Update website 2017-12-11 21:20:49 +00:00
Laurent Cozic
64031ac6cf Merge pull request #40 from Cogitri/german-locale
WIP: Add German (Germany) locale
2017-12-11 20:43:07 +00:00
Laurent Cozic
caae7f7cf8 CLI v0.10.83 2017-12-11 20:12:41 +00:00
Laurent Cozic
d56b247adf Electron release v0.10.39 2017-12-11 20:09:38 +00:00
Laurent Cozic
11bdfbde61 Fixed Readme typo 2017-12-10 16:44:43 +00:00
Laurent Cozic
a59bf55c16 Electron: Fixes #3: Paths with '.' would cause JSX compilation to fail 2017-12-10 16:06:43 +00:00
Laurent Cozic
043be1916c CLI: Display welcome message the first time the app is run. 2017-12-10 15:56:12 +00:00
Laurent Cozic
42e34b5c3b All: Fixes #87: Show warningn when deleting notebook that contains notes. 2017-12-10 14:09:12 +00:00
Laurent Cozic
931083b2e2 Electron: Fixes #86: App icon missing on Linux 2017-12-10 14:04:07 +00:00
Rasmus Thomsen
09b9df4228 German locale: adjust articulation 2017-12-07 16:02:18 +01:00
Laurent Cozic
37663bd110 Merge pull request #68 from dbinary/master
adding translate spanish Latin America
2017-12-06 23:59:22 +00:00
Laurent Cozic
f01c6aa8d1 Merge branch 'master' of github.com:laurent22/joplin 2017-12-06 23:56:18 +00:00
Laurent Cozic
8838017830 All: Updated translations 2017-12-06 23:55:22 +00:00
Laurent Cozic
1d6fb8058f Update BUILD.md 2017-12-06 23:34:56 +00:00
Laurent Cozic
bb51729bea Update BUILD.md 2017-12-06 23:34:31 +00:00
Laurent Cozic
507e7e6014 All: Improved ENEX import for web pages that have been saved as notes 2017-12-06 19:29:58 +00:00
Laurent Cozic
f42908b11c Merge branch 'sync-limits' 2017-12-05 17:30:16 +00:00
Laurent Cozic
03ec406627 All: Filter to sync target and refactored so that same code can be used by all clients 2017-12-05 19:21:01 +00:00
Laurent Cozic
c703521b6c All: Handling of unsyncable items 2017-12-05 18:56:39 +00:00
Laurent Cozic
cf97bf9a77 Updated readme 2017-12-05 08:47:48 +00:00
Laurent Cozic
304b9a582f Electron release v0.10.36 2017-12-04 23:57:30 +00:00
Laurent Cozic
4d5c4b1743 Electron: started unsynchronisable items UI 2017-12-04 23:57:13 +00:00
Laurent Cozic
4abe5d07c4 All: Handling of impossible-to-sync items (such as when they are over the size limit of the cloud provider) 2017-12-04 23:38:09 +00:00
Laurent Cozic
f6633e23f5 Minor tweaks 2017-12-04 23:01:22 +00:00
Laurent Cozic
a6d6201ecb All: Improved synchronisation process and saving of models so that reducer can deal with full objects 2017-12-04 22:58:42 +00:00
Laurent Cozic
0115e74163 All: Minor tweaks regarding encryption 2017-12-04 19:29:34 +00:00
Luis Pérez
4314c392f6 adding translate spanish Latin America 2017-12-04 13:24:55 -06:00
Laurent Cozic
685f541bb4 All: Fixed issue with local resource needlessly marked as encrypted 2017-12-04 19:15:14 +00:00
Laurent Cozic
f9634ea283 CLI: Added e2ee command to check encryption status of a sync target 2017-12-04 19:01:56 +00:00
Laurent Cozic
6252a4d8c8 Merge branch 'master' into encryption 2018-01-03 20:23:26 +01:00
Laurent Cozic
d13d7bec45 Minor changes 2018-01-03 20:20:16 +01:00
Laurent Cozic
74e284d795 Merge branch 'master' of github.com:laurent22/joplin 2018-01-03 00:17:39 +01:00
Laurent Cozic
7b82dacbf2 Update website 2018-01-03 00:17:31 +01:00
Laurent Cozic
f82162f94a Create CONTRIBUTING.md
Started "contributing" guide
2018-01-02 22:04:41 +01:00
Laurent Cozic
e2d5128624 Update README.md
More information on how to import notes into Joplin
2018-01-02 21:51:18 +01:00
Laurent Cozic
9074412472 Merge pull request #128 from tanrax/master
Update README with Importing from Standard Notes
2018-01-02 21:46:13 +01:00
Laurent Cozic
0db9c66317 Electron release v0.10.40 2018-01-02 21:28:56 +01:00
Laurent Cozic
b22211fada All: Updated translations. Added Japanese and Chinese. 2018-01-02 21:27:38 +01:00
Laurent Cozic
7efeaa3a22 All: Fixed minor issue when logger not defined 2018-01-02 21:23:35 +01:00
Laurent Cozic
79efac2f71 Merge pull request #130 from SamuelBlickle/master
Improved german translation
2018-01-02 21:22:27 +01:00
Laurent Cozic
9d7b7092f5 Merge pull request #132 from kcrt/master
Japanese localization
2018-01-02 21:22:14 +01:00
Laurent Cozic
71e877d369 All: Improved encryption and synchronisation 2018-01-02 20:17:14 +01:00
TAKAHASHI Kyohei
7e086a7730 Japanese localization 2018-01-02 14:17:39 +09:00
SamuelBlickle
3f810c71b0 improved german translations 2018-01-01 13:41:02 +01:00
Laurent Cozic
500fbc5294 Merge branch 'master' into encryption 2017-12-31 15:26:16 +01:00
Laurent Cozic
6d0f60d9a1 All: Fixed tests and minor fixes 2017-12-31 15:23:05 +01:00
Laurent Cozic
e19c26fdd1 Mobile: Done UI for E2EE 2017-12-31 14:58:50 +01:00
Andros Fenollosa
86b86513d9 Update README with Importing from Standard Notes 2017-12-30 21:37:37 +01:00
Laurent Cozic
6ff19063ef All: Got E2EE working in mobile app 2017-12-30 20:57:34 +01:00
Laurent Cozic
6a75451539 Merge pull request #120 from marcosvega91/fix_undo_note
Fix #119
2017-12-29 19:42:48 +01:00
Laurent Cozic
70a33f8533 CLI 0.10.84 2017-12-29 11:17:07 +01:00
Laurent Cozic
23722719f0 Merge pull request #82 from gabcoh/autocomplete
Added auto complete
2017-12-29 10:54:38 +01:00
Laurent Cozic
d499251206 Update app-gui.js
Invalidate root after inputting command
2017-12-29 10:39:50 +01:00
Laurent Cozic
d180e7b5e1 Mobile: Handle encrypted items on UI side 2017-12-28 19:57:21 +00:00
Laurent Cozic
9e869a5b1f CLI: Various UI improvements for E2EE 2017-12-28 19:51:24 +00:00
Laurent Cozic
ab959623aa CLI: Fixes #117: 'edit' command raising error in shell mode 2017-12-28 19:14:03 +00:00
Laurent Cozic
08d2655f13 All: Various improvements to E2EE 2017-12-26 11:38:53 +01:00
Gabe Cohen
20632ae1c1 Correctly implement autocomplete menu with prefix 2017-12-24 12:27:25 -06:00
Laurent Cozic
bef7c38724 Electron: Improved enabling/disabling E2EE 2017-12-24 11:23:51 +01:00
Laurent Cozic
d1abf4971d Electron: E2EE config 2017-12-24 09:36:31 +01:00
Laurent Cozic
d13c2cf8d7 All: Fixed reading file by chuncks 2017-12-23 21:21:11 +01:00
Gabe Cohen
3146273409 Improve autocomplete
All commands and sub commands should now autocomplete. Titles are now wrapped in spaces and quoted titles are now properly parsed.
2017-12-22 19:48:56 -06:00
Laurent Cozic
1891eb4998 All: Upgraded to fs-extra 5.0 2017-12-22 18:58:09 +00:00
Laurent Cozic
70b03971f6 All: Fixed handling of unloaded master key 2017-12-22 18:50:27 +00:00
marcosvega91
38c050b47e Removed duplicate editor variable 2017-12-22 15:43:01 +01:00
marcosvega91
0bf5c9ebdd Fix #119
Fix the bug that permit to undo changes from different notes.
I save the editor instance into the state and in the componentWillReceiveProps i reset the undo state
2017-12-22 14:48:44 +01:00
Laurent Cozic
6683da804b All: Fixed various issues regarding encryption and decryptino of resources, and started doing GUI for Electron app 2017-12-21 20:06:08 +01:00
Laurent Cozic
7750b954fc All: Make sure existing resources are encrypted once E2EE has been enabled 2017-12-20 19:43:43 +00:00
Laurent Cozic
edbff5a26a All: Simplified encryption header 2017-12-20 19:14:27 +00:00
Laurent Cozic
18846c11ed All: Allow disabling encryption and added more test cases 2017-12-20 20:45:25 +01:00
Laurent Cozic
cc02c1d585 All: Simplified synchronisation of resources to simplify encryption, and implemented resource encryption 2017-12-19 19:01:29 +00:00
Laurent Cozic
26bf7c4d46 All: Improved file and memory drivers to make it easier to use same sync method for all the drivers 2017-12-18 21:47:25 +01:00
Laurent Cozic
2959fa1080 All: Added uploadBlob method to Node apps 2017-12-18 21:46:22 +01:00
Laurent Cozic
3f4f154949 All: Refactored encryption/decryption method to use same algorithm for both file and string encryption 2017-12-18 20:54:03 +01:00
Laurent Cozic
4c0b472f67 All: Testing and better handling of E2EE initialisation 2017-12-17 20:51:45 +01:00
Gabe Cohen
4756238821 Remove unused import 2017-12-15 06:39:50 -06:00
Laurent Cozic
f5d26e0d81 All: Fixed filesystem driver bug when downloading resources. Added support for encrypting all items when encryption enabled. 2017-12-14 21:12:02 +00:00
Laurent Cozic
e9bb5bee9d All: Better handling of encrypted data on UI side and prevent modification of encrypted notes 2017-12-14 20:21:36 +00:00
Laurent Cozic
2c608bca3c All: getting encryption service and UI to work 2017-12-14 19:39:13 +00:00
Laurent Cozic
d9c1e30e9b Merge master into encryption branch 2017-12-15 07:31:57 +00:00
Laurent Cozic
5bc72e2b44 All: Decryption worker and handling of missing master key passwords 2017-12-14 18:53:08 +00:00
Laurent Cozic
df05d04dad All: Made model naming more consistent 2017-12-14 18:12:14 +00:00
Laurent Cozic
888ac8f4c2 Electron: Started integrating encryption 2017-12-14 17:58:10 +00:00
Laurent Cozic
55266e5694 Fixed test units 2017-12-14 17:41:53 +00:00
Gabe Cohen
39c73e1649 Improve autocompletion
1. Removed autocomplete menu because it lists the entire line, not just what is
being autocompleted.

2. Autocomplete positional args first unless cursor is at - then autocomplete
long options

3. Don't autocomplete an options that is already present.

4. Other fixes
2017-12-14 07:53:49 -06:00
Gabe Cohen
3bf9d01f0a Remove unused code and retab 2017-12-14 07:01:00 -06:00
Gabe Cohen
89ef33f7ca convert spaces to tabs 2017-12-13 21:25:18 -06:00
Gabe Cohen
f71fe9a1a6 Make autocomplete more intelligent 2017-12-13 21:13:43 -06:00
Laurent Cozic
1008b1835b All: Handle tag encryption and started CLI and Electron encryption front-end 2017-12-14 00:23:32 +00:00
Laurent Cozic
2ffa5419e2 Merge branch 'encryption' of github.com:laurent22/joplin into encryption 2017-12-13 22:53:30 +00:00
Laurent Cozic
bd20ecff78 All: Handle conflict for encrypted notes 2017-12-13 22:53:20 +00:00
Laurent Cozic
a073514c46 Update README_spec.md 2017-12-13 22:38:47 +00:00
Laurent Cozic
c6ff14226f Fixed readme 2017-12-13 22:37:11 +00:00
Laurent Cozic
ee02f8255e All: Encryption setup on apps 2017-12-13 19:01:04 +00:00
Laurent Cozic
5951ed3f55 All: Support encrypting notes and notebooks 2017-12-13 18:57:40 +00:00
Laurent Cozic
f6fbf3ba0f All: Handle master key in backend 2017-12-12 21:58:57 +00:00
Laurent Cozic
9bce52a92a All: Utilities to create and encrypt master keys 2017-12-12 18:41:02 +00:00
Laurent Cozic
e44975622a CLI: Handling of password prompt 2017-12-12 18:17:30 +00:00
Laurent Cozic
92b857d83b All: Added methods to get secure random bytes 2017-12-12 17:51:07 +00:00
Gabe Cohen
671e538740 Contain autocomplete in StatusBarWidget.js
StatusBarWidget.js now imports app itself and gets command names.
app-gui.js no longer sets the autocomplete of StatusBarWidget itself.
2017-12-11 19:31:11 -06:00
Laurent Cozic
8a282fd2e1 All: Added fs drivers and encryption service 2017-12-11 23:52:42 +00:00
Gabe Cohen
cda623a95c Added command auto complete
File based autocompletion is not yet implemented. This will require knowledge of
the command, and it's parameters. The autocomplete feture is pretty powerful
however, so this should not be very difficult to add.
2017-12-09 23:08:28 -06:00
Laurent Cozic
0f343bccda Electron: resolve #7: Show storage location in Options screen 2017-12-08 21:51:59 +00:00
Laurent Cozic
a513f6f3f0 Merge branch 'master' of github.com:laurent22/joplin 2017-12-08 21:42:37 +00:00
Laurent Cozic
3b4809714e iOS: version 0.10.6 2017-12-08 21:42:09 +00:00
Laurent Cozic
238b5ab9b9 CLI: version bump to fix Homebrew formula 2017-12-08 21:41:41 +00:00
Laurent Cozic
08d9e9b6aa All: Added support for HTML tags found in ENEX files: colgroup, col, ins, kbd, address, caption, var, area, map 2017-12-08 17:41:32 +00:00
Laurent Cozic
b22900eb3a Update website 2017-12-08 10:12:52 +00:00
Laurent Cozic
89fc2c4779 Removed uneeded assets 2017-12-07 23:29:47 +00:00
Laurent Cozic
353b79f5e5 Electron release v0.10.38 2017-12-07 23:25:06 +00:00
Laurent Cozic
b929b46281 Mobile: Fixed dropdown positioning 2017-12-07 23:24:14 +00:00
Laurent Cozic
5c4a536dad Android v0.10.65 2017-12-07 23:11:34 +00:00
Laurent Cozic
91e337307c Mobile: Upgrade react-native-popup-menu to fix scrolling bug 2017-12-07 23:00:22 +00:00
Laurent Cozic
2855b68ed4 Merge branch 'master' of github.com:laurent22/joplin 2017-12-07 22:56:41 +00:00
Laurent Cozic
45ca6284f9 iOS: Added safe area for iPhone X support 2017-12-07 22:42:40 +00:00
Laurent Cozic
145ee13356 Merge branch 'master' of github.com:laurent22/joplin 2017-12-07 22:42:08 +00:00
Laurent Cozic
6f97747199 Electron: Add support for file system sync 2017-12-07 22:29:02 +00:00
Laurent Cozic
f3751e4ba6 Mobile: Fixed auto-assignment of title for new notes 2017-12-07 21:32:22 +00:00
Laurent Cozic
5cd55cada6 Mobile: Made context menu scrollable 2017-12-07 21:23:41 +00:00
Laurent Cozic
bad4b2ecb8 Electron: Added dialog to export sync status 2017-12-07 21:18:18 +00:00
Laurent Cozic
7aafd63ff3 Update website 2017-12-07 19:38:24 +00:00
Laurent Cozic
3227a13035 Electron release v0.10.37 2017-12-07 18:00:28 +00:00
Laurent Cozic
027f96d100 Electron: Fixes #36: Set installation directory for Windows installer 2017-12-07 18:17:41 +00:00
Laurent Cozic
f242a3c215 Merge branch 'fix-cli' 2017-12-07 17:43:44 +00:00
Laurent Cozic
ad6c347180 CLI: Fixed shell mode 2017-12-07 18:12:46 +00:00
Laurent Cozic
4f0431da55 Merge branch 'master' of github.com:laurent22/joplin 2017-12-07 13:33:26 +00:00
Laurent Cozic
b873fdd029 iOS: Release 2017-12-07 17:46:59 +00:00
Laurent Cozic
c1ff820913 Electron: Fixes #65: Display 'no notebook' message on startup. 2017-12-07 13:16:38 +00:00
Laurent Cozic
7008daf92a All: Improved handling of empty links when importing ENEX files. Fixed minor layout issues in Electron app 2017-12-07 00:57:36 +00:00
Laurent Cozic
ed914c6907 All: Improved rendering of imported ENEX tables 2017-12-07 00:35:15 +00:00
Laurent Cozic
73e81a54b4 All: Fixed sync issue when target does not have reliable timestamps 2017-12-04 18:39:40 +00:00
Laurent Cozic
ab8c66a361 Updated tools 2017-12-04 18:16:14 +00:00
Laurent Cozic
4b55fefcb1 Cleaned up build tools 2017-12-04 17:55:06 +00:00
Laurent Cozic
0eac8b25e1 Deleted uneeded file 2017-12-03 23:06:02 +00:00
Laurent Cozic
aec556ff7d Delete package-lock.json 2017-12-03 23:03:16 +00:00
Laurent Cozic
110dc29bd4 Merge pull request #57 from mgroth0/patch-1
Add node-gyp dependency to instructions
2017-12-03 21:45:40 +00:00
Laurent Cozic
b1efea1bd9 Update BUILD.md 2017-12-03 21:44:04 +00:00
Laurent Cozic
8671467ed3 Update BUILD.md 2017-12-03 21:43:55 +00:00
Laurent Cozic
7851b6b429 Version update 2017-12-02 15:57:19 +00:00
Laurent Cozic
8eb5f8b74e Electron release v0.10.35 2017-12-02 15:18:23 +00:00
Laurent Cozic
1830ee9fd2 All: Fixed sync issue and database migration issue 2017-12-02 15:18:15 +00:00
Laurent Cozic
dd615d6a8f Update website 2017-12-02 14:50:56 +00:00
Laurent Cozic
08a518db70 Revert to 0.10.31 for now 2017-12-02 14:30:33 +00:00
Laurent Cozic
581372de0b Electron release v0.10.34 2017-12-02 14:26:55 +00:00
Laurent Cozic
fe2c1c197e All: fixed database creation error 2017-12-02 14:26:49 +00:00
Laurent Cozic
9854fddeb2 Electron release v0.10.33 2017-12-02 12:50:52 +00:00
Laurent Cozic
6c3918ebd2 All: Improved Evernote import for blockquotes and sup tags 2017-12-02 12:49:42 +00:00
Laurent Cozic
4af496632f Update website 2017-12-02 11:03:19 +00:00
Matt Groth
485ef1f2c2 Add node-gyp dependency to instructions
I was getting an error on `yarn dist` which I solved with the command `npm install -g node-gyp`.

This was the error:
```
Error: /usr/local/Cellar/node/8.9.1/bin/node exited with code 1
Output:
$ node-pre-gyp install --fallback-to-build
Failed to execute 'node-gyp clean' (Error: spawn node-gyp ENOENT)
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Error output:
node-pre-gyp info it worked if it ends with ok
node-pre-gyp info using node-pre-gyp@0.6.38
node-pre-gyp info using node@8.9.1 | darwin | x64
node-pre-gyp http GET https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v3.1.13/electron-v1.7-darwin-x64.tar.gz
node-pre-gyp http 403 https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v3.1.13/electron-v1.7-darwin-x64.tar.gz
node-pre-gyp ERR! Tried to download(403): https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v3.1.13/electron-v1.7-darwin-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for sqlite3@3.1.13 and electron@1.7.9 (electron-v1.7 ABI) (falling back to source compile with node-gyp)
node-pre-gyp http 403 status code downloading tarball https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v3.1.13/electron-v1.7-darwin-x64.tar.gz
node-pre-gyp ERR! build error
node-pre-gyp ERR! stack Error: Failed to execute 'node-gyp clean' (Error: spawn node-gyp ENOENT)
node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/Users/matt/joplin/ElectronClient/app/node_modules/sqlite3/node_modules/node-pre-gyp/lib/util/compile.js:77:29)
node-pre-gyp ERR! stack     at emitOne (events.js:116:13)
node-pre-gyp ERR! stack     at ChildProcess.emit (events.js:211:7)
node-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:196:12)
node-pre-gyp ERR! stack     at onErrorNT (internal/child_process.js:372:16)
node-pre-gyp ERR! stack     at _combinedTickCallback (internal/process/next_tick.js:138:11)
node-pre-gyp ERR! stack     at process._tickCallback (internal/process/next_tick.js:180:9)
node-pre-gyp ERR! System Darwin 16.7.0
node-pre-gyp ERR! command "/usr/local/Cellar/node/8.9.1/bin/node" "/Users/matt/joplin/ElectronClient/app/node_modules/sqlite3/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /Users/matt/joplin/ElectronClient/app/node_modules/sqlite3
node-pre-gyp ERR! node -v v8.9.1
node-pre-gyp ERR! node-pre-gyp -v v0.6.38
node-pre-gyp ERR! not ok
error Command failed with exit code 1.

    at ChildProcess.childProcess.once.code (/Users/matt/joplin/ElectronClient/app/node_modules/builder-util/src/util.ts:219:14)
    at Object.onceWrapper (events.js:317:30)
    at emitTwo (events.js:126:13)
    at ChildProcess.emit (events.js:214:7)
    at maybeClose (internal/child_process.js:925:16)
    at Socket.stream.socket.on (internal/child_process.js:346:11)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at Pipe._handle.close [as _onclose] (net.js:554:12)
From previous event:
    at spawn (/Users/matt/joplin/ElectronClient/app/node_modules/builder-util/src/util.ts:182:3)
    at default.map.concurrency (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/util/yarn.ts:154:7)
    at runCallback (timers.js:789:20)
    at tryOnImmediate (timers.js:751:5)
    at processImmediate [as _immediateCallback] (timers.js:722:5)
From previous event:
    at /Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/util/yarn.ts:152:27
From previous event:
    at rebuild (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/out/util/yarn.js:94:22)
    at /Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/util/yarn.ts:21:11
    at Generator.next (<anonymous>)
    at runCallback (timers.js:789:20)
    at tryOnImmediate (timers.js:751:5)
    at processImmediate [as _immediateCallback] (timers.js:722:5)
From previous event:
    at installOrRebuild (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/out/util/yarn.js:32:21)
    at /Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/packager.ts:388:7
    at Generator.next (<anonymous>)
From previous event:
    at Packager.installAppDependencies (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/out/packager.js:433:11)
    at /Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/packager.ts:284:20
    at Generator.next (<anonymous>)
From previous event:
    at Packager.doBuild (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/out/packager.js:369:11)
    at /Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/packager.ts:236:52
    at Generator.next (<anonymous>)
From previous event:
    at Packager.build (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/out/packager.js:298:11)
    at /Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/builder.ts:277:40
    at Generator.next (<anonymous>)
From previous event:
    at build (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/out/builder.js:63:21)
    at then (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/cli/cli.ts:49:4)
    at runCallback (timers.js:789:20)
    at tryOnImmediate (timers.js:751:5)
    at processImmediate [as _immediateCallback] (timers.js:722:5)
From previous event:
    at Object.args [as handler] (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/cli/cli.ts:49:4)
    at Object.runCommand (/Users/matt/joplin/ElectronClient/app/node_modules/yargs/lib/command.js:228:22)
    at Object.parseArgs [as _parseArgs] (/Users/matt/joplin/ElectronClient/app/node_modules/yargs/yargs.js:1041:24)
    at Object.get [as argv] (/Users/matt/joplin/ElectronClient/app/node_modules/yargs/yargs.js:957:21)
    at Object.<anonymous> (/Users/matt/joplin/ElectronClient/app/node_modules/electron-builder/src/cli/cli.ts:43:15)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Function.Module.runMain (module.js:676:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3
```
2017-12-01 21:28:13 -05:00
Laurent Cozic
cd1e7a1083 Electron release v0.10.32 2017-12-02 00:21:29 +00:00
Laurent Cozic
4dce9e9e47 Electron: Allow attaching multiple files 2017-12-01 23:26:08 +00:00
Laurent Cozic
dbeff4fd7d All: Allow attaching files of unknown mime type 2017-12-01 23:15:49 +00:00
Laurent Cozic
aef2e4845d Electron: Fixes #32: Error when manually input alarm date 2017-12-01 21:55:02 +00:00
Laurent Cozic
739c6be476 Update website 2017-12-01 20:06:42 +00:00
Laurent Cozic
ff502670bf Updated Readme, mentioned Homebrew 2017-12-01 20:06:20 +00:00
Laurent Cozic
3894dd1191 Merge branch 'master' of github.com:laurent22/joplin 2017-12-01 19:44:41 +00:00
Laurent Cozic
818537933a Android: Fixes #53: Back button should exit app if nothing to go back to 2017-12-01 19:44:34 +00:00
Laurent Cozic
ec50808ba1 Merge branch 'master' of github.com:laurent22/joplin 2017-12-01 19:15:56 +00:00
Laurent Cozic
33fd8325be Electron: Fix #33: Allow copy and paste in OneDrive login 2017-12-01 19:15:46 +00:00
Laurent Cozic
c72e0a14c0 Electron, Mobile: Fixed header sizes 2017-12-01 19:04:14 +00:00
Laurent Cozic
58bc708014 Merge branch 'master' of github.com:laurent22/joplin 2017-12-01 18:56:43 +00:00
Laurent Cozic
ede1ed8b22 macOS: Allow BACKSPACE instead of DELETE in CLI app 2017-12-01 18:56:35 +00:00
Laurent Cozic
22e39b4434 Merge branch 'master' of github.com:laurent22/joplin 2017-12-01 18:14:06 +00:00
Laurent Cozic
9d984596cc CLI: fixed crash when inputting command without closed quote 2017-12-01 17:51:27 +00:00
Laurent Cozic
fe909f659d All: Added error message for OneDrive for Business 2017-12-01 17:47:18 +00:00
Laurent Cozic
ea120eae91 Update README.md 2017-12-01 15:29:58 +00:00
Laurent Cozic
fa819d25b0 Update README.md 2017-12-01 13:06:26 +00:00
Laurent Cozic
65739a5077 Update website 2017-12-01 09:57:32 +00:00
Laurent Cozic
228d06e27f Electron release v0.10.31 2017-12-01 00:00:33 +00:00
Laurent Cozic
d386b83c53 Merge branch 'master' of github.com:laurent22/joplin 2017-12-01 00:00:26 +00:00
Laurent Cozic
e1b1f31cf1 Electron: #22 Fixes keyboard cursor jumps while typing. 2017-12-01 00:00:18 +00:00
Laurent Cozic
f80b403dfe Create BUILD.md 2017-11-30 23:02:14 +00:00
Laurent Cozic
5af55d7da3 Create issue_template.md 2017-11-30 22:33:18 +00:00
Laurent Cozic
5e6a389f97 Merge branch 'master' of github.com:laurent22/joplin 2017-11-30 21:48:36 +00:00
Laurent Cozic
6f26910243 Android v0.10.61 2017-11-30 21:47:55 +00:00
Laurent Cozic
b2056f9e4d Merge pull request #41 from dflock/patch-1
Minor grammar fix
2017-11-30 21:25:05 +00:00
Duncan Lock
dca4bb204b Minor grammar fix
loss -> lost.
2017-11-30 13:23:04 -08:00
Laurent Cozic
ade39837de Update README.md 2017-11-30 21:18:48 +00:00
Laurent Cozic
2ef2296566 Update website 2017-11-30 20:30:01 +00:00
Laurent Cozic
04ed914894 Electron release v0.10.30 2017-11-30 18:53:35 +00:00
Laurent Cozic
332dd0d859 Merge branch 'alarm-support' 2017-11-30 18:53:26 +00:00
Laurent Cozic
d9a1f7855d Merge branch 'alarm-support' of github.com:laurent22/joplin into alarm-support 2017-11-30 18:53:03 +00:00
Laurent Cozic
3ec59a835c Electron release v0.10.29 2017-11-30 18:44:53 +00:00
Laurent Cozic
620225bb2d Electron: Fixed copy/cut/paste problem in macOS 2017-11-30 18:44:37 +00:00
Laurent Cozic
9d7d469908 Electron: Fixed option page checkboxes 2017-11-30 18:36:26 +00:00
Laurent Cozic
16bf0cf646 All: Added Spanish (Costa Rica) locale 2017-11-30 18:29:10 +00:00
Laurent Cozic
8079106c3e Update websiyte 2017-11-30 01:08:29 +00:00
Laurent Cozic
28143db968 Electron release v0.10.28 2017-11-30 00:25:59 +00:00
Laurent Cozic
7f1a14fa22 All: Fixed note update issue 2017-11-30 00:25:52 +00:00
Laurent Cozic
4de1edda05 Electron release v0.10.27 2017-11-29 23:27:28 +00:00
Laurent Cozic
52f09d2638 Electron: Fixed import of certain images 2017-11-29 23:27:20 +00:00
Laurent Cozic
97b8cad755 Merge branch 'master' of github.com:laurent22/joplin 2017-11-29 23:04:08 +00:00
Laurent Cozic
52cb10dd4e Electron: added toolbar and fixed various state issues 2017-11-29 23:03:10 +00:00
Laurent Cozic
135a8a9273 Update README.md
Mentioned NextCloud support
2017-11-29 19:49:46 +00:00
Laurent Cozic
a346116d5f Update website 2017-11-29 16:03:19 +00:00
Laurent Cozic
934c3c8001 Update readme 2017-11-29 16:02:45 +00:00
Laurent Cozic
565c17df37 Mobile: Improved OneDrive login 2017-11-28 21:49:58 +00:00
Laurent Cozic
5ee9a35f7d Electron release v0.10.26 2017-11-29 15:32:41 +00:00
Laurent Cozic
bd73107853 Electron: Improved parsing of auth token 2017-11-28 21:36:04 +00:00
Laurent Cozic
2e8fe88f53 Don't needlessly reload resources 2017-11-28 21:15:22 +00:00
Laurent Cozic
444c96d5e7 Electron: Fixed scrolling issue 2017-11-28 20:58:07 +00:00
Laurent Cozic
f5ff68b236 Android: test release 2017-11-28 20:35:39 +00:00
Laurent Cozic
d1a83d065a Mobile: Added status info to view active alarms 2017-11-28 20:31:14 +00:00
Laurent Cozic
ddb73c8642 iOS: Fixed notification event 2017-11-28 20:23:22 +00:00
Laurent Cozic
4df73cd82c iOS: Handle foreground notifications 2017-11-28 20:17:34 +00:00
Laurent Cozic
c446e4471d Merge branch 'alarm-support' of github.com:laurent22/joplin into alarm-support 2017-11-28 17:29:31 +00:00
Laurent Cozic
fa22d5bae3 Electron: Fixed getting package info 2017-11-28 19:53:29 +00:00
Laurent Cozic
1a610054d3 Android: Fixed cancelling of notification 2017-11-28 19:49:03 +00:00
Laurent Cozic
11517fa037 iOS: Get notifications to work 2017-11-28 19:36:47 +00:00
Laurent Cozic
67a457b9c5 Android: Got notifications to work 2017-11-28 18:58:04 +00:00
Laurent Cozic
18dc6c826a Electron: Trigger notifications using node-notifier 2017-11-28 18:47:41 +00:00
Laurent Cozic
033d356b56 Removed dependency to marked and update locale 2017-11-28 18:07:49 +00:00
Laurent Cozic
f9f5974267 All: Added option to set date and time format 2017-11-28 18:02:54 +00:00
Laurent Cozic
6e23fead59 Electron: Getting notifications to work 2017-11-28 00:22:38 +00:00
Laurent Cozic
7df6541902 Merge branch 'alarm-support' of github.com:laurent22/joplin into alarm-support 2017-11-27 22:51:03 +00:00
Laurent Cozic
9a40851c77 Electron, Mobile: Created alarm service and drivers 2017-11-27 22:50:46 +00:00
Laurent Cozic
748acdf03f Merge branch 'master' into alarm-support 2017-11-26 21:08:14 +00:00
Laurent Cozic
13d27357a0 Updated Readme 2017-11-26 19:39:12 +00:00
Laurent Cozic
c72caad764 Updated website 2017-11-26 19:38:33 +00:00
Laurent Cozic
2933d09366 Updated Readme 2017-11-26 19:38:05 +00:00
Laurent Cozic
f51ad26db7 Release v0.10.59-android 2017-11-26 19:27:42 +00:00
Laurent Cozic
50ca686727 iOS: Added notification config 2017-11-24 18:27:41 +00:00
Laurent Cozic
3612529e52 iOS: Testing notification 2017-11-24 18:06:45 +00:00
Laurent Cozic
c053146885 iOS: Added notification config 2017-11-24 17:34:52 +00:00
Laurent Cozic
8ccf2ec521 Mobile: Trying RN notification 2017-11-24 20:14:56 +00:00
Laurent Cozic
0428917ea2 iOS: Updated version 2017-11-24 17:28:43 +00:00
Laurent Cozic
914a2554ab All: Updated translations 2017-11-24 19:59:21 +00:00
Laurent Cozic
26bb7dc33b All: Added dev sync target and option to select it in mobile 2017-11-24 19:47:24 +00:00
Laurent Cozic
8e5b0eadd9 All: Clean up 2017-11-24 19:26:49 +00:00
Laurent Cozic
a96b91cfef All: Removed sync target info out of setting class 2017-11-24 19:21:30 +00:00
Laurent Cozic
03251d4c40 All: renamed sync targets 2017-11-24 19:09:15 +00:00
Laurent Cozic
112609c5f1 All: Moving sync target logic to SyncTarget classes 2017-11-24 18:59:16 +00:00
Laurent Cozic
cc7cbc2ecf All: Started moving sync target logic under SyncTarget classes 2017-11-24 18:37:40 +00:00
Laurent Cozic
946ad7c71a All: Started moving sync target logic under SyncTarget classes 2017-11-24 18:06:30 +00:00
Laurent Cozic
60d2b0c763 Merge branch 'master' into alarm-support 2017-11-24 17:09:24 +00:00
Laurent Cozic
d7f3cfd778 All: Started moving sync glue logic to SyncTarget classes 2017-11-23 23:10:55 +00:00
Laurent Cozic
a2ae2c766a Merge branch 'master' of github.com:laurent22/joplin 2017-11-23 19:29:12 +00:00
Laurent Cozic
f52ff730b1 Disable cache 2017-11-23 19:29:03 +00:00
Laurent Cozic
9327a61a36 iOS: maybe bad change 2017-11-23 19:15:44 +00:00
Laurent Cozic
05997908e5 Electron release v0.10.25 2017-11-23 19:05:37 +00:00
Laurent Cozic
2a93dea378 Electron release v0.10.24 2017-11-23 19:04:56 +00:00
Laurent Cozic
fbf7b2cc43 Mobile: Hide irrelevant settings 2017-11-23 18:54:26 +00:00
Laurent Cozic
d8b19f7d08 Mobile: Also do multi-selection from search page 2017-11-23 18:41:35 +00:00
Laurent Cozic
acc4eb5d28 Mobile: Allow selecting, deleting and moving multiple notes 2017-11-23 18:47:51 +00:00
Laurent Cozic
bcd5cd9110 Electron: Hide invalid characters 2017-11-23 18:16:17 +00:00
Laurent Cozic
45a4034816 Android: Automate building for prod 2017-11-23 18:14:38 +00:00
Laurent Cozic
978a08fb06 Trying BuddyBuilder 72 2017-11-22 22:24:20 +00:00
Laurent Cozic
72dc5a6c99 Trying BuddyBuilder 2017-11-22 22:21:27 +00:00
Laurent Cozic
5340fb8af9 Electron: Disable Control+Click 2017-11-22 19:29:49 +00:00
Laurent Cozic
3ce1172c36 Allow changing notebook by drag and dropping notes 2017-11-22 19:20:19 +00:00
Laurent Cozic
e4d48f43d6 Allow multiple selection 2017-11-22 18:35:31 +00:00
Laurent Cozic
3e1ea0eb0a Android icons 2017-11-22 17:37:57 +00:00
Laurent Cozic
d10d6ba7de Merge branch 'master' of github.com:laurent22/joplin 2017-11-21 19:44:10 +00:00
Laurent Cozic
cf832354a2 Updated website 2017-11-21 19:43:09 +00:00
Laurent Cozic
b27519b85a Update appveyor.yml 2017-11-21 19:31:43 +00:00
Laurent Cozic
27af0e69ef Electron release v0.10.23 2017-11-21 18:26:17 +00:00
Laurent Cozic
6283bf6190 Minor fixing on note rendering 2017-11-21 19:47:29 +00:00
Laurent Cozic
48b648e656 Electron: allow disabling auto-updates 2017-11-21 19:37:34 +00:00
Laurent Cozic
367a18db93 Electron: fixed loading of resources, and disable drag and dropping of links in app 2017-11-21 19:31:21 +00:00
Laurent Cozic
f5feb595f6 Updated translation 2017-11-21 19:14:30 +00:00
Laurent Cozic
c6ec0279fc Mobile: Made checkboxes smaller 2017-11-21 19:05:59 +00:00
Laurent Cozic
b0b5488c2e Electron: Better error handling for auto-update 2017-11-21 18:59:32 +00:00
Laurent Cozic
3722012da5 Added command to export debug information from mobile and CLI 2017-11-21 18:48:50 +00:00
Laurent Cozic
c5214b6c44 Core: Fixed potential out-of-sync issue if user cancels while in the middle of delta step 2017-11-21 18:17:50 +00:00
Laurent Cozic
585ccc2b8b Update website 2017-11-20 22:31:29 +00:00
Laurent Cozic
ab8115b89d Added download badges 2017-11-20 22:28:22 +00:00
Laurent Cozic
8d8395c226 Added App Store icon 2017-11-20 20:06:32 +00:00
Laurent Cozic
8dbec0e8f4 Put locales under versioning 2017-11-20 19:14:02 +00:00
Laurent Cozic
1c1228bb88 Electron release v0.10.22 2017-11-20 18:59:13 +00:00
Laurent Cozic
7d9eec262a Updated translation 2017-11-20 18:58:51 +00:00
Laurent Cozic
a057fbf3bd Electron: added sync icon 2017-11-20 18:44:56 +00:00
Laurent Cozic
518feadc3e All: Better checkbox alignment and added padding on notebook title 2017-11-20 18:40:36 +00:00
Laurent Cozic
b1e351ce77 Merge branch 'master' of github.com:laurent22/joplin 2017-11-20 18:31:10 +00:00
Laurent Cozic
c6cb2800d7 Android: improved image type detection 2017-11-20 19:18:49 +00:00
Laurent Cozic
c31c7a8a67 Added iOS icon 512x512 2017-11-20 19:09:22 +00:00
Laurent Cozic
3d6fe4c2cd Android: Fixed image picker issues 2017-11-20 19:01:19 +00:00
Laurent Cozic
da7034ae08 iOS: Improved icon and fixed file attachement issue 2017-11-20 18:29:39 +00:00
Laurent Cozic
37de5fd4b3 Mobile: Improved loading of images. Added privacy policy url. 2017-11-20 18:25:23 +00:00
Laurent Cozic
e2cbef1538 Added privacy policy 2017-11-20 18:09:29 +00:00
Laurent Cozic
4de044dc90 Fix Android/iOS inconsitency with webview page scaling 2017-11-20 00:21:40 +00:00
Laurent Cozic
d5dc27d788 Use SVG icons for checkboxes 2017-11-19 23:34:41 +00:00
Laurent Cozic
e80dd59da2 iOS: Fixed attaching images 2017-11-19 22:08:58 +00:00
Laurent Cozic
cbd2075156 Merge branch 'ios-fixes-2' of github.com:laurent22/joplin into ios-fixes-2 2017-11-19 15:21:41 +00:00
Laurent Cozic
4b5c1491d0 iOS: various fixes 2017-11-19 15:19:36 +00:00
Laurent Cozic
ea077852a1 Mobile: allow attaching image or any other file 2017-11-19 15:18:07 +00:00
Laurent Cozic
ca20a2a1c2 Dropdown fioxes 2017-11-19 00:23:18 +00:00
Laurent Cozic
37c0b6d24a iOs tweaks 2017-11-19 00:03:42 +00:00
Laurent Cozic
0c14a42b28 RN: Replaced broken Picker by custom dropdown 2017-11-18 23:59:07 +00:00
Laurent Cozic
f126e0a944 Update website 2017-11-18 17:35:49 +00:00
Laurent Cozic
9519bb1218 Update website 2017-11-18 16:13:27 +00:00
Laurent Cozic
716b1315a9 Electron release v0.10.21 2017-11-17 23:42:45 +00:00
Laurent Cozic
6f88c025f5 Update locale 2017-11-17 23:33:20 +00:00
Laurent Cozic
2f3458e207 Added share buttons 2017-11-17 23:17:16 +00:00
Laurent Cozic
bd265e5a9d Added share buttons 2017-11-17 23:09:57 +00:00
Laurent Cozic
9d5d197747 Added share buttons 2017-11-17 23:07:04 +00:00
Laurent Cozic
ba1a005fcd Updading website 2017-11-17 22:15:54 +00:00
Laurent Cozic
f09cec794b Updading website 2017-11-17 22:12:30 +00:00
Laurent Cozic
9619d451f9 Trying to publish website from /docs 2017-11-17 21:34:24 +00:00
Laurent Cozic
240fbf1720 Trying to publish website from /docs 2017-11-17 21:34:04 +00:00
Laurent Cozic
286722fda7 Trying to publish website from /docs 2017-11-17 21:31:33 +00:00
Laurent Cozic
86b5f3582f Trying to publish website from /docs 2017-11-17 21:30:12 +00:00
Laurent Cozic
69ae32a9af Update Readme 2017-11-17 21:29:49 +00:00
Laurent Cozic
504c3d4c0d Updating website 2017-11-17 19:07:32 +00:00
Laurent Cozic
9e77f01088 Updating Readme 2017-11-17 19:05:12 +00:00
Laurent Cozic
409f2ca98d Electron: search 2017-11-17 18:57:27 +00:00
Laurent Cozic
2bfaa0e02c Merge branch 'master' of github.com:laurent22/joplin 2017-11-17 11:05:41 +00:00
Laurent Cozic
209f2cae55 Electron: Handle hide/show app logic for macOS 2017-11-17 18:05:25 +00:00
Laurent Cozic
ce9da90846 Merge branch 'master' of github.com:laurent22/joplin 2017-11-17 11:02:39 +00:00
Laurent Cozic
43bc7b5619 Electron: Fixed vertical scrollbar, and added option to display dev tool in prod 2017-11-17 18:02:01 +00:00
Laurent Cozic
056741e2c2 Electron release v0.10.20 2017-11-16 22:33:57 +00:00
Laurent Cozic
01ba0c3078 Fixed image upload for Linux and macOS 2017-11-16 22:33:45 +00:00
Laurent Cozic
7d58763fe9 Merge branch 'master' of github.com:laurent22/joplin 2017-11-16 21:14:49 +00:00
Laurent Cozic
4bb9be8f78 Electron release v0.10.19 2017-11-16 19:32:12 +00:00
Laurent Cozic
092c09065f Merge branch 'master' of github.com:laurent22/joplin 2017-11-16 20:31:55 +01:00
Laurent Cozic
fcc2eb6354 Fix for Linux icons 2017-11-16 20:31:43 +01:00
Laurent Cozic
94a800aa3c Electron release v0.10.18 2017-11-16 19:21:23 +00:00
Laurent Cozic
add69aa210 Version v0.10.17 2017-11-16 18:52:00 +00:00
Laurent Cozic
5098c03264 Allow setting extra flags and renaming folder 2017-11-16 18:51:11 +00:00
Laurent Cozic
2724167028 Tweaks for iOS 2017-11-16 18:45:50 +00:00
Laurent Cozic
eacd0e5cfd Linux icons 2017-11-16 18:45:01 +00:00
Laurent Cozic
e799062059 Version v0.10.16 2017-11-16 12:20:45 +00:00
Laurent Cozic
96a2aa6ad8 Mac icons 2017-11-16 12:20:25 +00:00
Laurent Cozic
82674e8bdb Merge branch 'master' of github.com:laurent22/joplin 2017-11-16 12:11:01 +00:00
Laurent Cozic
6404d3520d macOS icons 2017-11-16 18:31:01 +00:00
Laurent Cozic
667f5c0cfe mac update 2017-11-16 12:10:57 +00:00
Laurent Cozic
fca504d552 Version v0.10.15 2017-11-16 11:45:42 +00:00
Laurent Cozic
af78721568 Version v0.10.14 2017-11-16 11:42:06 +00:00
Laurent Cozic
9a10984e84 testing 2017-11-16 11:37:46 +00:00
Laurent Cozic
462a676442 update 2017-11-16 11:23:50 +00:00
Laurent Cozic
a2a714461c Merge branch 'master' of github.com:laurent22/joplin 2017-11-16 11:23:19 +00:00
Laurent Cozic
dfc5845025 Disable asar 2017-11-16 18:03:01 +00:00
Laurent Cozic
e382231d7d Update for iOS 2017-11-16 17:55:01 +00:00
Laurent Cozic
2bca9af9a7 Fixing macOS and Linux builds 2017-11-15 23:38:56 +00:00
Laurent Cozic
8b7ed05d7b Release 10.0.7 2017-11-15 22:43:35 +00:00
Laurent Cozic
bc80405f13 Merge branch 'master' of github.com:laurent22/joplin 2017-11-15 15:37:41 +00:00
Laurent Cozic
b4b9e285eb Updated for iOS 2017-11-15 15:37:02 +00:00
Laurent Cozic
35b9835fd5 Exclude build files 2017-11-14 23:05:35 +00:00
Laurent Cozic
11ad6c6bef Removing need for including build files 2017-11-14 23:01:19 +00:00
Laurent Cozic
c838548831 Unversioning build files 2017-11-14 20:58:40 +00:00
Laurent Cozic
dbb5599b0f Save window state 2017-11-14 18:02:58 +00:00
Laurent Cozic
bf916d5b9b Trying auto update 2017-11-14 11:18:15 +00:00
Laurent Cozic
b9194e94aa Electron: Fixes #84: Fields losing focus in Config screen 2017-11-08 11:41:23 +00:00
Laurent Cozic
7ac6f39658 Alarm support 2017-09-10 17:56:27 +01:00
522 changed files with 39038 additions and 24044 deletions

10
.gitignore vendored
View File

@@ -32,4 +32,12 @@ INFO.md
sync_staging.sh
*.swp
_vieux/
_mydocs
_mydocs
.DS_Store
Assets/DownloadBadges*.psd
node_modules
Tools/github_oauth_token.txt
_releases
ReactNativeClient/lib/csstojs/
ElectronClient/app/gui/note-viewer/fonts/
Tools/commit_hook.txt

View File

@@ -1,3 +1,6 @@
# Only build tags (Doesn't work - doesn't build anything)
if: tag IS present
rvm: 2.3.3
matrix:
@@ -28,17 +31,23 @@ matrix:
before_install:
# HOMEBREW_NO_AUTO_UPDATE needed so that Homebrew doesn't upgrade to the next
# version, which requires Ruby 2.3, which is not available on the Travis VM.
# Silence apt-get update errors (for example when a module doesn't exist) since
# otherwise it will make the whole build fails, even though all we need is yarn.
- |
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
HOMEBREW_NO_AUTO_UPDATE=1 brew install yarn
else
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
sudo apt-get update || true
sudo apt-get install -y yarn
fi
script:
- |
cd ElectronClient/app
cd Tools
npm install
yarn dist
cd ../ElectronClient/app
rsync -aP --delete ../../ReactNativeClient/lib/ lib/
npm install && yarn dist

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
Assets/LinuxIcons/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

BIN
Assets/LinuxIcons/24x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
Assets/LinuxIcons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 151 KiB

View File

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

BIN
Assets/iOSIcons/29.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Assets/iOSIcons/29x2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
Assets/iOSIcons/29x3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
Assets/iOSIcons/40.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
Assets/iOSIcons/40x2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
Assets/iOSIcons/40x3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
Assets/iOSIcons/57.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
Assets/iOSIcons/57x2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
Assets/iOSIcons/60x2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
Assets/iOSIcons/60x3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
Assets/macOs.icns Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

61
BUILD.md Normal file
View File

@@ -0,0 +1,61 @@
# General information
- All the applications share the same library, which, for historical reasons, is in ReactNativeClient/lib. This library is copied to the relevant directories when building each app.
- The translations are built by running CliClient/build-translation.sh. You normally don't need to run this if you haven't updated the translation since the compiled files are on the repository.
## macOS dependencies
brew install yarn node
echo 'export PATH="/usr/local/opt/gettext/bin:$PATH"' >> ~/.bash_profile
source ~/.bash_profile
If you get a node-gyp related error you might need to manually install it: `npm install -g node-gyp`
## Linux and Windows (WSL) dependencies
- Install yarn - https://yarnpkg.com/lang/en/docs/install/
- Install node v8.x (check with `node --version`) - https://nodejs.org/en/
- If you get a node-gyp related error you might need to manually install it: `npm install -g node-gyp`
# Building the tools
Before building any of the applications, you need to build the tools:
```
cd Tools
npm install
```
# Building the Electron application
```
cd ElectronClient/app
rsync --delete -a ../../ReactNativeClient/lib/ lib/
npm install
yarn dist
```
If there's an error `while loading shared libraries: libgconf-2.so.4: cannot open shared object file: No such file or directory`, run `sudo apt-get install libgconf-2-4`
For node-gyp to work, you might need to install the `windows-build-tools` using `npm install --global windows-build-tools`.
That will create the executable file in the `dist` directory.
From `/ElectronClient` you can also run `run.sh` to run the app for testing.
# Building the Mobile application
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "Building Projects with Native Code" tab.
Then, from `/ReactNativeClient`, run `npm install`, then `react-native run-ios` or `react-native run-android`.
# Building the Terminal application
```
cd CliClient
npm install
./build.sh
rsync --delete -aP ../ReactNativeClient/locales/ build/locales/
```
Run `run.sh` to start the application for testing.

20
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,20 @@
# Reporting a bug
Please check first that it [has not already been reported](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue). Also consider [enabling debug mode](https://github.com/laurent22/joplin/blob/master/README_debugging.md) before reporting the issue so that you can provide as much details as possible to help fix it.
If possible, **please provide a screenshot**. A screenshot showing the problem is often more useful than a paragraph describing it as it can make it immediately clear what the issue is.
# Feature requests
Again, please check that it has not already been requested. If it has, simply **up-vote the issue** - the ones with the most up-votes are likely to be implemented. Adding a "+1" comment does nothing.
# Adding new features
If you want to add a new feature, consider asking about it before implementing it to make sure it is within the scope of the project. Of course you are free to create the pull request directly but it is not guaranteed it is going to be accepted.
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/master/BUILD.md) for more details.
# Coding style
- Only use tabs for indentation, not spaces.
- Do not remove or add optional characters from other lines (such as colons or new line characters) as it can make the commit needlessly big, and create conflicts with other changes.

View File

@@ -1,6 +1,6 @@
const { _ } = require('lib/locale.js');
const { Logger } = require('lib/logger.js');
const { Resource } = require('lib/models/resource.js');
const Resource = require('lib/models/Resource.js');
const { netUtils } = require('lib/net-utils.js');
const http = require("http");

View File

@@ -1,11 +1,12 @@
const { Logger } = require('lib/logger.js');
const { Folder } = require('lib/models/folder.js');
const { Tag } = require('lib/models/tag.js');
const { BaseModel } = require('lib/base-model.js');
const { Note } = require('lib/models/note.js');
const { Resource } = require('lib/models/resource.js');
const Folder = require('lib/models/Folder.js');
const Tag = require('lib/models/Tag.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const Resource = require('lib/models/Resource.js');
const { cliUtils } = require('./cli-utils.js');
const { reducer, defaultState } = require('lib/reducer.js');
const { splitCommandString } = require('lib/string-utils.js');
const { reg } = require('lib/registry.js');
const { _ } = require('lib/locale.js');
@@ -13,6 +14,7 @@ const chalk = require('chalk');
const tk = require('terminal-kit');
const TermWrapper = require('tkwidgets/framework/TermWrapper.js');
const Renderer = require('tkwidgets/framework/Renderer.js');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const BaseWidget = require('tkwidgets/BaseWidget.js');
const ListWidget = require('tkwidgets/ListWidget.js');
@@ -33,37 +35,55 @@ const ConsoleWidget = require('./gui/ConsoleWidget.js');
class AppGui {
constructor(app, store) {
this.app_ = app;
this.store_ = store;
constructor(app, store, keymap) {
try {
this.app_ = app;
this.store_ = store;
BaseWidget.setLogger(app.logger());
BaseWidget.setLogger(app.logger());
this.term_ = new TermWrapper(tk.terminal);
this.term_ = new TermWrapper(tk.terminal);
this.renderer_ = null;
this.logger_ = new Logger();
this.buildUi();
// Some keys are directly handled by the tkwidget framework
// so they need to be remapped in a different way.
this.tkWidgetKeys_ = {
'focus_next': 'TAB',
'focus_previous': 'SHIFT_TAB',
'move_up': 'UP',
'move_down': 'DOWN',
'page_down': 'PAGE_DOWN',
'page_up': 'PAGE_UP',
};
this.renderer_ = new Renderer(this.term(), this.rootWidget_);
this.renderer_ = null;
this.logger_ = new Logger();
this.buildUi();
this.app_.on('modelAction', async (event) => {
await this.handleModelAction(event.action);
});
this.renderer_ = new Renderer(this.term(), this.rootWidget_);
this.shortcuts_ = this.setupShortcuts();
this.app_.on('modelAction', async (event) => {
await this.handleModelAction(event.action);
});
this.inputMode_ = AppGui.INPUT_MODE_NORMAL;
this.keymap_ = this.setupKeymap(keymap);
this.commandCancelCalled_ = false;
this.inputMode_ = AppGui.INPUT_MODE_NORMAL;
this.currentShortcutKeys_ = [];
this.lastShortcutKeyTime_ = 0;
this.commandCancelCalled_ = false;
// Recurrent sync is setup only when the GUI is started. In
// a regular command it's not necessary since the process
// exits right away.
reg.setupRecurrentSync();
this.currentShortcutKeys_ = [];
this.lastShortcutKeyTime_ = 0;
// Recurrent sync is setup only when the GUI is started. In
// a regular command it's not necessary since the process
// exits right away.
reg.setupRecurrentSync();
DecryptionWorker.instance().scheduleStart();
} catch (error) {
this.fullScreen(false);
console.error(error);
process.exit(1);
}
}
store() {
@@ -79,8 +99,16 @@ class AppGui {
await this.renderer_.renderRoot();
}
prompt(initialText = '', promptString = ':') {
return this.widget('statusBar').prompt(initialText, promptString);
termSaveState() {
return this.term().saveState();
}
termRestoreState(state) {
return this.term().restoreState(state);
}
prompt(initialText = '', promptString = ':', options = null) {
return this.widget('statusBar').prompt(initialText, promptString, options);
}
stdoutMaxWidth() {
@@ -94,6 +122,7 @@ class AppGui {
buildUi() {
this.rootWidget_ = new ReduxRootWidget(this.store_);
this.rootWidget_.name = 'root';
this.rootWidget_.autoShortcutsEnabled = false;
const folderList = new FolderListWidget();
folderList.style = {
@@ -166,7 +195,7 @@ class AppGui {
});
this.rootWidget_.connect(noteList, (state) => {
return {
selectedNoteId: state.selectedNoteId,
selectedNoteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
items: state.notes,
};
});
@@ -180,7 +209,7 @@ class AppGui {
};
this.rootWidget_.connect(noteText, (state) => {
return {
noteId: state.selectedNoteId,
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
notes: state.notes,
};
});
@@ -194,7 +223,7 @@ class AppGui {
borderRightWidth: 1,
};
this.rootWidget_.connect(noteMetadata, (state) => {
return { noteId: state.selectedNoteId };
return { noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null };
});
noteMetadata.hide();
@@ -258,148 +287,31 @@ class AppGui {
addCommandToConsole(cmd) {
if (!cmd) return;
const isConfigPassword = cmd.indexOf('config ') >= 0 && cmd.indexOf('password') >= 0;
if (isConfigPassword) return;
this.stdout(chalk.cyan.bold('> ' + cmd));
}
setupShortcuts() {
const shortcuts = {};
setupKeymap(keymap) {
const output = [];
shortcuts['TAB'] = {
friendlyName: 'Tab',
description: () => _('Give focus to next pane'),
isDocOnly: true,
}
for (let i = 0; i < keymap.length; i++) {
const item = Object.assign({}, keymap[i]);
shortcuts['SHIFT_TAB'] = {
friendlyName: 'Shift+Tab',
description: () => _('Give focus to previous pane'),
isDocOnly: true,
}
if (!item.command) throw new Error('Missing command for keymap item: ' + JSON.stringify(item));
shortcuts[':'] = {
description: () => _('Enter command line mode'),
action: async () => {
const cmd = await this.widget('statusBar').prompt();
if (!cmd) return;
this.addCommandToConsole(cmd);
await this.processCommand(cmd);
},
};
if (!('type' in item)) item.type = 'exec';
shortcuts['ESC'] = { // Built into terminal-kit inputField
description: () => _('Exit command line mode'),
isDocOnly: true,
};
shortcuts['ENTER'] = {
description: () => _('Edit the selected note'),
action: () => {
const w = this.widget('mainWindow').focusedWidget;
if (w.name === 'folderList') {
this.widget('noteList').focus();
} else if (w.name === 'noteList' || w.name === 'noteText') {
this.processCommand('edit $n');
}
},
}
shortcuts['CTRL_C'] = {
description: () => _('Cancel the current command.'),
friendlyName: 'Ctrl+C',
isDocOnly: true,
}
shortcuts['CTRL_D'] = {
description: () => _('Exit the application.'),
friendlyName: 'Ctrl+D',
isDocOnly: true,
}
shortcuts['DELETE'] = {
description: () => _('Delete the currently selected note or notebook.'),
action: async () => {
if (this.widget('folderList').hasFocus) {
const item = this.widget('folderList').selectedJoplinItem;
if (item.type_ === BaseModel.TYPE_FOLDER) {
await this.processCommand('rmbook ' + item.id);
} else if (item.type_ === BaseModel.TYPE_TAG) {
this.stdout(_('To delete a tag, untag the associated notes.'));
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
this.store().dispatch({
type: 'SEARCH_REMOVE',
id: item.id,
});
}
} else if (this.widget('noteList').hasFocus) {
await this.processCommand('rmnote $n');
} else {
this.stdout(_('Please select the note or notebook to be deleted first.'));
}
if (item.command in this.tkWidgetKeys_) {
item.type = 'tkwidgets';
}
};
shortcuts[' '] = {
friendlyName: 'SPACE',
description: () => _('Set a to-do as completed / not completed'),
action: 'todo toggle $n',
item.canRunAlongOtherCommands = item.type === 'function' && ['toggle_metadata', 'toggle_console'].indexOf(item.command) >= 0;
output.push(item);
}
shortcuts['tc'] = {
description: () => _('[t]oggle [c]onsole between maximized/minimized/hidden/visible.'),
action: () => {
if (!this.consoleIsShown()) {
this.showConsole();
this.minimizeConsole();
} else {
if (this.consoleIsMaximized()) {
this.hideConsole();
} else {
this.maximizeConsole();
}
}
},
canRunAlongOtherCommands: true,
}
shortcuts['/'] = {
description: () => _('Search'),
action: { type: 'prompt', initialText: 'search ""', cursorPosition: -2 },
};
shortcuts['tm'] = {
description: () => _('[t]oggle note [m]etadata.'),
action: () => {
this.toggleNoteMetadata();
},
canRunAlongOtherCommands: true,
}
shortcuts['mn'] = {
description: () => _('[M]ake a new [n]ote'),
action: { type: 'prompt', initialText: 'mknote ""', cursorPosition: -2 },
}
shortcuts['mt'] = {
description: () => _('[M]ake a new [t]odo'),
action: { type: 'prompt', initialText: 'mktodo ""', cursorPosition: -2 },
}
shortcuts['mb'] = {
description: () => _('[M]ake a new note[b]ook'),
action: { type: 'prompt', initialText: 'mkbook ""', cursorPosition: -2 },
}
shortcuts['yn'] = {
description: () => _('Copy ([Y]ank) the [n]ote to a notebook.'),
action: { type: 'prompt', initialText: 'cp $n ""', cursorPosition: -2 },
}
shortcuts['dn'] = {
description: () => _('Move the note to a notebook.'),
action: { type: 'prompt', initialText: 'mv $n ""', cursorPosition: -2 },
}
return shortcuts;
return output;
}
toggleConsole() {
@@ -474,8 +386,16 @@ class AppGui {
return this.logger_;
}
shortcuts() {
return this.shortcuts_;
keymap() {
return this.keymap_;
}
keymapItemByKey(key) {
for (let i = 0; i < this.keymap_.length; i++) {
const item = this.keymap_[i];
if (item.keys.indexOf(key) >= 0) return item;
}
return null;
}
term() {
@@ -506,40 +426,104 @@ class AppGui {
}
}
async processCommand(cmd) {
async processFunctionCommand(cmd) {
if (cmd === 'activate') {
const w = this.widget('mainWindow').focusedWidget;
if (w.name === 'folderList') {
this.widget('noteList').focus();
} else if (w.name === 'noteList' || w.name === 'noteText') {
this.processPromptCommand('edit $n');
}
} else if (cmd === 'delete') {
if (this.widget('folderList').hasFocus) {
const item = this.widget('folderList').selectedJoplinItem;
if (!item) return;
if (item.type_ === BaseModel.TYPE_FOLDER) {
await this.processPromptCommand('rmbook ' + item.id);
} else if (item.type_ === BaseModel.TYPE_TAG) {
this.stdout(_('To delete a tag, untag the associated notes.'));
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
this.store().dispatch({
type: 'SEARCH_DELETE',
id: item.id,
});
}
} else if (this.widget('noteList').hasFocus) {
await this.processPromptCommand('rmnote $n');
} else {
this.stdout(_('Please select the note or notebook to be deleted first.'));
}
} else if (cmd === 'toggle_console') {
if (!this.consoleIsShown()) {
this.showConsole();
this.minimizeConsole();
} else {
if (this.consoleIsMaximized()) {
this.hideConsole();
} else {
this.maximizeConsole();
}
}
} else if (cmd === 'toggle_metadata') {
this.toggleNoteMetadata();
} else if (cmd === 'enter_command_line_mode') {
const cmd = await this.widget('statusBar').prompt();
if (!cmd) return;
this.addCommandToConsole(cmd);
await this.processPromptCommand(cmd);
} else {
throw new Error('Unknown command: ' + cmd);
}
}
async processPromptCommand(cmd) {
if (!cmd) return;
cmd = cmd.trim();
if (!cmd.length) return;
this.logger().info('Got command: ' + cmd);
if (cmd === 'q' || cmd === 'wq' || cmd === 'qa') { // Vim bonus
await this.app().exit();
return;
}
try {
let note = this.widget('noteList').currentItem;
let folder = this.widget('folderList').currentItem;
let args = splitCommandString(cmd);
let note = this.widget('noteList').currentItem;
let folder = this.widget('folderList').currentItem;
let args = cliUtils.splitCommandString(cmd);
for (let i = 0; i < args.length; i++) {
if (args[i] == '$n') {
args[i] = note ? note.id : '';
} else if (args[i] == '$b') {
args[i] = folder ? folder.id : '';
} else if (args[i] == '$c') {
const item = this.activeListItem();
args[i] = item ? item.id : '';
for (let i = 0; i < args.length; i++) {
if (args[i] == '$n') {
args[i] = note ? note.id : '';
} else if (args[i] == '$b') {
args[i] = folder ? folder.id : '';
} else if (args[i] == '$c') {
const item = this.activeListItem();
args[i] = item ? item.id : '';
}
}
}
try {
await this.app().execCommand(args);
} catch (error) {
this.stdout(error.message);
}
this.widget('console').scrollBottom();
// Invalidate so that the screen is redrawn in case inputting a command has moved
// the GUI up (in particular due to autocompletion), it's moved back to the right position.
this.widget('root').invalidate();
}
async updateFolderList() {
@@ -764,32 +748,34 @@ class AppGui {
// -------------------------------------------------------------------------
const shortcutKey = this.currentShortcutKeys_.join('');
const cmd = shortcutKey in this.shortcuts_ ? this.shortcuts_[shortcutKey] : null;
let keymapItem = this.keymapItemByKey(shortcutKey);
let processShortcutKeys = !this.app().currentCommand() && cmd;
if (cmd && cmd.canRunAlongOtherCommands) processShortcutKeys = true;
// If this command is an alias to another command, resolve to the actual command
let processShortcutKeys = !this.app().currentCommand() && keymapItem;
if (keymapItem && keymapItem.canRunAlongOtherCommands) processShortcutKeys = true;
if (statusBar.promptActive) processShortcutKeys = false;
if (cmd && cmd.isDocOnly) processShortcutKeys = false;
if (processShortcutKeys) {
this.logger().info('Shortcut:', shortcutKey, cmd.description());
this.logger().info('Shortcut:', shortcutKey, keymapItem);
this.currentShortcutKeys_ = [];
if (typeof cmd.action === 'function') {
await cmd.action();
} else if (typeof cmd.action === 'object') {
if (cmd.action.type === 'prompt') {
let promptOptions = {};
if ('cursorPosition' in cmd.action) promptOptions.cursorPosition = cmd.action.cursorPosition;
const commandString = await statusBar.prompt(cmd.action.initialText ? cmd.action.initialText : '', null, promptOptions);
this.addCommandToConsole(commandString);
await this.processCommand(commandString);
} else {
throw new Error('Unknown command: ' + JSON.stringify(cmd.action));
}
} else { // String
this.stdout(cmd.action);
await this.processCommand(cmd.action);
if (keymapItem.type === 'function') {
this.processFunctionCommand(keymapItem.command);
} else if (keymapItem.type === 'prompt') {
let promptOptions = {};
if ('cursorPosition' in keymapItem) promptOptions.cursorPosition = keymapItem.cursorPosition;
const commandString = await statusBar.prompt(keymapItem.command ? keymapItem.command : '', null, promptOptions);
this.addCommandToConsole(commandString);
await this.processPromptCommand(commandString);
} else if (keymapItem.type === 'exec') {
this.stdout(keymapItem.command);
await this.processPromptCommand(keymapItem.command);
} else if (keymapItem.type === 'tkwidgets') {
this.widget('root').handleKey(this.tkWidgetKeys_[keymapItem.command]);
} else {
throw new Error('Unknown command type: ' + JSON.stringify(keymapItem));
}
}
@@ -815,4 +801,4 @@ class AppGui {
AppGui.INPUT_MODE_NORMAL = 1;
AppGui.INPUT_MODE_META = 2;
module.exports = AppGui;
module.exports = AppGui;

View File

@@ -5,12 +5,12 @@ const { JoplinDatabase } = require('lib/joplin-database.js');
const { Database } = require('lib/database.js');
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { BaseItem } = require('lib/models/base-item.js');
const { Note } = require('lib/models/note.js');
const { Tag } = require('lib/models/tag.js');
const { Setting } = require('lib/models/setting.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const BaseItem = require('lib/models/BaseItem.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const Setting = require('lib/models/Setting.js');
const { Logger } = require('lib/logger.js');
const { sprintf } = require('sprintf-js');
const { reg } = require('lib/registry.js');
@@ -21,6 +21,7 @@ const os = require('os');
const fs = require('fs-extra');
const { cliUtils } = require('./cli-utils.js');
const EventEmitter = require('events');
const Cache = require('lib/Cache');
class Application extends BaseApplication {
@@ -34,6 +35,7 @@ class Application extends BaseApplication {
this.allCommandsLoaded_ = false;
this.showStackTraces_ = false;
this.gui_ = null;
this.cache_ = new Cache();
}
gui() {
@@ -144,13 +146,15 @@ class Application extends BaseApplication {
message += ' (' + options.answers.join('/') + ')';
}
let answer = await this.gui().prompt('', message + ' ');
let answer = await this.gui().prompt('', message + ' ', options);
if (options.type === 'boolean') {
if (answer === null) return false; // Pressed ESCAPE
if (!answer) answer = options.answers[0];
let positiveIndex = options.booleanAnswerDefault == 'y' ? 0 : 1;
return answer.toLowerCase() === options.answers[positiveIndex].toLowerCase();
} else {
return answer;
}
});
@@ -168,31 +172,42 @@ class Application extends BaseApplication {
await doExit();
}, 5000);
if (await reg.syncStarted()) {
if (await reg.syncTarget().syncStarted()) {
this.stdout(_('Cancelling background synchronisation... Please wait.'));
const sync = await reg.synchronizer(Setting.value('sync.target'));
const sync = await reg.syncTarget().synchronizer();
await sync.cancel();
}
await doExit();
}
commands() {
if (this.allCommandsLoaded_) return this.commands_;
commands(uiType = null) {
if (!this.allCommandsLoaded_) {
fs.readdirSync(__dirname).forEach((path) => {
if (path.indexOf('command-') !== 0) return;
const ext = fileExtension(path)
if (ext != 'js') return;
fs.readdirSync(__dirname).forEach((path) => {
if (path.indexOf('command-') !== 0) return;
const ext = fileExtension(path)
if (ext != 'js') return;
let CommandClass = require('./' + path);
let cmd = new CommandClass();
if (!cmd.enabled()) return;
cmd = this.setupCommand(cmd);
this.commands_[cmd.name()] = cmd;
});
let CommandClass = require('./' + path);
let cmd = new CommandClass();
if (!cmd.enabled()) return;
cmd = this.setupCommand(cmd);
this.commands_[cmd.name()] = cmd;
});
this.allCommandsLoaded_ = true;
}
this.allCommandsLoaded_ = true;
if (uiType !== null) {
let temp = [];
for (let n in this.commands_) {
if (!this.commands_.hasOwnProperty(n)) continue;
const c = this.commands_[n];
if (!c.supportsUi(uiType)) continue;
temp[n] = c;
}
return temp;
}
return this.commands_;
}
@@ -210,12 +225,8 @@ class Application extends BaseApplication {
async commandMetadata() {
if (this.commandMetadata_) return this.commandMetadata_;
const osTmpdir = require('os-tmpdir');
const storage = require('node-persist');
await storage.init({ dir: osTmpdir() + '/commandMetadata', ttl: 1000 * 60 * 60 * 24 });
let output = await storage.getItem('metadata');
if (Setting.value('env') != 'dev' && output) {
let output = await this.cache_.getItem('metadata');
if (output) {
this.commandMetadata_ = output;
return Object.assign({}, this.commandMetadata_);
}
@@ -229,7 +240,7 @@ class Application extends BaseApplication {
output[n] = cmd.metadata();
}
await storage.setItem('metadata', output);
await this.cache_.setItem('metadata', output, 1000 * 60 * 60 * 24);
this.commandMetadata_ = output;
return Object.assign({}, this.commandMetadata_);
@@ -246,9 +257,13 @@ class Application extends BaseApplication {
try {
CommandClass = require(__dirname + '/command-' + name + '.js');
} catch (error) {
let e = new Error('No such command: ' + name);
e.type = 'notFound';
throw e;
if (error.message && error.message.indexOf('Cannot find module') >= 0) {
let e = new Error(_('No such command: %s', name));
e.type = 'notFound';
throw e;
} else {
throw error;
}
}
let cmd = new CommandClass();
@@ -260,7 +275,7 @@ class Application extends BaseApplication {
dummyGui() {
return {
isDummy: () => { return true; },
prompt: (initialText = '', promptString = '') => { return cliUtils.prompt(initialText, promptString); },
prompt: (initialText = '', promptString = '', options = null) => { return cliUtils.prompt(initialText, promptString, options); },
showConsole: () => {},
maximizeConsole: () => {},
stdout: (text) => { console.info(text); },
@@ -268,7 +283,10 @@ class Application extends BaseApplication {
exit: () => {},
showModalOverlay: (text) => {},
hideModalOverlay: () => {},
stdoutMaxWidth: () => { return 78; }
stdoutMaxWidth: () => { return 100; },
forceRender: () => {},
termSaveState: () => {},
termRestoreState: (state) => {},
};
}
@@ -294,6 +312,63 @@ class Application extends BaseApplication {
return this.activeCommand_;
}
async loadKeymaps() {
const defaultKeyMap = [
{ "keys": [":"], "type": "function", "command": "enter_command_line_mode" },
{ "keys": ["TAB"], "type": "function", "command": "focus_next" },
{ "keys": ["SHIFT_TAB"], "type": "function", "command": "focus_previous" },
{ "keys": ["UP"], "type": "function", "command": "move_up" },
{ "keys": ["DOWN"], "type": "function", "command": "move_down" },
{ "keys": ["PAGE_UP"], "type": "function", "command": "page_up" },
{ "keys": ["PAGE_DOWN"], "type": "function", "command": "page_down" },
{ "keys": ["ENTER"], "type": "function", "command": "activate" },
{ "keys": ["DELETE", "BACKSPACE"], "type": "function", "command": "delete" },
{ "keys": [" "], "command": "todo toggle $n" },
{ "keys": ["tc"], "type": "function", "command": "toggle_console" },
{ "keys": ["tm"], "type": "function", "command": "toggle_metadata" },
{ "keys": ["/"], "type": "prompt", "command": "search \"\"", "cursorPosition": -2 },
{ "keys": ["mn"], "type": "prompt", "command": "mknote \"\"", "cursorPosition": -2 },
{ "keys": ["mt"], "type": "prompt", "command": "mktodo \"\"", "cursorPosition": -2 },
{ "keys": ["mb"], "type": "prompt", "command": "mkbook \"\"", "cursorPosition": -2 },
{ "keys": ["yn"], "type": "prompt", "command": "cp $n \"\"", "cursorPosition": -2 },
{ "keys": ["dn"], "type": "prompt", "command": "mv $n \"\"", "cursorPosition": -2 }
];
// Filter the keymap item by command so that items in keymap.json can override
// the default ones.
const itemsByCommand = {};
for (let i = 0; i < defaultKeyMap.length; i++) {
itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i]
}
const filePath = Setting.value('profileDir') + '/keymap.json';
if (await fs.pathExists(filePath)) {
try {
let configString = await fs.readFile(filePath, 'utf-8');
configString = configString.replace(/^\s*\/\/.*/, ''); // Strip off comments
const keymap = JSON.parse(configString);
for (let keymapIndex = 0; keymapIndex < keymap.length; keymapIndex++) {
const item = keymap[keymapIndex];
itemsByCommand[item.command] = item;
}
} catch (error) {
let msg = error.message ? error.message : '';
msg = 'Could not load keymap ' + filePath + '\n' + msg;
error.message = msg;
throw error;
}
}
const output = [];
for (let n in itemsByCommand) {
if (!itemsByCommand.hasOwnProperty(n)) continue;
output.push(itemsByCommand[n]);
}
return output;
}
async start(argv) {
argv = await super.start(argv);
@@ -306,20 +381,25 @@ class Application extends BaseApplication {
if (argv.length) {
this.gui_ = this.dummyGui();
this.currentFolder_ = await Folder.load(Setting.value('activeFolderId'));
try {
await this.execCommand(argv);
} catch (error) {
if (this.showStackTraces_) {
console.info(error);
console.error(error);
} else {
console.info(error.message);
}
process.exit(1);
}
} else { // Otherwise open the GUI
this.initRedux();
const keymap = await this.loadKeymaps();
const AppGui = require('./app-gui.js');
this.gui_ = new AppGui(this, this.store());
this.gui_ = new AppGui(this, this.store(), keymap);
this.gui_.setLogger(this.logger_);
await this.gui_.start();
@@ -334,7 +414,7 @@ class Application extends BaseApplication {
this.dispatch({
type: 'TAG_UPDATE_ALL',
tags: tags,
items: tags,
});
this.store().dispatch({

View File

@@ -0,0 +1,199 @@
var { app } = require('./app.js');
var Note = require('lib/models/Note.js');
var Folder = require('lib/models/Folder.js');
var Tag = require('lib/models/Tag.js');
var { cliUtils } = require('./cli-utils.js');
var yargParser = require('yargs-parser');
var fs = require('fs-extra');
async function handleAutocompletionPromise(line) {
// Auto-complete the command name
const names = await app().commandNames();
let words = getArguments(line);
//If there is only one word and it is not already a command name then you
//should look for commmands it could be
if (words.length == 1) {
if (names.indexOf(words[0]) === -1) {
let x = names.filter((n) => n.indexOf(words[0]) === 0);
if (x.length === 1) {
return x[0] + ' ';
}
return x.length > 0 ? x.map((a) => a + ' ') : line;
} else {
return line;
}
}
//There is more than one word and it is a command
const metadata = (await app().commandMetadata())[words[0]];
//If for some reason this command does not have any associated metadata
//just don't autocomplete. However, this should not happen.
if (metadata === undefined) {
return line;
}
//complete an option
let next = words.length > 1 ? words[words.length - 1] : '';
let l = [];
if (next[0] === '-') {
for (let i = 0; i<metadata.options.length; i++) {
const options = metadata.options[i][0].split(' ');
//if there are multiple options then they will be seperated by comma and
//space. The comma should be removed
if (options[0][options[0].length - 1] === ',') {
options[0] = options[0].slice(0, -1);
}
if (words.includes(options[0]) || words.includes(options[1])) {
continue;
}
//First two elements are the flag and the third is the description
//Only autocomplete long
if (options.length > 1 && options[1].indexOf(next) === 0) {
l.push(options[1]);
} else if (options[0].indexOf(next) === 0) {
l.push(options[0]);
}
}
if (l.length === 0) {
return line;
}
let ret = l.map(a=>toCommandLine(a));
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
return ret;
}
//Complete an argument
//Determine the number of positional arguments by counting the number of
//words that don't start with a - less one for the command name
const positionalArgs = words.filter((a)=>a.indexOf('-') !== 0).length - 1;
let cmdUsage = yargParser(metadata.usage)['_'];
cmdUsage.splice(0, 1);
if (cmdUsage.length >= positionalArgs) {
let argName = cmdUsage[positionalArgs - 1];
argName = cliUtils.parseCommandArg(argName).name;
const currentFolder = app().currentFolder();
if (argName == 'note' || argName == 'note-pattern') {
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
l.push(...notes.map((n) => n.title));
}
if (argName == 'notebook') {
const folders = await Folder.search({ titlePattern: next + '*' });
l.push(...folders.map((n) => n.title));
}
if (argName == 'item') {
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
const folders = await Folder.search({ titlePattern: next + '*' });
l.push(...notes.map((n) => n.title), folders.map((n) => n.title));
}
if (argName == 'tag') {
let tags = await Tag.search({ titlePattern: next + '*' });
l.push(...tags.map((n) => n.title));
}
if (argName == 'file') {
let files = await fs.readdir('.');
l.push(...files);
}
if (argName == 'tag-command') {
let c = filterList(['add', 'remove', 'list'], next);
l.push(...c);
}
if (argName == 'todo-command') {
let c = filterList(['toggle', 'clear'], next);
l.push(...c);
}
}
if (l.length === 1) {
return toCommandLine([...words.slice(0, -1), l[0]]);
} else if (l.length > 1) {
let ret = l.map(a=>toCommandLine(a));
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
return ret;
}
return line;
}
function handleAutocompletion(str, callback) {
handleAutocompletionPromise(str).then(function(res) {
callback(undefined, res);
});
}
function toCommandLine(args) {
if (Array.isArray(args)) {
return args.map(function(a) {
if(a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
return "'" + a + "'";
} else if (a.indexOf("'") !== -1) {
return '"' + a + '"';
} else {
return a;
}
}).join(' ');
} else {
if(args.indexOf('"') !== -1 || args.indexOf(' ') !== -1) {
return "'" + args + "' ";
} else if (args.indexOf("'") !== -1) {
return '"' + args + '" ';
} else {
return args + ' ';
}
}
}
function getArguments(line) {
let inSingleQuotes = false;
let inDoubleQuotes = false;
let currentWord = '';
let parsed = [];
for(let i = 0; i<line.length; i++) {
if(line[i] === '"') {
if(inDoubleQuotes) {
inDoubleQuotes = false;
//maybe push word to parsed?
//currentWord += '"';
} else {
inDoubleQuotes = true;
//currentWord += '"';
}
} else if(line[i] === "'") {
if(inSingleQuotes) {
inSingleQuotes = false;
//maybe push word to parsed?
//currentWord += "'";
} else {
inSingleQuotes = true;
//currentWord += "'";
}
} else if (/\s/.test(line[i]) &&
!(inDoubleQuotes || inSingleQuotes)) {
if (currentWord !== '') {
parsed.push(currentWord);
currentWord = '';
}
} else {
currentWord += line[i];
}
}
if (!(inSingleQuotes || inDoubleQuotes) && /\s/.test(line[line.length - 1])) {
parsed.push('');
} else {
parsed.push(currentWord);
}
return parsed;
}
function filterList(list, next) {
let output = [];
for (let i = 0; i < list.length; i++) {
if (list[i].indexOf(next) !== 0) continue;
output.push(list[i]);
}
return output;
}
module.exports = { handleAutocompletion };

View File

@@ -12,6 +12,10 @@ class BaseCommand {
throw new Error('Usage not defined');
}
encryptionCheck(item) {
if (item && item.encryption_applied) throw new Error(_('Cannot change encrypted item'));
}
description() {
throw new Error('Description not defined');
}
@@ -28,10 +32,6 @@ class BaseCommand {
return this.compatibleUis().indexOf(ui) >= 0;
}
aliases() {
return [];
}
options() {
return [];
}

View File

@@ -1,154 +0,0 @@
"use strict"
require('app-module-path').addPath(__dirname);
const processArgs = process.argv.splice(2, process.argv.length);
const silentLog = processArgs.indexOf('--silent') >= 0;
const { basename, dirname } = require('lib/path-utils.js');
const fs = require('fs-extra');
const gettextParser = require('gettext-parser');
const rootDir = dirname(dirname(__dirname));
const cliDir = rootDir + '/CliClient';
const cliLocalesDir = cliDir + '/locales';
const rnDir = rootDir + '/ReactNativeClient';
const electronDir = rootDir + '/ElectronClient/app';
function execCommand(command) {
if (!silentLog) console.info('Running: ' + command);
const exec = require('child_process').exec
return new Promise((resolve, reject) => {
let childProcess = exec(command, (error, stdout, stderr) => {
if (error) {
if (error.signal == 'SIGTERM') {
resolve('Process was killed');
} else {
reject(error);
}
} else {
resolve(stdout.trim());
}
});
});
}
function parsePoFile(filePath) {
const content = fs.readFileSync(filePath);
return gettextParser.po.parse(content);
}
function serializeTranslation(translation) {
let output = {};
const translations = translation.translations[''];
for (let n in translations) {
if (!translations.hasOwnProperty(n)) continue;
if (n == '') continue;
const t = translations[n];
if (t.comments && t.comments.flag && t.comments.flag.indexOf('fuzzy') >= 0) {
output[n] = t['msgid'];
} else {
output[n] = t['msgstr'][0];
}
}
return JSON.stringify(output);
}
function saveToFile(filePath, data) {
fs.writeFileSync(filePath, data);
}
function buildLocale(inputFile, outputFile) {
const r = parsePoFile(inputFile);
const translation = serializeTranslation(r);
saveToFile(outputFile, translation);
}
async function removePoHeaderDate(filePath) {
await execCommand('sed -i -e\'/POT-Creation-Date:/d\' "' + filePath + '"');
await execCommand('sed -i -e\'/PO-Revision-Date:/d\' "' + filePath + '"');
}
async function createPotFile(potFilePath, sources) {
let baseArgs = [];
baseArgs.push('--from-code=utf-8');
baseArgs.push('--output="' + potFilePath + '"');
baseArgs.push('--language=JavaScript');
baseArgs.push('--copyright-holder="Laurent Cozic"');
baseArgs.push('--package-name=Joplin-CLI');
baseArgs.push('--package-version=1.0.0');
baseArgs.push('--no-location');
for (let i = 0; i < sources.length; i++) {
let args = baseArgs.slice();
if (i > 0) args.push('--join-existing');
args.push(sources[i]);
const result = await execCommand('xgettext ' + args.join(' '));
if (result) console.error(result);
await removePoHeaderDate(potFilePath);
}
}
async function mergePotToPo(potFilePath, poFilePath) {
const command = 'msgmerge -U "' + poFilePath + '" "' + potFilePath + '"';
const result = await execCommand(command);
if (result) console.error(result);
await removePoHeaderDate(poFilePath);
}
function buildIndex(locales) {
let output = [];
output.push('var locales = {};');
for (let i = 0; i < locales.length; i++) {
const locale = locales[i];
output.push("locales['" + locale + "'] = require('./" + locale + ".json');");
}
output.push('module.exports = { locales: locales };');
return output.join("\n");
}
async function main() {
let potFilePath = cliLocalesDir + '/joplin.pot';
let jsonLocalesDir = cliDir + '/build/locales';
const defaultLocale = 'en_GB';
await createPotFile(potFilePath, [
cliDir + '/app/*.js',
cliDir + '/app/gui/*.js',
electronDir + '/*.js',
electronDir + '/gui/*.js',
rnDir + '/lib/*.js',
rnDir + '/lib/models/*.js',
rnDir + '/lib/services/*.js',
rnDir + '/lib/components/*.js',
rnDir + '/lib/components/screens/*.js',
]);
await execCommand('cp "' + potFilePath + '" ' + '"' + cliLocalesDir + '/' + defaultLocale + '.po"');
fs.mkdirpSync(jsonLocalesDir, 0o755);
let locales = [defaultLocale, 'fr_FR'];
for (let i = 0; i < locales.length; i++) {
const locale = locales[i];
const poFilePäth = cliLocalesDir + '/' + locale + '.po';
const jsonFilePath = jsonLocalesDir + '/' + locale + '.json';
if (locale != defaultLocale) await mergePotToPo(potFilePath, poFilePäth);
buildLocale(poFilePäth, jsonFilePath);
}
saveToFile(jsonLocalesDir + '/index.js', buildIndex(locales));
const rnJsonLocaleDir = rnDir + '/locales';
await execCommand('rsync -a "' + jsonLocalesDir + '/" "' + rnJsonLocaleDir + '"');
const electronJsonLocaleDir = electronDir + '/locales';
await execCommand('rsync -a "' + jsonLocalesDir + '/" "' + electronJsonLocaleDir + '"');
}
main().catch((error) => {
console.error(error);
});

View File

@@ -1,208 +0,0 @@
const fs = require('fs-extra');
const { fileExtension, basename, dirname } = require('lib/path-utils.js');
const { _, setLocale, languageCode } = require('lib/locale.js');
const marked = require('lib/marked.js');
const headerHtml = `
<!doctype html>
<html>
<head>
<title>Joplin - a free, open source, te taking and to-do application with synchronisation capabilities</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<style>
body {
background-color: #F1F1F1;
color: #333333;
}
table {
margin-bottom: 1em;
}
td, th {
padding: .5em 1em .5em 0;
}
h1, h2 {
border-bottom: 1px solid #eaecef;
padding-bottom: 0.3em;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-weight: 600;
font-size: 2em;
margin-bottom: 16px;
}
h2 {
font-size: 1.6em;
}
h3 {
font-size: 1.3em;
}
code {
color: black;
background-color: #eee;
border: 1px solid #ccc;
}
pre code {
border: none;
}
.title-icon {
height: 2em;
}
.sub-title {
font-weight: bold;
font-size: 1.5em;
}
.container {
background-color: white;
padding: 0;
box-shadow: 0 10px 20px #888888;
}
table.screenshots {
margin-top: 2em;
margin-bottom: 2em;
}
table.screenshots th {
height: 3em;
text-align: center;
}
table.screenshots th,
table.screenshots td {
border: 1px solid #C2C2C2;
}
.mobile-screenshot {
height: 40em;
padding: 1em;
}
.cli-screenshot-wrapper {
background-color: black;
vertical-align: top;
padding: 1em 2em 1em 1em;
}
.cli-screenshot {
font-family: "Monaco", "Inconsolata", "CONSOLAS", "Deja Vu Sans Mono", "Droid Sans Mono", "Andale Mono", monospace;
background-color: black;
color: white;
border: none;
}
.cli-screenshot .prompt {
color: #48C2F0;
}
.header {
position: relative;
padding-left: 2em;
padding-right: 2em;
padding-top: 1em;
padding-bottom: 1em;
color: white;
background-color: #2B2B3D;
}
.content {
padding-left: 2em;
padding-right: 2em;
padding-bottom: 2em;
padding-top: 2em;
}
.forkme {
position: absolute;
right: 0;
top:0;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<a class="forkme" href="https://github.com/laurent22/joplin"><img src="docs/images/ForkMe.png"/></a>
<h1 id="joplin"><img class="title-icon" src="docs/images/Icon512.png">oplin</h1>
<p class="sub-title">A free, open source, note taking and to-do application with synchronisation capabilities.</p>
</div>
<div class="content">
`;
const footerHtml = `
</body>
</html>
`;
// const screenshotHtml = `
// <table class="screenshots">
// <tr>
// <th>
// Mobile
// </th>
// <th>
// Command line
// </th>
// </tr>
// <tr>
// <td>
// <img class="mobile-screenshot" src="docs/images/Mobile.png"/>
// </td>
// <td class="cli-screenshot-wrapper">
// <pre class="cli-screenshot">
// <span class="prompt">joplin:/My notebook$</span> ls -n 12
// [ ] 8am conference call ☎
// [ ] Make vet appointment
// [ ] Go pick up parcel
// [ ] Pay flat rent 💸
// [X] Book ferry 🚢
// [X] Deploy Joplin app
// Open source stuff
// Swimming pool time table 🏊
// Grocery shopping list 📝
// Work itinerary
// Tuesday random note
// Vacation plans ☀️
// </pre>
// </td>
// </tr>
// </table>
// `;
const gaHtml = `
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-103586105-1', 'auto');
ga('send', 'pageview');
</script>
`;
const rootDir = dirname(dirname(__dirname));
function markdownToHtml(md) {
const renderer = new marked.Renderer();
// Remove the header because it's going to be added back as HTML
md = md.replace(/# Joplin/, '');
let output = marked(md, {
gfm: true,
break: true,
renderer: renderer,
});
//output = output.replace(/<!-- \[SCREENSHOTS\] -->/, screenshotHtml);
return headerHtml + output + gaHtml + footerHtml;
}
async function main() {
const md = fs.readFileSync(rootDir + '/README.md', 'utf8');
const html = markdownToHtml(md);
fs.writeFileSync(rootDir + '/index.html', html);
}
main().catch((error) => {
console.error(error);
});

View File

@@ -5,10 +5,10 @@ const { Logger } = require('lib/logger.js');
const { dirname } = require('lib/path-utils.js');
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
const { JoplinDatabase } = require('lib/joplin-database.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const { Setting } = require('lib/models/setting.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const { sprintf } = require('sprintf-js');
const exec = require('child_process').exec

View File

@@ -5,75 +5,6 @@ const stringPadding = require('string-padding');
const cliUtils = {};
cliUtils.splitCommandString = function(command) {
let args = [];
let state = "start"
let current = ""
let quote = "\""
let escapeNext = false;
for (let i = 0; i < command.length; i++) {
let c = command[i]
if (state == "quotes") {
if (c != quote) {
current += c
} else {
args.push(current)
current = ""
state = "start"
}
continue
}
if (escapeNext) {
current += c;
escapeNext = false;
continue;
}
if (c == "\\") {
escapeNext = true;
continue;
}
if (c == '"' || c == '\'') {
state = "quotes"
quote = c
continue
}
if (state == "arg") {
if (c == ' ' || c == '\t') {
args.push(current)
current = ""
state = "start"
} else {
current += c
}
continue
}
if (c != ' ' && c != "\t") {
state = "arg"
current += c
}
}
if (state == "quotes") {
throw new Error("Unclosed quote in command line: " + command)
}
if (current != "") {
args.push(current)
}
if (args.length <= 0) {
throw new Error("Empty command line")
}
return args;
}
cliUtils.printArray = function(logFunction, rows, headers = null) {
if (!rows.length) return '';
@@ -247,38 +178,39 @@ cliUtils.promptConfirm = function(message, answers = null) {
});
}
cliUtils.promptInput = function(message) {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise((resolve, reject) => {
rl.question(message + ' ', (answer) => {
rl.close();
resolve(answer);
});
});
}
// Note: initialText is there to have the same signature as statusBar.prompt() so that
// it can be a drop-in replacement, however initialText is not used (and cannot be
// with readline.question?).
cliUtils.prompt = function(initialText = '', promptString = ':') {
cliUtils.prompt = function(initialText = '', promptString = ':', options = null) {
if (!options) options = {};
const readline = require('readline');
const Writable = require('stream').Writable;
const mutableStdout = new Writable({
write: function(chunk, encoding, callback) {
if (!this.muted)
process.stdout.write(chunk, encoding);
callback();
}
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
output: mutableStdout,
terminal: true,
});
return new Promise((resolve, reject) => {
mutableStdout.muted = false;
rl.question(promptString, (answer) => {
rl.close();
if (!!options.secure) this.stdout_('');
resolve(answer);
});
mutableStdout.muted = !!options.secure;
});
}

View File

@@ -1,7 +1,7 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim.js');
const fs = require('fs-extra');
@@ -19,6 +19,7 @@ class Command extends BaseCommand {
let title = args['note'];
let note = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
this.encryptionCheck(note);
if (!note) throw new Error(_('Cannot find "%s".', title));
const localFilePath = args['file'];

View File

@@ -1,9 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
@@ -21,10 +21,6 @@ class Command extends BaseCommand {
];
}
enabled() {
return false;
}
async action(args) {
let title = args['note'];
@@ -33,6 +29,9 @@ class Command extends BaseCommand {
const content = args.options.verbose ? await Note.serialize(item) : await Note.serializeForEdit(item);
this.stdout(content);
app().gui().showConsole();
app().gui().maximizeConsole();
}
}

View File

@@ -1,7 +1,7 @@
const { BaseCommand } = require('./base-command.js');
const { _, setLocale } = require('lib/locale.js');
const { app } = require('./app.js');
const { Setting } = require('lib/models/setting.js');
const Setting = require('lib/models/Setting.js');
class Command extends BaseCommand {
@@ -23,7 +23,11 @@ class Command extends BaseCommand {
const verbose = args.options.verbose;
const renderKeyValue = (name) => {
const value = Setting.value(name);
const md = Setting.settingMetadata(name);
let value = Setting.value(name);
if (typeof value === 'object' || Array.isArray(value)) value = JSON.stringify(value);
if (md.secure) value = '********';
if (Setting.isEnum(name)) {
return _('%s = %s (%s)', name, value, Setting.enumOptionsDoc(name));
} else {

View File

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

View File

@@ -1,9 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');
class Command extends BaseCommand {
@@ -16,8 +16,9 @@ class Command extends BaseCommand {
return _('Marks a to-do as done.');
}
static async handleAction(args, isCompleted) {
static async handleAction(commandInstance, args, isCompleted) {
const note = await app().loadItem(BaseModel.TYPE_NOTE, args.note);
commandInstance.encryptionCheck(note);
if (!note) throw new Error(_('Cannot find "%s".', args.note));
if (!note.is_todo) throw new Error(_('Note is not a to-do: "%s"', args.note));
@@ -32,7 +33,7 @@ class Command extends BaseCommand {
}
async action(args) {
await Command.handleAction(args, true);
await Command.handleAction(this, args, true);
}
}

View File

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

View File

@@ -0,0 +1,184 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const { cliUtils } = require('./cli-utils.js');
const EncryptionService = require('lib/services/EncryptionService');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const MasterKey = require('lib/models/MasterKey');
const BaseItem = require('lib/models/BaseItem');
const Setting = require('lib/models/Setting.js');
class Command extends BaseCommand {
usage() {
return 'e2ee <command> [path]';
}
description() {
return _('Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status` and `target-status`.');
}
options() {
return [
// This is here mostly for testing - shouldn't be used
['-p, --password <password>', 'Use this password as master password (For security reasons, it is not recommended to use this option).'],
['-v, --verbose', 'More verbose output for the `target-status` command'],
];
}
async action(args) {
// change-password
const options = args.options;
if (args.command === 'enable') {
const password = options.password ? options.password.toString() : await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
if (!password) {
this.stdout(_('Operation cancelled'));
return;
}
await EncryptionService.instance().generateMasterKeyAndEnableEncryption(password);
return;
}
if (args.command === 'disable') {
await EncryptionService.instance().disableEncryption();
return;
}
if (args.command === 'decrypt') {
this.stdout(_('Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.'));
while (true) {
try {
await DecryptionWorker.instance().start();
break;
} catch (error) {
if (error.code === 'masterKeyNotLoaded') {
const masterKeyId = error.masterKeyId;
const password = await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
if (!password) {
this.stdout(_('Operation cancelled'));
return;
}
Setting.setObjectKey('encryption.passwordCache', masterKeyId, password);
await EncryptionService.instance().loadMasterKeysFromSettings();
continue;
}
throw error;
}
}
this.stdout(_('Completed decryption.'));
return;
}
if (args.command === 'status') {
this.stdout(_('Encryption is: %s', Setting.value('encryption.enabled') ? _('Enabled') : _('Disabled')));
return;
}
if (args.command === 'target-status') {
const fs = require('fs-extra');
const pathUtils = require('lib/path-utils.js');
const fsDriver = new (require('lib/fs-driver-node.js').FsDriverNode)();
const targetPath = args.path;
if (!targetPath) throw new Error('Please specify the sync target path.');
const dirPaths = function(targetPath) {
let paths = [];
fs.readdirSync(targetPath).forEach((path) => {
paths.push(path);
});
return paths;
}
let itemCount = 0;
let resourceCount = 0;
let encryptedItemCount = 0;
let encryptedResourceCount = 0;
let otherItemCount = 0;
let encryptedPaths = [];
let decryptedPaths = [];
let paths = dirPaths(targetPath);
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
const fullPath = targetPath + '/' + path;
const stat = await fs.stat(fullPath);
// this.stdout(fullPath);
if (path === '.resource') {
let resourcePaths = dirPaths(fullPath);
for (let j = 0; j < resourcePaths.length; j++) {
const resourcePath = resourcePaths[j];
resourceCount++;
const fullResourcePath = fullPath + '/' + resourcePath;
const isEncrypted = await EncryptionService.instance().fileIsEncrypted(fullResourcePath);
if (isEncrypted) {
encryptedResourceCount++;
encryptedPaths.push(fullResourcePath);
} else {
decryptedPaths.push(fullResourcePath);
}
}
} else if (stat.isDirectory()) {
continue;
} else {
const content = await fs.readFile(fullPath, 'utf8');
const item = await BaseItem.unserialize(content);
const ItemClass = BaseItem.itemClass(item);
if (!ItemClass.encryptionSupported()) {
otherItemCount++;
continue;
}
itemCount++;
const isEncrypted = await EncryptionService.instance().itemIsEncrypted(item);
if (isEncrypted) {
encryptedItemCount++;
encryptedPaths.push(fullPath);
} else {
decryptedPaths.push(fullPath);
}
}
}
this.stdout('Encrypted items: ' + encryptedItemCount + '/' + itemCount);
this.stdout('Encrypted resources: ' + encryptedResourceCount + '/' + resourceCount);
this.stdout('Other items (never encrypted): ' + otherItemCount);
if (options.verbose) {
this.stdout('');
this.stdout('# Encrypted paths');
this.stdout('');
for (let i = 0; i < encryptedPaths.length; i++) {
const path = encryptedPaths[i];
this.stdout(path);
}
this.stdout('');
this.stdout('# Decrypted paths');
this.stdout('');
for (let i = 0; i < decryptedPaths.length; i++) {
const path = decryptedPaths[i];
this.stdout(path);
}
}
return;
}
}
}
module.exports = Command;

View File

@@ -3,10 +3,10 @@ const { BaseCommand } = require('./base-command.js');
const { uuid } = require('lib/uuid.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const { Setting } = require('lib/models/setting.js');
const { BaseModel } = require('lib/base-model.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const BaseModel = require('lib/BaseModel.js');
const { cliUtils } = require('./cli-utils.js');
const { time } = require('lib/time-utils.js');
@@ -44,6 +44,8 @@ class Command extends BaseCommand {
if (!app().currentFolder()) throw new Error(_('No active notebook.'));
let note = await app().loadItem(BaseModel.TYPE_NOTE, title);
this.encryptionCheck(note);
if (!note) {
const ok = await this.prompt(_('Note does not exist: "%s". Create it?', title));
if (!ok) return;
@@ -76,12 +78,14 @@ class Command extends BaseCommand {
app().gui().showModalOverlay(_('Starting to edit note. Close the editor to get back to the prompt.'));
await app().gui().forceRender();
const termState = app().gui().term().saveState();
const termState = app().gui().termSaveState();
const spawnSync = require('child_process').spawnSync;
spawnSync(editorPath, editorArgs, { stdio: 'inherit' });
const result = spawnSync(editorPath, editorArgs, { stdio: 'inherit' });
app().gui().term().restoreState(termState);
if (result.error) this.stdout(_('Error opening note in editor: %s', result.error.message));
app().gui().termRestoreState(termState);
app().gui().hideModalOverlay();
app().gui().forceRender();

View File

@@ -12,6 +12,10 @@ class Command extends BaseCommand {
return _('Exits the application.');
}
compatibleUis() {
return ['gui'];
}
async action(args) {
await app().exit();
}

View File

@@ -0,0 +1,36 @@
const { BaseCommand } = require('./base-command.js');
const { Database } = require('lib/database.js');
const { app } = require('./app.js');
const Setting = require('lib/models/Setting.js');
const { _ } = require('lib/locale.js');
const { ReportService } = require('lib/services/report.js');
const fs = require('fs-extra');
class Command extends BaseCommand {
usage() {
return 'export-sync-status';
}
description() {
return 'Export sync status';
}
hidden() {
return true;
}
async action(args) {
const service = new ReportService();
const csv = await service.basicItemList({ format: 'csv' });
const filePath = Setting.value('profileDir') + '/syncReport-' + (new Date()).getTime() + '.csv';
await fs.writeFileSync(filePath, csv);
this.stdout('Sync status exported to ' + filePath);
app().gui().showConsole();
app().gui().maximizeConsole();
}
}
module.exports = Command;

View File

@@ -1,7 +1,7 @@
const { BaseCommand } = require('./base-command.js');
const { Exporter } = require('lib/services/exporter.js');
const { BaseModel } = require('lib/base-model.js');
const { Note } = require('lib/models/note.js');
const InteropService = require('lib/services/InteropService.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const { reg } = require('lib/registry.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
@@ -10,15 +10,21 @@ const fs = require('fs-extra');
class Command extends BaseCommand {
usage() {
return 'export <directory>';
return 'export <path>';
}
description() {
return _('Exports Joplin data to the given directory. By default, it will export the complete database including notebooks, notes, tags and resources.');
return _('Exports Joplin data to the given path. By default, it will export the complete database including notebooks, notes, tags and resources.');
}
options() {
const service = new InteropService();
const formats = service.modules()
.filter(m => m.type === 'exporter')
.map(m => m.format + (m.description ? ' (' + m.description + ')' : ''));
return [
['--format <format>', _('Destination format: %s', formats.join(', '))],
['--note <note>', _('Exports only the given note.')],
['--notebook <notebook>', _('Exports only the given notebook.')],
];
@@ -26,13 +32,9 @@ class Command extends BaseCommand {
async action(args) {
let exportOptions = {};
exportOptions.destDir = args.directory;
exportOptions.writeFile = (filePath, data) => {
return fs.writeFile(filePath, data);
};
exportOptions.copyFile = (source, dest) => {
return fs.copy(source, dest, { overwrite: true });
};
exportOptions.path = args.path;
exportOptions.format = args.options.format ? args.options.format : 'jex';
if (args.options.note) {
@@ -48,10 +50,10 @@ class Command extends BaseCommand {
}
const exporter = new Exporter();
const result = await exporter.export(exportOptions);
const service = new InteropService();
const result = await service.export(exportOptions);
reg.logger().info('Export result: ', result);
result.warnings.map((w) => this.stdout(w));
}
}

View File

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

View File

@@ -2,7 +2,7 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { renderCommandHelp } = require('./help-utils.js');
const { Database } = require('lib/database.js');
const { Setting } = require('lib/models/setting.js');
const Setting = require('lib/models/Setting.js');
const { wrap } = require('lib/string-utils.js');
const { _ } = require('lib/locale.js');
const { cliUtils } = require('./cli-utils.js');
@@ -18,7 +18,7 @@ class Command extends BaseCommand {
}
allCommands() {
const commands = app().commands();
const commands = app().commands(app().uiType());
let output = [];
for (let n in commands) {
if (!commands.hasOwnProperty(n)) continue;
@@ -36,21 +36,22 @@ class Command extends BaseCommand {
async action(args) {
const stdoutWidth = app().commandStdoutMaxWidth();
if (args.command === 'shortcuts') {
if (args.command === 'shortcuts' || args.command === 'keymap') {
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'http://joplin.cozic.net/terminal/#shortcuts'));
this.stdout('');
if (app().gui().isDummy()) {
throw new Error(_('Shortcuts are not available in CLI mode.'));
}
const shortcuts = app().gui().shortcuts();
const keymap = app().gui().keymap();
let rows = [];
for (let n in shortcuts) {
if (!shortcuts.hasOwnProperty(n)) continue;
const shortcut = shortcuts[n];
if (!shortcut.description) continue;
n = shortcut.friendlyName ? shortcut.friendlyName : n;
rows.push([n, shortcut.description()]);
for (let i = 0; i < keymap.length; i++) {
const item = keymap[i];
const keys = item.keys.map((k) => k === ' ' ? '(SPACE)' : k);
rows.push([keys.join(', '), item.command]);
}
cliUtils.printArray(this.stdout.bind(this), rows);
@@ -65,7 +66,7 @@ class Command extends BaseCommand {
} else {
const commandNames = this.allCommands().map((a) => a.name());
this.stdout(_('Type `help [command]` for more information about a command.'));
this.stdout(_('Type `help [command]` for more information about a command; or type `help all` for the complete usage information.'));
this.stdout('');
this.stdout(_('The possible commands are:'));
this.stdout('');
@@ -78,7 +79,7 @@ class Command extends BaseCommand {
this.stdout(_('To maximise/minimise the console, press "TC".'));
this.stdout(_('To enter command line mode, press ":"'));
this.stdout(_('To exit command line mode, press ESCAPE'));
this.stdout(_('For the complete list of available keyboard shortcuts, type `help shortcuts`'));
this.stdout(_('For the list of keyboard shortcuts and config options, type `help keymap`'));
}
app().gui().showConsole();

View File

@@ -1,68 +0,0 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { Folder } = require('lib/models/folder.js');
const { importEnex } = require('import-enex');
const { filename, basename } = require('lib/path-utils.js');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {
usage() {
return 'import-enex <file> [notebook]';
}
description() {
return _('Imports an Evernote notebook file (.enex file).');
}
options() {
return [
['-f, --force', _('Do not ask for confirmation.')],
];
}
async action(args) {
let filePath = args.file;
let folder = null;
let folderTitle = args['notebook'];
let force = args.options.force === true;
if (!folderTitle) folderTitle = filename(filePath);
folder = await Folder.loadByField('title', folderTitle);
const msg = folder ? _('File "%s" will be imported into existing notebook "%s". Continue?', basename(filePath), folderTitle) : _('New notebook "%s" will be created and file "%s" will be imported into it. Continue?', folderTitle, basename(filePath));
const ok = force ? true : await this.prompt(msg);
if (!ok) return;
let lastProgress = '';
let options = {
onProgress: (progressState) => {
let line = [];
line.push(_('Found: %d.', progressState.loaded));
line.push(_('Created: %d.', progressState.created));
if (progressState.updated) line.push(_('Updated: %d.', progressState.updated));
if (progressState.skipped) line.push(_('Skipped: %d.', progressState.skipped));
if (progressState.resourcesCreated) line.push(_('Resources: %d.', progressState.resourcesCreated));
if (progressState.notesTagged) line.push(_('Tagged: %d.', progressState.notesTagged));
lastProgress = line.join(' ');
cliUtils.redraw(lastProgress);
},
onError: (error) => {
let s = error.trace ? error.trace : error.toString();
this.stdout(s);
},
}
folder = !folder ? await Folder.save({ title: folderTitle }) : folder;
app().gui().showConsole();
this.stdout(_('Importing notes...'));
await importEnex(folder.id, filePath, options);
cliUtils.redrawDone();
this.stdout(_('The notes have been imported: %s', lastProgress));
}
}
module.exports = Command;

View File

@@ -0,0 +1,75 @@
const { BaseCommand } = require('./base-command.js');
const InteropService = require('lib/services/InteropService.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const { filename, basename, fileExtension } = require('lib/path-utils.js');
const { importEnex } = require('lib/import-enex');
const { cliUtils } = require('./cli-utils.js');
const { reg } = require('lib/registry.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const fs = require('fs-extra');
class Command extends BaseCommand {
usage() {
return 'import <path> [notebook]';
}
description() {
return _('Imports data into Joplin.');
}
options() {
const service = new InteropService();
const formats = service.modules().filter(m => m.type === 'importer').map(m => m.format);
return [
['--format <format>', _('Source format: %s', (['auto'].concat(formats)).join(', '))],
['-f, --force', _('Do not ask for confirmation.')],
];
}
async action(args) {
let folder = await app().loadItem(BaseModel.TYPE_FOLDER, args.notebook);
if (args.notebook && !folder) throw new Error(_('Cannot find "%s".', args.notebook));
const importOptions = {};
importOptions.path = args.path;
importOptions.format = args.options.format ? args.options.format : 'auto';
importOptions.destinationFolderId = folder ? folder.id : null;
let lastProgress = '';
// onProgress/onError supported by Enex import only
importOptions.onProgress = (progressState) => {
let line = [];
line.push(_('Found: %d.', progressState.loaded));
line.push(_('Created: %d.', progressState.created));
if (progressState.updated) line.push(_('Updated: %d.', progressState.updated));
if (progressState.skipped) line.push(_('Skipped: %d.', progressState.skipped));
if (progressState.resourcesCreated) line.push(_('Resources: %d.', progressState.resourcesCreated));
if (progressState.notesTagged) line.push(_('Tagged: %d.', progressState.notesTagged));
lastProgress = line.join(' ');
cliUtils.redraw(lastProgress);
};
importOptions.onError = (error) => {
let s = error.trace ? error.trace : error.toString();
this.stdout(s);
};
app().gui().showConsole();
this.stdout(_('Importing notes...'));
const service = new InteropService();
const result = await service.import(importOptions);
result.warnings.map((w) => this.stdout(w));
cliUtils.redrawDone();
if (lastProgress) this.stdout(_('The notes have been imported: %s', lastProgress));
}
}
module.exports = Command;

View File

@@ -1,10 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Setting } = require('lib/models/setting.js');
const { Note } = require('lib/models/note.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Setting = require('lib/models/Setting.js');
const Note = require('lib/models/Note.js');
const { sprintf } = require('sprintf-js');
const { time } = require('lib/time-utils.js');
const { cliUtils } = require('./cli-utils.js');

View File

@@ -1,7 +1,7 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { Folder } = require('lib/models/folder.js');
const Folder = require('lib/models/Folder.js');
const { reg } = require('lib/registry.js');
class Command extends BaseCommand {
@@ -14,10 +14,6 @@ class Command extends BaseCommand {
return _('Creates a new notebook.');
}
aliases() {
return ['mkdir'];
}
async action(args) {
let folder = await Folder.save({ title: args['new-notebook'] }, { userSideValidation: true });
app().switchCurrentFolder(folder);

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
@@ -20,6 +20,7 @@ class Command extends BaseCommand {
const name = args['name'];
const item = await app().loadItem('folderOrNote', pattern);
this.encryptionCheck(item);
if (!item) throw new Error(_('Cannot find "%s".', pattern));
const newItem = {

View File

@@ -1,10 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseItem } = require('lib/models/base-item.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const { BaseModel } = require('lib/base-model.js');
const BaseItem = require('lib/models/BaseItem.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {
@@ -29,7 +29,7 @@ class Command extends BaseCommand {
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, pattern);
if (!folder) throw new Error(_('Cannot find "%s".', pattern));
const ok = force ? true : await this.prompt(_('Delete notebook "%s"?', folder.title), { booleanAnswerDefault: 'n' });
const ok = force ? true : await this.prompt(_('Delete notebook? All notes within this notebook will also be deleted.'), { booleanAnswerDefault: 'n' });
if (!ok) return;
await Folder.delete(folder.id);

View File

@@ -1,10 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseItem } = require('lib/models/base-item.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const { BaseModel } = require('lib/base-model.js');
const BaseItem = require('lib/models/BaseItem.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {

View File

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

View File

@@ -1,10 +1,11 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const { BaseItem } = require('lib/models/base-item.js');
const BaseModel = require('lib/BaseModel.js');
const { Database } = require('lib/database.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseItem = require('lib/models/BaseItem.js');
class Command extends BaseCommand {
@@ -12,16 +13,16 @@ class Command extends BaseCommand {
return 'set <note> <name> [value]';
}
enabled() {
return false;
}
description() {
return _('Sets the property <name> of the given <note> to the given [value].');
}
const fields = Note.fields();
const s = [];
for (let i = 0; i < fields.length; i++) {
const f = fields[i];
if (f.name === 'id') continue;
s.push(f.name + ' (' + Database.enumName('fieldType', f.type) + ')');
}
hidden() {
return true;
return _('Sets the property <name> of the given <note> to the given [value]. Possible properties are:\n\n%s', s.join(', '));
}
async action(args) {
@@ -34,6 +35,8 @@ class Command extends BaseCommand {
if (!notes.length) throw new Error(_('Cannot find "%s".', title));
for (let i = 0; i < notes.length; i++) {
this.encryptionCheck(notes[i]);
let newNote = {
id: notes[i].id,
type_: notes[i].type_,

View File

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

View File

@@ -2,21 +2,21 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { OneDriveApiNodeUtils } = require('./onedrive-api-node-utils.js');
const { Setting } = require('lib/models/setting.js');
const { BaseItem } = require('lib/models/base-item.js');
const Setting = require('lib/models/Setting.js');
const BaseItem = require('lib/models/BaseItem.js');
const { Synchronizer } = require('lib/synchronizer.js');
const { reg } = require('lib/registry.js');
const { cliUtils } = require('./cli-utils.js');
const md5 = require('md5');
const locker = require('proper-lockfile');
const fs = require('fs-extra');
const osTmpdir = require('os-tmpdir');
const SyncTargetRegistry = require('lib/SyncTargetRegistry');
class Command extends BaseCommand {
constructor() {
super();
this.syncTarget_ = null;
this.syncTargetId_ = null;
this.releaseLockFn_ = null;
this.oneDriveApiUtils_ = null;
}
@@ -32,7 +32,6 @@ class Command extends BaseCommand {
options() {
return [
['--target <target>', _('Sync to provided target (defaults to sync.target config value)')],
['--random-failures', 'For debugging purposes. Do not use.'],
];
}
@@ -62,11 +61,46 @@ class Command extends BaseCommand {
});
}
async doAuth() {
const syncTarget = reg.syncTarget(this.syncTargetId_);
const syncTargetMd = SyncTargetRegistry.idToMetadata(this.syncTargetId_);
if (this.syncTargetId_ === 3 || this.syncTargetId_ === 4) { // OneDrive
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
const auth = await this.oneDriveApiUtils_.oauthDance({
log: (...s) => { return this.stdout(...s); }
});
this.oneDriveApiUtils_ = null;
Setting.setValue('sync.' + this.syncTargetId_ + '.auth', auth ? JSON.stringify(auth) : null);
if (!auth) {
this.stdout(_('Authentication was not completed (did not receive an authentication token).'));
return false;
}
return true;
}
this.stdout(_('Not authentified with %s. Please provide any missing credentials.', syncTarget.label()));
return false;
}
cancelAuth() {
if (this.oneDriveApiUtils_) {
this.oneDriveApiUtils_.cancelOAuthDance();
return;
}
}
doingAuth() {
return !!this.oneDriveApiUtils_;
}
async action(args) {
this.releaseLockFn_ = null;
// Lock is unique per profile/database
const lockFilePath = osTmpdir() + '/synclock_' + md5(Setting.value('profileDir'));
const lockFilePath = require('os').tmpdir() + '/synclock_' + md5(escape(Setting.value('profileDir'))); // https://github.com/pvorb/node-md5/issues/41
if (!await fs.pathExists(lockFilePath)) await fs.writeFile(lockFilePath, 'synclock');
try {
@@ -91,25 +125,20 @@ class Command extends BaseCommand {
};
try {
this.syncTarget_ = Setting.value('sync.target');
if (args.options.target) this.syncTarget_ = args.options.target;
this.syncTargetId_ = Setting.value('sync.target');
if (args.options.target) this.syncTargetId_ = args.options.target;
if (this.syncTarget_ == Setting.SYNC_TARGET_ONEDRIVE && !reg.syncHasAuth(this.syncTarget_)) {
const syncTarget = reg.syncTarget(this.syncTargetId_);
if (!syncTarget.isAuthenticated()) {
app().gui().showConsole();
app().gui().maximizeConsole();
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(reg.oneDriveApi());
const auth = await this.oneDriveApiUtils_.oauthDance({
log: (...s) => { return this.stdout(...s); }
});
this.oneDriveApiUtils_ = null;
Setting.setValue('sync.3.auth', auth ? JSON.stringify(auth) : null);
if (!auth) {
this.stdout(_('Authentication was not completed (did not receive an authentication token).'));
return cleanUp();
}
const authDone = await this.doAuth();
if (!authDone) return cleanUp();
}
let sync = await reg.synchronizer(this.syncTarget_);
const sync = await syncTarget.synchronizer();
let options = {
onProgress: (report) => {
@@ -120,16 +149,15 @@ class Command extends BaseCommand {
cliUtils.redrawDone();
this.stdout(msg);
},
randomFailures: args.options['random-failures'] === true,
};
this.stdout(_('Synchronisation target: %s (%s)', Setting.enumOptionLabel('sync.target', this.syncTarget_), this.syncTarget_));
this.stdout(_('Synchronisation target: %s (%s)', Setting.enumOptionLabel('sync.target', this.syncTargetId_), this.syncTargetId_));
if (!sync) throw new Error(_('Cannot initialize synchroniser.'));
this.stdout(_('Starting synchronisation...'));
const contextKey = 'sync.' + this.syncTarget_ + '.context';
const contextKey = 'sync.' + this.syncTargetId_ + '.context';
let context = Setting.value(contextKey);
context = context ? JSON.parse(context) : {};
@@ -156,26 +184,28 @@ class Command extends BaseCommand {
}
async cancel() {
if (this.oneDriveApiUtils_) {
this.oneDriveApiUtils_.cancelOAuthDance();
if (this.doingAuth()) {
this.cancelAuth();
return;
}
const target = this.syncTarget_ ? this.syncTarget_ : Setting.value('sync.target');
const syncTargetId = this.syncTargetId_ ? this.syncTargetId_ : Setting.value('sync.target');
cliUtils.redrawDone();
this.stdout(_('Cancelling... Please wait.'));
if (reg.syncHasAuth(target)) {
let sync = await reg.synchronizer(target);
const syncTarget = reg.syncTarget(syncTargetId);
if (syncTarget.isAuthenticated()) {
const sync = await syncTarget.synchronizer();
if (sync) await sync.cancel();
} else {
if (this.releaseLockFn_) this.releaseLockFn_();
this.releaseLockFn_ = null;
}
this.syncTarget_ = null;
this.syncTargetId_ = null;
}
cancellable() {

View File

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

View File

@@ -1,9 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');
class Command extends BaseCommand {
@@ -25,6 +25,8 @@ class Command extends BaseCommand {
for (let i = 0; i < notes.length; i++) {
const note = notes[i];
this.encryptionCheck(note);
let toSave = {
id: note.id,
};

View File

@@ -1,9 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');
const CommandDone = require('./command-done.js');
@@ -19,7 +19,7 @@ class Command extends BaseCommand {
}
async action(args) {
await CommandDone.handleAction(args, false);
await CommandDone.handleAction(this, args, false);
}
}

View File

@@ -1,8 +1,8 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { BaseModel } = require('lib/base-model.js');
const { Folder } = require('lib/models/folder.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
class Command extends BaseCommand {
@@ -18,8 +18,8 @@ class Command extends BaseCommand {
return { data: autocompleteFolders };
}
enabled() {
return false;
compatibleUis() {
return ['cli'];
}
async action(args) {

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
const Folder = require('lib/models/folder.js').Folder;
const Tag = require('lib/models/tag.js').Tag;
const BaseModel = require('lib/base-model.js').BaseModel;
const Folder = require('lib/models/Folder.js');
const Tag = require('lib/models/Tag.js');
const BaseModel = require('lib/BaseModel.js');
const ListWidget = require('tkwidgets/ListWidget.js');
const _ = require('lib/locale.js')._;
@@ -24,9 +24,9 @@ class FolderListWidget extends ListWidget {
if (item === '-') {
output.push('-'.repeat(this.innerWidth));
} else if (item.type_ === Folder.modelType()) {
output.push(item.title);
output.push(Folder.displayTitle(item));
} else if (item.type_ === Tag.modelType()) {
output.push('[' + item.title + ']');
output.push('[' + Folder.displayTitle(item) + ']');
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
output.push(_('Search:'));
output.push(item.title);

View File

@@ -1,4 +1,4 @@
const Note = require('lib/models/note.js').Note;
const Note = require('lib/models/Note.js');
const ListWidget = require('tkwidgets/ListWidget.js');
class NoteListWidget extends ListWidget {
@@ -10,7 +10,7 @@ class NoteListWidget extends ListWidget {
this.updateIndexFromSelectedNoteId_ = false;
this.itemRenderer = (note) => {
let label = note.title; // + ' ' + note.id;
let label = Note.displayTitle(note); // + ' ' + note.id;
if (note.is_todo) {
label = '[' + (note.todo_completed ? 'X' : ' ') + '] ' + label;
}

View File

@@ -1,4 +1,4 @@
const Note = require('lib/models/note.js').Note;
const Note = require('lib/models/Note.js');
const TextWidget = require('tkwidgets/TextWidget.js');
class NoteMetadataWidget extends TextWidget {

View File

@@ -1,5 +1,6 @@
const Note = require('lib/models/note.js').Note;
const Note = require('lib/models/Note.js');
const TextWidget = require('tkwidgets/TextWidget.js');
const { _ } = require('lib/locale.js');
class NoteWidget extends TextWidget {
@@ -32,11 +33,24 @@ class NoteWidget extends TextWidget {
this.reloadNote();
}
welcomeText() {
return _('Welcome to Joplin!\n\nType `:help shortcuts` for the list of keyboard shortcuts, or just `:help` for usage information.\n\nFor example, to create a notebook press `mb`; to create a note press `mn`.');
}
reloadNote() {
if (this.noteId_) {
if (!this.noteId_ && !this.notes.length) {
this.text = this.welcomeText();
this.scrollTop = 0;
} else if (this.noteId_) {
this.doAsync('loadNote', async () => {
this.note_ = await Note.load(this.noteId_);
this.text = this.note_ ? this.note_.title + "\n\n" + this.note_.body : '';
if (this.note_ && this.note_.encryption_applied) {
this.text = _('One or more items are currently encrypted and you may need to supply a master password. To do so please type `e2ee decrypt`. If you have already supplied the password, the encrypted items are being decrypted in the background and will be available soon.');
} else {
this.text = this.note_ ? this.note_.title + "\n\n" + this.note_.body : '';
}
if (this.lastLoadedNoteId_ !== this.noteId_) this.scrollTop = 0;
this.lastLoadedNoteId_ = this.noteId_;
});

View File

@@ -2,6 +2,7 @@ const BaseWidget = require('tkwidgets/BaseWidget.js');
const chalk = require('chalk');
const termutils = require('tkwidgets/framework/termutils.js');
const stripAnsi = require('strip-ansi');
const { handleAutocompletion } = require('../autocompletion.js');
class StatusBarWidget extends BaseWidget {
@@ -41,6 +42,7 @@ class StatusBarWidget extends BaseWidget {
};
if ('cursorPosition' in options) this.promptState_.cursorPosition = options.cursorPosition;
if ('secure' in options) this.promptState_.secure = options.secure;
this.promptState_.promise = new Promise((resolve, reject) => {
this.promptState_.resolve = resolve;
@@ -104,13 +106,19 @@ class StatusBarWidget extends BaseWidget {
this.term.showCursor(true);
const isSecurePrompt = !!this.promptState_.secure;
let options = {
cancelable: true,
history: this.history,
default: this.promptState_.initialText,
autoComplete: handleAutocompletion,
autoCompleteHint : true,
autoCompleteMenu : true,
};
if ('cursorPosition' in this.promptState_) options.cursorPosition = this.promptState_.cursorPosition;
if (isSecurePrompt) options.echoChar = true;
this.inputEventEmitter_ = this.term.inputField(options, (error, input) => {
let resolveResult = null;
@@ -125,7 +133,8 @@ class StatusBarWidget extends BaseWidget {
resolveResult = input ? input.trim() : input;
// Add the command to history but only if it's longer than one character.
// Below that it's usually an answer like "y"/"n", etc.
if (input && input.length > 1) this.history_.push(input);
const isConfigPassword = input.indexOf('config ') >= 0 && input.indexOf('password') >= 0;
if (!isSecurePrompt && input && input.length > 1 && !isConfigPassword) this.history_.push(input);
}
}
@@ -159,4 +168,4 @@ class StatusBarWidget extends BaseWidget {
}
module.exports = StatusBarWidget;
module.exports = StatusBarWidget;

View File

@@ -1,6 +1,6 @@
const fs = require('fs-extra');
const { wrap } = require('lib/string-utils.js');
const { Setting } = require('lib/models/setting.js');
const Setting = require('lib/models/Setting.js');
const { fileExtension, basename, dirname } = require('lib/path-utils.js');
const { _, setLocale, languageCode } = require('lib/locale.js');
@@ -53,9 +53,8 @@ function renderCommandHelp(cmd, width = null) {
desc.push(label);
}
if (md.description) {
desc.push(md.description());
}
const description = Setting.keyDescription(md.key, 'cli');
if (description) desc.push(description);
desc.push(_('Type: %s.', md.isEnum ? _('Enum') : Setting.typeToString(md.type)));
if (md.isEnum) desc.push(_('Possible values: %s.', Setting.enumOptionsDoc(md.key, '%s (%s)')));

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