You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-08 23:07:32 +02:00
Compare commits
218 Commits
android-v1
...
android-v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85219a6004 | ||
|
|
e4a7851e57 | ||
|
|
b7529b40b5 | ||
|
|
74827e5324 | ||
|
|
2e16cc5433 | ||
|
|
7f41bc5703 | ||
|
|
a2380fb752 | ||
|
|
f6a902809d | ||
|
|
33a853397d | ||
|
|
4f02481899 | ||
|
|
b18076565f | ||
|
|
853ddc5840 | ||
|
|
7930ab66c6 | ||
|
|
c7716c0d59 | ||
|
|
49cbb254d0 | ||
|
|
cf9246796d | ||
|
|
e1dee546dc | ||
|
|
da6fdad2de | ||
|
|
567596643c | ||
|
|
cb617e1b14 | ||
|
|
facf8afa8b | ||
|
|
f0dd61a711 | ||
|
|
e958211a13 | ||
|
|
0ed170b5bc | ||
|
|
473d3453a2 | ||
|
|
fa9d7b0408 | ||
|
|
d4a28f48c9 | ||
|
|
ead6fff861 | ||
|
|
c7d06b35cd | ||
|
|
fa939e5c76 | ||
|
|
1bf2601f4f | ||
|
|
feb0c02c9a | ||
|
|
40a34a7c05 | ||
|
|
c62dcd96b0 | ||
|
|
1364d6786d | ||
|
|
a6a351e68d | ||
|
|
1db38a9699 | ||
|
|
c57db1834f | ||
|
|
3aeb49b469 | ||
|
|
80b467eead | ||
|
|
61572f287a | ||
|
|
0e545baf10 | ||
|
|
e65e647359 | ||
|
|
238268884e | ||
|
|
4c210d0956 | ||
|
|
5f32c6466a | ||
|
|
71bd39a8a3 | ||
|
|
ffb660f0f4 | ||
|
|
dde23632c1 | ||
|
|
9d26f13db0 | ||
|
|
2a4c9c4427 | ||
|
|
3bfde26b74 | ||
|
|
a419bc7253 | ||
|
|
89e0dad88b | ||
|
|
ff1ee1249b | ||
|
|
ba9cfd8041 | ||
|
|
80a51e02a4 | ||
|
|
a2e2a9a2f5 | ||
|
|
49e4c37cac | ||
|
|
11d323d8b7 | ||
|
|
784ba45f1f | ||
|
|
e534414874 | ||
|
|
01f4faf8f1 | ||
|
|
b33d30ca47 | ||
|
|
1ba3fae101 | ||
|
|
9550347e04 | ||
|
|
398946d39a | ||
|
|
05faf55e8d | ||
|
|
4cf5525e20 | ||
|
|
62e91c44d7 | ||
|
|
e4ec4ae92b | ||
|
|
c1f5dfd9cc | ||
|
|
0c0efeac1f | ||
|
|
5e0f2642e3 | ||
|
|
93966b0fa1 | ||
|
|
e90abf3517 | ||
|
|
d3fa0dce96 | ||
|
|
58a7c2fa94 | ||
|
|
962a8700c2 | ||
|
|
b5c704e2bb | ||
|
|
e7b52b19d7 | ||
|
|
903c2e6d92 | ||
|
|
abcb1ac760 | ||
|
|
b6bf76cc4c | ||
|
|
2bf87655da | ||
|
|
d4b19f19a1 | ||
|
|
d8ccc38d5b | ||
|
|
577bef5704 | ||
|
|
4e3b8a06ea | ||
|
|
363632ffa7 | ||
|
|
994c99f47f | ||
|
|
96571baadc | ||
|
|
4ce2b2c948 | ||
|
|
5d69f7a0a7 | ||
|
|
bcb1f36ad8 | ||
|
|
34c65a686c | ||
|
|
0b32741a12 | ||
|
|
dbb321a3cc | ||
|
|
a6e4f47adf | ||
|
|
fb6dee32ac | ||
|
|
984dd6f2c0 | ||
|
|
02bde2c6e9 | ||
|
|
782d24cc04 | ||
|
|
4d0af575e5 | ||
|
|
be8bda8e73 | ||
|
|
1242de532e | ||
|
|
7d7ec7f15e | ||
|
|
ca112ec5d3 | ||
|
|
5deb8cf76d | ||
|
|
a2c9737c17 | ||
|
|
d3fca3d6cc | ||
|
|
d5574098f0 | ||
|
|
f5a683f25c | ||
|
|
5f04adb392 | ||
|
|
edd0f7e255 | ||
|
|
67145d9104 | ||
|
|
003e2afff7 | ||
|
|
6e9d70c5cb | ||
|
|
4821b4cdf2 | ||
|
|
734d4db431 | ||
|
|
317aaed0ac | ||
|
|
9778098d6c | ||
|
|
5b1755f988 | ||
|
|
2a772895dd | ||
|
|
5fbb01cf2f | ||
|
|
f9e0870b4e | ||
|
|
a58f1e9b4b | ||
|
|
6fc0d89b30 | ||
|
|
2dcadab7d2 | ||
|
|
bb3307e156 | ||
|
|
ecd07f1209 | ||
|
|
266cb1174f | ||
|
|
bfb9b77b6e | ||
|
|
01b1361dcb | ||
|
|
3a921720d6 | ||
|
|
cdfd3d9c31 | ||
|
|
9961fb64bb | ||
|
|
3137c355cf | ||
|
|
16abaf60d2 | ||
|
|
9004b710ea | ||
|
|
6ebac21c2b | ||
|
|
99f79faf83 | ||
|
|
613fa20806 | ||
|
|
1b5f812278 | ||
|
|
3a9643c1ea | ||
|
|
aee7f5a8ac | ||
|
|
d3cd378922 | ||
|
|
4f5e7367d0 | ||
|
|
2280fb5c43 | ||
|
|
96fb7c2087 | ||
|
|
6e994fd8b9 | ||
|
|
a7cde1e269 | ||
|
|
f8310ba0d5 | ||
|
|
b239c3faba | ||
|
|
3c2281dbf9 | ||
|
|
ac07bf784d | ||
|
|
067455542f | ||
|
|
5bfeaa357b | ||
|
|
fe27a64331 | ||
|
|
ed638612aa | ||
|
|
1d7ec83510 | ||
|
|
75c710232d | ||
|
|
5af52afadb | ||
|
|
0f4324c2f8 | ||
|
|
b48e1dac94 | ||
|
|
f0ca8e1e31 | ||
|
|
74b83eb71e | ||
|
|
28dce0fbb5 | ||
|
|
c12d402c7e | ||
|
|
014f5b123c | ||
|
|
58601dfc04 | ||
|
|
9fe7f0adae | ||
|
|
ea1374371f | ||
|
|
bce4294529 | ||
|
|
de409b632a | ||
|
|
a677b2e844 | ||
|
|
c63bb19cb6 | ||
|
|
72fd77812e | ||
|
|
40f3e72bd1 | ||
|
|
d6d86f2aff | ||
|
|
c71809438b | ||
|
|
3e6e1a0a36 | ||
|
|
f590ce4a34 | ||
|
|
67608e29c8 | ||
|
|
d5c2982093 | ||
|
|
90fad2a3ab | ||
|
|
bc7c82e3da | ||
|
|
cb824f7dd7 | ||
|
|
32c47a96f1 | ||
|
|
4e3f8893f7 | ||
|
|
ca3946689a | ||
|
|
e2ad2dfcaa | ||
|
|
d6f7893c56 | ||
|
|
8c65a7cc31 | ||
|
|
aabb9be7de | ||
|
|
544f93bf22 | ||
|
|
f81dbf4a4c | ||
|
|
fbec8263a3 | ||
|
|
68d77a69e6 | ||
|
|
f2ef2446c6 | ||
|
|
875cb5387a | ||
|
|
ae9ecdad40 | ||
|
|
86a0e34975 | ||
|
|
1141074745 | ||
|
|
efc46d9989 | ||
|
|
2b45f745b6 | ||
|
|
37fb81e9b2 | ||
|
|
255a4fac93 | ||
|
|
3e3fb88de8 | ||
|
|
e4cf03ae46 | ||
|
|
554a3eb10d | ||
|
|
61881b528a | ||
|
|
c2507cbc4e | ||
|
|
c1bb51c12b | ||
|
|
945018b698 | ||
|
|
df7b981e5e | ||
|
|
c9e130a771 | ||
|
|
f595be07d4 |
@@ -3,6 +3,14 @@ if: tag IS present
|
|||||||
|
|
||||||
rvm: 2.3.3
|
rvm: 2.3.3
|
||||||
|
|
||||||
|
# It's important to only build production branches otherwise Electron Builder
|
||||||
|
# might take assets from dev branches and overwrite those of production.
|
||||||
|
# https://docs.travis-ci.com/user/customizing-the-build/#Building-Specific-Branches
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
|
|||||||
62
Assets/JoplinLetter.svg
Normal file
62
Assets/JoplinLetter.svg
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="116.54575mm"
|
||||||
|
height="131.19589mm"
|
||||||
|
viewBox="0 0 116.54575 131.19589"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
|
||||||
|
sodipodi:docname="JoplinLetter.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.49497475"
|
||||||
|
inkscape:cx="152.11122"
|
||||||
|
inkscape:cy="-26.090631"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-2.7903623,-2.175533)">
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke-width:0.26458332"
|
||||||
|
d="m 43.790458,133.13317 c -8.32317,-1.11843 -12.937,-2.40956 -18.46857,-5.16822 -10.21924,-5.09644 -18.1023498,-13.95338 -21.1745998,-23.79038 -1.22214,-3.91319 -1.3607,-4.872332 -1.35685,-9.392712 0.003,-3.72804 0.0907,-4.66941 0.59927,-6.44569 1.0664,-3.7246 2.49409,-6.1704 5.19529,-8.90014 3.2574198,-3.29184 6.6565798,-4.77332 11.3929598,-4.96548 4.53189,-0.18388 7.54661,0.59927 10.40386,2.70266 1.82035,1.34007 3.67693,3.96421 4.71565,6.66525 0.65839,1.71204 0.70959,2.1839 0.90042,8.29756 0.19973,6.39855 0.36372,7.6318 1.39223,10.469902 1.40468,3.87611 3.78939,6.56189 7.33039,8.25588 3.20047,1.53108 5.63801,2.00183 9.60817,1.8556 2.58182,-0.0951 3.60332,-0.25442 5.15337,-0.80371 4.61358,-1.63493 8.46322,-5.31381 10.31326,-9.85579 1.91154,-4.693002 1.90785,-4.609372 1.90213,-43.127082 -0.005,-33.78395 -0.0106,-34.14337 -0.54484,-35.32188 -1.30698,-2.882895 -2.68223,-3.398165 -9.66971,-3.622945 l -5.12472,-0.16486 V 10.998334 2.175533 l 31.41927,0.06723 31.419272,0.06723 0.0697,8.755726 0.0697,8.755724 -5.09675,0.1793 c -2.82759,0.0995 -5.60596,0.33101 -6.24051,0.52006 -1.72896,0.5151 -2.82899,1.538795 -3.52569,3.281045 l -0.61059,1.5269 -0.16762,34.7927 c -0.16988,35.26321 -0.19381,36.08914 -1.18496,40.914372 -1.81292,8.82581 -8.301582,17.89221 -16.959672,23.69719 -6.95182,4.66099 -14.48972,7.21214 -24.82645,8.40235 -2.7431,0.31585 -14.57797,0.31433 -16.93333,-0.002 z"
|
||||||
|
id="path21"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.1 KiB |
6
BUILD.md
6
BUILD.md
@@ -37,8 +37,6 @@ 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`
|
If there's an error `while loading shared libraries: libgconf-2.so.4: cannot open shared object file: No such file or directory`, run `sudo apt-get install libgconf-2-4`
|
||||||
|
|
||||||
For node-gyp to work, you might need to install the `windows-build-tools` using `npm install --global windows-build-tools`.
|
|
||||||
|
|
||||||
That will create the executable file in the `dist` directory.
|
That will create the executable file in the `dist` directory.
|
||||||
|
|
||||||
From `/ElectronClient` you can also run `run.sh` to run the app for testing.
|
From `/ElectronClient` you can also run `run.sh` to run the app for testing.
|
||||||
@@ -54,6 +52,10 @@ npm install
|
|||||||
yarn dist
|
yarn dist
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If node-gyp does not works (MSBUILD: error MSB3428: Could not load the Visual C++ component "VCBuild.exe"), you might need to install the `windows-build-tools` using `npm install --global windows-build-tools`.
|
||||||
|
|
||||||
|
If `yarn dist` fails, it may need administrative rights.
|
||||||
|
|
||||||
# Building the Mobile application
|
# Building the Mobile application
|
||||||
|
|
||||||
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "Building Projects with Native Code" tab.
|
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "Building Projects with Native Code" tab.
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# User support
|
||||||
|
|
||||||
|
For general discussion about Joplin, user support, software development questions, and to discuss new features, please go to the [Joplin Forum](https://discourse.joplin.cozic.net/). It is possible to login with your GitHub account.
|
||||||
|
|
||||||
# Reporting a bug
|
# Reporting a bug
|
||||||
|
|
||||||
Please check first that it [has not already been reported](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue). Also consider [enabling debug mode](https://github.com/laurent22/joplin/blob/master/readme/debugging.md) before reporting the issue so that you can provide as much details as possible to help fix it.
|
Please check first that it [has not already been reported](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue). Also consider [enabling debug mode](https://github.com/laurent22/joplin/blob/master/readme/debugging.md) before reporting the issue so that you can provide as much details as possible to help fix it.
|
||||||
@@ -6,14 +10,10 @@ If possible, **please provide a screenshot**. A screenshot showing the problem i
|
|||||||
|
|
||||||
# Feature requests
|
# Feature requests
|
||||||
|
|
||||||
Again, please check that it has not already been requested. If it has, simply **up-vote the issue** - the ones with the most up-votes are likely to be implemented. Adding a "+1" comment does nothing.
|
Again, please check that it has not already been requested. If it has, simply **up-vote the issue** - the ones with the most up-votes are likely to be implemented. "+1" comments are not tracked.
|
||||||
|
|
||||||
# Adding new features
|
# Adding new features
|
||||||
|
|
||||||
If you want to add a new feature, consider asking about it before implementing it to make sure it is within the scope of the project. Of course you are free to create the pull request directly but it is not guaranteed it is going to be accepted.
|
If you want to add a new feature, consider asking about it before implementing it or checking existing discussions to make sure it is within the scope of the project. Of course you are free to create the pull request directly but it is not guaranteed it is going to be accepted.
|
||||||
|
|
||||||
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/master/BUILD.md) for more details.
|
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/master/BUILD.md) for more details.
|
||||||
|
|
||||||
# Coding style
|
|
||||||
|
|
||||||
See the [prettier config](https://github.com/laurent22/joplin/blob/master/prettier.config.js).
|
|
||||||
|
|||||||
3
CliClient/.gitignore
vendored
3
CliClient/.gitignore
vendored
@@ -18,4 +18,5 @@ tests/cli-integration/
|
|||||||
tests/sync
|
tests/sync
|
||||||
out.txt
|
out.txt
|
||||||
linkToLocal.sh
|
linkToLocal.sh
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
tests/support/dropbox-auth.txt
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
const { Logger } = require('lib/logger.js');
|
const { Logger } = require('lib/logger.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
|
const BaseItem = require('lib/models/BaseItem.js');
|
||||||
const Tag = require('lib/models/Tag.js');
|
const Tag = require('lib/models/Tag.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
@@ -9,6 +10,8 @@ const { reducer, defaultState } = require('lib/reducer.js');
|
|||||||
const { splitCommandString } = require('lib/string-utils.js');
|
const { splitCommandString } = require('lib/string-utils.js');
|
||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
|
const Entities = require('html-entities').AllHtmlEntities;
|
||||||
|
const htmlentities = (new Entities()).encode;
|
||||||
|
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const tk = require('terminal-kit');
|
const tk = require('terminal-kit');
|
||||||
@@ -638,12 +641,27 @@ class AppGui {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link.type === 'resource') {
|
if (link.type === 'item') {
|
||||||
const resourceId = link.id;
|
const itemId = link.id;
|
||||||
let resource = await Resource.load(resourceId);
|
let item = await BaseItem.loadItemById(itemId);
|
||||||
if (!resource) throw new Error('No resource with ID ' + resourceId); // Should be nearly impossible
|
if (!item) throw new Error('No item with ID ' + itemId); // Should be nearly impossible
|
||||||
if (resource.mime) response.setHeader('Content-Type', resource.mime);
|
|
||||||
response.write(await Resource.content(resource));
|
if (item.type_ === BaseModel.TYPE_RESOURCE) {
|
||||||
|
if (item.mime) response.setHeader('Content-Type', item.mime);
|
||||||
|
response.write(await Resource.content(item));
|
||||||
|
} else if (item.type_ === BaseModel.TYPE_NOTE) {
|
||||||
|
const html = [`
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="client-nojs" lang="en" dir="ltr">
|
||||||
|
<head><meta charset="UTF-8"/></head><body>
|
||||||
|
`];
|
||||||
|
html.push('<pre>' + htmlentities(item.title) + '\n\n' + htmlentities(item.body) + '</pre>');
|
||||||
|
html.push('</body></html>');
|
||||||
|
response.write(html.join(''));
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported item type: ' + item.type_);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,7 +677,7 @@ class AppGui {
|
|||||||
|
|
||||||
if (resourceIdRegex.test(url)) {
|
if (resourceIdRegex.test(url)) {
|
||||||
noteLinks[index] = {
|
noteLinks[index] = {
|
||||||
type: 'resource',
|
type: 'item',
|
||||||
id: url.substr(2),
|
id: url.substr(2),
|
||||||
};
|
};
|
||||||
} else if (hasProtocol(url, ['http', 'https', 'file', 'ftp'])) {
|
} else if (hasProtocol(url, ['http', 'https', 'file', 'ftp'])) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const { JoplinDatabase } = require('lib/joplin-database.js');
|
|||||||
const { Database } = require('lib/database.js');
|
const { Database } = require('lib/database.js');
|
||||||
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
|
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
|
||||||
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
|
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
|
||||||
|
const ResourceService = require('lib/services/ResourceService');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
const BaseItem = require('lib/models/BaseItem.js');
|
const BaseItem = require('lib/models/BaseItem.js');
|
||||||
@@ -412,6 +413,8 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
const tags = await Tag.allWithNotes();
|
const tags = await Tag.allWithNotes();
|
||||||
|
|
||||||
|
ResourceService.runInBackground();
|
||||||
|
|
||||||
this.dispatch({
|
this.dispatch({
|
||||||
type: 'TAG_UPDATE_ALL',
|
type: 'TAG_UPDATE_ALL',
|
||||||
items: tags,
|
items: tags,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ async function handleAutocompletionPromise(line) {
|
|||||||
if (next[0] === '-') {
|
if (next[0] === '-') {
|
||||||
for (let i = 0; i<metadata.options.length; i++) {
|
for (let i = 0; i<metadata.options.length; i++) {
|
||||||
const options = metadata.options[i][0].split(' ');
|
const options = metadata.options[i][0].split(' ');
|
||||||
//if there are multiple options then they will be seperated by comma and
|
//if there are multiple options then they will be separated by comma and
|
||||||
//space. The comma should be removed
|
//space. The comma should be removed
|
||||||
if (options[0][options[0].length - 1] === ',') {
|
if (options[0][options[0].length - 1] === ',') {
|
||||||
options[0] = options[0].slice(0, -1);
|
options[0] = options[0].slice(0, -1);
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ function getFooter() {
|
|||||||
|
|
||||||
output.push('WEBSITE');
|
output.push('WEBSITE');
|
||||||
output.push('');
|
output.push('');
|
||||||
output.push(INDENT + 'http://joplin.cozic.net');
|
output.push(INDENT + 'https://joplin.cozic.net');
|
||||||
|
|
||||||
output.push('');
|
output.push('');
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class Command extends BaseCommand {
|
|||||||
const stdoutWidth = app().commandStdoutMaxWidth();
|
const stdoutWidth = app().commandStdoutMaxWidth();
|
||||||
|
|
||||||
if (args.command === 'shortcuts' || args.command === 'keymap') {
|
if (args.command === 'shortcuts' || args.command === 'keymap') {
|
||||||
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'http://joplin.cozic.net/terminal/#shortcuts'));
|
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'https://joplin.cozic.net/terminal/#shortcuts'));
|
||||||
this.stdout('');
|
this.stdout('');
|
||||||
|
|
||||||
if (app().gui().isDummy()) {
|
if (app().gui().isDummy()) {
|
||||||
@@ -72,11 +72,11 @@ class Command extends BaseCommand {
|
|||||||
this.stdout('');
|
this.stdout('');
|
||||||
this.stdout(commandNames.join(', '));
|
this.stdout(commandNames.join(', '));
|
||||||
this.stdout('');
|
this.stdout('');
|
||||||
this.stdout(_('In any command, a note or notebook can be refered to by title or ID, or 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.'));
|
this.stdout(_('In any command, a note or notebook can be referred to by title or ID, or 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.'));
|
||||||
this.stdout('');
|
this.stdout('');
|
||||||
this.stdout(_('To move from one pane to another, press Tab or Shift+Tab.'));
|
this.stdout(_('To move from one pane to another, press Tab or Shift+Tab.'));
|
||||||
this.stdout(_('Use the arrows and page up/down to scroll the lists and text areas (including this console).'));
|
this.stdout(_('Use the arrows and page up/down to scroll the lists and text areas (including this console).'));
|
||||||
this.stdout(_('To maximise/minimise the console, press "TC".'));
|
this.stdout(_('To maximise/minimise the console, press "tc".'));
|
||||||
this.stdout(_('To enter command line mode, press ":"'));
|
this.stdout(_('To enter command line mode, press ":"'));
|
||||||
this.stdout(_('To exit command line mode, press ESCAPE'));
|
this.stdout(_('To exit command line mode, press ESCAPE'));
|
||||||
this.stdout(_('For the list of keyboard shortcuts and config options, type `help keymap`'));
|
this.stdout(_('For the list of keyboard shortcuts and config options, type `help keymap`'));
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, pattern);
|
const folder = await app().loadItem(BaseModel.TYPE_FOLDER, pattern);
|
||||||
if (!folder) throw new Error(_('Cannot find "%s".', pattern));
|
if (!folder) throw new Error(_('Cannot find "%s".', pattern));
|
||||||
const ok = force ? true : await this.prompt(_('Delete notebook? All notes within this notebook will also be deleted.'), { booleanAnswerDefault: 'n' });
|
const ok = force ? true : await this.prompt(_('Delete notebook? All notes and sub-notebooks within this notebook will also be deleted.'), { booleanAnswerDefault: 'n' });
|
||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
|
|
||||||
await Folder.delete(folder.id);
|
await Folder.delete(folder.id);
|
||||||
|
|||||||
@@ -78,10 +78,26 @@ class Command extends BaseCommand {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (syncTargetMd.name === 'dropbox') { // Dropbox
|
||||||
|
const api = await syncTarget.api();
|
||||||
|
const loginUrl = api.loginUrl();
|
||||||
|
this.stdout(_('To allow Joplin to synchronise with Dropbox, please follow the steps below:'));
|
||||||
|
this.stdout(_('Step 1: Open this URL in your browser to authorise the application:'));
|
||||||
|
this.stdout(loginUrl);
|
||||||
|
const authCode = await this.prompt(_('Step 2: Enter the code provided by Dropbox:'), { type: 'string' });
|
||||||
|
if (!authCode) {
|
||||||
|
this.stdout(_('Authentication was not completed (did not receive an authentication token).'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api.execAuthToken(authCode);
|
||||||
|
Setting.setValue('sync.' + this.syncTargetId_ + '.auth', response.access_token);
|
||||||
|
api.setAuthToken(response.access_token);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stdout(_('Not authentified with %s. Please provide any missing credentials.', syncTarget.label()));
|
this.stdout(_('Not authentified with %s. Please provide any missing credentials.', syncTargetMd.label));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +116,7 @@ class Command extends BaseCommand {
|
|||||||
this.releaseLockFn_ = null;
|
this.releaseLockFn_ = null;
|
||||||
|
|
||||||
// Lock is unique per profile/database
|
// Lock is unique per profile/database
|
||||||
|
// TODO: use SQLite database to do lock?
|
||||||
const lockFilePath = require('os').tmpdir() + '/synclock_' + md5(escape(Setting.value('profileDir'))); // https://github.com/pvorb/node-md5/issues/41
|
const lockFilePath = require('os').tmpdir() + '/synclock_' + md5(escape(Setting.value('profileDir'))); // https://github.com/pvorb/node-md5/issues/41
|
||||||
if (!await fs.pathExists(lockFilePath)) await fs.writeFile(lockFilePath, 'synclock');
|
if (!await fs.pathExists(lockFilePath)) await fs.writeFile(lockFilePath, 'synclock');
|
||||||
|
|
||||||
@@ -130,7 +147,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
||||||
|
|
||||||
if (!syncTarget.isAuthenticated()) {
|
if (!await syncTarget.isAuthenticated()) {
|
||||||
app().gui().showConsole();
|
app().gui().showConsole();
|
||||||
app().gui().maximizeConsole();
|
app().gui().maximizeConsole();
|
||||||
|
|
||||||
@@ -197,7 +214,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const syncTarget = reg.syncTarget(syncTargetId);
|
const syncTarget = reg.syncTarget(syncTargetId);
|
||||||
|
|
||||||
if (syncTarget.isAuthenticated()) {
|
if (await syncTarget.isAuthenticated()) {
|
||||||
const sync = await syncTarget.synchronizer();
|
const sync = await syncTarget.synchronizer();
|
||||||
if (sync) await sync.cancel();
|
if (sync) await sync.cancel();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -18,19 +18,20 @@ class FolderListWidget extends ListWidget {
|
|||||||
this.notesParentType_ = 'Folder';
|
this.notesParentType_ = 'Folder';
|
||||||
this.updateIndexFromSelectedFolderId_ = false;
|
this.updateIndexFromSelectedFolderId_ = false;
|
||||||
this.updateItems_ = false;
|
this.updateItems_ = false;
|
||||||
|
this.trimItemTitle = false;
|
||||||
|
|
||||||
this.itemRenderer = (item) => {
|
this.itemRenderer = (item) => {
|
||||||
let output = [];
|
let output = [];
|
||||||
if (item === '-') {
|
if (item === '-') {
|
||||||
output.push('-'.repeat(this.innerWidth));
|
output.push('-'.repeat(this.innerWidth));
|
||||||
} else if (item.type_ === Folder.modelType()) {
|
} else if (item.type_ === Folder.modelType()) {
|
||||||
output.push(Folder.displayTitle(item));
|
output.push(' '.repeat(this.folderDepth(this.folders, item.id)) + Folder.displayTitle(item));
|
||||||
} else if (item.type_ === Tag.modelType()) {
|
} else if (item.type_ === Tag.modelType()) {
|
||||||
output.push('[' + Folder.displayTitle(item) + ']');
|
output.push('[' + Folder.displayTitle(item) + ']');
|
||||||
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
|
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
|
||||||
output.push(_('Search:'));
|
output.push(_('Search:'));
|
||||||
output.push(item.title);
|
output.push(item.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (item && item.id) output.push(item.id.substr(0, 5));
|
// if (item && item.id) output.push(item.id.substr(0, 5));
|
||||||
|
|
||||||
@@ -38,6 +39,17 @@ class FolderListWidget extends ListWidget {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
folderDepth(folders, folderId) {
|
||||||
|
let output = 0;
|
||||||
|
while (true) {
|
||||||
|
const folder = BaseModel.byId(folders, folderId);
|
||||||
|
if (!folder.parent_id) return output;
|
||||||
|
output++;
|
||||||
|
folderId = folder.parent_id;
|
||||||
|
}
|
||||||
|
throw new Error('unreachable');
|
||||||
|
}
|
||||||
|
|
||||||
get selectedFolderId() {
|
get selectedFolderId() {
|
||||||
return this.selectedFolderId_;
|
return this.selectedFolderId_;
|
||||||
}
|
}
|
||||||
|
|||||||
1436
CliClient/locales/cs_CZ.po
Normal file
1436
CliClient/locales/cs_CZ.po
Normal file
File diff suppressed because it is too large
Load Diff
1452
CliClient/locales/da_DK.po
Normal file
1452
CliClient/locales/da_DK.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,13 +7,13 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Joplin-CLI 1.0.0\n"
|
"Project-Id-Version: Joplin-CLI 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"Last-Translator: Tobias Strobel <git@strobeltobias.de>\n"
|
"Last-Translator: Philipp Zumstein <zuphilip@gmail.com>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: de_DE\n"
|
"Language: de_DE\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: Poedit 2.0.6\n"
|
"X-Generator: Poedit 2.0.7\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
msgid "To delete a tag, untag the associated notes."
|
msgid "To delete a tag, untag the associated notes."
|
||||||
@@ -38,7 +38,7 @@ msgid "No notebook selected."
|
|||||||
msgstr "Kein Notizbuch ausgewählt."
|
msgstr "Kein Notizbuch ausgewählt."
|
||||||
|
|
||||||
msgid "No notebook has been specified."
|
msgid "No notebook has been specified."
|
||||||
msgstr "Kein Notizbuch wurde ausgewählt."
|
msgstr "Es wurde kein Notizbuch festgelegt."
|
||||||
|
|
||||||
msgid "Y"
|
msgid "Y"
|
||||||
msgstr "J"
|
msgstr "J"
|
||||||
@@ -238,7 +238,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "Mögliche Befehle lauten:"
|
msgstr "Mögliche Befehle lauten:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -259,8 +259,8 @@ msgstr ""
|
|||||||
"Benutze die Pfeiltasten und Bild hoch/runter um durch Listen und Texte zu "
|
"Benutze die Pfeiltasten und Bild hoch/runter um durch Listen und Texte zu "
|
||||||
"scrollen (inklusive diesem Terminal)."
|
"scrollen (inklusive diesem Terminal)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Um das Terminal zu maximieren/minimieren, drücke \"TC\"."
|
msgstr "Um das Terminal zu maximieren/minimieren, drücke \"tc\"."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
msgstr "Um den Kommandozeilen Modus aufzurufen, drücke \":\""
|
msgstr "Um den Kommandozeilen Modus aufzurufen, drücke \":\""
|
||||||
@@ -379,7 +379,10 @@ msgstr "Löscht das ausgewählte Notizbuch."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Löscht das Notizbuch, ohne nach einer Bestätigung zu fragen."
|
msgstr "Löscht das Notizbuch, ohne nach einer Bestätigung zu fragen."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Notizbuch wirklich löschen? Alle Notizen darin werden ebenfalls gelöscht."
|
"Notizbuch wirklich löschen? Alle Notizen darin werden ebenfalls gelöscht."
|
||||||
|
|
||||||
@@ -429,6 +432,18 @@ msgstr ""
|
|||||||
"Authentifizierung wurde nicht abgeschlossen (keinen Authentifizierung-Token "
|
"Authentifizierung wurde nicht abgeschlossen (keinen Authentifizierung-Token "
|
||||||
"erhalten)."
|
"erhalten)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
"Um Joplin die Synchronisation mit Dropbox zu ermöglichen, folge bitte den "
|
||||||
|
"folgenden Schritten:"
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr "Schritt 1: URL im Browser öffnen um die Anwendung zu autorisieren:"
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr "Schritt 2: Den von Dropbox bereitgestellten Code eingeben:"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -520,9 +535,8 @@ msgstr "Standard: %s"
|
|||||||
msgid "Possible keys/values:"
|
msgid "Possible keys/values:"
|
||||||
msgstr "Mögliche Werte:"
|
msgstr "Mögliche Werte:"
|
||||||
|
|
||||||
#, fuzzy
|
|
||||||
msgid "Type `joplin help` for usage information."
|
msgid "Type `joplin help` for usage information."
|
||||||
msgstr "Zeigt die Nutzungsstatistik an."
|
msgstr "Gib `joplin help` ein um die Nutzungsstatistik anzuzeigen."
|
||||||
|
|
||||||
msgid "Fatal error:"
|
msgid "Fatal error:"
|
||||||
msgstr "Schwerwiegender Fehler:"
|
msgstr "Schwerwiegender Fehler:"
|
||||||
@@ -530,7 +544,7 @@ msgstr "Schwerwiegender Fehler:"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"The application has been authorised - you may now close this browser tab."
|
"The application has been authorised - you may now close this browser tab."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Das Programm wurde autorisiert - Du kannst diesen Browsertab nun schließen."
|
"Das Programm wurde autorisiert - du kannst diesen Browsertab nun schließen."
|
||||||
|
|
||||||
msgid "The application has been successfully authorised."
|
msgid "The application has been successfully authorised."
|
||||||
msgstr "Das Programm wurde erfolgreich autorisiert."
|
msgstr "Das Programm wurde erfolgreich autorisiert."
|
||||||
@@ -586,9 +600,8 @@ msgstr "Exportiere „%s“ ins „%s“ Format. Bitte warten..."
|
|||||||
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
|
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
|
||||||
msgstr "Importiere „%s“ ins „%s“ Format. Bitte warten…"
|
msgstr "Importiere „%s“ ins „%s“ Format. Bitte warten…"
|
||||||
|
|
||||||
#, fuzzy
|
|
||||||
msgid "PDF File"
|
msgid "PDF File"
|
||||||
msgstr "Datei"
|
msgstr "PDF-Datei"
|
||||||
|
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Datei"
|
msgstr "Datei"
|
||||||
@@ -609,7 +622,7 @@ msgid "Export"
|
|||||||
msgstr "Exportieren"
|
msgstr "Exportieren"
|
||||||
|
|
||||||
msgid "Print"
|
msgid "Print"
|
||||||
msgstr ""
|
msgstr "Drucken"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Hide %s"
|
msgid "Hide %s"
|
||||||
@@ -636,6 +649,9 @@ msgstr "Alle Notizen durchsuchen"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Ansicht"
|
msgstr "Ansicht"
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr "Seitenleiste ein/aus"
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr "Editor Layout umschalten"
|
msgstr "Editor Layout umschalten"
|
||||||
|
|
||||||
@@ -657,9 +673,8 @@ msgstr "Hilfe"
|
|||||||
msgid "Website and documentation"
|
msgid "Website and documentation"
|
||||||
msgstr "Webseite und Dokumentation"
|
msgstr "Webseite und Dokumentation"
|
||||||
|
|
||||||
#, fuzzy
|
|
||||||
msgid "Make a donation"
|
msgid "Make a donation"
|
||||||
msgstr "Webseite und Dokumentation"
|
msgstr "Spenden"
|
||||||
|
|
||||||
msgid "Check for updates..."
|
msgid "Check for updates..."
|
||||||
msgstr "Überprüfe auf Updates..."
|
msgstr "Überprüfe auf Updates..."
|
||||||
@@ -706,6 +721,9 @@ msgstr "Notizen und Einstellungen werden gespeichert in: %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr "Absenden"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -776,6 +794,13 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr "Die Master-Keas dieser IDs werden für die Verschlüsselung einiger ..."
|
msgstr "Die Master-Keas dieser IDs werden für die Verschlüsselung einiger ..."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
"Weitere Informationen zur Ende-zu-Ende-Verschlüsselung (E2EE) und Hinweise "
|
||||||
|
"zur Aktivierung findest du in der Dokumentation (auf Englisch):"
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
@@ -813,12 +838,12 @@ msgstr "Notizbuch umbenennen:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Alarm erstellen:"
|
msgstr "Alarm erstellen:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Suchen"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Layout"
|
msgstr "Layout"
|
||||||
|
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Suchen..."
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Manche Objekte können nicht synchronisiert werden."
|
msgstr "Manche Objekte können nicht synchronisiert werden."
|
||||||
|
|
||||||
@@ -837,6 +862,10 @@ msgstr "Markierungen hinzufügen oder entfernen"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Zwischen Notiz und To-Do Typ wechseln"
|
msgstr "Zwischen Notiz und To-Do Typ wechseln"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr "Markdown"
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Löschen"
|
msgstr "Löschen"
|
||||||
|
|
||||||
@@ -851,8 +880,8 @@ msgstr ""
|
|||||||
msgid ""
|
msgid ""
|
||||||
"There is currently no notebook. Create one by clicking on \"New notebook\"."
|
"There is currently no notebook. Create one by clicking on \"New notebook\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Momentan existieren noch keine Notizbücher. Erstelle eines, indem du auf den "
|
"Momentan existieren noch keine Notizbücher. Erstelle eines, indem du auf "
|
||||||
"(+) Knopf drückst."
|
"\"Neues Notizbuch\" drückst."
|
||||||
|
|
||||||
msgid "Open..."
|
msgid "Open..."
|
||||||
msgstr "Öffne..."
|
msgstr "Öffne..."
|
||||||
@@ -900,6 +929,9 @@ msgstr "Leeren"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "OneDrive Login"
|
msgstr "OneDrive Login"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr "Dropbox Anmeldung"
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Optionen"
|
msgstr "Optionen"
|
||||||
|
|
||||||
@@ -924,9 +956,6 @@ msgstr "Synchronisieren"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Notizbücher"
|
msgstr "Notizbücher"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Suchen"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bitte wähle aus, wohin der Synchronisations Status exportiert werden soll"
|
"Bitte wähle aus, wohin der Synchronisations Status exportiert werden soll"
|
||||||
@@ -939,6 +968,9 @@ msgstr "Nutzung: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Unbekanntes Argument: %s"
|
msgstr "Unbekanntes Argument: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr "Dropbox"
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Dateisystem"
|
msgstr "Dateisystem"
|
||||||
|
|
||||||
@@ -1017,8 +1049,8 @@ msgid "Fetched items: %d/%d."
|
|||||||
msgstr "Geladene Objekte: %d/%d."
|
msgstr "Geladene Objekte: %d/%d."
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Status: \"%s\"."
|
msgstr "Status: %s."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
msgstr "Abbrechen..."
|
msgstr "Abbrechen..."
|
||||||
@@ -1027,15 +1059,15 @@ msgstr "Abbrechen..."
|
|||||||
msgid "Completed: %s"
|
msgid "Completed: %s"
|
||||||
msgstr "Abgeschlossen: %s"
|
msgstr "Abgeschlossen: %s"
|
||||||
|
|
||||||
#, fuzzy, javascript-format
|
#, javascript-format
|
||||||
msgid "Last error: %s"
|
msgid "Last error: %s"
|
||||||
msgstr "Schwerwiegender Fehler:"
|
msgstr "Letzte Fehlermeldung: %s"
|
||||||
|
|
||||||
msgid "Idle"
|
msgid "Idle"
|
||||||
msgstr ""
|
msgstr "wartend"
|
||||||
|
|
||||||
msgid "In progress"
|
msgid "In progress"
|
||||||
msgstr ""
|
msgstr "In Bearbeitung"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Synchronisation is already in progress. State: %s"
|
msgid "Synchronisation is already in progress. State: %s"
|
||||||
@@ -1050,6 +1082,10 @@ msgstr "Verschlüsselte Objekte können nicht verändert werden"
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Konflikte"
|
msgstr "Konflikte"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Kann Notiz nicht zu Notizbuch \"%s\" verschieben"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Ein Notizbuch mit diesem Titel existiert bereits : \"%s\""
|
msgstr "Ein Notizbuch mit diesem Titel existiert bereits : \"%s\""
|
||||||
@@ -1129,6 +1165,9 @@ msgstr "Wenn eine neue Notiz erstellt wird:"
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr "Zeige Tray Icon"
|
msgstr "Zeige Tray Icon"
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr "Hinweis: Funktioniert nicht in allen Desktopumgebungen."
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr "Zoomstufe der Benutzeroberfläche"
|
msgstr "Zoomstufe der Benutzeroberfläche"
|
||||||
|
|
||||||
@@ -1257,7 +1296,7 @@ msgid ""
|
|||||||
"(which is displayed in brackets above)."
|
"(which is displayed in brackets above)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Diese Objekte verbleiben auf dem Gerät, werden aber nicht zum "
|
"Diese Objekte verbleiben auf dem Gerät, werden aber nicht zum "
|
||||||
"Synchronisationsziel hochgeladen. Um diese Objekte zu finden, suchen Sie "
|
"Synchronisationsziel hochgeladen. Um diese Objekte zu finden, suchst du "
|
||||||
"entweder nach dem Titel oder der ID (die oben in Klammern angezeigt wird)."
|
"entweder nach dem Titel oder der ID (die oben in Klammern angezeigt wird)."
|
||||||
|
|
||||||
msgid "Sync status (synced items / total items)"
|
msgid "Sync status (synced items / total items)"
|
||||||
@@ -1332,8 +1371,17 @@ msgstr "Bestätigen"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Synchronisation abbrechen"
|
msgstr "Synchronisation abbrechen"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr "Neue Markierungen:"
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr "Neue Markierungen eingeben oder aus der Liste auswählen"
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr "Website von Joplin"
|
||||||
|
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Mit Dropbox anmelden"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
@@ -1374,6 +1422,14 @@ msgstr "Änderungen speichern"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Änderungen verwerfen"
|
msgstr "Änderungen verwerfen"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Nicht unterstütztes Fotoformat: %s"
|
msgstr "Nicht unterstütztes Fotoformat: %s"
|
||||||
@@ -1405,6 +1461,9 @@ msgstr "Notizbuch löschen"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Mit OneDrive anmelden"
|
msgstr "Mit OneDrive anmelden"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Suchen"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1421,6 +1480,9 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Willkommen"
|
msgstr "Willkommen"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Suchen"
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
#~ "\n"
|
#~ "\n"
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -223,7 +223,7 @@ msgid ""
|
|||||||
"(including this console)."
|
"(including this console)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -332,7 +332,9 @@ msgstr ""
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Deletes the notes matching <note-pattern>."
|
msgid "Deletes the notes matching <note-pattern>."
|
||||||
@@ -372,6 +374,16 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -546,6 +558,9 @@ msgstr ""
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -615,6 +630,9 @@ msgstr ""
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -673,6 +691,11 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -708,10 +731,10 @@ msgstr ""
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Search"
|
msgid "Layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Search..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
@@ -732,6 +755,9 @@ msgstr ""
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -789,6 +815,9 @@ msgstr ""
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -813,9 +842,6 @@ msgstr ""
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -827,6 +853,9 @@ msgstr ""
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -897,7 +926,7 @@ msgid "Fetched items: %d/%d."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -930,6 +959,9 @@ msgstr ""
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1005,6 +1037,9 @@ msgstr ""
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1193,9 +1228,18 @@ msgstr ""
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1235,6 +1279,14 @@ msgstr ""
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1266,6 +1318,9 @@ msgstr ""
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "Los posibles comandos son:"
|
msgstr "Los posibles comandos son:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -250,8 +250,8 @@ msgstr ""
|
|||||||
"Para desplazar en las listas y areas de texto (incluyendo la consola) "
|
"Para desplazar en las listas y areas de texto (incluyendo la consola) "
|
||||||
"utilice las flechas y re pág/av pág."
|
"utilice las flechas y re pág/av pág."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Para maximizar/minimizar la consola, presione \"TC\"."
|
msgstr "Para maximizar/minimizar la consola, presione \"tc\"."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
msgstr "Para entrar a modo línea de comando, presione \":\""
|
msgstr "Para entrar a modo línea de comando, presione \":\""
|
||||||
@@ -368,7 +368,10 @@ msgstr "Elimina la libreta dada."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Elimina una libreta sin pedir confirmación."
|
msgstr "Elimina una libreta sin pedir confirmación."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"¿Desea eliminar la libreta? Todas las notas dentro de esta libreta también "
|
"¿Desea eliminar la libreta? Todas las notas dentro de esta libreta también "
|
||||||
"serán eliminadas."
|
"serán eliminadas."
|
||||||
@@ -416,6 +419,18 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr "Autenticación no completada (no se recibió token de autenticación)."
|
msgstr "Autenticación no completada (no se recibió token de autenticación)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
"Para permitir a Joplin sincronizar con Dropbox, por favor siga estos pasos:"
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
"Paso 1: Abra esta dirección en su navegador para autorizar a la aplicación:"
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr "Paso 2: Introduzca el código provisto por Dropbox:"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr "No autenticado con %s. Por favor provea las credenciales."
|
msgstr "No autenticado con %s. Por favor provea las credenciales."
|
||||||
@@ -620,6 +635,9 @@ msgstr "Buscar en todas las notas"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Ver"
|
msgstr "Ver"
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr "Cambia la barra lateral"
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr "Cambia el diseño del editor"
|
msgstr "Cambia el diseño del editor"
|
||||||
|
|
||||||
@@ -689,6 +707,9 @@ msgstr "Las notas y los ajustes se guardan en: %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Guardar"
|
msgstr "Guardar"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr "Aceptar"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -760,6 +781,13 @@ msgstr ""
|
|||||||
"elementos, pero la apliación no tiene acceso a ellas. Serán descargadas a "
|
"elementos, pero la apliación no tiene acceso a ellas. Serán descargadas a "
|
||||||
"través de la sincronización."
|
"través de la sincronización."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
"Para más información acerca del cifrado extremo a extremo (E2EE) y "
|
||||||
|
"advertencias de como habilitarlo por favor revise la documentación:"
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Estado"
|
msgstr "Estado"
|
||||||
|
|
||||||
@@ -795,12 +823,12 @@ msgstr "Renombrar libreta:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Ajustar alarma:"
|
msgstr "Ajustar alarma:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Buscar"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Diseño"
|
msgstr "Diseño"
|
||||||
|
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Buscar..."
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "No se han podido sincronizar algunos de los elementos."
|
msgstr "No se han podido sincronizar algunos de los elementos."
|
||||||
|
|
||||||
@@ -819,6 +847,9 @@ msgstr "Añadir o borrar etiquetas"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Cambiar entre nota y lista de tareas"
|
msgstr "Cambiar entre nota y lista de tareas"
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr "Copiar el enlace de Markdown"
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Eliminar"
|
msgstr "Eliminar"
|
||||||
|
|
||||||
@@ -878,6 +909,9 @@ msgstr "Limpiar"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "Inicio de sesión de OneDrive"
|
msgstr "Inicio de sesión de OneDrive"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr "Inicio de sesión de Dropbox"
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Opciones"
|
msgstr "Opciones"
|
||||||
|
|
||||||
@@ -902,9 +936,6 @@ msgstr "Sincronizar"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Libretas"
|
msgstr "Libretas"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Búsquedas"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr "Seleccione a dónde se debería exportar el estado de sincronización"
|
msgstr "Seleccione a dónde se debería exportar el estado de sincronización"
|
||||||
|
|
||||||
@@ -916,6 +947,9 @@ msgstr "Uso: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Etiqueta desconocida: %s"
|
msgstr "Etiqueta desconocida: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr "Dropbox"
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Sistema de archivos"
|
msgstr "Sistema de archivos"
|
||||||
|
|
||||||
@@ -994,7 +1028,7 @@ msgid "Fetched items: %d/%d."
|
|||||||
msgstr "Elementos obtenidos: %d/%d."
|
msgstr "Elementos obtenidos: %d/%d."
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Estado: «%s»."
|
msgstr "Estado: «%s»."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1027,6 +1061,10 @@ msgstr "Los elementos cifrados no pueden ser modificados"
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Conflictos"
|
msgstr "Conflictos"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "No se ha podido mover la nota a la libreta «%s»"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Ya existe una libreta con este nombre: «%s»"
|
msgstr "Ya existe una libreta con este nombre: «%s»"
|
||||||
@@ -1105,6 +1143,9 @@ msgstr "Cuando se crear una nota nueva:"
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr "Mostrar icono en la bandeja"
|
msgstr "Mostrar icono en la bandeja"
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr "Nota: No funciona en todos los entornos de escritorio."
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr "Establecer el porcentaje de aumento de la aplicación"
|
msgstr "Establecer el porcentaje de aumento de la aplicación"
|
||||||
|
|
||||||
@@ -1305,9 +1346,18 @@ msgstr "Confirmar"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Cancelar sincronización"
|
msgstr "Cancelar sincronización"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr "Nuevas etiquetas:"
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr "Escriba nuevas etiquetas o seleccionelas de la lista"
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr "Sitio web de Joplin"
|
msgstr "Sitio web de Joplin"
|
||||||
|
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Acceder con Dropbox"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr "Clave maestra %s"
|
msgstr "Clave maestra %s"
|
||||||
@@ -1347,6 +1397,15 @@ msgstr "Guardar cambios"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Descartar cambios"
|
msgstr "Descartar cambios"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr "No hay elementos con el ID %s"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
"La aplicación móvil de Joplin no soporta actualmente este tipo de enlace: %s"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Tipo de imagen no soportado: %s"
|
msgstr "Tipo de imagen no soportado: %s"
|
||||||
@@ -1378,6 +1437,9 @@ msgstr "Borrar libreta"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Acceder con OneDrive"
|
msgstr "Acceder con OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Buscar"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1392,6 +1454,16 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Bienvenido"
|
msgstr "Bienvenido"
|
||||||
|
|
||||||
|
#~ msgid ""
|
||||||
|
#~ "For more information about End-To-End Encryption (E2EE) and advices on "
|
||||||
|
#~ "how to enable it please check the documentation"
|
||||||
|
#~ msgstr ""
|
||||||
|
#~ "Para más información acerca del cifrado extremo a extremo (E2EE) y "
|
||||||
|
#~ "advertencias de como habilitarlo por favor revise la documentación"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Búsquedas"
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
#~ "\n"
|
#~ "\n"
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "Litezkeen komandoak hauek dira:"
|
msgstr "Litezkeen komandoak hauek dira:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -246,7 +246,8 @@ msgstr ""
|
|||||||
"Erabili geziak edo page up/down list eta testu guneen artean aldatzeko "
|
"Erabili geziak edo page up/down list eta testu guneen artean aldatzeko "
|
||||||
"(kontsola hau ere kontuan izanda)."
|
"(kontsola hau ere kontuan izanda)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
#, fuzzy
|
||||||
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Kontsola maximizatu edo minimizatzeko, saka \"TC\" ."
|
msgstr "Kontsola maximizatu edo minimizatzeko, saka \"TC\" ."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -367,7 +368,10 @@ msgstr "Ezabatu emandako koadernoak."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Ezabatu koadernoak berrespenik gabe."
|
msgstr "Ezabatu koadernoak berrespenik gabe."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr "Koadernoa ezabatu? Dituen ohar guztiak ere ezabatuko dira."
|
msgstr "Koadernoa ezabatu? Dituen ohar guztiak ere ezabatuko dira."
|
||||||
|
|
||||||
msgid "Deletes the notes matching <note-pattern>."
|
msgid "Deletes the notes matching <note-pattern>."
|
||||||
@@ -414,6 +418,16 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr "Autentifikazioa ez da egin osorik (ez du token-ik hartu)."
|
msgstr "Autentifikazioa ez da egin osorik (ez du token-ik hartu)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr "Ez da autentifikatu %s -rekin. Eman galdutako kredentzialak."
|
msgstr "Ez da autentifikatu %s -rekin. Eman galdutako kredentzialak."
|
||||||
@@ -619,6 +633,9 @@ msgstr "Bilatu ohar guztietan"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -691,6 +708,9 @@ msgstr "Oharrak eta ezarpenak hemen daude gordeta: %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Gorde"
|
msgstr "Gorde"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -761,6 +781,11 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Egoera"
|
msgstr "Egoera"
|
||||||
|
|
||||||
@@ -798,12 +823,13 @@ msgstr "Berrizendatu koadernoa:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Ezarri alarma:"
|
msgstr "Ezarri alarma:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Bilatu"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Diseinua"
|
msgstr "Diseinua"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Bilatu"
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Zenbait item ezin dira sinkronizatu."
|
msgstr "Zenbait item ezin dira sinkronizatu."
|
||||||
|
|
||||||
@@ -822,6 +848,9 @@ msgstr "Gehitu edo ezabatu etiketak"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Aldatu oharra eta zeregin eren artean."
|
msgstr "Aldatu oharra eta zeregin eren artean."
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Ezabatu"
|
msgstr "Ezabatu"
|
||||||
|
|
||||||
@@ -883,6 +912,9 @@ msgstr "Garbitu"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "Logeatu OneDriven"
|
msgstr "Logeatu OneDriven"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Aukerak"
|
msgstr "Aukerak"
|
||||||
|
|
||||||
@@ -907,9 +939,6 @@ msgstr "Sinkronizatu"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Koadernoak"
|
msgstr "Koadernoak"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Bilaketak"
|
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr "Aukeratu nora esportatu sinkronizazioaren egoera, mesedez"
|
msgstr "Aukeratu nora esportatu sinkronizazioaren egoera, mesedez"
|
||||||
@@ -922,6 +951,9 @@ msgstr "Erabili: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Marka ezezaguna: %s"
|
msgstr "Marka ezezaguna: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Fitxategi sistema"
|
msgstr "Fitxategi sistema"
|
||||||
|
|
||||||
@@ -1000,8 +1032,8 @@ msgstr "Urruneko itemak ezabatuta: %d."
|
|||||||
msgid "Fetched items: %d/%d."
|
msgid "Fetched items: %d/%d."
|
||||||
msgstr "Itemak eskuratuta: %d%d."
|
msgstr "Itemak eskuratuta: %d%d."
|
||||||
|
|
||||||
#, javascript-format
|
#, fuzzy, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Egoera: \"%s\"."
|
msgstr "Egoera: \"%s\"."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1034,6 +1066,10 @@ msgstr "Zifratutako itemak ezin aldatu daitezke"
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Gatazkak"
|
msgstr "Gatazkak"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Ezin eraman daiteke oharra \"%s\" koadernora"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Dagoeneko bada koaderno bat izen horrekin: \"%s\""
|
msgstr "Dagoeneko bada koaderno bat izen horrekin: \"%s\""
|
||||||
@@ -1116,6 +1152,9 @@ msgstr "Ohar berria sortzen du."
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr "Ezarri aplikazioaren zoomaren ehunekoa"
|
msgstr "Ezarri aplikazioaren zoomaren ehunekoa"
|
||||||
@@ -1317,9 +1356,19 @@ msgstr "Baieztatu"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Sinkronizazioa utzi"
|
msgstr "Sinkronizazioa utzi"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Login with OneDrive"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr "Pasahitz Nagusia %s"
|
msgstr "Pasahitz Nagusia %s"
|
||||||
@@ -1359,6 +1408,14 @@ msgstr "Gorde aldaketak"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Bertan behera utzi aldaketak"
|
msgstr "Bertan behera utzi aldaketak"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Irudi formatua ez onartua: %s"
|
msgstr "Irudi formatua ez onartua: %s"
|
||||||
@@ -1390,6 +1447,9 @@ msgstr "Ezabatu koadernoa"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Login with OneDrive"
|
msgstr "Login with OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Bilatu"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1403,6 +1463,9 @@ msgstr "Oraindik ez duzu koadernorik. Sortu bat (+) botoian sakatuta."
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Ongi etorri!"
|
msgstr "Ongi etorri!"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Bilaketak"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: Poedit 2.0.3\n"
|
"X-Generator: Poedit 2.0.3\n"
|
||||||
|
"POT-Creation-Date: \n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
|
||||||
msgid "To delete a tag, untag the associated notes."
|
msgid "To delete a tag, untag the associated notes."
|
||||||
msgstr "Pour supprimer une vignette, enlever là des notes associées."
|
msgstr "Pour supprimer une vignette, enlever là des notes associées."
|
||||||
@@ -229,7 +231,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "Les commandes possibles sont :"
|
msgstr "Les commandes possibles sont :"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -248,8 +250,8 @@ msgstr ""
|
|||||||
"Utilisez les touches fléchées et page précédente/suivante pour faire défiler "
|
"Utilisez les touches fléchées et page précédente/suivante pour faire défiler "
|
||||||
"les listes et zones de texte (y compris cette console)."
|
"les listes et zones de texte (y compris cette console)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Pour maximiser ou minimiser la console, pressez \"TC\"."
|
msgstr "Pour maximiser ou minimiser la console, pressez \"tc\"."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
msgstr "Pour démarrer le mode ligne de commande, pressez \":\""
|
msgstr "Pour démarrer le mode ligne de commande, pressez \":\""
|
||||||
@@ -365,10 +367,12 @@ msgstr "Supprimer le carnet."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Supprimer le carnet sans demander la confirmation."
|
msgstr "Supprimer le carnet sans demander la confirmation."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Effacer le carnet ? Toutes les notes dans ce carnet seront également "
|
"Effacer le carnet ? Toutes les notes et sous-carnets dans ce carnet seront "
|
||||||
"effacées."
|
"également effacés."
|
||||||
|
|
||||||
msgid "Deletes the notes matching <note-pattern>."
|
msgid "Deletes the notes matching <note-pattern>."
|
||||||
msgstr "Supprimer les notes correspondants à <note-pattern>."
|
msgstr "Supprimer les notes correspondants à <note-pattern>."
|
||||||
@@ -413,6 +417,20 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr "Impossible d'autoriser le logiciel (jeton d'identification non-reçu)."
|
msgstr "Impossible d'autoriser le logiciel (jeton d'identification non-reçu)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
"Pour permettre à Joplin de synchroniser avec Dropbox, veuillez suivre les "
|
||||||
|
"étapes ci-dessous :"
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
"Étape 1: Veuillez ouvrir cette URL dans votre navigateur internet pour "
|
||||||
|
"autoriser le logiciel :"
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr "Étape 2 : Entrez le code fourni par Dropbox :"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -617,6 +635,9 @@ msgstr "Chercher dans toutes les notes"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Affichage"
|
msgstr "Affichage"
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr "Basculer barre latérale"
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr "Basculer l'agencement de l'éditeur"
|
msgstr "Basculer l'agencement de l'éditeur"
|
||||||
|
|
||||||
@@ -687,6 +708,9 @@ msgstr "Les notes et paramètres se trouve dans : %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Enregistrer"
|
msgstr "Enregistrer"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr "Envoyer"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -760,6 +784,13 @@ msgstr ""
|
|||||||
"de vos objets, cependant le logiciel n'y a pour l'instant pas accès. Il est "
|
"de vos objets, cependant le logiciel n'y a pour l'instant pas accès. Il est "
|
||||||
"probable qu'elle vont être prochainement disponible via la synchronisation."
|
"probable qu'elle vont être prochainement disponible via la synchronisation."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
"Pour plus d'informations sur l'encryption de bout en bout, ainsi que des "
|
||||||
|
"conseils pour l'activer, veuillez consulter la documentation :"
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "État"
|
msgstr "État"
|
||||||
|
|
||||||
@@ -797,12 +828,12 @@ msgstr "Renommer le carnet :"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Régler alarme :"
|
msgstr "Régler alarme :"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Chercher"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Disposition"
|
msgstr "Disposition"
|
||||||
|
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Chercher..."
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Certains objets ne peuvent être synchronisés."
|
msgstr "Certains objets ne peuvent être synchronisés."
|
||||||
|
|
||||||
@@ -821,6 +852,9 @@ msgstr "Gérer les étiquettes"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Alterner entre note et tâche"
|
msgstr "Alterner entre note et tâche"
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr "Copier lien Markdown"
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Supprimer"
|
msgstr "Supprimer"
|
||||||
|
|
||||||
@@ -883,6 +917,9 @@ msgstr "Supprimer"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "Connexion OneDrive"
|
msgstr "Connexion OneDrive"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr "Connection à Dropbox"
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Options"
|
msgstr "Options"
|
||||||
|
|
||||||
@@ -907,9 +944,6 @@ msgstr "Synchroniser"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Carnets"
|
msgstr "Carnets"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Recherches"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Veuillez sélectionner un répertoire ou exporter l'état de la synchronisation"
|
"Veuillez sélectionner un répertoire ou exporter l'état de la synchronisation"
|
||||||
@@ -922,6 +956,9 @@ msgstr "Utilisation : %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Paramètre inconnu : %s"
|
msgstr "Paramètre inconnu : %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr "Dropbox"
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Système de fichier"
|
msgstr "Système de fichier"
|
||||||
|
|
||||||
@@ -1000,8 +1037,8 @@ msgid "Fetched items: %d/%d."
|
|||||||
msgstr "Téléchargés : %d/%d."
|
msgstr "Téléchargés : %d/%d."
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "État : \"%s\"."
|
msgstr "État : %s."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
msgstr "Annulation..."
|
msgstr "Annulation..."
|
||||||
@@ -1033,6 +1070,9 @@ msgstr "Les objets cryptés ne peuvent être modifiés"
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Conflits"
|
msgstr "Conflits"
|
||||||
|
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Impossible de déplacer le carnet vers le carnet \"%s\""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Un carnet avec ce titre existe déjà : \"%s\""
|
msgstr "Un carnet avec ce titre existe déjà : \"%s\""
|
||||||
@@ -1110,6 +1150,9 @@ msgstr "Lors de la création d'une note :"
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr "Afficher icône dans la zone de notifications"
|
msgstr "Afficher icône dans la zone de notifications"
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr "Note : Ne fonctionne pas dans tous les environnements de bureau."
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr "Niveau de zoom"
|
msgstr "Niveau de zoom"
|
||||||
|
|
||||||
@@ -1312,9 +1355,18 @@ msgstr "Confirmer"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Annuler synchronisation"
|
msgstr "Annuler synchronisation"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr "Nouvelles étiquettes :"
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr "Entrez de nouvelles étiquettes ou sélectionnez de la liste"
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr "Site web de Joplin"
|
msgstr "Site web de Joplin"
|
||||||
|
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Se connecter à Dropbox"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr "Clef maître %s"
|
msgstr "Clef maître %s"
|
||||||
@@ -1354,6 +1406,15 @@ msgstr "Enregistrer les changements"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Ignorer les changements"
|
msgstr "Ignorer les changements"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr "Aucun objet avec identifiant %s"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
"L'application mobile Joplin ne gère pas pour l'instant ce type de lien : %s"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Type d'image non géré : %s"
|
msgstr "Type d'image non géré : %s"
|
||||||
@@ -1385,6 +1446,9 @@ msgstr "Supprimer le carnet"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Se connecter à OneDrive"
|
msgstr "Se connecter à OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Chercher"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1400,6 +1464,16 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Bienvenue"
|
msgstr "Bienvenue"
|
||||||
|
|
||||||
|
#~ msgid ""
|
||||||
|
#~ "For more information about End-To-End Encryption (E2EE) and advices on "
|
||||||
|
#~ "how to enable it please check the documentation"
|
||||||
|
#~ msgstr ""
|
||||||
|
#~ "Pour plus d'informations sur l'encryption de bout en bout, ainsi que des "
|
||||||
|
#~ "conseils pour l'activer, veuillez consulter la documentation"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Recherches"
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
#~ "\n"
|
#~ "\n"
|
||||||
@@ -1587,12 +1661,6 @@ msgstr "Bienvenue"
|
|||||||
#~ msgid "Done."
|
#~ msgid "Done."
|
||||||
#~ msgstr "Terminé."
|
#~ msgstr "Terminé."
|
||||||
|
|
||||||
#~ msgid ""
|
|
||||||
#~ "Please open this URL in your browser to authenticate the application:"
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "Veuillez ouvrir cette URL dans votre navigateur internet pour autoriser "
|
|
||||||
#~ "le logiciel :"
|
|
||||||
|
|
||||||
#~ msgid "Note does not exist."
|
#~ msgid "Note does not exist."
|
||||||
#~ msgstr "Cette note n'existe pas."
|
#~ msgstr "Cette note n'existe pas."
|
||||||
|
|
||||||
|
|||||||
1441
CliClient/locales/gl_ES.po
Normal file
1441
CliClient/locales/gl_ES.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -229,15 +229,11 @@ msgstr ""
|
|||||||
msgid "The possible commands are:"
|
msgid "The possible commands are:"
|
||||||
msgstr "Moguće naredbe su:"
|
msgstr "Moguće naredbe su:"
|
||||||
|
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
|
||||||
"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."
|
|
||||||
|
|
||||||
msgid "To move from one pane to another, press Tab or Shift+Tab."
|
msgid "To move from one pane to another, press Tab or Shift+Tab."
|
||||||
msgstr "Za prijelaz iz jednog okna u drugo, pritisni Tab ili Shift+Tab."
|
msgstr "Za prijelaz iz jednog okna u drugo, pritisni Tab ili Shift+Tab."
|
||||||
@@ -250,7 +246,8 @@ msgstr ""
|
|||||||
"Use the arrows and page up/down to scroll the lists and text areas "
|
"Use the arrows and page up/down to scroll the lists and text areas "
|
||||||
"(including this console)."
|
"(including this console)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
#, fuzzy
|
||||||
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Za maksimiziranje/minimiziranje konzole, pritisni \"TC\"."
|
msgstr "Za maksimiziranje/minimiziranje konzole, pritisni \"TC\"."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -371,7 +368,10 @@ msgstr "Briše datu bilježnicu."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Briše bilježnicu bez traženja potvrde."
|
msgstr "Briše bilježnicu bez traženja potvrde."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Obrisati bilježnicu? Sve bilješke u toj bilježnici će također biti obrisane."
|
"Obrisati bilježnicu? Sve bilješke u toj bilježnici će također biti obrisane."
|
||||||
|
|
||||||
@@ -420,6 +420,16 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Ovjera nije dovršena (nije dobivena potvrda ovjere - authentication token)."
|
"Ovjera nije dovršena (nije dobivena potvrda ovjere - authentication token)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -621,6 +631,9 @@ msgstr "Pretraži u svim bilješkama"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -694,6 +707,9 @@ msgstr "Bilješke i postavke su pohranjene u: %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Spremi"
|
msgstr "Spremi"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -752,6 +768,11 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
@@ -789,12 +810,13 @@ msgstr "Preimenuj bilježnicu:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Postavi upozorenje:"
|
msgstr "Postavi upozorenje:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Traži"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Izgled"
|
msgstr "Izgled"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Traži"
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Neke stavke se ne mogu sinkronizirati."
|
msgstr "Neke stavke se ne mogu sinkronizirati."
|
||||||
|
|
||||||
@@ -814,6 +836,9 @@ msgstr "Dodaj ili makni oznake"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Zamijeni bilješku i zadatak"
|
msgstr "Zamijeni bilješku i zadatak"
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Obriši"
|
msgstr "Obriši"
|
||||||
|
|
||||||
@@ -874,6 +899,9 @@ msgstr "Očisti"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "OneDrive Login"
|
msgstr "OneDrive Login"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Opcije"
|
msgstr "Opcije"
|
||||||
|
|
||||||
@@ -898,9 +926,6 @@ msgstr "Sinkroniziraj"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Bilježnice"
|
msgstr "Bilježnice"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Pretraživanja"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr "Odaberi lokaciju za izvoz statusa sinkronizacije"
|
msgstr "Odaberi lokaciju za izvoz statusa sinkronizacije"
|
||||||
|
|
||||||
@@ -912,6 +937,9 @@ msgstr "Korištenje: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Nepoznata zastavica: %s"
|
msgstr "Nepoznata zastavica: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Datotečni sustav"
|
msgstr "Datotečni sustav"
|
||||||
|
|
||||||
@@ -987,8 +1015,8 @@ msgstr "Obrisane udaljene stavke: %d."
|
|||||||
msgid "Fetched items: %d/%d."
|
msgid "Fetched items: %d/%d."
|
||||||
msgstr "Stvorene lokalne stavke: %d."
|
msgstr "Stvorene lokalne stavke: %d."
|
||||||
|
|
||||||
#, javascript-format
|
#, fuzzy, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Stanje: \"%s\"."
|
msgstr "Stanje: \"%s\"."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1022,6 +1050,10 @@ msgstr "Neke stavke se ne mogu sinkronizirati."
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Sukobi"
|
msgstr "Sukobi"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Ne mogu premjestiti bilješku u bilježnicu %s"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Bilježnica s ovim naslovom već postoji: \"%s\""
|
msgstr "Bilježnica s ovim naslovom već postoji: \"%s\""
|
||||||
@@ -1104,6 +1136,9 @@ msgstr "Stvara novu bilješku."
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1297,9 +1332,19 @@ msgstr "Potvrdi"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Prekini sinkronizaciju"
|
msgstr "Prekini sinkronizaciju"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Prijavi se u OneDrive"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1340,6 +1385,14 @@ msgstr "Spremi promjene"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Odbaci promjene"
|
msgstr "Odbaci promjene"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Nepodržana vrsta slike: %s"
|
msgstr "Nepodržana vrsta slike: %s"
|
||||||
@@ -1371,6 +1424,9 @@ msgstr "Obriši bilježnicu"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Prijavi se u OneDrive"
|
msgstr "Prijavi se u OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Traži"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1384,6 +1440,9 @@ msgstr "Trenutno nemaš nijednu bilježnicu. Stvori novu klikom na (+) gumb."
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Dobro došli"
|
msgstr "Dobro došli"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Pretraživanja"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "I possibili comandi sono:"
|
msgstr "I possibili comandi sono:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -245,7 +245,8 @@ msgstr ""
|
|||||||
"Usa le frecce e pagina su/giù per scorrere le liste e le aree di testo "
|
"Usa le frecce e pagina su/giù per scorrere le liste e le aree di testo "
|
||||||
"(compresa questa console)."
|
"(compresa questa console)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
#, fuzzy
|
||||||
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Per massimizzare/minimizzare la console, premi \"TC\"."
|
msgstr "Per massimizzare/minimizzare la console, premi \"TC\"."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -363,7 +364,9 @@ msgstr "Elimina il seguente blocco note."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Elimina il blocco note senza richiedere una conferma."
|
msgstr "Elimina il blocco note senza richiedere una conferma."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Deletes the notes matching <note-pattern>."
|
msgid "Deletes the notes matching <note-pattern>."
|
||||||
@@ -407,6 +410,16 @@ msgstr ""
|
|||||||
"Autenticazione non completata (non è stato ricevuto alcun token di "
|
"Autenticazione non completata (non è stato ricevuto alcun token di "
|
||||||
"autenticazione)."
|
"autenticazione)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -603,6 +616,9 @@ msgstr "Cerca in tutte le note"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -676,6 +692,9 @@ msgstr ""
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -736,6 +755,11 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Stato"
|
msgstr "Stato"
|
||||||
|
|
||||||
@@ -771,12 +795,13 @@ msgstr "Rinomina il blocco note:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Imposta allarme:"
|
msgstr "Imposta allarme:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Cerca"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Disposizione"
|
msgstr "Disposizione"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Cerca"
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Alcuni elementi non possono essere sincronizzati."
|
msgstr "Alcuni elementi non possono essere sincronizzati."
|
||||||
|
|
||||||
@@ -796,6 +821,9 @@ msgstr "Aggiungi o rimuovi etichetta"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Passa da un tipo di nota a un elenco di attività"
|
msgstr "Passa da un tipo di nota a un elenco di attività"
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Elimina"
|
msgstr "Elimina"
|
||||||
|
|
||||||
@@ -857,6 +885,9 @@ msgstr "Pulisci"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "Login OneDrive"
|
msgstr "Login OneDrive"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Opzioni"
|
msgstr "Opzioni"
|
||||||
|
|
||||||
@@ -881,9 +912,6 @@ msgstr "Sincronizza"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Blocchi note"
|
msgstr "Blocchi note"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Ricerche"
|
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr "Per favore seleziona la nota o il blocco note da eliminare."
|
msgstr "Per favore seleziona la nota o il blocco note da eliminare."
|
||||||
@@ -896,6 +924,9 @@ msgstr "Uso: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Etichetta sconosciuta: %s"
|
msgstr "Etichetta sconosciuta: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "File system"
|
msgstr "File system"
|
||||||
|
|
||||||
@@ -973,8 +1004,8 @@ msgstr "Elementi remoti eliminati: %d."
|
|||||||
msgid "Fetched items: %d/%d."
|
msgid "Fetched items: %d/%d."
|
||||||
msgstr "Elementi locali creati: %d."
|
msgstr "Elementi locali creati: %d."
|
||||||
|
|
||||||
#, javascript-format
|
#, fuzzy, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Stato: \"%s\"."
|
msgstr "Stato: \"%s\"."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1008,6 +1039,10 @@ msgstr "Alcuni elementi non possono essere sincronizzati."
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Conflitti"
|
msgstr "Conflitti"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Non posso spostare la nota nel blocco note \"%s\""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Esiste già un blocco note col titolo \"%s\""
|
msgstr "Esiste già un blocco note col titolo \"%s\""
|
||||||
@@ -1090,6 +1125,9 @@ msgstr "Crea una nuova nota."
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1283,9 +1321,19 @@ msgstr "Conferma"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Cancella la sincronizzazione"
|
msgstr "Cancella la sincronizzazione"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Accedi a OneDrive"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1326,6 +1374,14 @@ msgstr "Salva i cambiamenti"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Ignora modifiche"
|
msgstr "Ignora modifiche"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Tipo di immagine non supportata: %s"
|
msgstr "Tipo di immagine non supportata: %s"
|
||||||
@@ -1357,6 +1413,9 @@ msgstr "Cancella blocco note"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Accedi a OneDrive"
|
msgstr "Accedi a OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Cerca"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1372,6 +1431,9 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Benvenuto"
|
msgstr "Benvenuto"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Ricerche"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "有効なコマンドは:"
|
msgstr "有効なコマンドは:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -240,7 +240,8 @@ msgid ""
|
|||||||
"(including this console)."
|
"(including this console)."
|
||||||
msgstr "リストや入力エリアの移動には矢印キーまたはPage Up/Downを使用します。"
|
msgstr "リストや入力エリアの移動には矢印キーまたはPage Up/Downを使用します。"
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
#, fuzzy
|
||||||
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "コンソールの最大化・最小化には\"TC\"と入力してください。"
|
msgstr "コンソールの最大化・最小化には\"TC\"と入力してください。"
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -360,7 +361,10 @@ msgstr "指定されたノートブックを削除します。"
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "ノートブックを確認なしで削除します。"
|
msgstr "ノートブックを確認なしで削除します。"
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr "ノートブックを削除しますか?中にあるノートはすべて消えてしまいます。"
|
msgstr "ノートブックを削除しますか?中にあるノートはすべて消えてしまいます。"
|
||||||
|
|
||||||
msgid "Deletes the notes matching <note-pattern>."
|
msgid "Deletes the notes matching <note-pattern>."
|
||||||
@@ -404,6 +408,16 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr "認証は完了していません(認証トークンが得られませんでした)"
|
msgstr "認証は完了していません(認証トークンが得られませんでした)"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -604,6 +618,9 @@ msgstr "すべてのノートを検索"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -676,6 +693,9 @@ msgstr "ノートと設定は、%sに保存されます。"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "保存"
|
msgstr "保存"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -738,6 +758,11 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "状態"
|
msgstr "状態"
|
||||||
|
|
||||||
@@ -775,12 +800,13 @@ msgstr "ノートブックの名前を変更:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "アラームをセット:"
|
msgstr "アラームをセット:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "検索"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "レイアウト"
|
msgstr "レイアウト"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "検索"
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "いくつかの項目は同期されませんでした。"
|
msgstr "いくつかの項目は同期されませんでした。"
|
||||||
|
|
||||||
@@ -800,6 +826,9 @@ msgstr "タグの追加・削除"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "ノートとToDoを切り替え"
|
msgstr "ノートとToDoを切り替え"
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "削除"
|
msgstr "削除"
|
||||||
|
|
||||||
@@ -860,6 +889,9 @@ msgstr "クリア"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "OneDriveログイン"
|
msgstr "OneDriveログイン"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "オプション"
|
msgstr "オプション"
|
||||||
|
|
||||||
@@ -884,9 +916,6 @@ msgstr "同期"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "ノートブック"
|
msgstr "ノートブック"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "検索"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr "同期状況の出力先を選択してください"
|
msgstr "同期状況の出力先を選択してください"
|
||||||
|
|
||||||
@@ -898,6 +927,9 @@ msgstr "使用方法: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "不明なフラグ: %s"
|
msgstr "不明なフラグ: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "ファイルシステム"
|
msgstr "ファイルシステム"
|
||||||
|
|
||||||
@@ -975,8 +1007,8 @@ msgstr "リモートアイテムの削除: %d."
|
|||||||
msgid "Fetched items: %d/%d."
|
msgid "Fetched items: %d/%d."
|
||||||
msgstr "ローカルアイテムの作成: %d."
|
msgstr "ローカルアイテムの作成: %d."
|
||||||
|
|
||||||
#, javascript-format
|
#, fuzzy, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "状態: \"%s\"。"
|
msgstr "状態: \"%s\"。"
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1010,6 +1042,10 @@ msgstr "いくつかの項目は同期されませんでした。"
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "衝突"
|
msgstr "衝突"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "ノートをノートブック \"%s\"に移動できませんでした。"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "\"%s\"という名前のノートブックはすでに存在しています。"
|
msgstr "\"%s\"という名前のノートブックはすでに存在しています。"
|
||||||
@@ -1094,6 +1130,9 @@ msgstr "あたらしいノートを作成します。"
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1287,9 +1326,19 @@ msgstr "確認"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "同期の中止"
|
msgstr "同期の中止"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "OneDriveログイン"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1330,6 +1379,14 @@ msgstr "変更を保存"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "変更を破棄"
|
msgstr "変更を破棄"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "サポートされていないイメージ形式: %s."
|
msgstr "サポートされていないイメージ形式: %s."
|
||||||
@@ -1361,6 +1418,9 @@ msgstr "ノートブックを削除"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "OneDriveログイン"
|
msgstr "OneDriveログイン"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "検索"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1376,6 +1436,9 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "ようこそ"
|
msgstr "ようこそ"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "検索"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -223,7 +223,7 @@ msgid ""
|
|||||||
"(including this console)."
|
"(including this console)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -332,7 +332,9 @@ msgstr ""
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Deletes the notes matching <note-pattern>."
|
msgid "Deletes the notes matching <note-pattern>."
|
||||||
@@ -372,6 +374,16 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -546,6 +558,9 @@ msgstr ""
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -615,6 +630,9 @@ msgstr ""
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -673,6 +691,11 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -708,10 +731,10 @@ msgstr ""
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Search"
|
msgid "Layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Search..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
@@ -732,6 +755,9 @@ msgstr ""
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -789,6 +815,9 @@ msgstr ""
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -813,9 +842,6 @@ msgstr ""
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -827,6 +853,9 @@ msgstr ""
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -897,7 +926,7 @@ msgid "Fetched items: %d/%d."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -930,6 +959,9 @@ msgstr ""
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1005,6 +1037,9 @@ msgstr ""
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1193,9 +1228,18 @@ msgstr ""
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1235,6 +1279,14 @@ msgstr ""
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1266,6 +1318,9 @@ msgstr ""
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "Mogelijke commando's zijn:"
|
msgstr "Mogelijke commando's zijn:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -249,7 +249,8 @@ msgstr ""
|
|||||||
"Gebruik de pijltjes en page up/down om door de lijsten en de tekstvelden te "
|
"Gebruik de pijltjes en page up/down om door de lijsten en de tekstvelden te "
|
||||||
"scrollen (ook deze console)."
|
"scrollen (ook deze console)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
#, fuzzy
|
||||||
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Om de console te maximaliseren/minimaliseren, typ \"TC\"."
|
msgstr "Om de console te maximaliseren/minimaliseren, typ \"TC\"."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -368,7 +369,10 @@ msgstr "Verwijdert het opgegeven notitieboek."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Verwijdert het notitieboek zonder te vragen om bevestiging."
|
msgstr "Verwijdert het notitieboek zonder te vragen om bevestiging."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Notitieboek verwijderen? Alle notities in dit notitieboek zullen ook "
|
"Notitieboek verwijderen? Alle notities in dit notitieboek zullen ook "
|
||||||
"verwijderd worden."
|
"verwijderd worden."
|
||||||
@@ -415,6 +419,16 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr "Authenticatie was niet voltooid (geen authenticatietoken ontvangen)."
|
msgstr "Authenticatie was niet voltooid (geen authenticatietoken ontvangen)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -621,6 +635,9 @@ msgstr "Zoek in alle notities"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -693,6 +710,9 @@ msgstr "Notities en instellingen zijn opgeslaan in %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Sla op"
|
msgstr "Sla op"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -763,6 +783,11 @@ msgid ""
|
|||||||
"they will eventually be downloaded via synchronisation."
|
"they will eventually be downloaded via synchronisation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
@@ -800,12 +825,13 @@ msgstr "Hernoem notitieboek:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Stel melding in:"
|
msgstr "Stel melding in:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Zoeken"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Layout"
|
msgstr "Layout"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Zoeken"
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Sommige items kunnen niet gesynchroniseerd worden."
|
msgstr "Sommige items kunnen niet gesynchroniseerd worden."
|
||||||
|
|
||||||
@@ -824,6 +850,9 @@ msgstr "Voeg tag toe of verwijder tag"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Wissel tussen notitie en to-do type"
|
msgstr "Wissel tussen notitie en to-do type"
|
||||||
|
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Verwijderen"
|
msgstr "Verwijderen"
|
||||||
|
|
||||||
@@ -886,6 +915,9 @@ msgstr "Vrijmaken"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "OneDrive Login"
|
msgstr "OneDrive Login"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Opties"
|
msgstr "Opties"
|
||||||
|
|
||||||
@@ -910,9 +942,6 @@ msgstr "Synchroniseer"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Notitieboeken"
|
msgstr "Notitieboeken"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Zoekopdrachten"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr "Selecteer waar de synchronisatie status naar geëxporteerd moet worden"
|
msgstr "Selecteer waar de synchronisatie status naar geëxporteerd moet worden"
|
||||||
|
|
||||||
@@ -924,6 +953,9 @@ msgstr "Gebruik: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Onbekende optie: %s"
|
msgstr "Onbekende optie: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Bestandssysteem"
|
msgstr "Bestandssysteem"
|
||||||
|
|
||||||
@@ -1002,8 +1034,8 @@ msgstr "Verwijderde remote items: %d."
|
|||||||
msgid "Fetched items: %d/%d."
|
msgid "Fetched items: %d/%d."
|
||||||
msgstr "Opgehaalde items: %d/%d."
|
msgstr "Opgehaalde items: %d/%d."
|
||||||
|
|
||||||
#, javascript-format
|
#, fuzzy, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Status: \"%s\""
|
msgstr "Status: \"%s\""
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1036,6 +1068,10 @@ msgstr "Versleutelde items kunnen niet aangepast worden"
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Conflicten"
|
msgstr "Conflicten"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Kan notitie niet naar notitieboek \"%s\" verplaatsen."
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Er bestaat al een notitieboek met \"%s\" als titel"
|
msgstr "Er bestaat al een notitieboek met \"%s\" als titel"
|
||||||
@@ -1120,6 +1156,9 @@ msgstr "Maakt een nieuwe notitie aan."
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1319,9 +1358,19 @@ msgstr "Bevestig"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Annuleer synchronisatie"
|
msgstr "Annuleer synchronisatie"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Log in met OneDrive"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr "Hoofdsleutel: %s"
|
msgstr "Hoofdsleutel: %s"
|
||||||
@@ -1361,6 +1410,14 @@ msgstr "Sla wijzigingen op"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Verwijder wijzigingen"
|
msgstr "Verwijder wijzigingen"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Afbeeldingstype %s wordt niet ondersteund"
|
msgstr "Afbeeldingstype %s wordt niet ondersteund"
|
||||||
@@ -1392,6 +1449,9 @@ msgstr "Verwijder notitieboek"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Log in met OneDrive"
|
msgstr "Log in met OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Zoeken"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1407,6 +1467,9 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Welkom"
|
msgstr "Welkom"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Zoekopdrachten"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: Poedit 2.0.6\n"
|
"X-Generator: Poedit 2.0.7\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
|
||||||
msgid "To delete a tag, untag the associated notes."
|
msgid "To delete a tag, untag the associated notes."
|
||||||
@@ -227,7 +227,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "Os comandos possíveis são:"
|
msgstr "Os comandos possíveis são:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -246,7 +246,8 @@ msgstr ""
|
|||||||
"Use as setas e a Page Up/Page Down para rolar as listas e áreas de texto "
|
"Use as setas e a Page Up/Page Down para rolar as listas e áreas de texto "
|
||||||
"(incluindo este console)."
|
"(incluindo este console)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
#, fuzzy
|
||||||
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Para maximizar / minimizar o console, pressione \"TC\"."
|
msgstr "Para maximizar / minimizar o console, pressione \"TC\"."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -362,7 +363,10 @@ msgstr "Exclui o caderno informado."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Exclui o caderno sem pedir confirmação."
|
msgstr "Exclui o caderno sem pedir confirmação."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Excluir o caderno? Todas as notas deste caderno notebook também serão "
|
"Excluir o caderno? Todas as notas deste caderno notebook também serão "
|
||||||
"excluídas."
|
"excluídas."
|
||||||
@@ -411,6 +415,18 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"A autenticação não foi concluída (não recebeu um token de autenticação)."
|
"A autenticação não foi concluída (não recebeu um token de autenticação)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
"Para permitir o Joplin sincronizar com o Dropbox, por favor, execute os "
|
||||||
|
"seguintes passos:"
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr "Passo 1: Abra essa URL em seu navegador para autorizar:"
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr "Passo 2: Entre o código fornecido pelo Dropbox:"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -567,9 +583,8 @@ msgstr "Exportando para \"%s\" com o formato \"%s\". Por favor, aguarde..."
|
|||||||
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
|
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
|
||||||
msgstr "Importando de \"%s\" com o formato \"%s\". Por favor, aguarde..."
|
msgstr "Importando de \"%s\" com o formato \"%s\". Por favor, aguarde..."
|
||||||
|
|
||||||
#, fuzzy
|
|
||||||
msgid "PDF File"
|
msgid "PDF File"
|
||||||
msgstr "Arquivo"
|
msgstr "Arquivo PDF"
|
||||||
|
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Arquivo"
|
msgstr "Arquivo"
|
||||||
@@ -590,7 +605,7 @@ msgid "Export"
|
|||||||
msgstr "Exportar"
|
msgstr "Exportar"
|
||||||
|
|
||||||
msgid "Print"
|
msgid "Print"
|
||||||
msgstr ""
|
msgstr "Imprimir"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Hide %s"
|
msgid "Hide %s"
|
||||||
@@ -617,6 +632,9 @@ msgstr "Pesquisar em todas as notas"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Visualizar"
|
msgstr "Visualizar"
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr "Alternar layout do editor"
|
msgstr "Alternar layout do editor"
|
||||||
|
|
||||||
@@ -686,6 +704,9 @@ msgstr "Notas e configurações estão armazenadas em: %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Salvar"
|
msgstr "Salvar"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr "Enviar"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -757,6 +778,13 @@ msgstr ""
|
|||||||
"itens, contudo a aplicação atualmente não tem acesso a elas. Provavelmente, "
|
"itens, contudo a aplicação atualmente não tem acesso a elas. Provavelmente, "
|
||||||
"elas serão baixadas via sincronização."
|
"elas serão baixadas via sincronização."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
"Para mais informações sobre Encriptação ponto-a-ponto (E2EE) e recomendações "
|
||||||
|
"sobre como habilitar, favor verificar a documentação:"
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
@@ -793,12 +821,12 @@ msgstr "Renomear caderno:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Definir alarme:"
|
msgstr "Definir alarme:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Procurar"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Layout"
|
msgstr "Layout"
|
||||||
|
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Pesquisar..."
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Alguns itens não podem ser sincronizados."
|
msgstr "Alguns itens não podem ser sincronizados."
|
||||||
|
|
||||||
@@ -817,6 +845,10 @@ msgstr "Adicionar ou remover tags"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Alternar entre os tipos Nota e Tarefa"
|
msgstr "Alternar entre os tipos Nota e Tarefa"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr "Markdown"
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Excluir"
|
msgstr "Excluir"
|
||||||
|
|
||||||
@@ -876,6 +908,9 @@ msgstr "Limpar (clear)"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "Login no OneDrive"
|
msgstr "Login no OneDrive"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr "Login no Dropbox"
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Opções"
|
msgstr "Opções"
|
||||||
|
|
||||||
@@ -900,9 +935,6 @@ msgstr "Sincronizar"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Cadernos"
|
msgstr "Cadernos"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Pesquisas"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Favor selecionar o local para onde o status de sincronia deveria ser "
|
"Favor selecionar o local para onde o status de sincronia deveria ser "
|
||||||
@@ -916,6 +948,9 @@ msgstr "Uso: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Flag desconhecido: %s"
|
msgstr "Flag desconhecido: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr "Dropbox"
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Sistema de arquivos"
|
msgstr "Sistema de arquivos"
|
||||||
|
|
||||||
@@ -994,7 +1029,7 @@ msgid "Fetched items: %d/%d."
|
|||||||
msgstr "Itens pesquisados: %d/%d."
|
msgstr "Itens pesquisados: %d/%d."
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Estado: \"%s\"."
|
msgstr "Estado: \"%s\"."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1004,15 +1039,15 @@ msgstr "Cancelando..."
|
|||||||
msgid "Completed: %s"
|
msgid "Completed: %s"
|
||||||
msgstr "Completado: %s"
|
msgstr "Completado: %s"
|
||||||
|
|
||||||
#, fuzzy, javascript-format
|
#, javascript-format
|
||||||
msgid "Last error: %s"
|
msgid "Last error: %s"
|
||||||
msgstr "Erro fatal:"
|
msgstr "Último erro: %s"
|
||||||
|
|
||||||
msgid "Idle"
|
msgid "Idle"
|
||||||
msgstr ""
|
msgstr "Inativo"
|
||||||
|
|
||||||
msgid "In progress"
|
msgid "In progress"
|
||||||
msgstr ""
|
msgstr "Em andamento"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Synchronisation is already in progress. State: %s"
|
msgid "Synchronisation is already in progress. State: %s"
|
||||||
@@ -1027,6 +1062,10 @@ msgstr "Itens encriptados não podem ser modificados"
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Conflitos"
|
msgstr "Conflitos"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Não é possível mover a nota para o caderno \"%s\""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Já existe caderno com este título: \"%s\""
|
msgstr "Já existe caderno com este título: \"%s\""
|
||||||
@@ -1105,6 +1144,9 @@ msgstr "Quando criar uma nota nova:"
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr "Exibir tray icon"
|
msgstr "Exibir tray icon"
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr "Porcentagem global do zoom"
|
msgstr "Porcentagem global do zoom"
|
||||||
|
|
||||||
@@ -1305,9 +1347,18 @@ msgstr "Confirmar"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Cancelar sincronização"
|
msgstr "Cancelar sincronização"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr "Novas tags:"
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr "Digite novsa tags, ou selecione da lista"
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr "Site do Joplin"
|
msgstr "Site do Joplin"
|
||||||
|
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Login com Dropbox"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr "Chave Master %s"
|
msgstr "Chave Master %s"
|
||||||
@@ -1347,6 +1398,14 @@ msgstr "Gravar alterações"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Descartar alterações"
|
msgstr "Descartar alterações"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Tipo de imagem não suportada: %s"
|
msgstr "Tipo de imagem não suportada: %s"
|
||||||
@@ -1378,6 +1437,9 @@ msgstr "Excluir caderno"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Login com OneDrive"
|
msgstr "Login com OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Procurar"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1391,6 +1453,9 @@ msgstr "Você não possui cadernos. Crie um clicando no botão (+)."
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Bem-vindo"
|
msgstr "Bem-vindo"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Pesquisas"
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
#~ "\n"
|
#~ "\n"
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ msgid "The possible commands are:"
|
|||||||
msgstr "Доступные команды:"
|
msgstr "Доступные команды:"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"In any command, a note or notebook can be refered to by title or ID, or "
|
"In any command, a note or notebook can be referred to by title or ID, or "
|
||||||
"using the shortcuts `$n` or `$b` for, respectively, the currently selected "
|
"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."
|
"note or notebook. `$c` can be used to refer to the currently selected item."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -249,7 +249,8 @@ msgstr ""
|
|||||||
"Используйте стрелки и клавиши перелистывания страницы вверх/вниз для "
|
"Используйте стрелки и клавиши перелистывания страницы вверх/вниз для "
|
||||||
"прокрутки списков и текстовых областей (включая эту консоль)."
|
"прокрутки списков и текстовых областей (включая эту консоль)."
|
||||||
|
|
||||||
msgid "To maximise/minimise the console, press \"TC\"."
|
#, fuzzy
|
||||||
|
msgid "To maximise/minimise the console, press \"tc\"."
|
||||||
msgstr "Чтобы развернуть/свернуть консоль, нажимайте «TC»."
|
msgstr "Чтобы развернуть/свернуть консоль, нажимайте «TC»."
|
||||||
|
|
||||||
msgid "To enter command line mode, press \":\""
|
msgid "To enter command line mode, press \":\""
|
||||||
@@ -368,7 +369,10 @@ msgstr "Удаляет заданный блокнот."
|
|||||||
msgid "Deletes the notebook without asking for confirmation."
|
msgid "Deletes the notebook without asking for confirmation."
|
||||||
msgstr "Удаляет блокнот без запроса подтверждения."
|
msgstr "Удаляет блокнот без запроса подтверждения."
|
||||||
|
|
||||||
msgid "Delete notebook? All notes within this notebook will also be deleted."
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
"Delete notebook? All notes and sub-notebooks within this notebook will also "
|
||||||
|
"be deleted."
|
||||||
msgstr "Удалить блокнот? Все заметки в этом блокноте также будут удалены."
|
msgstr "Удалить блокнот? Все заметки в этом блокноте также будут удалены."
|
||||||
|
|
||||||
msgid "Deletes the notes matching <note-pattern>."
|
msgid "Deletes the notes matching <note-pattern>."
|
||||||
@@ -414,6 +418,16 @@ msgid ""
|
|||||||
"Authentication was not completed (did not receive an authentication token)."
|
"Authentication was not completed (did not receive an authentication token)."
|
||||||
msgstr "Аутентификация не была завершена (не получен токен аутентификации)."
|
msgstr "Аутентификация не была завершена (не получен токен аутентификации)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"To allow Joplin to synchronise with Dropbox, please follow the steps below:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 1: Open this URL in your browser to authorise the application:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Step 2: Enter the code provided by Dropbox:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Not authentified with %s. Please provide any missing credentials."
|
msgid "Not authentified with %s. Please provide any missing credentials."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -618,6 +632,9 @@ msgstr "Поиск во всех заметках"
|
|||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "Вид"
|
msgstr "Вид"
|
||||||
|
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle editor layout"
|
msgid "Toggle editor layout"
|
||||||
msgstr "Переключить вид редактора"
|
msgstr "Переключить вид редактора"
|
||||||
|
|
||||||
@@ -687,6 +704,9 @@ msgstr "Заметки и настройки сохранены в: %s"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Сохранить"
|
msgstr "Сохранить"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Disabling encryption means *all* your notes and attachments are going to be "
|
"Disabling encryption means *all* your notes and attachments are going to be "
|
||||||
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
|
||||||
@@ -760,6 +780,11 @@ msgstr ""
|
|||||||
"элементов, однако у приложения сейчас нет к ним доступа. Скорее всего, они "
|
"элементов, однако у приложения сейчас нет к ним доступа. Скорее всего, они "
|
||||||
"загрузятся при синхронизации."
|
"загрузятся при синхронизации."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"For more information about End-To-End Encryption (E2EE) and advices on how "
|
||||||
|
"to enable it please check the documentation:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Статус"
|
msgstr "Статус"
|
||||||
|
|
||||||
@@ -795,12 +820,13 @@ msgstr "Переименовать блокнот:"
|
|||||||
msgid "Set alarm:"
|
msgid "Set alarm:"
|
||||||
msgstr "Установить напоминание:"
|
msgstr "Установить напоминание:"
|
||||||
|
|
||||||
msgid "Search"
|
|
||||||
msgstr "Поиск"
|
|
||||||
|
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Вид"
|
msgstr "Вид"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Search..."
|
||||||
|
msgstr "Поиск"
|
||||||
|
|
||||||
msgid "Some items cannot be synchronised."
|
msgid "Some items cannot be synchronised."
|
||||||
msgstr "Некоторые элементы не могут быть синхронизированы."
|
msgstr "Некоторые элементы не могут быть синхронизированы."
|
||||||
|
|
||||||
@@ -819,6 +845,10 @@ msgstr "Добавить или удалить теги"
|
|||||||
msgid "Switch between note and to-do type"
|
msgid "Switch between note and to-do type"
|
||||||
msgstr "Переключить тип между заметкой и задачей"
|
msgstr "Переключить тип между заметкой и задачей"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Copy Markdown link"
|
||||||
|
msgstr "Markdown"
|
||||||
|
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Удалить"
|
msgstr "Удалить"
|
||||||
|
|
||||||
@@ -878,6 +908,9 @@ msgstr "Очистить"
|
|||||||
msgid "OneDrive Login"
|
msgid "OneDrive Login"
|
||||||
msgstr "Вход в OneDrive"
|
msgstr "Вход в OneDrive"
|
||||||
|
|
||||||
|
msgid "Dropbox Login"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Options"
|
msgid "Options"
|
||||||
msgstr "Настройки"
|
msgstr "Настройки"
|
||||||
|
|
||||||
@@ -902,9 +935,6 @@ msgstr "Синхронизировать"
|
|||||||
msgid "Notebooks"
|
msgid "Notebooks"
|
||||||
msgstr "Блокноты"
|
msgstr "Блокноты"
|
||||||
|
|
||||||
msgid "Searches"
|
|
||||||
msgstr "Запросы"
|
|
||||||
|
|
||||||
msgid "Please select where the sync status should be exported to"
|
msgid "Please select where the sync status should be exported to"
|
||||||
msgstr "Выберите, куда должен быть экспортирован статус синхронизации"
|
msgstr "Выберите, куда должен быть экспортирован статус синхронизации"
|
||||||
|
|
||||||
@@ -916,6 +946,9 @@ msgstr "Использование: %s"
|
|||||||
msgid "Unknown flag: %s"
|
msgid "Unknown flag: %s"
|
||||||
msgstr "Неизвестный флаг: %s"
|
msgstr "Неизвестный флаг: %s"
|
||||||
|
|
||||||
|
msgid "Dropbox"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "File system"
|
msgid "File system"
|
||||||
msgstr "Файловая система"
|
msgstr "Файловая система"
|
||||||
|
|
||||||
@@ -993,8 +1026,8 @@ msgstr "Удалено удалённых элементов: %d."
|
|||||||
msgid "Fetched items: %d/%d."
|
msgid "Fetched items: %d/%d."
|
||||||
msgstr "Получено элементов: %d/%d."
|
msgstr "Получено элементов: %d/%d."
|
||||||
|
|
||||||
#, javascript-format
|
#, fuzzy, javascript-format
|
||||||
msgid "State: \"%s\"."
|
msgid "State: %s."
|
||||||
msgstr "Статус: «%s»."
|
msgstr "Статус: «%s»."
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
@@ -1027,6 +1060,10 @@ msgstr "Зашифрованные элементы не могут быть и
|
|||||||
msgid "Conflicts"
|
msgid "Conflicts"
|
||||||
msgstr "Конфликты"
|
msgstr "Конфликты"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cannot move notebook to this location"
|
||||||
|
msgstr "Не удалось переместить заметку в блокнот «%s»"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A notebook with this title already exists: \"%s\""
|
msgid "A notebook with this title already exists: \"%s\""
|
||||||
msgstr "Блокнот с таким названием уже существует: «%s»"
|
msgstr "Блокнот с таким названием уже существует: «%s»"
|
||||||
@@ -1104,6 +1141,9 @@ msgstr "При создании новой заметки:"
|
|||||||
msgid "Show tray icon"
|
msgid "Show tray icon"
|
||||||
msgstr "Показывать иконку в панели задач"
|
msgstr "Показывать иконку в панели задач"
|
||||||
|
|
||||||
|
msgid "Note: Does not work in all desktop environments."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Global zoom percentage"
|
msgid "Global zoom percentage"
|
||||||
msgstr "Глобальный масштаб в процентах"
|
msgstr "Глобальный масштаб в процентах"
|
||||||
|
|
||||||
@@ -1304,9 +1344,19 @@ msgstr "Подтвердить"
|
|||||||
msgid "Cancel synchronisation"
|
msgid "Cancel synchronisation"
|
||||||
msgstr "Отменить синхронизацию"
|
msgstr "Отменить синхронизацию"
|
||||||
|
|
||||||
|
msgid "New tags:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type new tags or select from list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Joplin website"
|
msgid "Joplin website"
|
||||||
msgstr "Сайт Joplin"
|
msgstr "Сайт Joplin"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Login with Dropbox"
|
||||||
|
msgstr "Войти в OneDrive"
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Master Key %s"
|
msgid "Master Key %s"
|
||||||
msgstr "Мастер-ключ %s"
|
msgstr "Мастер-ключ %s"
|
||||||
@@ -1346,6 +1396,14 @@ msgstr "Сохранить изменения"
|
|||||||
msgid "Discard changes"
|
msgid "Discard changes"
|
||||||
msgstr "Отменить изменения"
|
msgstr "Отменить изменения"
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "No item with ID %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "The Joplin mobile app does not currently support this type of link: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Unsupported image type: %s"
|
msgid "Unsupported image type: %s"
|
||||||
msgstr "Неподдерживаемый формат изображения: %s"
|
msgstr "Неподдерживаемый формат изображения: %s"
|
||||||
@@ -1377,6 +1435,9 @@ msgstr "Удалить блокнот"
|
|||||||
msgid "Login with OneDrive"
|
msgid "Login with OneDrive"
|
||||||
msgstr "Войти в OneDrive"
|
msgstr "Войти в OneDrive"
|
||||||
|
|
||||||
|
msgid "Search"
|
||||||
|
msgstr "Поиск"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Click on the (+) button to create a new note or notebook. Click on the side "
|
"Click on the (+) button to create a new note or notebook. Click on the side "
|
||||||
"menu to access your existing notebooks."
|
"menu to access your existing notebooks."
|
||||||
@@ -1390,6 +1451,9 @@ msgstr "У вас сейчас нет блокнота. Создайте его
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Добро пожаловать"
|
msgstr "Добро пожаловать"
|
||||||
|
|
||||||
|
#~ msgid "Searches"
|
||||||
|
#~ msgstr "Запросы"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Release notes:\n"
|
#~ "Release notes:\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
819
CliClient/package-lock.json
generated
819
CliClient/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@
|
|||||||
],
|
],
|
||||||
"owner": "Laurent Cozic"
|
"owner": "Laurent Cozic"
|
||||||
},
|
},
|
||||||
"version": "1.0.100",
|
"version": "1.0.106",
|
||||||
"bin": {
|
"bin": {
|
||||||
"joplin": "./main.js"
|
"joplin": "./main.js"
|
||||||
},
|
},
|
||||||
@@ -58,9 +58,10 @@
|
|||||||
"strip-ansi": "^4.0.0",
|
"strip-ansi": "^4.0.0",
|
||||||
"tar": "^4.4.0",
|
"tar": "^4.4.0",
|
||||||
"tcp-port-used": "^0.1.2",
|
"tcp-port-used": "^0.1.2",
|
||||||
"tkwidgets": "^0.5.25",
|
"tkwidgets": "^0.5.26",
|
||||||
"url-parse": "^1.2.0",
|
"url-parse": "^1.2.0",
|
||||||
"uuid": "^3.0.1",
|
"uuid": "^3.0.1",
|
||||||
|
"valid-url": "^1.0.9",
|
||||||
"word-wrap": "^1.2.3",
|
"word-wrap": "^1.2.3",
|
||||||
"xml2js": "^0.4.19",
|
"xml2js": "^0.4.19",
|
||||||
"yargs-parser": "^7.0.0"
|
"yargs-parser": "^7.0.0"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ rsync -a "$ROOT_DIR/build/locales/" "$BUILD_DIR/locales/"
|
|||||||
mkdir -p "$BUILD_DIR/data"
|
mkdir -p "$BUILD_DIR/data"
|
||||||
|
|
||||||
if [[ $TEST_FILE == "" ]]; then
|
if [[ $TEST_FILE == "" ]]; then
|
||||||
(cd "$ROOT_DIR" && npm test tests-build/synchronizer.js tests-build/encryption.js tests-build/ArrayUtils.js tests-build/models_Setting.js tests-build/services_InteropService.js)
|
(cd "$ROOT_DIR" && npm test tests-build/synchronizer.js tests-build/encryption.js tests-build/ArrayUtils.js tests-build/models_Setting.js tests-build/models_Note.js tests-build/models_Folder.js tests-build/services_InteropService.js)
|
||||||
else
|
else
|
||||||
(cd "$ROOT_DIR" && npm test tests-build/$TEST_FILE.js)
|
(cd "$ROOT_DIR" && npm test tests-build/$TEST_FILE.js)
|
||||||
fi
|
fi
|
||||||
55
CliClient/tests/models_Folder.js
Normal file
55
CliClient/tests/models_Folder.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
|
const { time } = require('lib/time-utils.js');
|
||||||
|
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||||
|
const Folder = require('lib/models/Folder.js');
|
||||||
|
const Note = require('lib/models/Note.js');
|
||||||
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
|
const { shim } = require('lib/shim');
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function allItems() {
|
||||||
|
let folders = await Folder.all();
|
||||||
|
let notes = await Note.all();
|
||||||
|
return folders.concat(notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('models_Folder', function() {
|
||||||
|
|
||||||
|
beforeEach(async (done) => {
|
||||||
|
await setupDatabaseAndSynchronizer(1);
|
||||||
|
await switchClient(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should tell if a notebook can be nested under another one', asyncTest(async () => {
|
||||||
|
let f1 = await Folder.save({ title: "folder1" });
|
||||||
|
let f2 = await Folder.save({ title: "folder2", parent_id: f1.id });
|
||||||
|
let f3 = await Folder.save({ title: "folder3", parent_id: f2.id });
|
||||||
|
let f4 = await Folder.save({ title: "folder4" });
|
||||||
|
|
||||||
|
expect(await Folder.canNestUnder(f1.id, f2.id)).toBe(false);
|
||||||
|
expect(await Folder.canNestUnder(f2.id, f2.id)).toBe(false);
|
||||||
|
expect(await Folder.canNestUnder(f3.id, f1.id)).toBe(true);
|
||||||
|
expect(await Folder.canNestUnder(f4.id, f1.id)).toBe(true);
|
||||||
|
expect(await Folder.canNestUnder(f2.id, f3.id)).toBe(false);
|
||||||
|
expect(await Folder.canNestUnder(f3.id, f2.id)).toBe(true);
|
||||||
|
expect(await Folder.canNestUnder(f1.id, '')).toBe(true);
|
||||||
|
expect(await Folder.canNestUnder(f2.id, '')).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should recursively delete notes and sub-notebooks', asyncTest(async () => {
|
||||||
|
let f1 = await Folder.save({ title: "folder1" });
|
||||||
|
let f2 = await Folder.save({ title: "folder2", parent_id: f1.id });
|
||||||
|
let n1 = await Note.save({ title: 'note1', parent_id: f2.id });
|
||||||
|
|
||||||
|
await Folder.delete(f1.id);
|
||||||
|
|
||||||
|
const all = await allItems();
|
||||||
|
expect(all.length).toBe(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
39
CliClient/tests/models_Note.js
Normal file
39
CliClient/tests/models_Note.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
|
const { time } = require('lib/time-utils.js');
|
||||||
|
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||||
|
const Folder = require('lib/models/Folder.js');
|
||||||
|
const Note = require('lib/models/Note.js');
|
||||||
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
|
const { shim } = require('lib/shim');
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('models_Note', function() {
|
||||||
|
|
||||||
|
beforeEach(async (done) => {
|
||||||
|
await setupDatabaseAndSynchronizer(1);
|
||||||
|
await switchClient(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find resource and note IDs', asyncTest(async () => {
|
||||||
|
let folder1 = await Folder.save({ title: "folder1" });
|
||||||
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
|
let note2 = await Note.save({ title: 'ma deuxième note', body: 'Lien vers première note : ' + Note.markdownTag(note1), parent_id: folder1.id });
|
||||||
|
|
||||||
|
let items = await Note.linkedItems(note2.body);
|
||||||
|
expect(items.length).toBe(1);
|
||||||
|
expect(items[0].id).toBe(note1.id);
|
||||||
|
|
||||||
|
await shim.attachFileToNote(note2, __dirname + '/../tests/support/photo.jpg');
|
||||||
|
note2 = await Note.load(note2.id);
|
||||||
|
items = await Note.linkedItems(note2.body);
|
||||||
|
expect(items.length).toBe(2);
|
||||||
|
expect(items[0].type_).toBe(BaseModel.TYPE_NOTE);
|
||||||
|
expect(items[1].type_).toBe(BaseModel.TYPE_RESOURCE);
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
@@ -180,7 +180,7 @@ describe('services_InteropService', function() {
|
|||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
||||||
note1 = await Note.load(note1.id);
|
note1 = await Note.load(note1.id);
|
||||||
let resourceIds = Note.linkedResourceIds(note1.body);
|
let resourceIds = await Note.linkedResourceIds(note1.body);
|
||||||
let resource1 = await Resource.load(resourceIds[0]);
|
let resource1 = await Resource.load(resourceIds[0]);
|
||||||
|
|
||||||
await service.export({ path: filePath });
|
await service.export({ path: filePath });
|
||||||
@@ -193,7 +193,7 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
let note2 = (await Note.all())[0];
|
let note2 = (await Note.all())[0];
|
||||||
expect(note2.body).not.toBe(note1.body);
|
expect(note2.body).not.toBe(note1.body);
|
||||||
resourceIds = Note.linkedResourceIds(note2.body);
|
resourceIds = await Note.linkedResourceIds(note2.body);
|
||||||
expect(resourceIds.length).toBe(1);
|
expect(resourceIds.length).toBe(1);
|
||||||
let resource2 = await Resource.load(resourceIds[0]);
|
let resource2 = await Resource.load(resourceIds[0]);
|
||||||
expect(resource2.id).not.toBe(resource1.id);
|
expect(resource2.id).not.toBe(resource1.id);
|
||||||
@@ -249,4 +249,28 @@ describe('services_InteropService', function() {
|
|||||||
expect(folder2.title).toBe('folder1');
|
expect(folder2.title).toBe('folder1');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should export and import links to notes', asyncTest(async () => {
|
||||||
|
const service = new InteropService();
|
||||||
|
const filePath = exportDir() + '/test.jex';
|
||||||
|
let folder1 = await Folder.save({ title: "folder1" });
|
||||||
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
|
let note2 = await Note.save({ title: 'ma deuxième note', body: 'Lien vers première note : ' + Note.markdownTag(note1), parent_id: folder1.id });
|
||||||
|
|
||||||
|
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
||||||
|
|
||||||
|
await Note.delete(note1.id);
|
||||||
|
await Note.delete(note2.id);
|
||||||
|
await Folder.delete(folder1.id);
|
||||||
|
|
||||||
|
await service.import({ path: filePath });
|
||||||
|
|
||||||
|
expect(await Note.count()).toBe(2);
|
||||||
|
expect(await Folder.count()).toBe(1);
|
||||||
|
|
||||||
|
let note1_2 = await Note.loadByTitle('ma note');
|
||||||
|
let note2_2 = await Note.loadByTitle('ma deuxième note');
|
||||||
|
|
||||||
|
expect(note2_2.body.indexOf(note1_2.id) >= 0).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
99
CliClient/tests/services_ResourceService.js
Normal file
99
CliClient/tests/services_ResourceService.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
|
const { time } = require('lib/time-utils.js');
|
||||||
|
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||||
|
const InteropService = require('lib/services/InteropService.js');
|
||||||
|
const Folder = require('lib/models/Folder.js');
|
||||||
|
const Note = require('lib/models/Note.js');
|
||||||
|
const Tag = require('lib/models/Tag.js');
|
||||||
|
const NoteTag = require('lib/models/NoteTag.js');
|
||||||
|
const Resource = require('lib/models/Resource.js');
|
||||||
|
const NoteResource = require('lib/models/NoteResource.js');
|
||||||
|
const ResourceService = require('lib/services/ResourceService.js');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const ArrayUtils = require('lib/ArrayUtils');
|
||||||
|
const ObjectUtils = require('lib/ObjectUtils');
|
||||||
|
const { shim } = require('lib/shim.js');
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
|
||||||
|
|
||||||
|
function exportDir() {
|
||||||
|
return __dirname + '/export';
|
||||||
|
}
|
||||||
|
|
||||||
|
function fieldsEqual(model1, model2, fieldNames) {
|
||||||
|
for (let i = 0; i < fieldNames.length; i++) {
|
||||||
|
const f = fieldNames[i];
|
||||||
|
expect(model1[f]).toBe(model2[f], 'For key ' + f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('services_ResourceService', function() {
|
||||||
|
|
||||||
|
beforeEach(async (done) => {
|
||||||
|
await setupDatabaseAndSynchronizer(1);
|
||||||
|
await switchClient(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete orphaned resources', asyncTest(async () => {
|
||||||
|
const service = new ResourceService();
|
||||||
|
|
||||||
|
let folder1 = await Folder.save({ title: "folder1" });
|
||||||
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
|
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
||||||
|
let resource1 = (await Resource.all())[0];
|
||||||
|
const resourcePath = Resource.fullPath(resource1);
|
||||||
|
|
||||||
|
await service.indexNoteResources();
|
||||||
|
await service.deleteOrphanResources(0);
|
||||||
|
|
||||||
|
expect(!!(await Resource.load(resource1.id))).toBe(true);
|
||||||
|
|
||||||
|
await Note.delete(note1.id);
|
||||||
|
await service.deleteOrphanResources(0);
|
||||||
|
|
||||||
|
expect(!!(await Resource.load(resource1.id))).toBe(true);
|
||||||
|
|
||||||
|
await service.indexNoteResources();
|
||||||
|
await service.deleteOrphanResources(1000 * 60);
|
||||||
|
|
||||||
|
expect(!!(await Resource.load(resource1.id))).toBe(true);
|
||||||
|
|
||||||
|
await service.deleteOrphanResources(0);
|
||||||
|
|
||||||
|
expect(!!(await Resource.load(resource1.id))).toBe(false);
|
||||||
|
expect(await shim.fsDriver().exists(resourcePath)).toBe(false);
|
||||||
|
expect(!(await NoteResource.all()).length).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should not delete resource if still associated with at least one note', asyncTest(async () => {
|
||||||
|
const service = new ResourceService();
|
||||||
|
|
||||||
|
let folder1 = await Folder.save({ title: "folder1" });
|
||||||
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
|
let note2 = await Note.save({ title: 'ma deuxième note', parent_id: folder1.id });
|
||||||
|
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
||||||
|
let resource1 = (await Resource.all())[0];
|
||||||
|
const resourcePath = Resource.fullPath(resource1);
|
||||||
|
|
||||||
|
await service.indexNoteResources();
|
||||||
|
|
||||||
|
await Note.delete(note1.id);
|
||||||
|
|
||||||
|
await service.indexNoteResources();
|
||||||
|
|
||||||
|
await Note.save({ id: note2.id, body: Resource.markdownTag(resource1) });
|
||||||
|
|
||||||
|
await service.indexNoteResources();
|
||||||
|
|
||||||
|
await service.deleteOrphanResources(0);
|
||||||
|
|
||||||
|
expect(!!(await Resource.load(resource1.id))).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
@@ -339,22 +339,17 @@ describe('Synchronizer', function() {
|
|||||||
it('should delete local folder', asyncTest(async () => {
|
it('should delete local folder', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: "folder1" });
|
||||||
let folder2 = await Folder.save({ title: "folder2" });
|
let folder2 = await Folder.save({ title: "folder2" });
|
||||||
await synchronizer().start();
|
let context1 = await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
|
|
||||||
await synchronizer().start();
|
let context2 = await synchronizer().start();
|
||||||
|
|
||||||
await sleep(0.1);
|
|
||||||
|
|
||||||
await Folder.delete(folder2.id);
|
await Folder.delete(folder2.id);
|
||||||
|
await synchronizer().start({ context: context2 });
|
||||||
await synchronizer().start();
|
|
||||||
|
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
|
|
||||||
await synchronizer().start();
|
await synchronizer().start({ context: context1 });
|
||||||
|
|
||||||
let items = await allItems();
|
let items = await allItems();
|
||||||
await localItemsSameAsRemote(items, expect);
|
await localItemsSameAsRemote(items, expect);
|
||||||
}));
|
}));
|
||||||
@@ -377,7 +372,7 @@ describe('Synchronizer', function() {
|
|||||||
expect(items.length).toBe(1);
|
expect(items.length).toBe(1);
|
||||||
expect(items[0].title).toBe('note1');
|
expect(items[0].title).toBe('note1');
|
||||||
expect(items[0].is_conflict).toBe(1);
|
expect(items[0].is_conflict).toBe(1);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve conflict if note has been deleted remotely and locally', asyncTest(async () => {
|
it('should resolve conflict if note has been deleted remotely and locally', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "folder" });
|
let folder = await Folder.save({ title: "folder" });
|
||||||
@@ -438,7 +433,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
expect(items1.length).toBe(0);
|
expect(items1.length).toBe(0);
|
||||||
expect(items1.length).toBe(items2.length);
|
expect(items1.length).toBe(items2.length);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle conflict when remote note is deleted then local note is modified', asyncTest(async () => {
|
it('should handle conflict when remote note is deleted then local note is modified', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: "folder1" });
|
||||||
@@ -547,11 +542,11 @@ describe('Synchronizer', function() {
|
|||||||
let n1 = await Note.save({ title: "mynote" });
|
let n1 = await Note.save({ title: "mynote" });
|
||||||
let n2 = await Note.save({ title: "mynote2" });
|
let n2 = await Note.save({ title: "mynote2" });
|
||||||
let tag = await Tag.save({ title: 'mytag' });
|
let tag = await Tag.save({ title: 'mytag' });
|
||||||
await synchronizer().start();
|
let context1 = await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
|
|
||||||
await synchronizer().start();
|
let context2 = await synchronizer().start();
|
||||||
if (withEncryption) {
|
if (withEncryption) {
|
||||||
const masterKey_2 = await MasterKey.load(masterKey.id);
|
const masterKey_2 = await MasterKey.load(masterKey.id);
|
||||||
await encryptionService().loadMasterKey(masterKey_2, '123456', true);
|
await encryptionService().loadMasterKey(masterKey_2, '123456', true);
|
||||||
@@ -565,21 +560,21 @@ describe('Synchronizer', function() {
|
|||||||
await Tag.addNote(remoteTag.id, n2.id);
|
await Tag.addNote(remoteTag.id, n2.id);
|
||||||
let noteIds = await Tag.noteIds(tag.id);
|
let noteIds = await Tag.noteIds(tag.id);
|
||||||
expect(noteIds.length).toBe(2);
|
expect(noteIds.length).toBe(2);
|
||||||
await synchronizer().start();
|
context2 = await synchronizer().start({ context: context2 });
|
||||||
|
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
|
|
||||||
await synchronizer().start();
|
context1 = await synchronizer().start({ context: context1 });
|
||||||
let remoteNoteIds = await Tag.noteIds(tag.id);
|
let remoteNoteIds = await Tag.noteIds(tag.id);
|
||||||
expect(remoteNoteIds.length).toBe(2);
|
expect(remoteNoteIds.length).toBe(2);
|
||||||
await Tag.removeNote(tag.id, n1.id);
|
await Tag.removeNote(tag.id, n1.id);
|
||||||
remoteNoteIds = await Tag.noteIds(tag.id);
|
remoteNoteIds = await Tag.noteIds(tag.id);
|
||||||
expect(remoteNoteIds.length).toBe(1);
|
expect(remoteNoteIds.length).toBe(1);
|
||||||
await synchronizer().start();
|
context1 = await synchronizer().start({ context: context1 });
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
|
|
||||||
await synchronizer().start();
|
context2 = await synchronizer().start({ context: context2 });
|
||||||
noteIds = await Tag.noteIds(tag.id);
|
noteIds = await Tag.noteIds(tag.id);
|
||||||
expect(noteIds.length).toBe(1);
|
expect(noteIds.length).toBe(1);
|
||||||
expect(remoteNoteIds[0]).toBe(noteIds[0]);
|
expect(remoteNoteIds[0]).toBe(noteIds[0]);
|
||||||
@@ -883,6 +878,37 @@ describe('Synchronizer', function() {
|
|||||||
expect(fileContentEqual(resourcePath1, resourcePath1_2)).toBe(true);
|
expect(fileContentEqual(resourcePath1, resourcePath1_2)).toBe(true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should delete resources', asyncTest(async () => {
|
||||||
|
while (insideBeforeEach) await time.msleep(500);
|
||||||
|
|
||||||
|
let folder1 = await Folder.save({ title: "folder1" });
|
||||||
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
|
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
||||||
|
let resource1 = (await Resource.all())[0];
|
||||||
|
let resourcePath1 = Resource.fullPath(resource1);
|
||||||
|
await synchronizer().start();
|
||||||
|
|
||||||
|
await switchClient(2);
|
||||||
|
|
||||||
|
await synchronizer().start();
|
||||||
|
let allResources = await Resource.all();
|
||||||
|
expect(allResources.length).toBe(1);
|
||||||
|
let all = await fileApi().list();
|
||||||
|
expect(all.items.length).toBe(3);
|
||||||
|
await Resource.delete(resource1.id);
|
||||||
|
await synchronizer().start();
|
||||||
|
all = await fileApi().list();
|
||||||
|
expect(all.items.length).toBe(2);
|
||||||
|
|
||||||
|
await switchClient(1);
|
||||||
|
|
||||||
|
expect(await shim.fsDriver().exists(resourcePath1)).toBe(true);
|
||||||
|
await synchronizer().start();
|
||||||
|
allResources = await Resource.all();
|
||||||
|
expect(allResources.length).toBe(0);
|
||||||
|
expect(await shim.fsDriver().exists(resourcePath1)).toBe(false);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should encryt resources', asyncTest(async () => {
|
it('should encryt resources', asyncTest(async () => {
|
||||||
Setting.setValue('encryption.enabled', true);
|
Setting.setValue('encryption.enabled', true);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ const { FileApi } = require('lib/file-api.js');
|
|||||||
const { FileApiDriverMemory } = require('lib/file-api-driver-memory.js');
|
const { FileApiDriverMemory } = require('lib/file-api-driver-memory.js');
|
||||||
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
|
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
|
||||||
const { FileApiDriverWebDav } = require('lib/file-api-driver-webdav.js');
|
const { FileApiDriverWebDav } = require('lib/file-api-driver-webdav.js');
|
||||||
|
const { FileApiDriverDropbox } = require('lib/file-api-driver-dropbox.js');
|
||||||
|
const BaseService = require('lib/services/BaseService.js');
|
||||||
const { FsDriverNode } = require('lib/fs-driver-node.js');
|
const { FsDriverNode } = require('lib/fs-driver-node.js');
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
const { shimInit } = require('lib/shim-init-node.js');
|
const { shimInit } = require('lib/shim-init-node.js');
|
||||||
@@ -24,9 +26,11 @@ const SyncTargetMemory = require('lib/SyncTargetMemory.js');
|
|||||||
const SyncTargetFilesystem = require('lib/SyncTargetFilesystem.js');
|
const SyncTargetFilesystem = require('lib/SyncTargetFilesystem.js');
|
||||||
const SyncTargetOneDrive = require('lib/SyncTargetOneDrive.js');
|
const SyncTargetOneDrive = require('lib/SyncTargetOneDrive.js');
|
||||||
const SyncTargetNextcloud = require('lib/SyncTargetNextcloud.js');
|
const SyncTargetNextcloud = require('lib/SyncTargetNextcloud.js');
|
||||||
|
const SyncTargetDropbox = require('lib/SyncTargetDropbox.js');
|
||||||
const EncryptionService = require('lib/services/EncryptionService.js');
|
const EncryptionService = require('lib/services/EncryptionService.js');
|
||||||
const DecryptionWorker = require('lib/services/DecryptionWorker.js');
|
const DecryptionWorker = require('lib/services/DecryptionWorker.js');
|
||||||
const WebDavApi = require('lib/WebDavApi');
|
const WebDavApi = require('lib/WebDavApi');
|
||||||
|
const DropboxApi = require('lib/DropboxApi');
|
||||||
|
|
||||||
let databases_ = [];
|
let databases_ = [];
|
||||||
let synchronizers_ = [];
|
let synchronizers_ = [];
|
||||||
@@ -50,10 +54,12 @@ SyncTargetRegistry.addClass(SyncTargetMemory);
|
|||||||
SyncTargetRegistry.addClass(SyncTargetFilesystem);
|
SyncTargetRegistry.addClass(SyncTargetFilesystem);
|
||||||
SyncTargetRegistry.addClass(SyncTargetOneDrive);
|
SyncTargetRegistry.addClass(SyncTargetOneDrive);
|
||||||
SyncTargetRegistry.addClass(SyncTargetNextcloud);
|
SyncTargetRegistry.addClass(SyncTargetNextcloud);
|
||||||
|
SyncTargetRegistry.addClass(SyncTargetDropbox);
|
||||||
|
|
||||||
// const syncTargetId_ = SyncTargetRegistry.nameToId("nextcloud");
|
// const syncTargetId_ = SyncTargetRegistry.nameToId("nextcloud");
|
||||||
const syncTargetId_ = SyncTargetRegistry.nameToId("memory");
|
const syncTargetId_ = SyncTargetRegistry.nameToId("memory");
|
||||||
//const syncTargetId_ = SyncTargetRegistry.nameToId('filesystem');
|
//const syncTargetId_ = SyncTargetRegistry.nameToId('filesystem');
|
||||||
|
// const syncTargetId_ = SyncTargetRegistry.nameToId('dropbox');
|
||||||
const syncDir = __dirname + '/../tests/sync';
|
const syncDir = __dirname + '/../tests/sync';
|
||||||
|
|
||||||
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 100;//400;
|
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 100;//400;
|
||||||
@@ -63,7 +69,7 @@ console.info('Testing with sync target: ' + SyncTargetRegistry.idToName(syncTarg
|
|||||||
const logger = new Logger();
|
const logger = new Logger();
|
||||||
logger.addTarget('console');
|
logger.addTarget('console');
|
||||||
logger.addTarget('file', { path: logDir + '/log.txt' });
|
logger.addTarget('file', { path: logDir + '/log.txt' });
|
||||||
logger.setLevel(Logger.LEVEL_WARN); // Set to INFO to display sync process in console
|
logger.setLevel(Logger.LEVEL_WARN); // Set to DEBUG to display sync process in console
|
||||||
|
|
||||||
BaseItem.loadClass('Note', Note);
|
BaseItem.loadClass('Note', Note);
|
||||||
BaseItem.loadClass('Folder', Folder);
|
BaseItem.loadClass('Folder', Folder);
|
||||||
@@ -75,6 +81,8 @@ BaseItem.loadClass('MasterKey', MasterKey);
|
|||||||
Setting.setConstant('appId', 'net.cozic.joplin-cli');
|
Setting.setConstant('appId', 'net.cozic.joplin-cli');
|
||||||
Setting.setConstant('appType', 'cli');
|
Setting.setConstant('appType', 'cli');
|
||||||
|
|
||||||
|
BaseService.logger_ = logger;
|
||||||
|
|
||||||
Setting.autoSaveEnabled = false;
|
Setting.autoSaveEnabled = false;
|
||||||
|
|
||||||
function syncTargetId() {
|
function syncTargetId() {
|
||||||
@@ -118,8 +126,9 @@ async function clearDatabase(id = null) {
|
|||||||
'DELETE FROM tags',
|
'DELETE FROM tags',
|
||||||
'DELETE FROM note_tags',
|
'DELETE FROM note_tags',
|
||||||
'DELETE FROM master_keys',
|
'DELETE FROM master_keys',
|
||||||
'DELETE FROM settings',
|
'DELETE FROM item_changes',
|
||||||
|
'DELETE FROM note_resources',
|
||||||
|
'DELETE FROM settings',
|
||||||
'DELETE FROM deleted_items',
|
'DELETE FROM deleted_items',
|
||||||
'DELETE FROM sync_items',
|
'DELETE FROM sync_items',
|
||||||
];
|
];
|
||||||
@@ -243,25 +252,15 @@ function fileApi() {
|
|||||||
|
|
||||||
const api = new WebDavApi(options);
|
const api = new WebDavApi(options);
|
||||||
fileApi_ = new FileApi('', new FileApiDriverWebDav(api));
|
fileApi_ = new FileApi('', new FileApiDriverWebDav(api));
|
||||||
|
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('dropbox')) {
|
||||||
|
const api = new DropboxApi();
|
||||||
|
const authTokenPath = __dirname + '/support/dropbox-auth.txt';
|
||||||
|
const authToken = fs.readFileSync(authTokenPath, 'utf8');
|
||||||
|
if (!authToken) throw new Error('Dropbox auth token missing in ' + authTokenPath);
|
||||||
|
api.setAuthToken(authToken);
|
||||||
|
fileApi_ = new FileApi('', new FileApiDriverDropbox(api));
|
||||||
}
|
}
|
||||||
|
|
||||||
// } else if (syncTargetId == Setting.SYNC_TARGET_ONEDRIVE) {
|
|
||||||
// let auth = require('./onedrive-auth.json');
|
|
||||||
// if (!auth) {
|
|
||||||
// const oneDriveApiUtils = new OneDriveApiNodeUtils(oneDriveApi);
|
|
||||||
// auth = await oneDriveApiUtils.oauthDance();
|
|
||||||
// fs.writeFileSync('./onedrive-auth.json', JSON.stringify(auth));
|
|
||||||
// process.exit(1);
|
|
||||||
// } else {
|
|
||||||
// auth = JSON.parse(auth);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // const oneDriveApiUtils = new OneDriveApiNodeUtils(reg.oneDriveApi());
|
|
||||||
// // const auth = await oneDriveApiUtils.oauthDance(this);
|
|
||||||
// // Setting.setValue('sync.3.auth', auth ? JSON.stringify(auth) : null);
|
|
||||||
// // if (!auth) return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
fileApi_.setLogger(logger);
|
fileApi_.setLogger(logger);
|
||||||
fileApi_.setSyncTargetId(syncTargetId_);
|
fileApi_.setSyncTargetId(syncTargetId_);
|
||||||
fileApi_.requestRepeatCount_ = 0;
|
fileApi_.requestRepeatCount_ = 0;
|
||||||
@@ -302,8 +301,9 @@ function asyncTest(callback) {
|
|||||||
await callback();
|
await callback();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
done();
|
||||||
}
|
}
|
||||||
done();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ const fs = require('fs-extra');
|
|||||||
|
|
||||||
class ElectronAppWrapper {
|
class ElectronAppWrapper {
|
||||||
|
|
||||||
constructor(electronApp, env) {
|
constructor(electronApp, env, profilePath) {
|
||||||
this.electronApp_ = electronApp;
|
this.electronApp_ = electronApp;
|
||||||
this.env_ = env;
|
this.env_ = env;
|
||||||
|
this.profilePath_ = profilePath;
|
||||||
this.win_ = null;
|
this.win_ = null;
|
||||||
this.willQuitApp_ = false;
|
this.willQuitApp_ = false;
|
||||||
this.tray_ = null;
|
this.tray_ = null;
|
||||||
@@ -37,12 +38,16 @@ class ElectronAppWrapper {
|
|||||||
createWindow() {
|
createWindow() {
|
||||||
const windowStateKeeper = require('electron-window-state');
|
const windowStateKeeper = require('electron-window-state');
|
||||||
|
|
||||||
// Load the previous state with fallback to defaults
|
const stateOptions = {
|
||||||
const windowState = windowStateKeeper({
|
|
||||||
defaultWidth: 800,
|
defaultWidth: 800,
|
||||||
defaultHeight: 600,
|
defaultHeight: 600,
|
||||||
file: 'window-state-' + this.env_ + '.json',
|
file: 'window-state-' + this.env_ + '.json',
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (this.profilePath_) stateOptions.path = this.profilePath_;
|
||||||
|
|
||||||
|
// Load the previous state with fallback to defaults
|
||||||
|
const windowState = windowStateKeeper(stateOptions);
|
||||||
|
|
||||||
const windowOptions = {
|
const windowOptions = {
|
||||||
x: windowState.x,
|
x: windowState.x,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const AlarmServiceDriverNode = require('lib/services/AlarmServiceDriverNode');
|
|||||||
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
||||||
const InteropService = require('lib/services/InteropService');
|
const InteropService = require('lib/services/InteropService');
|
||||||
const InteropServiceHelper = require('./InteropServiceHelper.js');
|
const InteropServiceHelper = require('./InteropServiceHelper.js');
|
||||||
|
const ResourceService = require('lib/services/ResourceService');
|
||||||
|
|
||||||
const { bridge } = require('electron').remote.require('./bridge');
|
const { bridge } = require('electron').remote.require('./bridge');
|
||||||
const Menu = bridge().Menu;
|
const Menu = bridge().Menu;
|
||||||
@@ -37,6 +38,7 @@ const appDefaultState = Object.assign({}, defaultState, {
|
|||||||
fileToImport: null,
|
fileToImport: null,
|
||||||
windowCommand: null,
|
windowCommand: null,
|
||||||
noteVisiblePanes: ['editor', 'viewer'],
|
noteVisiblePanes: ['editor', 'viewer'],
|
||||||
|
sidebarVisibility: true,
|
||||||
windowContentSize: bridge().windowContentSize(),
|
windowContentSize: bridge().windowContentSize(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
action = newAction;
|
action = newAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!goingBack) newNavHistory.push(currentRoute);
|
if (!goingBack) newNavHistory.push(currentRoute);
|
||||||
newState.navHistory = newNavHistory
|
newState.navHistory = newNavHistory
|
||||||
newState.route = action;
|
newState.route = action;
|
||||||
@@ -122,11 +124,22 @@ class Application extends BaseApplication {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'NOTE_VISIBLE_PANES_SET':
|
case 'NOTE_VISIBLE_PANES_SET':
|
||||||
|
|
||||||
newState = Object.assign({}, state);
|
newState = Object.assign({}, state);
|
||||||
newState.noteVisiblePanes = action.panes;
|
newState.noteVisiblePanes = action.panes;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'SIDEBAR_VISIBILITY_TOGGLE':
|
||||||
|
|
||||||
|
newState = Object.assign({}, state);
|
||||||
|
newState.sidebarVisibility = !state.sidebarVisibility;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SIDEBAR_VISIBILITY_SET':
|
||||||
|
newState = Object.assign({}, state);
|
||||||
|
newState.sidebarVisibility = action.visibility;
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action);
|
error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action);
|
||||||
@@ -151,7 +164,7 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (["NOTE_UPDATE_ONE", "NOTE_DELETE", "FOLDER_UPDATE_ONE", "FOLDER_DELETE"].indexOf(action.type) >= 0) {
|
if (["NOTE_UPDATE_ONE", "NOTE_DELETE", "FOLDER_UPDATE_ONE", "FOLDER_DELETE"].indexOf(action.type) >= 0) {
|
||||||
if (!await reg.syncTarget().syncStarted()) reg.scheduleSync(5, { syncSteps: ["update_remote", "delete_remote"] });
|
if (!await reg.syncTarget().syncStarted()) reg.scheduleSync(30, { syncSteps: ["update_remote", "delete_remote"] });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['EVENT_NOTE_ALARM_FIELD_CHANGE', 'NOTE_DELETE'].indexOf(action.type) >= 0) {
|
if (['EVENT_NOTE_ALARM_FIELD_CHANGE', 'NOTE_DELETE'].indexOf(action.type) >= 0) {
|
||||||
@@ -169,6 +182,10 @@ class Application extends BaseApplication {
|
|||||||
Setting.setValue('noteVisiblePanes', newState.noteVisiblePanes);
|
Setting.setValue('noteVisiblePanes', newState.noteVisiblePanes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (['SIDEBAR_VISIBILITY_TOGGLE', 'SIDEBAR_VISIBILITY_SET'].indexOf(action.type) >= 0) {
|
||||||
|
Setting.setValue('sidebarVisibility', newState.sidebarVisibility);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +211,7 @@ class Application extends BaseApplication {
|
|||||||
Setting.setValue('notes.sortOrder.field', field);
|
Setting.setValue('notes.sortOrder.field', field);
|
||||||
this.refreshMenu();
|
this.refreshMenu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const importItems = [];
|
const importItems = [];
|
||||||
@@ -272,7 +289,7 @@ class Application extends BaseApplication {
|
|||||||
this.dispatch({
|
this.dispatch({
|
||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'exportPdf',
|
name: 'exportPdf',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -348,17 +365,17 @@ class Application extends BaseApplication {
|
|||||||
label: _('Edit'),
|
label: _('Edit'),
|
||||||
submenu: [{
|
submenu: [{
|
||||||
label: _('Copy'),
|
label: _('Copy'),
|
||||||
screens: ['Main', 'OneDriveLogin', 'Config', 'EncryptionConfig'],
|
//screens: ['Main', 'OneDriveLogin', 'Config', 'EncryptionConfig'],
|
||||||
role: 'copy',
|
role: 'copy',
|
||||||
accelerator: 'CommandOrControl+C',
|
accelerator: 'CommandOrControl+C',
|
||||||
}, {
|
}, {
|
||||||
label: _('Cut'),
|
label: _('Cut'),
|
||||||
screens: ['Main', 'OneDriveLogin', 'Config', 'EncryptionConfig'],
|
//screens: ['Main', 'OneDriveLogin', 'Config', 'EncryptionConfig'],
|
||||||
role: 'cut',
|
role: 'cut',
|
||||||
accelerator: 'CommandOrControl+X',
|
accelerator: 'CommandOrControl+X',
|
||||||
}, {
|
}, {
|
||||||
label: _('Paste'),
|
label: _('Paste'),
|
||||||
screens: ['Main', 'OneDriveLogin', 'Config', 'EncryptionConfig'],
|
//screens: ['Main', 'OneDriveLogin', 'Config', 'EncryptionConfig'],
|
||||||
role: 'paste',
|
role: 'paste',
|
||||||
accelerator: 'CommandOrControl+V',
|
accelerator: 'CommandOrControl+V',
|
||||||
}, {
|
}, {
|
||||||
@@ -367,17 +384,27 @@ class Application extends BaseApplication {
|
|||||||
}, {
|
}, {
|
||||||
label: _('Search in all the notes'),
|
label: _('Search in all the notes'),
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
accelerator: 'F6',
|
accelerator: 'CommandOrControl+F',
|
||||||
click: () => {
|
click: () => {
|
||||||
this.dispatch({
|
this.dispatch({
|
||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'search',
|
name: 'focus_search',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
label: _('View'),
|
label: _('View'),
|
||||||
submenu: [{
|
submenu: [{
|
||||||
|
label: _('Toggle sidebar'),
|
||||||
|
screens: ['Main'],
|
||||||
|
accelerator: 'F10',
|
||||||
|
click: () => {
|
||||||
|
this.dispatch({
|
||||||
|
type: 'WINDOW_COMMAND',
|
||||||
|
name: 'toggleSidebar',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
label: _('Toggle editor layout'),
|
label: _('Toggle editor layout'),
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
accelerator: 'CommandOrControl+L',
|
accelerator: 'CommandOrControl+L',
|
||||||
@@ -447,10 +474,10 @@ class Application extends BaseApplication {
|
|||||||
submenu: [{
|
submenu: [{
|
||||||
label: _('Website and documentation'),
|
label: _('Website and documentation'),
|
||||||
accelerator: 'F1',
|
accelerator: 'F1',
|
||||||
click () { bridge().openExternal('http://joplin.cozic.net') }
|
click () { bridge().openExternal('https://joplin.cozic.net') }
|
||||||
}, {
|
}, {
|
||||||
label: _('Make a donation'),
|
label: _('Make a donation'),
|
||||||
click () { bridge().openExternal('http://joplin.cozic.net/donate') }
|
click () { bridge().openExternal('https://joplin.cozic.net/donate') }
|
||||||
}, {
|
}, {
|
||||||
label: _('Check for updates...'),
|
label: _('Check for updates...'),
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -509,11 +536,6 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateTray() {
|
updateTray() {
|
||||||
// Tray icon (called AppIndicator) doesn't work in Ubuntu
|
|
||||||
// http://www.webupd8.org/2017/04/fix-appindicator-not-working-for.html
|
|
||||||
// Might be fixed in Electron 18.x but no non-beta release yet.
|
|
||||||
if (!shim.isWindows() && !shim.isMac()) return;
|
|
||||||
|
|
||||||
const app = bridge().electronApp();
|
const app = bridge().electronApp();
|
||||||
|
|
||||||
if (app.trayShown() === Setting.value('showTrayIcon')) return;
|
if (app.trayShown() === Setting.value('showTrayIcon')) return;
|
||||||
@@ -546,6 +568,12 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(argv) {
|
async start(argv) {
|
||||||
|
const electronIsDev = require('electron-is-dev');
|
||||||
|
|
||||||
|
// If running inside a package, the command line, instead of being "node.exe <path> <flags>" is "joplin.exe <flags>" so
|
||||||
|
// insert an extra argument so that they can be processed in a consistent way everywhere.
|
||||||
|
if (!electronIsDev) argv.splice(1, 0, '.');
|
||||||
|
|
||||||
argv = await super.start(argv);
|
argv = await super.start(argv);
|
||||||
|
|
||||||
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
||||||
@@ -587,6 +615,11 @@ class Application extends BaseApplication {
|
|||||||
id: Setting.value('activeFolderId'),
|
id: Setting.value('activeFolderId'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.store().dispatch({
|
||||||
|
type: 'FOLDER_SET_COLLAPSED_ALL',
|
||||||
|
ids: Setting.value('collapsedFolderIds'),
|
||||||
|
});
|
||||||
|
|
||||||
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
||||||
// but then doesn't install it on exit.
|
// but then doesn't install it on exit.
|
||||||
if (shim.isWindows() || shim.isMac()) {
|
if (shim.isWindows() || shim.isMac()) {
|
||||||
@@ -595,7 +628,7 @@ class Application extends BaseApplication {
|
|||||||
bridge().checkForUpdates(true, bridge().window(), this.checkForUpdateLoggerPath());
|
bridge().checkForUpdates(true, bridge().window(), this.checkForUpdateLoggerPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial check on startup
|
// Initial check on startup
|
||||||
setTimeout(() => { runAutoUpdateCheck() }, 5000);
|
setTimeout(() => { runAutoUpdateCheck() }, 5000);
|
||||||
// Then every x hours
|
// Then every x hours
|
||||||
@@ -608,6 +641,8 @@ class Application extends BaseApplication {
|
|||||||
AlarmService.garbageCollect();
|
AlarmService.garbageCollect();
|
||||||
}, 1000 * 60 * 60);
|
}, 1000 * 60 * 60);
|
||||||
|
|
||||||
|
ResourceService.runInBackground();
|
||||||
|
|
||||||
if (Setting.value('env') === 'dev') {
|
if (Setting.value('env') === 'dev') {
|
||||||
AlarmService.updateAllNotifications();
|
AlarmService.updateAllNotifications();
|
||||||
} else {
|
} else {
|
||||||
@@ -630,4 +665,4 @@ function app() {
|
|||||||
return application_;
|
return application_;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { app };
|
module.exports = { app };
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ async function fetchLatestRelease() {
|
|||||||
for (let i = 0; i < json.assets.length; i++) {
|
for (let i = 0; i < json.assets.length; i++) {
|
||||||
const asset = json.assets[i];
|
const asset = json.assets[i];
|
||||||
let found = false;
|
let found = false;
|
||||||
if (platform === 'win32' && asset.name.indexOf('.exe') >= 0) {
|
if (platform === 'win32' && asset.name.indexOf('.exe') >= 0 && asset.name.indexOf('Setup') >= 0) {
|
||||||
found = true;
|
found = true;
|
||||||
} else if (platform === 'darwin' && asset.name.indexOf('.dmg') >= 0) {
|
} else if (platform === 'darwin' && asset.name.indexOf('.dmg') >= 0) {
|
||||||
found = true;
|
found = true;
|
||||||
|
|||||||
62
ElectronClient/app/gui/DropboxLoginScreen.jsx
Normal file
62
ElectronClient/app/gui/DropboxLoginScreen.jsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const { connect } = require('react-redux');
|
||||||
|
const { reg } = require('lib/registry.js');
|
||||||
|
const { bridge } = require('electron').remote.require('./bridge');
|
||||||
|
const { Header } = require('./Header.min.js');
|
||||||
|
const { themeStyle } = require('../theme.js');
|
||||||
|
const SyncTargetRegistry = require('lib/SyncTargetRegistry');
|
||||||
|
const { _ } = require('lib/locale.js');
|
||||||
|
const Shared = require('lib/components/shared/dropbox-login-shared');
|
||||||
|
|
||||||
|
class DropboxLoginScreenComponent extends React.Component {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.shared_ = new Shared(
|
||||||
|
this,
|
||||||
|
(msg) => bridge().showInfoMessageBox(msg),
|
||||||
|
(msg) => bridge().showErrorMessageBox(msg)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.shared_.refreshUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const style = this.props.style;
|
||||||
|
const theme = themeStyle(this.props.theme);
|
||||||
|
|
||||||
|
const headerStyle = {
|
||||||
|
width: style.width,
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputStyle = Object.assign({}, theme.inputStyle, { width: 500 });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header style={headerStyle} />
|
||||||
|
<div style={{padding: theme.margin}}>
|
||||||
|
<p style={theme.textStyle}>{_('To allow Joplin to synchronise with Dropbox, please follow the steps below:')}</p>
|
||||||
|
<p style={theme.textStyle}>{_('Step 1: Open this URL in your browser to authorise the application:')}</p>
|
||||||
|
<a style={theme.textStyle} href="#" onClick={this.shared_.loginUrl_click}>{this.state.loginUrl}</a>
|
||||||
|
<p style={theme.textStyle}>{_('Step 2: Enter the code provided by Dropbox:')}</p>
|
||||||
|
<p><input type="text" value={this.state.authCode} onChange={this.shared_.authCodeInput_change} style={inputStyle}/></p>
|
||||||
|
<button disabled={this.state.checkingAuthToken} onClick={this.shared_.submit_click}>{_('Submit')}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
theme: state.settings.theme,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const DropboxLoginScreen = connect(mapStateToProps)(DropboxLoginScreenComponent);
|
||||||
|
|
||||||
|
module.exports = { DropboxLoginScreen };
|
||||||
@@ -182,17 +182,11 @@ class EncryptionConfigScreenComponent extends React.Component {
|
|||||||
<div>
|
<div>
|
||||||
<Header style={headerStyle} />
|
<Header style={headerStyle} />
|
||||||
<div style={containerStyle}>
|
<div style={containerStyle}>
|
||||||
{/*<div style={{backgroundColor: theme.warningBackgroundColor, paddingLeft: 10, paddingRight: 10, paddingTop: 2, paddingBottom: 2 }}>
|
{<div style={{backgroundColor: theme.warningBackgroundColor, paddingLeft: 10, paddingRight: 10, paddingTop: 2, paddingBottom: 2 }}>
|
||||||
<p style={theme.textStyle}>
|
<p style={theme.textStyle}>
|
||||||
Important: This is a <b>beta</b> feature. It has been extensively tested and is already in use by some users, but it is possible that some bugs remain.
|
<span>{_('For more information about End-To-End Encryption (E2EE) and advices on how to enable it please check the documentation:')}</span> <a onClick={() => {bridge().openExternal('https://joplin.cozic.net/e2ee')}} href="#">https://joplin.cozic.net/e2ee</a>
|
||||||
</p>
|
</p>
|
||||||
<p style={theme.textStyle}>
|
</div>}
|
||||||
If you wish to you use it, it is recommended that you keep a backup of your data. The simplest way is to regularly backup <b>{pathUtils.toSystemSlashes(Setting.value('profileDir'), process.platform)}</b>
|
|
||||||
</p>
|
|
||||||
<p style={theme.textStyle}>
|
|
||||||
For more information about End-To-End Encryption (E2EE) and how it is going to work, please check the documentation: <a onClick={() => {bridge().openExternal('http://joplin.cozic.net/help/e2ee.html')}} href="#">http://joplin.cozic.net/help/e2ee.html</a>
|
|
||||||
</p>
|
|
||||||
</div>*/}
|
|
||||||
<h1 style={theme.h1Style}>{_('Status')}</h1>
|
<h1 style={theme.h1Style}>{_('Status')}</h1>
|
||||||
<p style={theme.textStyle}>{_('Encryption is:')} <strong>{this.props.encryptionEnabled ? _('Enabled') : _('Disabled')}</strong></p>
|
<p style={theme.textStyle}>{_('Encryption is:')} <strong>{this.props.encryptionEnabled ? _('Enabled') : _('Disabled')}</strong></p>
|
||||||
{decryptedItemsInfo}
|
{decryptedItemsInfo}
|
||||||
|
|||||||
@@ -6,6 +6,63 @@ const { _ } = require('lib/locale.js');
|
|||||||
|
|
||||||
class HeaderComponent extends React.Component {
|
class HeaderComponent extends React.Component {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
searchQuery: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
this.scheduleSearchChangeEventIid_ = null;
|
||||||
|
this.searchOnQuery_ = null;
|
||||||
|
this.searchElement_ = null;
|
||||||
|
|
||||||
|
const triggerOnQuery = (query) => {
|
||||||
|
clearTimeout(this.scheduleSearchChangeEventIid_);
|
||||||
|
if (this.searchOnQuery_) this.searchOnQuery_(query);
|
||||||
|
this.scheduleSearchChangeEventIid_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.search_onChange = (event) => {
|
||||||
|
this.setState({ searchQuery: event.target.value });
|
||||||
|
|
||||||
|
if (this.scheduleSearchChangeEventIid_) clearTimeout(this.scheduleSearchChangeEventIid_);
|
||||||
|
|
||||||
|
this.scheduleSearchChangeEventIid_ = setTimeout(() => {
|
||||||
|
triggerOnQuery(this.state.searchQuery);
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.search_onClear = (event) => {
|
||||||
|
this.setState({ searchQuery: '' });
|
||||||
|
triggerOnQuery('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillReceiveProps(nextProps) {
|
||||||
|
if (nextProps.windowCommand) {
|
||||||
|
this.doCommand(nextProps.windowCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async doCommand(command) {
|
||||||
|
if (!command) return;
|
||||||
|
|
||||||
|
let commandProcessed = true;
|
||||||
|
|
||||||
|
if (command.name === 'focus_search' && this.searchElement_) {
|
||||||
|
this.searchElement_.focus();
|
||||||
|
} else {
|
||||||
|
commandProcessed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commandProcessed) {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'WINDOW_COMMAND',
|
||||||
|
name: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
back_click() {
|
back_click() {
|
||||||
this.props.dispatch({ type: 'NAV_BACK' });
|
this.props.dispatch({ type: 'NAV_BACK' });
|
||||||
}
|
}
|
||||||
@@ -15,9 +72,10 @@ class HeaderComponent extends React.Component {
|
|||||||
if (options.iconName) {
|
if (options.iconName) {
|
||||||
const iconStyle = {
|
const iconStyle = {
|
||||||
fontSize: Math.round(style.fontSize * 1.4),
|
fontSize: Math.round(style.fontSize * 1.4),
|
||||||
color: style.color
|
color: style.color,
|
||||||
};
|
};
|
||||||
if (options.title) iconStyle.marginRight = 5;
|
if (options.title) iconStyle.marginRight = 5;
|
||||||
|
if (options.iconRotation) iconStyle.transform = 'rotate(' + options.iconRotation + 'deg)';
|
||||||
icon = <i style={iconStyle} className={"fa " + options.iconName}></i>
|
icon = <i style={iconStyle} className={"fa " + options.iconName}></i>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +98,59 @@ class HeaderComponent extends React.Component {
|
|||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
makeSearch(key, style, options, state) {
|
||||||
|
const inputStyle = {
|
||||||
|
display: 'flex',
|
||||||
|
flex: 1,
|
||||||
|
paddingLeft: 4,
|
||||||
|
paddingRight: 4,
|
||||||
|
color: style.color,
|
||||||
|
fontSize: style.fontSize,
|
||||||
|
fontFamily: style.fontFamily,
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchButton = {
|
||||||
|
paddingLeft: 4,
|
||||||
|
paddingRight: 4,
|
||||||
|
paddingTop: 2,
|
||||||
|
paddingBottom: 2,
|
||||||
|
textDecoration: 'none',
|
||||||
|
};
|
||||||
|
|
||||||
|
const iconStyle = {
|
||||||
|
display: 'flex',
|
||||||
|
fontSize: Math.round(style.fontSize) * 1.2,
|
||||||
|
color: style.color,
|
||||||
|
};
|
||||||
|
|
||||||
|
const containerStyle = {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
};
|
||||||
|
|
||||||
|
const iconName = state.searchQuery ? 'fa-times' : 'fa-search';
|
||||||
|
const icon = <i style={iconStyle} className={"fa " + iconName}></i>
|
||||||
|
if (options.onQuery) this.searchOnQuery_ = options.onQuery;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={key} style={containerStyle}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
style={inputStyle}
|
||||||
|
placeholder={options.title}
|
||||||
|
value={state.searchQuery}
|
||||||
|
onChange={this.search_onChange}
|
||||||
|
ref={elem => this.searchElement_ = elem}
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
style={searchButton}
|
||||||
|
onClick={this.search_onClear}
|
||||||
|
>{icon}</a>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const style = Object.assign({}, this.props.style);
|
const style = Object.assign({}, this.props.style);
|
||||||
const theme = themeStyle(this.props.theme);
|
const theme = themeStyle(this.props.theme);
|
||||||
@@ -50,9 +161,9 @@ class HeaderComponent extends React.Component {
|
|||||||
style.borderBottom = '1px solid ' + theme.dividerColor;
|
style.borderBottom = '1px solid ' + theme.dividerColor;
|
||||||
style.boxSizing = 'border-box';
|
style.boxSizing = 'border-box';
|
||||||
|
|
||||||
const buttons = [];
|
const items = [];
|
||||||
|
|
||||||
const buttonStyle = {
|
const itemStyle = {
|
||||||
height: theme.headerHeight,
|
height: theme.headerHeight,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -67,19 +178,24 @@ class HeaderComponent extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (showBackButton) {
|
if (showBackButton) {
|
||||||
buttons.push(this.makeButton('back', buttonStyle, { title: _('Back'), onClick: () => this.back_click(), iconName: 'fa-chevron-left ' }));
|
items.push(this.makeButton('back', itemStyle, { title: _('Back'), onClick: () => this.back_click(), iconName: 'fa-chevron-left ' }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.buttons) {
|
if (this.props.items) {
|
||||||
for (let i = 0; i < this.props.buttons.length; i++) {
|
for (let i = 0; i < this.props.items.length; i++) {
|
||||||
const o = this.props.buttons[i];
|
const item = this.props.items[i];
|
||||||
buttons.push(this.makeButton('btn_' + i + '_' + o.title, buttonStyle, o));
|
|
||||||
|
if (item.type === 'search') {
|
||||||
|
items.push(this.makeSearch('item_' + i + '_search', itemStyle, item, this.state));
|
||||||
|
} else {
|
||||||
|
items.push(this.makeButton('item_' + i + '_' + item.title, itemStyle, item));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="header" style={style}>
|
<div className="header" style={style}>
|
||||||
{ buttons }
|
{ items }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -87,7 +203,10 @@ class HeaderComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
return { theme: state.settings.theme };
|
return {
|
||||||
|
theme: state.settings.theme,
|
||||||
|
windowCommand: state.windowCommand,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const Header = connect(mapStateToProps)(HeaderComponent);
|
const Header = connect(mapStateToProps)(HeaderComponent);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class MainScreenComponent extends React.Component {
|
|||||||
modalLayer: {
|
modalLayer: {
|
||||||
visible: false,
|
visible: false,
|
||||||
message: '',
|
message: '',
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +41,12 @@ class MainScreenComponent extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSidebar() {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'SIDEBAR_VISIBILITY_TOGGLE',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async doCommand(command) {
|
async doCommand(command) {
|
||||||
if (!command) return;
|
if (!command) return;
|
||||||
|
|
||||||
@@ -83,7 +89,7 @@ class MainScreenComponent extends React.Component {
|
|||||||
if (answer) {
|
if (answer) {
|
||||||
let folder = null;
|
let folder = null;
|
||||||
try {
|
try {
|
||||||
folder = await Folder.save({ title: answer }, { userSideValidation: true });
|
folder = await Folder.save({ title: answer }, { userSideValidation: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
bridge().showErrorMessageBox(error.message);
|
bridge().showErrorMessageBox(error.message);
|
||||||
}
|
}
|
||||||
@@ -140,35 +146,31 @@ class MainScreenComponent extends React.Component {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (command.name === 'search') {
|
} else if (command.name === 'search') {
|
||||||
this.setState({
|
|
||||||
promptOptions: {
|
|
||||||
label: _('Search:'),
|
|
||||||
onClose: async (answer) => {
|
|
||||||
if (answer !== null) {
|
|
||||||
const searchId = uuid.create();
|
|
||||||
|
|
||||||
this.props.dispatch({
|
if (!this.searchId_) this.searchId_ = uuid.create();
|
||||||
type: 'SEARCH_ADD',
|
|
||||||
search: {
|
|
||||||
id: searchId,
|
|
||||||
title: answer,
|
|
||||||
query_pattern: answer,
|
|
||||||
query_folder_id: null,
|
|
||||||
type_: BaseModel.TYPE_SEARCH,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'SEARCH_SELECT',
|
type: 'SEARCH_UPDATE',
|
||||||
id: searchId,
|
search: {
|
||||||
});
|
id: this.searchId_,
|
||||||
}
|
title: command.query,
|
||||||
this.setState({ promptOptions: null });
|
query_pattern: command.query,
|
||||||
}
|
query_folder_id: null,
|
||||||
|
type_: BaseModel.TYPE_SEARCH,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (command.query) {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'SEARCH_SELECT',
|
||||||
|
id: this.searchId_,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} else if (command.name === 'toggleVisiblePanes') {
|
} else if (command.name === 'toggleVisiblePanes') {
|
||||||
this.toggleVisiblePanes();
|
this.toggleVisiblePanes();
|
||||||
|
} else if (command.name === 'toggleSidebar') {
|
||||||
|
this.toggleSidebar();
|
||||||
} else if (command.name === 'showModalMessage') {
|
} else if (command.name === 'showModalMessage') {
|
||||||
this.setState({ modalLayer: { visible: true, message: command.message } });
|
this.setState({ modalLayer: { visible: true, message: command.message } });
|
||||||
} else if (command.name === 'hideModalMessage') {
|
} else if (command.name === 'hideModalMessage') {
|
||||||
@@ -209,7 +211,7 @@ class MainScreenComponent extends React.Component {
|
|||||||
this.setState({ promptOptions: null });
|
this.setState({ promptOptions: null });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
commandProcessed = false;
|
commandProcessed = false;
|
||||||
}
|
}
|
||||||
@@ -222,8 +224,8 @@ class MainScreenComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
styles(themeId, width, height, messageBoxVisible) {
|
styles(themeId, width, height, messageBoxVisible, isSidebarVisible) {
|
||||||
const styleKey = themeId + '_' + width + '_' + height + '_' + messageBoxVisible;
|
const styleKey = themeId + '_' + width + '_' + height + '_' + messageBoxVisible + '_' + (+isSidebarVisible);
|
||||||
if (styleKey === this.styleKey_) return this.styles_;
|
if (styleKey === this.styleKey_) return this.styles_;
|
||||||
|
|
||||||
const theme = themeStyle(themeId);
|
const theme = themeStyle(themeId);
|
||||||
@@ -252,7 +254,12 @@ class MainScreenComponent extends React.Component {
|
|||||||
height: rowHeight,
|
height: rowHeight,
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
verticalAlign: 'top',
|
verticalAlign: 'top',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isSidebarVisible === false) {
|
||||||
|
this.styles_.sideBar.width = 0;
|
||||||
|
this.styles_.sideBar.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
this.styles_.noteList = {
|
this.styles_.noteList = {
|
||||||
width: Math.floor(layoutUtils.size(width * .2, 150, 300)),
|
width: Math.floor(layoutUtils.size(width * .2, 150, 300)),
|
||||||
@@ -278,7 +285,7 @@ class MainScreenComponent extends React.Component {
|
|||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
backgroundColor: theme.backgroundColorTransparent,
|
backgroundColor: theme.backgroundColor,
|
||||||
width: width - 20,
|
width: width - 20,
|
||||||
height: height - 20,
|
height: height - 20,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
@@ -293,46 +300,55 @@ class MainScreenComponent extends React.Component {
|
|||||||
const folders = this.props.folders;
|
const folders = this.props.folders;
|
||||||
const notes = this.props.notes;
|
const notes = this.props.notes;
|
||||||
const messageBoxVisible = this.props.hasDisabledSyncItems || this.props.showMissingMasterKeyMessage;
|
const messageBoxVisible = this.props.hasDisabledSyncItems || this.props.showMissingMasterKeyMessage;
|
||||||
const styles = this.styles(this.props.theme, style.width, style.height, messageBoxVisible);
|
const sidebarVisibility = this.props.sidebarVisibility;
|
||||||
|
const styles = this.styles(this.props.theme, style.width, style.height, messageBoxVisible, sidebarVisibility);
|
||||||
const theme = themeStyle(this.props.theme);
|
const theme = themeStyle(this.props.theme);
|
||||||
const selectedFolderId = this.props.selectedFolderId;
|
const selectedFolderId = this.props.selectedFolderId;
|
||||||
const onConflictFolder = this.props.selectedFolderId === Folder.conflictFolderId();
|
const onConflictFolder = this.props.selectedFolderId === Folder.conflictFolderId();
|
||||||
|
|
||||||
const headerButtons = [];
|
const headerItems = [];
|
||||||
|
|
||||||
headerButtons.push({
|
headerItems.push({
|
||||||
|
title: _('Toggle sidebar'),
|
||||||
|
iconName: 'fa-bars',
|
||||||
|
iconRotation: this.props.sidebarVisibility ? 0 : 90,
|
||||||
|
onClick: () => { this.doCommand({ name: 'toggleSidebar'}) }
|
||||||
|
});
|
||||||
|
|
||||||
|
headerItems.push({
|
||||||
title: _('New note'),
|
title: _('New note'),
|
||||||
iconName: 'fa-file-o',
|
iconName: 'fa-file-o',
|
||||||
enabled: !!folders.length && !onConflictFolder,
|
enabled: !!folders.length && !onConflictFolder,
|
||||||
onClick: () => { this.doCommand({ name: 'newNote' }) },
|
onClick: () => { this.doCommand({ name: 'newNote' }) },
|
||||||
});
|
});
|
||||||
|
|
||||||
headerButtons.push({
|
headerItems.push({
|
||||||
title: _('New to-do'),
|
title: _('New to-do'),
|
||||||
iconName: 'fa-check-square-o',
|
iconName: 'fa-check-square-o',
|
||||||
enabled: !!folders.length && !onConflictFolder,
|
enabled: !!folders.length && !onConflictFolder,
|
||||||
onClick: () => { this.doCommand({ name: 'newTodo' }) },
|
onClick: () => { this.doCommand({ name: 'newTodo' }) },
|
||||||
});
|
});
|
||||||
|
|
||||||
headerButtons.push({
|
headerItems.push({
|
||||||
title: _('New notebook'),
|
title: _('New notebook'),
|
||||||
iconName: 'fa-folder-o',
|
iconName: 'fa-folder-o',
|
||||||
onClick: () => { this.doCommand({ name: 'newNotebook' }) },
|
onClick: () => { this.doCommand({ name: 'newNotebook' }) },
|
||||||
});
|
});
|
||||||
|
|
||||||
headerButtons.push({
|
headerItems.push({
|
||||||
title: _('Search'),
|
|
||||||
iconName: 'fa-search',
|
|
||||||
onClick: () => { this.doCommand({ name: 'search' }) },
|
|
||||||
});
|
|
||||||
|
|
||||||
headerButtons.push({
|
|
||||||
title: _('Layout'),
|
title: _('Layout'),
|
||||||
iconName: 'fa-columns',
|
iconName: 'fa-columns',
|
||||||
enabled: !!notes.length,
|
enabled: !!notes.length,
|
||||||
onClick: () => { this.doCommand({ name: 'toggleVisiblePanes' }) },
|
onClick: () => { this.doCommand({ name: 'toggleVisiblePanes' }) },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
headerItems.push({
|
||||||
|
title: _('Search...'),
|
||||||
|
iconName: 'fa-search',
|
||||||
|
onQuery: (query) => { this.doCommand({ name: 'search', query: query }) },
|
||||||
|
type: 'search',
|
||||||
|
});
|
||||||
|
|
||||||
if (!this.promptOnClose_) {
|
if (!this.promptOnClose_) {
|
||||||
this.promptOnClose_ = (answer, buttonType) => {
|
this.promptOnClose_ = (answer, buttonType) => {
|
||||||
return this.state.promptOptions.onClose(answer, buttonType);
|
return this.state.promptOptions.onClose(answer, buttonType);
|
||||||
@@ -389,7 +405,7 @@ class MainScreenComponent extends React.Component {
|
|||||||
visible={!!this.state.promptOptions}
|
visible={!!this.state.promptOptions}
|
||||||
buttons={promptOptions && ('buttons' in promptOptions) ? promptOptions.buttons : null}
|
buttons={promptOptions && ('buttons' in promptOptions) ? promptOptions.buttons : null}
|
||||||
inputType={promptOptions && ('inputType' in promptOptions) ? promptOptions.inputType : null} />
|
inputType={promptOptions && ('inputType' in promptOptions) ? promptOptions.inputType : null} />
|
||||||
<Header style={styles.header} showBackButton={false} buttons={headerButtons} />
|
<Header style={styles.header} showBackButton={false} items={headerItems} />
|
||||||
{messageComp}
|
{messageComp}
|
||||||
<SideBar style={styles.sideBar} />
|
<SideBar style={styles.sideBar} />
|
||||||
<NoteList style={styles.noteList} />
|
<NoteList style={styles.noteList} />
|
||||||
@@ -405,14 +421,16 @@ const mapStateToProps = (state) => {
|
|||||||
theme: state.settings.theme,
|
theme: state.settings.theme,
|
||||||
windowCommand: state.windowCommand,
|
windowCommand: state.windowCommand,
|
||||||
noteVisiblePanes: state.noteVisiblePanes,
|
noteVisiblePanes: state.noteVisiblePanes,
|
||||||
|
sidebarVisibility: state.sidebarVisibility,
|
||||||
folders: state.folders,
|
folders: state.folders,
|
||||||
notes: state.notes,
|
notes: state.notes,
|
||||||
hasDisabledSyncItems: state.hasDisabledSyncItems,
|
hasDisabledSyncItems: state.hasDisabledSyncItems,
|
||||||
showMissingMasterKeyMessage: state.notLoadedMasterKeys.length && state.masterKeys.length,
|
showMissingMasterKeyMessage: state.notLoadedMasterKeys.length && state.masterKeys.length,
|
||||||
selectedFolderId: state.selectedFolderId,
|
selectedFolderId: state.selectedFolderId,
|
||||||
|
sidebarVisibility: state.sidebarVisibility,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const MainScreen = connect(mapStateToProps)(MainScreenComponent);
|
const MainScreen = connect(mapStateToProps)(MainScreenComponent);
|
||||||
|
|
||||||
module.exports = { MainScreen };
|
module.exports = { MainScreen };
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ const MenuItem = bridge().MenuItem;
|
|||||||
const eventManager = require('../eventManager');
|
const eventManager = require('../eventManager');
|
||||||
const InteropService = require('lib/services/InteropService');
|
const InteropService = require('lib/services/InteropService');
|
||||||
const InteropServiceHelper = require('../InteropServiceHelper.js');
|
const InteropServiceHelper = require('../InteropServiceHelper.js');
|
||||||
|
const Search = require('lib/models/Search');
|
||||||
|
const Mark = require('mark.js/dist/mark.min.js');
|
||||||
|
|
||||||
class NoteListComponent extends React.Component {
|
class NoteListComponent extends React.Component {
|
||||||
|
|
||||||
@@ -94,6 +96,16 @@ class NoteListComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
}}));
|
}}));
|
||||||
|
|
||||||
|
menu.append(new MenuItem({label: _('Copy Markdown link'), click: async () => {
|
||||||
|
const { clipboard } = require('electron');
|
||||||
|
const links = [];
|
||||||
|
for (let i = 0; i < noteIds.length; i++) {
|
||||||
|
const note = await Note.load(noteIds[i]);
|
||||||
|
links.push(Note.markdownTag(note));
|
||||||
|
}
|
||||||
|
clipboard.writeText(links.join(' '));
|
||||||
|
}}));
|
||||||
|
|
||||||
const exportMenu = new Menu();
|
const exportMenu = new Menu();
|
||||||
|
|
||||||
const ioService = new InteropService();
|
const ioService = new InteropService();
|
||||||
@@ -164,6 +176,12 @@ class NoteListComponent extends React.Component {
|
|||||||
|
|
||||||
const hPadding = 10;
|
const hPadding = 10;
|
||||||
|
|
||||||
|
let highlightedWords = [];
|
||||||
|
if (this.props.notesParentType === 'Search') {
|
||||||
|
const search = BaseModel.byId(this.props.searches, this.props.selectedSearchId);
|
||||||
|
highlightedWords = search ? Search.keywords(search.query_pattern) : [];
|
||||||
|
}
|
||||||
|
|
||||||
let style = Object.assign({ width: width }, this.style().listItem);
|
let style = Object.assign({ width: width }, this.style().listItem);
|
||||||
|
|
||||||
if (this.props.selectedNoteIds.indexOf(item.id) >= 0) {
|
if (this.props.selectedNoteIds.indexOf(item.id) >= 0) {
|
||||||
@@ -182,8 +200,30 @@ class NoteListComponent extends React.Component {
|
|||||||
listItemTitleStyle.paddingLeft = !checkbox ? hPadding : 4;
|
listItemTitleStyle.paddingLeft = !checkbox ? hPadding : 4;
|
||||||
if (item.is_todo && !!item.todo_completed) listItemTitleStyle = Object.assign(listItemTitleStyle, this.style().listItemTitleCompleted);
|
if (item.is_todo && !!item.todo_completed) listItemTitleStyle = Object.assign(listItemTitleStyle, this.style().listItemTitleCompleted);
|
||||||
|
|
||||||
|
let displayTitle = Note.displayTitle(item);
|
||||||
|
let titleComp = null;
|
||||||
|
|
||||||
|
if (highlightedWords.length) {
|
||||||
|
const titleElement = document.createElement('span');
|
||||||
|
titleElement.textContent = displayTitle;
|
||||||
|
const mark = new Mark(titleElement, {
|
||||||
|
exclude: ['img'],
|
||||||
|
acrossElements: true,
|
||||||
|
});
|
||||||
|
mark.mark(highlightedWords);
|
||||||
|
|
||||||
|
// Note: in this case it is safe to use dangerouslySetInnerHTML because titleElement
|
||||||
|
// is a span tag that we created and that contains data that's been inserted as plain text
|
||||||
|
// with `textContent` so it cannot contain any XSS attacks. We use this feature because
|
||||||
|
// mark.js can only deal with DOM elements.
|
||||||
|
// https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
|
||||||
|
titleComp = <span dangerouslySetInnerHTML={{ __html: titleElement.outerHTML }}></span>
|
||||||
|
} else {
|
||||||
|
titleComp = <span>{displayTitle}</span>
|
||||||
|
}
|
||||||
|
|
||||||
// Need to include "todo_completed" in key so that checkbox is updated when
|
// Need to include "todo_completed" in key so that checkbox is updated when
|
||||||
// item is changed via sync.
|
// item is changed via sync.
|
||||||
return <div key={item.id + '_' + item.todo_completed} style={style}>
|
return <div key={item.id + '_' + item.todo_completed} style={style}>
|
||||||
{checkbox}
|
{checkbox}
|
||||||
<a
|
<a
|
||||||
@@ -196,7 +236,7 @@ class NoteListComponent extends React.Component {
|
|||||||
onDragStart={(event) => onDragStart(event) }
|
onDragStart={(event) => onDragStart(event) }
|
||||||
data-id={item.id}
|
data-id={item.id}
|
||||||
>
|
>
|
||||||
{Note.displayTitle(item)}
|
{titleComp}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -239,7 +279,9 @@ const mapStateToProps = (state) => {
|
|||||||
folders: state.folders,
|
folders: state.folders,
|
||||||
selectedNoteIds: state.selectedNoteIds,
|
selectedNoteIds: state.selectedNoteIds,
|
||||||
theme: state.settings.theme,
|
theme: state.settings.theme,
|
||||||
// uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
|
notesParentType: state.notesParentType,
|
||||||
|
searches: state.searches,
|
||||||
|
selectedSearchId: state.selectedSearchId,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
47
ElectronClient/app/gui/NoteStatusBar.jsx
Normal file
47
ElectronClient/app/gui/NoteStatusBar.jsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const { connect } = require('react-redux');
|
||||||
|
const { time } = require('lib/time-utils.js');
|
||||||
|
const { themeStyle } = require('../theme.js');
|
||||||
|
const { _ } = require('lib/locale.js');
|
||||||
|
|
||||||
|
class NoteStatusBarComponent extends React.Component {
|
||||||
|
|
||||||
|
style() {
|
||||||
|
const theme = themeStyle(this.props.theme);
|
||||||
|
|
||||||
|
const itemHeight = 34;
|
||||||
|
|
||||||
|
let style = {
|
||||||
|
root: Object.assign({}, theme.textStyle, {
|
||||||
|
backgroundColor: theme.backgroundColor,
|
||||||
|
color: theme.colorFaded,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const theme = themeStyle(this.props.theme);
|
||||||
|
const style = this.props.style;
|
||||||
|
const note = this.props.note;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={this.style().root}>{time.formatMsToLocal(note.user_updated_time)}</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
// notes: state.notes,
|
||||||
|
// folders: state.folders,
|
||||||
|
// selectedNoteIds: state.selectedNoteIds,
|
||||||
|
theme: state.settings.theme,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const NoteStatusBar = connect(mapStateToProps)(NoteStatusBarComponent);
|
||||||
|
|
||||||
|
module.exports = { NoteStatusBar };
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
const React = require('react');
|
const React = require('react');
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
const BaseItem = require('lib/models/BaseItem.js');
|
||||||
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
|
const Search = require('lib/models/Search.js');
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { IconButton } = require('./IconButton.min.js');
|
const { IconButton } = require('./IconButton.min.js');
|
||||||
@@ -74,7 +77,6 @@ class NoteTextComponent extends React.Component {
|
|||||||
mdToHtml() {
|
mdToHtml() {
|
||||||
if (this.mdToHtml_) return this.mdToHtml_;
|
if (this.mdToHtml_) return this.mdToHtml_;
|
||||||
this.mdToHtml_ = new MdToHtml({
|
this.mdToHtml_ = new MdToHtml({
|
||||||
supportsResourceLinks: true,
|
|
||||||
resourceBaseUrl: 'file://' + Setting.value('resourceDir') + '/',
|
resourceBaseUrl: 'file://' + Setting.value('resourceDir') + '/',
|
||||||
});
|
});
|
||||||
return this.mdToHtml_;
|
return this.mdToHtml_;
|
||||||
@@ -195,7 +197,9 @@ class NoteTextComponent extends React.Component {
|
|||||||
this.editorSetScrollTop(1);
|
this.editorSetScrollTop(1);
|
||||||
this.restoreScrollTop_ = 0;
|
this.restoreScrollTop_ = 0;
|
||||||
|
|
||||||
if (note) {
|
// If a search is in progress we don't focus any field otherwise it will
|
||||||
|
// take the focus out of the search box.
|
||||||
|
if (note && this.props.notesParentType !== 'Search') {
|
||||||
const focusSettingName = !!note.is_todo ? 'newTodoFocus' : 'newNoteFocus';
|
const focusSettingName = !!note.is_todo ? 'newTodoFocus' : 'newNoteFocus';
|
||||||
|
|
||||||
if (Setting.value(focusSettingName) === 'title') {
|
if (Setting.value(focusSettingName) === 'title') {
|
||||||
@@ -206,10 +210,22 @@ class NoteTextComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.editor_) {
|
if (this.editor_) {
|
||||||
const session = this.editor_.editor.getSession();
|
// Calling setValue here does two things:
|
||||||
const undoManager = session.getUndoManager();
|
// 1. It sets the initial value as recorded by the undo manager. If we were to set it instead to "" and wait for the render
|
||||||
undoManager.reset();
|
// phase to set the value, the initial value would still be "", which means pressing "undo" on a note that has just loaded
|
||||||
session.setUndoManager(undoManager);
|
// would clear it.
|
||||||
|
// 2. It resets the undo manager - fixes https://github.com/laurent22/joplin/issues/355
|
||||||
|
// Note: calling undoManager.reset() doesn't work
|
||||||
|
try {
|
||||||
|
this.editor_.editor.getSession().setValue(note ? note.body : '');
|
||||||
|
} catch (error) {
|
||||||
|
if (error.message === "Cannot read property 'match' of undefined") {
|
||||||
|
// The internals of Ace Editor throws an exception when creating a new note,
|
||||||
|
// but that can be ignored.
|
||||||
|
} else {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.editor_.editor.clearSelection();
|
this.editor_.editor.clearSelection();
|
||||||
this.editor_.editor.moveCursorTo(0,0);
|
this.editor_.editor.moveCursorTo(0,0);
|
||||||
}
|
}
|
||||||
@@ -318,11 +334,29 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
menu.popup(bridge().window());
|
menu.popup(bridge().window());
|
||||||
} else if (msg.indexOf('joplin://') === 0) {
|
} else if (msg.indexOf('joplin://') === 0) {
|
||||||
const resourceId = msg.substr('joplin://'.length);
|
const itemId = msg.substr('joplin://'.length);
|
||||||
Resource.load(resourceId).then((resource) => {
|
const item = await BaseItem.loadItemById(itemId);
|
||||||
const filePath = Resource.fullPath(resource);
|
|
||||||
|
if (!item) throw new Error('No item with ID ' + itemId);
|
||||||
|
|
||||||
|
if (item.type_ === BaseModel.TYPE_RESOURCE) {
|
||||||
|
const filePath = Resource.fullPath(item);
|
||||||
bridge().openItem(filePath);
|
bridge().openItem(filePath);
|
||||||
});
|
} else if (item.type_ === BaseModel.TYPE_NOTE) {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: "FOLDER_SELECT",
|
||||||
|
id: item.parent_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'NOTE_SELECT',
|
||||||
|
id: item.id,
|
||||||
|
});
|
||||||
|
}, 10);
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported item type: ' + item.type_);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bridge().showErrorMessageBox(_('Unsupported link or message: %s', msg));
|
bridge().showErrorMessageBox(_('Unsupported link or message: %s', msg));
|
||||||
}
|
}
|
||||||
@@ -393,6 +427,18 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
if (this.editor_) {
|
if (this.editor_) {
|
||||||
this.editor_.editor.renderer.on('afterRender', this.onAfterEditorRender_);
|
this.editor_.editor.renderer.on('afterRender', this.onAfterEditorRender_);
|
||||||
|
|
||||||
|
const cancelledKeys = ['Ctrl+F', 'Ctrl+T', 'Ctrl+P', 'Ctrl+Q', 'Ctrl+L', 'Ctrl+,'];
|
||||||
|
for (let i = 0; i < cancelledKeys.length; i++) {
|
||||||
|
const k = cancelledKeys[i];
|
||||||
|
this.editor_.editor.commands.bindKey(k, () => {
|
||||||
|
// HACK: Ace doesn't seem to provide a way to override its shortcuts, but throwing
|
||||||
|
// an exception from this undocumented function seems to cancel it without any
|
||||||
|
// side effect.
|
||||||
|
// https://stackoverflow.com/questions/36075846
|
||||||
|
throw new Error('HACK: Overriding Ace Editor shortcut: ' + k);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,6 +530,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reg.logger().error(error);
|
reg.logger().error(error);
|
||||||
|
bridge().showErrorMessageBox(error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,6 +613,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
marginBottom: 0,
|
marginBottom: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
};
|
};
|
||||||
|
|
||||||
const titleEditorStyle = {
|
const titleEditorStyle = {
|
||||||
@@ -642,6 +690,10 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
const html = this.mdToHtml().render(bodyToRender, theme, mdOptions);
|
const html = this.mdToHtml().render(bodyToRender, theme, mdOptions);
|
||||||
this.webview_.send('setHtml', html);
|
this.webview_.send('setHtml', html);
|
||||||
|
|
||||||
|
const search = BaseModel.byId(this.props.searches, this.props.selectedSearchId);
|
||||||
|
const keywords = search ? Search.keywords(search.query_pattern) : [];
|
||||||
|
this.webview_.send('setMarkers', keywords);
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolbarItems = [];
|
const toolbarItems = [];
|
||||||
@@ -685,6 +737,8 @@ class NoteTextComponent extends React.Component {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
}} iconName="fa-caret-down" theme={this.props.theme} onClick={() => { this.itemContextMenu() }} />
|
}} iconName="fa-caret-down" theme={this.props.theme} onClick={() => { this.itemContextMenu() }} />
|
||||||
|
|
||||||
|
const titleBarDate = <span style={Object.assign({}, theme.textStyle, {color: theme.colorFaded})}>{time.formatMsToLocal(note.user_updated_time)}</span>
|
||||||
|
|
||||||
const viewer = <webview
|
const viewer = <webview
|
||||||
style={viewerStyle}
|
style={viewerStyle}
|
||||||
nodeintegration="1"
|
nodeintegration="1"
|
||||||
@@ -692,6 +746,24 @@ class NoteTextComponent extends React.Component {
|
|||||||
ref={(elem) => { this.webview_ref(elem); } }
|
ref={(elem) => { this.webview_ref(elem); } }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
// const markers = [{
|
||||||
|
// startRow: 2,
|
||||||
|
// startCol: 3,
|
||||||
|
// endRow: 2,
|
||||||
|
// endCol: 6,
|
||||||
|
// type: 'text',
|
||||||
|
// className: 'test-marker'
|
||||||
|
// }];
|
||||||
|
|
||||||
|
// markers={markers}
|
||||||
|
// editorProps={{$useWorker: false}}
|
||||||
|
|
||||||
|
// #note-editor .test-marker {
|
||||||
|
// background-color: red;
|
||||||
|
// color: yellow;
|
||||||
|
// position: absolute;
|
||||||
|
// }
|
||||||
|
|
||||||
const editorRootStyle = Object.assign({}, editorStyle);
|
const editorRootStyle = Object.assign({}, editorStyle);
|
||||||
delete editorRootStyle.width;
|
delete editorRootStyle.width;
|
||||||
delete editorRootStyle.height;
|
delete editorRootStyle.height;
|
||||||
@@ -718,14 +790,15 @@ class NoteTextComponent extends React.Component {
|
|||||||
editorProps={{$blockScrolling: true}}
|
editorProps={{$blockScrolling: true}}
|
||||||
|
|
||||||
// This is buggy (gets outside the container)
|
// This is buggy (gets outside the container)
|
||||||
highlightActiveLine={false}
|
highlightActiveLine={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={rootStyle}>
|
<div style={rootStyle}>
|
||||||
<div style={titleBarStyle}>
|
<div style={titleBarStyle}>
|
||||||
{ titleEditor }
|
{ titleEditor }
|
||||||
{ titleBarMenuButton }
|
{ titleBarDate }
|
||||||
|
{ false ? titleBarMenuButton : null }
|
||||||
</div>
|
</div>
|
||||||
{ toolbar }
|
{ toolbar }
|
||||||
{ editor }
|
{ editor }
|
||||||
@@ -747,6 +820,9 @@ const mapStateToProps = (state) => {
|
|||||||
syncStarted: state.syncStarted,
|
syncStarted: state.syncStarted,
|
||||||
newNote: state.newNote,
|
newNote: state.newNote,
|
||||||
windowCommand: state.windowCommand,
|
windowCommand: state.windowCommand,
|
||||||
|
notesParentType: state.notesParentType,
|
||||||
|
searches: state.searches,
|
||||||
|
selectedSearchId: state.selectedSearchId,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const Setting = require('lib/models/Setting.js');
|
|||||||
|
|
||||||
const { MainScreen } = require('./MainScreen.min.js');
|
const { MainScreen } = require('./MainScreen.min.js');
|
||||||
const { OneDriveLoginScreen } = require('./OneDriveLoginScreen.min.js');
|
const { OneDriveLoginScreen } = require('./OneDriveLoginScreen.min.js');
|
||||||
|
const { DropboxLoginScreen } = require('./DropboxLoginScreen.min.js');
|
||||||
const { StatusScreen } = require('./StatusScreen.min.js');
|
const { StatusScreen } = require('./StatusScreen.min.js');
|
||||||
const { ImportScreen } = require('./ImportScreen.min.js');
|
const { ImportScreen } = require('./ImportScreen.min.js');
|
||||||
const { ConfigScreen } = require('./ConfigScreen.min.js');
|
const { ConfigScreen } = require('./ConfigScreen.min.js');
|
||||||
@@ -46,6 +47,11 @@ async function initialize(dispatch) {
|
|||||||
type: 'NOTE_VISIBLE_PANES_SET',
|
type: 'NOTE_VISIBLE_PANES_SET',
|
||||||
panes: Setting.value('noteVisiblePanes'),
|
panes: Setting.value('noteVisiblePanes'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
store.dispatch({
|
||||||
|
type: 'SIDEBAR_VISIBILITY_SET',
|
||||||
|
visibility: Setting.value('sidebarVisibility')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class RootComponent extends React.Component {
|
class RootComponent extends React.Component {
|
||||||
@@ -75,6 +81,7 @@ class RootComponent extends React.Component {
|
|||||||
const screens = {
|
const screens = {
|
||||||
Main: { screen: MainScreen },
|
Main: { screen: MainScreen },
|
||||||
OneDriveLogin: { screen: OneDriveLoginScreen, title: () => _('OneDrive Login') },
|
OneDriveLogin: { screen: OneDriveLoginScreen, title: () => _('OneDrive Login') },
|
||||||
|
DropboxLogin: { screen: DropboxLoginScreen, title: () => _('Dropbox Login') },
|
||||||
Import: { screen: ImportScreen, title: () => _('Import') },
|
Import: { screen: ImportScreen, title: () => _('Import') },
|
||||||
Config: { screen: ConfigScreen, title: () => _('Options') },
|
Config: { screen: ConfigScreen, title: () => _('Options') },
|
||||||
Status: { screen: StatusScreen, title: () => _('Synchronisation Status') },
|
Status: { screen: StatusScreen, title: () => _('Synchronisation Status') },
|
||||||
|
|||||||
@@ -14,6 +14,57 @@ const MenuItem = bridge().MenuItem;
|
|||||||
const InteropServiceHelper = require("../InteropServiceHelper.js");
|
const InteropServiceHelper = require("../InteropServiceHelper.js");
|
||||||
|
|
||||||
class SideBarComponent extends React.Component {
|
class SideBarComponent extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.onFolderDragStart_ = (event) => {
|
||||||
|
const folderId = event.currentTarget.getAttribute('folderid');
|
||||||
|
if (!folderId) return;
|
||||||
|
|
||||||
|
event.dataTransfer.setDragImage(new Image(), 1, 1);
|
||||||
|
event.dataTransfer.clearData();
|
||||||
|
event.dataTransfer.setData('text/x-jop-folder-ids', JSON.stringify([folderId]));
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onFolderDragOver_ = (event) => {
|
||||||
|
if (event.dataTransfer.types.indexOf("text/x-jop-note-ids") >= 0) event.preventDefault();
|
||||||
|
if (event.dataTransfer.types.indexOf("text/x-jop-folder-ids") >= 0) event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onFolderDrop_ = async (event) => {
|
||||||
|
const folderId = event.currentTarget.getAttribute('folderid');
|
||||||
|
const dt = event.dataTransfer;
|
||||||
|
if (!dt) return;
|
||||||
|
|
||||||
|
if (dt.types.indexOf("text/x-jop-note-ids") >= 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const noteIds = JSON.parse(dt.getData("text/x-jop-note-ids"));
|
||||||
|
for (let i = 0; i < noteIds.length; i++) {
|
||||||
|
await Note.moveToFolder(noteIds[i], folderId);
|
||||||
|
}
|
||||||
|
} else if (dt.types.indexOf("text/x-jop-folder-ids") >= 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const folderIds = JSON.parse(dt.getData("text/x-jop-folder-ids"));
|
||||||
|
for (let i = 0; i < folderIds.length; i++) {
|
||||||
|
await Folder.moveToFolder(folderIds[i], folderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onFolderToggleClick_ = async (event) => {
|
||||||
|
const folderId = event.currentTarget.getAttribute('folderid');
|
||||||
|
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'FOLDER_TOGGLE',
|
||||||
|
id: folderId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
style() {
|
style() {
|
||||||
const theme = themeStyle(this.props.theme);
|
const theme = themeStyle(this.props.theme);
|
||||||
|
|
||||||
@@ -23,23 +74,39 @@ class SideBarComponent extends React.Component {
|
|||||||
root: {
|
root: {
|
||||||
backgroundColor: theme.backgroundColor2,
|
backgroundColor: theme.backgroundColor2,
|
||||||
},
|
},
|
||||||
listItem: {
|
listItemContainer: {
|
||||||
|
boxSizing: "border-box",
|
||||||
height: itemHeight,
|
height: itemHeight,
|
||||||
|
// paddingLeft: 14,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "stretch",
|
||||||
|
},
|
||||||
|
listItem: {
|
||||||
fontFamily: theme.fontFamily,
|
fontFamily: theme.fontFamily,
|
||||||
fontSize: theme.fontSize,
|
fontSize: theme.fontSize,
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
boxSizing: "border-box",
|
|
||||||
color: theme.color2,
|
color: theme.color2,
|
||||||
paddingLeft: 14,
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
cursor: "default",
|
cursor: "default",
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
|
display: "flex",
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
listItemSelected: {
|
listItemSelected: {
|
||||||
backgroundColor: theme.selectedColor2,
|
backgroundColor: theme.selectedColor2,
|
||||||
},
|
},
|
||||||
|
listItemExpandIcon: {
|
||||||
|
color: theme.color2,
|
||||||
|
cursor: "default",
|
||||||
|
opacity: 0.8,
|
||||||
|
// fontFamily: theme.fontFamily,
|
||||||
|
fontSize: theme.fontSize,
|
||||||
|
textDecoration: "none",
|
||||||
|
paddingRight: 5,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
conflictFolder: {
|
conflictFolder: {
|
||||||
color: theme.colorError2,
|
color: theme.colorError2,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
@@ -89,6 +156,10 @@ class SideBarComponent extends React.Component {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
style.tagItem = Object.assign({}, style.listItem);
|
||||||
|
style.tagItem.paddingLeft = 23;
|
||||||
|
style.tagItem.height = itemHeight;
|
||||||
|
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +172,7 @@ class SideBarComponent extends React.Component {
|
|||||||
|
|
||||||
let deleteMessage = "";
|
let deleteMessage = "";
|
||||||
if (itemType === BaseModel.TYPE_FOLDER) {
|
if (itemType === BaseModel.TYPE_FOLDER) {
|
||||||
deleteMessage = _("Delete notebook? All notes within this notebook will also be deleted.");
|
deleteMessage = _("Delete notebook? All notes and sub-notebooks within this notebook will also be deleted.");
|
||||||
} else if (itemType === BaseModel.TYPE_TAG) {
|
} else if (itemType === BaseModel.TYPE_TAG) {
|
||||||
deleteMessage = _("Remove this tag from all the notes?");
|
deleteMessage = _("Remove this tag from all the notes?");
|
||||||
} else if (itemType === BaseModel.TYPE_SEARCH) {
|
} else if (itemType === BaseModel.TYPE_SEARCH) {
|
||||||
@@ -150,6 +221,19 @@ class SideBarComponent extends React.Component {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// menu.append(
|
||||||
|
// new MenuItem({
|
||||||
|
// label: _("Move"),
|
||||||
|
// click: async () => {
|
||||||
|
// this.props.dispatch({
|
||||||
|
// type: "WINDOW_COMMAND",
|
||||||
|
// name: "renameFolder",
|
||||||
|
// id: itemId,
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
|
||||||
menu.append(new MenuItem({ type: "separator" }));
|
menu.append(new MenuItem({ type: "separator" }));
|
||||||
|
|
||||||
const InteropService = require("lib/services/InteropService.js");
|
const InteropService = require("lib/services/InteropService.js");
|
||||||
@@ -194,53 +278,51 @@ class SideBarComponent extends React.Component {
|
|||||||
await shared.synchronize_press(this);
|
await shared.synchronize_press(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
folderItem(folder, selected) {
|
folderItem(folder, selected, hasChildren, depth) {
|
||||||
let style = Object.assign({}, this.style().listItem);
|
let style = Object.assign({}, this.style().listItem);
|
||||||
if (selected) style = Object.assign(style, this.style().listItemSelected);
|
|
||||||
if (folder.id === Folder.conflictFolderId()) style = Object.assign(style, this.style().conflictFolder);
|
if (folder.id === Folder.conflictFolderId()) style = Object.assign(style, this.style().conflictFolder);
|
||||||
|
|
||||||
const onDragOver = (event, folder) => {
|
|
||||||
if (event.dataTransfer.types.indexOf("text/x-jop-note-ids") >= 0) event.preventDefault();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDrop = async (event, folder) => {
|
|
||||||
if (event.dataTransfer.types.indexOf("text/x-jop-note-ids") < 0) return;
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const noteIds = JSON.parse(event.dataTransfer.getData("text/x-jop-note-ids"));
|
|
||||||
for (let i = 0; i < noteIds.length; i++) {
|
|
||||||
await Note.moveToFolder(noteIds[i], folder.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const itemTitle = Folder.displayTitle(folder);
|
const itemTitle = Folder.displayTitle(folder);
|
||||||
|
|
||||||
|
let containerStyle = Object.assign({}, this.style().listItemContainer);
|
||||||
|
// containerStyle.paddingLeft = containerStyle.paddingLeft + depth * 10;
|
||||||
|
|
||||||
|
if (selected) containerStyle = Object.assign(containerStyle, this.style().listItemSelected);
|
||||||
|
|
||||||
|
let expandLinkStyle = Object.assign({}, this.style().listItemExpandIcon);
|
||||||
|
let expandIconStyle = {
|
||||||
|
visibility: hasChildren ? 'visible' : 'hidden',
|
||||||
|
paddingLeft: 8 + depth * 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'fa-plus-square' : 'fa-minus-square';
|
||||||
|
const expandIcon = <i style={expandIconStyle} className={"fa " + iconName}></i>
|
||||||
|
const expandLink = hasChildren ? <a style={expandLinkStyle} href="#" folderid={folder.id} onClick={this.onFolderToggleClick_}>{expandIcon}</a> : <span style={expandLinkStyle}>{expandIcon}</span>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<div className="list-item-container" style={containerStyle} key={folder.id} onDragStart={this.onFolderDragStart_} onDragOver={this.onFolderDragOver_} onDrop={this.onFolderDrop_} draggable={true} folderid={folder.id}>
|
||||||
className="list-item"
|
{ expandLink }
|
||||||
onDragOver={event => {
|
<a
|
||||||
onDragOver(event, folder);
|
className="list-item"
|
||||||
}}
|
href="#"
|
||||||
onDrop={event => {
|
data-id={folder.id}
|
||||||
onDrop(event, folder);
|
data-type={BaseModel.TYPE_FOLDER}
|
||||||
}}
|
onContextMenu={event => this.itemContextMenu(event)}
|
||||||
href="#"
|
style={style}
|
||||||
data-id={folder.id}
|
folderid={folder.id}
|
||||||
data-type={BaseModel.TYPE_FOLDER}
|
onClick={() => {
|
||||||
onContextMenu={event => this.itemContextMenu(event)}
|
this.folderItem_click(folder);
|
||||||
key={folder.id}
|
}}
|
||||||
style={style}
|
onDoubleClick={this.onFolderToggleClick_}
|
||||||
onClick={() => {
|
>
|
||||||
this.folderItem_click(folder);
|
{itemTitle}
|
||||||
}}
|
</a>
|
||||||
>
|
</div>
|
||||||
{itemTitle}
|
|
||||||
</a>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
tagItem(tag, selected) {
|
tagItem(tag, selected) {
|
||||||
let style = Object.assign({}, this.style().listItem);
|
let style = Object.assign({}, this.style().tagItem);
|
||||||
if (selected) style = Object.assign(style, this.style().listItemSelected);
|
if (selected) style = Object.assign(style, this.style().listItemSelected);
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
@@ -285,11 +367,11 @@ class SideBarComponent extends React.Component {
|
|||||||
return <div style={{ height: 2, backgroundColor: "blue" }} key={key} />;
|
return <div style={{ height: 2, backgroundColor: "blue" }} key={key} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeHeader(key, label, iconName) {
|
makeHeader(key, label, iconName, extraProps = {}) {
|
||||||
const style = this.style().header;
|
const style = this.style().header;
|
||||||
const icon = <i style={{ fontSize: style.fontSize * 1.2, marginRight: 5 }} className={"fa " + iconName} />;
|
const icon = <i style={{ fontSize: style.fontSize * 1.2, marginRight: 5 }} className={"fa " + iconName} />;
|
||||||
return (
|
return (
|
||||||
<div style={style} key={key}>
|
<div style={style} key={key} {...extraProps}>
|
||||||
{icon}
|
{icon}
|
||||||
{label}
|
{label}
|
||||||
</div>
|
</div>
|
||||||
@@ -326,7 +408,10 @@ class SideBarComponent extends React.Component {
|
|||||||
|
|
||||||
let items = [];
|
let items = [];
|
||||||
|
|
||||||
items.push(this.makeHeader("folderHeader", _("Notebooks"), "fa-folder-o"));
|
items.push(this.makeHeader("folderHeader", _("Notebooks"), "fa-folder-o", {
|
||||||
|
onDrop: this.onFolderDrop_,
|
||||||
|
folderid: '',
|
||||||
|
}));
|
||||||
|
|
||||||
if (this.props.folders.length) {
|
if (this.props.folders.length) {
|
||||||
const folderItems = shared.renderFolders(this.props, this.folderItem.bind(this));
|
const folderItems = shared.renderFolders(this.props, this.folderItem.bind(this));
|
||||||
@@ -345,18 +430,6 @@ class SideBarComponent extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.searches.length) {
|
|
||||||
items.push(this.makeHeader("searchHeader", _("Searches"), "fa-search"));
|
|
||||||
|
|
||||||
const searchItems = shared.renderSearches(this.props, this.searchItem.bind(this));
|
|
||||||
|
|
||||||
items.push(
|
|
||||||
<div className="searches" key="search_items">
|
|
||||||
{searchItems}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let lines = Synchronizer.reportToLines(this.props.syncReport);
|
let lines = Synchronizer.reportToLines(this.props.syncReport);
|
||||||
const syncReportText = [];
|
const syncReportText = [];
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
@@ -396,6 +469,7 @@ const mapStateToProps = state => {
|
|||||||
notesParentType: state.notesParentType,
|
notesParentType: state.notesParentType,
|
||||||
locale: state.settings.locale,
|
locale: state.settings.locale,
|
||||||
theme: state.settings.theme,
|
theme: state.settings.theme,
|
||||||
|
collapsedFolderIds: state.collapsedFolderIds,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -13,12 +15,18 @@
|
|||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background: #CF3F00;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.katex { font-size: 1.3em; } /* This controls the global Katex font size*/
|
.katex { font-size: 1.3em; } /* This controls the global Katex font size*/
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body id="body">
|
<body id="body">
|
||||||
<div id="hlScriptContainer"></div>
|
<div id="hlScriptContainer"></div>
|
||||||
|
<div id="markScriptContainer"></div>
|
||||||
<div id="content" ondragstart="return false;" ondrop="return false;"></div>
|
<div id="content" ondragstart="return false;" ondrop="return false;"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -38,7 +46,7 @@
|
|||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
script.onload = function () {
|
script.onload = function () {
|
||||||
hljsLoaded = true;
|
hljsLoaded = true;
|
||||||
applyHljs();
|
applyHljs();
|
||||||
};
|
};
|
||||||
script.src = 'highlight/highlight.pack.js';
|
script.src = 'highlight/highlight.pack.js';
|
||||||
document.getElementById('hlScriptContainer').appendChild(script);
|
document.getElementById('hlScriptContainer').appendChild(script);
|
||||||
@@ -116,17 +124,17 @@
|
|||||||
loadAndApplyHljs();
|
loadAndApplyHljs();
|
||||||
|
|
||||||
// Remove the bullet from "ul" for checkbox lists and extra padding
|
// Remove the bullet from "ul" for checkbox lists and extra padding
|
||||||
const checkboxes = document.getElementsByClassName('checkbox');
|
// const checkboxes = document.getElementsByClassName('checkbox');
|
||||||
for (let i = 0; i < checkboxes.length; i++) {
|
// for (let i = 0; i < checkboxes.length; i++) {
|
||||||
const cb = checkboxes[i];
|
// const cb = checkboxes[i];
|
||||||
const ul = cb.parentElement.parentElement;
|
// const ul = cb.parentElement.parentElement;
|
||||||
if (!ul) {
|
// if (!ul) {
|
||||||
console.warn('Unexpected layout for checkbox');
|
// console.warn('Unexpected layout for checkbox');
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
ul.style.listStyleType = 'none';
|
// ul.style.listStyleType = 'none';
|
||||||
ul.style.paddingLeft = 0;
|
// ul.style.paddingLeft = 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
let previousContentHeight = contentElement.scrollHeight;
|
let previousContentHeight = contentElement.scrollHeight;
|
||||||
let startTime = Date.now();
|
let startTime = Date.now();
|
||||||
@@ -160,6 +168,36 @@
|
|||||||
setPercentScroll(percent);
|
setPercentScroll(percent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mark_ = null;
|
||||||
|
function setMarkers(keywords) {
|
||||||
|
if (!mark_) {
|
||||||
|
mark_ = new Mark(document.getElementById('content'), {
|
||||||
|
exclude: ['img'],
|
||||||
|
acrossElements: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_.mark(keywords);
|
||||||
|
}
|
||||||
|
|
||||||
|
let markLoaded_ = false;
|
||||||
|
ipcRenderer.on('setMarkers', (event, keywords) => {
|
||||||
|
if (!keywords.length && !markLoaded_) return;
|
||||||
|
|
||||||
|
if (!markLoaded_) {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.onload = function() {
|
||||||
|
setMarkers(keywords);
|
||||||
|
};
|
||||||
|
|
||||||
|
script.src = '../../node_modules/mark.js/dist/mark.min.js';
|
||||||
|
document.getElementById('markScriptContainer').appendChild(script);
|
||||||
|
markLoaded_ = true;
|
||||||
|
} else {
|
||||||
|
setMarkers(keywords);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function maxScrollTop() {
|
function maxScrollTop() {
|
||||||
return Math.max(0, contentElement.scrollHeight - contentElement.clientHeight);
|
return Math.max(0, contentElement.scrollHeight - contentElement.clientHeight);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
.smalltalk .page {
|
.smalltalk .page {
|
||||||
max-width: 30em;
|
max-width: 30em;
|
||||||
}
|
}
|
||||||
|
mark {
|
||||||
|
background: #CF3F00;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
1
ElectronClient/app/locales/cs_CZ.json
Normal file
1
ElectronClient/app/locales/cs_CZ.json
Normal file
File diff suppressed because one or more lines are too long
1
ElectronClient/app/locales/da_DK.json
Normal file
1
ElectronClient/app/locales/da_DK.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
ElectronClient/app/locales/gl_ES.json
Normal file
1
ElectronClient/app/locales/gl_ES.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,9 +1,12 @@
|
|||||||
var locales = {};
|
var locales = {};
|
||||||
locales['en_GB'] = require('./en_GB.json');
|
locales['en_GB'] = require('./en_GB.json');
|
||||||
|
locales['cs_CZ'] = require('./cs_CZ.json');
|
||||||
|
locales['da_DK'] = require('./da_DK.json');
|
||||||
locales['de_DE'] = require('./de_DE.json');
|
locales['de_DE'] = require('./de_DE.json');
|
||||||
locales['es_ES'] = require('./es_ES.json');
|
locales['es_ES'] = require('./es_ES.json');
|
||||||
locales['eu'] = require('./eu.json');
|
locales['eu'] = require('./eu.json');
|
||||||
locales['fr_FR'] = require('./fr_FR.json');
|
locales['fr_FR'] = require('./fr_FR.json');
|
||||||
|
locales['gl_ES'] = require('./gl_ES.json');
|
||||||
locales['hr_HR'] = require('./hr_HR.json');
|
locales['hr_HR'] = require('./hr_HR.json');
|
||||||
locales['it_IT'] = require('./it_IT.json');
|
locales['it_IT'] = require('./it_IT.json');
|
||||||
locales['ja_JP'] = require('./ja_JP.json');
|
locales['ja_JP'] = require('./ja_JP.json');
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -24,11 +24,22 @@ function envFromArgs(args) {
|
|||||||
return 'prod';
|
return 'prod';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Likewise, we want to know if a profile is specified early, in particular
|
||||||
|
// to save the window state data.
|
||||||
|
function profileFromArgs(args) {
|
||||||
|
if (!args) return null;
|
||||||
|
const profileIndex = args.indexOf('--profile');
|
||||||
|
if (profileIndex <= 0 || profileIndex >= args.length - 1) return null;
|
||||||
|
const profileValue = args[profileIndex + 1];
|
||||||
|
return profileValue ? profileValue : null;
|
||||||
|
}
|
||||||
|
|
||||||
Logger.fsDriver_ = new FsDriverNode();
|
Logger.fsDriver_ = new FsDriverNode();
|
||||||
|
|
||||||
const env = envFromArgs(process.argv);
|
const env = envFromArgs(process.argv);
|
||||||
|
const profilePath = profileFromArgs(process.argv);
|
||||||
|
|
||||||
const wrapper = new ElectronAppWrapper(electronApp, env);
|
const wrapper = new ElectronAppWrapper(electronApp, env, profilePath);
|
||||||
|
|
||||||
initBridge(wrapper);
|
initBridge(wrapper);
|
||||||
|
|
||||||
|
|||||||
926
ElectronClient/app/package-lock.json
generated
926
ElectronClient/app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Joplin",
|
"name": "Joplin",
|
||||||
"version": "1.0.73",
|
"version": "1.0.89",
|
||||||
"description": "Joplin for Desktop",
|
"description": "Joplin for Desktop",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -26,7 +26,23 @@
|
|||||||
"build/icons/*"
|
"build/icons/*"
|
||||||
],
|
],
|
||||||
"win": {
|
"win": {
|
||||||
"icon": "../../Assets/Joplin.ico"
|
"icon": "../../Assets/Joplin.ico",
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"target": "nsis",
|
||||||
|
"arch": [
|
||||||
|
"x64",
|
||||||
|
"ia32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target": "portable",
|
||||||
|
"arch": [
|
||||||
|
"x64",
|
||||||
|
"ia32"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"nsis": {
|
"nsis": {
|
||||||
"oneClick": false,
|
"oneClick": false,
|
||||||
@@ -48,7 +64,7 @@
|
|||||||
"babel-cli": "^6.26.0",
|
"babel-cli": "^6.26.0",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
"electron": "^1.7.11",
|
"electron": "^1.7.11",
|
||||||
"electron-builder": "^20.2.0"
|
"electron-builder": "^20.10.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"7zip-bin-mac": "^1.0.1",
|
"7zip-bin-mac": "^1.0.1",
|
||||||
@@ -61,6 +77,7 @@
|
|||||||
"base-64": "^0.1.0",
|
"base-64": "^0.1.0",
|
||||||
"compare-versions": "^3.1.0",
|
"compare-versions": "^3.1.0",
|
||||||
"electron-context-menu": "^0.9.1",
|
"electron-context-menu": "^0.9.1",
|
||||||
|
"electron-is-dev": "^0.3.0",
|
||||||
"electron-window-state": "^4.1.1",
|
"electron-window-state": "^4.1.1",
|
||||||
"follow-redirects": "^1.2.5",
|
"follow-redirects": "^1.2.5",
|
||||||
"form-data": "^2.3.1",
|
"form-data": "^2.3.1",
|
||||||
@@ -71,6 +88,7 @@
|
|||||||
"katex": "^0.9.0-beta1",
|
"katex": "^0.9.0-beta1",
|
||||||
"levenshtein": "^1.0.5",
|
"levenshtein": "^1.0.5",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
|
"mark.js": "^8.11.1",
|
||||||
"markdown-it": "^8.4.0",
|
"markdown-it": "^8.4.0",
|
||||||
"markdown-it-katex": "^2.0.3",
|
"markdown-it-katex": "^2.0.3",
|
||||||
"md5": "^2.2.1",
|
"md5": "^2.2.1",
|
||||||
@@ -86,7 +104,6 @@
|
|||||||
"react-dom": "^16.0.0",
|
"react-dom": "^16.0.0",
|
||||||
"react-redux": "^5.0.6",
|
"react-redux": "^5.0.6",
|
||||||
"redux": "^3.7.2",
|
"redux": "^3.7.2",
|
||||||
"sharp": "^0.17.3",
|
|
||||||
"smalltalk": "^2.5.1",
|
"smalltalk": "^2.5.1",
|
||||||
"sprintf-js": "^1.1.1",
|
"sprintf-js": "^1.1.1",
|
||||||
"sqlite3": "^3.1.13",
|
"sqlite3": "^3.1.13",
|
||||||
@@ -96,6 +113,7 @@
|
|||||||
"tcp-port-used": "^0.1.2",
|
"tcp-port-used": "^0.1.2",
|
||||||
"url-parse": "^1.2.0",
|
"url-parse": "^1.2.0",
|
||||||
"uuid": "^3.1.0",
|
"uuid": "^3.1.0",
|
||||||
|
"valid-url": "^1.0.9",
|
||||||
"xml2js": "^0.4.19"
|
"xml2js": "^0.4.19"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,15 +34,15 @@ table td, table th {
|
|||||||
background-color: rgba(0,160,255,0.1) !important;
|
background-color: rgba(0,160,255,0.1) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-bar .list-item:hover,
|
/*.side-bar .list-item:hover,
|
||||||
.side-bar .synchronize-button:hover {
|
.side-bar .synchronize-button:hover {
|
||||||
background-color: #453E53;
|
background-color: #01427B;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-bar .list-item:active,
|
.side-bar .list-item:active,
|
||||||
.side-bar .synchronize-button:active {
|
.side-bar .synchronize-button:active {
|
||||||
background-color: #564B6C;
|
background-color: #0465BB;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
.editor-toolbar .button:not(.disabled):hover,
|
.editor-toolbar .button:not(.disabled):hover,
|
||||||
.header .button:not(.disabled):hover {
|
.header .button:not(.disabled):hover {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
|
|
||||||
const globalStyle = {
|
const globalStyle = {
|
||||||
fontSize: 12 * Setting.value('style.zoom')/100,
|
fontSize: 12 * Setting.value('style.zoom') / 100,
|
||||||
fontFamily: 'sans-serif',
|
fontFamily: 'sans-serif',
|
||||||
margin: 15, // No text and no interactive component should be within this margin
|
margin: 15, // No text and no interactive component should be within this margin
|
||||||
itemMarginTop: 10,
|
itemMarginTop: 10,
|
||||||
@@ -21,9 +21,11 @@ const globalStyle = {
|
|||||||
buttonMinHeight: 30,
|
buttonMinHeight: 30,
|
||||||
textAreaLineHeight: 17,
|
textAreaLineHeight: 17,
|
||||||
|
|
||||||
backgroundColor2: "#2B2634",
|
//backgroundColor2: "#2B2634",
|
||||||
|
backgroundColor2: "#162B3D",
|
||||||
color2: "#ffffff",
|
color2: "#ffffff",
|
||||||
selectedColor2: "#5A4D70",
|
//selectedColor2: "#5A4D70",
|
||||||
|
selectedColor2: "#0269C2",
|
||||||
colorError2: "#ff6c6c",
|
colorError2: "#ff6c6c",
|
||||||
|
|
||||||
warningBackgroundColor: "#FFD08D",
|
warningBackgroundColor: "#FFD08D",
|
||||||
@@ -60,6 +62,7 @@ globalStyle.icon = {
|
|||||||
globalStyle.lineInput = {
|
globalStyle.lineInput = {
|
||||||
color: globalStyle.color,
|
color: globalStyle.color,
|
||||||
backgroundColor: globalStyle.backgroundColor,
|
backgroundColor: globalStyle.backgroundColor,
|
||||||
|
fontFamily: globalStyle.fontFamily,
|
||||||
};
|
};
|
||||||
|
|
||||||
globalStyle.textStyle = {
|
globalStyle.textStyle = {
|
||||||
|
|||||||
191
README.md
191
README.md
@@ -1,14 +1,16 @@
|
|||||||
# Joplin
|
# Joplin
|
||||||
|
|
||||||
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=E8JMYD2LQ8MMA&lc=GB&item_name=Joplin+Development¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) [](https://joplin.cozic.net/donate/#bitcoin) [](https://travis-ci.org/laurent22/joplin) [](https://ci.appveyor.com/project/laurent22/joplin)
|
||||||
|
|
||||||
Joplin is a free, open source note taking and to-do application, which can handle a large number of notes organised into notebooks. The notes are searchable, can be copied, tagged and modified either from the applications directly or from your own text editor. The notes are in [Markdown format](#markdown).
|
Joplin is a free, open source note taking and to-do application, which can handle a large number of notes organised into notebooks. The notes are searchable, can be copied, tagged and modified either from the applications directly or from your own text editor. The notes are in [Markdown format](#markdown).
|
||||||
|
|
||||||
Notes exported from Evernote via .enex files [can be imported](#importing) into Joplin, including the formatted content (which is converted to Markdown), resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.). Plain Markdown files can also be imported.
|
Notes exported from Evernote via .enex files [can be imported](#importing) into Joplin, including the formatted content (which is converted to Markdown), resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.). Plain Markdown files can also be imported.
|
||||||
|
|
||||||
The notes can be [synchronised](#synchronisation) with various targets including [Nextcloud](https://nextcloud.com/), the file system (for example with a network directory) or with Microsoft OneDrive. When synchronising the notes, notebooks, tags and other metadata are saved to plain text files which can be easily inspected, backed up and moved around.
|
The notes can be [synchronised](#synchronisation) with various cloud services including [Nextcloud](https://nextcloud.com/), Dropbox, OneDrive or the file system (for example with a network directory). When synchronising the notes, notebooks, tags and other metadata are saved to plain text files which can be easily inspected, backed up and moved around.
|
||||||
|
|
||||||
The UI of the terminal client is built on top of the great [terminal-kit](https://github.com/cronvel/terminal-kit) library, the desktop client using [Electron](https://electronjs.org/), and the Android client front end is done using [React Native](https://facebook.github.io/react-native/).
|
The UI of the terminal client is built on top of the great [terminal-kit](https://github.com/cronvel/terminal-kit) library, the desktop client using [Electron](https://electronjs.org/), and the Android client front end is done using [React Native](https://facebook.github.io/react-native/).
|
||||||
|
|
||||||
<div class="top-screenshot"><img src="https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/AllClients.jpg" style="max-width: 100%; max-height: 35em;"></div>
|
<div class="top-screenshot"><img src="https://joplin.cozic.net/images/AllClients.jpg" style="max-width: 100%; max-height: 35em;"></div>
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
@@ -16,43 +18,60 @@ Three types of applications are available: for the **desktop** (Windows, macOS a
|
|||||||
|
|
||||||
## Desktop applications
|
## Desktop applications
|
||||||
|
|
||||||
Operating System | Download
|
Operating System | Download | Alternative
|
||||||
-----------------|--------
|
-----------------|--------|-------------------
|
||||||
Windows | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.70/Joplin-Setup-1.0.70.exe'><img alt='Get it on Windows' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeWindows.png'/></a>
|
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.89/Joplin-1.0.89.exe'><img alt='Get it on Windows' height="40px" src='https://joplin.cozic.net/images/BadgeWindows.png'/></a> |
|
||||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.70/Joplin-1.0.70.dmg'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeMacOS.png'/></a>
|
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.89/Joplin-1.0.89.dmg'><img alt='Get it on macOS' height="40px" src='https://joplin.cozic.net/images/BadgeMacOS.png'/></a> |
|
||||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.70/Joplin-1.0.70-x86_64.AppImage'><img alt='Get it on Linux' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeLinux.png'/></a>
|
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.89/Joplin-1.0.89-x86_64.AppImage'><img alt='Get it on Linux' height="40px" src='https://joplin.cozic.net/images/BadgeLinux.png'/></a> | An Arch Linux package [is also available](#terminal-application).
|
||||||
|
|
||||||
## Mobile applications
|
## Mobile applications
|
||||||
|
|
||||||
Operating System | Download | Alt. Download
|
Operating System | Download | Alt. Download
|
||||||
-----------------|----------|----------------
|
-----------------|----------|----------------
|
||||||
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.107/joplin-v1.0.107.apk)
|
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://joplin.cozic.net/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.123/joplin-v1.0.123.apk)
|
||||||
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeIOS.png'/></a> | -
|
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://joplin.cozic.net/images/BadgeIOS.png'/></a> | -
|
||||||
|
|
||||||
## Terminal application
|
## Terminal application
|
||||||
|
|
||||||
On macOS:
|
Operating system | Method
|
||||||
|
-----------------|----------------
|
||||||
brew install joplin
|
macOS | `brew install joplin`
|
||||||
|
Linux or Windows (via [WSL](https://msdn.microsoft.com/en-us/commandline/wsl/faq?f=255&MSPPError=-2147217396)) | **Important:** First, [install Node 8+](https://nodejs.org/en/download/package-manager/). Node 8 is LTS but not yet available everywhere so you might need to manually install it.<br/><br/>`NPM_CONFIG_PREFIX=~/.joplin-bin npm install -g joplin`<br/>`sudo ln -s ~/.joplin-bin/bin/joplin /usr/bin/joplin`<br><br>By default, the application binary will be installed under `~/.joplin-bin`. You may change this directory if needed. Alternatively, if your npm permissions are setup as described [here](https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-2-change-npms-default-directory-to-another-directory) (Option 2) then simply running `npm -g install joplin` would work.
|
||||||
On Linux or Windows (via [WSL](https://msdn.microsoft.com/en-us/commandline/wsl/faq?f=255&MSPPError=-2147217396)):
|
Arch Linux | An Arch Linux package is available [here](https://aur.archlinux.org/packages/joplin/). To install it, use an AUR wrapper such as yay: `yay -S joplin`. Both the CLI tool (type `joplin`) and desktop app (type `joplin-desktop`) are packaged. For support, please go to the [GitHub repo](https://github.com/masterkorp/joplin-pkgbuild).
|
||||||
|
|
||||||
**Important:** First, [install Node 8+](https://nodejs.org/en/download/package-manager/). Node 8 is LTS but not yet available everywhere so you might need to manually install it.
|
|
||||||
|
|
||||||
NPM_CONFIG_PREFIX=~/.joplin-bin npm install -g joplin
|
|
||||||
sudo ln -s ~/.joplin-bin/bin/joplin /usr/bin/joplin
|
|
||||||
|
|
||||||
By default, the application binary will be installed under `~/.joplin-bin`. You may change this directory if needed. Alternatively, if your npm permissions are setup as described [here](https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-2-change-npms-default-directory-to-another-directory) (Option 2) then simply running `npm -g install joplin` would work.
|
|
||||||
|
|
||||||
To start it, type `joplin`.
|
To start it, type `joplin`.
|
||||||
|
|
||||||
For usage information, please refer to the full [Joplin Terminal Application Documentation](http://joplin.cozic.net/terminal).
|
For usage information, please refer to the full [Joplin Terminal Application Documentation](https://joplin.cozic.net/terminal).
|
||||||
|
|
||||||
|
<!-- TOC -->
|
||||||
|
# Table of contents
|
||||||
|
|
||||||
|
- Applications
|
||||||
|
|
||||||
|
- [Desktop application](https://github.com/laurent22/joplin/blob/master/readme/desktop.md)
|
||||||
|
- [Mobile applications](https://github.com/laurent22/joplin/blob/master/readme/mobile.md)
|
||||||
|
- [Terminal application](https://github.com/laurent22/joplin/blob/master/readme/terminal.md)
|
||||||
|
|
||||||
|
- Support
|
||||||
|
|
||||||
|
- [Joplin Forum](https://discourse.joplin.cozic.net)
|
||||||
|
- [How to enable end-to-end encryption](https://github.com/laurent22/joplin/blob/master/readme/e2ee.md)
|
||||||
|
- [End-to-end encryption spec](https://github.com/laurent22/joplin/blob/master/readme/spec.md)
|
||||||
|
- [How to enable debug mode](https://github.com/laurent22/joplin/blob/master/readme/debugging.md)
|
||||||
|
- [FAQ](https://github.com/laurent22/joplin/blob/master/readme/faq.md)
|
||||||
|
|
||||||
|
- About
|
||||||
|
|
||||||
|
- [Changelog](https://github.com/laurent22/joplin/blob/master/readme/changelog.md)
|
||||||
|
- [Stats](https://github.com/laurent22/joplin/blob/master/readme/stats.md)
|
||||||
|
- [Donate](https://github.com/laurent22/joplin/blob/master/readme/donate.md)
|
||||||
|
<!-- TOC -->
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
- Desktop, mobile and terminal applications.
|
- Desktop, mobile and terminal applications.
|
||||||
- End To End Encryption (E2EE)
|
- End To End Encryption (E2EE)
|
||||||
- Synchronisation with various services, including NextCloud, WebDAV and OneDrive. Dropbox is planned.
|
- Synchronisation with various services, including NextCloud, Dropbox, WebDAV and OneDrive.
|
||||||
- Import Enex files (Evernote export format) and Markdown files.
|
- Import Enex files (Evernote export format) and Markdown files.
|
||||||
- Export JEX files (Joplin Export format) and raw files.
|
- Export JEX files (Joplin Export format) and raw files.
|
||||||
- Support notes, to-dos, tags and notebooks.
|
- Support notes, to-dos, tags and notebooks.
|
||||||
@@ -79,7 +98,7 @@ To import Evernote data, first export your Evernote notebooks to ENEX files as d
|
|||||||
|
|
||||||
On the **desktop application**, open File > Import > ENEX and select your file. The notes will be imported into a new separate notebook. If needed they can then be moved to a different notebook, or the notebook can be renamed, etc.
|
On the **desktop application**, open File > Import > ENEX and select your file. The notes will be imported into a new separate notebook. If needed they can then be moved to a different notebook, or the notebook can be renamed, etc.
|
||||||
|
|
||||||
On the **terminal application**, in [command-line mode](/terminal#command-line-mode), type `import /path/to/file.enex`. This will import the notes into a new notebook named after the filename.
|
On the **terminal application**, in [command-line mode](https://joplin.cozic.net/terminal#command-line-mode), type `import /path/to/file.enex`. This will import the notes into a new notebook named after the filename.
|
||||||
|
|
||||||
## Importing from Markdown files
|
## Importing from Markdown files
|
||||||
|
|
||||||
@@ -87,7 +106,7 @@ Joplin can import notes from plain Markdown file. You can either import a comple
|
|||||||
|
|
||||||
On the **desktop application**, open File > Import > MD and select your Markdown file or directory.
|
On the **desktop application**, open File > Import > MD and select your Markdown file or directory.
|
||||||
|
|
||||||
On the **terminal application**, in [command-line mode](/terminal#command-line-mode), type `import --format md /path/to/file.md` or `import --format md /path/to/directory/`.
|
On the **terminal application**, in [command-line mode](https://joplin.cozic.net/terminal#command-line-mode), type `import --format md /path/to/file.md` or `import --format md /path/to/directory/`.
|
||||||
|
|
||||||
## Importing from other applications
|
## Importing from other applications
|
||||||
|
|
||||||
@@ -95,6 +114,7 @@ In general the way to import notes from any application into Joplin is to conver
|
|||||||
|
|
||||||
* Standard Notes: Please see [this tutorial](https://programadorwebvalencia.com/migrate-notes-from-standard-notes-to-joplin/)
|
* Standard Notes: Please see [this tutorial](https://programadorwebvalencia.com/migrate-notes-from-standard-notes-to-joplin/)
|
||||||
* Tomboy Notes: Export the notes to ENEX files [as described here](https://askubuntu.com/questions/243691/how-can-i-export-my-tomboy-notes-into-evernote/608551) for example, and import these ENEX files into Joplin.
|
* Tomboy Notes: Export the notes to ENEX files [as described here](https://askubuntu.com/questions/243691/how-can-i-export-my-tomboy-notes-into-evernote/608551) for example, and import these ENEX files into Joplin.
|
||||||
|
* OneNote: First [import the notes from OneNote into Evernote](https://discussion.evernote.com/topic/107736-is-there-a-way-to-import-from-onenote-into-evernote-on-the-mac/). Then export the ENEX file from Evernote and import it into Joplin.
|
||||||
|
|
||||||
# Exporting
|
# Exporting
|
||||||
|
|
||||||
@@ -102,31 +122,44 @@ Joplin can export to the JEX format (Joplin Export file), which is a tar file th
|
|||||||
|
|
||||||
# Synchronisation
|
# Synchronisation
|
||||||
|
|
||||||
One of the goals of Joplin was to avoid being tied to any particular company or service, whether it is Evernote, Google or Microsoft. As such the synchronisation is designed without any hard dependency to any particular service. Most of the synchronisation process is done at an abstract level and access to external services, such as Nextcloud or OneDrive, is done via lightweight drivers. It is easy to support new services by creating simple drivers that provide a filesystem-like interface, i.e. the ability to read, write, delete and list items. It is also simple to switch from one service to another or to even sync to multiple services at once. Each note, notebook, tags, as well as the relation between items is transmitted as plain text files during synchronisation, which means the data can also be moved to a different application, can be easily backed up, inspected, etc.
|
One of the goals of Joplin was to avoid being tied to any particular company or service, whether it is Evernote, Google or Microsoft. As such the synchronisation is designed without any hard dependency to any particular service. Most of the synchronisation process is done at an abstract level and access to external services, such as Nextcloud or Dropbox, is done via lightweight drivers. It is easy to support new services by creating simple drivers that provide a filesystem-like interface, i.e. the ability to read, write, delete and list items. It is also simple to switch from one service to another or to even sync to multiple services at once. Each note, notebook, tags, as well as the relation between items is transmitted as plain text files during synchronisation, which means the data can also be moved to a different application, can be easily backed up, inspected, etc.
|
||||||
|
|
||||||
Currently, synchronisation is possible with Nextcloud and OneDrive (by default) or the local filesystem. A Dropbox one will also be available once [this React Native bug](https://github.com/facebook/react-native/issues/14445) is fixed. To setup synchronisation please follow the instructions below. After that, the application will synchronise in the background whenever it is running, or you can click on "Synchronise" to start a synchronisation manually.
|
Currently, synchronisation is possible with Nextcloud, Dropbox (by default) or the local filesystem. To setup synchronisation please follow the instructions below. After that, the application will synchronise in the background whenever it is running, or you can click on "Synchronise" to start a synchronisation manually.
|
||||||
|
|
||||||
## Nextcloud synchronisation
|
## Nextcloud synchronisation
|
||||||
|
|
||||||
On the **desktop application** or **mobile application**, go to the config screen and select Nextcloud as the synchronisation target. Then input [the WebDAV URL](https://docs.nextcloud.com/server/9/user_manual/files/access_webdav.html), this is normally `https://example.com/nextcloud/remote.php/dav/files/USERNAME/Joplin` (make sure to create the "Joplin" directory in Nextcloud and to replace USERNAME by your Nextcloud username), and set the username and password.
|
<img src="https://joplin.cozic.net/images/nextcloud-logo-background.png" width="100" align="left"> <a href="https://nextcloud.com/">Nextcloud</a> is a self-hosted, private cloud solution. It can store documents, images and videos but also calendars, passwords and countless other things and can sync them to your laptop or phone. As you can host your own Nextcloud server, you own both the data on your device and infrastructure used for synchronisation. As such it is a good fit for Joplin. The platform is also well supported and with a strong community, so it is likely to be around for a while - since it's open source anyway, it is not a service that can be closed, it can exist on a server for as long as one chooses.
|
||||||
|
|
||||||
|
On the **desktop application** or **mobile application**, go to the config screen and select Nextcloud as the synchronisation target. Then input the WebDAV URL (to get it, click on Settings in the bottom left corner of the page, in Nextcloud), this is normally `https://example.com/nextcloud/remote.php/webdav/Joplin` (**make sure to create the "Joplin" directory in Nextcloud**), and set the username and password. If it does not work, please [see this explanation](https://github.com/laurent22/joplin/issues/61#issuecomment-373282608) for more details.
|
||||||
|
|
||||||
On the **terminal application**, you will need to set the `sync.target` config variable and all the `sync.5.path`, `sync.5.username` and `sync.5.password` config variables to, respectively the Nextcloud WebDAV URL, your username and your password. This can be done from the command line mode using:
|
On the **terminal application**, you will need to set the `sync.target` config variable and all the `sync.5.path`, `sync.5.username` and `sync.5.password` config variables to, respectively the Nextcloud WebDAV URL, your username and your password. This can be done from the command line mode using:
|
||||||
|
|
||||||
:config sync.5.path https://example.com/nextcloud/remote.php/dav/files/USERNAME/Joplin
|
:config sync.5.path https://example.com/nextcloud/remote.php/webdav/Joplin
|
||||||
:config sync.5.username YOUR_USERNAME
|
:config sync.5.username YOUR_USERNAME
|
||||||
:config sync.5.password YOUR_PASSWORD
|
:config sync.5.password YOUR_PASSWORD
|
||||||
:config sync.target 5
|
:config sync.target 5
|
||||||
|
|
||||||
If synchronisation does not work, please consult the logs in the app profile directory - it is often due to a misconfigured URL or password. The log should indicate what the exact issue is.
|
If synchronisation does not work, please consult the logs in the app profile directory - it is often due to a misconfigured URL or password. The log should indicate what the exact issue is.
|
||||||
|
|
||||||
|
## Dropbox synchronisation
|
||||||
|
|
||||||
|
When syncing with Dropbox, Joplin creates a sub-directory in Dropbox, in /Apps/Joplin and read/write the notes and notebooks from it. The application does not have access to anything outside this directory.
|
||||||
|
|
||||||
|
On the **desktop application** or **mobile application**, select "Dropbox" as the synchronisation target in the config screen (it is selected by default). Then, to initiate the synchronisation process, click on the "Synchronise" button in the sidebar and follow the instructions.
|
||||||
|
|
||||||
|
On the **terminal application**, to initiate the synchronisation process, type `:sync`. You will be asked to follow a link to authorise the application. It is possible to also synchronise outside of the user interface by typing `joplin sync` from the terminal. This can be used to setup a cron script to synchronise at regular interval. For example, this would do it every 30 minutes:
|
||||||
|
|
||||||
|
*/30 * * * * /path/to/joplin sync
|
||||||
|
|
||||||
## WebDAV synchronisation
|
## WebDAV synchronisation
|
||||||
|
|
||||||
Select the "WebDAV" synchronisation target and follow the same instructions as for Nextcloud above.
|
Select the "WebDAV" synchronisation target and follow the same instructions as for Nextcloud above.
|
||||||
|
|
||||||
WebDAV-compatible services that are known to work with Joplin:
|
WebDAV-compatible services that are known to work with Joplin.
|
||||||
|
|
||||||
- [Box.com](https://www.box.com/)
|
- [Box.com](https://www.box.com/)
|
||||||
- [DriveHQ](https://www.drivehq.com)
|
- [DriveHQ](https://www.drivehq.com)
|
||||||
|
- [HiDrive](https://www.strato.fr/stockage-en-ligne/) from Strato. [Setup help](https://github.com/laurent22/joplin/issues/309)
|
||||||
- [OwnCloud](https://owncloud.org/)
|
- [OwnCloud](https://owncloud.org/)
|
||||||
- [Seafile](https://www.seafile.com/)
|
- [Seafile](https://www.seafile.com/)
|
||||||
- [Stack](https://www.transip.nl/stack/)
|
- [Stack](https://www.transip.nl/stack/)
|
||||||
@@ -136,22 +169,24 @@ WebDAV-compatible services that are known to work with Joplin:
|
|||||||
|
|
||||||
When syncing with OneDrive, Joplin creates a sub-directory in OneDrive, in /Apps/Joplin and read/write the notes and notebooks from it. The application does not have access to anything outside this directory.
|
When syncing with OneDrive, Joplin creates a sub-directory in OneDrive, in /Apps/Joplin and read/write the notes and notebooks from it. The application does not have access to anything outside this directory.
|
||||||
|
|
||||||
On the **desktop application** or **mobile application**, select "OneDrive" as the synchronisation target in the config screen (it is selected by default). Then, to initiate the synchronisation process, click on the "Synchronise" button in the sidebar. You will be asked to login to OneDrive to authorise the application (simply input your Microsoft credentials - you do not need to register with OneDrive).
|
On the **desktop application** or **mobile application**, select "OneDrive" as the synchronisation target in the config screen. Then, to initiate the synchronisation process, click on the "Synchronise" button in the sidebar and follow the instructions.
|
||||||
|
|
||||||
On the **terminal application**, to initiate the synchronisation process, type `:sync`. You will be asked to follow a link to authorise the application (simply input your Microsoft credentials - you do not need to register with OneDrive). It is possible to also synchronise outside of the user interface by typing `joplin sync` from the terminal. This can be used to setup a cron script to synchronise at regular interval. For example, this would do it every 30 minutes:
|
On the **terminal application**, to initiate the synchronisation process, type `:sync`. You will be asked to follow a link to authorise the application (simply input your Microsoft credentials - you do not need to register with OneDrive).
|
||||||
|
|
||||||
*/30 * * * * /path/to/joplin sync
|
|
||||||
|
|
||||||
# Encryption
|
# Encryption
|
||||||
|
|
||||||
Joplin supports end-to-end encryption (E2EE) on all the applications. E2EE is a system where only the owner of the notes, notebooks, tags or resources can read them. It prevents potential eavesdroppers - including telecom providers, internet providers, and even the developers of Joplin from being able to access the data. Please see the [End-To-End Encryption Tutorial](http://joplin.cozic.net/help/e2ee) for more information about this feature and how to enable it.
|
Joplin supports end-to-end encryption (E2EE) on all the applications. E2EE is a system where only the owner of the notes, notebooks, tags or resources can read them. It prevents potential eavesdroppers - including telecom providers, internet providers, and even the developers of Joplin from being able to access the data. Please see the [End-To-End Encryption Tutorial](https://joplin.cozic.net/e2ee) for more information about this feature and how to enable it.
|
||||||
|
|
||||||
For a more technical description, mostly relevant for development or to review the method being used, please see the [Encryption specification](http://joplin.cozic.net/help/spec).
|
For a more technical description, mostly relevant for development or to review the method being used, please see the [Encryption specification](https://joplin.cozic.net/spec).
|
||||||
|
|
||||||
# Attachments / Resources
|
# Attachments / Resources
|
||||||
|
|
||||||
Any kind of file can be attached to a note. In Markdown, links to these files are represented as a simple ID to the resource. In the note viewer, these files, if they are images, will be displayed or, if they are other files (PDF, text files, etc.) they will be displayed as links. Clicking on this link will open the file in the default application.
|
Any kind of file can be attached to a note. In Markdown, links to these files are represented as a simple ID to the resource. In the note viewer, these files, if they are images, will be displayed or, if they are other files (PDF, text files, etc.) they will be displayed as links. Clicking on this link will open the file in the default application.
|
||||||
|
|
||||||
|
Resources that are not attached to any note will be automatically deleted after a day or two.
|
||||||
|
|
||||||
|
**Important:** Resources larger than 10 MB are not currently supported on mobile. They will crash the application when synchronising so it is recommended not to attach such resources at the moment. The issue is being looked at.
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|
||||||
On the desktop and mobile apps, an alarm can be associated with any to-do. It will be triggered at the given time by displaying a notification. How the notification will be displayed depends on the operating system since each has a different way to handle this. Please see below for the requirements for the desktop applications:
|
On the desktop and mobile apps, an alarm can be associated with any to-do. It will be triggered at the given time by displaying a notification. How the notification will be displayed depends on the operating system since each has a different way to handle this. Please see below for the requirements for the desktop applications:
|
||||||
@@ -166,37 +201,55 @@ On mobile, the alarms will be displayed using the built-in notification system.
|
|||||||
|
|
||||||
If for any reason the notifications do not work, please [open an issue](https://github.com/laurent22/joplin/issues).
|
If for any reason the notifications do not work, please [open an issue](https://github.com/laurent22/joplin/issues).
|
||||||
|
|
||||||
|
# Sub-notebooks
|
||||||
|
|
||||||
|
Sub-notebooks allow organising multiple notebooks into a tree of notebooks. For example it can be used to regroup all the notebooks related to work, to family or to a particular project under a parent notebook.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- On the **desktop application**, to create a subnotebook, drag and drop it onto another notebook. To move it back to the root, drag and drop it on the "Notebooks" header. Currently only the desktop app can be used to organise the notebooks.
|
||||||
|
- The **mobile application** supports displaying and collapsing/expanding the tree of notebooks, however it does not currently support moving the subnotebooks to different notebooks.
|
||||||
|
- The **terminal app** supports displaying the tree of subnotebooks but it does not support collapsing/expanding them or moving the subnotebooks around.
|
||||||
|
|
||||||
# Markdown
|
# Markdown
|
||||||
|
|
||||||
Joplin uses and renders [Github-flavoured Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) with a few variations and additions. In particular:
|
Joplin uses and renders [Github-flavoured Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) with a few variations and additions. In particular:
|
||||||
|
|
||||||
|
## Links to other notes
|
||||||
|
|
||||||
|
You can create a link to a note by specifying its ID in the URL. For example:
|
||||||
|
|
||||||
|
[Link to my note](:/0b0d62d15e60409dac34f354b6e9e839)
|
||||||
|
|
||||||
|
Since getting the ID of a note is not straightforward, each app provides a way to create such link. In the **desktop app**, right click on a note an select "Copy Markdown link". In the **mobile app**, open a note and, in the top right menu, select "Copy Markdown link". You can then paste this link anywhere in another note.
|
||||||
|
|
||||||
## Math notation
|
## Math notation
|
||||||
|
|
||||||
Math expressions can be added using the [Katex notation](https://khan.github.io/KaTeX/). To add an inline equation, wrap the expression in `$EXPRESSION$`, eg. `$\sqrt{3x-1}+(1+x)^2$`. To create an expression block, wrap it as follow:
|
Math expressions can be added using the [Katex notation](https://khan.github.io/KaTeX/). To add an inline equation, wrap the expression in `$EXPRESSION$`, eg. `$\sqrt{3x-1}+(1+x)^2$`. To create an expression block, wrap it as follow:
|
||||||
|
|
||||||
$$
|
$$
|
||||||
EXPRESSION
|
EXPRESSION
|
||||||
$$
|
$$
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
$$
|
$$
|
||||||
f(x) = \int_{-\infty}^\infty
|
f(x) = \int_{-\infty}^\infty
|
||||||
\hat f(\xi)\,e^{2 \pi i \xi x}
|
\hat f(\xi)\,e^{2 \pi i \xi x}
|
||||||
\,d\xi
|
\,d\xi
|
||||||
$$
|
$$
|
||||||
|
|
||||||
Here is an example with the Markdown and rendered result side by side:
|
Here is an example with the Markdown and rendered result side by side:
|
||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/Katex.png" style="max-width: 100%; max-height: 35em;">
|
<img src="https://joplin.cozic.net/images/Katex.png" style="max-width: 100%; max-height: 35em;">
|
||||||
|
|
||||||
## Checkboxes
|
## Checkboxes
|
||||||
|
|
||||||
Checkboxes can be added like so:
|
Checkboxes can be added like so:
|
||||||
|
|
||||||
- [ ] Milk
|
- [ ] Milk
|
||||||
- [ ] Rice
|
- [ ] Rice
|
||||||
- [ ] Eggs
|
- [ ] Eggs
|
||||||
|
|
||||||
The checkboxes can then be ticked in the mobile and desktop applications.
|
The checkboxes can then be ticked in the mobile and desktop applications.
|
||||||
|
|
||||||
@@ -204,7 +257,13 @@ The checkboxes can then be ticked in the mobile and desktop applications.
|
|||||||
|
|
||||||
Donations to Joplin support the development of the project. Developing quality applications mostly takes time, but there are also some expenses, such as digital certificates to sign the applications, app store fees, hosting, etc. Most of all, your donation will make it possible to keep up the current development standard.
|
Donations to Joplin support the development of the project. Developing quality applications mostly takes time, but there are also some expenses, such as digital certificates to sign the applications, app store fees, hosting, etc. Most of all, your donation will make it possible to keep up the current development standard.
|
||||||
|
|
||||||
Please see the [donation page](http://joplin.cozic.net/donate/) for information on how to support the development of Joplin.
|
Please see the [donation page](https://joplin.cozic.net/donate/) for information on how to support the development of Joplin.
|
||||||
|
|
||||||
|
# Community
|
||||||
|
|
||||||
|
- For general discussion about Joplin, user support, software development questions, and to discuss new features, go to the [Joplin Forum](https://discourse.joplin.cozic.net/). It is possible to login with your GitHub account.
|
||||||
|
- For bug reports and feature requests, go to the [GitHub Issue Tracker](https://github.com/laurent22/joplin/issues).
|
||||||
|
- The latest news are often posted [on this Twitter account](https://twitter.com/laurent2233).
|
||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
@@ -228,24 +287,28 @@ Current translations:
|
|||||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||||
| Language | Po File | Last translator | Percent done
|
| Language | Po File | Last translator | Percent done
|
||||||
---|---|---|---|---
|
---|---|---|---|---
|
||||||
 | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 80%
|
 | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 75%
|
||||||
 | Croatian | [hr_HR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po) | Hrvoje Mandić <trbuhom@net.hr> | 65%
|
 | Croatian | [hr_HR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po) | Hrvoje Mandić <trbuhom@net.hr> | 61%
|
||||||
 | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Tobias Strobel <git@strobeltobias.de> | 97%
|
 | Czech | [cs_CZ](https://github.com/laurent22/joplin/blob/master/CliClient/locales/cs_CZ.po) | Lukas Helebrandt <lukas@aiya.cz> | 95%
|
||||||
 | English | [en_GB](https://github.com/laurent22/joplin/blob/master/CliClient/locales/en_GB.po) | | 100%
|
 | Dansk | [da_DK](https://github.com/laurent22/joplin/blob/master/CliClient/locales/da_DK.po) | Morten Juhl-Johansen Zölde-Fejér <mjjzf@syntaktisk. | 97%
|
||||||
 | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín <f@mrtn.es> | 100%
|
 | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Philipp Zumstein <zuphilip@gmail.com> | 98%
|
||||||
 | Français | [fr_FR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po) | Laurent Cozic | 100%
|
 | English | [en_GB](https://github.com/laurent22/joplin/blob/master/CliClient/locales/en_GB.po) | | 100%
|
||||||
 | Italiano | [it_IT](https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po) | | 66%
|
 | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín <f@mrtn.es> | 99%
|
||||||
 | Nederlands | [nl_BE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po) | | 80%
|
 | Français | [fr_FR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po) | Laurent Cozic | 98%
|
||||||
 | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po) | Renato Nunes Bastos <rnbastos@gmail.com> | 98%
|
 | Galician | [gl_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/gl_ES.po) | Marcos Lans <marcoslansgarza@gmail.com> | 95%
|
||||||
 | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov <artyom.karlov@gmail.com> | 100%
|
 | Italiano | [it_IT](https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po) | | 63%
|
||||||
 | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po) | RCJacH <RCJacH@outlook.com> | 66%
|
 | Nederlands | [nl_BE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po) | | 76%
|
||||||
 | 日本語 | [ja_JP](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po) | | 65%
|
 | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po) | Renato Nunes Bastos <rnbastos@gmail.com> | 97%
|
||||||
|
 | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov <artyom.karlov@gmail.com> | 94%
|
||||||
|
 | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po) | | 91%
|
||||||
|
 | 日本語 | [ja_JP](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po) | | 61%
|
||||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||||
|
|
||||||
# Known bugs
|
# Known bugs
|
||||||
|
|
||||||
|
- Resources larger than 10 MB are not currently supported on mobile. They will crash the application so it is recommended not to attach such resources at the moment. The issue is being looked at.
|
||||||
- Non-alphabetical characters such as Chinese or Arabic might create glitches in the terminal on Windows. This is a limitation of the current Windows console.
|
- Non-alphabetical characters such as Chinese or Arabic might create glitches in the terminal on Windows. This is a limitation of the current Windows console.
|
||||||
- While the mobile can sync and load tags, it is not currently possible to create new ones. The desktop and terminal apps can create, delete and edit tags.
|
- It is only possible to upload files of up to 4MB to OneDrive due to a limitation of [the API](https://docs.microsoft.com/en-gb/onedrive/developer/rest-api/api/driveitem_put_content) being currently used. There is currently no plan to support OneDrive "large file" API.
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "net.cozic.joplin"
|
applicationId "net.cozic.joplin"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 22
|
targetSdkVersion 26
|
||||||
versionCode 2097285
|
versionCode 2097301
|
||||||
versionName "1.0.107"
|
versionName "1.0.123"
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters "armeabi-v7a", "x86"
|
abiFilters "armeabi-v7a", "x86"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="16"
|
android:minSdkVersion="16"
|
||||||
android:targetSdkVersion="22" />
|
android:targetSdkVersion="26" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MainApplication"
|
android:name=".MainApplication"
|
||||||
|
|||||||
@@ -306,6 +306,34 @@
|
|||||||
remoteGlobalIDString = 139D7E881E25C6D100323FB7;
|
remoteGlobalIDString = 139D7E881E25C6D100323FB7;
|
||||||
remoteInfo = "double-conversion";
|
remoteInfo = "double-conversion";
|
||||||
};
|
};
|
||||||
|
4D7F8DA020A32BA0008B757D /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||||
|
proxyType = 2;
|
||||||
|
remoteGlobalIDString = EBF21BDC1FC498900052F4D5;
|
||||||
|
remoteInfo = jsinspector;
|
||||||
|
};
|
||||||
|
4D7F8DA220A32BA0008B757D /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||||
|
proxyType = 2;
|
||||||
|
remoteGlobalIDString = EBF21BFA1FC4989A0052F4D5;
|
||||||
|
remoteInfo = "jsinspector-tvOS";
|
||||||
|
};
|
||||||
|
4D7F8DA420A32BA0008B757D /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||||
|
proxyType = 2;
|
||||||
|
remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
|
||||||
|
remoteInfo = privatedata;
|
||||||
|
};
|
||||||
|
4D7F8DA620A32BA0008B757D /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||||
|
proxyType = 2;
|
||||||
|
remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
|
||||||
|
remoteInfo = "privatedata-tvOS";
|
||||||
|
};
|
||||||
4DA7F80C1FC1DA9C00353191 /* PBXContainerItemProxy */ = {
|
4DA7F80C1FC1DA9C00353191 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = A4716DB8654B431D894F89E1 /* RNImagePicker.xcodeproj */;
|
containerPortal = A4716DB8654B431D894F89E1 /* RNImagePicker.xcodeproj */;
|
||||||
@@ -540,10 +568,14 @@
|
|||||||
4D2AFF8D1FDA002000599716 /* libcxxreact.a */,
|
4D2AFF8D1FDA002000599716 /* libcxxreact.a */,
|
||||||
3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
|
3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
|
||||||
4D2AFF8F1FDA002000599716 /* libjschelpers.a */,
|
4D2AFF8F1FDA002000599716 /* libjschelpers.a */,
|
||||||
|
4D7F8DA120A32BA0008B757D /* libjsinspector.a */,
|
||||||
|
4D7F8DA320A32BA0008B757D /* libjsinspector-tvOS.a */,
|
||||||
4D3A19271FBDDA9400457703 /* libthird-party.a */,
|
4D3A19271FBDDA9400457703 /* libthird-party.a */,
|
||||||
4D2AFF911FDA002000599716 /* libthird-party.a */,
|
4D2AFF911FDA002000599716 /* libthird-party.a */,
|
||||||
4D3A192B1FBDDA9400457703 /* libdouble-conversion.a */,
|
4D3A192B1FBDDA9400457703 /* libdouble-conversion.a */,
|
||||||
4D2AFF931FDA002000599716 /* libdouble-conversion.a */,
|
4D2AFF931FDA002000599716 /* libdouble-conversion.a */,
|
||||||
|
4D7F8DA520A32BA0008B757D /* libprivatedata.a */,
|
||||||
|
4D7F8DA720A32BA0008B757D /* libprivatedata-tvOS.a */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1150,6 +1182,34 @@
|
|||||||
remoteRef = 4D3A192A1FBDDA9400457703 /* PBXContainerItemProxy */;
|
remoteRef = 4D3A192A1FBDDA9400457703 /* PBXContainerItemProxy */;
|
||||||
sourceTree = BUILT_PRODUCTS_DIR;
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
};
|
};
|
||||||
|
4D7F8DA120A32BA0008B757D /* libjsinspector.a */ = {
|
||||||
|
isa = PBXReferenceProxy;
|
||||||
|
fileType = archive.ar;
|
||||||
|
path = libjsinspector.a;
|
||||||
|
remoteRef = 4D7F8DA020A32BA0008B757D /* PBXContainerItemProxy */;
|
||||||
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
|
};
|
||||||
|
4D7F8DA320A32BA0008B757D /* libjsinspector-tvOS.a */ = {
|
||||||
|
isa = PBXReferenceProxy;
|
||||||
|
fileType = archive.ar;
|
||||||
|
path = "libjsinspector-tvOS.a";
|
||||||
|
remoteRef = 4D7F8DA220A32BA0008B757D /* PBXContainerItemProxy */;
|
||||||
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
|
};
|
||||||
|
4D7F8DA520A32BA0008B757D /* libprivatedata.a */ = {
|
||||||
|
isa = PBXReferenceProxy;
|
||||||
|
fileType = archive.ar;
|
||||||
|
path = libprivatedata.a;
|
||||||
|
remoteRef = 4D7F8DA420A32BA0008B757D /* PBXContainerItemProxy */;
|
||||||
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
|
};
|
||||||
|
4D7F8DA720A32BA0008B757D /* libprivatedata-tvOS.a */ = {
|
||||||
|
isa = PBXReferenceProxy;
|
||||||
|
fileType = archive.ar;
|
||||||
|
path = "libprivatedata-tvOS.a";
|
||||||
|
remoteRef = 4D7F8DA620A32BA0008B757D /* PBXContainerItemProxy */;
|
||||||
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
|
};
|
||||||
4DA7F80D1FC1DA9C00353191 /* libRNImagePicker.a */ = {
|
4DA7F80D1FC1DA9C00353191 /* libRNImagePicker.a */ = {
|
||||||
isa = PBXReferenceProxy;
|
isa = PBXReferenceProxy;
|
||||||
fileType = archive.ar;
|
fileType = archive.ar;
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0.13</string>
|
<string>10.0.21</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>13</string>
|
<string>21</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
@@ -67,6 +67,13 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const BaseSyncTarget = require('lib/BaseSyncTarget.js');
|
|||||||
const { fileExtension } = require('lib/path-utils.js');
|
const { fileExtension } = require('lib/path-utils.js');
|
||||||
const { shim } = require('lib/shim.js');
|
const { shim } = require('lib/shim.js');
|
||||||
const { _, setLocale, defaultLocale, closestSupportedLocale } = require('lib/locale.js');
|
const { _, setLocale, defaultLocale, closestSupportedLocale } = require('lib/locale.js');
|
||||||
|
const reduxSharedMiddleware = require('lib/components/shared/reduxSharedMiddleware');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const JoplinError = require('lib/JoplinError');
|
const JoplinError = require('lib/JoplinError');
|
||||||
@@ -29,14 +30,17 @@ const SyncTargetOneDrive = require('lib/SyncTargetOneDrive.js');
|
|||||||
const SyncTargetOneDriveDev = require('lib/SyncTargetOneDriveDev.js');
|
const SyncTargetOneDriveDev = require('lib/SyncTargetOneDriveDev.js');
|
||||||
const SyncTargetNextcloud = require('lib/SyncTargetNextcloud.js');
|
const SyncTargetNextcloud = require('lib/SyncTargetNextcloud.js');
|
||||||
const SyncTargetWebDAV = require('lib/SyncTargetWebDAV.js');
|
const SyncTargetWebDAV = require('lib/SyncTargetWebDAV.js');
|
||||||
|
const SyncTargetDropbox = require('lib/SyncTargetDropbox.js');
|
||||||
const EncryptionService = require('lib/services/EncryptionService');
|
const EncryptionService = require('lib/services/EncryptionService');
|
||||||
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
||||||
|
const BaseService = require('lib/services/BaseService');
|
||||||
|
|
||||||
SyncTargetRegistry.addClass(SyncTargetFilesystem);
|
SyncTargetRegistry.addClass(SyncTargetFilesystem);
|
||||||
SyncTargetRegistry.addClass(SyncTargetOneDrive);
|
SyncTargetRegistry.addClass(SyncTargetOneDrive);
|
||||||
SyncTargetRegistry.addClass(SyncTargetOneDriveDev);
|
SyncTargetRegistry.addClass(SyncTargetOneDriveDev);
|
||||||
SyncTargetRegistry.addClass(SyncTargetNextcloud);
|
SyncTargetRegistry.addClass(SyncTargetNextcloud);
|
||||||
SyncTargetRegistry.addClass(SyncTargetWebDAV);
|
SyncTargetRegistry.addClass(SyncTargetWebDAV);
|
||||||
|
SyncTargetRegistry.addClass(SyncTargetDropbox);
|
||||||
|
|
||||||
class BaseApplication {
|
class BaseApplication {
|
||||||
|
|
||||||
@@ -140,6 +144,14 @@ class BaseApplication {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg.indexOf('-psn') === 0) {
|
||||||
|
// Some weird flag passed by macOS - can be ignored.
|
||||||
|
// https://github.com/laurent22/joplin/issues/480
|
||||||
|
// https://stackoverflow.com/questions/10242115
|
||||||
|
argv.splice(0, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg.length && arg[0] == '-') {
|
if (arg.length && arg[0] == '-') {
|
||||||
throw new JoplinError(_('Unknown flag: %s', arg), 'flagError');
|
throw new JoplinError(_('Unknown flag: %s', arg), 'flagError');
|
||||||
} else {
|
} else {
|
||||||
@@ -259,7 +271,9 @@ class BaseApplication {
|
|||||||
const newState = store.getState();
|
const newState = store.getState();
|
||||||
let refreshNotes = false;
|
let refreshNotes = false;
|
||||||
|
|
||||||
if (action.type == 'FOLDER_SELECT' || action.type === 'FOLDER_DELETE') {
|
reduxSharedMiddleware(store, next, action);
|
||||||
|
|
||||||
|
if (action.type == 'FOLDER_SELECT' || action.type === 'FOLDER_DELETE' || (action.type === 'SEARCH_UPDATE' && newState.notesParentType === 'Folder')) {
|
||||||
Setting.setValue('activeFolderId', newState.selectedFolderId);
|
Setting.setValue('activeFolderId', newState.selectedFolderId);
|
||||||
this.currentFolder_ = newState.selectedFolderId ? await Folder.load(newState.selectedFolderId) : null;
|
this.currentFolder_ = newState.selectedFolderId ? await Folder.load(newState.selectedFolderId) : null;
|
||||||
refreshNotes = true;
|
refreshNotes = true;
|
||||||
@@ -365,11 +379,11 @@ class BaseApplication {
|
|||||||
let initArgs = startFlags.matched;
|
let initArgs = startFlags.matched;
|
||||||
if (argv.length) this.showPromptString_ = false;
|
if (argv.length) this.showPromptString_ = false;
|
||||||
|
|
||||||
if (process.argv[1].indexOf('joplindev') >= 0) {
|
// if (process.argv[1].indexOf('joplindev') >= 0) {
|
||||||
if (!initArgs.profileDir) initArgs.profileDir = '/mnt/d/Temp/TestNotes2';
|
// if (!initArgs.profileDir) initArgs.profileDir = '/mnt/d/Temp/TestNotes2';
|
||||||
initArgs.logLevel = Logger.LEVEL_DEBUG;
|
// initArgs.logLevel = Logger.LEVEL_DEBUG;
|
||||||
initArgs.env = 'dev';
|
// initArgs.env = 'dev';
|
||||||
}
|
// }
|
||||||
|
|
||||||
let appName = initArgs.env == 'dev' ? 'joplindev' : 'joplin';
|
let appName = initArgs.env == 'dev' ? 'joplindev' : 'joplin';
|
||||||
if (Setting.value('appId').indexOf('-desktop') >= 0) appName += '-desktop';
|
if (Setting.value('appId').indexOf('-desktop') >= 0) appName += '-desktop';
|
||||||
@@ -420,12 +434,19 @@ class BaseApplication {
|
|||||||
if (Setting.value('firstStart')) {
|
if (Setting.value('firstStart')) {
|
||||||
const locale = shim.detectAndSetLocale(Setting);
|
const locale = shim.detectAndSetLocale(Setting);
|
||||||
reg.logger().info('First start: detected locale as ' + locale);
|
reg.logger().info('First start: detected locale as ' + locale);
|
||||||
if (Setting.value('env') === 'dev') Setting.setValue('sync.target', SyncTargetRegistry.nameToId('onedrive_dev'));
|
|
||||||
Setting.setValue('firstStart', 0)
|
if (Setting.value('env') === 'dev') {
|
||||||
|
Setting.setValue('showTrayIcon', 0);
|
||||||
|
Setting.setValue('autoUpdateEnabled', 0);
|
||||||
|
Setting.setValue('sync.interval', 3600);
|
||||||
|
}
|
||||||
|
|
||||||
|
Setting.setValue('firstStart', 0);
|
||||||
} else {
|
} else {
|
||||||
setLocale(Setting.value('locale'));
|
setLocale(Setting.value('locale'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BaseService.logger_ = this.logger_;
|
||||||
EncryptionService.instance().setLogger(this.logger_);
|
EncryptionService.instance().setLogger(this.logger_);
|
||||||
BaseItem.encryptionService_ = EncryptionService.instance();
|
BaseItem.encryptionService_ = EncryptionService.instance();
|
||||||
DecryptionWorker.instance().setLogger(this.logger_);
|
DecryptionWorker.instance().setLogger(this.logger_);
|
||||||
|
|||||||
@@ -44,6 +44,15 @@ class BaseModel {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefer the use of this function to compare IDs as it handles the case where
|
||||||
|
// one ID is null and the other is "", in which case they are actually considered to be the same.
|
||||||
|
static idsEqual(id1, id2) {
|
||||||
|
if (!id1 && !id2) return true;
|
||||||
|
if (!id1 && !!id2) return false;
|
||||||
|
if (!!id1 && !id2) return false;
|
||||||
|
return id1 === id2;
|
||||||
|
}
|
||||||
|
|
||||||
static modelTypeToName(type) {
|
static modelTypeToName(type) {
|
||||||
for (let i = 0; i < BaseModel.typeEnum_.length; i++) {
|
for (let i = 0; i < BaseModel.typeEnum_.length; i++) {
|
||||||
const e = BaseModel.typeEnum_[i];
|
const e = BaseModel.typeEnum_[i];
|
||||||
@@ -121,15 +130,6 @@ class BaseModel {
|
|||||||
return id.substr(0, 5);
|
return id.substr(0, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static minimalPartialId(id) {
|
|
||||||
// let length = 2;
|
|
||||||
// while (true) {
|
|
||||||
// const partialId = id.substr(0, length);
|
|
||||||
// const r = await this.db().selectOne('SELECT count(*) as total FROM `' + this.tableName() + '` WHERE `id` LIKE ?', [partialId + '%']);
|
|
||||||
// if (r['total'] <= 1) return partialId;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
static loadByPartialId(partialId) {
|
static loadByPartialId(partialId) {
|
||||||
return this.modelSelectAll('SELECT * FROM `' + this.tableName() + '` WHERE `id` LIKE ?', [partialId + '%']);
|
return this.modelSelectAll('SELECT * FROM `' + this.tableName() + '` WHERE `id` LIKE ?', [partialId + '%']);
|
||||||
}
|
}
|
||||||
@@ -221,20 +221,6 @@ class BaseModel {
|
|||||||
}
|
}
|
||||||
if ('type_' in newModel) output.type_ = newModel.type_;
|
if ('type_' in newModel) output.type_ = newModel.type_;
|
||||||
return output;
|
return output;
|
||||||
// let output = {};
|
|
||||||
// let type = null;
|
|
||||||
// for (let n in newModel) {
|
|
||||||
// if (!newModel.hasOwnProperty(n)) continue;
|
|
||||||
// if (n == 'type_') {
|
|
||||||
// type = newModel[n];
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// if (!(n in oldModel) || newModel[n] !== oldModel[n]) {
|
|
||||||
// output[n] = newModel[n];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (type !== null) output.type_ = type;
|
|
||||||
// return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static diffObjectsFields(oldModel, newModel) {
|
static diffObjectsFields(oldModel, newModel) {
|
||||||
@@ -421,11 +407,10 @@ class BaseModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output = this.filter(o);
|
output = this.filter(o);
|
||||||
} catch (error) {
|
} finally {
|
||||||
this.logger().error('Cannot save model', error);
|
this.releaseSaveMutex(o, mutexRelease);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.releaseSaveMutex(o, mutexRelease);
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -504,6 +489,8 @@ BaseModel.typeEnum_ = [
|
|||||||
['TYPE_SEARCH', 7],
|
['TYPE_SEARCH', 7],
|
||||||
['TYPE_ALARM', 8],
|
['TYPE_ALARM', 8],
|
||||||
['TYPE_MASTER_KEY', 9],
|
['TYPE_MASTER_KEY', 9],
|
||||||
|
['TYPE_ITEM_CHANGE', 10],
|
||||||
|
['TYPE_NOTE_RESOURCE', 11],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0; i < BaseModel.typeEnum_.length; i++) {
|
for (let i = 0; i < BaseModel.typeEnum_.length; i++) {
|
||||||
@@ -511,16 +498,6 @@ for (let i = 0; i < BaseModel.typeEnum_.length; i++) {
|
|||||||
BaseModel[e[0]] = e[1];
|
BaseModel[e[0]] = e[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseModel.TYPE_NOTE = 1;
|
|
||||||
// BaseModel.TYPE_FOLDER = 2;
|
|
||||||
// BaseModel.TYPE_SETTING = 3;
|
|
||||||
// BaseModel.TYPE_RESOURCE = 4;
|
|
||||||
// BaseModel.TYPE_TAG = 5;
|
|
||||||
// BaseModel.TYPE_NOTE_TAG = 6;
|
|
||||||
// BaseModel.TYPE_SEARCH = 7;
|
|
||||||
// BaseModel.TYPE_ALARM = 8;
|
|
||||||
// BaseModel.TYPE_MASTER_KEY = 9;
|
|
||||||
|
|
||||||
BaseModel.db_ = null;
|
BaseModel.db_ = null;
|
||||||
BaseModel.dispatch = function(o) {};
|
BaseModel.dispatch = function(o) {};
|
||||||
BaseModel.saveMutexes_ = {};
|
BaseModel.saveMutexes_ = {};
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class BaseSyncTarget {
|
|||||||
return this.db_;
|
return this.db_;
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthenticated() {
|
async isAuthenticated() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +66,10 @@ class BaseSyncTarget {
|
|||||||
return this.fileApi_;
|
return this.fileApi_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileApiSync() {
|
||||||
|
return this.fileApi_;
|
||||||
|
}
|
||||||
|
|
||||||
// Usually each sync target should create and setup its own file API via initFileApi()
|
// Usually each sync target should create and setup its own file API via initFileApi()
|
||||||
// but for testing purposes it might be convenient to provide it here so that multiple
|
// but for testing purposes it might be convenient to provide it here so that multiple
|
||||||
// clients can share and sync to the same file api (see test-utils.js)
|
// clients can share and sync to the same file api (see test-utils.js)
|
||||||
@@ -109,7 +113,7 @@ class BaseSyncTarget {
|
|||||||
|
|
||||||
async syncStarted() {
|
async syncStarted() {
|
||||||
if (!this.synchronizer_) return false;
|
if (!this.synchronizer_) return false;
|
||||||
if (!this.isAuthenticated()) return false;
|
if (!await this.isAuthenticated()) return false;
|
||||||
const sync = await this.synchronizer();
|
const sync = await this.synchronizer();
|
||||||
return sync.state() != 'idle';
|
return sync.state() != 'idle';
|
||||||
}
|
}
|
||||||
|
|||||||
214
ReactNativeClient/lib/DropboxApi.js
Normal file
214
ReactNativeClient/lib/DropboxApi.js
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
const { Logger } = require('lib/logger.js');
|
||||||
|
const { shim } = require('lib/shim.js');
|
||||||
|
const JoplinError = require('lib/JoplinError');
|
||||||
|
const URL = require('url-parse');
|
||||||
|
const { time } = require('lib/time-utils');
|
||||||
|
const EventDispatcher = require('lib/EventDispatcher');
|
||||||
|
|
||||||
|
class DropboxApi {
|
||||||
|
|
||||||
|
constructor(options) {
|
||||||
|
this.logger_ = new Logger();
|
||||||
|
this.options_ = options;
|
||||||
|
this.authToken_ = null;
|
||||||
|
this.dispatcher_ = new EventDispatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
clientId() {
|
||||||
|
return this.options_.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientSecret() {
|
||||||
|
return this.options_.secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLogger(l) {
|
||||||
|
this.logger_ = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger() {
|
||||||
|
return this.logger_;
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken() {
|
||||||
|
return this.authToken_; // Without the "Bearer " prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
on(eventName, callback) {
|
||||||
|
return this.dispatcher_.on(eventName, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
setAuthToken(v) {
|
||||||
|
this.authToken_ = v;
|
||||||
|
this.dispatcher_.dispatch('authRefreshed', this.authToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
loginUrl() {
|
||||||
|
return 'https://www.dropbox.com/oauth2/authorize?response_type=code&client_id=' + this.clientId();
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUrl(endPointFormat) {
|
||||||
|
if (['content', 'api'].indexOf(endPointFormat) < 0) throw new Error('Invalid end point format: ' + endPointFormat);
|
||||||
|
return 'https://' + endPointFormat + '.dropboxapi.com/2';
|
||||||
|
}
|
||||||
|
|
||||||
|
requestToCurl_(url, options) {
|
||||||
|
let output = [];
|
||||||
|
output.push('curl');
|
||||||
|
if (options.method) output.push('-X ' + options.method);
|
||||||
|
if (options.headers) {
|
||||||
|
for (let n in options.headers) {
|
||||||
|
if (!options.headers.hasOwnProperty(n)) continue;
|
||||||
|
output.push('-H ' + "'" + n + ': ' + options.headers[n] + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.body) output.push('--data ' + '"' + options.body + '"');
|
||||||
|
output.push(url);
|
||||||
|
|
||||||
|
return output.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
async execAuthToken(authCode) {
|
||||||
|
const postData = {
|
||||||
|
code: authCode,
|
||||||
|
grant_type: 'authorization_code',
|
||||||
|
client_id: this.clientId(),
|
||||||
|
client_secret: this.clientSecret(),
|
||||||
|
};
|
||||||
|
|
||||||
|
var formBody = [];
|
||||||
|
for (var property in postData) {
|
||||||
|
var encodedKey = encodeURIComponent(property);
|
||||||
|
var encodedValue = encodeURIComponent(postData[property]);
|
||||||
|
formBody.push(encodedKey + "=" + encodedValue);
|
||||||
|
}
|
||||||
|
formBody = formBody.join("&");
|
||||||
|
|
||||||
|
const response = await shim.fetch('https://api.dropboxapi.com/oauth2/token', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
|
||||||
|
},
|
||||||
|
body: formBody
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseText = await response.text();
|
||||||
|
if (!response.ok) throw new Error(responseText);
|
||||||
|
return JSON.parse(responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
isTokenError(status, responseText) {
|
||||||
|
if (status === 401) return true;
|
||||||
|
if (responseText.indexOf('OAuth 2 access token is malformed') >= 0) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async exec(method, path = '', body = null, headers = null, options = null) {
|
||||||
|
if (headers === null) headers = {};
|
||||||
|
if (options === null) options = {};
|
||||||
|
if (!options.target) options.target = 'string';
|
||||||
|
|
||||||
|
const authToken = this.authToken();
|
||||||
|
|
||||||
|
if (authToken) headers['Authorization'] = 'Bearer ' + authToken;
|
||||||
|
|
||||||
|
const endPointFormat = ['files/upload', 'files/download'].indexOf(path) >= 0 ? 'content' : 'api';
|
||||||
|
|
||||||
|
if (endPointFormat === 'api') {
|
||||||
|
headers['Content-Type'] = 'application/json';
|
||||||
|
if (body && typeof body === 'object') body = JSON.stringify(body);
|
||||||
|
} else {
|
||||||
|
headers['Content-Type'] = 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchOptions = {};
|
||||||
|
fetchOptions.headers = headers;
|
||||||
|
fetchOptions.method = method;
|
||||||
|
if (options.path) fetchOptions.path = options.path;
|
||||||
|
if (body) fetchOptions.body = body;
|
||||||
|
|
||||||
|
const url = path.indexOf('https://') === 0 ? path : this.baseUrl(endPointFormat) + '/' + path;
|
||||||
|
|
||||||
|
let tryCount = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
let response = null;
|
||||||
|
|
||||||
|
// console.info(this.requestToCurl_(url, fetchOptions));
|
||||||
|
|
||||||
|
// console.info(method + ' ' + url);
|
||||||
|
|
||||||
|
if (options.source == 'file' && (method == 'POST' || method == 'PUT')) {
|
||||||
|
response = await shim.uploadBlob(url, fetchOptions);
|
||||||
|
} else if (options.target == 'string') {
|
||||||
|
response = await shim.fetch(url, fetchOptions);
|
||||||
|
} else { // file
|
||||||
|
response = await shim.fetchBlob(url, fetchOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseText = await response.text();
|
||||||
|
|
||||||
|
// console.info('Response: ' + responseText);
|
||||||
|
|
||||||
|
let responseJson_ = null;
|
||||||
|
const loadResponseJson = () => {
|
||||||
|
if (!responseText) return null;
|
||||||
|
if (responseJson_) return responseJson_;
|
||||||
|
try {
|
||||||
|
responseJson_ = JSON.parse(responseText);
|
||||||
|
} catch (error) {
|
||||||
|
return { error: responseText };
|
||||||
|
}
|
||||||
|
return responseJson_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an error object with as much data as possible as it will appear in the log, which will make debugging easier
|
||||||
|
const newError = (message) => {
|
||||||
|
const json = loadResponseJson();
|
||||||
|
let code = '';
|
||||||
|
if (json && json.error_summary) {
|
||||||
|
code = json.error_summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gives a shorter response for error messages. Useful for cases where a full HTML page is accidentally loaded instead of
|
||||||
|
// JSON. That way the error message will still show there's a problem but without filling up the log or screen.
|
||||||
|
const shortResponseText = (responseText + '').substr(0, 1024);
|
||||||
|
const error = new JoplinError(method + ' ' + path + ': ' + message + ' (' + response.status + '): ' + shortResponseText, code);
|
||||||
|
error.httpStatus = response.status;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const json = loadResponseJson();
|
||||||
|
if (this.isTokenError(response.status, responseText)) {
|
||||||
|
this.setAuthToken(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When using fetchBlob we only get a string (not xml or json) back
|
||||||
|
if (options.target === 'file') throw newError('fetchBlob error');
|
||||||
|
|
||||||
|
throw newError('Error');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.responseFormat === 'text') return responseText;
|
||||||
|
|
||||||
|
return loadResponseJson();
|
||||||
|
} catch (error) {
|
||||||
|
tryCount++;
|
||||||
|
if (error.code.indexOf('too_many_write_operations') >= 0) {
|
||||||
|
this.logger().warn('too_many_write_operations ' + tryCount);
|
||||||
|
if (tryCount >= 3) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
await time.sleep(tryCount * 2);
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DropboxApi;
|
||||||
@@ -32,4 +32,4 @@ class EventDispatcher {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { EventDispatcher };
|
module.exports = EventDispatcher;
|
||||||
@@ -3,7 +3,9 @@ const Entities = require('html-entities').AllHtmlEntities;
|
|||||||
const htmlentities = (new Entities()).encode;
|
const htmlentities = (new Entities()).encode;
|
||||||
const Resource = require('lib/models/Resource.js');
|
const Resource = require('lib/models/Resource.js');
|
||||||
const ModelCache = require('lib/ModelCache');
|
const ModelCache = require('lib/ModelCache');
|
||||||
|
const ObjectUtils = require('lib/ObjectUtils');
|
||||||
const { shim } = require('lib/shim.js');
|
const { shim } = require('lib/shim.js');
|
||||||
|
const { _ } = require('lib/locale');
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
const MdToHtml_Katex = require('lib/MdToHtml_Katex');
|
const MdToHtml_Katex = require('lib/MdToHtml_Katex');
|
||||||
|
|
||||||
@@ -12,7 +14,6 @@ class MdToHtml {
|
|||||||
constructor(options = null) {
|
constructor(options = null) {
|
||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
|
|
||||||
this.supportsResourceLinks_ = !!options.supportsResourceLinks;
|
|
||||||
this.loadedResources_ = {};
|
this.loadedResources_ = {};
|
||||||
this.cachedContent_ = null;
|
this.cachedContent_ = null;
|
||||||
this.cachedContentKey_ = null;
|
this.cachedContentKey_ = null;
|
||||||
@@ -54,11 +55,11 @@ class MdToHtml {
|
|||||||
return output.join(' ');
|
return output.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
getAttr_(attrs, name) {
|
getAttr_(attrs, name, defaultValue = null) {
|
||||||
for (let i = 0; i < attrs.length; i++) {
|
for (let i = 0; i < attrs.length; i++) {
|
||||||
if (attrs[i][0] === name) return attrs[i].length > 1 ? attrs[i][1] : null;
|
if (attrs[i][0] === name) return attrs[i].length > 1 ? attrs[i][1] : null;
|
||||||
}
|
}
|
||||||
return null;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAttr_(attrs, name, value) {
|
setAttr_(attrs, name, value) {
|
||||||
@@ -130,35 +131,27 @@ class MdToHtml {
|
|||||||
const isResourceUrl = Resource.isResourceUrl(href);
|
const isResourceUrl = Resource.isResourceUrl(href);
|
||||||
const title = isResourceUrl ? this.getAttr_(attrs, 'title') : href;
|
const title = isResourceUrl ? this.getAttr_(attrs, 'title') : href;
|
||||||
|
|
||||||
if (isResourceUrl && !this.supportsResourceLinks_) {
|
let resourceIdAttr = "";
|
||||||
// In mobile, links to local resources, such as PDF, etc. currently aren't supported.
|
let icon = "";
|
||||||
// Ideally they should be opened in the user's browser.
|
let hrefAttr = '#';
|
||||||
return '<span style="opacity: 0.5">(Resource not yet supported: '; //+ htmlentities(text) + ']';
|
if (isResourceUrl) {
|
||||||
|
const resourceId = Resource.pathToId(href);
|
||||||
|
href = "joplin://" + resourceId;
|
||||||
|
resourceIdAttr = "data-resource-id='" + resourceId + "'";
|
||||||
|
icon = '<span class="resource-icon"></span>';
|
||||||
} else {
|
} else {
|
||||||
let resourceIdAttr = "";
|
// If the link is a plain URL (as opposed to a resource link), set the href to the actual
|
||||||
let icon = "";
|
// link. This allows the link to be exported too when exporting to PDF.
|
||||||
if (isResourceUrl) {
|
hrefAttr = href;
|
||||||
const resourceId = Resource.pathToId(href);
|
|
||||||
href = "joplin://" + resourceId;
|
|
||||||
resourceIdAttr = "data-resource-id='" + resourceId + "'";
|
|
||||||
icon = '<span class="resource-icon"></span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
const js = options.postMessageSyntax + "(" + JSON.stringify(href) + "); return false;";
|
|
||||||
let output = "<a " + resourceIdAttr + " title='" + htmlentities(title) + "' href='#' onclick='" + js + "'>" + icon;
|
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const js = options.postMessageSyntax + "(" + JSON.stringify(href) + "); return false;";
|
||||||
|
let output = "<a " + resourceIdAttr + " title='" + htmlentities(title) + "' href='" + hrefAttr + "' onclick='" + js + "'>" + icon;
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCloseLink_(attrs, options) {
|
renderCloseLink_(attrs, options) {
|
||||||
const href = this.getAttr_(attrs, 'href');
|
return '</a>';
|
||||||
const isResourceUrl = Resource.isResourceUrl(href);
|
|
||||||
|
|
||||||
if (isResourceUrl && !this.supportsResourceLinks_) {
|
|
||||||
return ')</span>';
|
|
||||||
} else {
|
|
||||||
return '</a>';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rendererPlugin_(language) {
|
rendererPlugin_(language) {
|
||||||
@@ -182,11 +175,23 @@ class MdToHtml {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
urldecode_(str) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent((str+'').replace(/\+/g, '%20'));
|
||||||
|
} catch (error) {
|
||||||
|
// decodeURIComponent can throw if the string contains non-encoded data (for example "100%")
|
||||||
|
// so in this case just return the non encoded string.
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
renderTokens_(markdownIt, tokens, options) {
|
renderTokens_(markdownIt, tokens, options) {
|
||||||
let output = [];
|
let output = [];
|
||||||
let previousToken = null;
|
let previousToken = null;
|
||||||
let anchorAttrs = [];
|
let anchorAttrs = [];
|
||||||
let extraCssBlocks = {};
|
let extraCssBlocks = {};
|
||||||
|
let anchorHrefs = [];
|
||||||
|
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
let t = tokens[i];
|
let t = tokens[i];
|
||||||
@@ -202,15 +207,11 @@ class MdToHtml {
|
|||||||
const codeBlockLanguage = t && t.info ? t.info : null;
|
const codeBlockLanguage = t && t.info ? t.info : null;
|
||||||
let rendererPlugin = null;
|
let rendererPlugin = null;
|
||||||
let rendererPluginOptions = { tagType: 'inline' };
|
let rendererPluginOptions = { tagType: 'inline' };
|
||||||
|
let linkHref = null;
|
||||||
|
|
||||||
if (isCodeBlock) rendererPlugin = this.rendererPlugin_(codeBlockLanguage);
|
if (isCodeBlock) rendererPlugin = this.rendererPlugin_(codeBlockLanguage);
|
||||||
|
|
||||||
if (previousToken && previousToken.tag === 'li' && tag === 'p') {
|
if (isInlineCode) {
|
||||||
// Markdown-it render list items as <li><p>Text<p></li> which makes it
|
|
||||||
// complicated to style and layout the HTML, so we remove this extra
|
|
||||||
// <p> here and below in closeTag.
|
|
||||||
openTag = null;
|
|
||||||
} else if (isInlineCode) {
|
|
||||||
openTag = null;
|
openTag = null;
|
||||||
} else if (tag && t.type.indexOf('html_inline') >= 0) {
|
} else if (tag && t.type.indexOf('html_inline') >= 0) {
|
||||||
openTag = null;
|
openTag = null;
|
||||||
@@ -233,6 +234,7 @@ class MdToHtml {
|
|||||||
if (openTag) {
|
if (openTag) {
|
||||||
if (openTag === 'a') {
|
if (openTag === 'a') {
|
||||||
anchorAttrs.push(attrs);
|
anchorAttrs.push(attrs);
|
||||||
|
anchorHrefs.push(this.getAttr_(attrs, 'href'));
|
||||||
output.push(this.renderOpenLink_(attrs, options));
|
output.push(this.renderOpenLink_(attrs, options));
|
||||||
} else {
|
} else {
|
||||||
const attrsHtml = this.renderAttrs_(attrs);
|
const attrsHtml = this.renderAttrs_(attrs);
|
||||||
@@ -317,7 +319,33 @@ class MdToHtml {
|
|||||||
|
|
||||||
if (closeTag) {
|
if (closeTag) {
|
||||||
if (closeTag === 'a') {
|
if (closeTag === 'a') {
|
||||||
output.push(this.renderCloseLink_(anchorAttrs.pop(), options));
|
const currentAnchorAttrs = anchorAttrs.pop();
|
||||||
|
|
||||||
|
// NOTE: Disabled for now due to this:
|
||||||
|
// https://github.com/laurent22/joplin/issues/318#issuecomment-375854848
|
||||||
|
|
||||||
|
// const previousContent = output.length ? output[output.length - 1].trim() : '';
|
||||||
|
// const anchorHref = this.getAttr_(currentAnchorAttrs, 'href', '').trim();
|
||||||
|
|
||||||
|
// Optimisation: If the content of the anchor is the same as the URL, we replace the content
|
||||||
|
// by (Link). This is to shorten the text, which is important especially when the note comes
|
||||||
|
// from imported HTML, which can contain many such links and make the text unreadble. An example
|
||||||
|
// would be a movie review that has multiple links to allow a user to rate the film from 1 to 5 stars.
|
||||||
|
// In the original page, it might be rendered as stars, via CSS, but in the imported note it would look like this:
|
||||||
|
// http://example.com/rate/1 http://example.com/rate/2 http://example.com/rate/3
|
||||||
|
// http://example.com/rate/4 http://example.com/rate/5
|
||||||
|
// which would take a lot of screen space even though it doesn't matter since the user is unlikely
|
||||||
|
// to rate the film from the note. This is actually a nice example, still readable, but there is way
|
||||||
|
// worse that this in notes that come from web-clipped content.
|
||||||
|
// With this change, the links will still be preserved but displayed like
|
||||||
|
// (link) (link) (link) (link) (link)
|
||||||
|
|
||||||
|
// if (this.urldecode_(previousContent) === htmlentities(this.urldecode_(anchorHref))) {
|
||||||
|
// output.pop();
|
||||||
|
// output.push(_('(Link)'));
|
||||||
|
// }
|
||||||
|
|
||||||
|
output.push(this.renderCloseLink_(currentAnchorAttrs, options));
|
||||||
} else {
|
} else {
|
||||||
output.push('</' + closeTag + '>');
|
output.push('</' + closeTag + '>');
|
||||||
}
|
}
|
||||||
@@ -336,14 +364,16 @@ class MdToHtml {
|
|||||||
|
|
||||||
// Insert the extra CSS at the top of the HTML
|
// Insert the extra CSS at the top of the HTML
|
||||||
|
|
||||||
const temp = ['<style>'];
|
if (!ObjectUtils.isEmpty(extraCssBlocks)) {
|
||||||
for (let n in extraCssBlocks) {
|
const temp = ['<style>'];
|
||||||
if (!extraCssBlocks.hasOwnProperty(n)) continue;
|
for (let n in extraCssBlocks) {
|
||||||
temp.push(extraCssBlocks[n]);
|
if (!extraCssBlocks.hasOwnProperty(n)) continue;
|
||||||
}
|
temp.push(extraCssBlocks[n]);
|
||||||
temp.push('</style>');
|
}
|
||||||
|
temp.push('</style>');
|
||||||
|
|
||||||
output = temp.concat(output);
|
output = temp.concat(output);
|
||||||
|
}
|
||||||
|
|
||||||
return output.join('');
|
return output.join('');
|
||||||
}
|
}
|
||||||
@@ -376,8 +406,8 @@ class MdToHtml {
|
|||||||
|
|
||||||
if (HORRIBLE_HACK) {
|
if (HORRIBLE_HACK) {
|
||||||
let counter = -1;
|
let counter = -1;
|
||||||
while (body.indexOf('- [ ]') >= 0 || body.indexOf('- [X]') >= 0) {
|
while (body.indexOf('- [ ]') >= 0 || body.indexOf('- [X]') >= 0 || body.indexOf('- [x]') >= 0) {
|
||||||
body = body.replace(/- \[(X| )\]/, function(v, p1) {
|
body = body.replace(/- \[(X| |x)\]/, function(v, p1) {
|
||||||
let s = p1 == ' ' ? 'NOTICK' : 'TICK';
|
let s = p1 == ' ' ? 'NOTICK' : 'TICK';
|
||||||
counter++;
|
counter++;
|
||||||
return '- mJOPmCHECKBOXm' + s + 'm' + counter + 'm';
|
return '- mJOPmCHECKBOXm' + s + 'm' + counter + 'm';
|
||||||
@@ -446,6 +476,9 @@ class MdToHtml {
|
|||||||
ul {
|
ul {
|
||||||
padding-left: 1.3em;
|
padding-left: 1.3em;
|
||||||
}
|
}
|
||||||
|
li p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
.resource-icon {
|
.resource-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -533,10 +566,10 @@ class MdToHtml {
|
|||||||
|
|
||||||
toggleTickAt(body, index) {
|
toggleTickAt(body, index) {
|
||||||
let counter = -1;
|
let counter = -1;
|
||||||
while (body.indexOf('- [ ]') >= 0 || body.indexOf('- [X]') >= 0) {
|
while (body.indexOf('- [ ]') >= 0 || body.indexOf('- [X]') >= 0 || body.indexOf('- [x]') >= 0) {
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
body = body.replace(/- \[(X| )\]/, function(v, p1) {
|
body = body.replace(/- \[(X| |x)\]/, function(v, p1) {
|
||||||
let s = p1 == ' ' ? 'NOTICK' : 'TICK';
|
let s = p1 == ' ' ? 'NOTICK' : 'TICK';
|
||||||
if (index == counter) {
|
if (index == counter) {
|
||||||
s = s == 'NOTICK' ? 'TICK' : 'NOTICK';
|
s = s == 'NOTICK' ? 'TICK' : 'NOTICK';
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ class MdToHtml_Katex {
|
|||||||
|
|
||||||
processContent(renderedTokens, content, tagType) {
|
processContent(renderedTokens, content, tagType) {
|
||||||
try {
|
try {
|
||||||
let renderered = katex.renderToString(content);
|
let renderered = katex.renderToString(content, {
|
||||||
|
displayMode: tagType === 'block',
|
||||||
|
});
|
||||||
|
|
||||||
if (tagType === 'block') renderered = '<p>' + renderered + '</p>';
|
if (tagType === 'block') renderered = '<p>' + renderered + '</p>';
|
||||||
|
|
||||||
|
|||||||
@@ -53,4 +53,9 @@ ObjectUtils.convertValuesToFunctions = function(o) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectUtils.isEmpty = function(o) {
|
||||||
|
if (!o) return true;
|
||||||
|
return Object.keys(o).length === 0 && o.constructor === Object;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = ObjectUtils;
|
module.exports = ObjectUtils;
|
||||||
73
ReactNativeClient/lib/SyncTargetDropbox.js
Normal file
73
ReactNativeClient/lib/SyncTargetDropbox.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const BaseSyncTarget = require('lib/BaseSyncTarget.js');
|
||||||
|
const { _ } = require('lib/locale.js');
|
||||||
|
const DropboxApi = require('lib/DropboxApi');
|
||||||
|
const Setting = require('lib/models/Setting.js');
|
||||||
|
const { parameters } = require('lib/parameters.js');
|
||||||
|
const { FileApi } = require('lib/file-api.js');
|
||||||
|
const { Synchronizer } = require('lib/synchronizer.js');
|
||||||
|
const { FileApiDriverDropbox } = require('lib/file-api-driver-dropbox.js');
|
||||||
|
|
||||||
|
class SyncTargetDropbox extends BaseSyncTarget {
|
||||||
|
|
||||||
|
static id() {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(db, options = null) {
|
||||||
|
super(db, options);
|
||||||
|
this.api_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static targetName() {
|
||||||
|
return 'dropbox';
|
||||||
|
}
|
||||||
|
|
||||||
|
static label() {
|
||||||
|
return _('Dropbox');
|
||||||
|
}
|
||||||
|
|
||||||
|
authRouteName() {
|
||||||
|
return 'DropboxLogin';
|
||||||
|
}
|
||||||
|
|
||||||
|
async isAuthenticated() {
|
||||||
|
const f = await this.fileApi();
|
||||||
|
return !!f.driver().api().authToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
async api() {
|
||||||
|
const fileApi = await this.fileApi();
|
||||||
|
return fileApi.driver().api();
|
||||||
|
}
|
||||||
|
|
||||||
|
async initFileApi() {
|
||||||
|
const params = parameters().dropbox;
|
||||||
|
|
||||||
|
const api = new DropboxApi({
|
||||||
|
id: params.id,
|
||||||
|
secret: params.secret,
|
||||||
|
});
|
||||||
|
|
||||||
|
api.on('authRefreshed', (auth) => {
|
||||||
|
this.logger().info('Saving updated OneDrive auth.');
|
||||||
|
Setting.setValue('sync.' + SyncTargetDropbox.id() + '.auth', auth ? auth : null);
|
||||||
|
});
|
||||||
|
|
||||||
|
const authToken = Setting.value('sync.' + SyncTargetDropbox.id() + '.auth');
|
||||||
|
api.setAuthToken(authToken);
|
||||||
|
|
||||||
|
const appDir = '';
|
||||||
|
const fileApi = new FileApi(appDir, new FileApiDriverDropbox(api));
|
||||||
|
fileApi.setSyncTargetId(SyncTargetDropbox.id());
|
||||||
|
fileApi.setLogger(this.logger());
|
||||||
|
return fileApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
async initSynchronizer() {
|
||||||
|
if (!(await this.isAuthenticated())) throw new Error('User is not authentified');
|
||||||
|
return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SyncTargetDropbox;
|
||||||
@@ -19,7 +19,7 @@ class SyncTargetFilesystem extends BaseSyncTarget {
|
|||||||
return _('File system');
|
return _('File system');
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthenticated() {
|
async isAuthenticated() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SyncTargetMemory extends BaseSyncTarget {
|
|||||||
return 'Memory';
|
return 'Memory';
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthenticated() {
|
async isAuthenticated() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class SyncTargetNextcloud extends BaseSyncTarget {
|
|||||||
return _('Nextcloud');
|
return _('Nextcloud');
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthenticated() {
|
async isAuthenticated() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class SyncTargetOneDrive extends BaseSyncTarget {
|
|||||||
return _('OneDrive');
|
return _('OneDrive');
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthenticated() {
|
async isAuthenticated() {
|
||||||
return this.api().auth();
|
return this.api().auth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ class SyncTargetOneDrive extends BaseSyncTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initSynchronizer() {
|
async initSynchronizer() {
|
||||||
if (!this.isAuthenticated()) throw new Error('User is not authentified');
|
if (!await this.isAuthenticated()) throw new Error('User is not authentified');
|
||||||
return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType'));
|
return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class SyncTargetWebDAV extends BaseSyncTarget {
|
|||||||
return _('WebDAV');
|
return _('WebDAV');
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthenticated() {
|
async isAuthenticated() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class Dropdown extends React.Component {
|
|||||||
this.headerRef_ = null;
|
this.headerRef_ = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
this.setState({
|
this.setState({
|
||||||
headerSize: { x: 0, y: 0, width: 0, height: 0 },
|
headerSize: { x: 0, y: 0, width: 0, height: 0 },
|
||||||
listVisible: false,
|
listVisible: false,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ItemList extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
this.setState({
|
this.setState({
|
||||||
topItemIndex: 0,
|
topItemIndex: 0,
|
||||||
bottomItemIndex: 0,
|
bottomItemIndex: 0,
|
||||||
@@ -45,7 +45,7 @@ class ItemList extends React.Component {
|
|||||||
this.updateStateItemIndexes();
|
this.updateStateItemIndexes();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
UNSAFE_componentWillReceiveProps(newProps) {
|
||||||
if (newProps.itemHeight) {
|
if (newProps.itemHeight) {
|
||||||
this.setState({
|
this.setState({
|
||||||
itemHeight: newProps.itemHeight,
|
itemHeight: newProps.itemHeight,
|
||||||
|
|||||||
@@ -30,16 +30,17 @@ class ModalDialog extends React.Component {
|
|||||||
borderColor:theme.dividerColor,
|
borderColor:theme.dividerColor,
|
||||||
margin: 20,
|
margin: 20,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
|
borderRadius: 5,
|
||||||
},
|
},
|
||||||
modalContentWrapper2: {
|
modalContentWrapper2: {
|
||||||
paddingTop: 10,
|
|
||||||
flex:1,
|
flex:1,
|
||||||
},
|
},
|
||||||
title: {
|
title: Object.assign({}, theme.normalText, {
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: theme.dividerColor,
|
borderBottomColor: theme.dividerColor,
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
},
|
fontWeight: 'bold',
|
||||||
|
}),
|
||||||
buttonRow: {
|
buttonRow: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
@@ -54,21 +55,22 @@ class ModalDialog extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const ContentComponent = this.props.ContentComponent;
|
const ContentComponent = this.props.ContentComponent;
|
||||||
|
const buttonBarEnabled = this.props.buttonBarEnabled !== false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={this.styles().modalWrapper}>
|
<View style={this.styles().modalWrapper}>
|
||||||
<Modal transparent={true} visible={true} onRequestClose={() => { }} >
|
<Modal transparent={true} visible={true} onRequestClose={() => { }} >
|
||||||
<View style={this.styles().modalContentWrapper}>
|
<View elevation={10} style={this.styles().modalContentWrapper}>
|
||||||
<Text style={this.styles().title}>Title</Text>
|
<Text style={this.styles().title}>{this.props.title}</Text>
|
||||||
<View style={this.styles().modalContentWrapper2}>
|
<View style={this.styles().modalContentWrapper2}>
|
||||||
{ContentComponent}
|
{ContentComponent}
|
||||||
</View>
|
</View>
|
||||||
<View style={this.styles().buttonRow}>
|
<View style={this.styles().buttonRow}>
|
||||||
<View style={{flex:1}}>
|
<View style={{flex:1}}>
|
||||||
<Button title={_('OK')} onPress={() => {}}></Button>
|
<Button disabled={!buttonBarEnabled} title={_('OK')} onPress={this.props.onOkPress}></Button>
|
||||||
</View>
|
</View>
|
||||||
<View style={{flex:1, marginLeft: 5}}>
|
<View style={{flex:1, marginLeft: 5}}>
|
||||||
<Button title={_('Cancel')} onPress={() => {}}></Button>
|
<Button disabled={!buttonBarEnabled} title={_('Cancel')} onPress={this.props.onCancelPress}></Button>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ActionButtonComponent extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
UNSAFE_componentWillReceiveProps(newProps) {
|
||||||
if ('buttonIndex' in newProps) {
|
if ('buttonIndex' in newProps) {
|
||||||
this.setState({ buttonIndex: newProps.buttonIndex });
|
this.setState({ buttonIndex: newProps.buttonIndex });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class AppNavComponent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
if (Platform.OS === 'ios') {
|
if (Platform.OS === 'ios') {
|
||||||
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
|
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
|
||||||
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide.bind(this));
|
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide.bind(this));
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ class Checkbox extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
this.setState({ checked: this.props.checked });
|
this.setState({ checked: this.props.checked });
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(newProps) {
|
UNSAFE_componentWillReceiveProps(newProps) {
|
||||||
if ('checked' in newProps) {
|
if ('checked' in newProps) {
|
||||||
this.setState({ checked: newProps.checked });
|
this.setState({ checked: newProps.checked });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
|
const { Platform } = require('react-native');
|
||||||
|
|
||||||
const globalStyle = {
|
const globalStyle = {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -14,6 +15,8 @@ const globalStyle = {
|
|||||||
dividerColor: "#dddddd",
|
dividerColor: "#dddddd",
|
||||||
selectedColor: '#e5e5e5',
|
selectedColor: '#e5e5e5',
|
||||||
disabledOpacity: 0.2,
|
disabledOpacity: 0.2,
|
||||||
|
colorUrl: '#000CFF',
|
||||||
|
textSelectionColor: "#0096FF",
|
||||||
|
|
||||||
raisedBackgroundColor: "#0080EF",
|
raisedBackgroundColor: "#0080EF",
|
||||||
raisedColor: "#003363",
|
raisedColor: "#003363",
|
||||||
@@ -36,29 +39,83 @@ globalStyle.marginTop = globalStyle.margin;
|
|||||||
globalStyle.marginBottom = globalStyle.margin;
|
globalStyle.marginBottom = globalStyle.margin;
|
||||||
globalStyle.htmlMarginLeft = ((globalStyle.marginLeft / 10) * 0.6).toFixed(2) + 'em';
|
globalStyle.htmlMarginLeft = ((globalStyle.marginLeft / 10) * 0.6).toFixed(2) + 'em';
|
||||||
|
|
||||||
globalStyle.icon = {
|
// globalStyle.icon = {
|
||||||
color: globalStyle.color,
|
// color: globalStyle.color,
|
||||||
fontSize: 30,
|
// fontSize: 30,
|
||||||
};
|
// };
|
||||||
|
|
||||||
globalStyle.lineInput = {
|
// globalStyle.lineInput = {
|
||||||
color: globalStyle.color,
|
// color: globalStyle.color,
|
||||||
backgroundColor: globalStyle.backgroundColor,
|
// backgroundColor: globalStyle.backgroundColor,
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
// globalStyle.buttonRow = {
|
||||||
|
// flexDirection: 'row',
|
||||||
|
// borderTopWidth: 1,
|
||||||
|
// borderTopColor: globalStyle.dividerColor,
|
||||||
|
// paddingTop: 10,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// globalStyle.normalText = {
|
||||||
|
// color: globalStyle.color,
|
||||||
|
// fontSize: globalStyle.fontSize,
|
||||||
|
// };
|
||||||
|
|
||||||
let themeCache_ = {};
|
let themeCache_ = {};
|
||||||
|
|
||||||
|
function addExtraStyles(style) {
|
||||||
|
style.icon = {
|
||||||
|
color: style.color,
|
||||||
|
fontSize: 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
style.lineInput = {
|
||||||
|
color: style.color,
|
||||||
|
backgroundColor: style.backgroundColor,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Platform.OS === 'ios') {
|
||||||
|
style.lineInput.borderBottomWidth = 1;
|
||||||
|
style.lineInput.borderBottomColor = style.dividerColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
style.buttonRow = {
|
||||||
|
flexDirection: 'row',
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: style.dividerColor,
|
||||||
|
paddingTop: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
style.normalText = {
|
||||||
|
color: style.color,
|
||||||
|
fontSize: style.fontSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
style.urlText = {
|
||||||
|
color: style.colorUrl,
|
||||||
|
fontSize: style.fontSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
function themeStyle(theme) {
|
function themeStyle(theme) {
|
||||||
|
if (!theme) {
|
||||||
|
console.warn('Theme not set!! Defaulting to Light theme');
|
||||||
|
theme = Setting.THEME_LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
if (themeCache_[theme]) return themeCache_[theme];
|
if (themeCache_[theme]) return themeCache_[theme];
|
||||||
|
|
||||||
let output = Object.assign({}, globalStyle);
|
let output = Object.assign({}, globalStyle);
|
||||||
if (theme == Setting.THEME_LIGHT) return output;
|
if (theme == Setting.THEME_LIGHT) return addExtraStyles(output);
|
||||||
|
|
||||||
output.backgroundColor = '#1D2024';
|
output.backgroundColor = '#1D2024';
|
||||||
output.color = '#dddddd';
|
output.color = '#dddddd';
|
||||||
output.colorFaded = '#777777';
|
output.colorFaded = '#777777';
|
||||||
output.dividerColor = '#555555';
|
output.dividerColor = '#555555';
|
||||||
output.selectedColor = '#333333';
|
output.selectedColor = '#333333';
|
||||||
|
output.textSelectionColor = '#00AEFF';
|
||||||
|
|
||||||
output.raisedBackgroundColor = "#0F2051";
|
output.raisedBackgroundColor = "#0F2051";
|
||||||
output.raisedColor = "#788BC3";
|
output.raisedColor = "#788BC3";
|
||||||
@@ -69,7 +126,7 @@ function themeStyle(theme) {
|
|||||||
output.htmlLinkColor = 'rgb(166,166,255)';
|
output.htmlLinkColor = 'rgb(166,166,255)';
|
||||||
|
|
||||||
themeCache_[theme] = output;
|
themeCache_[theme] = output;
|
||||||
return themeCache_[theme];
|
return addExtraStyles(themeCache_[theme]);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { globalStyle, themeStyle };
|
module.exports = { globalStyle, themeStyle };
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
const React = require('react'); const Component = React.Component;
|
const React = require('react'); const Component = React.Component;
|
||||||
const { Platform, WebView, View, Linking } = require('react-native');
|
const { Platform, WebView, View } = require('react-native');
|
||||||
const { globalStyle } = require('lib/components/global-style.js');
|
const { globalStyle } = require('lib/components/global-style.js');
|
||||||
const Resource = require('lib/models/Resource.js');
|
const Resource = require('lib/models/Resource.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
@@ -18,8 +18,8 @@ class NoteBodyViewer extends Component {
|
|||||||
this.isMounted_ = false;
|
this.isMounted_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
UNSAFE_componentWillMount() {
|
||||||
this.mdToHtml_ = new MdToHtml({ supportsResourceLinks: false });
|
this.mdToHtml_ = new MdToHtml();
|
||||||
this.isMounted_ = true;
|
this.isMounted_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class NoteBodyViewer extends Component {
|
|||||||
//msg = msg.split(':');
|
//msg = msg.split(':');
|
||||||
//this.bodyScrollTop_ = Number(msg[1]);
|
//this.bodyScrollTop_ = Number(msg[1]);
|
||||||
} else {
|
} else {
|
||||||
Linking.openURL(msg);
|
this.props.onJoplinLinkClick(msg);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user