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

Compare commits

..

182 Commits

Author SHA1 Message Date
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
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
7ac6f39658 Alarm support 2017-09-10 17:56:27 +01:00
257 changed files with 8141 additions and 3793 deletions

5
.gitignore vendored
View File

@@ -32,4 +32,7 @@ INFO.md
sync_staging.sh
*.swp
_vieux/
_mydocs
_mydocs
.DS_Store
Assets/DownloadBadges*.psd
node_modules

View File

@@ -28,13 +28,17 @@ 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:
@@ -42,6 +46,4 @@ script:
cd ElectronClient/app
rsync -aP ../../ReactNativeClient/lib/ lib/
npm install
ls -la .
ls -la lib
yarn dist

BIN
Assets/All.psd Normal file

Binary file not shown.

BIN
Assets/DemoDesktop.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
Assets/DemoDesktop.psd Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
Assets/Icon-Android-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
Assets/Icon-Android.psd Normal file

Binary file not shown.

BIN
Assets/Icon-ios-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
Assets/Icon-ios.psd Normal file

Binary file not shown.

BIN
Assets/Laptop-Terminal.psd 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: 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

BIN
Assets/LinuxIcons/48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
Assets/LinuxIcons/72x72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
Assets/LinuxIcons/96x96.png Normal file

Binary file not shown.

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/Tablet.psd Normal file

Binary file not shown.

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1472 930v318q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q63 0 117 25 15 7 18 23 3 17-9 29l-49 49q-10 10-23 10-3 0-9-2-23-6-45-6h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-254q0-13 9-22l64-64q10-10 23-10 6 0 12 3 20 8 20 29zm231-489l-814 814q-24 24-57 24t-57-24l-430-430q-24-24-24-57t24-57l110-110q24-24 57-24t57 24l263 263 647-647q24-24 57-24t57 24l110 110q24 24 24 57t-24 57z"/></svg>

After

Width:  |  Height:  |  Size: 612 B

2
Assets/check-square.svg Normal file
View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M813 1299l614-614q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-467 467-211-211q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l358 358q19 19 45 19t45-19zm851-883v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"/></svg>

After

Width:  |  Height:  |  Size: 447 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

2
Assets/square-o.svg Normal file
View File

@@ -0,0 +1,2 @@
<?xml version='1.0' encoding='utf-8'?>
<svg viewBox='0 0 1792 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1312 256h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-832q0-66-47-113t-113-47zm288 160v832q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119 0 203.5 84.5t84.5 203.5z'/></svg>

After

Width:  |  Height:  |  Size: 370 B

38
BUILD.md Normal file
View File

@@ -0,0 +1,38 @@
# 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 builing each app.
- The translations are built by running CliClient/build-translation.sh. For this reasons, it's generally better to get the CLI app to build first so that everything is setup correctly.
## macOS dependencies
brew install yarn node xgettext
echo 'export PATH="/usr/local/opt/gettext/bin:$PATH"' >> ~/.bash_profile
source ~/.bash_profile
## Linux and Windows dependencies
- Install yarn - https://yarnpkg.com/lang/en/docs/install/
- Install node v8.x (check with `node --version`) - https://nodejs.org/en/
# Building the Electron application
```
cd ElectronClient/app
rsync -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`
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
From `/ReactNativeClient`, run `npm install`, then `react-native run-ios` or `react-native run-android`.
# Building the Terminal application
From `/CliClient`, run `npm install` then run `run.sh`. If you get an error about `xgettext`, comment out the command `node build-translation.js --silent` in build.sh

View File

@@ -6,6 +6,7 @@ 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');
@@ -166,7 +167,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 +181,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 +195,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();
@@ -320,13 +321,16 @@ class AppGui {
action: async () => {
if (this.widget('folderList').hasFocus) {
const item = this.widget('folderList').selectedJoplinItem;
if (!item) return;
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',
type: 'SEARCH_DELETE',
id: item.id,
});
}
@@ -338,6 +342,10 @@ class AppGui {
}
};
shortcuts['BACKSPACE'] = {
alias: 'DELETE',
};
shortcuts[' '] = {
friendlyName: 'SPACE',
description: () => _('Set a to-do as completed / not completed'),
@@ -518,22 +526,22 @@ class AppGui {
return;
}
let note = this.widget('noteList').currentItem;
let folder = this.widget('folderList').currentItem;
let args = cliUtils.splitCommandString(cmd);
try {
let note = this.widget('noteList').currentItem;
let folder = this.widget('folderList').currentItem;
let args = 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);
@@ -764,7 +772,10 @@ class AppGui {
// -------------------------------------------------------------------------
const shortcutKey = this.currentShortcutKeys_.join('');
const cmd = shortcutKey in this.shortcuts_ ? this.shortcuts_[shortcutKey] : null;
let cmd = shortcutKey in this.shortcuts_ ? this.shortcuts_[shortcutKey] : null;
// If this command is an alias to another command, resolve to the actual command
if (cmd && cmd.alias) cmd = this.shortcuts_[cmd.alias];
let processShortcutKeys = !this.app().currentCommand() && cmd;
if (cmd && cmd.canRunAlongOtherCommands) processShortcutKeys = true;

View File

@@ -168,9 +168,9 @@ 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();
}

View File

@@ -6,7 +6,7 @@ const processArgs = process.argv.splice(2, process.argv.length);
const silentLog = processArgs.indexOf('--silent') >= 0;
const { basename, dirname } = require('lib/path-utils.js');
const { basename, dirname, filename, fileExtension } = require('lib/path-utils.js');
const fs = require('fs-extra');
const gettextParser = require('gettext-parser');
@@ -68,6 +68,9 @@ function buildLocale(inputFile, outputFile) {
}
async function removePoHeaderDate(filePath) {
// Note: on macOS this will fail because it needs to be 'sed -i ""'
// Solution would be to install gsed, detect it here, and use it in place of sed in macOS
// https://stackoverflow.com/questions/30003570/how-to-use-gnu-sed-on-mac-os-x#34815955
await execCommand('sed -i -e\'/POT-Creation-Date:/d\' "' + filePath + '"');
await execCommand('sed -i -e\'/PO-Revision-Date:/d\' "' + filePath + '"');
}
@@ -110,6 +113,17 @@ function buildIndex(locales) {
return output.join("\n");
}
function availableLocales(defaultLocale) {
const output = [defaultLocale];
fs.readdirSync(cliLocalesDir).forEach((path) => {
if (fileExtension(path) !== 'po') return;
const locale = filename(path);
if (locale === defaultLocale) return;
output.push(locale);
});
return output;
}
async function main() {
let potFilePath = cliLocalesDir + '/joplin.pot';
let jsonLocalesDir = cliDir + '/build/locales';
@@ -131,7 +145,7 @@ async function main() {
fs.mkdirpSync(jsonLocalesDir, 0o755);
let locales = [defaultLocale, 'fr_FR'];
let locales = availableLocales(defaultLocale);
for (let i = 0; i < locales.length; i++) {
const locale = locales[i];
const poFilePäth = cliLocalesDir + '/' + locale + '.po';

View File

@@ -1,18 +1,20 @@
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 marked = require('marked');
const Mustache = require('mustache');
const headerHtml = `
<!doctype html>
const headerHtml = `<!doctype html>
<html>
<head>
<title>Joplin - a free, open source, te taking and to-do application with synchronisation capabilities</title>
<title>Joplin - an open source note 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">
<link rel="stylesheet" href="https://opensource.keycdn.com/fontawesome/4.7.0/font-awesome.min.css" integrity="sha384-dNpIIXE8U05kAbPhy3G1cz+yZmTzA6CY8Vg/u2L9xRnHjJiAK76m2BIEaSEV+/aU" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g=" crossorigin="anonymous"></script>
<style>
body {
background-color: #F1F1F1;
@@ -22,7 +24,8 @@ const headerHtml = `
margin-bottom: 1em;
}
td, th {
padding: .5em 1em .5em 0;
padding: .8em;
border: 1px solid #ccc;
}
h1, h2 {
border-bottom: 1px solid #eaecef;
@@ -88,6 +91,10 @@ const headerHtml = `
.cli-screenshot .prompt {
color: #48C2F0;
}
.top-screenshot {
margin-top: 2em;
text-align: center;
}
.header {
position: relative;
padding-left: 2em;
@@ -108,7 +115,68 @@ const headerHtml = `
right: 0;
top:0;
}
</style>
.nav-wrapper {
position: relative;
width: inherit;
}
.nav {
background-color: black;
display: table;
width: inherit;
}
.nav.sticky {
position:fixed;
top: 0;
width: inherit;
box-shadow: 0 0 10px #000000;
}
.nav a {
color: white;
display: inline-block;
padding: .6em .9em .6em .9em;
}
.nav ul {
padding-left: 2em;
margin-bottom: 0;
display: table-cell;
min-width: 165px;
}
.nav ul li {
display: inline-block;
padding: 0;
}
.nav li.selected {
background-color: #222;
font-weight: bold;
}
.nav-right {
display: table-cell;
width: 100%;
text-align: right;
vertical-align: middle;
line-height: 0;
}
.nav-right .share-btn {
display: none;
}
.share-btn-github {
display: inline-block;
}
.nav-right .small-share-btn {
display: none;
}
.nav-right .share-btn-github {
display: inline-block;
}
@media all and (min-width: 400px) {
.nav-right .share-btn {
display: inline-block;
}
.nav-right .small-share-btn {
display: none;
}
}
</style>
</head>
<body>
@@ -116,9 +184,24 @@ const headerHtml = `
<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>
<a class="forkme" href="https://github.com/laurent22/joplin"><img src="{{{imageBaseUrl}}}/ForkMe.png"/></a>
<h1 id="joplin"><img class="title-icon" src="{{{imageBaseUrl}}}/Icon512.png">oplin</h1>
<p class="sub-title">An open source note taking and to-do application with synchronisation capabilities.</p>
</div>
<div class="nav-wrapper">
<div class="nav">
<ul>
<li class="{{selectedHome}}"><a href="{{baseUrl}}/" title="Home"><i class="fa fa-home"></i></a></li>
<li class="{{selectedTerminal}}"><a href="{{baseUrl}}/terminal" title="Terminal"><i class="fa fa-terminal"></i></a></li>
<li class="{{selectedDesktop}}"><a href="{{baseUrl}}/desktop" title="Desktop"><i class="fa fa-desktop"></i></a></li>
</ul>
<div class="nav-right">
<iframe class="share-btn" src="https://www.facebook.com/plugins/share_button.php?href=http%3A%2F%2Fjoplin.cozic.net&layout=button&size=small&mobile_iframe=true&width=60&height=20&appId" width="60" height="20" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true"></iframe>
<iframe class="share-btn" src="https://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fjoplin.cozic.net" width="62" height="20" title="Tweet" style="border: 0; overflow: hidden;"></iframe>
<iframe class="share-btn share-btn-github" src="https://ghbtns.com/github-btn.html?user=laurent22&repo=joplin&type=star&count=true" frameborder="0" scrolling="0" width="80px" height="20px"></iframe>
</div>
</div>
</div>
<div class="content">
@@ -157,26 +240,40 @@ const footerHtml = `
// Grocery shopping list 📝
// Work itinerary
// Tuesday random note
// Vacation plans ☀
// Vacation plans ☀
// </pre>
// </td>
// </tr>
// </table>
// `;
const gaHtml = `
const scriptHtml = `
<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');
function stickyHeader() {
if ($(window).scrollTop() > 179) {
$('.nav').addClass('sticky');
} else {
$('.nav').removeClass('sticky');
}
}
ga('create', 'UA-103586105-1', 'auto');
ga('send', 'pageview');
$(window).scroll(function() {
stickyHeader();
});
(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>
`;
// <a href="#" class="small-share-btn" style="background-color: #365899;"><img src="images/ShareFacebook.svg" style=" width: 1.2em; height: 1.2em"/></a>
// <a href="#" class="small-share-btn" style="background-color: #1b95e0;"><img src="images/ShareTwitter.svg" style=" width: 1.2em; height: 1.2em"/></a>
// <a href="#" class="small-share-btn" style="background-color: #eee;"><img src="images/ShareGithub.svg" style=" width: 1.2em; height: 1.2em"/></a>
const rootDir = dirname(dirname(__dirname));
function markdownToHtml(md) {
@@ -193,14 +290,29 @@ function markdownToHtml(md) {
//output = output.replace(/<!-- \[SCREENSHOTS\] -->/, screenshotHtml);
return headerHtml + output + gaHtml + footerHtml;
return headerHtml + output + scriptHtml + footerHtml;
}
function renderFileToHtml(sourcePath, targetPath, params) {
const md = fs.readFileSync(sourcePath, 'utf8');
params.baseUrl = 'http://joplin.cozic.net';
params.imageBaseUrl = params.baseUrl + '/images';
const html = Mustache.render(markdownToHtml(md), params);
fs.writeFileSync(targetPath, html);
}
async function main() {
const md = fs.readFileSync(rootDir + '/README.md', 'utf8');
const html = markdownToHtml(md);
renderFileToHtml(rootDir + '/README.md', rootDir + '/docs/index.html', {
selectedHome: 'selected',
});
fs.writeFileSync(rootDir + '/index.html', html);
renderFileToHtml(rootDir + '/README_terminal.md', rootDir + '/docs/terminal/index.html', {
selectedTerminal: 'selected',
});
renderFileToHtml(rootDir + '/README_desktop.md', rootDir + '/docs/desktop/index.html', {
selectedDesktop: 'selected',
});
}
main().catch((error) => {

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 '';

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

@@ -2,7 +2,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 { importEnex } = require('import-enex');
const { importEnex } = require('lib/import-enex');
const { filename, basename } = require('lib/path-utils.js');
const { cliUtils } = require('./cli-utils.js');

View File

@@ -16,7 +16,7 @@ class Command extends BaseCommand {
constructor() {
super();
this.syncTarget_ = null;
this.syncTargetId_ = null;
this.releaseLockFn_ = null;
this.oneDriveApiUtils_ = null;
}
@@ -62,6 +62,27 @@ class Command extends BaseCommand {
});
}
async doAuth(syncTargetId) {
const syncTarget = reg.syncTarget(this.syncTargetId_);
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
const auth = await this.oneDriveApiUtils_.oauthDance({
log: (...s) => { return this.stdout(...s); }
});
this.oneDriveApiUtils_ = null;
return auth;
}
cancelAuth() {
if (this.oneDriveApiUtils_) {
this.oneDriveApiUtils_.cancelOAuthDance();
return;
}
}
doingAuth() {
return !!this.oneDriveApiUtils_;
}
async action(args) {
this.releaseLockFn_ = null;
@@ -91,25 +112,24 @@ 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);
const auth = await this.doAuth(this.syncTargetId_);
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 cleanUp();
}
}
let sync = await reg.synchronizer(this.syncTarget_);
const sync = await syncTarget.synchronizer();
let options = {
onProgress: (report) => {
@@ -123,13 +143,13 @@ class Command extends BaseCommand {
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 +176,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,3 +1,4 @@
#!/bin/bash
set -e
./build.sh && NODE_PATH=build node build/build-website.js
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
"$ROOT_DIR/build.sh" && NODE_PATH="$ROOT_DIR/build" node "$ROOT_DIR/build/build-website.js"

View File

@@ -8,53 +8,5 @@ rsync -a "$ROOT_DIR/../ReactNativeClient/lib/" "$BUILD_DIR/lib/"
cp "$ROOT_DIR/package.json" "$BUILD_DIR"
chmod 755 "$BUILD_DIR/main.js"
cd "$BUILD_DIR"
node build-translation.js --silent
# ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# # require('cache-require-paths');
# mkdir -p "$ROOT_DIR/build"
# rm -f "$ROOT_DIR/app/lib"
# ln -s "$ROOT_DIR/../ReactNativeClient/lib" "$ROOT_DIR/app"
# npm run build || exit 1
# # Files under app/gui are in ES6 already but I cannot get Babel
# # to ignore them, so copy them back to the build directory.
# rsync -a "$ROOT_DIR/app/gui/" "$ROOT_DIR/build/gui/"
# cp "$ROOT_DIR/package.json" "$ROOT_DIR/build"
# chmod 755 "$ROOT_DIR/build/main.js"
# # if [[ ! -f "$ROOT_DIR/package.json.md5" ]]; then
# # "$ROOT_DIR/update-package-md5.sh"
# # fi
# # Add modules on top of main.js:
# # - cache-require-paths to cache require() calls
# # - app-module-path so that lib/something paths can be resolved.
# #PACKAGE_MD5=$(cat "$ROOT_DIR/package.json.md5")
# MAIN_PATH="$ROOT_DIR/build/main.js"
# #LINE_TO_ADD="var osTmpdir = require('os-tmpdir'); process.env.CACHE_REQUIRE_PATHS_FILE = osTmpdir() + '/joplin-module-path-cache-$PACKAGE_MD5'; require('cache-require-paths'); require('app-module-path').addPath(__dirname);"
# LINE_TO_ADD="require('app-module-path').addPath(__dirname);"
# RESULT="$(grep "$LINE_TO_ADD" "$MAIN_PATH")"
# if [[ -z "$RESULT" ]]; then
# echo "Adding extra modules..."
# sed -i "2i $LINE_TO_ADD" "$MAIN_PATH"
# else
# echo "Extra modules already added."
# fi
# NODE_PATH="$ROOT_DIR/build" node "$ROOT_DIR/build/build-translation.js" --silent
# cd "$BUILD_DIR"
# node build-translation.js --silent

View File

@@ -490,6 +490,21 @@ msgstr ""
msgid "Quit"
msgstr ""
msgid "Edit"
msgstr ""
msgid "Copy"
msgstr ""
msgid "Cut"
msgstr ""
msgid "Paste"
msgstr ""
msgid "Search in all the notes"
msgstr ""
msgid "Tools"
msgstr ""
@@ -544,18 +559,27 @@ msgstr ""
msgid "Separate each tag by a comma."
msgstr ""
msgid "Rename notebook:"
msgstr ""
msgid "Set alarm:"
msgstr ""
msgid "Layout"
msgstr ""
msgid "Add or remove tags"
msgstr ""
msgid "Switch between note and to-do"
msgid "Switch between note and to-do type"
msgstr ""
msgid "Delete"
msgstr ""
msgid "Delete notes?"
msgstr ""
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
@@ -566,31 +590,43 @@ msgstr ""
msgid "Attach file"
msgstr ""
msgid "Set alarm"
msgstr ""
msgid "Refresh"
msgstr ""
msgid "Clear"
msgstr ""
msgid "OneDrive Login"
msgstr ""
msgid "Import"
msgstr ""
msgid "Configuration"
msgstr ""
msgid "Delete notebook?"
msgstr ""
msgid "Remove this tag from all the notes?"
msgstr ""
msgid "Remove this search from the sidebar?"
msgstr ""
msgid "Rename"
msgstr ""
msgid "Synchronise"
msgstr ""
msgid "Notebooks"
msgstr ""
msgid "Tags"
msgstr ""
msgid "Synchronise"
msgid "Searches"
msgstr ""
#, javascript-format
@@ -601,6 +637,15 @@ msgstr ""
msgid "Unknown flag: %s"
msgstr ""
msgid "File system"
msgstr ""
msgid "OneDrive"
msgstr ""
msgid "OneDrive Dev (For testing only)"
msgstr ""
#, javascript-format
msgid "Unknown log level: %s"
msgstr ""
@@ -615,8 +660,12 @@ msgid ""
msgstr ""
msgid ""
"Please set the \"sync.2.path\" config value to the desired synchronisation "
"destination."
"Could not synchronize with OneDrive.\n"
"\n"
"This error often happens when using OneDrive for Business, which "
"unfortunately cannot be supported.\n"
"\n"
"Please consider using a regular OneDrive account."
msgstr ""
#, javascript-format
@@ -687,10 +736,6 @@ msgstr ""
msgid "Cannot move note to \"%s\" notebook"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
msgid "File system synchronisation target directory"
msgstr ""
@@ -699,20 +744,6 @@ msgid ""
"See `sync.target`."
msgstr ""
msgid "Synchronisation target"
msgstr ""
msgid ""
"The target to synchonise to. If synchronising with the file system, set "
"`sync.2.path` to specify the target directory."
msgstr ""
msgid "File system"
msgstr ""
msgid "OneDrive"
msgstr ""
msgid "Text editor"
msgstr ""
@@ -724,6 +755,12 @@ msgstr ""
msgid "Language"
msgstr ""
msgid "Date format"
msgstr ""
msgid "Time format"
msgstr ""
msgid "Theme"
msgstr ""
@@ -757,9 +794,24 @@ msgstr ""
msgid "%d hours"
msgstr ""
msgid "Automatically update the application"
msgstr ""
msgid "Show advanced options"
msgstr ""
msgid "Synchronisation target"
msgstr ""
msgid ""
"The target to synchonise to. If synchronising with the file system, set "
"`sync.2.path` to specify the target directory."
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr ""
@@ -786,15 +838,44 @@ msgstr ""
msgid "%s: %d notes"
msgstr ""
msgid "Coming alarms"
msgstr ""
#, javascript-format
msgid "On %s: %s"
msgstr ""
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr ""
msgid "Delete these notes?"
msgstr ""
msgid "Log"
msgstr ""
msgid "Status"
msgstr ""
msgid "Export Debug Report"
msgstr ""
msgid "Configuration"
msgstr ""
msgid "Move to notebook..."
msgstr ""
#, javascript-format
msgid "Move %d notes to notebook \"%s\"?"
msgstr ""
msgid "Select date"
msgstr ""
msgid "Confirm"
msgstr ""
msgid "Cancel synchronisation"
msgstr ""
@@ -814,10 +895,17 @@ msgstr ""
msgid "Discard changes"
msgstr ""
msgid "Delete note"
#, javascript-format
msgid "Unsupported image type: %s"
msgstr ""
msgid "Convert to regular note"
msgid "Attach photo"
msgstr ""
msgid "Attach any file"
msgstr ""
msgid "Convert to note"
msgstr ""
msgid "Convert to todo"
@@ -829,10 +917,7 @@ msgstr ""
msgid "Show metadata"
msgstr ""
msgid "View location on map"
msgstr ""
msgid "Edit"
msgid "View on map"
msgstr ""
msgid "Delete notebook"

1002
CliClient/locales/es_CR.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ msgid "Exit command line mode"
msgstr "Sortir du mode de ligne de commande"
msgid "Edit the selected note"
msgstr "Editer la note sélectionnée"
msgstr "Éditer la note sélectionnée"
msgid "Cancel the current command."
msgstr "Annuler la commande en cours."
@@ -114,7 +114,7 @@ msgid "%s: %s"
msgstr "%s : %s"
msgid "Your choice: "
msgstr "Votre choix :"
msgstr "Votre choix : "
#, javascript-format
msgid "Invalid answer: %s"
@@ -157,7 +157,7 @@ msgid ""
"Duplicates the notes matching <note> to [notebook]. If no notebook is "
"specified the note is duplicated in the current notebook."
msgstr ""
"Copie les notes correspondant à <nom> vers [carnet]. Si aucun carnet n'est "
"Copier les notes correspondant à <nom> vers [carnet]. Si aucun carnet n'est "
"spécifié, la note est dupliquée sur place."
msgid "Marks a to-do as done."
@@ -168,7 +168,7 @@ msgid "Note is not a to-do: \"%s\""
msgstr "La note n'est pas une tâche : \"%s\""
msgid "Edit note."
msgstr "Editer la note."
msgstr "Éditer la note."
msgid ""
"No text editor is defined. Please set it using `config editor <editor-path>`"
@@ -185,7 +185,7 @@ msgstr "Cette note n'existe pas : \"%s\". La créer ?"
msgid "Starting to edit note. Close the editor to get back to the prompt."
msgstr ""
"Edition de la note en cours. Fermez l'éditeur de texte pour retourner à "
"Édition de la note en cours. Fermez l'éditeur de texte pour retourner à "
"l'invite de commande."
msgid "Note has been saved."
@@ -228,8 +228,8 @@ msgid ""
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
"note or notebook. `$c` can be used to refer to the currently selected item."
msgstr ""
"Dans n'importe quelle commande, une note ou carnet peut être référé par "
"titre ou identifiant, ou en utilisant les raccourcis `$n` et `$b` pour, "
"Dans une commande, une note ou carnet peut être référé par titre ou "
"identifiant, ou en utilisant les raccourcis `$n` et `$b` pour, "
"respectivement, la note sélectionnée et le carnet sélectionné. `$c` peut "
"être utilisé pour faire référence à l'objet sélectionné en cours."
@@ -286,7 +286,7 @@ msgstr "Créés : %d."
#, javascript-format
msgid "Updated: %d."
msgstr "Mise à jour : %d."
msgstr "Mis à jour : %d."
#, javascript-format
msgid "Skipped: %d."
@@ -298,7 +298,7 @@ msgstr "Ressources : %d."
#, javascript-format
msgid "Tagged: %d."
msgstr "Etiquettes : %d."
msgstr "Étiquettes : %d."
msgid "Importing notes..."
msgstr "Importation des notes..."
@@ -510,18 +510,17 @@ msgid ""
"any files outside this directory nor to any other personal data. No data "
"will be shared with any third party."
msgstr ""
"Veuillez ouvrir le lien ci-dessous dans votre browser pour authentifier le "
"logiciel. Joplin va créer un répertoire \"Apps/Joplin\" et lire/écrira des "
"fichiers uniquement dans ce répertoire. Le logiciel n'aura pas d'accès à "
"Veuillez ouvrir le lien ci-dessous dans votre navigateur pour authentifier "
"le logiciel. Joplin va créer un répertoire \"Apps/Joplin\" et lire/écrira "
"des fichiers uniquement dans ce répertoire. Le logiciel n'aura pas d'accès à "
"aucun fichier en dehors de ce répertoire, ni à d'autres données "
"personnelles. Aucune donnée ne sera partagé avec aucun tier."
#, fuzzy
msgid "Search:"
msgstr "Chercher"
msgstr "Recherche :"
msgid "File"
msgstr ""
msgstr "Fichier"
msgid "New note"
msgstr "Nouvelle note"
@@ -533,7 +532,7 @@ msgid "New notebook"
msgstr "Nouveau carnet"
msgid "Import Evernote notes"
msgstr "Importer notes d'Evernotes"
msgstr "Importer notes d'Evernote"
msgid "Evernote Export Files"
msgstr "Fichiers d'export Evernote"
@@ -541,6 +540,21 @@ msgstr "Fichiers d'export Evernote"
msgid "Quit"
msgstr "Quitter"
msgid "Edit"
msgstr "Édition"
msgid "Copy"
msgstr "Copier"
msgid "Cut"
msgstr "Couper"
msgid "Paste"
msgstr "Coller"
msgid "Search in all the notes"
msgstr "Chercher dans toutes les notes"
msgid "Tools"
msgstr "Outils"
@@ -550,16 +564,15 @@ msgstr "Options"
msgid "Help"
msgstr "Aide"
#, fuzzy
msgid "Website and documentation"
msgstr "Documentation"
msgstr "Documentation en ligne"
msgid "About Joplin"
msgstr "A props de Joplin"
msgstr "A propos de Joplin"
#, fuzzy, javascript-format
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s)"
msgstr "%s %s (%s, %s)"
msgid "OK"
msgstr "OK"
@@ -570,95 +583,107 @@ msgstr "Annulation"
msgid "Back"
msgstr "Retour"
#, fuzzy, javascript-format
#, javascript-format
msgid ""
"New notebook \"%s\" will be created and file \"%s\" will be imported into it"
msgstr ""
"Un nouveau carnet \"%s\" va être créé et le fichier \"%s\" va être importé "
"dedans. Continuer ?"
"dedans"
#, fuzzy
msgid "Please create a notebook first."
msgstr "Veuillez d'abord sélectionner un carnet."
#, fuzzy
msgid "Note title:"
msgstr "cat <titre>"
msgstr "Titre de la note :"
#, fuzzy
msgid "Please create a notebook first"
msgstr "Veuillez d'abord sélectionner un carnet."
msgstr "Veuillez d'abord créer un carnet d'abord"
#, fuzzy
msgid "To-do title:"
msgstr "cat <titre>"
msgstr "Titre de la tâche :"
#, fuzzy
msgid "Notebook title:"
msgstr "cat <titre>"
msgstr "Titre du carnet :"
msgid "Add or remove tags:"
msgstr "Modifier les étiquettes"
msgstr "Modifier les étiquettes :"
msgid "Separate each tag by a comma."
msgstr ""
msgstr "Séparez chaque étiquette par une virgule."
msgid "Rename notebook:"
msgstr "Renommer le carnet :"
#, fuzzy
msgid "Set alarm:"
msgstr "Définir ou modifier alarme"
msgid "Layout"
msgstr ""
msgstr "Disposition"
msgid "Add or remove tags"
msgstr ""
msgstr "Gérer les étiquettes"
msgid "Switch between note and to-do"
msgstr ""
msgid "Switch between note and to-do type"
msgstr "Alterner entre note et tâche"
#, fuzzy
msgid "Delete"
msgstr "Supprimer la note"
msgstr "Supprimer"
msgid "Delete notes?"
msgstr "Supprimer les notes ?"
#, fuzzy
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
"Vous n'avez pour l'instant pas de carnets. Créez-en un en pressant le bouton "
"(+)."
"Pas de notes ici. Créez-en une en pressant le bouton \"Nouvelle note\"."
#, javascript-format
msgid "Unsupported link or message: %s"
msgstr ""
msgstr "Lien ou message non géré : %s"
msgid "Attach file"
msgstr "Attacher un fichier"
#, fuzzy
msgid "Set alarm"
msgstr "Définir ou modifier alarme"
msgid "Refresh"
msgstr "Rafraîchir"
#, fuzzy
msgid "Clear"
msgstr "Supprimer"
msgid "OneDrive Login"
msgstr "OneDrive"
msgstr "Connexion OneDrive"
#, fuzzy
msgid "Import"
msgstr "Importé - %s"
msgid "Configuration"
msgstr "Configuration"
msgstr "Importer"
msgid "Delete notebook?"
msgstr "Supprimer le carnet ?"
msgid "Remove this tag from all the notes?"
msgstr ""
msgstr "Enlever cette étiquette de toutes les notes ?"
#, fuzzy
msgid "Notebooks"
msgstr "Nouveau carnet"
msgid "Remove this search from the sidebar?"
msgstr "Enlever cette recherche de la barre latérale ?"
msgid "Tags"
msgstr ""
msgid "Rename"
msgstr "Renommer"
msgid "Synchronise"
msgstr "Synchroniser"
msgid "Notebooks"
msgstr "Carnets"
msgid "Tags"
msgstr "Étiquettes"
msgid "Searches"
msgstr "Recherches"
#, javascript-format
msgid "Usage: %s"
msgstr "Utilisation : %s"
@@ -667,6 +692,15 @@ msgstr "Utilisation : %s"
msgid "Unknown flag: %s"
msgstr "Paramètre inconnu : %s"
msgid "File system"
msgstr "Système de fichier"
msgid "OneDrive"
msgstr "OneDrive"
msgid "OneDrive Dev (For testing only)"
msgstr "OneDrive Dév (Pour tester uniquement)"
#, javascript-format
msgid "Unknown log level: %s"
msgstr "Paramètre inconnu : %s"
@@ -679,15 +713,17 @@ msgid ""
"Cannot refresh token: authentication data is missing. Starting the "
"synchronisation again may fix the problem."
msgstr ""
"Impossible de rafraîchir la connection à OneDrive. Démarrez la "
"Impossible de rafraîchir la connexion à OneDrive. Démarrez la "
"synchronisation à nouveau pour corriger le problème."
msgid ""
"Please set the \"sync.2.path\" config value to the desired synchronisation "
"destination."
"Could not synchronize with OneDrive.\n"
"\n"
"This error often happens when using OneDrive for Business, which "
"unfortunately cannot be supported.\n"
"\n"
"Please consider using a regular OneDrive account."
msgstr ""
"Veuillez attribuer une valeur au paramètre de configuration \"sync.2.path\" "
"pour indiquer le dossier où devra se faire la synchronisation."
#, javascript-format
msgid "Cannot access %s"
@@ -719,7 +755,7 @@ msgstr "Objets distants supprimés : %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Etat : \"%s\"."
msgstr "État : \"%s\"."
msgid "Cancelling..."
msgstr "Annulation..."
@@ -730,7 +766,7 @@ msgstr "Terminé : %s"
#, javascript-format
msgid "Synchronisation is already in progress. State: %s"
msgstr "La synchronisation est déjà en cours. Etat : %s"
msgstr "La synchronisation est déjà en cours. État : %s"
msgid "Conflicts"
msgstr "Conflits"
@@ -757,10 +793,6 @@ msgstr "Impossible de copier la note vers le carnet \"%s\""
msgid "Cannot move note to \"%s\" notebook"
msgstr "Impossible de déplacer la note vers le carnet \"%s\""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s."
msgid "File system synchronisation target directory"
msgstr "Cible de la synchronisation sur le disque dur"
@@ -771,24 +803,8 @@ msgstr ""
"Le chemin du répertoire avec lequel synchroniser lorsque la synchronisation "
"par système de fichier est activée. Voir `sync.target`."
msgid "Synchronisation target"
msgstr "Cible de la synchronisation"
msgid ""
"The target to synchonise to. If synchronising with the file system, set "
"`sync.2.path` to specify the target directory."
msgstr ""
"La cible avec laquelle synchroniser. Pour synchroniser avec le système de "
"fichier, veuillez spécifier le répertoire avec `sync.2.path`."
msgid "File system"
msgstr "Système de fichier"
msgid "OneDrive"
msgstr "OneDrive"
msgid "Text editor"
msgstr "Editeur de texte"
msgstr "Éditeur de texte"
msgid ""
"The editor that will be used to open a note. If none is provided it will try "
@@ -800,6 +816,12 @@ msgstr ""
msgid "Language"
msgstr "Langue"
msgid "Date format"
msgstr "Format de la date"
msgid "Time format"
msgstr "Format de l'heure"
msgid "Theme"
msgstr "Apparence"
@@ -816,7 +838,7 @@ msgid "Save geo-location with notes"
msgstr "Enregistrer l'emplacement avec les notes"
msgid "Synchronisation interval"
msgstr "Interval de synchronisation"
msgstr "Intervalle de synchronisation"
msgid "Disabled"
msgstr "Désactivé"
@@ -833,9 +855,26 @@ msgstr "%d heure"
msgid "%d hours"
msgstr "%d heures"
msgid "Automatically update the application"
msgstr "Mettre à jour le logiciel automatiquement"
msgid "Show advanced options"
msgstr "Montrer les options avancées"
msgid "Synchronisation target"
msgstr "Cible de la synchronisation"
msgid ""
"The target to synchonise to. If synchronising with the file system, set "
"`sync.2.path` to specify the target directory."
msgstr ""
"La cible avec laquelle synchroniser. Pour synchroniser avec le système de "
"fichier, veuillez spécifier le répertoire avec `sync.2.path`."
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s."
msgid "Sync status (synced items / total items)"
msgstr "Status de la synchronisation (objets synchro. / total)"
@@ -862,16 +901,45 @@ msgstr "Carnets"
msgid "%s: %d notes"
msgstr "%s : %d notes"
msgid "Coming alarms"
msgstr "Alarmes à venir"
#, javascript-format
msgid "On %s: %s"
msgstr "Le %s : %s"
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr ""
"Ce carnet ne contient aucune note. Créez-en une en appuyant sur le bouton "
"(+)."
msgid "Delete these notes?"
msgstr "Supprimer ces notes ?"
msgid "Log"
msgstr "Journal"
msgid "Status"
msgstr "Etat"
msgstr "État"
msgid "Export Debug Report"
msgstr "Exporter rapport de débogage"
msgid "Configuration"
msgstr "Configuration"
msgid "Move to notebook..."
msgstr "Déplacer la note vers carnet..."
#, javascript-format
msgid "Move %d notes to notebook \"%s\"?"
msgstr "Déplacer %d notes vers carnet \"%s\" ?"
msgid "Select date"
msgstr "Sélectionner date"
msgid "Confirm"
msgstr "Confirmer"
msgid "Cancel synchronisation"
msgstr "Annuler synchronisation"
@@ -881,7 +949,7 @@ msgid "The notebook could not be saved: %s"
msgstr "Ce carnet n'a pas pu être sauvegardé : %s"
msgid "Edit notebook"
msgstr "Editer le carnet"
msgstr "Éditer le carnet"
msgid "This note has been modified:"
msgstr "Cette note a été modifiée :"
@@ -892,10 +960,17 @@ msgstr "Enregistrer les changements"
msgid "Discard changes"
msgstr "Ignorer les changements"
msgid "Delete note"
msgstr "Supprimer la note"
#, javascript-format
msgid "Unsupported image type: %s"
msgstr "Type d'image non géré : %s"
msgid "Convert to regular note"
msgid "Attach photo"
msgstr "Attacher une photo"
msgid "Attach any file"
msgstr "Attacher un fichier"
msgid "Convert to note"
msgstr "Convertir en note"
msgid "Convert to todo"
@@ -907,17 +982,14 @@ msgstr "Cacher les métadonnées"
msgid "Show metadata"
msgstr "Afficher les métadonnées"
msgid "View location on map"
msgstr "Voir l'emplacement sur la carte"
msgid "Edit"
msgstr "Editer"
msgid "View on map"
msgstr "Voir emplacement sur carte"
msgid "Delete notebook"
msgstr "Supprimer le carnet"
msgid "Login with OneDrive"
msgstr "Se connecter avec OneDrive"
msgstr "Se connecter à OneDrive"
msgid ""
"Click on the (+) button to create a new note or notebook. Click on the side "
@@ -934,6 +1006,37 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenue"
#~ msgid "Set or clear alarm:"
#~ msgstr "Définir ou modifier alarme :"
#~ msgid "Set or clear alarm"
#~ msgstr "Définir ou modifier alarme"
#~ msgid "Attach image"
#~ msgstr "Joindre une image ou photo"
#~ msgid "Attach any other file"
#~ msgstr "Joindre un fichier"
#~ msgid "Delete note"
#~ msgstr "Supprimer la note"
#~ msgid "Convert to regular note"
#~ msgstr "Convertir en note"
#~ msgid ""
#~ "Please set the \"sync.2.path\" config value to the desired "
#~ "synchronisation destination."
#~ msgstr ""
#~ "Veuillez attribuer une valeur au paramètre de configuration \"sync.2.path"
#~ "\" pour indiquer le dossier où devra se faire la synchronisation."
#~ msgid "Seach:"
#~ msgstr "Chercher :"
#~ msgid "Seach"
#~ msgstr "Chercher"
#~ msgid ""
#~ "Command line argument \"%s\" contains both quotes and double-quotes - "
#~ "aborting."
@@ -982,10 +1085,6 @@ msgstr "Bienvenue"
#~ msgid "Done editing."
#~ msgstr "Edition terminée."
#, fuzzy
#~ msgid "Confirm"
#~ msgstr "Conflits"
#~ msgid "Last error: %s (stacktrace in log)."
#~ msgstr "Dernière erreur : %s (Plus d'information dans le journal d'erreurs)"

View File

@@ -490,6 +490,21 @@ msgstr ""
msgid "Quit"
msgstr ""
msgid "Edit"
msgstr ""
msgid "Copy"
msgstr ""
msgid "Cut"
msgstr ""
msgid "Paste"
msgstr ""
msgid "Search in all the notes"
msgstr ""
msgid "Tools"
msgstr ""
@@ -544,18 +559,27 @@ msgstr ""
msgid "Separate each tag by a comma."
msgstr ""
msgid "Rename notebook:"
msgstr ""
msgid "Set alarm:"
msgstr ""
msgid "Layout"
msgstr ""
msgid "Add or remove tags"
msgstr ""
msgid "Switch between note and to-do"
msgid "Switch between note and to-do type"
msgstr ""
msgid "Delete"
msgstr ""
msgid "Delete notes?"
msgstr ""
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
@@ -566,31 +590,43 @@ msgstr ""
msgid "Attach file"
msgstr ""
msgid "Set alarm"
msgstr ""
msgid "Refresh"
msgstr ""
msgid "Clear"
msgstr ""
msgid "OneDrive Login"
msgstr ""
msgid "Import"
msgstr ""
msgid "Configuration"
msgstr ""
msgid "Delete notebook?"
msgstr ""
msgid "Remove this tag from all the notes?"
msgstr ""
msgid "Remove this search from the sidebar?"
msgstr ""
msgid "Rename"
msgstr ""
msgid "Synchronise"
msgstr ""
msgid "Notebooks"
msgstr ""
msgid "Tags"
msgstr ""
msgid "Synchronise"
msgid "Searches"
msgstr ""
#, javascript-format
@@ -601,6 +637,15 @@ msgstr ""
msgid "Unknown flag: %s"
msgstr ""
msgid "File system"
msgstr ""
msgid "OneDrive"
msgstr ""
msgid "OneDrive Dev (For testing only)"
msgstr ""
#, javascript-format
msgid "Unknown log level: %s"
msgstr ""
@@ -615,8 +660,12 @@ msgid ""
msgstr ""
msgid ""
"Please set the \"sync.2.path\" config value to the desired synchronisation "
"destination."
"Could not synchronize with OneDrive.\n"
"\n"
"This error often happens when using OneDrive for Business, which "
"unfortunately cannot be supported.\n"
"\n"
"Please consider using a regular OneDrive account."
msgstr ""
#, javascript-format
@@ -687,10 +736,6 @@ msgstr ""
msgid "Cannot move note to \"%s\" notebook"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
msgid "File system synchronisation target directory"
msgstr ""
@@ -699,20 +744,6 @@ msgid ""
"See `sync.target`."
msgstr ""
msgid "Synchronisation target"
msgstr ""
msgid ""
"The target to synchonise to. If synchronising with the file system, set "
"`sync.2.path` to specify the target directory."
msgstr ""
msgid "File system"
msgstr ""
msgid "OneDrive"
msgstr ""
msgid "Text editor"
msgstr ""
@@ -724,6 +755,12 @@ msgstr ""
msgid "Language"
msgstr ""
msgid "Date format"
msgstr ""
msgid "Time format"
msgstr ""
msgid "Theme"
msgstr ""
@@ -757,9 +794,24 @@ msgstr ""
msgid "%d hours"
msgstr ""
msgid "Automatically update the application"
msgstr ""
msgid "Show advanced options"
msgstr ""
msgid "Synchronisation target"
msgstr ""
msgid ""
"The target to synchonise to. If synchronising with the file system, set "
"`sync.2.path` to specify the target directory."
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr ""
@@ -786,15 +838,44 @@ msgstr ""
msgid "%s: %d notes"
msgstr ""
msgid "Coming alarms"
msgstr ""
#, javascript-format
msgid "On %s: %s"
msgstr ""
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr ""
msgid "Delete these notes?"
msgstr ""
msgid "Log"
msgstr ""
msgid "Status"
msgstr ""
msgid "Export Debug Report"
msgstr ""
msgid "Configuration"
msgstr ""
msgid "Move to notebook..."
msgstr ""
#, javascript-format
msgid "Move %d notes to notebook \"%s\"?"
msgstr ""
msgid "Select date"
msgstr ""
msgid "Confirm"
msgstr ""
msgid "Cancel synchronisation"
msgstr ""
@@ -814,10 +895,17 @@ msgstr ""
msgid "Discard changes"
msgstr ""
msgid "Delete note"
#, javascript-format
msgid "Unsupported image type: %s"
msgstr ""
msgid "Convert to regular note"
msgid "Attach photo"
msgstr ""
msgid "Attach any file"
msgstr ""
msgid "Convert to note"
msgstr ""
msgid "Convert to todo"
@@ -829,10 +917,7 @@ msgstr ""
msgid "Show metadata"
msgstr ""
msgid "View location on map"
msgstr ""
msgid "Edit"
msgid "View on map"
msgstr ""
msgid "Delete notebook"

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "0.10.68",
"version": "0.10.77",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -797,6 +797,12 @@
"highlight.js": "9.12.0"
}
},
"marked": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz",
"integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=",
"dev": true
},
"md5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
@@ -878,6 +884,12 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"mustache": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz",
"integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=",
"dev": true
},
"nan": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
@@ -911,6 +923,14 @@
"resolved": "https://registry.npmjs.org/node-bitmap/-/node-bitmap-0.0.1.tgz",
"integrity": "sha1-GA6scAPgxwdhjvMTaPYvhLKmkJE="
},
"node-emoji": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz",
"integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==",
"requires": {
"lodash.toarray": "4.4.0"
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",

View File

@@ -18,7 +18,7 @@
],
"owner": "Laurent Cozic"
},
"version": "0.10.68",
"version": "0.10.77",
"bin": {
"joplin": "./main.js"
},
@@ -37,6 +37,7 @@
"md5": "^2.2.1",
"mime": "^2.0.3",
"moment": "^2.18.1",
"node-emoji": "^1.8.1",
"node-fetch": "^1.7.1",
"node-persist": "^2.1.0",
"os-tmpdir": "^1.0.2",
@@ -60,7 +61,9 @@
},
"devDependencies": {
"gettext-parser": "^1.2.2",
"jasmine": "^2.6.0"
"jasmine": "^2.6.0",
"marked": "^0.3.6",
"mustache": "^2.3.0"
},
"scripts": {
"test": "jasmine"

View File

@@ -1,40 +0,0 @@
const { time } = require('lib/time-utils.js');
const { setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient } = require('test-utils.js');
const { Folder } = require('lib/models/folder.js');
const { Note } = require('lib/models/note.js');
const { Setting } = require('lib/models/setting.js');
const { BaseItem } = require('lib/models/base-item.js');
const { BaseModel } = require('lib/base-model.js');
process.on('unhandledRejection', (reason, p) => {
console.error('Unhandled promise rejection at: Promise', p, 'reason:', reason);
});
describe('BaseItem', function() {
beforeEach( async (done) => {
await setupDatabaseAndSynchronizer(1);
switchClient(1);
done();
});
it('should create a deleted_items record', async (done) => {
let folder1 = await Folder.save({ title: 'folder1' });
let folder2 = await Folder.save({ title: 'folder2' });
await Folder.delete(folder1.id);
let items = await BaseItem.deletedItems();
expect(items.length).toBe(1);
expect(items[0].item_id).toBe(folder1.id);
expect(items[0].item_type).toBe(folder1.type_);
let folders = await Folder.all();
expect(folders.length).toBe(1);
done();
});
});

View File

@@ -9,6 +9,7 @@ const { Database } = require('lib/database.js');
const { Setting } = require('lib/models/setting.js');
const { BaseItem } = require('lib/models/base-item.js');
const { BaseModel } = require('lib/base-model.js');
const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
@@ -37,7 +38,7 @@ async function localItemsSameAsRemote(locals, expect) {
expect(!!remote).toBe(true);
if (!remote) continue;
if (syncTargetId() == Setting.SYNC_TARGET_FILESYSTEM) {
if (syncTargetId() == SyncTargetRegistry.nameToId('filesystem')) {
expect(remote.updated_time).toBe(Math.floor(dbItem.updated_time / 1000) * 1000);
} else {
expect(remote.updated_time).toBe(dbItem.updated_time);
@@ -606,5 +607,25 @@ describe('Synchronizer', function() {
done();
});
it('items should be downloaded again when user cancels in the middle of delta operation', async (done) => {
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id });
await synchronizer().start();
await switchClient(2);
synchronizer().debugFlags_ = ['cancelDeltaLoop2'];
let context = await synchronizer().start();
let notes = await Note.all();
expect(notes.length).toBe(0);
synchronizer().debugFlags_ = [];
await synchronizer().start({ context: context });
notes = await Note.all();
expect(notes.length).toBe(1);
done();
});
});

View File

@@ -16,6 +16,10 @@ const { FileApiDriverMemory } = require('lib/file-api-driver-memory.js');
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
const { FsDriverNode } = require('lib/fs-driver-node.js');
const { time } = require('lib/time-utils.js');
const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
const SyncTargetMemory = require('lib/SyncTargetMemory.js');
const SyncTargetFilesystem = require('lib/SyncTargetFilesystem.js');
const SyncTargetOneDrive = require('lib/SyncTargetOneDrive.js');
let databases_ = [];
let synchronizers_ = [];
@@ -29,12 +33,14 @@ Resource.fsDriver_ = fsDriver;
const logDir = __dirname + '/../tests/logs';
fs.mkdirpSync(logDir, 0o755);
const syncTargetId_ = Setting.SYNC_TARGET_MEMORY;
//const syncTargetId_ = Setting.SYNC_TARGET_FILESYSTEM;
//const syncTargetId_ = Setting.SYNC_TARGET_ONEDRIVE;
SyncTargetRegistry.addClass(SyncTargetMemory);
SyncTargetRegistry.addClass(SyncTargetFilesystem);
SyncTargetRegistry.addClass(SyncTargetOneDrive);
const syncTargetId_ = SyncTargetRegistry.nameToId('memory');
const syncDir = __dirname + '/../tests/sync';
const sleepTime = syncTargetId_ == Setting.SYNC_TARGET_FILESYSTEM ? 1001 : 400;
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 400;
const logger = new Logger();
logger.addTarget('file', { path: logDir + '/log.txt' });
@@ -121,11 +127,14 @@ async function setupDatabaseAndSynchronizer(id = null) {
await setupDatabase(id);
if (!synchronizers_[id]) {
synchronizers_[id] = new Synchronizer(db(id), fileApi(), Setting.value('appType'));
synchronizers_[id].setLogger(logger);
const SyncTargetClass = SyncTargetRegistry.classById(syncTargetId_);
const syncTarget = new SyncTargetClass(db(id));
syncTarget.setFileApi(fileApi());
syncTarget.setLogger(logger);
synchronizers_[id] = await syncTarget.synchronizer();
}
if (syncTargetId_ == Setting.SYNC_TARGET_FILESYSTEM) {
if (syncTargetId_ == SyncTargetRegistry.nameToId('filesystem')) {
fs.removeSync(syncDir)
fs.mkdirpSync(syncDir, 0o755);
} else {
@@ -146,13 +155,12 @@ function synchronizer(id = null) {
function fileApi() {
if (fileApi_) return fileApi_;
if (syncTargetId_ == Setting.SYNC_TARGET_FILESYSTEM) {
if (syncTargetId_ == SyncTargetRegistry.nameToId('filesystem')) {
fs.removeSync(syncDir)
fs.mkdirpSync(syncDir, 0o755);
fileApi_ = new FileApi(syncDir, new FileApiDriverLocal());
} else if (syncTargetId_ == Setting.SYNC_TARGET_MEMORY) {
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('memory')) {
fileApi_ = new FileApi('/root', new FileApiDriverMemory());
fileApi_.setLogger(logger);
}
// } else if (syncTargetId == Setting.SYNC_TARGET_ONEDRIVE) {
// let auth = require('./onedrive-auth.json');

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{
"name": "demo-joplin",
"version": "1.0.6",
"version": "1.0.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -25,7 +25,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
"requires": {
"color-convert": "1.9.0"
"color-convert": "1.9.1"
}
},
"app-module-path": {
@@ -79,23 +79,6 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
},
"babel-plugin-transform-runtime": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
"integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
"requires": {
"babel-runtime": "6.26.0"
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
}
},
"bcrypt-pbkdf": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
@@ -113,11 +96,6 @@
"hoek": "4.2.0"
}
},
"cache-require-paths": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/cache-require-paths/-/cache-require-paths-0.3.0.tgz",
"integrity": "sha1-EqYHWj5JiNpMIvIY4pSFZj5MSmM="
},
"camelcase": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
@@ -165,18 +143,18 @@
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-2.0.0.tgz",
"integrity": "sha1-4MmXLR6WmFcASxAeqlXOq1lh1n0=",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color/-/color-2.0.1.tgz",
"integrity": "sha512-ubUCVVKfT7r2w2D3qtHakj8mbmKms+tThR8gI8zEYCbUBl8/voqFGt3kgBqGwXAopgXybnkuOq+qMYCRrp4cXw==",
"requires": {
"color-convert": "1.9.0",
"color-convert": "1.9.1",
"color-string": "1.5.2"
}
},
"color-convert": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
"integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
"requires": {
"color-name": "1.1.3"
}
@@ -212,11 +190,6 @@
"proto-list": "1.2.4"
}
},
"core-js": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
"integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -306,6 +279,53 @@
"jsbn": "0.1.1"
}
},
"emphasize": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/emphasize/-/emphasize-1.5.0.tgz",
"integrity": "sha1-48WvLdzLSYKCKjNJtHFhPMfOzJI=",
"requires": {
"chalk": "1.1.3",
"highlight.js": "9.12.0",
"lowlight": "1.9.1"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "2.2.1",
"escape-string-regexp": "1.0.5",
"has-ansi": "2.0.0",
"strip-ansi": "3.0.1",
"supports-color": "2.0.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "2.1.1"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
}
}
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
@@ -395,7 +415,7 @@
"resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz",
"integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==",
"requires": {
"npm-conf": "1.1.2"
"npm-conf": "1.1.3"
}
},
"getpass": {
@@ -425,6 +445,21 @@
"har-schema": "2.0.0"
}
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"requires": {
"ansi-regex": "2.1.1"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
}
}
},
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
@@ -454,11 +489,21 @@
"sntp": "2.1.0"
}
},
"highlight.js": {
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
},
"hoek": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
},
"html-entities": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
"integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -577,22 +622,21 @@
}
},
"joplin": {
"version": "0.10.64",
"resolved": "https://registry.npmjs.org/joplin/-/joplin-0.10.64.tgz",
"integrity": "sha512-CdhUZCnbpGmvOJqpeJp4ri9kGk6nP+VxulbaJLx8MTWho8n3tBRHcvAGP/lOLovFvUy760lOyzqHiYfcimonJQ==",
"version": "0.10.69",
"resolved": "https://registry.npmjs.org/joplin/-/joplin-0.10.69.tgz",
"integrity": "sha512-P5b7pRiUqM2O/vG4etiAquGd7LM6j/eh93OmQgJmfcGu5F6D9DJERIjBP8Po/BnzXQVxsGnURHr3SmLlaUxQSg==",
"requires": {
"app-module-path": "2.2.0",
"babel-plugin-transform-runtime": "6.23.0",
"cache-require-paths": "0.3.0",
"follow-redirects": "1.2.5",
"form-data": "2.3.1",
"fs-extra": "3.0.1",
"html-entities": "1.2.1",
"jssha": "2.3.1",
"levenshtein": "1.0.5",
"lodash": "4.17.4",
"md5": "2.2.1",
"mime": "2.0.3",
"moment": "2.19.1",
"moment": "2.19.2",
"node-fetch": "1.7.3",
"node-persist": "2.1.0",
"os-tmpdir": "1.0.2",
@@ -603,14 +647,13 @@
"sax": "1.2.4",
"server-destroy": "1.0.1",
"sharp": "0.18.4",
"source-map-support": "0.4.18",
"sprintf-js": "1.1.1",
"sqlite3": "3.1.13",
"string-padding": "1.0.2",
"string-to-stream": "1.1.0",
"strip-ansi": "4.0.0",
"tcp-port-used": "0.1.2",
"tkwidgets": "0.5.19",
"tkwidgets": "0.5.20",
"uuid": "3.1.0",
"word-wrap": "1.2.3",
"yargs-parser": "7.0.0"
@@ -719,6 +762,14 @@
"js-tokens": "3.0.2"
}
},
"lowlight": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.9.1.tgz",
"integrity": "sha512-CpDhyVhI+xHjruiGvH2F/Fr5q5aTn5A6Oyh7MI+4oI8G0A1E7p9a3Zqv9Hzx9WByK8gAiNifEueAXz+cA2xdEA==",
"requires": {
"highlight.js": "9.12.0"
}
},
"md5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
@@ -782,9 +833,9 @@
}
},
"moment": {
"version": "2.19.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.19.1.tgz",
"integrity": "sha1-VtoaLRy/AdOLfhr8McELz6GSkWc="
"version": "2.19.2",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.19.2.tgz",
"integrity": "sha512-Rf6jiHPEfxp9+dlzxPTmRHbvoFXsh2L/U8hOupUMpnuecHQmI6cF6lUbJl3QqKPko1u6ujO+FxtcajLVfLpAtA=="
},
"ms": {
"version": "2.0.0",
@@ -792,9 +843,9 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nan": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
"integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY="
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
"integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo="
},
"ndarray": {
"version": "1.0.18",
@@ -850,9 +901,9 @@
}
},
"npm-conf": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.2.tgz",
"integrity": "sha512-dotwbpwVzfNB/2EF3A2wjK5tEMLggKfuA/8TG6WvBB1Zrv+JsvF7E8ei9B/HGq211st/GwXFbREcNJvJ1eySUQ==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz",
"integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==",
"requires": {
"config-chain": "1.1.11",
"pify": "3.0.0"
@@ -985,11 +1036,6 @@
"symbol-observable": "1.0.4"
}
},
"regenerator-runtime": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
"integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A=="
},
"request": {
"version": "2.83.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
@@ -1050,9 +1096,9 @@
"integrity": "sha1-/jKcDwaJbCiqJDdt8f/wKuV/LTQ=",
"requires": {
"caw": "2.0.1",
"color": "2.0.0",
"color": "2.0.1",
"detect-libc": "0.2.0",
"nan": "2.7.0",
"nan": "2.8.0",
"semver": "5.4.1",
"simple-get": "2.7.0",
"tar": "3.2.1"
@@ -1097,19 +1143,6 @@
"hoek": "4.2.0"
}
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
},
"source-map-support": {
"version": "0.4.18",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
"integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
"requires": {
"source-map": "0.5.7"
}
},
"sprintf-js": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
@@ -1518,6 +1551,11 @@
"version": "2.0.0",
"bundled": true
},
"nan": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
"integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY="
},
"node-pre-gyp": {
"version": "0.6.38",
"bundled": true,
@@ -1947,9 +1985,9 @@
}
},
"terminal-kit": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/terminal-kit/-/terminal-kit-1.14.0.tgz",
"integrity": "sha512-ir0I2QtcBDSg2w0UvohlqdDpGlS3S2UYBG4NnYKnK/4VywgnbfxgdpXN3el0uCH3OeH6fG38luW7RmDM96FqUw==",
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/terminal-kit/-/terminal-kit-1.14.3.tgz",
"integrity": "sha512-ZHtuElnBhK0IXOYNvQ7eYgaArwEoOv7saQc4Q0Z9p02JeC7iajC20/odV77BKB3jw/Qthvf9mpASf8gNDYv7xQ==",
"requires": {
"async-kit": "2.2.3",
"get-pixels": "3.3.0",
@@ -1965,15 +2003,16 @@
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"tkwidgets": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/tkwidgets/-/tkwidgets-0.5.19.tgz",
"integrity": "sha512-Etskz52RInmmB1aGD9cIodIZ33Gwf0yPP3+lh6ceANgS4N8LpquQajDRyahjZnvwDhfYdo1N87eEKzXBJbLQDg==",
"version": "0.5.20",
"resolved": "https://registry.npmjs.org/tkwidgets/-/tkwidgets-0.5.20.tgz",
"integrity": "sha512-9wGsMrrFJvE/6TKUc0dEFFhwxvZLeNsYOxnpy1JCwyk/hYCEF70nuvk7VvJeG4TPaQBaGKPj6c7pCgdREvz4Jw==",
"requires": {
"chalk": "2.3.0",
"emphasize": "1.5.0",
"node-emoji": "git+https://github.com/laurent22/node-emoji.git#9fa01eac463e94dde1316ef8c53089eeef4973b5",
"slice-ansi": "1.0.0",
"string-width": "2.1.1",
"terminal-kit": "1.14.0",
"terminal-kit": "1.14.3",
"wrap-ansi": "3.0.1"
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "demo-joplin",
"version": "1.0.6",
"version": "1.0.8",
"description": "Demo for Joplin CLI",
"bin": {
"demo-joplin": "./index.js"
@@ -25,7 +25,7 @@
},
"dependencies": {
"fs-extra": "^4.0.2",
"joplin": "^0.10.64"
"joplin": "^0.10.69"
},
"author": "Laurent Cozic",
"license": "MIT"

View File

@@ -1,5 +1,5 @@
build/
app/node_modules/
app/packageInfo.js
dist/
app/lib/
app/gui/*.min.js

View File

@@ -10,6 +10,7 @@ class ElectronAppWrapper {
this.electronApp_ = electronApp;
this.env_ = env;
this.win_ = null;
this.willQuitApp_ = false;
}
electronApp() {
@@ -50,10 +51,16 @@ class ElectronAppWrapper {
slashes: true
}))
// Uncomment this to view errors if the application does not start
if (this.env_ === 'dev') this.win_.webContents.openDevTools();
this.win_.on('closed', () => {
this.win_ = null
this.win_.on('close', (event) => {
if (this.willQuitApp_ || process.platform !== 'darwin') {
this.win_ = null;
} else {
event.preventDefault();
this.win_.hide();
}
})
// Let us register listeners on the window, so we can update the state
@@ -86,20 +93,16 @@ class ElectronAppWrapper {
this.createWindow();
this.electronApp_.on('before-quit', () => {
this.willQuitApp_ = true;
})
this.electronApp_.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
this.electronApp_.quit()
}
this.electronApp_.quit();
})
this.electronApp_.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (this.win_ === null) {
createWindow()
}
this.win_.show();
})
}

View File

@@ -8,7 +8,6 @@ const { BaseModel } = require('lib/base-model.js');
const { _, setLocale } = require('lib/locale.js');
const os = require('os');
const fs = require('fs-extra');
const { Logger } = require('lib/logger.js');
const { Tag } = require('lib/models/tag.js');
const { reg } = require('lib/registry.js');
const { sprintf } = require('sprintf-js');
@@ -16,6 +15,9 @@ const { JoplinDatabase } = require('lib/joplin-database.js');
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
const { ElectronAppWrapper } = require('./ElectronAppWrapper');
const { defaultState } = require('lib/reducer.js');
const packageInfo = require('./packageInfo.js');
const AlarmService = require('lib/services/AlarmService.js');
const AlarmServiceDriverNode = require('lib/services/AlarmServiceDriverNode');
const { bridge } = require('electron').remote.require('./bridge');
const Menu = bridge().Menu;
@@ -133,7 +135,11 @@ class Application extends BaseApplication {
}
if (['NOTE_UPDATE_ONE', 'NOTE_DELETE', 'FOLDER_UPDATE_ONE', 'FOLDER_DELETE'].indexOf(action.type) >= 0) {
if (!await reg.syncStarted()) reg.scheduleSync();
if (!await reg.syncTarget().syncStarted()) reg.scheduleSync();
}
if (['EVENT_NOTE_ALARM_FIELD_CHANGE', 'NOTE_DELETE'].indexOf(action.type) >= 0) {
await AlarmService.updateNoteNotification(action.id, action.type === 'NOTE_DELETE');
}
const result = await super.generalMiddleware(store, next, action);
@@ -219,6 +225,37 @@ class Application extends BaseApplication {
accelerator: 'CommandOrControl+Q',
click: () => { bridge().electronApp().exit() }
}]
}, {
label: _('Edit'),
submenu: [{
label: _('Copy'),
screens: ['Main', 'OneDriveLogin'],
role: 'copy',
accelerator: 'CommandOrControl+C',
}, {
label: _('Cut'),
screens: ['Main', 'OneDriveLogin'],
role: 'cut',
accelerator: 'CommandOrControl+X',
}, {
label: _('Paste'),
screens: ['Main', 'OneDriveLogin'],
role: 'paste',
accelerator: 'CommandOrControl+V',
}, {
type: 'separator',
screens: ['Main'],
}, {
label: _('Search in all the notes'),
screens: ['Main'],
accelerator: 'F6',
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'search',
});
},
}]
}, {
label: _('Tools'),
submenu: [{
@@ -239,7 +276,7 @@ class Application extends BaseApplication {
}, {
label: _('About Joplin'),
click: () => {
const p = require('./package.json');
const p = packageInfo;
let message = [
p.description,
'',
@@ -254,12 +291,21 @@ class Application extends BaseApplication {
},
];
function isEmptyMenu(template) {
for (let i = 0; i < template.length; i++) {
const t = template[i];
if (t.type !== 'separator') return false;
}
return true;
}
function removeUnwantedItems(template, screen) {
let output = [];
for (let i = 0; i < template.length; i++) {
const t = Object.assign({}, template[i]);
if (t.screens && t.screens.indexOf(screen) < 0) continue;
if (t.submenu) t.submenu = removeUnwantedItems(t.submenu, screen);
if (('submenu' in t) && isEmptyMenu(t.submenu)) continue;
output.push(t);
}
return output;
@@ -276,20 +322,19 @@ class Application extends BaseApplication {
async start(argv) {
argv = await super.start(argv);
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
AlarmService.setLogger(reg.logger());
reg.setShowErrorMessageBoxHandler((message) => { bridge().showErrorMessageBox(message) });
if (Setting.value('openDevTools')) {
bridge().window().webContents.openDevTools();
}
this.updateMenu('Main');
this.initRedux();
// const windowSize = Setting.value('windowSize');
// const width = windowSize && windowSize.width ? windowSize.width : 800;
// const height = windowSize && windowSize.height ? windowSize.height : 800;
// bridge().windowSetSize(width, height);
// this.store().dispatch({
// type: 'WINDOW_CONTENT_SIZE_SET',
// size: bridge().windowContentSize(),
// });
// Since the settings need to be loaded before the store is created, it will never
// receive the SETTING_UPDATE_ALL even, which mean state.settings will not be
// initialised. So we manually call dispatchUpdateAll() to force an update.
@@ -313,13 +358,29 @@ class Application extends BaseApplication {
// but then doesn't install it on exit.
if (shim.isWindows() || shim.isMac()) {
const runAutoUpdateCheck = function() {
bridge().checkForUpdatesAndNotify(Setting.value('profileDir') + '/log-autoupdater.txt');
if (Setting.value('autoUpdateEnabled')) {
bridge().checkForUpdatesAndNotify(Setting.value('profileDir') + '/log-autoupdater.txt');
}
}
setTimeout(() => { runAutoUpdateCheck() }, 5000);
// For those who leave the app always open
setInterval(() => { runAutoUpdateCheck() }, 2 * 60 * 60 * 1000);
}
setTimeout(() => {
AlarmService.garbageCollect();
}, 1000 * 60 * 60);
if (Setting.value('env') === 'dev') {
AlarmService.updateAllNotifications();
} else {
reg.scheduleSync().then(() => {
// Wait for the first sync before updating the notifications, since synchronisation
// might change the notifications.
AlarmService.updateAllNotifications();
});
}
}
}

View File

@@ -1,10 +1,13 @@
const { _ } = require('lib/locale.js');
const { dirname } = require('lib/path-utils.js');
const { Logger } = require('lib/logger.js');
class Bridge {
constructor(electronWrapper) {
this.electronWrapper_ = electronWrapper;
this.autoUpdateLogger_ = null;
this.lastSelectedPath_ = null;
}
electronApp() {
@@ -38,7 +41,13 @@ class Bridge {
showOpenDialog(options) {
const {dialog} = require('electron');
return dialog.showOpenDialog(options);
if (!options) options = {};
if (!('defaultPath' in options) && this.lastSelectedPath_) options.defaultPath = this.lastSelectedPath_;
const filePaths = dialog.showOpenDialog(options);
if (filePaths && filePaths.length) {
this.lastSelectedPath_ = dirname(filePaths[0]);
}
return filePaths;
}
showMessageBox(options) {
@@ -78,17 +87,21 @@ class Bridge {
return require('electron').shell.openItem(fullPath)
}
checkForUpdatesAndNotify(logFilePath) {
async checkForUpdatesAndNotify(logFilePath) {
if (!this.autoUpdater_) {
const logger = new Logger();
logger.addTarget('file', { path: logFilePath });
logger.setLevel(Logger.LEVEL_DEBUG);
logger.info('checkForUpdatesAndNotify: Intializing...');
this.autoUpdateLogger_ = new Logger();
this.autoUpdateLogger_.addTarget('file', { path: logFilePath });
this.autoUpdateLogger_.setLevel(Logger.LEVEL_DEBUG);
this.autoUpdateLogger_.info('checkForUpdatesAndNotify: Initializing...');
this.autoUpdater_ = require("electron-updater").autoUpdater;
this.autoUpdater_.logger = logger;
this.autoUpdater_.logger = this.autoUpdateLogger_;
}
return this.autoUpdater_.checkForUpdatesAndNotify();
try {
await this.autoUpdater_.checkForUpdatesAndNotify();
} catch (error) {
this.autoUpdateLogger_.error(error);
}
}
}

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: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 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: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,23 @@
const fs = require('fs-extra');
// Electron Builder strip off certain important keys from package.json, which we need, in particular build.appId
// so this script is used to preserve the keys that we need.
const packageInfo = require(__dirname + '/package.json');
let removeKeys = ['scripts', 'devDependencies', 'optionalDependencies', 'dependencies'];
for (let i = 0; i < removeKeys.length; i++) {
delete packageInfo[removeKeys[i]];
}
const appId = packageInfo.build.appId;
delete packageInfo.build;
packageInfo.build = { appId: appId };
let fileContent = "// Auto-generated by compile-package-info.js\n// Do not change directly\nconst packageInfo = " + JSON.stringify(packageInfo, null, 4) + ';';
fileContent += "\n";
fileContent += "module.exports = packageInfo;";
fs.writeFileSync(__dirname + '/packageInfo.js', fileContent);

View File

@@ -0,0 +1,25 @@
const events = require('events');
class EventManager {
constructor() {
this.emitter_ = new events.EventEmitter();
}
on(eventName, callback) {
return this.emitter_.on(eventName, callback);
}
emit(eventName, object = null) {
return this.emitter_.emit(eventName, object);
}
removeListener(eventName, callback) {
return this.emitter_.removeListener(eventName, callback);
}
}
const eventManager = new EventManager();
module.exports = eventManager;

View File

@@ -31,6 +31,8 @@ class ConfigScreenComponent extends React.Component {
Setting.setValue(key, value);
}
// Component key needs to be key+value otherwise it doesn't update when the settings change.
const md = Setting.settingMetadata(key);
if (md.isEnum) {
@@ -42,7 +44,7 @@ class ConfigScreenComponent extends React.Component {
}
return (
<div key={key} style={rowStyle}>
<div key={key+value} style={rowStyle}>
<div style={labelStyle}><label>{md.label()}</label></div>
<select value={value} style={controlStyle} onChange={(event) => { updateSettingValue(key, event.target.value) }}>
{items}
@@ -51,7 +53,7 @@ class ConfigScreenComponent extends React.Component {
);
} else if (md.type === Setting.TYPE_BOOL) {
return (
<div key={key} style={rowStyle}>
<div key={key+value} style={rowStyle}>
<div style={controlStyle}>
<label><input type="checkbox" defaultChecked={!!value} onChange={(event) => { updateSettingValue(key, !!event.target.checked) }}/><span style={labelStyle}> {md.label()}</span></label>
</div>

View File

@@ -41,7 +41,7 @@ class HeaderComponent extends React.Component {
}
render() {
const style = this.props.style;
const style = Object.assign({}, this.props.style);
const theme = themeStyle(this.props.theme);
const showBackButton = this.props.showBackButton === undefined || this.props.showBackButton === true;
style.height = theme.headerHeight;

View File

@@ -6,13 +6,16 @@ const { NoteList } = require('./NoteList.min.js');
const { NoteText } = require('./NoteText.min.js');
const { PromptDialog } = require('./PromptDialog.min.js');
const { Setting } = require('lib/models/setting.js');
const { BaseModel } = require('lib/base-model.js');
const { Tag } = require('lib/models/tag.js');
const { Note } = require('lib/models/note.js');
const { uuid } = require('lib/uuid.js');
const { Folder } = require('lib/models/folder.js');
const { themeStyle } = require('../theme.js');
const { _ } = require('lib/locale.js');
const layoutUtils = require('lib/layout-utils.js');
const { bridge } = require('electron').remote.require('./bridge');
const eventManager = require('../eventManager');
class MainScreenComponent extends React.Component {
@@ -97,13 +100,14 @@ class MainScreenComponent extends React.Component {
folder = await Folder.save({ title: answer }, { userSideValidation: true });
} catch (error) {
bridge().showErrorMessageBox(error.message);
return;
}
this.props.dispatch({
type: 'FOLDER_SELECT',
id: folder.id,
});
if (folder) {
this.props.dispatch({
type: 'FOLDER_SELECT',
id: folder.id,
});
}
}
this.setState({ promptOptions: null });
@@ -128,6 +132,91 @@ class MainScreenComponent extends React.Component {
}
},
});
} else if (command.name === 'renameNotebook') {
const folder = await Folder.load(command.id);
if (!folder) return;
this.setState({
promptOptions: {
label: _('Rename notebook:'),
value: folder.title,
onClose: async (answer) => {
if (answer !== null) {
try {
await Folder.save({ id: folder.id, title: answer }, { userSideValidation: true });
} catch (error) {
bridge().showErrorMessageBox(error.message);
}
}
this.setState({ promptOptions: null });
}
},
});
} else if (command.name === 'search') {
this.setState({
promptOptions: {
label: _('Search:'),
onClose: async (answer) => {
if (answer !== null) {
const searchId = uuid.create();
this.props.dispatch({
type: 'SEARCH_ADD',
search: {
id: searchId,
title: answer,
query_pattern: answer,
query_folder_id: null,
type_: BaseModel.TYPE_SEARCH,
},
});
this.props.dispatch({
type: 'SEARCH_SELECT',
id: searchId,
});
}
this.setState({ promptOptions: null });
}
},
});
} else if (command.name === 'editAlarm') {
const note = await Note.load(command.noteId);
let defaultDate = new Date(Date.now() + 2 * 3600 * 1000);
defaultDate.setMinutes(0);
defaultDate.setSeconds(0);
this.setState({
promptOptions: {
label: _('Set alarm:'),
inputType: 'datetime',
buttons: ['ok', 'cancel', 'clear'],
value: note.todo_due ? new Date(note.todo_due) : defaultDate,
onClose: async (answer, buttonType) => {
let newNote = null;
if (buttonType === 'clear') {
newNote = {
id: note.id,
todo_due: 0,
};
} else if (answer !== null) {
newNote = {
id: note.id,
todo_due: answer.getTime(),
};
}
if (newNote) {
await Note.save(newNote);
eventManager.emit('alarmChange', { noteId: note.id });
}
this.setState({ promptOptions: null });
}
},
});
} else {
commandProcessed = false;
}
@@ -140,44 +229,58 @@ class MainScreenComponent extends React.Component {
}
}
styles(themeId, width, height) {
const styleKey = themeId + '_' + width + '_' + height;
if (styleKey === this.styleKey_) return this.styles_;
const theme = themeStyle(themeId);
this.styleKey_ = styleKey;
this.styles_ = {};
const rowHeight = height - theme.headerHeight;
this.styles_.header = {
width: width,
};
this.styles_.sideBar = {
width: Math.floor(layoutUtils.size(width * .2, 150, 300)),
height: rowHeight,
display: 'inline-block',
verticalAlign: 'top',
};
this.styles_.noteList = {
width: Math.floor(layoutUtils.size(width * .2, 150, 300)),
height: rowHeight,
display: 'inline-block',
verticalAlign: 'top',
};
this.styles_.noteText = {
width: Math.floor(layoutUtils.size(width - this.styles_.sideBar.width - this.styles_.noteList.width, 0)),
height: rowHeight,
display: 'inline-block',
verticalAlign: 'top',
};
this.styles_.prompt = {
width: width,
height: height,
};
return this.styles_;
}
render() {
const style = this.props.style;
const theme = themeStyle(this.props.theme);
const promptOptions = this.state.promptOptions;
const folders = this.props.folders;
const notes = this.props.notes;
const headerStyle = {
width: style.width,
};
const rowHeight = style.height - theme.headerHeight;
const sideBarStyle = {
width: Math.floor(layoutUtils.size(style.width * .2, 150, 300)),
height: rowHeight,
display: 'inline-block',
verticalAlign: 'top',
};
const noteListStyle = {
width: Math.floor(layoutUtils.size(style.width * .2, 150, 300)),
height: rowHeight,
display: 'inline-block',
verticalAlign: 'top',
};
const noteTextStyle = {
width: Math.floor(layoutUtils.size(style.width - sideBarStyle.width - noteListStyle.width, 0)),
height: rowHeight,
display: 'inline-block',
verticalAlign: 'top',
};
const promptStyle = {
width: style.width,
height: style.height,
};
const styles = this.styles(this.props.theme, style.width, style.height);
const headerButtons = [];
@@ -201,6 +304,12 @@ class MainScreenComponent extends React.Component {
onClick: () => { this.doCommand({ name: 'newNotebook' }) },
});
headerButtons.push({
title: _('Search'),
iconName: 'fa-search',
onClick: () => { this.doCommand({ name: 'search' }) },
});
headerButtons.push({
title: _('Layout'),
iconName: 'fa-columns',
@@ -210,20 +319,29 @@ class MainScreenComponent extends React.Component {
},
});
if (!this.promptOnClose_) {
this.promptOnClose_ = (answer, buttonType) => {
return this.state.promptOptions.onClose(answer, buttonType);
}
}
return (
<div style={style}>
<PromptDialog
value={promptOptions && promptOptions.value ? promptOptions.value : ''}
autocomplete={promptOptions && ('autocomplete' in promptOptions) ? promptOptions.autocomplete : null}
defaultValue={promptOptions && promptOptions.value ? promptOptions.value : ''}
theme={this.props.theme}
style={promptStyle}
onClose={(answer) => promptOptions.onClose(answer)}
style={styles.prompt}
onClose={this.promptOnClose_}
label={promptOptions ? promptOptions.label : ''}
description={promptOptions ? promptOptions.description : null}
visible={!!this.state.promptOptions} />
<Header style={headerStyle} showBackButton={false} buttons={headerButtons} />
<SideBar style={sideBarStyle} />
<NoteList style={noteListStyle} />
<NoteText style={noteTextStyle} visiblePanes={this.props.noteVisiblePanes} />
visible={!!this.state.promptOptions}
buttons={promptOptions && ('buttons' in promptOptions) ? promptOptions.buttons : null}
inputType={promptOptions && ('inputType' in promptOptions) ? promptOptions.inputType : null} />
<Header style={styles.header} showBackButton={false} buttons={headerButtons} />
<SideBar style={styles.sideBar} />
<NoteList style={styles.noteList} />
<NoteText style={styles.noteText} visiblePanes={this.props.noteVisiblePanes} />
</div>
);
}

View File

@@ -33,8 +33,6 @@ class NavigatorComponent extends Component {
height: this.props.style.height,
};
return (
<div style={this.props.style}>
<Screen style={screenStyle} {...screenProps}/>

View File

@@ -7,6 +7,7 @@ const { _ } = require('lib/locale.js');
const { bridge } = require('electron').remote.require('./bridge');
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
const eventManager = require('../eventManager');
class NoteListComponent extends React.Component {
@@ -52,28 +53,31 @@ class NoteListComponent extends React.Component {
}
itemContextMenu(event) {
const noteId = event.target.getAttribute('data-id');
if (!noteId) throw new Error('No data-id on element');
const noteIds = this.props.selectedNoteIds;
if (!noteIds.length) return;
const menu = new Menu()
menu.append(new MenuItem({label: _('Add or remove tags'), click: async () => {
menu.append(new MenuItem({label: _('Add or remove tags'), enabled: noteIds.length === 1, click: async () => {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'setTags',
noteId: noteId,
noteId: noteIds[0],
});
}}));
menu.append(new MenuItem({label: _('Switch between note and to-do'), click: async () => {
const note = await Note.load(noteId);
await Note.save(Note.toggleIsTodo(note));
menu.append(new MenuItem({label: _('Switch between note and to-do type'), click: async () => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
await Note.save(Note.toggleIsTodo(note));
eventManager.emit('noteTypeToggle', { noteId: note.id });
}
}}));
menu.append(new MenuItem({label: _('Delete'), click: async () => {
const ok = bridge().showConfirmMessageBox(_('Delete note?'));
const ok = bridge().showConfirmMessageBox(noteIds.length > 1 ? _('Delete notes?') : _('Delete note?'));
if (!ok) return;
await Note.delete(noteId);
await Note.batchDelete(noteIds);
}}));
menu.popup(bridge().window());
@@ -81,10 +85,33 @@ class NoteListComponent extends React.Component {
itemRenderer(item, theme, width) {
const onTitleClick = async (event, item) => {
this.props.dispatch({
type: 'NOTE_SELECT',
id: item.id,
});
if (event.ctrlKey) {
event.preventDefault();
this.props.dispatch({
type: 'NOTE_SELECT_TOGGLE',
id: item.id,
});
} else if (event.shiftKey) {
event.preventDefault();
this.props.dispatch({
type: 'NOTE_SELECT_EXTEND',
id: item.id,
});
} else {
this.props.dispatch({
type: 'NOTE_SELECT',
id: item.id,
});
}
}
const onDragStart = (event) => {
const noteIds = this.props.selectedNoteIds;
if (!noteIds.length) return;
event.dataTransfer.setDragImage(new Image(), 1, 1);
event.dataTransfer.clearData();
event.dataTransfer.setData('text/x-jop-note-ids', JSON.stringify(noteIds));
}
const onCheckboxClick = async (event) => {
@@ -94,12 +121,13 @@ class NoteListComponent extends React.Component {
todo_completed: checked ? time.unixMs() : 0,
}
await Note.save(newNote);
eventManager.emit('todoToggle', { noteId: item.id });
}
const hPadding = 10;
let style = Object.assign({ width: width }, this.style().listItem);
if (this.props.selectedNoteId === item.id) style = Object.assign(style, this.style().listItemSelected);
if (this.props.selectedNoteIds.indexOf(item.id) >= 0) style = Object.assign(style, this.style().listItemSelected);
// Setting marginBottom = 1 because it makes the checkbox looks more centered, at least on Windows
// but don't know how it will look in other OSes.
@@ -118,12 +146,13 @@ class NoteListComponent extends React.Component {
return <div key={item.id + '_' + item.todo_completed} style={style}>
{checkbox}
<a
data-id={item.id}
className="list-item"
onContextMenu={(event) => this.itemContextMenu(event)}
href="#"
draggable={true}
style={listItemTitleStyle}
onClick={(event) => { onTitleClick(event, item) }}
onDragStart={(event) => onDragStart(event) }
>
{item.title}
</a>
@@ -164,7 +193,7 @@ class NoteListComponent extends React.Component {
const mapStateToProps = (state) => {
return {
notes: state.notes,
selectedNoteId: state.selectedNoteId,
selectedNoteIds: state.selectedNoteIds,
theme: state.settings.theme,
// uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
};

View File

@@ -1,7 +1,9 @@
const React = require('react');
const { Note } = require('lib/models/note.js');
const { time } = require('lib/time-utils.js');
const { Setting } = require('lib/models/setting.js');
const { IconButton } = require('./IconButton.min.js');
const Toolbar = require('./Toolbar.min.js');
const { connect } = require('react-redux');
const { _ } = require('lib/locale.js');
const { reg } = require('lib/registry.js');
@@ -13,6 +15,7 @@ const AceEditor = require('react-ace').default;
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
const { shim } = require('lib/shim.js');
const eventManager = require('../eventManager');
require('brace/mode/markdown');
// https://ace.c9.io/build/kitchen-sink.html
@@ -55,11 +58,18 @@ class NoteTextComponent extends React.Component {
this.restoreScrollTop_ = null;
}
}
this.onAlarmChange_ = (event) => { if (event.noteId === this.props.noteId) this.reloadNote(this.props); }
this.onNoteTypeToggle_ = (event) => { if (event.noteId === this.props.noteId) this.reloadNote(this.props); }
this.onTodoToggle_ = (event) => { if (event.noteId === this.props.noteId) this.reloadNote(this.props); }
}
mdToHtml() {
if (this.mdToHtml_) return this.mdToHtml_;
this.mdToHtml_ = new MdToHtml({ supportsResourceLinks: true });
this.mdToHtml_ = new MdToHtml({
supportsResourceLinks: true,
resourceBaseUrl: 'file://' + Setting.value('resourceDir') + '/',
});
return this.mdToHtml_;
}
@@ -79,6 +89,10 @@ class NoteTextComponent extends React.Component {
});
this.lastLoadedNoteId_ = note ? note.id : null;
eventManager.on('alarmChange', this.onAlarmChange_);
eventManager.on('noteTypeToggle', this.onNoteTypeToggle_);
eventManager.on('todoToggle', this.onTodoToggle_);
}
componentWillUnmount() {
@@ -86,6 +100,10 @@ class NoteTextComponent extends React.Component {
this.mdToHtml_ = null;
this.destroyWebview();
eventManager.removeListener('alarmChange', this.onAlarmChange_);
eventManager.removeListener('noteTypeToggle', this.onNoteTypeToggle_);
eventManager.removeListener('todoToggle', this.onTodoToggle_);
}
async saveIfNeeded() {
@@ -106,13 +124,24 @@ class NoteTextComponent extends React.Component {
}, 500);
}
async reloadNote(props) {
this.mdToHtml_ = null;
async reloadNote(props, options = null) {
if (!options) options = {};
if (!('noReloadIfLocalChanges' in options)) options.noReloadIfLocalChanges = false;
const noteId = props.noteId;
this.lastLoadedNoteId_ = noteId;
const note = noteId ? await Note.load(noteId) : null;
if (noteId !== this.lastLoadedNoteId_) return; // Race condition - current note was changed while this one was loading
if (!options.noReloadIfLocalChanges && this.isModified()) return;
// If the note hasn't been changed, exit now
if (this.state.note && note) {
let diff = Note.diffObjects(this.state.note, note);
delete diff.type_;
if (!Object.getOwnPropertyNames(diff).length) return;
}
this.mdToHtml_ = null;
// If we are loading nothing (noteId == null), make sure to
// set webviewReady to false too because the webview component
@@ -141,7 +170,7 @@ class NoteTextComponent extends React.Component {
}
if ('syncStarted' in nextProps && !nextProps.syncStarted && !this.isModified()) {
await this.reloadNote(nextProps);
await this.reloadNote(nextProps, { noReloadIfLocalChanges: true });
}
}
@@ -305,6 +334,45 @@ class NoteTextComponent extends React.Component {
this.scheduleSave();
}
async commandAttachFile() {
const noteId = this.props.noteId;
if (!noteId) return;
const filePaths = bridge().showOpenDialog({
properties: ['openFile', 'createDirectory', 'multiSelections'],
});
if (!filePaths || !filePaths.length) return;
await this.saveIfNeeded();
let note = await Note.load(noteId);
for (let i = 0; i < filePaths.length; i++) {
const filePath = filePaths[i];
try {
reg.logger().info('Attaching ' + filePath);
note = await shim.attachFileToNote(note, filePath);
reg.logger().info('File was attached.');
this.setState({
note: Object.assign({}, note),
lastSavedNote: Object.assign({}, note),
});
} catch (error) {
reg.logger().error(error);
}
}
}
commandSetAlarm() {
const noteId = this.props.noteId;
if (!noteId) return;
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'editAlarm',
noteId: noteId,
});
}
itemContextMenu(event) {
const noteId = this.props.noteId;
if (!noteId) return;
@@ -312,24 +380,26 @@ class NoteTextComponent extends React.Component {
const menu = new Menu()
menu.append(new MenuItem({label: _('Attach file'), click: async () => {
const filePaths = bridge().showOpenDialog({
properties: ['openFile', 'createDirectory'],
});
if (!filePaths || !filePaths.length) return;
return this.commandAttachFile();
}}));
await this.saveIfNeeded();
const note = await Note.load(noteId);
const newNote = await shim.attachFileToNote(note, filePaths[0]);
this.setState({
note: newNote,
lastSavedNote: Object.assign({}, newNote),
});
menu.append(new MenuItem({label: _('Set alarm'), click: async () => {
return this.commandSetAlarm();
}}));
menu.popup(bridge().window());
}
// shouldComponentUpdate(nextProps, nextState) {
// //console.info('NEXT PROPS', JSON.stringify(nextProps));
// console.info('NEXT STATE ====================');
// for (var n in nextProps) {
// if (!nextProps.hasOwnProperty(n)) continue;
// console.info(n + ' = ' + (nextProps[n] === this.props[n]));
// }
// return true;
// }
render() {
const style = this.props.style;
const note = this.state.note;
@@ -361,7 +431,7 @@ class NoteTextComponent extends React.Component {
height: 30,
boxSizing: 'border-box',
marginTop: 10,
marginBottom: 10,
marginBottom: 0,
display: 'flex',
flexDirection: 'row',
};
@@ -377,7 +447,11 @@ class NoteTextComponent extends React.Component {
marginRight: rootStyle.paddingLeft,
};
const bottomRowHeight = rootStyle.height - titleBarStyle.height - titleBarStyle.marginBottom - titleBarStyle.marginTop;
const toolbarStyle = {
marginBottom: 10,
};
const bottomRowHeight = rootStyle.height - titleBarStyle.height - titleBarStyle.marginBottom - titleBarStyle.marginTop - theme.toolbarHeight - toolbarStyle.marginBottom;
const viewerStyle = {
width: Math.floor(innerWidth / 2),
@@ -431,6 +505,28 @@ class NoteTextComponent extends React.Component {
this.webview_.send('setHtml', html);
}
const toolbarItems = [];
toolbarItems.push({
title: _('Attach file'),
iconName: 'fa-paperclip',
onClick: () => { return this.commandAttachFile(); },
});
if (note.is_todo) {
toolbarItems.push({
title: Note.needAlarm(note) ? time.formatMsToLocal(note.todo_due) : _('Set alarm'),
iconName: 'fa-clock-o',
enabled: !note.todo_completed,
onClick: () => { return this.commandSetAlarm(); },
});
}
const toolbar = <Toolbar
style={toolbarStyle}
items={toolbarItems}
/>
const titleEditor = <input
type="text"
style={titleEditorStyle}
@@ -485,6 +581,7 @@ class NoteTextComponent extends React.Component {
{ titleEditor }
{ titleBarMenuButton }
</div>
{ toolbar }
{ editor }
{ viewer }
</div>
@@ -495,7 +592,7 @@ class NoteTextComponent extends React.Component {
const mapStateToProps = (state) => {
return {
noteId: state.selectedNoteId,
noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
folderId: state.selectedFolderId,
itemType: state.selectedItemType,
folders: state.folders,

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