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

Compare commits

...

95 Commits

Author SHA1 Message Date
Laurent Cozic
5710e3fad0 CLI v1.0.122 2019-02-10 16:34:41 +00:00
Laurent Cozic
a03aa62d58 Desktop: Moved buttons up on Config screen for consistency with other screens 2019-02-10 16:29:06 +00:00
Laurent Cozic
2203a39917 Desktop: Disable userstyle.css when printing or exporting to PDF 2019-02-10 16:11:41 +00:00
Laurent Cozic
bc58668483 Desktop: Fixes #1200: Note list was hidden when minimizing and
maximizing window
2019-02-10 15:59:28 +00:00
Ladislav Benc
0b4650f355 Suggesting some language improvements for the Welcome page (#1199)
I'm not sure about the "Joplin has three main columns" part. While it would be more correct to put definite articles
2019-02-10 15:44:43 +00:00
Laurent Cozic
aecdec48ad Electron release v1.0.126 2019-02-09 19:32:04 +00:00
Laurent Cozic
e49198a0d4 oops 2019-02-09 19:31:07 +00:00
Laurent Cozic
6aa4553dd3 Updated translations 2019-02-09 19:28:19 +00:00
Laurent Cozic
860e8a8f5a Desktop: Added a few more shortcuts for macOS and other platforms 2019-02-09 19:13:23 +00:00
Laurent Cozic
434037d793 Done Welcome integration on mobile and CLI 2019-02-09 19:04:34 +00:00
Laurent Cozic
214eae27da CLI: Fixed performance issue which was causing CLI to wait up to 10 seconds when closing the app 2019-02-09 19:04:00 +00:00
Laurent Cozic
0567188fa8 Desktop: Select Welcome notebook the first time it is created 2019-02-08 23:38:29 +00:00
Laurent Cozic
4326902683 Desktop: Fixes #1196: Moved webview to separate component to more precisely handle lifecycle events and precent uncessary reloading 2019-02-08 23:07:01 +00:00
Laurent Cozic
da3589149d Desktop: Fixed restored scroll position when only viewer is visible 2019-02-08 08:28:27 +00:00
Laurent Cozic
69b4b4d1f4 Deskop: Integrated Welcome notes to desktop 2019-02-07 23:27:50 +00:00
Laurent Cozic
dd4b46a88b All: Finished Welcome notebook 2019-02-07 23:17:58 +00:00
Laurent Cozic
6f2253b2f4 Updated Chinese translation (Thanks HongSen) 2019-02-07 22:25:50 +00:00
Laurent Cozic
4c00d9512e Desktop: Resolves #1041: Go back to previous note after clicking link 2019-02-07 18:17:09 +00:00
Laurent Cozic
6f511cb1e6 All: Tweaked blockquote CSS to make it fit more with styling update 2019-02-07 08:23:44 +00:00
Caleb John
029e84f538 Add new styling to tables and blockquote (#1185)
* Add new styling to tables and blockquote

* Update styling to tables
2019-02-07 08:01:38 +00:00
Laurent Cozic
42b1db1d08 Desktop: Use Arial for note viewer in Windows 2019-02-07 00:00:08 +00:00
Laurent Cozic
9d4b34cad7 All: Applied styles to mobile too 2019-02-06 23:52:29 +00:00
Laurent Cozic
cd9aff0f59 Desktop: Make default editor font a bit bigger 2019-02-06 23:06:37 +00:00
Laurent Cozic
032816fffc All: Made note font slightly smaller 2019-02-06 22:48:02 +00:00
Laurent Cozic
1408f06c8d All: darker text 2019-02-06 22:39:03 +00:00
Laurent Cozic
49f8d0c6d8 API: Allow specifying item ID for any item 2019-02-06 22:36:39 +00:00
Laurent Cozic
0d6443c30a All: Improve styling and layout of notes in note viewer 2019-02-05 23:55:09 +00:00
Laurent Cozic
e62d91dda8 Desktop: Allow using macOS App bundle as external editor, and improved error handling 2019-02-05 22:00:25 +00:00
Laurent Cozic
0e122c9dc5 Merge branch 'welcome' 2019-02-05 21:14:43 +00:00
Laurent Cozic
c2bd453e8c Updated welcome notes 2019-02-05 21:14:32 +00:00
Laurent Cozic
949ea7afb7 Merge branch 'welcome' of github.com:laurent22/joplin into welcome 2019-02-05 18:46:41 +00:00
Laurent Cozic
9f575101d2 Updated doc 2019-02-05 18:46:32 +00:00
Laurent Cozic
2b4470054e Merge branch 'welcome' of github.com:laurent22/joplin into welcome 2019-02-05 18:45:24 +00:00
Laurent Cozic
b220613e54 Remove logo 2019-02-05 18:45:16 +00:00
Laurent Cozic
11328babe8 Add NC logo 2019-02-05 18:26:49 +00:00
Laurent Cozic
735bc92bc4 Mobile: Added shim.createResourceFromPath to support Welcome assets 2019-02-05 18:11:03 +00:00
Laurent Cozic
6894b9b1b7 All: Added tests for Welcome asset handling 2019-02-05 17:39:10 +00:00
Laurent Cozic
4de7815f31 doc 2019-02-05 17:08:25 +00:00
Laurent Cozic
4ce7b48468 Merge branch 'master' of github.com:laurent22/joplin 2019-02-05 17:07:41 +00:00
Laurent Cozic
77e4cb87ad iOS v29 2019-02-05 17:06:36 +00:00
Laurent Cozic
dd6b43035e Link between notes on Welcome notes 2019-02-03 20:30:59 +00:00
Laurent Cozic
e76094c546 Also set tags on Welcome notes 2019-02-03 20:19:17 +00:00
Laurent Cozic
9c00dc4cab All: Added script to build welcome assets and to import them on startup 2019-02-03 18:58:44 +00:00
Laurent Cozic
fc416de348 Doc: Removed note 'tags' property from doc as not fully supported (only used in Web Clipper) 2019-02-03 17:01:49 +00:00
Laurent Cozic
a2156be4ec Mobile: Fixed search screen 2019-02-03 16:57:29 +00:00
Laurent Cozic
cf427eba0f Mobile: Fixed sidebar error 2019-02-03 16:15:07 +00:00
Laurent Cozic
0050c90678 Update translations 2019-02-03 15:57:10 +00:00
Laurent Cozic
5eeff02dbe Revert "Исправлен и обновлен перевод (#1175)"
This reverts commit eb283efc20.
2019-02-03 15:56:20 +00:00
0ndrey
eb283efc20 Исправлен и обновлен перевод (#1175) 2019-02-03 15:50:30 +00:00
Laurent Cozic
87121c9c21 All: Fixed importing ENEX file when note incorrectly contains a reminder tag 2019-02-02 13:04:42 +00:00
Laurent Cozic
a2dbbbf832 Merge branch 'master' of github.com:laurent22/joplin 2019-02-02 10:54:07 +00:00
Laurent Cozic
fd251cd9a9 Desktop: started writing welcome notes 2019-02-02 10:53:57 +00:00
Laurent Cozic
8ced2d288e Desktop: Note reloading issue 2019-02-02 10:47:26 +00:00
Laurent Cozic
242926d381 Fixed regressions in test units 2019-01-31 09:48:48 +00:00
Laurent Cozic
8c9a148e71 All: Better handle search queries that include dashes 2019-01-31 08:35:41 +00:00
Laurent Cozic
9e165fc7dc Desktop: Fixes #1161: Display highlighted text and other background colours and images when exporting to PDF or printing 2019-01-31 08:23:47 +00:00
Laurent Cozic
f46e4e0cec Desktop: Fixes #1142: Disallow dropping notes on sidebar Notebook header 2019-01-31 08:02:12 +00:00
Laurent Cozic
efcf5ecef4 Desktop: When deleting note, display title or number of notes 2019-01-31 07:55:51 +00:00
Laurent Cozic
b6ba843d09 Desktop: Added 'Insert date time' option to menu 2019-01-30 22:45:49 +00:00
Laurent Cozic
915112e274 Desktop: Restore scroll position when switching notes 2019-01-30 22:45:28 +00:00
Laurent Cozic
cc8f8fcd2c Desktop: Allow selecting editor path with dialog window 2019-01-30 19:19:06 +00:00
Laurent Cozic
bda3ea9a35 Desktop: Improve how new notes are created to make it more reliable 2019-01-30 18:06:47 +00:00
Laurent Cozic
a7aed1f93a Desktop: Fixed scrolling issue 2019-01-30 17:35:41 +00:00
Laurent Cozic
a33f602f3b Desktop: Record last selected note IDs and restore it when opening notebook 2019-01-29 18:32:52 +00:00
Laurent Cozic
4d08b49578 Desktop: Added Usage link next to search box 2019-01-29 18:11:31 +00:00
Laurent Cozic
21e049ab45 Desktop: When selecting multiple notes, display possible actions as buttons 2019-01-29 18:02:34 +00:00
Helmut K. C. Tessarek
1d4234caea Merge pull request #1155 from chenlhlinux/patch-1
Update zh_CN.po
2019-01-29 01:10:48 -05:00
Laurent Cozic
d1269de3a7 Desktop: Made confirmation buttons sticky on Config screen 2019-01-27 23:44:16 +00:00
Laurent Cozic
8c19fcf8fc Merge branch 'master' of github.com:laurent22/joplin 2019-01-27 23:16:37 +00:00
Laurent Cozic
beaba2be55 Desktop: Group config options into sections 2019-01-27 23:15:56 +00:00
chenlhlinux
32c9ad1d59 Update zh_CN.po 2019-01-27 19:35:10 +08:00
Helmut K. C. Tessarek
a194513252 de_DE.po: remove the last 2 occurences of fuzzy
Both 2 translations are accurate, thus I'm removing the fuzzy flag.
2019-01-26 22:22:09 -05:00
Helmut K. C. Tessarek
cd93a1d1e1 Merge pull request #1157 from xissy/patch-2
All: Update Korean translations
2019-01-26 21:53:36 -05:00
Taeho Kim
2867728996 Update ko.po
Added proper Korean translations into empty messages and fuzzy translations.
2019-01-26 17:34:57 -08:00
Laurent Cozic
394cc78851 Desktop: Use ENTER and ESCAPE to go to next search result or to close search bar 2019-01-26 18:40:43 +00:00
Laurent Cozic
76f0a26322 Desktop: Keep synchronise button and status at bottom of side bar 2019-01-26 18:36:20 +00:00
Laurent Cozic
92d7a577a0 Desktop: Use SPACE to collapse or expand a folder in sidebar 2019-01-26 18:09:09 +00:00
Laurent Cozic
9c1219b188 Desktop: Use arrow to move between items, and added shortcuts to focus different elements 2019-01-26 18:04:32 +00:00
Laurent Cozic
f62bbfe286 Desktop: Toggle todo checkbox using SPACE key 2019-01-26 15:33:45 +00:00
Laurent Cozic
fef176eb96 Merge branch 'master' of github.com:laurent22/joplin 2019-01-26 15:15:35 +00:00
Laurent Cozic
ed541dac3b Desktop: Delete note using keyboard 2019-01-26 15:15:16 +00:00
chenlhlinux
4a175b2158 Update zh_CN.po 2019-01-26 20:06:08 +08:00
Helmut K. C. Tessarek
4076899e11 Merge pull request #1149 from matsest/update-norwegian-190125
All: Update norwegian translations
2019-01-26 02:43:15 -05:00
Laurent Cozic
998bdf3b56 Desktop: Move up and down in note list using arrow keys 2019-01-25 19:59:36 +00:00
Laurent Cozic
76b211eb6d Electron release v1.0.125 2019-01-25 18:03:43 +00:00
Laurent Cozic
f781cb3922 Android release v1.0.236 2019-01-25 18:00:24 +00:00
Laurent Cozic
ced3e5d623 Android: Trying to remove Firebase libraries 2019-01-25 17:54:43 +00:00
Mats Estensen
2a4812cb87 update norwegian translations 2019-01-25 18:35:08 +01:00
Laurent Cozic
1f384c7ae4 Merge branch 'master' of github.com:laurent22/joplin 2019-01-25 17:14:26 +00:00
Laurent Cozic
01a3285636 Updated doc 2019-01-25 17:14:17 +00:00
Laurent Cozic
53166cb3f5 All: Fixes #1137: Fixed regression on SeaFile sync 2019-01-21 17:34:41 +00:00
Laurent Cozic
893462ae87 Check that resource could be loaded 2019-01-20 16:28:10 +00:00
Laurent Cozic
949dbf45f1 Desktop: Resolves #1099: Show Markdown images in external editor 2019-01-20 16:27:33 +00:00
Laurent Cozic
d7dc625042 Clipper: Fixes #1058: Import images at correct size 2019-01-20 15:26:43 +00:00
Laurent Cozic
cc91c77f9e Mobile: Prevent search box from being cleared when updated from somewhere else 2019-01-19 18:40:21 +00:00
149 changed files with 4780 additions and 1745 deletions

View File

@@ -16,14 +16,16 @@ If possible, **please provide a screenshot**. A screenshot showing the problem i
Again, please check that it has not already been requested. If it has, simply **up-vote the issue** - the ones with the most up-votes are likely to be implemented. "+1" comments are not tracked.
# Adding new features
# Creating a pull request
If you want to add a new feature, consider asking about it before implementing it or checking existing discussions to make sure it is within the scope of the project. Of course you are free to create the pull request directly but it is not guaranteed it is going to be accepted.
- If you want to add a new feature, consider asking about it before implementing it or checking existing discussions to make sure it is within the scope of the project. That scope, due to limited resources, might be narrower than you think. As a rule of thumb **if your change is likely to involve more than 50 lines of code, you should discuss it in the forum**, just so that you don't waste your time implementing something that might not be accepted.
- Bug fixes have a very high change of being accepted.
- A pull request that is relevant to the current roadmap has a very high change of being accepted.
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/master/BUILD.md) for more details.
Pull requests that automatically change many files tend to be rejected (for example changes that automatically update the code styling, or to add new lines to many files, or to automatically convert images to a different format) so if you have such a pull request in mind, please discuss it first in the forum.
# Coding style
There are only two rules, but not following them means the pull request will not be accepted (it can be accepted once the issues are fixed):

View File

@@ -22,6 +22,7 @@ const os = require('os');
const fs = require('fs-extra');
const { cliUtils } = require('./cli-utils.js');
const Cache = require('lib/Cache');
const WelcomeUtils = require('lib/WelcomeUtils');
class Application extends BaseApplication {
@@ -376,6 +377,8 @@ class Application extends BaseApplication {
return this.stdout(object);
});
await WelcomeUtils.install(this.dispatch.bind(this));
// If we have some arguments left at this point, it's a command
// so execute it.
if (argv.length) {
@@ -393,6 +396,12 @@ class Application extends BaseApplication {
}
process.exit(1);
}
await Setting.saveAll();
// Need to call exit() explicitely, otherwise Node wait for any timeout to complete
// https://stackoverflow.com/questions/18050095
process.exit(0);
} else { // Otherwise open the GUI
this.initRedux();

View File

@@ -154,11 +154,11 @@ class Command extends BaseCommand {
type: Database.enumId('fieldType', 'text'),
description: 'If an image is provided, you can also specify an optional rectangle that will be used to crop the image. In format `{ x: x, y: y, width: width, height: height }`',
});
tableFields.push({
name: 'tags',
type: Database.enumId('fieldType', 'text'),
description: 'Comma-separated list of tags. eg. `tag1,tag2`.',
});
// tableFields.push({
// name: 'tags',
// type: Database.enumId('fieldType', 'text'),
// description: 'Comma-separated list of tags. eg. `tag1,tag2`.',
// });
}
lines.push('# ' + toTitleCase(tableName));

View File

@@ -1,5 +1,8 @@
#!/usr/bin/env node
// Use njstrace to find out what Node.js might be spending time on
// var njstrace = require('njstrace').inject();
// Make it possible to require("/lib/...") without specifying full path
require('app-module-path').addPath(__dirname);

View File

@@ -589,6 +589,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "S'està exportant a «%s» com a format «%s». Espereu..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Títol del bloc de notes:"
#, fuzzy
msgid "Note body"
msgstr "Blocs de notes"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "S'està important des de «%s» com a format «%s». Espereu..."
@@ -646,6 +660,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -668,6 +685,10 @@ msgstr "Mostra o amaga la barra lateral"
msgid "Toggle editor layout"
msgstr "Canvia el disseny de l'editor"
#, fuzzy
msgid "Focus"
msgstr "Vés al cos"
msgid "Tools"
msgstr "Eines"
@@ -807,13 +828,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprova la configuració de la sincronització"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Les notes i la configuració es desen a: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprova la configuració de la sincronització"
msgid "Apply"
msgstr ""
@@ -908,6 +932,10 @@ msgstr "Estat"
msgid "Encryption is:"
msgstr "El xifratge és:"
#, fuzzy
msgid "Usage"
msgstr "Ús: %s"
msgid "Back"
msgstr "Enrere"
@@ -958,36 +986,6 @@ msgstr "Alguns elements no s'han pogut desxifrar."
msgid "Set the password"
msgstr "Establiu la contrasenya"
msgid "Add or remove tags"
msgstr "Afegeix o suprimeix etiquetes"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Copia"
msgid "Switch between note and to-do type"
msgstr "Alterna entre el tipus nota i tasques pendents"
#, fuzzy
msgid "Switch to note type"
msgstr "Alterna entre el tipus nota i tasques pendents"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Alterna entre el tipus nota i tasques pendents"
msgid "Copy Markdown link"
msgstr "Copia l'enllaç Markdown"
msgid "Delete"
msgstr "Suprimeix"
msgid "Delete notes?"
msgstr "Voleu suprimir les notes?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "No hi ha cap nota aquí. Creeu-ne una fent clic a «Nota nova»."
@@ -1133,6 +1131,9 @@ msgstr "Voleu suprimir aquesta etiqueta de totes les notes?"
msgid "Remove this search from the sidebar?"
msgstr "Voleu suprimir aquesta cerca de la barra laterla?"
msgid "Delete"
msgstr "Suprimeix"
msgid "Rename"
msgstr "Canvia el nom"
@@ -1481,6 +1482,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "El valor de l'opció no és vàlid: «%s». Els valors possibles són: %s."
#, fuzzy
msgid "General"
msgstr "Opcions generals"
#, fuzzy
msgid "Synchronisation"
msgstr "Estat de la sincronització"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Blocs de notes"
#, fuzzy
msgid "Application"
msgstr "Surt de l'aplicació"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1776,6 +1796,9 @@ msgstr "Converteix a nota"
msgid "Convert to todo"
msgstr "Converteix a llistat de tasques pendents"
msgid "Copy Markdown link"
msgstr "Copia l'enllaç Markdown"
msgid "Hide metadata"
msgstr "Amaga les metadades"
@@ -1811,6 +1834,27 @@ msgstr ""
msgid "Welcome"
msgstr "Benvingut"
#~ msgid "Add or remove tags"
#~ msgstr "Afegeix o suprimeix etiquetes"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Copia"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Alterna entre el tipus nota i tasques pendents"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Alterna entre el tipus nota i tasques pendents"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Alterna entre el tipus nota i tasques pendents"
#~ msgid "Delete notes?"
#~ msgstr "Voleu suprimir les notes?"
#~ msgid "State: %s."
#~ msgstr "Estat: %s"

View File

@@ -571,6 +571,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exportuji do \"%s\" jako formát \"%s\". Chvíli strpení..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Název zápisníku:"
#, fuzzy
msgid "Note body"
msgstr "Zápisníky"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importuji z \"%s\" jako formát \"%s\". Chvíli strpení..."
@@ -628,6 +642,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -650,6 +667,10 @@ msgstr ""
msgid "Toggle editor layout"
msgstr "Změňit layout editoru"
#, fuzzy
msgid "Focus"
msgstr "Vybrat text poznámky"
msgid "Tools"
msgstr "Nástroje"
@@ -782,13 +803,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Zkontrolujte nastavení synchronizace"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Poznámky a nastavení uloženo v: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Zkontrolujte nastavení synchronizace"
msgid "Apply"
msgstr ""
@@ -878,6 +902,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Šifrování je:"
#, fuzzy
msgid "Usage"
msgstr "Použití: %s"
msgid "Back"
msgstr "Zpět"
@@ -930,37 +958,6 @@ msgstr "Některé položky nelze rozšifrovat."
msgid "Set the password"
msgstr "Nastavit heslo"
msgid "Add or remove tags"
msgstr "Přidat či odebrat tagy"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Kopírovat"
msgid "Switch between note and to-do type"
msgstr "Přepnout mezi poznámkou a to-do"
#, fuzzy
msgid "Switch to note type"
msgstr "Přepnout mezi poznámkou a to-do"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Přepnout mezi poznámkou a to-do"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Delete"
msgstr "Smazat"
msgid "Delete notes?"
msgstr "Smazat poznámky?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Žádné poznámky. Vytvořte jednu kliknutím na \"Nová poznámka\"."
@@ -1103,6 +1100,9 @@ msgstr "Odebrat tento tag ze všech poznámek?"
msgid "Remove this search from the sidebar?"
msgstr "Smazat tento hledaný výraz z panelu?"
msgid "Delete"
msgstr "Smazat"
msgid "Rename"
msgstr "Přejmenovat"
@@ -1456,6 +1456,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Neplatná hodnota: \"%s\". Přípustné hodnoty jsou: %s."
#, fuzzy
msgid "General"
msgstr "Obecná nastavení"
#, fuzzy
msgid "Synchronisation"
msgstr "Stav synchronizace"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Zápisníky"
#, fuzzy
msgid "Application"
msgstr "Ukončí aplikaci."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1745,6 +1764,10 @@ msgstr "Konvertovat na poznámku"
msgid "Convert to todo"
msgstr "Konvertovat na todo"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Hide metadata"
msgstr "Schovat metadata"
@@ -1779,6 +1802,27 @@ msgstr "Nemáte žádný zápisník. Vytvořte jeden kliknutím na tlačítko (+
msgid "Welcome"
msgstr "Vítejte"
#~ msgid "Add or remove tags"
#~ msgstr "Přidat či odebrat tagy"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Kopírovat"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Přepnout mezi poznámkou a to-do"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Přepnout mezi poznámkou a to-do"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Přepnout mezi poznámkou a to-do"
#~ msgid "Delete notes?"
#~ msgstr "Smazat poznámky?"
#~ msgid "State: %s."
#~ msgstr "Stav: %s."

View File

@@ -576,6 +576,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Eksporterer til \"%s\" som \"%s\"-format. Vent venligst..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Notesbogs titel:"
#, fuzzy
msgid "Note body"
msgstr "Notesbøger"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importerer fra \"%s\" som \"%s\"-format. Vent venligst..."
@@ -633,6 +647,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -655,6 +672,10 @@ msgstr ""
msgid "Toggle editor layout"
msgstr "Skift editor layout"
#, fuzzy
msgid "Focus"
msgstr "Fokuser på brødtekst"
msgid "Tools"
msgstr "Værktøjer"
@@ -787,13 +808,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Check synkroniserings Indstillinger"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Noter og indstillinger er gemt i: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Check synkroniserings Indstillinger"
msgid "Apply"
msgstr ""
@@ -887,6 +911,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Kryptering er:"
#, fuzzy
msgid "Usage"
msgstr "Forbrug: %s"
msgid "Back"
msgstr "Tilbage"
@@ -939,37 +967,6 @@ msgstr "Nogle emner kan ikke krypteres."
msgid "Set the password"
msgstr "Indstil kodeord"
msgid "Add or remove tags"
msgstr "Tilføj eller slet mærker"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Kopier"
msgid "Switch between note and to-do type"
msgstr "Skift mellem note- og opgave type"
#, fuzzy
msgid "Switch to note type"
msgstr "Skift mellem note- og opgave type"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Skift mellem note- og opgave type"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Delete"
msgstr "Slet"
msgid "Delete notes?"
msgstr "Slet noter?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Der er ingen noter her. Opret en ved at klikke på \"Ny note\"."
@@ -1112,6 +1109,9 @@ msgstr "Slet denne markering fra alle noter?"
msgid "Remove this search from the sidebar?"
msgstr "Slet denne søgning fra sidebjælke?"
msgid "Delete"
msgstr "Slet"
msgid "Rename"
msgstr "Omdøb"
@@ -1465,6 +1465,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ulovlig værdi: \"%s\". Mulige valg er: %s."
#, fuzzy
msgid "General"
msgstr "Generelle indstillinger"
#, fuzzy
msgid "Synchronisation"
msgstr "Synkroniserings status"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Notesbøger"
#, fuzzy
msgid "Application"
msgstr "Forlad/luk program."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1754,6 +1773,10 @@ msgstr "Konverter til note"
msgid "Convert to todo"
msgstr "Konverter til opgave"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Hide metadata"
msgstr "Skjul metadata"
@@ -1788,6 +1811,27 @@ msgstr "Du har ingen notesbøger. Opret en ved at klikke på (+) knappen."
msgid "Welcome"
msgstr "Velkommen"
#~ msgid "Add or remove tags"
#~ msgstr "Tilføj eller slet mærker"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Kopier"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Skift mellem note- og opgave type"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Skift mellem note- og opgave type"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Skift mellem note- og opgave type"
#~ msgid "Delete notes?"
#~ msgstr "Slet noter?"
#~ msgid "State: %s."
#~ msgstr "Tilstand: %s."

View File

@@ -598,6 +598,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exportiere „%s“ ins „%s“ Format. Bitte warten..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Notizbuch-Titel:"
#, fuzzy
msgid "Note body"
msgstr "Notizbücher"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importiere „%s“ ins „%s“ Format. Bitte warten..."
@@ -654,6 +668,9 @@ msgstr "Fett"
msgid "Italic"
msgstr "Kursiv"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "Datum / Uhrzeit einfügen"
@@ -675,6 +692,10 @@ msgstr "Seitenleiste umschalten"
msgid "Toggle editor layout"
msgstr "Editor-Layout umschalten"
#, fuzzy
msgid "Focus"
msgstr "Fokussiere Inhalt"
msgid "Tools"
msgstr "Werkzeuge"
@@ -817,13 +838,16 @@ msgstr ""
"Dieses Autorisierung-Token wird nur benötigt, um Drittanbieter-Anwendungen "
"Zugriff auf Joplin zu gewähren."
msgid "Check synchronisation configuration"
msgstr "Überprüfen der Synchronisationseinstellungen"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Notizen und Einstellungen werden gespeichert in: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Überprüfen der Synchronisationseinstellungen"
msgid "Apply"
msgstr "Anwenden"
@@ -917,6 +941,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Die Verschlüsselung ist:"
#, fuzzy
msgid "Usage"
msgstr "Nutzung: %s"
msgid "Back"
msgstr "Zurück"
@@ -969,34 +997,6 @@ msgstr "Einige Objekte können nicht entschlüsselt werden."
msgid "Set the password"
msgstr "Setze ein Passwort"
msgid "Add or remove tags"
msgstr "Schlagwörter hinzufügen oder entfernen"
msgid "Duplicate"
msgstr "Duplizieren"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Kopieren"
msgid "Switch between note and to-do type"
msgstr "Zwischen Notiz und To-Do Typ wechseln"
msgid "Switch to note type"
msgstr "Zu Notiz-Typ wechseln"
msgid "Switch to to-do type"
msgstr "Zu To-Do-Typ wechseln"
msgid "Copy Markdown link"
msgstr "Markdown-Link kopieren"
msgid "Delete"
msgstr "Löschen"
msgid "Delete notes?"
msgstr "Notizen löschen?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
"Keine Notizen vorhanden. Erstelle eine, indem du auf \"Neue Notiz\" drückst."
@@ -1144,6 +1144,9 @@ msgstr "Dieses Schlagwort von allen Notizen entfernen?"
msgid "Remove this search from the sidebar?"
msgstr "Diese Suche von der Seitenleiste entfernen?"
msgid "Delete"
msgstr "Löschen"
msgid "Rename"
msgstr "Umbenennen"
@@ -1503,6 +1506,26 @@ msgstr "Ignoriere TLS-Zertifikatfehler"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ungültiger Optionswert: \"%s\". Mögliche Werte sind: %s."
#, fuzzy
msgid "General"
msgstr "Allgemeine Einstellungen"
#, fuzzy
msgid "Synchronisation"
msgstr "Status der Synchronisation"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Notizbücher"
# Please note: The term 'Location' is assumed to be the geographical location where the note has been created. For this the german word 'Standort' fits better than the previously used 'Ablageort'. The latter one is used for the folder where files are stored.
#, fuzzy
msgid "Application"
msgstr "Standort"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1730,7 +1753,6 @@ msgstr "FTS aktiviert: %d"
msgid "Login with Dropbox"
msgstr "Mit Dropbox anmelden"
#, fuzzy
msgid "Enter code here"
msgstr "Hier Code eingeben"
@@ -1804,6 +1826,9 @@ msgstr "In eine Notiz umwandeln"
msgid "Convert to todo"
msgstr "In ein To-Do umwandeln"
msgid "Copy Markdown link"
msgstr "Markdown-Link kopieren"
msgid "Hide metadata"
msgstr "Metadaten verstecken"
@@ -1841,6 +1866,27 @@ msgstr ""
msgid "Welcome"
msgstr "Willkommen"
#~ msgid "Add or remove tags"
#~ msgstr "Schlagwörter hinzufügen oder entfernen"
#~ msgid "Duplicate"
#~ msgstr "Duplizieren"
#~ msgid "%s - Copy"
#~ msgstr "%s - Kopieren"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Zwischen Notiz und To-Do Typ wechseln"
#~ msgid "Switch to note type"
#~ msgstr "Zu Notiz-Typ wechseln"
#~ msgid "Switch to to-do type"
#~ msgstr "Zu To-Do-Typ wechseln"
#~ msgid "Delete notes?"
#~ msgstr "Notizen löschen?"
#~ msgid "State: %s."
#~ msgstr "Status: %s."
@@ -1902,7 +1948,6 @@ msgstr "Willkommen"
#~ msgid "Set a to-do as completed / not completed"
#~ msgstr "Ein To-Do als abgeschlossen / nicht abgeschlossen markieren"
#, fuzzy
#~ msgid "[t]oggle [c]onsole between maximized/minimized/hidden/visible."
#~ msgstr ""
#~ "Schal[t]e das Terminal zwischen maximiert/minimiert/versteckt/sichtbar um."

View File

@@ -508,6 +508,18 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr ""
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
msgid "Note title"
msgstr ""
msgid "Note body"
msgstr ""
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr ""
@@ -564,6 +576,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -585,6 +600,9 @@ msgstr ""
msgid "Toggle editor layout"
msgstr ""
msgid "Focus"
msgstr ""
msgid "Tools"
msgstr ""
@@ -716,13 +734,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr ""
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr ""
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr ""
msgid "Apply"
msgstr ""
@@ -801,6 +822,9 @@ msgstr ""
msgid "Encryption is:"
msgstr ""
msgid "Usage"
msgstr ""
msgid "Back"
msgstr ""
@@ -851,34 +875,6 @@ msgstr ""
msgid "Set the password"
msgstr ""
msgid "Add or remove tags"
msgstr ""
msgid "Duplicate"
msgstr ""
#, javascript-format
msgid "%s - Copy"
msgstr ""
msgid "Switch between note and to-do type"
msgstr ""
msgid "Switch to note type"
msgstr ""
msgid "Switch to to-do type"
msgstr ""
msgid "Copy Markdown link"
msgstr ""
msgid "Delete"
msgstr ""
msgid "Delete notes?"
msgstr ""
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
@@ -1019,6 +1015,9 @@ msgstr ""
msgid "Remove this search from the sidebar?"
msgstr ""
msgid "Delete"
msgstr ""
msgid "Rename"
msgstr ""
@@ -1347,6 +1346,21 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
msgid "General"
msgstr ""
msgid "Synchronisation"
msgstr ""
msgid "Appearance"
msgstr ""
msgid "Note"
msgstr ""
msgid "Application"
msgstr ""
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1623,6 +1637,9 @@ msgstr ""
msgid "Convert to todo"
msgstr ""
msgid "Copy Markdown link"
msgstr ""
msgid "Hide metadata"
msgstr ""

View File

@@ -585,6 +585,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exportando el formato de \"%s\" a \"%s\". Por favor espere..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Título de libreta:"
#, fuzzy
msgid "Note body"
msgstr "Libretas"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importando el formato de \"%s\" a \"%s\". Por favor espere..."
@@ -642,6 +656,9 @@ msgstr "Negrita"
msgid "Italic"
msgstr "Cursiva"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "Introduce fecha"
@@ -664,6 +681,10 @@ msgstr "Cambia la barra lateral"
msgid "Toggle editor layout"
msgstr "Cambia el diseño del editor"
#, fuzzy
msgid "Focus"
msgstr "Foco en el cuerpo"
msgid "Tools"
msgstr "Herramientas"
@@ -803,13 +824,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprobar sincronización"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Las notas y los ajustes se guardan en: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprobar sincronización"
msgid "Apply"
msgstr "Aplicar"
@@ -903,6 +927,10 @@ msgstr "Estado"
msgid "Encryption is:"
msgstr "El cifrado está:"
#, fuzzy
msgid "Usage"
msgstr "Uso: %s"
msgid "Back"
msgstr "Atrás"
@@ -953,36 +981,6 @@ msgstr "No se han podido descifrar algunos elementos."
msgid "Set the password"
msgstr "Establecer la contraseña"
msgid "Add or remove tags"
msgstr "Añadir o borrar etiquetas"
msgid "Duplicate"
msgstr "Duplicado"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Copiar"
msgid "Switch between note and to-do type"
msgstr "Cambiar entre nota y lista de tareas"
#, fuzzy
msgid "Switch to note type"
msgstr "Cambiar entre nota y lista de tareas"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Cambiar entre nota y lista de tareas"
msgid "Copy Markdown link"
msgstr "Copiar el enlace de Markdown"
msgid "Delete"
msgstr "Eliminar"
msgid "Delete notes?"
msgstr "¿Desea eliminar notas?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "No hay ninguna nota. Cree una pulsando «Nota nueva»."
@@ -1125,6 +1123,9 @@ msgstr "¿Desea eliminar esta etiqueta de todas las notas?"
msgid "Remove this search from the sidebar?"
msgstr "¿Desea eliminar esta búsqueda de la barra lateral?"
msgid "Delete"
msgstr "Eliminar"
msgid "Rename"
msgstr "Renombrar"
@@ -1479,6 +1480,25 @@ msgstr "Ignorar errores en certificados TLS"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Opción inválida: «%s». Los valores posibles son: %s."
#, fuzzy
msgid "General"
msgstr "Opciones generales"
#, fuzzy
msgid "Synchronisation"
msgstr "Estado de la sincronización"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Libretas"
#, fuzzy
msgid "Application"
msgstr "Salir de la aplicación."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1775,6 +1795,9 @@ msgstr "Convertir a nota"
msgid "Convert to todo"
msgstr "Convertir a lista de tareas"
msgid "Copy Markdown link"
msgstr "Copiar el enlace de Markdown"
msgid "Hide metadata"
msgstr "Ocultar metadatos"
@@ -1810,6 +1833,29 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenido"
#~ msgid "Add or remove tags"
#~ msgstr "Añadir o borrar etiquetas"
#~ msgid "Duplicate"
#~ msgstr "Duplicado"
#~ msgid "%s - Copy"
#~ msgstr "%s - Copiar"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Cambiar entre nota y lista de tareas"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Cambiar entre nota y lista de tareas"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Cambiar entre nota y lista de tareas"
#~ msgid "Delete notes?"
#~ msgstr "¿Desea eliminar notas?"
#~ msgid "State: %s."
#~ msgstr "Estado: «%s»."
@@ -1869,9 +1915,6 @@ msgstr "Bienvenido"
#~ msgid "Cancel the current command."
#~ msgstr "Cancelar el comando actual."
#~ msgid "Exit the application."
#~ msgstr "Salir de la aplicación."
#~ msgid "Delete the currently selected note or notebook."
#~ msgstr "Eliminar la nota o libreta seleccionada."

View File

@@ -582,6 +582,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr ""
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Koadernoaren izenburua: "
#, fuzzy
msgid "Note body"
msgstr "Koadernoak"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr ""
@@ -641,6 +655,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -663,6 +680,9 @@ msgstr ""
msgid "Toggle editor layout"
msgstr ""
msgid "Focus"
msgstr ""
msgid "Tools"
msgstr "Tresnak"
@@ -797,14 +817,17 @@ msgid ""
"access Joplin."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Sinkronizazioa utzi"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Oharrak eta ezarpenak hemen daude gordeta: %s"
msgid "Browse..."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Sinkronizazioa utzi"
msgid "Apply"
msgstr ""
@@ -895,6 +918,10 @@ msgstr "Egoera"
msgid "Encryption is:"
msgstr "Zifratua da:"
#, fuzzy
msgid "Usage"
msgstr "Erabili: %s"
msgid "Back"
msgstr "Atzera"
@@ -949,36 +976,6 @@ msgstr "Zenbait item ezin dira deszifratu."
msgid "Set the password"
msgstr "Ezarri pasahitza"
msgid "Add or remove tags"
msgstr "Gehitu edo ezabatu etiketak"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Kopiatu"
msgid "Switch between note and to-do type"
msgstr "Aldatu oharra eta zeregin eren artean."
#, fuzzy
msgid "Switch to note type"
msgstr "Aldatu oharra eta zeregin eren artean."
#, fuzzy
msgid "Switch to to-do type"
msgstr "Aldatu oharra eta zeregin eren artean."
msgid "Copy Markdown link"
msgstr ""
msgid "Delete"
msgstr "Ezabatu"
msgid "Delete notes?"
msgstr "Oharrak ezabatu?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Hemen ez dago oharrik. Sortu bat \"Ohar berria\" sakatuta."
@@ -1125,6 +1122,9 @@ msgstr "Kendu etiketa hori ohar guztietatik?"
msgid "Remove this search from the sidebar?"
msgstr "Kendu bilaketa hori ohar guztietatik?"
msgid "Delete"
msgstr "Ezabatu"
msgid "Rename"
msgstr "Berrizendatu"
@@ -1486,6 +1486,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Balio aukera baliogabea: \"%s\". Litezkeen balioak: %s."
#, fuzzy
msgid "General"
msgstr "Ezarpenak"
#, fuzzy
msgid "Synchronisation"
msgstr "Sinkronizazioaren egoera"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Koadernoak"
#, fuzzy
msgid "Application"
msgstr "Irten aplikaziotik"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1776,6 +1795,9 @@ msgstr "Oharra bihurtu"
msgid "Convert to todo"
msgstr "Zeregina bihurtu"
msgid "Copy Markdown link"
msgstr ""
msgid "Hide metadata"
msgstr "Ezkutatu metadatuak"
@@ -1810,6 +1832,27 @@ msgstr "Oraindik ez duzu koadernorik. Sortu bat (+) botoian sakatuta."
msgid "Welcome"
msgstr "Ongi etorri!"
#~ msgid "Add or remove tags"
#~ msgstr "Gehitu edo ezabatu etiketak"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Kopiatu"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Aldatu oharra eta zeregin eren artean."
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Aldatu oharra eta zeregin eren artean."
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Aldatu oharra eta zeregin eren artean."
#~ msgid "Delete notes?"
#~ msgstr "Oharrak ezabatu?"
#, fuzzy
#~ msgid "State: %s."
#~ msgstr "Egoera: \"%s\"."
@@ -1861,9 +1904,6 @@ msgstr "Ongi etorri!"
#~ msgid "Cancel the current command."
#~ msgstr "Utzi uneko komandoa"
#~ msgid "Exit the application."
#~ msgstr "Irten aplikaziotik"
#~ msgid "Delete the currently selected note or notebook."
#~ msgstr "Ezabatu aukeratutako oharra edo koadernoa"

View File

@@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.0.3\n"
"X-Generator: Poedit 2.2.1\n"
msgid "To delete a tag, untag the associated notes."
msgstr "Pour supprimer une vignette, enlever là des notes associées."
@@ -583,6 +583,18 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exporter vers \"%s\" au format \"%s\". Veuillez patienter..."
msgid "Sidebar"
msgstr "Barre latérale"
msgid "Note list"
msgstr "Liste de notes"
msgid "Note title"
msgstr "Titre de la note"
msgid "Note body"
msgstr "Corps de la note"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importer depuis \"%s\" au format \"%s\". Veuillez patienter..."
@@ -639,6 +651,9 @@ msgstr "Gras"
msgid "Italic"
msgstr "Italique"
msgid "Link"
msgstr "Lien"
msgid "Insert Date Time"
msgstr "Insérer la date et l'heure"
@@ -660,6 +675,9 @@ msgstr "Basculer barre latérale"
msgid "Toggle editor layout"
msgstr "Basculer l'agencement de l'éditeur"
msgid "Focus"
msgstr "Naviguer"
msgid "Tools"
msgstr "Outils"
@@ -801,13 +819,16 @@ msgstr ""
"Ce code d'authentification est nécessaire uniquement pour permettre aux "
"logiciels tiers d'accéder aux données de Joplin."
msgid "Check synchronisation configuration"
msgstr "Vérifier config synchronisation"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Les notes et paramètres se trouve dans : %s"
msgid "Browse..."
msgstr "Parcourir…"
msgid "Check synchronisation configuration"
msgstr "Vérifier config synchronisation"
msgid "Apply"
msgstr "Appliquer"
@@ -903,6 +924,9 @@ msgstr "État"
msgid "Encryption is:"
msgstr "Le chiffrement est :"
msgid "Usage"
msgstr "Utilisation"
msgid "Back"
msgstr "Retour"
@@ -955,34 +979,6 @@ msgstr "Certains objets ne peuvent être déchiffrés."
msgid "Set the password"
msgstr "Définir le mot de passe"
msgid "Add or remove tags"
msgstr "Gérer les étiquettes"
msgid "Duplicate"
msgstr "Dupliquer"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Copie"
msgid "Switch between note and to-do type"
msgstr "Alterner entre note et tâche"
msgid "Switch to note type"
msgstr "Convertir en note"
msgid "Switch to to-do type"
msgstr "Convertir en tâche"
msgid "Copy Markdown link"
msgstr "Copier lien Markdown"
msgid "Delete"
msgstr "Supprimer"
msgid "Delete notes?"
msgstr "Supprimer les notes ?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
"Pas de notes ici. Créez-en une en pressant le bouton \"Nouvelle note\"."
@@ -1130,6 +1126,9 @@ msgstr "Enlever cette étiquette de toutes les notes ?"
msgid "Remove this search from the sidebar?"
msgstr "Enlever cette recherche de la barre latérale ?"
msgid "Delete"
msgstr "Supprimer"
msgid "Rename"
msgstr "Renommer"
@@ -1488,6 +1487,21 @@ msgstr "Ignorer les erreurs de certificats TLS"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s."
msgid "General"
msgstr "Général"
msgid "Synchronisation"
msgstr "Synchronisation"
msgid "Appearance"
msgstr "Apparence"
msgid "Note"
msgstr "Note"
msgid "Application"
msgstr "Application"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr "L'étiquette \"%s\" existe déjà. Veuillez choisir un autre nom."
@@ -1785,6 +1799,9 @@ msgstr "Convertir en note"
msgid "Convert to todo"
msgstr "Convertir en tâche"
msgid "Copy Markdown link"
msgstr "Copier lien Markdown"
msgid "Hide metadata"
msgstr "Cacher les métadonnées"
@@ -1821,6 +1838,27 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenue"
#~ msgid "Add or remove tags"
#~ msgstr "Gérer les étiquettes"
#~ msgid "Duplicate"
#~ msgstr "Dupliquer"
#~ msgid "%s - Copy"
#~ msgstr "%s - Copie"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Alterner entre note et tâche"
#~ msgid "Switch to note type"
#~ msgstr "Convertir en note"
#~ msgid "Switch to to-do type"
#~ msgstr "Convertir en tâche"
#~ msgid "Delete notes?"
#~ msgstr "Supprimer les notes ?"
#~ msgid "State: %s."
#~ msgstr "État : %s."

View File

@@ -576,6 +576,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exportando a «%s» como formato «%s». Agarde..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Título do caderno:"
#, fuzzy
msgid "Note body"
msgstr "Cadernos"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importando de «%s» como formato «%s». Agarde..."
@@ -633,6 +647,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -655,6 +672,10 @@ msgstr ""
msgid "Toggle editor layout"
msgstr "Cambiar a disposición do editor"
#, fuzzy
msgid "Focus"
msgstr "Focar no corpo"
msgid "Tools"
msgstr "Ferramentas"
@@ -787,13 +808,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprobar a configuración da sincronización"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "As notas e axustes gardáronse en: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprobar a configuración da sincronización"
msgid "Apply"
msgstr ""
@@ -885,6 +909,10 @@ msgstr "Estado"
msgid "Encryption is:"
msgstr "O cifrado é:"
#, fuzzy
msgid "Usage"
msgstr "Uso: %s"
msgid "Back"
msgstr "Anterior"
@@ -936,37 +964,6 @@ msgstr "Non é posíbel descifrar algúns elementos."
msgid "Set the password"
msgstr "Estabelecer un contrasinal"
msgid "Add or remove tags"
msgstr "Engadir ou eliminar etiquetas"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Copiar"
msgid "Switch between note and to-do type"
msgstr "Cambiar entre notas e tarefas"
#, fuzzy
msgid "Switch to note type"
msgstr "Cambiar entre notas e tarefas"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Cambiar entre notas e tarefas"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Delete"
msgstr "Eliminar"
msgid "Delete notes?"
msgstr "Desexa eliminar as notas?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Aquí non hai notas. Cree unha premendo en «Nova nota»."
@@ -1111,6 +1108,9 @@ msgstr "Desexa eliminar esta etiqueta de todas as notas?"
msgid "Remove this search from the sidebar?"
msgstr "Desexa eliminar esta busca da barra lateral?"
msgid "Delete"
msgstr "Eliminar"
msgid "Rename"
msgstr "Renomear"
@@ -1464,6 +1464,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Valor incorrecto de opción: «%s». Os valores posíbeis son: %s."
#, fuzzy
msgid "General"
msgstr "Opcións xerais"
#, fuzzy
msgid "Synchronisation"
msgstr "Estado da sincronización"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Cadernos"
#, fuzzy
msgid "Application"
msgstr "Sae do aplicativo."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1753,6 +1772,10 @@ msgstr "Converter para nota"
msgid "Convert to todo"
msgstr "Converter para tarefa"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Hide metadata"
msgstr "Ocultar metadados"
@@ -1787,6 +1810,27 @@ msgstr "Non ten cadernos actualmente. Cree un premendo no botón (+)."
msgid "Welcome"
msgstr "Benvido/a"
#~ msgid "Add or remove tags"
#~ msgstr "Engadir ou eliminar etiquetas"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Copiar"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Cambiar entre notas e tarefas"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Cambiar entre notas e tarefas"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Cambiar entre notas e tarefas"
#~ msgid "Delete notes?"
#~ msgstr "Desexa eliminar as notas?"
#~ msgid "State: %s."
#~ msgstr "Estado: %s."

View File

@@ -579,6 +579,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr ""
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Naslov bilježnice:"
#, fuzzy
msgid "Note body"
msgstr "Bilježnice"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr ""
@@ -638,6 +652,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -660,6 +677,10 @@ msgstr ""
msgid "Toggle editor layout"
msgstr ""
#, fuzzy
msgid "Focus"
msgstr "Naslov bilješke:"
msgid "Tools"
msgstr "Alati"
@@ -795,14 +816,17 @@ msgid ""
"access Joplin."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Prekini sinkronizaciju"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Bilješke i postavke su pohranjene u: %s"
msgid "Browse..."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Prekini sinkronizaciju"
msgid "Apply"
msgstr ""
@@ -881,6 +905,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Usage"
msgstr "Korištenje: %s"
msgid "Back"
msgstr "Natrag"
@@ -936,36 +964,6 @@ msgstr "Neke stavke se ne mogu sinkronizirati."
msgid "Set the password"
msgstr ""
msgid "Add or remove tags"
msgstr "Dodaj ili makni oznake"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Kopiraj"
msgid "Switch between note and to-do type"
msgstr "Zamijeni bilješku i zadatak"
#, fuzzy
msgid "Switch to note type"
msgstr "Zamijeni bilješku i zadatak"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Zamijeni bilješku i zadatak"
msgid "Copy Markdown link"
msgstr ""
msgid "Delete"
msgstr "Obriši"
msgid "Delete notes?"
msgstr "Obriši bilješke?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Ovdje nema bilješki. Stvori novu pritiskom na \"Nova bilješka\"."
@@ -1111,6 +1109,9 @@ msgstr "Makni ovu oznaku iz svih bilješki?"
msgid "Remove this search from the sidebar?"
msgstr "Makni ovu pretragu iz izbornika?"
msgid "Delete"
msgstr "Obriši"
msgid "Rename"
msgstr "Preimenuj"
@@ -1463,6 +1464,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Nevažeća vrijednost: \"%s\". Moguće vrijednosti su: %s."
#, fuzzy
msgid "General"
msgstr "Opcije"
#, fuzzy
msgid "Synchronisation"
msgstr "Status sinkronizacije"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Bilježnice"
#, fuzzy
msgid "Application"
msgstr "Izađi iz aplikacije."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1752,6 +1772,9 @@ msgstr "Pretvori u bilješku"
msgid "Convert to todo"
msgstr "Pretvori u zadatak"
msgid "Copy Markdown link"
msgstr ""
msgid "Hide metadata"
msgstr "Sakrij metapodatke"
@@ -1786,6 +1809,27 @@ msgstr "Trenutno nemaš nijednu bilježnicu. Stvori novu klikom na (+) gumb."
msgid "Welcome"
msgstr "Dobro došli"
#~ msgid "Add or remove tags"
#~ msgstr "Dodaj ili makni oznake"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Kopiraj"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Zamijeni bilješku i zadatak"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Zamijeni bilješku i zadatak"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Zamijeni bilješku i zadatak"
#~ msgid "Delete notes?"
#~ msgstr "Obriši bilješke?"
#, fuzzy
#~ msgid "State: %s."
#~ msgstr "Stanje: \"%s\"."
@@ -1836,9 +1880,6 @@ msgstr "Dobro došli"
#~ msgid "Cancel the current command."
#~ msgstr "Prekini trenutnu naredbu."
#~ msgid "Exit the application."
#~ msgstr "Izađi iz aplikacije."
#~ msgid "Delete the currently selected note or notebook."
#~ msgstr "Obriši odabranu bilješku ili bilježnicu."

View File

@@ -589,6 +589,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Esportazione da \"%s\" come formato \"%s\". Si prega di attendere..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Titolo del Taccuino:"
#, fuzzy
msgid "Note body"
msgstr "Taccuini"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importazione da \"%s\" come formato \"%s\". Si prega di attendere..."
@@ -645,6 +659,9 @@ msgstr "Grasseto"
msgid "Italic"
msgstr "Corsivo"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "Inserisci data e ora"
@@ -666,6 +683,10 @@ msgstr "Attiva / disattiva barra laterale"
msgid "Toggle editor layout"
msgstr "Attiva / disattiva il layout dell'editor"
#, fuzzy
msgid "Focus"
msgstr "Focus sul testo"
msgid "Tools"
msgstr "Strumenti"
@@ -804,13 +825,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Controlla la configurazione della sincronizzazione"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Le note e le impostazioni sono memorizzate in: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Controlla la configurazione della sincronizzazione"
msgid "Apply"
msgstr "Applica"
@@ -906,6 +930,10 @@ msgstr "Stato"
msgid "Encryption is:"
msgstr "La crittografia è:"
#, fuzzy
msgid "Usage"
msgstr "Uso: %s"
msgid "Back"
msgstr "Indietro"
@@ -956,34 +984,6 @@ msgstr "Alcuni elementi non possono essere decodificati."
msgid "Set the password"
msgstr "Imposta la password"
msgid "Add or remove tags"
msgstr "Aggiungi o rimuovi etichetta"
msgid "Duplicate"
msgstr "Duplicare"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Copia"
msgid "Switch between note and to-do type"
msgstr "Converti nota in \"Cose-da-fare\" e viceversa"
msgid "Switch to note type"
msgstr "Converti in nota"
msgid "Switch to to-do type"
msgstr "Converti in \"Cose-da-fare\""
msgid "Copy Markdown link"
msgstr "Copia il link Markdown"
msgid "Delete"
msgstr "Elimina"
msgid "Delete notes?"
msgstr "Eliminare le note?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Non è presente nessuna nota. Creane una cliccando \"Nuova nota\"."
@@ -1129,6 +1129,9 @@ msgstr "Rimuovere questa etichetta da tutte le note?"
msgid "Remove this search from the sidebar?"
msgstr "Rimuovere questa ricerca dalla barra laterale?"
msgid "Delete"
msgstr "Elimina"
msgid "Rename"
msgstr "Rinomina"
@@ -1483,6 +1486,25 @@ msgstr "Ignora gli errori del certificato TLS"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Opzione non valida: \"%s\". I valori possibili sono: %s."
#, fuzzy
msgid "General"
msgstr "Opzioni Generali"
#, fuzzy
msgid "Synchronisation"
msgstr "Stato di sincronizzazione"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Taccuini"
#, fuzzy
msgid "Application"
msgstr "Esci dall'applicazione."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr "Il tag \"%s\" esiste già. Scegliere un nome differente."
@@ -1777,6 +1799,9 @@ msgstr "Converti in nota"
msgid "Convert to todo"
msgstr "Converti in Todo"
msgid "Copy Markdown link"
msgstr "Copia il link Markdown"
msgid "Hide metadata"
msgstr "Nascondi i Metadati"
@@ -1812,6 +1837,27 @@ msgstr ""
msgid "Welcome"
msgstr "Benvenuto"
#~ msgid "Add or remove tags"
#~ msgstr "Aggiungi o rimuovi etichetta"
#~ msgid "Duplicate"
#~ msgstr "Duplicare"
#~ msgid "%s - Copy"
#~ msgstr "%s - Copia"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Converti nota in \"Cose-da-fare\" e viceversa"
#~ msgid "Switch to note type"
#~ msgstr "Converti in nota"
#~ msgid "Switch to to-do type"
#~ msgstr "Converti in \"Cose-da-fare\""
#~ msgid "Delete notes?"
#~ msgstr "Eliminare le note?"
#~ msgid "State: %s."
#~ msgstr "Stato: %s."
@@ -1878,9 +1924,6 @@ msgstr "Benvenuto"
#~ msgid "Cancel the current command."
#~ msgstr "Cancella il comando corrente."
#~ msgid "Exit the application."
#~ msgstr "Esci dall'applicazione."
#~ msgid "Delete the currently selected note or notebook."
#~ msgstr "Elimina la nota o il taccuino selezionato."

View File

@@ -570,6 +570,20 @@ msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr ""
"\"%s\" を \"%s\" フォーマットにエクスポート中。しばらくお待ちください..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "ノートブックの題名:"
#, fuzzy
msgid "Note body"
msgstr "ノートブック"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr ""
@@ -627,6 +641,9 @@ msgstr "太字"
msgid "Italic"
msgstr "斜体"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "日付の入力"
@@ -648,6 +665,10 @@ msgstr "サイドバーの表示切り替え"
msgid "Toggle editor layout"
msgstr "エディターレイアウトの表示切り替え"
#, fuzzy
msgid "Focus"
msgstr "本文にフォーカス"
msgid "Tools"
msgstr "ツール"
@@ -786,13 +807,16 @@ msgstr ""
"この認証トークンはサードパーティアプリケーションがJoplinにアクセスするためだ"
"けに必要です。"
msgid "Check synchronisation configuration"
msgstr "同期の設定を確認する"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "ノートと設定は次の場所に保存されます: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "同期の設定を確認する"
msgid "Apply"
msgstr "適用"
@@ -884,6 +908,10 @@ msgstr "状態"
msgid "Encryption is:"
msgstr "暗号化の状態:"
#, fuzzy
msgid "Usage"
msgstr "使用方法: %s"
msgid "Back"
msgstr "戻る"
@@ -936,34 +964,6 @@ msgstr "いくつかの項目は復号されませんでした。"
msgid "Set the password"
msgstr "パスワードの設定"
msgid "Add or remove tags"
msgstr "タグの追加と削除"
msgid "Duplicate"
msgstr "複製"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - コピー"
msgid "Switch between note and to-do type"
msgstr "ノートとToDoを切り替え"
msgid "Switch to note type"
msgstr "ノートに切り替え"
msgid "Switch to to-do type"
msgstr "ToDoに切り替え"
msgid "Copy Markdown link"
msgstr "Markdownのリンクをコピー"
msgid "Delete"
msgstr "削除"
msgid "Delete notes?"
msgstr "ノートを削除しますか?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "ノートがありません。新しいノートを作成して下さい。"
@@ -1106,6 +1106,9 @@ msgstr "すべてのノートからこのタグを削除しますか?"
msgid "Remove this search from the sidebar?"
msgstr "サイドバーからこの検索を削除しますか?"
msgid "Delete"
msgstr "削除"
msgid "Rename"
msgstr "名前の変更"
@@ -1461,6 +1464,25 @@ msgstr "TLS証明書のエラーを無視"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "無効な設定値: \"%s\"。有効な値は: %sです。"
#, fuzzy
msgid "General"
msgstr "全般のオプション"
#, fuzzy
msgid "Synchronisation"
msgstr "同期状況"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "ノートブック"
#, fuzzy
msgid "Application"
msgstr "場所"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr "タグ \"%s\" はすでにあります。ほかの名前を選択してください。"
@@ -1754,6 +1776,9 @@ msgstr "ノートに変換"
msgid "Convert to todo"
msgstr "ToDoに変換"
msgid "Copy Markdown link"
msgstr "Markdownのリンクをコピー"
msgid "Hide metadata"
msgstr "メタデータを隠す"
@@ -1790,6 +1815,27 @@ msgstr ""
msgid "Welcome"
msgstr "ようこそ"
#~ msgid "Add or remove tags"
#~ msgstr "タグの追加と削除"
#~ msgid "Duplicate"
#~ msgstr "複製"
#~ msgid "%s - Copy"
#~ msgstr "%s - コピー"
#~ msgid "Switch between note and to-do type"
#~ msgstr "ノートとToDoを切り替え"
#~ msgid "Switch to note type"
#~ msgstr "ノートに切り替え"
#~ msgid "Switch to to-do type"
#~ msgstr "ToDoに切り替え"
#~ msgid "Delete notes?"
#~ msgstr "ノートを削除しますか?"
#~ msgid "State: %s."
#~ msgstr "状態: \"%s\"."

View File

@@ -508,6 +508,18 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr ""
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
msgid "Note title"
msgstr ""
msgid "Note body"
msgstr ""
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr ""
@@ -564,6 +576,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -585,6 +600,9 @@ msgstr ""
msgid "Toggle editor layout"
msgstr ""
msgid "Focus"
msgstr ""
msgid "Tools"
msgstr ""
@@ -716,13 +734,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr ""
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr ""
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr ""
msgid "Apply"
msgstr ""
@@ -801,6 +822,9 @@ msgstr ""
msgid "Encryption is:"
msgstr ""
msgid "Usage"
msgstr ""
msgid "Back"
msgstr ""
@@ -851,34 +875,6 @@ msgstr ""
msgid "Set the password"
msgstr ""
msgid "Add or remove tags"
msgstr ""
msgid "Duplicate"
msgstr ""
#, javascript-format
msgid "%s - Copy"
msgstr ""
msgid "Switch between note and to-do type"
msgstr ""
msgid "Switch to note type"
msgstr ""
msgid "Switch to to-do type"
msgstr ""
msgid "Copy Markdown link"
msgstr ""
msgid "Delete"
msgstr ""
msgid "Delete notes?"
msgstr ""
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
@@ -1019,6 +1015,9 @@ msgstr ""
msgid "Remove this search from the sidebar?"
msgstr ""
msgid "Delete"
msgstr ""
msgid "Rename"
msgstr ""
@@ -1347,6 +1346,21 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
msgid "General"
msgstr ""
msgid "Synchronisation"
msgstr ""
msgid "Appearance"
msgstr ""
msgid "Note"
msgstr ""
msgid "Application"
msgstr ""
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1623,6 +1637,9 @@ msgstr ""
msgid "Convert to todo"
msgstr ""
msgid "Copy Markdown link"
msgstr ""
msgid "Hide metadata"
msgstr ""

View File

@@ -447,12 +447,11 @@ msgid "Starting synchronisation..."
msgstr "동기화를 시작합니다..."
msgid "Downloading resources..."
msgstr ""
msgstr "리소스 다운로드 중..."
msgid "Cancelling... Please wait."
msgstr "취소하는 중입니다... 잠시만 기다리세요."
#, fuzzy
msgid ""
"<tag-command> can be \"add\", \"remove\" or \"list\" to assign or remove "
"[tag] from [note], or to list the notes associated with [tag]. The command "
@@ -460,7 +459,8 @@ msgid ""
msgstr ""
"[note]로부터 [tag]를 지우거나 지정할 때, 아니면 [tag]와 관련된 노트의 목록을 "
"확인할 때 <tag-command>로 \"add\", \"remove\" 또는 \"list\" 를 사용할 수 있습"
"니다. `tag list` 명령어로 모든 태그의 목록을 확인할 수 있습니다."
"니다. `tag list` 명령어로 모든 태그의 목록을 확인할 수 있습니다 (옵션 -l 사"
"용 가능)."
#, javascript-format
msgid "Invalid command: \"%s\""
@@ -568,6 +568,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "\"%s\"에 \"%s\" 포맷으로 내보내는 중입니다. 잠시만 기다리세요..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "노트북 제목:"
#, fuzzy
msgid "Note body"
msgstr "노트북"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "\"%s\"에서 \"%s\" 포맷으로 가져오는 중입니다. 잠시만 기다리세요..."
@@ -615,9 +629,8 @@ msgstr "잘라내기"
msgid "Paste"
msgstr "붙여넣기"
#, fuzzy
msgid "Select all"
msgstr "날짜 선택"
msgstr "모두 선택"
msgid "Bold"
msgstr "굵게"
@@ -625,6 +638,9 @@ msgstr "굵게"
msgid "Italic"
msgstr "기울임"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "날짜와 시간 입력"
@@ -634,9 +650,8 @@ msgstr "외부 편집기에서 편집하기"
msgid "Search in all the notes"
msgstr "모든 노트에서 검색"
#, fuzzy
msgid "Search in current note"
msgstr "모든 노트에서 검색"
msgstr "현재 노트에서 검색"
msgid "View"
msgstr "보기"
@@ -647,6 +662,10 @@ msgstr "사이드바 표시 전환"
msgid "Toggle editor layout"
msgstr "편집기 배치 형태 전환"
#, fuzzy
msgid "Focus"
msgstr "내용에 포커스"
msgid "Tools"
msgstr "도구"
@@ -699,18 +718,18 @@ msgstr "현재 버전은 최신입니다."
#, javascript-format
msgid "%s (pre-release)"
msgstr ""
msgstr "%s (프리-릴리즈)"
msgid "An update is available, do you want to download it now?"
msgstr "업데이트가 있습니다. 지금 다운로드할까요?"
#, javascript-format
msgid "Your version: v%s"
msgstr ""
msgstr "현재 버전: v%s"
#, javascript-format
msgid "New version: v%s"
msgstr ""
msgstr "새 버전: v%s"
msgid "Yes"
msgstr "예"
@@ -719,7 +738,7 @@ msgid "No"
msgstr "아니오"
msgid "Token has been copied to the clipboard!"
msgstr ""
msgstr "토큰이 클립보드로 복사되었습니다!"
msgid "The web clipper service is enabled and set to auto-start."
msgstr "웹 수집기 서비스가 활성화되었고 자동으로 시작하도록 설정되었습니다."
@@ -768,28 +787,32 @@ msgstr "2단계: 확장 기능 설치"
msgid "Download and install the relevant extension for your browser:"
msgstr "브라우저에 적절한 확장 기능을 다운로드 및 설치하세요:"
#, fuzzy
msgid "Advanced options"
msgstr "고급 옵션"
msgid "Authorisation token:"
msgstr ""
msgstr "인증 토큰:"
msgid "Copy token"
msgstr ""
msgstr "토큰 복사"
msgid ""
"This authorisation token is only needed to allow third-party applications to "
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "동기화 설정 확인"
"이 인증 토큰은 오직 서드파티 애플리케이션에서 조플린을 접근할 때만 필요합니"
"다."
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "노트와 설정값이 다음에 저장되었습니다: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "동기화 설정 확인"
msgid "Apply"
msgstr "적용"
@@ -881,6 +904,10 @@ msgstr "상태"
msgid "Encryption is:"
msgstr "암호화는 다음과 같습니다:"
#, fuzzy
msgid "Usage"
msgstr "사용량: %s"
msgid "Back"
msgstr "뒤로 가기"
@@ -931,36 +958,6 @@ msgstr "일부 항목들은 암호화할 수 없습니다."
msgid "Set the password"
msgstr "암호 설정"
msgid "Add or remove tags"
msgstr "태그 추가 및 제거"
msgid "Duplicate"
msgstr "복제"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - 복사"
msgid "Switch between note and to-do type"
msgstr "'노트' 또는'할 일' 형식으로 전환합니다."
#, fuzzy
msgid "Switch to note type"
msgstr "'노트' 또는'할 일' 형식으로 전환합니다."
#, fuzzy
msgid "Switch to to-do type"
msgstr "'노트' 또는'할 일' 형식으로 전환합니다."
msgid "Copy Markdown link"
msgstr "마크다운 링크 복사"
msgid "Delete"
msgstr "삭제"
msgid "Delete notes?"
msgstr "노트를 삭제할까요?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "노트가 없습니다. '새 노트'를 선택해서 노트를 새로 만드세요."
@@ -969,13 +966,13 @@ msgid ""
msgstr "노트북이 없습니다. '새 노트북'을 선택해서 노트북을 새로 만드세요."
msgid "Location"
msgstr ""
msgstr "위치"
msgid "URL"
msgstr ""
msgstr "URL"
msgid "Note properties"
msgstr ""
msgstr "노트 속성"
msgid "Open..."
msgstr "열기..."
@@ -994,7 +991,7 @@ msgid "Copy Link Address"
msgstr "링크 주소 복사"
msgid "This attachment is not downloaded or not decrypted yet."
msgstr ""
msgstr "이 첨부는 아직 다운로드 또는 복호화 되지 않았습니다."
#, javascript-format
msgid "Unsupported link or message: %s"
@@ -1009,7 +1006,7 @@ msgstr ""
"요."
msgid "Only one note can be printed or exported to PDF at a time."
msgstr ""
msgstr "한 번에 오직 하나의 노트만 출력하거나 내보내기 할 수 있습니다."
msgid "strong text"
msgstr "중요 텍스트"
@@ -1103,6 +1100,9 @@ msgstr "모든 노트에서 이 태그를 제거할까요?"
msgid "Remove this search from the sidebar?"
msgstr "사이드바에서 이 검색 항목을 제거할까요?"
msgid "Delete"
msgstr "삭제"
msgid "Rename"
msgstr "이름 바꾸기"
@@ -1116,9 +1116,9 @@ msgstr "노트북"
msgid "Decrypting items: %d/%d"
msgstr "복호화 항목: %d/%d"
#, fuzzy, javascript-format
#, javascript-format
msgid "Fetching resources: %d"
msgstr "리소스: %d."
msgstr "리소스 가져오는 중: %d."
msgid "Please select where the sync status should be exported to"
msgstr "동기화 상태를 내보낼 대상을 선택하세요"
@@ -1327,16 +1327,17 @@ msgid ""
"this setting so that your notes are constantly being synchronised, thus "
"reducing the number of conflicts."
msgstr ""
"조플린을 백그라운드에서 구동합니다. 노트가 정기적으로 동기화 되어 충돌 횟수"
"를 줄이기 위해 이 옵션을 활성화 하는 것을 추천합니다."
msgid "Start application minimised in the tray icon"
msgstr ""
msgstr "트레이 아이콘에 최소화 된 상태로 애플리케이션 시작"
msgid "Global zoom percentage"
msgstr "전체적 확대 비율"
#, fuzzy
msgid "Editor font size"
msgstr "편집기 글꼴 집합"
msgstr "편집기 글꼴 크기"
msgid "Editor font family"
msgstr "편집기 글꼴 집합"
@@ -1353,11 +1354,11 @@ msgid "Automatically update the application"
msgstr "애플리케이션을 자동으로 업데이트"
msgid "Get pre-releases when checking for updates"
msgstr ""
msgstr "업데이트 확인 시 프리-릴리즈 받기"
#, javascript-format
msgid "See the pre-release page for more details: %s"
msgstr ""
msgstr "자세한 내용은 프리-릴리즈 페이지를 참조하세요: %s"
msgid "Synchronisation interval"
msgstr "동기화 간격"
@@ -1416,6 +1417,8 @@ msgid ""
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"주의: 이 위치를 변경하시려면, 동기화 전에 모든 컨텐트를 복사했는지 확인하세"
"요, 그렇지 않으면 모든 파일이 삭제됩니다! 자세한 정보는 FAQ를 참조하세요: %s"
msgid "Nextcloud username"
msgstr "Nextcloud 사용자 이름"
@@ -1453,9 +1456,28 @@ msgstr "TLS 인증서 오류 무시"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "올바르지 않은 옵션 값: \"%s\". 가능한 값은 다음과 같습니다: \"%s\"."
#, fuzzy
msgid "General"
msgstr "일반 옵션"
#, fuzzy
msgid "Synchronisation"
msgstr "동기화 상태"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "노트북"
#, fuzzy
msgid "Application"
msgstr "위치"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
msgstr "태그 \"%s\"(이)가 이미 존재합니다. 다른 이름을 선택해 주세요."
msgid "Joplin Export File"
msgstr "조플린 내보내기 파일"
@@ -1469,9 +1491,8 @@ msgstr "조플린 내보내기 폴더"
msgid "Evernote Export File"
msgstr "에버노트 내보내기 파일"
#, fuzzy
msgid "Json Export Directory"
msgstr "조플린 내보내기 폴더"
msgstr "Json 내보내기 폴더"
msgid "Directory"
msgstr "폴더"
@@ -1548,10 +1569,10 @@ msgid "On %s: %s"
msgstr "%s: %s"
msgid "Permission to use camera"
msgstr ""
msgstr "카메라 사용 허가"
msgid "Your permission to use your camera is required."
msgstr ""
msgstr "카메라 사용을 허가가 요구됩니다."
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr "노트가 없습니다. (+) 버튼을 선택해 새로 만드세요."
@@ -1581,9 +1602,8 @@ msgstr "%d 노트를 \"%s\" 노트북으로 옮길까요?"
msgid "Press to set the decryption password."
msgstr "복호화 암호를 설정하려면 누르세요."
#, fuzzy
msgid "Clear alarm"
msgstr "알람 설정"
msgstr "알람 취소"
msgid "Save alarm"
msgstr "알람 저장"
@@ -1597,20 +1617,19 @@ msgstr "확인"
msgid "Cancel synchronisation"
msgstr "동기화 취소"
#, fuzzy
msgid "Checking... Please wait."
msgstr "취소하는 중입니다... 잠시만 기다리세요."
msgstr "확인 중입니다... 잠시만 기다리세요."
#, fuzzy
msgid "Success! Synchronisation configuration appears to be correct."
msgstr "동기화 설정 확인"
msgstr "성공! 동기화 설정이 올바릅니다."
msgid ""
"Error. Please check that URL, username, password, etc. are correct and that "
"the sync target is accessible. The reported error was:"
msgstr ""
"Error. Please check that URL, username, password, etc. are correct and that "
"the sync target is accessible. The reported error was:"
#, fuzzy
msgid "The application has been authorised!"
msgstr "애플리케이션이 성공적으로 허가되었습니다."
@@ -1622,10 +1641,15 @@ msgid ""
"\n"
"Please try again."
msgstr ""
"애플리케이션을 허가할 수 없습니다:\n"
"\n"
"%s\n"
"\n"
"다시 시도해 주세요."
#, fuzzy, javascript-format
#, javascript-format
msgid "Decrypted items: %s / %s"
msgstr "복호화 항목: %d/%d"
msgstr "복호화 항목: %s / %s"
msgid "New tags:"
msgstr "새 태그:"
@@ -1656,23 +1680,23 @@ msgstr "- 위치: 지리적 위치 정보를 노트에 첨부하기 위해서
msgid "Joplin website"
msgstr "조플린 웹사이트"
#, fuzzy, javascript-format
#, javascript-format
msgid "Joplin v%s"
msgstr "조플린 웹사이트"
msgstr "조플린 v%s"
#, javascript-format
msgid "Database v%s"
msgstr ""
msgstr "데이터베이스 v%s"
#, fuzzy, javascript-format
#, javascript-format
msgid "FTS enabled: %d"
msgstr "삭제: %d"
msgstr "FTS 활성됨: %d"
msgid "Login with Dropbox"
msgstr "Dropbox로 로그인"
msgid "Enter code here"
msgstr ""
msgstr "여기에 코드를 입력하세요"
#, javascript-format
msgid "Master Key %s"
@@ -1725,9 +1749,8 @@ msgstr "조플린 모바일 앱은 현재 해당 형식의 링크를 지원하
msgid "Unsupported image type: %s"
msgstr "지원하지 않는 이미지 형식: %s"
#, fuzzy
msgid "Take photo"
msgstr "사진 첨부"
msgstr "사진 찍기"
msgid "Attach photo"
msgstr "사진 첨부"
@@ -1744,6 +1767,9 @@ msgstr "노트로 변환"
msgid "Convert to todo"
msgstr "'할 일'로 변환"
msgid "Copy Markdown link"
msgstr "마크다운 링크 복사"
msgid "Hide metadata"
msgstr "메타데이터 숨김"
@@ -1754,7 +1780,7 @@ msgid "View on map"
msgstr "지도에 표시"
msgid "Go to source URL"
msgstr ""
msgstr "소스 URL로 이동"
msgid "Delete notebook"
msgstr "노트북 삭제"
@@ -1778,6 +1804,27 @@ msgstr "노트북이 없습니다. (+) 버튼을 눌러 새로 만드세요."
msgid "Welcome"
msgstr "환영합니다"
#~ msgid "Add or remove tags"
#~ msgstr "태그 추가 및 제거"
#~ msgid "Duplicate"
#~ msgstr "복제"
#~ msgid "%s - Copy"
#~ msgstr "%s - 복사"
#~ msgid "Switch between note and to-do type"
#~ msgstr "'노트' 또는'할 일' 형식으로 전환합니다."
#~ msgid "Switch to note type"
#~ msgstr "'노트' 형식으로 전환합니다."
#~ msgid "Switch to to-do type"
#~ msgstr "'할 일' 형식으로 전환합니다."
#~ msgid "Delete notes?"
#~ msgstr "노트를 삭제할까요?"
#~ msgid "State: %s."
#~ msgstr "상태: %s."

View File

@@ -164,7 +164,7 @@ msgstr "Rediger notat."
msgid ""
"No text editor is defined. Please set it using `config editor <editor-path>`"
msgstr ""
"Inger teksteditor er valgt. Velg en ved å bruke `config editor <editor-path>`"
"Ingen teksteditor er valgt. Velg en ved å bruke `config editor <editor-path>`"
msgid "No active notebook."
msgstr "Ingen aktiv notatbok."
@@ -576,6 +576,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Eksporterer til \"%s\" i \"%s\" format. Vennligst vent..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Tittel på notatbok:"
#, fuzzy
msgid "Note body"
msgstr "Notatbøker"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importerer fra \"%s\" i \"%s\"-format. Vennligst vent..."
@@ -632,6 +646,9 @@ msgstr "Fet"
msgid "Italic"
msgstr "Kursiv"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "Sett inn dato/tid"
@@ -646,7 +663,7 @@ msgid "Search in current note"
msgstr "Søk i nåværende notat"
msgid "View"
msgstr "Utseende"
msgstr "Vis"
msgid "Toggle sidebar"
msgstr "Vis/skjul sidepanel"
@@ -654,6 +671,10 @@ msgstr "Vis/skjul sidepanel"
msgid "Toggle editor layout"
msgstr "Bytt editorutseende"
#, fuzzy
msgid "Focus"
msgstr "Fokuser på brødtekst"
msgid "Tools"
msgstr "Verktøy"
@@ -706,18 +727,18 @@ msgstr "Nåværende versjon er den siste tilgjengelige."
#, javascript-format
msgid "%s (pre-release)"
msgstr ""
msgstr "%s (førutgivelse)"
msgid "An update is available, do you want to download it now?"
msgstr "En oppdatering er tilgjengelig, vil du laste den ned nå?"
#, javascript-format
msgid "Your version: v%s"
msgstr ""
msgstr "Din versjon: v%s"
#, javascript-format
msgid "New version: v%s"
msgstr ""
msgstr "Ny versjon: v%s"
msgid "Yes"
msgstr "Ja"
@@ -789,16 +810,19 @@ msgid ""
"This authorisation token is only needed to allow third-party applications to "
"access Joplin."
msgstr ""
"Denne autentiseringsbeviset er det eneste nødvendig for å gi "
"Denne autoriseringsbeviset er det eneste nødvendig for å gi "
"tredjepartsapplikasjoner tilgang til Joplin."
msgid "Check synchronisation configuration"
msgstr "Sjekk synkroniseringskonfigurasjon"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Notater og innstillinger er lagret i: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Sjekk synkroniseringskonfigurasjon"
msgid "Apply"
msgstr "Bruk"
@@ -893,6 +917,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Kryptering er:"
#, fuzzy
msgid "Usage"
msgstr "Bruk: %s"
msgid "Back"
msgstr "Tilbake"
@@ -945,34 +973,6 @@ msgstr "Noen elementer kan ikke dekrypteres."
msgid "Set the password"
msgstr "Sett passord"
msgid "Add or remove tags"
msgstr "Legg til eller fjern merkelapper"
msgid "Duplicate"
msgstr "Dupliser"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Kopier"
msgid "Switch between note and to-do type"
msgstr "Bytt mellom notat og gjøremål"
msgid "Switch to note type"
msgstr "Bytt til notatmodus"
msgid "Switch to to-do type"
msgstr "Bytt til gjøremålmodus"
msgid "Copy Markdown link"
msgstr "Kopier Markdown-link"
msgid "Delete"
msgstr "Slett"
msgid "Delete notes?"
msgstr "Slette notater?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Ingen notater her enda. Opprett et ved å klikke på \"Nytt notat\"."
@@ -1115,6 +1115,9 @@ msgstr "Fjern denne merkelappen fra alle notater?"
msgid "Remove this search from the sidebar?"
msgstr "Fjerne dette søket fra sidepanelet?"
msgid "Delete"
msgstr "Slett"
msgid "Rename"
msgstr "Gi nytt navn"
@@ -1368,11 +1371,11 @@ msgid "Automatically update the application"
msgstr "Oppdater applikasjonen automatisk"
msgid "Get pre-releases when checking for updates"
msgstr ""
msgstr "Få førutgivelse når du sjekker etter oppdateringer"
#, javascript-format
msgid "See the pre-release page for more details: %s"
msgstr ""
msgstr "Se førutgivelsessiden for flere detaljer: %s"
msgid "Synchronisation interval"
msgstr "Synkroniserinsintervall"
@@ -1471,6 +1474,25 @@ msgstr "Ignorer TLS-sertifikatfeil"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ugyldig verdi: \"%s\". Mulige verdier er: %s."
#, fuzzy
msgid "General"
msgstr "Generelle innstillinger"
#, fuzzy
msgid "Synchronisation"
msgstr "Synkroniseringsstatus"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Notatbøker"
#, fuzzy
msgid "Application"
msgstr "Lokasjon"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr "Merkelappen \"%s\" eksiterer allerede. Vennligst velg et annet navn."
@@ -1764,6 +1786,9 @@ msgstr "Konverter til notat"
msgid "Convert to todo"
msgstr "Konverter til gjøremål"
msgid "Copy Markdown link"
msgstr "Kopier Markdown-link"
msgid "Hide metadata"
msgstr "Skjul metadata"
@@ -1797,3 +1822,24 @@ msgstr "Du har enda ingen notatbok. Lag en ved å klikke på (+)-knappen."
msgid "Welcome"
msgstr "Velkommen"
#~ msgid "Add or remove tags"
#~ msgstr "Legg til eller fjern merkelapper"
#~ msgid "Duplicate"
#~ msgstr "Dupliser"
#~ msgid "%s - Copy"
#~ msgstr "%s - Kopier"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Bytt mellom notat og gjøremål"
#~ msgid "Switch to note type"
#~ msgstr "Bytt til notatmodus"
#~ msgid "Switch to to-do type"
#~ msgstr "Bytt til gjøremålmodus"
#~ msgid "Delete notes?"
#~ msgstr "Slette notater?"

View File

@@ -584,6 +584,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr ""
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Notitieboek titel:"
#, fuzzy
msgid "Note body"
msgstr "Notitieboeken"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr ""
@@ -643,6 +657,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -665,6 +682,9 @@ msgstr ""
msgid "Toggle editor layout"
msgstr ""
msgid "Focus"
msgstr ""
msgid "Tools"
msgstr "Tools"
@@ -799,14 +819,17 @@ msgid ""
"access Joplin."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Annuleer synchronisatie"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Notities en instellingen zijn opgeslaan in %s"
msgid "Browse..."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Annuleer synchronisatie"
msgid "Apply"
msgstr ""
@@ -897,6 +920,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Versleuteling is:"
#, fuzzy
msgid "Usage"
msgstr "Gebruik: %s"
msgid "Back"
msgstr "Terug"
@@ -951,36 +978,6 @@ msgstr "Sommige items kunnen niet gedecodeerd worden."
msgid "Set the password"
msgstr "Stel wachtwoord in"
msgid "Add or remove tags"
msgstr "Voeg tag toe of verwijder tag"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Kopieer"
msgid "Switch between note and to-do type"
msgstr "Wissel tussen notitie en to-do type"
#, fuzzy
msgid "Switch to note type"
msgstr "Wissel tussen notitie en to-do type"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Wissel tussen notitie en to-do type"
msgid "Copy Markdown link"
msgstr ""
msgid "Delete"
msgstr "Verwijderen"
msgid "Delete notes?"
msgstr "Notities verwijderen?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Geen notities. Maak een notitie door op \"Nieuwe notitie\" te klikken."
@@ -1128,6 +1125,9 @@ msgstr "Deze tag verwijderen van alle notities?"
msgid "Remove this search from the sidebar?"
msgstr "Dit item verwijderen van de zijbalk?"
msgid "Delete"
msgstr "Verwijderen"
msgid "Rename"
msgstr "Hernoem"
@@ -1486,6 +1486,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ongeldige optie: \"%s\". Geldige waarden zijn: %s."
#, fuzzy
msgid "General"
msgstr "Algemene opties"
#, fuzzy
msgid "Synchronisation"
msgstr "Synchronisatie status"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Notitieboeken"
#, fuzzy
msgid "Application"
msgstr "Sluit de applicatie."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1778,6 +1797,9 @@ msgstr "Converteer naar notitie"
msgid "Convert to todo"
msgstr "Converteer naar to-do"
msgid "Copy Markdown link"
msgstr ""
msgid "Hide metadata"
msgstr "Verberg metadata"
@@ -1814,6 +1836,27 @@ msgstr ""
msgid "Welcome"
msgstr "Welkom"
#~ msgid "Add or remove tags"
#~ msgstr "Voeg tag toe of verwijder tag"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Kopieer"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Wissel tussen notitie en to-do type"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Wissel tussen notitie en to-do type"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Wissel tussen notitie en to-do type"
#~ msgid "Delete notes?"
#~ msgstr "Notities verwijderen?"
#, fuzzy
#~ msgid "State: %s."
#~ msgstr "Status: \"%s\""
@@ -1865,9 +1908,6 @@ msgstr "Welkom"
#~ msgid "Cancel the current command."
#~ msgstr "Annuleer het huidige commando."
#~ msgid "Exit the application."
#~ msgstr "Sluit de applicatie."
#~ msgid "Delete the currently selected note or notebook."
#~ msgstr ""
#~ "Verwijder de geselecteerde notitie of het geselecteerde notitieboek."

View File

@@ -585,6 +585,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Bezig met exporteren van \"%s\" in het formaat \"%s\". Even geduld..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Titel van notitieboek:"
#, fuzzy
msgid "Note body"
msgstr "Notitieboeken"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Bezig met importeren van \"%s\" in het formaat \"%s\". Even geduld..."
@@ -642,6 +656,9 @@ msgstr "Vetgedrukt"
msgid "Italic"
msgstr "Cursief"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "Datum en tijd invoegen"
@@ -664,6 +681,10 @@ msgstr "Zijbalk tonen/verbergen"
msgid "Toggle editor layout"
msgstr "Bewerkindeling tonen/verbergen"
#, fuzzy
msgid "Focus"
msgstr "Inhoud focussen"
msgid "Tools"
msgstr "Hulpmiddelen"
@@ -802,13 +823,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Synchronisatieconfiguratie controleren"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Notities en instellingen worden opgeslagen in: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Synchronisatieconfiguratie controleren"
msgid "Apply"
msgstr "Toepassen"
@@ -903,6 +927,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Gebruikte versleuteling:"
#, fuzzy
msgid "Usage"
msgstr "Gebruik: %s"
msgid "Back"
msgstr "Terug"
@@ -955,36 +983,6 @@ msgstr "Sommige items kunnen niet worden ontsleuteled."
msgid "Set the password"
msgstr "Wachtwoord instellen"
msgid "Add or remove tags"
msgstr "Labels toevoegen of verwijderen"
msgid "Duplicate"
msgstr "Dupliceren"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - kopiëren"
msgid "Switch between note and to-do type"
msgstr "Schakelen tussen notitie en taak"
#, fuzzy
msgid "Switch to note type"
msgstr "Schakelen tussen notitie en taak"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Schakelen tussen notitie en taak"
msgid "Copy Markdown link"
msgstr "Markdownlink kopiëren"
msgid "Delete"
msgstr "Verwijderen"
msgid "Delete notes?"
msgstr "Notities verwijderen?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
"Er zijn hier geen notities. Creëer een notitie door de klikken op \"Nieuwe "
@@ -1131,6 +1129,9 @@ msgstr "Wil je dit label verwijderen van alle notities?"
msgid "Remove this search from the sidebar?"
msgstr "Wil je deze zoekopdracht verwijderen uit de zijbalk?"
msgid "Delete"
msgstr "Verwijderen"
msgid "Rename"
msgstr "Naam wijzigen"
@@ -1484,6 +1485,25 @@ msgstr "TLS-certificaatfouten negeren"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ongeldige optie: \"%s\". Geldige waarden zijn: %s."
#, fuzzy
msgid "General"
msgstr "Algemene opties"
#, fuzzy
msgid "Synchronisation"
msgstr "Synchronisatiestatus"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Notitieboeken"
#, fuzzy
msgid "Application"
msgstr "Sluit de applicatie af."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1780,6 +1800,9 @@ msgstr "Omzetten naar notitie"
msgid "Convert to todo"
msgstr "Omzetten naar taak"
msgid "Copy Markdown link"
msgstr "Markdownlink kopiëren"
msgid "Hide metadata"
msgstr "Metagegevens verbergen"
@@ -1816,6 +1839,29 @@ msgstr ""
msgid "Welcome"
msgstr "Welkom"
#~ msgid "Add or remove tags"
#~ msgstr "Labels toevoegen of verwijderen"
#~ msgid "Duplicate"
#~ msgstr "Dupliceren"
#~ msgid "%s - Copy"
#~ msgstr "%s - kopiëren"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Schakelen tussen notitie en taak"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Schakelen tussen notitie en taak"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Schakelen tussen notitie en taak"
#~ msgid "Delete notes?"
#~ msgstr "Notities verwijderen?"
#~ msgid "State: %s."
#~ msgstr "Status: %s."

View File

@@ -582,6 +582,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exportando para \"%s\" com o formato \"%s\". Por favor, aguarde..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Título do caderno:"
#, fuzzy
msgid "Note body"
msgstr "Cadernos"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importando de \"%s\" com o formato \"%s\". Por favor, aguarde..."
@@ -638,6 +652,9 @@ msgstr "Negrito"
msgid "Italic"
msgstr "Itálico"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "Inserir Data e Hora"
@@ -659,6 +676,10 @@ msgstr "Alternar barra lateral"
msgid "Toggle editor layout"
msgstr "Alternar layout do editor"
#, fuzzy
msgid "Focus"
msgstr "Focar no corpo"
msgid "Tools"
msgstr "Ferramentas"
@@ -798,13 +819,16 @@ msgstr ""
"Esse token de autoriza\\u00e7\\u00e3o só é necess\\u00e1rio para permitir "
"que aplicativos de terceiros acessem o Joplin."
msgid "Check synchronisation configuration"
msgstr "Verificar a configuração da sincronização"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Notas e configurações estão armazenadas em: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Verificar a configuração da sincronização"
msgid "Apply"
msgstr "Aplicar"
@@ -898,6 +922,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Encriptação está:"
#, fuzzy
msgid "Usage"
msgstr "Uso: %s"
msgid "Back"
msgstr "Voltar"
@@ -949,34 +977,6 @@ msgstr "Alguns itens não podem ser decriptados."
msgid "Set the password"
msgstr "Configurar a senha"
msgid "Add or remove tags"
msgstr "Adicionar ou remover tags"
msgid "Duplicate"
msgstr "Duplicar"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Copiar"
msgid "Switch between note and to-do type"
msgstr "Alternar entre os tipos Nota e Tarefa"
msgid "Switch to note type"
msgstr "Alternar para o tipo Nota"
msgid "Switch to to-do type"
msgstr "Alternar para o tipo Tarefa"
msgid "Copy Markdown link"
msgstr "Copiar link de Markdown"
msgid "Delete"
msgstr "Excluir"
msgid "Delete notes?"
msgstr "Excluir notas?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Não há notas aqui. Crie uma, clicando em \"Nova nota\"."
@@ -1119,6 +1119,9 @@ msgstr "Remover esta tag de todas as notas?"
msgid "Remove this search from the sidebar?"
msgstr "Remover essa pesquisa da barra lateral?"
msgid "Delete"
msgstr "Excluir"
msgid "Rename"
msgstr "Renomear"
@@ -1478,6 +1481,25 @@ msgstr "Ignorar erros de certificados TLS"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Valor da opção inválida: \"%s\". Os valores possíveis são: %s."
#, fuzzy
msgid "General"
msgstr "Opções Gerais"
#, fuzzy
msgid "Synchronisation"
msgstr "Status de sincronização"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Cadernos"
#, fuzzy
msgid "Application"
msgstr "Localização"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr "A tag \"%s\" já existe. Escolha um nome diferente."
@@ -1776,6 +1798,9 @@ msgstr "Converter para nota"
msgid "Convert to todo"
msgstr "Converter para tarefa"
msgid "Copy Markdown link"
msgstr "Copiar link de Markdown"
msgid "Hide metadata"
msgstr "Ocultar metadados"
@@ -1810,6 +1835,27 @@ msgstr "Você não possui cadernos. Crie um clicando no botão (+)."
msgid "Welcome"
msgstr "Bem-vindo"
#~ msgid "Add or remove tags"
#~ msgstr "Adicionar ou remover tags"
#~ msgid "Duplicate"
#~ msgstr "Duplicar"
#~ msgid "%s - Copy"
#~ msgstr "%s - Copiar"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Alternar entre os tipos Nota e Tarefa"
#~ msgid "Switch to note type"
#~ msgstr "Alternar para o tipo Nota"
#~ msgid "Switch to to-do type"
#~ msgstr "Alternar para o tipo Tarefa"
#~ msgid "Delete notes?"
#~ msgstr "Excluir notas?"
#~ msgid "State: %s."
#~ msgstr "Estado: \"%s\"."

View File

@@ -521,6 +521,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Se exportă către \"%s\" în format \"%s\". Vă rugăm să așteotați..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Titlul caietului de notițe:"
#, fuzzy
msgid "Note body"
msgstr "Caiete de notițe"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr ""
@@ -578,6 +592,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -600,6 +617,9 @@ msgstr ""
msgid "Toggle editor layout"
msgstr ""
msgid "Focus"
msgstr ""
msgid "Tools"
msgstr "Unelte"
@@ -732,13 +752,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr ""
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr ""
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr ""
msgid "Apply"
msgstr "Aplicați"
@@ -817,6 +840,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Criptarea este:"
#, fuzzy
msgid "Usage"
msgstr "Utilizare: %s"
msgid "Back"
msgstr "Înapoi"
@@ -867,36 +894,6 @@ msgstr "Câțiva itemi nu pot fi descriptați."
msgid "Set the password"
msgstr "Setați parola"
msgid "Add or remove tags"
msgstr "Adăugați ori eliminați etichete"
msgid "Duplicate"
msgstr "Duplicați"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Copiați"
msgid "Switch between note and to-do type"
msgstr "Schimbați între notiță și sarcină"
#, fuzzy
msgid "Switch to note type"
msgstr "Schimbați între notiță și sarcină"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Schimbați între notiță și sarcină"
msgid "Copy Markdown link"
msgstr "Copiați link-ul Markdown"
msgid "Delete"
msgstr "Ștergeți"
msgid "Delete notes?"
msgstr "Ștergeți notițele?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
@@ -1037,6 +1034,9 @@ msgstr ""
msgid "Remove this search from the sidebar?"
msgstr ""
msgid "Delete"
msgstr "Ștergeți"
msgid "Rename"
msgstr "Redenumiți"
@@ -1366,6 +1366,25 @@ msgstr "Ignoră erorile de certificat TLS"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
#, fuzzy
msgid "General"
msgstr "Opțiuni Generale"
#, fuzzy
msgid "Synchronisation"
msgstr "Statusul sincronizării"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Caiete de notițe"
#, fuzzy
msgid "Application"
msgstr "Duplicați"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1645,6 +1664,9 @@ msgstr ""
msgid "Convert to todo"
msgstr ""
msgid "Copy Markdown link"
msgstr "Copiați link-ul Markdown"
msgid "Hide metadata"
msgstr "Ascundeți metadatele"
@@ -1680,6 +1702,26 @@ msgstr ""
msgid "Welcome"
msgstr "Bine ați venit"
#~ msgid "Add or remove tags"
#~ msgstr "Adăugați ori eliminați etichete"
#~ msgid "%s - Copy"
#~ msgstr "%s - Copiați"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Schimbați între notiță și sarcină"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Schimbați între notiță și sarcină"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Schimbați între notiță și sarcină"
#~ msgid "Delete notes?"
#~ msgstr "Ștergeți notițele?"
#~ msgid "State: %s."
#~ msgstr "Statut: %s."

View File

@@ -583,6 +583,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Экспорт в «%s» в формате «%s». Пожалуйста, ожидайте..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Название блокнота:"
#, fuzzy
msgid "Note body"
msgstr "Блокноты"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Импорт из «%s» в формате «%s». Пожалуйста, ожидайте..."
@@ -640,6 +654,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -662,6 +679,10 @@ msgstr "Переключить панель"
msgid "Toggle editor layout"
msgstr "Переключить вид редактора"
#, fuzzy
msgid "Focus"
msgstr "Фокус на содержимом"
msgid "Tools"
msgstr "Инструменты"
@@ -794,13 +815,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Проверить настройки синхронизации"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Заметки и настройки сохранены в: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Проверить настройки синхронизации"
msgid "Apply"
msgstr "Применить"
@@ -894,6 +918,10 @@ msgstr "Статус"
msgid "Encryption is:"
msgstr "Шифрование:"
#, fuzzy
msgid "Usage"
msgstr "Использование: %s"
msgid "Back"
msgstr "Назад"
@@ -946,37 +974,6 @@ msgstr "Некоторые элементы не могут быть расши
msgid "Set the password"
msgstr "Установить пароль"
msgid "Add or remove tags"
msgstr "Добавить или удалить теги"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Копировать"
msgid "Switch between note and to-do type"
msgstr "Переключить тип между заметкой и задачей"
#, fuzzy
msgid "Switch to note type"
msgstr "Переключить тип между заметкой и задачей"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Переключить тип между заметкой и задачей"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Delete"
msgstr "Удалить"
msgid "Delete notes?"
msgstr "Удалить заметки?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Здесь нет заметок. Создайте новую нажатием на «Новая заметка»."
@@ -1121,6 +1118,9 @@ msgstr "Убрать этот тег со всех заметок?"
msgid "Remove this search from the sidebar?"
msgstr "Убрать этот запрос с боковой панели?"
msgid "Delete"
msgstr "Удалить"
msgid "Rename"
msgstr "Переименовать"
@@ -1474,6 +1474,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Неверное значение параметра: «%s». Доступные значения: %s."
#, fuzzy
msgid "General"
msgstr "Основные настройки"
#, fuzzy
msgid "Synchronisation"
msgstr "Статус синхронизации"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Блокноты"
#, fuzzy
msgid "Application"
msgstr "Выйти из приложения."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1765,6 +1784,10 @@ msgstr "Преобразовать в заметку"
msgid "Convert to todo"
msgstr "Преобразовать в задачу"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Markdown"
msgid "Hide metadata"
msgstr "Скрыть метаданные"
@@ -1799,6 +1822,27 @@ msgstr "У вас сейчас нет блокнота. Создайте его
msgid "Welcome"
msgstr "Добро пожаловать"
#~ msgid "Add or remove tags"
#~ msgstr "Добавить или удалить теги"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Копировать"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Переключить тип между заметкой и задачей"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Переключить тип между заметкой и задачей"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Переключить тип между заметкой и задачей"
#~ msgid "Delete notes?"
#~ msgstr "Удалить заметки?"
#, fuzzy
#~ msgid "State: %s."
#~ msgstr "Статус: «%s»."
@@ -1849,9 +1893,6 @@ msgstr "Добро пожаловать"
#~ msgid "Cancel the current command."
#~ msgstr "Отменить текущую команду."
#~ msgid "Exit the application."
#~ msgstr "Выйти из приложения."
#~ msgid "Delete the currently selected note or notebook."
#~ msgstr "Удалить текущую выбранную заметку или блокнот."

View File

@@ -582,6 +582,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Izvažam v \"%s\" kot \"%s\" format. Prosim počakajte..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Naslov beležnice:"
#, fuzzy
msgid "Note body"
msgstr "Beležnice"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Uvažam v \"%s\" kot \"%s\" format. Prosim počakajte..."
@@ -639,6 +653,9 @@ msgstr ""
msgid "Italic"
msgstr ""
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr ""
@@ -661,6 +678,10 @@ msgstr ""
msgid "Toggle editor layout"
msgstr "Spremeni izgled urejevalnika"
#, fuzzy
msgid "Focus"
msgstr "Fokusiraj vsebino"
msgid "Tools"
msgstr "Orodja"
@@ -793,13 +814,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Preveri nastavitve sinhronizacije"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Zabeležke in nastavitve so shranjene v: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Preveri nastavitve sinhronizacije"
msgid "Apply"
msgstr ""
@@ -893,6 +917,10 @@ msgstr "Status"
msgid "Encryption is:"
msgstr "Enkripcija je:"
#, fuzzy
msgid "Usage"
msgstr "Uporaba: %s"
msgid "Back"
msgstr "Nazaj"
@@ -946,37 +974,6 @@ msgstr "Nekateri predmeti ne morejo biti dekriptirani."
msgid "Set the password"
msgstr "Nastavi geslo"
msgid "Add or remove tags"
msgstr "Dodaj ali odstrani oznake"
msgid "Duplicate"
msgstr ""
#, fuzzy, javascript-format
msgid "%s - Copy"
msgstr "Kopiraj"
msgid "Switch between note and to-do type"
msgstr "Menjaj med zabeležko in seznamom opravil"
#, fuzzy
msgid "Switch to note type"
msgstr "Menjaj med zabeležko in seznamom opravil"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Menjaj med zabeležko in seznamom opravil"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Sistem označevanja"
msgid "Delete"
msgstr "Izbriši"
msgid "Delete notes?"
msgstr "Izbriši zabeležke?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
"Trenutno ni tukaj nobene zabeležke. Ustvarite jo z klikom na \"Nova zabeležka"
@@ -1125,6 +1122,9 @@ msgstr "Odstranite to oznako iz vseh zabeležk?"
msgid "Remove this search from the sidebar?"
msgstr "Odstranite ta iskalni niz iz stranske vrstice?"
msgid "Delete"
msgstr "Izbriši"
msgid "Rename"
msgstr "Preimenuj"
@@ -1478,6 +1478,25 @@ msgstr ""
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Neveljavna vrednost: \"%s\". Možne vrednosti so : %s."
#, fuzzy
msgid "General"
msgstr "Splošne možnosti"
#, fuzzy
msgid "Synchronisation"
msgstr "Status sinhronizacije"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Beležnice"
#, fuzzy
msgid "Application"
msgstr "Izhod iz aplikacije."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1767,6 +1786,10 @@ msgstr "Pretvori v zabeležko"
msgid "Convert to todo"
msgstr "Pretvori v za narediti"
#, fuzzy
msgid "Copy Markdown link"
msgstr "Sistem označevanja"
msgid "Hide metadata"
msgstr "Skrij meta podatke"
@@ -1801,6 +1824,27 @@ msgstr "Trenutno nimate nobene beležnice. Ustvarite jo s klikom na (+) gumb."
msgid "Welcome"
msgstr "Dobrodošli"
#~ msgid "Add or remove tags"
#~ msgstr "Dodaj ali odstrani oznake"
#, fuzzy
#~ msgid "%s - Copy"
#~ msgstr "Kopiraj"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Menjaj med zabeležko in seznamom opravil"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Menjaj med zabeležko in seznamom opravil"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Menjaj med zabeležko in seznamom opravil"
#~ msgid "Delete notes?"
#~ msgstr "Izbriši zabeležke?"
#~ msgid "State: %s."
#~ msgstr "Stanje: %s."

View File

@@ -589,6 +589,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Exportera till \"%s\" som \"%s\" format. Vänta..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "Titel på anteckningsbok:"
#, fuzzy
msgid "Note body"
msgstr "Anteckningsböcker"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "Importerar från \"%s\" som \"%s\" format. Vänta..."
@@ -646,6 +660,9 @@ msgstr "Fet"
msgid "Italic"
msgstr "Kursiv"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "Infoga datumtid"
@@ -668,6 +685,10 @@ msgstr "Växla sidofältet"
msgid "Toggle editor layout"
msgstr "Växla redigeringslayout"
#, fuzzy
msgid "Focus"
msgstr "Fokus på huvuddel"
msgid "Tools"
msgstr "Verktyg"
@@ -805,13 +826,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Kontrollera synkroniseringskonfigurationen"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Anteckningar och inställningar lagras i: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Kontrollera synkroniseringskonfigurationen"
msgid "Apply"
msgstr "Tillämpa"
@@ -906,6 +930,10 @@ msgstr "Tillstånd"
msgid "Encryption is:"
msgstr "Kryptering är:"
#, fuzzy
msgid "Usage"
msgstr "Användning: %s"
msgid "Back"
msgstr "Tillbaka"
@@ -958,36 +986,6 @@ msgstr "Några objekt kan inte dekrypteras."
msgid "Set the password"
msgstr "Ställ in lösenord"
msgid "Add or remove tags"
msgstr "Lägg till eller ta bort taggar"
msgid "Duplicate"
msgstr "Duplikat"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - Kopiera"
msgid "Switch between note and to-do type"
msgstr "Växla mellan antecknings- och att-göra-typ"
#, fuzzy
msgid "Switch to note type"
msgstr "Växla mellan antecknings- och att-göra-typ"
#, fuzzy
msgid "Switch to to-do type"
msgstr "Växla mellan antecknings- och att-göra-typ"
msgid "Copy Markdown link"
msgstr "Kopiera Markdown-länk"
msgid "Delete"
msgstr "Ta bort"
msgid "Delete notes?"
msgstr "Ta bort anteckningar?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "Inga anteckningar här. Skapa en genom att klicka på \"Ny anteckning\"."
@@ -1132,6 +1130,9 @@ msgstr "Ta bort den här taggen från alla anteckningar?"
msgid "Remove this search from the sidebar?"
msgstr "Ta bort den här sökningen från sidofältet?"
msgid "Delete"
msgstr "Ta bort"
msgid "Rename"
msgstr "Byt namn"
@@ -1485,6 +1486,25 @@ msgstr "Ignorera TLS-certifikatfel"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ogiltigt inställningsvärde: \"%s\". Möjliga värden är: %s."
#, fuzzy
msgid "General"
msgstr "Allmänna inställningar"
#, fuzzy
msgid "Synchronisation"
msgstr "Synkroniseringstillstånd"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "Anteckningsböcker"
#, fuzzy
msgid "Application"
msgstr "Avslutar programmet."
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1783,6 +1803,9 @@ msgstr "Konvertera till anteckning"
msgid "Convert to todo"
msgstr "Konvertera till att-göra"
msgid "Copy Markdown link"
msgstr "Kopiera Markdown-länk"
msgid "Hide metadata"
msgstr "Dölj metadata"
@@ -1820,6 +1843,29 @@ msgstr ""
msgid "Welcome"
msgstr "Välkommen"
#~ msgid "Add or remove tags"
#~ msgstr "Lägg till eller ta bort taggar"
#~ msgid "Duplicate"
#~ msgstr "Duplikat"
#~ msgid "%s - Copy"
#~ msgstr "%s - Kopiera"
#~ msgid "Switch between note and to-do type"
#~ msgstr "Växla mellan antecknings- och att-göra-typ"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "Växla mellan antecknings- och att-göra-typ"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "Växla mellan antecknings- och att-göra-typ"
#~ msgid "Delete notes?"
#~ msgstr "Ta bort anteckningar?"
#~ msgid "State: %s."
#~ msgstr "Tillstånd: %s."

File diff suppressed because it is too large Load Diff

View File

@@ -548,6 +548,20 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "匯出到 \"%s\" 為 \"%s\" 格式。請稍候..."
msgid "Sidebar"
msgstr ""
msgid "Note list"
msgstr ""
#, fuzzy
msgid "Note title"
msgstr "記事本標題:"
#, fuzzy
msgid "Note body"
msgstr "記事本"
#, javascript-format
msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
msgstr "從 \"%s\" 匯入為 \"%s\" 格式。請稍候..."
@@ -605,6 +619,9 @@ msgstr "粗體"
msgid "Italic"
msgstr "斜體"
msgid "Link"
msgstr ""
msgid "Insert Date Time"
msgstr "插入日期時間"
@@ -627,6 +644,10 @@ msgstr "顯示 / 隱藏側邊欄"
msgid "Toggle editor layout"
msgstr "切換編輯器佈局"
#, fuzzy
msgid "Focus"
msgstr "游標置於內文"
msgid "Tools"
msgstr "工具"
@@ -761,13 +782,16 @@ msgid ""
"access Joplin."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "檢測同步設置"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "所有記事和設置均儲存於: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "檢測同步設置"
msgid "Apply"
msgstr "套用"
@@ -855,6 +879,10 @@ msgstr "狀態"
msgid "Encryption is:"
msgstr "加密:"
#, fuzzy
msgid "Usage"
msgstr "使用資訊: %s"
msgid "Back"
msgstr "返回"
@@ -905,36 +933,6 @@ msgstr "有些項目不能解密。"
msgid "Set the password"
msgstr "設置密碼"
msgid "Add or remove tags"
msgstr "新增或移除標籤"
msgid "Duplicate"
msgstr "新增複本"
#, javascript-format
msgid "%s - Copy"
msgstr "%s - 複本"
msgid "Switch between note and to-do type"
msgstr "切換到記事 / 待辦事項"
#, fuzzy
msgid "Switch to note type"
msgstr "切換到記事 / 待辦事項"
#, fuzzy
msgid "Switch to to-do type"
msgstr "切換到記事 / 待辦事項"
msgid "Copy Markdown link"
msgstr "複製 Markdown 連結"
msgid "Delete"
msgstr "刪除"
msgid "Delete notes?"
msgstr "刪除此記事?"
msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr "當前沒有任何筆記。通過按一下 \"新增筆記\" 去建立。"
@@ -1075,6 +1073,9 @@ msgstr "是否從所有記事中刪除此標籤?"
msgid "Remove this search from the sidebar?"
msgstr "是否從側邊欄中刪除此搜索?"
msgid "Delete"
msgstr "刪除"
msgid "Rename"
msgstr "重新命名"
@@ -1418,6 +1419,25 @@ msgstr "忽略 TLS 證書錯誤"
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "不正確選項值: \"%s\"。可能的值為: %s。"
#, fuzzy
msgid "General"
msgstr "一般選項"
#, fuzzy
msgid "Synchronisation"
msgstr "顯示同步狀態"
msgid "Appearance"
msgstr ""
#, fuzzy
msgid "Note"
msgstr "記事本"
#, fuzzy
msgid "Application"
msgstr "離開本程式。"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr ""
@@ -1704,6 +1724,9 @@ msgstr "轉換為記事"
msgid "Convert to todo"
msgstr "轉換為待辦事項"
msgid "Copy Markdown link"
msgstr "複製 Markdown 連結"
msgid "Hide metadata"
msgstr "隱藏後設資料 (metadata)"
@@ -1736,6 +1759,29 @@ msgstr "您當前沒有任何筆記本。通過按一下 (+) 鍵去建立一本
msgid "Welcome"
msgstr "歡迎"
#~ msgid "Add or remove tags"
#~ msgstr "新增或移除標籤"
#~ msgid "Duplicate"
#~ msgstr "新增複本"
#~ msgid "%s - Copy"
#~ msgstr "%s - 複本"
#~ msgid "Switch between note and to-do type"
#~ msgstr "切換到記事 / 待辦事項"
#, fuzzy
#~ msgid "Switch to note type"
#~ msgstr "切換到記事 / 待辦事項"
#, fuzzy
#~ msgid "Switch to to-do type"
#~ msgstr "切換到記事 / 待辦事項"
#~ msgid "Delete notes?"
#~ msgstr "刪除此記事?"
#~ msgid "State: %s."
#~ msgstr "狀態: %s。"

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "1.0.120",
"version": "1.0.122",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -29,16 +29,16 @@
},
"dependencies": {
"acorn": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.2.tgz",
"integrity": "sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg=="
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.6.tgz",
"integrity": "sha512-5M3G/A4uBSMIlfJ+h9W125vJvPFH/zirISsW5qfxF5YzEvXJCtolLoQvM5yZft0DvMcUrPGKPOlgEu55I6iUtA=="
}
}
},
"acorn-walk": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.0.1.tgz",
"integrity": "sha512-PqVQ8c6a3kyqdsUZlC7nljp3FFuxipBRHKu+7C1h8QygBFlzTaDX5HD383jej3Peed+1aDG8HwkfB1Z1HMNPkw=="
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
"integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw=="
},
"ajv": {
"version": "5.5.2",
@@ -488,12 +488,12 @@
"integrity": "sha1-GK6XmmoMqZSwYlhTkW0mYruuCxo="
},
"data-urls": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.1.tgz",
"integrity": "sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
"integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
"requires": {
"abab": "^2.0.0",
"whatwg-mimetype": "^2.1.0",
"whatwg-mimetype": "^2.2.0",
"whatwg-url": "^7.0.0"
},
"dependencies": {
@@ -1427,9 +1427,9 @@
"dev": true
},
"joplin-turndown": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.9.tgz",
"integrity": "sha512-8MOxX4t5Ai22muHhXPMGNoKc/AB7gSo0eUvNh6dyd6b3vcSiMIRZE8UHpMjS9ruJQ+8e+8TtJXc0nfbexeHwrA==",
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.11.tgz",
"integrity": "sha512-2oiwWX0nKYi1NVcaprSsrXQkYdGoRtPWFmnXdWQnQW44jlgjFV38B4VrgliwX5ZMq7cbx6A9IBwfXcBL2YV2NA==",
"requires": {
"jsdom": "^11.9.0"
}
@@ -1488,6 +1488,17 @@
"xml-name-validator": "^3.0.0"
},
"dependencies": {
"ajv": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz",
"integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==",
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"aws4": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
@@ -1506,46 +1517,46 @@
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
},
"form-data": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "1.0.6",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
},
"dependencies": {
"combined-stream": {
"version": "1.0.6",
"resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"requires": {
"delayed-stream": "~1.0.0"
}
}
}
},
"har-validator": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
"integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"requires": {
"ajv": "^5.3.0",
"ajv": "^6.5.5",
"har-schema": "^2.0.0"
}
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"mime-db": {
"version": "1.36.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz",
"integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw=="
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
},
"mime-types": {
"version": "2.1.20",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz",
"integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==",
"version": "2.1.21",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
"requires": {
"mime-db": "~1.36.0"
"mime-db": "~1.37.0"
}
},
"oauth-sign": {
@@ -2793,7 +2804,7 @@
"requires": {
"chalk": "^2.1.0",
"emphasize": "^1.5.0",
"node-emoji": "git+https://github.com/laurent22/node-emoji.git#9fa01eac463e94dde1316ef8c53089eeef4973b5",
"node-emoji": "git+https://github.com/laurent22/node-emoji.git",
"slice-ansi": "^1.0.0",
"string-width": "^2.1.1",
"terminal-kit": "^1.13.11",
@@ -2915,6 +2926,21 @@
"resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
"integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
},
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"requires": {
"punycode": "^2.1.0"
},
"dependencies": {
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
}
}
},
"url-parse": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.2.0.tgz",
@@ -2963,17 +2989,17 @@
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
},
"whatwg-encoding": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz",
"integrity": "sha512-vM9KWN6MP2mIHZ86ytcyIv7e8Cj3KTfO2nd2c8PFDqcI4bxFmQp83ibq4wadq7rL9l9sZV6o9B0LTt8ygGAAXg==",
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
"integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
"requires": {
"iconv-lite": "0.4.23"
"iconv-lite": "0.4.24"
},
"dependencies": {
"iconv-lite": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
@@ -2981,9 +3007,9 @@
}
},
"whatwg-mimetype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz",
"integrity": "sha512-5YSO1nMd5D1hY3WzAQV3PzZL83W3YeyR1yW9PcH26Weh1t+Vzh9B6XkDh7aXm83HBZ4nSMvkjvN2H2ySWIvBgw=="
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
"version": "6.5.0",

View File

@@ -20,7 +20,7 @@
],
"owner": "Laurent Cozic"
},
"version": "1.0.120",
"version": "1.0.122",
"bin": {
"joplin": "./main.js"
},
@@ -41,7 +41,7 @@
"html-minifier": "^3.5.15",
"image-data-uri": "^2.0.0",
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.9",
"joplin-turndown": "^4.0.11",
"joplin-turndown-plugin-gfm": "^1.0.7",
"jssha": "^2.3.0",
"levenshtein": "^1.0.5",

View File

@@ -22,20 +22,22 @@ trap finish EXIT
cd "$ROOT_DIR"
npm test tests-build/ArrayUtils.js
npm test tests-build/encryption.js
npm test tests-build/EnexToMd.js
npm test tests-build/HtmlToMd.js
npm test tests-build/markdownUtils.js
npm test tests-build/models_BaseItem.js
npm test tests-build/models_Folder.js
npm test tests-build/models_Note.js
npm test tests-build/models_Tag.js
npm test tests-build/models_ItemChange.js
npm test tests-build/models_Note.js
npm test tests-build/models_Resource.js
npm test tests-build/models_Setting.js
npm test tests-build/models_Tag.js
npm test tests-build/pathUtils.js
npm test tests-build/StringUtils.js
npm test tests-build/services_InteropService.js
npm test tests-build/services_ResourceService.js
npm test tests-build/urlUtils.js
npm test tests-build/encryption.js
npm test tests-build/services_rest_Api.js
npm test tests-build/synchronizer.js
npm test tests-build/services_SearchEngine.js
npm test tests-build/StringUtils.js
npm test tests-build/synchronizer.js
npm test tests-build/urlUtils.js

View File

@@ -37,7 +37,7 @@ describe('HtmlToMd', function() {
const htmlPath = basePath + '/' + htmlFilename;
const mdPath = basePath + '/' + filename(htmlFilename) + '.md';
// if (htmlFilename !== 'anchor_with_url_with_spaces.html') continue;
// if (htmlFilename !== 'picture.html') continue;
const html = await shim.fsDriver().readFile(htmlPath);
let expectedMd = await shim.fsDriver().readFile(mdPath);

View File

@@ -20,9 +20,9 @@ describe('StringUtils', function() {
[['test'], 'test', 'a', 'b', 'atestb'],
[['test'], 'Test', 'a', 'b', 'aTestb'],
[['te[]st'], 'Te[]st', 'a', 'b', 'aTe[]stb'],
[['test1', 'test2'], 'bla test1 blabla test1 bla test2 not this one - test22', 'a', 'b', 'bla atest1b blabla atest1b bla atest2b not this one - test22'],
// [['test1', 'test2'], 'bla test1 blabla test1 bla test2 not this one - test22', 'a', 'b', 'bla atest1b blabla atest1b bla atest2b not this one - test22'],
[['test1', 'test2'], 'bla test1 test1 bla test2', '<span class="highlighted-keyword">', '</span>', 'bla <span class="highlighted-keyword">test1</span> <span class="highlighted-keyword">test1</span> bla <span class="highlighted-keyword">test2</span>'],
[[{ type:'regex', value:'test.*?'}], 'bla test1 test1 bla test2 test tttest', 'a', 'b', 'bla atest1b atest1b bla atest2b atestb tttest'],
// [[{ type:'regex', value:'test.*?'}], 'bla test1 test1 bla test2 test tttest', 'a', 'b', 'bla atest1b atest1b bla atest2b atestb tttest'],
];
for (let i = 0; i < testCases.length; i++) {
@@ -36,7 +36,7 @@ describe('StringUtils', function() {
const actual = StringUtils.surroundKeywords(keywords, input, prefix, suffix);
expect(actual).toBe(expected);
expect(actual).toBe(expected, 'Test case ' + i);
}
done();

View File

@@ -0,0 +1,47 @@
<figure itemprop="associatedMedia image" itemscope="" itemtype="http://schema.org/ImageObject" data-component="image" data-media-id="75583fcfe2eb74f1e89ea320355ff4156f4ade7b" id="img-1">
<meta itemprop="representativeOfPage" content="true">
<meta itemprop="url" content="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=700&amp;quality=85&amp;auto=format&amp;fit=max&amp;s=2a6a7ba9738c6a6a79eab39ba46c34cd">
<meta itemprop="width" content="3904">
<meta itemprop="height" content="2342">
<a href="#img-1" data-link-name="Launch Article Lightbox" data-is-ajax="">
<div>
<picture>
<!--[if IE 9]><video style="display: none;"><![endif]-->
<source media="(min-width: 980px) and (-webkit-min-device-pixel-ratio: 1.25), (min-width: 980px) and (min-resolution: 120dpi)" sizes="620px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=620&amp;quality=45&amp;auto=format&amp;fit=max&amp;dpr=2&amp;s=bacff59339e5ba117f957c24218ef76b 1240w">
<source media="(min-width: 980px)" sizes="620px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=620&amp;quality=85&amp;auto=format&amp;fit=max&amp;s=f1427ce6689688d3d6e0087fe9cb5c18 620w">
<source media="(min-width: 740px) and (-webkit-min-device-pixel-ratio: 1.25), (min-width: 740px) and (min-resolution: 120dpi)" sizes="700px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=700&amp;quality=45&amp;auto=format&amp;fit=max&amp;dpr=2&amp;s=70accd3c6e7d2c36f5ccc7321eab097e 1400w">
<source media="(min-width: 740px)" sizes="700px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=700&amp;quality=85&amp;auto=format&amp;fit=max&amp;s=2a6a7ba9738c6a6a79eab39ba46c34cd 700w">
<source media="(min-width: 660px) and (-webkit-min-device-pixel-ratio: 1.25), (min-width: 660px) and (min-resolution: 120dpi)" sizes="620px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=620&amp;quality=45&amp;auto=format&amp;fit=max&amp;dpr=2&amp;s=bacff59339e5ba117f957c24218ef76b 1240w">
<source media="(min-width: 660px)" sizes="620px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=620&amp;quality=85&amp;auto=format&amp;fit=max&amp;s=f1427ce6689688d3d6e0087fe9cb5c18 620w">
<source media="(min-width: 480px) and (-webkit-min-device-pixel-ratio: 1.25), (min-width: 480px) and (min-resolution: 120dpi)" sizes="645px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=645&amp;quality=45&amp;auto=format&amp;fit=max&amp;dpr=2&amp;s=6751fcff1b880acc45ed5aab6511a2ca 1290w">
<source media="(min-width: 480px)" sizes="645px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=645&amp;quality=85&amp;auto=format&amp;fit=max&amp;s=d18702564383ce5d613d22b96ec6d726 645w">
<source media="(min-width: 0px) and (-webkit-min-device-pixel-ratio: 1.25), (min-width: 0px) and (min-resolution: 120dpi)" sizes="465px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=465&amp;quality=45&amp;auto=format&amp;fit=max&amp;dpr=2&amp;s=a7b87fb26b9813d197f3c236a5282ca4 930w">
<source media="(min-width: 0px)" sizes="465px" srcset="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=465&amp;quality=85&amp;auto=format&amp;fit=max&amp;s=821ae9e950ae92371b40a35e98a31116 465w">
<!--[if IE 9]></video><![endif]-->
<img itemprop="contentUrl" alt="A blood moon" src="https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=300&amp;quality=85&amp;auto=format&amp;fit=max&amp;s=1e9b643d2c109a1e271f50046eac1324">
</picture>
</div>
<span>
<svg width="22" height="22" viewBox="0 0 22 22">
<path d="M3.4 20.2L9 14.5 7.5 13l-5.7 5.6L1 14H0v7.5l.5.5H8v-1l-4.6-.8M18.7 1.9L13 7.6 14.4 9l5.7-5.7.5 4.7h1.2V.6l-.5-.5H14v1.2l4.7.6"></path>
</svg>
</span>
</a>
<label for="show-caption">
<span>
<svg width="6" height="14" viewBox="0 0 6 14">
<path d="M4.6 12l-.4 1.4c-.7.2-1.9.6-3 .6-.7 0-1.2-.2-1.2-.9 0-.2 0-.3.1-.5l2-6.7H.7l.4-1.5 4.2-.6h.2L3 12h1.6zm-.3-9.2c-.9 0-1.4-.5-1.4-1.3C2.9.5 3.7 0 4.6 0 5.4 0 6 .5 6 1.3c0 1-.8 1.5-1.7 1.5z"></path>
</svg>
</span>
</label>
<figcaption itemprop="description">
<span>
<svg width="11" height="10" viewBox="0 0 11 10">
<path fill-rule="evenodd" d="M5.5 0L11 10H0z"></path>
</svg>
</span>
A blood moon last occurred in July 2018, though clouds largely obscured the celestial phenomenon in the UK.
Photograph: JM F Almeida/Getty Images
</figcaption>
</figure>

View File

@@ -0,0 +1,3 @@
[![A blood moon](https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=300&quality=85&auto=format&fit=max&s=1e9b643d2c109a1e271f50046eac1324)](#img-1)
A blood moon last occurred in July 2018, though clouds largely obscured the celestial phenomenon in the UK. Photograph: JM F Almeida/Getty Images

View File

@@ -1,6 +1,6 @@
require('app-module-path').addPath(__dirname);
const { friendlySafeFilename } = require('lib/path-utils.js');
const { extractExecutablePath, quotePath, unquotePath, friendlySafeFilename } = require('lib/path-utils.js');
const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
process.on('unhandledRejection', (reason, p) => {
@@ -36,4 +36,41 @@ describe('pathUtils', function() {
done();
});
it('should quote and unquote paths', async (done) => {
const testCases = [
['', ''],
['/my/path', '/my/path'],
['/my/path with spaces', '"/my/path with spaces"'],
['/my/weird"path', '"/my/weird\\"path"'],
['c:\\Windows\\test.dll', 'c:\\Windows\\test.dll'],
['c:\\Windows\\test test.dll', '"c:\\Windows\\test test.dll"'],
];
for (let i = 0; i < testCases.length; i++) {
const t = testCases[i];
expect(quotePath(t[0])).toBe(t[1]);
expect(unquotePath(quotePath(t[0]))).toBe(t[0]);
}
done();
});
it('should extract executable path from command', async (done) => {
const testCases = [
['', ''],
['/my/cmd -some -args', '/my/cmd'],
['"/my/cmd" -some -args', '"/my/cmd"'],
['"/my/cmd"', '"/my/cmd"'],
['"/my/cmd and space" -some -flags', '"/my/cmd and space"'],
['"" -some -flags', '""'],
];
for (let i = 0; i < testCases.length; i++) {
const t = testCases[i];
expect(extractExecutablePath(t[0])).toBe(t[1]);
}
done();
});
});

View File

@@ -221,37 +221,63 @@ describe('services_SearchEngine', function() {
const expected = t[1];
const actual = engine.parseQuery(input);
expect(JSON.stringify(actual.terms._)).toBe(JSON.stringify(expected._));
expect(JSON.stringify(actual.terms.title)).toBe(JSON.stringify(expected.title));
expect(JSON.stringify(actual.terms.body)).toBe(JSON.stringify(expected.body));
const _Values = actual.terms._ ? actual.terms._.map(v => v.value) : undefined;
const titleValues = actual.terms.title ? actual.terms.title.map(v => v.value) : undefined;
const bodyValues = actual.terms.body ? actual.terms.body.map(v => v.value) : undefined;
expect(JSON.stringify(_Values)).toBe(JSON.stringify(expected._), 'Test case (_) ' + i);
expect(JSON.stringify(titleValues)).toBe(JSON.stringify(expected.title), 'Test case (title) ' + i);
expect(JSON.stringify(bodyValues)).toBe(JSON.stringify(expected.body), 'Test case (body) ' + i);
}
}));
it('should parse query strings with wildcards', asyncTest(async () => {
// it('should parse query strings with wildcards', asyncTest(async () => {
// let rows;
// const testCases = [
// ['do*', ['do', 'dog', 'domino'], [] ],
// // "*" is a wildcard only when used at the end (to search for documents with the specified prefix)
// // If it's at the beginning, it's ignored, if it's in the middle, it's treated as a litteral "*".
// ['*an*', ['an', 'anneau'], ['piano', 'plan'] ],
// ['no*no', ['no*no'], ['nonono'] ],
// ];
// for (let i = 0; i < testCases.length; i++) {
// const t = testCases[i];
// const input = t[0];
// const shouldMatch = t[1];
// const shouldNotMatch = t[2];
// const regex = new RegExp(engine.parseQuery(input).terms._[0].value, 'gmi');
// for (let j = 0; j < shouldMatch.length; j++) {
// const r = shouldMatch[j].match(regex);
// expect(!!r).toBe(true, '"' + input + '" should match "' + shouldMatch[j] + '"');
// }
// }
// expect(engine.parseQuery('*').termCount).toBe(0);
// }));
it('should handle queries with special characters', asyncTest(async () => {
let rows;
const testCases = [
['do*', ['do', 'dog', 'domino'], [] ],
// "*" is a wildcard only when used at the end (to searhc for documents with the specified prefix)
// If it's at the beginning, it's ignored, if it's in the middle, it's treated as a litteral "*".
['*an*', ['an', 'anneau'], ['piano', 'plan'] ],
['no*no', ['no*no'], ['nonono'] ],
['did-not-match', 'did-not-match'],
['does match', 'does match'],
];
for (let i = 0; i < testCases.length; i++) {
const t = testCases[i];
const input = t[0];
const shouldMatch = t[1];
const shouldNotMatch = t[2];
const regex = new RegExp(engine.parseQuery(input).terms._[0].value, 'gmi');
const content = t[0];
const query = t[1];
for (let j = 0; j < shouldMatch.length; j++) {
const r = shouldMatch[j].match(regex);
expect(!!r).toBe(true, '"' + input + '" should match "' + shouldMatch[j] + '"');
}
const n = await Note.save({ title: content });
await engine.syncTables();
rows = await engine.search(query);
expect(rows.length).toBe(1);
await Note.delete(n.id);
}
expect(engine.parseQuery('*').termCount).toBe(0);
}));
});

View File

@@ -170,6 +170,17 @@ describe('services_rest_Api', function() {
done();
});
it('should create folders with supplied ID', async (done) => {
const response = await api.route('POST', 'folders', null, JSON.stringify({
id: '12345678123456781234567812345678',
title: 'from api',
}));
expect(response.id).toBe('12345678123456781234567812345678');
done();
});
it('should create notes with images', async (done) => {
let response = null;
const f = await Folder.save({ title: "mon carnet" });

View File

@@ -15,6 +15,7 @@ const MasterKey = require('lib/models/MasterKey');
const BaseItem = require('lib/models/BaseItem.js');
const BaseModel = require('lib/BaseModel.js');
const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
const WelcomeUtils = require('lib/WelcomeUtils');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
@@ -1099,4 +1100,44 @@ describe('Synchronizer', function() {
expect(note2.title).toBe("un UPDATE");
}));
it("should sync Welcome notebook and not duplicate it", asyncTest(async () => {
// Create the Welcome items on two separate clients and verify
// that they appear only once (due to having hard-coded IDs), that they are not duplicated.
Setting.setConstant('env', 'prod');
await WelcomeUtils.createWelcomeItems();
await synchronizer().start();
await switchClient(2);
await WelcomeUtils.createWelcomeItems();
const beforeFolderCount = (await Folder.all()).length;
const beforeNoteCount = (await Note.all()).length;
expect(beforeFolderCount >= 1).toBe(true);
expect(beforeNoteCount > 1).toBe(true);
await synchronizer().start();
const afterFolderCount = (await Folder.all()).length;
const afterNoteCount = (await Note.all()).length;
expect(afterFolderCount).toBe(beforeFolderCount);
expect(afterNoteCount).toBe(beforeNoteCount);
// Changes to the Welcome items should be synced to all clients
const f1 = (await Folder.all())[0];
await Folder.save({ id: f1.id, title: 'Welcome MOD' });
await synchronizer().start();
await switchClient(1);
await synchronizer().start();
const f1_1 = (await Folder.all())[0];
expect(f1_1.title).toBe('Welcome MOD');
}));
});

View File

@@ -30,6 +30,21 @@
return output;
}
function getImageSizes(element) {
const images = element.getElementsByTagName('img');
const output = {};
for (let i = 0; i < images.length; i++) {
const img = images[i];
output[img.src] = {
width: img.width,
height: img.height,
naturalWidth: img.naturalWidth,
naturalHeight: img.naturalHeight,
};
}
return output;
}
// Cleans up element by removing all its invisible children (which we don't want to render as Markdown)
function cleanUpElement(element) {
const childNodes = element.childNodes;
@@ -74,7 +89,7 @@
async function prepareCommandResponse(command) {
console.info('Got command: ' + command.name);
const clippedContentResponse = (title, html) => {
const clippedContentResponse = (title, html, imageSizes) => {
return {
name: 'clippedContent',
title: title,
@@ -83,6 +98,7 @@
url: location.origin + location.pathname + location.search,
parent_id: command.parent_id,
tags: command.tags || '',
image_sizes: imageSizes,
};
}
@@ -99,20 +115,20 @@
response.warning = 'Could not retrieve simplified version of page - full page has been saved instead.';
return response;
}
return clippedContentResponse(article.title, article.body);
return clippedContentResponse(article.title, article.body, getImageSizes(document));
} else if (command.name === "completePageHtml") {
const cleanDocument = document.body.cloneNode(true);
cleanUpElement(cleanDocument);
return clippedContentResponse(pageTitle(), cleanDocument.innerHTML);
return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, getImageSizes(document));
} else if (command.name === "selectedHtml") {
const range = window.getSelection().getRangeAt(0);
const container = document.createElement('div');
container.appendChild(range.cloneContents());
return clippedContentResponse(pageTitle(), container.innerHTML);
return clippedContentResponse(pageTitle(), container.innerHTML, getImageSizes(document));
} else if (command.name === 'screenshot') {

View File

@@ -29,6 +29,7 @@ class Bridge {
source_url: command.url,
parent_id: command.parent_id,
tags: command.tags || '',
image_sizes: command.image_sizes || {},
};
this.dispatch({ type: 'CLIPPED_CONTENT_SET', content: content });

View File

@@ -42,6 +42,7 @@ const appDefaultState = Object.assign({}, defaultState, {
sidebarVisibility: true,
windowContentSize: bridge().windowContentSize(),
watchedNoteFiles: [],
lastEditorScrollPercents: {},
});
class Application extends BaseApplication {
@@ -171,6 +172,14 @@ class Application extends BaseApplication {
}
break;
case 'EDITOR_SCROLL_PERCENT_SET':
newState = Object.assign({}, state);
const newPercents = Object.assign({}, newState.lastEditorScrollPercents);
newPercents[action.noteId] = action.percent;
newState.lastEditorScrollPercents = newPercents;
break;
}
} catch (error) {
error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action);
@@ -225,6 +234,14 @@ class Application extends BaseApplication {
this.updateMenu(screen);
}
focusElement_(target) {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'focusElement',
target: target,
});
}
updateMenu(screen) {
if (this.lastMenuScreen_ === screen) return;
@@ -244,6 +261,32 @@ class Application extends BaseApplication {
});
}
const focusItems = [];
focusItems.push({
label: _('Sidebar'),
click: () => { this.focusElement_('sideBar') },
accelerator: 'CommandOrControl+Shift+S',
});
focusItems.push({
label: _('Note list'),
click: () => { this.focusElement_('noteList') },
accelerator: 'CommandOrControl+Shift+L',
});
focusItems.push({
label: _('Note title'),
click: () => { this.focusElement_('noteTitle') },
accelerator: 'CommandOrControl+Shift+N',
});
focusItems.push({
label: _('Note body'),
click: () => { this.focusElement_('noteBody') },
accelerator: 'CommandOrControl+Shift+B',
});
const importItems = [];
const exportItems = [];
const ioService = new InteropService();
@@ -431,10 +474,22 @@ class Application extends BaseApplication {
name: 'textItalic',
});
},
}, {
label: _('Link'),
screens: ['Main'],
accelerator: 'CommandOrControl+K',
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'textLink',
});
},
}, {
type: 'separator',
screens: ['Main'],
}, {
label: _('Insert Date Time'),
screens: ['Main'],
visible: false,
accelerator: 'CommandOrControl+Shift+T',
click: () => {
this.dispatch({
@@ -461,7 +516,7 @@ class Application extends BaseApplication {
}, {
label: _('Search in all the notes'),
screens: ['Main'],
accelerator: 'F6',
accelerator: shim.isMac() ? 'Shift+Command+F' : 'F6',
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
@@ -484,7 +539,7 @@ class Application extends BaseApplication {
submenu: [{
label: _('Toggle sidebar'),
screens: ['Main'],
accelerator: 'F10',
accelerator: shim.isMac() ? 'Option+Command+S' : 'F10',
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
@@ -532,6 +587,13 @@ class Application extends BaseApplication {
click: () => {
Setting.setValue('showCompletedTodos', !Setting.value('showCompletedTodos'));
},
}, {
type: 'separator',
screens: ['Main'],
}, {
label: _('Focus'),
screens: ['Main'],
submenu: focusItems,
}],
}, {
label: _('Tools'),

View File

@@ -7,6 +7,7 @@ const { Header } = require('./Header.min.js');
const { themeStyle } = require('../theme.js');
const pathUtils = require('lib/path-utils.js');
const { _ } = require('lib/locale.js');
const { commandArgumentsToString } = require('lib/string-utils');
const SyncTargetRegistry = require('lib/SyncTargetRegistry');
const shared = require('lib/components/shared/config-shared.js');
@@ -43,6 +44,49 @@ class ConfigScreenComponent extends React.Component {
return output;
}
sectionToComponent(key, section, settings) {
const theme = themeStyle(this.props.theme);
const settingComps = [];
for (let i = 0; i < section.metadatas.length; i++) {
const md = section.metadatas[i];
const settingComp = this.settingToComponent(md.key, settings[md.key]);
settingComps.push(settingComp);
}
const sectionStyle = {
marginBottom: 20,
};
const headerStyle = Object.assign({}, theme.headerStyle, {
borderBottomWidth: 1,
borderBottomColor: theme.dividerColor,
borderBottomStyle: 'solid',
paddingBottom: '.4em',
});
if (section.name === 'general') {
sectionStyle.borderTopWidth = 0;
}
const noteComp = section.name !== 'general' ? null : (
<div style={Object.assign({}, theme.textStyle, {marginBottom: 10})}>
{_('Notes and settings are stored in: %s', pathUtils.toSystemSlashes(Setting.value('profileDir'), process.platform))}
</div>
);
return (
<div key={key} style={sectionStyle}>
<h2 style={headerStyle}>{Setting.sectionNameToLabel(section.name)}</h2>
{noteComp}
<div>
{settingComps}
</div>
</div>
);
}
settingToComponent(key, value) {
const theme = themeStyle(this.props.theme);
@@ -56,6 +100,15 @@ class ConfigScreenComponent extends React.Component {
color: theme.color,
});
const subLabel = Object.assign({}, labelStyle, {
opacity: 0.7,
marginBottom: Math.round(rowStyle.marginBottom * 0.7),
});
const invisibleLabel = Object.assign({}, labelStyle, {
opacity: 0,
});
const controlStyle = {
display: 'inline-block',
color: theme.color,
@@ -70,6 +123,7 @@ class ConfigScreenComponent extends React.Component {
});
const updateSettingValue = (key, value) => {
// console.info(key + ' = ' + value);
return shared.updateSettingValue(this, key, value);
}
@@ -119,23 +173,93 @@ class ConfigScreenComponent extends React.Component {
</div>
);
} else if (md.type === Setting.TYPE_STRING) {
const onTextChange = (event) => {
updateSettingValue(key, event.target.value);
}
const inputStyle = Object.assign({}, controlStyle, {
width: '50%',
minWidth: '20em',
border: '1px solid' });
const inputType = md.secure === true ? 'password' : 'text';
return (
<div key={key} style={rowStyle}>
<div style={labelStyle}><label>{md.label()}</label></div>
<input type={inputType} style={inputStyle} value={this.state.settings[key]} onChange={(event) => {onTextChange(event)}} />
{ descriptionComp }
</div>
);
if (md.subType === 'file_path_and_args') {
inputStyle.marginBottom = subLabel.marginBottom;
const splitCmd = cmdString => {
const path = pathUtils.extractExecutablePath(cmdString);
const args = cmdString.substr(path.length + 1);
return [pathUtils.unquotePath(path), args];
}
const joinCmd = cmdArray => {
if (!cmdArray[0] && !cmdArray[1]) return '';
let cmdString = pathUtils.quotePath(cmdArray[0]);
if (!cmdString) cmdString = '""';
if (cmdArray[1]) cmdString += ' ' + cmdArray[1];
return cmdString;
}
const onPathChange = event => {
const cmd = splitCmd(this.state.settings[key]);
cmd[0] = event.target.value;
updateSettingValue(key, joinCmd(cmd));
}
const onArgsChange = event => {
const cmd = splitCmd(this.state.settings[key]);
cmd[1] = event.target.value;
updateSettingValue(key, joinCmd(cmd));
}
const browseButtonClick = () => {
const paths = bridge().showOpenDialog();
if (!paths || !paths.length) return;
const cmd = splitCmd(this.state.settings[key]);
cmd[0] = paths[0]
updateSettingValue(key, joinCmd(cmd));
}
const cmd = splitCmd(this.state.settings[key]);
return (
<div key={key} style={rowStyle}>
<div style={{display:'flex'}}>
<div style={{flex:0, whiteSpace: 'nowrap'}}>
<div style={labelStyle}><label>{md.label()}</label></div>
</div>
<div style={{flex:0}}>
<div style={subLabel}>Path:</div>
<div style={subLabel}>Arguments:</div>
</div>
<div style={{flex:1}}>
<div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', marginBottom: inputStyle.marginBottom}}>
<input type={inputType} style={Object.assign({}, inputStyle, {marginBottom:0})} onChange={(event) => {onPathChange(event)}} value={cmd[0]} />
<button onClick={browseButtonClick} style={Object.assign({}, theme.buttonStyle, { marginLeft: 5, minHeight: 20, height: 20 })}>{_('Browse...')}</button>
</div>
<input type={inputType} style={inputStyle} onChange={(event) => {onArgsChange(event)}} value={cmd[1]}/>
</div>
</div>
<div style={{display:'flex'}}>
<div style={{flex:0, whiteSpace: 'nowrap'}}>
<div style={invisibleLabel}><label>{md.label()}</label></div>
</div>
<div style={{flex:1}}>
{ descriptionComp }
</div>
</div>
</div>
);
} else {
const onTextChange = (event) => {
updateSettingValue(key, event.target.value);
}
return (
<div key={key} style={rowStyle}>
<div style={labelStyle}><label>{md.label()}</label></div>
<input type={inputType} style={inputStyle} value={this.state.settings[key]} onChange={(event) => {onTextChange(event)}} />
{ descriptionComp }
</div>
);
}
} else if (md.type === Setting.TYPE_INT) {
const onNumChange = (event) => {
updateSettingValue(key, event.target.value);
@@ -170,21 +294,31 @@ class ConfigScreenComponent extends React.Component {
render() {
const theme = themeStyle(this.props.theme);
const style = Object.assign({
backgroundColor: theme.backgroundColor
}, this.props.style, { overflow: 'auto' });
const settings = this.state.settings;
}, this.props.style, {
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
});
const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width });
let settings = this.state.settings;
const containerStyle = Object.assign({}, theme.containerStyle, { padding: 10 });
const containerStyle = Object.assign({}, theme.containerStyle, { padding: 10, paddingTop: 0 });
const hasChanges = !!this.state.changedSettingKeys.length;
const buttonStyle = Object.assign({}, theme.buttonStyle, {
display: this.state.changedSettingKeys.length ? 'inline-block' : 'none',
display: 'inline-block',
marginRight: 10,
});
const settingComps = shared.settingsToComponents(this, 'desktop', settings);
const buttonStyleApprove = Object.assign({}, buttonStyle, {
opacity: hasChanges ? 1 : theme.disabledOpacity,
});
const settingComps = shared.settingsToComponents2(this, 'desktop', settings);
const syncTargetMd = SyncTargetRegistry.idToMetadata(settings['sync.target']);
@@ -199,22 +333,29 @@ class ConfigScreenComponent extends React.Component {
settingComps.push(
<div key="check_sync_config_button" style={this.rowStyle_}>
<button style={buttonStyle} disabled={this.state.checkSyncConfigResult === 'checking'} onClick={this.checkSyncConfig_}>{_('Check synchronisation configuration')}</button>
<button disabled={this.state.checkSyncConfigResult === 'checking'} style={buttonStyle} onClick={this.checkSyncConfig_}>{_('Check synchronisation configuration')}</button>
{ statusComp }
</div>);
}
const buttonBarStyle = {
display: 'flex',
alignItems: 'center',
padding: 15,
borderBottomWidth: 1,
borderBottomStyle: 'solid',
borderBottomColor: theme.dividerColor,
};
return (
<div style={style}>
<Header style={headerStyle} />
<div style={buttonBarStyle}>
<button onClick={() => {this.onCancelClick()}} style={buttonStyle}>{'⬅ ' + _('Cancel')}</button>
<button disabled={!hasChanges} onClick={() => {this.onSaveClick()}} style={buttonStyleApprove}>{_('OK')}</button>
<button disabled={!hasChanges} onClick={() => {this.onApplyClick()}} style={buttonStyleApprove}>{_('Apply')}</button>
</div>
<div style={containerStyle}>
<div style={Object.assign({}, theme.textStyle, {marginBottom: 20})}>
{_('Notes and settings are stored in: %s', pathUtils.toSystemSlashes(Setting.value('profileDir'), process.platform))}
</div>
{ settingComps }
<button onClick={() => {this.onSaveClick()}} style={buttonStyle}>{_('OK')}</button>
<button onClick={() => {this.onCancelClick()}} style={buttonStyle}>{_('Cancel')}</button>
<button onClick={() => {this.onApplyClick()}} style={buttonStyle}>{_('Apply')}</button>
</div>
</div>
);

View File

@@ -3,6 +3,7 @@ const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
const { themeStyle } = require('../theme.js');
const { _ } = require('lib/locale.js');
const { bridge } = require('electron').remote.require('./bridge');
class HeaderComponent extends React.Component {
@@ -10,6 +11,7 @@ class HeaderComponent extends React.Component {
super();
this.state = {
searchQuery: '',
showSearchUsageLink: false,
};
this.scheduleSearchChangeEventIid_ = null;
@@ -37,6 +39,27 @@ class HeaderComponent extends React.Component {
triggerOnQuery('');
if (this.searchElement_) this.searchElement_.focus();
}
this.search_onFocus = event => {
if (this.hideSearchUsageLinkIID_) {
clearTimeout(this.hideSearchUsageLinkIID_);
this.hideSearchUsageLinkIID_ = null;
}
this.setState({ showSearchUsageLink: true });
}
this.search_onBlur = event => {
if (this.hideSearchUsageLinkIID_) return;
this.hideSearchUsageLinkIID_ = setTimeout(() => {
this.setState({ showSearchUsageLink: false });
}, 5000);
}
this.searchUsageLink_click = event => {
bridge().openExternal('https://joplin.cozic.net/#searching');
}
}
async componentWillReceiveProps(nextProps) {
@@ -45,6 +68,13 @@ class HeaderComponent extends React.Component {
}
}
componentWillUnmount() {
if (this.hideSearchUsageLinkIID_) {
clearTimeout(this.hideSearchUsageLinkIID_);
this.hideSearchUsageLinkIID_ = null;
}
}
async doCommand(command) {
if (!command) return;
@@ -100,6 +130,8 @@ class HeaderComponent extends React.Component {
}
makeSearch(key, style, options, state) {
const theme = themeStyle(this.props.theme);
const inputStyle = {
display: 'flex',
flex: 1,
@@ -137,6 +169,10 @@ class HeaderComponent extends React.Component {
const icon = <i style={iconStyle} className={"fa " + iconName}></i>
if (options.onQuery) this.searchOnQuery_ = options.onQuery;
const usageLink = !this.state.showSearchUsageLink ? null : (
<a onClick={this.searchUsageLink_click} style={theme.urlStyle} href="#">{_('Usage')}</a>
);
return (
<div key={key} style={containerStyle}>
<input
@@ -146,12 +182,15 @@ class HeaderComponent extends React.Component {
value={state.searchQuery}
onChange={this.search_onChange}
ref={elem => this.searchElement_ = elem}
onFocus={this.search_onFocus}
onBlur={this.search_onBlur}
/>
<a
href="#"
style={searchButton}
onClick={this.search_onClear}
>{icon}</a>
{usageLink}
</div>);
}

View File

@@ -6,13 +6,23 @@ class ItemList extends React.Component {
super();
this.scrollTop_ = 0;
this.listRef = React.createRef();
this.onScroll = this.onScroll.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
}
visibleItemCount(props) {
if (typeof props === 'undefined') props = this.props;
return Math.ceil(props.style.height / props.itemHeight);
}
updateStateItemIndexes(props) {
if (typeof props === 'undefined') props = this.props;
const topItemIndex = Math.floor(this.scrollTop_ / props.itemHeight);
const visibleItemCount = Math.ceil(props.style.height / props.itemHeight);
const visibleItemCount = this.visibleItemCount(props);
let bottomItemIndex = topItemIndex + visibleItemCount;
if (bottomItemIndex >= props.items.length) bottomItemIndex = props.items.length - 1;
@@ -31,8 +41,33 @@ class ItemList extends React.Component {
this.updateStateItemIndexes(newProps);
}
onScroll(scrollTop) {
onScroll(event) {
this.scrollTop_ = event.target.scrollTop;
this.updateStateItemIndexes();
}
onKeyDown(event) {
if (this.props.onKeyDown) this.props.onKeyDown(event);
}
makeItemIndexVisible(itemIndex) {
const top = Math.min(this.props.items.length - 1, this.state.topItemIndex + 1);
const bottom = Math.max(0, this.state.bottomItemIndex - 1)
if (itemIndex >= top && itemIndex <= bottom) return;
let scrollTop = 0;
if (itemIndex < top) {
scrollTop = this.props.itemHeight * itemIndex;
} else {
scrollTop = this.props.itemHeight * itemIndex - (this.visibleItemCount() - 1) * this.props.itemHeight;
}
if (scrollTop < 0) scrollTop = 0;
this.scrollTop_ = scrollTop;
this.listRef.current.scrollTop = scrollTop;
this.updateStateItemIndexes();
}
@@ -61,10 +96,8 @@ class ItemList extends React.Component {
let classes = ['item-list'];
if (this.props.className) classes.push(this.props.className);
const that = this;
return (
<div className={classes.join(' ')} style={style} onScroll={ (event) => { this.onScroll(event.target.scrollTop) }}>
<div ref={this.listRef} className={classes.join(' ')} style={style} onScroll={this.onScroll} onKeyDown={this.onKeyDown}>
{ itemComps }
</div>
);

View File

@@ -295,7 +295,7 @@ class MainScreenComponent extends React.Component {
height: rowHeight,
display: 'inline-block',
verticalAlign: 'top',
};
};
if (isSidebarVisible === false) {
this.styles_.sideBar.width = 0;
@@ -338,9 +338,9 @@ class MainScreenComponent extends React.Component {
render() {
const theme = themeStyle(this.props.theme);
const style = Object.assign({
color: theme.color,
backgroundColor: theme.backgroundColor,
}, this.props.style);
color: theme.color,
backgroundColor: theme.backgroundColor,
}, this.props.style);
const promptOptions = this.state.promptOptions;
const folders = this.props.folders;
const notes = this.props.notes;

View File

@@ -13,8 +13,10 @@ const eventManager = require('../eventManager');
const InteropService = require('lib/services/InteropService');
const InteropServiceHelper = require('../InteropServiceHelper.js');
const Search = require('lib/models/Search');
const { stateUtils } = require('lib/reducer');
const Mark = require('mark.js/dist/mark.min.js');
const SearchEngine = require('lib/services/SearchEngine');
const NoteListUtils = require('./utils/NoteListUtils');
const { replaceRegexDiacritics, pregQuote } = require('lib/string-utils');
class NoteListComponent extends React.Component {
@@ -22,7 +24,11 @@ class NoteListComponent extends React.Component {
constructor() {
super();
this.itemListRef = React.createRef();
this.itemAnchorRefs_ = {};
this.itemRenderer = this.itemRenderer.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
}
style() {
@@ -79,103 +85,10 @@ class NoteListComponent extends React.Component {
if (!noteIds.length) return;
const notes = noteIds.map((id) => BaseModel.byId(this.props.notes, id));
let hasEncrypted = false;
for (let i = 0; i < notes.length; i++) {
if (!!notes[i].encryption_applied) hasEncrypted = true;
}
const menu = new Menu()
if (!hasEncrypted) {
menu.append(new MenuItem({label: _('Add or remove tags'), enabled: noteIds.length === 1, click: async () => {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'setTags',
noteId: noteIds[0],
});
}}));
menu.append(new MenuItem({label: _('Duplicate'), click: async () => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
await Note.duplicate(noteIds[i], {
uniqueTitle: _('%s - Copy', note.title),
});
}
}}));
if (noteIds.length <= 1) {
menu.append(new MenuItem({label: _('Switch between note and to-do type'), click: async () => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
await Note.save(Note.toggleIsTodo(note), { userSideValidation: true });
eventManager.emit('noteTypeToggle', { noteId: note.id });
}
}}));
} else {
const switchNoteType = async (noteIds, type) => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
const newNote = Note.changeNoteType(note, type);
if (newNote === note) continue;
await Note.save(newNote, { userSideValidation: true });
eventManager.emit('noteTypeToggle', { noteId: note.id });
}
}
menu.append(new MenuItem({label: _('Switch to note type'), click: async () => {
await switchNoteType(noteIds, 'note');
}}));
menu.append(new MenuItem({label: _('Switch to to-do type'), click: async () => {
await switchNoteType(noteIds, 'todo');
}}));
}
menu.append(new MenuItem({label: _('Copy Markdown link'), click: async () => {
const { clipboard } = require('electron');
const links = [];
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
links.push(Note.markdownTag(note));
}
clipboard.writeText(links.join(' '));
}}));
const exportMenu = new Menu();
const ioService = new InteropService();
const ioModules = ioService.modules();
for (let i = 0; i < ioModules.length; i++) {
const module = ioModules[i];
if (module.type !== 'exporter') continue;
exportMenu.append(new MenuItem({ label: module.fullLabel() , click: async () => {
await InteropServiceHelper.export(this.props.dispatch.bind(this), module, { sourceNoteIds: noteIds });
}}));
}
if (noteIds.length === 1) {
exportMenu.append(new MenuItem({ label: 'PDF - ' + _('PDF File') , click: () => {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'exportPdf',
});
}}));
}
const exportMenuItem = new MenuItem({label: _('Export'), submenu: exportMenu});
menu.append(exportMenuItem);
}
menu.append(new MenuItem({label: _('Delete'), click: async () => {
const ok = bridge().showConfirmMessageBox(noteIds.length > 1 ? _('Delete notes?') : _('Delete note?'));
if (!ok) return;
await Note.batchDelete(noteIds);
}}));
const menu = NoteListUtils.makeContextMenu(noteIds, {
notes: this.props.notes,
dispatch: this.props.dispatch,
});
menu.popup(bridge().window());
}
@@ -185,7 +98,7 @@ class NoteListComponent extends React.Component {
const width = this.props.style.width;
const onTitleClick = async (event, item) => {
if (event.ctrlKey) {
if (event.ctrlKey || event.metaKey) {
event.preventDefault();
this.props.dispatch({
type: 'NOTE_SELECT_TOGGLE',
@@ -304,11 +217,15 @@ class NoteListComponent extends React.Component {
<i style={watchedIconStyle} className={"fa fa-external-link"}></i>
);
if (!this.itemAnchorRefs_[item.id]) this.itemAnchorRefs_[item.id] = React.createRef();
const ref = this.itemAnchorRefs_[item.id];
// Need to include "todo_completed" in key so that checkbox is updated when
// item is changed via sync.
return <div key={item.id + '_' + item.todo_completed} style={style}>
{checkbox}
<a
ref={ref}
className="list-item"
onContextMenu={(event) => this.itemContextMenu(event)}
href="#"
@@ -324,6 +241,142 @@ class NoteListComponent extends React.Component {
</div>
}
itemAnchorRef(itemId) {
if (this.itemAnchorRefs_[itemId] && this.itemAnchorRefs_[itemId].current) return this.itemAnchorRefs_[itemId].current;
return null;
}
doCommand(command) {
if (!command) return;
let commandProcessed = true;
if (command.name === 'focusElement' && command.target === 'noteList') {
if (this.props.selectedNoteIds.length) {
const ref = this.itemAnchorRef(this.props.selectedNoteIds[0]);
if (ref) ref.focus();
}
} else {
commandProcessed = false;
}
if (commandProcessed) {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: null,
});
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.windowCommand !== this.props.windowCommand) {
this.doCommand(this.props.windowCommand);
}
if (prevProps.selectedNoteIds !== this.props.selectedNoteIds && this.props.selectedNoteIds.length === 1) {
const id = this.props.selectedNoteIds[0];
for (let i = 0; i < this.props.notes.length; i++) {
if (this.props.notes[i].id === id) {
this.itemListRef.current.makeItemIndexVisible(i);
break;
}
}
}
}
async onKeyDown(event) {
const keyCode = event.keyCode;
const noteIds = this.props.selectedNoteIds;
if (noteIds.length === 1 && (keyCode === 40 || keyCode === 38)) { // DOWN / UP
const noteId = noteIds[0];
let noteIndex = BaseModel.modelIndexById(this.props.notes, noteId);
const inc = keyCode === 38 ? -1 : +1;
noteIndex += inc;
if (noteIndex < 0) noteIndex = 0;
if (noteIndex > this.props.notes.length - 1) noteIndex = this.props.notes.length - 1;
const newSelectedNote = this.props.notes[noteIndex];
this.props.dispatch({
type: 'NOTE_SELECT',
id: newSelectedNote.id,
});
this.itemListRef.current.makeItemIndexVisible(noteIndex);
this.focusNoteId_(newSelectedNote.id);
event.preventDefault();
}
if (noteIds.length && keyCode === 46) { // DELETE
event.preventDefault();
await NoteListUtils.confirmDeleteNotes(noteIds);
}
if (noteIds.length && keyCode === 32) { // SPACE
event.preventDefault();
const notes = BaseModel.modelsByIds(this.props.notes, noteIds);
const todos = notes.filter(n => !!n.is_todo);
if (!todos.length) return;
for (let i = 0; i < todos.length; i++) {
const toggledTodo = Note.toggleTodoCompleted(todos[i]);
await Note.save(toggledTodo);
}
this.focusNoteId_(todos[0].id);
}
if (keyCode === 9) { // TAB
event.preventDefault();
if (event.shiftKey) {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'focusElement',
target: 'sideBar',
});
} else {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'focusElement',
target: 'noteTitle',
});
}
}
}
focusNoteId_(noteId) {
// - We need to focus the item manually otherwise focus might be lost when the
// list is scrolled and items within it are being rebuilt.
// - We need to use an interval because when leaving the arrow pressed, the rendering
// of items might lag behind and so the ref is not yet available at this point.
if (!this.itemAnchorRef(noteId)) {
if (this.focusItemIID_) clearInterval(this.focusItemIID_);
this.focusItemIID_ = setInterval(() => {
if (this.itemAnchorRef(noteId)) {
this.itemAnchorRef(noteId).focus();
clearInterval(this.focusItemIID_)
this.focusItemIID_ = null;
}
}, 10);
} else {
this.itemAnchorRef(noteId).focus();
}
}
componentWillUnmount() {
if (this.focusItemIID_) {
clearInterval(this.focusItemIID_);
this.focusItemIID_ = null;
}
}
render() {
const theme = themeStyle(this.props.theme);
const style = this.props.style;
@@ -345,11 +398,13 @@ class NoteListComponent extends React.Component {
return (
<ItemList
ref={this.itemListRef}
itemHeight={this.style().listItem.height}
style={style}
className={"note-list"}
items={notes}
itemRenderer={this.itemRenderer}
onKeyDown={this.onKeyDown}
></ItemList>
);
}
@@ -366,6 +421,7 @@ const mapStateToProps = (state) => {
searches: state.searches,
selectedSearchId: state.selectedSearchId,
watchedNoteFiles: state.watchedNoteFiles,
windowCommand: state.windowCommand,
};
};

View File

@@ -13,6 +13,7 @@ class NoteSearchBarComponent extends React.Component {
};
this.searchInput_change = this.searchInput_change.bind(this);
this.searchInput_keyDown = this.searchInput_keyDown.bind(this);
this.previousButton_click = this.previousButton_click.bind(this);
this.nextButton_click = this.nextButton_click.bind(this);
this.closeButton_click = this.closeButton_click.bind(this);
@@ -70,6 +71,24 @@ class NoteSearchBarComponent extends React.Component {
this.triggerOnChange(query);
}
searchInput_keyDown(event) {
if (event.keyCode === 13) { // ENTER
event.preventDefault();
if (!event.shiftKey) {
if (this.props.onNext) this.props.onNext();
} else {
if (this.props.onPrevious) this.props.onPrevious();
}
}
if (event.keyCode === 27) { // ESCAPE
event.preventDefault();
if (this.props.onClose) this.props.onClose();
}
}
previousButton_click(event) {
if (this.props.onPrevious) this.props.onPrevious();
}
@@ -101,7 +120,7 @@ class NoteSearchBarComponent extends React.Component {
<div style={this.props.style}>
<div style={{display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
{ closeButton }
<input placeholder={_('Search...')} value={this.state.query} onChange={this.searchInput_change} ref="searchInput" type="text" style={{width: 200, marginRight: 5}}></input>
<input placeholder={_('Search...')} value={this.state.query} onChange={this.searchInput_change} onKeyDown={this.searchInput_keyDown} ref="searchInput" type="text" style={{width: 200, marginRight: 5}}></input>
{ nextButton }
{ previousButton }
</div>

View File

@@ -28,6 +28,7 @@ const ArrayUtils = require('lib/ArrayUtils');
const ObjectUtils = require('lib/ObjectUtils');
const urlUtils = require('lib/urlUtils');
const dialogs = require('./dialogs');
const NoteListUtils = require('./utils/NoteListUtils');
const NoteSearchBar = require('./NoteSearchBar.min.js');
const markdownUtils = require('lib/markdownUtils');
const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
@@ -35,6 +36,7 @@ const ResourceFetcher = require('lib/services/ResourceFetcher');
const { toSystemSlashes, safeFilename } = require('lib/path-utils');
const { clipboard } = require('electron');
const SearchEngine = require('lib/services/SearchEngine');
const NoteTextViewer = require('./NoteTextViewer.min');
require('brace/mode/markdown');
// https://ace.c9.io/build/kitchen-sink.html
@@ -78,6 +80,8 @@ class NoteTextComponent extends React.Component {
localSearch: Object.assign({}, this.localSearchDefaultState),
};
this.webviewRef_ = React.createRef();
this.lastLoadedNoteId_ = null;
this.webviewListeners_ = null;
@@ -103,9 +107,9 @@ class NoteTextComponent extends React.Component {
}
}
this.onAlarmChange_ = (event) => { if (event.noteId === this.props.noteId) this.reloadNote(this.props); }
this.onNoteTypeToggle_ = (event) => { if (event.noteId === this.props.noteId) this.reloadNote(this.props); }
this.onTodoToggle_ = (event) => { if (event.noteId === this.props.noteId) this.reloadNote(this.props); }
this.onAlarmChange_ = (event) => { if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); }
this.onNoteTypeToggle_ = (event) => { if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); }
this.onTodoToggle_ = (event) => { if (event.noteId === this.props.noteId) this.scheduleReloadNote(this.props); }
this.onEditorPaste_ = async (event = null) => {
const formats = clipboard.availableFormats();
@@ -214,7 +218,7 @@ class NoteTextComponent extends React.Component {
this.externalEditWatcher_noteChange = (event) => {
if (!this.state.note || !this.state.note.id) return;
if (event.id === this.state.note.id) {
this.reloadNote(this.props);
this.scheduleReloadNote(this.props);
}
}
@@ -257,6 +261,10 @@ class NoteTextComponent extends React.Component {
showLocalSearch: false,
});
}
this.titleField_keyDown = this.titleField_keyDown.bind(this);
this.webview_ipcMessage = this.webview_ipcMessage.bind(this);
this.webview_domReady = this.webview_domReady.bind(this);
}
// Note:
@@ -357,7 +365,6 @@ class NoteTextComponent extends React.Component {
this.saveIfNeeded();
this.mdToHtml_ = null;
this.destroyWebview();
eventManager.removeListener('alarmChange', this.onAlarmChange_);
eventManager.removeListener('noteTypeToggle', this.onNoteTypeToggle_);
@@ -398,6 +405,20 @@ class NoteTextComponent extends React.Component {
}, 500);
}
scheduleReloadNote(props, options = null) {
if (this.scheduleReloadNoteIID_) {
clearTimeout(this.scheduleReloadNoteIID_);
this.scheduleReloadNoteIID_ = null;
}
this.scheduleReloadNoteIID_ = setTimeout(() => {
this.reloadNote(props, options);
}, 10);
}
// Generally, reloadNote() should not be called directly so that it's not called multiple times
// from multiple places within a short interval of time. Instead use scheduleReloadNote() to
// delay reloading a bit and make sure that only one reload operation is performed.
async reloadNote(props, options = null) {
if (!options) options = {};
if (!('noReloadIfLocalChanges' in options)) options.noReloadIfLocalChanges = false;
@@ -412,12 +433,17 @@ class NoteTextComponent extends React.Component {
let loadingNewNote = true;
let parentFolder = null;
let noteTags = [];
let scrollPercent = 0;
if (props.newNote) {
note = Object.assign({}, props.newNote);
this.lastLoadedNoteId_ = null;
} else {
noteId = props.noteId;
scrollPercent = this.props.lastEditorScrollPercents[noteId];
if (!scrollPercent) scrollPercent = 0;
loadingNewNote = stateNoteId !== noteId;
noteTags = await Tag.tagsByNoteId(noteId);
this.lastLoadedNoteId_ = noteId;
@@ -438,7 +464,7 @@ class NoteTextComponent extends React.Component {
// If we are loading nothing (noteId == null), make sure to
// set webviewReady to false too because the webview component
// is going to be removed in render().
const webviewReady = this.webview_ && this.state.webviewReady && (noteId || props.newNote);
const webviewReady = !!this.webviewRef_.current && this.state.webviewReady && (!!noteId || !!props.newNote);
// Scroll back to top when loading new note
if (loadingNewNote) {
@@ -481,6 +507,11 @@ class NoteTextComponent extends React.Component {
}
this.editor_.editor.clearSelection();
this.editor_.editor.moveCursorTo(0,0);
setTimeout(() => {
this.setEditorPercentScroll(scrollPercent ? scrollPercent : 0);
this.setViewerPercentScroll(scrollPercent ? scrollPercent : 0);
}, 10);
}
}
@@ -534,18 +565,18 @@ class NoteTextComponent extends React.Component {
}
async componentWillReceiveProps(nextProps) {
if (nextProps.newNote) {
await this.reloadNote(nextProps);
} else if ('noteId' in nextProps && nextProps.noteId !== this.props.noteId) {
await this.reloadNote(nextProps);
if (this.props.newNote !== nextProps.newNote && nextProps.newNote) {
await this.scheduleReloadNote(nextProps);
} else if (('noteId' in nextProps) && nextProps.noteId !== this.props.noteId) {
await this.scheduleReloadNote(nextProps);
} else if ('noteTags' in nextProps && this.areNoteTagsModified(nextProps.noteTags, this.state.noteTags)) {
this.setState({
noteTags: nextProps.noteTags
});
}
if ('syncStarted' in nextProps && !nextProps.syncStarted && !this.isModified()) {
await this.reloadNote(nextProps, { noReloadIfLocalChanges: true });
if ((nextProps.syncStarted !== this.props.syncStarted) && ('syncStarted' in nextProps) && !nextProps.syncStarted && !this.isModified()) {
await this.scheduleReloadNote(nextProps, { noReloadIfLocalChanges: true });
}
if (nextProps.windowCommand) {
@@ -678,6 +709,10 @@ class NoteTextComponent extends React.Component {
type: "FOLDER_AND_NOTE_SELECT",
folderId: item.parent_id,
noteId: item.id,
historyNoteAction: {
id: this.state.note.id,
parent_id: this.state.note.parent_id,
},
});
} else {
throw new Error('Unsupported item type: ' + item.type_);
@@ -710,11 +745,31 @@ class NoteTextComponent extends React.Component {
}
setEditorPercentScroll(p) {
const noteId = this.props.noteId;
if (noteId) {
this.props.dispatch({
type: 'EDITOR_SCROLL_PERCENT_SET',
noteId: noteId,
percent: p,
});
}
this.editorSetScrollTop(p * this.editorMaxScroll());
}
setViewerPercentScroll(p) {
this.webview_.send('setPercentScroll', p);
const noteId = this.props.noteId;
if (noteId) {
this.props.dispatch({
type: 'EDITOR_SCROLL_PERCENT_SET',
noteId: noteId,
percent: p,
});
}
if (this.webviewRef_.current) this.webviewRef_.current.wrappedInstance.send('setPercentScroll', p);
}
editor_scroll() {
@@ -724,30 +779,19 @@ class NoteTextComponent extends React.Component {
}
const m = this.editorMaxScroll();
this.setViewerPercentScroll(m ? this.editorScrollTop() / m : 0);
const percent = m ? this.editorScrollTop() / m : 0;
this.setViewerPercentScroll(percent);
}
webview_domReady() {
if (!this.webview_) return;
if (!this.webviewRef_.current) return;
this.setState({
webviewReady: true,
});
if (Setting.value('env') === 'dev') this.webview_.openDevTools();
}
webview_ref(element) {
if (this.webview_) {
if (this.webview_ === element) return;
this.destroyWebview();
}
if (!element) {
this.destroyWebview();
} else {
this.initWebview(element);
}
// if (Setting.value('env') === 'dev') this.webview_.openDevTools();
}
editor_ref(element) {
@@ -822,35 +866,6 @@ class NoteTextComponent extends React.Component {
}
}
initWebview(wv) {
if (!this.webviewListeners_) {
this.webviewListeners_ = {
'dom-ready': this.webview_domReady.bind(this),
'ipc-message': this.webview_ipcMessage.bind(this),
};
}
for (let n in this.webviewListeners_) {
if (!this.webviewListeners_.hasOwnProperty(n)) continue;
const fn = this.webviewListeners_[n];
wv.addEventListener(n, fn);
}
this.webview_ = wv;
}
destroyWebview() {
if (!this.webview_) return;
for (let n in this.webviewListeners_) {
if (!this.webviewListeners_.hasOwnProperty(n)) continue;
const fn = this.webviewListeners_[n];
this.webview_.removeEventListener(n, fn);
}
this.webview_ = null;
}
aceEditor_change(body) {
shared.noteComponent_change(this, 'body', body);
this.scheduleHtmlUpdate();
@@ -872,7 +887,10 @@ class NoteTextComponent extends React.Component {
}
}
updateHtml(body = null) {
updateHtml(body = null, options = null) {
if (!options) options = {};
if (!('useCustomCss' in options)) options.useCustomCss = true;
const mdOptions = {
onResourceLoaded: () => {
if (this.resourceLoadedTimeoutId_) {
@@ -893,7 +911,6 @@ class NoteTextComponent extends React.Component {
let bodyToRender = body;
if (bodyToRender === null) bodyToRender = this.state.note && this.state.note.body ? this.state.note.body : '';
bodyToRender = '<style>' + this.props.customCss + '</style>\n' + bodyToRender;
let bodyHtml = '';
const visiblePanes = this.props.visiblePanes || ['editor', 'viewer'];
@@ -903,11 +920,35 @@ class NoteTextComponent extends React.Component {
bodyToRender = '*' + _('This note has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout')) + '*';
}
if (options.useCustomCss) bodyToRender = '<style>' + this.props.customCss + '</style>\n' + bodyToRender;
bodyHtml = this.mdToHtml().render(bodyToRender, theme, mdOptions);
this.setState({ bodyHtml: bodyHtml });
}
titleField_keyDown(event) {
const keyCode = event.keyCode;
if (keyCode === 9) { // TAB
event.preventDefault();
if (event.shiftKey) {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'focusElement',
target: 'noteList',
});
} else {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'focusElement',
target: 'noteBody',
});
}
}
}
async doCommand(command) {
if (!command) return;
@@ -924,7 +965,9 @@ class NoteTextComponent extends React.Component {
fn = this.commandTextBold;
} else if (command.name === 'textItalic') {
fn = this.commandTextItalic;
} else if (command.name === 'insertDateTime' ) {
} else if (command.name === 'textLink') {
fn = this.commandTextLink;
} else if (command.name === 'insertDateTime') {
fn = this.commandDateTime;
} else if (command.name === 'commandStartExternalEditing') {
fn = this.commandStartExternalEditing;
@@ -933,6 +976,20 @@ class NoteTextComponent extends React.Component {
}
}
if (command.name === 'focusElement' && command.target === 'noteTitle') {
fn = () => {
if (!this.titleField_) return;
this.titleField_.focus();
}
}
if (command.name === 'focusElement' && command.target === 'noteBody') {
fn = () => {
if (!this.editor_) return;
this.editor_.editor.focus();
}
}
if (!fn) return;
this.props.dispatch({
@@ -1002,7 +1059,7 @@ class NoteTextComponent extends React.Component {
}
printTo_(target, options) {
if (this.props.selectedNoteIds.length !== 1 || !this.webview_) {
if (this.props.selectedNoteIds.length !== 1 || !this.webviewRef_.current) {
throw new Error(_('Only one note can be printed or exported to PDF at a time.'));
}
@@ -1012,7 +1069,7 @@ class NoteTextComponent extends React.Component {
const previousTheme = Setting.value('theme');
Setting.setValue('theme', Setting.THEME_LIGHT);
this.lastSetHtml_ = '';
this.updateHtml(tempBody);
this.updateHtml(tempBody, { useCustomCss: false });
this.forceUpdate();
const restoreSettings = () => {
@@ -1024,7 +1081,7 @@ class NoteTextComponent extends React.Component {
setTimeout(() => {
if (target === 'pdf') {
this.webview_.printToPDF({}, (error, data) => {
this.webviewRef_.current.wrappedInstance.printToPDF({}, (error, data) => {
restoreSettings();
if (error) {
@@ -1034,7 +1091,7 @@ class NoteTextComponent extends React.Component {
}
});
} else if (target === 'printer') {
this.webview_.print();
this.webviewRef_.current.wrappedInstance.print();
restoreSettings();
}
}, 100);
@@ -1318,6 +1375,25 @@ class NoteTextComponent extends React.Component {
});
}
if (this.props.historyNotes.length) {
toolbarItems.push({
tooltip: _('Back'),
iconName: 'fa-arrow-left',
onClick: () => {
if (!this.props.historyNotes.length) return;
const lastItem = this.props.historyNotes[this.props.historyNotes.length - 1];
this.props.dispatch({
type: "FOLDER_AND_NOTE_SELECT",
folderId: lastItem.parent_id,
noteId: lastItem.id,
historyNoteAction: 'pop',
});
},
});
}
toolbarItems.push({
tooltip: _('Bold'),
iconName: 'fa-bold',
@@ -1453,6 +1529,61 @@ class NoteTextComponent extends React.Component {
return toolbarItems;
}
renderNoNotes(rootStyle) {
const emptyDivStyle = Object.assign({
backgroundColor: 'black',
opacity: 0.1,
}, rootStyle);
return <div style={emptyDivStyle}></div>
}
renderMultiNotes(rootStyle) {
const theme = themeStyle(this.props.theme);
const multiNotesButton_click = item => {
if (item.submenu) {
item.submenu.popup(bridge().window());
} else {
item.click();
}
}
const menu = NoteListUtils.makeContextMenu(this.props.selectedNoteIds, {
notes: this.props.notes,
dispatch: this.props.dispatch,
});
const buttonStyle = Object.assign({}, theme.buttonStyle, {
marginBottom: 10,
});
const itemComps = [];
const menuItems = menu.items;
for (let i = 0; i < menuItems.length; i++) {
const item = menuItems[i];
if (!item.enabled) continue;
itemComps.push(<button
key={item.label}
style={buttonStyle}
onClick={() => multiNotesButton_click(item)}
>{item.label}</button>);
}
rootStyle = Object.assign({}, rootStyle, {
paddingTop: rootStyle.paddingLeft,
display: 'inline-flex',
justifyContent: 'center',
});
return (<div style={rootStyle}>
<div style={{display: 'flex', flexDirection: 'column'}}>
{itemComps}
</div>
</div>);
}
render() {
const style = this.props.style;
const note = this.state.note;
@@ -1472,12 +1603,10 @@ class NoteTextComponent extends React.Component {
const innerWidth = rootStyle.width - rootStyle.paddingLeft - rootStyle.paddingRight - borderWidth;
if (!note || !!note.encryption_applied) {
const emptyDivStyle = Object.assign({
backgroundColor: 'black',
opacity: 0.1,
}, rootStyle);
return <div style={emptyDivStyle}></div>
if (this.props.selectedNoteIds.length > 1) {
return this.renderMultiNotes(rootStyle);
} else if (!note || !!note.encryption_applied) { //|| (note && !this.props.newNote && this.props.noteId && note.id !== this.props.noteId)) { // note.id !== props.noteId is when the note has not been loaded yet, and the previous one is still in the state
return this.renderNoNotes(rootStyle);
}
const titleBarStyle = {
@@ -1580,7 +1709,7 @@ class NoteTextComponent extends React.Component {
const htmlHasChanged = this.lastSetHtml_ !== html;
if (htmlHasChanged) {
let options = {codeTheme: theme.codeThemeCss};
this.webview_.send('setHtml', html, options);
this.webviewRef_.current.wrappedInstance.send('setHtml', html, options);
this.lastSetHtml_ = html;
}
@@ -1606,7 +1735,7 @@ class NoteTextComponent extends React.Component {
if (htmlHasChanged || keywordHash !== this.lastSetMarkers_ || !ObjectUtils.fieldsEqual(this.lastSetMarkersOptions_, markerOptions)) {
this.lastSetMarkers_ = keywordHash;
this.lastSetMarkersOptions_ = Object.assign({}, markerOptions);
this.webview_.send('setMarkers', keywords, markerOptions);
this.webviewRef_.current.wrappedInstance.send('setMarkers', keywords, markerOptions);
}
}
@@ -1623,6 +1752,7 @@ class NoteTextComponent extends React.Component {
style={titleEditorStyle}
value={note && note.title ? note.title : ''}
onChange={(event) => { this.title_changeText(event); }}
onKeyDown={this.titleField_keyDown}
placeholder={ this.props.newNote ? _('Creating new %s...', isTodo ? _('to-do') : _('note')) : '' }
/>
@@ -1637,32 +1767,13 @@ class NoteTextComponent extends React.Component {
const titleBarDate = <span style={Object.assign({}, theme.textStyle, {color: theme.colorFaded})}>{time.formatMsToLocal(note.user_updated_time)}</span>
const viewer = <webview
style={viewerStyle}
preload="gui/note-viewer/preload.js"
src="gui/note-viewer/index.html"
webpreferences="contextIsolation"
ref={(elem) => { this.webview_ref(elem); } }
const viewer = <NoteTextViewer
ref={this.webviewRef_}
viewerStyle={viewerStyle}
onDomReady={this.webview_domReady}
onIpcMessage={this.webview_ipcMessage}
/>
// const markers = [{
// startRow: 2,
// startCol: 3,
// endRow: 2,
// endCol: 6,
// type: 'text',
// className: 'test-marker'
// }];
// markers={markers}
// editorProps={{$useWorker: false}}
// #note-editor .test-marker {
// background-color: red;
// color: yellow;
// position: absolute;
// }
const editorRootStyle = Object.assign({}, editorStyle);
delete editorRootStyle.width;
delete editorRootStyle.height;
@@ -1684,6 +1795,7 @@ class NoteTextComponent extends React.Component {
showPrintMargin={false}
onSelectionChange={this.aceEditor_selectionChange}
onFocus={this.aceEditor_focus}
readOnly={visiblePanes.indexOf('editor') < 0}
// Disable warning: "Automatically scrolling cursor into view after
// selection change this will be disabled in the next version set
@@ -1727,6 +1839,7 @@ class NoteTextComponent extends React.Component {
const mapStateToProps = (state) => {
return {
noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
notes: state.notes,
selectedNoteIds: state.selectedNoteIds,
noteTags: state.selectedNoteTags,
folderId: state.selectedFolderId,
@@ -1742,6 +1855,8 @@ const mapStateToProps = (state) => {
selectedSearchId: state.selectedSearchId,
watchedNoteFiles: state.watchedNoteFiles,
customCss: state.customCss,
lastEditorScrollPercents: state.lastEditorScrollPercents,
historyNotes: state.historyNotes,
};
};

View File

@@ -0,0 +1,99 @@
const React = require('react');
const { connect } = require('react-redux');
const { themeStyle } = require('../theme.js');
const { _ } = require('lib/locale.js');
class NoteTextViewerComponent extends React.Component {
constructor() {
super();
this.initialized_ = false;
this.webviewRef_ = React.createRef();
this.webviewListeners_ = null;
this.webview_domReady = this.webview_domReady.bind(this);
this.webview_ipcMessage = this.webview_ipcMessage.bind(this);
}
webview_domReady(event) {
this.props.onDomReady(event);
}
webview_ipcMessage(event) {
this.props.onIpcMessage(event);
}
initWebview() {
const wv = this.webviewRef_.current;
if (!this.webviewListeners_) {
this.webviewListeners_ = {
'dom-ready': this.webview_domReady.bind(this),
'ipc-message': this.webview_ipcMessage.bind(this),
};
}
for (let n in this.webviewListeners_) {
if (!this.webviewListeners_.hasOwnProperty(n)) continue;
const fn = this.webviewListeners_[n];
wv.addEventListener(n, fn);
}
}
destroyWebview() {
const wv = this.webviewRef_.current;
if (!wv || !this.initialized_) return;
for (let n in this.webviewListeners_) {
if (!this.webviewListeners_.hasOwnProperty(n)) continue;
const fn = this.webviewListeners_[n];
wv.removeEventListener(n, fn);
}
}
componentDidUpdate() {
if (!this.initialized_ && this.webviewRef_.current) {
this.initWebview();
this.initialized_ = true;
}
}
componentWillUnmount() {
this.destroyWebview();
}
send(channel, arg0 = null, arg1 = null, arg2 = null, arg3 = null) {
return this.webviewRef_.current.send(channel, arg0, arg1, arg2, arg3);
}
printToPDF(options, callback) {
return this.webviewRef_.current.printToPDF(options, callback);
}
print(options = {}) {
return this.webviewRef_.current.print(options);
}
render() {
return <webview
ref={this.webviewRef_}
style={this.props.viewerStyle}
preload="gui/note-viewer/preload.js"
src="gui/note-viewer/index.html"
webpreferences="contextIsolation"
/>
}
}
const mapStateToProps = (state) => {
return {
theme: state.settings.theme,
};
};
const NoteTextViewer = connect(mapStateToProps, null, null, { withRef: true })(NoteTextViewerComponent);
module.exports = NoteTextViewer;

View File

@@ -15,6 +15,7 @@ const { ConfigScreen } = require('./ConfigScreen.min.js');
const { EncryptionConfigScreen } = require('./EncryptionConfigScreen.min.js');
const { ClipperConfigScreen } = require('./ClipperConfigScreen.min.js');
const { Navigator } = require('./Navigator.min.js');
const WelcomeUtils = require('lib/WelcomeUtils');
const { app } = require('../app');
@@ -71,6 +72,8 @@ class RootComponent extends React.Component {
state: 'ready',
});
}
await WelcomeUtils.install(this.props.dispatch);
}
render() {

View File

@@ -40,9 +40,15 @@ class SideBarComponent extends React.Component {
const dt = event.dataTransfer;
if (!dt) return;
// folderId can be NULL when dropping on the sidebar Notebook header. In that case, it's used
// to put the dropped folder at the root. But for notes, folderId needs to always be defined
// since there's no such thing as a root note.
if (dt.types.indexOf("text/x-jop-note-ids") >= 0) {
event.preventDefault();
if (!folderId) return;
const noteIds = JSON.parse(dt.getData("text/x-jop-note-ids"));
for (let i = 0; i < noteIds.length; i++) {
await Note.moveToFolder(noteIds[i], folderId);
@@ -81,6 +87,15 @@ class SideBarComponent extends React.Component {
});
};
this.folderItemsOrder_ = [];
this.tagItemsOrder_ = [];
this.onKeyDown = this.onKeyDown.bind(this);
this.rootRef = React.createRef();
this.anchorItemRefs = {};
this.state = {
tagHeaderIsExpanded: Setting.value('tagHeaderIsExpanded'),
folderHeaderIsExpanded: Setting.value('folderHeaderIsExpanded')
@@ -172,9 +187,8 @@ class SideBarComponent extends React.Component {
marginTop: 10,
marginLeft: 5,
marginRight: 5,
minHeight: 70,
marginBottom: 10,
wordWrap: "break-word",
//width: "100%",
},
};
@@ -192,6 +206,31 @@ class SideBarComponent extends React.Component {
}
}
doCommand(command) {
if (!command) return;
let commandProcessed = true;
if (command.name === 'focusElement' && command.target === 'sideBar') {
if (this.props.sidebarVisibility) {
const item = this.selectedItem();
if (item) {
const anchorRef = this.anchorItemRefs[item.type][item.id];
if (anchorRef) anchorRef.current.focus();
}
}
} else {
commandProcessed = false;
}
if (commandProcessed) {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: null,
});
}
}
componentDidUpdate(prevProps) {
if (shim.isLinux()) {
// For some reason, the UI seems to sleep in some Linux distro during
@@ -214,6 +253,12 @@ class SideBarComponent extends React.Component {
this.clearForceUpdateDuringSync();
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.windowCommand !== this.props.windowCommand) {
this.doCommand(this.props.windowCommand);
}
}
itemContextMenu(event) {
const itemId = event.target.getAttribute("data-id");
if (itemId === Folder.conflictFolderId()) return;
@@ -341,17 +386,26 @@ class SideBarComponent extends React.Component {
});
}
searchItem_click(search) {
this.props.dispatch({
type: "SEARCH_SELECT",
id: search ? search.id : null,
});
}
// searchItem_click(search) {
// this.props.dispatch({
// type: "SEARCH_SELECT",
// id: search ? search.id : null,
// });
// }
async sync_click() {
await shared.synchronize_press(this);
}
anchorItemRef(type, id) {
let refs = null;
if (!this.anchorItemRefs[type]) this.anchorItemRefs[type] = {};
if (this.anchorItemRefs[type][id]) return this.anchorItemRefs[type][id];
this.anchorItemRefs[type][id] = React.createRef();
return this.anchorItemRefs[type][id];
}
folderItem(folder, selected, hasChildren, depth) {
let style = Object.assign({}, this.style().listItem);
if (folder.id === Folder.conflictFolderId()) style = Object.assign(style, this.style().conflictFolder);
@@ -359,8 +413,6 @@ class SideBarComponent extends React.Component {
const itemTitle = Folder.displayTitle(folder);
let containerStyle = Object.assign({}, this.style().listItemContainer);
// containerStyle.paddingLeft = containerStyle.paddingLeft + depth * 10;
if (selected) containerStyle = Object.assign(containerStyle, this.style().listItemSelected);
let expandLinkStyle = Object.assign({}, this.style().listItemExpandIcon);
@@ -373,10 +425,13 @@ class SideBarComponent extends React.Component {
const expandIcon = <i style={expandIconStyle} className={"fa " + iconName}></i>
const expandLink = hasChildren ? <a style={expandLinkStyle} href="#" folderid={folder.id} onClick={this.onFolderToggleClick_}>{expandIcon}</a> : <span style={expandLinkStyle}>{expandIcon}</span>
const anchorRef = this.anchorItemRef('folder', folder.id);
return (
<div className="list-item-container" style={containerStyle} key={folder.id} onDragStart={this.onFolderDragStart_} onDragOver={this.onFolderDragOver_} onDrop={this.onFolderDrop_} draggable={true} folderid={folder.id}>
{ expandLink }
<a
ref={anchorRef}
className="list-item"
href="#"
data-id={folder.id}
@@ -398,10 +453,14 @@ class SideBarComponent extends React.Component {
tagItem(tag, selected) {
let style = Object.assign({}, this.style().tagItem);
if (selected) style = Object.assign(style, this.style().listItemSelected);
const anchorRef = this.anchorItemRef('tag', tag.id);
return (
<a
className="list-item"
href="#"
ref={anchorRef}
data-id={tag.id}
data-type={BaseModel.TYPE_TAG}
onContextMenu={event => this.itemContextMenu(event)}
@@ -418,26 +477,26 @@ class SideBarComponent extends React.Component {
);
}
searchItem(search, selected) {
let style = Object.assign({}, this.style().listItem);
if (selected) style = Object.assign(style, this.style().listItemSelected);
return (
<a
className="list-item"
href="#"
data-id={search.id}
data-type={BaseModel.TYPE_SEARCH}
onContextMenu={event => this.itemContextMenu(event)}
key={search.id}
style={style}
onClick={() => {
this.searchItem_click(search);
}}
>
{search.title}
</a>
);
}
// searchItem(search, selected) {
// let style = Object.assign({}, this.style().listItem);
// if (selected) style = Object.assign(style, this.style().listItemSelected);
// return (
// <a
// className="list-item"
// href="#"
// data-id={search.id}
// data-type={BaseModel.TYPE_SEARCH}
// onContextMenu={event => this.itemContextMenu(event)}
// key={search.id}
// style={style}
// onClick={() => {
// this.searchItem_click(search);
// }}
// >
// {search.title}
// </a>
// );
// }
makeDivider(key) {
return <div style={{ height: 2, backgroundColor: "blue" }} key={key} />;
@@ -462,8 +521,11 @@ class SideBarComponent extends React.Component {
toggleIcon = <i className={`fa ${isExpanded ? 'fa-chevron-down' : 'fa-chevron-left'}`} style={{ fontSize: style.fontSize * 0.75,
marginRight: 12, marginLeft: 5, marginTop: style.fontSize * 0.125}}></i>;
}
const ref = this.anchorItemRef('headers', key);
return (
<div style={style} key={key} {...extraProps} onClick={(event) => {
<div ref={ref} style={style} key={key} {...extraProps} onClick={(event) => {
// if a custom click event is attached, trigger that.
if (headerClick) {
headerClick(key, event);
@@ -477,6 +539,91 @@ class SideBarComponent extends React.Component {
);
}
selectedItem() {
if (this.props.notesParentType === 'Folder' && this.props.selectedFolderId) {
return { type: 'folder', id: this.props.selectedFolderId };
} else if (this.props.notesParentType === 'Tag' && this.props.selectedTagId) {
return { type: 'tag', id: this.props.selectedTagId };
} else if (this.props.notesParentType === 'Search' && this.props.selectedSearchId) {
return { type: 'search', id: this.props.selectedSearchId };
}
return null;
}
onKeyDown(event) {
const keyCode = event.keyCode;
const selectedItem = this.selectedItem();
if (keyCode === 40 || keyCode === 38) { // DOWN / UP
event.preventDefault();
const focusItems = [];
for (let i = 0; i < this.folderItemsOrder_.length; i++) {
const id = this.folderItemsOrder_[i];
focusItems.push({ id: id, ref: this.anchorItemRefs['folder'][id], type: 'folder' });
}
for (let i = 0; i < this.tagItemsOrder_.length; i++) {
const id = this.tagItemsOrder_[i];
focusItems.push({ id: id, ref: this.anchorItemRefs['tag'][id], type: 'tag' });
}
let currentIndex = 0;
for (let i = 0; i < focusItems.length; i++) {
if (!selectedItem || focusItems[i].id === selectedItem.id) {
currentIndex = i;
break;
}
}
const inc = keyCode === 38 ? -1 : +1;
let newIndex = currentIndex + inc;
if (newIndex < 0) newIndex = 0;
if (newIndex > focusItems.length - 1) newIndex = focusItems.length - 1;
const focusItem = focusItems[newIndex];
let actionName = focusItem.type.toUpperCase() + '_SELECT';
this.props.dispatch({
type: actionName,
id: focusItem.id,
});
focusItem.ref.current.focus();
}
if (keyCode === 9) { // TAB
event.preventDefault();
if (event.shiftKey) {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'focusElement',
target: 'noteBody',
});
} else {
this.props.dispatch({
type: 'WINDOW_COMMAND',
name: 'focusElement',
target: 'noteList',
});
}
}
if (selectedItem && selectedItem.type === 'folder' && keyCode === 32) { // SPACE
event.preventDefault();
this.props.dispatch({
type: 'FOLDER_TOGGLE',
id: selectedItem.id,
});
}
}
onHeaderClick_(key, event) {
const currentHeader = event.currentTarget;
const toggleBlock = +currentHeader.getAttribute('toggleblock');
@@ -489,7 +636,7 @@ class SideBarComponent extends React.Component {
}
synchronizeButton(type) {
const style = this.style().button;
const style = Object.assign({}, this.style().button, { marginBottom: 5 });
const iconName = type === "sync" ? "fa-refresh" : "fa-times";
const label = type === "sync" ? _("Synchronise") : _("Cancel");
const icon = <i style={{ fontSize: style.fontSize, marginRight: 5 }} className={"fa " + iconName} />;
@@ -513,7 +660,9 @@ class SideBarComponent extends React.Component {
const theme = themeStyle(this.props.theme);
const style = Object.assign({}, this.style().root, this.props.style, {
overflowX: "hidden",
overflowY: "auto",
overflowY: "hidden",
display: 'inline-flex',
flexDirection: 'column',
});
let items = [];
@@ -524,7 +673,9 @@ class SideBarComponent extends React.Component {
}));
if (this.props.folders.length) {
const folderItems = shared.renderFolders(this.props, this.folderItem.bind(this));
const result = shared.renderFolders(this.props, this.folderItem.bind(this));
const folderItems = result.items;
this.folderItemsOrder_ = result.order;
items.push(<div className="folders" key="folder_items" style={{display: this.state.folderHeaderIsExpanded ? 'block': 'none'}}>
{folderItems}</div>);
}
@@ -534,7 +685,9 @@ class SideBarComponent extends React.Component {
}));
if (this.props.tags.length) {
const tagItems = shared.renderTags(this.props, this.tagItem.bind(this));
const result = shared.renderTags(this.props, this.tagItem.bind(this));
const tagItems = result.items;
this.tagItemsOrder_ = result.order;
items.push(
<div className="tags" key="tag_items" style={{display: this.state.tagHeaderIsExpanded ? 'block': 'none'}}>
@@ -565,17 +718,23 @@ class SideBarComponent extends React.Component {
);
}
items.push(this.synchronizeButton(this.props.syncStarted ? "cancel" : "sync"));
const syncButton = this.synchronizeButton(this.props.syncStarted ? "cancel" : "sync");
items.push(
const syncReportComp = !syncReportText.length ? null : (
<div style={this.style().syncReport} key="sync_report">
{syncReportText}
</div>
);
{syncReportText}
</div>
);
return (
<div className="side-bar" style={style}>
{items}
<div ref={this.rootRef} onKeyDown={this.onKeyDown} className="side-bar" style={style}>
<div style={{flex:1, overflowY: 'auto'}}>
{items}
</div>
<div style={{flex:0}}>
{syncButton}
{syncReportComp}
</div>
</div>
);
}
@@ -597,6 +756,8 @@ const mapStateToProps = state => {
collapsedFolderIds: state.collapsedFolderIds,
decryptionWorker: state.decryptionWorker,
resourceFetcher: state.resourceFetcher,
windowCommand: state.windowCommand,
sidebarVisibility: state.sidebarVisibility,
};
};

View File

@@ -0,0 +1,137 @@
const { time } = require('lib/time-utils.js');
const BaseModel = require('lib/BaseModel');
const markJsUtils = require('lib/markJsUtils');
const { _ } = require('lib/locale.js');
const { bridge } = require('electron').remote.require('./bridge');
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
const eventManager = require('../../eventManager');
const InteropService = require('lib/services/InteropService');
const InteropServiceHelper = require('../../InteropServiceHelper.js');
const Search = require('lib/models/Search');
const Note = require('lib/models/Note');
const SearchEngine = require('lib/services/SearchEngine');
const { replaceRegexDiacritics, pregQuote, substrWithEllipsis } = require('lib/string-utils');
class NoteListUtils {
static makeContextMenu(noteIds, props) {
const notes = noteIds.map((id) => BaseModel.byId(props.notes, id));
let hasEncrypted = false;
for (let i = 0; i < notes.length; i++) {
if (!!notes[i].encryption_applied) hasEncrypted = true;
}
const menu = new Menu()
if (!hasEncrypted) {
menu.append(new MenuItem({label: _('Add or remove tags'), enabled: noteIds.length === 1, click: async () => {
props.dispatch({
type: 'WINDOW_COMMAND',
name: 'setTags',
noteId: noteIds[0],
});
}}));
menu.append(new MenuItem({label: _('Duplicate'), click: async () => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
await Note.duplicate(noteIds[i], {
uniqueTitle: _('%s - Copy', note.title),
});
}
}}));
if (noteIds.length <= 1) {
menu.append(new MenuItem({label: _('Switch between note and to-do type'), click: async () => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
await Note.save(Note.toggleIsTodo(note), { userSideValidation: true });
eventManager.emit('noteTypeToggle', { noteId: note.id });
}
}}));
} else {
const switchNoteType = async (noteIds, type) => {
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
const newNote = Note.changeNoteType(note, type);
if (newNote === note) continue;
await Note.save(newNote, { userSideValidation: true });
eventManager.emit('noteTypeToggle', { noteId: note.id });
}
}
menu.append(new MenuItem({label: _('Switch to note type'), click: async () => {
await switchNoteType(noteIds, 'note');
}}));
menu.append(new MenuItem({label: _('Switch to to-do type'), click: async () => {
await switchNoteType(noteIds, 'todo');
}}));
}
menu.append(new MenuItem({label: _('Copy Markdown link'), click: async () => {
const { clipboard } = require('electron');
const links = [];
for (let i = 0; i < noteIds.length; i++) {
const note = await Note.load(noteIds[i]);
links.push(Note.markdownTag(note));
}
clipboard.writeText(links.join(' '));
}}));
const exportMenu = new Menu();
const ioService = new InteropService();
const ioModules = ioService.modules();
for (let i = 0; i < ioModules.length; i++) {
const module = ioModules[i];
if (module.type !== 'exporter') continue;
exportMenu.append(new MenuItem({ label: module.fullLabel() , click: async () => {
await InteropServiceHelper.export(props.dispatch.bind(this), module, { sourceNoteIds: noteIds });
}}));
}
if (noteIds.length === 1) {
exportMenu.append(new MenuItem({ label: 'PDF - ' + _('PDF File') , click: () => {
props.dispatch({
type: 'WINDOW_COMMAND',
name: 'exportPdf',
});
}}));
}
const exportMenuItem = new MenuItem({label: _('Export'), submenu: exportMenu});
menu.append(exportMenuItem);
}
menu.append(new MenuItem({label: _('Delete'), click: async () => {
await this.confirmDeleteNotes(noteIds);
}}));
return menu;
}
static async confirmDeleteNotes(noteIds) {
if (!noteIds.length) return;
let msg = '';
if (noteIds.length === 1) {
const note = await Note.load(noteIds[0]);
if (!note) return;
msg = _('Delete note "%s"?', substrWithEllipsis(note.title, 0, 32));
} else {
msg = _('Delete these %d notes?', noteIds.length);
}
const ok = bridge().showConfirmMessageBox(msg);
if (!ok) return;
await Note.batchDelete(noteIds);
}
}
module.exports = NoteListUtils;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.0.124",
"version": "1.0.126",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -59,16 +59,16 @@
},
"dependencies": {
"acorn": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.2.tgz",
"integrity": "sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg=="
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz",
"integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg=="
}
}
},
"acorn-walk": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.0.tgz",
"integrity": "sha512-ugTb7Lq7u4GfWSqqpwE0bGyoBZNMTok/zDBXxfEG0QM50jNlGhIWjRC1pPN7bvV1anhF+bs+/gNcRw+o55Evbg=="
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
"integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw=="
},
"ajv": {
"version": "6.5.0",
@@ -1720,12 +1720,12 @@
}
},
"data-urls": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.1.tgz",
"integrity": "sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
"integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
"requires": {
"abab": "^2.0.0",
"whatwg-mimetype": "^2.1.0",
"whatwg-mimetype": "^2.2.0",
"whatwg-url": "^7.0.0"
},
"dependencies": {
@@ -3992,9 +3992,9 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"joplin-turndown": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.9.tgz",
"integrity": "sha512-8MOxX4t5Ai22muHhXPMGNoKc/AB7gSo0eUvNh6dyd6b3vcSiMIRZE8UHpMjS9ruJQ+8e+8TtJXc0nfbexeHwrA==",
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.11.tgz",
"integrity": "sha512-2oiwWX0nKYi1NVcaprSsrXQkYdGoRtPWFmnXdWQnQW44jlgjFV38B4VrgliwX5ZMq7cbx6A9IBwfXcBL2YV2NA==",
"requires": {
"jsdom": "^11.9.0"
}
@@ -4594,7 +4594,7 @@
},
"nan": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"resolved": "http://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA=="
},
"nanomatch": {
@@ -6651,17 +6651,17 @@
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
},
"whatwg-encoding": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz",
"integrity": "sha512-vM9KWN6MP2mIHZ86ytcyIv7e8Cj3KTfO2nd2c8PFDqcI4bxFmQp83ibq4wadq7rL9l9sZV6o9B0LTt8ygGAAXg==",
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
"integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
"requires": {
"iconv-lite": "0.4.23"
"iconv-lite": "0.4.24"
},
"dependencies": {
"iconv-lite": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
@@ -6674,9 +6674,9 @@
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
},
"whatwg-mimetype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz",
"integrity": "sha512-5YSO1nMd5D1hY3WzAQV3PzZL83W3YeyR1yW9PcH26Weh1t+Vzh9B6XkDh7aXm83HBZ4nSMvkjvN2H2ySWIvBgw=="
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
"version": "6.5.0",

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.0.124",
"version": "1.0.126",
"description": "Joplin for Desktop",
"main": "main.js",
"scripts": {
@@ -96,7 +96,7 @@
"highlight.js": "^9.12.0",
"html-entities": "^1.2.1",
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.9",
"joplin-turndown": "^4.0.11",
"joplin-turndown-plugin-gfm": "^1.0.7",
"jssha": "^2.3.1",
"katex": "^0.10.0",

View File

@@ -36,7 +36,9 @@ globalStyle.lineInput = {
fontFamily: globalStyle.fontFamily,
};
globalStyle.headerStyle = {};
globalStyle.headerStyle = {
fontFamily: globalStyle.fontFamily,
};
globalStyle.inputStyle = {
border: '1px solid',
@@ -50,6 +52,11 @@ globalStyle.containerStyle = {
globalStyle.buttonStyle = {
marginRight: 10,
border: '1px solid',
minHeight: 30,
minWidth: 80,
maxWidth: 160,
paddingLeft: 12,
paddingRight: 12,
};
const lightStyle = {
@@ -74,15 +81,14 @@ const lightStyle = {
warningBackgroundColor: "#FFD08D",
codeColor: "#EFF0F1",
codeBorderColor: '#CBCBCB',
htmlColor:'black', // Note: CSS in WebView component only supports named colors or rgb() notation
htmlColor:'#222222',
htmlBackgroundColor: 'white',
htmlDividerColor: 'rgb(150,150,150)',
htmlLinkColor: 'blue',
htmlCodeColor: 'rgb(239, 240, 241)',
htmlCodeBorderColor: 'rgb(203, 203, 203)',
htmlDividerColor: 'rgb(230,230,230)',
htmlLinkColor: 'rgb(80,130,190)',
htmlTableBackgroundColor: 'rgb(247, 247, 247)',
htmlCodeBackgroundColor: 'rgb(243, 243, 243)',
htmlCodeBorderColor: 'rgb(220, 220, 220)',
htmlCodeColor: 'rgb(0,0,0)',
editorTheme: "chrome",
codeThemeCss: "atom-one-light.css",
@@ -111,14 +117,13 @@ const darkStyle = {
warningBackgroundColor: "#CC6600",
codeColor: "#2F3031",
codeBorderColor: '#464646',
htmlColor: 'rgb(220,220,220)', // Note: CSS in WebView component only supports named colors or rgb() notation
htmlColor: 'rgb(220,220,220)',
htmlBackgroundColor: 'rgb(29,32,36)',
htmlDividerColor: 'rgb(150,150,150)',
htmlDividerColor: '#3D444E',
htmlCodeColor: '#ffffff',
htmlLinkColor: 'rgb(166,166,255)',
htmlCodeColor: 'rgb(47, 48, 49)',
htmlTableBackgroundColor: 'rgb(40, 41, 42)',
htmlCodeBackgroundColor: 'rgb(47, 48, 49)',
htmlCodeBorderColor: 'rgb(70, 70, 70)',
editorTheme: 'twilight',
@@ -192,7 +197,6 @@ function addExtraStyles(style) {
}
);
return style;
}
@@ -213,8 +217,10 @@ function themeStyle(theme) {
textAreaLineHeight: Math.round(17 * editorFontSize / 12),
// For WebView - must correspond to the properties above
htmlFontSize: Math.round(12 * zoomRatio) + 'px',
htmlLineHeight: Math.round(20 * zoomRatio) + 'px'
htmlFontSize: Math.round(15 * zoomRatio) + 'px',
htmlLineHeight: '1.6em', //Math.round(20 * zoomRatio) + 'px'
htmlCodeFontSize: '.9em',
}
let output = {};

View File

@@ -36,7 +36,7 @@ wget -O - https://raw.githubusercontent.com/laurent22/joplin/master/Joplin_insta
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://joplin.cozic.net/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.235/joplin-v1.0.235.apk)
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://joplin.cozic.net/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.236/joplin-v1.0.236.apk)
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://joplin.cozic.net/images/BadgeIOS.png'/></a> | -
## Terminal application
@@ -184,6 +184,7 @@ WebDAV-compatible services that are known to work with Joplin:
- [OwnCloud](https://owncloud.org/)
- [Seafile](https://www.seafile.com/)
- [Stack](https://www.transip.nl/stack/)
- [WebDAV Nav](https://www.schimera.com/products/webdav-nav-server/), a macOS server.
- [Zimbra](https://www.zimbra.com/)
## OneDrive synchronisation
@@ -200,6 +201,10 @@ Joplin supports end-to-end encryption (E2EE) on all the applications. E2EE is a
For a more technical description, mostly relevant for development or to review the method being used, please see the [Encryption specification](https://joplin.cozic.net/spec).
# External text editor
Joplin notes can be opened and edited using an external editor of your choice. It can be a simple text editor like Notepad++ or Sublime Text or an actual Markdown editor like Typora. In that case, images will also be displayed within the editor. To open the note in an external editor, click on the icon in the toolbar or press Ctrl+E (or Cmd+E). Your default text editor will be used to open the note. If needed, you can also specify the editor directly in the General Options, under "Text editor command".
# Attachments / Resources
Any kind of file can be attached to a note. In Markdown, links to these files are represented as a simple ID to the resource. In the note viewer, these files, if they are images, will be displayed or, if they are other files (PDF, text files, etc.) they will be displayed as links. Clicking on this link will open the file in the default application.
@@ -284,7 +289,7 @@ It is generally recommended to enter the notes as Markdown as it makes the notes
## Custom CSS
Rendered markdown can be customized by placing a userstyle file in the profile directory `~/.config/joplin-desktop/userstyle.css` (This path might be different on your device - check at the top of the Config screen for the exact path). This file supports standard CSS syntax.
Rendered markdown can be customized by placing a userstyle file in the profile directory `~/.config/joplin-desktop/userstyle.css` (This path might be different on your device - check at the top of the Config screen for the exact path). This file supports standard CSS syntax. Note that this file is used only when display the notes, **not when printing or exporting to PDF**. This is because printing has a lot more restrictions (for example, printing white text over a black background is usually not wanted), so special rules are applied to make it look good when printing, and a userstyle.css would interfer with that.
# Searching
@@ -335,29 +340,29 @@ Current translations:
<!-- LOCALE-TABLE-AUTO-GENERATED -->
&nbsp; | Language | Po File | Last translator | Percent done
---|---|---|---|---
![](https://joplin.cozic.net/images/flags/es/basque_country.png) | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 59%
![](https://joplin.cozic.net/images/flags/es/catalonia.png) | Catalan | [ca](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ca.po) | jmontane, 2018 | 84%
![](https://joplin.cozic.net/images/flags/country-4x3/hr.png) | Croatian | [hr_HR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po) | Hrvoje Mandić (trbuhom@net.hr) | 48%
![](https://joplin.cozic.net/images/flags/country-4x3/cz.png) | Czech | [cs_CZ](https://github.com/laurent22/joplin/blob/master/CliClient/locales/cs_CZ.po) | Lukas Helebrandt (lukas@aiya.cz) | 75%
![](https://joplin.cozic.net/images/flags/country-4x3/dk.png) | Dansk | [da_DK](https://github.com/laurent22/joplin/blob/master/CliClient/locales/da_DK.po) | Morten Juhl-Johansen Zölde-Fejér (mjjzf@syntaktisk. | 76%
![](https://joplin.cozic.net/images/flags/country-4x3/de.png) | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Michael Sonntag (ms@editorei.de) | 98%
![](https://joplin.cozic.net/images/flags/es/basque_country.png) | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 25%
![](https://joplin.cozic.net/images/flags/es/catalonia.png) | Catalan | [ca](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ca.po) | jmontane, 2018 | 10%
![](https://joplin.cozic.net/images/flags/country-4x3/hr.png) | Croatian | [hr_HR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po) | Hrvoje Mandić (trbuhom@net.hr) | 33%
![](https://joplin.cozic.net/images/flags/country-4x3/cz.png) | Czech | [cs_CZ](https://github.com/laurent22/joplin/blob/master/CliClient/locales/cs_CZ.po) | Lukas Helebrandt (lukas@aiya.cz) | 17%
![](https://joplin.cozic.net/images/flags/country-4x3/dk.png) | Dansk | [da_DK](https://github.com/laurent22/joplin/blob/master/CliClient/locales/da_DK.po) | Morten Juhl-Johansen Zölde-Fejér (mjjzf@syntaktisk. | 15%
![](https://joplin.cozic.net/images/flags/country-4x3/de.png) | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Michael Sonntag (ms@editorei.de) | 2%
![](https://joplin.cozic.net/images/flags/country-4x3/gb.png) | English | [en_GB](https://github.com/laurent22/joplin/blob/master/CliClient/locales/en_GB.po) | | 100%
![](https://joplin.cozic.net/images/flags/country-4x3/es.png) | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín (f@mrtn.es) | 90%
![](https://joplin.cozic.net/images/flags/country-4x3/fr.png) | Français | [fr_FR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po) | Laurent Cozic | 100%
![](https://joplin.cozic.net/images/flags/es/galicia.png) | Galician | [gl_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/gl_ES.po) | Marcos Lans (marcoslansgarza@gmail.com) | 75%
![](https://joplin.cozic.net/images/flags/country-4x3/it.png) | Italiano | [it_IT](https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po) | | 93%
![](https://joplin.cozic.net/images/flags/country-4x3/be.png) | Nederlands | [nl_BE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po) | | 60%
![](https://joplin.cozic.net/images/flags/country-4x3/nl.png) | Nederlands | [nl_NL](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_NL.po) | Heimen Stoffels (vistausss@outlook.com) | 90%
![](https://joplin.cozic.net/images/flags/country-4x3/no.png) | Norwegian | [nb_NO](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nb_NO.po) | Mats Estensen (code@mxe.no) | 97%
![](https://joplin.cozic.net/images/flags/country-4x3/br.png) | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po) | Renato Nunes Bastos (rnbastos@gmail.com) | 97%
![](https://joplin.cozic.net/images/flags/country-4x3/ro.png) | Română | [ro](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ro.po) | | 59%
![](https://joplin.cozic.net/images/flags/country-4x3/si.png) | Slovenian | [sl_SI](https://github.com/laurent22/joplin/blob/master/CliClient/locales/sl_SI.po) | | 74%
![](https://joplin.cozic.net/images/flags/country-4x3/se.png) | Svenska | [sv](https://github.com/laurent22/joplin/blob/master/CliClient/locales/sv.po) | Jonatan Nyberg (jonatan@autistici.org) | 89%
![](https://joplin.cozic.net/images/flags/country-4x3/ru.png) | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov (artyom.karlov@gmail.com) | 77%
![](https://joplin.cozic.net/images/flags/country-4x3/cn.png) | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po) | | 93%
![](https://joplin.cozic.net/images/flags/country-4x3/tw.png) | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_TW.po) | penguinsam (samliu@gmail.com) | 90%
![](https://joplin.cozic.net/images/flags/country-4x3/jp.png) | 日本語 | [ja_JP](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po) | AWASHIRO Ikuya (ikunya@gmail.com) | 97%
![](https://joplin.cozic.net/images/flags/country-4x3/kr.png) | 한국말 | [ko](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ko.po) | | 90%
![](https://joplin.cozic.net/images/flags/country-4x3/es.png) | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín (f@mrtn.es) | 6%
![](https://joplin.cozic.net/images/flags/country-4x3/fr.png) | Français | [fr_FR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po) | Laurent Cozic | 0%
![](https://joplin.cozic.net/images/flags/es/galicia.png) | Galician | [gl_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/gl_ES.po) | Marcos Lans (marcoslansgarza@gmail.com) | 17%
![](https://joplin.cozic.net/images/flags/country-4x3/it.png) | Italiano | [it_IT](https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po) | | 5%
![](https://joplin.cozic.net/images/flags/country-4x3/be.png) | Nederlands | [nl_BE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po) | | 26%
![](https://joplin.cozic.net/images/flags/country-4x3/nl.png) | Nederlands | [nl_NL](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_NL.po) | Heimen Stoffels (vistausss@outlook.com) | 6%
![](https://joplin.cozic.net/images/flags/country-4x3/no.png) | Norwegian | [nb_NO](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nb_NO.po) | Mats Estensen (code@mxe.no) | 1%
![](https://joplin.cozic.net/images/flags/country-4x3/br.png) | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po) | Renato Nunes Bastos (rnbastos@gmail.com) | 2%
![](https://joplin.cozic.net/images/flags/country-4x3/ro.png) | Română | [ro](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ro.po) | | 38%
![](https://joplin.cozic.net/images/flags/country-4x3/si.png) | Slovenian | [sl_SI](https://github.com/laurent22/joplin/blob/master/CliClient/locales/sl_SI.po) | | 17%
![](https://joplin.cozic.net/images/flags/country-4x3/se.png) | Svenska | [sv](https://github.com/laurent22/joplin/blob/master/CliClient/locales/sv.po) | Jonatan Nyberg (jonatan@autistici.org) | 7%
![](https://joplin.cozic.net/images/flags/country-4x3/ru.png) | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov (artyom.karlov@gmail.com) | 14%
![](https://joplin.cozic.net/images/flags/country-4x3/cn.png) | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po) | | 0%
![](https://joplin.cozic.net/images/flags/country-4x3/tw.png) | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_TW.po) | penguinsam (samliu@gmail.com) | 6%
![](https://joplin.cozic.net/images/flags/country-4x3/jp.png) | 日本語 | [ja_JP](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po) | AWASHIRO Ikuya (ikunya@gmail.com) | 2%
![](https://joplin.cozic.net/images/flags/country-4x3/kr.png) | 한국말 | [ko](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ko.po) | | 1%
<!-- LOCALE-TABLE-AUTO-GENERATED -->
# Known bugs

View File

@@ -90,8 +90,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097471
versionName "1.0.235"
versionCode 2097472
versionName "1.0.236"
ndk {
abiFilters "armeabi-v7a", "x86"
}
@@ -166,8 +166,8 @@ dependencies {
implementation project(':react-native-version-info')
implementation "com.facebook.react:react-native:+"
implementation "com.google.android.gms:play-services-base:16.0.1" // For Firebase
implementation 'me.leolin:ShortcutBadger:1.1.21@aar' // For Firebase - this line if you wish to use badge on Android
// implementation "com.google.android.gms:play-services-base:16.0.1" // For Firebase
// implementation 'me.leolin:ShortcutBadger:1.1.21@aar' // For Firebase - this line if you wish to use badge on Android
// To fix the error below, which happened after adding react-native-camera.
// Doesn't make any sense since rn-camera neither defines v26 nor 27 but

View File

@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>10.0.28</string>
<string>10.0.29</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>28</string>
<string>29</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>

View File

@@ -237,9 +237,30 @@ class BaseApplication {
id: state.selectedNoteIds && state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
});
} else {
const lastSelectedNoteIds = stateUtils.lastSelectedNoteIds(state);
const foundIds = [];
for (let i = 0; i < lastSelectedNoteIds.length; i++) {
const noteId = lastSelectedNoteIds[i];
let found = false;
for (let j = 0; j < notes.length; j++) {
if (notes[j].id === noteId) {
found = true;
break;
}
}
if (found) foundIds.push(noteId);
}
let selectedNoteId = null;
if (foundIds.length) {
selectedNoteId = foundIds[0];
} else {
selectedNoteId = notes.length ? notes[0].id : null;
}
this.store().dispatch({
type: 'NOTE_SELECT',
id: notes.length ? notes[0].id : null,
id: selectedNoteId,
});
}
}
@@ -543,8 +564,6 @@ class BaseApplication {
if (!currentFolder) currentFolder = await Folder.defaultFolder();
Setting.setValue('activeFolderId', currentFolder ? currentFolder.id : '');
// await this.testing();process.exit();
return argv;
}

View File

@@ -44,6 +44,23 @@ class BaseModel {
return null;
}
static modelIndexById(items, id) {
for (let i = 0; i < items.length; i++) {
if (items[i].id == id) return i;
}
return -1;
}
static modelsByIds(items, ids) {
const output = [];
for (let i = 0; i < items.length; i++) {
if (ids.indexOf(items[i].id) >= 0) {
output.push(items[i]);
}
}
return output;
}
// Prefer the use of this function to compare IDs as it handles the case where
// one ID is null and the other is "", in which case they are actually considered to be the same.
static idsEqual(id1, id2) {

View File

@@ -145,7 +145,7 @@ class ClipperServer {
const execRequest = async (request, body = '', files = []) => {
try {
const response = await this.api_.route(request.method, url.pathname, url.query, body, files);
writeResponse(200, response);
writeResponse(200, response ? response : '');
} catch (error) {
this.logger().error(error);
writeResponse(error.httpCode ? error.httpCode : 500, error.message);

View File

@@ -525,7 +525,7 @@ class MdToHtml {
b,strong{font-weight:bolder}small{font-size:80%}img{border-style:none}
`;
const fontFamily = 'sans-serif';
const fontFamily = "'Avenir', 'Arial', sans-serif";
const css = `
body {
@@ -535,28 +535,44 @@ class MdToHtml {
background-color: ` + style.htmlBackgroundColor + `;
font-family: ` + fontFamily + `;
padding-bottom: ` + options.paddingBottom + `;
/* So that, for example, highlighted text or background images are printed too, otherwise browsers tend not to print these things */
-webkit-print-color-adjust: exact;
}
p, h1, h2, h3, h4, h5, h6, ul, table {
margin-top: 0;
margin-bottom: 14px;
margin-top: .6em;
margin-bottom: .65em;
}
h1, h2, h3, h4, h5, h6 {
line-height: 1.5em;
}
h1 {
font-size: 1.5em;
font-weight: bold;
border-bottom: 1px solid ` + style.htmlDividerColor + `;
padding-bottom: .3em;
}
h2 {
font-size: 1.2em;
font-size: 1.3em;
font-weight: bold;
/ *border-bottom: 1px solid ` + style.htmlDividerColor + `;
padding-bottom: .1em; */
}
h3, h4, h5, h6 {
h3 {
font-size: 1.1em;
}
h4, h5, h6 {
font-size: 1em;
font-weight: bold;
}
a {
color: ` + style.htmlLinkColor + `
color: ` + style.htmlLinkColor + `;
}
ul {
padding-left: 1.3em;
ul, ol {
padding-left: 0;
margin-left: 1.7em;
}
li {
margin-bottom: .4em;
}
li p {
margin-bottom: 0;
@@ -567,7 +583,7 @@ class MdToHtml {
top: .5em;
text-decoration: none;
width: 1.15em;
height: 1.5em;
height: 1.45em;
margin-right: 0.4em;
background-color: ` + style.htmlColor + `;
/* Awesome Font file */
@@ -590,30 +606,51 @@ class MdToHtml {
/* Awesome Font check-square-o */
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1792 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1472 930v318q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q63 0 117 25 15 7 18 23 3 17-9 29l-49 49q-10 10-23 10-3 0-9-2-23-6-45-6h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-254q0-13 9-22l64-64q10-10 23-10 6 0 12 3 20 8 20 29zm231-489l-814 814q-24 24-57 24t-57-24l-430-430q-24-24-24-57t24-57l110-110q24-24 57-24t57 24l263 263 647-647q24-24 57-24t57 24l110 110q24 24 24 57t-24 57z'/></svg>");
}
blockquote {
border-left: 4px solid ` + style.htmlCodeBorderColor + `;
padding-left: 1.2em;
margin-left: 0;
opacity: .7;
}
table {
text-align: left-align;
border-collapse: collapse;
border: 1px solid ` + style.htmlCodeBorderColor + `;
background-color: ` + style.htmlBackgroundColor + `;
}
td, th {
border: 1px solid silver;
padding: .5em 1em .5em 1em;
font-size: ` + style.htmlFontSize + `;
color: ` + style.htmlColor + `;
background-color: ` + style.htmlBackgroundColor + `;
font-family: ` + fontFamily + `;
}
td {
border: 1px solid ` + style.htmlCodeBorderColor + `;
}
th {
border: 1px solid ` + style.htmlCodeBorderColor + `;
border-bottom: 2px solid ` + style.htmlCodeBorderColor + `;
background-color: ` + style.htmlTableBackgroundColor + `;
}
tr:nth-child(even) {
background-color: ` + style.htmlTableBackgroundColor + `;
}
hr {
border: none;
border-bottom: 1px solid ` + style.htmlDividerColor + `;
border-bottom: 2px solid ` + style.htmlDividerColor + `;
}
img {
/* width: auto; */
max-width: 100%;
height: auto;
}
.inline-code {
border: 1px solid ` + style.htmlCodeBorderColor + `;
background-color: ` + style.htmlCodeColor + `;
background-color: ` + style.htmlCodeBackgroundColor + `;
padding-right: .2em;
padding-left: .2em;
border-radius: .25em;
color: ` + style.htmlCodeColor + `;
font-size: ` + style.htmlCodeFontSize + `;
}
.highlighted-keyword {
@@ -635,24 +672,9 @@ class MdToHtml {
height: auto !important;
}
a.checkbox {
border: 1pt solid ` + style.htmlColor + `;
border-radius: 2pt;
width: 1em;
height: 1em;
line-height: 1em;
text-align: center;
top: .4em;
}
a.checkbox.tick:after {
content: "X";
}
a.checkbox.tick {
top: 0;
left: -0.02em;
color: ` + style.htmlColor + `;
/* Checkbox ticks are displayed upside down when printed for some reason */
transform: scaleY(-1);
}
pre {
@@ -665,10 +687,35 @@ class MdToHtml {
}
`;
// To style the checkboxes in print when webkit-print-color-adjust is not enabled.
// Keep it there for now in case that CSS parameter needs to be removed.
// a.checkbox {
// border: 1pt solid ` + style.htmlColor + `;
// border-radius: 2pt;
// width: 1em;
// height: 1em;
// line-height: 1em;
// text-align: center;
// top: .4em;
// }
// a.checkbox.tick:after {
// content: "X";
// }
// a.checkbox.tick {
// top: 0;
// left: -0.02em;
// color: ` + style.htmlColor + `;
// }
const styleHtml = '<style>' + normalizeCss + "\n" + css + '</style>';
const output = styleHtml + renderedBody;
// console.info('<!DOCTYPE html><html><head><meta charset="UTF-8">' + output + '</body></html>');
this.cachedContent_ = output;
this.cachedContentKey_ = cacheKey;
return this.cachedContent_;

View File

@@ -41,7 +41,7 @@ class WebDavApi {
}
baseUrl() {
return this.options_.baseUrl();
return rtrimSlashes(this.options_.baseUrl());
}
relativeBaseUrl() {
@@ -216,7 +216,71 @@ class WebDavApi {
output.push(url);
return output.join(' ');
}
}
handleNginxHack_(jsonResponse, newErrorHandler) {
// Trying to fix 404 error issue with Nginx WebDAV server.
// https://github.com/laurent22/joplin/issues/624
// https://github.com/laurent22/joplin/issues/808
// Not tested but someone confirmed it worked - https://github.com/laurent22/joplin/issues/808#issuecomment-443552858
// and fix is narrowly scoped so shouldn't affect anything outside this particular edge case.
//
// The issue is that instead of an HTTP 404 status code, Nginx returns 200 but with this response:
//
// <?xml version="1.0" encoding="utf-8" ?>
// <D:multistatus xmlns:D="DAV:">
// <D:response>
// <D:href>/notes/ecd4027a5271483984b00317433e2c66.md</D:href>
// <D:propstat>
// <D:prop/>
// <D:status>HTTP/1.1 404 Not Found</D:status>
// </D:propstat>
// </D:response>
// </D:multistatus>
//
// So we need to parse this and find that it is in fact a 404 error.
//
// HOWEVER, some implementations also return 404 for missing props, for example SeaFile:
// (indicates that the props "getlastmodified" is not present, but this call is only
// used when checking the conf, so we don't really need it)
// https://github.com/laurent22/joplin/issues/1137
//
// <?xml version='1.0' encoding='UTF-8'?>
// <ns0:multistatus xmlns:ns0="DAV:">
// <ns0:response>
// <ns0:href>/seafdav/joplin/</ns0:href>
// <ns0:propstat>
// <ns0:prop>
// <ns0:getlastmodified/>
// </ns0:prop>
// <ns0:status>HTTP/1.1 404 Not Found</ns0:status>
// </ns0:propstat>
// <ns0:propstat>
// <ns0:prop>
// <ns0:resourcetype>
// <ns0:collection/>
// </ns0:resourcetype>
// </ns0:prop>
// <ns0:status>HTTP/1.1 200 OK</ns0:status>
// </ns0:propstat>
// </ns0:response>
// </ns0:multistatus>
//
// As a simple fix for now it's enough to check if ALL the statuses are 404 - in that case
// it really means that the file doesn't exist. Otherwise we can proceed as usual.
const responseArray = this.arrayFromJson(jsonResponse, ['d:multistatus', 'd:response']);
if (responseArray && responseArray.length === 1) {
const propStats = this.arrayFromJson(jsonResponse, ['d:multistatus', 'd:response', 0, 'd:propstat']);
if (!propStats.length) return;
let count404 = 0;
for (let i = 0; i < propStats.length; i++) {
const status = this.arrayFromJson(jsonResponse, ['d:multistatus', 'd:response', 0, 'd:propstat', i, 'd:status']);
if (status && status.length && status[0].indexOf('404') >= 0) count404++;
}
if (count404 === propStats.length) throw newErrorHandler('Not found', 404);
}
}
// curl -u admin:123456 'http://nextcloud.local/remote.php/dav/files/admin/' -X PROPFIND --data '<?xml version="1.0" encoding="UTF-8"?>
// <d:propfind xmlns:d="DAV:">
@@ -321,17 +385,7 @@ class WebDavApi {
if (['MKCOL', 'DELETE', 'PUT', 'MOVE'].indexOf(method) >= 0) return null;
const output = await loadResponseJson();
// Trying to fix 404 error issue with Nginx WebDAV server.
// https://github.com/laurent22/joplin/issues/624
// https://github.com/laurent22/joplin/issues/808
// Not tested but someone confirmed it worked - https://github.com/laurent22/joplin/issues/808#issuecomment-443552858
// and fix is narrowly scoped so shouldn't affect anything outside this particular edge case.
const responseArray = this.arrayFromJson(output, ['d:multistatus', 'd:response']);
if (responseArray && responseArray.length === 1) {
const status = this.stringFromJson(output, ['d:multistatus', 'd:response', 0, 'd:propstat', 0, 'd:status', 0]);
if (status && status.indexOf('404') >= 0) throw newError('Not found', 404);
}
this.handleNginxHack_(output, newError);
// Check that we didn't get for example an HTML page (as an error) instead of the JSON response
// null responses are possible, for example for DELETE calls

View File

@@ -0,0 +1,118 @@
const welcomeAssets = require('./welcomeAssets');
const Note = require('lib/models/Note');
const Setting = require('lib/models/Setting');
const Folder = require('lib/models/Folder');
const Tag = require('lib/models/Tag');
const Resource = require('lib/models/Resource');
const { shim } = require('lib/shim');
const { uuid } = require('lib/uuid');
const { fileExtension, basename} = require('lib/path-utils');
const { pregQuote } = require('lib/string-utils');
class WelcomeUtils {
static async createWelcomeItems() {
const overwriteExisting = Setting.value('env') === 'dev';
const output = {
defaultFolderId: null,
};
const noteAssets = welcomeAssets.notes;
const folderAssets = welcomeAssets.folders;
const tempDir = Setting.value('resourceDir');
for (let i = 0; i < folderAssets.length; i++) {
const folderAsset = folderAssets[i];
const folderId = folderAsset.id;
if (!output.defaultFolderId) output.defaultFolderId = folderId;
let existingFolder = await Folder.load(folderId);
if (existingFolder && overwriteExisting) {
await Folder.delete(existingFolder.id);
existingFolder = null;
}
if (existingFolder) continue;
await Folder.save({
id: folderId,
title: folderAsset.title,
}, { isNew: true });
}
for (let i = noteAssets.length - 1; i >= 0; i--) {
const noteAsset = noteAssets[i];
const noteId = noteAsset.id;
let existingNote = await Note.load(noteId);
if (existingNote && overwriteExisting) {
await Note.delete(existingNote.id);
existingNote = null;
}
if (existingNote) continue;
let noteBody = noteAsset.body;
for (let resourceUrl in noteAsset.resources) {
if (!noteAsset.resources.hasOwnProperty(resourceUrl)) continue;
const resourceAsset = noteAsset.resources[resourceUrl];
const resourceId = resourceAsset.id;
let existingResource = await Resource.load(resourceId);
if (existingResource && overwriteExisting) {
await Resource.delete(resourceId);
existingResource = null;
}
if (!existingResource) {
const ext = fileExtension(resourceUrl);
const tempFilePath = tempDir + '/' + uuid.create() + '.tmp.' + ext;
await shim.fsDriver().writeFile(tempFilePath, resourceAsset.body, 'base64');
await shim.createResourceFromPath(tempFilePath, {
id: resourceId,
title: basename(resourceUrl),
});
await shim.fsDriver().remove(tempFilePath);
}
const regex = new RegExp(pregQuote('(' + resourceUrl + ')'), 'g');
noteBody = noteBody.replace(regex, '(:/' + resourceId + ')');
}
await Note.save({
id: noteId,
parent_id: noteAsset.parent_id,
title: noteAsset.title,
body: noteBody,
}, { isNew: true });
if (noteAsset.tags) await Tag.setNoteTagsByTitles(noteId, noteAsset.tags);
}
return output;
}
static async install(dispatch) {
if (!Setting.value('welcome.wasBuilt')) {
const result = await WelcomeUtils.createWelcomeItems();
Setting.setValue('welcome.wasBuilt', true);
dispatch({
type: 'FOLDER_SELECT',
id: result.defaultFolderId,
});
Setting.setValue('activeFolderId', result.defaultFolderId);
}
}
}
module.exports = WelcomeUtils;

View File

@@ -27,11 +27,15 @@ const globalStyle = {
// For WebView - must correspond to the properties above
htmlFontSize: '16px',
htmlColor: 'black', // Note: CSS in WebView component only supports named colors or rgb() notation
htmlColor: '#222222',
htmlBackgroundColor: 'white',
htmlDividerColor: 'Gainsboro',
htmlLinkColor: 'blue',
htmlLineHeight: '20px',
htmlDividerColor: 'rgb(230,230,230)',
htmlLinkColor: 'rgb(80,130,190)',
htmlLineHeight: '1.6em',
htmlCodeBackgroundColor: 'rgb(243, 243, 243)',
htmlCodeBorderColor: 'rgb(220, 220, 220)',
htmlCodeColor: 'rgb(0,0,0)',
};
globalStyle.marginRight = globalStyle.margin;
@@ -40,28 +44,6 @@ globalStyle.marginTop = globalStyle.margin;
globalStyle.marginBottom = globalStyle.margin;
globalStyle.htmlMarginLeft = ((globalStyle.marginLeft / 10) * 0.6).toFixed(2) + 'em';
// globalStyle.icon = {
// color: globalStyle.color,
// fontSize: 30,
// };
// globalStyle.lineInput = {
// color: globalStyle.color,
// backgroundColor: globalStyle.backgroundColor,
// };
// globalStyle.buttonRow = {
// flexDirection: 'row',
// borderTopWidth: 1,
// borderTopColor: globalStyle.dividerColor,
// paddingTop: 10,
// };
// globalStyle.normalText = {
// color: globalStyle.color,
// fontSize: globalStyle.fontSize,
// };
let themeCache_ = {};
function addExtraStyles(style) {
@@ -79,8 +61,8 @@ function addExtraStyles(style) {
};
if (Platform.OS === 'ios') {
style.lineInput.borderBottomWidth = 1;
style.lineInput.borderBottomColor = style.dividerColor;
delete style.lineInput.borderBottomWidth;
delete style.lineInput.borderColor;
}
style.buttonRow = {
@@ -130,6 +112,12 @@ function themeStyle(theme) {
output.htmlBackgroundColor = 'rgb(29,32,36)';
output.htmlLinkColor = 'rgb(166,166,255)';
output.htmlDividerColor = '#3D444E';
output.htmlLinkColor = 'rgb(166,166,255)';
output.htmlCodeColor = '#ffffff';
output.htmlCodeBackgroundColor = 'rgb(47, 48, 49)';
output.htmlCodeBorderColor = 'rgb(70, 70, 70)';
output.colorUrl = '#7B81FF';
themeCache_[theme] = output;

View File

@@ -71,15 +71,17 @@ class SearchScreenComponent extends BaseScreenComponent {
this.isMounted_ = false;
}
UNSAFE_componentWillReceiveProps(newProps) {
let newState = {};
if ('query' in newProps) newState.query = newProps.query;
// UNSAFE_componentWillReceiveProps(newProps) {
// console.info('UNSAFE_componentWillReceiveProps', newProps);
if (Object.getOwnPropertyNames(newState).length) {
this.setState(newState);
this.refreshSearch(newState.query);
}
}
// let newState = {};
// if ('query' in newProps && !this.state.query) newState.query = newProps.query;
// if (Object.getOwnPropertyNames(newState).length) {
// this.setState(newState);
// this.refreshSearch(newState.query);
// }
// }
searchTextInput_submit() {
const query = this.state.query.trim();
@@ -89,6 +91,9 @@ class SearchScreenComponent extends BaseScreenComponent {
type: 'SEARCH_QUERY',
query: query,
});
this.setState({ query: query });
this.refreshSearch(query);
}
clearButton_press() {
@@ -96,6 +101,9 @@ class SearchScreenComponent extends BaseScreenComponent {
type: 'SEARCH_QUERY',
query: '',
});
this.setState({ query: '' });
this.refreshSearch('');
}
async refreshSearch(query = null) {

View File

@@ -79,4 +79,31 @@ shared.settingsToComponents = function(comp, device, settings) {
return settingComps
}
shared.settingsToComponents2 = function(comp, device, settings) {
const keys = Setting.keys(true, device);
const sectionComps = [];
const metadatas = [];
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (!Setting.isPublic(key)) continue;
const md = Setting.settingMetadata(key);
if (md.show && !md.show(settings)) continue;
metadatas.push(md);
}
const sections = Setting.groupMetadatasBySections(metadatas);
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
const sectionComp = comp.sectionToComponent(section.name, section, settings);
if (!sectionComp) continue;
sectionComps.push(sectionComp);
}
return sectionComps
}
module.exports = shared;

View File

@@ -3,15 +3,22 @@ const Folder = require('lib/models/Folder.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const Mutex = require('async-mutex').Mutex;
const shared = {};
// If saveNoteButton_press is called multiple times in short intervals, it might result in
// the same new note being created twice, so we need to a mutex to access this function.
const saveNoteMutex_ = new Mutex();
shared.noteExists = async function(noteId) {
const existingNote = await Note.load(noteId);
return !!existingNote;
}
shared.saveNoteButton_press = async function(comp, folderId = null) {
const releaseMutex = await saveNoteMutex_.acquire();
let note = Object.assign({}, comp.state.note);
// Note has been deleted while user was modifying it. In that case, we
@@ -24,7 +31,7 @@ shared.saveNoteButton_press = async function(comp, folderId = null) {
const activeFolderId = Setting.value('activeFolderId');
let folder = await Folder.load(activeFolderId);
if (!folder) folder = await Folder.defaultFolder();
if (!folder) return;
if (!folder) return releaseMutex();
note.parent_id = folder.id;
}
@@ -46,7 +53,7 @@ shared.saveNoteButton_press = async function(comp, folderId = null) {
const stateNote = comp.state.note;
// Note was reloaded while being saved.
if (!isNew && (!stateNote || stateNote.id !== savedNote.id)) return;
if (!isNew && (!stateNote || stateNote.id !== savedNote.id)) return releaseMutex();
// Re-assign any property that might have changed during saving (updated_time, etc.)
note = Object.assign(note, savedNote);
@@ -105,6 +112,8 @@ shared.saveNoteButton_press = async function(comp, folderId = null) {
id: savedNote.id,
});
}
releaseMutex();
}
shared.saveOneProperty = async function(comp, name, value) {

View File

@@ -26,43 +26,61 @@ function folderIsVisible(folders, folderId, collapsedFolderIds) {
return true;
}
function renderFoldersRecursive_(props, renderItem, items, parentId, depth) {
function renderFoldersRecursive_(props, renderItem, items, parentId, depth, order) {
const folders = props.folders;
for (let i = 0; i < folders.length; i++) {
let folder = folders[i];
if (!Folder.idsEqual(folder.parent_id, parentId)) continue;
if (!folderIsVisible(props.folders, folder.id, props.collapsedFolderIds)) continue;
const hasChildren = folderHasChildren_(folders, folder.id);
order.push(folder.id);
items.push(renderItem(folder, props.selectedFolderId == folder.id && props.notesParentType == 'Folder', hasChildren, depth));
if (hasChildren) items = renderFoldersRecursive_(props, renderItem, items, folder.id, depth + 1);
if (hasChildren) {
const result = renderFoldersRecursive_(props, renderItem, items, folder.id, depth + 1, order);
items = result.items;
order = result.order;
}
}
return items;
return {
items: items,
order: order,
};
}
shared.renderFolders = function(props, renderItem) {
return renderFoldersRecursive_(props, renderItem, [], '', 0);
return renderFoldersRecursive_(props, renderItem, [], '', 0, []);
}
shared.renderTags = function(props, renderItem) {
let tags = props.tags.slice();
tags.sort((a, b) => { return a.title < b.title ? -1 : +1; });
let tagItems = [];
const order = [];
for (let i = 0; i < tags.length; i++) {
const tag = tags[i];
order.push(tag.id);
tagItems.push(renderItem(tag, props.selectedTagId == tag.id && props.notesParentType == 'Tag'));
}
return tagItems;
return {
items: tagItems,
order: order,
};
}
shared.renderSearches = function(props, renderItem) {
let searches = props.searches.slice();
let searchItems = [];
for (let i = 0; i < searches.length; i++) {
const search = searches[i];
searchItems.push(renderItem(search, props.selectedSearchId == search.id && props.notesParentType == 'Search'));
}
return searchItems;
}
// shared.renderSearches = function(props, renderItem) {
// let searches = props.searches.slice();
// let searchItems = [];
// const order = [];
// for (let i = 0; i < searches.length; i++) {
// const search = searches[i];
// order.push(search.id);
// searchItems.push(renderItem(search, props.selectedSearchId == search.id && props.notesParentType == 'Search'));
// }
// return {
// items: searchItems,
// order: order,
// };
// }
shared.synchronize_press = async function(comp) {
const Setting = require('lib/models/Setting.js');

View File

@@ -200,13 +200,15 @@ class SideMenuContentComponent extends Component {
items.push(<View style={{ height: globalStyle.marginTop }} key='bottom_top_hack'/>);
if (this.props.folders.length) {
const folderItems = shared.renderFolders(this.props, this.folderItem.bind(this));
const result = shared.renderFolders(this.props, this.folderItem.bind(this));
const folderItems = result.items;
items = items.concat(folderItems);
if (items.length) items.push(this.makeDivider('divider_1'));
}
if (this.props.tags.length) {
const tagItems = shared.renderTags(this.props, this.tagItem.bind(this));
const result = shared.renderTags(this.props, this.tagItem.bind(this));
const tagItems = result.items;
items.push(
<View style={this.styles().tagItemList} key="tag_items">

View File

@@ -364,7 +364,7 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
note.longitude = noteAttributes.longitude;
note.altitude = noteAttributes.altitude;
note.author = noteAttributes.author;
note.is_todo = !!noteAttributes['reminder-order'];
note.is_todo = noteAttributes['reminder-order'] !== '0' && !!noteAttributes['reminder-order'];
note.todo_due = dateToTimestamp(noteAttributes['reminder-time'], true);
note.todo_completed = dateToTimestamp(noteAttributes['reminder-done-time'], true);
note.order = dateToTimestamp(noteAttributes['reminder-order'], true);

View File

@@ -4,6 +4,8 @@ const BaseItem = require('lib/models/BaseItem.js');
const ItemChange = require('lib/models/ItemChange.js');
const Setting = require('lib/models/Setting.js');
const { shim } = require('lib/shim.js');
const { pregQuote } = require('lib/string-utils.js');
const { toSystemSlashes } = require('lib/path-utils.js');
const { time } = require('lib/time-utils.js');
const { _ } = require('lib/locale.js');
const ArrayUtils = require('lib/ArrayUtils.js');
@@ -27,7 +29,7 @@ class Note extends BaseItem {
}
static async serializeForEdit(note) {
return super.serialize(note, ['title', 'body']);
return this.replaceResourceInternalToExternalLinks(await super.serialize(note, ['title', 'body']));
}
static async unserializeForEdit(content) {
@@ -35,6 +37,7 @@ class Note extends BaseItem {
let output = await super.unserialize(content);
if (!output.title) output.title = '';
if (!output.body) output.body = '';
output.body = await this.replaceResourceExternalToInternalLinks(output.body);
return output;
}
@@ -165,6 +168,30 @@ class Note extends BaseItem {
return await this.linkedItemIdsByType(BaseModel.TYPE_RESOURCE, body);
}
static async replaceResourceInternalToExternalLinks(body) {
const resourceIds = await this.linkedResourceIds(body);
const Resource = this.getClass('Resource');
for (let i = 0; i < resourceIds.length; i++) {
const id = resourceIds[i];
const resource = await Resource.load(id);
if (!resource) continue;
body = body.replace(new RegExp(':/' + id, 'gi'), toSystemSlashes(Resource.fullPath(resource)));
}
return body;
}
static async replaceResourceExternalToInternalLinks(body) {
const reString = pregQuote(toSystemSlashes(Resource.baseDirectoryPath() + '/')) + '[a-zA-Z0-9\.]+';
const re = new RegExp(reString, 'gi');
body = body.replace(re, (match) => {
const id = Resource.pathToId(match);
return ':/' + id;
});
return body;
}
static new(parentId = '') {
let output = super.new();
output.parent_id = parentId;
@@ -447,6 +474,19 @@ class Note extends BaseItem {
return this.changeNoteType(note, !!note.is_todo ? 'note' : 'todo');
}
static toggleTodoCompleted(note) {
if (!('todo_completed' in note)) throw new Error('Missing "todo_completed" property');
note = Object.assign({}, note);
if (note.todo_completed) {
note.todo_completed = 0;
} else {
note.todo_completed = Date.now();
}
return note;
}
static async duplicate(noteId, options = null) {
const changes = options && options.changes;
const uniqueTitle = options && options.uniqueTitle;

View File

@@ -63,6 +63,10 @@ class Resource extends BaseItem {
return output + extension;
}
static baseDirectoryPath() {
return Setting.value('resourceDir');
}
static fullPath(resource, encryptedBlob = false) {
return Setting.value('resourceDir') + '/' + this.filename(resource, encryptedBlob);
}

View File

@@ -53,15 +53,15 @@ class Setting extends BaseModel {
options[Setting.TIME_FORMAT_2] = time.formatMsToLocal(now, Setting.TIME_FORMAT_2);
return options;
}},
'theme': { value: Setting.THEME_LIGHT, type: Setting.TYPE_INT, public: true, appTypes: ['mobile', 'desktop'], isEnum: true, label: () => _('Theme'), options: () => {
'theme': { value: Setting.THEME_LIGHT, type: Setting.TYPE_INT, public: true, appTypes: ['mobile', 'desktop'], isEnum: true, label: () => _('Theme'), section: 'appearance', options: () => {
let output = {};
output[Setting.THEME_LIGHT] = _('Light');
output[Setting.THEME_DARK] = _('Dark');
return output;
}},
'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, public: true, appTypes: ['cli'], label: () => _('Uncompleted to-dos on top') },
'showCompletedTodos': { value: true, type: Setting.TYPE_BOOL, public: true, appTypes: ['cli'], label: () => _('Show completed to-dos') },
'notes.sortOrder.field': { value: 'user_updated_time', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['cli'], label: () => _('Sort notes by'), options: () => {
'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, section: 'note', public: true, appTypes: ['cli'], label: () => _('Uncompleted to-dos on top') },
'showCompletedTodos': { value: true, type: Setting.TYPE_BOOL, section: 'note', public: true, appTypes: ['cli'], label: () => _('Show completed to-dos') },
'notes.sortOrder.field': { value: 'user_updated_time', type: Setting.TYPE_STRING, section: 'note', isEnum: true, public: true, appTypes: ['cli'], label: () => _('Sort notes by'), options: () => {
const Note = require('lib/models/Note');
const noteSortFields = ['user_updated_time', 'user_created_time', 'title'];
const options = {};
@@ -70,15 +70,15 @@ class Setting extends BaseModel {
}
return options;
}},
'notes.sortOrder.reverse': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Reverse sort order'), appTypes: ['cli'] },
'trackLocation': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Save geo-location with notes') },
'newTodoFocus': { value: 'title', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['desktop'], label: () => _('When creating a new to-do:'), options: () => {
'notes.sortOrder.reverse': { value: true, type: Setting.TYPE_BOOL, section: 'note', public: true, label: () => _('Reverse sort order'), appTypes: ['cli'] },
'trackLocation': { value: true, type: Setting.TYPE_BOOL, section: 'note', public: true, label: () => _('Save geo-location with notes') },
'newTodoFocus': { value: 'title', type: Setting.TYPE_STRING, section: 'note', isEnum: true, public: true, appTypes: ['desktop'], label: () => _('When creating a new to-do:'), options: () => {
return {
'title': _('Focus title'),
'body': _('Focus body'),
};
}},
'newNoteFocus': { value: 'body', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['desktop'], label: () => _('When creating a new note:'), options: () => {
'newNoteFocus': { value: 'body', type: Setting.TYPE_STRING, section: 'note', isEnum: true, public: true, appTypes: ['desktop'], label: () => _('When creating a new note:'), options: () => {
return {
'title': _('Focus title'),
'body': _('Focus body'),
@@ -89,11 +89,11 @@ class Setting extends BaseModel {
// http://www.webupd8.org/2017/04/fix-appindicator-not-working-for.html
// Might be fixed in Electron 18.x but no non-beta release yet. So for now
// by default we disable it on Linux.
'showTrayIcon': { value: platform !== 'linux', type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Show tray icon'), description: () => {
'showTrayIcon': { value: platform !== 'linux', type: Setting.TYPE_BOOL, section:'application', public: true, appTypes: ['desktop'], label: () => _('Show tray icon'), description: () => {
return platform === 'linux' ? _('Note: Does not work in all desktop environments.') : _('This will allow Joplin to run in the background. It is recommended to enable this setting so that your notes are constantly being synchronised, thus reducing the number of conflicts.');
}},
'startMinimized': { value: false, type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Start application minimised in the tray icon') },
'startMinimized': { value: false, type: Setting.TYPE_BOOL, section:'application', public: true, appTypes: ['desktop'], label: () => _('Start application minimised in the tray icon') },
'collapsedFolderIds': { value: [], type: Setting.TYPE_ARRAY, public: false },
@@ -101,13 +101,13 @@ class Setting extends BaseModel {
'encryption.enabled': { value: false, type: Setting.TYPE_BOOL, public: false },
'encryption.activeMasterKeyId': { value: '', type: Setting.TYPE_STRING, public: false },
'encryption.passwordCache': { value: {}, type: Setting.TYPE_OBJECT, public: false, secure: true },
'style.zoom': {value: 100, type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], label: () => _('Global zoom percentage'), minimum: 50, maximum: 500, step: 10},
'style.editor.fontSize': {value: 12, type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], label: () => _('Editor font size'), minimum: 4, maximum: 50, step: 1},
'style.editor.fontFamily': {value: "", type: Setting.TYPE_STRING, public: true, appTypes: ['desktop'], label: () => _('Editor font family'), description: () => _('This must be *monospace* font or it will not work properly. If the font is incorrect or empty, it will default to a generic monospace font.')},
'autoUpdateEnabled': { value: true, type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Automatically update the application') },
'autoUpdate.includePreReleases': { value: false, type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Get pre-releases when checking for updates'), description: () => _('See the pre-release page for more details: %s', 'https://joplin.cozic.net/prereleases') },
'style.zoom': {value: 100, type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], section: 'appearance', label: () => _('Global zoom percentage'), minimum: 50, maximum: 500, step: 10},
'style.editor.fontSize': {value: 13, type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], section: 'appearance', label: () => _('Editor font size'), minimum: 4, maximum: 50, step: 1},
'style.editor.fontFamily': {value: "", type: Setting.TYPE_STRING, public: true, appTypes: ['desktop'], section: 'appearance', label: () => _('Editor font family'), description: () => _('This must be *monospace* font or it will not work properly. If the font is incorrect or empty, it will default to a generic monospace font.')},
'autoUpdateEnabled': { value: true, type: Setting.TYPE_BOOL, section:'application', public: true, appTypes: ['desktop'], label: () => _('Automatically update the application') },
'autoUpdate.includePreReleases': { value: false, type: Setting.TYPE_BOOL, section:'application', public: true, appTypes: ['desktop'], label: () => _('Get pre-releases when checking for updates'), description: () => _('See the pre-release page for more details: %s', 'https://joplin.cozic.net/prereleases') },
'clipperServer.autoStart': { value: false, type: Setting.TYPE_BOOL, public: false },
'sync.interval': { value: 300, type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation interval'), options: () => {
'sync.interval': { value: 300, type: Setting.TYPE_INT, section:'sync', isEnum: true, public: true, label: () => _('Synchronisation interval'), options: () => {
return {
0: _('Disabled'),
300: _('%d minutes', 5),
@@ -122,13 +122,13 @@ class Setting extends BaseModel {
'sidebarVisibility': { value: true, type: Setting.TYPE_BOOL, public: false, appTypes: ['desktop'] },
'tagHeaderIsExpanded': { value: true, type: Setting.TYPE_BOOL, public: false, appTypes: ['desktop'] },
'folderHeaderIsExpanded': { value: true, type: Setting.TYPE_BOOL, public: false, appTypes: ['desktop'] },
'editor': { value: '', type: Setting.TYPE_STRING, public: true, appTypes: ['cli', 'desktop'], label: () => _('Text editor command'), description: () => _('The editor command (may include arguments) that will be used to open a note. If none is provided it will try to auto-detect the default editor.') },
'editor': { value: '', type: Setting.TYPE_STRING, subType: 'file_path_and_args', public: true, appTypes: ['cli', 'desktop'], label: () => _('Text editor command'), description: () => _('The editor command (may include arguments) that will be used to open a note. If none is provided it will try to auto-detect the default editor.') },
'showAdvancedOptions': { value: false, type: Setting.TYPE_BOOL, public: true, appTypes: ['mobile' ], label: () => _('Show advanced options') },
'sync.target': { value: SyncTargetRegistry.nameToId('dropbox'), type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation target'), description: (appType) => { return appType !== 'cli' ? null : _('The target to synchonise to. Each sync target may have additional parameters which are named as `sync.NUM.NAME` (all documented below).') }, options: () => {
'sync.target': { value: SyncTargetRegistry.nameToId('dropbox'), type: Setting.TYPE_INT, isEnum: true, public: true, section:'sync', label: () => _('Synchronisation target'), description: (appType) => { return appType !== 'cli' ? null : _('The target to synchonise to. Each sync target may have additional parameters which are named as `sync.NUM.NAME` (all documented below).') }, options: () => {
return SyncTargetRegistry.idAndLabelPlainObject();
}},
'sync.2.path': { value: '', type: Setting.TYPE_STRING, show: (settings) => {
'sync.2.path': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => {
try {
return settings['sync.target'] == SyncTargetRegistry.nameToId('filesystem')
} catch (error) {
@@ -138,13 +138,13 @@ class Setting extends BaseModel {
return value ? rtrimSlashes(value) : '';
}, public: true, label: () => _('Directory to synchronise with (absolute path)'), description: (appType) => { return appType !== 'cli' ? null : _('The path to synchronise with when file system synchronisation is enabled. See `sync.target`.'); } },
'sync.5.path': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud WebDAV URL'), description: () => _('Attention: If you change this location, make sure you copy all your content to it before syncing, otherwise all files will be removed! See the FAQ for more details: %s', 'https://joplin.cozic.net/faq/') },
'sync.5.username': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud username') },
'sync.5.password': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud password'), secure: true },
'sync.5.path': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud WebDAV URL'), description: () => _('Attention: If you change this location, make sure you copy all your content to it before syncing, otherwise all files will be removed! See the FAQ for more details: %s', 'https://joplin.cozic.net/faq/') },
'sync.5.username': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud username') },
'sync.5.password': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud password'), secure: true },
'sync.6.path': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('webdav') }, public: true, label: () => _('WebDAV URL'), description: () => _('Attention: If you change this location, make sure you copy all your content to it before syncing, otherwise all files will be removed! See the FAQ for more details: %s', 'https://joplin.cozic.net/faq/') },
'sync.6.username': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('webdav') }, public: true, label: () => _('WebDAV username') },
'sync.6.password': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('webdav') }, public: true, label: () => _('WebDAV password'), secure: true },
'sync.6.path': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('webdav') }, public: true, label: () => _('WebDAV URL'), description: () => _('Attention: If you change this location, make sure you copy all your content to it before syncing, otherwise all files will be removed! See the FAQ for more details: %s', 'https://joplin.cozic.net/faq/') },
'sync.6.username': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('webdav') }, public: true, label: () => _('WebDAV username') },
'sync.6.password': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('webdav') }, public: true, label: () => _('WebDAV password'), secure: true },
'sync.3.auth': { value: '', type: Setting.TYPE_STRING, public: false },
'sync.4.auth': { value: '', type: Setting.TYPE_STRING, public: false },
@@ -157,14 +157,15 @@ class Setting extends BaseModel {
'sync.6.context': { value: '', type: Setting.TYPE_STRING, public: false },
'sync.7.context': { value: '', type: Setting.TYPE_STRING, public: false },
'net.customCertificates': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return [SyncTargetRegistry.nameToId('nextcloud'), SyncTargetRegistry.nameToId('webdav')].indexOf(settings['sync.target']) >= 0 }, public: true, appTypes: ['desktop', 'cli'], label: () => _('Custom TLS certificates'), description: () => _('Comma-separated list of paths to directories to load the certificates from, or path to individual cert files. For example: /my/cert_dir, /other/custom.pem. Note that if you make changes to the TLS settings, you must save your changes before clicking on "Check synchronisation configuration".') },
'net.ignoreTlsErrors': { value: false, type: Setting.TYPE_BOOL, show: (settings) => { return [SyncTargetRegistry.nameToId('nextcloud'), SyncTargetRegistry.nameToId('webdav')].indexOf(settings['sync.target']) >= 0 }, public: true, appTypes: ['desktop', 'cli'], label: () => _('Ignore TLS certificate errors') },
'net.customCertificates': { value: '', type: Setting.TYPE_STRING, section:'sync', show: (settings) => { return [SyncTargetRegistry.nameToId('nextcloud'), SyncTargetRegistry.nameToId('webdav')].indexOf(settings['sync.target']) >= 0 }, public: true, appTypes: ['desktop', 'cli'], label: () => _('Custom TLS certificates'), description: () => _('Comma-separated list of paths to directories to load the certificates from, or path to individual cert files. For example: /my/cert_dir, /other/custom.pem. Note that if you make changes to the TLS settings, you must save your changes before clicking on "Check synchronisation configuration".') },
'net.ignoreTlsErrors': { value: false, type: Setting.TYPE_BOOL, section:'sync', show: (settings) => { return [SyncTargetRegistry.nameToId('nextcloud'), SyncTargetRegistry.nameToId('webdav')].indexOf(settings['sync.target']) >= 0 }, public: true, appTypes: ['desktop', 'cli'], label: () => _('Ignore TLS certificate errors') },
'api.token': { value: null, type: Setting.TYPE_STRING, public: false },
'resourceService.lastProcessedChangeId': { value: 0, type: Setting.TYPE_INT, public: false },
'searchEngine.lastProcessedChangeId': { value: 0, type: Setting.TYPE_INT, public: false },
'searchEngine.initialIndexingDone': { value: false, type: Setting.TYPE_BOOL, public: false },
'welcome.wasBuilt': { value: false, type: Setting.TYPE_BOOL, public: false },
};
return this.metadata_;
@@ -527,6 +528,36 @@ class Setting extends BaseModel {
if (typeId === Setting.TYPE_OBJECT) return 'object';
}
static groupMetadatasBySections(metadatas) {
let sections = [];
const generalSection = { name: 'general', metadatas: [] };
const nameToSections = {};
nameToSections['general'] = generalSection;
sections.push(generalSection);
for (let i = 0; i < metadatas.length; i++) {
const md = metadatas[i];
if (!md.section) {
generalSection.metadatas.push(md);
} else {
if (!nameToSections[md.section]) {
nameToSections[md.section] = { name: md.section, metadatas: [] };
sections.push(nameToSections[md.section]);
}
nameToSections[md.section].metadatas.push(md);
}
}
return sections;
}
static sectionNameToLabel(name) {
if (name === 'general') return _('General');
if (name === 'sync') return _('Synchronisation');
if (name === 'appearance') return _('Appearance');
if (name === 'note') return _('Note');
if (name === 'application') return _('Application');
return name;
}
}
Setting.TYPE_INT = 1;

View File

@@ -114,4 +114,43 @@ function ltrimSlashes(path) {
return path.replace(/^\/+/, '');
}
module.exports = { basename, dirname, filename, isHidden, fileExtension, safeFilename, friendlySafeFilename, safeFileExtension, toSystemSlashes, rtrimSlashes, ltrimSlashes };
function quotePath(path) {
if (!path) return '';
if (path.indexOf('"') < 0 && path.indexOf(' ') < 0) return path;
path = path.replace(/"/, '\\"');
return '"' + path + '"';
}
function unquotePath(path) {
if (!path.length) return '';
if (path.length && path[0] === '"') {
path = path.substr(1, path.length - 2);
}
path = path.replace(/\\"/, '"');
return path;
}
function extractExecutablePath(cmd) {
if (!cmd.length) return '';
const quoteType = ['"', "'"].indexOf(cmd[0]) >= 0 ? cmd[0] : '';
let output = '';
for (let i = 0; i < cmd.length; i++) {
const c = cmd[i];
if (quoteType) {
if (i > 0 && c === quoteType) {
output += c;
break;
}
} else {
if (c === ' ') break;
}
output += c;
}
return output;
}
module.exports = { extractExecutablePath, basename, dirname, filename, isHidden, fileExtension, safeFilename, friendlySafeFilename, safeFileExtension, toSystemSlashes, rtrimSlashes, ltrimSlashes, quotePath, unquotePath };

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