mirror of
https://github.com/laurent22/joplin.git
synced 2026-10-30 05:28:22 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e81427a1f2 | ||
|
|
958e9163b6 |
No files matched your search
@@ -701,9 +701,6 @@ packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js.map
|
||||
packages/app-mobile/components/SelectDateTimeDialog.d.ts
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js.map
|
||||
packages/app-mobile/components/screens/ConfigScreen.d.ts
|
||||
packages/app-mobile/components/screens/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen.js.map
|
||||
packages/app-mobile/components/screens/Note.d.ts
|
||||
packages/app-mobile/components/screens/Note.js
|
||||
packages/app-mobile/components/screens/Note.js.map
|
||||
@@ -809,9 +806,6 @@ packages/lib/BaseModel.js.map
|
||||
packages/lib/BaseSyncTarget.d.ts
|
||||
packages/lib/BaseSyncTarget.js
|
||||
packages/lib/BaseSyncTarget.js.map
|
||||
packages/lib/ClipperServer.d.ts
|
||||
packages/lib/ClipperServer.js
|
||||
packages/lib/ClipperServer.js.map
|
||||
packages/lib/HtmlToMd.d.ts
|
||||
packages/lib/HtmlToMd.js
|
||||
packages/lib/HtmlToMd.js.map
|
||||
@@ -878,9 +872,6 @@ packages/lib/eventManager.js.map
|
||||
packages/lib/file-api-driver-joplinServer.d.ts
|
||||
packages/lib/file-api-driver-joplinServer.js
|
||||
packages/lib/file-api-driver-joplinServer.js.map
|
||||
packages/lib/file-api-driver-memory.d.ts
|
||||
packages/lib/file-api-driver-memory.js
|
||||
packages/lib/file-api-driver-memory.js.map
|
||||
packages/lib/file-api-driver.test.d.ts
|
||||
packages/lib/file-api-driver.test.js
|
||||
packages/lib/file-api-driver.test.js.map
|
||||
@@ -971,9 +962,6 @@ packages/lib/models/ResourceLocalState.js.map
|
||||
packages/lib/models/Revision.d.ts
|
||||
packages/lib/models/Revision.js
|
||||
packages/lib/models/Revision.js.map
|
||||
packages/lib/models/Revision.test.d.ts
|
||||
packages/lib/models/Revision.test.js
|
||||
packages/lib/models/Revision.test.js.map
|
||||
packages/lib/models/Search.d.ts
|
||||
packages/lib/models/Search.js
|
||||
packages/lib/models/Search.js.map
|
||||
@@ -1094,9 +1082,6 @@ packages/lib/services/ResourceService.test.js.map
|
||||
packages/lib/services/RevisionService.d.ts
|
||||
packages/lib/services/RevisionService.js
|
||||
packages/lib/services/RevisionService.js.map
|
||||
packages/lib/services/RevisionService.test.d.ts
|
||||
packages/lib/services/RevisionService.test.js
|
||||
packages/lib/services/RevisionService.test.js.map
|
||||
packages/lib/services/SettingUtils.d.ts
|
||||
packages/lib/services/SettingUtils.js
|
||||
packages/lib/services/SettingUtils.js.map
|
||||
@@ -1241,9 +1226,6 @@ packages/lib/services/plugins/api/Global.js.map
|
||||
packages/lib/services/plugins/api/Joplin.d.ts
|
||||
packages/lib/services/plugins/api/Joplin.js
|
||||
packages/lib/services/plugins/api/Joplin.js.map
|
||||
packages/lib/services/plugins/api/JoplinClipboard.d.ts
|
||||
packages/lib/services/plugins/api/JoplinClipboard.js
|
||||
packages/lib/services/plugins/api/JoplinClipboard.js.map
|
||||
packages/lib/services/plugins/api/JoplinCommands.d.ts
|
||||
packages/lib/services/plugins/api/JoplinCommands.js
|
||||
packages/lib/services/plugins/api/JoplinCommands.js.map
|
||||
@@ -1334,9 +1316,6 @@ packages/lib/services/rest/ApiResponse.js.map
|
||||
packages/lib/services/rest/actionApi.desktop.d.ts
|
||||
packages/lib/services/rest/actionApi.desktop.js
|
||||
packages/lib/services/rest/actionApi.desktop.js.map
|
||||
packages/lib/services/rest/routes/auth.d.ts
|
||||
packages/lib/services/rest/routes/auth.js
|
||||
packages/lib/services/rest/routes/auth.js.map
|
||||
packages/lib/services/rest/routes/folders.d.ts
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/folders.js.map
|
||||
@@ -1412,12 +1391,6 @@ packages/lib/services/spellChecker/SpellCheckerService.js.map
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.d.ts
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js.map
|
||||
packages/lib/services/synchronizer/ItemUploader.d.ts
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js.map
|
||||
packages/lib/services/synchronizer/ItemUploader.test.d.ts
|
||||
packages/lib/services/synchronizer/ItemUploader.test.js
|
||||
packages/lib/services/synchronizer/ItemUploader.test.js.map
|
||||
packages/lib/services/synchronizer/LockHandler.d.ts
|
||||
packages/lib/services/synchronizer/LockHandler.js
|
||||
packages/lib/services/synchronizer/LockHandler.js.map
|
||||
|
||||
@@ -72,7 +72,7 @@ fi
|
||||
# release randomly fail.
|
||||
# =============================================================================
|
||||
|
||||
if [ "$IS_PULL_REQUEST" == "1" ]; then
|
||||
if [ "$IS_PULL_REQUEST" != "1" ]; then
|
||||
npm run linter-ci ./
|
||||
testResult=$?
|
||||
if [ $testResult -ne 0 ]; then
|
||||
|
||||
-27
@@ -687,9 +687,6 @@ packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js.map
|
||||
packages/app-mobile/components/SelectDateTimeDialog.d.ts
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js.map
|
||||
packages/app-mobile/components/screens/ConfigScreen.d.ts
|
||||
packages/app-mobile/components/screens/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen.js.map
|
||||
packages/app-mobile/components/screens/Note.d.ts
|
||||
packages/app-mobile/components/screens/Note.js
|
||||
packages/app-mobile/components/screens/Note.js.map
|
||||
@@ -795,9 +792,6 @@ packages/lib/BaseModel.js.map
|
||||
packages/lib/BaseSyncTarget.d.ts
|
||||
packages/lib/BaseSyncTarget.js
|
||||
packages/lib/BaseSyncTarget.js.map
|
||||
packages/lib/ClipperServer.d.ts
|
||||
packages/lib/ClipperServer.js
|
||||
packages/lib/ClipperServer.js.map
|
||||
packages/lib/HtmlToMd.d.ts
|
||||
packages/lib/HtmlToMd.js
|
||||
packages/lib/HtmlToMd.js.map
|
||||
@@ -864,9 +858,6 @@ packages/lib/eventManager.js.map
|
||||
packages/lib/file-api-driver-joplinServer.d.ts
|
||||
packages/lib/file-api-driver-joplinServer.js
|
||||
packages/lib/file-api-driver-joplinServer.js.map
|
||||
packages/lib/file-api-driver-memory.d.ts
|
||||
packages/lib/file-api-driver-memory.js
|
||||
packages/lib/file-api-driver-memory.js.map
|
||||
packages/lib/file-api-driver.test.d.ts
|
||||
packages/lib/file-api-driver.test.js
|
||||
packages/lib/file-api-driver.test.js.map
|
||||
@@ -957,9 +948,6 @@ packages/lib/models/ResourceLocalState.js.map
|
||||
packages/lib/models/Revision.d.ts
|
||||
packages/lib/models/Revision.js
|
||||
packages/lib/models/Revision.js.map
|
||||
packages/lib/models/Revision.test.d.ts
|
||||
packages/lib/models/Revision.test.js
|
||||
packages/lib/models/Revision.test.js.map
|
||||
packages/lib/models/Search.d.ts
|
||||
packages/lib/models/Search.js
|
||||
packages/lib/models/Search.js.map
|
||||
@@ -1080,9 +1068,6 @@ packages/lib/services/ResourceService.test.js.map
|
||||
packages/lib/services/RevisionService.d.ts
|
||||
packages/lib/services/RevisionService.js
|
||||
packages/lib/services/RevisionService.js.map
|
||||
packages/lib/services/RevisionService.test.d.ts
|
||||
packages/lib/services/RevisionService.test.js
|
||||
packages/lib/services/RevisionService.test.js.map
|
||||
packages/lib/services/SettingUtils.d.ts
|
||||
packages/lib/services/SettingUtils.js
|
||||
packages/lib/services/SettingUtils.js.map
|
||||
@@ -1227,9 +1212,6 @@ packages/lib/services/plugins/api/Global.js.map
|
||||
packages/lib/services/plugins/api/Joplin.d.ts
|
||||
packages/lib/services/plugins/api/Joplin.js
|
||||
packages/lib/services/plugins/api/Joplin.js.map
|
||||
packages/lib/services/plugins/api/JoplinClipboard.d.ts
|
||||
packages/lib/services/plugins/api/JoplinClipboard.js
|
||||
packages/lib/services/plugins/api/JoplinClipboard.js.map
|
||||
packages/lib/services/plugins/api/JoplinCommands.d.ts
|
||||
packages/lib/services/plugins/api/JoplinCommands.js
|
||||
packages/lib/services/plugins/api/JoplinCommands.js.map
|
||||
@@ -1320,9 +1302,6 @@ packages/lib/services/rest/ApiResponse.js.map
|
||||
packages/lib/services/rest/actionApi.desktop.d.ts
|
||||
packages/lib/services/rest/actionApi.desktop.js
|
||||
packages/lib/services/rest/actionApi.desktop.js.map
|
||||
packages/lib/services/rest/routes/auth.d.ts
|
||||
packages/lib/services/rest/routes/auth.js
|
||||
packages/lib/services/rest/routes/auth.js.map
|
||||
packages/lib/services/rest/routes/folders.d.ts
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/folders.js.map
|
||||
@@ -1398,12 +1377,6 @@ packages/lib/services/spellChecker/SpellCheckerService.js.map
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.d.ts
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js.map
|
||||
packages/lib/services/synchronizer/ItemUploader.d.ts
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js.map
|
||||
packages/lib/services/synchronizer/ItemUploader.test.d.ts
|
||||
packages/lib/services/synchronizer/ItemUploader.test.js
|
||||
packages/lib/services/synchronizer/ItemUploader.test.js.map
|
||||
packages/lib/services/synchronizer/LockHandler.d.ts
|
||||
packages/lib/services/synchronizer/LockHandler.js
|
||||
packages/lib/services/synchronizer/LockHandler.js.map
|
||||
|
||||
@@ -162,13 +162,11 @@ DESKTOP=${DESKTOP,,} # convert to lower case
|
||||
|
||||
# Detect distribution environment
|
||||
DISTVER=$(lsb_release -is) && DISTVER=$DISTVER$(lsb_release -rs)
|
||||
DISTCODENAME=$(lsb_release -cs)
|
||||
#-----------------------------------------------------
|
||||
echo 'Create Desktop icon...'
|
||||
# Check for "The SUID sandbox helper binary was found, but is not configured correctly" problem.
|
||||
# It is present in Debian 10 Buster. A (temporary) patch will be applied at .desktop file
|
||||
# Linux Mint 4 Debbie is based on Debian 10 and requires the same param handling.
|
||||
if [ "$DISTVER" = "Debian10" ] || [ "$DISTVER" = "Linuxmint4" ] && [ "$DISTCODENAME" = "debbie" ]
|
||||
if [ "$DISTVER" = "Debian10" ]
|
||||
then
|
||||
SANDBOXPARAM=" --no-sandbox"
|
||||
else
|
||||
|
||||
@@ -2,39 +2,32 @@ All code in this repository is licensed under the MIT License **unless a
|
||||
directory contains a LICENSE file**, in which case that LICENSE file applies to
|
||||
the code in that sub-directory.
|
||||
|
||||
For example, packages/fork-sax contains a ISC LICENSE file, thus all code under
|
||||
the packages/fork-sax directory is licensed under ISC.
|
||||
For example, packages/fork-sax contains a ISC LICENSE file, thus all files
|
||||
under the packages/fork-sax directory are licensed under ISC.
|
||||
|
||||
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.
|
||||
|
||||
* * *
|
||||
|
||||
Logo and Icon License
|
||||
|
||||
The Joplin logos and icons are copyright (c) Laurent Cozic, all rights reserved,
|
||||
and may not be used without a permission. If you would like to use the logos or
|
||||
icons please contact the author in order to get a permission.
|
||||
For example, packages/app-cli does NOT contain a LICENSE file, thus all files
|
||||
under that directory are licensed under the default license, which is MIT.
|
||||
|
||||
* * *
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2021 Laurent Cozic
|
||||
Copyright (c) 2016-2020 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:
|
||||
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.
|
||||
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.
|
||||
@@ -36,7 +36,7 @@ Linux | <a href='https://github.com/laurent22/joplin/releases/download/v2.0.11/J
|
||||
|
||||
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://joplinapp.org/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.1.4/joplin-v2.1.4.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.1.4/joplin-v2.1.4-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://joplinapp.org/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.0.4/joplin-v2.0.4.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.0.4/joplin-v2.0.4-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://joplinapp.org/images/BadgeIOS.png'/></a> | -
|
||||
|
||||
## Terminal application
|
||||
@@ -520,46 +520,46 @@ Current translations:
|
||||
| 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) | 95%
|
||||
<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 | 29%
|
||||
<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 | 30%
|
||||
<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) | 74%
|
||||
<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) | | 57%
|
||||
<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) | jmontane, 2019 | 82%
|
||||
<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) | 99%
|
||||
<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) | 99%
|
||||
<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) | 100%
|
||||
<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) | 100%
|
||||
<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) | Mustafa Al-Dailemi (dailemi@hotmail.com)Language-Team: | 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) | [Atalanttore](mailto:atalanttore@googlemail.com) | 94%
|
||||
<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) | | 56%
|
||||
<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) | 99%
|
||||
<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) | [Mario Campo](mailto:mario.campo@gmail.com) | 94%
|
||||
<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 | 32%
|
||||
<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) | mrkaato | 93%
|
||||
<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) | mrkaato | 94%
|
||||
<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) | 37%
|
||||
<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) | 38%
|
||||
<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) | [eresytter](mailto:42007357+eresytter@users.noreply.github.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) | [Manuel Tassi](mailto:mannivuwiki@gmail.com) | 98%
|
||||
<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) | [Szőke Sándor](mailto:mail@szokesandor.hu) | 87%
|
||||
<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) | 99%
|
||||
<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) | [Szőke Sándor](mailto:mail@szokesandor.hu) | 88%
|
||||
<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) | | 91%
|
||||
<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) | [MetBril](mailto:metbril@users.noreply.github.com) | 94%
|
||||
<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) | 75%
|
||||
<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) | 71%
|
||||
<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) | [konhi](mailto:hello.konhi@gmail.com) | 93%
|
||||
<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) | [Nicolas Suzuki](mailto:nicolas.suzuki@pm.me) | 93%
|
||||
<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) | 93%
|
||||
<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) | [konhi](mailto:hello.konhi@gmail.com) | 94%
|
||||
<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) | [Nicolas Suzuki](mailto:nicolas.suzuki@pm.me) | 94%
|
||||
<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) | 94%
|
||||
<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) | 66%
|
||||
<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) | 94%
|
||||
<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) | 95%
|
||||
<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) | 61%
|
||||
<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) | | 45%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/vi.png" width="16px"/> | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 72%
|
||||
<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) | 93%
|
||||
<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) | 93%
|
||||
<img src="https://joplinapp.org/images/flags/country-4x3/vi.png" width="16px"/> | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 73%
|
||||
<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) | 94%
|
||||
<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) | 94%
|
||||
<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) | 96%
|
||||
<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) | 93%
|
||||
<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) | | 70%
|
||||
<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) | 94%
|
||||
<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) | | 71%
|
||||
<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) | [南宫小骏](mailto:jackytsu@vip.qq.com) | 99%
|
||||
<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) | [Po-Chiang Chao](mailto:BobChao%29%20%28bobchao@gmail.com) | 98%
|
||||
<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) | [Po-Chiang Chao](mailto:BobChao%29%20%28bobchao@gmail.com) | 99%
|
||||
<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) | 96%
|
||||
<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) | 98%
|
||||
<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) | 99%
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
|
||||
# Contributors
|
||||
|
||||
@@ -82,8 +82,6 @@ class Command extends BaseCommand {
|
||||
lines.push('');
|
||||
lines.push('In the documentation below, the token will not be specified every time however you will need to include it.');
|
||||
lines.push('');
|
||||
lines.push('If needed you may also [request the token programmatically](https://github.com/laurent22/joplin/blob/dev/readme/spec/clipper_auth.md)');
|
||||
lines.push('');
|
||||
|
||||
lines.push('# Using the API');
|
||||
lines.push('');
|
||||
@@ -116,7 +114,6 @@ class Command extends BaseCommand {
|
||||
lines.push('\tcurl http://localhost:41184/tags?fields=id');
|
||||
lines.push('');
|
||||
lines.push('By default API results will contain the following fields: **id**, **parent_id**, **title**');
|
||||
lines.push('');
|
||||
|
||||
lines.push('# Pagination');
|
||||
lines.push('');
|
||||
|
||||
@@ -17,7 +17,7 @@ class Command extends BaseCommand {
|
||||
async action(args) {
|
||||
const command = args.command;
|
||||
|
||||
const ClipperServer = require('@joplin/lib/ClipperServer').default;
|
||||
const ClipperServer = require('@joplin/lib/ClipperServer');
|
||||
ClipperServer.instance().initialize();
|
||||
const stdoutFn = (...s) => this.stdout(s.join(' '));
|
||||
const clipperLogger = new Logger();
|
||||
|
||||
@@ -33,7 +33,6 @@ class Command extends BaseCommand {
|
||||
return [
|
||||
['--target <target>', _('Sync to provided target (defaults to sync.target config value)')],
|
||||
['--upgrade', _('Upgrade the sync target to the latest version.')],
|
||||
['--use-lock <value>', 'Disable local locks that prevent multiple clients from synchronizing at the same time (Default = 1)'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -125,21 +124,17 @@ class Command extends BaseCommand {
|
||||
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');
|
||||
|
||||
const useLock = args.options.useLock !== 0;
|
||||
try {
|
||||
if (await Command.isLocked(lockFilePath)) throw new Error(_('Synchronisation is already in progress.'));
|
||||
|
||||
if (useLock) {
|
||||
try {
|
||||
if (await Command.isLocked(lockFilePath)) throw new Error(_('Synchronisation is already in progress.'));
|
||||
|
||||
this.releaseLockFn_ = await Command.lockFile(lockFilePath);
|
||||
} catch (error) {
|
||||
if (error.code == 'ELOCKED') {
|
||||
const msg = _('Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at "%s" and resume the operation.', error.file);
|
||||
this.stdout(msg);
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
this.releaseLockFn_ = await Command.lockFile(lockFilePath);
|
||||
} catch (error) {
|
||||
if (error.code == 'ELOCKED') {
|
||||
const msg = _('Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at "%s" and resume the operation.', error.file);
|
||||
this.stdout(msg);
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
const cleanUp = () => {
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "joplin",
|
||||
"version": "2.1.2",
|
||||
"version": "2.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "2.1.2",
|
||||
"version": "2.1.0",
|
||||
"bin": {
|
||||
"joplin": "./main.js"
|
||||
},
|
||||
@@ -40,8 +40,8 @@
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/lib": "2.1",
|
||||
"@joplin/renderer": "2.1",
|
||||
"@joplin/lib": "2.0",
|
||||
"@joplin/renderer": "2.0",
|
||||
"aws-sdk": "^2.588.0",
|
||||
"chalk": "^4.1.0",
|
||||
"compare-version": "^0.1.2",
|
||||
@@ -65,7 +65,7 @@
|
||||
"yargs-parser": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "2.1",
|
||||
"@joplin/tools": "2.0",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^14.14.6",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<div><br /></div><div style="--en-codeblock:true;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;"><div>public class SwapIntegerWithoutTemp {</div><div><br /></div><div> public void swapAddition() {</div><div> int a = 3;</div><div> int b = 5;</div><div><br /></div><div> a = a + b; // a=8, b=5</div><div> b = a - b; // a=8, b=3</div><div> a = a - b; // a=5, b=3</div><div> }</div><div>}</div></div><div><br /></div>
|
||||
@@ -1,13 +0,0 @@
|
||||
```
|
||||
public class SwapIntegerWithoutTemp {
|
||||
|
||||
public void swapAddition() {
|
||||
int a = 3;
|
||||
int b = 5;
|
||||
|
||||
a = a + b; // a=8, b=5
|
||||
b = a - b; // a=8, b=3
|
||||
a = a - b; // a=5, b=3
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,742 +0,0 @@
|
||||
# Reserved Strings
|
||||
#
|
||||
# Strings which may be used elsewhere in code
|
||||
|
||||
undefined
|
||||
undef
|
||||
null
|
||||
NULL
|
||||
(null)
|
||||
nil
|
||||
NIL
|
||||
true
|
||||
false
|
||||
True
|
||||
False
|
||||
TRUE
|
||||
FALSE
|
||||
None
|
||||
hasOwnProperty
|
||||
then
|
||||
constructor
|
||||
\
|
||||
\\
|
||||
|
||||
# Numeric Strings
|
||||
#
|
||||
# Strings which can be interpreted as numeric
|
||||
|
||||
0
|
||||
1
|
||||
1.00
|
||||
$1.00
|
||||
1/2
|
||||
1E2
|
||||
1E02
|
||||
1E+02
|
||||
-1
|
||||
-1.00
|
||||
-$1.00
|
||||
-1/2
|
||||
-1E2
|
||||
-1E02
|
||||
-1E+02
|
||||
1/0
|
||||
0/0
|
||||
-2147483648/-1
|
||||
-9223372036854775808/-1
|
||||
-0
|
||||
-0.0
|
||||
+0
|
||||
+0.0
|
||||
0.00
|
||||
0..0
|
||||
.
|
||||
0.0.0
|
||||
0,00
|
||||
0,,0
|
||||
,
|
||||
0,0,0
|
||||
0.0/0
|
||||
1.0/0.0
|
||||
0.0/0.0
|
||||
1,0/0,0
|
||||
0,0/0,0
|
||||
--1
|
||||
-
|
||||
-.
|
||||
-,
|
||||
999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
|
||||
NaN
|
||||
Infinity
|
||||
-Infinity
|
||||
INF
|
||||
1#INF
|
||||
-1#IND
|
||||
1#QNAN
|
||||
1#SNAN
|
||||
1#IND
|
||||
0x0
|
||||
0xffffffff
|
||||
0xffffffffffffffff
|
||||
0xabad1dea
|
||||
123456789012345678901234567890123456789
|
||||
1,000.00
|
||||
1 000.00
|
||||
1'000.00
|
||||
1,000,000.00
|
||||
1 000 000.00
|
||||
1'000'000.00
|
||||
1.000,00
|
||||
1 000,00
|
||||
1'000,00
|
||||
1.000.000,00
|
||||
1 000 000,00
|
||||
1'000'000,00
|
||||
01000
|
||||
08
|
||||
09
|
||||
2.2250738585072011e-308
|
||||
|
||||
# Special Characters
|
||||
#
|
||||
# ASCII punctuation. All of these characters may need to be escaped in some
|
||||
# contexts. Divided into three groups based on (US-layout) keyboard position.
|
||||
|
||||
,./;'[]\-=
|
||||
<>?:"{}|_+
|
||||
!@#$%^&*()`~
|
||||
|
||||
# Non-whitespace C0 controls: U+0001 through U+0008, U+000E through U+001F,
|
||||
# and U+007F (DEL)
|
||||
# Often forbidden to appear in various text-based file formats (e.g. XML),
|
||||
# or reused for internal delimiters on the theory that they should never
|
||||
# appear in input.
|
||||
# The next line may appear to be blank or mojibake in some viewers.
|
||||
|
||||
|
||||
# Non-whitespace C1 controls: U+0080 through U+0084 and U+0086 through U+009F.
|
||||
# Commonly misinterpreted as additional graphic characters.
|
||||
# The next line may appear to be blank, mojibake, or dingbats in some viewers.
|
||||
|
||||
|
||||
# Whitespace: all of the characters with category Zs, Zl, or Zp (in Unicode
|
||||
# version 8.0.0), plus U+0009 (HT), U+000B (VT), U+000C (FF), U+0085 (NEL),
|
||||
# and U+200B (ZERO WIDTH SPACE), which are in the C categories but are often
|
||||
# treated as whitespace in some contexts.
|
||||
# This file unfortunately cannot express strings containing
|
||||
# U+0000, U+000A, or U+000D (NUL, LF, CR).
|
||||
# The next line may appear to be blank or mojibake in some viewers.
|
||||
# The next line may be flagged for "trailing whitespace" in some viewers.
|
||||
|
||||
|
||||
# Unicode additional control characters: all of the characters with
|
||||
# general category Cf (in Unicode 8.0.0).
|
||||
# The next line may appear to be blank or mojibake in some viewers.
|
||||
|
||||
|
||||
# "Byte order marks", U+FEFF and U+FFFE, each on its own line.
|
||||
# The next two lines may appear to be blank or mojibake in some viewers.
|
||||
|
||||
|
||||
|
||||
# Unicode Symbols
|
||||
#
|
||||
# Strings which contain common unicode symbols (e.g. smart quotes)
|
||||
|
||||
Ω≈ç√∫˜µ≤≥÷
|
||||
åß∂ƒ©˙∆˚¬…æ
|
||||
œ∑´®†¥¨ˆøπ“‘
|
||||
¡™£¢∞§¶•ªº–≠
|
||||
¸˛Ç◊ı˜Â¯˘¿
|
||||
ÅÍÎÏ˝ÓÔÒÚÆ☃
|
||||
Œ„´‰ˇÁ¨ˆØ∏”’
|
||||
`⁄€‹›fifl‡°·‚—±
|
||||
⅛⅜⅝⅞
|
||||
ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя
|
||||
٠١٢٣٤٥٦٧٨٩
|
||||
|
||||
# Unicode Subscript/Superscript/Accents
|
||||
#
|
||||
# Strings which contain unicode subscripts/superscripts; can cause rendering issues
|
||||
|
||||
⁰⁴⁵
|
||||
₀₁₂
|
||||
⁰⁴⁵₀₁₂
|
||||
ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็
|
||||
|
||||
# Quotation Marks
|
||||
#
|
||||
# Strings which contain misplaced quotation marks; can cause encoding errors
|
||||
|
||||
'
|
||||
"
|
||||
''
|
||||
""
|
||||
'"'
|
||||
"''''"'"
|
||||
"'"'"''''"
|
||||
<foo val=“bar” />
|
||||
<foo val=“bar” />
|
||||
<foo val=”bar“ />
|
||||
<foo val=`bar' />
|
||||
|
||||
# Two-Byte Characters
|
||||
#
|
||||
# Strings which contain two-byte characters: can cause rendering issues or character-length issues
|
||||
|
||||
田中さんにあげて下さい
|
||||
パーティーへ行かないか
|
||||
和製漢語
|
||||
部落格
|
||||
사회과학원 어학연구소
|
||||
찦차를 타고 온 펲시맨과 쑛다리 똠방각하
|
||||
社會科學院語學研究所
|
||||
울란바토르
|
||||
𠜎𠜱𠝹𠱓𠱸𠲖𠳏
|
||||
|
||||
# Strings which contain two-byte letters: can cause issues with naïve UTF-16 capitalizers which think that 16 bits == 1 character
|
||||
|
||||
𐐜 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐙𐐊𐐡𐐝𐐓/𐐝𐐇𐐗𐐊𐐤𐐔 𐐒𐐋𐐗 𐐒𐐌 𐐜 𐐡𐐀𐐖𐐇𐐤𐐓𐐝 𐐱𐑂 𐑄 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐏𐐆𐐅𐐤𐐆𐐚𐐊𐐡𐐝𐐆𐐓𐐆
|
||||
|
||||
# Special Unicode Characters Union
|
||||
#
|
||||
# A super string recommended by VMware Inc. Globalization Team: can effectively cause rendering issues or character-length issues to validate product globalization readiness.
|
||||
#
|
||||
# 表 CJK_UNIFIED_IDEOGRAPHS (U+8868)
|
||||
# ポ KATAKANA LETTER PO (U+30DD)
|
||||
# あ HIRAGANA LETTER A (U+3042)
|
||||
# A LATIN CAPITAL LETTER A (U+0041)
|
||||
# 鷗 CJK_UNIFIED_IDEOGRAPHS (U+9DD7)
|
||||
# Œ LATIN SMALL LIGATURE OE (U+0153)
|
||||
# é LATIN SMALL LETTER E WITH ACUTE (U+00E9)
|
||||
# B FULLWIDTH LATIN CAPITAL LETTER B (U+FF22)
|
||||
# 逍 CJK_UNIFIED_IDEOGRAPHS (U+900D)
|
||||
# Ü LATIN SMALL LETTER U WITH DIAERESIS (U+00FC)
|
||||
# ß LATIN SMALL LETTER SHARP S (U+00DF)
|
||||
# ª FEMININE ORDINAL INDICATOR (U+00AA)
|
||||
# ą LATIN SMALL LETTER A WITH OGONEK (U+0105)
|
||||
# ñ LATIN SMALL LETTER N WITH TILDE (U+00F1)
|
||||
# 丂 CJK_UNIFIED_IDEOGRAPHS (U+4E02)
|
||||
# 㐀 CJK Ideograph Extension A, First (U+3400)
|
||||
# 𠀀 CJK Ideograph Extension B, First (U+20000)
|
||||
|
||||
表ポあA鷗ŒéB逍Üߪąñ丂㐀𠀀
|
||||
|
||||
# Changing length when lowercased
|
||||
#
|
||||
# Characters which increase in length (2 to 3 bytes) when lowercased
|
||||
# Credit: https://twitter.com/jifa/status/625776454479970304
|
||||
|
||||
Ⱥ
|
||||
Ⱦ
|
||||
|
||||
# Japanese Emoticons
|
||||
#
|
||||
# Strings which consists of Japanese-style emoticons which are popular on the web
|
||||
|
||||
ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ
|
||||
(。◕ ∀ ◕。)
|
||||
`ィ(´∀`∩
|
||||
__ロ(,_,*)
|
||||
・( ̄∀ ̄)・:*:
|
||||
゚・✿ヾ╲(。◕‿◕。)╱✿・゚
|
||||
,。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’
|
||||
(╯°□°)╯︵ ┻━┻)
|
||||
(ノಥ益ಥ)ノ ┻━┻
|
||||
┬─┬ノ( º _ ºノ)
|
||||
( ͡° ͜ʖ ͡°)
|
||||
¯\_(ツ)_/¯
|
||||
|
||||
# Emoji
|
||||
#
|
||||
# Strings which contain Emoji; should be the same behavior as two-byte characters, but not always
|
||||
|
||||
😍
|
||||
👩🏽
|
||||
👨🦰 👨🏿🦰 👨🦱 👨🏿🦱 🦹🏿♂️
|
||||
👾 🙇 💁 🙅 🙆 🙋 🙎 🙍
|
||||
🐵 🙈 🙉 🙊
|
||||
❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙
|
||||
✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿
|
||||
👨👩👦 👨👩👧👦 👨👨👦 👩👩👧 👨👦 👨👧👦 👩👦 👩👧👦
|
||||
🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧
|
||||
0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟
|
||||
|
||||
# Regional Indicator Symbols
|
||||
#
|
||||
# Regional Indicator Symbols can be displayed differently across
|
||||
# fonts, and have a number of special behaviors
|
||||
|
||||
🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸
|
||||
🇺🇸🇷🇺🇸🇦🇫🇦🇲
|
||||
🇺🇸🇷🇺🇸🇦
|
||||
|
||||
# Unicode Numbers
|
||||
#
|
||||
# Strings which contain unicode numbers; if the code is localized, it should see the input as numeric
|
||||
|
||||
123
|
||||
١٢٣
|
||||
|
||||
# Right-To-Left Strings
|
||||
#
|
||||
# Strings which contain text that should be rendered RTL if possible (e.g. Arabic, Hebrew)
|
||||
|
||||
ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو.
|
||||
בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ
|
||||
הָיְתָהtestالصفحات التّحول
|
||||
﷽
|
||||
ﷺ
|
||||
مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ،
|
||||
الكل في المجمو عة (5)
|
||||
|
||||
# Ogham Text
|
||||
#
|
||||
# The only unicode alphabet to use a space which isn't empty but should still act like a space.
|
||||
|
||||
᚛ᚄᚓᚐᚋᚒᚄ ᚑᚄᚂᚑᚏᚅ᚜
|
||||
᚛ ᚜
|
||||
|
||||
# Trick Unicode
|
||||
#
|
||||
# Strings which contain unicode with unusual properties (e.g. Right-to-left override) (c.f. http://www.unicode.org/charts/PDF/U2000.pdf)
|
||||
|
||||
test
|
||||
test
|
||||
test
|
||||
testtest
|
||||
test
|
||||
|
||||
# Zalgo Text
|
||||
#
|
||||
# Strings which contain "corrupted" text. The corruption will not appear in non-HTML text, however. (via http://www.eeemo.net)
|
||||
|
||||
Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣
|
||||
̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰
|
||||
̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟
|
||||
̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕
|
||||
Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮
|
||||
|
||||
# Unicode Upsidedown
|
||||
#
|
||||
# Strings which contain unicode with an "upsidedown" effect (via http://www.upsidedowntext.com)
|
||||
|
||||
˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥
|
||||
00˙Ɩ$-
|
||||
|
||||
# Unicode font
|
||||
#
|
||||
# Strings which contain bold/italic/etc. versions of normal characters
|
||||
|
||||
The quick brown fox jumps over the lazy dog
|
||||
𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠
|
||||
𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌
|
||||
𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈
|
||||
𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰
|
||||
𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘
|
||||
𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐
|
||||
⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢
|
||||
|
||||
# Script Injection
|
||||
#
|
||||
# Strings which attempt to invoke a benign script injection; shows vulnerability to XSS
|
||||
|
||||
<script>alert(0)</script>
|
||||
<script>alert('1');</script>
|
||||
<img src=x onerror=alert(2) />
|
||||
<svg><script>123<1>alert(3)</script>
|
||||
"><script>alert(4)</script>
|
||||
'><script>alert(5)</script>
|
||||
><script>alert(6)</script>
|
||||
</script><script>alert(7)</script>
|
||||
< / script >< script >alert(8)< / script >
|
||||
onfocus=JaVaSCript:alert(9) autofocus
|
||||
" onfocus=JaVaSCript:alert(10) autofocus
|
||||
' onfocus=JaVaSCript:alert(11) autofocus
|
||||
<script>alert(12)</script>
|
||||
<sc<script>ript>alert(13)</sc</script>ript>
|
||||
--><script>alert(14)</script>
|
||||
";alert(15);t="
|
||||
';alert(16);t='
|
||||
JavaSCript:alert(17)
|
||||
;alert(18);
|
||||
src=JaVaSCript:prompt(19)
|
||||
"><script>alert(20);</script x="
|
||||
'><script>alert(21);</script x='
|
||||
><script>alert(22);</script x=
|
||||
" autofocus onkeyup="javascript:alert(23)
|
||||
' autofocus onkeyup='javascript:alert(24)
|
||||
<script\x20type="text/javascript">javascript:alert(25);</script>
|
||||
<script\x3Etype="text/javascript">javascript:alert(26);</script>
|
||||
<script\x0Dtype="text/javascript">javascript:alert(27);</script>
|
||||
<script\x09type="text/javascript">javascript:alert(28);</script>
|
||||
<script\x0Ctype="text/javascript">javascript:alert(29);</script>
|
||||
<script\x2Ftype="text/javascript">javascript:alert(30);</script>
|
||||
<script\x0Atype="text/javascript">javascript:alert(31);</script>
|
||||
'`"><\x3Cscript>javascript:alert(32)</script>
|
||||
'`"><\x00script>javascript:alert(33)</script>
|
||||
ABC<div style="x\x3Aexpression(javascript:alert(34)">DEF
|
||||
ABC<div style="x:expression\x5C(javascript:alert(35)">DEF
|
||||
ABC<div style="x:expression\x00(javascript:alert(36)">DEF
|
||||
ABC<div style="x:exp\x00ression(javascript:alert(37)">DEF
|
||||
ABC<div style="x:exp\x5Cression(javascript:alert(38)">DEF
|
||||
ABC<div style="x:\x0Aexpression(javascript:alert(39)">DEF
|
||||
ABC<div style="x:\x09expression(javascript:alert(40)">DEF
|
||||
ABC<div style="x:\xE3\x80\x80expression(javascript:alert(41)">DEF
|
||||
ABC<div style="x:\xE2\x80\x84expression(javascript:alert(42)">DEF
|
||||
ABC<div style="x:\xC2\xA0expression(javascript:alert(43)">DEF
|
||||
ABC<div style="x:\xE2\x80\x80expression(javascript:alert(44)">DEF
|
||||
ABC<div style="x:\xE2\x80\x8Aexpression(javascript:alert(45)">DEF
|
||||
ABC<div style="x:\x0Dexpression(javascript:alert(46)">DEF
|
||||
ABC<div style="x:\x0Cexpression(javascript:alert(47)">DEF
|
||||
ABC<div style="x:\xE2\x80\x87expression(javascript:alert(48)">DEF
|
||||
ABC<div style="x:\xEF\xBB\xBFexpression(javascript:alert(49)">DEF
|
||||
ABC<div style="x:\x20expression(javascript:alert(50)">DEF
|
||||
ABC<div style="x:\xE2\x80\x88expression(javascript:alert(51)">DEF
|
||||
ABC<div style="x:\x00expression(javascript:alert(52)">DEF
|
||||
ABC<div style="x:\xE2\x80\x8Bexpression(javascript:alert(53)">DEF
|
||||
ABC<div style="x:\xE2\x80\x86expression(javascript:alert(54)">DEF
|
||||
ABC<div style="x:\xE2\x80\x85expression(javascript:alert(55)">DEF
|
||||
ABC<div style="x:\xE2\x80\x82expression(javascript:alert(56)">DEF
|
||||
ABC<div style="x:\x0Bexpression(javascript:alert(57)">DEF
|
||||
ABC<div style="x:\xE2\x80\x81expression(javascript:alert(58)">DEF
|
||||
ABC<div style="x:\xE2\x80\x83expression(javascript:alert(59)">DEF
|
||||
ABC<div style="x:\xE2\x80\x89expression(javascript:alert(60)">DEF
|
||||
<a href="\x0Bjavascript:javascript:alert(61)" id="fuzzelement1">test</a>
|
||||
<a href="\x0Fjavascript:javascript:alert(62)" id="fuzzelement1">test</a>
|
||||
<a href="\xC2\xA0javascript:javascript:alert(63)" id="fuzzelement1">test</a>
|
||||
<a href="\x05javascript:javascript:alert(64)" id="fuzzelement1">test</a>
|
||||
<a href="\xE1\xA0\x8Ejavascript:javascript:alert(65)" id="fuzzelement1">test</a>
|
||||
<a href="\x18javascript:javascript:alert(66)" id="fuzzelement1">test</a>
|
||||
<a href="\x11javascript:javascript:alert(67)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x88javascript:javascript:alert(68)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x89javascript:javascript:alert(69)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x80javascript:javascript:alert(70)" id="fuzzelement1">test</a>
|
||||
<a href="\x17javascript:javascript:alert(71)" id="fuzzelement1">test</a>
|
||||
<a href="\x03javascript:javascript:alert(72)" id="fuzzelement1">test</a>
|
||||
<a href="\x0Ejavascript:javascript:alert(73)" id="fuzzelement1">test</a>
|
||||
<a href="\x1Ajavascript:javascript:alert(74)" id="fuzzelement1">test</a>
|
||||
<a href="\x00javascript:javascript:alert(75)" id="fuzzelement1">test</a>
|
||||
<a href="\x10javascript:javascript:alert(76)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x82javascript:javascript:alert(77)" id="fuzzelement1">test</a>
|
||||
<a href="\x20javascript:javascript:alert(78)" id="fuzzelement1">test</a>
|
||||
<a href="\x13javascript:javascript:alert(79)" id="fuzzelement1">test</a>
|
||||
<a href="\x09javascript:javascript:alert(80)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x8Ajavascript:javascript:alert(81)" id="fuzzelement1">test</a>
|
||||
<a href="\x14javascript:javascript:alert(82)" id="fuzzelement1">test</a>
|
||||
<a href="\x19javascript:javascript:alert(83)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\xAFjavascript:javascript:alert(84)" id="fuzzelement1">test</a>
|
||||
<a href="\x1Fjavascript:javascript:alert(85)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x81javascript:javascript:alert(86)" id="fuzzelement1">test</a>
|
||||
<a href="\x1Djavascript:javascript:alert(87)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x87javascript:javascript:alert(88)" id="fuzzelement1">test</a>
|
||||
<a href="\x07javascript:javascript:alert(89)" id="fuzzelement1">test</a>
|
||||
<a href="\xE1\x9A\x80javascript:javascript:alert(90)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x83javascript:javascript:alert(91)" id="fuzzelement1">test</a>
|
||||
<a href="\x04javascript:javascript:alert(92)" id="fuzzelement1">test</a>
|
||||
<a href="\x01javascript:javascript:alert(93)" id="fuzzelement1">test</a>
|
||||
<a href="\x08javascript:javascript:alert(94)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x84javascript:javascript:alert(95)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x86javascript:javascript:alert(96)" id="fuzzelement1">test</a>
|
||||
<a href="\xE3\x80\x80javascript:javascript:alert(97)" id="fuzzelement1">test</a>
|
||||
<a href="\x12javascript:javascript:alert(98)" id="fuzzelement1">test</a>
|
||||
<a href="\x0Djavascript:javascript:alert(99)" id="fuzzelement1">test</a>
|
||||
<a href="\x0Ajavascript:javascript:alert(100)" id="fuzzelement1">test</a>
|
||||
<a href="\x0Cjavascript:javascript:alert(101)" id="fuzzelement1">test</a>
|
||||
<a href="\x15javascript:javascript:alert(102)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\xA8javascript:javascript:alert(103)" id="fuzzelement1">test</a>
|
||||
<a href="\x16javascript:javascript:alert(104)" id="fuzzelement1">test</a>
|
||||
<a href="\x02javascript:javascript:alert(105)" id="fuzzelement1">test</a>
|
||||
<a href="\x1Bjavascript:javascript:alert(106)" id="fuzzelement1">test</a>
|
||||
<a href="\x06javascript:javascript:alert(107)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\xA9javascript:javascript:alert(108)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x80\x85javascript:javascript:alert(109)" id="fuzzelement1">test</a>
|
||||
<a href="\x1Ejavascript:javascript:alert(110)" id="fuzzelement1">test</a>
|
||||
<a href="\xE2\x81\x9Fjavascript:javascript:alert(111)" id="fuzzelement1">test</a>
|
||||
<a href="\x1Cjavascript:javascript:alert(112)" id="fuzzelement1">test</a>
|
||||
<a href="javascript\x00:javascript:alert(113)" id="fuzzelement1">test</a>
|
||||
<a href="javascript\x3A:javascript:alert(114)" id="fuzzelement1">test</a>
|
||||
<a href="javascript\x09:javascript:alert(115)" id="fuzzelement1">test</a>
|
||||
<a href="javascript\x0D:javascript:alert(116)" id="fuzzelement1">test</a>
|
||||
<a href="javascript\x0A:javascript:alert(117)" id="fuzzelement1">test</a>
|
||||
`"'><img src=xxx:x \x0Aonerror=javascript:alert(118)>
|
||||
`"'><img src=xxx:x \x22onerror=javascript:alert(119)>
|
||||
`"'><img src=xxx:x \x0Bonerror=javascript:alert(120)>
|
||||
`"'><img src=xxx:x \x0Donerror=javascript:alert(121)>
|
||||
`"'><img src=xxx:x \x2Fonerror=javascript:alert(122)>
|
||||
`"'><img src=xxx:x \x09onerror=javascript:alert(123)>
|
||||
`"'><img src=xxx:x \x0Conerror=javascript:alert(124)>
|
||||
`"'><img src=xxx:x \x00onerror=javascript:alert(125)>
|
||||
`"'><img src=xxx:x \x27onerror=javascript:alert(126)>
|
||||
`"'><img src=xxx:x \x20onerror=javascript:alert(127)>
|
||||
"`'><script>\x3Bjavascript:alert(128)</script>
|
||||
"`'><script>\x0Djavascript:alert(129)</script>
|
||||
"`'><script>\xEF\xBB\xBFjavascript:alert(130)</script>
|
||||
"`'><script>\xE2\x80\x81javascript:alert(131)</script>
|
||||
"`'><script>\xE2\x80\x84javascript:alert(132)</script>
|
||||
"`'><script>\xE3\x80\x80javascript:alert(133)</script>
|
||||
"`'><script>\x09javascript:alert(134)</script>
|
||||
"`'><script>\xE2\x80\x89javascript:alert(135)</script>
|
||||
"`'><script>\xE2\x80\x85javascript:alert(136)</script>
|
||||
"`'><script>\xE2\x80\x88javascript:alert(137)</script>
|
||||
"`'><script>\x00javascript:alert(138)</script>
|
||||
"`'><script>\xE2\x80\xA8javascript:alert(139)</script>
|
||||
"`'><script>\xE2\x80\x8Ajavascript:alert(140)</script>
|
||||
"`'><script>\xE1\x9A\x80javascript:alert(141)</script>
|
||||
"`'><script>\x0Cjavascript:alert(142)</script>
|
||||
"`'><script>\x2Bjavascript:alert(143)</script>
|
||||
"`'><script>\xF0\x90\x96\x9Ajavascript:alert(144)</script>
|
||||
"`'><script>-javascript:alert(145)</script>
|
||||
"`'><script>\x0Ajavascript:alert(146)</script>
|
||||
"`'><script>\xE2\x80\xAFjavascript:alert(147)</script>
|
||||
"`'><script>\x7Ejavascript:alert(148)</script>
|
||||
"`'><script>\xE2\x80\x87javascript:alert(149)</script>
|
||||
"`'><script>\xE2\x81\x9Fjavascript:alert(150)</script>
|
||||
"`'><script>\xE2\x80\xA9javascript:alert(151)</script>
|
||||
"`'><script>\xC2\x85javascript:alert(152)</script>
|
||||
"`'><script>\xEF\xBF\xAEjavascript:alert(153)</script>
|
||||
"`'><script>\xE2\x80\x83javascript:alert(154)</script>
|
||||
"`'><script>\xE2\x80\x8Bjavascript:alert(155)</script>
|
||||
"`'><script>\xEF\xBF\xBEjavascript:alert(156)</script>
|
||||
"`'><script>\xE2\x80\x80javascript:alert(157)</script>
|
||||
"`'><script>\x21javascript:alert(158)</script>
|
||||
"`'><script>\xE2\x80\x82javascript:alert(159)</script>
|
||||
"`'><script>\xE2\x80\x86javascript:alert(160)</script>
|
||||
"`'><script>\xE1\xA0\x8Ejavascript:alert(161)</script>
|
||||
"`'><script>\x0Bjavascript:alert(162)</script>
|
||||
"`'><script>\x20javascript:alert(163)</script>
|
||||
"`'><script>\xC2\xA0javascript:alert(164)</script>
|
||||
<img \x00src=x onerror="alert(165)">
|
||||
<img \x47src=x onerror="javascript:alert(166)">
|
||||
<img \x11src=x onerror="javascript:alert(167)">
|
||||
<img \x12src=x onerror="javascript:alert(168)">
|
||||
<img\x47src=x onerror="javascript:alert(169)">
|
||||
<img\x10src=x onerror="javascript:alert(170)">
|
||||
<img\x13src=x onerror="javascript:alert(171)">
|
||||
<img\x32src=x onerror="javascript:alert(172)">
|
||||
<img\x47src=x onerror="javascript:alert(173)">
|
||||
<img\x11src=x onerror="javascript:alert(174)">
|
||||
<img \x47src=x onerror="javascript:alert(175)">
|
||||
<img \x34src=x onerror="javascript:alert(176)">
|
||||
<img \x39src=x onerror="javascript:alert(177)">
|
||||
<img \x00src=x onerror="javascript:alert(178)">
|
||||
<img src\x09=x onerror="javascript:alert(179)">
|
||||
<img src\x10=x onerror="javascript:alert(180)">
|
||||
<img src\x13=x onerror="javascript:alert(181)">
|
||||
<img src\x32=x onerror="javascript:alert(182)">
|
||||
<img src\x12=x onerror="javascript:alert(183)">
|
||||
<img src\x11=x onerror="javascript:alert(184)">
|
||||
<img src\x00=x onerror="javascript:alert(185)">
|
||||
<img src\x47=x onerror="javascript:alert(186)">
|
||||
<img src=x\x09onerror="javascript:alert(187)">
|
||||
<img src=x\x10onerror="javascript:alert(188)">
|
||||
<img src=x\x11onerror="javascript:alert(189)">
|
||||
<img src=x\x12onerror="javascript:alert(190)">
|
||||
<img src=x\x13onerror="javascript:alert(191)">
|
||||
<img[a][b][c]src[d]=x[e]onerror=[f]"alert(192)">
|
||||
<img src=x onerror=\x09"javascript:alert(193)">
|
||||
<img src=x onerror=\x10"javascript:alert(194)">
|
||||
<img src=x onerror=\x11"javascript:alert(195)">
|
||||
<img src=x onerror=\x12"javascript:alert(196)">
|
||||
<img src=x onerror=\x32"javascript:alert(197)">
|
||||
<img src=x onerror=\x00"javascript:alert(198)">
|
||||
<a href=javascript:javascript:alert(199)>XXX</a>
|
||||
<img src="x` `<script>javascript:alert(200)</script>"` `>
|
||||
<img src onerror /" '"= alt=javascript:alert(201)//">
|
||||
<title onpropertychange=javascript:alert(202)></title><title title=>
|
||||
<a href=http://foo.bar/#x=`y></a><img alt="`><img src=x:x onerror=javascript:alert(203)></a>">
|
||||
<!--[if]><script>javascript:alert(204)</script -->
|
||||
<!--[if<img src=x onerror=javascript:alert(205)//]> -->
|
||||
<script src="/\%(jscript)s"></script>
|
||||
<script src="\\%(jscript)s"></script>
|
||||
<IMG """><SCRIPT>alert("206")</SCRIPT>">
|
||||
<IMG SRC=javascript:alert(String.fromCharCode(50,48,55))>
|
||||
<IMG SRC=# onmouseover="alert('208')">
|
||||
<IMG SRC= onmouseover="alert('209')">
|
||||
<IMG onmouseover="alert('210')">
|
||||
<IMG SRC=javascript:alert('211')>
|
||||
<IMG SRC=javascript:alert('212')>
|
||||
<IMG SRC=javascript:alert('213')>
|
||||
<IMG SRC="jav ascript:alert('214');">
|
||||
<IMG SRC="jav	ascript:alert('215');">
|
||||
<IMG SRC="jav
ascript:alert('216');">
|
||||
<IMG SRC="jav
ascript:alert('217');">
|
||||
perl -e 'print "<IMG SRC=java\0script:alert(\"218\")>";' > out
|
||||
<IMG SRC="  javascript:alert('219');">
|
||||
<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>
|
||||
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("220")>
|
||||
<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>
|
||||
<<SCRIPT>alert("221");//<</SCRIPT>
|
||||
<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >
|
||||
<SCRIPT SRC=//ha.ckers.org/.j>
|
||||
<IMG SRC="javascript:alert('222')"
|
||||
<iframe src=http://ha.ckers.org/scriptlet.html <
|
||||
\";alert('223');//
|
||||
<u oncopy=alert()> Copy me</u>
|
||||
<i onwheel=alert(224)> Scroll over me </i>
|
||||
<plaintext>
|
||||
http://a/%%30%30
|
||||
</textarea><script>alert(225)</script>
|
||||
|
||||
# SQL Injection
|
||||
#
|
||||
# Strings which can cause a SQL injection if inputs are not sanitized
|
||||
|
||||
1;DROP TABLE users
|
||||
1'; DROP TABLE users-- 1
|
||||
' OR 1=1 -- 1
|
||||
' OR '1'='1
|
||||
'; EXEC sp_MSForEachTable 'DROP TABLE ?'; --
|
||||
|
||||
%
|
||||
_
|
||||
|
||||
# Server Code Injection
|
||||
#
|
||||
# Strings which can cause user to run code on server as a privileged user (c.f. https://news.ycombinator.com/item?id=7665153)
|
||||
|
||||
-
|
||||
--
|
||||
--version
|
||||
--help
|
||||
$USER
|
||||
/dev/null; touch /tmp/blns.fail ; echo
|
||||
`touch /tmp/blns.fail`
|
||||
$(touch /tmp/blns.fail)
|
||||
@{[system "touch /tmp/blns.fail"]}
|
||||
|
||||
# Command Injection (Ruby)
|
||||
#
|
||||
# Strings which can call system commands within Ruby/Rails applications
|
||||
|
||||
eval("puts 'hello world'")
|
||||
System("ls -al /")
|
||||
`ls -al /`
|
||||
Kernel.exec("ls -al /")
|
||||
Kernel.exit(1)
|
||||
%x('ls -al /')
|
||||
|
||||
# XXE Injection (XML)
|
||||
#
|
||||
# String which can reveal system files when parsed by a badly configured XML parser
|
||||
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>
|
||||
|
||||
# Unwanted Interpolation
|
||||
#
|
||||
# Strings which can be accidentally expanded into different strings if evaluated in the wrong context, e.g. used as a printf format string or via Perl or shell eval. Might expose sensitive data from the program doing the interpolation, or might just represent the wrong string.
|
||||
|
||||
$HOME
|
||||
$ENV{'HOME'}
|
||||
%d
|
||||
%s%s%s%s%s
|
||||
{0}
|
||||
%*.*s
|
||||
%@
|
||||
%n
|
||||
File:///
|
||||
|
||||
# File Inclusion
|
||||
#
|
||||
# Strings which can cause user to pull in files that should not be a part of a web server
|
||||
|
||||
../../../../../../../../../../../etc/passwd%00
|
||||
../../../../../../../../../../../etc/hosts
|
||||
|
||||
# Known CVEs and Vulnerabilities
|
||||
#
|
||||
# Strings that test for known vulnerabilities
|
||||
|
||||
() { 0; }; touch /tmp/blns.shellshock1.fail;
|
||||
() { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; }
|
||||
<<< %s(un='%s') = %u
|
||||
+++ATH0
|
||||
|
||||
# MSDOS/Windows Special Filenames
|
||||
#
|
||||
# Strings which are reserved characters in MSDOS/Windows
|
||||
|
||||
CON
|
||||
PRN
|
||||
AUX
|
||||
CLOCK$
|
||||
NUL
|
||||
A:
|
||||
ZZ:
|
||||
COM1
|
||||
LPT1
|
||||
LPT2
|
||||
LPT3
|
||||
COM2
|
||||
COM3
|
||||
COM4
|
||||
|
||||
# IRC specific strings
|
||||
#
|
||||
# Strings that may occur on IRC clients that make security products freak out
|
||||
|
||||
DCC SEND STARTKEYLOGGER 0 0 0
|
||||
|
||||
# Scunthorpe Problem
|
||||
#
|
||||
# Innocuous strings which may be blocked by profanity filters (https://en.wikipedia.org/wiki/Scunthorpe_problem)
|
||||
|
||||
Scunthorpe General Hospital
|
||||
Penistone Community Church
|
||||
Lightwater Country Park
|
||||
Jimmy Clitheroe
|
||||
Horniman Museum
|
||||
shitake mushrooms
|
||||
RomansInSussex.co.uk
|
||||
http://www.cum.qc.ca/
|
||||
Craig Cockburn, Software Specialist
|
||||
Linda Callahan
|
||||
Dr. Herman I. Libshitz
|
||||
magna cum laude
|
||||
Super Bowl XXX
|
||||
medieval erection of parapets
|
||||
evaluate
|
||||
mocha
|
||||
expression
|
||||
Arsenal canal
|
||||
classic
|
||||
Tyson Gay
|
||||
Dick Van Dyke
|
||||
basement
|
||||
|
||||
# Human injection
|
||||
#
|
||||
# Strings which may cause human to reinterpret worldview
|
||||
|
||||
If you're reading this, you've been in a coma for almost 20 years now. We're trying a new technique. We don't know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.
|
||||
|
||||
# Terminal escape codes
|
||||
#
|
||||
# Strings which punish the fools who use cat/type on this file
|
||||
|
||||
Roses are [0;31mred[0m, violets are [0;34mblue. Hope you enjoy terminal hue
|
||||
But now...[20Cfor my greatest trick...[8m
|
||||
The quick brown fox... [Beeeep]
|
||||
|
||||
# iOS Vulnerabilities
|
||||
#
|
||||
# Strings which crashed iMessage in various versions of iOS
|
||||
|
||||
Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗
|
||||
🏳0🌈️
|
||||
జ్ఞా
|
||||
|
||||
# Persian special characters
|
||||
#
|
||||
# This is a four characters string which includes Persian special characters (گچپژ)
|
||||
|
||||
گچپژ
|
||||
|
||||
# jinja2 injection
|
||||
#
|
||||
# first one is supposed to raise "MemoryError" exception
|
||||
# second, obviously, prints contents of /etc/passwd
|
||||
|
||||
{% print 'x' * 64 * 1024**3 %}
|
||||
{{ "".__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read() }}
|
||||
@@ -1,3 +0,0 @@
|
||||
dist/
|
||||
node_modules/
|
||||
publish/
|
||||
@@ -1,8 +0,0 @@
|
||||
*.md
|
||||
!README.md
|
||||
/*.jpl
|
||||
/api
|
||||
/src
|
||||
/dist
|
||||
tsconfig.json
|
||||
webpack.config.js
|
||||
@@ -1,72 +0,0 @@
|
||||
# generator-joplin
|
||||
|
||||
Scaffolds out a new Joplin plugin
|
||||
|
||||
## Installation
|
||||
|
||||
First, install [Yeoman](http://yeoman.io) and generator-joplin using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)).
|
||||
|
||||
```bash
|
||||
npm install -g yo
|
||||
npm install -g generator-joplin
|
||||
```
|
||||
|
||||
Then generate your new project:
|
||||
|
||||
```bash
|
||||
yo joplin
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
To test the generator for development purposes, follow the instructions there: https://yeoman.io/authoring/#running-the-generator
|
||||
This is a template to create a new Joplin plugin.
|
||||
|
||||
## Structure
|
||||
|
||||
The main two files you will want to look at are:
|
||||
|
||||
- `/src/index.ts`, which contains the entry point for the plugin source code.
|
||||
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
|
||||
|
||||
The file `/plugin.config.json` could also be useful if you intend to use [external scripts](#external-script-files), such as content scripts or webview scripts.
|
||||
|
||||
## Building the plugin
|
||||
|
||||
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
|
||||
|
||||
To build the plugin, simply run `npm run dist`.
|
||||
|
||||
The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
|
||||
|
||||
## Publishing the plugin
|
||||
|
||||
To publish the plugin, add it to npmjs.com by running `npm publish`. Later on, a script will pick up your plugin and add it automatically to the Joplin plugin repository as long as the package satisfies these conditions:
|
||||
|
||||
- In `package.json`, the name starts with "joplin-plugin-". For example, "joplin-plugin-toc".
|
||||
- In `package.json`, the keywords include "joplin-plugin".
|
||||
- In the `publish/` directory, there should be a .jpl and .json file (which are built by `npm run dist`)
|
||||
|
||||
In general all this is done automatically by the plugin generator, which will set the name and keywords of package.json, and will put the right files in the "publish" directory. But if something doesn't work and your plugin doesn't appear in the repository, double-check the above conditions.
|
||||
|
||||
## Updating the plugin framework
|
||||
|
||||
To update the plugin framework, run `npm run update`.
|
||||
|
||||
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
|
||||
|
||||
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
|
||||
|
||||
## External script files
|
||||
|
||||
By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
|
||||
|
||||
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
|
||||
|
||||
- The script requires modules you've added to package.json. In that case, the script, whether JS or TS, must be compiled so that the dependencies are bundled with the JPL file.
|
||||
|
||||
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
|
||||
|
||||
## License
|
||||
|
||||
MIT © Laurent Cozic
|
||||
@@ -1,24 +0,0 @@
|
||||
# Joplin Plugin
|
||||
|
||||
This is a template to create a new Joplin plugin.
|
||||
|
||||
The main two files you will want to look at are:
|
||||
|
||||
- `/src/index.ts`, which contains the entry point for the plugin source code.
|
||||
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
|
||||
|
||||
## Building the plugin
|
||||
|
||||
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
|
||||
|
||||
To build the plugin, simply run `npm run dist`.
|
||||
|
||||
The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
|
||||
|
||||
## Updating the plugin framework
|
||||
|
||||
To update the plugin framework, run `npm run update`.
|
||||
|
||||
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
|
||||
|
||||
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
|
||||
@@ -1,14 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import Joplin from './Joplin';
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
export default class Global {
|
||||
private joplin_;
|
||||
constructor(implementation: any, plugin: Plugin, store: any);
|
||||
get joplin(): Joplin;
|
||||
get process(): any;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import JoplinData from './JoplinData';
|
||||
import JoplinPlugins from './JoplinPlugins';
|
||||
import JoplinWorkspace from './JoplinWorkspace';
|
||||
import JoplinFilters from './JoplinFilters';
|
||||
import JoplinCommands from './JoplinCommands';
|
||||
import JoplinViews from './JoplinViews';
|
||||
import JoplinInterop from './JoplinInterop';
|
||||
import JoplinSettings from './JoplinSettings';
|
||||
import JoplinContentScripts from './JoplinContentScripts';
|
||||
/**
|
||||
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
|
||||
*
|
||||
* **This is a beta API**
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* - Maintain backward compatibility;
|
||||
* - When possible, deprecate features instead of removing them;
|
||||
* - 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.
|
||||
*/
|
||||
export default class Joplin {
|
||||
private data_;
|
||||
private plugins_;
|
||||
private workspace_;
|
||||
private filters_;
|
||||
private commands_;
|
||||
private views_;
|
||||
private interop_;
|
||||
private settings_;
|
||||
private contentScripts_;
|
||||
constructor(implementation: any, plugin: Plugin, store: any);
|
||||
get data(): JoplinData;
|
||||
get plugins(): JoplinPlugins;
|
||||
get workspace(): JoplinWorkspace;
|
||||
get contentScripts(): JoplinContentScripts;
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* Not sure if it's the best way to hook into the app
|
||||
* so for now disable filters.
|
||||
*/
|
||||
get filters(): JoplinFilters;
|
||||
get commands(): JoplinCommands;
|
||||
get views(): JoplinViews;
|
||||
get interop(): JoplinInterop;
|
||||
get settings(): JoplinSettings;
|
||||
/**
|
||||
* It is not possible to bundle native packages with a plugin, because they
|
||||
* need to work cross-platforms. Instead access to certain useful native
|
||||
* packages is provided using this function.
|
||||
*
|
||||
* Currently these packages are available:
|
||||
*
|
||||
* - [sqlite3](https://www.npmjs.com/package/sqlite3)
|
||||
* - [fs-extra](https://www.npmjs.com/package/fs-extra)
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
|
||||
*/
|
||||
require(_path: string): any;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import { Command } from './types';
|
||||
/**
|
||||
* This class allows executing or registering new Joplin commands. Commands
|
||||
* can be executed or associated with
|
||||
* {@link JoplinViewsToolbarButtons | toolbar buttons} or
|
||||
* {@link JoplinViewsMenuItems | menu items}.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
|
||||
*
|
||||
* ## Executing Joplin's internal commands
|
||||
*
|
||||
* It is also possible to execute internal Joplin's commands which, as of
|
||||
* now, are not well documented. You can find the list directly on GitHub
|
||||
* though at the following locations:
|
||||
*
|
||||
* * [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)
|
||||
*
|
||||
* To view what arguments are supported, you can open any of these files
|
||||
* and look at the `execute()` command.
|
||||
*
|
||||
* ## Executing editor commands
|
||||
*
|
||||
* There might be a situation where you want to invoke editor commands
|
||||
* without using a {@link JoplinContentScripts | contentScript}. For this
|
||||
* reason Joplin provides the built in `editor.execCommand` command.
|
||||
*
|
||||
* `editor.execCommand` should work with any core command in both the
|
||||
* [CodeMirror](https://codemirror.net/doc/manual.html#execCommand) and
|
||||
* [TinyMCE](https://www.tiny.cloud/docs/api/tinymce/tinymce.editorcommands/#execcommand) editors,
|
||||
* as well as most functions calls directly on a CodeMirror editor object (extensions).
|
||||
*
|
||||
* * [CodeMirror commands](https://codemirror.net/doc/manual.html#commands)
|
||||
* * [TinyMCE core editor commands](https://www.tiny.cloud/docs/advanced/editor-command-identifiers/#coreeditorcommands)
|
||||
*
|
||||
* `editor.execCommand` supports adding arguments for the commands.
|
||||
*
|
||||
* ```typescript
|
||||
* await joplin.commands.execute('editor.execCommand', {
|
||||
* name: 'madeUpCommand', // CodeMirror and TinyMCE
|
||||
* args: [], // CodeMirror and TinyMCE
|
||||
* ui: false, // TinyMCE only
|
||||
* value: '', // TinyMCE only
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* [View the example using the CodeMirror editor](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/codemirror_content_script/src/index.ts)
|
||||
*
|
||||
*/
|
||||
export default class JoplinCommands {
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Executes the given
|
||||
* command.
|
||||
*
|
||||
* The command can take any number of arguments, and the supported
|
||||
* arguments will vary based on the command. For custom commands, this
|
||||
* is the `args` passed to the `execute()` function. For built-in
|
||||
* commands, you can find the supported arguments by checking the links
|
||||
* above.
|
||||
*
|
||||
* ```typescript
|
||||
* // Create a new note in the current notebook:
|
||||
* await joplin.commands.execute('newNote');
|
||||
*
|
||||
* // Create a new sub-notebook under the provided notebook
|
||||
* // Note: internally, notebooks are called "folders".
|
||||
* await joplin.commands.execute('newFolder', "SOME_FOLDER_ID");
|
||||
* ```
|
||||
*/
|
||||
execute(commandName: string, ...args: any[]): Promise<any | void>;
|
||||
/**
|
||||
* <span class="platform-desktop">desktop</span> Registers a new command.
|
||||
*
|
||||
* ```typescript
|
||||
* // Register a new commmand called "testCommand1"
|
||||
*
|
||||
* await joplin.commands.register({
|
||||
* name: 'testCommand1',
|
||||
* label: 'My Test Command 1',
|
||||
* iconName: 'fas fa-music',
|
||||
* execute: () => {
|
||||
* alert('Testing plugin command 1');
|
||||
* },
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
register(command: Command): Promise<void>;
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import { ContentScriptType } from './types';
|
||||
export default class JoplinContentScripts {
|
||||
private plugin;
|
||||
constructor(plugin: Plugin);
|
||||
/**
|
||||
* Registers a new content script. Unlike regular plugin code, which runs in
|
||||
* a separate process, content scripts run within the main process code and
|
||||
* thus allow improved performances and more customisations in specific
|
||||
* cases. It can be used for example to load a Markdown or editor plugin.
|
||||
*
|
||||
* Note that registering a content script in itself will do nothing - it
|
||||
* will only be loaded in specific cases by the relevant app modules (eg.
|
||||
* the Markdown renderer or the code editor). So it is not a way to inject
|
||||
* and run arbitrary code in the app, which for safety and performance
|
||||
* reasons is not supported.
|
||||
*
|
||||
* The plugin generator provides a way to build any content script you might
|
||||
* want to package as well as its dependencies. See the [Plugin Generator
|
||||
* doc](https://github.com/laurent22/joplin/blob/dev/packages/generator-joplin/README.md)
|
||||
* for more information.
|
||||
*
|
||||
* * [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
|
||||
* * [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
|
||||
*
|
||||
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
|
||||
*
|
||||
* @param type Defines how the script will be used. See the type definition for more information about each supported type.
|
||||
* @param id A unique ID for the content script.
|
||||
* @param scriptPath Must be a path relative to the plugin main script. For example, if your file content_script.js is next to your index.ts file, you would set `scriptPath` to `"./content_script.js`.
|
||||
*/
|
||||
register(type: ContentScriptType, id: string, scriptPath: string): Promise<void>;
|
||||
/**
|
||||
* Listens to a messages sent from the content script using postMessage().
|
||||
* See {@link ContentScriptType} for more information as well as the
|
||||
* [postMessage
|
||||
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
|
||||
*/
|
||||
onMessage(contentScriptId: string, callback: any): Promise<void>;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { Path } from './types';
|
||||
/**
|
||||
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
|
||||
* This is the main way to retrieve data, such as notes, notebooks, tags, etc.
|
||||
* or to update them or delete them.
|
||||
*
|
||||
* This is also what you would use to search notes, via the `search` endpoint.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/simple)
|
||||
*
|
||||
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
|
||||
* And each method takes these parameters:
|
||||
*
|
||||
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
|
||||
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
|
||||
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
|
||||
* * `files`: (Optional) Used to create new resources and associate them with files.
|
||||
*
|
||||
* Please refer to the [Joplin API documentation](https://joplinapp.org/api/references/rest_api/) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```typescript
|
||||
* // Get a note ID, title and body
|
||||
* const noteId = 'some_note_id';
|
||||
* const note = await joplin.data.get(['notes', noteId], { fields: ['id', 'title', 'body'] });
|
||||
*
|
||||
* // Get all folders
|
||||
* const folders = await joplin.data.get(['folders']);
|
||||
*
|
||||
* // Set the note body
|
||||
* await joplin.data.put(['notes', noteId], null, { body: "New note body" });
|
||||
*
|
||||
* // Create a new note under one of the folders
|
||||
* await joplin.data.post(['notes'], null, { body: "my new note", title: "some title", parent_id: folders[0].id });
|
||||
* ```
|
||||
*/
|
||||
export default class JoplinData {
|
||||
private api_;
|
||||
private pathSegmentRegex_;
|
||||
private serializeApiBody;
|
||||
private pathToString;
|
||||
get(path: Path, query?: any): Promise<any>;
|
||||
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>;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* Not sure if it's the best way to hook into the app
|
||||
* so for now disable filters.
|
||||
*/
|
||||
export default class JoplinFilters {
|
||||
on(name: string, callback: Function): Promise<void>;
|
||||
off(name: string, callback: Function): Promise<void>;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { ExportModule, ImportModule } from './types';
|
||||
/**
|
||||
* Provides a way to create modules to import external data into Joplin or to export notes into any arbitrary format.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/json_export)
|
||||
*
|
||||
* To implement an import or export module, you would simply define an object with various event handlers that are called
|
||||
* by the application during the import/export process.
|
||||
*
|
||||
* See the documentation of the [[ExportModule]] and [[ImportModule]] for more information.
|
||||
*
|
||||
* 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>;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import { ContentScriptType, Script } from './types';
|
||||
/**
|
||||
* This class provides access to plugin-related features.
|
||||
*/
|
||||
export default class JoplinPlugins {
|
||||
private plugin;
|
||||
constructor(plugin: Plugin);
|
||||
/**
|
||||
* Registers a new plugin. This is the entry point when creating a plugin. You should pass a simple object with an `onStart` method to it.
|
||||
* That `onStart` method will be executed as soon as the plugin is loaded.
|
||||
*
|
||||
* ```typescript
|
||||
* joplin.plugins.register({
|
||||
* onStart: async function() {
|
||||
* // Run your plugin code here
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
register(script: Script): Promise<void>;
|
||||
/**
|
||||
* @deprecated Use joplin.contentScripts.register()
|
||||
*/
|
||||
registerContentScript(type: ContentScriptType, id: string, scriptPath: string): Promise<void>;
|
||||
/**
|
||||
* Gets the plugin own data directory path. Use this to store any
|
||||
* plugin-related data. Unlike [[installationDir]], any data stored here
|
||||
* will be persisted.
|
||||
*/
|
||||
dataDir(): Promise<string>;
|
||||
/**
|
||||
* Gets the plugin installation directory. This can be used to access any
|
||||
* asset that was packaged with the plugin. This directory should be
|
||||
* considered read-only because any data you store here might be deleted or
|
||||
* re-created at any time. To store new persistent data, use [[dataDir]].
|
||||
*/
|
||||
installationDir(): Promise<string>;
|
||||
/**
|
||||
* @deprecated Use joplin.require()
|
||||
*/
|
||||
require(_path: string): any;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import { SettingItem, SettingSection } from './types';
|
||||
export interface ChangeEvent {
|
||||
/**
|
||||
* Setting keys that have been changed
|
||||
*/
|
||||
keys: string[];
|
||||
}
|
||||
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.
|
||||
*
|
||||
* Settings are essentially key/value pairs.
|
||||
*
|
||||
* Note: Currently this API does **not** provide access to Joplin's built-in settings. This is by design as plugins that modify user settings could give unexpected results
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/settings)
|
||||
*/
|
||||
export default class JoplinSettings {
|
||||
private plugin_;
|
||||
constructor(plugin: Plugin);
|
||||
private get keyPrefix();
|
||||
private namespacedKey;
|
||||
/**
|
||||
* Registers new settings.
|
||||
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
|
||||
* What it means is that you need to register the setting every time the plugin starts (for example in the onStart event).
|
||||
* The setting value however will be preserved from one launch to the next so there is no risk that it will be lost even if for some
|
||||
* reason the plugin fails to start at some point.
|
||||
*/
|
||||
registerSettings(settings: Record<string, SettingItem>): Promise<void>;
|
||||
/**
|
||||
* @deprecated Use joplin.settings.registerSettings()
|
||||
*
|
||||
* Registers a new setting.
|
||||
*/
|
||||
registerSetting(key: string, settingItem: SettingItem): Promise<void>;
|
||||
/**
|
||||
* Registers a new setting section. Like for registerSetting, it is dynamic and needs to be done every time the plugin starts.
|
||||
*/
|
||||
registerSection(name: string, section: SettingSection): Promise<void>;
|
||||
/**
|
||||
* Gets a setting value (only applies to setting you registered from your plugin)
|
||||
*/
|
||||
value(key: string): Promise<any>;
|
||||
/**
|
||||
* Sets a setting value (only applies to setting you registered from your plugin)
|
||||
*/
|
||||
setValue(key: string, value: any): Promise<void>;
|
||||
/**
|
||||
* Gets a global setting value, including app-specific settings and those set by other plugins.
|
||||
*
|
||||
* The list of available settings is not documented yet, but can be found by looking at the source code:
|
||||
*
|
||||
* https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142
|
||||
*/
|
||||
globalValue(key: string): Promise<any>;
|
||||
/**
|
||||
* Called when one or multiple settings of your plugin have been changed.
|
||||
* - For performance reasons, this event is triggered with a delay.
|
||||
* - You will only get events for your own plugin settings.
|
||||
*/
|
||||
onChange(handler: ChangeHandler): Promise<void>;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import JoplinViewsDialogs from './JoplinViewsDialogs';
|
||||
import JoplinViewsMenuItems from './JoplinViewsMenuItems';
|
||||
import JoplinViewsMenus from './JoplinViewsMenus';
|
||||
import JoplinViewsToolbarButtons from './JoplinViewsToolbarButtons';
|
||||
import JoplinViewsPanels from './JoplinViewsPanels';
|
||||
/**
|
||||
* This namespace provides access to view-related services.
|
||||
*
|
||||
* All view services provide a `create()` method which you would use to create the view object, whether it's a dialog, a toolbar button or a menu item.
|
||||
* In some cases, the `create()` method will return a [[ViewHandle]], which you would use to act on the view, for example to set certain properties or call some methods.
|
||||
*/
|
||||
export default class JoplinViews {
|
||||
private store;
|
||||
private plugin;
|
||||
private dialogs_;
|
||||
private panels_;
|
||||
private menuItems_;
|
||||
private menus_;
|
||||
private toolbarButtons_;
|
||||
private implementation_;
|
||||
constructor(implementation: any, plugin: Plugin, store: any);
|
||||
get dialogs(): JoplinViewsDialogs;
|
||||
get panels(): JoplinViewsPanels;
|
||||
get menuItems(): JoplinViewsMenuItems;
|
||||
get menus(): JoplinViewsMenus;
|
||||
get toolbarButtons(): JoplinViewsToolbarButtons;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import { ButtonSpec, ViewHandle, DialogResult } from './types';
|
||||
/**
|
||||
* Allows creating and managing dialogs. A dialog is modal window that
|
||||
* contains a webview and a row of buttons. You can update the update the
|
||||
* webview using the `setHtml` method. Dialogs are hidden by default and
|
||||
* you need to call `open()` to open them. Once the user clicks on a
|
||||
* button, the `open` call will return an object indicating what button was
|
||||
* clicked on.
|
||||
*
|
||||
* ## Retrieving form values
|
||||
*
|
||||
* If your HTML content included one or more forms, a `formData` object
|
||||
* will also be included with the key/value for each form.
|
||||
*
|
||||
* ## Special button IDs
|
||||
*
|
||||
* The following buttons IDs have a special meaning:
|
||||
*
|
||||
* - `ok`, `yes`, `submit`, `confirm`: They are considered "submit" buttons
|
||||
* - `cancel`, `no`, `reject`: They are considered "dismiss" buttons
|
||||
*
|
||||
* This information is used by the application to determine what action
|
||||
* should be done when the user presses "Enter" or "Escape" within the
|
||||
* dialog. If they press "Enter", the first "submit" button will be
|
||||
* automatically clicked. If they press "Escape" the first "dismiss" button
|
||||
* will be automatically clicked.
|
||||
*
|
||||
* [View the demo
|
||||
* plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/dialog)
|
||||
*/
|
||||
export default class JoplinViewsDialogs {
|
||||
private store;
|
||||
private plugin;
|
||||
private implementation_;
|
||||
constructor(implementation: any, plugin: Plugin, store: any);
|
||||
private controller;
|
||||
/**
|
||||
* Creates a new dialog
|
||||
*/
|
||||
create(id: string): Promise<ViewHandle>;
|
||||
/**
|
||||
* Displays a message box with OK/Cancel buttons. Returns the button index that was clicked - "0" for OK and "1" for "Cancel"
|
||||
*/
|
||||
showMessageBox(message: string): Promise<number>;
|
||||
/**
|
||||
* Sets the dialog HTML content
|
||||
*/
|
||||
setHtml(handle: ViewHandle, html: string): Promise<string>;
|
||||
/**
|
||||
* Adds and loads a new JS or CSS files into the dialog.
|
||||
*/
|
||||
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
|
||||
/**
|
||||
* Sets the dialog buttons.
|
||||
*/
|
||||
setButtons(handle: ViewHandle, buttons: ButtonSpec[]): Promise<ButtonSpec[]>;
|
||||
/**
|
||||
* Opens the dialog
|
||||
*/
|
||||
open(handle: ViewHandle): Promise<DialogResult>;
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
import { CreateMenuItemOptions, MenuItemLocation } from './types';
|
||||
import Plugin from '../Plugin';
|
||||
/**
|
||||
* Allows creating and managing menu items.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
|
||||
*/
|
||||
export default class JoplinViewsMenuItems {
|
||||
private store;
|
||||
private plugin;
|
||||
constructor(plugin: Plugin, store: any);
|
||||
/**
|
||||
* Creates a new menu item and associate it with the given command. You can specify under which menu the item should appear using the `location` parameter.
|
||||
*/
|
||||
create(id: string, commandName: string, location?: MenuItemLocation, options?: CreateMenuItemOptions): Promise<void>;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { MenuItem, MenuItemLocation } from './types';
|
||||
import Plugin from '../Plugin';
|
||||
/**
|
||||
* Allows creating menus.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/menu)
|
||||
*/
|
||||
export default class JoplinViewsMenus {
|
||||
private store;
|
||||
private plugin;
|
||||
constructor(plugin: Plugin, store: any);
|
||||
private registerCommandAccelerators;
|
||||
/**
|
||||
* Creates a new menu from the provided menu items and place it at the given location. As of now, it is only possible to place the
|
||||
* menu as a sub-menu of the application build-in menus.
|
||||
*/
|
||||
create(id: string, label: string, menuItems: MenuItem[], location?: MenuItemLocation): Promise<void>;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import Plugin from '../Plugin';
|
||||
import { ViewHandle } from './types';
|
||||
/**
|
||||
* Allows creating and managing view panels. View panels currently are
|
||||
* displayed at the right of the sidebar and allows displaying any HTML
|
||||
* content (within a webview) and update it in real-time. For example it
|
||||
* could be used to display a table of content for the active note, or
|
||||
* display various metadata or graph.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/toc)
|
||||
*/
|
||||
export default class JoplinViewsPanels {
|
||||
private store;
|
||||
private plugin;
|
||||
constructor(plugin: Plugin, store: any);
|
||||
private controller;
|
||||
/**
|
||||
* Creates a new panel
|
||||
*/
|
||||
create(id: string): Promise<ViewHandle>;
|
||||
/**
|
||||
* Sets the panel webview HTML
|
||||
*/
|
||||
setHtml(handle: ViewHandle, html: string): Promise<string>;
|
||||
/**
|
||||
* Adds and loads a new JS or CSS files into the panel.
|
||||
*/
|
||||
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
|
||||
/**
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*
|
||||
* To post a message from the webview to the plugin use:
|
||||
*
|
||||
* ```javascript
|
||||
* const response = await webviewApi.postMessage(message);
|
||||
* ```
|
||||
*
|
||||
* - `message` can be any JavaScript object, string or number
|
||||
* - `response` is whatever was returned by the `onMessage` handler
|
||||
*
|
||||
* Using this mechanism, you can have two-way communication between the
|
||||
* plugin and webview.
|
||||
*
|
||||
* See the [postMessage
|
||||
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages) for more details.
|
||||
*
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
import { ToolbarButtonLocation } from './types';
|
||||
import Plugin from '../Plugin';
|
||||
/**
|
||||
* Allows creating and managing toolbar buttons.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
|
||||
*/
|
||||
export default class JoplinViewsToolbarButtons {
|
||||
private store;
|
||||
private plugin;
|
||||
constructor(plugin: Plugin, store: any);
|
||||
/**
|
||||
* Creates a new toolbar button and associate it with the given command.
|
||||
*/
|
||||
create(id: string, commandName: string, location: ToolbarButtonLocation): Promise<void>;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import { FolderEntity } from '../../database/types';
|
||||
import { Disposable } from './types';
|
||||
declare enum ItemChangeEventType {
|
||||
Create = 1,
|
||||
Update = 2,
|
||||
Delete = 3,
|
||||
}
|
||||
interface ItemChangeEvent {
|
||||
id: string;
|
||||
event: ItemChangeEventType;
|
||||
}
|
||||
interface SyncStartEvent {
|
||||
withErrors: boolean;
|
||||
}
|
||||
declare type ItemChangeHandler = (event: ItemChangeEvent)=> void;
|
||||
declare type SyncStartHandler = (event: SyncStartEvent)=> 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
|
||||
* well as various related events, such as when a new note is selected, or
|
||||
* when the note content changes.
|
||||
*
|
||||
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins)
|
||||
*/
|
||||
export default class JoplinWorkspace {
|
||||
private store;
|
||||
constructor(store: any);
|
||||
/**
|
||||
* Called when a new note or notes are selected.
|
||||
*/
|
||||
onNoteSelectionChange(callback: Function): Promise<Disposable>;
|
||||
/**
|
||||
* Called when the content of a note changes.
|
||||
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
|
||||
*/
|
||||
onNoteContentChange(callback: Function): Promise<void>;
|
||||
/**
|
||||
* Called when the content of the current note changes.
|
||||
*/
|
||||
onNoteChange(handler: ItemChangeHandler): Promise<Disposable>;
|
||||
/**
|
||||
* Called when an alarm associated with a to-do is triggered.
|
||||
*/
|
||||
onNoteAlarmTrigger(handler: Function): Promise<Disposable>;
|
||||
/**
|
||||
* Called when the synchronisation process is starting.
|
||||
*/
|
||||
onSyncStart(handler: SyncStartHandler): Promise<Disposable>;
|
||||
/**
|
||||
* Called when the synchronisation process has finished.
|
||||
*/
|
||||
onSyncComplete(callback: Function): Promise<Disposable>;
|
||||
/**
|
||||
* Gets the currently selected note
|
||||
*/
|
||||
selectedNote(): Promise<any>;
|
||||
/**
|
||||
* Gets the currently selected folder. In some cases, for example during
|
||||
* search or when viewing a tag, no folder is actually selected in the user
|
||||
* interface. In that case, that function would return the last selected
|
||||
* folder.
|
||||
*/
|
||||
selectedFolder(): Promise<FolderEntity>;
|
||||
/**
|
||||
* Gets the IDs of the selected notes (can be zero, one, or many). Use the data API to retrieve information about these notes.
|
||||
*/
|
||||
selectedNoteIds(): Promise<string[]>;
|
||||
}
|
||||
export {};
|
||||
@@ -1,5 +0,0 @@
|
||||
import type Joplin from './Joplin';
|
||||
|
||||
declare const joplin: Joplin;
|
||||
|
||||
export default joplin;
|
||||
@@ -1,616 +0,0 @@
|
||||
// =================================================================
|
||||
// Command API types
|
||||
// =================================================================
|
||||
|
||||
export interface Command {
|
||||
/**
|
||||
* Name of command - must be globally unique
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Label to be displayed on menu items or keyboard shortcut editor for example.
|
||||
* If it is missing, it's assumed it's a private command, to be called programmatically only.
|
||||
* In that case the command will not appear in the shortcut editor or command panel, and logically
|
||||
* should not be used as a menu item.
|
||||
*/
|
||||
label?: string;
|
||||
|
||||
/**
|
||||
* Icon to be used on toolbar buttons for example
|
||||
*/
|
||||
iconName?: string;
|
||||
|
||||
/**
|
||||
* Code to be ran when the command is executed. It may return a result.
|
||||
*/
|
||||
execute(...args: any[]): Promise<any | void>;
|
||||
|
||||
/**
|
||||
* Defines whether the command should be enabled or disabled, which in turns
|
||||
* affects the enabled state of any associated button or menu item.
|
||||
*
|
||||
* The condition should be expressed as a "when-clause" (as in Visual Studio
|
||||
* Code). It's a simple boolean expression that evaluates to `true` or
|
||||
* `false`. It supports the following operators:
|
||||
*
|
||||
* Operator | Symbol | Example
|
||||
* -- | -- | --
|
||||
* Equality | == | "editorType == markdown"
|
||||
* Inequality | != | "currentScreen != config"
|
||||
* Or | \|\| | "noteIsTodo \|\| noteTodoCompleted"
|
||||
* And | && | "oneNoteSelected && !inConflictFolder"
|
||||
*
|
||||
* Joplin, unlike VSCode, also supports parenthesis, which allows creating
|
||||
* more complex expressions such as `cond1 || (cond2 && cond3)`. Only one
|
||||
* level of parenthesis is possible (nested ones aren't supported).
|
||||
*
|
||||
* Currently the supported context variables aren't documented, but you can
|
||||
* find the list below:
|
||||
*
|
||||
* - [Global When Clauses](https://github.com/laurent22/joplin/blob/dev/packages/lib/services/commands/stateToWhenClauseContext.ts)
|
||||
* - [Desktop app When Clauses](https://github.com/laurent22/joplin/blob/dev/packages/app-desktop/services/commands/stateToWhenClauseContext.ts)
|
||||
*
|
||||
* Note: Commands are enabled by default unless you use this property.
|
||||
*/
|
||||
enabledCondition?: string;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Interop API types
|
||||
// =================================================================
|
||||
|
||||
export enum FileSystemItem {
|
||||
File = 'file',
|
||||
Directory = 'directory',
|
||||
}
|
||||
|
||||
export enum ImportModuleOutputFormat {
|
||||
Markdown = 'md',
|
||||
Html = 'html',
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to implement a module to export data from Joplin. [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/json_export) for an example.
|
||||
*
|
||||
* In general, all the event handlers you'll need to implement take a `context` object as a first argument. This object will contain the export or import path as well as various optional properties, such as which notes or notebooks need to be exported.
|
||||
*
|
||||
* To get a better sense of what it will contain it can be useful to print it using `console.info(context)`.
|
||||
*/
|
||||
export interface ExportModule {
|
||||
/**
|
||||
* The format to be exported, eg "enex", "jex", "json", etc.
|
||||
*/
|
||||
format: string;
|
||||
|
||||
/**
|
||||
* The description that will appear in the UI, for example in the menu item.
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Whether the module will export a single file or multiple files in a directory. It affects the open dialog that will be presented to the user when using your exporter.
|
||||
*/
|
||||
target: FileSystemItem;
|
||||
|
||||
/**
|
||||
* Only applies to single file exporters or importers
|
||||
* It tells whether the format can package multiple notes into one file.
|
||||
* For example JEX or ENEX can, but HTML cannot.
|
||||
*/
|
||||
isNoteArchive: boolean;
|
||||
|
||||
/**
|
||||
* The extensions of the files exported by your module. For example, it is `["htm", "html"]` for the HTML module, and just `["jex"]` for the JEX module.
|
||||
*/
|
||||
fileExtensions?: string[];
|
||||
|
||||
/**
|
||||
* Called when the export process starts.
|
||||
*/
|
||||
onInit(context: ExportContext): Promise<void>;
|
||||
|
||||
/**
|
||||
* Called when an item needs to be processed. An "item" can be any Joplin object, such as a note, a folder, a notebook, etc.
|
||||
*/
|
||||
onProcessItem(context: ExportContext, itemType: number, item: any): Promise<void>;
|
||||
|
||||
/**
|
||||
* Called when a resource file needs to be exported.
|
||||
*/
|
||||
onProcessResource(context: ExportContext, resource: any, filePath: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Called when the export process is done.
|
||||
*/
|
||||
onClose(context: ExportContext): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ImportModule {
|
||||
/**
|
||||
* The format to be exported, eg "enex", "jex", "json", etc.
|
||||
*/
|
||||
format: string;
|
||||
|
||||
/**
|
||||
* The description that will appear in the UI, for example in the menu item.
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Only applies to single file exporters or importers
|
||||
* It tells whether the format can package multiple notes into one file.
|
||||
* For example JEX or ENEX can, but HTML cannot.
|
||||
*/
|
||||
isNoteArchive: boolean;
|
||||
|
||||
/**
|
||||
* The type of sources that are supported by the module. Tells whether the module can import files or directories or both.
|
||||
*/
|
||||
sources: FileSystemItem[];
|
||||
|
||||
/**
|
||||
* Tells the file extensions of the exported files.
|
||||
*/
|
||||
fileExtensions?: string[];
|
||||
|
||||
/**
|
||||
* Tells the type of notes that will be generated, either HTML or Markdown (default).
|
||||
*/
|
||||
outputFormat?: ImportModuleOutputFormat;
|
||||
|
||||
/**
|
||||
* Called when the import process starts. There is only one event handler within which you should import the complete data.
|
||||
*/
|
||||
onExec(context: ImportContext): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExportOptions {
|
||||
format?: string;
|
||||
path?: string;
|
||||
sourceFolderIds?: string[];
|
||||
sourceNoteIds?: string[];
|
||||
// modulePath?: string;
|
||||
target?: FileSystemItem;
|
||||
}
|
||||
|
||||
export interface ExportContext {
|
||||
destPath: string;
|
||||
options: ExportOptions;
|
||||
|
||||
/**
|
||||
* You can attach your own custom data using this propery - it will then be passed to each event handler, allowing you to keep state from one event to the next.
|
||||
*/
|
||||
userData?: any;
|
||||
}
|
||||
|
||||
export interface ImportContext {
|
||||
sourcePath: string;
|
||||
options: any;
|
||||
warnings: string[];
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Misc types
|
||||
// =================================================================
|
||||
|
||||
export interface Script {
|
||||
onStart?(event: any): Promise<void>;
|
||||
}
|
||||
|
||||
export interface Disposable {
|
||||
// dispose():void;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Menu types
|
||||
// =================================================================
|
||||
|
||||
export interface CreateMenuItemOptions {
|
||||
accelerator: string;
|
||||
}
|
||||
|
||||
export enum MenuItemLocation {
|
||||
File = 'file',
|
||||
Edit = 'edit',
|
||||
View = 'view',
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
Context = 'context',
|
||||
|
||||
// If adding an item here, don't forget to update isContextMenuItemLocation()
|
||||
|
||||
/**
|
||||
* When a command is called from the note list context menu, the
|
||||
* command will receive the following arguments:
|
||||
*
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
* When a command is called from a folder context menu, the
|
||||
* command will receive the following arguments:
|
||||
*
|
||||
* - `folderId:string`: ID of the folder that was right-clicked on
|
||||
*/
|
||||
FolderContextMenu = 'folderContextMenu',
|
||||
|
||||
/**
|
||||
* When a command is called from a tag context menu, the
|
||||
* command will receive the following arguments:
|
||||
*
|
||||
* - `tagId:string`: ID of the tag that was right-clicked on
|
||||
*/
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
MenuItemLocation.EditorContextMenu,
|
||||
MenuItemLocation.FolderContextMenu,
|
||||
MenuItemLocation.TagContextMenu,
|
||||
].includes(location);
|
||||
}
|
||||
|
||||
export interface MenuItem {
|
||||
/**
|
||||
* Command that should be associated with the menu item. All menu item should
|
||||
* have a command associated with them unless they are a sub-menu.
|
||||
*/
|
||||
commandName?: string;
|
||||
|
||||
/**
|
||||
* Accelerator associated with the menu item
|
||||
*/
|
||||
accelerator?: string;
|
||||
|
||||
/**
|
||||
* Menu items that should appear below this menu item. Allows creating a menu tree.
|
||||
*/
|
||||
submenu?: MenuItem[];
|
||||
|
||||
/**
|
||||
* Menu item label. If not specified, the command label will be used instead.
|
||||
*/
|
||||
label?: string;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// View API types
|
||||
// =================================================================
|
||||
|
||||
export interface ButtonSpec {
|
||||
id: ButtonId;
|
||||
title?: string;
|
||||
onClick?(): void;
|
||||
}
|
||||
|
||||
export type ButtonId = string;
|
||||
|
||||
export enum ToolbarButtonLocation {
|
||||
/**
|
||||
* This toolbar in the top right corner of the application. It applies to the note as a whole, including its metadata.
|
||||
*/
|
||||
NoteToolbar = 'noteToolbar',
|
||||
|
||||
/**
|
||||
* This toolbar is right above the text editor. It applies to the note body only.
|
||||
*/
|
||||
EditorToolbar = 'editorToolbar',
|
||||
}
|
||||
|
||||
export type ViewHandle = string;
|
||||
|
||||
export interface EditorCommand {
|
||||
name: string;
|
||||
value?: any;
|
||||
}
|
||||
|
||||
export interface DialogResult {
|
||||
id: ButtonId;
|
||||
formData?: any;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Settings types
|
||||
// =================================================================
|
||||
|
||||
export enum SettingItemType {
|
||||
Int = 1,
|
||||
String = 2,
|
||||
Bool = 3,
|
||||
Array = 4,
|
||||
Object = 5,
|
||||
Button = 6,
|
||||
}
|
||||
|
||||
// Redefine a simplified interface to mask internal details
|
||||
// and to remove function calls as they would have to be async.
|
||||
export interface SettingItem {
|
||||
value: any;
|
||||
type: SettingItemType;
|
||||
|
||||
label: string;
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* A public setting will appear in the Configuration screen and will be
|
||||
* modifiable by the user. A private setting however will not appear there,
|
||||
* and can only be changed programmatically. You may use this to store some
|
||||
* values that you do not want to directly expose.
|
||||
*/
|
||||
public: boolean;
|
||||
|
||||
/**
|
||||
* You would usually set this to a section you would have created
|
||||
* specifically for the plugin.
|
||||
*/
|
||||
section?: string;
|
||||
|
||||
/**
|
||||
* To create a setting with multiple options, set this property to `true`.
|
||||
* That setting will render as a dropdown list in the configuration screen.
|
||||
*/
|
||||
isEnum?: boolean;
|
||||
|
||||
/**
|
||||
* This property is required when `isEnum` is `true`. In which case, it
|
||||
* should contain a map of value => label.
|
||||
*/
|
||||
options?: Record<any, any>;
|
||||
|
||||
/**
|
||||
* Reserved property. Not used at the moment.
|
||||
*/
|
||||
appTypes?: string[];
|
||||
|
||||
/**
|
||||
* Set this to `true` to store secure data, such as passwords. Any such
|
||||
* setting will be stored in the system keychain if one is available.
|
||||
*/
|
||||
secure?: boolean;
|
||||
|
||||
/**
|
||||
* An advanced setting will be moved under the "Advanced" button in the
|
||||
* config screen.
|
||||
*/
|
||||
advanced?: boolean;
|
||||
|
||||
/**
|
||||
* Set the min, max and step values if you want to restrict an int setting
|
||||
* to a particular range.
|
||||
*/
|
||||
minimum?: number;
|
||||
maximum?: number;
|
||||
step?: number;
|
||||
}
|
||||
|
||||
export interface SettingSection {
|
||||
label: string;
|
||||
iconName?: string;
|
||||
description?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Data API types
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* An array of at least one element and at most three elements.
|
||||
*
|
||||
* - **[0]**: Resource name (eg. "notes", "folders", "tags", etc.)
|
||||
* - **[1]**: (Optional) Resource ID.
|
||||
* - **[2]**: (Optional) Resource link.
|
||||
*/
|
||||
export type Path = string[];
|
||||
|
||||
// =================================================================
|
||||
// Content Script types
|
||||
// =================================================================
|
||||
|
||||
export type PostMessageHandler = (id: string, message: any)=> Promise<any>;
|
||||
|
||||
/**
|
||||
* When a content script is initialised, it receives a `context` object.
|
||||
*/
|
||||
export interface ContentScriptContext {
|
||||
/**
|
||||
* The plugin ID that registered this content script
|
||||
*/
|
||||
pluginId: string;
|
||||
|
||||
/**
|
||||
* The content script ID, which may be necessary to post messages
|
||||
*/
|
||||
contentScriptId: string;
|
||||
|
||||
/**
|
||||
* Can be used by CodeMirror content scripts to post a message to the plugin
|
||||
*/
|
||||
postMessage: PostMessageHandler;
|
||||
}
|
||||
|
||||
export enum ContentScriptType {
|
||||
/**
|
||||
* Registers a new Markdown-It plugin, which should follow the template
|
||||
* below.
|
||||
*
|
||||
* ```javascript
|
||||
* module.exports = {
|
||||
* default: function(context) {
|
||||
* return {
|
||||
* plugin: function(markdownIt, options) {
|
||||
* // ...
|
||||
* },
|
||||
* assets: {
|
||||
* // ...
|
||||
* },
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* See [the
|
||||
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
|
||||
* for a simple Markdown-it plugin example.
|
||||
*
|
||||
* ## Exported members
|
||||
*
|
||||
* - The `context` argument is currently unused but could be used later on
|
||||
* to provide access to your own plugin so that the content script and
|
||||
* plugin can communicate.
|
||||
*
|
||||
* - The **required** `plugin` key is the actual Markdown-It plugin - check
|
||||
* the [official doc](https://github.com/markdown-it/markdown-it) for more
|
||||
* information. The `options` parameter is of type
|
||||
* [RuleOptions](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts),
|
||||
* which contains a number of options, mostly useful for Joplin's internal
|
||||
* code.
|
||||
*
|
||||
* - Using the **optional** `assets` key you may specify assets such as JS
|
||||
* or CSS that should be loaded in the rendered HTML document. Check for
|
||||
* example the Joplin [Mermaid
|
||||
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
|
||||
* to see how the data should be structured.
|
||||
*
|
||||
* ## Posting messages from the content script to your plugin
|
||||
*
|
||||
* The application provides the following function to allow executing
|
||||
* commands from the rendered HTML code:
|
||||
*
|
||||
* ```javascript
|
||||
* const response = await webviewApi.postMessage(contentScriptId, message);
|
||||
* ```
|
||||
*
|
||||
* - `contentScriptId` is the ID you've defined when you registered the
|
||||
* content script. You can retrieve it from the
|
||||
* {@link ContentScriptContext | context}.
|
||||
* - `message` can be any basic JavaScript type (number, string, plain
|
||||
* object), but it cannot be a function or class instance.
|
||||
*
|
||||
* When you post a message, the plugin can send back a `response` thus
|
||||
* allowing two-way communication:
|
||||
*
|
||||
* ```javascript
|
||||
* await joplin.contentScripts.onMessage(contentScriptId, (message) => {
|
||||
* // Process message
|
||||
* return response; // Can be any object, string or number
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* See {@link JoplinContentScripts.onMessage} for more details, as well as
|
||||
* the [postMessage
|
||||
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
|
||||
*
|
||||
* ## Registering an existing Markdown-it plugin
|
||||
*
|
||||
* To include a regular Markdown-It plugin, that doesn't make use of any
|
||||
* Joplin-specific features, you would simply create a file such as this:
|
||||
*
|
||||
* ```javascript
|
||||
* module.exports = {
|
||||
* default: function(context) {
|
||||
* return {
|
||||
* plugin: require('markdown-it-toc-done-right');
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
MarkdownItPlugin = 'markdownItPlugin',
|
||||
|
||||
/**
|
||||
* Registers a new CodeMirror plugin, which should follow the template
|
||||
* below.
|
||||
*
|
||||
* ```javascript
|
||||
* module.exports = {
|
||||
* default: function(context) {
|
||||
* return {
|
||||
* plugin: function(CodeMirror) {
|
||||
* // ...
|
||||
* },
|
||||
* codeMirrorResources: [],
|
||||
* codeMirrorOptions: {
|
||||
* // ...
|
||||
* },
|
||||
* assets: {
|
||||
* // ...
|
||||
* },
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* - The `context` argument is currently unused but could be used later on
|
||||
* to provide access to your own plugin so that the content script and
|
||||
* plugin can communicate.
|
||||
*
|
||||
* - The `plugin` key is your CodeMirror plugin. This is where you can
|
||||
* register new commands with CodeMirror or interact with the CodeMirror
|
||||
* instance as needed.
|
||||
*
|
||||
* - The `codeMirrorResources` key is an array of CodeMirror resources that
|
||||
* will be loaded and attached to the CodeMirror module. These are made up
|
||||
* of addons, keymaps, and modes. For example, for a plugin that want's to
|
||||
* enable clojure highlighting in code blocks. `codeMirrorResources` would
|
||||
* be set to `['mode/clojure/clojure']`.
|
||||
*
|
||||
* - The `codeMirrorOptions` key contains all the
|
||||
* [CodeMirror](https://codemirror.net/doc/manual.html#config) options
|
||||
* that will be set or changed by this plugin. New options can alse be
|
||||
* declared via
|
||||
* [`CodeMirror.defineOption`](https://codemirror.net/doc/manual.html#defineOption),
|
||||
* and then have their value set here. For example, a plugin that enables
|
||||
* line numbers would set `codeMirrorOptions` to `{'lineNumbers': true}`.
|
||||
*
|
||||
* - Using the **optional** `assets` key you may specify **only** CSS assets
|
||||
* that should be loaded in the rendered HTML document. Check for example
|
||||
* the Joplin [Mermaid
|
||||
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
|
||||
* to see how the data should be structured.
|
||||
*
|
||||
* One of the `plugin`, `codeMirrorResources`, or `codeMirrorOptions` keys
|
||||
* must be provided for the plugin to be valid. Having multiple or all
|
||||
* provided is also okay.
|
||||
*
|
||||
* See also the [demo
|
||||
* plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
|
||||
* for an example of all these keys being used in one plugin.
|
||||
*
|
||||
* ## Posting messages from the content script to your plugin
|
||||
*
|
||||
* In order to post messages to the plugin, you can use the postMessage
|
||||
* function passed to the {@link ContentScriptContext | context}.
|
||||
*
|
||||
* ```javascript
|
||||
* const response = await context.postMessage('messageFromCodeMirrorContentScript');
|
||||
* ```
|
||||
*
|
||||
* When you post a message, the plugin can send back a `response` thus
|
||||
* allowing two-way communication:
|
||||
*
|
||||
* ```javascript
|
||||
* await joplin.contentScripts.onMessage(contentScriptId, (message) => {
|
||||
* // Process message
|
||||
* return response; // Can be any object, string or number
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* See {@link JoplinContentScripts.onMessage} for more details, as well as
|
||||
* the [postMessage
|
||||
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages).
|
||||
*
|
||||
*/
|
||||
CodeMirrorPlugin = 'codeMirrorPlugin',
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"name": "joplin-plugin-clipboad-demo",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
|
||||
"prepare": "npm run dist",
|
||||
"update": "npm install -g generator-joplin && yo joplin --update"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"joplin-plugin"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.14",
|
||||
"chalk": "^4.1.0",
|
||||
"copy-webpack-plugin": "^6.1.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob": "^7.1.6",
|
||||
"on-build-webpack": "^0.1.0",
|
||||
"tar": "^6.0.5",
|
||||
"ts-loader": "^7.0.5",
|
||||
"typescript": "^3.9.3",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"yargs": "^16.2.0"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extraScripts": []
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import joplin from 'api';
|
||||
import { ToolbarButtonLocation } from 'api/types';
|
||||
|
||||
const imageDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAkCAYAAAD7PHgWAAAG0UlEQVRYhe2YXYhcZxnHf+97zszsxyTdpCa7zcYkXZstYpFUMdGC2AsRBIs3loCgdxW8Fo25UoTi10UpqBeFIrmI8UaLUD+QQmhBESoSzTaUZmNNstkmXXc3SWd2Zs6Z93m8eN/zNR+7C73QCw8MM3M+nvd//s//+T/POeajJ04q/8Ob/W8D2Gn7P8D3u8W7PfHBxSfYSgwiCgqgaPgGQKv/VQtpqxbXWGuYbsDdf/31/QOM4hqPP32G5bUazeOniDoO0QBGxH9U/UccKIgIqHiwmh0XVBR/sWAalsbsZfpXf4PbWN4WoBlXxcbGHDv9HL3mcZJUQRVUPCND4CQHI04CbVI6pvkxvy8ARXlAb7J+8YeIS0cCHKnBKK5x7PRztCcfIUkVg5bY0Ao4wkdEEYEkFbo9R7cndLqObtfR6Tg6nT7driPtC+CvcX1h083z4JPfHMvgyBR/7Okz3GoeR1LFGMIdZ8QMAJWClSiCTyxOVsBrplUVrIGbawkrt7eIjT/eV2VdDhHtW8Bt/nN3AK+u1YgbAZxzVWAD32F1nCj79lp+9pVDgBnLyLnX7vCDX75HNGFQFKOKiBAd+Txs/nTo/KEUH1h8gpnFU35hGdCcSEVzqODJKQHeBhyAteRFpOILyDnH1NyH2X/s8Z0ZbCUG2/E6Gac5zYEXFmON0uk6Xv77PQ7P1DhxdKoS9937CZdvtLn0dhtrTYgpeaxWKyVqD9frEEARRTIg5VSWmIRsP3nxoEK7JXznwi3qMfz27CL7p4vwz/9+lZdefZe4ZomicvX7IhRRCHLaFmDGSM6SVoOpCmBgAJyK+OSqkiaCy+wmbO2ueMWot5csHpkGxyhjJEAVDYY7mFavsbK3eVY1N2mjgjFgTHVFg2IQzMD1eZy82+wA0AveDQDwTGUM+WMu/NScRfDNwqoMhg0FEUCoIoAJGTEqqD+wM0BjgnNAUa0BmM+qQ1UQpySpw6US+rO3pcgqapzfVwaoijiHivU3q0HrIogqNsTfmcG8d0reIXKAQS9JKsQWHluY4tOPTnNopoY1sLSyxflX7uQ3OBA5Zz/TcsUldstgFijzqGy1DHiSCkdmG3zrCwf41IealStPLUxz4ZXbOBmR4uw+KQioWNiuiySIfbhdCb1enyNzDX7y1Xnm99VLiyvGGHqp4kL6BtnIYvnEaJ7mrIqxptD59gwC4vXiIxdTSmwNZ5+arYCDomIn6gYjgpPhjpJblRS/M7/Nb2A3DHqdZYZZGHTaFz7y8CQnF6Yr5//jeptfv/5vYmtYmG1gDEU+q4F9cam3GVOyFw1VvSsNlqffssW4VDi5MFkCbljZSPj6C8usr/cwBhp1Q5o6328HF1MBBCPeJqQMUMQTvhsfLOKVq0xxTpiZisr4uHKrzb17KY0J6xkRwZhsIK1uIlnhUQGXuYMdaTJjBta8ylzWJXy/3GiFqTfIa3FukkYd+qkLthFaXjbyV2IWuhscPFSEEYU/DqAGMy4FUMVa+NvbW5QRHjswwZc+c4B+4uh2UpwT0sSbe6NWDa0DmiusTIOzFUPJ9gCzOc1pMcWoEhnl8tX3eONmO98HcPaLR/jG6aPMHfT6nJywfPlz88xM1yphb9xphy5V9O/sYao8JQ1uI3ywatL+jj3yXs/x/B9WeeGZ4xhjcv/72mfneerjH+D6WodmI+Kxo3sqId9aaXFtpYWxhT5zcMEHrdUhWYxk0FhfTpr1XhVQByrUYvjTpU2efem6Pzdv3MpD+xp8cnGmBK5Y7Ue/WqbXTsKwQcFgPpj4Kcfa4XYyBLDZ8GkqqC+qD/xAcP6Pq5w9f417W6mfLnJTLlPg933vwptcfP0dbGwLreWPCFkTUJrTNWaawwmNZufmv1ve0b27ipv6IDpxMDT2EBCvTW8jwtLyfX53aR1FaTYseyZjIm+AbLYS/vLmBt/++RVefnUFY8AaMwCuJCPA3r+Gu3VxCOBIH3z0Ics1B52O5P6U3TGqRBZsw7J6e4tnz73FzEyNwwcnmJqIcH3H2maPG6st+okjim14dC3AAXkscd4hGpt/HgVl9JsFG9XY/+QZNmUel7el0gimYDT0UnGkqcP1HeKCWVuwUWCtXK1aSm34b1DmpjfoLb04EuBIoxaXsn7x+zzADeqxwYl4AJlpq+Aygw0eWa9Z6g1LfSKiVo+GwZV0l70CsQbmpjZIrpwbCW4sQJ9Sx93Xfswj8RLx5hLN6ZjIFKOXKT38ZNPxoLkXTPk+rOGavXvqTCbX2fvOL+i98SIq/bEAx748Gtz2Hj5Bq5ONUuVXIdnv0a/bsur3JextbM9UxNadK7tZlv8AuLmWJqiAwrcAAAAASUVORK5CYII=';
|
||||
|
||||
joplin.plugins.register({
|
||||
onStart: async function() {
|
||||
await joplin.commands.register({
|
||||
name: 'readFromClipboard',
|
||||
label: 'Read data from clipboard',
|
||||
iconName: 'fas fa-drum',
|
||||
execute: async () => {
|
||||
const clipboard = (joplin as any).clipboard;
|
||||
console.info('Formats', await clipboard.availableFormats());
|
||||
console.info('Text:', await clipboard.readText());
|
||||
console.info('HTML:', await clipboard.readHtml());
|
||||
console.info('Image:', await clipboard.readImage());
|
||||
},
|
||||
});
|
||||
|
||||
await joplin.commands.register({
|
||||
name: 'writeToClipboard',
|
||||
label: 'Read data from clipboard',
|
||||
iconName: 'fas fa-music',
|
||||
execute: async () => {
|
||||
const clipboard = (joplin as any).clipboard;
|
||||
await clipboard.writeImage(imageDataUrl);
|
||||
// await clipboard.writeText('text from plugin');
|
||||
// await clipboard.writeHtml('<p>text <strong>from</strong> plugin</p>');
|
||||
},
|
||||
});
|
||||
|
||||
await joplin.views.toolbarButtons.create('readFromClipboard', 'readFromClipboard', ToolbarButtonLocation.NoteToolbar);
|
||||
await joplin.views.toolbarButtons.create('writeToClipboard', 'writeToClipboard', ToolbarButtonLocation.NoteToolbar);
|
||||
},
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"id": "org.joplinapp.plugins.ClipboardDemo",
|
||||
"app_min_version": "2.0",
|
||||
"version": "1.0.0",
|
||||
"name": "Clipboad Demo",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"homepage_url": "",
|
||||
"repository_url": "",
|
||||
"keywords": []
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"module": "commonjs",
|
||||
"target": "es2015",
|
||||
"jsx": "react",
|
||||
"allowJs": true,
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// This file is used to build the plugin file (.jpl) and plugin info (.json). It
|
||||
// is recommended not to edit this file as it would be overwritten when updating
|
||||
// the plugin framework. If you do make some changes, consider using an external
|
||||
// JS file and requiring it here to minimize the changes. That way when you
|
||||
// update, you can easily restore the functionality you've added.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs-extra');
|
||||
const chalk = require('chalk');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const WebpackOnBuildPlugin = require('on-build-webpack');
|
||||
const tar = require('tar');
|
||||
const glob = require('glob');
|
||||
const execSync = require('child_process').execSync;
|
||||
|
||||
const rootDir = path.resolve(__dirname);
|
||||
const userConfigFilename = './plugin.config.json';
|
||||
const userConfigPath = path.resolve(rootDir, userConfigFilename);
|
||||
const distDir = path.resolve(rootDir, 'dist');
|
||||
const srcDir = path.resolve(rootDir, 'src');
|
||||
const publishDir = path.resolve(rootDir, 'publish');
|
||||
|
||||
const userConfig = Object.assign({}, {
|
||||
extraScripts: [],
|
||||
}, fs.pathExistsSync(userConfigPath) ? require(userConfigFilename) : {});
|
||||
|
||||
const manifestPath = `${srcDir}/manifest.json`;
|
||||
const packageJsonPath = `${rootDir}/package.json`;
|
||||
const manifest = readManifest(manifestPath);
|
||||
const pluginArchiveFilePath = path.resolve(publishDir, `${manifest.id}.jpl`);
|
||||
const pluginInfoFilePath = path.resolve(publishDir, `${manifest.id}.json`);
|
||||
|
||||
function validatePackageJson() {
|
||||
const content = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||
if (!content.name || content.name.indexOf('joplin-plugin-') !== 0) {
|
||||
console.warn(chalk.yellow(`WARNING: To publish the plugin, the package name should start with "joplin-plugin-" (found "${content.name}") in ${packageJsonPath}`));
|
||||
}
|
||||
|
||||
if (!content.keywords || content.keywords.indexOf('joplin-plugin') < 0) {
|
||||
console.warn(chalk.yellow(`WARNING: To publish the plugin, the package keywords should include "joplin-plugin" (found "${JSON.stringify(content.keywords)}") in ${packageJsonPath}`));
|
||||
}
|
||||
|
||||
if (content.scripts && content.scripts.postinstall) {
|
||||
console.warn(chalk.yellow(`WARNING: package.json contains a "postinstall" script. It is recommended to use a "prepare" script instead so that it is executed before publish. In ${packageJsonPath}`));
|
||||
}
|
||||
}
|
||||
|
||||
function fileSha256(filePath) {
|
||||
const content = fs.readFileSync(filePath);
|
||||
return crypto.createHash('sha256').update(content).digest('hex');
|
||||
}
|
||||
|
||||
function currentGitInfo() {
|
||||
try {
|
||||
let branch = execSync('git rev-parse --abbrev-ref HEAD', { stdio: 'pipe' }).toString().trim();
|
||||
const commit = execSync('git rev-parse HEAD', { stdio: 'pipe' }).toString().trim();
|
||||
if (branch === 'HEAD') branch = 'master';
|
||||
return `${branch}:${commit}`;
|
||||
} catch (error) {
|
||||
const messages = error.message ? error.message.split('\n') : [''];
|
||||
console.info(chalk.cyan('Could not get git commit (not a git repo?):', messages[0].trim()));
|
||||
console.info(chalk.cyan('Git information will not be stored in plugin info file'));
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
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}`);
|
||||
return output;
|
||||
}
|
||||
|
||||
function createPluginArchive(sourceDir, destPath) {
|
||||
const distFiles = glob.sync(`${sourceDir}/**/*`, { nodir: true })
|
||||
.map(f => f.substr(sourceDir.length + 1));
|
||||
|
||||
if (!distFiles.length) throw new Error('Plugin archive was not created because the "dist" directory is empty');
|
||||
fs.removeSync(destPath);
|
||||
|
||||
tar.create(
|
||||
{
|
||||
strict: true,
|
||||
portable: true,
|
||||
file: destPath,
|
||||
cwd: sourceDir,
|
||||
sync: true,
|
||||
},
|
||||
distFiles
|
||||
);
|
||||
|
||||
console.info(chalk.cyan(`Plugin archive has been created in ${destPath}`));
|
||||
}
|
||||
|
||||
function createPluginInfo(manifestPath, destPath, jplFilePath) {
|
||||
const contentText = fs.readFileSync(manifestPath, 'utf8');
|
||||
const content = JSON.parse(contentText);
|
||||
content._publish_hash = `sha256:${fileSha256(jplFilePath)}`;
|
||||
content._publish_commit = currentGitInfo();
|
||||
fs.writeFileSync(destPath, JSON.stringify(content, null, '\t'), 'utf8');
|
||||
}
|
||||
|
||||
function onBuildCompleted() {
|
||||
try {
|
||||
fs.removeSync(path.resolve(publishDir, 'index.js'));
|
||||
createPluginArchive(distDir, pluginArchiveFilePath);
|
||||
createPluginInfo(manifestPath, pluginInfoFilePath, pluginArchiveFilePath);
|
||||
validatePackageJson();
|
||||
} catch (error) {
|
||||
console.error(chalk.red(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
const baseConfig = {
|
||||
mode: 'production',
|
||||
target: 'node',
|
||||
stats: 'errors-only',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const pluginConfig = Object.assign({}, baseConfig, {
|
||||
entry: './src/index.ts',
|
||||
resolve: {
|
||||
alias: {
|
||||
api: path.resolve(__dirname, 'api'),
|
||||
},
|
||||
// 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'],
|
||||
},
|
||||
output: {
|
||||
filename: 'index.js',
|
||||
path: distDir,
|
||||
},
|
||||
plugins: [
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: '**/*',
|
||||
context: path.resolve(__dirname, 'src'),
|
||||
to: path.resolve(__dirname, 'dist'),
|
||||
globOptions: {
|
||||
ignore: [
|
||||
// All TypeScript files are compiled to JS and
|
||||
// already copied into /dist so we don't copy them.
|
||||
'**/*.ts',
|
||||
'**/*.tsx',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const extraScriptConfig = Object.assign({}, baseConfig, {
|
||||
resolve: {
|
||||
alias: {
|
||||
api: path.resolve(__dirname, 'api'),
|
||||
},
|
||||
extensions: ['.tsx', '.ts', '.js', '.json'],
|
||||
},
|
||||
});
|
||||
|
||||
const createArchiveConfig = {
|
||||
stats: 'errors-only',
|
||||
entry: './dist/index.js',
|
||||
output: {
|
||||
filename: 'index.js',
|
||||
path: publishDir,
|
||||
},
|
||||
plugins: [new WebpackOnBuildPlugin(onBuildCompleted)],
|
||||
};
|
||||
|
||||
function resolveExtraScriptPath(name) {
|
||||
const relativePath = `./src/${name}`;
|
||||
|
||||
const fullPath = path.resolve(`${rootDir}/${relativePath}`);
|
||||
if (!fs.pathExistsSync(fullPath)) throw new Error(`Could not find extra script: "${name}" at "${fullPath}"`);
|
||||
|
||||
const s = name.split('.');
|
||||
s.pop();
|
||||
const nameNoExt = s.join('.');
|
||||
|
||||
return {
|
||||
entry: relativePath,
|
||||
output: {
|
||||
filename: `${nameNoExt}.js`,
|
||||
path: distDir,
|
||||
library: 'default',
|
||||
libraryTarget: 'commonjs',
|
||||
libraryExport: 'default',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildExtraScriptConfigs(userConfig) {
|
||||
if (!userConfig.extraScripts.length) return [];
|
||||
|
||||
const output = [];
|
||||
|
||||
for (const scriptName of userConfig.extraScripts) {
|
||||
const scriptPaths = resolveExtraScriptPath(scriptName);
|
||||
output.push(Object.assign({}, extraScriptConfig, {
|
||||
entry: scriptPaths.entry,
|
||||
output: scriptPaths.output,
|
||||
}));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function main(processArgv) {
|
||||
const yargs = require('yargs/yargs');
|
||||
const argv = yargs(processArgv).argv;
|
||||
|
||||
const configName = argv['joplin-plugin-config'];
|
||||
if (!configName) throw new Error('A config file must be specified via the --joplin-plugin-config flag');
|
||||
|
||||
// Webpack configurations run in parallel, while we need them to run in
|
||||
// sequence, and to do that it seems the only way is to run webpack multiple
|
||||
// times, with different config each time.
|
||||
|
||||
const configs = {
|
||||
// Builds the main src/index.ts and copy the extra content from /src to
|
||||
// /dist including scripts, CSS and any other asset.
|
||||
buildMain: [pluginConfig],
|
||||
|
||||
// Builds the extra scripts as defined in plugin.config.json. When doing
|
||||
// so, some JavaScript files that were copied in the previous might be
|
||||
// overwritten here by the compiled version. This is by design. The
|
||||
// result is that JS files that don't need compilation, are simply
|
||||
// copied to /dist, while those that do need it are correctly compiled.
|
||||
buildExtraScripts: buildExtraScriptConfigs(userConfig),
|
||||
|
||||
// Ths config is for creating the .jpl, which is done via the plugin, so
|
||||
// it doesn't actually need an entry and output, however webpack won't
|
||||
// run without this. So we give it an entry that we know is going to
|
||||
// exist and output in the publish dir. Then the plugin will delete this
|
||||
// temporary file before packaging the plugin.
|
||||
createArchive: [createArchiveConfig],
|
||||
};
|
||||
|
||||
// If we are running the first config step, we clean up and create the build
|
||||
// directories.
|
||||
if (configName === 'buildMain') {
|
||||
fs.removeSync(distDir);
|
||||
fs.removeSync(publishDir);
|
||||
fs.mkdirpSync(publishDir);
|
||||
}
|
||||
|
||||
return configs[configName];
|
||||
}
|
||||
|
||||
let exportedConfigs = [];
|
||||
|
||||
try {
|
||||
exportedConfigs = main(process.argv);
|
||||
} catch (error) {
|
||||
console.error(chalk.red(error.message));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!exportedConfigs.length) {
|
||||
// Nothing to do - for example where there are no external scripts to
|
||||
// compile.
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
module.exports = exportedConfigs;
|
||||
@@ -8,46 +8,25 @@ joplin.plugins.register({
|
||||
iconName: 'fas fa-music',
|
||||
});
|
||||
|
||||
await joplin.settings.registerSettings({
|
||||
'myCustomSetting': {
|
||||
value: 123,
|
||||
type: SettingItemType.Int,
|
||||
section: 'myCustomSection',
|
||||
public: true,
|
||||
label: 'My Custom Setting',
|
||||
},
|
||||
await joplin.settings.registerSetting('myCustomSetting', {
|
||||
value: 123,
|
||||
type: SettingItemType.Int,
|
||||
section: 'myCustomSection',
|
||||
public: true,
|
||||
label: 'My Custom Setting',
|
||||
});
|
||||
|
||||
'multiOptionTest': {
|
||||
value: 'en',
|
||||
type: SettingItemType.String,
|
||||
section: 'myCustomSection',
|
||||
isEnum: true,
|
||||
public: true,
|
||||
label: 'Multi-options test',
|
||||
options: {
|
||||
'en': 'English',
|
||||
'fr': 'French',
|
||||
'es': 'Spanish',
|
||||
},
|
||||
},
|
||||
|
||||
'mySecureSetting': {
|
||||
value: 'hunter2',
|
||||
type: SettingItemType.String,
|
||||
section: 'myCustomSection',
|
||||
public: true,
|
||||
secure: true,
|
||||
label: 'My Secure Setting',
|
||||
},
|
||||
|
||||
'myFileSetting': {
|
||||
value: 'abcd',
|
||||
type: SettingItemType.String,
|
||||
section: 'myCustomSection',
|
||||
public: true,
|
||||
label: 'My file setting',
|
||||
description: 'This setting will be saved to settings.json',
|
||||
['storage' as any]: 2, // Should be `storage: SettingStorage.File`
|
||||
await joplin.settings.registerSetting('multiOptionTest', {
|
||||
value: 'en',
|
||||
type: SettingItemType.String,
|
||||
section: 'myCustomSection',
|
||||
isEnum: true,
|
||||
public: true,
|
||||
label: 'Multi-options test',
|
||||
options: {
|
||||
'en': 'English',
|
||||
'fr': 'French',
|
||||
'es': 'Spanish',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -68,11 +47,7 @@ joplin.plugins.register({
|
||||
iconName: 'fas fa-drum',
|
||||
execute: async () => {
|
||||
const value = await joplin.settings.value('myCustomSetting');
|
||||
console.info('Current value is: ' + value);
|
||||
const secureValue = await joplin.settings.value('mySecureSetting');
|
||||
console.info('Secure value is: ' + secureValue);
|
||||
const fileValue = await joplin.settings.value('myFileSetting');
|
||||
console.info('Setting in file is: ' + fileValue);
|
||||
alert('Current value is: ' + value);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@ set -e
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
ROOT_DIR="$SCRIPT_DIR/../../../../.."
|
||||
|
||||
API_BASE_URL="https://test.joplincloud.com"
|
||||
# API_BASE_URL="http://api.joplincloud.local:22300"
|
||||
|
||||
COMMANDS=($(echo $1 | tr "," "\n"))
|
||||
PROFILE_DIR=~/.config/joplindev-testperf
|
||||
|
||||
@@ -19,7 +16,7 @@ for CMD in "${COMMANDS[@]}"
|
||||
do
|
||||
if [[ $CMD == "createUsers" ]]; then
|
||||
|
||||
curl --data '{"action": "createTestUsers"}' -H 'Content-Type: application/json' $API_BASE_URL/api/debug
|
||||
curl --data '{"action": "createTestUsers"}' -H 'Content-Type: application/json' http://api.joplincloud.local:22300/api/debug
|
||||
|
||||
# elif [[ $CMD == "createData" ]]; then
|
||||
|
||||
@@ -35,7 +32,7 @@ do
|
||||
rm -rf "$PROFILE_DIR"
|
||||
echo "config keychain.supported 0" >> "$CMD_FILE"
|
||||
echo "config sync.target 9" >> "$CMD_FILE"
|
||||
echo "config sync.9.path $API_BASE_URL" >> "$CMD_FILE"
|
||||
echo "config sync.9.path http://api.joplincloud.local:22300" >> "$CMD_FILE"
|
||||
echo "config sync.9.username $USER_EMAIL" >> "$CMD_FILE"
|
||||
echo "config sync.9.password 123456" >> "$CMD_FILE"
|
||||
|
||||
@@ -54,5 +51,5 @@ done
|
||||
cd "$ROOT_DIR/packages/app-cli"
|
||||
npm start -- --profile "$PROFILE_DIR" batch "$CMD_FILE"
|
||||
npm start -- --profile "$PROFILE_DIR" import ~/Desktop/Joplin_17_06_2021.jex
|
||||
# npm start -- --profile "$PROFILE_DIR" import ~/Desktop/Tout_18_06_2021.jex
|
||||
npm start -- --profile "$PROFILE_DIR" sync --use-lock 1
|
||||
npm start -- --profile "$PROFILE_DIR" sync
|
||||
|
||||
@@ -106,7 +106,7 @@ browser_.runtime.onMessage.addListener(async (command) => {
|
||||
newArea.height *= ratio;
|
||||
content.crop_rect = newArea;
|
||||
|
||||
fetch(`${command.api_base_url}/notes?token=${encodeURIComponent(command.token)}`, {
|
||||
fetch(`${command.api_base_url}/notes`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,11 +0,0 @@
|
||||
# Updating Readability
|
||||
|
||||
Because of the way content scripts are loaded, we need to manually copy the whole Readability files here. That should be fine since they rarely change.
|
||||
|
||||
The files to update are:
|
||||
|
||||
- Readability.js
|
||||
- Readability-readerable.js (for the function isProbablyReaderable)
|
||||
- JSDOMParser.js
|
||||
|
||||
When updating, **make sure you add the commit and version number at the top of each file**.
|
||||
@@ -1,6 +1,7 @@
|
||||
// v0.4.1 - https://github.com/mozilla/readability/commit/28843b6de84447dd6cef04058fda336938e628dc
|
||||
// https://github.com/mozilla/readability/tree/814f0a3884350b6f1adfdebb79ca3599e9806605
|
||||
|
||||
/* eslint-env es6:false */
|
||||
/* globals exports */
|
||||
/*
|
||||
* Copyright (c) 2010 Arc90 Inc
|
||||
*
|
||||
@@ -25,38 +26,27 @@
|
||||
var REGEXPS = {
|
||||
// NOTE: These two regular expressions are duplicated in
|
||||
// Readability.js. Please keep both copies in sync.
|
||||
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
|
||||
okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i,
|
||||
};
|
||||
|
||||
function isNodeVisible(node) {
|
||||
// Have to null-check node.style and node.className.indexOf to deal with SVG and MathML nodes.
|
||||
return (!node.style || node.style.display != "none")
|
||||
&& !node.hasAttribute("hidden")
|
||||
//check for "fallback-image" so that wikimedia math images are displayed
|
||||
&& (!node.hasAttribute("aria-hidden") || node.getAttribute("aria-hidden") != "true" || (node.className && node.className.indexOf && node.className.indexOf("fallback-image") !== -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether or not the document is reader-able without parsing the whole thing.
|
||||
* @param {Object} options Configuration object.
|
||||
* @param {number} [options.minContentLength=140] The minimum node content length used to decide if the document is readerable.
|
||||
* @param {number} [options.minScore=20] The minumum cumulated 'score' used to determine if the document is readerable.
|
||||
* @param {Function} [options.visibilityChecker=isNodeVisible] The function used to determine if a node is visible.
|
||||
* @return {boolean} Whether or not we suspect Readability.parse() will suceeed at returning an article object.
|
||||
*/
|
||||
function isProbablyReaderable(doc, options = {}) {
|
||||
// For backward compatibility reasons 'options' can either be a configuration object or the function used
|
||||
// to determine if a node is visible.
|
||||
if (typeof options == "function") {
|
||||
options = { visibilityChecker: options };
|
||||
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
|
||||
okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
|
||||
};
|
||||
|
||||
function isNodeVisible(node) {
|
||||
// Have to null-check node.style to deal with SVG and MathML nodes.
|
||||
return (!node.style || node.style.display != 'none') && !node.hasAttribute('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether or not the document is reader-able without parsing the whole thing.
|
||||
*
|
||||
* @return boolean Whether or not we suspect Readability.parse() will suceeed at returning an article object.
|
||||
*/
|
||||
function isProbablyReaderable(doc, isVisible) {
|
||||
if (!isVisible) {
|
||||
isVisible = isNodeVisible;
|
||||
}
|
||||
|
||||
var defaultOptions = { minScore: 20, minContentLength: 140, visibilityChecker: isNodeVisible };
|
||||
options = Object.assign(defaultOptions, options);
|
||||
|
||||
var nodes = doc.querySelectorAll("p, pre");
|
||||
|
||||
|
||||
var nodes = doc.querySelectorAll('p, pre');
|
||||
|
||||
// Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
|
||||
// Some articles' DOM structures might look like
|
||||
// <div>
|
||||
@@ -64,47 +54,46 @@ var REGEXPS = {
|
||||
// <br>
|
||||
// Sentences<br>
|
||||
// </div>
|
||||
var brNodes = doc.querySelectorAll("div > br");
|
||||
var brNodes = doc.querySelectorAll('div > br');
|
||||
if (brNodes.length) {
|
||||
var set = new Set(nodes);
|
||||
[].forEach.call(brNodes, function (node) {
|
||||
set.add(node.parentNode);
|
||||
});
|
||||
nodes = Array.from(set);
|
||||
var set = new Set(nodes);
|
||||
[].forEach.call(brNodes, function(node) {
|
||||
set.add(node.parentNode);
|
||||
});
|
||||
nodes = Array.from(set);
|
||||
}
|
||||
|
||||
|
||||
var score = 0;
|
||||
// This is a little cheeky, we use the accumulator 'score' to decide what to return from
|
||||
// this callback:
|
||||
return [].some.call(nodes, function (node) {
|
||||
if (!options.visibilityChecker(node)) {
|
||||
return [].some.call(nodes, function(node) {
|
||||
if (!isVisible(node))
|
||||
return false;
|
||||
|
||||
var matchString = node.className + ' ' + node.id;
|
||||
if (REGEXPS.unlikelyCandidates.test(matchString) &&
|
||||
!REGEXPS.okMaybeItsACandidate.test(matchString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.matches('li p')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var textContentLength = node.textContent.trim().length;
|
||||
if (textContentLength < 140) {
|
||||
return false;
|
||||
}
|
||||
|
||||
score += Math.sqrt(textContentLength - 140);
|
||||
|
||||
if (score > 20) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var matchString = node.className + " " + node.id;
|
||||
if (REGEXPS.unlikelyCandidates.test(matchString) &&
|
||||
!REGEXPS.okMaybeItsACandidate.test(matchString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.matches("li p")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var textContentLength = node.textContent.trim().length;
|
||||
if (textContentLength < options.minContentLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
score += Math.sqrt(textContentLength - options.minContentLength);
|
||||
|
||||
if (score > options.minScore) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof module === "object") {
|
||||
module.exports = isProbablyReaderable;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof exports === 'object') {
|
||||
exports.isProbablyReaderable = isProbablyReaderable;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -521,7 +521,6 @@
|
||||
name: 'screenshotArea',
|
||||
content: content,
|
||||
api_base_url: command.api_base_url,
|
||||
token: command.token,
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Joplin Web Clipper [DEV]",
|
||||
"version": "2.1.2",
|
||||
"version": "2.1.0",
|
||||
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
|
||||
"homepage_url": "https://joplinapp.org",
|
||||
"content_security_policy": "script-src 'self'; object-src 'self'",
|
||||
|
||||
@@ -2,7 +2,6 @@ body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.App {
|
||||
@@ -14,19 +13,11 @@ body {
|
||||
flex-direction: column;
|
||||
background-color: #162b3d;
|
||||
font-size: 16px;
|
||||
color: #c1e2ff;
|
||||
color: #5A95C7;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.App.Startup {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.App.Startup h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.App h2 {
|
||||
font-size: 1em;
|
||||
margin-top: .5em;
|
||||
@@ -35,7 +26,7 @@ body {
|
||||
}
|
||||
|
||||
.App a {
|
||||
color: #c1e2ff;
|
||||
color: #5A95C7;
|
||||
}
|
||||
|
||||
.App .Disabled {
|
||||
@@ -148,7 +139,7 @@ body {
|
||||
}
|
||||
|
||||
.App .StatusBar {
|
||||
color: #c1e2ff;
|
||||
color: #5A95C7;
|
||||
font-size: .7em;
|
||||
display: flex;
|
||||
flex: 0;
|
||||
|
||||
@@ -50,6 +50,17 @@ class PreviewComponent extends React.PureComponent {
|
||||
<a className={'Confirm Button'} href="#" onClick={this.props.onConfirmClick}>Confirm</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
// return (
|
||||
// <div className="Preview">
|
||||
// <a className={"Confirm Button"} onClick={this.props.onConfirmClick}>Confirm</a>
|
||||
// <h2>Preview:</h2>
|
||||
// <input className={"Title"} value={this.props.title} onChange={this.props.onTitleChange}/>
|
||||
// <div className={"BodyWrapper"}>
|
||||
// <div className={"Body"} ref={this.bodyRef} dangerouslySetInnerHTML={{__html: this.props.body_html}}></div>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,7 +131,6 @@ class AppComponent extends Component {
|
||||
api_base_url: baseUrl,
|
||||
parent_id: this.props.selectedFolderId,
|
||||
tags: this.state.selectedTags.join(','),
|
||||
token: bridge().token(),
|
||||
});
|
||||
|
||||
window.close();
|
||||
@@ -184,8 +194,6 @@ class AppComponent extends Component {
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
bridge().onReactAppStarts();
|
||||
|
||||
try {
|
||||
await this.loadContentScripts();
|
||||
} catch (error) {
|
||||
@@ -234,52 +242,7 @@ class AppComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
renderStartupScreen() {
|
||||
const messages = {
|
||||
serverFoundState: {
|
||||
// We need to display the "Connecting to the Joplin
|
||||
// application..." message because if the app doesn't currently
|
||||
// allow access to the clipper API, the clipper tries several
|
||||
// ports and it takes time before failing. So if we don't
|
||||
// display any message, it looks like it's not doing anything
|
||||
// when clicking on the extension button.
|
||||
'searching': 'Connecting to the Joplin application...',
|
||||
'not_found': 'Error: Could not connect to the Joplin application. Please ensure that it is started and that the clipper service is enabled in the configuration.',
|
||||
},
|
||||
authState: {
|
||||
'starting': 'Starting...',
|
||||
'waiting': 'The Joplin Web Clipper requires your authorisation in order to access your data. To proceed, please open the Joplin desktop application and grant permission. Note: Joplin 2.1+ is needed to use this version of the Web Clipper.',
|
||||
'rejected': 'Permission to access your data was not granted. To try again please close this popup and open it again.',
|
||||
},
|
||||
};
|
||||
|
||||
const foundState = this.props.clipperServer.foundState;
|
||||
|
||||
let msg = '';
|
||||
let title = '';
|
||||
|
||||
if (messages.serverFoundState[foundState]) {
|
||||
msg = messages.serverFoundState[foundState];
|
||||
} else {
|
||||
msg = messages.authState[this.props.authStatus];
|
||||
title = <h1>{'Permission needed'}</h1>;
|
||||
}
|
||||
|
||||
if (!msg) throw new Error(`Invalidate state: ${foundState} / ${this.props.authStatus}`);
|
||||
|
||||
return (
|
||||
<div className="App Startup">
|
||||
{title}
|
||||
{msg}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.authStatus !== 'accepted') {
|
||||
return this.renderStartupScreen();
|
||||
}
|
||||
|
||||
if (!this.state.contentScriptLoaded) {
|
||||
let msg = 'Loading...';
|
||||
if (this.state.contentScriptError) msg = `The Joplin extension is not available on this tab due to: ${this.state.contentScriptError}`;
|
||||
@@ -454,7 +417,6 @@ const mapStateToProps = (state) => {
|
||||
tags: state.tags,
|
||||
selectedFolderId: state.selectedFolderId,
|
||||
isProbablyReaderable: state.isProbablyReaderable,
|
||||
authStatus: state.authStatus,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
const { randomClipperPort } = require('./randomClipperPort');
|
||||
|
||||
function msleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, ms);
|
||||
});
|
||||
}
|
||||
|
||||
class Bridge {
|
||||
|
||||
constructor() {
|
||||
this.nounce_ = Date.now();
|
||||
this.token_ = null;
|
||||
}
|
||||
|
||||
async init(browser, browserSupportsPromises, store) {
|
||||
@@ -85,113 +76,8 @@ class Bridge {
|
||||
type: 'ENV_SET',
|
||||
env: this.env(),
|
||||
});
|
||||
}
|
||||
|
||||
token() {
|
||||
return this.token_;
|
||||
}
|
||||
|
||||
async onReactAppStarts() {
|
||||
await this.findClipperServerPort();
|
||||
|
||||
if (this.clipperServerPortStatus_ !== 'found') {
|
||||
console.info('Skipping initialisation because server port was not found');
|
||||
return;
|
||||
}
|
||||
|
||||
await this.restoreState();
|
||||
|
||||
await this.checkAuth();
|
||||
if (!this.token_) return; // Didn't get a token
|
||||
|
||||
const folders = await this.folderTree();
|
||||
this.dispatch({ type: 'FOLDERS_SET', folders: folders.items ? folders.items : folders });
|
||||
|
||||
let tags = [];
|
||||
for (let page = 1; page < 10000; page++) {
|
||||
const result = await this.clipperApiExec('GET', 'tags', { page: page, order_by: 'title', order_dir: 'ASC' });
|
||||
const resultTags = result.items ? result.items : result;
|
||||
const hasMore = ('has_more' in result) && result.has_more;
|
||||
tags = tags.concat(resultTags);
|
||||
if (!hasMore) break;
|
||||
}
|
||||
|
||||
this.dispatch({ type: 'TAGS_SET', tags: tags });
|
||||
}
|
||||
|
||||
async checkAuth() {
|
||||
this.dispatch({ type: 'AUTH_STATE_SET', value: 'starting' });
|
||||
|
||||
const existingToken = await this.storageGet(['token']);
|
||||
this.token_ = existingToken.token;
|
||||
|
||||
const authCheckResponse = await this.clipperApiExec('GET', 'auth/check', { token: this.token_ });
|
||||
|
||||
if (authCheckResponse.valid) {
|
||||
console.info('checkAuth: we already have a valid token - exiting');
|
||||
this.dispatch({ type: 'AUTH_STATE_SET', value: 'accepted' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.token_ = null;
|
||||
await this.storageSet({ token: this.token_ });
|
||||
|
||||
this.dispatch({ type: 'AUTH_STATE_SET', value: 'waiting' });
|
||||
|
||||
// Note that Firefox and Chrome works differently for this:
|
||||
//
|
||||
// - In Chrome, the popup stays open, even when the user leaves the
|
||||
// browser to grant permission in the application.
|
||||
//
|
||||
// - In Firefox, as soon as the browser loses focus, the popup closes.
|
||||
//
|
||||
// It means we can't rely on local state to get this working - instead
|
||||
// we request the auth token, and cache it to local storage (along
|
||||
// with a timestamp). Then next time the user opens the popup (after
|
||||
// it was automatically closed by Firefox), that cached auth token is
|
||||
// re-used and the auth process continues.
|
||||
//
|
||||
// https://github.com/laurent22/joplin/issues/5125#issuecomment-869547421
|
||||
|
||||
const existingAuthInfo = await this.storageGet(['authToken', 'authTokenTimestamp']);
|
||||
|
||||
let authToken = null;
|
||||
if (existingAuthInfo.authToken && Date.now() - existingAuthInfo.authTokenTimestamp < 5 * 60 * 1000) {
|
||||
console.info('checkAuth: we already have an auth token - reusing it');
|
||||
authToken = existingAuthInfo.authToken;
|
||||
} else {
|
||||
console.info('checkAuth: we do not have an auth token - requesting it...');
|
||||
const response = await this.clipperApiExec('POST', 'auth');
|
||||
authToken = response.auth_token;
|
||||
|
||||
await this.storageSet({ authToken: authToken, authTokenTimestamp: Date.now() });
|
||||
}
|
||||
|
||||
console.info('checkAuth: we do not have a token - requesting one using auth_token: ', authToken);
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const response = await this.clipperApiExec('GET', 'auth/check', { auth_token: authToken });
|
||||
|
||||
if (response.status === 'rejected') {
|
||||
console.info('checkAuth: Auth request was not accepted', response);
|
||||
this.dispatch({ type: 'AUTH_STATE_SET', value: 'rejected' });
|
||||
break;
|
||||
} else if (response.status === 'accepted') {
|
||||
console.info('checkAuth: Auth request was accepted', response);
|
||||
this.dispatch({ type: 'AUTH_STATE_SET', value: 'accepted' });
|
||||
this.token_ = response.token;
|
||||
await this.storageSet({ token: this.token_ });
|
||||
break;
|
||||
} else if (response.status === 'waiting') {
|
||||
await msleep(1000);
|
||||
} else {
|
||||
throw new Error(`Unknown auth/check status: ${response.status}`);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await this.storageSet({ authToken: '', authTokenTimestamp: 0 });
|
||||
}
|
||||
this.findClipperServerPort();
|
||||
}
|
||||
|
||||
async backgroundPage(browser) {
|
||||
@@ -260,6 +146,22 @@ class Bridge {
|
||||
this.clipperServerPortStatus_ = 'found';
|
||||
this.clipperServerPort_ = state.port;
|
||||
this.dispatch({ type: 'CLIPPER_SERVER_SET', foundState: 'found', port: state.port });
|
||||
|
||||
const folders = await this.folderTree();
|
||||
this.dispatch({ type: 'FOLDERS_SET', folders: folders.items ? folders.items : folders });
|
||||
|
||||
let tags = [];
|
||||
for (let page = 1; page < 10000; page++) {
|
||||
const result = await this.clipperApiExec('GET', 'tags', { page: page, order_by: 'title', order_dir: 'ASC' });
|
||||
const resultTags = result.items ? result.items : result;
|
||||
const hasMore = ('has_more' in result) && result.has_more;
|
||||
tags = tags.concat(resultTags);
|
||||
if (!hasMore) break;
|
||||
}
|
||||
|
||||
this.dispatch({ type: 'TAGS_SET', tags: tags });
|
||||
|
||||
bridge().restoreState();
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -409,8 +311,6 @@ class Bridge {
|
||||
|
||||
if (body) fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
|
||||
|
||||
query = Object.assign(query || {}, { token: this.token_ });
|
||||
|
||||
let queryString = '';
|
||||
if (query) {
|
||||
const s = [];
|
||||
|
||||
@@ -19,7 +19,6 @@ const defaultState = {
|
||||
selectedFolderId: null,
|
||||
env: 'prod',
|
||||
isProbablyReaderable: true,
|
||||
authStatus: 'starting',
|
||||
};
|
||||
|
||||
const reduxMiddleware = store => next => async (action) => {
|
||||
@@ -95,11 +94,6 @@ function reducer(state = defaultState, action) {
|
||||
newState = Object.assign({}, state);
|
||||
newState.env = action.env;
|
||||
|
||||
} else if (action.type === 'AUTH_STATE_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.authStatus = action.value;
|
||||
|
||||
}
|
||||
|
||||
return newState;
|
||||
|
||||
@@ -35,7 +35,7 @@ import Tag from '@joplin/lib/models/Tag';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
const packageInfo = require('./packageInfo.js');
|
||||
import DecryptionWorker from '@joplin/lib/services/DecryptionWorker';
|
||||
import ClipperServer from '@joplin/lib/ClipperServer';
|
||||
const ClipperServer = require('@joplin/lib/ClipperServer');
|
||||
const { webFrame } = require('electron');
|
||||
const Menu = bridge().Menu;
|
||||
const PluginManager = require('@joplin/lib/services/PluginManager');
|
||||
@@ -757,7 +757,7 @@ class Application extends BaseApplication {
|
||||
ClipperServer.instance().setDispatch(this.store().dispatch);
|
||||
|
||||
if (Setting.value('clipperServer.autoStart')) {
|
||||
void ClipperServer.instance().start();
|
||||
ClipperServer.instance().start();
|
||||
}
|
||||
|
||||
ExternalEditWatcher.instance().setLogger(reg.logger());
|
||||
|
||||
@@ -3,7 +3,7 @@ const { connect } = require('react-redux');
|
||||
const bridge = require('electron').remote.require('./bridge').default;
|
||||
const { themeStyle } = require('@joplin/lib/theme');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const ClipperServer = require('@joplin/lib/ClipperServer').default;
|
||||
const ClipperServer = require('@joplin/lib/ClipperServer');
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const { clipboard } = require('electron');
|
||||
const ExtensionBadge = require('./ExtensionBadge.min');
|
||||
@@ -44,7 +44,7 @@ class ClipperConfigScreenComponent extends React.Component {
|
||||
if (confirm(_('Are you sure you want to renew the authorisation token?'))) {
|
||||
void EncryptionService.instance()
|
||||
.generateApiToken()
|
||||
.then((token) => {
|
||||
.then((token: string) => {
|
||||
Setting.setValue('api.token', token);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import ButtonBar from './ButtonBar';
|
||||
import Button, { ButtonLevel } from '../Button/Button';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import bridge from '../../services/bridge';
|
||||
import Setting, { AppType, SyncStartupOperation } from '@joplin/lib/models/Setting';
|
||||
import Setting, { SyncStartupOperation } from '@joplin/lib/models/Setting';
|
||||
import control_PluginsStates from './controls/plugins/PluginsStates';
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
@@ -360,7 +360,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
|
||||
const md = Setting.settingMetadata(key);
|
||||
|
||||
const descriptionText = Setting.keyDescription(key, AppType.Desktop);
|
||||
const descriptionText = Setting.keyDescription(key, 'desktop');
|
||||
const descriptionComp = this.renderDescription(this.props.themeId, descriptionText);
|
||||
|
||||
if (settingKeyToControl[key]) {
|
||||
|
||||
@@ -35,7 +35,6 @@ import { ShareInvitation } from '@joplin/lib/services/share/reducer';
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import removeKeylessItems from '../ResizableLayout/utils/removeKeylessItems';
|
||||
import ClipperServer from '@joplin/lib/ClipperServer';
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
const { PromptDialog } = require('../PromptDialog.min.js');
|
||||
@@ -71,7 +70,6 @@ interface Props {
|
||||
startupPluginsLoaded: boolean;
|
||||
shareInvitations: ShareInvitation[];
|
||||
isSafeMode: boolean;
|
||||
needApiAuth: boolean;
|
||||
}
|
||||
|
||||
interface ShareFolderDialogOptions {
|
||||
@@ -508,30 +506,6 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
return this.styles_;
|
||||
}
|
||||
|
||||
private renderNotificationMessage(message: string, callForAction: string, callForActionHandler: Function, callForAction2: string = null, callForActionHandler2: Function = null) {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const urlStyle: any = { color: theme.colorWarnUrl, textDecoration: 'underline' };
|
||||
|
||||
const cfa = (
|
||||
<a href="#" style={urlStyle} onClick={() => callForActionHandler()}>
|
||||
{callForAction}
|
||||
</a>
|
||||
);
|
||||
|
||||
const cfa2 = !callForAction2 ? null : (
|
||||
<a href="#" style={urlStyle} onClick={() => callForActionHandler2()}>
|
||||
{callForAction2}
|
||||
</a>
|
||||
);
|
||||
|
||||
return (
|
||||
<span>
|
||||
{message}{callForAction ? ' ' : ''}
|
||||
{cfa}{callForAction2 ? ' / ' : ''}{cfa2}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
renderNotification(theme: any, styles: any) {
|
||||
if (!this.messageBoxVisible()) return null;
|
||||
|
||||
@@ -570,75 +544,86 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
void reg.scheduleSync(1000);
|
||||
};
|
||||
|
||||
const onApiGrantAuthorization = (accept: boolean) => {
|
||||
ClipperServer.instance().api.acceptAuthToken(accept);
|
||||
};
|
||||
|
||||
let msg = null;
|
||||
|
||||
// When adding something here, don't forget to update the condition in
|
||||
// this.messageBoxVisible()
|
||||
|
||||
if (this.props.needApiAuth) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('The Web Clipper needs your authorisation to access your data.'),
|
||||
_('Grant authorisation'),
|
||||
() => onApiGrantAuthorization(true),
|
||||
_('Reject'),
|
||||
() => onApiGrantAuthorization(false)
|
||||
);
|
||||
} else if (this.props.isSafeMode) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('Safe mode is currently active. Note rendering and all plugins are temporarily disabled.'),
|
||||
_('Disable safe mode and restart'),
|
||||
onDisableSafeModeAndRestart
|
||||
if (this.props.isSafeMode) {
|
||||
msg = (
|
||||
<span>
|
||||
{_('Safe mode is currently active. Note rendering and all plugins are temporarily disabled.')}{' '}
|
||||
<a href="#" onClick={() => onDisableSafeModeAndRestart()}>
|
||||
{_('Disable safe mode and restart')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if (this.props.shouldUpgradeSyncTarget) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('The sync target needs to be upgraded before Joplin can sync. The operation may take a few minutes to complete and the app needs to be restarted. To proceed please click on the link.'),
|
||||
_('Restart and upgrade'),
|
||||
onRestartAndUpgrade
|
||||
msg = (
|
||||
<span>
|
||||
{_('The sync target needs to be upgraded before Joplin can sync. The operation may take a few minutes to complete and the app needs to be restarted. To proceed please click on the link.')}{' '}
|
||||
<a href="#" onClick={() => onRestartAndUpgrade()}>
|
||||
{_('Restart and upgrade')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if (this.props.hasDisabledEncryptionItems) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('Some items cannot be decrypted.'),
|
||||
_('View them now'),
|
||||
onViewStatusScreen
|
||||
msg = (
|
||||
<span>
|
||||
{_('Some items cannot be decrypted.')}{' '}
|
||||
<a href="#" onClick={() => onViewStatusScreen()}>
|
||||
{_('View them now')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if (this.props.showNeedUpgradingMasterKeyMessage) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('One of your master keys use an obsolete encryption method.'),
|
||||
_('View them now'),
|
||||
onViewEncryptionConfigScreen
|
||||
msg = (
|
||||
<span>
|
||||
{_('One of your master keys use an obsolete encryption method.')}{' '}
|
||||
<a href="#" onClick={() => onViewEncryptionConfigScreen()}>
|
||||
{_('View them now')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if (this.props.showShouldReencryptMessage) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('The default encryption method has been changed, you should re-encrypt your data.'),
|
||||
_('More info'),
|
||||
onViewEncryptionConfigScreen
|
||||
msg = (
|
||||
<span>
|
||||
{_('The default encryption method has been changed, you should re-encrypt your data.')}{' '}
|
||||
<a href="#" onClick={() => onViewEncryptionConfigScreen()}>
|
||||
{_('More info')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if (this.showShareInvitationNotification(this.props)) {
|
||||
const invitation = this.props.shareInvitations[0];
|
||||
const sharer = invitation.share.user;
|
||||
|
||||
msg = this.renderNotificationMessage(
|
||||
_('%s (%s) would like to share a notebook with you.', sharer.full_name, sharer.email),
|
||||
_('Accept'),
|
||||
() => onInvitationRespond(invitation.id, true),
|
||||
_('Reject'),
|
||||
() => onInvitationRespond(invitation.id, false)
|
||||
msg = (
|
||||
<span>
|
||||
{_('%s (%s) would like to share a notebook with you.', sharer.full_name, sharer.email)}{' '}
|
||||
<a href="#" onClick={() => onInvitationRespond(invitation.id, true)}>
|
||||
{_('Accept')}
|
||||
</a>
|
||||
{' / '}
|
||||
<a href="#" onClick={() => onInvitationRespond(invitation.id,true)}>
|
||||
{_('Reject')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if (this.props.hasDisabledSyncItems) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('Some items cannot be synchronised.'),
|
||||
_('View them now'),
|
||||
onViewStatusScreen
|
||||
msg = (
|
||||
<span>
|
||||
{_('Some items cannot be synchronised.')}{' '}
|
||||
<a href="#" onClick={() => onViewStatusScreen()}>
|
||||
{_('View them now')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
} else if (this.props.showMissingMasterKeyMessage) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('One or more master keys need a password.'),
|
||||
_('Set the password'),
|
||||
onViewEncryptionConfigScreen
|
||||
msg = (
|
||||
<span>
|
||||
{_('One or more master keys need a password.')}{' '}
|
||||
<a href="#" onClick={() => onViewEncryptionConfigScreen()}>
|
||||
{_('Set the password')}
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -651,7 +636,7 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
|
||||
messageBoxVisible(props: Props = null) {
|
||||
if (!props) props = this.props;
|
||||
return props.hasDisabledSyncItems || props.showMissingMasterKeyMessage || props.showNeedUpgradingMasterKeyMessage || props.showShouldReencryptMessage || props.hasDisabledEncryptionItems || this.props.shouldUpgradeSyncTarget || props.isSafeMode || this.showShareInvitationNotification(props) || this.props.needApiAuth;
|
||||
return props.hasDisabledSyncItems || props.showMissingMasterKeyMessage || props.showNeedUpgradingMasterKeyMessage || props.showShouldReencryptMessage || props.hasDisabledEncryptionItems || this.props.shouldUpgradeSyncTarget || props.isSafeMode || this.showShareInvitationNotification(props);
|
||||
}
|
||||
|
||||
registerCommands() {
|
||||
@@ -877,7 +862,6 @@ const mapStateToProps = (state: AppState) => {
|
||||
startupPluginsLoaded: state.startupPluginsLoaded,
|
||||
shareInvitations: state.shareService.shareInvitations,
|
||||
isSafeMode: state.settings.isSafeMode,
|
||||
needApiAuth: state.needApiAuth,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -442,16 +442,6 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
background-color: ${theme.backgroundColor} !important;
|
||||
}
|
||||
|
||||
/*
|
||||
When creating dialogs, TinyMCE doesn't seem to offer a way to style the components or to assign classes to them.
|
||||
We want the code dialog box text area to be monospace, and since we can't target this precisely, we apply the style
|
||||
to all textareas of all dialogs. As I think only the code dialog displays a textarea that should be fine.
|
||||
*/
|
||||
|
||||
.tox .tox-dialog textarea {
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
|
||||
.tox .tox-editor-header {
|
||||
border: none;
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.1.8",
|
||||
"version": "2.0.11",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.1.8",
|
||||
"version": "2.1.0",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import bridge from '../bridge';
|
||||
const { clipboard, nativeImage } = require('electron');
|
||||
|
||||
interface JoplinViewsDialogs {
|
||||
showMessageBox(message: string): Promise<number>;
|
||||
@@ -17,9 +16,6 @@ interface Components {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// PlatformImplementation provides access to platform specific dependencies,
|
||||
// such as the clipboard, message dialog, etc. It allows having the same plugin
|
||||
// API for all platforms, but with different implementations.
|
||||
export default class PlatformImplementation {
|
||||
|
||||
private static instance_: PlatformImplementation;
|
||||
@@ -31,14 +27,6 @@ export default class PlatformImplementation {
|
||||
return this.instance_;
|
||||
}
|
||||
|
||||
public get clipboard() {
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
public get nativeImage() {
|
||||
return nativeImage;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.components_ = {};
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
# It could be used to develop plugins too.
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/settings"
|
||||
PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/external_assets"
|
||||
npm i --prefix="$PLUGIN_PATH" && npm start -- --dev-plugins "$PLUGIN_PATH"
|
||||
@@ -56,31 +56,26 @@ module.exports = async function(params) {
|
||||
console.log('.');
|
||||
}, 60000);
|
||||
|
||||
try {
|
||||
await electron_notarize.notarize({
|
||||
appBundleId: appId,
|
||||
appPath: appPath,
|
||||
await electron_notarize.notarize({
|
||||
appBundleId: appId,
|
||||
appPath: appPath,
|
||||
|
||||
// Apple Developer email address
|
||||
appleId: process.env.APPLE_ID,
|
||||
// Apple Developer email address
|
||||
appleId: process.env.APPLE_ID,
|
||||
|
||||
// App-specific password: https://support.apple.com/en-us/HT204397
|
||||
appleIdPassword: process.env.APPLE_ID_PASSWORD,
|
||||
// App-specific password: https://support.apple.com/en-us/HT204397
|
||||
appleIdPassword: process.env.APPLE_ID_PASSWORD,
|
||||
|
||||
// When Apple ID is attached to multiple providers (eg if the
|
||||
// account has been used to build multiple apps for different
|
||||
// companies), in that case the provider "Team Short Name" (also
|
||||
// known as "ProviderShortname") must be provided.
|
||||
//
|
||||
// Use this to get it:
|
||||
//
|
||||
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
|
||||
ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
// When Apple ID is attached to multiple providers (eg if the
|
||||
// account has been used to build multiple apps for different
|
||||
// companies), in that case the provider "Team Short Name" (also
|
||||
// known as "ProviderShortname") must be provided.
|
||||
//
|
||||
// Use this to get it:
|
||||
//
|
||||
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
|
||||
ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
});
|
||||
|
||||
clearInterval(waitingIntervalId);
|
||||
|
||||
|
||||
@@ -141,8 +141,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097639
|
||||
versionName "2.1.4"
|
||||
versionCode 2097635
|
||||
versionName "2.1.0"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const React = require('react');
|
||||
|
||||
const { StyleSheet } = require('react-native');
|
||||
const { themeStyle } = require('./global-style.js');
|
||||
|
||||
|
||||
+40
-80
@@ -1,29 +1,28 @@
|
||||
import Slider from '@react-native-community/slider';
|
||||
const React = require('react');
|
||||
const { Platform, Linking, View, Switch, StyleSheet, ScrollView, Text, Button, TouchableOpacity, TextInput, Alert, PermissionsAndroid } = require('react-native');
|
||||
import Setting, { AppType } from '@joplin/lib/models/Setting';
|
||||
import NavService from '@joplin/lib/services/NavService';
|
||||
import ReportService from '@joplin/lib/services/ReportService';
|
||||
import SearchEngine from '@joplin/lib/services/searchengine/SearchEngine';
|
||||
import checkPermissions from '../../utils/checkPermissions';
|
||||
import time from '@joplin/lib/time';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import setIgnoreTlsErrors from '../../utils/TlsUtils';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import { State } from '@joplin/lib/reducer';
|
||||
const VersionInfo = require('react-native-version-info').default;
|
||||
const { Platform, TouchableOpacity, Linking, View, Switch, StyleSheet, Text, Button, ScrollView, TextInput, Alert, PermissionsAndroid } = require('react-native');
|
||||
const { connect } = require('react-redux');
|
||||
const { ScreenHeader } = require('../screen-header.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const { BaseScreenComponent } = require('../base-screen.js');
|
||||
const { Dropdown } = require('../Dropdown.js');
|
||||
const { themeStyle } = require('../global-style.js');
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const shared = require('@joplin/lib/components/shared/config-shared.js');
|
||||
const SyncTargetRegistry = require('@joplin/lib/SyncTargetRegistry');
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const NavService = require('@joplin/lib/services/NavService').default;
|
||||
const VersionInfo = require('react-native-version-info').default;
|
||||
const ReportService = require('@joplin/lib/services/ReportService').default;
|
||||
const time = require('@joplin/lib/time').default;
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
const SearchEngine = require('@joplin/lib/services/searchengine/SearchEngine').default;
|
||||
const RNFS = require('react-native-fs');
|
||||
const checkPermissions = require('../../utils/checkPermissions.js').default;
|
||||
import setIgnoreTlsErrors from '../../utils/TlsUtils';
|
||||
|
||||
class ConfigScreenComponent extends BaseScreenComponent {
|
||||
static navigationOptions(): any {
|
||||
static navigationOptions() {
|
||||
return { header: null };
|
||||
}
|
||||
|
||||
@@ -50,7 +49,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
};
|
||||
|
||||
this.e2eeConfig_ = () => {
|
||||
void NavService.go('EncryptionConfig');
|
||||
NavService.go('EncryptionConfig');
|
||||
};
|
||||
|
||||
this.saveButton_press = async () => {
|
||||
@@ -70,7 +69,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
};
|
||||
|
||||
this.syncStatusButtonPress_ = () => {
|
||||
void NavService.go('Status');
|
||||
NavService.go('Status');
|
||||
};
|
||||
|
||||
this.exportDebugButtonPress_ = async () => {
|
||||
@@ -121,7 +120,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
throw new Error('Permission denied');
|
||||
}
|
||||
|
||||
const copyFiles = async (source: string, dest: string) => {
|
||||
const copyFiles = async (source, dest) => {
|
||||
await shim.fsDriver().mkdir(dest);
|
||||
|
||||
const files = await shim.fsDriver().readDirStats(source);
|
||||
@@ -149,7 +148,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
};
|
||||
|
||||
this.logButtonPress_ = () => {
|
||||
void NavService.go('Log');
|
||||
NavService.go('Log');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -176,7 +175,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
if (this.styles_[themeId]) return this.styles_[themeId];
|
||||
this.styles_ = {};
|
||||
|
||||
const styles: any = {
|
||||
const styles = {
|
||||
body: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-start',
|
||||
@@ -264,7 +263,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
return this.styles_[themeId];
|
||||
}
|
||||
|
||||
renderHeader(key: string, title: string) {
|
||||
renderHeader(key, title) {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
return (
|
||||
<View key={key} style={this.styles().headerWrapperStyle}>
|
||||
@@ -273,7 +272,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
);
|
||||
}
|
||||
|
||||
renderButton(key: string, title: string, clickHandler: Function, options: any = null) {
|
||||
renderButton(key, title, clickHandler, options = null) {
|
||||
if (!options) options = {};
|
||||
|
||||
let descriptionComp = null;
|
||||
@@ -298,7 +297,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
);
|
||||
}
|
||||
|
||||
sectionToComponent(key: string, section: any, settings: any) {
|
||||
sectionToComponent(key, section, settings) {
|
||||
const settingComps = [];
|
||||
|
||||
for (let i = 0; i < section.metadatas.length; i++) {
|
||||
@@ -342,32 +341,12 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
);
|
||||
}
|
||||
|
||||
private renderToggle(key: string, label: string, value: any, updateSettingValue: Function, descriptionComp: any = null) {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
return (
|
||||
<View key={key}>
|
||||
<View style={this.containerStyle(false)}>
|
||||
<Text key="label" style={this.styles().switchSettingText}>
|
||||
{label}
|
||||
</Text>
|
||||
<Switch key="control" style={this.styles().switchSettingControl} trackColor={{ false: theme.dividerColor }} value={value} onValueChange={(value: any) => updateSettingValue(key, value)} />
|
||||
</View>
|
||||
{descriptionComp}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
private containerStyle(hasDescription: boolean): any {
|
||||
return !hasDescription ? this.styles().settingContainer : this.styles().settingContainerNoBottomBorder;
|
||||
}
|
||||
|
||||
settingToComponent(key: string, value: any) {
|
||||
settingToComponent(key, value) {
|
||||
const themeId = this.props.themeId;
|
||||
const theme = themeStyle(themeId);
|
||||
const output: any = null;
|
||||
const output = null;
|
||||
|
||||
const updateSettingValue = (key: string, value: any) => {
|
||||
const updateSettingValue = (key, value) => {
|
||||
return shared.updateSettingValue(this, key, value);
|
||||
};
|
||||
|
||||
@@ -375,7 +354,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
const settingDescription = md.description ? md.description() : '';
|
||||
|
||||
const descriptionComp = !settingDescription ? null : <Text style={this.styles().settingDescriptionText}>{settingDescription}</Text>;
|
||||
const containerStyle = this.containerStyle(!!settingDescription);
|
||||
const containerStyle = !settingDescription ? this.styles().settingContainer : this.styles().settingContainerNoBottomBorder;
|
||||
|
||||
if (md.isEnum) {
|
||||
value = value.toString();
|
||||
@@ -409,7 +388,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
}}
|
||||
onValueChange={(itemValue: any) => {
|
||||
onValueChange={(itemValue) => {
|
||||
updateSettingValue(key, itemValue);
|
||||
}}
|
||||
/>
|
||||
@@ -418,18 +397,17 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
</View>
|
||||
);
|
||||
} else if (md.type == Setting.TYPE_BOOL) {
|
||||
return this.renderToggle(key, md.label(), value, updateSettingValue, descriptionComp);
|
||||
// return (
|
||||
// <View key={key}>
|
||||
// <View style={containerStyle}>
|
||||
// <Text key="label" style={this.styles().switchSettingText}>
|
||||
// {md.label()}
|
||||
// </Text>
|
||||
// <Switch key="control" style={this.styles().switchSettingControl} trackColor={{ false: theme.dividerColor }} value={value} onValueChange={(value:any) => updateSettingValue(key, value)} />
|
||||
// </View>
|
||||
// {descriptionComp}
|
||||
// </View>
|
||||
// );
|
||||
return (
|
||||
<View key={key}>
|
||||
<View style={containerStyle}>
|
||||
<Text key="label" style={this.styles().switchSettingText}>
|
||||
{md.label()}
|
||||
</Text>
|
||||
<Switch key="control" style={this.styles().switchSettingControl} trackColor={{ false: theme.dividerColor }} value={value} onValueChange={value => updateSettingValue(key, value)} />
|
||||
</View>
|
||||
{descriptionComp}
|
||||
</View>
|
||||
);
|
||||
} else if (md.type == Setting.TYPE_INT) {
|
||||
const unitLabel = md.unitLabel ? md.unitLabel(value) : value;
|
||||
// Note: Do NOT add the minimumTrackTintColor and maximumTrackTintColor props
|
||||
@@ -453,7 +431,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
<Text key="label" style={this.styles().settingText}>
|
||||
{md.label()}
|
||||
</Text>
|
||||
<TextInput autoCorrect={false} autoCompleteType="off" selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} autoCapitalize="none" key="control" style={this.styles().settingControl} value={value} onChangeText={(value: any) => updateSettingValue(key, value)} secureTextEntry={!!md.secure} />
|
||||
<TextInput autoCorrect={false} autoCompleteType="off" selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} autoCapitalize="none" key="control" style={this.styles().settingControl} value={value} onChangeText={value => updateSettingValue(key, value)} secureTextEntry={!!md.secure} />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
@@ -463,18 +441,6 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
return output;
|
||||
}
|
||||
|
||||
private renderFeatureFlags(settings: any, featureFlagKeys: string[]): any[] {
|
||||
const updateSettingValue = (key: string, value: any) => {
|
||||
return shared.updateSettingValue(this, key, value);
|
||||
};
|
||||
|
||||
const output: any[] = [];
|
||||
for (const key of featureFlagKeys) {
|
||||
output.push(this.renderToggle(key, key, settings[key], updateSettingValue));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
render() {
|
||||
const settings = this.state.settings;
|
||||
|
||||
@@ -498,7 +464,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
const profileExportPrompt = (
|
||||
<View style={this.styles().settingContainer} key="profileExport">
|
||||
<Text style={this.styles().settingText}>Path:</Text>
|
||||
<TextInput style={{ ...this.styles().textInput, paddingRight: 20 }} onChange={(event: any) => this.setState({ profileExportPath: event.nativeEvent.text })} value={this.state.profileExportPath} placeholder="/path/to/sdcard" keyboardAppearance={theme.keyboardAppearance}></TextInput>
|
||||
<TextInput style={{ ...this.styles().textInput, paddingRight: 20 }} onChange={(event) => this.setState({ profileExportPath: event.nativeEvent.text })} value={this.state.profileExportPath} placeholder="/path/to/sdcard" keyboardAppearance={theme.keyboardAppearance}></TextInput>
|
||||
<Button title="OK" onPress={this.exportProfileButtonPress2_}></Button>
|
||||
</View>
|
||||
);
|
||||
@@ -507,12 +473,6 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
const featureFlagKeys = Setting.featureFlagKeys(AppType.Mobile);
|
||||
if (featureFlagKeys.length) {
|
||||
settingComps.push(this.renderHeader('featureFlags', _('Feature flags')));
|
||||
settingComps.push(<View key="featureFlagsContainer">{this.renderFeatureFlags(settings, featureFlagKeys)}</View>);
|
||||
}
|
||||
|
||||
settingComps.push(this.renderHeader('moreInfo', _('More information')));
|
||||
|
||||
if (Platform.OS === 'android' && Platform.Version >= 23) {
|
||||
@@ -608,11 +568,11 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
const ConfigScreen = connect((state: State) => {
|
||||
const ConfigScreen = connect(state => {
|
||||
return {
|
||||
settings: state.settings,
|
||||
themeId: state.settings.theme,
|
||||
};
|
||||
})(ConfigScreenComponent);
|
||||
|
||||
export default ConfigScreen;
|
||||
module.exports = { ConfigScreen };
|
||||
@@ -486,13 +486,13 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 69;
|
||||
CURRENT_PROJECT_VERSION = 68;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 12.1.1;
|
||||
MARKETING_VERSION = 12.1.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -514,12 +514,12 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 69;
|
||||
CURRENT_PROJECT_VERSION = 68;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 12.1.1;
|
||||
MARKETING_VERSION = 12.1.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -659,14 +659,14 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 69;
|
||||
CURRENT_PROJECT_VERSION = 68;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 12.1.1;
|
||||
MARKETING_VERSION = 12.1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
|
||||
@@ -690,14 +690,14 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 69;
|
||||
CURRENT_PROJECT_VERSION = 68;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 12.1.1;
|
||||
MARKETING_VERSION = 12.1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
hash:"6608023b8053b48e0eec248644475e33", files: {
|
||||
hash:"45572502e8b0a8e9b85192de7291684c", files: {
|
||||
'highlight.js/atom-one-dark-reasonable.css': { data: require('./highlight.js/atom-one-dark-reasonable.css.base64.js'), mime: 'text/css', encoding: 'base64' },
|
||||
'highlight.js/atom-one-light.css': { data: require('./highlight.js/atom-one-light.css.base64.js'), mime: 'text/css', encoding: 'base64' },
|
||||
'katex/fonts/KaTeX_AMS-Regular.woff2': { data: require('./katex/fonts/KaTeX_AMS-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = `IWZ1bmN0aW9uKHQsZSl7Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzJiYib2JqZWN0Ij09dHlwZW9mIG1vZHVsZT9tb2R1bGUuZXhwb3J0cz1lKCk6ImZ1bmN0aW9uIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZD9kZWZpbmUoW10sZSk6Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzP2V4cG9ydHMubWVybWFpZD1lKCk6dC5tZXJtYWlkPWUoKX0oInVuZGVmaW5lZCIhPXR5cGVvZiBzZWxmP3NlbGY6dGhpcywoZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24odCl7dmFyIGU9e307ZnVuY3Rpb24gbihyKXtpZihlW3JdKXJldHVybiBlW3JdLmV4cG9ydHM7dmFyIGk9ZVtyXT17aTpyLGw6ITEsZXhwb3J0czp7fX07cmV0dXJuIHRbcl0uY2FsbChpLmV4cG9ydHMsaSxpLmV4cG9ydHMsbiksaS5sPSEwLGkuZXhwb3J0c31yZXR1cm4gbi5tPXQsbi5jPWUsbi5kPWZ1bmN0aW9uKHQsZSxyKXtuLm8odCxlKXx8T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsZSx7ZW51bWVyYWJsZTohMCxnZXQ6cn0pfSxuLnI9ZnVuY3Rpb24odCl7InVuZGVmaW5lZCIhPXR5cGVvZiBTeW1ib2wmJlN5bWJvbC50b1N0cmluZ1RhZyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsU3ltYm9sLnRvU3RyaW5nVGFnLHt2YWx1ZToiTW9kdWxlIn0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KX0sbi50PWZ1bmN0aW9uKHQsZSl7aWYoMSZlJiYodD1uKHQpKSw4JmUpcmV0dXJuIHQ7aWYoNCZlJiYib2JqZWN0Ij09dHlwZW9mIHQmJnQmJnQuX19lc01vZHVsZSlyZXR1cm4gdDt2YXIgcj1PYmplY3QuY3JlYXRlKG51bGwpO2lmKG4ucihyKSxPYmplY3QuZGVmaW5lUHJvcGVydHkociwiZGVmYXVsdCIse2VudW1lcmFibGU6ITAsdmFsdWU6dH0pLDImZSYmInN0cmluZyIhPXR5cGVvZiB0KWZvcih2YXIgaSBpbiB0KW4uZChyLGksZnVuY3Rpb24oZSl7cmV0dXJuIHRbZV19LmJpbmQobnVsbCxpKSk7cmV0dXJuIHJ9LG4ubj1mdW5jdGlvbih0KXt2YXIgZT10JiZ0Ll9fZXNNb2R1bGU/ZnVuY3Rpb24oKXtyZXR1cm4gdC5kZWZhdWx0fTpmdW5jdGlvbigpe3JldHVybiB0fTtyZXR1cm4gbi5kKGUsImEiLGUpLGV9LG4ubz1mdW5jdGlvbih0LGUpe3JldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxlKX0sbi5wPSIiLG4obi5zPTM4NCl9KFtmdW5jdGlvbih0LGUsbil7InVzZSBzdHJpY3QiO24ucihlKTt2YXIgcj1mdW5jdGlvbih0LGUpe3JldHVybiB0PGU/LTE6dD5lPzE6dD49ZT8wOk5hTn0saT1mdW5jdGlvbih0KXt2YXIgZTtyZXR1cm4gMT09PXQubGVuZ3RoJiYoZT10LHQ9ZnVuY3Rpb24odCxuKXtyZXR1cm4gcihlKHQpLG4pfSkse2xlZnQ6ZnVuY3Rpb24oZSxuLHIsaSl7Zm9yKG51bGw9PXImJihyPTApLG51bGw9PWkmJihpPWUubGVuZ3RoKTtyPGk7KXt2YXIgYT1yK2k+Pj4xO3QoZVthXSxuKTwwP3I9YSsxOmk9YX1yZXR1cm4gcn0scmlnaHQ6ZnVuY3Rpb24oZSxuLHIsaSl7Zm9yKG51bGw9PXImJihyPTApLG51bGw9PWkmJihpPWUubGVuZ3RoKTtyPGk7KXt2YXIgYT1yK2k+Pj4xO3QoZVthXSxuKT4wP2k9YTpyPWErMX1yZXR1cm4gcn19fTt2YXIgYT1pKHIpLG89YS5yaWdodCxzPWEubGVmdCxjPW8sdT1mdW5jdGlvbih0LGUpe251bGw9PWUmJihlPWwpO2Zvcih2YXIgbj0wLHI9dC5sZW5ndGgtMSxpPXRbMF0sYT1uZXcgQXJyYXkocjwwPzA6cik7bjxyOylhW25dPWUoaSxpPXRbKytuXSk7cmV0dXJuIGF9O2Z1bmN0aW9uIGwodCxlKXtyZXR1cm5bdCxlXX12YXIgaD1mdW5jdGlvbih0LGUsbil7dmFyIHIsaSxhLG8scz10Lmxlbmd0aCxjPWUubGVuZ3RoLHU9bmV3IEFycmF5KHMqYyk7Zm9yKG51bGw9PW4mJihuPWwpLHI9YT0wO3I8czsrK3IpZm9yKG89dFtyXSxpPTA7aTxjOysraSwrK2EpdVthXT1uKG8sZVtpXSk7cmV0dXJuIHV9LGY9ZnVuY3Rpb24odCxlKXtyZXR1cm4gZTx0Py0xOmU+dD8xOmU+PXQ/MDpOYU59LGQ9ZnVuY3Rpb24odCl7cmV0dXJuIG51bGw9PT10P05hTjordH0scD1mdW5jdGlvbih0LGUpe3ZhciBuLHIsaT10Lmxlbmd0aCxhPTAsbz0tMSxzPTAsYz0wO2lmKG51bGw9PWUpZm9yKDsrK288aTspaXNOYU4obj1kKHRbb10pKXx8KGMrPShyPW4tcykqKG4tKHMrPXIvKythKSkpO2Vsc2UgZm9yKDsrK288aTspaXNOYU4obj1kKGUodFtvXSxvLHQpKSl8fChjKz0ocj1uLXMpKihuLShzKz1yLysrYSkpKTtpZihhPjEpcmV0dXJuIGMvKGEtMSl9LHk9ZnVuY3Rpb24odCxlKXt2YXIgbj1wKHQsZSk7cmV0dXJuIG4/TWF0aC5zcXJ0KG4pOm59LGc9ZnVuY3Rpb24odCxlKXt2YXIgbixyLGksYT10Lmxlbmd0aCxvPS0xO2lmKG51bGw9PWUpe2Zvcig7KytvPGE7KWlmKG51bGwhPShuPXRbb10pJiZuPj1uKWZvcihyPWk9bjsrK288YTspbnVsbCE9KG49dFtvXSkmJihyPm4mJihyPW4pLGk8biYmKGk9bikpfWVsc2UgZm9yKDsrK288YTspaWYobnVsbCE9KG49ZSh0W29dLG8sdCkpJiZuPj1uKWZvcihyPWk9bjsrK288YTspbnVsbCE9KG49ZSh0W29dLG8sdCkpJiYocj5uJiYocj1uKSxpPG4mJihpPW4pKTtyZXR1cm5bcixpXX0sdj1BcnJheS5wcm90b3R5cGUsbT12LnNsaWNlLGI9di5tYXAseD1mdW5jdGlvbih0KXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gdH19LF89ZnVuY3Rpb24odCl7cmV0dXJuIHR9LGs9ZnVuY3Rpb24odCxlLG4pe3Q9K3QsZT0rZSxuPShpPWFyZ3VtZW50cy5sZW5ndGgpPDI/KGU9dCx0PTAsMSk6aTwzPzE6K247Zm9yKHZhciByPS0xLGk9MHxNYXRoLm1heCgwLE1hdGguY2VpbCgoZS10KS9uKSksYT1uZXcgQXJyYXkoaSk7KytyPGk7KWFbcl09dCtyKm47cmV0dXJuIGF9LHc9TWF0aC5zcXJ0KDUwKSxFPU1hdGguc3FydCgxMCksVD1NYXRoLnNxcnQoMiksQz1mdW5jdGlvbih0LGUsbil7dmFyIHIsaSxhLG8scz0tMTtpZihuPStuLCh0PSt0KT09PShlPStlKSYmbj4wKXJldHVyblt0XTtpZigocj1lPHQpJiYoaT10LHQ9ZSxlPWkpLDA9PT0obz1TKHQsZSxuKSl8fCFpc0Zpbml0ZShvKSlyZXR1cm5bXTtpZihvPjApZm9yKHQ9TWF0aC5jZWlsKHQvbyksZT1NYXRoLmZsb29yKGUvbyksYT1uZXcgQXJyYXkoaT1NYXRoLmNlaWwoZS10KzEpKTsrK3M8aTspYVtzXT0odCtzKSpvO2Vsc2UgZm9yKHQ9TWF0aC5mbG9vcih0Km8pLGU9TWF0aC5jZWlsKGUqbyksYT1uZXcgQXJyYXkoaT1NYXRoLmNlaWwodC1lKzEpKTsrK3M8aTspYVtzXT0odC1zKS9vO3JldHVybiByJiZhLnJldmVyc2UoKSxhfTtmdW5jdGlvbiBTKHQsZSxuKXt2YXIgcj0oZS10KS9NYXRoLm1heCgwLG4pLGk9TWF0aC5mbG9vcihNYXRoLmxvZyhyKS9NYXRoLkxOMTApLGE9ci9NYXRoLnBvdygxMCxpKTtyZXR1cm4gaT49MD8oYT49dz8xMDphPj1FPzU6YT49VD8yOjEpKk1hdGgucG93KDEwLGkpOi1NYXRoLnBvdygxMCwtaSkvKGE+PXc/MTA6YT49RT81OmE+PVQ/MjoxKX1mdW5jdGlvbiBBKHQsZSxuKXt2YXIgcj1NYXRoLmFicyhlLXQpL01hdGgubWF4KDAsbiksaT1NYXRoLnBvdygxMCxNYXRoLmZsb29yKE1hdGgubG9nKHIpL01hdGguTE4xMCkpLGE9ci9pO3JldHVybiBhPj13P2kqPTEwOmE+PUU/aSo9NTphPj1UJiYoaSo9MiksZTx0Py1pOml9dmFyIE09ZnVuY3Rpb24odCl7cmV0dXJuIE1hdGguY2VpbChNYXRoLmxvZyh0Lmxlbmd0aCkvTWF0aC5MTjIpKzF9LE89ZnVuY3Rpb24oKXt2YXIgdD1fLGU9ZyxuPU07ZnVuY3Rpb24gcihyKXt2YXIgaSxhLG89ci5sZW5ndGgscz1uZXcgQXJyYXkobyk7Zm9yKGk9MDtpPG87KytpKXNbaV09dChyW2ldL
Line truncated
|
||||
module.exports = `IWZ1bmN0aW9uKHQsZSl7Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzJiYib2JqZWN0Ij09dHlwZW9mIG1vZHVsZT9tb2R1bGUuZXhwb3J0cz1lKCk6ImZ1bmN0aW9uIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZD9kZWZpbmUoW10sZSk6Im9iamVjdCI9PXR5cGVvZiBleHBvcnRzP2V4cG9ydHMubWVybWFpZD1lKCk6dC5tZXJtYWlkPWUoKX0oInVuZGVmaW5lZCIhPXR5cGVvZiBzZWxmP3NlbGY6dGhpcywoZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24odCl7dmFyIGU9e307ZnVuY3Rpb24gbihyKXtpZihlW3JdKXJldHVybiBlW3JdLmV4cG9ydHM7dmFyIGk9ZVtyXT17aTpyLGw6ITEsZXhwb3J0czp7fX07cmV0dXJuIHRbcl0uY2FsbChpLmV4cG9ydHMsaSxpLmV4cG9ydHMsbiksaS5sPSEwLGkuZXhwb3J0c31yZXR1cm4gbi5tPXQsbi5jPWUsbi5kPWZ1bmN0aW9uKHQsZSxyKXtuLm8odCxlKXx8T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsZSx7ZW51bWVyYWJsZTohMCxnZXQ6cn0pfSxuLnI9ZnVuY3Rpb24odCl7InVuZGVmaW5lZCIhPXR5cGVvZiBTeW1ib2wmJlN5bWJvbC50b1N0cmluZ1RhZyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsU3ltYm9sLnRvU3RyaW5nVGFnLHt2YWx1ZToiTW9kdWxlIn0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KX0sbi50PWZ1bmN0aW9uKHQsZSl7aWYoMSZlJiYodD1uKHQpKSw4JmUpcmV0dXJuIHQ7aWYoNCZlJiYib2JqZWN0Ij09dHlwZW9mIHQmJnQmJnQuX19lc01vZHVsZSlyZXR1cm4gdDt2YXIgcj1PYmplY3QuY3JlYXRlKG51bGwpO2lmKG4ucihyKSxPYmplY3QuZGVmaW5lUHJvcGVydHkociwiZGVmYXVsdCIse2VudW1lcmFibGU6ITAsdmFsdWU6dH0pLDImZSYmInN0cmluZyIhPXR5cGVvZiB0KWZvcih2YXIgaSBpbiB0KW4uZChyLGksZnVuY3Rpb24oZSl7cmV0dXJuIHRbZV19LmJpbmQobnVsbCxpKSk7cmV0dXJuIHJ9LG4ubj1mdW5jdGlvbih0KXt2YXIgZT10JiZ0Ll9fZXNNb2R1bGU/ZnVuY3Rpb24oKXtyZXR1cm4gdC5kZWZhdWx0fTpmdW5jdGlvbigpe3JldHVybiB0fTtyZXR1cm4gbi5kKGUsImEiLGUpLGV9LG4ubz1mdW5jdGlvbih0LGUpe3JldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxlKX0sbi5wPSIiLG4obi5zPTM4Myl9KFtmdW5jdGlvbih0LGUsbil7InVzZSBzdHJpY3QiO24ucihlKTt2YXIgcj1mdW5jdGlvbih0LGUpe3JldHVybiB0PGU/LTE6dD5lPzE6dD49ZT8wOk5hTn0saT1mdW5jdGlvbih0KXt2YXIgZTtyZXR1cm4gMT09PXQubGVuZ3RoJiYoZT10LHQ9ZnVuY3Rpb24odCxuKXtyZXR1cm4gcihlKHQpLG4pfSkse2xlZnQ6ZnVuY3Rpb24oZSxuLHIsaSl7Zm9yKG51bGw9PXImJihyPTApLG51bGw9PWkmJihpPWUubGVuZ3RoKTtyPGk7KXt2YXIgYT1yK2k+Pj4xO3QoZVthXSxuKTwwP3I9YSsxOmk9YX1yZXR1cm4gcn0scmlnaHQ6ZnVuY3Rpb24oZSxuLHIsaSl7Zm9yKG51bGw9PXImJihyPTApLG51bGw9PWkmJihpPWUubGVuZ3RoKTtyPGk7KXt2YXIgYT1yK2k+Pj4xO3QoZVthXSxuKT4wP2k9YTpyPWErMX1yZXR1cm4gcn19fTt2YXIgYT1pKHIpLG89YS5yaWdodCxzPWEubGVmdCxjPW8sdT1mdW5jdGlvbih0LGUpe251bGw9PWUmJihlPWwpO2Zvcih2YXIgbj0wLHI9dC5sZW5ndGgtMSxpPXRbMF0sYT1uZXcgQXJyYXkocjwwPzA6cik7bjxyOylhW25dPWUoaSxpPXRbKytuXSk7cmV0dXJuIGF9O2Z1bmN0aW9uIGwodCxlKXtyZXR1cm5bdCxlXX12YXIgaD1mdW5jdGlvbih0LGUsbil7dmFyIHIsaSxhLG8scz10Lmxlbmd0aCxjPWUubGVuZ3RoLHU9bmV3IEFycmF5KHMqYyk7Zm9yKG51bGw9PW4mJihuPWwpLHI9YT0wO3I8czsrK3IpZm9yKG89dFtyXSxpPTA7aTxjOysraSwrK2EpdVthXT1uKG8sZVtpXSk7cmV0dXJuIHV9LGY9ZnVuY3Rpb24odCxlKXtyZXR1cm4gZTx0Py0xOmU+dD8xOmU+PXQ/MDpOYU59LGQ9ZnVuY3Rpb24odCl7cmV0dXJuIG51bGw9PT10P05hTjordH0scD1mdW5jdGlvbih0LGUpe3ZhciBuLHIsaT10Lmxlbmd0aCxhPTAsbz0tMSxzPTAsYz0wO2lmKG51bGw9PWUpZm9yKDsrK288aTspaXNOYU4obj1kKHRbb10pKXx8KGMrPShyPW4tcykqKG4tKHMrPXIvKythKSkpO2Vsc2UgZm9yKDsrK288aTspaXNOYU4obj1kKGUodFtvXSxvLHQpKSl8fChjKz0ocj1uLXMpKihuLShzKz1yLysrYSkpKTtpZihhPjEpcmV0dXJuIGMvKGEtMSl9LGc9ZnVuY3Rpb24odCxlKXt2YXIgbj1wKHQsZSk7cmV0dXJuIG4/TWF0aC5zcXJ0KG4pOm59LHk9ZnVuY3Rpb24odCxlKXt2YXIgbixyLGksYT10Lmxlbmd0aCxvPS0xO2lmKG51bGw9PWUpe2Zvcig7KytvPGE7KWlmKG51bGwhPShuPXRbb10pJiZuPj1uKWZvcihyPWk9bjsrK288YTspbnVsbCE9KG49dFtvXSkmJihyPm4mJihyPW4pLGk8biYmKGk9bikpfWVsc2UgZm9yKDsrK288YTspaWYobnVsbCE9KG49ZSh0W29dLG8sdCkpJiZuPj1uKWZvcihyPWk9bjsrK288YTspbnVsbCE9KG49ZSh0W29dLG8sdCkpJiYocj5uJiYocj1uKSxpPG4mJihpPW4pKTtyZXR1cm5bcixpXX0sdj1BcnJheS5wcm90b3R5cGUsbT12LnNsaWNlLGI9di5tYXAseD1mdW5jdGlvbih0KXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gdH19LF89ZnVuY3Rpb24odCl7cmV0dXJuIHR9LGs9ZnVuY3Rpb24odCxlLG4pe3Q9K3QsZT0rZSxuPShpPWFyZ3VtZW50cy5sZW5ndGgpPDI/KGU9dCx0PTAsMSk6aTwzPzE6K247Zm9yKHZhciByPS0xLGk9MHxNYXRoLm1heCgwLE1hdGguY2VpbCgoZS10KS9uKSksYT1uZXcgQXJyYXkoaSk7KytyPGk7KWFbcl09dCtyKm47cmV0dXJuIGF9LHc9TWF0aC5zcXJ0KDUwKSxFPU1hdGguc3FydCgxMCksVD1NYXRoLnNxcnQoMiksQz1mdW5jdGlvbih0LGUsbil7dmFyIHIsaSxhLG8scz0tMTtpZihuPStuLCh0PSt0KT09PShlPStlKSYmbj4wKXJldHVyblt0XTtpZigocj1lPHQpJiYoaT10LHQ9ZSxlPWkpLDA9PT0obz1TKHQsZSxuKSl8fCFpc0Zpbml0ZShvKSlyZXR1cm5bXTtpZihvPjApZm9yKHQ9TWF0aC5jZWlsKHQvbyksZT1NYXRoLmZsb29yKGUvbyksYT1uZXcgQXJyYXkoaT1NYXRoLmNlaWwoZS10KzEpKTsrK3M8aTspYVtzXT0odCtzKSpvO2Vsc2UgZm9yKHQ9TWF0aC5mbG9vcih0Km8pLGU9TWF0aC5jZWlsKGUqbyksYT1uZXcgQXJyYXkoaT1NYXRoLmNlaWwodC1lKzEpKTsrK3M8aTspYVtzXT0odC1zKS9vO3JldHVybiByJiZhLnJldmVyc2UoKSxhfTtmdW5jdGlvbiBTKHQsZSxuKXt2YXIgcj0oZS10KS9NYXRoLm1heCgwLG4pLGk9TWF0aC5mbG9vcihNYXRoLmxvZyhyKS9NYXRoLkxOMTApLGE9ci9NYXRoLnBvdygxMCxpKTtyZXR1cm4gaT49MD8oYT49dz8xMDphPj1FPzU6YT49VD8yOjEpKk1hdGgucG93KDEwLGkpOi1NYXRoLnBvdygxMCwtaSkvKGE+PXc/MTA6YT49RT81OmE+PVQ/MjoxKX1mdW5jdGlvbiBBKHQsZSxuKXt2YXIgcj1NYXRoLmFicyhlLXQpL01hdGgubWF4KDAsbiksaT1NYXRoLnBvdygxMCxNYXRoLmZsb29yKE1hdGgubG9nKHIpL01hdGguTE4xMCkpLGE9ci9pO3JldHVybiBhPj13P2kqPTEwOmE+PUU/aSo9NTphPj1UJiYoaSo9MiksZTx0Py1pOml9dmFyIE09ZnVuY3Rpb24odCl7cmV0dXJuIE1hdGguY2VpbChNYXRoLmxvZyh0Lmxlbmd0aCkvTWF0aC5MTjIpKzF9LE89ZnVuY3Rpb24oKXt2YXIgdD1fLGU9eSxuPU07ZnVuY3Rpb24gcihyKXt2YXIgaSxhLG89ci5sZW5ndGgscz1uZXcgQXJyYXkobyk7Zm9yKGk9MDtpPG87KytpKXNbaV09dChyW2ldL
Line truncated
|
||||
@@ -57,7 +57,7 @@ import JoplinDatabase from '@joplin/lib/JoplinDatabase';
|
||||
import Database from '@joplin/lib/database';
|
||||
const { NotesScreen } = require('./components/screens/notes.js');
|
||||
const { TagsScreen } = require('./components/screens/tags.js');
|
||||
import ConfigScreen from './components/screens/ConfigScreen';
|
||||
const { ConfigScreen } = require('./components/screens/config.js');
|
||||
const { FolderScreen } = require('./components/screens/folder.js');
|
||||
const { LogScreen } = require('./components/screens/log.js');
|
||||
const { StatusScreen } = require('./components/screens/status.js');
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/fork-htmlparser2",
|
||||
"version": "4.1.28",
|
||||
"version": "4.1.27",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@joplin/fork-htmlparser2",
|
||||
"description": "Fast & forgiving HTML/XML/RSS parser",
|
||||
"version": "4.1.28",
|
||||
"version": "4.1.27",
|
||||
"author": "Felix Boehm <me@feedic.com>",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/fork-sax",
|
||||
"version": "1.2.32",
|
||||
"version": "1.2.31",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@joplin/fork-sax",
|
||||
"description": "An evented streaming XML parser in JavaScript",
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
||||
"version": "1.2.32",
|
||||
"version": "1.2.31",
|
||||
"main": "lib/sax.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -1,31 +1,18 @@
|
||||
import Setting from './models/Setting';
|
||||
import Logger from './Logger';
|
||||
import Api, { RequestFile } from './services/rest/Api';
|
||||
import ApiResponse from './services/rest/ApiResponse';
|
||||
const urlParser = require('url');
|
||||
const Setting = require('./models/Setting').default;
|
||||
const Logger = require('./Logger').default;
|
||||
const { randomClipperPort, startPort } = require('./randomClipperPort');
|
||||
const enableServerDestroy = require('server-destroy');
|
||||
const Api = require('./services/rest/Api').default;
|
||||
const ApiResponse = require('./services/rest/ApiResponse').default;
|
||||
const multiparty = require('multiparty');
|
||||
|
||||
export enum StartState {
|
||||
Idle = 'idle',
|
||||
Starting = 'starting',
|
||||
Started = 'started',
|
||||
}
|
||||
|
||||
export default class ClipperServer {
|
||||
|
||||
private logger_: Logger;
|
||||
private startState_: StartState = StartState.Idle;
|
||||
private server_: any = null;
|
||||
private port_: number = null;
|
||||
private api_: Api = null;
|
||||
private dispatch_: Function;
|
||||
|
||||
private static instance_: ClipperServer = null;
|
||||
|
||||
class ClipperServer {
|
||||
constructor() {
|
||||
this.logger_ = new Logger();
|
||||
this.startState_ = 'idle';
|
||||
this.server_ = null;
|
||||
this.port_ = null;
|
||||
}
|
||||
|
||||
static instance() {
|
||||
@@ -34,17 +21,13 @@ export default class ClipperServer {
|
||||
return this.instance_;
|
||||
}
|
||||
|
||||
public get api(): Api {
|
||||
return this.api_;
|
||||
}
|
||||
|
||||
initialize(actionApi: any = null) {
|
||||
initialize(actionApi = null) {
|
||||
this.api_ = new Api(() => {
|
||||
return Setting.value('api.token');
|
||||
}, (action: any) => { this.dispatch(action); }, actionApi);
|
||||
}, actionApi);
|
||||
}
|
||||
|
||||
setLogger(l: Logger) {
|
||||
setLogger(l) {
|
||||
this.logger_ = l;
|
||||
}
|
||||
|
||||
@@ -52,16 +35,16 @@ export default class ClipperServer {
|
||||
return this.logger_;
|
||||
}
|
||||
|
||||
setDispatch(d: Function) {
|
||||
setDispatch(d) {
|
||||
this.dispatch_ = d;
|
||||
}
|
||||
|
||||
dispatch(action: any) {
|
||||
dispatch(action) {
|
||||
if (!this.dispatch_) throw new Error('dispatch not set!');
|
||||
this.dispatch_(action);
|
||||
}
|
||||
|
||||
setStartState(v: StartState) {
|
||||
setStartState(v) {
|
||||
if (this.startState_ === v) return;
|
||||
this.startState_ = v;
|
||||
this.dispatch({
|
||||
@@ -70,7 +53,7 @@ export default class ClipperServer {
|
||||
});
|
||||
}
|
||||
|
||||
setPort(v: number) {
|
||||
setPort(v) {
|
||||
if (this.port_ === v) return;
|
||||
this.port_ = v;
|
||||
this.dispatch({
|
||||
@@ -102,7 +85,7 @@ export default class ClipperServer {
|
||||
async start() {
|
||||
this.setPort(null);
|
||||
|
||||
this.setStartState(StartState.Starting);
|
||||
this.setStartState('starting');
|
||||
|
||||
const settingPort = Setting.value('api.port');
|
||||
|
||||
@@ -110,15 +93,15 @@ export default class ClipperServer {
|
||||
const p = settingPort ? settingPort : await this.findAvailablePort();
|
||||
this.setPort(p);
|
||||
} catch (error) {
|
||||
this.setStartState(StartState.Idle);
|
||||
this.setStartState('idle');
|
||||
this.logger().error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.server_ = require('http').createServer();
|
||||
|
||||
this.server_.on('request', async (request: any, response: any) => {
|
||||
const writeCorsHeaders = (code: any, contentType = 'application/json', additionalHeaders: any = null) => {
|
||||
this.server_.on('request', async (request, response) => {
|
||||
const writeCorsHeaders = (code, contentType = 'application/json', additionalHeaders = null) => {
|
||||
const headers = Object.assign(
|
||||
{},
|
||||
{
|
||||
@@ -132,19 +115,19 @@ export default class ClipperServer {
|
||||
response.writeHead(code, headers);
|
||||
};
|
||||
|
||||
const writeResponseJson = (code: any, object: any) => {
|
||||
const writeResponseJson = (code, object) => {
|
||||
writeCorsHeaders(code);
|
||||
response.write(JSON.stringify(object));
|
||||
response.end();
|
||||
};
|
||||
|
||||
const writeResponseText = (code: any, text: any) => {
|
||||
const writeResponseText = (code, text) => {
|
||||
writeCorsHeaders(code, 'text/plain');
|
||||
response.write(text);
|
||||
response.end();
|
||||
};
|
||||
|
||||
const writeResponseInstance = (code: any, instance: any) => {
|
||||
const writeResponseInstance = (code, instance) => {
|
||||
if (instance.type === 'attachment') {
|
||||
const filename = instance.attachmentFilename ? instance.attachmentFilename : 'file';
|
||||
writeCorsHeaders(code, instance.contentType ? instance.contentType : 'application/octet-stream', {
|
||||
@@ -157,7 +140,7 @@ export default class ClipperServer {
|
||||
}
|
||||
};
|
||||
|
||||
const writeResponse = (code: any, response: any) => {
|
||||
const writeResponse = (code, response) => {
|
||||
if (response instanceof ApiResponse) {
|
||||
writeResponseInstance(code, response);
|
||||
} else if (typeof response === 'string') {
|
||||
@@ -173,7 +156,7 @@ export default class ClipperServer {
|
||||
|
||||
const url = urlParser.parse(request.url, true);
|
||||
|
||||
const execRequest = async (request: any, body = '', files: RequestFile[] = []) => {
|
||||
const execRequest = async (request, body = '', files = []) => {
|
||||
try {
|
||||
const response = await this.api_.route(request.method, url.pathname, url.query, body, files);
|
||||
writeResponse(200, response);
|
||||
@@ -198,27 +181,27 @@ export default class ClipperServer {
|
||||
if (contentType.indexOf('multipart/form-data') === 0) {
|
||||
const form = new multiparty.Form();
|
||||
|
||||
form.parse(request, function(error: any, fields: any, files: any) {
|
||||
form.parse(request, function(error, fields, files) {
|
||||
if (error) {
|
||||
writeResponse(error.httpCode ? error.httpCode : 500, error.message);
|
||||
return;
|
||||
} else {
|
||||
void execRequest(request, fields && fields.props && fields.props.length ? fields.props[0] : '', files && files.data ? files.data : []);
|
||||
execRequest(request, fields && fields.props && fields.props.length ? fields.props[0] : '', files && files.data ? files.data : []);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (request.method === 'POST' || request.method === 'PUT') {
|
||||
let body = '';
|
||||
|
||||
request.on('data', (data: any) => {
|
||||
request.on('data', data => {
|
||||
body += data;
|
||||
});
|
||||
|
||||
request.on('end', async () => {
|
||||
void execRequest(request, body);
|
||||
execRequest(request, body);
|
||||
});
|
||||
} else {
|
||||
void execRequest(request);
|
||||
execRequest(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,7 +213,7 @@ export default class ClipperServer {
|
||||
|
||||
this.server_.listen(this.port_, '127.0.0.1');
|
||||
|
||||
this.setStartState(StartState.Started);
|
||||
this.setStartState('started');
|
||||
|
||||
// We return an empty promise that never resolves so that it's possible to `await` the server indefinitely.
|
||||
// This is used only in command-server.js
|
||||
@@ -240,7 +223,9 @@ export default class ClipperServer {
|
||||
async stop() {
|
||||
this.server_.destroy();
|
||||
this.server_ = null;
|
||||
this.setStartState(StartState.Idle);
|
||||
this.setStartState('idle');
|
||||
this.setPort(null);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClipperServer;
|
||||
@@ -91,7 +91,7 @@ export default class JoplinServerApi {
|
||||
return _('Could not connect to Joplin Server. Please check the Synchronisation options in the config screen. Full error was:\n\n%s', msg);
|
||||
}
|
||||
|
||||
private hidePasswords(o: any): any {
|
||||
private hidePassword(o: any): any {
|
||||
if (typeof o === 'string') {
|
||||
try {
|
||||
const output = JSON.parse(o);
|
||||
@@ -104,7 +104,6 @@ export default class JoplinServerApi {
|
||||
} else {
|
||||
const output = { ...o };
|
||||
if (output.password) output.password = '******';
|
||||
if (output['X-API-AUTH']) output['X-API-AUTH'] = '******';
|
||||
return output;
|
||||
}
|
||||
}
|
||||
@@ -115,14 +114,14 @@ export default class JoplinServerApi {
|
||||
output.push('-v');
|
||||
if (options.method) output.push(`-X ${options.method}`);
|
||||
if (options.headers) {
|
||||
const headers = this.hidePasswords(options.headers);
|
||||
for (const n in options.headers) {
|
||||
if (!options.headers.hasOwnProperty(n)) continue;
|
||||
output.push(`${'-H ' + '"'}${n}: ${headers[n]}"`);
|
||||
const headerValue = n === 'X-API-AUTH' ? '******' : options.headers[n];
|
||||
output.push(`${'-H ' + '"'}${n}: ${headerValue}"`);
|
||||
}
|
||||
}
|
||||
if (options.body) {
|
||||
const serialized = typeof options.body !== 'string' ? JSON.stringify(this.hidePasswords(options.body)) : this.hidePasswords(options.body);
|
||||
const serialized = typeof options.body !== 'string' ? JSON.stringify(this.hidePassword(options.body)) : this.hidePassword(options.body);
|
||||
output.push(`${'--data ' + '\''}${serialized}'`);
|
||||
}
|
||||
output.push(`'${url}'`);
|
||||
@@ -142,7 +141,6 @@ export default class JoplinServerApi {
|
||||
}
|
||||
|
||||
if (sessionId) headers['X-API-AUTH'] = sessionId;
|
||||
headers['X-API-MIN-VERSION'] = '2.1.4';
|
||||
|
||||
const fetchOptions: any = {};
|
||||
fetchOptions.headers = headers;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const BaseSyncTarget = require('./BaseSyncTarget').default;
|
||||
const Setting = require('./models/Setting').default;
|
||||
const { FileApi } = require('./file-api.js');
|
||||
const FileApiDriverMemory = require('./file-api-driver-memory').default;
|
||||
const { FileApiDriverMemory } = require('./file-api-driver-memory.js');
|
||||
const Synchronizer = require('./Synchronizer').default;
|
||||
|
||||
class SyncTargetMemory extends BaseSyncTarget {
|
||||
|
||||
@@ -19,8 +19,7 @@ import EncryptionService from './services/EncryptionService';
|
||||
import JoplinError from './JoplinError';
|
||||
import ShareService from './services/share/ShareService';
|
||||
import TaskQueue from './TaskQueue';
|
||||
import ItemUploader from './services/synchronizer/ItemUploader';
|
||||
import { FileApi } from './file-api';
|
||||
import { preUploadItems, serializeAndUploadItem } from './services/synchronizer/uploadUtils';
|
||||
const { sprintf } = require('sprintf-js');
|
||||
const { Dirnames } = require('./services/synchronizer/utils/types');
|
||||
|
||||
@@ -28,18 +27,6 @@ interface RemoteItem {
|
||||
id: string;
|
||||
path?: string;
|
||||
type_?: number;
|
||||
isDeleted?: boolean;
|
||||
|
||||
// This the time when the file was created on the server. It is used for
|
||||
// example for the locking mechanim or any file that's not an actual Joplin
|
||||
// item.
|
||||
updated_time?: number;
|
||||
|
||||
// This is the time that corresponds to the actual Joplin item updated_time
|
||||
// value. A note is always uploaded with a delay so the server updated_time
|
||||
// value will always be ahead. However for synchronising we need to know the
|
||||
// exact Joplin item updated_time value.
|
||||
jop_updated_time?: number;
|
||||
}
|
||||
|
||||
function isCannotSyncError(error: any): boolean {
|
||||
@@ -63,7 +50,7 @@ export default class Synchronizer {
|
||||
public static verboseMode: boolean = true;
|
||||
|
||||
private db_: any;
|
||||
private api_: FileApi;
|
||||
private api_: any;
|
||||
private appType_: string;
|
||||
private logger_: Logger = new Logger();
|
||||
private state_: string = 'idle';
|
||||
@@ -87,7 +74,7 @@ export default class Synchronizer {
|
||||
|
||||
public dispatch: Function;
|
||||
|
||||
public constructor(db: any, api: FileApi, appType: string) {
|
||||
constructor(db: any, api: any, appType: string) {
|
||||
this.db_ = db;
|
||||
this.api_ = api;
|
||||
this.appType_ = appType;
|
||||
@@ -97,8 +84,6 @@ export default class Synchronizer {
|
||||
this.progressReport_ = {};
|
||||
|
||||
this.dispatch = function() {};
|
||||
|
||||
this.apiCall = this.apiCall.bind(this);
|
||||
}
|
||||
|
||||
state() {
|
||||
@@ -316,11 +301,11 @@ export default class Synchronizer {
|
||||
return '';
|
||||
}
|
||||
|
||||
private async apiCall(fnName: string, ...args: any[]) {
|
||||
async apiCall(fnName: string, ...args: any[]) {
|
||||
if (this.syncTargetIsLocked_) throw new JoplinError('Sync target is locked - aborting API call', 'lockError');
|
||||
|
||||
try {
|
||||
const output = await (this.api() as any)[fnName](...args);
|
||||
const output = await this.api()[fnName](...args);
|
||||
return output;
|
||||
} catch (error) {
|
||||
const lockStatus = await this.lockErrorStatus_();
|
||||
@@ -378,7 +363,7 @@ export default class Synchronizer {
|
||||
this.dispatch({ type: 'SYNC_STARTED' });
|
||||
eventManager.emit('syncStart');
|
||||
|
||||
this.logSyncOperation('starting', null, null, `Starting synchronisation to target ${syncTargetId}... supportsAccurateTimestamp = ${this.api().supportsAccurateTimestamp}; supportsMultiPut = ${this.api().supportsMultiPut} [${synchronizationId}]`);
|
||||
this.logSyncOperation('starting', null, null, `Starting synchronisation to target ${syncTargetId}... [${synchronizationId}]`);
|
||||
|
||||
const handleCannotSyncItem = async (ItemClass: any, syncTargetId: any, item: any, cannotSyncReason: string, itemLocation: any = null) => {
|
||||
await ItemClass.saveSyncDisabled(syncTargetId, item, cannotSyncReason, itemLocation);
|
||||
@@ -405,7 +390,11 @@ export default class Synchronizer {
|
||||
// correctly so as to share/unshare the right items.
|
||||
await Folder.updateAllShareIds();
|
||||
|
||||
const itemUploader = new ItemUploader(this.api(), this.apiCall);
|
||||
const uploadQueue = new TaskQueue('syncUpload', this.logger());
|
||||
|
||||
const uploadItem = (path: string, content: any) => {
|
||||
return this.apiCall('put', path, content);
|
||||
};
|
||||
|
||||
let errorToThrow = null;
|
||||
let syncLock = null;
|
||||
@@ -458,7 +447,7 @@ export default class Synchronizer {
|
||||
const result = await BaseItem.itemsThatNeedSync(syncTargetId);
|
||||
const locals = result.items;
|
||||
|
||||
await itemUploader.preUploadItems(result.items.filter((it: any) => result.neverSyncedItemIds.includes(it.id)));
|
||||
await preUploadItems(uploadItem, uploadQueue, result.items.filter((it: any) => result.neverSyncedItemIds.includes(it.id)));
|
||||
|
||||
for (let i = 0; i < locals.length; i++) {
|
||||
if (this.cancelling()) break;
|
||||
@@ -608,7 +597,7 @@ export default class Synchronizer {
|
||||
let canSync = true;
|
||||
try {
|
||||
if (this.testingHooks_.indexOf('notesRejectedByTarget') >= 0 && local.type_ === BaseModel.TYPE_NOTE) throw new JoplinError('Testing rejectedByTarget', 'rejectedByTarget');
|
||||
await itemUploader.serializeAndUploadItem(ItemClass, path, local);
|
||||
await serializeAndUploadItem(uploadItem, uploadQueue, ItemClass, path, local);
|
||||
} catch (error) {
|
||||
if (error && error.code === 'rejectedByTarget') {
|
||||
await handleCannotSyncItem(ItemClass, syncTargetId, local, error.message);
|
||||
@@ -638,6 +627,7 @@ export default class Synchronizer {
|
||||
// above also doesn't use it because it fetches the whole remote object and read the
|
||||
// more reliable 'updated_time' property. Basically remote.updated_time is deprecated.
|
||||
|
||||
// await this.api().setTimestamp(path, local.updated_time);
|
||||
await ItemClass.saveSyncTime(syncTargetId, local, local.updated_time);
|
||||
}
|
||||
} else if (action == 'itemConflict') {
|
||||
@@ -782,27 +772,16 @@ export default class Synchronizer {
|
||||
logger: this.logger(),
|
||||
});
|
||||
|
||||
const remotes: RemoteItem[] = listResult.items;
|
||||
const remotes = listResult.items;
|
||||
|
||||
this.logSyncOperation('fetchingTotal', null, null, 'Fetching delta items from sync target', remotes.length);
|
||||
|
||||
const remoteIds = remotes.map(r => BaseItem.pathToId(r.path));
|
||||
const locals = await BaseItem.loadItemsByIds(remoteIds);
|
||||
|
||||
for (const remote of remotes) {
|
||||
if (this.cancelling()) break;
|
||||
|
||||
let needsToDownload = true;
|
||||
if (this.api().supportsAccurateTimestamp) {
|
||||
const local = locals.find(l => l.id === BaseItem.pathToId(remote.path));
|
||||
if (local && local.updated_time === remote.jop_updated_time) needsToDownload = false;
|
||||
}
|
||||
|
||||
if (needsToDownload) {
|
||||
this.downloadQueue_.push(remote.path, async () => {
|
||||
return this.apiCall('get', remote.path);
|
||||
});
|
||||
}
|
||||
this.downloadQueue_.push(remote.path, async () => {
|
||||
return this.apiCall('get', remote.path);
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < remotes.length; i++) {
|
||||
@@ -824,10 +803,9 @@ export default class Synchronizer {
|
||||
};
|
||||
|
||||
const path = remote.path;
|
||||
const remoteId = BaseItem.pathToId(path);
|
||||
let action = null;
|
||||
let reason = '';
|
||||
let local = locals.find(l => l.id === remoteId);
|
||||
let local = await BaseItem.loadItemByPath(path);
|
||||
let ItemClass = null;
|
||||
let content = null;
|
||||
|
||||
@@ -846,14 +824,10 @@ export default class Synchronizer {
|
||||
action = 'deleteLocal';
|
||||
reason = 'remote has been deleted';
|
||||
} else {
|
||||
if (this.api().supportsAccurateTimestamp && remote.jop_updated_time === local.updated_time) {
|
||||
// Nothing to do, and no need to fetch the content
|
||||
} else {
|
||||
content = await loadContent();
|
||||
if (content && content.updated_time > local.updated_time) {
|
||||
action = 'updateLocal';
|
||||
reason = 'remote is more recent than local';
|
||||
}
|
||||
content = await loadContent();
|
||||
if (content && content.updated_time > local.updated_time) {
|
||||
action = 'updateLocal';
|
||||
reason = 'remote is more recent than local';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { MultiPutItem } from './file-api';
|
||||
import JoplinError from './JoplinError';
|
||||
import JoplinServerApi from './JoplinServerApi';
|
||||
import { trimSlashes } from './path-utils';
|
||||
@@ -32,14 +31,6 @@ export default class FileApiDriverJoplinServer {
|
||||
return this.api_;
|
||||
}
|
||||
|
||||
public get supportsMultiPut() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public get supportsAccurateTimestamp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public requestRepeatCount() {
|
||||
return 3;
|
||||
}
|
||||
@@ -48,8 +39,7 @@ export default class FileApiDriverJoplinServer {
|
||||
const output = {
|
||||
path: rootPath ? path.substr(rootPath.length + 1) : path,
|
||||
updated_time: md.updated_time,
|
||||
jop_updated_time: md.jop_updated_time,
|
||||
isDir: false,
|
||||
isDir: false, // !!md.is_directory,
|
||||
isDeleted: isDeleted,
|
||||
};
|
||||
|
||||
@@ -184,10 +174,6 @@ export default class FileApiDriverJoplinServer {
|
||||
}
|
||||
}
|
||||
|
||||
public async multiPut(items: MultiPutItem[], options: any = null) {
|
||||
return this.api().exec('PUT', 'api/batch_items', null, { items: items }, null, options);
|
||||
}
|
||||
|
||||
public async delete(path: string) {
|
||||
return this.api().exec('DELETE', this.apiFilePath_(path));
|
||||
}
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import time from './time';
|
||||
const time = require('./time').default;
|
||||
const fs = require('fs-extra');
|
||||
import { basicDelta, MultiPutItem } from './file-api';
|
||||
|
||||
export default class FileApiDriverMemory {
|
||||
|
||||
private items_: any[];
|
||||
private deletedItems_: any[];
|
||||
const { basicDelta } = require('./file-api');
|
||||
|
||||
class FileApiDriverMemory {
|
||||
constructor() {
|
||||
this.items_ = [];
|
||||
this.deletedItems_ = [];
|
||||
}
|
||||
|
||||
encodeContent_(content: any) {
|
||||
encodeContent_(content) {
|
||||
if (content instanceof Buffer) {
|
||||
return content.toString('base64');
|
||||
} else {
|
||||
@@ -20,31 +16,23 @@ export default class FileApiDriverMemory {
|
||||
}
|
||||
}
|
||||
|
||||
public get supportsMultiPut() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public get supportsAccurateTimestamp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
decodeContent_(content: any) {
|
||||
decodeContent_(content) {
|
||||
return Buffer.from(content, 'base64').toString('utf-8');
|
||||
}
|
||||
|
||||
itemIndexByPath(path: string) {
|
||||
itemIndexByPath(path) {
|
||||
for (let i = 0; i < this.items_.length; i++) {
|
||||
if (this.items_[i].path == path) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
itemByPath(path: string) {
|
||||
itemByPath(path) {
|
||||
const index = this.itemIndexByPath(path);
|
||||
return index < 0 ? null : this.items_[index];
|
||||
}
|
||||
|
||||
newItem(path: string, isDir = false) {
|
||||
newItem(path, isDir = false) {
|
||||
const now = time.unixMs();
|
||||
return {
|
||||
path: path,
|
||||
@@ -55,18 +43,18 @@ export default class FileApiDriverMemory {
|
||||
};
|
||||
}
|
||||
|
||||
stat(path: string) {
|
||||
stat(path) {
|
||||
const item = this.itemByPath(path);
|
||||
return Promise.resolve(item ? Object.assign({}, item) : null);
|
||||
}
|
||||
|
||||
async setTimestamp(path: string, timestampMs: number): Promise<any> {
|
||||
async setTimestamp(path, timestampMs) {
|
||||
const item = this.itemByPath(path);
|
||||
if (!item) return Promise.reject(new Error(`File not found: ${path}`));
|
||||
item.updated_time = timestampMs;
|
||||
}
|
||||
|
||||
async list(path: string) {
|
||||
async list(path) {
|
||||
const output = [];
|
||||
|
||||
for (let i = 0; i < this.items_.length; i++) {
|
||||
@@ -89,7 +77,7 @@ export default class FileApiDriverMemory {
|
||||
});
|
||||
}
|
||||
|
||||
async get(path: string, options: any) {
|
||||
async get(path, options) {
|
||||
const item = this.itemByPath(path);
|
||||
if (!item) return Promise.resolve(null);
|
||||
if (item.isDir) return Promise.reject(new Error(`${path} is a directory, not a file`));
|
||||
@@ -105,13 +93,13 @@ export default class FileApiDriverMemory {
|
||||
return output;
|
||||
}
|
||||
|
||||
async mkdir(path: string) {
|
||||
async mkdir(path) {
|
||||
const index = this.itemIndexByPath(path);
|
||||
if (index >= 0) return;
|
||||
this.items_.push(this.newItem(path, true));
|
||||
}
|
||||
|
||||
async put(path: string, content: any, options: any = null) {
|
||||
async put(path, content, options = null) {
|
||||
if (!options) options = {};
|
||||
|
||||
if (options.source === 'file') content = await fs.readFile(options.path);
|
||||
@@ -121,38 +109,13 @@ export default class FileApiDriverMemory {
|
||||
const item = this.newItem(path, false);
|
||||
item.content = this.encodeContent_(content);
|
||||
this.items_.push(item);
|
||||
return item;
|
||||
} else {
|
||||
this.items_[index].content = this.encodeContent_(content);
|
||||
this.items_[index].updated_time = time.unixMs();
|
||||
return this.items_[index];
|
||||
}
|
||||
}
|
||||
|
||||
public async multiPut(items: MultiPutItem[], options: any = null) {
|
||||
const output: any = {
|
||||
items: {},
|
||||
};
|
||||
|
||||
for (const item of items) {
|
||||
try {
|
||||
const processedItem = await this.put(`/root/${item.name}`, item.body, options);
|
||||
output.items[item.name] = {
|
||||
item: processedItem,
|
||||
error: null,
|
||||
};
|
||||
} catch (error) {
|
||||
output.items[item.name] = {
|
||||
item: null,
|
||||
error: error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
async delete(path: string) {
|
||||
async delete(path) {
|
||||
const index = this.itemIndexByPath(path);
|
||||
if (index >= 0) {
|
||||
const item = Object.assign({}, this.items_[index]);
|
||||
@@ -163,10 +126,10 @@ export default class FileApiDriverMemory {
|
||||
}
|
||||
}
|
||||
|
||||
async move(oldPath: string, newPath: string): Promise<any> {
|
||||
async move(oldPath, newPath) {
|
||||
const sourceItem = this.itemByPath(oldPath);
|
||||
if (!sourceItem) return Promise.reject(new Error(`Path not found: ${oldPath}`));
|
||||
await this.delete(newPath); // Overwrite if newPath already exists
|
||||
this.delete(newPath); // Overwrite if newPath already exists
|
||||
sourceItem.path = newPath;
|
||||
}
|
||||
|
||||
@@ -174,8 +137,8 @@ export default class FileApiDriverMemory {
|
||||
this.items_ = [];
|
||||
}
|
||||
|
||||
async delta(path: string, options: any = null) {
|
||||
const getStatFn = async (path: string) => {
|
||||
async delta(path, options = null) {
|
||||
const getStatFn = async path => {
|
||||
const output = this.items_.slice();
|
||||
for (let i = 0; i < output.length; i++) {
|
||||
const item = Object.assign({}, output[i]);
|
||||
@@ -193,3 +156,5 @@ export default class FileApiDriverMemory {
|
||||
this.items_ = [];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { FileApiDriverMemory };
|
||||
@@ -11,11 +11,6 @@ const Mutex = require('async-mutex').Mutex;
|
||||
|
||||
const logger = Logger.create('FileApi');
|
||||
|
||||
export interface MultiPutItem {
|
||||
name: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
function requestCanBeRepeated(error: any) {
|
||||
const errorCode = typeof error === 'object' && error.code ? error.code : null;
|
||||
|
||||
@@ -86,26 +81,6 @@ class FileApi {
|
||||
if (this.driver_.initialize) return this.driver_.initialize(this.fullPath(''));
|
||||
}
|
||||
|
||||
// This can be true if the driver implements uploading items in batch. Will
|
||||
// probably only be supported by Joplin Server.
|
||||
public get supportsMultiPut(): boolean {
|
||||
return !!this.driver().supportsMultiPut;
|
||||
}
|
||||
|
||||
// This can be true when the sync target timestamps (updated_time) provided
|
||||
// in the delta call are guaranteed to be accurate. That requires
|
||||
// explicitely setting the timestamp, which is not done anymore on any sync
|
||||
// target as it wasn't accurate (for example, the file system can't be
|
||||
// relied on, and even OneDrive for some reason doesn't guarantee that the
|
||||
// timestamp you set is what you get back).
|
||||
//
|
||||
// The only reliable one at the moment is Joplin Server since it reads the
|
||||
// updated_time property directly from the item (it unserializes it
|
||||
// server-side).
|
||||
public get supportsAccurateTimestamp(): boolean {
|
||||
return !!this.driver().supportsAccurateTimestamp;
|
||||
}
|
||||
|
||||
async fetchRemoteDateOffset_() {
|
||||
const tempFile = `${this.tempDirName()}/timeCheck${Math.round(Math.random() * 1000000)}.txt`;
|
||||
const startTime = Date.now();
|
||||
@@ -276,6 +251,12 @@ class FileApi {
|
||||
if (!output) return output;
|
||||
output.path = path;
|
||||
return output;
|
||||
|
||||
// return this.driver_.stat(this.fullPath(path)).then((output) => {
|
||||
// if (!output) return output;
|
||||
// output.path = path;
|
||||
// return output;
|
||||
// });
|
||||
}
|
||||
|
||||
// Returns UTF-8 encoded string by default, or a Response if `options.target = 'file'`
|
||||
@@ -296,11 +277,6 @@ class FileApi {
|
||||
return tryAndRepeat(() => this.driver_.put(this.fullPath(path), content, options), this.requestRepeatCount());
|
||||
}
|
||||
|
||||
public async multiPut(items: MultiPutItem[], options: any = null) {
|
||||
if (!this.driver().supportsMultiPut) throw new Error('Multi PUT not supported');
|
||||
return tryAndRepeat(() => this.driver_.multiPut(items, options), this.requestRepeatCount());
|
||||
}
|
||||
|
||||
delete(path: string) {
|
||||
logger.debug(`delete ${this.fullPath(path)}`);
|
||||
return tryAndRepeat(() => this.driver_.delete(this.fullPath(path)), this.requestRepeatCount());
|
||||
|
||||
@@ -503,15 +503,31 @@ function isCodeBlock(context: any, nodeName: string, attributes: any) {
|
||||
if (nodeName === 'code') return true;
|
||||
|
||||
if (attributes && attributes.style) {
|
||||
// Yes, this property sometimes appears as -en-codeblock, sometimes as
|
||||
// --en-codeblock. Would be too easy to import ENEX data otherwise.
|
||||
// https://github.com/laurent22/joplin/issues/4965
|
||||
const enCodeBlock = cssValue(context, attributes.style, '-en-codeblock') || cssValue(context, attributes.style, '--en-codeblock');
|
||||
const enCodeBlock = cssValue(context, attributes.style, '-en-codeblock');
|
||||
if (enCodeBlock && enCodeBlock.toLowerCase() === 'true') return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// function removeSectionParent(section:Section | string) {
|
||||
// if (typeof section === 'string') return section;
|
||||
|
||||
// section = { ...section };
|
||||
// delete section.parent;
|
||||
|
||||
// section.lines = section.lines.slice();
|
||||
|
||||
// for (let i = 0; i < section.lines.length; i++) {
|
||||
// section.lines[i] = removeSectionParent(section.lines[i]);
|
||||
// }
|
||||
|
||||
// return section;
|
||||
// }
|
||||
|
||||
// function printSection(section:Section) {
|
||||
// console.info(JSON.stringify(removeSectionParent(section), null, 4));
|
||||
// }
|
||||
|
||||
function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<EnexXmlToMdArrayResult> {
|
||||
const remainingResources = resources.slice();
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"OK":"موافق","Cancel":"إلغاء","The app is now going to close. Please relaunch it to complete the process.":"سيتم إغلاق التطبيق الآن. يرجى إعادة تشغيله لإكمال العملية.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"اكتب عنوان ملاحظة أو جزء من محتواه للانتقال إليه. أو اكتب # متبوعاً بإسم وسم، أو @ متبوعاً باسم دفتر ملاحظات. أو اكتب : للبحث عن الأوامر.","Goto Anything...":"اذهب إلى أي شيء...","Command palette":"لوحة الأوامر","Exporting to \"%s\" as \"%s\" format. Please wait...":"التصدير إلى \"%s\" بتنسيق \"%s\". فضلاً انتظر...","Could not export notes: %s":"تعذر تصدير الملاحظات: %s","Current version is up-to-date.":"النسخة الحالية محدَّثة.","%s (pre-release)":"%s (ما قبل الإصدار)","An update is available, do you want to download it now?":"يتوفر تحديث ، هل تريد تنزيله الآن؟","Your version: %s":"النسخة لديك: %s","New version: %s":"النسخة الجديدة: %s","Download":"تحميل","This note has no history":"هذه المذكرة ليس لها تاريخ","Unsupported link or message: %s":"رابط أو رسالة غير مدعومان: %s","Restore":"استعادة","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"انقر \"%s\" لاستعادة الملاحظة. سيتم نسخه في دفتر الملاحظات المسمى \"%s\". لن يتم استبدال أو تعديل الإصدار الحالي من الملاحظة.","Back":"عودة","Remove":"إزالة","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"حذف دفتر الملاحظات \"%s\" ؟\n\nسيتم حذف كل الملاحظات و دفاتر الملاحظات الفرعية ضمن هذا الدفتر أيضاً.","Delete":"حذف","Remove tag \"%s\" from all notes?":"إزالة الوسم \"%s\" من كل الملاحظات؟","Remove this search from the sidebar?":"حذف هذا البحث من الشريط الجانبي؟","Export":"تصدير","All notes":"جميع الملاحظات","Synchronise":"زامِن","Notebooks":"دفاتر ملاحظات","Tags":"وسوم","Decrypting items: %d/%d":"فك تشفير العناصر: %d/%d","Fetching resources: %d/%d":"جلب الموارد: %d/%d","Sidebar":"الشريط الجانبي","Focus":"تركيز","Please select where the sync status should be exported to":"فضلاً اختر أين سيتم تصدير حالة المزامنة","Retry All":"إعادة محاولة الجميع","Retry":"إعادة المحاولة","strong text":"نص مشدَّد","emphasised text":"نص مشدَّد علية","Insert Hyperlink":"إدراج ارتباط تشعبي","List item":"عنصر قائمة","Layout":"تخطيط","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"ليس لهذه الملاحظة أي محتوى. اضغط على \"%s\" لتبديل المحرّر وتحرير الملاحظة.","Cut":"قص","Copy":"نسخ","Paste":"لصق","Checkbox list":"قائمة خانات اختيار","Highlight":"تَمييز النَص","Strikethrough":"توسيط خط في النص","Insert":"إدخال","Superscript":"أحرف فوقية","Subscript":"حرف تحتي","Edit":"تحرير","Attach file":"إرفاق ملف","Code Block":"كتلة للغة البرمجة","Inline Code":"نص لغة برمجة في النسق","Insert Date Time":"إدراج التاريخ والوقت","Drop notes or files here":"قم بإسقاط الملاحظات أو الملفات هنا","Code View":"عرض بلغة البرمجة","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"يرجى الانتظار حتى يتم تنزيل جميع المرفقات وفك تشفيرها. يمكنك أيضًا التبديل إلى %s لتحرير الملاحظة.","There was an error downloading this attachment:":"حدث خطأ أثناء تنزيل هذا المرفق:","This attachment is not downloaded or not decrypted yet":"لم يجر تنزيل هذا المرفق أو فك تشفيره حتى الآن","Open...":"فتح...","Save as...":"حفظ باسم...","Reveal file in folder":"اضهار الملف في المجلد","Copy path to clipboard":"نسخ المسار إلى الحافظة","Copy Link Address":"نسخ عنوان الرابط","to-do":"قائمة مهام","note":"ملاحظة","Creating new %s...":"إنشاء %s جديد ...","Click to add tags...":"اضغط لإدراج سمات...","This Rich Text editor has a number of limitations Line truncated
|
||||
{"OK":"موافق","Cancel":"إلغاء","The app is now going to close. Please relaunch it to complete the process.":"سيتم إغلاق التطبيق الآن. يرجى إعادة تشغيله لإكمال العملية.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"اكتب عنوان ملاحظة أو جزء من محتواه للانتقال إليه. أو اكتب # متبوعاً بإسم وسم، أو @ متبوعاً باسم دفتر ملاحظات. أو اكتب : للبحث عن الأوامر.","Goto Anything...":"اذهب إلى أي شيء...","Command palette":"لوحة الأوامر","Exporting to \"%s\" as \"%s\" format. Please wait...":"التصدير إلى \"%s\" بتنسيق \"%s\". فضلاً انتظر...","Could not export notes: %s":"تعذر تصدير الملاحظات: %s","Current version is up-to-date.":"النسخة الحالية محدَّثة.","%s (pre-release)":"%s (ما قبل الإصدار)","An update is available, do you want to download it now?":"يتوفر تحديث ، هل تريد تنزيله الآن؟","Your version: %s":"النسخة لديك: %s","New version: %s":"النسخة الجديدة: %s","Download":"تحميل","The note \"%s\" has been successfully restored to the notebook \"%s\".":"تمت استعادة الملاحظة \"%s\" بنجاح إلى دفتر الملاحظات \"%s\".","This note has no history":"هذه المذكرة ليس لها تاريخ","Unsupported link or message: %s":"رابط أو رسالة غير مدعومان: %s","Restore":"استعادة","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"انقر \"%s\" لاستعادة الملاحظة. سيتم نسخه في دفتر الملاحظات المسمى \"%s\". لن يتم استبدال أو تعديل الإصدار الحالي من الملاحظة.","Back":"عودة","Remove":"إزالة","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"حذف دفتر الملاحظات \"%s\" ؟\n\nسيتم حذف كل الملاحظات و دفاتر الملاحظات الفرعية ضمن هذا الدفتر أيضاً.","Delete":"حذف","Remove tag \"%s\" from all notes?":"إزالة الوسم \"%s\" من كل الملاحظات؟","Remove this search from the sidebar?":"حذف هذا البحث من الشريط الجانبي؟","Export":"تصدير","All notes":"جميع الملاحظات","Synchronise":"زامِن","Notebooks":"دفاتر ملاحظات","Tags":"وسوم","Decrypting items: %d/%d":"فك تشفير العناصر: %d/%d","Fetching resources: %d/%d":"جلب الموارد: %d/%d","Sidebar":"الشريط الجانبي","Focus":"تركيز","Please select where the sync status should be exported to":"فضلاً اختر أين سيتم تصدير حالة المزامنة","Retry All":"إعادة محاولة الجميع","Retry":"إعادة المحاولة","strong text":"نص مشدَّد","emphasised text":"نص مشدَّد علية","Insert Hyperlink":"إدراج ارتباط تشعبي","List item":"عنصر قائمة","Layout":"تخطيط","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"ليس لهذه الملاحظة أي محتوى. اضغط على \"%s\" لتبديل المحرّر وتحرير الملاحظة.","Cut":"قص","Copy":"نسخ","Paste":"لصق","Checkbox list":"قائمة خانات اختيار","Highlight":"تَمييز النَص","Strikethrough":"توسيط خط في النص","Insert":"إدخال","Superscript":"أحرف فوقية","Subscript":"حرف تحتي","Edit":"تحرير","Attach file":"إرفاق ملف","Code Block":"كتلة للغة البرمجة","Inline Code":"نص لغة برمجة في النسق","Insert Date Time":"إدراج التاريخ والوقت","Drop notes or files here":"قم بإسقاط الملاحظات أو الملفات هنا","Code View":"عرض بلغة البرمجة","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"يرجى الانتظار حتى يتم تنزيل جميع المرفقات وفك تشفيرها. يمكنك أيضًا التبديل إلى %s لتحرير الملاحظة.","There was an error downloading this attachment:":"حدث خطأ أثناء تنزيل هذا المرفق:","This attachment is not downloaded or not decrypted yet":"لم يجر تنزيل هذا المرفق أو فك تشفيره حتى الآن","Open...":"فتح...","Save as...":"حفظ باسم...","Reveal file in folder":"اضهار الملف في المجلد","Copy path to clipboard":"نسخ المسار إلى الحافظة","Copy Link Address":"نسخ عنوان الرابط","to-do":"قائمة مهام","note":Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"Добре","Cancel":"Отмени","Goto Anything...":"Отиди на нещо...","Exporting to \"%s\" as \"%s\" format. Please wait...":"Експортирам към \"%s\" във формат \"%s\". Моля изчакайте...","Current version is up-to-date.":"Настоящата версия е най-новата.","%s (pre-release)":"%s (експериментална)","An update is available, do you want to download it now?":"Има обновление, искате ли да го свалите сега?","Your version: %s":"Вашата версия: %s","New version: %s":"Нова версия: %s","This note has no history":"Тази бележка няма история","Unsupported link or message: %s":"Неподдържан линк или съобщение: %s","Restore":"Възстанови","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Натиснете \"%s\" за да възстановите бележката. Тя ще бъде копирана в тетрадка с име \"%s\". Настоящата версия на бележката няма да бъде подменена или променена.","Back":"Назад","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Да изтрия ли тетрадка \"%s\"?\n\nВсички бележки и под-тетрадки също ще бъдат изтрити.","Delete":"Изтрий","Remove tag \"%s\" from all notes?":"Да премахна ли таг \"%s\" от всички бележки?","Remove this search from the sidebar?":"Да премахна ли това търсене от страничния панел?","Export":"Експортиране","Synchronise":"Синхронизация","Notebooks":"Тетрадки","Tags":"Тагове","Decrypting items: %d/%d":"Декриптиране на обекти: %d/%d","Fetching resources: %d/%d":"Взимане на ресурси: %d/%d","Sidebar":"Страничен панел","Focus":"Фокусирай","Please select where the sync status should be exported to":"Моля изберете къде да бъде експортиран статуса на синхронизацията","Retry":"Нов опит","strong text":"силно наблегнат текст","Insert Hyperlink":"Вкарай линк","List item":"Елемент на списък","Layout":"Разположеня","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Тази бележка няма съдържание. Натиснете \"%s\" за да покажете редакторя и да редактирате бележката.","Cut":"Изрежи","Copy":"Копирай","Paste":"Постави","Edit":"Редактиране","Attach file":"Прикачи файл","Insert Date Time":"Постави датата и часа","Open...":"Отвори...","Save as...":"Запазаи като...","Copy path to clipboard":"Копирай пътя в клипборда","Copy Link Address":"Копирай адреса на линка","to-do":"задача","note":"бележка","Creating new %s...":"Създаване на нова %s...","In: %s":"В: %s","Select all":"Избери всичко","Bold":"Удебелен","Italic":"Курсив","Hyperlink":"Линк","Code":"Код","Numbered List":"Номериран списък","Bulleted List":"Неномериран списък","Checkbox":"Поле за отметка","Heading":"Заглавие","Horizontal Rule":"Хоризонтална черта","Note title":"Заглавие на бележката","Search in current note":"Търсене в настоящата бележка","Note body":"Съдържание на бележката","ID":"Идентификатор","Created":"Създаден","Updated":"Обновен","Location":"Местоположение","URL":"Уеб адрес (URL)","Note History":"История на бележката","Previous versions of this note":"Предишни версии на бележката","Note properties":"Атрибути на бележката","Disabled":"Изключено","Search...":"Търсене...","Import":"Импортиране","Quit":"Изход","Website and documentation":"Уебсайт и документация","Close Window":"Затвори прозорец","Options":"Конфигурация","Save":"Запази","View them now":"Покажи ги сега","Some items cannot be synchronised.":"Някои обекти не можаха да бъдат синхронизирани.","One or more master keys need a password.":"Поне един главен ключ се нуждае от парола.","Set the password":"Задаване на паролата","Rename":"Преименувай","Rename notebook:":"ПрLine truncated
|
||||
{"OK":"Добре","Cancel":"Отмени","Goto Anything...":"Отиди на нещо...","Exporting to \"%s\" as \"%s\" format. Please wait...":"Експортирам към \"%s\" във формат \"%s\". Моля изчакайте...","Current version is up-to-date.":"Настоящата версия е най-новата.","%s (pre-release)":"%s (експериментална)","An update is available, do you want to download it now?":"Има обновление, искате ли да го свалите сега?","Your version: %s":"Вашата версия: %s","New version: %s":"Нова версия: %s","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Бележка \"%s\" бе успешно създадена и сложена в тетрадка \"%s\".","This note has no history":"Тази бележка няма история","Unsupported link or message: %s":"Неподдържан линк или съобщение: %s","Restore":"Възстанови","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Натиснете \"%s\" за да възстановите бележката. Тя ще бъде копирана в тетрадка с име \"%s\". Настоящата версия на бележката няма да бъде подменена или променена.","Back":"Назад","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Да изтрия ли тетрадка \"%s\"?\n\nВсички бележки и под-тетрадки също ще бъдат изтрити.","Delete":"Изтрий","Remove tag \"%s\" from all notes?":"Да премахна ли таг \"%s\" от всички бележки?","Remove this search from the sidebar?":"Да премахна ли това търсене от страничния панел?","Export":"Експортиране","Synchronise":"Синхронизация","Notebooks":"Тетрадки","Tags":"Тагове","Decrypting items: %d/%d":"Декриптиране на обекти: %d/%d","Fetching resources: %d/%d":"Взимане на ресурси: %d/%d","Sidebar":"Страничен панел","Focus":"Фокусирай","Please select where the sync status should be exported to":"Моля изберете къде да бъде експортиран статуса на синхронизацията","Retry":"Нов опит","strong text":"силно наблегнат текст","Insert Hyperlink":"Вкарай линк","List item":"Елемент на списък","Layout":"Разположеня","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Тази бележка няма съдържание. Натиснете \"%s\" за да покажете редакторя и да редактирате бележката.","Cut":"Изрежи","Copy":"Копирай","Paste":"Постави","Edit":"Редактиране","Attach file":"Прикачи файл","Insert Date Time":"Постави датата и часа","Open...":"Отвори...","Save as...":"Запазаи като...","Copy path to clipboard":"Копирай пътя в клипборда","Copy Link Address":"Копирай адреса на линка","to-do":"задача","note":"бележка","Creating new %s...":"Създаване на нова %s...","In: %s":"В: %s","Select all":"Избери всичко","Bold":"Удебелен","Italic":"Курсив","Hyperlink":"Линк","Code":"Код","Numbered List":"Номериран списък","Bulleted List":"Неномериран списък","Checkbox":"Поле за отметка","Heading":"Заглавие","Horizontal Rule":"Хоризонтална черта","Note title":"Заглавие на бележката","Search in current note":"Търсене в настоящата бележка","Note body":"Съдържание на бележката","ID":"Идентификатор","Created":"Създаден","Updated":"Обновен","Location":"Местоположение","URL":"Уеб адрес (URL)","Note History":"История на бележката","Previous versions of this note":"Предишни версии на бележката","Note properties":"Атрибути на бележката","Disabled":"Изключено","Search...":"Търсене...","Import":"Импортиране","Quit":"Изход","Website and documentation":"Уебсайт и документация","Close Window":"Затвори прозорец","Options":"Конфигурация","Save":"Запази","View them now":"Покажи ги сега","Some items cannot be synchronised.":"Някои обекти не можаха да бъдат синхронизирани.","One or more master keys need a password.":"Поне едиLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"Uredu","Cancel":"Otkaži","The app is now going to close. Please relaunch it to complete the process.":"Aplikacija ce se zatvoriti. Molimo ponovo otvorite da bi se radnja potpuno zavrsila.","Goto Anything...":"Pronađite bilo šta...","Current version is up-to-date.":"Trenutna je verzija ažurirana.","%s (pre-release)":"%s (verzija pred objavljivanje)","An update is available, do you want to download it now?":"Nova je verzija dostupna. Želite li je preuzeti?","Your version: %s":"Vaša verzija: %s","New version: %s":"Nova verzija: %s","This note has no history":"Bilješka nema ranijih verzija","Unsupported link or message: %s":"Nepodržana veza ili poruka: %s","Restore":"Rekonstruiši","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Pritisnite na \"%s\" da rekonstruišete bilješku. Rezultat će biti kopiran u bilježnicu \"%s\". Trenutna verzija bilješke ostat će netaknuta.","Back":"Nazad","Remove":"Ukloni","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Izbrisati bilježnicu \"%s\"?\n\nSve bilješke i bilježnice unutar ove bilježnice također će biti izbrisane.","Delete":"Izbriši","Remove tag \"%s\" from all notes?":"Ukloniti oznaku \"%s\" iz svih bilješki?","Remove this search from the sidebar?":"Ukloniti ovu pretragu iz pomoćnog menija?","Export":"Iznesi","All notes":"Sve bilješke","Synchronise":"Sinhronizuj","Notebooks":"Bilježnice","Tags":"Oznake","Decrypting items: %d/%d":"Dešifrujem stavke: %d/%d","Fetching resources: %d/%d":"Preuzimam resurse: %d/%d","Sidebar":"Bočni meni","Focus":"Fokus","Please select where the sync status should be exported to":"Navedite gdje će biti pohranjen status sinhronizacije","Retry":"Ponovi","strong text":"podebljani tekst","Insert Hyperlink":"Unesi poveznicu","List item":"Stavka nabrajanja","Layout":"Prikaz","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Bilješka je prazna. Pritisnite na \"%s\" da otvorite program za rad s tekstom i uredite bilješku.","Cut":"Izreži","Copy":"Kopiraj","Paste":"Zalijepi","Highlight":"Oznaci","Edit":"Uredi","Attach file":"Priloži datoteku","Code Block":"Kōd (izdvojen)","Inline Code":"Kōd (unutar teksta)","Insert Date Time":"Unesi datum i vrijeme","Drop notes or files here":"Ispustite bilješke ili datoteke ovdje","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Pričekajte dok svi prilozi ne budu preuzeti i dešifrovani. Također možete otvoriti %s da uredite bilješku.","There was an error downloading this attachment:":"Došlo je do greške prilikom preuzimanja priloga:","Open...":"Otvori...","Save as...":"Pohrani kao...","Reveal file in folder":"Pokaži datoteku u direktoriju","Copy path to clipboard":"Kopiraj putanju u spremnik","Copy Link Address":"Kopiraj adresu veze","to-do":"zadatak","note":"bilješka","Creating new %s...":"Kreiram: %s...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Ovaj Text editor ima par ogranicenja i preporucujemo da budete upoznati sa njima prije koristenja.","Read more about it":"Saznajte vise","Dismiss":"Odbaci","In: %s":"U: %s","Select all":"Označi sve","Bold":"Masna slova","Italic":"Kurziv","Hyperlink":"Poveznica","Code":"Kōd","Numbered List":"Numerisano nabrajanje","Bulleted List":"Nabrajanje","Checkbox":"Polje za kvačicu","Heading":"Naslov","Horizontal Rule":"Vodoravna linija","Sort selected lines":"Poredaj oznacene linije","Search in current note":"Potraži u trenutnoj bilješci","ID":"ID","Created":"Kreirano","Updated":"Ažurirano","Location":"Lokacija","URL":"URL","Note History":"Historija bilješke","Markup":"Markup","Previous versions of this note":"Ranije verzije ove bilješke","Note properties":"Svojstva bilješke","Disabled":"Isključeno","Search...":"Pretraživanje...","Import":"Unesi","Quit":"Zatvori","Actual Size":"Početne dimenzije","Website and documentation":"Internet stranica i dokumentacija","Close Window":"Zatvori prozor","Options":"Opcije","Save":"Pohrani","Safe mode is currently active. Note rendering and all plugins are temporarily disabled.":" ","Disable safe mode and restart":" ","View them now":"Pregledajte ih sada","Some items cannot be synchronised.":"Neke stavke nije moguće sinhronizovati.","One or more master keys need a password.":"Jedan ili više glavnih ključeva zahtijevaju lozinku.","Set the password":"Zadajte lozinku","Statistics...":"Statistika...","Rename":"Preimenuj","Rename notebook:":"Preimenujte bilježnicu:","New to-do":"Novi zadatak","Toggle sidebar":"Bočni meni","Set alarm":"Podesi zvučnu napomenu","Set alarm:":"Podesite zvučnu napomenu:","PDF File":"PDF datoteka","New note":"Nova bilješka","Toggle editor layout":"Prikaži uređivač","Rename tag:":"Preimenujte oznaku:","New notebook":"Nova bilježnica","NoteboLine truncated
|
||||
{"OK":"Uredu","Cancel":"Otkaži","The app is now going to close. Please relaunch it to complete the process.":"Aplikacija ce se zatvoriti. Molimo ponovo otvorite da bi se radnja potpuno zavrsila.","Goto Anything...":"Pronađite bilo šta...","Current version is up-to-date.":"Trenutna je verzija ažurirana.","%s (pre-release)":"%s (verzija pred objavljivanje)","An update is available, do you want to download it now?":"Nova je verzija dostupna. Želite li je preuzeti?","Your version: %s":"Vaša verzija: %s","New version: %s":"Nova verzija: %s","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Bilješka \"%s\" uspješno je rekonstruisana i pohranjena u bilježnicu \"%s\".","This note has no history":"Bilješka nema ranijih verzija","Unsupported link or message: %s":"Nepodržana veza ili poruka: %s","Restore":"Rekonstruiši","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Pritisnite na \"%s\" da rekonstruišete bilješku. Rezultat će biti kopiran u bilježnicu \"%s\". Trenutna verzija bilješke ostat će netaknuta.","Back":"Nazad","Remove":"Ukloni","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Izbrisati bilježnicu \"%s\"?\n\nSve bilješke i bilježnice unutar ove bilježnice također će biti izbrisane.","Delete":"Izbriši","Remove tag \"%s\" from all notes?":"Ukloniti oznaku \"%s\" iz svih bilješki?","Remove this search from the sidebar?":"Ukloniti ovu pretragu iz pomoćnog menija?","Export":"Iznesi","All notes":"Sve bilješke","Synchronise":"Sinhronizuj","Notebooks":"Bilježnice","Tags":"Oznake","Decrypting items: %d/%d":"Dešifrujem stavke: %d/%d","Fetching resources: %d/%d":"Preuzimam resurse: %d/%d","Sidebar":"Bočni meni","Focus":"Fokus","Please select where the sync status should be exported to":"Navedite gdje će biti pohranjen status sinhronizacije","Retry":"Ponovi","strong text":"podebljani tekst","Insert Hyperlink":"Unesi poveznicu","List item":"Stavka nabrajanja","Layout":"Prikaz","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Bilješka je prazna. Pritisnite na \"%s\" da otvorite program za rad s tekstom i uredite bilješku.","Cut":"Izreži","Copy":"Kopiraj","Paste":"Zalijepi","Highlight":"Oznaci","Edit":"Uredi","Attach file":"Priloži datoteku","Code Block":"Kōd (izdvojen)","Inline Code":"Kōd (unutar teksta)","Insert Date Time":"Unesi datum i vrijeme","Drop notes or files here":"Ispustite bilješke ili datoteke ovdje","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Pričekajte dok svi prilozi ne budu preuzeti i dešifrovani. Također možete otvoriti %s da uredite bilješku.","There was an error downloading this attachment:":"Došlo je do greške prilikom preuzimanja priloga:","Open...":"Otvori...","Save as...":"Pohrani kao...","Reveal file in folder":"Pokaži datoteku u direktoriju","Copy path to clipboard":"Kopiraj putanju u spremnik","Copy Link Address":"Kopiraj adresu veze","to-do":"zadatak","note":"bilješka","Creating new %s...":"Kreiram: %s...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Ovaj Text editor ima par ogranicenja i preporucujemo da budete upoznati sa njima prije koristenja.","Read more about it":"Saznajte vise","Dismiss":"Odbaci","In: %s":"U: %s","Select all":"Označi sve","Bold":"Masna slova","Italic":"Kurziv","Hyperlink":"Poveznica","Code":"Kōd","Numbered List":"Numerisano nabrajanje","Bulleted List":"Nabrajanje","Checkbox":"Polje za kvačicu","Heading":"Naslov","Horizontal Rule":"Vodoravna linija","Sort selected lines":"Poredaj oznacene linije","Search in current note":"Potraži u trenutnoj bilješci","ID":"ID","Created":"Kreirano","Updated":"Ažurirano","Location":"Lokacija","URL":"URL","Note History":"Historija bilješke","Markup":"Markup","Previous versions of this note":"Ranije verzije ove bilješke","Note properties":"Svojstva bilješke","Disabled":"Isključeno","Search...":"Pretraživanje...","Import":"Unesi","Quit":"Zatvori","Actual Size":"Početne dimenzije","Website and documentation":"Internet stranica i dokumentacija","Close Window":"Zatvori prozor","Options":"Opcije","Save":"Pohrani","Safe mode is currently active. Note rendering and all plugins are temporarily disabled.":" ","Disable safe mode and restart":" ","View them now":"Pregledajte ih sada","Some items cannot be synchronised.":"Neke stavke nije moguće sinhronizovati.","One or more master keys need a password.":"Jedan ili više glavnih ključeva zahtijevaju lozinku.","Set the password":"Zadajte lozinku","Statistics...":"Statistika...","Rename":"Preimenuj","Rename notebook:":"Preimenujte bilježnicu:","New to-do":"Novi zadatak","Toggle sidebar":"Bočni meni","Set alarm":"Podesi zvučnu napomenu","Set alarm:":"Podesite zvučnu napomenu:","PDF File":"PDF datotLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"D'acord","Cancel":"Cancel·la","Goto Anything...":"Anar a qualsevol cosa...","Exporting to \"%s\" as \"%s\" format. Please wait...":"S'està exportant a «%s» com a format «%s». Espereu...","Could not export notes: %s":"No s'han pogut exportar les notes: %s","Current version is up-to-date.":"La versió actual està actualitzada.","%s (pre-release)":"%s (pre-llençament)","An update is available, do you want to download it now?":"Hi ha disponible una actualització. Voleu descarregar-la ara?","Your version: %s":"La vostra versió: %s","New version: %s":"Nova versió: %s","This note has no history":"Aquesta nota no té historial","Unsupported link or message: %s":"Missatge o enllaç no suportat: %s","Restore":"Restaurar","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Cliqueu «%s» per restaurar la nota. Aquesta serà copiada al el notebook anomenat «%s». La versió actual de la nota no serà substituïda o modificada.","Back":"Enrere","Remove":"Elimina","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Voleu suprimir el bloc de notes \"%s\"? \n\nTambé se suprimiran totes les notes i els sub-blocs d'aquest bloc de notes.","Delete":"Suprimeix","Remove tag \"%s\" from all notes?":"Voleu suprimir l'etiqueta \"%s\" de totes les notes?","Remove this search from the sidebar?":"Voleu suprimir aquesta cerca de la barra lateral?","Export":"Exporta","All notes":"Totes les notes","Synchronise":"Sincronitza","Notebooks":"Blocs de notes","Tags":"Etiquetes","Decrypting items: %d/%d":"S'estan desxifrant els elements: %d/%d","Fetching resources: %d/%d":"Obtenint recursos: %d/%d","Sidebar":"Barra lateral","Focus":"Focus","Please select where the sync status should be exported to":"Seleccioneu on s'hauria d'exportar l'estat de la sincronització","Retry All":"Torna a provar-los tots","Retry":"Torna a provar","strong text":"text destacat","emphasised text":"text ressaltat","Insert Hyperlink":"Introdueix un enllaç","List item":"Element de llista","Layout":"Disposició","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Aquesta nota no té contingut. Feu clic a «%s» per a anar a l'editor i modificar-la.","Cut":"Retalla","Copy":"Copia","Paste":"Enganxa","Checkbox list":"Llista de caselles de verificació","Edit":"Edita","Attach file":"Adjunta un fitxer","Code Block":"Bloc de codi","Inline Code":"Codi en línia","Insert Date Time":"Insereix la data i hora","Drop notes or files here":"Arrossega les notes o fitxers aquí","Code View":"Vista de codi","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Espereu que tots els adjunts hagin estat descarregats i desxifrats. També podeu canviar a %s per editar la nota.","There was an error downloading this attachment:":"Hi ha hagut un error al descarregar aquest adjunt:","This attachment is not downloaded or not decrypted yet":"Aquest adjunt no ha estat descarregat o desxifrat encara","Open...":"Obre...","Save as...":"Anomena i desa...","Reveal file in folder":"Mostra el fitxer a la carpeta","Copy path to clipboard":"Copia el camí al porta-retalls","Copy Link Address":"Copia l'adreça de l'enllaç","to-do":"tasques pendents","note":"nota","Creating new %s...":"S'està creant una %s...","In: %s":"A: %s","Select all":"Seleccioneu tot","Bold":"Negreta","Italic":"Cursiva","Hyperlink":"Enllaç","Code":"Codi","Numbered List":"Llista numerada","Bulleted List":"Llista de pics","Checkbox":"Casella de verificació","Heading":"Capçalera","Horizontal Rule":"Línia horitzontal","Note title":"Títol de la nota","Search in current note":"Cerca en la nota actual","Note body":"Cos de la nota","ID":"ID","Created":"Creació","Updated":"Actualització","Completed":"Finalitzat","Location":"Ubicació","URL":"URL","Note History":"Historial de la nota","Markup":"Marcatge","Previous versions of this note":"Versions prèvies d'aquesta nota","Note properties":"Propietats de la nota","Disabled":"Desactivat","Search...":"Cerca...","Import":"Importació","Quit":"Surt","Insert template":"Insereix plantilla","Actual Size":"Mida real","Website and documentation":"Lloc web i documentació","Close Window":"Tanca la finestra","Options":"Opcions","Save":"Desa","Some items cannot be decrypted.":"Alguns elements no s'han pogut desxifrar.","View them now":"Mostra'ls ara","One of your master keys use an obsolete encryption method.":"Una de les vostres claus mestres utilitza un mètode de xifratge obsolet.","The default encryption method has been changed, you should re-encrypt your data.":"El mètode de xifratge per defecte s'ha canviat, hauríeu de tornar a xifrar les vostres dades.","More info":"Més informació","Some items cannot be synchronised.":"Alguns elements no s'han pogut sincronitzar.","One or more master keys need a password.":"Una o més claus mestres neceLine truncated
|
||||
{"OK":"D'acord","Cancel":"Cancel·la","Goto Anything...":"Anar a qualsevol cosa...","Exporting to \"%s\" as \"%s\" format. Please wait...":"S'està exportant a «%s» com a format «%s». Espereu...","Could not export notes: %s":"No s'han pogut exportar les notes: %s","Current version is up-to-date.":"La versió actual està actualitzada.","%s (pre-release)":"%s (pre-llençament)","An update is available, do you want to download it now?":"Hi ha disponible una actualització. Voleu descarregar-la ara?","Your version: %s":"La vostra versió: %s","New version: %s":"Nova versió: %s","The note \"%s\" has been successfully restored to the notebook \"%s\".":"La nota «%s» s'ha restaurat amb èxit en el bloc de notes «%s».","This note has no history":"Aquesta nota no té historial","Unsupported link or message: %s":"Missatge o enllaç no suportat: %s","Restore":"Restaurar","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Cliqueu «%s» per restaurar la nota. Aquesta serà copiada al el notebook anomenat «%s». La versió actual de la nota no serà substituïda o modificada.","Back":"Enrere","Remove":"Elimina","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Voleu suprimir el bloc de notes \"%s\"? \n\nTambé se suprimiran totes les notes i els sub-blocs d'aquest bloc de notes.","Delete":"Suprimeix","Remove tag \"%s\" from all notes?":"Voleu suprimir l'etiqueta \"%s\" de totes les notes?","Remove this search from the sidebar?":"Voleu suprimir aquesta cerca de la barra lateral?","Export":"Exporta","All notes":"Totes les notes","Synchronise":"Sincronitza","Notebooks":"Blocs de notes","Tags":"Etiquetes","Decrypting items: %d/%d":"S'estan desxifrant els elements: %d/%d","Fetching resources: %d/%d":"Obtenint recursos: %d/%d","Sidebar":"Barra lateral","Focus":"Focus","Please select where the sync status should be exported to":"Seleccioneu on s'hauria d'exportar l'estat de la sincronització","Retry All":"Torna a provar-los tots","Retry":"Torna a provar","strong text":"text destacat","emphasised text":"text ressaltat","Insert Hyperlink":"Introdueix un enllaç","List item":"Element de llista","Layout":"Disposició","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Aquesta nota no té contingut. Feu clic a «%s» per a anar a l'editor i modificar-la.","Cut":"Retalla","Copy":"Copia","Paste":"Enganxa","Checkbox list":"Llista de caselles de verificació","Edit":"Edita","Attach file":"Adjunta un fitxer","Code Block":"Bloc de codi","Inline Code":"Codi en línia","Insert Date Time":"Insereix la data i hora","Drop notes or files here":"Arrossega les notes o fitxers aquí","Code View":"Vista de codi","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Espereu que tots els adjunts hagin estat descarregats i desxifrats. També podeu canviar a %s per editar la nota.","There was an error downloading this attachment:":"Hi ha hagut un error al descarregar aquest adjunt:","This attachment is not downloaded or not decrypted yet":"Aquest adjunt no ha estat descarregat o desxifrat encara","Open...":"Obre...","Save as...":"Anomena i desa...","Reveal file in folder":"Mostra el fitxer a la carpeta","Copy path to clipboard":"Copia el camí al porta-retalls","Copy Link Address":"Copia l'adreça de l'enllaç","to-do":"tasques pendents","note":"nota","Creating new %s...":"S'està creant una %s...","In: %s":"A: %s","Select all":"Seleccioneu tot","Bold":"Negreta","Italic":"Cursiva","Hyperlink":"Enllaç","Code":"Codi","Numbered List":"Llista numerada","Bulleted List":"Llista de pics","Checkbox":"Casella de verificació","Heading":"Capçalera","Horizontal Rule":"Línia horitzontal","Note title":"Títol de la nota","Search in current note":"Cerca en la nota actual","Note body":"Cos de la nota","ID":"ID","Created":"Creació","Updated":"Actualització","Completed":"Finalitzat","Location":"Ubicació","URL":"URL","Note History":"Historial de la nota","Markup":"Marcatge","Previous versions of this note":"Versions prèvies d'aquesta nota","Note properties":"Propietats de la nota","Disabled":"Desactivat","Search...":"Cerca...","Import":"Importació","Quit":"Surt","Insert template":"Insereix plantilla","Actual Size":"Mida real","Website and documentation":"Lloc web i documentació","Close Window":"Tanca la finestra","Options":"Opcions","Save":"Desa","Some items cannot be decrypted.":"Alguns elements no s'han pogut desxifrar.","View them now":"Mostra'ls ara","One of your master keys use an obsolete encryption method.":"Una de les vostres claus mestres utilitza un mètode de xifratge obsolet.","The default encryption method has been changed, you should re-encrypt your data.":"El mètode de xifratge per defecte s'ha canviat, hauríeu de tornar a xifrar les vostres dades.","More info":"Més informació","Some items caLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Zrušit","The app is now going to close. Please relaunch it to complete the process.":"Aplikace se nyní vypne. Pro dokončení procesu ji znovu spusťte.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Zadejte název poznámky, na kterou chcete přeskočit, nebo část jejího obsahu. Nebo zadejte # následovaný názvem štítku, @ následovaný názvem poznámky, nebo : pro vyhledávání příkazů.","Goto Anything...":"Přejít na...","Command palette":"Nabídka příkazů","Exporting to \"%s\" as \"%s\" format. Please wait...":"Probíhá export do \"%s\" ve formátu \"%s\". Počkejte prosím...","Could not export notes: %s":"Nelze exportovat poznámky: %s","Current version is up-to-date.":"Současná verze je aktuální.","%s (pre-release)":"%s (nefinální vydání)","An update is available, do you want to download it now?":"Je k dispozici aktualizace, chcete ji stáhnout?","Your version: %s":"Vaše verze: %s","New version: %s":"Nová verze: %s","Download":"Stáhnout","Skip this version":"Přeskočit tuto verzi","Full changelog":"Úplný seznam změn","This note has no history":"Tato poznámka nemá historii","Unsupported link or message: %s":"Nepodporovaný odkaz či zpráva: %s","Restore":"Obnovit","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Pro obnovení poznámky klepněte na \"%s\". Poznámka bude zkopírována do zápisníku \"%s\". Současná verze poznámky nebude nahrazena ani změněna.","Back":"Zpět","Remove":"Odstranit","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Smazat zápisník \"%s\"?\n\nBudou smazány i všechny poznámky a pod-zápisníky v tomto zápisníku.","Delete":"Smazat","Remove tag \"%s\" from all notes?":"Odebrat štítek \"%s\" ze všech poznámek?","Remove this search from the sidebar?":"Smazat tento hledaný výraz z panelu?","Export":"Exportovat","All notes":"Všechny poznámky","Synchronise":"Synchronizovat","Notebooks":"Zápisníky","Tags":"Štítky","Decrypting items: %d/%d":"Dešifrování položek: %d/%d","Fetching resources: %d/%d":"Stahování zdrojů: %d/%d","Sidebar":"Postranní lišta","Focus":"Přejít na","Please select where the sync status should be exported to":"Prosím vyberte, kam má být stav synchronizace exportován","Retry All":"Opakovat vše","Retry":"Znovu","Advanced tools":"Pokročilé volby","Export debug report":"Exportovat ladicí hlášení","strong text":"tučný text","emphasised text":"zvýrazněný text","Insert Hyperlink":"Vložit odkaz","List item":"Seznam položek","Layout":"Rozložení","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Tato poznámka je prázdná. pro otevření editoru klepněte na \"%s\".","Cut":"Vyjmout","Copy":"Kopírovat","Paste":"Vložit","Checkbox list":"Zaškrtávací pole","Highlight":"Zvýraznění","Strikethrough":"Přeškrtnutí","Insert":"Vložit","Superscript":"Horní index","Subscript":"Dolní index","Edit":"Upravit","Attach file":"Přiložit soubor","Code Block":"Blok kódu","Inline Code":"Vložený kód","Insert Date Time":"Vložit datum a čas","Drop notes or files here":"Sem přetáhněte poznámky nebo soubory","Code View":"Zobrazit kód","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Počkejte prosím na stažení a dešifrování všech příloh. Můžete také přepnout na %s a poznámku upravit.","There was an error downloading this attachment:":"Při stahování této přílohy došlo k chybě:","This attachment is not downloaded or not decrypted yet":"Tato příloha ještě není stažena nebo dešifrována","Open...":"Otevřít...","Save as...":"Uložit jako...","Reveal file in folder":"Ukázat soubor ve složce","Copy path to clipboard":"Kopírovat cestu do schránky","Copy Link Address":"Kopírovat adresu odkazu","to-do":"Nový úkol","note":"Nová poznámka","Creating new %s...":"%s...","Click to add tags...":"Klepněte pro přidání štítku...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Tento editor formátovaného textu má řadu omezení a při jeho používání doporučujeme mít se na pozoru.","Read more about it":"Zjistit více","Dismiss":"Zavřít","The following attachments are being watched for changes:":"Následující přílohy jsou sledovány, zda došlo k jejich změně:","The attachments will no longer be watched when you switch to a different note.":"Když přepnete na jinou poznámku, přílohy již nebudou sledovány.","In: %s":"V: %s","Select all":"Vybrat vše","Bold":"Tučně","Italic":"Kurzíva","Hyperlink":"Odkaz","Code":"Kód","Numbered List":"Číslovaný seznam","Bulleted List":"Seznam s odrážkami",Line truncated
|
||||
{"OK":"OK","Cancel":"Zrušit","The app is now going to close. Please relaunch it to complete the process.":"Aplikace se nyní vypne. Pro dokončení procesu ji znovu spusťte.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Zadejte název poznámky, na kterou chcete přeskočit, nebo část jejího obsahu. Nebo zadejte # následovaný názvem štítku, @ následovaný názvem poznámky, nebo : pro vyhledávání příkazů.","Goto Anything...":"Přejít na...","Command palette":"Nabídka příkazů","Exporting to \"%s\" as \"%s\" format. Please wait...":"Probíhá export do \"%s\" ve formátu \"%s\". Počkejte prosím...","Could not export notes: %s":"Nelze exportovat poznámky: %s","Current version is up-to-date.":"Současná verze je aktuální.","%s (pre-release)":"%s (nefinální vydání)","An update is available, do you want to download it now?":"Je k dispozici aktualizace, chcete ji stáhnout?","Your version: %s":"Vaše verze: %s","New version: %s":"Nová verze: %s","Download":"Stáhnout","Skip this version":"Přeskočit tuto verzi","Full changelog":"Úplný seznam změn","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Poznámka \"%s\" byla úspěšně obnovena v zápisníku \"%s\".","This note has no history":"Tato poznámka nemá historii","Unsupported link or message: %s":"Nepodporovaný odkaz či zpráva: %s","Restore":"Obnovit","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Pro obnovení poznámky klepněte na \"%s\". Poznámka bude zkopírována do zápisníku \"%s\". Současná verze poznámky nebude nahrazena ani změněna.","Back":"Zpět","Remove":"Odstranit","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Smazat zápisník \"%s\"?\n\nBudou smazány i všechny poznámky a pod-zápisníky v tomto zápisníku.","Delete":"Smazat","Remove tag \"%s\" from all notes?":"Odebrat štítek \"%s\" ze všech poznámek?","Remove this search from the sidebar?":"Smazat tento hledaný výraz z panelu?","Export":"Exportovat","All notes":"Všechny poznámky","Synchronise":"Synchronizovat","Notebooks":"Zápisníky","Tags":"Štítky","Decrypting items: %d/%d":"Dešifrování položek: %d/%d","Fetching resources: %d/%d":"Stahování zdrojů: %d/%d","Sidebar":"Postranní lišta","Focus":"Přejít na","Please select where the sync status should be exported to":"Prosím vyberte, kam má být stav synchronizace exportován","Retry All":"Opakovat vše","Retry":"Znovu","Advanced tools":"Pokročilé volby","Export debug report":"Exportovat ladicí hlášení","strong text":"tučný text","emphasised text":"zvýrazněný text","Insert Hyperlink":"Vložit odkaz","List item":"Seznam položek","Layout":"Rozložení","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Tato poznámka je prázdná. pro otevření editoru klepněte na \"%s\".","Cut":"Vyjmout","Copy":"Kopírovat","Paste":"Vložit","Checkbox list":"Zaškrtávací pole","Highlight":"Zvýraznění","Strikethrough":"Přeškrtnutí","Insert":"Vložit","Superscript":"Horní index","Subscript":"Dolní index","Edit":"Upravit","Attach file":"Přiložit soubor","Code Block":"Blok kódu","Inline Code":"Vložený kód","Insert Date Time":"Vložit datum a čas","Drop notes or files here":"Sem přetáhněte poznámky nebo soubory","Code View":"Zobrazit kód","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Počkejte prosím na stažení a dešifrování všech příloh. Můžete také přepnout na %s a poznámku upravit.","There was an error downloading this attachment:":"Při stahování této přílohy došlo k chybě:","This attachment is not downloaded or not decrypted yet":"Tato příloha ještě není stažena nebo dešifrována","Open...":"Otevřít...","Save as...":"Uložit jako...","Reveal file in folder":"Ukázat soubor ve složce","Copy path to clipboard":"Kopírovat cestu do schránky","Copy Link Address":"Kopírovat adresu odkazu","to-do":"Nový úkol","note":"Nová poznámka","Creating new %s...":"%s...","Click to add tags...":"Klepněte pro přidání štítku...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Tento editor formátovaného textu má řadu omezení a při jeho používání doporučujeme mít se na pozoru.","Read more about it":"Zjistit více","Dismiss":"Zavřít","The following attachments are being watched for changes:":"Následující přílohy jsou sledovány, zda došlo k jejich změně:","The attachments will no longer be watched when you switch to a different note.":"Když přepnete na jinou poznámku, přílohy již nebudou sledovány.","In: %s":"V: %s","Select all":"Vybrat vše","Bold":"Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Annullér","The app is now going to close. Please relaunch it to complete the process.":"Appen lukker nu. Genstart den for at fuldføre processen.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Skriv titlen på en note eller noget af notens indhold for at hoppe til den. Eller skriv # efterfulgt af et etikettenavn, eller @ efterfulgt af en notesbogs navn. Eller skriv: for at søge efter kommandoer.","Goto Anything...":"Gå til tilfældig...","Command palette":"Kommando-udvalg","Exporting to \"%s\" as \"%s\" format. Please wait...":"Eksporterer til \"%s\" som \"%s\"-format. Vent venligst...","Could not export notes: %s":"Kunne ikke eksportere noterne: %s","Current version is up-to-date.":"Aktuel version er den nyeste.","%s (pre-release)":"%s (pre-release)","An update is available, do you want to download it now?":"Opdatering er tilgængelig, vil du hente den nu?","Your version: %s":"Din version: %s","New version: %s":"Ny version: %s","Download":"Download","Skip this version":"Spring denne version over","Full changelog":"Komplet ændringslog","This note has no history":"Denne note har ingen historie","Unsupported link or message: %s":"Ugyldigt link eller besked: %s","Restore":"Gendan","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Klik på \"%s\" for at gendanne noten. Den vil blive kopieret til notesbogen \"%s\". Den nuværende version af noten vil ikke blive erstattet eller ændret.","Back":"Tilbage","Remove":"Fjern","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Slet notesbogen \"%s\"?\n\nAlle noter og undernotesbøger i denne notesbog bliver også slettet.","Delete":"Slet","Remove tag \"%s\" from all notes?":"Slet etikette \"%s\" fra alle noter?","Remove this search from the sidebar?":"Slet denne søgning fra sidebjælken?","Export":"Eksportér","All notes":"Alle noter","Synchronise":"Synkroniser","Notebooks":"Notesbøger","Tags":"Etiketter","Decrypting items: %d/%d":"Dekrypterede emner: %d/%d","Fetching resources: %d/%d":"Henter ressourcer: %d/%d","Sidebar":"Sidebjælke","Focus":"Fokuser","Please select where the sync status should be exported to":"Vælg hvor synk-status skal eksporteres til","Retry All":"Prøv Alle","Retry":"Prøv igen","Export debug report":"Eksporter fejlrapport","strong text":"fed (strong) tekst","emphasised text":"fremhævet tekst","Insert Hyperlink":"Indsæt hyperlink","List item":"Listepunkt","Layout":"Layout","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Denne note er har intet indhold. Klik på \"%s\" for at starte editoren og redigere noten.","Cut":"Klip","Copy":"Kopier","Paste":"Indsæt","Checkbox list":"Afkrydsningsliste","Highlight":"Fremhæv","Strikethrough":"Gennemstregning","Insert":"Indsæt","Superscript":"Hævet skrift","Subscript":"Sænket skrift","Edit":"Redigér","Attach file":"Vedhæft fil","Code Block":"Kode blok","Inline Code":"Inline-kode","Insert Date Time":"Indsæt dato og tid","Drop notes or files here":"Slip noter eller filer her","Code View":"Kodevisning","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Vent venligst på at alle vedhæftninger downloades og dekrypteres. Du kan også skifte til %s for at redigere noten.","There was an error downloading this attachment:":"Der opstod en fejl ved download af denne vedhæftning:","This attachment is not downloaded or not decrypted yet":"Denne vedhæftning er ikke downloadet eller ikke dekrypteret endnu","Open...":"Åbn...","Save as...":"Gem som...","Reveal file in folder":"Vis fil i mappe","Copy path to clipboard":"Kopier sti til udklipsholder","Copy Link Address":"Kopier linkadresse","to-do":"opgave","note":"note","Creating new %s...":"Opretter ny %s...","Click to add tags...":"Klik for at tilføje etiketter...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Denne Rich Text editor har en række begrænsninger, og det anbefales at være opmærksom på disse, før den bruges.","Read more about it":"Læs mere om det","Dismiss":"Afvis","The following attachments are being watched for changes:":"Følgende vedhæftninger overvåges for ændringer:","The attachments will no longer be watched when you switch to a different note.":"Vedhæftningerne vil ikke længere blive overvåget, hvis du skifter til en anden note.","In: %s":"I: %s","Select all":"Vælg alt","Bold":"Fed","Italic":"Kursiv","Hyperlink":"Hyperlink","Code":"Kode","Numbered List":"Nummeret liste","Bulleted List":"Punktliste","Checkbox":"Afkrydsningsfelt","Heading":"Overskrift","Horizontal Rule":"Vandret linje","Delete line":"Slet linje","Duplicate line":"Dupliker linje","Undo":"Fortryd","Redo":"Gentag","InLine truncated
|
||||
{"OK":"OK","Cancel":"Annullér","The app is now going to close. Please relaunch it to complete the process.":"Appen lukker nu. Genstart den for at fuldføre processen.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Skriv titlen på en note eller noget af notens indhold for at hoppe til den. Eller skriv # efterfulgt af et etikettenavn, eller @ efterfulgt af en notesbogs navn. Eller skriv: for at søge efter kommandoer.","Goto Anything...":"Gå til tilfældig...","Command palette":"Kommando-palet","Exporting to \"%s\" as \"%s\" format. Please wait...":"Eksporterer til \"%s\" som \"%s\"-format. Vent venligst...","Could not export notes: %s":"Kunne ikke eksportere noterne: %s","Current version is up-to-date.":"Aktuel version er den nyeste.","%s (pre-release)":"%s (pre-release)","An update is available, do you want to download it now?":"Opdatering er tilgængelig, vil du hente den nu?","Your version: %s":"Din version: %s","New version: %s":"Ny version: %s","Download":"Download","Skip this version":"Spring denne version over","Full changelog":"Komplet ændringslog","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Noten \"%s\" er blevet gendannet til notesbogen \"%s\".","This note has no history":"Denne note har ingen historie","Unsupported link or message: %s":"Ugyldigt link eller besked: %s","Restore":"Gendan","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Klik på \"%s\" for at gendanne noten. Den vil blive kopieret til notesbogen \"%s\". Den nuværende version af noten vil ikke blive erstattet eller ændret.","Back":"Tilbage","Remove":"Fjern","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Slet notesbogen \"%s\"?\n\nAlle noter og undernotesbøger i denne notesbog bliver også slettet.","Delete":"Slet","Remove tag \"%s\" from all notes?":"Slet etikette \"%s\" fra alle noter?","Remove this search from the sidebar?":"Slet denne søgning fra sidebjælken?","Export":"Eksportér","All notes":"Alle noter","Synchronise":"Synkroniser","Notebooks":"Notesbøger","Tags":"Etiketter","Decrypting items: %d/%d":"Dekrypterede emner: %d/%d","Fetching resources: %d/%d":"Henter ressourcer: %d/%d","Sidebar":"Sidebjælke","Focus":"Fokuser","Please select where the sync status should be exported to":"Vælg hvor synk-status skal eksporteres til","Retry All":"Prøv Alle","Retry":"Prøv igen","Export debug report":"Eksporter fejlrapport","strong text":"fed (strong) tekst","emphasised text":"fremhævet tekst","Insert Hyperlink":"Indsæt hyperlink","List item":"Listepunkt","Layout":"Layout","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Denne note er har intet indhold. Klik på \"%s\" for at starte editoren og redigere noten.","Cut":"Klip","Copy":"Kopier","Paste":"Indsæt","Checkbox list":"Afkrydsningsliste","Highlight":"Fremhæv","Strikethrough":"Gennemstregning","Insert":"Indsæt","Superscript":"Hævet skrift","Subscript":"Sænket skrift","Edit":"Rediger","Attach file":"Vedhæft fil","Code Block":"Kode blok","Inline Code":"Inline-kode","Insert Date Time":"Indsæt dato og tid","Drop notes or files here":"Slip noter eller filer her","Code View":"Kodevisning","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Vent venligst på at alle vedhæftninger downloades og dekrypteres. Du kan også skifte til %s for at redigere noten.","There was an error downloading this attachment:":"Der opstod en fejl ved download af denne vedhæftning:","This attachment is not downloaded or not decrypted yet":"Denne vedhæftning er ikke downloadet eller ikke dekrypteret endnu","Open...":"Åbn...","Save as...":"Gem som...","Reveal file in folder":"Vis fil i mappe","Copy path to clipboard":"Kopier sti til udklipsholder","Copy Link Address":"Kopier linkadresse","to-do":"opgave","note":"note","Creating new %s...":"Opretter ny %s...","Click to add tags...":"Klik for at tilføje etiketter...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Denne Rich Text editor har en række begrænsninger, og det anbefales at være opmærksom på disse, før den bruges.","Read more about it":"Læs mere om det","Dismiss":"Afvis","The following attachments are being watched for changes:":"Følgende vedhæftninger overvåges for ændringer:","The attachments will no longer be watched when you switch to a different note.":"Vedhæftningerne vil ikke længere blive overvåget, hvis du skifter til en anden note.","In: %s":"I: %s","Select all":"Vælg alt","Bold":"Fed","Italic":"Kursiv","Hyperlink":"Hyperlink","Code":"Kode","Numbered List":"Nummeret liste","Bulleted List":"Punktliste","Checkbox":"Afkrydsningsfelt","Heading":"Overskrift","HLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Abbrechen","The app is now going to close. Please relaunch it to complete the process.":"Die App wird nun geschlossen. Bitte starte sie erneut, um den Vorgang abzuschließen.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Gib den Titel einer Notiz oder einen Teil seines Inhalts ein, um dorthin zu springen. Oder gib # gefolgt von einem Schlagwort oder @ gefolgt vom Namen eines Notizbuchs ein. Oder gib : für eine Suche nach Kommandos ein.","Goto Anything...":"Gehe zu ...","Command palette":"Befehlspalette","Exporting to \"%s\" as \"%s\" format. Please wait...":"Es wird nach „%s“ im Format „%s“ exportiert. Bitte warten ...","Could not export notes: %s":"Konnte Notizen nicht exportieren: %s","Current version is up-to-date.":"Die aktuelle Version ist auf dem neuesten Stand.","%s (pre-release)":"%s (Vorabversion)","An update is available, do you want to download it now?":"Es ist eine Aktualisierung verfügbar. Soll sie jetzt heruntergeladen werden?","Your version: %s":"Deine Version: %s","New version: %s":"Neue Version: %s","Download":"Herunterladen","This note has no history":"Diese Notiz hat keinen Verlauf","Unsupported link or message: %s":"Nicht unterstützter Link oder Nachricht: %s","Restore":"Wiederherstellen","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Klicke „%s“, um die Notiz wiederherzustellen. Sie wird in das Notizbuch namens „%s“ kopiert. Die aktuelle Version der Notiz wird nicht ersetzt oder verändert.","Back":"Zurück","Remove":"Entfernen","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Notizbuch „%s“ löschen?\n\nAlle Notizen und Unter-Notizbücher in diesem Notizbuch werden ebenfalls gelöscht.","Delete":"Löschen","Remove tag \"%s\" from all notes?":"Schlagwort „%s“ von allen Notizen entfernen?","Remove this search from the sidebar?":"Diese Suche von der Seitenleiste entfernen?","Export":"Exportieren","All notes":"Alle Notizen","Synchronise":"Synchronisieren","Notebooks":"Notizbücher","Tags":"Schlagwörter","Decrypting items: %d/%d":"Entschlüsselte Objekte: %d/%d","Fetching resources: %d/%d":"Anhänge abrufen: %d/%d","Sidebar":"Seitenleiste","Focus":"Fokus","Please select where the sync status should be exported to":"Bitte wähle aus, wohin der Synchronisations-Status exportiert werden soll","Retry All":"Erneut alle versuchen","Retry":"Erneut versuchen","strong text":"fetter Text","emphasised text":"hervorgehobener Text","Insert Hyperlink":"Weblink einfügen","List item":"Listeneintrag","Layout":"Layout","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Diese Notiz hat keinen Inhalt. Klicke auf „%s“, um den Editor zu aktivieren und die Notiz zu bearbeiten.","Cut":"Ausschneiden","Copy":"Kopieren","Paste":"Einfügen","Checkbox list":"Liste mit Kontrollkästchen","Highlight":"Hervorheben","Strikethrough":"Durchstreichen","Insert":"Einfügen","Superscript":"Hochgestellt","Subscript":"Tiefgestellt","Edit":"Bearbeiten","Attach file":"Datei anhängen","Code Block":"Code-Block","Inline Code":"Code im Fließtext","Insert Date Time":"Datum / Uhrzeit einfügen","Drop notes or files here":"Notizen oder Dateien hierher ziehen","Code View":"Code-Ansicht","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Bitte warte, bis alle Anhänge heruntergeladen und entschlüsselt sind. Du kannst auch auf/zu %s wechseln, um die Notiz zu bearbeiten.","There was an error downloading this attachment:":"Es gab einen Fehler beim Herunterladen dieses Anhangs:","This attachment is not downloaded or not decrypted yet":"Dieser Anhang wurde noch nicht heruntergeladen oder entschlüsselt","Open...":"Öffnen ...","Save as...":"Speichern unter ...","Reveal file in folder":"Datei im Ordner anzeigen","Copy path to clipboard":"Pfad in Zwischenablage kopieren","Copy Link Address":"Link-Adresse kopieren","to-do":"Aufgabe","note":"Notiz","Creating new %s...":"Neue(s) %s wird erstellt ...","Click to add tags...":"Zum Hinzufügen von Schlagwörtern klicken ...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Dieser Rich Text Editor hat eine Reihe von Unzulänglichkeiten, die bei der Nutzung beachtet werden sollten.","Read more about it":"Mehr erfahren","Dismiss":"Ausblenden","The following attachments are being watched for changes:":"Die folgenden Anhänge werden auf Änderungen überwacht:","The attachments will no longer be watched when you switch to a different note.":"Die Anhänge werden nicht mehr überwacht, wenn Sie zu einer anderen Notiz wechseln.","In: %s":"In: %s","Select all":"Alles auswählen","Bold":"Fett","Italic":"Kursiv","Hyperlink":"Hyperlink","CLine truncated
|
||||
{"OK":"OK","Cancel":"Abbrechen","The app is now going to close. Please relaunch it to complete the process.":"Die App wird nun geschlossen. Bitte starte sie erneut, um den Vorgang abzuschließen.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Gib den Titel einer Notiz oder einen Teil seines Inhalts ein, um dorthin zu springen. Oder gib # gefolgt von einem Schlagwort oder @ gefolgt vom Namen eines Notizbuchs ein. Oder gib : für eine Suche nach Kommandos ein.","Goto Anything...":"Gehe zu ...","Command palette":"Befehlspalette","Exporting to \"%s\" as \"%s\" format. Please wait...":"Es wird nach „%s“ im Format „%s“ exportiert. Bitte warten ...","Could not export notes: %s":"Konnte Notizen nicht exportieren: %s","Current version is up-to-date.":"Die aktuelle Version ist auf dem neuesten Stand.","%s (pre-release)":"%s (Vorabversion)","An update is available, do you want to download it now?":"Es ist eine Aktualisierung verfügbar. Soll sie jetzt heruntergeladen werden?","Your version: %s":"Deine Version: %s","New version: %s":"Neue Version: %s","Download":"Herunterladen","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Die Notiz „%s“ wurde erfolgreich im Notizbuch „%s“ wiederhergestellt.","This note has no history":"Diese Notiz hat keinen Verlauf","Unsupported link or message: %s":"Nicht unterstützter Link oder Nachricht: %s","Restore":"Wiederherstellen","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Klicke „%s“, um die Notiz wiederherzustellen. Sie wird in das Notizbuch namens „%s“ kopiert. Die aktuelle Version der Notiz wird nicht ersetzt oder verändert.","Back":"Zurück","Remove":"Entfernen","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Notizbuch „%s“ löschen?\n\nAlle Notizen und Unter-Notizbücher in diesem Notizbuch werden ebenfalls gelöscht.","Delete":"Löschen","Remove tag \"%s\" from all notes?":"Schlagwort „%s“ von allen Notizen entfernen?","Remove this search from the sidebar?":"Diese Suche von der Seitenleiste entfernen?","Export":"Exportieren","All notes":"Alle Notizen","Synchronise":"Synchronisieren","Notebooks":"Notizbücher","Tags":"Schlagwörter","Decrypting items: %d/%d":"Entschlüsselte Objekte: %d/%d","Fetching resources: %d/%d":"Anhänge abrufen: %d/%d","Sidebar":"Seitenleiste","Focus":"Fokus","Please select where the sync status should be exported to":"Bitte wähle aus, wohin der Synchronisations-Status exportiert werden soll","Retry All":"Erneut alle versuchen","Retry":"Erneut versuchen","strong text":"fetter Text","emphasised text":"hervorgehobener Text","Insert Hyperlink":"Weblink einfügen","List item":"Listeneintrag","Layout":"Layout","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Diese Notiz hat keinen Inhalt. Klicke auf „%s“, um den Editor zu aktivieren und die Notiz zu bearbeiten.","Cut":"Ausschneiden","Copy":"Kopieren","Paste":"Einfügen","Checkbox list":"Liste mit Kontrollkästchen","Highlight":"Hervorheben","Strikethrough":"Durchstreichen","Insert":"Einfügen","Superscript":"Hochgestellt","Subscript":"Tiefgestellt","Edit":"Bearbeiten","Attach file":"Datei anhängen","Code Block":"Code-Block","Inline Code":"Code im Fließtext","Insert Date Time":"Datum / Uhrzeit einfügen","Drop notes or files here":"Notizen oder Dateien hierher ziehen","Code View":"Code-Ansicht","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Bitte warte, bis alle Anhänge heruntergeladen und entschlüsselt sind. Du kannst auch auf/zu %s wechseln, um die Notiz zu bearbeiten.","There was an error downloading this attachment:":"Es gab einen Fehler beim Herunterladen dieses Anhangs:","This attachment is not downloaded or not decrypted yet":"Dieser Anhang wurde noch nicht heruntergeladen oder entschlüsselt","Open...":"Öffnen ...","Save as...":"Speichern unter ...","Reveal file in folder":"Datei im Ordner anzeigen","Copy path to clipboard":"Pfad in Zwischenablage kopieren","Copy Link Address":"Link-Adresse kopieren","to-do":"Aufgabe","note":"Notiz","Creating new %s...":"Neue(s) %s wird erstellt ...","Click to add tags...":"Zum Hinzufügen von Schlagwörtern klicken ...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Dieser Rich Text Editor hat eine Reihe von Unzulänglichkeiten, die bei der Nutzung beachtet werden sollten.","Read more about it":"Mehr erfahren","Dismiss":"Ausblenden","The following attachments are being watched for changes:":"Die folgenden Anhänge werden auf Änderungen überwacht:","The attachments will no longer be watched when you switch to a different note.":"Die Anhänge werden nicht mehr überwachtLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"Εντάξει","Cancel":"Άκυρο","The app is now going to close. Please relaunch it to complete the process.":"Η εφαρμογή θα κλείσει τώρα. Παρακαλώ ανοίξτε την ξανά για να ολοκληρώσετε τη διαδικασία.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Πληκτρολογήστε έναν τίτλο σημείωσης ή μέρος του περιεχομένου του για να μεταβείτε σε αυτόν. Ή πληκτρολογήστε # ακολουθούμενο από ένα όνομα ετικέτας ή @ ακολουθούμενο από ένα σημειωματάριο. Ή πληκτρολογίστε : για να ψάξετε για εντολές.","Goto Anything...":"Γρήγορη Μετακίνηση...","Command palette":"Παλέτα εντολών","Exporting to \"%s\" as \"%s\" format. Please wait...":"Γίνεται εξαγωγή στο \"%s\" με μορφή \"%s\". Παρακαλώ περιμένετε...","Could not export notes: %s":"Δεν ήταν δυνατή η εξαγωγή σημειώσεων: %s","Current version is up-to-date.":"Η τρέχουσα έκδοση είναι ενημερωμένη.","%s (pre-release)":"%s (pre-release)","An update is available, do you want to download it now?":"Υπάρχει διαθέσιμη μια ενημέρωση, θέλετε να την κατεβάσετε τώρα;","Your version: %s":"Η έκδοσή σου: %s","New version: %s":"Νέα έκδοση: %s","Download":"Λήψη","Full changelog":"Πλήρες αρχείο αλλαγών","This note has no history":"Αυτή η σημείωση δεν έχει ιστορικό","Unsupported link or message: %s":"Μη υποστηριζόμενος σύνδεσμος ή μήνυμα: %s","Restore":"Επαναφορά","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Κάντε κλικ στο \"%s\" για να επαναφέρετε τη σημείωση. Θα αντιγραφεί στο σημειωματάριο που ονομάζεται \"%s\". Η τρέχουσα έκδοση της σημείωσης δεν αντικαθίσταται ή τροποποιείται.","Back":"Πίσω","Remove":"Κατάργηση","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Διαγραφή σημειωματάριου \"%s\";\n\nΌλες οι σημειώσεις και τα υπο-σημειωματάρια που περιέχει θα διαγραφούν επίσης.","Delete":"Διαγραφή","Remove tag \"%s\" from all notes?":"Κατάργηση της ετικέτας \"%s\" από όλες τις σημειώσεις;","Remove this search from the sidebar?":"Κατάργηση αυτής της αναζήτησης από την πλευρική μπάρα;","Export":"Εξαγωγή","All notes":"Όλες οι σημειώσεις","Synchronise":"Συγχρονισμός","Notebooks":"Σημειωματάρια","Tags":"Ετικέτες","Decrypting items: %d/%d":"Αποκρυπτογράφηση αντικειμένων: %d/%d","Fetching resources: %d/%d":"Λήψη πόρων: %d/%d","Sidebar":"Πλευρική μπάρα","Focus":"Εστίαση σε","Please select where the sync status should be exported to":"Επιλέξτε την τοποθεσία στην οποία θα εξαχθεί η κατάσταση του συγχρονισμού","Retry All":"Δοκιμή ξανά για Όλα","Retry":"Δοκιμή ξανά","Advanced tools":"Προηγμένα εργαλεία","Export debug report":"Εξαγωγή Debug report","strong text":"έντονη γραφή","emphasised text":"κείμενο με έμφαση","Insert Hyperlink":"Εισαγωγή υπερσύνδεσης","List item":"Στοιχείο λίστας","Layout":"Διάταξη","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Αυτή η σημείωση δεν περιέχει περιεχόμενο. Κάντε κλικ στο \"%s\" για να επεξεργαστείτε τη σημείωση στον editor.","Cut":"Αποκοπή","Copy":"Αντιγραφή","Paste":"Επικόλληση","Checkbox list":"Λίστα πλαισίων ελέγχου","Highlight":"Επισήμανση","Strikethrough":"Διακριτή διαγραφή","Insert":"Εισαγωγή","Superscript":"Εκθέτης","Subscript":"Δείκτης","Edit":"Επεξεργασία","Attach file":"Επισύναψη αρχείου","Code Block":"Μπλοκ Κώδικα","Inline Code":"Ενσωματωμένος κώδικας","Insert Date Time":"Εισαγωγή Ημερομηνίας Ώρας","Drop notes or files here":"ΑπόθεLine truncated
|
||||
{"OK":"Εντάξει","Cancel":"Άκυρο","The app is now going to close. Please relaunch it to complete the process.":"Η εφαρμογή θα κλείσει τώρα. Παρακαλώ ανοίξτε την ξανά για να ολοκληρώσετε τη διαδικασία.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Πληκτρολογήστε έναν τίτλο σημείωσης ή μέρος του περιεχομένου του για να μεταβείτε σε αυτόν. Ή πληκτρολογήστε # ακολουθούμενο από ένα όνομα ετικέτας ή @ ακολουθούμενο από ένα σημειωματάριο. Ή πληκτρολογίστε : για να ψάξετε για εντολές.","Goto Anything...":"Γρήγορη Μετακίνηση...","Command palette":"Παλέτα εντολών","Exporting to \"%s\" as \"%s\" format. Please wait...":"Γίνεται εξαγωγή στο \"%s\" με μορφή \"%s\". Παρακαλώ περιμένετε...","Could not export notes: %s":"Δεν ήταν δυνατή η εξαγωγή σημειώσεων: %s","Current version is up-to-date.":"Η τρέχουσα έκδοση είναι ενημερωμένη.","%s (pre-release)":"%s (pre-release)","An update is available, do you want to download it now?":"Υπάρχει διαθέσιμη μια ενημέρωση, θέλετε να την κατεβάσετε τώρα;","Your version: %s":"Η έκδοσή σου: %s","New version: %s":"Νέα έκδοση: %s","Download":"Λήψη","Full changelog":"Πλήρες αρχείο αλλαγών","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Η σημείωση \"%s\" έχει επαναφερθεί με επιτυχία στο σημειωματάριο \"%s\".","This note has no history":"Αυτή η σημείωση δεν έχει ιστορικό","Unsupported link or message: %s":"Μη υποστηριζόμενος σύνδεσμος ή μήνυμα: %s","Restore":"Επαναφορά","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Κάντε κλικ στο \"%s\" για να επαναφέρετε τη σημείωση. Θα αντιγραφεί στο σημειωματάριο που ονομάζεται \"%s\". Η τρέχουσα έκδοση της σημείωσης δεν αντικαθίσταται ή τροποποιείται.","Back":"Πίσω","Remove":"Κατάργηση","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Διαγραφή σημειωματάριου \"%s\";\n\nΌλες οι σημειώσεις και τα υπο-σημειωματάρια που περιέχει θα διαγραφούν επίσης.","Delete":"Διαγραφή","Remove tag \"%s\" from all notes?":"Κατάργηση της ετικέτας \"%s\" από όλες τις σημειώσεις;","Remove this search from the sidebar?":"Κατάργηση αυτής της αναζήτησης από την πλευρική μπάρα;","Export":"Εξαγωγή","All notes":"Όλες οι σημειώσεις","Synchronise":"Συγχρονισμός","Notebooks":"Σημειωματάρια","Tags":"Ετικέτες","Decrypting items: %d/%d":"Αποκρυπτογράφηση αντικειμένων: %d/%d","Fetching resources: %d/%d":"Λήψη πόρων: %d/%d","Sidebar":"Πλευρική μπάρα","Focus":"Εστίαση σε","Please select where the sync status should be exported to":"Επιλέξτε την τοποθεσία στην οποία θα εξαχθεί η κατάσταση του συγχρονισμού","Retry All":"Δοκιμή ξανά για Όλα","Retry":"Δοκιμή ξανά","Advanced tools":"Προηγμένα εργαλεία","Export debug report":"Εξαγωγή Debug report","strong text":"έντονη γραφή","emphasised text":"κείμενο με έμφαση","Insert Hyperlink":"Εισαγωγή υπερσύνδεσης","List item":"Στοιχείο λίστας","Layout":"Διάταξη","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Αυτή η σημείωση δεν περιέχει περιεχόμενο. Κάντε κλικ στο \"%s\" για να επεξεργαστείτε τη σημείωση στον editor.","Cut":"Αποκοπή","Copy":"Αντιγραφή","Paste":"Επικόλληση","Checkbox list":"Λίστα πλαισίων ελέγχου","Highlight":"Επισήμανση","Strikethrough":"Διακριτή διαγραφή","Insert":"Εισαγωγή","Superscript":"Εκθέτης","Subscript":"Δείκτης","Edit":"Επεξεργασία","Attach file":"Επισύναψη αρχείου","Code BlLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"Bone","Cancel":"Nuligi","%s (pre-release)":"%s (antaŭeldono)","Your version: %s":"Via versio: %s","New version: %s":"Nova versio: %s","This note has no history":"Tiu noto ne havas historion","Restore":"Restaŭri","Back":"Reen","Remove":"Forigi","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Forigi notlibron \"%s\"?\n\nĈiuj notoj kaj subnotlibroj ene de tiu notlibro estos ankaŭ forigitaj.","Delete":"Forigi","Remove tag \"%s\" from all notes?":"Forigi etikedon \"%s\" el ĉiuj notoj?","Remove this search from the sidebar?":"Forigi tiun sercôn el la flankpanelo?","Export":"Eksporti","All notes":"Ĉiuj notoj","Synchronise":"Sinkronigi","Notebooks":"Notlibroj","Tags":"Etikedoj","Focus":"Fokusi","Retry":"Reprovi","Layout":"Aspektigo","Cut":"Eltondi","Copy":"Kopii","Paste":"Alglui","Edit":"Redakti","Attach file":"Aldoni dosieron","Open...":"Malfermi...","Save as...":"Konservi kiel...","to-do":"tasko","note":"noto","Creating new %s...":"Kreante novan %s...","In: %s":"En: %s","Select all":"Elekti ĉiujn","Bold":"Grasa","Italic":"Kursiva","Hyperlink":"Hiperligilo","Code":"Kodo","Checkbox":"Markobutono","ID":"Identigilo","Created":"Kreita","Updated":"Ĝisdatigita","Location":"Loko","URL":"URL","Note History":"Nota Historio","Markup":"Markado","Note properties":"Notaj atributoj","Disabled":"Malebligita","Search...":"Serĉi...","Import":"Importi","Quit":"Eliri","Website and documentation":"Retejo kaj dokumentado","Close Window":"Fermi Fenestron","Options":"Opcioj","Save":"Konservi","View them now":"Vidi ilin nun","Set the password":"Elekti pasvorton","Rename":"Renomi","Rename notebook:":"Renomi notlibron:","New to-do":"Nova tasko","PDF File":"PDF-dosiero","New note":"Nova noto","Rename tag:":"Renomi etikedon:","New notebook":"Nova notlibro","Notebook title:":"Notlibra titolo:","New sub-notebook":"Nova subnotlibro","Template file:":"Modela dosiero:","Add or remove tags:":"Aldoni aŭ forigi etikedojn:","Submit":"Submeti","Status: %s":"Stato: %s","Advanced options":"Altnivelaj opcioj","Copy token":"Kopii ĵetonon","&File":"&Dosiero","About Joplin":"Pri Joplin","Preferences...":"Preferoj...","Check for updates...":"Kontrolu ĝisdatigojn...","Templates":"Modeloj","Hide %s":"Kaŝi %s","&Edit":"&Redakti","&View":"&Monti","&Tools":"&Ilaro","&Help":"&Helpo","Joplin Forum":"Joplin-forumo","Get it now:":"Akiri ĝin nun:","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"Nova notlibro \"%s\" estos kreita kaj dosiero \"%s\" estos importita al ĝi","Found: %d.":"Trovita: %d.","Created: %d.":"Kreita: %d.","Updated: %d.":"Ĝisdatigita: %d.","The notes have been imported: %s":"La notoj estis importitaj: %s","Duplicate":"Duobligi","%s - Copy":"%s - Kopii","Switch between note and to-do type":"Ŝalti inter nota kaj taska tipo","Switch to note type":"Ŝalti al nota tipo","Switch to to-do type":"Ŝalti al taska tipo","Delete note \"%s\"?":"Forigi noton \"%s\"?","Delete these %d notes?":"Forigi tiujn %d notojn?","Master Keys":"Ĉefaj Klavoj","Active":"Aktiva","Source":"Fonto","Password":"Pasvorto","Password OK":"Pasvorto bone","Status":"Stato","Enabled":"Ebligita","OneDrive Login":"OneDrive-salutnomo","Dropbox Login":"Dropbox-salutnomo","Browse...":"Esplori...","Plugins":"Kromprogramoj","Apply":"Apliki","Clear":"Klariĝi","Sort notes by":"Ordigi notojn laŭ","No notes in here. Create one by clicking on \"New note\".":"Neniu noto ĉi tie. Por krei noton, alklaku \"Nova noto\".","Search in all the notes":"Ŝerci en ĉiuj notoj","Untitled":"Sen titolo","Share":"Konigi","Open %s":"Malfermi %s","Yes":"Jes","No":"Ne","Clear alarm":"Forigi alarmon","Save alarm":"Konservi alarmon","Permission to use camera":"Permeso por uzi kameraon","Delete these notes?":"Forigi tiujn notojn?","Notebook: %s":"Notlibro: %s","New Notebook":"Nova notlibro","Configuration":"Agordoj","Create a notebook":"Krei notlibron","Edit notebook":"Redakti notlibron","Enter notebook title":"Entajpu notlibron titolon","Login with OneDrive":"Ensaluti per OneDrive","Refresh":"Aktualigi","New tags:":"Novaj etikedoj:","Type new tags or select from list":"Tajpu novan etikedon aŭ elektu el la listo","Warning":"Averto","Tools":"Ilaro","Log":"Protokolo","More information":"Pli da informoj","Joplin website":"Joplin-retejo","Database v%s":"Datumbazo v%s","FTS enabled: %d":"FTS ebligita: %d","Login with Dropbox":"Ensaluti per Dropbox","Enter code here":"Entajpu kodon ĉi tie","Master Key %s":"Ĉefa Klavo %s","Created: %s":"Kreita: %s","Password:":"Pasvorto:","Password cannot be empty":"Pasvorto ne eblas esti malplena","Confirm password cannot be empty":"Konfimi pasvorton ne eblas esti malplena","Passwords do not match!":"Pasvorto ne kongruas!","Confirm password:":"Konfirmi pasvorton:","Enable":"Ebligi","This note has been modified:":"Tiu noto estis ŝanĝita:","Save changes":"Konservi la ŝanĝojn","Delete note?":"Ĉu forigi noton?","Unsupported image type: %s":"Nesubtenata bilda tipo: %s","Updated:Line truncated
|
||||
{"OK":"Bone","Cancel":"Nuligi","%s (pre-release)":"%s (antaŭeldono)","Your version: %s":"Via versio: %s","New version: %s":"Nova versio: %s","This note has no history":"Tiu noto ne havas historion","Restore":"Restaŭri","Back":"Reen","Remove":"Forigi","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Forigi notlibron \"%s\"?\n\nĈiuj notoj kaj subnotlibroj ene de tiu notlibro estos ankaŭ forigitaj.","Delete":"Forigi","Remove tag \"%s\" from all notes?":"Forigi etikedon \"%s\" el ĉiuj notoj?","Remove this search from the sidebar?":"Forigi tiun sercôn el la flankpanelo?","Export":"Eksporti","All notes":"Ĉiuj notoj","Synchronise":"Sinkronigi","Notebooks":"Notlibroj","Tags":"Etikedoj","Focus":"Fokusi","Retry":"Reprovi","Layout":"Aspektigo","Cut":"Eltondi","Copy":"Kopii","Paste":"Alglui","Edit":"Redakti","Attach file":"Aldoni dosieron","Open...":"Malfermi...","Save as...":"Konservi kiel...","to-do":"tasko","note":"noto","Creating new %s...":"Kreante novan %s...","In: %s":"En: %s","Select all":"Elekti ĉiujn","Bold":"Grasa","Italic":"Kursiva","Hyperlink":"Hiperligilo","Code":"Kodo","Checkbox":"Markobutono","ID":"Identigilo","Created":"Kreita","Updated":"Ĝisdatigita","Location":"Loko","URL":"URL","Note History":"Nota Historio","Markup":"Markado","Note properties":"Notaj atributoj","Disabled":"Malebligita","Search...":"Serĉi...","Import":"Importi","Quit":"Eliri","Website and documentation":"Retejo kaj dokumentado","Close Window":"Fermi Fenestron","Options":"Opcioj","Save":"Konservi","View them now":"Vidi ilin nun","Set the password":"Elekti pasvorton","Rename":"Renomi","Rename notebook:":"Renomi notlibron:","New to-do":"Nova tasko","PDF File":"PDF-dosiero","New note":"Nova noto","Rename tag:":"Renomi etikedon:","New notebook":"Nova notlibro","Notebook title:":"Notlibra titolo:","New sub-notebook":"Nova subnotlibro","Template file:":"Modela dosiero:","Add or remove tags:":"Aldoni aŭ forigi etikedojn:","Submit":"Submeti","Status: %s":"Stato: %s","Advanced options":"Altnivelaj opcioj","Copy token":"Kopii ĵetonon","&File":"&Dosiero","About Joplin":"Pri Joplin","Preferences...":"Preferoj...","Check for updates...":"Kontrolu ĝisdatigojn...","Templates":"Modeloj","Hide %s":"Kaŝi %s","&Edit":"&Redakti","&View":"&Monti","&Tools":"&Ilaro","&Help":"&Helpo","Joplin Forum":"Joplin-forumo","Get it now:":"Akiri ĝin nun:","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"Nova notlibro \"%s\" estos kreita kaj dosiero \"%s\" estos importita al ĝi","Found: %d.":"Trovita: %d.","Created: %d.":"Kreita: %d.","Updated: %d.":"Ĝisdatigita: %d.","The notes have been imported: %s":"La notoj estis importitaj: %s","Duplicate":"Duobligi","%s - Copy":"%s - Kopii","Switch between note and to-do type":"Ŝalti inter nota kaj taska tipo","Switch to note type":"Ŝalti al nota tipo","Switch to to-do type":"Ŝalti al taska tipo","Delete note \"%s\"?":"Forigi noton \"%s\"?","Delete these %d notes?":"Forigi tiujn %d notojn?","Master Keys":"Ĉefaj Klavoj","Active":"Aktiva","Source":"Fonto","Password":"Pasvorto","Password OK":"Pasvorto bone","Status":"Stato","Enabled":"Ebligita","OneDrive Login":"OneDrive-salutnomo","Dropbox Login":"Dropbox-salutnomo","Browse...":"Esplori...","Plugins":"Kromprogramoj","Apply":"Apliki","Clear":"Klariĝi","Sort notes by":"Ordigi notojn laŭ","No notes in here. Create one by clicking on \"New note\".":"Neniu noto ĉi tie. Por krei noton, alklaku \"Nova noto\".","Search in all the notes":"Ŝerci en ĉiuj notoj","Untitled":"Sen titolo","Share":"Konigi","Open %s":"Malfermi %s","Yes":"Jes","No":"Ne","Clear alarm":"Forigi alarmon","Save alarm":"Konservi alarmon","Permission to use camera":"Permeso por uzi kameraon","Delete these notes?":"Forigi tiujn notojn?","Notebook: %s":"Notlibro: %s","New Notebook":"Nova notlibro","Configuration":"Agordoj","Create a notebook":"Krei notlibron","Edit notebook":"Redakti notlibron","Enter notebook title":"Entajpu notlibron titolon","Login with OneDrive":"Ensaluti per OneDrive","Refresh":"Aktualigi","New tags:":"Novaj etikedoj:","Type new tags or select from list":"Tajpu novan etikedon aŭ elektu el la listo","Login with Dropbox":"Ensaluti per Dropbox","Enter code here":"Entajpu kodon ĉi tie","Master Key %s":"Ĉefa Klavo %s","Created: %s":"Kreita: %s","Password:":"Pasvorto:","Password cannot be empty":"Pasvorto ne eblas esti malplena","Confirm password cannot be empty":"Konfimi pasvorton ne eblas esti malplena","Passwords do not match!":"Pasvorto ne kongruas!","Confirm password:":"Konfirmi pasvorton:","Enable":"Ebligi","Warning":"Averto","Tools":"Ilaro","Log":"Protokolo","More information":"Pli da informoj","Joplin website":"Joplin-retejo","This note has been modified:":"Tiu noto estis ŝanĝita:","Save changes":"Konservi la ŝanĝojn","Delete note?":"Ĉu forigi noton?","Unsupported image type: %s":"Nesubtenata bilda tipo: %s","Updated: %s":"Ĝisdatigita: %s","View on map":"Vidi en mapo","Go to source ULine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Cancelar","The app is now going to close. Please relaunch it to complete the process.":"La aplicación se va a cerrar. Por favor, vuelva a iniciarla para completar el proceso.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Escriba el título de una nota o parte de su contenido para abrirla. O escriba # seguido del nombre de una etiqueta, o @ seguido del nombre de una libreta. O escriba : para buscar comandos.","Goto Anything...":"Ir a...","Command palette":"Paleta de comandos","Exporting to \"%s\" as \"%s\" format. Please wait...":"Exportando a «%s» como formato «%s». Por favor espere...","Could not export notes: %s":"No se pudo exportar las notas: %s","Current version is up-to-date.":"La versión actual está actualizada.","%s (pre-release)":"%s (prelanzamiento)","An update is available, do you want to download it now?":"Está disponible una actualización. ¿Quiere descargarla ahora?","Your version: %s":"Su versión: %s","New version: %s":"Nueva versión: %s","Download":"Descargar","Skip this version":"Omitir esta versión","Full changelog":"Registro de cambios completo","This note has no history":"Esta nota no tiene historial","Unsupported link or message: %s":"Enlace o mensaje no soportado: %s","Restore":"Restaurar","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Haga clic en «%s» para restaurar la nota. Será copiada en la libreta «%s». La versión actual de la nota no se reemplazará ni se modificará.","Back":"Retroceder","Remove":"Eliminar","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"¿Borrar libreta «%s»?\n\nTodas las notas y sublibretas de esta libreta serán borradas.","Delete":"Borrar","Remove tag \"%s\" from all notes?":"¿Desea eliminar la etiqueta «%s» de todas las notas?","Remove this search from the sidebar?":"¿Desea eliminar esta búsqueda de la barra lateral?","Export":"Exportar","All notes":"Todas las notas","Synchronise":"Sincronizar","Notebooks":"Libretas","Tags":"Etiquetas","Decrypting items: %d/%d":"Descifrando elementos: %d/%d","Fetching resources: %d/%d":"Obteniendo recursos: %d/%d","Sidebar":"Barra lateral","Focus":"Enfocar","Please select where the sync status should be exported to":"Seleccione a dónde se debería exportar el estado de sincronización","Retry All":"Reintentar Todos","Retry":"Reintentar","Advanced tools":"Herramientas avanzadas","Export debug report":"Exportar Informe de depuración","strong text":"texto en negrita","emphasised text":"texto en cursiva","Insert Hyperlink":"Insertar Hipervínculo","List item":"Listar elemento","Layout":"Diseño","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Esta nota no tiene contenido. Haga clic en «%s» para cambiar al editor y editar la nota.","Cut":"Cortar","Copy":"Copiar","Paste":"Pegar","Checkbox list":"Casillas","Highlight":"Destacar","Strikethrough":"Tachado","Insert":"Insertar","Superscript":"Superindice","Subscript":"Subíndice","Edit":"Editar","Attach file":"Adjuntar archivo","Code Block":"Bloque de Código","Inline Code":"Código Integrado","Insert Date Time":"Introducir fecha","Drop notes or files here":"Suelta notas o archivos aquí","Code View":"Código","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Por favor espere a que todos los adjuntos hayan sido descargados y descifrados. Puede también cambiar a %s para editar la nota.","There was an error downloading this attachment:":"Ha habido un error al descargar este adjunto:","This attachment is not downloaded or not decrypted yet":"Este adjunto todavía no ha sido descargado o descifrado","Open...":"Abrir...","Save as...":"Guardar como...","Reveal file in folder":"Mostrar archivo en carpeta","Copy path to clipboard":"Copiar la ruta al portapapeles","Copy Link Address":"Copiar Enlace","to-do":"tarea","note":"nota","Creating new %s...":"Creando nuevo %s...","Click to add tags...":"Haga clic aquí para agregar etiquetas...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Este editor de Texto Enriquecido tiene ciertas limitaciones y se recomienda estar consciente de estas antes de usarlo.","Read more about it":"Leer más al respecto","Dismiss":"Descartar","The following attachments are being watched for changes:":"Los adjuntos siguientes están siendo vigilados en busca de cambios:","The attachments will no longer be watched when you switch to a different note.":"Los adjuntos ya no serán vigilados cuando cambie a una nota diferente.","In: %s":"En: %s","Select all":"Seleccionar todo","Bold":"Negrita","Italic":"Cursiva","Hyperlink":"Hipervínculo","Code":"Código","Numbered List":"Lista Numerada","BulletLine truncated
|
||||
{"OK":"OK","Cancel":"Cancelar","The app is now going to close. Please relaunch it to complete the process.":"La aplicación se va a cerrar. Por favor, vuelva a iniciarla para completar el proceso.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Escriba el título de una nota o parte de su contenido para abrirla. O escriba # seguido del nombre de una etiqueta, o @ seguido del nombre de una libreta. O escriba : para buscar comandos.","Goto Anything...":"Ir a...","Command palette":"Paleta de comandos","Exporting to \"%s\" as \"%s\" format. Please wait...":"Exportando a «%s» como formato «%s». Por favor espere...","Could not export notes: %s":"No se pudo exportar las notas: %s","Current version is up-to-date.":"La versión actual está actualizada.","%s (pre-release)":"%s (prelanzamiento)","An update is available, do you want to download it now?":"Está disponible una actualización. ¿Quiere descargarla ahora?","Your version: %s":"Su versión: %s","New version: %s":"Nueva versión: %s","Download":"Descargar","The note \"%s\" has been successfully restored to the notebook \"%s\".":"La nota «%s» se ha restaurado exitosamente a la libreta «%s».","This note has no history":"Esta nota no tiene historial","Unsupported link or message: %s":"Enlace o mensaje no soportado: %s","Restore":"Restaurar","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Haga clic en «%s» para restaurar la nota. Será copiada en la libreta «%s». La versión actual de la nota no se reemplazará ni se modificará.","Back":"Retroceder","Remove":"Eliminar","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"¿Borrar libreta «%s»?\n\nTodas las notas y sublibretas de esta libreta serán borradas.","Delete":"Borrar","Remove tag \"%s\" from all notes?":"¿Desea eliminar la etiqueta «%s» de todas las notas?","Remove this search from the sidebar?":"¿Desea eliminar esta búsqueda de la barra lateral?","Export":"Exportar","All notes":"Todas las notas","Synchronise":"Sincronizar","Notebooks":"Libretas","Tags":"Etiquetas","Decrypting items: %d/%d":"Descifrando elementos: %d/%d","Fetching resources: %d/%d":"Obteniendo recursos: %d/%d","Sidebar":"Barra lateral","Focus":"Enfocar","Please select where the sync status should be exported to":"Seleccione a dónde se debería exportar el estado de sincronización","Retry All":"Reintentar Todos","Retry":"Reintentar","strong text":"texto en negrita","emphasised text":"texto en cursiva","Insert Hyperlink":"Insertar Hipervínculo","List item":"Listar elemento","Layout":"Diseño","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Esta nota no tiene contenido. Haga clic en «%s» para cambiar al editor y editar la nota.","Cut":"Cortar","Copy":"Copiar","Paste":"Pegar","Checkbox list":"Casillas","Edit":"Editar","Attach file":"Adjuntar archivo","Code Block":"Bloque de Código","Inline Code":"Código Integrado","Insert Date Time":"Introducir fecha","Drop notes or files here":"Suelta notas o archivos aquí","Code View":"Código","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Por favor espere a que todos los adjuntos hayan sido descargados y descifrados. Puede también cambiar a %s para editar la nota.","There was an error downloading this attachment:":"Ha habido un error al descargar este adjunto:","This attachment is not downloaded or not decrypted yet":"Este adjunto todavía no ha sido descargado o descifrado","Open...":"Abrir...","Save as...":"Guardar como...","Reveal file in folder":"Mostrar archivo en carpeta","Copy path to clipboard":"Copiar la ruta al portapapeles","Copy Link Address":"Copiar Enlace","to-do":"tarea","note":"nota","Creating new %s...":"Creando nuevo %s...","Click to add tags...":"Haga clic aquí para agregar etiquetas...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Este editor de Texto Enriquecido tiene ciertas limitaciones y se recomienda estar consciente de estas antes de usarlo.","Read more about it":"Leer más al respecto","Dismiss":"Descartar","The following attachments are being watched for changes:":"Los adjuntos siguientes están siendo vigilados en busca de cambios:","The attachments will no longer be watched when you switch to a different note.":"Los adjuntos ya no serán vigilados cuando cambie a una nota diferente.","In: %s":"En: %s","Select all":"Seleccionar todo","Bold":"Negrita","Italic":"Cursiva","Hyperlink":"Hipervínculo","Code":"Código","Numbered List":"Lista Numerada","Bulleted List":"Lista con Viñetas","Checkbox":"Casilla","Heading":"Título","Horizontal Rule":"Regla Horizontal","Delete line":"Borrar línea","Undo":"Deshacer","Redo":"RehaceLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Tühista","Current version is up-to-date.":"Praegune versioon on ajakohane.","%s (pre-release)":"%s (väljalaske-eelne)","An update is available, do you want to download it now?":"Saadaval on värskendus, kas soovite selle kohe alla laadida?","Your version: %s":"Teie versioon: %s","New version: %s":"Uus versioon: %s","This note has no history":"Sellel märkel pole ajalugu","Unsupported link or message: %s":"Toetuseta link või sõnum: %s","Restore":"Taasta","Back":"Tagasi","Remove":"Eemalda","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Kas soovite märkmiku \"%s\"?\n\nKustutatakse ka kõik selle märkmiku märkmed ja alammärkmikud.","Delete":"Kustuta","Remove tag \"%s\" from all notes?":"Kas eemaldada silt \"%s\" kõigist märkmetest?","Remove this search from the sidebar?":"Kas soovite selle otsingu külgribalt eemaldada?","Export":"Eksport","All notes":"Kõik märkmed","Synchronise":"Sünkroniseeri","Notebooks":"Sülearvutid","Tags":"Sildid","Decrypting items: %d/%d":"Üksuste dekrüpteerimine: %d/%d","Fetching resources: %d/%d":"Ressursside toomine: %d/%d","Focus":"Fookus","Please select where the sync status should be exported to":"Palun valige, kus sünkroonimise olekut tuleks eksportida","Retry":"Uuesti","Insert Hyperlink":"Lisa hüperlink","Layout":"Paigutus","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Sellel märkel pole sisu. Klõpsake \" %s\" redaktori vahetamiseks ja märkme redigeerimiseks.","Cut":"Lõika","Copy":"Kopeeri","Paste":"Kleebi","Edit":"Muuda","Attach file":"Manusta fail","Insert Date Time":"Lisa kuupäev kellaaeg","There was an error downloading this attachment:":"Selle manuse allalaadimisel ilmnes tõrge:","This attachment is not downloaded or not decrypted yet":"Seda manust ei laadita alla või pole veel dekrüpteeritud","Open...":"Avatud...","Save as...":"Salvesta kui...","Copy path to clipboard":"Kopeeri tee lõikelauale","Copy Link Address":"Kopeeri lingi aadress","to-do":"ülesande nimekiri","note":"paberraha","Creating new %s...":"Uue %s loomine...","In: %s":"Asukoht: %s","Select all":"Vali kõik","Bold":"Paks","Italic":"Kald","Hyperlink":"Hüperlink","Code":"Kood","Numbered List":"Nummerdatud loend","Bulleted List":"Täpp-loend","Checkbox":"Märkekast","Heading":"Pealkiri","Search in current note":"Otsi praeguses märkuses","ID":"ID","Created":"Loodud","Updated":"Uuendatud","Completed":"Lõpetatud","Location":"Asukoht","URL":"URL","Note History":"Märkmete ajalugu","Previous versions of this note":"Selle märkme eelmised versioonid","Note properties":"Märkme atribuudid","Disabled":"Keelatud","Search...":"Otsi...","Import":"Impordi","Quit":"Lõpeta","Website and documentation":"Veebileht ja dokumentatsioon","Close Window":"Sule aken","Options":"Valikud","Save":"Salvesta","View them now":"Vaata neid nüüd","Some items cannot be synchronised.":"Mõnda üksust ei saa sünkroonida.","One or more master keys need a password.":"Üks või mitu Põhivõtit vajavad parooli.","Set the password":"Parooli seadmine","Rename":"Nimeta ümber","Rename notebook:":"Märkmiku ümbernimetamine:","Toggle note list":"Lülita märkuseloend sisse/välja","Toggle sidebar":"Lülita külgriba sisse/välja","Set alarm":"Alarmi seadmine","Set alarm:":"Alarmi seadmine:","PDF File":"PDF-fail","New note":"Uus Märkus","Toggle editor layout":"Lülita redaktori paigutus sisse/välja","Rename tag:":"Nimeta silt ümber:","New notebook":"Uus märkmik","Notebook title:":"Märkmiku tiitel:","Share note...":"Jaga märkust...","New sub-notebook":"Uus alammärkmik","Template file:":"Mallifail:","Add or remove tags:":"Siltide lisamine või eemaldamine:","Submit":"Saada","Token has been copied to the clipboard!":"Token on kopeeritud lõikelauale!","The web clipper service is enabled and set to auto-start.":"Web Clipper service on lubatud ja seadke automaatselt käivituma.","Status: Started on port %d":"Olek: alustatud porti %d","Status: %s":"Staatus: %s","Disable Web Clipper Service":"Keela Web Clipper Service","The web clipper service is not enabled.":"Web clipper service pole lubatud.","Enable Web Clipper Service":"Luba Web Clipper Service","Joplin Web Clipper allows saving web pages and screenshots from your browser to Joplin.":"Joplin Web Clipper võimaldab salvestada veebilehti ja ekraanipilte brauserist Joplini.","In order to use the web clipper, you need to do the following:":"Selleks, et kasutada Web Clipper, peate tegema järgmist:","Step 1: Enable the clipper service":"1. samm: Lubage Clipper service","This service allows the browser extension to communicate with Joplin. When enabling it your firewall may ask you to give permission to Joplin to listen to a particular port.":"See teenus võimaldab brauseri laiendil suhelda Joplini-ga. Kui lubate selle, võib tulemüür paluda teil anda luba Joplini kuulata teatud porti.","Step 2: Install the extension":"2. toiming: installige laiend","DownloLine truncated
|
||||
{"OK":"OK","Cancel":"Tühista","Current version is up-to-date.":"Praegune versioon on ajakohane.","%s (pre-release)":"%s (väljalaske-eelne)","An update is available, do you want to download it now?":"Saadaval on värskendus, kas soovite selle kohe alla laadida?","Your version: %s":"Teie versioon: %s","New version: %s":"Uus versioon: %s","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Märkus \"%s\" on märkmikku \"%s\" edukalt taastatud.","This note has no history":"Sellel märkel pole ajalugu","Unsupported link or message: %s":"Toetuseta link või sõnum: %s","Restore":"Taasta","Back":"Tagasi","Remove":"Eemalda","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Kas soovite märkmiku \"%s\"?\n\nKustutatakse ka kõik selle märkmiku märkmed ja alammärkmikud.","Delete":"Kustuta","Remove tag \"%s\" from all notes?":"Kas eemaldada silt \"%s\" kõigist märkmetest?","Remove this search from the sidebar?":"Kas soovite selle otsingu külgribalt eemaldada?","Export":"Eksport","All notes":"Kõik märkmed","Synchronise":"Sünkroniseeri","Notebooks":"Sülearvutid","Tags":"Sildid","Decrypting items: %d/%d":"Üksuste dekrüpteerimine: %d/%d","Fetching resources: %d/%d":"Ressursside toomine: %d/%d","Focus":"Fookus","Please select where the sync status should be exported to":"Palun valige, kus sünkroonimise olekut tuleks eksportida","Retry":"Uuesti","Insert Hyperlink":"Lisa hüperlink","Layout":"Paigutus","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Sellel märkel pole sisu. Klõpsake \" %s\" redaktori vahetamiseks ja märkme redigeerimiseks.","Cut":"Lõika","Copy":"Kopeeri","Paste":"Kleebi","Edit":"Muuda","Attach file":"Manusta fail","Insert Date Time":"Lisa kuupäev kellaaeg","There was an error downloading this attachment:":"Selle manuse allalaadimisel ilmnes tõrge:","This attachment is not downloaded or not decrypted yet":"Seda manust ei laadita alla või pole veel dekrüpteeritud","Open...":"Avatud...","Save as...":"Salvesta kui...","Copy path to clipboard":"Kopeeri tee lõikelauale","Copy Link Address":"Kopeeri lingi aadress","to-do":"ülesande nimekiri","note":"paberraha","Creating new %s...":"Uue %s loomine...","In: %s":"Asukoht: %s","Select all":"Vali kõik","Bold":"Paks","Italic":"Kald","Hyperlink":"Hüperlink","Code":"Kood","Numbered List":"Nummerdatud loend","Bulleted List":"Täpp-loend","Checkbox":"Märkekast","Heading":"Pealkiri","Search in current note":"Otsi praeguses märkuses","ID":"ID","Created":"Loodud","Updated":"Uuendatud","Completed":"Lõpetatud","Location":"Asukoht","URL":"URL","Note History":"Märkmete ajalugu","Previous versions of this note":"Selle märkme eelmised versioonid","Note properties":"Märkme atribuudid","Disabled":"Keelatud","Search...":"Otsi...","Import":"Impordi","Quit":"Lõpeta","Website and documentation":"Veebileht ja dokumentatsioon","Close Window":"Sule aken","Options":"Valikud","Save":"Salvesta","View them now":"Vaata neid nüüd","Some items cannot be synchronised.":"Mõnda üksust ei saa sünkroonida.","One or more master keys need a password.":"Üks või mitu Põhivõtit vajavad parooli.","Set the password":"Parooli seadmine","Rename":"Nimeta ümber","Rename notebook:":"Märkmiku ümbernimetamine:","Toggle note list":"Lülita märkuseloend sisse/välja","Toggle sidebar":"Lülita külgriba sisse/välja","Set alarm":"Alarmi seadmine","Set alarm:":"Alarmi seadmine:","PDF File":"PDF-fail","New note":"Uus Märkus","Toggle editor layout":"Lülita redaktori paigutus sisse/välja","Rename tag:":"Nimeta silt ümber:","New notebook":"Uus märkmik","Notebook title:":"Märkmiku tiitel:","Share note...":"Jaga märkust...","New sub-notebook":"Uus alammärkmik","Template file:":"Mallifail:","Add or remove tags:":"Siltide lisamine või eemaldamine:","Submit":"Saada","Token has been copied to the clipboard!":"Token on kopeeritud lõikelauale!","The web clipper service is enabled and set to auto-start.":"Web Clipper service on lubatud ja seadke automaatselt käivituma.","Status: Started on port %d":"Olek: alustatud porti %d","Status: %s":"Staatus: %s","Disable Web Clipper Service":"Keela Web Clipper Service","The web clipper service is not enabled.":"Web clipper service pole lubatud.","Enable Web Clipper Service":"Luba Web Clipper Service","Joplin Web Clipper allows saving web pages and screenshots from your browser to Joplin.":"Joplin Web Clipper võimaldab salvestada veebilehti ja ekraanipilte brauserist Joplini.","In order to use the web clipper, you need to do the following:":"Selleks, et kasutada Web Clipper, peate tegema järgmist:","Step 1: Enable the clipper service":"1. samm: Lubage Clipper service","This service allows the browser extension to communicate with Joplin. When enabling it your firewall may ask you to give permission to Joplin to listen to a particular port.":"See teenus võimaldab brauseri laiendil suhelda Joplini-ga. Kui lubate selle, võib tulemLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Utzi","Unsupported link or message: %s":"Esteka edo mezu ez dago onartua: %s","Back":"Atzera","Delete":"Ezabatu","Remove this search from the sidebar?":"Kendu bilaketa hori ohar guztietatik?","Synchronise":"Sinkronizatu","Notebooks":"Koadernoak","Tags":"Etiketak","Layout":"Diseinua","Cut":"Moztu","Copy":"Kopiatu","Paste":"Itsatsi","Edit":"Editatu","Attach file":"Erantsi fitxategia","ID":"ID","Created":"Sortua","Updated":"Eguneratua","Disabled":"Desgaituta","Import":"Inportatu","Quit":"Irten","Website and documentation":"Web orria eta dokumentazioa (en)","Options":"Aukerak","Save":"Gorde","Some items cannot be decrypted.":"Zenbait item ezin dira deszifratu.","View them now":"Ikusi hori orain","Some items cannot be synchronised.":"Zenbait item ezin dira sinkronizatu.","Set the password":"Ezarri pasahitza","Rename":"Berrizendatu","Rename notebook:":"Berrizendatu koadernoa:","New to-do":"Zeregin berria","Set alarm":"Ezarri alarma","Set alarm:":"Ezarri alarma:","New note":"Ohar berria","New notebook":"Koaderno berria","Notebook title:":"Koadernoaren izenburua: ","Add or remove tags:":"Gehitu edo ezabatu etiketak:","Synchronisation Status":"Sinkronizazioaren egoera","About Joplin":"Joplin-i buruz","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"\"%s\" koaderno berria sortuko da eta \"%s\" Fitxategia inportatuko da bertara","Found: %d.":"Aurkitua: %d","Created: %d.":"Sortuta: %d.","Updated: %d.":"Eguneratuta: %d.","Skipped: %d.":"Saltatuta: %d.","Resources: %d.":"Baliabideak: %d.","Tagged: %d.":"Etiketatuta: %d.","The notes have been imported: %s":"Oharrak inportatu dira: %s","Switch between note and to-do type":"Aldatu oharra eta zeregin eren artean.","Authentication was not completed (did not receive an authentication token).":"Autentifikazioa ez da egin osorik (ez du token-ik hartu).","Disabling encryption means *all* your notes and attachments are going to be re-synchronised and sent unencrypted to the sync target. Do you wish to continue?":"Zifratua desgaitzeak esan nahi du zure ohar eta eranskin *guztiak* berriro deszifratuta sinkronizatuko eta bidaliko direla sinkronizazio helburura. Segitu nahi duzu?","Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.":"Zifratua gaitzeak esan nahi du zure ohar eta eranskin *guztiak* zifratuta sinkronizatuko eta bidaliko direla sinkronizazio helburura. Ez galdu pasahitza, bera izango baita datuak deszifratzeko bide *bakarra*! Zifratua baimentzeko, mesedez, aurretik sartu zure pasahitza.","Disable encryption":"Zifratzea desgaitu","Enable encryption":"Zifratua gaitu","Master Keys":"Pasahitz nagusia","Active":"Aktibo","Source":"Iturburua","Password":"Pasahitza","Password OK":"Pasahitza ondo","Status":"Egoera","Encryption is:":"Zifratua da:","Enabled":"Gaituta","OneDrive Login":"Logeatu OneDriven","Clear":"Garbitu","No notes in here. Create one by clicking on \"New note\".":"Hemen ez dago oharrik. Sortu bat \"Ohar berria\" sakatuta.","There is currently no notebook. Create one by clicking on \"New notebook\".":"Momentuz ez dago koadernorik. Sortu bat \"Koaderno berria\" sakatuta.","Search in all the notes":"Bilatu ohar guztietan","Untitled":"Titulu gabekoa","Error opening note in editor: %s":"Errorea editorean oharra zabaltzean: %s","Delete these notes?":"Oharrok ezabatu?","Configuration":"Konfigurazioa","There are currently no notes. Create one by clicking on the (+) button.":"Ez dago oharrik. Sortu bat (+) botoian klik eginaz.","The notebook could not be saved: %s":"Koadernoa ezin gorde daiteke: %s","Edit notebook":"Editatu koadernoa","Login with OneDrive":"Login with OneDrive","Encryption Config":"Zifratze Ezarpenak","Log":"Egunkaria","Export Debug Report":"Esportatu arazketa txostena","Master Key %s":"Pasahitz Nagusia %s","Created: %s":"Sortuta: %s","Password:":"Pasahitza:","Password cannot be empty":"Pasahitza ezin utz daiteke hutsik","Enable":"Gaituta","Encryption is: %s":"Zifratzea da: %s","This note has been modified:":"Ohar hau mugitua izan da:","Save changes":"Gorde aldaketak","Discard changes":"Bertan behera utzi aldaketak","Delete note?":"Oharra ezabatu?","Unsupported image type: %s":"Irudi formatua ez onartua: %s","View on map":"Ikusi mapan","Attach photo":"Argazkia erantsi","Convert to note":"Oharra bihurtu","Convert to todo":"Zeregina bihurtu","Search":"Bilatu","The application has been authorised - you may now close this browser tab.":"Aplikazioak baimena hartu du - Orain fitxa hau zarratu dezakezu.","The application has been successfully authorised.":"Aplikazioak baimena hartu du.","Cannot access %s":"Ezin atzituta %s","Conflicts":"Gatazkak","Notebooks cannot be named \"%s\", which is a reserved title.":"Koadernoak ezin izendatu daitezke \"%s\", izen hori Joplinek gordeta daLine truncated
|
||||
{"OK":"OK","Cancel":"Utzi","Unsupported link or message: %s":"Esteka edo mezu ez dago onartua: %s","Back":"Atzera","Delete":"Ezabatu","Remove this search from the sidebar?":"Kendu bilaketa hori ohar guztietatik?","Synchronise":"Sinkronizatu","Notebooks":"Koadernoak","Tags":"Etiketak","Layout":"Diseinua","Cut":"Moztu","Copy":"Kopiatu","Paste":"Itsatsi","Edit":"Editatu","Attach file":"Erantsi fitxategia","ID":"ID","Created":"Sortua","Updated":"Eguneratua","Disabled":"Desgaituta","Import":"Inportatu","Quit":"Irten","Website and documentation":"Web orria eta dokumentazioa (en)","Options":"Aukerak","Save":"Gorde","Some items cannot be decrypted.":"Zenbait item ezin dira deszifratu.","View them now":"Ikusi hori orain","Some items cannot be synchronised.":"Zenbait item ezin dira sinkronizatu.","Set the password":"Ezarri pasahitza","Rename":"Berrizendatu","Rename notebook:":"Berrizendatu koadernoa:","New to-do":"Zeregin berria","Set alarm":"Ezarri alarma","Set alarm:":"Ezarri alarma:","New note":"Ohar berria","New notebook":"Koaderno berria","Notebook title:":"Koadernoaren izenburua: ","Add or remove tags:":"Gehitu edo ezabatu etiketak:","Synchronisation Status":"Sinkronizazioaren egoera","About Joplin":"Joplin-i buruz","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"\"%s\" koaderno berria sortuko da eta \"%s\" Fitxategia inportatuko da bertara","Found: %d.":"Aurkitua: %d","Created: %d.":"Sortuta: %d.","Updated: %d.":"Eguneratuta: %d.","Skipped: %d.":"Saltatuta: %d.","Resources: %d.":"Baliabideak: %d.","Tagged: %d.":"Etiketatuta: %d.","The notes have been imported: %s":"Oharrak inportatu dira: %s","Switch between note and to-do type":"Aldatu oharra eta zeregin eren artean.","Authentication was not completed (did not receive an authentication token).":"Autentifikazioa ez da egin osorik (ez du token-ik hartu).","Disabling encryption means *all* your notes and attachments are going to be re-synchronised and sent unencrypted to the sync target. Do you wish to continue?":"Zifratua desgaitzeak esan nahi du zure ohar eta eranskin *guztiak* berriro deszifratuta sinkronizatuko eta bidaliko direla sinkronizazio helburura. Segitu nahi duzu?","Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.":"Zifratua gaitzeak esan nahi du zure ohar eta eranskin *guztiak* zifratuta sinkronizatuko eta bidaliko direla sinkronizazio helburura. Ez galdu pasahitza, bera izango baita datuak deszifratzeko bide *bakarra*! Zifratua baimentzeko, mesedez, aurretik sartu zure pasahitza.","Disable encryption":"Zifratzea desgaitu","Enable encryption":"Zifratua gaitu","Master Keys":"Pasahitz nagusia","Active":"Aktibo","Source":"Iturburua","Password":"Pasahitza","Password OK":"Pasahitza ondo","Status":"Egoera","Encryption is:":"Zifratua da:","Enabled":"Gaituta","OneDrive Login":"Logeatu OneDriven","Clear":"Garbitu","No notes in here. Create one by clicking on \"New note\".":"Hemen ez dago oharrik. Sortu bat \"Ohar berria\" sakatuta.","There is currently no notebook. Create one by clicking on \"New notebook\".":"Momentuz ez dago koadernorik. Sortu bat \"Koaderno berria\" sakatuta.","Search in all the notes":"Bilatu ohar guztietan","Untitled":"Titulu gabekoa","Error opening note in editor: %s":"Errorea editorean oharra zabaltzean: %s","Delete these notes?":"Oharrok ezabatu?","Configuration":"Konfigurazioa","There are currently no notes. Create one by clicking on the (+) button.":"Ez dago oharrik. Sortu bat (+) botoian klik eginaz.","The notebook could not be saved: %s":"Koadernoa ezin gorde daiteke: %s","Edit notebook":"Editatu koadernoa","Login with OneDrive":"Login with OneDrive","Master Key %s":"Pasahitz Nagusia %s","Created: %s":"Sortuta: %s","Password:":"Pasahitza:","Password cannot be empty":"Pasahitza ezin utz daiteke hutsik","Enable":"Gaituta","Encryption Config":"Zifratze Ezarpenak","Encryption is: %s":"Zifratzea da: %s","Log":"Egunkaria","Export Debug Report":"Esportatu arazketa txostena","This note has been modified:":"Ohar hau mugitua izan da:","Save changes":"Gorde aldaketak","Discard changes":"Bertan behera utzi aldaketak","Delete note?":"Oharra ezabatu?","Unsupported image type: %s":"Irudi formatua ez onartua: %s","View on map":"Ikusi mapan","Attach photo":"Argazkia erantsi","Convert to note":"Oharra bihurtu","Convert to todo":"Zeregina bihurtu","Search":"Bilatu","The application has been authorised - you may now close this browser tab.":"Aplikazioak baimena hartu du - Orain fitxa hau zarratu dezakezu.","The application has been successfully authorised.":"Aplikazioak baimena hartu du.","Cannot access %s":"Ezin atzituta %s","Conflicts":"Gatazkak","Notebooks cannot be named \"%s\", which is a reserved title.":"Koadernoak ezin izendatu daitezke \"%s\", izen hori Joplinek gordeta daLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"باشه","Cancel":"لغو","The app is now going to close. Please relaunch it to complete the process.":"برنامه اکنون در حال بسته شدن است. لطفاً برای تکمیل مراحل آن را مجدداً راه اندازی کنید.","Goto Anything...":"رفنت به هر چیزی...","Exporting to \"%s\" as \"%s\" format. Please wait...":"در حال استخراج به «%s» با فرمت «%s». لطفا صبر کنید...","Could not export notes: %s":"یادداشتها استخراج نشدند: %s","Current version is up-to-date.":"ورژن فعلی بهروز است.","An update is available, do you want to download it now?":"یک بروزرسانی موجود است، آیا میخواهید هم اکنون بارگیریاش کنید؟","Your version: %s":"ورژن شما: %s","New version: %s":"ورژن جدید: %s","This note has no history":"این یادداشت هیچ تاریخچه ای ندارد","Unsupported link or message: %s":"پیوند یا پیام پشتیبانی نشده: %s","Restore":"بازگرداندن","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"برای بازیابی یادداشت بر روی «%s» کلیک کنید. یادداشت در دفترچهای به نام «%s» کپی میشود. این نسخه از یادداشت جایگزین یا تغییر داده نمیشود.","Back":"بازگشت","Remove":"برداشتن","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"دفترچه «%s» حذف شود؟\n\nتمامی یادداشتها و زیر-دفترچههای درون این دفترچه نیز حذف میشوند.","Delete":"حذف","Remove tag \"%s\" from all notes?":"حذف برچسب «%s» از همهی یادداشتها؟","Remove this search from the sidebar?":"این جستجو از نوار کناری حذف شود؟","Export":"استخراج","All notes":"همه یادداشتها","Synchronise":"همگام سازی","Notebooks":"دفترچه ها","Tags":"برچسبها","Decrypting items: %d/%d":"در حال رمزگشایی موارد: %d/%d","Fetching resources: %d/%d":"در حال دریافت منابع: %d/%d","Sidebar":"نوار کناری","Focus":"تمرکز","Please select where the sync status should be exported to":"لطفا محلی که وضعیت همگامسازی باید استخراج شود را مشخص کنید","Retry All":"تلاش مجدد همه","Retry":"تلاش مجدد","emphasised text":"متن تأکید شده","Insert Hyperlink":"درج پیوند برجسته","List item":"لیست مورد","Layout":"قالب","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"این یادداشت هیچ محتوایی ندارد. برای تغییر وضعیت ویرایشگر و ویرایش یادداشت ، روی \"%s\" کلیک کنید.","Cut":"بریدن","Copy":"کپی","Paste":"چسباندن","Checkbox list":"لیست چکباکس","Edit":"ویرایش","Attach file":"پیوست فایل","Code Block":"بلوک کد","Inline Code":"کد درون خطی","Insert Date Time":"درج تاریخ و ساعت","Drop notes or files here":"یادداشتها یا فایلها را اینجا رها کنید","Code View":"نمای کد","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"لطفا صبر کنید تا همه پیوست ها بارگیری و رمزگشایی شوند. شما همچنین میتوانید به %s برای ویرایش یادداشت بروید.","There was an error downloading this attachment:":"یک خطا در بارگیری این پیوست بود:","This attachment is not downloaded or not decrypted yet":"این پیوست هنوز بارگیری یا رمزگشایی نشده","Open...":"باز کردن...","Save as...":"ذخیره به عنوان...","Reveal file in folder":"نمایش فایل در پوشه","Copy path to clipboard":"کپی کردن مسیر در کلیپ بورد","Copy Link Address":"کپی کردن آدرس پیوند","to-do":"فهرست کار","note":"یادداشت","Creating new %s...":"ایجاد یک %s جدید...","In: %s":"در: %s","Select all":"انتخاب همه","Bold":"پررنگ","Italic":"مورب","Hyperlink":"پیوند برجسته","Code":"کد","Numbered List":"لیست شماره گذاری شده","Bulleted List":"لیست گلوله ای بدون ترتیب","Checkbox":"چکباکس","Heading":"عنوان","Horizontal Rule":"خط افقی","Note title":"عنوان یادداشت","Search in current note":"جستجو در همین یادداشت","Note body":"بدنه ی یادداشت","ID":"شناسه","Created":"ایجاد شده","Updated":"بهروز شده","Completed":"کامل شده","LocatLine truncated
|
||||
{"OK":"باشه","Cancel":"لغو","The app is now going to close. Please relaunch it to complete the process.":"برنامه اکنون در حال بسته شدن است. لطفاً برای تکمیل مراحل آن را مجدداً راه اندازی کنید.","Goto Anything...":"رفنت به هر چیزی...","Exporting to \"%s\" as \"%s\" format. Please wait...":"در حال استخراج به «%s» با فرمت «%s». لطفا صبر کنید...","Could not export notes: %s":"یادداشتها استخراج نشدند: %s","Current version is up-to-date.":"ورژن فعلی بهروز است.","An update is available, do you want to download it now?":"یک بروزرسانی موجود است، آیا میخواهید هم اکنون بارگیریاش کنید؟","Your version: %s":"ورژن شما: %s","New version: %s":"ورژن جدید: %s","The note \"%s\" has been successfully restored to the notebook \"%s\".":"یادداشت «%s» با موفقیت به دفترچه «%s» بازگردانده شد.","This note has no history":"این یادداشت هیچ تاریخچه ای ندارد","Unsupported link or message: %s":"پیوند یا پیام پشتیبانی نشده: %s","Restore":"بازگرداندن","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"برای بازیابی یادداشت بر روی «%s» کلیک کنید. یادداشت در دفترچهای به نام «%s» کپی میشود. این نسخه از یادداشت جایگزین یا تغییر داده نمیشود.","Back":"بازگشت","Remove":"برداشتن","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"دفترچه «%s» حذف شود؟\n\nتمامی یادداشتها و زیر-دفترچههای درون این دفترچه نیز حذف میشوند.","Delete":"حذف","Remove tag \"%s\" from all notes?":"حذف برچسب «%s» از همهی یادداشتها؟","Remove this search from the sidebar?":"این جستجو از نوار کناری حذف شود؟","Export":"استخراج","All notes":"همه یادداشتها","Synchronise":"همگام سازی","Notebooks":"دفترچه ها","Tags":"برچسبها","Decrypting items: %d/%d":"در حال رمزگشایی موارد: %d/%d","Fetching resources: %d/%d":"در حال دریافت منابع: %d/%d","Sidebar":"نوار کناری","Focus":"تمرکز","Please select where the sync status should be exported to":"لطفا محلی که وضعیت همگامسازی باید استخراج شود را مشخص کنید","Retry All":"تلاش مجدد همه","Retry":"تلاش مجدد","emphasised text":"متن تأکید شده","Insert Hyperlink":"درج پیوند برجسته","List item":"لیست مورد","Layout":"قالب","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"این یادداشت هیچ محتوایی ندارد. برای تغییر وضعیت ویرایشگر و ویرایش یادداشت ، روی \"%s\" کلیک کنید.","Cut":"بریدن","Copy":"کپی","Paste":"چسباندن","Checkbox list":"لیست چکباکس","Edit":"ویرایش","Attach file":"پیوست فایل","Code Block":"بلوک کد","Inline Code":"کد درون خطی","Insert Date Time":"درج تاریخ و ساعت","Drop notes or files here":"یادداشتها یا فایلها را اینجا رها کنید","Code View":"نمای کد","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"لطفا صبر کنید تا همه پیوست ها بارگیری و رمزگشایی شوند. شما همچنین میتوانید به %s برای ویرایش یادداشت بروید.","There was an error downloading this attachment:":"یک خطا در بارگیری این پیوست بود:","This attachment is not downloaded or not decrypted yet":"این پیوست هنوز بارگیری یا رمزگشایی نشده","Open...":"باز کردن...","Save as...":"ذخیره به عنوان...","Reveal file in folder":"نمایش فایل در پوشه","Copy path to clipboard":"کپی کردن مسیر در کلیپ بورد","Copy Link Address":"کپی کردن آدرس پیوند","to-do":"فهرست کار","note":"یادداشت","Creating new %s...":"ایجاد یک %s جدید...","In: %s":"در: %s","Select all":"انتخاب همه","Bold":"پررنگ","Italic":"مورب","Hyperlink":"پیوند برجسته","Code":"کد","Numbered List":"لیست شماره گذاری شده","Bulleted List":"لیست گلوله ای بدون ترتیب","Checkbox":"چکباکس","Heading":"عنوان","Horizontal Rule":"خط افقی","Note title":"عنوان یادداشت","Search in current note":"جستجو در همین یادLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Peruuta","The app is now going to close. Please relaunch it to complete the process.":"Sovellus suljetaan nyt. Käynnistä se uudelleen prosessin loppuun saamiseksi.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Kirjoita muistiinpanon otsikko, jos haluat siirtyä siihen. Voit myös kirjoittaa # ja sen jälkeen tunnisteen nimen tai @ ja sen jälkeen muistikirjan nimen. Voit myös etsiä komentoja kirjoittamalla : .","Goto Anything...":"Siirry mihin tahansa...","Command palette":"Komentovalikoima","Exporting to \"%s\" as \"%s\" format. Please wait...":"Viedään tiedostoon \"%s\" muodossa \"%s\". Odota...","Could not export notes: %s":"Muistiinpanoja ei voitu viedä: %s","Current version is up-to-date.":"Nykyinen versio on ajan tasalla.","%s (pre-release)":"%s (ennakkojulkaisu)","An update is available, do you want to download it now?":"Päivitys on saatavilla. Haluatko ladata sen nyt?","Your version: %s":"Sinun versiosi: %s","New version: %s":"Uusi versio: %s","Download":"Lataa","This note has no history":"Tällä muistiinpanolla ei ole historiaa","Unsupported link or message: %s":"Linkkiä tai viestiä ei tueta: %s","Restore":"Palauttaa","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Napsauta \"%s\" palauttaaksesi muistiinpanon. Se kopioidaan muistikirjaan nimeltä \"%s\". Huomautuksen nykyistä versiota ei korvata tai muuteta.","Back":"Takaisin","Remove":"Poista","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Poista muistikirja \"%s\"?\n\nMyös kaikki tämän muistikirjan muistiinpanot ja alimuistikirjat poistetaan.","Delete":"Poista","Remove tag \"%s\" from all notes?":"Poistetaanko tunniste \"%s\" kaikista muistiinpanoista?","Remove this search from the sidebar?":"Poistetaanko tämä haku sivupalkista?","Export":"Vie","All notes":"Kaikki muistiinpanot","Synchronise":"Synkronoi","Notebooks":"Muistikirjat","Tags":"Tunnisteet","Decrypting items: %d/%d":"Kohteiden salauksen purkaminen: %d/%d","Fetching resources: %d/%d":"Haetaan resursseja: %d/%d","Sidebar":"Sivupalkki","Focus":"Keskittää","Please select where the sync status should be exported to":"Valitse, mihin synkronoinnin tila viedään","Retry All":"Yritä uudelleen kaikkia","Retry":"Yritä uudelleen","strong text":"vahva teksti","emphasised text":"korostettu teksti","Insert Hyperlink":"Lisää hyperlinkki","List item":"Luettelon kohde","Layout":"Ulkoasu","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Tällä muistiinpanolla ei ole sisältöä. Napsauta \"%s\" vaihtaaksesi editoria ja muokataksesi muistiinpanoa.","Cut":"Leikkaa","Copy":"Kopioi","Paste":"Liitä","Checkbox list":"Valintaruutujen luettelo","Edit":"Muokkaa","Attach file":"Liitä tiedosto","Code Block":"Koodilohko","Inline Code":"Inline-koodi","Insert Date Time":"Lisää Päivämäärä Aika","Drop notes or files here":"Pudota muistiinpanot tai tiedostot tähän","Code View":"Koodinäkymä","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Odota, että kaikki liitteet ladataan ja puretaan. Voit myös vaihtaa kohtaan %s muokkaamaan muistiinpanoa.","There was an error downloading this attachment:":"Tämän liitteen lataamisessa tapahtui virhe:","This attachment is not downloaded or not decrypted yet":"Tätä liitettä ei ole vielä ladattu tai sitä ei ole vielä purettu","Open...":"Avaa...","Save as...":"Tallenna nimellä...","Reveal file in folder":"Osoita kansion tiedosto","Copy path to clipboard":"Kopioi polku leikepöydälle","Copy Link Address":"Kopioi linkin osoite","to-do":"tehtävä","note":"merkintä","Creating new %s...":"Luodaan uusi %s...","Click to add tags...":"Klikkaa lisätäksesi tunnisteita...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Tällä Rich Text -editorilla on useita rajoituksia, on suositeltavaa olla tietoinen niistä ennen sen käyttöä.","Read more about it":"Lue lisää siitä","Dismiss":"Hylkää","The following attachments are being watched for changes:":"Seuraavia liitteitä tarkkaillaan muutosten vuoksi:","The attachments will no longer be watched when you switch to a different note.":"Liitteitä ei enää katsota, kun vaihdat toiseen muistiinpanoon.","In: %s":"Sisään: %s","Select all":"Valitse kaikki","Bold":"Lihavoitu","Italic":"Kursiivi","Hyperlink":"Hyperlinkki","Code":"Koodi","Numbered List":"Numeroitu luettelo","Bulleted List":"Luettelomerkitty luettelo","Checkbox":"Valintaruutu","Heading":"Otsikko","Horizontal Rule":"Vaakaviiva","Delete line":"Poista rivi","Undo":"Kumoa","Redo":"Tee uudelleen","Indent less":"Sisennä vähemmän","Indent more":"Sisennä lisää","Toggle comment":"Vaihda komLine truncated
|
||||
{"OK":"OK","Cancel":"Peruuta","The app is now going to close. Please relaunch it to complete the process.":"Sovellus suljetaan nyt. Käynnistä se uudelleen prosessin loppuun saamiseksi.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Kirjoita muistiinpanon otsikko, jos haluat siirtyä siihen. Voit myös kirjoittaa # ja sen jälkeen tunnisteen nimen tai @ ja sen jälkeen muistikirjan nimen. Voit myös etsiä komentoja kirjoittamalla : .","Goto Anything...":"Siirry mihin tahansa...","Command palette":"Komentovalikoima","Exporting to \"%s\" as \"%s\" format. Please wait...":"Viedään tiedostoon \"%s\" muodossa \"%s\". Odota...","Could not export notes: %s":"Muistiinpanoja ei voitu viedä: %s","Current version is up-to-date.":"Nykyinen versio on ajan tasalla.","%s (pre-release)":"%s (ennakkojulkaisu)","An update is available, do you want to download it now?":"Päivitys on saatavilla. Haluatko ladata sen nyt?","Your version: %s":"Sinun versiosi: %s","New version: %s":"Uusi versio: %s","Download":"Lataa","The note \"%s\" has been successfully restored to the notebook \"%s\".":"Muistiinpano \"%s\" on palautettu muistikirjaan \"%s\".","This note has no history":"Tällä muistiinpanolla ei ole historiaa","Unsupported link or message: %s":"Linkkiä tai viestiä ei tueta: %s","Restore":"Palauttaa","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Napsauta \"%s\" palauttaaksesi muistiinpanon. Se kopioidaan muistikirjaan nimeltä \"%s\". Huomautuksen nykyistä versiota ei korvata tai muuteta.","Back":"Takaisin","Remove":"Poista","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Poista muistikirja \"%s\"?\n\nMyös kaikki tämän muistikirjan muistiinpanot ja alimuistikirjat poistetaan.","Delete":"Poista","Remove tag \"%s\" from all notes?":"Poistetaanko tunniste \"%s\" kaikista muistiinpanoista?","Remove this search from the sidebar?":"Poistetaanko tämä haku sivupalkista?","Export":"Vie","All notes":"Kaikki muistiinpanot","Synchronise":"Synkronoi","Notebooks":"Muistikirjat","Tags":"Tunnisteet","Decrypting items: %d/%d":"Kohteiden salauksen purkaminen: %d/%d","Fetching resources: %d/%d":"Haetaan resursseja: %d/%d","Sidebar":"Sivupalkki","Focus":"Keskittää","Please select where the sync status should be exported to":"Valitse, mihin synkronoinnin tila viedään","Retry All":"Yritä uudelleen kaikkia","Retry":"Yritä uudelleen","strong text":"vahva teksti","emphasised text":"korostettu teksti","Insert Hyperlink":"Lisää hyperlinkki","List item":"Luettelon kohde","Layout":"Ulkoasu","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Tällä muistiinpanolla ei ole sisältöä. Napsauta \"%s\" vaihtaaksesi editoria ja muokataksesi muistiinpanoa.","Cut":"Leikkaa","Copy":"Kopioi","Paste":"Liitä","Checkbox list":"Valintaruutujen luettelo","Edit":"Muokkaa","Attach file":"Liitä tiedosto","Code Block":"Koodilohko","Inline Code":"Inline-koodi","Insert Date Time":"Lisää Päivämäärä Aika","Drop notes or files here":"Pudota muistiinpanot tai tiedostot tähän","Code View":"Koodinäkymä","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Odota, että kaikki liitteet ladataan ja puretaan. Voit myös vaihtaa kohtaan %s muokkaamaan muistiinpanoa.","There was an error downloading this attachment:":"Tämän liitteen lataamisessa tapahtui virhe:","This attachment is not downloaded or not decrypted yet":"Tätä liitettä ei ole vielä ladattu tai sitä ei ole vielä purettu","Open...":"Avaa...","Save as...":"Tallenna nimellä...","Reveal file in folder":"Osoita kansion tiedosto","Copy path to clipboard":"Kopioi polku leikepöydälle","Copy Link Address":"Kopioi linkin osoite","to-do":"tehtävä","note":"merkintä","Creating new %s...":"Luodaan uusi %s...","Click to add tags...":"Klikkaa lisätäksesi tunnisteita...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Tällä Rich Text -editorilla on useita rajoituksia, on suositeltavaa olla tietoinen niistä ennen sen käyttöä.","Read more about it":"Lue lisää siitä","Dismiss":"Hylkää","The following attachments are being watched for changes:":"Seuraavia liitteitä tarkkaillaan muutosten vuoksi:","The attachments will no longer be watched when you switch to a different note.":"Liitteitä ei enää katsota, kun vaihdat toiseen muistiinpanoon.","In: %s":"Sisään: %s","Select all":"Valitse kaikki","Bold":"Lihavoitu","Italic":"Kursiivi","Hyperlink":"Hyperlinkki","Code":"Koodi","Numbered List":"Numeroitu luettelo","Bulleted List":"Luettelomerkitty luettelo","Checkbox":"Valintaruutu","Heading":"Otsikko","Horizontal Rule":"Vaakaviiva","Delete line":"Poista rivi","UndLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"OK":"OK","Cancel":"Annuler","The app is now going to close. Please relaunch it to complete the process.":"L'application va maintenant se fermer. Veuillez la relancer pour terminer l'opération.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Entrez le titre d’une note, ou entrez # suivi du nom d’une étiquette, ou @ suivi du nom d’un carnet. Ou entrez : pour chercher une commande.","Goto Anything...":"Navigation rapide…","Command palette":"Palette de commandes","Exporting to \"%s\" as \"%s\" format. Please wait...":"Exportation en cours vers \"%s\" au format \"%s\". Veuillez patienter...","Could not export notes: %s":"Impossible d'exporter les notes : %s","Current version is up-to-date.":"La version actuelle est à jour.","%s (pre-release)":"%s (pré-release)","An update is available, do you want to download it now?":"Une mise à jour est disponible, souhaitez vous la télécharger maintenant ?","Your version: %s":"Votre version : %s","New version: %s":"Nouvelle version : %s","Download":"Télécharger","Skip this version":"Ignorer cette versiojn","Full changelog":"Changements complets","This note has no history":"Cette note n'a pas d'historique","Unsupported link or message: %s":"Lien ou message non géré : %s","Restore":"Restaurer","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Cliquez sur \"%s\" pour restaurer cette note. Elle sera copiée dans le carnet \"%s\". La version actuelle de la note ne sera pas replacée ou modifiée.","Back":"Retour","Remove":"Supprimer","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Effacer le carnet \"%s\" ?\n\nToutes les notes et sous-carnets dans ce carnet seront également effacés.","Delete":"Supprimer","Remove tag \"%s\" from all notes?":"Enlever l’étiquette \"%s\" de toutes les notes ?","Remove this search from the sidebar?":"Enlever cette recherche de la barre latérale ?","Export":"Exporter","All notes":"Toutes les notes","Synchronise":"Synchroniser","Notebooks":"Carnets","Tags":"Étiquettes","Decrypting items: %d/%d":"Déchiffrement des objets : %d/%d","Fetching resources: %d/%d":"Tél. ressources : %d/%d","Sidebar":"Barre latérale","Focus":"Naviguer","Please select where the sync status should be exported to":"Veuillez sélectionner un répertoire ou exporter l'état de la synchronisation","Retry All":"Tout réessayer","Retry":"Réessayer","Advanced tools":"Outils avancés","Export debug report":"Exporter rapport de débogage","strong text":"texte en gras","emphasised text":"texte en italique","Insert Hyperlink":"Insérer lien","List item":"Élément de liste","Layout":"Disposition","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Cette note n'a pas de contenu. Cliquer sur \"%s\" pour basculer vers l'éditeur et éditer cette note.","Cut":"Couper","Copy":"Copier","Paste":"Coller","Checkbox list":"Liste de cases à cocher","Highlight":"Surligner","Strikethrough":"Barrer","Insert":"Insérer","Superscript":"Exposant","Subscript":"Indice","Edit":"Édition","Attach file":"Attacher un fichier","Code Block":"Bloc de code","Inline Code":"Ligne de code","Insert Date Time":"Insérer la date et l'heure","Drop notes or files here":"Déposez des notes ou fichiers ici","Code View":"Code","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Veuillez patienter jusqu'à ce que tous les fichiers joints soient téléchargés et déchiffrés. Vous pouvez également éditer la note maintenant en passant au mode %s.","There was an error downloading this attachment:":"Il y a eu une erreur lors du téléchargement de ce fichier :","This attachment is not downloaded or not decrypted yet":"Cet fichier n'est pas téléchargé ou pas encore déchiffré","Open...":"Ouvrir...","Save as...":"Enregistrer sous...","Reveal file in folder":"Révéler fichier dans dossier","Copy path to clipboard":"Copier le chemin","Copy Link Address":"Copier l'adresse du lien","to-do":"tâche","note":"note","Creating new %s...":"Création de %s...","Click to add tags...":"Cliquer pour ajouter des étiquettes...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Cet éditeur de texte enrichi a certaines limitations, et il est recommandé de les connaître avant de l'utiliser.","Read more about it":"En savoir plus","Dismiss":"Fermer","The following attachments are being watched for changes:":"Les changements sur les éléments suivants sont monitorés :","The attachments will no longer be watched when you switch to a different note.":"Les pièces jointes ne seront plus monitorées lorsque vous changerez de note.","In: %s":"Dans : %s","Select all":"Sélectionner tout","Bold":"Gras","Line truncated
|
||||
{"OK":"OK","Cancel":"Annuler","The app is now going to close. Please relaunch it to complete the process.":"L'application va maintenant se fermer. Veuillez la relancer pour terminer l'opération.","Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.":"Entrez le titre d’une note, ou entrez # suivi du nom d’une étiquette, ou @ suivi du nom d’un carnet. Ou entrez : pour chercher une commande.","Goto Anything...":"Navigation rapide…","Command palette":"Palette de commandes","Exporting to \"%s\" as \"%s\" format. Please wait...":"Exportation en cours vers \"%s\" au format \"%s\". Veuillez patienter...","Could not export notes: %s":"Impossible d'exporter les notes : %s","Current version is up-to-date.":"La version actuelle est à jour.","%s (pre-release)":"%s (pré-release)","An update is available, do you want to download it now?":"Une mise à jour est disponible, souhaitez vous la télécharger maintenant ?","Your version: %s":"Votre version : %s","New version: %s":"Nouvelle version : %s","Download":"Télécharger","Skip this version":"Ignorer cette versiojn","Full changelog":"Changements complets","The note \"%s\" has been successfully restored to the notebook \"%s\".":"La note \"%s\" a été restaurée dans le carnet \"%s\".","This note has no history":"Cette note n'a pas d'historique","Unsupported link or message: %s":"Lien ou message non géré : %s","Restore":"Restaurer","Click \"%s\" to restore the note. It will be copied in the notebook named \"%s\". The current version of the note will not be replaced or modified.":"Cliquez sur \"%s\" pour restaurer cette note. Elle sera copiée dans le carnet \"%s\". La version actuelle de la note ne sera pas replacée ou modifiée.","Back":"Retour","Remove":"Supprimer","Delete notebook \"%s\"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.":"Effacer le carnet \"%s\" ?\n\nToutes les notes et sous-carnets dans ce carnet seront également effacés.","Delete":"Supprimer","Remove tag \"%s\" from all notes?":"Enlever l’étiquette \"%s\" de toutes les notes ?","Remove this search from the sidebar?":"Enlever cette recherche de la barre latérale ?","Export":"Exporter","All notes":"Toutes les notes","Synchronise":"Synchroniser","Notebooks":"Carnets","Tags":"Étiquettes","Decrypting items: %d/%d":"Déchiffrement des objets : %d/%d","Fetching resources: %d/%d":"Tél. ressources : %d/%d","Sidebar":"Barre latérale","Focus":"Naviguer","Please select where the sync status should be exported to":"Veuillez sélectionner un répertoire ou exporter l'état de la synchronisation","Retry All":"Tout réessayer","Retry":"Réessayer","Advanced tools":"Outils avancés","Export debug report":"Exporter rapport de débogage","strong text":"texte en gras","emphasised text":"texte en italique","Insert Hyperlink":"Insérer lien","List item":"Élément de liste","Layout":"Disposition","This note has no content. Click on \"%s\" to toggle the editor and edit the note.":"Cette note n'a pas de contenu. Cliquer sur \"%s\" pour basculer vers l'éditeur et éditer cette note.","Cut":"Couper","Copy":"Copier","Paste":"Coller","Checkbox list":"Liste de cases à cocher","Highlight":"Surligner","Strikethrough":"Barrer","Insert":"Insérer","Superscript":"Exposant","Subscript":"Indice","Edit":"Édition","Attach file":"Attacher un fichier","Code Block":"Bloc de code","Inline Code":"Ligne de code","Insert Date Time":"Insérer la date et l'heure","Drop notes or files here":"Déposez des notes ou fichiers ici","Code View":"Code","Please wait for all attachments to be downloaded and decrypted. You may also switch to %s to edit the note.":"Veuillez patienter jusqu'à ce que tous les fichiers joints soient téléchargés et déchiffrés. Vous pouvez également éditer la note maintenant en passant au mode %s.","There was an error downloading this attachment:":"Il y a eu une erreur lors du téléchargement de ce fichier :","This attachment is not downloaded or not decrypted yet":"Cet fichier n'est pas téléchargé ou pas encore déchiffré","Open...":"Ouvrir...","Save as...":"Enregistrer sous...","Reveal file in folder":"Révéler fichier dans dossier","Copy path to clipboard":"Copier le chemin","Copy Link Address":"Copier l'adresse du lien","to-do":"tâche","note":"note","Creating new %s...":"Création de %s...","Click to add tags...":"Cliquer pour ajouter des étiquettes...","This Rich Text editor has a number of limitations and it is recommended to be aware of them before using it.":"Cet éditeur de texte enrichi a certaines limitations, et il est recommandé de les connaître avant de l'utiliser.","Read more about it":"En savoir plus","Dismiss":"Fermer","The following attachments are being watched for changes:":"Les changements sur les éléments suivants sont monitorés :","The attachments will no longer be watched when you switch to a different note.":"Les pièces jointeLine truncated
|
||||
Loaded 100 of 250 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user