Compare commits
646 Commits
server-v2.
...
binary-sig
Author | SHA1 | Date | |
---|---|---|---|
|
57195ef715 | ||
|
531f2d7f78 | ||
|
3db882d940 | ||
|
b824ff5457 | ||
|
3669a1b5d6 | ||
|
b93f9aaf01 | ||
|
8679290206 | ||
|
4acec5c6c7 | ||
|
f1b03453a4 | ||
|
7972dd5556 | ||
|
ed58ed91fd | ||
|
a0fd942a1c | ||
|
4842500f0a | ||
|
84c7f28ec5 | ||
|
f3eea43d24 | ||
|
8babaddbcb | ||
|
13cdaabb17 | ||
|
a94aa21088 | ||
|
6116bed4e3 | ||
|
fabd0b4dda | ||
|
6b72f86e7b | ||
|
02cf546124 | ||
|
eecb012d64 | ||
|
04e9b40769 | ||
|
efdbaeb397 | ||
|
46425b920c | ||
|
f5be43c2ac | ||
|
080541a2fe | ||
|
0b3919fd62 | ||
|
7dc638edf4 | ||
|
3b686194d8 | ||
|
5c2640f88f | ||
|
eca0f92dff | ||
|
260fa6c038 | ||
|
8ec6bc9138 | ||
|
93fa92369b | ||
|
bc6c5ab7a7 | ||
|
1826625e4f | ||
|
20b8fb2719 | ||
|
f813e71b29 | ||
|
02422a6e31 | ||
|
69a34e87f3 | ||
|
cbeaa16b61 | ||
|
05917ac142 | ||
|
897fd0f727 | ||
|
9edb402b18 | ||
|
36ae58ffe1 | ||
|
5ef8b86957 | ||
|
c7228cfcd6 | ||
|
7a791dbf98 | ||
|
a543588527 | ||
|
998ad142a6 | ||
|
b6a53f96f7 | ||
|
841a9c6e09 | ||
|
d25c078ef0 | ||
|
0c8de68b80 | ||
|
44d93d52d3 | ||
|
073bec9e8c | ||
|
e6a8c2bea5 | ||
|
81c316cd2c | ||
|
659c851960 | ||
|
572701d9a0 | ||
|
ff69ac17be | ||
|
b44945b3a0 | ||
|
2584224026 | ||
|
46136871bf | ||
|
66ef37bd4e | ||
|
9ddf75604d | ||
|
3ed7e1d7e8 | ||
|
b2b412105a | ||
|
60a3c4f65e | ||
|
9645414c17 | ||
|
af0136ef39 | ||
|
b76586c4fd | ||
|
376e4ebde0 | ||
|
1439b8787f | ||
|
b8854a99be | ||
|
6cf02173dc | ||
|
4d8a53d8c9 | ||
|
7f43718e1d | ||
|
690ce637b1 | ||
|
4d023e679e | ||
|
6e220a978f | ||
|
39757cd90e | ||
|
5ccbbea757 | ||
|
309222c082 | ||
|
50f5fe2c91 | ||
|
eacae83182 | ||
|
403d770b1d | ||
|
a481bf1b53 | ||
|
0d32570c9e | ||
|
f017e99b02 | ||
|
a89d64d435 | ||
|
3a27086534 | ||
|
413c1e41b5 | ||
|
8b879464b8 | ||
|
97c9bbc1fe | ||
|
e5bebef7b2 | ||
|
73752c4b3f | ||
|
dcf7c9838d | ||
|
f325e7694b | ||
|
75d204c9ca | ||
|
cf4008951d | ||
|
d67818d096 | ||
|
6aaea8ad4f | ||
|
de41278096 | ||
|
f01ab70907 | ||
|
bbdb221a67 | ||
|
7d053f8c79 | ||
|
fcad0bf3ca | ||
|
58f929f6b5 | ||
|
943198c56e | ||
|
2112ad4004 | ||
|
5995dc81f3 | ||
|
104e752634 | ||
|
fc335cd15d | ||
|
45923ba0d3 | ||
|
8fefa99d81 | ||
|
85d652cd67 | ||
|
88e41e9c7d | ||
|
26750488d0 | ||
|
a0f582b2b9 | ||
|
917b53bec2 | ||
|
e44a93422a | ||
|
e115ef4259 | ||
|
bcec699124 | ||
|
d23c728a1a | ||
|
0a2d507dec | ||
|
0c08617606 | ||
|
29fba45c33 | ||
|
1071a455b6 | ||
|
57e4b36fd7 | ||
|
f08fa92294 | ||
|
3a8d87d292 | ||
|
53302c9e90 | ||
|
28a24d8c03 | ||
|
3e52411bc4 | ||
|
1548ea18e1 | ||
|
f8cd1ba8e5 | ||
|
d18a4be31f | ||
|
c56f270ed6 | ||
|
2bca3d1032 | ||
|
9f81d69c5e | ||
|
815419260d | ||
|
6729a3d51f | ||
|
6d8ce280dd | ||
|
9e5b455065 | ||
|
09cbac3019 | ||
|
5354ad3934 | ||
|
7754048b80 | ||
|
ffeeff260f | ||
|
71ea74d273 | ||
|
3a744c79ae | ||
|
d9ba27a1ec | ||
|
0a3540049c | ||
|
ab50ca9bbd | ||
|
0bee793ab8 | ||
|
89fc5e19d9 | ||
|
6a3bf51084 | ||
|
df1e298c84 | ||
|
b9c706324b | ||
|
ab7e2de1d9 | ||
|
7ef8753b94 | ||
|
d48a5efa03 | ||
|
0804b62ffb | ||
|
37995b9ec7 | ||
|
7a3e6fde7f | ||
|
bd4291462e | ||
|
489d6778db | ||
|
538a1413d9 | ||
|
3c9b755045 | ||
|
fd7b345efa | ||
|
c96468149a | ||
|
d6d4897e1c | ||
|
e07e248fea | ||
|
b561460307 | ||
|
f6d1a27f51 | ||
|
80a1500634 | ||
|
bcb578c933 | ||
|
75ad454971 | ||
|
e90b7f2d81 | ||
|
ffca11ca8a | ||
|
bd98951d32 | ||
|
9106fb82f3 | ||
|
5c6e17bc89 | ||
|
538e9e9b4e | ||
|
d871b3c7d6 | ||
|
99c6c9b411 | ||
|
3eca4ada5a | ||
|
19431abc73 | ||
|
3e299f1ab9 | ||
|
42873d3829 | ||
|
4983327f90 | ||
|
fddbe6cf6c | ||
|
57f00c612d | ||
|
235288e903 | ||
|
38be744c3e | ||
|
2384ec8792 | ||
|
85f7caa0eb | ||
|
ad0f0414c4 | ||
|
437320f90c | ||
|
c1db7182ac | ||
|
aa4af69afc | ||
|
21a39af97b | ||
|
0812cc5944 | ||
|
1fb5d2c6c5 | ||
|
1b9901d232 | ||
|
f15d2793cc | ||
|
ad4d71dbe1 | ||
|
4bee6ffc90 | ||
|
01f63b3d97 | ||
|
b19b590efc | ||
|
6b7577f94d | ||
|
4d09b14522 | ||
|
9f1e95324d | ||
|
f98314346d | ||
|
fa659b615a | ||
|
e4aafa7edb | ||
|
811c40b074 | ||
|
405c528ef0 | ||
|
a176216374 | ||
|
8d0b090f66 | ||
|
337c5ed61c | ||
|
b32d39860b | ||
|
a091608f72 | ||
|
9686ee7833 | ||
|
3b55dcac65 | ||
|
d524d11d8a | ||
|
9c080ec631 | ||
|
da11476fd7 | ||
|
d157b9cfc7 | ||
|
bc8c61748a | ||
|
3ad727889b | ||
|
8df128bb7a | ||
|
5a4568f4db | ||
|
170295919a | ||
|
2262cbfdfd | ||
|
43e40bcf5a | ||
|
e60595f0de | ||
|
527a7c115d | ||
|
c22f910500 | ||
|
667b7969ff | ||
|
1bbf065142 | ||
|
606cad3c3a | ||
|
c9612dc8b8 | ||
|
6ee30e22a6 | ||
|
a6536e1ef9 | ||
|
92cf5abd08 | ||
|
d1e545ac2c | ||
|
ec6567c68d | ||
|
3b236307f7 | ||
|
14ac54bf3d | ||
|
e53b796523 | ||
|
9d189b2b34 | ||
|
84545cf26d | ||
|
c427a6d0a5 | ||
|
42dc6e1ea6 | ||
|
431b95ff7b | ||
|
041fb731a6 | ||
|
5289f80394 | ||
|
6c12ce0e04 | ||
|
46982c7d64 | ||
|
359448eb69 | ||
|
32bb256cca | ||
|
219585bbcf | ||
|
1a9dbcbd1d | ||
|
6a9848ebe7 | ||
|
9e73d3590b | ||
|
08c9a25182 | ||
|
5b9a45dc1d | ||
|
9dd2fb9674 | ||
|
234b5c8363 | ||
|
1dc7ec3701 | ||
|
72773caf58 | ||
|
094249d074 | ||
|
c324f17453 | ||
|
25a31b0689 | ||
|
f2995dd196 | ||
|
ca575162f7 | ||
|
f0ade02435 | ||
|
b13c02017a | ||
|
716c8c1ce4 | ||
|
30a49b84ad | ||
|
b8e4150bfd | ||
|
ed0edcb36c | ||
|
e93046e8e2 | ||
|
18a0ca0881 | ||
|
21dbc800d5 | ||
|
5c1eda3392 | ||
|
1139317788 | ||
|
a24ccb8da9 | ||
|
0aaa396315 | ||
|
f9dc19e1c4 | ||
|
1839724d7c | ||
|
a5aeb3a2f8 | ||
|
d5d57aa360 | ||
|
9aa5df7790 | ||
|
a7697465a8 | ||
|
aeb7e5ce47 | ||
|
42cef1e918 | ||
|
b832930512 | ||
|
057ac550bd | ||
|
3a14b76a61 | ||
|
e1a8c76598 | ||
|
b62e6552cd | ||
|
ca6e50e80c | ||
|
ad8947a85d | ||
|
fb562210b2 | ||
|
34940d1c4f | ||
|
7fa1459dc3 | ||
|
625689dbb1 | ||
|
dc976047d2 | ||
|
a014e830e7 | ||
|
1e828bfdca | ||
|
60309ec6a3 | ||
|
aabba090b1 | ||
|
6ae903ef4d | ||
|
dd86940c6b | ||
|
7d7b7ed6f3 | ||
|
8de904cd3c | ||
|
c706b8dd2f | ||
|
d55d4d42e5 | ||
|
bbfeffec69 | ||
|
3c471dc120 | ||
|
be0fa69b3b | ||
|
bf1bdf0951 | ||
|
a1a10a6c55 | ||
|
02e8307093 | ||
|
285a3a211e | ||
|
80cb1471fc | ||
|
a7a194f835 | ||
|
41a0b3359a | ||
|
1f70357d37 | ||
|
107f2e128e | ||
|
e1cd8d9b85 | ||
|
293f621e46 | ||
|
c5b551bbcb | ||
|
ac776eabc1 | ||
|
05c17fbfac | ||
|
6b9de394ca | ||
|
bef9a29581 | ||
|
1546aad7e9 | ||
|
fe47fef261 | ||
|
288f4ab43b | ||
|
294cbaea4d | ||
|
f5fc1f2f22 | ||
|
c90865c4d2 | ||
|
322641ccd6 | ||
|
2656666ed8 | ||
|
2d673902a4 | ||
|
631c41a1ff | ||
|
7841c99c02 | ||
|
ac75d8f6ac | ||
|
200ff617dc | ||
|
bbdc18f371 | ||
|
0d35b64f9a | ||
|
765c4482d6 | ||
|
0a0e31a37c | ||
|
0c1f4031b4 | ||
|
9ed022458b | ||
|
ba5f0bc6e3 | ||
|
793e8f6c0f | ||
|
6182ce521d | ||
|
544c50663a | ||
|
53aa9e2b42 | ||
|
884260189c | ||
|
2f9464f21f | ||
|
c6e993b04a | ||
|
89eb012b25 | ||
|
1e2aa4e2b5 | ||
|
0019bb8d6b | ||
|
e629a4d325 | ||
|
049c769d37 | ||
|
47aed8742a | ||
|
8aad67ccfe | ||
|
af7cbcbca7 | ||
|
88a91314af | ||
|
9873c2d756 | ||
|
46b68cf461 | ||
|
6b96b1f355 | ||
|
dc819700bb | ||
|
1d1d5fea06 | ||
|
c3afc0ede7 | ||
|
2092110a6e | ||
|
fc940e9a7c | ||
|
8718310dd0 | ||
|
1b527f2bbe | ||
|
4da217bc2f | ||
|
d3abd4ebf2 | ||
|
38851edf86 | ||
|
05efb765d6 | ||
|
28dc4a6abd | ||
|
2f7b56f96f | ||
|
fdaa3735fb | ||
|
7dfaea12f7 | ||
|
18199b27d9 | ||
|
a7c52082bb | ||
|
3b5357e0c1 | ||
|
10dd4e45ed | ||
|
1963835309 | ||
|
46ec0c1381 | ||
|
bb84ae4d68 | ||
|
b3ff53c0da | ||
|
acd7bfd9f5 | ||
|
1dff50d080 | ||
|
af40970d09 | ||
|
07535a494e | ||
|
907422cefa | ||
|
f643baea25 | ||
|
55a4f33982 | ||
|
df6700959a | ||
|
fde8235f3e | ||
|
f6ba56d966 | ||
|
4a5312823b | ||
|
31a27b0e1c | ||
|
984ad868e8 | ||
|
9b657eeda2 | ||
|
6f3ad4b3b0 | ||
|
56f06fae3c | ||
|
c22d884357 | ||
|
35dc22197d | ||
|
70d56ca0be | ||
|
bca09b9476 | ||
|
b82bf16505 | ||
|
2f254d81cd | ||
|
b14ce03e5b | ||
|
90b04cbd37 | ||
|
5ae866ea85 | ||
|
b450ab9f5a | ||
|
138bc8144b | ||
|
c9831833c4 | ||
|
2813f93c18 | ||
|
27bec674a0 | ||
|
ff79ca8781 | ||
|
34a1342db6 | ||
|
e252986b98 | ||
|
3537c3e5f9 | ||
|
fdc86f94c4 | ||
|
dc5dc94ed5 | ||
|
f7682d3da3 | ||
|
8e2975d23d | ||
|
ce85489166 | ||
|
13f5738090 | ||
|
cce2ae7401 | ||
|
c9b49a50c8 | ||
|
c419c43622 | ||
|
cc5ecfba2b | ||
|
a98d5feff6 | ||
|
7aa4feffd4 | ||
|
0b46a744f1 | ||
|
4d5efff2af | ||
|
4b2aaa6836 | ||
|
4e27600f9c | ||
|
6d4394a88d | ||
|
aad9c803ba | ||
|
5418cc82ca | ||
|
79eb33a7f4 | ||
|
cdef433f38 | ||
|
b29b50df0b | ||
|
91c3986f88 | ||
|
29e4a335fb | ||
|
4e942afba6 | ||
|
3bee0a142b | ||
|
9a9fdef512 | ||
|
4888b4bd14 | ||
|
bba3af17b7 | ||
|
b695acf4ed | ||
|
3367b52b53 | ||
|
c31622f286 | ||
|
488e469e33 | ||
|
fa7d48a3bd | ||
|
0cd2fd660d | ||
|
6bb52d5ad6 | ||
|
c2d5fc13d7 | ||
|
b1e5896d4c | ||
|
cc42b7bc38 | ||
|
4bdb3d0b7e | ||
|
6601547b81 | ||
|
7e29804e68 | ||
|
257a24166e | ||
|
8b3c9e81a7 | ||
|
c65e051e1f | ||
|
a91c8ffbf3 | ||
|
0530c74924 | ||
|
2feed88c51 | ||
|
2017e9d7e9 | ||
|
afe6cb9454 | ||
|
690e22b39a | ||
|
8a0aa40707 | ||
|
1f40a14084 | ||
|
6b9a270225 | ||
|
0bc55bff7f | ||
|
d9215b044f | ||
|
2f9384f891 | ||
|
a172b1380e | ||
|
0d4c074e84 | ||
|
9eff7e6060 | ||
|
1edb345e85 | ||
|
54ed374af6 | ||
|
9866e5912c | ||
|
4058f624f4 | ||
|
0bc15f40b3 | ||
|
7a55a08fec | ||
|
4efb6003dc | ||
|
f4f96cfe89 | ||
|
a43ce33adf | ||
|
f95ccd6700 | ||
|
07184301d1 | ||
|
0678dad2d6 | ||
|
b2d59002bb | ||
|
7557791230 | ||
|
f10d9f75b0 | ||
|
5a05cc5797 | ||
|
488394ff47 | ||
|
b2ba0ee849 | ||
|
6c108bbf6c | ||
|
275c80ade5 | ||
|
00bc25ed5c | ||
|
f5ef318f70 | ||
|
ff355b9f4d | ||
|
9a9d51caaf | ||
|
3e6e75c27b | ||
|
a8689816bf | ||
|
27d1a0ee7c | ||
|
8e12ace3ed | ||
|
d5c6690606 | ||
|
f6741cf342 | ||
|
44fad32ee5 | ||
|
bae7ff0ca5 | ||
|
074d02da56 | ||
|
70b01b70c6 | ||
|
d29e4c434c | ||
|
423191bda9 | ||
|
7a0af66c63 | ||
|
49e444e73b | ||
|
0db0a565b7 | ||
|
5fb01b5c7a | ||
|
854f1163cd | ||
|
d55f6aeb2a | ||
|
ea30a6bd38 | ||
|
e09b26b99b | ||
|
e7386e6fe3 | ||
|
767213cdc1 | ||
|
a189b2eff0 | ||
|
655ea6945d | ||
|
5106ccee91 | ||
|
1ee515454a | ||
|
fc46c87ef7 | ||
|
422b81ae24 | ||
|
17124e86d1 | ||
|
d2aab6536c | ||
|
ed71f68e1d | ||
|
01d451f72a | ||
|
5b3f07f3c5 | ||
|
edf7cab1ef | ||
|
caaac5c1a2 | ||
|
5a28a6bc90 | ||
|
f9f7c86915 | ||
|
e2d59ee1fa | ||
|
d81802e7d2 | ||
|
73bb79b558 | ||
|
c41ebe8d9d | ||
|
8e2e7eccd9 | ||
|
527a7da2ff | ||
|
40399cf3e1 | ||
|
873808a66a | ||
|
cf300bc842 | ||
|
9a06824fde | ||
|
186316bb8b | ||
|
5c8861cbd1 | ||
|
c710cfd273 | ||
|
3ef41016b5 | ||
|
85423fd835 | ||
|
d690146f9f | ||
|
944e0ef304 | ||
|
409dcea0c6 | ||
|
6c20cdefd4 | ||
|
300f1590ba | ||
|
f6c2013df8 | ||
|
e3dc77357c | ||
|
a739636ce6 | ||
|
7620c2b0b7 | ||
|
60c4045000 | ||
|
39fb40dc37 | ||
|
145cb6c41e | ||
|
de9f9985d1 | ||
|
23277aaf85 | ||
|
e9e7a1d0df | ||
|
3453240833 | ||
|
1882aac628 | ||
|
6868e7086b | ||
|
b35eeb6626 | ||
|
98c56818bb | ||
|
722a0df681 | ||
|
115cf116a2 | ||
|
f34e048fad | ||
|
a754659ab9 | ||
|
0517d1e5d6 | ||
|
31795f6c78 | ||
|
5ac9178f79 | ||
|
faf0a4ec8d | ||
|
be70cdf75b | ||
|
5284989a08 | ||
|
739449bde4 | ||
|
1e9cbc9606 | ||
|
0527dbbdc2 | ||
|
80f061a2ca | ||
|
d687abd7ef | ||
|
c16a92081d | ||
|
1289be1d90 | ||
|
fdfabe8f92 | ||
|
db4e45ba61 | ||
|
28621f7e89 | ||
|
ad2b6ef2fa | ||
|
f6ca396e6e | ||
|
2f46a175ab | ||
|
79c84150a0 | ||
|
318a61e7c5 | ||
|
31c66ae3cd | ||
|
c50fdde5da | ||
|
a7f5a2089d | ||
|
10252228ae | ||
|
573222762a | ||
|
a2be4fc535 | ||
|
e555eafb33 | ||
|
fa7eb0ff9d | ||
|
733b38250b | ||
|
50177bd997 | ||
|
37ad911659 | ||
|
538d6f3d47 | ||
|
1c7ad612a7 | ||
|
789b2005b8 | ||
|
83038de321 | ||
|
871190b7ee | ||
|
0a65d538c5 | ||
|
5edf10c398 | ||
|
60db566c2d | ||
|
36381a098f | ||
|
e6b54efe1b | ||
|
ecde67c25f | ||
|
46d0100bb7 | ||
|
957b311872 | ||
|
7051459c47 | ||
|
69038e2d84 | ||
|
652a72aba7 | ||
|
9a1adff5fe |
1568
.eslintignore
32
.eslintrc.js
@@ -77,6 +77,7 @@ module.exports = {
|
||||
'no-array-constructor': ['error'],
|
||||
'radix': ['error'],
|
||||
'eqeqeq': ['error', 'always'],
|
||||
'no-console': ['error', { 'allow': ['warn', 'error'] }],
|
||||
|
||||
// Warn only for now because fixing everything would take too much
|
||||
// refactoring, but new code should try to stick to it.
|
||||
@@ -90,7 +91,12 @@ module.exports = {
|
||||
// Disable because of this: https://github.com/facebook/react/issues/16265
|
||||
// "react-hooks/exhaustive-deps": "warn",
|
||||
|
||||
'jest/require-top-level-describe': ['error', { 'maxNumberOfTopLevelDescribes': 1 }],
|
||||
'jest/no-identical-title': ['error'],
|
||||
'jest/prefer-lowercase-title': ['error', { 'ignoreTopLevelDescribe': true }],
|
||||
|
||||
'promise/prefer-await-to-then': 'error',
|
||||
'no-unneeded-ternary': 'error',
|
||||
|
||||
// -------------------------------
|
||||
// Formatting
|
||||
@@ -109,6 +115,7 @@ module.exports = {
|
||||
'exports': 'always-multiline',
|
||||
'functions': 'never',
|
||||
}],
|
||||
'comma-spacing': ['error', { 'before': false, 'after': true }],
|
||||
'no-trailing-spaces': 'error',
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
'prefer-template': ['error'],
|
||||
@@ -134,6 +141,14 @@ module.exports = {
|
||||
'spaced-comment': ['error', 'always'],
|
||||
'keyword-spacing': ['error', { 'before': true, 'after': true }],
|
||||
'no-multi-spaces': ['error'],
|
||||
|
||||
// Regarding the keyword blacklist:
|
||||
// - err: We generally avoid using too many abbreviations, so it should
|
||||
// be "error", not "err"
|
||||
// - notebook: In code, it should always be "folder" (not "notebook").
|
||||
// In user-facing text, it should be "notebook".
|
||||
'id-denylist': ['error', 'err', 'notebook', 'notebooks'],
|
||||
'prefer-arrow-callback': ['error'],
|
||||
},
|
||||
'plugins': [
|
||||
'react',
|
||||
@@ -144,8 +159,19 @@ module.exports = {
|
||||
// 'react-hooks',
|
||||
'import',
|
||||
'promise',
|
||||
'jest',
|
||||
],
|
||||
'overrides': [
|
||||
{
|
||||
'files': [
|
||||
'packages/tools/**',
|
||||
'packages/app-mobile/tools/**',
|
||||
'packages/app-desktop/tools/**',
|
||||
],
|
||||
'rules': {
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
// enable the rule specifically for TypeScript files
|
||||
'files': ['*.ts', '*.tsx'],
|
||||
@@ -154,10 +180,9 @@ module.exports = {
|
||||
'project': './tsconfig.eslint.json',
|
||||
},
|
||||
'rules': {
|
||||
// Warn only because it would make it difficult to convert JS classes to TypeScript, unless we
|
||||
// make everything public which is not great. New code however should specify member accessibility.
|
||||
'@typescript-eslint/explicit-member-accessibility': ['warn'],
|
||||
'@typescript-eslint/explicit-member-accessibility': ['error'],
|
||||
'@typescript-eslint/type-annotation-spacing': ['error', { 'before': false, 'after': true }],
|
||||
'@typescript-eslint/no-inferrable-types': ['error', { 'ignoreParameters': true, 'ignoreProperties': true }],
|
||||
'@typescript-eslint/comma-dangle': ['error', {
|
||||
'arrays': 'always-multiline',
|
||||
'objects': 'always-multiline',
|
||||
@@ -168,6 +193,7 @@ module.exports = {
|
||||
'tuples': 'always-multiline',
|
||||
'functions': 'never',
|
||||
}],
|
||||
'@typescript-eslint/object-curly-spacing': ['error', 'always'],
|
||||
'@typescript-eslint/semi': ['error', 'always'],
|
||||
'@typescript-eslint/member-delimiter-style': ['error', {
|
||||
'multiline': {
|
||||
|
9
.github/scripts/run_ci.sh
vendored
@@ -107,6 +107,12 @@ if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
|
||||
if [ $testResult -ne 0 ]; then
|
||||
exit $testResult
|
||||
fi
|
||||
|
||||
yarn run packageJsonLint
|
||||
testResult=$?
|
||||
if [ $testResult -ne 0 ]; then
|
||||
exit $testResult
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
@@ -174,9 +180,6 @@ cd "$ROOT_DIR/packages/app-desktop"
|
||||
|
||||
if [[ $GIT_TAG_NAME = v* ]]; then
|
||||
echo "Step: Building and publishing desktop application..."
|
||||
# cd "$ROOT_DIR/packages/tools"
|
||||
# node bundleDefaultPlugins.js
|
||||
cd "$ROOT_DIR/packages/app-desktop"
|
||||
USE_HARD_LINKS=false yarn run dist
|
||||
elif [[ $IS_LINUX = 1 ]] && [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
|
||||
echo "Step: Building Docker Image..."
|
||||
|
2
.github/workflows/build-android.yml
vendored
@@ -6,6 +6,7 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
pre_job:
|
||||
if: github.repository == 'laurent22/joplin'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
@@ -16,6 +17,7 @@ jobs:
|
||||
concurrent_skipping: 'same_content_newer'
|
||||
|
||||
BuildAndroidDebug:
|
||||
if: github.repository == 'laurent22/joplin'
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
runs-on: ubuntu-latest
|
||||
|
37
.github/workflows/cla.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: "CLA Assistant"
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_target:
|
||||
types: [opened,closed,synchronize]
|
||||
|
||||
jobs:
|
||||
CLAAssistant:
|
||||
if: github.repository == 'laurent22/joplin'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "CLA Assistant"
|
||||
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
|
||||
# Beta Release
|
||||
uses: contributor-assistant/github-action@v2.3.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# the below token should have repo scope and must be manually added by you in the repository's secret
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
with:
|
||||
path-to-signatures: 'readme/cla_signatures.json'
|
||||
path-to-document: 'https://github.com/laurent22/joplin/blob/dev/readme/cla.md' # e.g. a CLA or a DCO document
|
||||
# branch should not be protected
|
||||
branch: 'dev'
|
||||
allowlist: joplinbot,renovate[bot]
|
||||
|
||||
# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
|
||||
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
|
||||
#remote-repository-name: enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository)
|
||||
#create-file-commit-message: 'For example: Creating file for storing CLA Signatures'
|
||||
#signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo'
|
||||
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
|
||||
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
|
||||
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
|
||||
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
|
||||
#use-dco-flag: true - If you are using DCO instead of CLA
|
1
.github/workflows/close-stale-issues.yml
vendored
@@ -6,6 +6,7 @@ permissions:
|
||||
issues: write
|
||||
jobs:
|
||||
ProcessStaleIssues:
|
||||
if: github.repository == 'laurent22/joplin'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
|
7
.github/workflows/github-actions-main.yml
vendored
@@ -2,6 +2,7 @@ name: Joplin Continuous Integration
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
pre_job:
|
||||
if: github.repository == 'laurent22/joplin'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||
@@ -13,7 +14,8 @@ jobs:
|
||||
|
||||
Main:
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
# We always process server or desktop release tags, because they also publish the release
|
||||
if: github.repository == 'laurent22/joplin' && (needs.pre_job.outputs.should_skip != 'true' || startsWith(github.ref, 'refs/tags/server-v') || startsWith(github.ref, 'refs/tags/v'))
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -91,6 +93,7 @@ jobs:
|
||||
APPLE_ASC_PROVIDER: ${{ secrets.APPLE_ASC_PROVIDER }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
|
||||
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
@@ -128,7 +131,7 @@ jobs:
|
||||
|
||||
ServerDockerImage:
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: github.repository == 'laurent22/joplin' && needs.pre_job.outputs.should_skip != 'true'
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
|
1571
.gitignore
vendored
2
.npmpackagejsonlintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
packages/app-clipper/popup/
|
||||
packages/app-cli/tests/support/plugins/
|
24
.npmpackagejsonlintrc.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"rules": {
|
||||
"prefer-absolute-version-dependencies": ["error",
|
||||
{
|
||||
"exceptions": [
|
||||
"@joplin/lib",
|
||||
"@joplin/renderer",
|
||||
"@joplin/pdf-viewer",
|
||||
"@joplin/fork-htmlparser2",
|
||||
"@joplin/fork-sax",
|
||||
"@joplin/fork-uslug",
|
||||
"@joplin/htmlpack",
|
||||
"@joplin/turndown",
|
||||
"@joplin/turndown-plugin-gfm",
|
||||
"@joplin/tools",
|
||||
"@joplin/react-native-saf-x",
|
||||
"@joplin/react-native-alarm-notification",
|
||||
"@joplin/utils"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -1,33 +0,0 @@
|
||||
diff --git a/android/build.gradle b/android/build.gradle
|
||||
index 1ae415331855895ed6c65d72e155ff91d02b4b39..a7548535a7fb08800fb4731c1d8e36efa8afa1ae 100644
|
||||
--- a/android/build.gradle
|
||||
+++ b/android/build.gradle
|
||||
@@ -22,7 +22,7 @@ def safeExtGet(prop, fallback) {
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
-apply plugin: 'maven'
|
||||
+apply plugin: 'maven-publish'
|
||||
|
||||
buildscript {
|
||||
// The Android Gradle plugin is only required when opening the android folder stand-alone.
|
||||
@@ -41,7 +41,7 @@ buildscript {
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
-apply plugin: 'maven'
|
||||
+apply plugin: 'maven-publish'
|
||||
|
||||
android {
|
||||
compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
|
||||
@@ -140,10 +140,5 @@ afterEvaluate { project ->
|
||||
|
||||
task installArchives(type: Upload) {
|
||||
configuration = configurations.archives
|
||||
- repositories.mavenDeployer {
|
||||
- // Deploy to react-native-event-bridge/maven, ready to publish to npm
|
||||
- repository url: "file://${projectDir}/../android/maven"
|
||||
- configureReactNativePom pom
|
||||
- }
|
||||
}
|
||||
}
|
20
.yarn/patches/react-native-camera-npm-4.2.1-24b2600a7e.patch
Normal file
@@ -0,0 +1,20 @@
|
||||
diff --git a/src/RNCamera.js b/src/RNCamera.js
|
||||
index b7a271ad64771c0f654dbd5fe3c0d9e0d2e2c4ef..1182a40ace081a32fbaefe2bc4a499b79c2e7dac 100644
|
||||
--- a/src/RNCamera.js
|
||||
+++ b/src/RNCamera.js
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
findNodeHandle,
|
||||
Platform,
|
||||
NativeModules,
|
||||
- ViewPropTypes,
|
||||
requireNativeComponent,
|
||||
View,
|
||||
ActivityIndicator,
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
PermissionsAndroid,
|
||||
} from 'react-native';
|
||||
|
||||
+import ViewPropTypes from 'deprecated-react-native-prop-types';
|
||||
import type { FaceFeature } from './FaceDetector';
|
||||
|
||||
const Rationale = PropTypes.shape({
|
30
.yarn/patches/rn-fetch-blob-npm-0.12.0-cf02e3c544.patch
Normal file
@@ -0,0 +1,30 @@
|
||||
diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
|
||||
index a8abd71833879201e3438b2fa51d712a311c4551..ffe9c2c6dfa5c703ba76b65d94d5dd6784102c19 100644
|
||||
--- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
|
||||
+++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
|
||||
@@ -591,7 +591,7 @@ public class RNFetchBlobReq extends BroadcastReceiver implements Runnable {
|
||||
// ignored.printStackTrace();
|
||||
}
|
||||
|
||||
- RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody;
|
||||
+ RNFetchBlobFileResp rnFetchBlobFileResp = new RNFetchBlobFileResp(responseBody);
|
||||
|
||||
if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){
|
||||
callback.invoke("Download interrupted.", null);
|
||||
diff --git a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
|
||||
index 2470eef612308c15a89dfea5a1f16937469be29f..965f8becc195965907699182c764ec9e51811450 100644
|
||||
--- a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
|
||||
+++ b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
|
||||
@@ -35,6 +35,12 @@ public class RNFetchBlobFileResp extends ResponseBody {
|
||||
FileOutputStream ofStream;
|
||||
boolean isEndMarkerReceived;
|
||||
|
||||
+ // ref: https://github.com/joltup/rn-fetch-blob/issues/490#issuecomment-990899440
|
||||
+ public RNFetchBlobFileResp(ResponseBody body) {
|
||||
+ super();
|
||||
+ this.originalBody = body;
|
||||
+ }
|
||||
+
|
||||
public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseBody body, String path, boolean overwrite) throws IOException {
|
||||
super();
|
||||
this.rctContext = ctx;
|
@@ -6,7 +6,7 @@ plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
|
||||
spec: "@yarnpkg/plugin-workspace-tools"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.3.0.cjs
|
||||
yarnPath: .yarn/releases/yarn-3.3.1.cjs
|
||||
|
||||
logFilters:
|
||||
|
||||
|
@@ -728,6 +728,16 @@ footer .bottom-links-row p {
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
LARGE VIEW
|
||||
*****************************************************************/
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
#nav-section a {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
MEDIUM VIEW
|
||||
- Make menu bar elements smaller and closer to each others
|
||||
@@ -770,6 +780,7 @@ footer .bottom-links-row p {
|
||||
|
||||
#menu-mobile .social-links .social-link-mastodon,
|
||||
#menu-mobile .social-links .social-link-reddit,
|
||||
#menu-mobile .social-links .social-link-linkedin,
|
||||
#menu-mobile .social-links .social-link-patreon {
|
||||
display: none;
|
||||
}
|
||||
@@ -937,6 +948,41 @@ footer .bottom-links-row p {
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
MORE NARROW VIEW
|
||||
eg for Galaxy S9
|
||||
*****************************************************************/
|
||||
|
||||
@media (max-width: 580px) {
|
||||
|
||||
#nav-section .plans-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
MORE NARROW VIEW
|
||||
eg for Galaxy S9
|
||||
*****************************************************************/
|
||||
|
||||
@media (max-width: 400px) {
|
||||
|
||||
#nav-section .navbar-mobile-content a.sponsor-button .sponsor-button-label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#nav-section .navbar-mobile-content a.sponsor-button {
|
||||
padding: 2px 6px;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
#nav-section a {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
VERY NARROW VIEW
|
||||
eg for Galaxy Fold
|
||||
@@ -954,6 +1000,19 @@ footer .bottom-links-row p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#nav-section a {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
div.navbar-mobile-content a.sponsor-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#nav-section .button-link {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 167 KiB |
BIN
Assets/WebsiteAssets/images/news/20221216-mobile-beta-editor.png
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
Assets/WebsiteAssets/images/news/20221216-notebook-icons.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
Assets/WebsiteAssets/images/news/20221216-proxy-support.png
Normal file
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 10 KiB |
BIN
Assets/WebsiteAssets/images/news/20230116-ga-raw-log-colored.png
Normal file
After Width: | Height: | Size: 963 KiB |
BIN
Assets/WebsiteAssets/images/news/20230116-ga-raw-log.png
Normal file
After Width: | Height: | Size: 295 KiB |
BIN
Assets/WebsiteAssets/images/news/20230202-jdll.jpg
Normal file
After Width: | Height: | Size: 238 KiB |
BIN
Assets/WebsiteAssets/images/sponsors/Grundstueckspreise.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
@@ -39,7 +39,7 @@ msgstr "<span class=\"frame-bg frame-bg-yellow\">多媒体</span>说明"
|
||||
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
|
||||
msgstr "百分之百<span class=\"frame-bg frame-bg-yellow-lg\">你的数据</span>"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:284
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:298
|
||||
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
|
||||
msgstr "一个<span class=\"frame-bg frame-bg-yellow-lg\">法国</span>的替代方案"
|
||||
|
||||
@@ -80,7 +80,7 @@ msgstr "下载该应用程序"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:213
|
||||
msgid "Find out more"
|
||||
msgstr ""
|
||||
msgstr "了解更多"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:54
|
||||
msgid "Free your <span class=\"frame-bg frame-bg-blue\">notes</span>"
|
||||
@@ -99,7 +99,7 @@ msgstr ""
|
||||
"Joplin,由于其起源和设计,适应并尊重中国的标准和规则。这保证了您的使用不受限"
|
||||
"制,以及您的使用数据的完全透明和安全。"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:327
|
||||
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
|
||||
msgstr ""
|
||||
|
||||
@@ -107,6 +107,15 @@ msgstr ""
|
||||
msgid "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">plans</span>"
|
||||
msgstr "乔普林云<span class=\"frame-bg frame-bg-yellow\">计划</span>"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
|
||||
msgid ""
|
||||
"Joplin Cloud is based in France. This means your data is protected by strict "
|
||||
"European Union privacy laws. In addition, Joplin Cloud implements strong end-"
|
||||
"to-end encryption so that not even us can have access to your data."
|
||||
msgstr ""
|
||||
"Joplin Cloud 位于法国。 这意味着您的数据受到严格的欧盟隐私法的保护。 此外,"
|
||||
"Joplin Cloud 实施了强大的端到端加密,因此即使是我们也无法访问您的数据。"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
|
||||
msgid ""
|
||||
"Joplin is an open source note-taking app. Capture your thoughts and securely "
|
||||
@@ -114,20 +123,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Joplin是一个开源的记事本应用程序。捕捉你的想法并从任何设备上安全地访问它们。"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:287
|
||||
msgid ""
|
||||
"Joplin, due to its origin and design, adapts and respects Chinese standards "
|
||||
"and rules. This guarantees your unrestricted use and complete transparency "
|
||||
"and security of your usage data."
|
||||
msgstr ""
|
||||
"Joplin,由于其起源和设计,适应并尊重中国的标准和规则。这保证了您的使用不受限"
|
||||
"制,以及您的使用数据的完全透明和安全。"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:262
|
||||
msgid "More about E2EE"
|
||||
msgstr ""
|
||||
msgstr "关于E2EE的更多信息"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:365
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:391
|
||||
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
|
||||
msgstr ""
|
||||
|
||||
@@ -148,7 +148,7 @@ msgstr "保存<span class=\"frame-bg frame-bg-blue\">网页</span> <br>作为笔
|
||||
msgid "Sign up with Joplin Cloud"
|
||||
msgstr "与乔布林云签约"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:368
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:394
|
||||
msgid "Thank you for your support!"
|
||||
msgstr ""
|
||||
|
||||
@@ -184,7 +184,7 @@ msgstr "<span class=\"frame-bg frame-bg-yellow\">一起</span>工作"
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:141
|
||||
msgid ""
|
||||
"You can also publish a note to the internet and share the URL with others."
|
||||
msgstr ""
|
||||
msgstr "您还可以将笔记发布到 Internet 并与其他人共享 URL。"
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:233
|
||||
msgid ""
|
||||
@@ -192,3 +192,11 @@ msgid ""
|
||||
"are"
|
||||
msgstr ""
|
||||
"你的笔记<span class=\"frame-bg frame-bg-blue-lg\">你在哪里都可以</span>"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Joplin, due to its origin and design, adapts and respects Chinese "
|
||||
#~ "standards and rules. This guarantees your unrestricted use and complete "
|
||||
#~ "transparency and security of your usage data."
|
||||
#~ msgstr ""
|
||||
#~ "Joplin,由于其起源和设计,适应并尊重中国的标准和规则。这保证了您的使用不受"
|
||||
#~ "限制,以及您的使用数据的完全透明和安全。"
|
||||
|
@@ -1,4 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Fri, 09 Dec 2022 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Fri, 09 Dec 2022 00:00:00 GMT</pubDate><item><title><![CDATA[Joplin is hiring!]]></title><description><![CDATA[<p>Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device.</p>
|
||||
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Thu, 02 Mar 2023 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Thu, 02 Mar 2023 00:00:00 GMT</pubDate><item><title><![CDATA[Joplin will participate in JdLL 2023!]]></title><description><![CDATA[<p>On 1 and 2 April 2023, we will have a stand for Joplin at the <a href="https://www.jdll.org/">Journées du Logiciel Libre</a> in Lyon, France. The JdLL has been taking place in Lyon for 24 years and is a popular open source conference in France. We had a stand in 2020 and 2021 but that was cancelled due to Covid, so this year is a first for Joplin!</p>
|
||||
<p>Admission is free, so don't hesitate to come and meet us, exchange ideas and learn more about Joplin!</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230202-jdll.jpg" alt="Joplin at JdLL 2023"></p>
|
||||
]]></description><link>https://joplinapp.org/news/20230302-jdll-2023/</link><guid isPermaLink="false">20230302-jdll-2023</guid><pubDate>Thu, 02 Mar 2023 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Introducing the "GitHub Actions Raw Log Viewer" extension for Chrome]]></title><description><![CDATA[<p>If you've ever used GitHub Actions, you will find that they provide by default a nice coloured output for the log. It looks good and it's even interactive! (You can click to collapse/expand blocks of text) But unfortunately it doesn't scale to large workflows, like we have for Joplin - the log can freeze and it will take forever to search for something. Indeed searching is done in "real time"... which mostly means it will freeze for a minute or two for each letter you type in the search box. Not great.</p>
|
||||
<p>Thankfully GitHub provides an alternative access: the raw logs. This is much better because they will open as plain text, without any styling or JS magic, which means you can use the browser native search and it will be fast.</p>
|
||||
<p>But now the problem is that raw logs look like this:</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230116-ga-raw-log.png" alt="Raw log without extension"></p>
|
||||
<p>While it's not impossible to read, all colours that would display nicely in a terminal are gone and replaced by <a href="https://en.wikipedia.org/wiki/ANSI_escape_code">ANSI codes</a>. You can find what you need in there but it's not particularly easy.</p>
|
||||
<p>This is where the new <strong>GitHub Action Raw Log Viewer</strong> extension for Chrome can help. It will parse your raw log and convert the ANSI codes to proper colours. This results in a much more readable rendering:</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230116-ga-raw-log-colored.png" alt="Raw log with extension"></p>
|
||||
<p>The extension is fast even for very large logs and it's of course easy to search for text since it simply works with your browser built-in search.</p>
|
||||
<p>The extension is open source, with the code available here: <a href="https://github.com/laurent22/github-actions-logs-extension">https://github.com/laurent22/github-actions-logs-extension</a></p>
|
||||
<p>And to install it, follow this link:</p>
|
||||
<p><a href="https://chrome.google.com/webstore/detail/github-action-raw-log-vie/lgejlnoopmcdglhfjblaeldbcfnmjddf"><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20230116-extension-get-it-now.png" alt="Download GitHub Action Raw Log Viewer extension"></a></p>
|
||||
]]></description><link>https://joplinapp.org/news/20230116-github-actions-log-viewer/</link><guid isPermaLink="false">20230116-github-actions-log-viewer</guid><pubDate>Mon, 16 Jan 2023 00:00:00 GMT</pubDate><twitter-text>Introducing the "GitHub Action Raw Log Viewer" extension for Chrome</twitter-text></item><item><title><![CDATA[Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0)]]></title><description><![CDATA[<p>As was <a href="https://discourse.joplinapp.org/t/rfc-switch-to-agpl-license-for-joplin-server/16529">discussed last year</a>, Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0) for the desktop, mobile and CLI applications, as well as the web clipper.</p>
|
||||
<p>Any open source or commercial fork of Joplin will have to license any changes they make under AGPL, and share these changes back with the community. This is the main reason we switch to this license. It allows us to continue releasing the project as open source while ensuring that those who benefit commercially (or not) from it share back their changes.</p>
|
||||
<h2>What is the GPL license?<a name="what-is-the-gpl-license" href="#what-is-the-gpl-license" class="heading-anchor">🔗</a></h2>
|
||||
<p>The AGPL license is based on the GPL license. This is what tldr;Legal has to say about the GPL license:</p>
|
||||
<blockquote>
|
||||
<p>You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions. (<a href="https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)">source</a>)</p>
|
||||
</blockquote>
|
||||
<h2>What is the AGPL license?<a name="what-is-the-agpl-license" href="#what-is-the-agpl-license" class="heading-anchor">🔗</a></h2>
|
||||
<p>This is the license we'll use for Joplin from now on:</p>
|
||||
<blockquote>
|
||||
<p>The AGPL license differs from the other GNU licenses in that it was built for network software. You can distribute modified versions if you keep track of the changes and the date you made them. As per usual with GNU licenses, you must license derivatives under AGPL. It provides the same restrictions and freedoms as the GPLv3 but with an additional clause which makes it so that source code must be distributed along with web publication. Since web sites and services are never distributed in the traditional sense, the AGPL is the GPL of the web. (<a href="https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)">source</a>)</p>
|
||||
</blockquote>
|
||||
<h2>What does it change for users?<a name="what-does-it-change-for-users" href="#what-does-it-change-for-users" class="heading-anchor">🔗</a></h2>
|
||||
<p>There is no changes for users of Joplin - the apps remain open sources and you can still use them freely.</p>
|
||||
<h2>What does it change for developers?<a name="what-does-it-change-for-developers" href="#what-does-it-change-for-developers" class="heading-anchor">🔗</a></h2>
|
||||
<p>Any code you develop for Joplin will also remain open source. The only difference is that we'll ask to sign an Individual Contributor License Agreement (CLA) to ensure that the copyright of the entire codebase remains with the Joplin organisation. This is necessary so that if we ever want to change the license again we are able to do so without having to get the agreement of each individual contributor afterwards (which would be nearly impossible).</p>
|
||||
<p>This is a bit of an extra constraint but it is hard to avoid. Contributor License Agreements are very common for GPL or AGPL projects. For example Apache, Canonical or Python all require their contributors to sign a CLA.</p>
|
||||
<h2>Questions?<a name="questions" href="#questions" class="heading-anchor">🔗</a></h2>
|
||||
<p>If you have any questions please let us know. Overall we believe this is a positive improvements for Joplin as it means any work derives from it will also benefit the project.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20221221-agpl/</link><guid isPermaLink="false">20221221-agpl</guid><pubDate>Wed, 21 Dec 2022 00:00:00 GMT</pubDate><twitter-text>Joplin is switching to the GNU Affero General Public License v3 (AGPL-3.0)</twitter-text></item><item><title><![CDATA[What's new in Joplin 2.9]]></title><description><![CDATA[<h2>Proxy support<a name="proxy-support" href="#proxy-support" class="heading-anchor">🔗</a></h2>
|
||||
<p>Both the desktop and mobile application now support proxies thanks to the work of Jason Williams. This will allow you to use the apps in particular when you are behind a company proxy.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20221216-proxy-support.png" alt=""></p>
|
||||
<h2>New PDF viewer<a name="new-pdf-viewer" href="#new-pdf-viewer" class="heading-anchor">🔗</a></h2>
|
||||
<p>The desktop application now features a new PDF viewer thanks to the work of Asrient during GSoC.</p>
|
||||
<p>The main advantage for now is that this viewer preserves the last PDF page that was read. In the next version, the viewer will also include a way to annotate PDF files.</p>
|
||||
<h2>Multi-language spell checking<a name="multi-language-spell-checking" href="#multi-language-spell-checking" class="heading-anchor">🔗</a></h2>
|
||||
<p>The desktop app include a multi-language spell checking features, which allows you, for example, to spell-check notes in your native language and in English.</p>
|
||||
<h2>New mobile text editor<a name="new-mobile-text-editor" href="#new-mobile-text-editor" class="heading-anchor">🔗</a></h2>
|
||||
<p>Writing formatted notes on mobile has always been cumbersome due to the need to enter special format characters like <code>*</code> or <code>[</code>, etc.</p>
|
||||
<p>Thanks to the work of Henry Heino during GSoC, writing notes on the go is now easier thanks to an improved Markdown editor.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20221216-mobile-beta-editor.png" alt=""></p>
|
||||
<p>The most visible feature is the addition of a toolbar, which helps input those special characters, like on desktop.</p>
|
||||
<p>Moreover Henry made a lot of subtle but useful improvements to the editor, for example to improve the note appearance, to improve list continuation, etc. Search within a note is now also supported as well as spell-checking.</p>
|
||||
<p>At a more technical level, Henry also added many test units to ensure that the editor remains robust and reliable.</p>
|
||||
<p>To enable the feature, go to the configuration screen and selected "Opt-in to the editor beta". It is already very stable so we will probably promote it to be the main editor from the next version.</p>
|
||||
<h2>Improved alignment of notebook icons<a name="improved-alignment-of-notebook-icons" href="#improved-alignment-of-notebook-icons" class="heading-anchor">🔗</a></h2>
|
||||
<p>Previously, when you would assign an icon to a notebook, it would shift the title to the right, but notebook without an icon would not. It means that notebooks with and without an icon would not be vertically aligned.</p>
|
||||
<p>To tidy things up, this new version adds a default icons to notebooks without an explicitly assigned icon. This result in the notebook titles being correctly vertically aligned.</p>
|
||||
<p>Note that this feature is only enabled if you use custom icons - otherwise it will simply display the notebook titles without any default icons, as before.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20221216-notebook-icons.png" alt=""></p>
|
||||
<h2>Improved handling of file attachments<a name="improved-handling-of-file-attachments" href="#improved-handling-of-file-attachments" class="heading-anchor">🔗</a></h2>
|
||||
<p>Self Not Found made a number of small but useful improvements to attachment handling, including increasing the maximum size to 200MB, adding support for attaching multiple files, and fixing issues with synchronising attachments via proxy.</p>
|
||||
<h2>Fixed filesystem sync on mobile<a name="fixed-filesystem-sync-on-mobile" href="#fixed-filesystem-sync-on-mobile" class="heading-anchor">🔗</a></h2>
|
||||
<p>This was a long and complex change due to the need to support new Android APIs but hopefully that should now be working again, thanks to the work of jd1378.</p>
|
||||
<p>So you can now sync again your notes with Syncthing and other file-based synchronisation systems.</p>
|
||||
<h2>And more...<a name="and-more" href="#and-more" class="heading-anchor">🔗</a></h2>
|
||||
<p>In total this new desktop version includes 36 improvements, bug fixes, and security fixes.</p>
|
||||
<p>As always, a lot of work went into the Android and iOS app too, which include 37 improvements, bug fixes, and security fixes.</p>
|
||||
<p>See here for the changelogs:</p>
|
||||
<ul>
|
||||
<li><a href="https://joplinapp.org/changelog/">Desktop app changelog</a></li>
|
||||
<li><a href="https://joplinapp.org/changelog_android/">Android app changelog</a></li>
|
||||
</ul>
|
||||
<h2>About the Android version<a name="about-the-android-version" href="#about-the-android-version" class="heading-anchor">🔗</a></h2>
|
||||
<p>Unfortunately we cannot publish the Android version because it is based on a framework version that Google does not accept. To upgrade the app a lot of changes are needed and another round of pre-releases, and therefore there will not be a 2.9 version for Google Play. You may however download the official APK directly from there: <a href="https://github.com/laurent22/joplin-android/releases/tag/android-v2.9.8">Android 2.9 Official Release</a></p>
|
||||
<p>This is the reality of app stores in general - small developers being imposed never ending new requirements by all-powerful companies, and by the time a version is finally ready we can't even publish it because yet more requirements are in place.</p>
|
||||
<p>For the record the current 2.9 app works perfectly fine. It targets Android 11, which is only 2 years old and is still supported (and installed on millions of phones). Google requires us to target Android 12 which only came out last year.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20221216-release-2-9/</link><guid isPermaLink="false">20221216-release-2-9</guid><pubDate>Fri, 16 Dec 2022 00:00:00 GMT</pubDate><twitter-text>What's new in Joplin 2.9</twitter-text></item><item><title><![CDATA[Joplin is hiring!]]></title><description><![CDATA[<p>Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device.</p>
|
||||
<p>We are looking to hire two JavaScript software developers to work on the desktop, mobile, and server applications. All those are built using modern technologies, including React, React Native and Electron with a strong focus on test units.</p>
|
||||
<p>You need to demonstrate some experience with at least some of these technologies, and willing to learn more and touch various different projects.</p>
|
||||
<p>You will be part of a small team, so you will have an opportunity for a high-impact role, targeting hundreds of thousands of users.</p>
|
||||
@@ -226,27 +297,4 @@
|
||||
<p>This release also includes about 30 various bug fixes and improvements.</p>
|
||||
<p>A notable one is a fix for GotoAnything, which recently wasn't working on first try.</p>
|
||||
<p>The plugin screen has also been improved so that search works even when GitHub is down or blocked, as it is in China in particular.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20210929-144036/</link><guid isPermaLink="false">20210929-144036</guid><pubDate>Wed, 29 Sep 2021 14:40:36 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Introducing recommended plugins in the next Joplin version]]></title><description><![CDATA[<p>A common request from new users is how to know which plugin is safe to install or not. In fact probably all of them are safe but as a new user that's not necessarily easy to know. So to help with this, the next version of Joplin will support recommended plugins - those will be plugins that meet our standards of quality and performance, and they will be indicated by a small crown tag inside the plugin box. Recommended plugins will also appear on top when searching.</p>
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20210901-113415_0.png" alt=""></p>
|
||||
<p>For now, since we don't have a review process, the recommended plugins are those developed by the Joplin team and frequent contributors, because we know those are safe to use.</p>
|
||||
<p>Later we might have a review process and add more recommended plugins. That being said, in the meantime even if a plugin is not marked as recommended, there's a good chance it is still safe and have good performance too. Often you can search for it on the forum and if it's active with many users commenting, you're most likely good to go.</p>
|
||||
<p>But if there's any doubt, the recommended tag is a good way to be sure.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20210901-113415/</link><guid isPermaLink="false">20210901-113415</guid><pubDate>Wed, 01 Sep 2021 11:34:15 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Joplin Cloud is officially production ready!]]></title><description><![CDATA[<p><a href="https://joplinapp.org/plans/">Joplin Cloud</a> has been out of beta for a few weeks now and since then it has been quietly running without any troubles. There is no known bugs and the service is running smoothly so it's now safe to say that it is production ready!</p>
|
||||
<p>As a reminder, Joplin Cloud is meant to provide a more seamless Joplin experience - if you want to quickly get started, it's as easy as downloading the app and getting a Joplin Cloud account. Besides improved sync performance, that will give you the ability to collaborate on notebooks with others, as well as publishing and sharing notes.</p>
|
||||
<p>Of course Joplin still supports other sync options such as Nextcloud, Dropbox and OneDrive or AWS S3. You can also self host using Joplin Server. The advantage of Joplin Cloud being that you don't need to maintain a server yourself - for a small fee you'll get that taken care of.</p>
|
||||
<p>Additionally, subscribing to Joplin Cloud is a great way to support the project as a whole, including the open source applications. Such support is needed in the long term to provide bug and security fixes, add new features, and provide support.</p>
|
||||
<p>At some level it is also an experiment, to see if such a service is financially viable and can allow me to work full time on the project. This is certainly something I would like, and perhaps Joplin Cloud combined with your donations will allow that.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20210831-154354/</link><guid isPermaLink="false">20210831-154354</guid><pubDate>Tue, 31 Aug 2021 15:43:54 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[How to start your subscription if you have a free Joplin Cloud Beta account]]></title><description><![CDATA[<p>For anyone with a beta account, if you would like to keep using it after the end of the trial period, there is now a button to do this from the Joplin Cloud home page:</p>
|
||||
<img height="222" src="https://aws1.discourse-cdn.com/standard14/uploads/cozic/optimized/2X/e/e2b54352d0e401e692a75817f6faa0432322c405_2_517x222.png" width="517">
|
||||
<p>If you click on it you will be sent to the Plans page via a special link. Then once you click on "Buy now" you will be sent to the Stripe page where you can start the subscription.</p>
|
||||
<p>As mentioned in the message, the process takes into account your remaining beta trial days. So for example, if your beta account expires in 60 days, the subscription will have a free 60 days trial period. This is so you don't lose any of the beta trial days no matter when you start the subscription.</p>
|
||||
<p>If you have any question about it, please let me know.</p>
|
||||
]]></description><link>https://joplinapp.org/news/20210804-085003/</link><guid isPermaLink="false">20210804-085003</guid><pubDate>Wed, 04 Aug 2021 08:50:03 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[New beta editor for the mobile app]]></title><description><![CDATA[<p>The <a href="https://github.com/laurent22/joplin-android/releases">latest Android pre-release 24</a> features an improved beta editor, which I hope could become a replacement for the very basic editor we have at the moment.</p>
|
||||
<p>It's still experimental because it's based on the equally experimental CodeMirror 6, however for simple editing tasks it seems to work fine. At the moment the improvements are:</p>
|
||||
<p>- Syntax highlighting for various tags such as bold, italic and headings.</p>
|
||||
<p>- List continuation for ordered and unordered lists (I didn't try checklists but I assume it doesn't work)</p>
|
||||
<p>- Improved undo/redo</p>
|
||||
<p>- Maybe better handling of large documents? CodeMirror 6 has a demo that loads a document with millions of lines, so maybe that will solve the performance issues that some users were having</p>
|
||||
<p>If everything works well, later on we should be able to add things like a toolbar, spellchecking and other features that are impossible with the current editor.</p>
|
||||
<p>If you find any bug, feel free to report here. Also make sure you backup your notes regularly in case there's an issue!</p>
|
||||
]]></description><link>https://joplinapp.org/news/20210729-103234/</link><guid isPermaLink="false">20210729-103234</guid><pubDate>Thu, 29 Jul 2021 10:32:34 GMT</pubDate><twitter-text></twitter-text></item></channel></rss>
|
||||
]]></description><link>https://joplinapp.org/news/20210929-144036/</link><guid isPermaLink="false">20210929-144036</guid><pubDate>Wed, 29 Sep 2021 14:40:36 GMT</pubDate><twitter-text></twitter-text></item></channel></rss>
|
@@ -16,6 +16,7 @@
|
||||
<a href="{{baseUrl}}/news/" class="fw500">News</a>
|
||||
<a href="{{baseUrl}}/help/" class="fw500">Help</a>
|
||||
<a href="{{forumUrl}}" class="fw500">Forum</a>
|
||||
<a href="{{baseUrl}}/cn/" class="fw500">中文</a>
|
||||
{{#showJoplinCloudLinks}}
|
||||
{{> joplinCloudButton}}
|
||||
{{/showJoplinCloudLinks}}
|
||||
@@ -23,6 +24,8 @@
|
||||
</div>
|
||||
<div class="col-9 text-right d-block d-md-none navbar-mobile-content">
|
||||
{{> twitterLink}}
|
||||
<a href="{{baseUrl}}/cn/" class="fw500 chinese-page-link">中文</a>
|
||||
{{> joplinCloudButton}}
|
||||
{{> supportButton}}
|
||||
|
||||
<span class="pointer"
|
||||
|
@@ -4,6 +4,7 @@
|
||||
<a class="social-link-mastodon" href="https://mastodon.social/@joplinapp" title="Joplin Mastodon feed"><i class="fab fa-mastodon"></i></a>
|
||||
<a class="social-link-patreon" href="https://www.patreon.com/joplin" title="Joplin Patreon"><i class="fab fa-patreon"></i></a>
|
||||
<a class="social-link-discord" href="https://discord.gg/VSj7AFHvpq" title="Joplin Discord chat"><i class="fab fa-discord"></i></a>
|
||||
<a class="social-link-linkedin" href="https://www.linkedin.com/company/joplin" title="Joplin LinkedIn Feed"><i class="fab fa-linkedin"></i></a>
|
||||
<a class="social-link-reddit" href="https://www.reddit.com/r/joplinapp/" title="Joplin Subreddit"><i class="fab fa-reddit"></i></a>
|
||||
<a class="social-link-github" href="https://github.com/laurent22/joplin/" title="Joplin GitHub repository"><i class="fab fa-github"></i></a>
|
||||
</div>
|
||||
|
@@ -1 +1 @@
|
||||
<a href="https://twitter.com/joplinapp" title="Joplin Twitter feed" class="fw500"><i class="fab fa-twitter"></i></a>
|
||||
<a href="https://twitter.com/joplinapp" title="Joplin Twitter feed" class="fw500 twitter-link"><i class="fab fa-twitter"></i></a>
|
@@ -130,7 +130,11 @@
|
||||
});
|
||||
|
||||
setupBetaHandling(urlQuery);
|
||||
applyPeriod('yearly');
|
||||
if (urlQuery.get('period') === 'monthly') {
|
||||
// Nothing - this is the default
|
||||
} else {
|
||||
applyPeriod('yearly');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
@@ -27,7 +27,7 @@ msgstr ""
|
||||
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
|
||||
msgstr ""
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:284
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:298
|
||||
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
|
||||
msgstr ""
|
||||
|
||||
@@ -68,7 +68,7 @@ msgstr ""
|
||||
msgid "Images, videos, PDFs and audio files are supported. Create math expressions and diagrams directly from the app. Take photos with the mobile app and save them to a note."
|
||||
msgstr ""
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:327
|
||||
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
|
||||
msgstr ""
|
||||
|
||||
@@ -76,19 +76,19 @@ msgstr ""
|
||||
msgid "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">plans</span>"
|
||||
msgstr ""
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
|
||||
msgid "Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device."
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
|
||||
msgid "Joplin Cloud is based in France. This means your data is protected by strict European Union privacy laws. In addition, Joplin Cloud implements strong end-to-end encryption so that not even us can have access to your data."
|
||||
msgstr ""
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:287
|
||||
msgid "Joplin, due to its origin and design, adapts and respects Chinese standards and rules. This guarantees your unrestricted use and complete transparency and security of your usage data."
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
|
||||
msgid "Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device."
|
||||
msgstr ""
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:262
|
||||
msgid "More about E2EE"
|
||||
msgstr ""
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:365
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:391
|
||||
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
|
||||
msgstr ""
|
||||
|
||||
@@ -108,7 +108,7 @@ msgstr ""
|
||||
msgid "Sign up with Joplin Cloud"
|
||||
msgstr ""
|
||||
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:368
|
||||
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:394
|
||||
msgid "Thank you for your support!"
|
||||
msgstr ""
|
||||
|
||||
|
@@ -43,6 +43,10 @@ If you want to start contributing to the project's code, please follow these gui
|
||||
|
||||
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/dev/BUILD.md) for more details.
|
||||
|
||||
## Signing the Individual Contributor License Agreement
|
||||
|
||||
All contributors to the project must sign our [Individual Contributor License Agreement](https://github.com/laurent22/joplin/blob/dev/readme/cla.md).
|
||||
|
||||
## Coding style
|
||||
|
||||
Please see [readme/coding_style.md](readme/coding_style.md).
|
||||
|
@@ -30,6 +30,7 @@ COPY packages/fork-uslug ./packages/fork-uslug
|
||||
COPY packages/htmlpack ./packages/htmlpack
|
||||
COPY packages/renderer ./packages/renderer
|
||||
COPY packages/tools ./packages/tools
|
||||
COPY packages/utils ./packages/utils
|
||||
COPY packages/lib ./packages/lib
|
||||
COPY packages/server ./packages/server
|
||||
|
||||
|
@@ -201,20 +201,22 @@ fi
|
||||
# If a new environment needs to be supported, then the command check section should be re-thought
|
||||
if [[ $DESKTOP =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*x-cinnamon.*|.*deepin.*|.*pantheon.*|.*lxde.*|.*i3.*|.*sway.* ]] || [[ `command -v update-desktop-database` ]]
|
||||
then
|
||||
DATA_HOME=${XDG_DATA_HOME:-~/.local/share}
|
||||
DESKTOP_FILE_LOCATION="$DATA_HOME/applications"
|
||||
# Only delete the desktop file if it will be replaced
|
||||
rm -f ~/.local/share/applications/appimagekit-joplin.desktop
|
||||
rm -f "$DESKTOP_FILE_LOCATION/appimagekit-joplin.desktop"
|
||||
|
||||
# On some systems this directory doesn't exist by default
|
||||
mkdir -p ~/.local/share/applications
|
||||
mkdir -p "$DESKTOP_FILE_LOCATION"
|
||||
|
||||
# Tabs specifically, and not spaces, are needed for indentation with Bash heredocs
|
||||
cat >> ~/.local/share/applications/appimagekit-joplin.desktop <<-EOF
|
||||
cat >> "$DESKTOP_FILE_LOCATION/appimagekit-joplin.desktop" <<-EOF
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=Joplin
|
||||
Comment=Joplin for Desktop
|
||||
Exec=${HOME}/.joplin/Joplin.AppImage ${SANDBOXPARAM} %u
|
||||
Icon=@joplinapp-desktop
|
||||
Icon=joplin
|
||||
StartupWMClass=Joplin
|
||||
Type=Application
|
||||
Categories=Office;
|
||||
@@ -224,7 +226,7 @@ then
|
||||
EOF
|
||||
|
||||
# Update application icons
|
||||
[[ `command -v update-desktop-database` ]] && update-desktop-database ~/.local/share/applications && update-desktop-database ~/.local/share/icons
|
||||
[[ `command -v update-desktop-database` ]] && update-desktop-database "$DESKTOP_FILE_LOCATION" && update-desktop-database "$DATA_HOME/icons"
|
||||
print "${COLOR_GREEN}OK${COLOR_RESET}"
|
||||
else
|
||||
print "${COLOR_RED}NOT DONE, unknown desktop '${DESKTOP}'${COLOR_RESET}"
|
||||
|
28
LICENSE
@@ -1,12 +1,13 @@
|
||||
All code in this repository is licensed under the MIT License **unless a
|
||||
directory contains a LICENSE or LICENSE.md file**, in which case that file
|
||||
applies to the code in that sub-directory.
|
||||
All code in this repository is licensed under the AGPL-3.0-or-later License
|
||||
**unless a directory contains a LICENSE or LICENSE.md file**, in which case that
|
||||
file applies to the code in that sub-directory.
|
||||
|
||||
For example, packages/server contains a LICENSE.md file, thus all code under the
|
||||
packages/server directory is licensed under that license.
|
||||
|
||||
For example, packages/app-cli does NOT contain a LICENSE file, thus all code
|
||||
under that directory is licensed under the default license, which is MIT.
|
||||
under that directory is licensed under the default license, which is
|
||||
AGPL-3.0-or-later.
|
||||
|
||||
* * *
|
||||
|
||||
@@ -23,23 +24,8 @@ icons please contact the author in order to get a permission.
|
||||
|
||||
* * *
|
||||
|
||||
MIT License
|
||||
AGPL-3.0-or-later License
|
||||
|
||||
Copyright (c) 2016-2022 Laurent Cozic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
https://spdx.org/licenses/AGPL-3.0-or-later.html
|
||||
|
103
README.md
@@ -22,11 +22,11 @@ Three types of applications are available: for **desktop** (Windows, macOS and L
|
||||
|
||||
Operating System | Download
|
||||
---|---
|
||||
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v2.8.8/Joplin-Setup-2.8.8.exe'><img alt='Get it on Windows' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeWindows.png'/></a>
|
||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v2.8.8/Joplin-2.8.8.dmg'><img alt='Get it on macOS' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeMacOS.png'/></a>
|
||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v2.8.8/Joplin-2.8.8.AppImage'><img alt='Get it on Linux' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeLinux.png'/></a>
|
||||
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-Setup-2.9.17.exe'><img alt='Get it on Windows' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeWindows.png'/></a>
|
||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-2.9.17.dmg'><img alt='Get it on macOS' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeMacOS.png'/></a>
|
||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-2.9.17.AppImage'><img alt='Get it on Linux' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeLinux.png'/></a>
|
||||
|
||||
**On Windows**, you may also use the <a href='https://github.com/laurent22/joplin/releases/download/v2.8.8/JoplinPortable.exe'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
|
||||
**On Windows**, you may also use the <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/JoplinPortable.exe'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
|
||||
|
||||
**On Linux**, the recommended way is to use the following installation script as it will handle the desktop icon too:
|
||||
|
||||
@@ -36,7 +36,7 @@ Linux | <a href='https://github.com/laurent22/joplin/releases/download/v2.8.8/Jo
|
||||
|
||||
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/dev/Assets/WebsiteAssets/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.8.1/joplin-v2.8.1.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.8.1/joplin-v2.8.1-32bit.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://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.9.8/joplin-v2.9.8.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.9.8/joplin-v2.9.8-32bit.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/dev/Assets/WebsiteAssets/images/BadgeIOS.png'/></a> | -
|
||||
|
||||
## Terminal application
|
||||
@@ -64,7 +64,7 @@ A community maintained list of these distributions can be found here: [Unofficia
|
||||
# Sponsors
|
||||
|
||||
<!-- SPONSORS-ORG -->
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://usrigging.com/"><img title="U.S. Ringing Supply" width="256" src="https://joplinapp.org/images/sponsors/RingingSupply.svg"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-github&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a>
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></a>
|
||||
<!-- SPONSORS-ORG -->
|
||||
|
||||
* * *
|
||||
@@ -72,14 +72,11 @@ A community maintained list of these distributions can be found here: [Unofficia
|
||||
<!-- SPONSORS-GITHUB -->
|
||||
| | | | |
|
||||
| :---: | :---: | :---: | :---: |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/215668?s=96&v=4"/></br>[avanderberg](https://github.com/avanderberg) | <img width="50" src="https://avatars2.githubusercontent.com/u/3061769?s=96&v=4"/></br>[c-nagy](https://github.com/c-nagy) | <img width="50" src="https://avatars2.githubusercontent.com/u/70780798?s=96&v=4"/></br>[cabottech](https://github.com/cabottech) | <img width="50" src="https://avatars2.githubusercontent.com/u/67130?s=96&v=4"/></br>[chr15m](https://github.com/chr15m) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/4862947?s=96&v=4"/></br>[chrootlogin](https://github.com/chrootlogin) | <img width="50" src="https://avatars2.githubusercontent.com/u/82579431?s=96&v=4"/></br>[clmntsl](https://github.com/clmntsl) | <img width="50" src="https://avatars2.githubusercontent.com/u/808091?s=96&v=4"/></br>[cuongtransc](https://github.com/cuongtransc) | <img width="50" src="https://avatars2.githubusercontent.com/u/1307332?s=96&v=4"/></br>[dbrandonjohnson](https://github.com/dbrandonjohnson) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/1439535?s=96&v=4"/></br>[fbloise](https://github.com/fbloise) | <img width="50" src="https://avatars2.githubusercontent.com/u/49439044?s=96&v=4"/></br>[fourstepper](https://github.com/fourstepper) | <img width="50" src="https://avatars2.githubusercontent.com/u/38898566?s=96&v=4"/></br>[h4sh5](https://github.com/h4sh5) | <img width="50" src="https://avatars2.githubusercontent.com/u/3266447?s=96&v=4"/></br>[iamwillbar](https://github.com/iamwillbar) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/37297218?s=96&v=4"/></br>[Jesssullivan](https://github.com/Jesssullivan) | <img width="50" src="https://avatars2.githubusercontent.com/u/1310474?s=96&v=4"/></br>[jknowles](https://github.com/jknowles) | <img width="50" src="https://avatars2.githubusercontent.com/u/1248504?s=96&v=4"/></br>[joesfer](https://github.com/joesfer) | <img width="50" src="https://avatars2.githubusercontent.com/u/5588131?s=96&v=4"/></br>[kianenigma](https://github.com/kianenigma) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/24908652?s=96&v=4"/></br>[konishi-t](https://github.com/konishi-t) | <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) | <img width="50" src="https://avatars2.githubusercontent.com/u/1788010?s=96&v=4"/></br>[maxtruxa](https://github.com/maxtruxa) | <img width="50" src="https://avatars2.githubusercontent.com/u/29300939?s=96&v=4"/></br>[mcejp](https://github.com/mcejp) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/1168659?s=96&v=4"/></br>[nicholashead](https://github.com/nicholashead) | <img width="50" src="https://avatars2.githubusercontent.com/u/5782817?s=96&v=4"/></br>[piccobit](https://github.com/piccobit) | <img width="50" src="https://avatars2.githubusercontent.com/u/77214738?s=96&v=4"/></br>[Polymathic-Company](https://github.com/Polymathic-Company) | <img width="50" src="https://avatars2.githubusercontent.com/u/47742?s=96&v=4"/></br>[ravenscroftj](https://github.com/ravenscroftj) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/327998?s=96&v=4"/></br>[sif](https://github.com/sif) | <img width="50" src="https://avatars2.githubusercontent.com/u/54626606?s=96&v=4"/></br>[skyrunner15](https://github.com/skyrunner15) | <img width="50" src="https://avatars2.githubusercontent.com/u/765564?s=96&v=4"/></br>[taskcruncher](https://github.com/taskcruncher) | <img width="50" src="https://avatars2.githubusercontent.com/u/73081837?s=96&v=4"/></br>[thismarty](https://github.com/thismarty) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/15859362?s=96&v=4"/></br>[thomasbroussard](https://github.com/thomasbroussard) | | | |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/215668?s=96&v=4"/></br>[avanderberg](https://github.com/avanderberg) | <img width="50" src="https://avatars2.githubusercontent.com/u/67130?s=96&v=4"/></br>[chr15m](https://github.com/chr15m) | <img width="50" src="https://avatars2.githubusercontent.com/u/2793530?s=96&v=4"/></br>[CyberXZT](https://github.com/CyberXZT) | <img width="50" src="https://avatars2.githubusercontent.com/u/1307332?s=96&v=4"/></br>[dbrandonjohnson](https://github.com/dbrandonjohnson) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/49439044?s=96&v=4"/></br>[fourstepper](https://github.com/fourstepper) | <img width="50" src="https://avatars2.githubusercontent.com/u/64712218?s=96&v=4"/></br>[Hegghammer](https://github.com/Hegghammer) | <img width="50" src="https://avatars2.githubusercontent.com/u/3266447?s=96&v=4"/></br>[iamwillbar](https://github.com/iamwillbar) | <img width="50" src="https://avatars2.githubusercontent.com/u/1310474?s=96&v=4"/></br>[jknowles](https://github.com/jknowles) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/11947658?s=96&v=4"/></br>[KentBrockman](https://github.com/KentBrockman) | <img width="50" src="https://avatars2.githubusercontent.com/u/5588131?s=96&v=4"/></br>[kianenigma](https://github.com/kianenigma) | <img width="50" src="https://avatars2.githubusercontent.com/u/24908652?s=96&v=4"/></br>[konishi-t](https://github.com/konishi-t) | <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/126279083?s=96&v=4"/></br>[matmoly](https://github.com/matmoly) | <img width="50" src="https://avatars2.githubusercontent.com/u/1788010?s=96&v=4"/></br>[maxtruxa](https://github.com/maxtruxa) | <img width="50" src="https://avatars2.githubusercontent.com/u/29300939?s=96&v=4"/></br>[mcejp](https://github.com/mcejp) | <img width="50" src="https://avatars2.githubusercontent.com/u/31054972?s=96&v=4"/></br>[saarantras](https://github.com/saarantras) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/327998?s=96&v=4"/></br>[sif](https://github.com/sif) | <img width="50" src="https://avatars2.githubusercontent.com/u/765564?s=96&v=4"/></br>[taskcruncher](https://github.com/taskcruncher) | <img width="50" src="https://avatars2.githubusercontent.com/u/333944?s=96&v=4"/></br>[tateisu](https://github.com/tateisu) | |
|
||||
<!-- SPONSORS-GITHUB -->
|
||||
|
||||
<!-- TOC -->
|
||||
@@ -129,6 +126,7 @@ A community maintained list of these distributions can be found here: [Unofficia
|
||||
- [Writing a technical spec](https://github.com/laurent22/joplin/blob/dev/readme/technical_spec.md)
|
||||
- [Desktop application styling](https://github.com/laurent22/joplin/blob/dev/readme/spec/desktop_styling.md)
|
||||
- [Note History spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/history.md)
|
||||
- [Synchronisation spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync.md)
|
||||
- [Sync Lock spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync_lock.md)
|
||||
- [Synchronous Scroll spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync_scroll.md)
|
||||
- [Plugin Architecture spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/plugins.md)
|
||||
@@ -505,6 +503,7 @@ Name | Description
|
||||
[Mastodon feed](https://mastodon.social/@joplinapp) | Follow us on Mastodon
|
||||
[Patreon page](https://www.patreon.com/joplin) |The latest news are often posted there
|
||||
[Discord server](https://discord.gg/VSj7AFHvpq) | Our chat server
|
||||
[LinkedIn](https://www.linkedin.com/company/joplin) | Our LinkedIn page
|
||||
[Sub-reddit](https://www.reddit.com/r/joplinapp/) | Also a good place to get help
|
||||
|
||||
# Contributing
|
||||
@@ -530,47 +529,47 @@ Current translations:
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
| Language | Po File | Last translator | Percent done
|
||||
---|---|---|---|---
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/arableague.png" width="16px"/> | Arabic | [ar](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ar.po) | [Whaell O](mailto:Whaell@protonmail.com) | 82%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/arableague.png" width="16px"/> | Arabic | [ar](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ar.po) | [Whaell O](mailto:Whaell@protonmail.com) | 80%
|
||||
<img src="https://joplinapp.org/images/flags/es/basque_country.png" width="16px"/> | Basque | [eu](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eu.po) | juan.abasolo@ehu.eus | 23%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ba.png" width="16px"/> | Bosnian (Bosna i Hercegovina) | [bs_BA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bs_BA.po) | [Derviš T.](mailto:dervis.t@pm.me) | 59%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/bg.png" width="16px"/> | Bulgarian (България) | [bg_BG](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bg_BG.po) | | 46%
|
||||
<img src="https://joplinapp.org/images/flags/es/catalonia.png" width="16px"/> | Catalan | [ca](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ca.po) | [Xavi Ivars](mailto:xavi.ivars@gmail.com) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/hr.png" width="16px"/> | Croatian (Hrvatska) | [hr_HR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hr_HR.po) | [Milo Ivir](mailto:mail@milotype.de) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/cz.png" width="16px"/> | Czech (Česká republika) | [cs_CZ](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/cs_CZ.po) | [Michal Stanke](mailto:michal@stanke.cz) | 79%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/dk.png" width="16px"/> | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | ERYpTION | 98%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/de.png" width="16px"/> | Deutsch (Deutschland) | [de_DE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/de_DE.po) | [MrKanister](mailto:pueblos_spatulas@aleeas.com) | 98%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ee.png" width="16px"/> | Eesti Keel (Eesti) | [et_EE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/et_EE.po) | | 46%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ba.png" width="16px"/> | Bosnian (Bosna i Hercegovina) | [bs_BA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bs_BA.po) | [Derviš T.](mailto:dervis.t@pm.me) | 58%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/bg.png" width="16px"/> | Bulgarian (България) | [bg_BG](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bg_BG.po) | | 45%
|
||||
<img src="https://joplinapp.org/images/flags/es/catalonia.png" width="16px"/> | Catalan | [ca](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ca.po) | [Xavi Ivars](mailto:xavi.ivars@gmail.com) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/hr.png" width="16px"/> | Croatian (Hrvatska) | [hr_HR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hr_HR.po) | [Milo Ivir](mailto:mail@milotype.de) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/cz.png" width="16px"/> | Czech (Česká republika) | [cs_CZ](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/cs_CZ.po) | [Michal Stanke](mailto:michal@stanke.cz) | 77%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/dk.png" width="16px"/> | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | ERYpTION | 99%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/de.png" width="16px"/> | Deutsch (Deutschland) | [de_DE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/de_DE.po) | [MrKanister](mailto:pueblos_spatulas@aleeas.com) | 99%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ee.png" width="16px"/> | Eesti Keel (Eesti) | [et_EE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/et_EE.po) | | 44%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/gb.png" width="16px"/> | English (United Kingdom) | [en_GB](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/en_GB.po) | | 100%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/us.png" width="16px"/> | English (United States of America) | [en_US](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/en_US.po) | | 100%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/es.png" width="16px"/> | Español (España) | [es_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/es_ES.po) | [Francisco Mora](mailto:francisco.m.collao@gmail.com) | 91%
|
||||
<img src="https://joplinapp.org/images/flags/esperanto.png" width="16px"/> | Esperanto | [eo](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eo.po) | Marton Paulo | 26%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/fi.png" width="16px"/> | Finnish (Suomi) | [fi_FI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fi_FI.po) | mrkaato0 | 98%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/fr.png" width="16px"/> | Français (France) | [fr_FR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fr_FR.po) | Laurent Cozic | 98%
|
||||
<img src="https://joplinapp.org/images/flags/es/galicia.png" width="16px"/> | Galician (España) | [gl_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/gl_ES.po) | [Marcos Lans](mailto:marcoslansgarza@gmail.com) | 30%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/id.png" width="16px"/> | Indonesian (Indonesia) | [id_ID](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/id_ID.po) | [Wisnu Adi Santoso](mailto:waditos@gmail.com) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/it.png" width="16px"/> | Italiano (Italia) | [it_IT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/it_IT.po) | [Albano Battistella](mailto:albano_battistella@hotmail.com) | 80%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/hu.png" width="16px"/> | Magyar (Magyarország) | [hu_HU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hu_HU.po) | [Magyari Balázs](mailto:balmag@gmail.com) | 80%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/be.png" width="16px"/> | Nederlands (België, Belgique, Belgien) | [nl_BE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_BE.po) | | 81%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/nl.png" width="16px"/> | Nederlands (Nederland) | [nl_NL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_NL.po) | [MHolkamp](mailto:mholkamp@users.noreply.github.com) | 91%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/no.png" width="16px"/> | Norwegian (Norge, Noreg) | [nb_NO](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nb_NO.po) | [Mats Estensen](mailto:code@mxe.no) | 91%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ir.png" width="16px"/> | Persian | [fa](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fa.po) | [Kourosh Firoozbakht](mailto:kourox@protonmail.com) | 57%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/pl.png" width="16px"/> | Polski (Polska) | [pl_PL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pl_PL.po) | [X3NO](mailto:X3NO@disroot.org) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/br.png" width="16px"/> | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_BR.po) | [Renato Nunes Bastos](mailto:rnbastos@gmail.com) | 91%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/pt.png" width="16px"/> | Português (Portugal) | [pt_PT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_PT.po) | [Diogo Caveiro](mailto:dcaveiro@yahoo.com) | 75%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ro.png" width="16px"/> | Română | [ro](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ro.po) | [Cristi Duluta](mailto:cristi.duluta@gmail.com) | 52%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/si.png" width="16px"/> | Slovenian (Slovenija) | [sl_SI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sl_SI.po) | [Martin Korelič](mailto:martin.korelic@protonmail.com) | 83%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/se.png" width="16px"/> | Svenska | [sv](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sv.po) | [Jonatan Nyberg](mailto:jonatan@autistici.org) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/th.png" width="16px"/> | Thai (ประเทศไทย) | [th_TH](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/th_TH.po) | | 38%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/vn.png" width="16px"/> | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 80%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tr.png" width="16px"/> | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ua.png" width="16px"/> | Ukrainian (Україна) | [uk_UA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/uk_UA.po) | [Vyacheslav Andreykiv](mailto:vandreykiv@gmail.com) | 75%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/gr.png" width="16px"/> | Ελληνικά (Ελλάδα) | [el_GR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/el_GR.po) | [Harris Arvanitis](mailto:xaris@tuta.io) | 91%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ru.png" width="16px"/> | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Sergey Segeda](mailto:thesermanarm@gmail.com) | 83%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/rs.png" width="16px"/> | српски језик (Србија) | [sr_RS](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sr_RS.po) | | 67%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/cn.png" width="16px"/> | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_CN.po) | [KaneGreen](mailto:737445366KG@Gmail.com) | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tw.png" width="16px"/> | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Kevin Hsu](mailto:kevin.hsu.hws@gmail.com) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/jp.png" width="16px"/> | 日本語 (日本) | [ja_JP](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ja_JP.po) | [genneko](mailto:genneko217@gmail.com) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/kr.png" width="16px"/> | 한국어 | [ko](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ko.po) | [Ji-Hyeon Gim](mailto:potatogim@potatogim.net) | 92%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/es.png" width="16px"/> | Español (España) | [es_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/es_ES.po) | [Francisco Villaverde](mailto:teko.gr@gmail.com) | 99%
|
||||
<img src="https://joplinapp.org/images/flags/esperanto.png" width="16px"/> | Esperanto | [eo](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eo.po) | Marton Paulo | 25%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/fi.png" width="16px"/> | Finnish (Suomi) | [fi_FI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fi_FI.po) | mrkaato0 | 95%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/fr.png" width="16px"/> | Français (France) | [fr_FR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fr_FR.po) | Laurent Cozic | 99%
|
||||
<img src="https://joplinapp.org/images/flags/es/galicia.png" width="16px"/> | Galician (España) | [gl_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/gl_ES.po) | [Marcos Lans](mailto:marcoslansgarza@gmail.com) | 29%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/id.png" width="16px"/> | Indonesian (Indonesia) | [id_ID](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/id_ID.po) | [Wisnu Adi Santoso](mailto:waditos@gmail.com) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/it.png" width="16px"/> | Italiano (Italia) | [it_IT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/it_IT.po) | [Manuel Tassi](mailto:mannivuwiki@gmail.com) | 81%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/hu.png" width="16px"/> | Magyar (Magyarország) | [hu_HU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hu_HU.po) | [Magyari Balázs](mailto:balmag@gmail.com) | 78%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/be.png" width="16px"/> | Nederlands (België, Belgique, Belgien) | [nl_BE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_BE.po) | | 79%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/nl.png" width="16px"/> | Nederlands (Nederland) | [nl_NL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_NL.po) | [MHolkamp](mailto:mholkamp@users.noreply.github.com) | 88%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/no.png" width="16px"/> | Norwegian (Norge, Noreg) | [nb_NO](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nb_NO.po) | [Mats Estensen](mailto:code@mxe.no) | 88%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ir.png" width="16px"/> | Persian | [fa](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fa.po) | [Kourosh Firoozbakht](mailto:kourox@protonmail.com) | 55%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/pl.png" width="16px"/> | Polski (Polska) | [pl_PL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pl_PL.po) | [X3NO](mailto:X3NO@disroot.org) | 91%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/br.png" width="16px"/> | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_BR.po) | [Renato Nunes Bastos](mailto:rnbastos@gmail.com) | 88%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/pt.png" width="16px"/> | Português (Portugal) | [pt_PT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_PT.po) | [Diogo Caveiro](mailto:dcaveiro@yahoo.com) | 73%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ro.png" width="16px"/> | Română | [ro](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ro.po) | [Cristi Duluta](mailto:cristi.duluta@gmail.com) | 51%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/si.png" width="16px"/> | Slovenian (Slovenija) | [sl_SI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sl_SI.po) | [Martin Korelič](mailto:martin.korelic@protonmail.com) | 80%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/se.png" width="16px"/> | Svenska | [sv](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sv.po) | [Jonatan Nyberg](mailto:jonatan@autistici.org) | 96%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/th.png" width="16px"/> | Thai (ประเทศไทย) | [th_TH](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/th_TH.po) | | 36%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/vn.png" width="16px"/> | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 78%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tr.png" width="16px"/> | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ua.png" width="16px"/> | Ukrainian (Україна) | [uk_UA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/uk_UA.po) | [Vyacheslav Andreykiv](mailto:vandreykiv@gmail.com) | 72%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/gr.png" width="16px"/> | Ελληνικά (Ελλάδα) | [el_GR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/el_GR.po) | [Harris Arvanitis](mailto:xaris@tuta.io) | 88%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/ru.png" width="16px"/> | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Dmitriy Q](mailto:krotesk@mail.ru) | 99%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/rs.png" width="16px"/> | српски језик (Србија) | [sr_RS](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sr_RS.po) | | 65%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/cn.png" width="16px"/> | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_CN.po) | [wh201906](mailto:wh201906@yandex.com) | 97%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/tw.png" width="16px"/> | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Kevin Hsu](mailto:kevin.hsu.hws@gmail.com) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/jp.png" width="16px"/> | 日本語 (日本) | [ja_JP](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ja_JP.po) | [genneko](mailto:genneko217@gmail.com) | 89%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/kr.png" width="16px"/> | 한국어 | [ko](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ko.po) | [Ji-Hyeon Gim](mailto:potatogim@potatogim.net) | 89%
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
|
||||
# Contributors
|
||||
|
53
gulpfile.js
@@ -1,23 +1,52 @@
|
||||
const gulp = require('gulp');
|
||||
const utils = require('./packages/tools/gulp/utils');
|
||||
const execa = require('execa');
|
||||
const { stdout } = require('process');
|
||||
|
||||
const execCommand = async (executableName, args, options = null) => {
|
||||
options = {
|
||||
showInput: true,
|
||||
showStdout: true,
|
||||
showStderr: true,
|
||||
quiet: false,
|
||||
...options,
|
||||
};
|
||||
|
||||
if (options.quiet) {
|
||||
options.showInput = false;
|
||||
options.showStdout = false;
|
||||
options.showStderr = false;
|
||||
}
|
||||
|
||||
if (options.showInput) {
|
||||
stdout.write(`> ${executableName} ${args.join(' ')}\n`);
|
||||
}
|
||||
|
||||
const promise = execa(executableName, args);
|
||||
if (options.showStdout && promise.stdout) promise.stdout.pipe(process.stdout);
|
||||
if (options.showStderr && promise.stderr) promise.stderr.pipe(process.stderr);
|
||||
const result = await promise;
|
||||
return result.stdout.trim();
|
||||
};
|
||||
|
||||
|
||||
const tasks = {
|
||||
updateIgnoredTypeScriptBuild: require('./packages/tools/gulp/tasks/updateIgnoredTypeScriptBuild'),
|
||||
buildCommandIndex: require('./packages/tools/gulp/tasks/buildCommandIndex'),
|
||||
completePublishAll: {
|
||||
fn: async () => {
|
||||
|
||||
await utils.execCommandVerbose('git', ['add', '-A']);
|
||||
await utils.execCommandVerbose('git', ['commit', '-m', 'Releasing sub-packages']);
|
||||
await execCommand('git', ['add', '-A']);
|
||||
await execCommand('git', ['commit', '-m', 'Releasing sub-packages']);
|
||||
|
||||
// Lerna does some unnecessary auth check that doesn't work with
|
||||
// automation tokens, thus the --no-verify-access. Automation token
|
||||
// is still used for access when publishing even with this flag
|
||||
// (publishing would fail otherwise).
|
||||
// https://github.com/lerna/lerna/issues/2788
|
||||
await utils.execCommandVerbose('lerna', ['publish', 'from-package', '-y', '--no-verify-access']);
|
||||
await execCommand('lerna', ['publish', 'from-package', '-y', '--no-verify-access']);
|
||||
|
||||
await utils.execCommandVerbose('git', ['push']);
|
||||
await execCommand('yarn', ['install']);
|
||||
await execCommand('git', ['add', '-A']);
|
||||
await execCommand('git', ['commit', '-m', 'Lock file']);
|
||||
|
||||
await execCommand('git', ['push']);
|
||||
},
|
||||
},
|
||||
build: {
|
||||
@@ -30,12 +59,14 @@ const tasks = {
|
||||
// faster, especially when having to rebuild after adding a
|
||||
// dependency.
|
||||
if (process.env.BUILD_SEQUENCIAL === '1') {
|
||||
await utils.execCommandVerbose('yarn', ['run', 'buildSequential']);
|
||||
await execCommand('yarn', ['run', 'buildSequential']);
|
||||
} else {
|
||||
await utils.execCommandVerbose('yarn', ['run', 'buildParallel']);
|
||||
await execCommand('yarn', ['run', 'buildParallel']);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
utils.registerGulpTasks(gulp, tasks);
|
||||
for (const taskName in tasks) {
|
||||
gulp.task(taskName, tasks[taskName].fn);
|
||||
}
|
||||
|
@@ -317,6 +317,9 @@
|
||||
"packages/app-tools/github_oauth_token.txt": true,
|
||||
"packages/generator-joplin/generators/app/templates/api/": true,
|
||||
"packages/htmlpack/dist/": true,
|
||||
"packages/react-native-alarm-notification/android/build": true,
|
||||
"packages/react-native-saf-x/android/build": true,
|
||||
"packages/react-native-saf-x/android/wrapper": true,
|
||||
"packages/renderer/**/.vscode/": true,
|
||||
"packages/renderer/**/copyLib.bat": true,
|
||||
"packages/renderer/**/node_modules/": true,
|
||||
@@ -326,6 +329,7 @@
|
||||
"packages/renderer/MdToHtml/rules/sanitize_html.js": true,
|
||||
"packages/server/db-*.sqlite": true,
|
||||
"packages/server/dist/": true,
|
||||
"packages/utils/dist/": true,
|
||||
"packages/server/temp": true,
|
||||
"packages/server/test.pid": true,
|
||||
"phpunit.xml": true,
|
||||
|
@@ -13,7 +13,5 @@ module.exports = {
|
||||
'*.{js,jsx,ts,tsx}': [
|
||||
'yarn run linter-precommit',
|
||||
'yarn run checkLibPaths',
|
||||
// 'yarn run spellcheck',
|
||||
// 'git add',
|
||||
],
|
||||
};
|
||||
|
38
package.json
@@ -15,7 +15,7 @@
|
||||
"buildParallel": "yarn workspaces foreach --verbose --interlaced --parallel --jobs 2 --topological run build && yarn run tsc",
|
||||
"buildSequential": "yarn workspaces foreach --verbose --interlaced --topological run build && yarn run tsc",
|
||||
"buildApiDoc": "yarn workspace joplin start apidoc ../../readme/api/references/rest_api.md",
|
||||
"buildCommandIndex": "gulp buildCommandIndex",
|
||||
"buildCommandIndex": "node packages/tools/gulp/tasks/buildCommandIndexRun.js",
|
||||
"buildPluginDoc": "typedoc --name 'Joplin Plugin API Documentation' --mode file -theme './Assets/PluginDocTheme/' --readme './Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out ../joplin-website/docs/api/references/plugin_api packages/lib/services/plugins/api/",
|
||||
"updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc",
|
||||
"updateNews": "node ./packages/tools/website/updateNews",
|
||||
@@ -33,6 +33,7 @@
|
||||
"linter-precommit": "eslint --resolve-plugins-relative-to . --fix --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter": "eslint --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter-interactive": "eslint-interactive --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"packageJsonLint": "npmPkgJsonLint --configFile .npmpackagejsonlintrc.json --quiet .",
|
||||
"postinstall": "gulp build",
|
||||
"publishAll": "git pull && yarn run buildParallel && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
|
||||
"releaseAndroid": "PATH=\"/usr/local/opt/openjdk@11/bin:$PATH\" node packages/tools/release-android.js",
|
||||
@@ -52,44 +53,49 @@
|
||||
"test-ci": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test-ci",
|
||||
"test": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test",
|
||||
"tsc": "yarn workspaces foreach --parallel --verbose --interlaced run tsc",
|
||||
"updateIgnored": "gulp updateIgnoredTypeScriptBuild",
|
||||
"updateIgnored": "node packages/tools/gulp/tasks/updateIgnoredTypeScriptBuildRun.js",
|
||||
"updatePluginTypes": "./packages/generator-joplin/updateTypes.sh",
|
||||
"watch": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 999 run watch",
|
||||
"watchWebsite": "nodemon --verbose --watch Assets/WebsiteAssets --watch packages/tools/website --watch packages/tools/website/utils --ext md,ts,js,mustache,css,tsx,gif,png,svg --exec \"node packages/tools/website/build.js && http-server --port 8077 ../joplin-website/docs -a localhost\""
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
"pre-commit": "lint-staged && yarn run packageJsonLint"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@joplin/utils": "~2.11",
|
||||
"@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.46.1",
|
||||
"@typescript-eslint/parser": "5.46.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.48.2",
|
||||
"@typescript-eslint/parser": "5.48.2",
|
||||
"cspell": "5.21.2",
|
||||
"eslint": "8.29.0",
|
||||
"eslint": "8.31.0",
|
||||
"eslint-interactive": "10.3.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"eslint-plugin-import": "2.27.4",
|
||||
"eslint-plugin-jest": "27.2.1",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-react": "7.31.11",
|
||||
"fs-extra": "11.1.0",
|
||||
"glob": "8.0.3",
|
||||
"eslint-plugin-react": "7.32.0",
|
||||
"execa": "5.1.1",
|
||||
"fs-extra": "11.1.1",
|
||||
"glob": "8.1.0",
|
||||
"gulp": "4.0.2",
|
||||
"husky": "3.1.0",
|
||||
"lerna": "3.22.1",
|
||||
"lint-staged": "13.1.0",
|
||||
"madge": "5.0.1",
|
||||
"lint-staged": "13.2.0",
|
||||
"madge": "6.0.0",
|
||||
"npm-package-json-lint": "6.4.0",
|
||||
"typedoc": "0.17.8",
|
||||
"typescript": "4.9.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"http-server": "14.1.1",
|
||||
"node-gyp": "9.3.0",
|
||||
"nodemon": "2.0.20"
|
||||
"node-gyp": "9.3.1",
|
||||
"nodemon": "2.0.22"
|
||||
},
|
||||
"packageManager": "yarn@3.3.0",
|
||||
"packageManager": "yarn@3.3.1",
|
||||
"resolutions": {
|
||||
"joplin-rn-alarm-notification@1.0.5": "patch:joplin-rn-alarm-notification@npm:1.0.5#.yarn/patches/joplin-rn-alarm-notification-npm-1.0.5-662e871c03"
|
||||
"react-native-camera@4.2.1": "patch:react-native-camera@npm%3A4.2.1#./.yarn/patches/react-native-camera-npm-4.2.1-24b2600a7e.patch",
|
||||
"rn-fetch-blob@0.12.0": "patch:rn-fetch-blob@npm%3A0.12.0#./.yarn/patches/rn-fetch-blob-npm-0.12.0-cf02e3c544.patch"
|
||||
}
|
||||
}
|
||||
|
@@ -6,14 +6,14 @@ interface LinkStoreEntry {
|
||||
}
|
||||
|
||||
class LinkSelector {
|
||||
noteId_: string;
|
||||
scrollTop_: number;
|
||||
renderedText_: string;
|
||||
currentLinkIndex_: number;
|
||||
linkStore_: LinkStoreEntry[];
|
||||
linkRegex_: RegExp;
|
||||
private noteId_: string;
|
||||
private scrollTop_: number;
|
||||
private renderedText_: string;
|
||||
private currentLinkIndex_: number;
|
||||
private linkStore_: LinkStoreEntry[];
|
||||
private linkRegex_: RegExp;
|
||||
|
||||
constructor() {
|
||||
public constructor() {
|
||||
this.noteId_ = null;
|
||||
this.scrollTop_ = null; // used so 'o' won't open unhighlighted link after scrolling
|
||||
this.renderedText_ = null;
|
||||
@@ -22,22 +22,22 @@ class LinkSelector {
|
||||
this.linkRegex_ = /http:\/\/[0-9.]+:[0-9]+\/[0-9]+/g;
|
||||
}
|
||||
|
||||
get link(): string | null {
|
||||
public get link(): string | null {
|
||||
if (this.currentLinkIndex_ === null) return null;
|
||||
return this.linkStore_[this.currentLinkIndex_].link;
|
||||
}
|
||||
|
||||
get noteX(): number | null {
|
||||
public get noteX(): number | null {
|
||||
if (this.currentLinkIndex_ === null) return null;
|
||||
return this.linkStore_[this.currentLinkIndex_].noteX;
|
||||
}
|
||||
|
||||
get noteY(): number | null {
|
||||
public get noteY(): number | null {
|
||||
if (this.currentLinkIndex_ === null) return null;
|
||||
return this.linkStore_[this.currentLinkIndex_].noteY;
|
||||
}
|
||||
|
||||
findLinks(renderedText: string): LinkStoreEntry[] {
|
||||
public findLinks(renderedText: string): LinkStoreEntry[] {
|
||||
const newLinkStore: LinkStoreEntry[] = [];
|
||||
const lines: string[] = renderedText.split('\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
@@ -56,19 +56,19 @@ class LinkSelector {
|
||||
return newLinkStore;
|
||||
}
|
||||
|
||||
updateText(renderedText: string): void {
|
||||
public updateText(renderedText: string): void {
|
||||
this.currentLinkIndex_ = null;
|
||||
this.renderedText_ = renderedText;
|
||||
this.linkStore_ = this.findLinks(this.renderedText_);
|
||||
}
|
||||
|
||||
updateNote(textWidget: any): void {
|
||||
public updateNote(textWidget: any): void {
|
||||
this.noteId_ = textWidget.noteId;
|
||||
this.scrollTop_ = textWidget.scrollTop_;
|
||||
this.updateText(textWidget.renderedText_);
|
||||
}
|
||||
|
||||
scrollWidget(textWidget: any): void {
|
||||
public scrollWidget(textWidget: any): void {
|
||||
if (this.currentLinkIndex_ === null) return;
|
||||
|
||||
const noteY = this.linkStore_[this.currentLinkIndex_].noteY;
|
||||
@@ -93,7 +93,7 @@ class LinkSelector {
|
||||
return;
|
||||
}
|
||||
|
||||
changeLink(textWidget: any, offset: number): void | null {
|
||||
public changeLink(textWidget: any, offset: number): void | null {
|
||||
if (textWidget.noteId !== this.noteId_) {
|
||||
this.updateNote(textWidget);
|
||||
this.changeLink(textWidget, offset);
|
||||
@@ -123,7 +123,7 @@ class LinkSelector {
|
||||
return;
|
||||
}
|
||||
|
||||
openLink(textWidget: any): void {
|
||||
public openLink(textWidget: any): void {
|
||||
if (textWidget.noteId !== this.noteId_) return;
|
||||
if (textWidget.renderedText_ !== this.renderedText_) return;
|
||||
if (textWidget.scrollTop_ !== this.scrollTop_) return;
|
||||
|
@@ -8,7 +8,7 @@ const Resource = require('@joplin/lib/models/Resource').default;
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const reducer = require('@joplin/lib/reducer').default;
|
||||
const { defaultState } = require('@joplin/lib/reducer');
|
||||
const { splitCommandString } = require('@joplin/lib/string-utils.js');
|
||||
const { splitCommandString } = require('@joplin/utils');
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
|
@@ -9,7 +9,8 @@ const Tag = require('@joplin/lib/models/Tag').default;
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const { fileExtension } = require('@joplin/lib/path-utils');
|
||||
const { splitCommandString, splitCommandBatch } = require('@joplin/lib/string-utils');
|
||||
const { splitCommandString } = require('@joplin/utils');
|
||||
const { splitCommandBatch } = require('@joplin/lib/string-utils');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const fs = require('fs-extra');
|
||||
const { cliUtils } = require('./cli-utils.js');
|
||||
@@ -246,6 +247,7 @@ class Application extends BaseApplication {
|
||||
showConsole: () => {},
|
||||
maximizeConsole: () => {},
|
||||
stdout: text => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(text);
|
||||
},
|
||||
fullScreen: () => {},
|
||||
@@ -407,6 +409,7 @@ class Application extends BaseApplication {
|
||||
if (this.showStackTraces_) {
|
||||
console.error(error);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(error.message);
|
||||
}
|
||||
process.exit(1);
|
||||
|
@@ -125,14 +125,14 @@ async function handleAutocompletionPromise(line) {
|
||||
}
|
||||
function handleAutocompletion(str, callback) {
|
||||
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
|
||||
handleAutocompletionPromise(str).then(function(res) {
|
||||
handleAutocompletionPromise(str).then((res) => {
|
||||
callback(undefined, res);
|
||||
});
|
||||
}
|
||||
function toCommandLine(args) {
|
||||
if (Array.isArray(args)) {
|
||||
return args
|
||||
.map(function(a) {
|
||||
.map((a) => {
|
||||
if (a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
|
||||
return `'${a}'`;
|
||||
} else if (a.indexOf('\'') !== -1) {
|
||||
|
@@ -1,97 +0,0 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const locale_1 = require("@joplin/lib/locale");
|
||||
const registry_js_1 = require("@joplin/lib/registry.js");
|
||||
class BaseCommand {
|
||||
constructor() {
|
||||
this.stdout_ = null;
|
||||
this.prompt_ = null;
|
||||
}
|
||||
usage() {
|
||||
throw new Error('Usage not defined');
|
||||
}
|
||||
encryptionCheck(item) {
|
||||
if (item && item.encryption_applied)
|
||||
throw new Error((0, locale_1._)('Cannot change encrypted item'));
|
||||
}
|
||||
description() {
|
||||
throw new Error('Description not defined');
|
||||
}
|
||||
action(_args) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
throw new Error('Action not defined');
|
||||
});
|
||||
}
|
||||
compatibleUis() {
|
||||
return ['cli', 'gui'];
|
||||
}
|
||||
supportsUi(ui) {
|
||||
return this.compatibleUis().indexOf(ui) >= 0;
|
||||
}
|
||||
options() {
|
||||
return [];
|
||||
}
|
||||
hidden() {
|
||||
return false;
|
||||
}
|
||||
enabled() {
|
||||
return true;
|
||||
}
|
||||
cancellable() {
|
||||
return false;
|
||||
}
|
||||
cancel() {
|
||||
return __awaiter(this, void 0, void 0, function* () { });
|
||||
}
|
||||
name() {
|
||||
const r = this.usage().split(' ');
|
||||
return r[0];
|
||||
}
|
||||
setDispatcher(fn) {
|
||||
this.dispatcher_ = fn;
|
||||
}
|
||||
dispatch(action) {
|
||||
if (!this.dispatcher_)
|
||||
throw new Error('Dispatcher not defined');
|
||||
return this.dispatcher_(action);
|
||||
}
|
||||
setStdout(fn) {
|
||||
this.stdout_ = fn;
|
||||
}
|
||||
stdout(text) {
|
||||
if (this.stdout_)
|
||||
this.stdout_(text);
|
||||
}
|
||||
setPrompt(fn) {
|
||||
this.prompt_ = fn;
|
||||
}
|
||||
prompt(message, options = null) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (!this.prompt_)
|
||||
throw new Error('Prompt is undefined');
|
||||
return yield this.prompt_(message, options);
|
||||
});
|
||||
}
|
||||
metadata() {
|
||||
return {
|
||||
name: this.name(),
|
||||
usage: this.usage(),
|
||||
options: this.options(),
|
||||
hidden: this.hidden(),
|
||||
};
|
||||
}
|
||||
logger() {
|
||||
return registry_js_1.reg.logger();
|
||||
}
|
||||
}
|
||||
exports.default = BaseCommand;
|
||||
//# sourceMappingURL=base-command.js.map
|
@@ -7,80 +7,80 @@ export default class BaseCommand {
|
||||
protected prompt_: any = null;
|
||||
protected dispatcher_: any;
|
||||
|
||||
usage(): string {
|
||||
public usage(): string {
|
||||
throw new Error('Usage not defined');
|
||||
}
|
||||
|
||||
encryptionCheck(item: any) {
|
||||
public encryptionCheck(item: any) {
|
||||
if (item && item.encryption_applied) throw new Error(_('Cannot change encrypted item'));
|
||||
}
|
||||
|
||||
description() {
|
||||
public description() {
|
||||
throw new Error('Description not defined');
|
||||
}
|
||||
|
||||
async action(_args: any) {
|
||||
public async action(_args: any) {
|
||||
throw new Error('Action not defined');
|
||||
}
|
||||
|
||||
compatibleUis() {
|
||||
public compatibleUis() {
|
||||
return ['cli', 'gui'];
|
||||
}
|
||||
|
||||
supportsUi(ui: string) {
|
||||
public supportsUi(ui: string) {
|
||||
return this.compatibleUis().indexOf(ui) >= 0;
|
||||
}
|
||||
|
||||
options(): any[] {
|
||||
public options(): any[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
hidden() {
|
||||
public hidden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
enabled() {
|
||||
public enabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
cancellable() {
|
||||
public cancellable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
async cancel() {}
|
||||
public async cancel() {}
|
||||
|
||||
name() {
|
||||
public name() {
|
||||
const r = this.usage().split(' ');
|
||||
return r[0];
|
||||
}
|
||||
|
||||
setDispatcher(fn: Function) {
|
||||
public setDispatcher(fn: Function) {
|
||||
this.dispatcher_ = fn;
|
||||
}
|
||||
|
||||
dispatch(action: any) {
|
||||
public dispatch(action: any) {
|
||||
if (!this.dispatcher_) throw new Error('Dispatcher not defined');
|
||||
return this.dispatcher_(action);
|
||||
}
|
||||
|
||||
setStdout(fn: Function) {
|
||||
public setStdout(fn: Function) {
|
||||
this.stdout_ = fn;
|
||||
}
|
||||
|
||||
stdout(text: string) {
|
||||
public stdout(text: string) {
|
||||
if (this.stdout_) this.stdout_(text);
|
||||
}
|
||||
|
||||
setPrompt(fn: Function) {
|
||||
public setPrompt(fn: Function) {
|
||||
this.prompt_ = fn;
|
||||
}
|
||||
|
||||
async prompt(message: string, options: any = null) {
|
||||
public async prompt(message: string, options: any = null) {
|
||||
if (!this.prompt_) throw new Error('Prompt is undefined');
|
||||
return await this.prompt_(message, options);
|
||||
}
|
||||
|
||||
metadata() {
|
||||
public metadata() {
|
||||
return {
|
||||
name: this.name(),
|
||||
usage: this.usage(),
|
||||
@@ -89,7 +89,7 @@ export default class BaseCommand {
|
||||
};
|
||||
}
|
||||
|
||||
logger() {
|
||||
public logger() {
|
||||
return reg.logger();
|
||||
}
|
||||
}
|
||||
|
@@ -131,6 +131,7 @@ async function main() {
|
||||
const commandsText = commandBlocks.join('\n\n');
|
||||
const footerText = getFooter();
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(`${headerText}\n\n` + 'USAGE' + `\n\n${commandsText}\n\n${footerText}`);
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const { dirname } = require('@joplin/lib/path-utils');
|
||||
|
@@ -82,6 +82,7 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
|
||||
const options = cmd.options();
|
||||
const booleanFlags = [];
|
||||
const aliases = {};
|
||||
const flagSpecs = [];
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i].length !== 2) throw new Error(`Invalid options: ${options[i]}`);
|
||||
let flags = options[i][0];
|
||||
@@ -96,6 +97,8 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
|
||||
if (flags.short && flags.long) {
|
||||
aliases[flags.long] = [flags.short];
|
||||
}
|
||||
|
||||
flagSpecs.push(flags);
|
||||
}
|
||||
|
||||
const args = yargParser(argv, {
|
||||
@@ -121,6 +124,19 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
|
||||
argOptions[key] = args[key];
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(argOptions)) {
|
||||
const flagSpec = flagSpecs.find(s => {
|
||||
return s.short === key || s.long === key;
|
||||
});
|
||||
if (flagSpec?.arg?.required) {
|
||||
// If a flag is required, and no value is provided for it, Yargs
|
||||
// sets the value to `true`.
|
||||
if (value === true) {
|
||||
throw new Error(_('Missing required flag value: %s', `-${flagSpec.short} <${flagSpec.arg.name}>`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output.options = argOptions;
|
||||
|
||||
return output;
|
||||
|
@@ -39,9 +39,9 @@ class Command extends BaseCommand {
|
||||
let settingsObj;
|
||||
try {
|
||||
settingsObj = JSON.parse(json);
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
isSettled = true;
|
||||
return reject(new Error(`Invalid JSON passed to config --import: \n${err.message}.`));
|
||||
return reject(new Error(`Invalid JSON passed to config --import: \n${error.message}.`));
|
||||
}
|
||||
if (settingsObj) {
|
||||
Object.entries(settingsObj)
|
||||
|
@@ -12,15 +12,15 @@ const imageType = require('image-type');
|
||||
const readChunk = require('read-chunk');
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public usage() {
|
||||
return 'e2ee <command> [path]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public description() {
|
||||
return _('Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, `status`, `decrypt-file`, and `target-status`.'); // `generate-ppk`
|
||||
}
|
||||
|
||||
options() {
|
||||
public options() {
|
||||
return [
|
||||
// This is here mostly for testing - shouldn't be used
|
||||
['-p, --password <password>', 'Use this password as master password (For security reasons, it is not recommended to use this option).'],
|
||||
@@ -30,7 +30,7 @@ class Command extends BaseCommand {
|
||||
];
|
||||
}
|
||||
|
||||
async action(args: any) {
|
||||
public async action(args: any) {
|
||||
const options = args.options;
|
||||
|
||||
const askForMasterKey = async (error: any) => {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
const fs = require('fs-extra');
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const { splitCommandString } = require('@joplin/lib/string-utils.js');
|
||||
const { splitCommandString } = require('@joplin/utils');
|
||||
const uuid = require('@joplin/lib/uuid').default;
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
|
@@ -1,21 +0,0 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
return 'mkbook <new-notebook>';
|
||||
}
|
||||
|
||||
description() {
|
||||
return _('Creates a new notebook.');
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
const folder = await Folder.save({ title: args['new-notebook'] }, { userSideValidation: true });
|
||||
app().switchCurrentFolder(folder);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Command;
|
50
packages/app-cli/app/command-mkbook.test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
|
||||
import { setupCommandForTesting, setupApplication } from './utils/testUtils';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
const Command = require('./command-mkbook');
|
||||
|
||||
|
||||
describe('command-mkbook', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
await setupApplication();
|
||||
});
|
||||
|
||||
|
||||
it('should create a subfolder in first folder', async () => {
|
||||
const command = setupCommandForTesting(Command);
|
||||
await command.action({ 'new-notebook': 'folder1', options: {} });
|
||||
await command.action({ 'new-notebook': 'folder1_1', options: { parent: 'folder1' } });
|
||||
|
||||
const folder1 = await Folder.loadByTitle('folder1');
|
||||
const folder1_1 = await Folder.loadByTitle('folder1_1');
|
||||
|
||||
expect(folder1.title).toBe('folder1');
|
||||
expect(folder1_1.parent_id).toBe(folder1.id);
|
||||
});
|
||||
|
||||
it('should not be possible to create a subfolder without an argument.', async () => {
|
||||
const command = setupCommandForTesting(Command);
|
||||
await command.action({ 'new-notebook': 'folder2', options: {} });
|
||||
await expect(command.action({ 'new-notebook': 'folder2_1', options: { parent: true } })).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('should not be possible to create subfolder in ambiguous destination folder', async () => {
|
||||
const command = setupCommandForTesting(Command);
|
||||
await command.action({ 'new-notebook': 'folder3', options: {} });
|
||||
await command.action({ 'new-notebook': 'folder3', options: {} }); // ambiguous folder
|
||||
await expect(command.action({ 'new-notebook': 'folder3_1', options: { parent: 'folder3' } })).rejects.toThrowError();
|
||||
|
||||
// check if duplicate entries have been created.
|
||||
const folderAll = await Folder.all();
|
||||
const folders3 = folderAll.filter(x => x.title === 'folder3');
|
||||
expect(folders3.length).toBe(2);
|
||||
|
||||
// check if something has been created in one of the duplicate entries.
|
||||
expect(await Folder.childrenIds(folders3[0].id)).toEqual([]);
|
||||
expect(await Folder.childrenIds(folders3[1].id)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
65
packages/app-cli/app/command-mkbook.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const { app } = require('./app.js');
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import { FolderEntity } from '@joplin/lib/services/database/types';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
public usage() {
|
||||
return 'mkbook <new-notebook>';
|
||||
}
|
||||
|
||||
public description() {
|
||||
return _('Creates a new notebook.');
|
||||
}
|
||||
|
||||
public options() {
|
||||
return [
|
||||
['-p, --parent <parent-notebook>', _('Create a new notebook under a parent notebook.')],
|
||||
];
|
||||
}
|
||||
|
||||
// validDestinationFolder check for presents and ambiguous folders
|
||||
public async validDestinationFolder(targetFolder: string) {
|
||||
|
||||
const destinationFolder = await app().loadItem(BaseModel.TYPE_FOLDER, targetFolder);
|
||||
if (!destinationFolder) {
|
||||
throw new Error(_('Cannot find: "%s"', targetFolder));
|
||||
}
|
||||
|
||||
const destinationDups = await Folder.search({ titlePattern: targetFolder, limit: 2 });
|
||||
if (destinationDups.length > 1) {
|
||||
throw new Error(_('Ambiguous notebook "%s". Please use short notebook id instead - press "ti" to see the short notebook id', targetFolder));
|
||||
}
|
||||
|
||||
return destinationFolder;
|
||||
}
|
||||
|
||||
public async saveAndSwitchFolder(newFolder: FolderEntity) {
|
||||
|
||||
const folder = await Folder.save(newFolder, { userSideValidation: true });
|
||||
app().switchCurrentFolder(folder);
|
||||
|
||||
}
|
||||
|
||||
public async action(args: any) {
|
||||
const targetFolder = args.options.parent;
|
||||
|
||||
const newFolder: FolderEntity = {
|
||||
title: args['new-notebook'],
|
||||
};
|
||||
|
||||
if (targetFolder) {
|
||||
|
||||
const destinationFolder = await this.validDestinationFolder(targetFolder);
|
||||
newFolder.parent_id = destinationFolder.id;
|
||||
await this.saveAndSwitchFolder(newFolder);
|
||||
|
||||
} else {
|
||||
await this.saveAndSwitchFolder(newFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Command;
|
@@ -26,7 +26,7 @@ class Command extends BaseCommand {
|
||||
|
||||
const destinationDuplicates = await Folder.search({ titlePattern: destination, limit: 2 });
|
||||
if (destinationDuplicates.length > 1) {
|
||||
throw new Error(_('Ambiguous notebook "%s". Please use short notebook id instead - press "ti" to see the short notebook id' , destination));
|
||||
throw new Error(_('Ambiguous notebook "%s". Please use short notebook id instead - press "ti" to see the short notebook id', destination));
|
||||
}
|
||||
|
||||
const itemFolder = await app().loadItem(BaseModel.TYPE_FOLDER, pattern);
|
||||
|
@@ -23,19 +23,19 @@ function settingTypeToSchemaType(type: SettingItemType): string {
|
||||
}
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public usage() {
|
||||
return 'settingschema <file>';
|
||||
}
|
||||
|
||||
description() {
|
||||
public description() {
|
||||
return 'Build the setting schema file';
|
||||
}
|
||||
|
||||
enabled() {
|
||||
public enabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
async action(args: any) {
|
||||
public async action(args: any) {
|
||||
const schema: Record<string, any> = {
|
||||
title: 'JSON schema for Joplin setting files',
|
||||
'$id': Setting.schemaUrl,
|
||||
|
@@ -9,11 +9,11 @@ import { appTypeToLockType } from '@joplin/lib/services/synchronizer/LockHandler
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const { app } = require('./app.js');
|
||||
const { OneDriveApiNodeUtils } = require('@joplin/lib/onedrive-api-node-utils.js');
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
const { cliUtils } = require('./cli-utils.js');
|
||||
const md5 = require('md5');
|
||||
const locker = require('proper-lockfile');
|
||||
const fs = require('fs-extra');
|
||||
import * as locker from 'proper-lockfile';
|
||||
import { pathExists, writeFile } from 'fs-extra';
|
||||
|
||||
class Command extends BaseCommand {
|
||||
|
||||
@@ -21,15 +21,15 @@ class Command extends BaseCommand {
|
||||
private releaseLockFn_: Function = null;
|
||||
private oneDriveApiUtils_: any = null;
|
||||
|
||||
usage() {
|
||||
public usage() {
|
||||
return 'sync';
|
||||
}
|
||||
|
||||
description() {
|
||||
public description() {
|
||||
return _('Synchronises with remote storage.');
|
||||
}
|
||||
|
||||
options() {
|
||||
public options() {
|
||||
return [
|
||||
['--target <target>', _('Sync to provided target (defaults to sync.target config value)')],
|
||||
['--upgrade', _('Upgrade the sync target to the latest version.')],
|
||||
@@ -37,24 +37,15 @@ class Command extends BaseCommand {
|
||||
];
|
||||
}
|
||||
|
||||
static async lockFile(filePath: string): Promise<Function> {
|
||||
private static async lockFile(filePath: string) {
|
||||
return locker.lock(filePath, { stale: 1000 * 60 * 5 });
|
||||
}
|
||||
|
||||
static isLocked(filePath: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
locker.check(filePath, (error: any, isLocked: boolean) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(isLocked);
|
||||
});
|
||||
});
|
||||
private static async isLocked(filePath: string) {
|
||||
return locker.check(filePath);
|
||||
}
|
||||
|
||||
async doAuth() {
|
||||
public async doAuth() {
|
||||
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
||||
const syncTargetMd = SyncTargetRegistry.idToMetadata(this.syncTargetId_);
|
||||
|
||||
@@ -98,23 +89,23 @@ class Command extends BaseCommand {
|
||||
return false;
|
||||
}
|
||||
|
||||
cancelAuth() {
|
||||
public cancelAuth() {
|
||||
if (this.oneDriveApiUtils_) {
|
||||
this.oneDriveApiUtils_.cancelOAuthDance();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
doingAuth() {
|
||||
public doingAuth() {
|
||||
return !!this.oneDriveApiUtils_;
|
||||
}
|
||||
|
||||
async action(args: any) {
|
||||
public async action(args: any) {
|
||||
this.releaseLockFn_ = null;
|
||||
|
||||
// Lock is unique per profile/database
|
||||
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 pathExists(lockFilePath))) await writeFile(lockFilePath, 'synclock');
|
||||
|
||||
const useLock = args.options.useLock !== 0;
|
||||
|
||||
@@ -247,7 +238,7 @@ class Command extends BaseCommand {
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
async cancel() {
|
||||
public async cancel() {
|
||||
if (this.doingAuth()) {
|
||||
this.cancelAuth();
|
||||
return;
|
||||
@@ -272,7 +263,7 @@ class Command extends BaseCommand {
|
||||
this.syncTargetId_ = null;
|
||||
}
|
||||
|
||||
cancellable() {
|
||||
public cancellable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -18,19 +18,19 @@ function itemCount(args: any) {
|
||||
}
|
||||
|
||||
class Command extends BaseCommand {
|
||||
usage() {
|
||||
public usage() {
|
||||
return 'testing <command> [arg0]';
|
||||
}
|
||||
|
||||
description() {
|
||||
public description() {
|
||||
return 'testing';
|
||||
}
|
||||
|
||||
enabled() {
|
||||
public enabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
options(): any[] {
|
||||
public options(): any[] {
|
||||
return [
|
||||
['--folder-count <count>', 'Folders to create'],
|
||||
['--note-count <count>', 'Notes to create'],
|
||||
@@ -40,7 +40,7 @@ class Command extends BaseCommand {
|
||||
];
|
||||
}
|
||||
|
||||
async action(args: any) {
|
||||
public async action(args: any) {
|
||||
const { command, options } = args;
|
||||
|
||||
if (command === 'populate') {
|
||||
@@ -118,6 +118,7 @@ class Command extends BaseCommand {
|
||||
}
|
||||
await Promise.all(promises);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(await api.exec('GET', 'api/items/root:/testing:'));
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,7 @@ class Command extends BaseCommand {
|
||||
}
|
||||
|
||||
async action() {
|
||||
this.stdout(versionInfo(require('./package.json')).message);
|
||||
this.stdout(versionInfo(require('./package.json'), {}).message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -36,7 +36,7 @@ class FolderListWidget extends ListWidget {
|
||||
if (Setting.value('showNoteCounts')) {
|
||||
let noteCount = item.note_count;
|
||||
// Subtract children note_count from parent folder.
|
||||
if (this.folderHasChildren_(this.folders,item.id)) {
|
||||
if (this.folderHasChildren_(this.folders, item.id)) {
|
||||
for (let i = 0; i < this.folders.length; i++) {
|
||||
if (this.folders[i].parent_id === item.id) {
|
||||
noteCount -= this.folders[i].note_count;
|
||||
|
@@ -5,7 +5,7 @@ const stripAnsi = require('strip-ansi');
|
||||
const { handleAutocompletion } = require('../autocompletion.js');
|
||||
|
||||
export default class StatusBarWidget extends BaseWidget {
|
||||
constructor() {
|
||||
public constructor() {
|
||||
super();
|
||||
|
||||
this.promptState_ = null;
|
||||
@@ -14,20 +14,20 @@ export default class StatusBarWidget extends BaseWidget {
|
||||
this.items_ = [];
|
||||
}
|
||||
|
||||
get name() {
|
||||
public get name() {
|
||||
return 'statusBar';
|
||||
}
|
||||
|
||||
get canHaveFocus() {
|
||||
public get canHaveFocus() {
|
||||
return false;
|
||||
}
|
||||
|
||||
setItemAt(index: number, text: string) {
|
||||
public setItemAt(index: number, text: string) {
|
||||
this.items_[index] = stripAnsi(text).trim();
|
||||
this.invalidate();
|
||||
}
|
||||
|
||||
async prompt(initialText = '', promptString: any = null, options: any = null) {
|
||||
public async prompt(initialText = '', promptString: any = null, options: any = null) {
|
||||
if (this.promptState_) throw new Error('Another prompt already active');
|
||||
if (promptString === null) promptString = ':';
|
||||
if (options === null) options = {};
|
||||
@@ -53,15 +53,15 @@ export default class StatusBarWidget extends BaseWidget {
|
||||
return this.promptState_.promise;
|
||||
}
|
||||
|
||||
get promptActive() {
|
||||
public get promptActive() {
|
||||
return !!this.promptState_;
|
||||
}
|
||||
|
||||
get history() {
|
||||
public get history() {
|
||||
return this.history_;
|
||||
}
|
||||
|
||||
resetCursor() {
|
||||
public resetCursor() {
|
||||
if (!this.promptActive) return;
|
||||
if (!this.inputEventEmitter_) return;
|
||||
|
||||
@@ -70,7 +70,7 @@ export default class StatusBarWidget extends BaseWidget {
|
||||
this.term.moveTo(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString) + this.inputEventEmitter_.getInput().length, this.absoluteInnerY);
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
super.render();
|
||||
|
||||
const doSaveCursor = !this.promptActive;
|
||||
|
@@ -75,14 +75,14 @@ if (process.platform === 'win32') {
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
rl.on('SIGINT', function() {
|
||||
rl.on('SIGINT', () => {
|
||||
process.emit('SIGINT');
|
||||
});
|
||||
}
|
||||
|
||||
process.stdout.on('error', function(err) {
|
||||
process.stdout.on('error', (error) => {
|
||||
// https://stackoverflow.com/questions/12329816/error-write-epipe-when-piping-node-output-to-head#15884508
|
||||
if (err.code === 'EPIPE') {
|
||||
if (error.code === 'EPIPE') {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
|
@@ -11,6 +11,7 @@ function createConsoleWrapper(pluginId: string) {
|
||||
const wrapper: any = {};
|
||||
|
||||
for (const n in console) {
|
||||
// eslint-disable-next-line no-console
|
||||
if (!console.hasOwnProperty(n)) continue;
|
||||
wrapper[n] = (...args: any[]) => {
|
||||
const newArgs = args.slice();
|
||||
@@ -34,7 +35,7 @@ export default class PluginRunner extends BasePluginRunner {
|
||||
private eventHandlers_: EventHandlers = {};
|
||||
private activeSandboxCalls_: any = {};
|
||||
|
||||
constructor() {
|
||||
public constructor() {
|
||||
super();
|
||||
|
||||
this.eventHandler = this.eventHandler.bind(this);
|
||||
@@ -63,7 +64,7 @@ export default class PluginRunner extends BasePluginRunner {
|
||||
};
|
||||
}
|
||||
|
||||
async run(plugin: Plugin, sandbox: Global): Promise<void> {
|
||||
public async run(plugin: Plugin, sandbox: Global): Promise<void> {
|
||||
return new Promise((resolve: Function, reject: Function) => {
|
||||
const onStarted = () => {
|
||||
plugin.off('started', onStarted);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "joplin",
|
||||
"description": "Joplin CLI Client",
|
||||
"license": "MIT",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Laurent Cozic",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -30,34 +30,36 @@
|
||||
2019,
|
||||
2020,
|
||||
2021,
|
||||
2022
|
||||
2022,
|
||||
2023
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "2.10.0",
|
||||
"version": "2.11.0",
|
||||
"bin": "./main.js",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/lib": "~2.10",
|
||||
"@joplin/renderer": "~2.10",
|
||||
"aws-sdk": "2.1275.0",
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@joplin/utils": "~2.11",
|
||||
"aws-sdk": "2.1290.0",
|
||||
"chalk": "4.1.2",
|
||||
"compare-version": "0.1.2",
|
||||
"fs-extra": "11.1.0",
|
||||
"fs-extra": "11.1.1",
|
||||
"html-entities": "1.4.0",
|
||||
"image-type": "3.1.0",
|
||||
"keytar": "7.9.0",
|
||||
"md5": "2.3.0",
|
||||
"node-rsa": "1.1.1",
|
||||
"open": "8.4.0",
|
||||
"open": "8.4.2",
|
||||
"proper-lockfile": "4.1.2",
|
||||
"read-chunk": "2.1.0",
|
||||
"server-destroy": "1.0.1",
|
||||
"sharp": "0.31.2",
|
||||
"sharp": "0.31.3",
|
||||
"sprintf-js": "1.1.2",
|
||||
"sqlite3": "5.1.4",
|
||||
"sqlite3": "5.1.6",
|
||||
"string-padding": "1.0.2",
|
||||
"strip-ansi": "6.0.1",
|
||||
"tcp-port-used": "1.0.2",
|
||||
@@ -68,12 +70,13 @@
|
||||
"yargs-parser": "21.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "~2.10",
|
||||
"@joplin/tools": "~2.11",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/jest": "29.2.4",
|
||||
"@types/node": "18.11.15",
|
||||
"@types/jest": "29.2.6",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/proper-lockfile": "^4.1.2",
|
||||
"gulp": "4.0.2",
|
||||
"jest": "29.3.1",
|
||||
"jest": "29.4.3",
|
||||
"temp": "0.9.4",
|
||||
"typescript": "4.9.4"
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ const shim = require('@joplin/lib/shim').default;
|
||||
const HtmlToHtml = require('@joplin/renderer/HtmlToHtml').default;
|
||||
const { enexXmlToMd } = require('@joplin/lib/import-enex-md-gen.js');
|
||||
|
||||
describe('HtmlToHtml', function() {
|
||||
describe('HtmlToHtml', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
@@ -49,6 +49,7 @@ describe('HtmlToHtml', function() {
|
||||
}
|
||||
|
||||
if (actualHtml !== expectedHtml) {
|
||||
/* eslint-disable no-console */
|
||||
console.info('');
|
||||
console.info(`Error converting file: ${htmlSourceFilename}`);
|
||||
console.info('--------------------------------- Got:');
|
||||
@@ -59,6 +60,7 @@ describe('HtmlToHtml', function() {
|
||||
console.info(expectedHtml.split('\n'));
|
||||
console.info('--------------------------------------------');
|
||||
console.info('');
|
||||
/* eslint-enable */
|
||||
|
||||
expect(false).toBe(true);
|
||||
// return;
|
||||
|
@@ -3,7 +3,7 @@ const os = require('os');
|
||||
const { filename } = require('@joplin/lib/path-utils');
|
||||
import HtmlToMd from '@joplin/lib/HtmlToMd';
|
||||
|
||||
describe('HtmlToMd', function() {
|
||||
describe('HtmlToMd', () => {
|
||||
|
||||
it('should convert from Html to Markdown', (async () => {
|
||||
const basePath = `${__dirname}/html_to_md`;
|
||||
@@ -57,6 +57,7 @@ describe('HtmlToMd', function() {
|
||||
result.push('--------------------------------------------');
|
||||
result.push('');
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(result.join('\n'));
|
||||
|
||||
// console.info('');
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
const MarkupToHtml = require('@joplin/renderer/MarkupToHtml').default;
|
||||
|
||||
describe('MarkupToHtml', function() {
|
||||
describe('MarkupToHtml', () => {
|
||||
|
||||
it('should strip markup', (async () => {
|
||||
const service = new MarkupToHtml();
|
||||
|
@@ -16,7 +16,7 @@ function newTestMdToHtml(options: any = null) {
|
||||
return new MdToHtml(options);
|
||||
}
|
||||
|
||||
describe('MdToHtml', function() {
|
||||
describe('MdToHtml', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
@@ -72,6 +72,7 @@ describe('MdToHtml', function() {
|
||||
'',
|
||||
];
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(msg.join('\n'));
|
||||
|
||||
expect(false).toBe(true);
|
||||
|
11
packages/app-cli/tests/enex_to_html/checklist.enex
Normal file
@@ -0,0 +1,11 @@
|
||||
<en-note>
|
||||
<div>
|
||||
<p>In Evernote a checklist is not the same as a list with checkboxes.</p>
|
||||
|
||||
<ul style="--en-todo:true;">
|
||||
<li style="--en-checked:false;"><div>One</div></li>
|
||||
<li style="--en-checked:true;"><div>Two</div>
|
||||
</li><li style="--en-checked:false;"><div>Three</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</en-note>
|
19
packages/app-cli/tests/enex_to_html/checklist.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<en-note>
|
||||
<div>
|
||||
<p>In Evernote a checklist is not the same as a list with checkboxes.</p>
|
||||
<ul style="--en-todo:true;">
|
||||
<li style="--en-checked:false;">
|
||||
<input type="checkbox" onclick="return false;">
|
||||
<div>One</div>
|
||||
</li>
|
||||
<li style="--en-checked:true;">
|
||||
<input checked="checked" type="checkbox" onclick="return false;">
|
||||
<div>Two</div>
|
||||
</li>
|
||||
<li style="--en-checked:false;">
|
||||
<input type="checkbox" onclick="return false;">
|
||||
<div>Three</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</en-note>
|
7
packages/app-cli/tests/enex_to_md/checklist.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<ul style="--en-todo:true;">
|
||||
<li style="--en-checked:false;"><div>One</div></li>
|
||||
<li style="--en-checked:true;"><div>Two</div>
|
||||
</li><li style="--en-checked:false;"><div>Three</div></li>
|
||||
</ul>
|
||||
|
||||
<p>More text</p>
|
7
packages/app-cli/tests/enex_to_md/checklist.md
Normal file
@@ -0,0 +1,7 @@
|
||||
- [ ] One
|
||||
|
||||
- [X] Two
|
||||
|
||||
- [ ] Three
|
||||
|
||||
More text
|
@@ -22,7 +22,7 @@ const goToNote = (testApp, note) => {
|
||||
testApp.dispatch({ type: 'NOTE_SELECT', id: note.id });
|
||||
};
|
||||
|
||||
describe('feature_NoteHistory', function() {
|
||||
describe('feature_NoteHistory', () => {
|
||||
beforeEach(async () => {
|
||||
testApp = new TestApp();
|
||||
await testApp.start(['--no-welcome']);
|
||||
|
@@ -8,7 +8,7 @@ const time = require('@joplin/lib/time').default;
|
||||
|
||||
let testApp = null;
|
||||
|
||||
describe('integration_NoteList', function() {
|
||||
describe('integration_NoteList', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
testApp = new TestApp();
|
||||
|
@@ -22,7 +22,7 @@ const { ALL_NOTES_FILTER_ID } = require('@joplin/lib/reserved-ids.js');
|
||||
|
||||
let testApp = null;
|
||||
|
||||
describe('integration_ShowAllNotes', function() {
|
||||
describe('integration_ShowAllNotes', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
testApp = new TestApp();
|
||||
|
@@ -8,7 +8,7 @@ const time = require('@joplin/lib/time').default;
|
||||
|
||||
let testApp = null;
|
||||
|
||||
describe('integration_TagList', function() {
|
||||
describe('integration_TagList', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
testApp = new TestApp();
|
||||
|
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable jest/require-top-level-describe */
|
||||
|
||||
import KeychainService from '@joplin/lib/services/keychain/KeychainService';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
@@ -11,7 +13,7 @@ function describeIfCompatible(name: string, fn: any, elseFn: any) {
|
||||
}
|
||||
}
|
||||
|
||||
describeIfCompatible('services_KeychainService', function() {
|
||||
describeIfCompatible('services_KeychainService', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1, { keychainEnabled: true });
|
||||
|
@@ -29,7 +29,7 @@ function newPluginService(appVersion: string = '1.4') {
|
||||
return service;
|
||||
}
|
||||
|
||||
describe('services_PluginService', function() {
|
||||
describe('services_PluginService', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
|
@@ -8,7 +8,7 @@ async function newRepoApi(): Promise<RepositoryApi> {
|
||||
return repo;
|
||||
}
|
||||
|
||||
describe('services_plugins_RepositoryApi', function() {
|
||||
describe('services_plugins_RepositoryApi', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
@@ -47,9 +47,11 @@ describe('services_plugins_RepositoryApi', function() {
|
||||
|
||||
it('should tell if a plugin can be updated', (async () => {
|
||||
const api = await newRepoApi();
|
||||
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.0')).toBe(true);
|
||||
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.2')).toBe(false);
|
||||
expect(await api.pluginCanBeUpdated('does.not.exist', '1.0.0')).toBe(false);
|
||||
|
||||
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.0', '3.0.0')).toBe(true);
|
||||
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.0', '1.0.0')).toBe(false);
|
||||
expect(await api.pluginCanBeUpdated('org.joplinapp.plugins.ToggleSidebars', '1.0.2', '3.0.0')).toBe(false);
|
||||
expect(await api.pluginCanBeUpdated('does.not.exist', '1.0.0', '3.0.0')).toBe(false);
|
||||
}));
|
||||
|
||||
});
|
||||
|
@@ -24,7 +24,7 @@ function newPluginService(appVersion: string = '1.4') {
|
||||
return service;
|
||||
}
|
||||
|
||||
describe('defaultPluginsUtils', function() {
|
||||
describe('defaultPluginsUtils', () => {
|
||||
|
||||
const pluginsId = ['joplin.plugin.ambrt.backlinksToNote', 'org.joplinapp.plugins.ToggleSidebars'];
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
const sandboxProxy = require('@joplin/lib/services/plugins/sandboxProxy');
|
||||
import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
|
||||
|
||||
describe('services_plugins_sandboxProxy', function() {
|
||||
describe('services_plugins_sandboxProxy', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
|
@@ -13,17 +13,14 @@ import JoplinWindow from './JoplinWindow';
|
||||
/**
|
||||
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
|
||||
*
|
||||
* **This is a beta API**
|
||||
* The API is now relatively stable and in general maintaining backward compatibility is a top priority, so you shouldn't except much breakages.
|
||||
*
|
||||
* Please note that the plugin API is relatively new and should be considered Beta state. Besides possible bugs, what it means is that there might be necessary breaking changes from one version to the next. Whenever such change is needed, best effort will be done to:
|
||||
* If a breaking change ever becomes needed, best effort will be done to:
|
||||
*
|
||||
* - Maintain backward compatibility;
|
||||
* - When possible, deprecate features instead of removing them;
|
||||
* - Deprecate features instead of removing them, so as to give you time to fix the issue;
|
||||
* - Document breaking changes in the changelog;
|
||||
*
|
||||
* So if you are developing a plugin, please keep an eye on the changelog as everything will be in there with information about how to update your code. There won't be any major API rewrite or architecture changes, but possibly small tweaks like function signature change, type change, etc.
|
||||
*
|
||||
* Eventually, the plugin API will be versioned to make this process smoother.
|
||||
* So if you are developing a plugin, please keep an eye on the changelog as everything will be in there with information about how to update your code.
|
||||
*/
|
||||
export default class Joplin {
|
||||
private data_;
|
||||
|
@@ -15,7 +15,7 @@ import { Command } from './types';
|
||||
*
|
||||
* * [Main screen commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/MainScreen/commands)
|
||||
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/commands)
|
||||
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.ts)
|
||||
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts)
|
||||
*
|
||||
* To view what arguments are supported, you can open any of these files
|
||||
* and look at the `execute()` command.
|
||||
@@ -49,7 +49,7 @@ import { Command } from './types';
|
||||
*
|
||||
*/
|
||||
export default class JoplinCommands {
|
||||
/**
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Executes the given
|
||||
* command.
|
||||
*
|
||||
@@ -68,8 +68,8 @@ export default class JoplinCommands {
|
||||
* await joplin.commands.execute('newFolder', "SOME_FOLDER_ID");
|
||||
* ```
|
||||
*/
|
||||
execute(commandName: string, ...args: any[]): Promise<any | void>;
|
||||
/**
|
||||
execute(commandName: string, ...args: any[]): Promise<any | void>;
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Registers a new command.
|
||||
*
|
||||
* ```typescript
|
||||
@@ -85,5 +85,5 @@ export default class JoplinCommands {
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
register(command: Command): Promise<void>;
|
||||
register(command: Command): Promise<void>;
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { ModelType } from '../../../BaseModel';
|
||||
import { Path } from './types';
|
||||
/**
|
||||
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
|
||||
@@ -44,4 +45,6 @@ export default class JoplinData {
|
||||
post(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
|
||||
put(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
|
||||
delete(path: Path, query?: any): Promise<any>;
|
||||
itemType(itemId: string): Promise<ModelType>;
|
||||
resourcePath(resourceId: string): Promise<string>;
|
||||
}
|
||||
|
@@ -5,6 +5,6 @@
|
||||
* so for now disable filters.
|
||||
*/
|
||||
export default class JoplinFilters {
|
||||
on(name: string, callback: Function): Promise<void>;
|
||||
off(name: string, callback: Function): Promise<void>;
|
||||
on(name: string, callback: Function): Promise<void>;
|
||||
off(name: string, callback: Function): Promise<void>;
|
||||
}
|
||||
|
@@ -12,6 +12,6 @@ import { ExportModule, ImportModule } from './types';
|
||||
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/api/references/rest_api/
|
||||
*/
|
||||
export default class JoplinInterop {
|
||||
registerExportModule(module: ExportModule): Promise<void>;
|
||||
registerImportModule(module: ImportModule): Promise<void>;
|
||||
registerExportModule(module: ExportModule): Promise<void>;
|
||||
registerImportModule(module: ImportModule): Promise<void>;
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ export interface ChangeEvent {
|
||||
*/
|
||||
keys: string[];
|
||||
}
|
||||
export declare type ChangeHandler = (event: ChangeEvent)=> void;
|
||||
export declare type ChangeHandler = (event: ChangeEvent) => void;
|
||||
/**
|
||||
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
|
||||
*
|
||||
|
@@ -61,8 +61,7 @@ export default class JoplinViewsDialogs {
|
||||
open(handle: ViewHandle): Promise<DialogResult>;
|
||||
/**
|
||||
* Toggle on whether to fit the dialog size to the content or not.
|
||||
* When set to false, the dialog stretches to fill the application
|
||||
* window.
|
||||
* When set to false, the dialog is set to 90vw and 80vh
|
||||
* @default true
|
||||
*/
|
||||
setFitToContent(handle: ViewHandle, status: boolean): Promise<boolean>;
|
||||
|
@@ -46,6 +46,23 @@ export default class JoplinViewsPanels {
|
||||
*
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Sends a message to the webview.
|
||||
*
|
||||
* The webview must have registered a message handler prior, otherwise the message is ignored. Use;
|
||||
*
|
||||
* ```javascript
|
||||
* webviewApi.onMessage((message) => { ... });
|
||||
* ```
|
||||
*
|
||||
* - `message` can be any JavaScript object, string or number
|
||||
*
|
||||
* The view API may have only one onMessage handler defined.
|
||||
* This method is fire and forget so no response is returned.
|
||||
*
|
||||
* It is particularly useful when the webview needs to react to events emitted by the plugin or the joplin api.
|
||||
*/
|
||||
postMessage(handle: ViewHandle, message: any): void;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
|
@@ -1,9 +1,13 @@
|
||||
import { FolderEntity } from '../../database/types';
|
||||
import { Disposable } from './types';
|
||||
import { Disposable, MenuItem } from './types';
|
||||
export interface EditContextMenuFilterObject {
|
||||
items: MenuItem[];
|
||||
}
|
||||
declare type FilterHandler<T> = (object: T) => Promise<void>;
|
||||
declare enum ItemChangeEventType {
|
||||
Create = 1,
|
||||
Update = 2,
|
||||
Delete = 3,
|
||||
Delete = 3
|
||||
}
|
||||
interface ItemChangeEvent {
|
||||
id: string;
|
||||
@@ -12,8 +16,12 @@ interface ItemChangeEvent {
|
||||
interface SyncStartEvent {
|
||||
withErrors: boolean;
|
||||
}
|
||||
declare type ItemChangeHandler = (event: ItemChangeEvent)=> void;
|
||||
declare type SyncStartHandler = (event: SyncStartEvent)=> void;
|
||||
interface ResourceChangeEvent {
|
||||
id: string;
|
||||
}
|
||||
declare type ItemChangeHandler = (event: ItemChangeEvent) => void;
|
||||
declare type SyncStartHandler = (event: SyncStartEvent) => void;
|
||||
declare type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
|
||||
/**
|
||||
* The workspace service provides access to all the parts of Joplin that
|
||||
* are being worked on - i.e. the currently selected notes or notebooks as
|
||||
@@ -38,6 +46,11 @@ export default class JoplinWorkspace {
|
||||
* Called when the content of the current note changes.
|
||||
*/
|
||||
onNoteChange(handler: ItemChangeHandler): Promise<Disposable>;
|
||||
/**
|
||||
* Called when a resource is changed. Currently this handled will not be
|
||||
* called when a resource is added or deleted.
|
||||
*/
|
||||
onResourceChange(handler: ResourceChangeHandler): Promise<void>;
|
||||
/**
|
||||
* Called when an alarm associated with a to-do is triggered.
|
||||
*/
|
||||
@@ -50,6 +63,11 @@ export default class JoplinWorkspace {
|
||||
* Called when the synchronisation process has finished.
|
||||
*/
|
||||
onSyncComplete(callback: Function): Promise<Disposable>;
|
||||
/**
|
||||
* Called just before the editor context menu is about to open. Allows
|
||||
* adding items to it.
|
||||
*/
|
||||
filterEditorContextMenu(handler: FilterHandler<EditContextMenuFilterObject>): void;
|
||||
/**
|
||||
* Gets the currently selected note
|
||||
*/
|
||||
|
@@ -202,6 +202,25 @@ export interface Disposable {
|
||||
// dispose():void;
|
||||
}
|
||||
|
||||
export enum ModelType {
|
||||
Note = 1,
|
||||
Folder = 2,
|
||||
Setting = 3,
|
||||
Resource = 4,
|
||||
Tag = 5,
|
||||
NoteTag = 6,
|
||||
Search = 7,
|
||||
Alarm = 8,
|
||||
MasterKey = 9,
|
||||
ItemChange = 10,
|
||||
NoteResource = 11,
|
||||
ResourceLocalState = 12,
|
||||
Revision = 13,
|
||||
Migration = 14,
|
||||
SmartFilter = 15,
|
||||
Command = 16,
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Menu types
|
||||
// =================================================================
|
||||
@@ -269,6 +288,17 @@ export interface MenuItem {
|
||||
*/
|
||||
commandName?: string;
|
||||
|
||||
/**
|
||||
* Arguments that should be passed to the command. They will be as rest
|
||||
* parameters.
|
||||
*/
|
||||
commandArgs?: any[];
|
||||
|
||||
/**
|
||||
* Set to "separator" to create a divider line
|
||||
*/
|
||||
type?: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio');
|
||||
|
||||
/**
|
||||
* Accelerator associated with the menu item
|
||||
*/
|
||||
@@ -334,6 +364,12 @@ export enum SettingItemType {
|
||||
Button = 6,
|
||||
}
|
||||
|
||||
export enum SettingItemSubType {
|
||||
FilePathAndArgs = 'file_path_and_args',
|
||||
FilePath = 'file_path', // Not supported on mobile!
|
||||
DirectoryPath = 'directory_path', // Not supported on mobile!
|
||||
}
|
||||
|
||||
export enum AppType {
|
||||
Desktop = 'desktop',
|
||||
Mobile = 'mobile',
|
||||
@@ -351,6 +387,12 @@ export interface SettingItem {
|
||||
value: any;
|
||||
type: SettingItemType;
|
||||
|
||||
/**
|
||||
* Currently only used to display a file or directory selector. Always set
|
||||
* `type` to `SettingItemType.String` when using this property.
|
||||
*/
|
||||
subType?: SettingItemSubType;
|
||||
|
||||
label: string;
|
||||
description?: string;
|
||||
|
||||
|
@@ -14,15 +14,18 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.14",
|
||||
"copy-webpack-plugin": "^6.1.0",
|
||||
"fs-extra": "9.1.0",
|
||||
"glob": "7.2.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob": "^7.1.6",
|
||||
"on-build-webpack": "^0.1.0",
|
||||
"tar": "6.1.11",
|
||||
"tar": "^6.0.5",
|
||||
"ts-loader": "^7.0.5",
|
||||
"typescript": "^3.9.3",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"chalk": "4.1.2",
|
||||
"yargs": "16.2.0"
|
||||
}
|
||||
}
|
||||
"chalk": "^4.1.0",
|
||||
"yargs": "^16.2.0"
|
||||
},
|
||||
"files": [
|
||||
"publish"
|
||||
]
|
||||
}
|
@@ -29,6 +29,7 @@ const userConfig = Object.assign({}, {
|
||||
|
||||
const manifestPath = `${srcDir}/manifest.json`;
|
||||
const packageJsonPath = `${rootDir}/package.json`;
|
||||
const allPossibleCategories = ['appearance', 'developer tools', 'productivity', 'themes', 'integrations', 'viewer', 'search', 'tags', 'editor', 'files', 'personal knowledge management'];
|
||||
const manifest = readManifest(manifestPath);
|
||||
const pluginArchiveFilePath = path.resolve(publishDir, `${manifest.id}.jpl`);
|
||||
const pluginInfoFilePath = path.resolve(publishDir, `${manifest.id}.json`);
|
||||
@@ -67,10 +68,19 @@ function currentGitInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
function validateCategories(categories) {
|
||||
if (!categories) return null;
|
||||
if ((categories.length !== new Set(categories).size)) throw new Error('Repeated categories are not allowed');
|
||||
categories.forEach(category => {
|
||||
if (!allPossibleCategories.includes(category)) throw new Error(`${category} is not a valid category. Please make sure that the category name is lowercase. Valid Categories are: \n${allPossibleCategories}\n`);
|
||||
});
|
||||
}
|
||||
|
||||
function readManifest(manifestPath) {
|
||||
const content = fs.readFileSync(manifestPath, 'utf8');
|
||||
const output = JSON.parse(content);
|
||||
if (!output.id) throw new Error(`Manifest plugin ID is not set in ${manifestPath}`);
|
||||
validateCategories(output.categories);
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -137,7 +147,7 @@ const pluginConfig = Object.assign({}, baseConfig, {
|
||||
},
|
||||
// JSON files can also be required from scripts so we include this.
|
||||
// https://github.com/joplin/plugin-bibtex/pull/2
|
||||
extensions: ['.tsx', '.ts', '.js', '.json'],
|
||||
extensions: ['.js', '.tsx', '.ts', '.json'],
|
||||
},
|
||||
output: {
|
||||
filename: 'index.js',
|
||||
@@ -169,7 +179,7 @@ const extraScriptConfig = Object.assign({}, baseConfig, {
|
||||
alias: {
|
||||
api: path.resolve(__dirname, 'api'),
|
||||
},
|
||||
extensions: ['.tsx', '.ts', '.js', '.json'],
|
||||
extensions: ['.js', '.tsx', '.ts', '.json'],
|
||||
},
|
||||
});
|
||||
|
||||
|
@@ -13,17 +13,14 @@ import JoplinWindow from './JoplinWindow';
|
||||
/**
|
||||
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
|
||||
*
|
||||
* **This is a beta API**
|
||||
* The API is now relatively stable and in general maintaining backward compatibility is a top priority, so you shouldn't except much breakages.
|
||||
*
|
||||
* Please note that the plugin API is relatively new and should be considered Beta state. Besides possible bugs, what it means is that there might be necessary breaking changes from one version to the next. Whenever such change is needed, best effort will be done to:
|
||||
* If a breaking change ever becomes needed, best effort will be done to:
|
||||
*
|
||||
* - Maintain backward compatibility;
|
||||
* - When possible, deprecate features instead of removing them;
|
||||
* - Deprecate features instead of removing them, so as to give you time to fix the issue;
|
||||
* - Document breaking changes in the changelog;
|
||||
*
|
||||
* So if you are developing a plugin, please keep an eye on the changelog as everything will be in there with information about how to update your code. There won't be any major API rewrite or architecture changes, but possibly small tweaks like function signature change, type change, etc.
|
||||
*
|
||||
* Eventually, the plugin API will be versioned to make this process smoother.
|
||||
* So if you are developing a plugin, please keep an eye on the changelog as everything will be in there with information about how to update your code.
|
||||
*/
|
||||
export default class Joplin {
|
||||
private data_;
|
||||
|
@@ -15,7 +15,7 @@ import { Command } from './types';
|
||||
*
|
||||
* * [Main screen commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/MainScreen/commands)
|
||||
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/commands)
|
||||
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.ts)
|
||||
* * [Editor commands](https://github.com/laurent22/joplin/tree/dev/packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts)
|
||||
*
|
||||
* To view what arguments are supported, you can open any of these files
|
||||
* and look at the `execute()` command.
|
||||
@@ -49,7 +49,7 @@ import { Command } from './types';
|
||||
*
|
||||
*/
|
||||
export default class JoplinCommands {
|
||||
/**
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Executes the given
|
||||
* command.
|
||||
*
|
||||
@@ -68,8 +68,8 @@ export default class JoplinCommands {
|
||||
* await joplin.commands.execute('newFolder', "SOME_FOLDER_ID");
|
||||
* ```
|
||||
*/
|
||||
execute(commandName: string, ...args: any[]): Promise<any | void>;
|
||||
/**
|
||||
execute(commandName: string, ...args: any[]): Promise<any | void>;
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Registers a new command.
|
||||
*
|
||||
* ```typescript
|
||||
@@ -85,5 +85,5 @@ export default class JoplinCommands {
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
register(command: Command): Promise<void>;
|
||||
register(command: Command): Promise<void>;
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { ModelType } from '../../../BaseModel';
|
||||
import { Path } from './types';
|
||||
/**
|
||||
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
|
||||
@@ -44,4 +45,6 @@ export default class JoplinData {
|
||||
post(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
|
||||
put(path: Path, query?: any, body?: any, files?: any[]): Promise<any>;
|
||||
delete(path: Path, query?: any): Promise<any>;
|
||||
itemType(itemId: string): Promise<ModelType>;
|
||||
resourcePath(resourceId: string): Promise<string>;
|
||||
}
|
||||
|