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

Compare commits

...

95 Commits

Author SHA1 Message Date
Laurent Cozic
a5f17fad58 Android release v1.0.308 2019-10-13 23:19:15 +02:00
Laurent Cozic
22c3646fc6 Electron release v1.0.170 2019-10-13 23:13:19 +02:00
Laurent Cozic
a3e7f0b5ef Tools: Fixed building Android app on Windows 2019-10-13 01:21:56 +02:00
Laurent Cozic
9f5da92ab4 Desktop, Mobile: Added support for chemical equations using mhchem for Katex 2019-10-13 00:22:24 +02:00
Laurent Cozic
fdafe3b947 Desktop: Fixes #1854: Prevent note content from being deleted when using certain external editors (in particular Typora) 2019-10-12 22:51:38 +02:00
Laurent Cozic
6dec711a0a Desktop: Fixes #1854: Prevent external editor from clearing the note in some hard to replicate cases 2019-10-12 21:30:38 +02:00
Laurent Cozic
ec67bc7f1a Mobile: Fixes #1910: Make sure side bar text is white when dark theme is used 2019-10-12 20:55:59 +02:00
Laurent Cozic
47aaf639b3 Merge branch 'master' of github.com:laurent22/joplin 2019-10-12 20:49:42 +02:00
Laurent Cozic
51233c2745 Mobile: Fixes #1975: Images were not being displayed just after having been taken or attached 2019-10-12 20:49:10 +02:00
Laurent Cozic
90bc84c010 Clipper: Fixed: Some tables were imported with a duplicate header 2019-10-12 19:36:06 +02:00
Laurent Cozic
7f1e684dab Updated package to fix tests 2019-10-12 10:47:16 +02:00
Helmut K. C. Tessarek
5f28d0ec24 Desktop: Add option to set page dimensions when printing (#1976)
* add setting: export.pdfPageSize

* create 2 settings: size and orientation

* export.pdfPageOrientation: use string instead of boolean

* add other page formats supported by Electron
2019-10-12 01:21:19 +02:00
Matthew Crumley
348c4ad3a3 Desktop: Resolves #1222: Truncate update changelog when it's too long (#1967)
The changelong text is truncated if it's longer than 1000 characters,
but avoids cutting off a partial line, unless that would lead to cutting
off too much of the text. An ellipsis is added to mark the truncation.

Additionally, when the changelong is truncated, it adds a "Full Release Notes"
button that opens the GitHub release page in a browser window.
2019-10-12 00:44:58 +02:00
J0J0 T
f90cc8d67d Desktop, Cli: enex_to_md: Support italic in span tags (#1966)
* Desktop, Cli: enex_to_md: support italic in span tags

* Desktop, Cli: enex_to_md: readd debug message to resolve CI conflict

* Desktop, Cli: enex_to_md: fix CI errors

add spaces to commented out debug messages

* Desktop, Cli: enex_to_md: remove redundant commented out debug message

* Desktop, Cli: enex_to_md: readd redundant commented out debug message

CI wants it in there - maybe remove in another PR
2019-10-12 00:39:13 +02:00
Alan Martins Silva
d3e9ffcaea Mobile: Added duplicate option when selecting notes. (#1969)
* Adding duplicate button on screen-header.js when selecting notes; Adding 'duplicateMultipleNotes' function on Note.js;

* Using for-loop like the rest of the code does

* changing from 'uniqueTitle' to 'ensureUniqueTitle'
2019-10-12 00:37:16 +02:00
Laurent Cozic
b0a4a10dcc Clipper: Fixes #1876: Handle more styles of named anchors, including spans 2019-10-12 00:18:40 +02:00
Laurent Cozic
8ef5c96cb6 Desktop: Fixes #1970: Display error message when notes cannot be exported 2019-10-11 20:20:12 +02:00
Laurent Cozic
6be36ffe17 Desktop: Fixes #1819: Note view was not reloaded after viewing revisions 2019-10-11 20:10:25 +02:00
Laurent Cozic
7d7975daf4 Cli: Allow setting user timestamps with "set" command 2019-10-11 19:49:47 +02:00
Laurent Cozic
c98644b72f All: Allow a sync client to lock a sync target, so that migration operations can be performed on it 2019-10-11 01:03:23 +02:00
Laurent Cozic
8a097fb79c All: Added concept of sync version and client ID to allow upgrading sync targets 2019-10-10 23:23:11 +02:00
Laurent Cozic
f71e7f4fd3 Update ISSUE_TEMPLATE.md 2019-10-09 22:13:14 +02:00
Laurent Cozic
9c8add97e7 Tests: Add EnexToHtml to the list 2019-10-09 22:10:18 +02:00
Laurent Cozic
b099c811cc Merge branch 'master' of github.com:laurent22/joplin 2019-10-09 21:35:33 +02:00
Laurent Cozic
a8ae0f8078 Apply linter config 2019-10-09 21:35:13 +02:00
Laurent Cozic
d355169b60 Tools: Added rules to linter 2019-10-09 21:33:21 +02:00
Helmut K. C. Tessarek
08295525de Desktop: Add checkmark to menu item, if Dev Tools are on (#1949)
* add checkmark to menu item, if Dev Tools are on

If one closed the dev tools window, one could think that the Dev Tools are closed.
This is not the case. After the next action, the window opens again. This can be
confusing, therefore I added a checkmark to the menu item so that it is very clear.

* fix no-case-declarations

* fix reducer issue
2019-10-09 19:55:35 +02:00
Nathan Leiby
fdcf27fc65 Mobile: confirm encryption password (#1939)
* mobile: confirm encryption password

* pr feedback: translatable strings + style refactor

also added placeholder text

* s/did/do
2019-10-08 18:04:25 -04:00
Caleb John
f2c82b05d9 Desktop: Improved resource hover title (#1965)
* Improved resource hover title

* Add mimetype to resource links

* Escape mime type for resource links
2019-10-08 21:39:38 +02:00
Laurent Cozic
add9dda759 Desktop, Cli: Give correct mime type to more file types 2019-10-08 21:36:33 +02:00
Rafael Cavalcanti
fbba4a1ec4 Fix category on Linux installation script (#1964) 2019-10-08 19:45:08 +02:00
Laurent Cozic
154d303463 Merge branch 'master' of github.com:laurent22/joplin 2019-10-07 23:15:14 +02:00
Laurent Cozic
fdef2db232 Desktop, Cli: Fixes #1960: Apply default style to notes in HTML format 2019-10-07 23:14:49 +02:00
Rafael Cavalcanti
d49fa8e42b Minor fix on install script (#1954) 2019-10-07 22:32:17 +02:00
Irvin Dominin
871d3cb87d Fixed italian locale (#1955)
* Fixed italian locale

* Fixed italian locale

* Revert "Fixed italian locale"

This reverts commit b48695593f.
2019-10-07 16:20:31 -04:00
Laurent Cozic
f1d751b356 Tools: Handle Api commit messages 2019-10-07 10:12:10 +02:00
Laurent Cozic
60c1939d26 Api: Resolves #1956: Allow getting the resources of a note 2019-10-07 09:57:24 +02:00
Devon Zuegel
d2aaac22e5 Desktop: Add loading animation to import/export (#1888)
* Add loading animation to import/export

* Removed unecessary CSS prefixes
2019-10-05 22:46:39 +01:00
Andros Fenollosa
c6842a8591 Update Joplin_install_and_update.sh (#1952)
- Add argument: Mutes messages by console.
- Remove unset.
- Variables in capital letters.
2019-10-05 18:14:45 +01:00
Laurent Cozic
60e9abdd61 GitHub: Remove option to create feature requests 2019-10-04 13:54:07 +01:00
Laurent Cozic
9796630aa2 Update markdown.md 2019-10-04 09:14:18 +01:00
Laurent Cozic
7230cdea33 Doc: Added table example to Markdown cheatsheet 2019-10-04 09:13:24 +01:00
Andros Fenollosa
6460907976 Updating translation es_ES.po (#1947)
* Update language es_ES

* Add Last-Translator

* Translation fix
2019-10-03 17:42:07 -04:00
Helmut K. C. Tessarek
d7a50a1b48 Desktop: Resolves #1662: Set cancel as the default in dangerous operations (#1934)
* set cancel as the  default in dangerous operations, rename buttons (delete, remove) and context menu (for tags)

fixes #1662 (partially, because I can't fix the upstream issue, unless we update Electron)

* add default value for buttonLabel
2019-10-03 22:33:49 +01:00
oskar
4a88343372 Mobile: Added Front Camera toggle when taking a picture (#1913)
* added front camera support

* added front camera button and logic
2019-10-03 22:23:43 +01:00
Helmut K. C. Tessarek
74c2bbc2f0 change tense when passwords do not match 2019-10-02 19:32:32 -04:00
Nathan Leiby
5ed5d16716 Desktop: Resolves #1896: Hide some toolbar buttons when editor hidden (#1940)
addresses issue: https://github.com/laurent22/joplin/issues/1896
2019-10-03 00:07:58 +01:00
Subodh Dahal
43083b0b7a Desktop: Resolves #917: Larger search bar (#1933)
* Increased the width of search bar

* Added some margin to the left ofsearch bar

* Reduced left margin for the search bar
2019-10-02 22:55:29 +01:00
fabianskibr
a4e5054008 Doc: Add AUR repository (#1941) 2019-10-02 22:52:22 +01:00
Laurent Cozic
02eb2f2e45 Desktop, Cli: Resolves #1932: Use profile temp dir when exporting files 2019-10-02 19:22:32 +01:00
Laurent Cozic
5d015bf746 All: Fixes #1906: Fixed translation of "Synchronisation Status" 2019-10-02 19:07:51 +01:00
Laurent Cozic
ce5db5a5c1 Add more logging info to ExternalEditWatcher so that I do not need to ask to enable debug mode 2019-10-02 19:04:50 +01:00
Laurent Cozic
cdcc3902c5 Merge branch 'master' of github.com:laurent22/joplin 2019-10-02 19:03:59 +01:00
Laurent Cozic
309835f2fe Clipper: Fixes #1881: Some pages could not be clipped in Firefox due to an issue with dynamic images 2019-10-02 19:03:36 +01:00
Laurent Cozic
eca0ab0ef6 Desktop: Fixes #1829: Fixed alarms that would trigger immediately when they were set too far in future 2019-10-02 18:21:42 +00:00
Laurent Cozic
4ce35ee1ed Desktop: Fixes #1703: Text input context menu was not working in Windows 2019-10-02 18:05:30 +00:00
Laurent Cozic
8856456afd Doc: Update Markdown page 2019-10-02 08:12:03 +01:00
Helmut K. C. Tessarek
4259d900f4 Mobile: Don't display Dracula theme on mobile (#1935) 2019-10-02 07:49:38 +01:00
Nathan Leiby
438c448ef7 CLI: confirm encryption password (#1937)
Successful flow:
https://gyazo.com/354ca9ea412ffe3756ee77938d544341

Flow with error (non-matching passwords):
https://gyazo.com/9adda69278e3631da33d9fb366815d04
2019-10-02 07:48:58 +01:00
Laurent Cozic
0fb5b35212 All: Fixes #1938: App would crash if trying to index a note that has not been decrypted yet 2019-10-02 07:38:16 +01:00
Laurent Cozic
b69efb4970 Added Markdown Guide to website menu 2019-10-01 22:50:30 +01:00
Laurent Cozic
44ea237538 Merge branch 'master' of github.com:laurent22/joplin 2019-10-01 22:36:11 +01:00
Laurent Cozic
a58316b24c Doc: Fixed Markdown cheat sheet so that it looks better on GitHub 2019-10-01 22:33:19 +01:00
Mats Estensen
df95d01f6e update nb_NO translation to be 100 percent complete (#1930) 2019-10-01 17:32:38 -04:00
Laurent Cozic
d6924893e5 Merge branch 'master' of github.com:laurent22/joplin 2019-10-01 22:28:40 +01:00
Laurent Cozic
0f04ea4f70 Doc: Various changes and added Markdown cheat sheet 2019-10-01 22:27:57 +01:00
Laurent Cozic
4b8026cf83 Update PULL_REQUEST_TEMPLATE 2019-10-01 21:37:55 +01:00
JRaiden
a98a586295 Update es_ES.po (#1929)
I added some translations and change a couple more in order to improve there meaning in Spanish.
I am a native spanish speaker so I could help with some more translate if you want.
2019-10-01 16:32:11 -04:00
Laurent Cozic
29ec7ba03a Apply linter 2019-10-01 19:33:46 +01:00
Helmut K. C. Tessarek
a35cc23d28 Update localization de_DE.po (#1928) 2019-10-01 14:08:33 -04:00
Alexey Pyltsyn
20a8ddd841 Improve Russian translation (#1926) 2019-10-01 14:07:58 -04:00
Davide Cazzin
774fc9ce53 Update Italian translation (#1925) 2019-10-01 14:07:36 -04:00
Dom Goodwin
84ab395fae Desktop: Resolves (#1863): Added Dracula theme (#1924)
* Added dracula theme

* Removed package-lock
2019-10-01 12:23:32 +01:00
Reinhart Previano K
edc4dc5801 Doc: Update React Native build documentation (#1922) 2019-10-01 09:03:31 +01:00
Helmut K. C. Tessarek
6e128a7285 update question template
Somebody deleted the label `question`, so I changed the template to use `invalid`, since a question is technically invalid on the issue tracker.
2019-09-30 19:50:46 -04:00
Helmut K. C. Tessarek
ff977cebaf update issue templates 2019-09-30 19:45:44 -04:00
Caleb John
5bcd5f050a Desktop: Code button now detects multiline (#1915)
* Code button now detects multiline

* Fix text selection for code insertion
2019-09-30 23:24:07 +01:00
Laurent Cozic
fe57f163f3 Merge branch 'master' of github.com:laurent22/joplin 2019-09-30 23:19:31 +01:00
Laurent Cozic
cb24db4e39 Renamed "feature request" to "enhancement" (which is already for feature requests) 2019-09-30 14:57:45 +01:00
Laurent Cozic
e93d96193c eslint 2019-09-29 22:11:36 +00:00
Laurent Cozic
637a4dc1f9 Improve eslint rules and run them from CI 2019-09-29 22:01:10 +00:00
Laurent Cozic
2c522637ef Update website 2019-09-29 15:32:11 +01:00
Laurent Cozic
8fbb1fd246 A bit shorter 2019-09-29 15:32:00 +01:00
Laurent Cozic
75b7e7d999 Update website 2019-09-29 15:30:19 +01:00
Laurent Cozic
7e2e901035 Added note about Hacktoberfest 2019-09-29 15:30:01 +01:00
Laurent Cozic
a73a1f896c Merge branch 'master' of github.com:laurent22/joplin 2019-09-29 14:46:18 +01:00
Laurent Cozic
ae7f0e8ffb Tools: Disable build for macOS on pull requests due to electron-builder bug 2019-09-29 14:46:05 +01:00
abonte
08343e6be9 update translation (#1911) 2019-09-29 14:31:17 +01:00
Laurent Cozic
9cb3496159 Updated Russian translation (Thanks Kirill Keller) 2019-09-29 14:26:51 +01:00
Helmut K. C. Tessarek
37b035d0d0 update issue templates
Some people still ignore the templates. This update makes the important statements more prominent.
2019-09-28 20:48:01 -04:00
genneko
f37ac8b5de Update ja_JP.po Japanese translation. (#1902)
* Translate new strings.
* Check and update 'fuzzy' strings.
2019-09-27 21:31:55 -04:00
Robert
343d04b05d Update nl_NL.po (#1901)
Updated for missing translations in  1.0.168
2019-09-27 21:30:48 -04:00
Laurent Cozic
e92741edd6 CLI v1.0.149 2019-09-27 22:19:13 +01:00
Laurent Cozic
8565cd7d40 Cli: Resolves #1905: Add support to Termux by returning a default when platform name cannot be determined 2019-09-27 22:18:22 +01:00
Laurent Cozic
58e299383d CLI v1.0.148 2019-09-27 19:43:22 +01:00
132 changed files with 5562 additions and 2380 deletions

View File

@@ -45,3 +45,4 @@ Server/docs/
Server/dist/
Server/bin/
Server/node_modules/
ElectronClient/app/packageInfo.js

View File

@@ -33,14 +33,22 @@ module.exports = {
"sourceType": "module",
},
'rules': {
// -------------------------------
// Code correctness
// -------------------------------
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
// Ignore all unused function arguments, because in some
// case they are kept to indicate the function signature.
//"no-unused-vars": ["error", { "argsIgnorePattern": ".*" }],
"@typescript-eslint/no-unused-vars": ["error"],
"no-unused-vars": "error",
"no-constant-condition": 0,
"no-prototype-builtins": 0,
// This error is always a false positive so far since it detects
// possible race conditions in contexts where we know it cannot happen.
"require-atomic-updates": 0,
// "no-lonely-if": "error",
// -------------------------------
// Formatting
// -------------------------------
"space-in-parens": ["error", "never"],
"semi": ["error", "always"],
"eol-last": ["error", "always"],
@@ -49,11 +57,26 @@ module.exports = {
"comma-dangle": ["error", "always-multiline"],
"no-trailing-spaces": "error",
"linebreak-style": ["error", "unix"],
// This error is always a false positive so far since it detects
// possible race conditions in contexts where we know it cannot happen.
"require-atomic-updates": 0,
"prefer-template": ["error"],
"template-curly-spacing": ["error", "never"]
"template-curly-spacing": ["error", "never"],
"key-spacing": ["error", {
"beforeColon": false,
"afterColon": true,
"mode": "strict"
}],
"block-spacing": ["error"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"no-spaced-func": ["error"],
"func-call-spacing": ["error"],
"space-before-function-paren": ["error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}],
"multiline-comment-style": ["error", "separate-lines"],
"space-before-blocks": "error",
"spaced-comment": ["error", "always"],
"keyword-spacing": ["error", { "before": true, "after": true }]
},
"plugins": [
"react",

View File

@@ -1,4 +1,9 @@
👉 Please follow one of these issue templates:
- https://github.com/laurent22/joplin/issues/new/choose
⚠️
The GitHub issue tracker is for **bugs** and **security issues** ONLY. For feature requests and support, please use the forum:
https://discourse.joplinapp.org/
⚠️
Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates.

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Report an accepted feature request.
title: ''
labels: 'feature request'
---
<!--
Please search open issues first - many features have already been requested!
-->
🚨 A feature request that has not been accepted on the forum will be closed! 🚨
## Has it been discussed in the forum? Link to topic.
<!--
Feature requests must be discussed and accepted in the forum first. https://discourse.joplinapp.org
Please provide a link to the topic.
Feature requests without a link to the discussion/topic on the forum will be closed.
-->

View File

@@ -2,11 +2,11 @@
name: "🤔 Questions and Help"
about: The issue tracker is not for questions. Please ask questions on https://discourse.joplinapp.org/.
title: ''
labels: 'question'
labels: 'invalid'
---
🚨 The issue tracker is not for questions. 🚨
⚠🚨⛔ The issue tracker is not for questions. ⛔🚨⚠
As it happens, support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek.

View File

@@ -6,6 +6,8 @@ Please prefix the title with the platform you are targetting:
- "Mobile" for the mobile app (or "Android" / "iOS" if the pull request only applies to one of the mobile platforms)
- "CLI" for the CLI app
If it's not related to any platform (such as a translation, change to the documentation, etc.), simply don't add a platform.
For example: "Desktop: Added new setting to change font", or "Mobile: Fixed config screen error"
PLEASE READ THE GUIDE FIRST: https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md

View File

@@ -55,19 +55,42 @@ before_install:
script:
- |
# Install tools
npm install
cd Tools
npm install
cd ..
# Run test units
cd ../CliClient
cd CliClient
npm install
./run_test.sh
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
fi
cd ..
# Run linter for pull requests only - this is so that
# bypassing eslint is allowed for urgent fixes.
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
npm run linter-ci ./
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
fi
fi
# Find out if we should run the build or not. Electron-builder gets stuck when
# builing PRs so we disable it in this case. The Linux build should provide
# enough info if the app builds or not.
# https://github.com/electron-userland/electron-builder/issues/4263
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
exit 0
fi
fi
# Prepare the Electron app and build it
cd ../ElectronClient/app
cd ElectronClient/app
rsync -aP --delete ../../ReactNativeClient/lib/ lib/
npm install && USE_HARD_LINKS=false yarn dist

View File

@@ -65,7 +65,7 @@ The [building\_win32\_tips on this page](./readme/building_win32_tips.md) might
# Building the Mobile application
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "Building Projects with Native Code" tab.
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "React Native CLI Quickstart" tab.
Then, from `/ReactNativeClient`, run `npm install`, then `react-native run-ios` or `react-native run-android`.

View File

@@ -10,8 +10,8 @@ async function handleAutocompletionPromise(line) {
// Auto-complete the command name
const names = await app().commandNames();
let words = getArguments(line);
//If there is only one word and it is not already a command name then you
//should look for commmands it could be
// If there is only one word and it is not already a command name then you
// should look for commmands it could be
if (words.length == 1) {
if (names.indexOf(words[0]) === -1) {
let x = names.filter(n => n.indexOf(words[0]) === 0);
@@ -23,29 +23,29 @@ async function handleAutocompletionPromise(line) {
return line;
}
}
//There is more than one word and it is a command
// There is more than one word and it is a command
const metadata = (await app().commandMetadata())[words[0]];
//If for some reason this command does not have any associated metadata
//just don't autocomplete. However, this should not happen.
// If for some reason this command does not have any associated metadata
// just don't autocomplete. However, this should not happen.
if (metadata === undefined) {
return line;
}
//complete an option
// complete an option
let next = words.length > 1 ? words[words.length - 1] : '';
let l = [];
if (next[0] === '-') {
for (let i = 0; i < metadata.options.length; i++) {
const options = metadata.options[i][0].split(' ');
//if there are multiple options then they will be separated by comma and
//space. The comma should be removed
// if there are multiple options then they will be separated by comma and
// space. The comma should be removed
if (options[0][options[0].length - 1] === ',') {
options[0] = options[0].slice(0, -1);
}
if (words.includes(options[0]) || words.includes(options[1])) {
continue;
}
//First two elements are the flag and the third is the description
//Only autocomplete long
// First two elements are the flag and the third is the description
// Only autocomplete long
if (options.length > 1 && options[1].indexOf(next) === 0) {
l.push(options[1]);
} else if (options[0].indexOf(next) === 0) {
@@ -59,9 +59,9 @@ async function handleAutocompletionPromise(line) {
ret.prefix = `${toCommandLine(words.slice(0, -1))} `;
return ret;
}
//Complete an argument
//Determine the number of positional arguments by counting the number of
//words that don't start with a - less one for the command name
// Complete an argument
// Determine the number of positional arguments by counting the number of
// words that don't start with a - less one for the command name
const positionalArgs = words.filter(a => a.indexOf('-') !== 0).length - 1;
let cmdUsage = yargParser(metadata.usage)['_'];
@@ -155,20 +155,20 @@ function getArguments(line) {
if (line[i] === '"') {
if (inDoubleQuotes) {
inDoubleQuotes = false;
//maybe push word to parsed?
//currentWord += '"';
// maybe push word to parsed?
// currentWord += '"';
} else {
inDoubleQuotes = true;
//currentWord += '"';
// currentWord += '"';
}
} else if (line[i] === '\'') {
if (inSingleQuotes) {
inSingleQuotes = false;
//maybe push word to parsed?
//currentWord += "'";
// maybe push word to parsed?
// currentWord += "'";
} else {
inSingleQuotes = true;
//currentWord += "'";
// currentWord += "'";
}
} else if (/\s/.test(line[i]) && !(inDoubleQuotes || inSingleQuotes)) {
if (currentWord !== '') {

View File

@@ -50,7 +50,15 @@ class Command extends BaseCommand {
this.stdout(_('Operation cancelled'));
return;
}
const password2 = await this.prompt(_('Confirm master password:'), { type: 'string', secure: true });
if (!password2) {
this.stdout(_('Operation cancelled'));
return;
}
if (password !== password2) {
this.stdout(_('Passwords do not match!'));
return;
}
await EncryptionService.instance().generateMasterKeyAndEnableEncryption(password);
return;
}

View File

@@ -39,7 +39,14 @@ class Command extends BaseCommand {
type_: notes[i].type_,
};
newNote[propName] = propValue;
await Note.save(newNote);
const timestamp = Date.now();
await Note.save(newNote, {
autoTimestamp: false, // No auto-timestamp because user may have provided them
updated_time: timestamp,
created_time: timestamp,
});
}
}
}

View File

@@ -84,8 +84,8 @@ class StatusBarWidget extends BaseWidget {
// On Windows, bgBlueBright is fine and looks dark enough (Windows is probably in the wrong though)
// For now, just don't use any colour at all.
//const textStyle = this.promptActive ? (s) => s : chalk.bgBlueBright.white;
//const textStyle = (s) => s;
// const textStyle = this.promptActive ? (s) => s : chalk.bgBlueBright.white;
// const textStyle = (s) => s;
const textStyle = this.promptActive ? s => s : chalk.gray;
this.term.drawHLine(this.absoluteInnerX, this.absoluteInnerY, this.innerWidth, textStyle(' '));

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.2.3\n"
"X-Generator: Poedit 2.2.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "To delete a tag, untag the associated notes."
@@ -396,17 +396,20 @@ msgid ""
"Start, stop or check the API server. To specify on which port it should run, "
"set the api.port config variable. Commands are (%s)."
msgstr ""
"Starte, stoppe oder überprüfe den API Server. Um den Port zu spezifizieren "
"auf dem er laufen soll, setze die api.port Konfigurationsvariable. Die "
"Befehle lauten (%s)."
#, javascript-format
msgid "Server is already running on port %d"
msgstr ""
msgstr "Der Server lauft schon auf Port %d"
#, javascript-format
msgid "Server is running on port %d"
msgstr ""
msgstr "Der Server lauft auf Port %d"
msgid "Server is not running."
msgstr ""
msgstr "Der Server ist nicht gestartet."
#, javascript-format
msgid ""
@@ -701,9 +704,8 @@ msgstr "&Hilfe"
msgid "Website and documentation"
msgstr "Webseite und Dokumentation"
#, fuzzy
msgid "Joplin Forum"
msgstr "Joplin v%s"
msgstr "Joplin Forum"
msgid "Make a donation"
msgstr "Spenden"
@@ -821,6 +823,7 @@ msgstr ""
msgid "This will open a new screen. Save your current changes?"
msgstr ""
"Diese Aktion wird ein neues Fenster öffnen. Aktuelle Änderungen speichern?"
#, javascript-format
msgid "Notes and settings are stored in: %s"
@@ -850,7 +853,7 @@ msgid ""
"continue?"
msgstr ""
"Durch die Deaktivierung der Verschlüsselung werden *alle* Notizen und "
"Anhänge neu synchronisiert und unverschlüsselt an das Synchronisierungsziel "
"Anhänge neu synchronisiert und unverschlüsselt an das Synchronisationsziel "
"gesendet. Möchtest du fortfahren?"
msgid ""
@@ -929,13 +932,13 @@ msgid "Encryption is:"
msgstr "Die Verschlüsselung ist:"
msgid "Firefox Extension"
msgstr ""
msgstr "Firefox Erweiterung"
msgid "Chrome Web Store"
msgstr ""
msgstr "Chrome-Webstore"
msgid "Get it now:"
msgstr ""
msgstr "Hole es jetzt:"
# 'Nutzung', 'Gebrauch', or 'Verwendung' - depends on the context
msgid "Usage"
@@ -1551,9 +1554,8 @@ msgstr "Aktiviere ++insert++ Syntax"
msgid "Enable multimarkdown table extension"
msgstr "Aktiviere multimarkdown Tabellen Erweiterung"
#, fuzzy
msgid "Enable Fountain syntax support"
msgstr "Aktiviere ~sub~ Syntax"
msgstr "Aktiviere Fountain Unterstützung"
msgid "Show tray icon"
msgstr "Zeige Tray-Icon"
@@ -1579,7 +1581,6 @@ msgstr "Zoomstufe der Benutzeroberfläche"
msgid "Editor font size"
msgstr "Schriftgröße im Editor"
#, fuzzy
msgid "Editor font"
msgstr "Schriftgröße im Editor"
@@ -1651,11 +1652,16 @@ msgid ""
"Fail-safe: Do not wipe out local data when sync target is empty (often the "
"result of a misconfiguration or bug)"
msgstr ""
"Störungssicher: Lösche nicht die lokalen Daten, wenn das "
"Synchronisationsziel leer ist (oft ein Resultat von Fehlkonfiguration oder "
"einem Programmfehler)"
msgid ""
"Specify the port that should be used by the API server. If not set, a "
"default will be used."
msgstr ""
"Spezifiziere den Port, der vom API Server verwendet werden soll. Wenn er "
"nicht gesetzt ist, wird ein Standardwert verwendet."
msgid "Enable note history"
msgstr "Aktiviere Notizen-Verlauf"
@@ -1693,13 +1699,11 @@ msgstr "Zusatzprogramme"
msgid "Application"
msgstr "Applikation"
#, fuzzy
msgid "Encryption"
msgstr "Die Verschlüsselung ist:"
msgstr "Verschlüsselung"
#, fuzzy
msgid "Web Clipper"
msgstr "Web-Clipper Optionen"
msgstr "Web Clipper"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
@@ -1715,13 +1719,11 @@ msgstr "Markdown"
msgid "Joplin Export Directory"
msgstr "Joplin Export Verzeichnis"
#, fuzzy
msgid "Evernote Export File (as Markdown)"
msgstr "Evernote Export Datei"
msgstr "Evernote Export Datei (als Markdown)"
#, fuzzy
msgid "Evernote Export File (as HTML)"
msgstr "Evernote Export Datei"
msgstr "Evernote Export Datei (als HTML)"
msgid "Json Export Directory"
msgstr "Json Export Verzeichnis"
@@ -1830,13 +1832,11 @@ msgstr "Berechtigung zur Verwendung der Kamera"
msgid "Your permission to use your camera is required."
msgstr "Deine Zustimmung zur Verwendung deiner Kamera ist erforderlich."
#, fuzzy
msgid "You currently have no notebooks."
msgstr "Die/das momentan ausgewählte Notiz(-buch) löschen."
msgstr "Du hast momentan keine Notizbücher."
#, fuzzy
msgid "Create a notebook"
msgstr "Erstellt ein neues Notizbuch."
msgstr "Notizbuch erstellen"
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr ""
@@ -1896,7 +1896,7 @@ msgid ""
"the sync target is accessible. The reported error was:"
msgstr ""
"Fehler. Bitte überprüfe, ob die URL, der Benutzername, das Passwort. usw. "
"korrekt sind und das das Synchronisierungsziel erreichbar ist. Fehlermeldung:"
"korrekt sind und das das Synchronisationsziel erreichbar ist. Fehlermeldung:"
msgid "The application has been authorised!"
msgstr "Das Programm wurde erfolgreich autorisiert!"

File diff suppressed because it is too large Load Diff

View File

@@ -211,7 +211,6 @@ msgstr ""
msgid "Shortcuts are not available in CLI mode."
msgstr "Le scorciatoie non sono disponibili nella modalità CLI."
#, fuzzy
msgid ""
"Type `help [command]` for more information about a command; or type `help "
"all` for the complete usage information."
@@ -459,7 +458,7 @@ msgid ""
"operation."
msgstr ""
"Trovato un file di blocco. Se si è certi che non è in corso alcuna "
"sincronizzazione, è possibile eliminare il file di blocco in \"% s\" e "
"sincronizzazione, è possibile eliminare il file di blocco in \"%s\" e "
"riprendere l'operazione."
#, javascript-format
@@ -731,7 +730,7 @@ msgstr "È disponibile un aggiornamento, vuoi scaricarlo ora?"
#, javascript-format
msgid "Your version: %s"
msgstr "Tua versione: %s"
msgstr "La tua versione: %s"
#, javascript-format
msgid "New version: %s"
@@ -812,7 +811,7 @@ msgstr ""
"terze parti di accedere a Joplin."
msgid "This will open a new screen. Save your current changes?"
msgstr ""
msgstr "Questo aprirà una nuova schermata. Salvare le tue modifiche correnti?"
#, javascript-format
msgid "Notes and settings are stored in: %s"
@@ -1524,22 +1523,22 @@ msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgstr "Abilita abbreviazioni"
msgid "Enable markdown emoji"
msgstr ""
msgstr "Abilita emoji markdown"
msgid "Enable ++insert++ syntax"
msgstr "Attiva sintassi ++insert++"
msgid "Enable multimarkdown table extension"
msgstr ""
msgstr "Abilita estensione tavola dei contenuti"
msgid "Enable Fountain syntax support"
msgstr "Attiva supporto sintassi Fountain"
msgid "Show tray icon"
msgstr "Visualizza tray icon"
msgstr "Visualizza nella barra delle applicazioni"
msgid "Note: Does not work in all desktop environments."
msgstr "Nota: non funziona in tutti gli ambienti desktop."
@@ -1549,12 +1548,12 @@ msgid ""
"this setting so that your notes are constantly being synchronised, thus "
"reducing the number of conflicts."
msgstr ""
"Questo consentirà Joplin di essere in esecuzione in background. E’ "
"Questo consentirà a Joplin di essere in esecuzione in background. E’ "
"raccomandata l’attivazione di questa impostazione per sincronizzare "
"costantemente le tue note e quindi ridurre il numero di conflitti."
msgid "Start application minimised in the tray icon"
msgstr "Avvia applicazione minimizzata nell’icona del vassoio"
msgstr "Avvia applicazione minimizzata nella barra delle applicazioni"
msgid "Global zoom percentage"
msgstr "Percentuale di zoom globale"
@@ -1562,9 +1561,8 @@ msgstr "Percentuale di zoom globale"
msgid "Editor font size"
msgstr "Editor dimensione caratteri"
#, fuzzy
msgid "Editor font"
msgstr "Editor dimensione caratteri"
msgstr "Editor caratteri"
msgid "Editor font family"
msgstr "Editor famiglia caratteri"
@@ -1654,7 +1652,7 @@ msgid "%d days"
msgstr "%d giorni"
msgid "Keep note history for"
msgstr "Mantieni cronologia nota per"
msgstr "Mantieni la cronologia note per"
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
@@ -1678,13 +1676,11 @@ msgstr "Plugins"
msgid "Application"
msgstr "Applicazione"
#, fuzzy
msgid "Encryption"
msgstr "La crittografia è:"
msgstr "Crittografia"
#, fuzzy
msgid "Web Clipper"
msgstr "Opzioni Web Clipper"
msgstr "Web Clipper"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
@@ -1699,13 +1695,11 @@ msgstr "Markdown"
msgid "Joplin Export Directory"
msgstr "Cartella di esportazione di Joplin"
#, fuzzy
msgid "Evernote Export File (as Markdown)"
msgstr "Esporta files di Evernote"
msgstr "Esporta files di Evernote (come Markdown)"
#, fuzzy
msgid "Evernote Export File (as HTML)"
msgstr "Esporta files di Evernote"
msgstr "Esporta files di Evernote (come HTML)"
msgid "Json Export Directory"
msgstr "Cartella di esportazione JSON"
@@ -1807,7 +1801,7 @@ msgid "On %s: %s"
msgstr "Su %s: %s"
msgid "Permission to use camera"
msgstr "Permesso di usare la fotocamera"
msgstr "Permesso per usare la fotocamera"
msgid "Your permission to use your camera is required."
msgstr "E’ richiesto il permesso di usare la fotocamera."
@@ -1911,6 +1905,8 @@ msgid ""
"In order to use file system synchronisation your permission to write to "
"external storage is required."
msgstr ""
"Per usare la sincronizzazione del file system è necessario il tuo permesso "
"di scrittura sulla memoria esterna."
msgid "Encryption Config"
msgstr "Configurazione Crittografia"
@@ -2054,7 +2050,7 @@ msgid "View on map"
msgstr "Guarda sulla mappa"
msgid "Go to source URL"
msgstr ""
msgstr "Vai all'URL"
msgid "Attach..."
msgstr "Allega..."

View File

@@ -7,14 +7,16 @@ msgid ""
msgstr ""
"Project-Id-Version: Joplin-CLI 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: AWASHIRO Ikuya <ikunya@gmail.com>\n"
"Last-Translator: genneko <genneko217@gmail.com>\n"
"Language-Team: \n"
"Language: ja_JP\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.2.3\n"
"X-Generator: Poedit 1.8.4\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
msgid "To delete a tag, untag the associated notes."
msgstr "タグを削除するには、関連するノートからタグを外してください。"
@@ -789,7 +791,7 @@ msgstr ""
"するときにだけ使用します。"
msgid "This will open a new screen. Save your current changes?"
msgstr ""
msgstr "新しい画面を開きます。変更を保存しますか?"
#, javascript-format
msgid "Notes and settings are stored in: %s"
@@ -896,13 +898,13 @@ msgid "Encryption is:"
msgstr "暗号化の状態:"
msgid "Firefox Extension"
msgstr ""
msgstr "Firefox 拡張機能"
msgid "Chrome Web Store"
msgstr ""
msgstr "Chrome ウェブストア"
msgid "Get it now:"
msgstr ""
msgstr "今すぐ取得:"
msgid "Usage"
msgstr "使い方"
@@ -1534,9 +1536,8 @@ msgstr "全体ズームの割合"
msgid "Editor font size"
msgstr "エディターのフォントサイズ"
#, fuzzy
msgid "Editor font"
msgstr "エディターのフォントサイズ"
msgstr "エディターのフォント"
msgid "Editor font family"
msgstr "エディターのフォントファミリー"
@@ -1604,6 +1605,8 @@ msgid ""
"Fail-safe: Do not wipe out local data when sync target is empty (often the "
"result of a misconfiguration or bug)"
msgstr ""
"フェイルセーフ: 同期先が空の場合 (設定ミスやバグに起因することが多い) にロー"
"カルデータを消去しないようにする"
msgid ""
"Specify the port that should be used by the API server. If not set, a "
@@ -1647,13 +1650,11 @@ msgstr "プラグイン"
msgid "Application"
msgstr "アプリケーション"
#, fuzzy
msgid "Encryption"
msgstr "暗号化の状態:"
msgstr "暗号化"
#, fuzzy
msgid "Web Clipper"
msgstr "Webクリッパーのオプション"
msgstr "Webクリッパー"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
@@ -1668,13 +1669,11 @@ msgstr "Markdown"
msgid "Joplin Export Directory"
msgstr "Joplin エクスポートディレクトリ"
#, fuzzy
msgid "Evernote Export File (as Markdown)"
msgstr "Evernote エクスポートファイル"
msgstr "Evernote エクスポートファイル (Markdownとしてインポート)"
#, fuzzy
msgid "Evernote Export File (as HTML)"
msgstr "Evernote エクスポートファイル"
msgstr "Evernote エクスポートファイル (HTMLとしてインポート)"
msgid "Json Export Directory"
msgstr "Json エクスポートディレクトリ"

View File

@@ -380,18 +380,19 @@ msgstr "Søker etter angitt <pattern> i alle notatene."
msgid ""
"Start, stop or check the API server. To specify on which port it should run, "
"set the api.port config variable. Commands are (%s)."
msgstr ""
msgstr "Start, stopp eller sjekk API-serveren. For å angi på hvilken port den skal kjøre,"
"sett api.port konfigurasjonsvariablen. Kommandoer er (%s)."
#, javascript-format
msgid "Server is already running on port %d"
msgstr ""
msgstr "Serveren kjører allerede på port %d"
#, javascript-format
msgid "Server is running on port %d"
msgstr ""
msgstr "Serveren kjører på port %d"
msgid "Server is not running."
msgstr ""
msgstr "Serveren kjører ikke"
#, javascript-format
msgid ""
@@ -587,13 +588,13 @@ msgid "About Joplin"
msgstr "Om Joplin"
msgid "Preferences..."
msgstr ""
msgstr "Innstillinger..."
msgid "Check for updates..."
msgstr "Se etter oppdatering..."
msgid "Templates"
msgstr ""
msgstr "Maler"
msgid "Import"
msgstr "Importer"
@@ -612,7 +613,7 @@ msgid "Quit"
msgstr "Avslutt"
msgid "Close Window"
msgstr ""
msgstr "Lukk vindu"
msgid "&Edit"
msgstr "&Rediger"
@@ -677,15 +678,14 @@ msgstr "&Hjelp"
msgid "Website and documentation"
msgstr "Nettsted og dokumentasjon"
#, fuzzy
msgid "Joplin Forum"
msgstr "Joplin v%s"
msgstr "Joplin Forum"
msgid "Make a donation"
msgstr "Gi et bidrag"
msgid "Toggle development tools"
msgstr ""
msgstr "Skru på/av utviklingsverktøy"
#, javascript-format
msgid "Open %s"
@@ -792,7 +792,7 @@ msgstr ""
"tredjepartsapplikasjoner tilgang til Joplin."
msgid "This will open a new screen. Save your current changes?"
msgstr ""
msgstr "Dette vil åpne et nytt vindu. Vil du lagre nåværende endringer?"
#, javascript-format
msgid "Notes and settings are stored in: %s"
@@ -902,13 +902,13 @@ msgid "Encryption is:"
msgstr "Kryptering er:"
msgid "Firefox Extension"
msgstr ""
msgstr "Firefox-utvidelse"
msgid "Chrome Web Store"
msgstr ""
msgstr "Chrome Web Store"
msgid "Get it now:"
msgstr ""
msgstr "Få den nå:"
msgid "Usage"
msgstr "Bruk"
@@ -942,7 +942,7 @@ msgid "Set alarm:"
msgstr "Angi alarm:"
msgid "Template file:"
msgstr ""
msgstr "Malfiler"
msgid "New note"
msgstr "Nytt notat"
@@ -965,9 +965,8 @@ msgstr "Noen elementer kan ikke synkroniseres."
msgid "View them now"
msgstr "Vis nå"
#, fuzzy
msgid "One or more master keys need a password."
msgstr "Skriv inn masterpassordet:"
msgstr "En eller flere masternøkler trenger et passord."
msgid "Set the password"
msgstr "Sett passord"
@@ -986,35 +985,34 @@ msgstr "Lokasjon"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Notatliste"
msgstr "Notathistorikk"
msgid "Markup"
msgstr ""
msgstr "Markup"
msgid "Previous versions of this note"
msgstr ""
msgstr "Forrige versjon av dette notatet"
msgid "Note properties"
msgstr "Notategenskaper"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
msgstr "Notatet \"%s\" has blitt vellykket gjenopprettet i notatboken \"%s\"."
#, fuzzy
msgid "This note has no history"
msgstr "Dette notatet har blitt endret:"
msgstr "Dette notatet har ingen historikk"
msgid "Restore"
msgstr ""
msgstr "Gjenopprett"
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgstr "Velg \"%s\" for å gjenopprette notatet. Det vil bli kopiert til notatboken"
"\"%s\". Den nåværende versjonen av notatet vil ikke bli erstattet eller modifisert."
msgid "Open..."
msgstr "Åpne..."
@@ -1169,7 +1167,7 @@ msgid "Please select where the sync status should be exported to"
msgstr "Velg hvor synkroniseringsstatusen skal eksporteres til"
msgid "Retry"
msgstr ""
msgstr "Prøv igjen"
msgid "Add or remove tags"
msgstr "Legg til eller fjern merkelapper"
@@ -1204,10 +1202,11 @@ msgstr "Slett disse %d notatene?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgstr "Skriv inn tittelen på et notat for å hoppe til det. Eller skriv # etterfulgt av en merkelapp,"
" eller @ etterfulgt av tittelen på en notatbok."
msgid "Goto Anything..."
msgstr ""
msgstr "Hopp til..."
#, javascript-format
msgid "Usage: %s"
@@ -1399,25 +1398,28 @@ msgid "WebDAV password"
msgstr "WebDAV-passord"
msgid "Attachment download behaviour"
msgstr ""
msgstr "Nedlastningsoppførsel for vedlegg"
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
"I \"Manuell\" modus blir vedlegg kun lastet ned når du klikker på de. "
"I \"Auto\" blir de lastet ned når du åpner notatet. I \"Alltid\" blir "
"vedleggene lastet ned uansett om du åpner notatet eller ikke."
msgid "Always"
msgstr ""
msgstr "Alltid"
msgid "Manual"
msgstr ""
msgstr "Manuell"
msgid "Auto"
msgstr ""
msgstr "Auto"
msgid "Max concurrent connections"
msgstr ""
msgstr "Maksimalt samtidige tilkoblinger"
msgid "Language"
msgstr "Språk"
@@ -1438,10 +1440,10 @@ msgid "Dark"
msgstr "Mørk"
msgid "Solarised Light"
msgstr ""
msgstr "Solarisert lys"
msgid "Solarised Dark"
msgstr ""
msgstr "Solarisert mørk"
msgid "Uncompleted to-dos on top"
msgstr "Uferdige gjøremål på topp"
@@ -1471,50 +1473,46 @@ msgid "Focus body"
msgstr "Fokuser på brødtekst"
msgid "When creating a new note:"
msgstr "Når du lager et nytt notat:"
msgstr "Når du oppretter et nytt notat:"
#, fuzzy
msgid "Enable soft breaks"
msgstr "Liste over innhold"
msgstr "Aktiver myke linjeskift"
#, fuzzy
msgid "Enable math expressions"
msgstr "Aktiver kryptering"
msgstr "Aktiver matteuttrykk"
msgid "Enable ==mark== syntax"
msgstr ""
msgstr "Aktiver ==mark==-syntaks"
#, fuzzy
msgid "Enable footnotes"
msgstr "Liste over innhold"
msgstr "Aktiver fotnoter"
#, fuzzy
msgid "Enable table of contents extension"
msgstr "Liste over innhold"
msgstr "Aktiver liste over innhold-utvidelse"
msgid "Enable ~sub~ syntax"
msgstr ""
msgstr "Aktiver ~sub~-syntaks"
msgid "Enable ^sup^ syntax"
msgstr ""
msgstr "Aktiver ^sup^-syntaks"
msgid "Enable deflist syntax"
msgstr ""
msgstr "Aktiver deflist-syntaks"
msgid "Enable abbreviation syntax"
msgstr ""
msgstr "Aktiver forkortelsesyntaks"
msgid "Enable markdown emoji"
msgstr ""
msgstr "Aktiver markdown-emoji"
msgid "Enable ++insert++ syntax"
msgstr ""
msgstr "Aktiver ++insert++-syntaks"
msgid "Enable multimarkdown table extension"
msgstr ""
msgstr "Aktiver multimarkdown-tabellutvidelse"
msgid "Enable Fountain syntax support"
msgstr ""
msgstr "Aktiver Fountain syntaksstøtte"
msgid "Show tray icon"
msgstr "Vis systemmenyikon"
@@ -1540,12 +1538,11 @@ msgstr "Global forstørrelse"
msgid "Editor font size"
msgstr "Editorskriftstørrelse"
#, fuzzy
msgid "Editor font"
msgstr "Editorskriftstørrelse"
msgstr "Editorskrift"
msgid "Editor font family"
msgstr "Editorskrifttype"
msgstr "Editorskriftfamilie"
msgid ""
"This must be *monospace* font or it will not work properly. If the font is "
@@ -1611,25 +1608,27 @@ msgid ""
"Fail-safe: Do not wipe out local data when sync target is empty (often the "
"result of a misconfiguration or bug)"
msgstr ""
"Feilhåndtering: Ikke slett lokal data når synkroniseringsmålet er tomt (ofte "
"resultatet av en miskonfigurering eller bug)"
msgid ""
"Specify the port that should be used by the API server. If not set, a "
"default will be used."
msgstr ""
"Spesifiser porten som skal brukes av API-serveren. Hvis ikke satt vil "
"en standardport brukes."
#, fuzzy
msgid "Enable note history"
msgstr "Liste over innhold"
msgstr "Aktiver notathistorikk"
msgid "days"
msgstr ""
msgstr "dager"
#, javascript-format
msgid "%d days"
msgstr ""
msgstr "%d dager"
msgid "Keep note history for"
msgstr ""
msgstr "Behold notathistorikk i"
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
@@ -1648,18 +1647,16 @@ msgid "Note"
msgstr "Notat"
msgid "Plugins"
msgstr ""
msgstr "Utvidelser"
msgid "Application"
msgstr "Applikasjon"
#, fuzzy
msgid "Encryption"
msgstr "Kryptering er:"
msgstr "Kryptering"
#, fuzzy
msgid "Web Clipper"
msgstr "Web Clipper-innstillinger"
msgstr "Web Clipper"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
@@ -1674,13 +1671,11 @@ msgstr "Markdown"
msgid "Joplin Export Directory"
msgstr "Joplin-eksportert katalog"
#, fuzzy
msgid "Evernote Export File (as Markdown)"
msgstr "Evernote-eksportert fil"
msgstr "Evernote-eksportert fil (Markdown)"
#, fuzzy
msgid "Evernote Export File (as HTML)"
msgstr "Evernote-eksportert fil"
msgstr "Evernote-eksportert fil (HTML)"
msgid "Json Export Directory"
msgstr "Json-eksportert katalog"
@@ -1714,7 +1709,7 @@ msgid "Please specify the notebook where the notes should be imported to."
msgstr "Velg notatbok som notatene skal importeres til."
msgid "Restored Notes"
msgstr ""
msgstr "Gjenopprettede notater"
msgid "Items that cannot be synchronised"
msgstr "Elementer som ikke vil synkronisere"
@@ -1728,23 +1723,25 @@ msgstr ""
"synkroniseringsmålet. For å finne disse elementene, enten søk etter tittel "
"eller ID (som vises i parentes over)."
#, fuzzy, javascript-format
#, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Filen kunne ikke åpnes: %s"
msgstr "%s (%s) ble ikke opplasted: %s"
#, fuzzy, javascript-format
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Filen kunne ikke åpnes: %s"
msgstr "Element \"%s\" ble ikke nedlastet: %s"
#, fuzzy
msgid "Items that cannot be decrypted"
msgstr "Elementer som ikke vil synkronisere"
msgstr "Elementer som ikke kan dekrypteres"
msgid ""
"Joplin failed to decrypt these items multiple times, possibly because they "
"are corrupted or too large. These items will remain on the device but Joplin "
"will no longer attempt to decrypt them."
msgstr ""
"Joplin feilet i å dekryptere disse elementene flere ganger, muligens fordi "
"de er korrupte eller for store. Disse elementene vil forbli på enheten men "
"Joplin vil ikke lenger forsøke å dekryptere de."
msgid "Sync status (synced items / total items)"
msgstr "Synkroniseringsstatus (synkroniserte elementer / totale elementer)"
@@ -1785,13 +1782,11 @@ msgstr "Tillatelse til å bruke kamera"
msgid "Your permission to use your camera is required."
msgstr "Tillatelse til å bruke kamera er nødvendig."
#, fuzzy
msgid "You currently have no notebooks."
msgstr "Ingen aktiv notatbok."
msgstr "Du har ingen notatbøker."
#, fuzzy
msgid "Create a notebook"
msgstr "Oppretter en ny notatbok."
msgstr "Opprett en notatbok"
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr "Det finnes enda ingen notater. Lag en ved å klikke på (+)-knappen."
@@ -1821,24 +1816,21 @@ msgstr "Velg dato"
msgid "Confirm"
msgstr "Bekreft"
#, fuzzy, javascript-format
#, javascript-format
msgid "Notebook: %s"
msgstr "Notatbøker"
msgstr "Notatbok: %s"
#, fuzzy
msgid "Encrypted notebooks cannot be renamed"
msgstr "Krypterte elementer kan ikke modifiseres"
msgstr "Krypterte elementer kan ikke få endret navn"
#, fuzzy
msgid "New Notebook"
msgstr "Ny notatbok"
msgid "Configuration"
msgstr "Konfigurasjon"
#, fuzzy
msgid "All notes"
msgstr "notat"
msgstr "Alle notater"
msgid "Checking... Please wait."
msgstr "Sjekker… Vennligst vent."
@@ -1881,48 +1873,48 @@ msgid "Type new tags or select from list"
msgstr "Skriv inn nye merkelapper eller velg fra listen"
msgid "Warning"
msgstr ""
msgstr "Advarsel"
msgid ""
"In order to use file system synchronisation your permission to write to "
"external storage is required."
msgstr ""
"For å kunne bruke filsystemsynkronisering behøves din tillatelse til å "
"kunne skrive til ekstern lagrging."
msgid "Encryption Config"
msgstr "Krypteringsinnstillinger"
#, fuzzy
msgid "Tools"
msgstr "&Verktøy"
msgstr "Verktøy"
#, fuzzy
msgid "Sync Status"
msgstr "Status"
msgstr "Synkroniseringsstatus"
msgid "Log"
msgstr "Logg"
#, fuzzy
msgid "Creating report..."
msgstr "Oppretter nytt %s..."
msgstr "Oppretter rapport..."
msgid "Export Debug Report"
msgstr "Eksporter feilsøkingsrapport"
msgid "Fixing search index..."
msgstr ""
msgstr "Fikser søkeindeks..."
msgid "Fix search index"
msgstr ""
msgstr "Fiks søkeindeks"
msgid ""
"Use this to rebuild the search index if there is a problem with search. It "
"may take a long time depending on the number of notes."
msgstr ""
"Velg dette for å gjenoppbygge søkeindeksen dersom du har problemer med søk. "
"Det kan ta lang tid avhengig av antall notater."
#, fuzzy
msgid "More information"
msgstr "Konfigurasjon"
msgstr "Mer informasjon"
msgid ""
"To work correctly, the app needs the following permissions. Please enable "
@@ -1985,9 +1977,8 @@ msgstr "Denne notatboken kunne ikke lagres: %s"
msgid "Edit notebook"
msgstr "Rediger notatbok"
#, fuzzy
msgid "Enter notebook title"
msgstr "Tittel på notatbok:"
msgstr "Angi tittel på notatbok"
msgid "Show all"
msgstr "Vis alle"
@@ -2014,15 +2005,15 @@ msgstr "Joplins mobilapp støtter for tiden ikke denne type linker: %s"
#, javascript-format
msgid "Links with protocol \"%s\" are not supported"
msgstr ""
msgstr "Linker med protokoll \"%s\" er ikke støttet"
#, javascript-format
msgid "Unsupported image type: %s"
msgstr "Bildetypen er ikke støttet: %s"
#, fuzzy, javascript-format
#, javascript-format
msgid "Updated: %s"
msgstr "Oppdatert: %d."
msgstr "Oppdatert: %s"
msgid "View on map"
msgstr "Vis på kart"
@@ -2030,13 +2021,11 @@ msgstr "Vis på kart"
msgid "Go to source URL"
msgstr "Gå til kilde-URL"
#, fuzzy
msgid "Attach..."
msgstr "Søk..."
msgstr "Legg ved..."
#, fuzzy
msgid "Choose an option"
msgstr "Vis avanserte innstillinger"
msgstr "Velg et alternativ"
msgid "Take photo"
msgstr "Ta bilde"
@@ -2056,19 +2045,17 @@ msgstr "Konverter til notat"
msgid "Convert to todo"
msgstr "Konverter til gjøremål"
#, fuzzy
msgid "Properties"
msgstr "Notategenskaper"
msgstr "Egenskaper"
msgid "Add body"
msgstr ""
msgstr "Legg til brødtekst"
msgid "Edit"
msgstr "Rediger"
#, fuzzy
msgid "Add title"
msgstr "tittel"
msgstr "Legg til tittel"
msgid "Login with OneDrive"
msgstr "Innlogging med OneDrive"
@@ -2111,17 +2098,14 @@ msgstr "Søk"
#~ msgid "Encryption options"
#~ msgstr "Krypteringsvalg"
#, fuzzy
#~ msgid "Insert template"
#~ msgstr "Sett inn dato/tid"
#~ msgstr "Legg inn mal"
#, fuzzy
#~ msgid "Open template directory"
#~ msgstr "Joplin-eksportert katalog"
#~ msgstr "Åpne malkatalog"
#, fuzzy
#~ msgid "Revision: %s (%s)"
#~ msgstr "%s %s (%s)"
#~ msgstr "Revisjon: %s (%s)"
#~ msgid "%s %s (%s, %s)"
#~ msgstr "%s %s (%s, %s)"
@@ -2132,13 +2116,11 @@ msgstr "Søk"
#~ msgid "Clipper Options"
#~ msgstr "Clipper-innstillinger"
#, fuzzy
#~ msgid "Information"
#~ msgstr "Konfigurasjon"
#~ msgstr "Informasjon"
#, fuzzy
#~ msgid "Permission to write to external storage"
#~ msgstr "Tillatelse til å bruke kamera"
#~ msgstr "Tillatelse til å skrive til ekstern lagring"
#~ msgid "Cancel synchronisation"
#~ msgstr "Avbryt synkronisering"

View File

@@ -7,14 +7,16 @@ msgid ""
msgstr ""
"Project-Id-Version: Joplin-CLI 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: Heimen Stoffels <vistausss@outlook.com>\n"
"Language-Team: Dutch <vistausss@outlook.com>\n"
"Last-Translator: Robert <metbril@outlook.com>\n"
"Language-Team: Dutch / Nederlands\n"
"Language: nl_NL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.2.3\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
msgid "To delete a tag, untag the associated notes."
msgstr ""
@@ -389,17 +391,20 @@ msgid ""
"Start, stop or check the API server. To specify on which port it should run, "
"set the api.port config variable. Commands are (%s)."
msgstr ""
"Start, stop of controleer de API-server. Stel de api.port "
"configuratievariabele in om te specificeren op welke poort deze draait. "
"Commando's zijn (%s)."
#, javascript-format
msgid "Server is already running on port %d"
msgstr ""
msgstr "Server draait reeds op poort %d"
#, javascript-format
msgid "Server is running on port %d"
msgstr ""
msgstr "Server draait op poort %d"
msgid "Server is not running."
msgstr ""
msgstr "Server draait niet."
#, javascript-format
msgid ""
@@ -687,9 +692,8 @@ msgstr "&Help"
msgid "Website and documentation"
msgstr "Website en documentatie"
#, fuzzy
msgid "Joplin Forum"
msgstr "Joplin-website"
msgstr "Joplin-forum"
msgid "Make a donation"
msgstr "Doneren"
@@ -803,7 +807,7 @@ msgstr ""
"geven tot Joplin."
msgid "This will open a new screen. Save your current changes?"
msgstr ""
msgstr "Dit opent een nieuw scherm. Wijzigingen opslaan?"
#, javascript-format
msgid "Notes and settings are stored in: %s"
@@ -913,13 +917,13 @@ msgid "Encryption is:"
msgstr "Gebruikte versleuteling:"
msgid "Firefox Extension"
msgstr ""
msgstr "Firefox-extensie"
msgid "Chrome Web Store"
msgstr ""
msgstr "Chrome Web Store"
msgid "Get it now:"
msgstr ""
msgstr "Haal nu op:"
msgid "Usage"
msgstr "Gebruik"
@@ -1533,9 +1537,8 @@ msgstr "Inschakelen ++insert++ syntaxis"
msgid "Enable multimarkdown table extension"
msgstr "Inschakelen multimarkdown tabel extensie"
#, fuzzy
msgid "Enable Fountain syntax support"
msgstr "Inschakelen ~sub~ syntaxis"
msgstr "Inschakelen ondersteuning voor Fountain syntaxis"
msgid "Show tray icon"
msgstr "Systeemvakpictogram tonen"
@@ -1561,9 +1564,8 @@ msgstr "Globaal zoompercentage"
msgid "Editor font size"
msgstr "Lettergrootte van bewerker"
#, fuzzy
msgid "Editor font"
msgstr "Lettergrootte van bewerker"
msgstr "Lettertype van bewerker"
msgid "Editor font family"
msgstr "Lettertype van bewerker"
@@ -1634,11 +1636,15 @@ msgid ""
"Fail-safe: Do not wipe out local data when sync target is empty (often the "
"result of a misconfiguration or bug)"
msgstr ""
"Veiligheidswaarschuwing: Wis lokale gegevens niet wanneer synchronisatiedoel "
"leeg is (vaak het gevolg van een misconfiguratie of softwarefout)"
msgid ""
"Specify the port that should be used by the API server. If not set, a "
"default will be used."
msgstr ""
"Specificeer de door de API-server te gebruiken poort. Indien niet ingesteld, "
"wordt een standaardwaarde gebruikt."
msgid "Enable note history"
msgstr "Inschakelen geschiedenis van notities"
@@ -1675,13 +1681,11 @@ msgstr "Plugins"
msgid "Application"
msgstr "Applicatie"
#, fuzzy
msgid "Encryption"
msgstr "Gebruikte versleuteling:"
msgstr "Versleuteling"
#, fuzzy
msgid "Web Clipper"
msgstr "Webclipper-opties"
msgstr "Webclipper"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
@@ -1696,13 +1700,11 @@ msgstr "Markdown"
msgid "Joplin Export Directory"
msgstr "Joplin-exportmap"
#, fuzzy
msgid "Evernote Export File (as Markdown)"
msgstr "Evernote-exportbestand"
msgstr "Evernote-exportbestand (als Markdown)"
#, fuzzy
msgid "Evernote Export File (as HTML)"
msgstr "Evernote-exportbestand"
msgstr "Evernote-exportbestand (als HTML)"
msgid "Json Export Directory"
msgstr "JSON-exportmap"
@@ -1811,13 +1813,11 @@ msgstr "Toestemming om de camera te gebruiken"
msgid "Your permission to use your camera is required."
msgstr "Je toestemming om de camera te gebruiken is vereist."
#, fuzzy
msgid "You currently have no notebooks."
msgstr "Geen actief notitieboek."
msgstr "Je hebt nog geen notitieboeken."
#, fuzzy
msgid "Create a notebook"
msgstr "Creëert een nieuw notitieboek."
msgstr "Creëer een notitieboek"
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr ""
@@ -1849,24 +1849,21 @@ msgstr "Datum kiezen"
msgid "Confirm"
msgstr "Bevestigen"
#, fuzzy, javascript-format
#, javascript-format
msgid "Notebook: %s"
msgstr "Notitieboeken"
msgstr "Notitieboek: %s"
#, fuzzy
msgid "Encrypted notebooks cannot be renamed"
msgstr "Versleutelde items kunnen niet worden bewerkt"
msgstr "Versleutelde notitieboeken kunnen niet worden hernoemd"
#, fuzzy
msgid "New Notebook"
msgstr "Nieuw notitieboek"
msgid "Configuration"
msgstr "Configuratie"
#, fuzzy
msgid "All notes"
msgstr "notitie"
msgstr "Alle notities"
msgid "Checking... Please wait."
msgstr "Controleren… Even geduld."
@@ -1921,20 +1918,17 @@ msgstr ""
msgid "Encryption Config"
msgstr "Versleutelconfiguratie"
#, fuzzy
msgid "Tools"
msgstr "E&xtra"
msgstr "Hulpmiddelen"
#, fuzzy
msgid "Sync Status"
msgstr "Status"
msgstr "Synchronisatiestatus"
msgid "Log"
msgstr "Log"
#, fuzzy
msgid "Creating report..."
msgstr "Bezig met creëren van nieuw(e) %s..."
msgstr "Creëren rapport..."
msgid "Export Debug Report"
msgstr "Foutopsporingsrapportage exporteren"
@@ -2017,9 +2011,8 @@ msgstr "Het notitieboek kan niet worden opgeslagen: %s"
msgid "Edit notebook"
msgstr "Notitieboek bewerken"
#, fuzzy
msgid "Enter notebook title"
msgstr "Titel van notitieboek:"
msgstr "Invoeren titel notitieboek"
msgid "Show all"
msgstr "Alles tonen"
@@ -2052,9 +2045,9 @@ msgstr "Links met protocol “%s” worden niet ondersteund"
msgid "Unsupported image type: %s"
msgstr "Niet-ondersteunde afbeeldingssoort: %s"
#, fuzzy, javascript-format
#, javascript-format
msgid "Updated: %s"
msgstr "Bijgewerkt: %d."
msgstr "Bijgewerkt: %s"
msgid "View on map"
msgstr "Tonen op kaart"
@@ -2062,13 +2055,11 @@ msgstr "Tonen op kaart"
msgid "Go to source URL"
msgstr "Ga naar bron-URL"
#, fuzzy
msgid "Attach..."
msgstr "Zoeken..."
msgstr "Bijvoegen..."
#, fuzzy
msgid "Choose an option"
msgstr "Geavanceerde opties tonen"
msgstr "Kies een optie"
msgid "Take photo"
msgstr "Foto maken"
@@ -2088,9 +2079,8 @@ msgstr "Omzetten naar notitie"
msgid "Convert to todo"
msgstr "Omzetten naar taak"
#, fuzzy
msgid "Properties"
msgstr "Eigenschappen van notitie"
msgstr "Eigenschappen"
msgid "Add body"
msgstr "Inhoud toevoegen"
@@ -2098,9 +2088,8 @@ msgstr "Inhoud toevoegen"
msgid "Edit"
msgstr "Bewerken"
#, fuzzy
msgid "Add title"
msgstr "titel"
msgstr "Toevoegen titel"
msgid "Login with OneDrive"
msgstr "Inloggen met OneDrive"

View File

@@ -13,17 +13,18 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.0.6\n"
"X-Generator: Poedit 2.2.3\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
msgid "To delete a tag, untag the associated notes."
msgstr "Для удаления метки, открепите ее от связанных с ней заметок."
msgid "Please select the note or notebook to be deleted first."
msgstr ""
"Пожалуйста, выберите заметку или блокнот, которые будут удалены в первую "
"очередь."
"Пожалуйста, выберите заметку или блокнот, которые будут удалены первыми."
msgid "Press Ctrl+D or type \"exit\" to exit the application"
msgstr "Для выхода из приложения нажмите Ctrl+D или введите \"exit\""
@@ -103,7 +104,7 @@ msgstr ""
"конфигурацию."
msgid "Also displays unset and hidden config variables."
msgstr "Также выводит неустановленные или скрытые переменные конфигурации."
msgstr "Также показывает неустановленные или скрытые переменные конфигурации."
#, javascript-format
msgid "%s = %s (%s)"
@@ -127,7 +128,6 @@ msgstr "Отмечает задачу как выполненную."
msgid "Note is not a to-do: \"%s\""
msgstr "Заметка не является задачей: «%s»"
#, fuzzy
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status`, `decrypt-file` and `target-status`."
@@ -177,6 +177,18 @@ msgstr "Нет активного блокнота."
msgid "Note does not exist: \"%s\". Create it?"
msgstr "Заметка не существует: \"%s\". Создать?"
msgid "Starting to edit note. Close the editor to get back to the prompt."
msgstr ""
"Запуск редактирования заметки. Закройте редактор, чтобы вернуться к "
"приглашению."
#, javascript-format
msgid "Error opening note in editor: %s"
msgstr "Ошибка при открытии заметки в редакторе: %s"
msgid "Note has been saved."
msgstr "Заметка сохранена."
msgid "Exits the application."
msgstr "Выйти из приложения."
@@ -387,17 +399,19 @@ msgid ""
"Start, stop or check the API server. To specify on which port it should run, "
"set the api.port config variable. Commands are (%s)."
msgstr ""
"Запустить, остановить или проверить сервер API. Порт сервера настраивается с "
"помощью переменной api.port. Доступные команды: (%s)."
#, javascript-format
msgid "Server is already running on port %d"
msgstr ""
msgstr "Сервер уже запущен на порту %d"
#, javascript-format
msgid "Server is running on port %d"
msgstr ""
msgstr "Сервер запущен на порту %d"
msgid "Server is not running."
msgstr ""
msgstr "Сервер не запущен."
#, javascript-format
msgid ""
@@ -539,6 +553,10 @@ msgstr "Введите `joplin help` для получения информац
msgid "Fatal error:"
msgstr "Фатальная ошибка:"
#, javascript-format
msgid "All potential ports are in use - please report the issue at %s"
msgstr "Все возможные порты заняты - пожалуйста, сообщите о проблеме в %s"
msgid ""
"The application has been authorised - you may now close this browser tab."
msgstr "Приложение авторизовано — можно закрыть вкладку браузера."
@@ -593,6 +611,72 @@ msgstr ""
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Экспорт в \"%s\" в формате \"%s\". Пожалуйста, подождите..."
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 "Импорт из \"%s\" в формате \"%s\". Пожалуйста, подождите..."
msgid "PDF File"
msgstr "Файл PDF"
msgid "Synchronisation status"
msgstr "Статус синхронизации"
msgid "New note"
msgstr "Новая заметка"
msgid "New to-do"
msgstr "Новая задача"
msgid "New notebook"
msgstr "Новый блокнот"
msgid "Print"
msgstr "Печать"
msgid "General Options"
msgstr "Основные настройки"
msgid "Encryption options"
msgstr "Настройки шифрования"
msgid "Web clipper options"
msgstr "Настройки веб-клиппера"
msgid "Create note from template"
msgstr "Создать заметку из шаблона"
msgid "Create to-do from template"
msgstr "Создать задачу из шаблона"
msgid "Insert template"
msgstr "Вставить шаблон"
msgid "Open template directory"
msgstr "Открыть папку с шаблонами"
msgid "Refresh templates"
msgstr "Обновить шаблоны"
#, javascript-format
msgid "Revision: %s (%s)"
msgstr "Изменения: %s (%s)"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "&Файл"
@@ -600,13 +684,13 @@ msgid "About Joplin"
msgstr "О Joplin"
msgid "Preferences..."
msgstr ""
msgstr "Настройки…"
msgid "Check for updates..."
msgstr "Проверить обновления..."
msgid "Templates"
msgstr ""
msgstr "Шаблоны"
msgid "Import"
msgstr "Импорт"
@@ -625,7 +709,7 @@ msgid "Quit"
msgstr "Выход"
msgid "Close Window"
msgstr ""
msgstr "Закрыть окно"
msgid "&Edit"
msgstr "&Правка"
@@ -643,10 +727,10 @@ msgid "Select all"
msgstr "Выбрать все"
msgid "Bold"
msgstr "Жирный"
msgstr "Полужирный"
msgid "Italic"
msgstr "Наклонный"
msgstr "Курсивный"
msgid "Link"
msgstr "Ссылка"
@@ -690,15 +774,14 @@ msgstr "&Помощь"
msgid "Website and documentation"
msgstr "Сайт и документация"
#, fuzzy
msgid "Joplin Forum"
msgstr "Joplin v%s"
msgstr "Форум Joplin"
msgid "Make a donation"
msgstr "Сделать пожертвование"
msgstr "Пожертвовать"
msgid "Toggle development tools"
msgstr ""
msgstr "Включить средства разработки"
#, javascript-format
msgid "Open %s"
@@ -768,7 +851,7 @@ msgstr ""
"браузера в Joplin."
msgid "In order to use the web clipper, you need to do the following:"
msgstr "Для того, чтобы использовать веб-клиппер, вам нужно сделать следующее:"
msgstr "Для использования веб-клиппера вам нужно сделать следующее:"
msgid "Step 1: Enable the clipper service"
msgstr "Шаг 1: включите службу веб-клиппера"
@@ -778,7 +861,7 @@ msgid ""
"enabling it your firewall may ask you to give permission to Joplin to listen "
"to a particular port."
msgstr ""
"Эта служба позволяет расширению браузера общаться с Joplin. После ее "
"Эта служба позволяет расширению браузера взаимодействовать с Joplin. После ее "
"включения брандмауэр ОС может запросить разрешение на использование Joplin "
"определенного порта."
@@ -804,9 +887,6 @@ msgstr ""
"Этот токен авторизации необходим только для разрешения сторонним приложениям "
"получать доступ к Joplin."
msgid "This will open a new screen. Save your current changes?"
msgstr ""
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr "Заметки и настройки сохранены в: %s"
@@ -817,9 +897,6 @@ msgstr "Проверить настройки синхронизации"
msgid "Browse..."
msgstr "Обзор..."
msgid "Back"
msgstr "Назад"
msgid "Apply"
msgstr "Применить"
@@ -915,18 +992,12 @@ msgstr "Статус"
msgid "Encryption is:"
msgstr "Шифрование:"
msgid "Firefox Extension"
msgstr ""
msgid "Chrome Web Store"
msgstr ""
msgid "Get it now:"
msgstr ""
msgid "Usage"
msgstr "Использование: %s"
msgid "Back"
msgstr "Назад"
#, javascript-format
msgid ""
"New notebook \"%s\" will be created and file \"%s\" will be imported into it"
@@ -955,16 +1026,7 @@ msgid "Set alarm:"
msgstr "Установить напоминание:"
msgid "Template file:"
msgstr ""
msgid "New note"
msgstr "Новая заметка"
msgid "New to-do"
msgstr "Новая задача"
msgid "New notebook"
msgstr "Новый блокнот"
msgstr "Файл шаблона:"
msgid "Layout"
msgstr "Разметка"
@@ -978,9 +1040,8 @@ msgstr "Некоторые элементы не могут быть синхр
msgid "View them now"
msgstr "Просмотреть их сейчас"
#, fuzzy
msgid "One or more master keys need a password."
msgstr "Введите мастер-пароль:"
msgstr "Для одного или нескольких мастер-ключей требуется пароль."
msgid "Set the password"
msgstr "Установить пароль"
@@ -998,35 +1059,35 @@ msgstr "Местоположение"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Список заметок"
msgstr "История заметок"
msgid "Markup"
msgstr ""
msgstr "Разметка"
msgid "Previous versions of this note"
msgstr ""
msgstr "Предыдущая версия заметки"
msgid "Note properties"
msgstr "Свойства заметки"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
msgstr "Заметка “%s” была успешно восстановлена в блокнот “%s”."
#, fuzzy
msgid "This note has no history"
msgstr "Эта заметка была изменена:"
msgstr "Эта заметка не имеет предыдущей версии"
msgid "Restore"
msgstr ""
msgstr "Восстановить"
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
"Нажмите “%s”, чтобы восстановить заметку. Она будет скопирована в блокнот "
"“%s”. Текущая версия заметки не будет заменена или изменена."
msgid "Open..."
msgstr "Открыть..."
@@ -1063,13 +1124,6 @@ msgid "Only one note can be printed or exported to PDF at a time."
msgstr ""
"Только одна заметка может быть напечатана или экспортирована в PDF за раз."
msgid "PDF File"
msgstr "Файл PDF"
#, javascript-format
msgid "Error opening note in editor: %s"
msgstr "Ошибка при открытии заметки в редакторе: %s"
msgid "strong text"
msgstr "выделенный текст"
@@ -1144,18 +1198,25 @@ msgstr "Настройки"
msgid "Synchronisation Status"
msgstr "Статус синхронизации"
#, fuzzy, javascript-format
msgid "Encryption Options"
msgstr "Настройки шифрования"
msgid "Clipper Options"
msgstr "Настройки клиппера"
#, javascript-format
msgid ""
"Delete notebook \"%s\"?\n"
"\n"
"All notes and sub-notebooks within this notebook will also be deleted."
msgstr ""
"Удалить блокнот? Все заметки и вложенные блокноты в этом блокноте также "
"будут удалены."
"Удалить блокнот “%s”?\n"
"\n"
"Все заметки и вложенные блокноты в этом блокноте также будут удалены."
#, fuzzy, javascript-format
#, javascript-format
msgid "Remove tag \"%s\" from all notes?"
msgstr "Удалить эту метку из всех заметок?"
msgstr "Удалить метку “%s” из всех заметок?"
msgid "Remove this search from the sidebar?"
msgstr "Удалить этот поиск из боковой панели?"
@@ -1166,23 +1227,12 @@ msgstr "Удалить"
msgid "Rename"
msgstr "Переименовать"
msgid "Notebooks"
msgstr "Блокноты"
#, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Расшифровано элементов: %d/%d"
#, javascript-format
msgid "Fetching resources: %d/%d"
msgstr "Получение ресурсов: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr ""
"Пожалуйста, выберите, куда должен быть экспортирован статус синхронизации"
msgid "Retry"
msgstr ""
msgstr "Повторить попытку"
msgid "Add or remove tags"
msgstr "Добавить или удалить метки"
@@ -1218,9 +1268,11 @@ msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
"Введите название заметки, чтобы перейти к ней, либо введите #имя_тега или "
"@имя_блокнота."
msgid "Goto Anything..."
msgstr ""
msgstr "Перейти к чему угодно…"
#, javascript-format
msgid "Usage: %s"
@@ -1334,6 +1386,12 @@ msgstr "Выполнение"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Синхронизация уже выполняется. Состояние: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
"Обнаружен неизвестный тип файла - пожалуйста, обновите Joplin до последней "
"версии"
msgid "Encrypted"
msgstr "Зашифровано"
@@ -1395,7 +1453,7 @@ msgid "Directory to synchronise with (absolute path)"
msgstr "Каталог синхронизации (абсолютный путь)"
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
msgstr "URL-адрес WebDAV-сервера Nextcloud"
msgid "Nextcloud username"
msgstr "Имя пользователя Nextcloud"
@@ -1404,7 +1462,7 @@ msgid "Nextcloud password"
msgstr "Пароль Nextcloud"
msgid "WebDAV URL"
msgstr "WebDAV URL"
msgstr "URL-адрес WebDAV"
msgid "WebDAV username"
msgstr "Имя пользователя WebDAV"
@@ -1413,25 +1471,28 @@ msgid "WebDAV password"
msgstr "Пароль WebDAV"
msgid "Attachment download behaviour"
msgstr ""
msgstr "Правило загрузок вложений"
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
"В режиме “Ручной” вложения скачиваются, если на них кликнуть. В режиме "
"“Автоматически”, вложения скачиваются при открытии заметки. В режиме "
"“Всегда” все заметки скачиваются всегда."
msgid "Always"
msgstr ""
msgstr "Всегда"
msgid "Manual"
msgstr ""
msgstr "Ручной"
msgid "Auto"
msgstr ""
msgstr "Автоматически"
msgid "Max concurrent connections"
msgstr ""
msgstr "Максимальное число одновременных соединений"
msgid "Language"
msgstr "Язык"
@@ -1449,13 +1510,13 @@ msgid "Light"
msgstr "Светлая"
msgid "Dark"
msgstr "Темная"
msgstr "Тёмная"
msgid "Solarised Light"
msgstr ""
msgstr "Ярко-светлая"
msgid "Solarised Dark"
msgstr ""
msgstr "Ярко-тёмная"
msgid "Uncompleted to-dos on top"
msgstr "Незавершенные задачи сверху"
@@ -1488,44 +1549,43 @@ msgid "When creating a new note:"
msgstr "При создании новой заметки:"
msgid "Enable soft breaks"
msgstr ""
msgstr "Включить мягкие отступы"
#, fuzzy
msgid "Enable math expressions"
msgstr "Включить шифрование"
msgstr "Включить математические выражения"
msgid "Enable ==mark== syntax"
msgstr ""
msgstr "Включить синтаксис ==mark=="
msgid "Enable footnotes"
msgstr ""
msgstr "Включить постраничные сноски"
msgid "Enable table of contents extension"
msgstr ""
msgstr "Включить расширение содержания"
msgid "Enable ~sub~ syntax"
msgstr ""
msgstr "Включить синтаксис ~sub~"
msgid "Enable ^sup^ syntax"
msgstr ""
msgstr "Включить синтаксис ^sup^"
msgid "Enable deflist syntax"
msgstr ""
msgstr "Включить синтаксис deflist"
msgid "Enable abbreviation syntax"
msgstr ""
msgstr "Включить синтаксис аббревиатур"
msgid "Enable markdown emoji"
msgstr ""
msgstr "Включить markdown emoji"
msgid "Enable ++insert++ syntax"
msgstr ""
msgstr "Включить синтаксис ++insert++"
msgid "Enable multimarkdown table extension"
msgstr ""
msgstr "Включить расширение таблиц multimarkdown"
msgid "Enable Fountain syntax support"
msgstr ""
msgstr "Включить поддержку Fountain"
msgid "Show tray icon"
msgstr "Показывать иконку в трее"
@@ -1551,10 +1611,6 @@ msgstr "Глобальный масштаб в процентах"
msgid "Editor font size"
msgstr "Размер шрифта редактора"
#, fuzzy
msgid "Editor font"
msgstr "Размер шрифта редактора"
msgid "Editor font family"
msgstr "Семейство шрифтов редактора"
@@ -1621,29 +1677,25 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Игнорировать ошибки сертификата TLS"
msgid ""
"Fail-safe: Do not wipe out local data when sync target is empty (often the "
"result of a misconfiguration or bug)"
msgstr ""
msgid ""
"Specify the port that should be used by the API server. If not set, a "
"default will be used."
msgstr ""
"Укажите порт для работы сервера API. Если не указано, будет использовано "
"значение по умолчанию."
#, fuzzy
msgid "Enable note history"
msgstr "Включить шифрование"
msgstr "Включить историю заметок"
msgid "days"
msgstr ""
msgstr "дни"
#, javascript-format
msgid "%d days"
msgstr ""
msgstr "%d дней"
msgid "Keep note history for"
msgstr ""
msgstr "Хранить историю заметки"
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
@@ -1662,19 +1714,11 @@ msgid "Note"
msgstr "Заметки"
msgid "Plugins"
msgstr ""
msgstr "Плагины"
msgid "Application"
msgstr "Приложение"
#, fuzzy
msgid "Encryption"
msgstr "Шифрование:"
#, fuzzy
msgid "Web Clipper"
msgstr "Настройки веб-клиппера"
#, javascript-format
msgid "The tag \"%s\" already exists. Please choose a different name."
msgstr "Метка \"%s\" уже существует. Пожалуйста, выберите другое имя."
@@ -1688,12 +1732,7 @@ msgstr "Markdown"
msgid "Joplin Export Directory"
msgstr "Каталог экспорта Joplin"
#, fuzzy
msgid "Evernote Export File (as Markdown)"
msgstr "Файл экспорта Evernote"
#, fuzzy
msgid "Evernote Export File (as HTML)"
msgid "Evernote Export File"
msgstr "Файл экспорта Evernote"
msgid "Json Export Directory"
@@ -1729,7 +1768,7 @@ msgstr ""
"Пожалуйста, укажите блокнот, в который должны быть импортированы заметки."
msgid "Restored Notes"
msgstr ""
msgstr "Восстановленные заметки"
msgid "Items that cannot be synchronised"
msgstr "Элементы, которые не могут быть синхронизированы"
@@ -1743,23 +1782,25 @@ msgstr ""
"синхронизации. Чтобы найти эти элементы, воспользуйтесь поиском по названию "
"или ID (который указывается в скобках выше)."
#, fuzzy, javascript-format
#, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Этот файл не может быть открыт: %s"
msgstr "Не удается загрузить файл %s (%s): %s"
#, fuzzy, javascript-format
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Этот файл не может быть открыт: %s"
msgstr "Не удается скачать файл “%s”: %s"
#, fuzzy
msgid "Items that cannot be decrypted"
msgstr "Элементы, которые не могут быть синхронизированы"
msgstr "Элементы, которые не могут быть расшифрованы"
msgid ""
"Joplin failed to decrypt these items multiple times, possibly because they "
"are corrupted or too large. These items will remain on the device but Joplin "
"will no longer attempt to decrypt them."
msgstr ""
"Joplin не удалось расшифровать эти файлы несколько раз. Возможно они "
"повреждены или слишком большие. Файлы останутся на устройстве без дальнейших "
"попыток расшифровать их."
msgid "Sync status (synced items / total items)"
msgstr "Статус синхронизации (синхронизировано / всего)"
@@ -1800,13 +1841,11 @@ msgstr "Разрешение на использование камеры"
msgid "Your permission to use your camera is required."
msgstr "Необходимо ваше разрешение на использование камеры."
#, fuzzy
msgid "You currently have no notebooks."
msgstr "Нет активного блокнота."
msgstr "Сейчас у вас нет блокнотов."
#, fuzzy
msgid "Create a notebook"
msgstr "Создает новый блокнот."
msgstr "Создать новый блокнот"
msgid "There are currently no notes. Create one by clicking on the (+) button."
msgstr "Сейчас здесь нет заметок. Создайте новую, нажав кнопку (+)."
@@ -1836,24 +1875,32 @@ msgstr "Выбрать дату"
msgid "Confirm"
msgstr "Подтвердить"
#, fuzzy, javascript-format
#, javascript-format
msgid "Notebook: %s"
msgstr "Блокноты"
msgstr "Блокноты: %s"
#, fuzzy
msgid "Encrypted notebooks cannot be renamed"
msgstr "Зашифрованные элементы не могут быть изменены"
msgstr "Невозможно переименовать зашифрованные блокноты"
#, fuzzy
msgid "New Notebook"
msgstr "Новый блокнот"
msgid "Configuration"
msgstr "Конфигурация"
#, fuzzy
#, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Расшифровано элементов: %d/%d"
#, javascript-format
msgid "Fetching resources: %d/%d"
msgstr "Получение ресурсов: %d/%d"
msgid "All notes"
msgstr "заметка"
msgstr "Все заметки"
msgid "Notebooks"
msgstr "Блокноты"
msgid "Checking... Please wait."
msgstr "Проверка... Пожалуйста, подождите."
@@ -1896,48 +1943,51 @@ msgid "Type new tags or select from list"
msgstr "Введите новые метки или выберите из списка"
msgid "Warning"
msgstr ""
msgstr "Предупрежение"
msgid ""
"In order to use file system synchronisation your permission to write to "
"external storage is required."
msgstr ""
"Для использование синхронизации файловой системы, необходимо дать разрешение "
"на запись."
msgid "Information"
msgstr "Информация"
msgid "Encryption Config"
msgstr "Конфигурация шифрования"
#, fuzzy
msgid "Tools"
msgstr "&Сервис"
msgstr "Инструменты"
#, fuzzy
msgid "Sync Status"
msgstr "Статус"
msgstr "Синхронизировать статус"
msgid "Log"
msgstr "Журнал"
#, fuzzy
msgid "Creating report..."
msgstr "Создание новой %s..."
msgstr "Создание отчета…"
msgid "Export Debug Report"
msgstr "Экспортировать отладочный отчет"
msgid "Fixing search index..."
msgstr ""
msgstr "Исправление индекса поиска…"
msgid "Fix search index"
msgstr ""
msgstr "Исправить индекс поиска"
msgid ""
"Use this to rebuild the search index if there is a problem with search. It "
"may take a long time depending on the number of notes."
msgstr ""
"Используйте это, чтобы перестроить индекс поиска, если возникли проблемы с "
"поиском. Это может занять много времени в зависимости от количества заметок."
#, fuzzy
msgid "More information"
msgstr "Конфигурация"
msgstr "Больше информации"
msgid ""
"To work correctly, the app needs the following permissions. Please enable "
@@ -2002,9 +2052,8 @@ msgstr "Блокнот не может быть сохранен: %s"
msgid "Edit notebook"
msgstr "Редактировать блокнот"
#, fuzzy
msgid "Enter notebook title"
msgstr "Название блокнота:"
msgstr "Введите название блокнота"
msgid "Show all"
msgstr "Показать все"
@@ -2033,15 +2082,15 @@ msgstr ""
#, javascript-format
msgid "Links with protocol \"%s\" are not supported"
msgstr ""
msgstr "Связь с протоколом “%s” не поддерживается"
#, javascript-format
msgid "Unsupported image type: %s"
msgstr "Неподдерживаемый формат изображения: %s"
#, fuzzy, javascript-format
#, javascript-format
msgid "Updated: %s"
msgstr "Обновлено: %d."
msgstr "Обновлено: %s"
msgid "View on map"
msgstr "Посмотреть на карте"
@@ -2049,13 +2098,11 @@ msgstr "Посмотреть на карте"
msgid "Go to source URL"
msgstr "Перейти к исходному URL"
#, fuzzy
msgid "Attach..."
msgstr "Поиск..."
msgstr "Прикрепить…"
#, fuzzy
msgid "Choose an option"
msgstr "Показывать расширенные настройки"
msgstr "Выберите"
msgid "Take photo"
msgstr "Сделать фото"
@@ -2075,19 +2122,17 @@ msgstr "Преобразовать в заметку"
msgid "Convert to todo"
msgstr "Преобразовать в задачу"
#, fuzzy
msgid "Properties"
msgstr "Свойства заметки"
msgstr "Свойства"
msgid "Add body"
msgstr ""
msgstr "Добавить тело"
msgid "Edit"
msgstr "Правка"
#, fuzzy
msgid "Add title"
msgstr "заголовок"
msgstr "Добавить заголовок"
msgid "Login with OneDrive"
msgstr "Войти с OneDrive"
@@ -2095,66 +2140,6 @@ msgstr "Войти с OneDrive"
msgid "Search"
msgstr "Поиск"
#~ msgid "Starting to edit note. Close the editor to get back to the prompt."
#~ msgstr ""
#~ "Запуск редактирования заметки. Закройте редактор, чтобы вернуться к "
#~ "приглашению."
#~ msgid "Note has been saved."
#~ msgstr "Заметка сохранена."
#~ msgid "Sidebar"
#~ msgstr "Боковая панель"
#~ msgid "Note list"
#~ msgstr "Список заметок"
#~ msgid "Note title"
#~ msgstr "Название заметки"
#~ msgid "Note body"
#~ msgstr "Тело заметки"
#~ msgid "Importing from \"%s\" as \"%s\" format. Please wait..."
#~ msgstr "Импорт из \"%s\" в формате \"%s\". Пожалуйста, подождите..."
#~ msgid "Synchronisation status"
#~ msgstr "Статус синхронизации"
#~ msgid "Print"
#~ msgstr "Печать"
#~ msgid "General Options"
#~ msgstr "Основные настройки"
#~ msgid "Encryption options"
#~ msgstr "Настройки шифрования"
#, fuzzy
#~ msgid "Insert template"
#~ msgstr "Вставить дату и время"
#, fuzzy
#~ msgid "Open template directory"
#~ msgstr "Каталог экспорта Joplin"
#, fuzzy
#~ msgid "Revision: %s (%s)"
#~ msgstr "%s %s (%s)"
#~ msgid "%s %s (%s, %s)"
#~ msgstr "%s %s (%s, %s)"
#~ msgid "Encryption Options"
#~ msgstr "Настройки шифрования"
#~ msgid "Clipper Options"
#~ msgstr "Настройки клиппера"
#, fuzzy
#~ msgid "Information"
#~ msgstr "Конфигурация"
#, fuzzy
#~ msgid "Permission to write to external storage"
#~ msgstr "Разрешение на использование камеры"

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "1.0.147",
"version": "1.0.149",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -18,9 +18,9 @@
}
},
"abab": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
"integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz",
"integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg=="
},
"abbrev": {
"version": "1.1.1",
@@ -28,17 +28,24 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz",
"integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw=="
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
},
"acorn-globals": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz",
"integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz",
"integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==",
"requires": {
"acorn": "^6.0.1",
"acorn-walk": "^6.0.1"
},
"dependencies": {
"acorn": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
"integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA=="
}
}
},
"acorn-walk": {
@@ -141,9 +148,9 @@
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"async-mutex": {
"version": "0.1.3",
@@ -467,11 +474,11 @@
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
},
"cssstyle": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.3.0.tgz",
"integrity": "sha512-wXsoRfsRfsLVNaVzoKdqvEmK/5PFaEXNspVT22Ots6K/cnJdpoDKuQFw+qlMiXnmaif1OgeC466X1zISgAOcGg==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
"integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
"requires": {
"cssom": "~0.3.6"
"cssom": "0.3.x"
}
},
"cwise-compiler": {
@@ -498,6 +505,18 @@
"abab": "^2.0.0",
"whatwg-mimetype": "^2.2.0",
"whatwg-url": "^7.0.0"
},
"dependencies": {
"whatwg-url": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
}
}
},
"debug": {
@@ -705,9 +724,9 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"escodegen": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
"integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz",
"integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==",
"requires": {
"esprima": "^3.1.3",
"estraverse": "^4.2.0",
@@ -730,14 +749,14 @@
"integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
},
"estraverse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
},
"exit": {
"version": "0.1.2",
@@ -1112,6 +1131,25 @@
}
}
},
"http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
"integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
},
"dependencies": {
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -1516,206 +1554,19 @@
"dev": true
},
"joplin-turndown": {
"version": "4.0.17",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.17.tgz",
"integrity": "sha512-57mw92ZOKoR77YBLUkauN1xNq1xlxOm2KaPty/jlYrkEyGotUBBvq46a6wXh6d3aM4CccGuwymSge18/9IoB3A==",
"version": "4.0.18",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.18.tgz",
"integrity": "sha512-YD0pkj2a7+XjjNNI1X9ZIwYthFwNsswvO4gl5aAoWdwJj5m8tunnoSyVenvqleXzAcaURIi/q9EOAQ1jw7xDiQ==",
"requires": {
"css": "^2.2.4",
"html-entities": "^1.2.1",
"jsdom": "^11.9.0"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
},
"ajv": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz",
"integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==",
"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",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"extend": {
"version": "3.0.2",
"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.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",
"mime-types": "^2.1.12"
}
},
"har-validator": {
"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": "^6.5.5",
"har-schema": "^2.0.0"
}
},
"jsdom": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
"integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
"requires": {
"abab": "^2.0.0",
"acorn": "^5.5.3",
"acorn-globals": "^4.1.0",
"array-equal": "^1.0.0",
"cssom": ">= 0.3.2 < 0.4.0",
"cssstyle": "^1.0.0",
"data-urls": "^1.0.0",
"domexception": "^1.0.1",
"escodegen": "^1.9.1",
"html-encoding-sniffer": "^1.0.2",
"left-pad": "^1.3.0",
"nwsapi": "^2.0.7",
"parse5": "4.0.0",
"pn": "^1.1.0",
"request": "^2.87.0",
"request-promise-native": "^1.0.5",
"sax": "^1.2.4",
"symbol-tree": "^3.2.2",
"tough-cookie": "^2.3.4",
"w3c-hr-time": "^1.0.1",
"webidl-conversions": "^4.0.2",
"whatwg-encoding": "^1.0.3",
"whatwg-mimetype": "^2.1.0",
"whatwg-url": "^6.4.1",
"ws": "^5.2.0",
"xml-name-validator": "^3.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.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
},
"mime-types": {
"version": "2.1.24",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
"requires": {
"mime-db": "1.40.0"
}
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
},
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.0",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.4.3",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
}
}
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
},
"whatwg-url": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
},
"ws": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"requires": {
"async-limiter": "~1.0.0"
}
}
}
},
"joplin-turndown-plugin-gfm": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/joplin-turndown-plugin-gfm/-/joplin-turndown-plugin-gfm-1.0.9.tgz",
"integrity": "sha512-SOa/Uiy3nyoBGtHqFe+TBg10UTIOzzcUUzNhx2MyR4Z0vbKL3enGggGypig1t7G5uHwv5j+NhooRuM619Zk0bw=="
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/joplin-turndown-plugin-gfm/-/joplin-turndown-plugin-gfm-1.0.11.tgz",
"integrity": "sha512-S2I+VCTqIhpWKKkPHsyJ5rdll9H/JjMXoBVClRX1TnphcmrSxufevdoXWWVgLncdXpSSiuoifCXgFZy3ueVElg=="
},
"jpeg-js": {
"version": "0.1.2",
@@ -1733,6 +1584,39 @@
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"optional": true
},
"jsdom": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
"integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
"requires": {
"abab": "^2.0.0",
"acorn": "^5.5.3",
"acorn-globals": "^4.1.0",
"array-equal": "^1.0.0",
"cssom": ">= 0.3.2 < 0.4.0",
"cssstyle": "^1.0.0",
"data-urls": "^1.0.0",
"domexception": "^1.0.1",
"escodegen": "^1.9.1",
"html-encoding-sniffer": "^1.0.2",
"left-pad": "^1.3.0",
"nwsapi": "^2.0.7",
"parse5": "4.0.0",
"pn": "^1.1.0",
"request": "^2.87.0",
"request-promise-native": "^1.0.5",
"sax": "^1.2.4",
"symbol-tree": "^3.2.2",
"tough-cookie": "^2.3.4",
"w3c-hr-time": "^1.0.1",
"webidl-conversions": "^4.0.2",
"whatwg-encoding": "^1.0.3",
"whatwg-mimetype": "^2.1.0",
"whatwg-url": "^6.4.1",
"ws": "^5.2.0",
"xml-name-validator": "^3.0.0"
}
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
@@ -2293,6 +2177,11 @@
"no-case": "^2.2.0"
}
},
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -2595,13 +2484,6 @@
"integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
"requires": {
"lodash": "^4.17.11"
},
"dependencies": {
"lodash": {
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw=="
}
}
},
"request-promise-native": {
@@ -3208,7 +3090,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",
@@ -3235,11 +3117,19 @@
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"tough-cookie": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"requires": {
"punycode": "^1.4.1"
"psl": "^1.1.28",
"punycode": "^2.1.1"
},
"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=="
}
}
},
"tr46": {
@@ -3434,9 +3324,9 @@
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
@@ -3489,6 +3379,14 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"ws": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"requires": {
"async-limiter": "~1.0.0"
}
},
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",

View File

@@ -20,7 +20,7 @@
],
"owner": "Laurent Cozic"
},
"version": "1.0.147",
"version": "1.0.149",
"bin": {
"joplin": "./main.js"
},
@@ -44,8 +44,8 @@
"html-minifier": "^3.5.15",
"image-data-uri": "^2.0.0",
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.17",
"joplin-turndown-plugin-gfm": "^1.0.9",
"joplin-turndown": "^4.0.18",
"joplin-turndown-plugin-gfm": "^1.0.11",
"jssha": "^2.3.0",
"levenshtein": "^1.0.5",
"markdown-it": "^8.4.2",

View File

@@ -24,6 +24,7 @@ cd "$ROOT_DIR"
NODE_ENV=testing npm test tests-build/ArrayUtils.js && \
NODE_ENV=testing npm test tests-build/encryption.js && \
NODE_ENV=testing npm test tests-build/EnexToMd.js && \
NODE_ENV=testing npm test tests-build/EnexToHtml.js && \
NODE_ENV=testing npm test tests-build/HtmlToMd.js && \
NODE_ENV=testing npm test tests-build/markdownUtils.js && \
NODE_ENV=testing npm test tests-build/models_BaseItem.js && \
@@ -44,4 +45,4 @@ NODE_ENV=testing npm test tests-build/services_Revision.js && \
NODE_ENV=testing npm test tests-build/StringUtils.js && \
NODE_ENV=testing npm test tests-build/TaskQueue.js && \
NODE_ENV=testing npm test tests-build/synchronizer.js && \
NODE_ENV=testing npm test tests-build/urlUtils.js
NODE_ENV=testing npm test tests-build/urlUtils.js

View File

@@ -39,7 +39,7 @@ describe('HtmlToMd', function() {
const htmlPath = `${basePath}/${htmlFilename}`;
const mdPath = `${basePath}/${filename(htmlFilename)}.md`;
// if (htmlFilename !== 'table_with_pipe.html') continue;
// if (htmlFilename !== 'table_with_header.html') continue;
const htmlToMdOptions = {};
@@ -48,7 +48,7 @@ describe('HtmlToMd', function() {
// This is straightforward when the document is still in DOM format, as with the clipper,
// but otherwise it would need to be somehow parsed out from the HTML. Here we just
// hard code the anchors that we know are in the file.
htmlToMdOptions.anchorNames = ['first', 'second'];
htmlToMdOptions.anchorNames = ['first', 'second', 'fourth'];
}
const html = await shim.fsDriver().readFile(htmlPath);

View File

@@ -0,0 +1,8 @@
<div><span style="font-style: italic;">singleline italic text with span style font-style: italic;.</span></div><div><br/></div>
<div><span style="font-style: italic;">multiline italic
text with span style font-style: italic;.</span></div><div><br/></div>
<div><span style="font-style: italic;">singleline italic text with span style font-style: italic;</span> next to normal text with leading space.</div><div><br/></div>
<div><span style="font-style: italic;">singleline italic text with span style font-style: italic; and with trailing space </span>next to normal text.</div><div><br/></div>
<div><span style="font-style: italic;">singleline italic text with span style font-style: italic;</span><span style="font-style: italic;"> next to more italic text with span style font-style: italic; and with leading space.</span></div><div><br/></div>
<div><span style="font-style: italic;">singleline italic text with span style font-style: italic; and with trailing space </span><span style="font-style: italic;">next to more italic text with span style font-style: italic;.</span></div>

View File

@@ -0,0 +1,11 @@
*singleline italic text with span style font-style: italic;.*
*multiline italic text with span style font-style: italic;.*
*singleline italic text with span style font-style: italic;* next to normal text with leading space.
*singleline italic text with span style font-style: italic; and with trailing space *next to normal text.
*singleline italic text with span style font-style: italic;** next to more italic text with span style font-style: italic; and with leading space.*
*singleline italic text with span style font-style: italic; and with trailing space **next to more italic text with span style font-style: italic;.*

View File

@@ -1,6 +1,8 @@
<p><a href="#first">First</a></p>
<p><a href="#second">Second</a></p>
<p>Third</p>
<p><a href="#fourth">Fourth</a></p>
<p><a name="first"></a>First</p>
<p><a id="second"></a>Second</p>
<p><a id="third"></a>Third</p>
<p><a id="third"></a>Third</p>
<p><span id="fourth">Fourth</span></p>

View File

@@ -4,8 +4,12 @@
Third
[Fourth](#fourth)
<a id="first"></a>First
<a id="second"></a>Second
Third
Third
<a id="fourth"></a>Fourth

View File

@@ -0,0 +1,14 @@
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
</tr>
</thead>
<tbody>
<tr>
<td>c</td>
<td>d</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,3 @@
| A | B |
| --- | --- |
| c | d |

View File

@@ -92,11 +92,11 @@ describe('models_Note', function() {
it('should serialize and unserialize without modifying data', asyncTest(async () => {
let folder1 = await Folder.save({ title: 'folder1'});
const testCases = [
[ {title: '', body:'Body and no title\nSecond line\nThird Line', parent_id: folder1.id},
[ {title: '', body: 'Body and no title\nSecond line\nThird Line', parent_id: folder1.id},
'', 'Body and no title\nSecond line\nThird Line'],
[ {title: 'Note title', body:'Body and title', parent_id: folder1.id},
[ {title: 'Note title', body: 'Body and title', parent_id: folder1.id},
'Note title', 'Body and title'],
[ {title: 'Title and no body', body:'', parent_id: folder1.id},
[ {title: 'Title and no body', body: '', parent_id: folder1.id},
'Title and no body', ''],
];

View File

@@ -279,7 +279,7 @@ describe('services_rest_Api', function() {
const response = await api.route('GET', 'notes', { token: 'mytoken' });
expect(response.length).toBe(0);
hasThrown = await checkThrowAsync(async () => await api.route('POST', 'notes', null, JSON.stringify({title:'testing'})));
hasThrown = await checkThrowAsync(async () => await api.route('POST', 'notes', null, JSON.stringify({title: 'testing'})));
expect(hasThrown).toBe(true);
}));

View File

@@ -892,10 +892,12 @@ describe('Synchronizer', function() {
await synchronizer().start();
const fetcher = new ResourceFetcher(() => { return {
const fetcher = new ResourceFetcher(() => {
return {
// Simulate a failed download
get: () => { return new Promise((resolve, reject) => { reject(new Error('did not work')); }); },
}; });
get: () => { return new Promise((resolve, reject) => { reject(new Error('did not work')); }); },
};
});
fetcher.queueDownload_(resource1.id);
await fetcher.waitForAllFinished();
@@ -1025,8 +1027,8 @@ describe('Synchronizer', function() {
// If we try to disable encryption now, it should throw an error because some items are
// currently encrypted. They must be decrypted first so that they can be sent as
// plain text to the sync target.
//let hasThrown = await checkThrowAsync(async () => await encryptionService().disableEncryption());
//expect(hasThrown).toBe(true);
// let hasThrown = await checkThrowAsync(async () => await encryptionService().disableEncryption());
// expect(hasThrown).toBe(true);
// Now supply the password, and decrypt the items
Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
@@ -1504,4 +1506,39 @@ describe('Synchronizer', function() {
expect((await Note.all()).length).toBe(11);
}));
it('should not sync if client sync version is lower than target', asyncTest(async () => {
// This should work - syncing two clients with same supported sync target version
await synchronizer().start();
await switchClient(2);
await synchronizer().start();
// This should not work - syncing two clients, but one of them has not been upgraded yet to the latest sync version
await switchClient(1);
Setting.setConstant('syncVersion', 2);
await synchronizer().start();
await switchClient(2);
Setting.setConstant('syncVersion', 1);
const hasThrown = await checkThrowAsync(async () => synchronizer().start({ throwOnError: true }));
expect(hasThrown).toBe(true);
}));
it('should not sync when target is locked', asyncTest(async () => {
await synchronizer().start();
await synchronizer().acquireLock_();
await switchClient(2);
const hasThrown = await checkThrowAsync(async () => synchronizer().start({ throwOnError: true }));
expect(hasThrown).toBe(true);
}));
it('should clear a lock if it was created by the same app as the current one', asyncTest(async () => {
await synchronizer().start();
await synchronizer().acquireLock_();
expect((await synchronizer().lockFiles_()).length).toBe(1);
await synchronizer().start({ throwOnError: true });
expect((await synchronizer().lockFiles_()).length).toBe(0);
}));
});

View File

@@ -24,6 +24,7 @@ const BaseService = require('lib/services/BaseService.js');
const { FsDriverNode } = require('lib/fs-driver-node.js');
const { time } = require('lib/time-utils.js');
const { shimInit } = require('lib/shim-init-node.js');
const { uuid } = require('lib/uuid.js');
const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
const SyncTargetMemory = require('lib/SyncTargetMemory.js');
const SyncTargetFilesystem = require('lib/SyncTargetFilesystem.js');
@@ -69,11 +70,11 @@ SyncTargetRegistry.addClass(SyncTargetDropbox);
// const syncTargetId_ = SyncTargetRegistry.nameToId("nextcloud");
const syncTargetId_ = SyncTargetRegistry.nameToId('memory');
//const syncTargetId_ = SyncTargetRegistry.nameToId('filesystem');
// const syncTargetId_ = SyncTargetRegistry.nameToId('filesystem');
// const syncTargetId_ = SyncTargetRegistry.nameToId('dropbox');
const syncDir = `${__dirname}/../tests/sync`;
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 100;//400;
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 100;// 400;
console.info(`Testing with sync target: ${SyncTargetRegistry.idToName(syncTargetId_)}`);
@@ -137,6 +138,7 @@ async function switchClient(id) {
await Setting.load();
if (!Setting.value('clientId')) Setting.setValue('clientId', uuid.create());
Setting.setValue('sync.wipeOutFailSafe', false); // To keep things simple, always disable fail-safe unless explicitely set in the test itself
}
@@ -180,6 +182,7 @@ async function setupDatabase(id = null) {
if (databases_[id]) {
await clearDatabase(id);
await Setting.load();
if (!Setting.value('clientId')) Setting.setValue('clientId', uuid.create());
return;
}
@@ -197,6 +200,7 @@ async function setupDatabase(id = null) {
BaseModel.db_ = databases_[id];
await Setting.load();
if (!Setting.value('clientId')) Setting.setValue('clientId', uuid.create());
}
function resourceDir(id = null) {

View File

@@ -83,14 +83,18 @@
}
function getAnchorNames(element) {
const anchors = element.getElementsByTagName('a');
const output = [];
for (let i = 0; i < anchors.length; i++) {
const anchor = anchors[i];
if (anchor.id) {
output.push(anchor.id);
} else if (anchor.name) {
output.push(anchor.name);
// Anchor names are normally in A tags but can be in SPAN too
// https://github.com/laurent22/joplin-turndown/commit/45f4ee6bf15b8804bdc2aa1d7ecb2f8cb594b8e5#diff-172b8b2bc3ba160589d3a7eeb4913687R232
for (const tagName of ['a', 'span']) {
const anchors = element.getElementsByTagName(tagName);
for (let i = 0; i < anchors.length; i++) {
const anchor = anchors[i];
if (anchor.id) {
output.push(anchor.id);
} else if (anchor.name) {
output.push(anchor.name);
}
}
}
return output;
@@ -134,11 +138,17 @@
const src = absoluteUrl(imageSrc(node));
node.setAttribute('src', src);
if (!(src in imageIndexes)) imageIndexes[src] = 0;
const imageSize = imageSizes[src][imageIndexes[src]];
imageIndexes[src]++;
if (imageSize && convertToMarkup === 'markdown') {
node.width = imageSize.width;
node.height = imageSize.height;
if (!imageSizes[src]) {
// This seems to concern dynamic images that don't really such as Gravatar, etc.
console.warn('Found an image for which the size had not been fetched:', src);
} else {
const imageSize = imageSizes[src][imageIndexes[src]];
imageIndexes[src]++;
if (imageSize && convertToMarkup === 'markdown') {
node.width = imageSize.width;
node.height = imageSize.height;
}
}
}

View File

@@ -1,20 +1,22 @@
function randomClipperPort(state, env) {
const startPorts = {
prod: 41184,
dev: 27583,
};
const startPort = env === 'prod' ? startPorts.prod : startPorts.dev;
if (!state) {
state = { offset: 0 };
} else {
state.offset++;
}
state.port = startPort + state.offset;
state.port = startPort(env) + state.offset;
return state;
}
module.exports = { randomClipperPort };
function startPort(env) {
const startPorts = {
prod: 41184,
dev: 27583,
};
return env === 'prod' ? startPorts.prod : startPorts.dev;
}
module.exports = { randomClipperPort, startPort };

View File

@@ -36,9 +36,13 @@ class InteropServiceHelper {
if (options.sourceNoteIds) exportOptions.sourceNoteIds = options.sourceNoteIds;
const service = new InteropService();
const result = await service.export(exportOptions);
console.info('Export result: ', result);
try {
const result = await service.export(exportOptions);
console.info('Export result: ', result);
} catch (error) {
bridge().showErrorMessageBox(_('Could not export notes: %s', error.message));
}
dispatch({
type: 'WINDOW_COMMAND',

View File

@@ -196,7 +196,6 @@ class Application extends BaseApplication {
break;
case 'NOTE_DEVTOOLS_TOGGLE':
newState = Object.assign({}, state);
newState.noteDevToolsVisible = !newState.noteDevToolsVisible;
break;
@@ -250,6 +249,11 @@ class Application extends BaseApplication {
this.updateMenuItemStates();
}
if (action.type === 'NOTE_DEVTOOLS_TOGGLE') {
const menuItem = Menu.getApplicationMenu().getMenuItemById('help:toggleDevTools');
menuItem.checked = newState.noteDevToolsVisible;
}
return result;
}
@@ -418,15 +422,15 @@ class Application extends BaseApplication {
},
});
/* We need a dummy entry, otherwise the ternary operator to show a
* menu item only on a specific OS does not work. */
// We need a dummy entry, otherwise the ternary operator to show a
// menu item only on a specific OS does not work.
const noItem = {
type: 'separator',
visible: false,
};
const syncStatusItem = {
label: _('Synchronisation status'),
label: _('Synchronisation Status'),
click: () => {
this.dispatch({
type: 'NAV_GO',
@@ -565,6 +569,9 @@ class Application extends BaseApplication {
'',
'Copyright © 2016-2019 Laurent Cozic',
_('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform),
'',
_('Client ID: %s', Setting.value('clientId')),
_('Sync Version: %s', Setting.value('syncVersion')),
];
if (gitInfo) {
message.push(`\n${gitInfo}`);
@@ -576,13 +583,13 @@ class Application extends BaseApplication {
}
const rootMenuFile = {
/* Using a dummy entry for macOS here, because first menu
* becomes 'Joplin' and we need a nenu called 'File' later. */
// Using a dummy entry for macOS here, because first menu
// becomes 'Joplin' and we need a nenu called 'File' later.
label: shim.isMac() ? '&JoplinMainMenu' : _('&File'),
/* `&` before one of the char in the label name mean, that
* <Alt + F> will open this menu. It's needed becase electron
* opens the first menu on Alt press if no hotkey assigned.
* Issue: https://github.com/laurent22/joplin/issues/934 */
// `&` before one of the char in the label name mean, that
// <Alt + F> will open this menu. It's needed becase electron
// opens the first menu on Alt press if no hotkey assigned.
// Issue: https://github.com/laurent22/joplin/issues/934
submenu: [{
label: _('About Joplin'),
visible: shim.isMac() ? true : false,
@@ -898,13 +905,13 @@ class Application extends BaseApplication {
submenu: [{
label: _('Website and documentation'),
accelerator: 'F1',
click () { bridge().openExternal('https://joplinapp.org'); },
click() { bridge().openExternal('https://joplinapp.org'); },
}, {
label: _('Joplin Forum'),
click () { bridge().openExternal('https://discourse.joplinapp.org'); },
click() { bridge().openExternal('https://discourse.joplinapp.org'); },
}, {
label: _('Make a donation'),
click () { bridge().openExternal('https://joplinapp.org/donate/'); },
click() { bridge().openExternal('https://joplinapp.org/donate/'); },
}, {
label: _('Check for updates...'),
visible: shim.isMac() ? false : true,
@@ -913,6 +920,8 @@ class Application extends BaseApplication {
type: 'separator',
screens: ['Main'],
}, {
id: 'help:toggleDevTools',
type: 'checkbox',
label: _('Toggle development tools'),
visible: true,
click: () => {

View File

@@ -93,6 +93,18 @@ async function fetchLatestRelease(options) {
};
}
function truncateText(text, length) {
let truncated = text.substring(0, length);
const lastNewLine = truncated.lastIndexOf('\n');
// Cut off at a line break unless we'd be cutting off half the text
if (lastNewLine > length / 2) {
truncated = `${truncated.substring(0, lastNewLine)}\n...`;
} else {
truncated = `${truncated.trim()}...`;
}
return truncated;
}
function checkForUpdates(inBackground, window, logFilePath, options) {
if (isCheckingForUpdate_) {
autoUpdateLogger_.info('checkForUpdates: Skipping check because it is already running');
@@ -126,16 +138,21 @@ function checkForUpdates(inBackground, window, logFilePath, options) {
buttons: [_('OK')],
});
} else {
const releaseNotes = release.notes.trim() ? `\n\n${release.notes.trim()}` : '';
const fullReleaseNotes = release.notes.trim() ? `\n\n${release.notes.trim()}` : '';
const MAX_RELEASE_NOTES_LENGTH = 1000;
const truncateReleaseNotes = fullReleaseNotes.length > MAX_RELEASE_NOTES_LENGTH;
const releaseNotes = truncateReleaseNotes ? truncateText(fullReleaseNotes, MAX_RELEASE_NOTES_LENGTH) : fullReleaseNotes;
const newVersionString = release.prerelease ? _('%s (pre-release)', release.version) : release.version;
const buttonIndex = dialog.showMessageBox(parentWindow_, {
type: 'info',
message: `${_('An update is available, do you want to download it now?')}\n\n${_('Your version: %s', packageInfo.version)}\n${_('New version: %s', newVersionString)}${releaseNotes}`,
buttons: [_('Yes'), _('No')],
buttons: [_('Yes'), _('No')].concat(truncateReleaseNotes ? [_('Full Release Notes')] : []),
});
if (buttonIndex === 0) require('electron').shell.openExternal(release.downloadUrl ? release.downloadUrl : release.pageUrl);
if (buttonIndex === 2) require('electron').shell.openExternal(release.pageUrl);
}
}).catch(error => {
autoUpdateLogger_.error(error);

View File

@@ -22,8 +22,7 @@ let hash;
try {
branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
hash = execSync('git log --pretty="%h" -1').toString().trim();
}
catch(err) {
} catch (err) {
console.warn('Could not get git info', err);
}
if (typeof branch !== 'undefined' && typeof hash !== 'undefined') {

View File

@@ -28,7 +28,7 @@ function ConfigMenuBar(props) {
key={section.name}
iconName={Setting.sectionNameToIcon(section.name)}
label={Setting.sectionNameToLabel(section.name)}
onClick={() => { props.onSelectionChange({ section: section });}}
onClick={() => { props.onSelectionChange({ section: section }); }}
/>);
}

View File

@@ -478,7 +478,7 @@ class ConfigScreenComponent extends React.Component {
borderTopColor: theme.dividerColor,
};
const screenComp = this.state.screenName ? <div style={{overflow: 'scroll', flex:1}}>{this.screenFromName(this.state.screenName)}</div> : null;
const screenComp = this.state.screenName ? <div style={{overflow: 'scroll', flex: 1}}>{this.screenFromName(this.state.screenName)}</div> : null;
if (screenComp) containerStyle.display = 'none';

View File

@@ -161,11 +161,13 @@ class HeaderComponent extends React.Component {
const inputStyle = {
display: 'flex',
flex: 1,
marginLeft: 10,
paddingLeft: 6,
paddingRight: 6,
paddingTop: 1, // vertical alignment with buttons
paddingBottom: 0, // vertical alignment with buttons
height: style.fontSize * 2,
width: 300,
color: style.color,
fontSize: style.fontSize,
fontFamily: style.fontFamily,

View File

@@ -245,7 +245,16 @@ class MainScreenComponent extends React.Component {
} else if (command.name === 'toggleSidebar') {
this.toggleSidebar();
} else if (command.name === 'showModalMessage') {
this.setState({ modalLayer: { visible: true, message: command.message } });
this.setState({
modalLayer: {
visible: true,
message:
<div className="modal-message">
<div id="loading-animation" />
<div className="text">{command.message}</div>
</div>,
},
});
} else if (command.name === 'hideModalMessage') {
this.setState({ modalLayer: { visible: false, message: '' } });
} else if (command.name === 'editAlarm') {

View File

@@ -106,7 +106,7 @@ class NotePropertiesDialog extends React.Component {
this.styles_.controlBox = {
marginBottom: '1em',
color: 'black', //This will apply for the calendar
color: 'black', // This will apply for the calendar
};
this.styles_.button = {

View File

@@ -48,6 +48,7 @@ require('brace/theme/chrome');
require('brace/theme/solarized_light');
require('brace/theme/solarized_dark');
require('brace/theme/twilight');
require('brace/theme/dracula');
const NOTE_TAG_BAR_FEATURE_ENABLED = false;
@@ -690,10 +691,13 @@ class NoteTextComponent extends React.Component {
}
async noteRevisionViewer_onBack() {
this.setState({ showRevisions: false });
this.lastSetHtml_ = '';
this.scheduleReloadNote(this.props);
// When coming back from the revision viewer, the webview has been
// unmounted so will need to reload. We set webviewReady to false
// to make sure everything is reloaded as expected.
this.setState({ showRevisions: false, webviewReady: false }, () => {
this.lastSetHtml_ = '';
this.scheduleReloadNote(this.props);
});
}
title_changeText(event) {
@@ -1209,7 +1213,7 @@ class NoteTextComponent extends React.Component {
setTimeout(() => {
if (target === 'pdf') {
this.webviewRef_.current.wrappedInstance.printToPDF({ printBackground: true }, (error, data) => {
this.webviewRef_.current.wrappedInstance.printToPDF({ printBackground: true, pageSize: Setting.value('export.pdfPageSize'), landscape: Setting.value('export.pdfPageOrientation') === 'landscape' }, (error, data) => {
restoreSettings();
if (error) {
@@ -1369,9 +1373,16 @@ class NoteTextComponent extends React.Component {
const r = this.selectionRange_;
// Because some insertion strings will have newlines, we'll need to account for them
const str1Split = string1.split(/\r?\n/);
// Add the number of newlines to the row
// and add the length of the final line to the column (for strings with no newlines this is the string length)
const newRange = {
start: { row: r.start.row, column: r.start.column + string1.length },
end: { row: r.end.row, column: r.end.column + string1.length },
start: { row: r.start.row + str1Split.length - 1,
column: r.start.column + str1Split[str1Split.length - 1].length },
end: { row: r.end.row + str1Split.length - 1,
column: r.end.column + str1Split[str1Split.length - 1].length },
};
if (replacementText) {
@@ -1444,7 +1455,18 @@ class NoteTextComponent extends React.Component {
}
commandTextCode() {
this.wrapSelectionWithStrings('`', '`');
const selection = this.textOffsetSelection();
let string = this.state.note.body.substr(selection.start, selection.end - selection.start);
// Look for newlines
let match = string.match(/\r?\n/);
if (match && match.length > 0) {
// Follow the same newline style
this.wrapSelectionWithStrings(`\`\`\`${match[0]}`, `${match[0]}\`\`\``);
} else {
this.wrapSelectionWithStrings('`', '`');
}
}
commandTemplate(value) {
@@ -1524,7 +1546,7 @@ class NoteTextComponent extends React.Component {
menu.popup(bridge().window());
}
createToolbarItems(note) {
createToolbarItems(note, editorIsVisible) {
const toolbarItems = [];
if (note && this.state.folder && ['Search', 'Tag'].includes(this.props.notesParentType)) {
toolbarItems.push({
@@ -1559,7 +1581,7 @@ class NoteTextComponent extends React.Component {
});
}
if (note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN) {
if (note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN && editorIsVisible) {
toolbarItems.push({
tooltip: _('Bold'),
iconName: 'fa-bold',
@@ -1821,7 +1843,7 @@ class NoteTextComponent extends React.Component {
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
// || (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);
}
@@ -1961,7 +1983,8 @@ class NoteTextComponent extends React.Component {
}
}
const toolbarItems = this.createToolbarItems(note);
const editorIsVisible = visiblePanes.indexOf('editor') >= 0;
const toolbarItems = this.createToolbarItems(note, editorIsVisible);
const toolbar = <Toolbar style={toolbarStyle} items={toolbarItems} />;

View File

@@ -267,9 +267,11 @@ class SideBarComponent extends React.Component {
if (!itemId || !itemType) throw new Error('No data on element');
let deleteMessage = '';
let buttonLabel = _('Remove');
if (itemType === BaseModel.TYPE_FOLDER) {
const folder = await Folder.load(itemId);
deleteMessage = _('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', substrWithEllipsis(folder.title, 0, 32));
buttonLabel = _('Delete');
} else if (itemType === BaseModel.TYPE_TAG) {
const tag = await Tag.load(itemId);
deleteMessage = _('Remove tag "%s" from all notes?', substrWithEllipsis(tag.title, 0, 32));
@@ -286,9 +288,12 @@ class SideBarComponent extends React.Component {
menu.append(
new MenuItem({
label: _('Delete'),
label: buttonLabel,
click: async () => {
const ok = bridge().showConfirmMessageBox(deleteMessage);
const ok = bridge().showConfirmMessageBox(deleteMessage, {
buttons: [buttonLabel, _('Cancel')],
defaultId: 1,
});
if (!ok) return;
if (itemType === BaseModel.TYPE_FOLDER) {

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.0.169",
"version": "1.0.170",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -144,9 +144,9 @@
"dev": true
},
"abab": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
"integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz",
"integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg=="
},
"abbrev": {
"version": "1.1.1",
@@ -154,17 +154,24 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz",
"integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw=="
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
},
"acorn-globals": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz",
"integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz",
"integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==",
"requires": {
"acorn": "^6.0.1",
"acorn-walk": "^6.0.1"
},
"dependencies": {
"acorn": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
"integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA=="
}
}
},
"acorn-walk": {
@@ -399,6 +406,11 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"astral-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
},
"async-each": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
@@ -413,9 +425,9 @@
"dev": true
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"async-mutex": {
"version": "0.1.3",
@@ -1955,6 +1967,50 @@
"integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==",
"dev": true
},
"cli-truncate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.0.0.tgz",
"integrity": "sha512-C4hp+8GCIFVsUUiXcw+ce+7wexVWImw8rQrgMBFsqerx9LvvcGlwm6sMjQYAEmV/Xb87xc1b5Ttx505MSpZVqg==",
"requires": {
"slice-ansi": "^2.1.0",
"string-width": "^4.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"string-width": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz",
"integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^5.2.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"requires": {
"ansi-regex": "^4.1.0"
}
}
}
},
"cliui": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
@@ -2019,7 +2075,6 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@@ -2027,8 +2082,7 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"colors": {
"version": "1.3.3",
@@ -2222,11 +2276,11 @@
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
},
"cssstyle": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.3.0.tgz",
"integrity": "sha512-wXsoRfsRfsLVNaVzoKdqvEmK/5PFaEXNspVT22Ots6K/cnJdpoDKuQFw+qlMiXnmaif1OgeC466X1zISgAOcGg==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
"integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
"requires": {
"cssom": "~0.3.6"
"cssom": "0.3.x"
}
},
"csstype": {
@@ -2264,6 +2318,18 @@
"abab": "^2.0.0",
"whatwg-mimetype": "^2.2.0",
"whatwg-url": "^7.0.0"
},
"dependencies": {
"whatwg-url": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
}
}
},
"debug": {
@@ -2540,25 +2606,26 @@
}
},
"electron-context-menu": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-0.9.1.tgz",
"integrity": "sha1-7U3yDAgEkcPJlqv8s2MVmUajgFg=",
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-0.15.0.tgz",
"integrity": "sha512-XLdtbX90NPkWycG3IzwtCmfX4ggu+lofNOW1nVRStb+ScFs49WTourW1k77Z4DTyThR3gUHg3UPXVBMbW1gNsg==",
"requires": {
"cli-truncate": "^2.0.0",
"electron-dl": "^1.2.0",
"electron-is-dev": "^0.1.1"
"electron-is-dev": "^1.0.1"
},
"dependencies": {
"electron-is-dev": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-0.1.2.tgz",
"integrity": "sha1-ihBD4ys6HaHD9VPc4oznZCRhZ+M="
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.1.0.tgz",
"integrity": "sha512-Z1qA/1oHNowGtSBIcWk0pcLEqYT/j+13xUw/MYOrBUOL4X7VN0i0KCTf5SqyvMPmW5pSPKbo28wkxMxzZ20YnQ=="
}
}
},
"electron-dl": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.12.0.tgz",
"integrity": "sha512-UMc2CL45Ybpvu66LDPYzwmDRmYK4Ivz+wdnTM0eXcNMztvQwhixAk2UPme1c7McqG8bAlKEkQpZn3epmQy4EWg==",
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.14.0.tgz",
"integrity": "sha512-4okyei42a1mLsvLK7hLrIfd20EQzB18nIlLTwBV992aMSmTGLUEFRTmO1MfSslGNrzD8nuPuy1l/VxO8so4lig==",
"requires": {
"ext-name": "^5.0.0",
"pupa": "^1.0.0",
@@ -2955,9 +3022,9 @@
"dev": true
},
"escodegen": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
"integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz",
"integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==",
"requires": {
"esprima": "^3.1.3",
"estraverse": "^4.2.0",
@@ -2985,9 +3052,9 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"estraverse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
},
"esutils": {
"version": "2.0.2",
@@ -3312,9 +3379,9 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz",
"integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.0.tgz",
"integrity": "sha512-+iXhW3LuDQsno8dOIrCIT/CBjeBWuP7PXe8w9shnj9Lebny/Gx1ZjVBYwexLz36Ri2jKuXMNpV6CYNh8lHHgrQ==",
"optional": true
},
"fullstore": {
@@ -3908,6 +3975,11 @@
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
"dev": true
},
"is-wsl": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz",
"integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog=="
},
"is2": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/is2/-/is2-0.0.9.tgz",
@@ -3947,82 +4019,19 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"joplin-turndown": {
"version": "4.0.17",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.17.tgz",
"integrity": "sha512-57mw92ZOKoR77YBLUkauN1xNq1xlxOm2KaPty/jlYrkEyGotUBBvq46a6wXh6d3aM4CccGuwymSge18/9IoB3A==",
"version": "4.0.18",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.18.tgz",
"integrity": "sha512-YD0pkj2a7+XjjNNI1X9ZIwYthFwNsswvO4gl5aAoWdwJj5m8tunnoSyVenvqleXzAcaURIi/q9EOAQ1jw7xDiQ==",
"requires": {
"css": "^2.2.4",
"html-entities": "^1.2.1",
"jsdom": "^11.9.0"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
},
"jsdom": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
"integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
"requires": {
"abab": "^2.0.0",
"acorn": "^5.5.3",
"acorn-globals": "^4.1.0",
"array-equal": "^1.0.0",
"cssom": ">= 0.3.2 < 0.4.0",
"cssstyle": "^1.0.0",
"data-urls": "^1.0.0",
"domexception": "^1.0.1",
"escodegen": "^1.9.1",
"html-encoding-sniffer": "^1.0.2",
"left-pad": "^1.3.0",
"nwsapi": "^2.0.7",
"parse5": "4.0.0",
"pn": "^1.1.0",
"request": "^2.87.0",
"request-promise-native": "^1.0.5",
"sax": "^1.2.4",
"symbol-tree": "^3.2.2",
"tough-cookie": "^2.3.4",
"w3c-hr-time": "^1.0.1",
"webidl-conversions": "^4.0.2",
"whatwg-encoding": "^1.0.3",
"whatwg-mimetype": "^2.1.0",
"whatwg-url": "^6.4.1",
"ws": "^5.2.0",
"xml-name-validator": "^3.0.0"
}
},
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
},
"whatwg-url": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
},
"ws": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"requires": {
"async-limiter": "~1.0.0"
}
}
}
},
"joplin-turndown-plugin-gfm": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/joplin-turndown-plugin-gfm/-/joplin-turndown-plugin-gfm-1.0.9.tgz",
"integrity": "sha512-SOa/Uiy3nyoBGtHqFe+TBg10UTIOzzcUUzNhx2MyR4Z0vbKL3enGggGypig1t7G5uHwv5j+NhooRuM619Zk0bw=="
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/joplin-turndown-plugin-gfm/-/joplin-turndown-plugin-gfm-1.0.11.tgz",
"integrity": "sha512-S2I+VCTqIhpWKKkPHsyJ5rdll9H/JjMXoBVClRX1TnphcmrSxufevdoXWWVgLncdXpSSiuoifCXgFZy3ueVElg=="
},
"js-tokens": {
"version": "3.0.2",
@@ -4045,6 +4054,39 @@
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"optional": true
},
"jsdom": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
"integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
"requires": {
"abab": "^2.0.0",
"acorn": "^5.5.3",
"acorn-globals": "^4.1.0",
"array-equal": "^1.0.0",
"cssom": ">= 0.3.2 < 0.4.0",
"cssstyle": "^1.0.0",
"data-urls": "^1.0.0",
"domexception": "^1.0.1",
"escodegen": "^1.9.1",
"html-encoding-sniffer": "^1.0.2",
"left-pad": "^1.3.0",
"nwsapi": "^2.0.7",
"parse5": "4.0.0",
"pn": "^1.1.0",
"request": "^2.87.0",
"request-promise-native": "^1.0.5",
"sax": "^1.2.4",
"symbol-tree": "^3.2.2",
"tough-cookie": "^2.3.4",
"w3c-hr-time": "^1.0.1",
"webidl-conversions": "^4.0.2",
"whatwg-encoding": "^1.0.3",
"whatwg-mimetype": "^2.1.0",
"whatwg-url": "^6.4.1",
"ws": "^5.2.0",
"xml-name-validator": "^3.0.0"
}
},
"jsesc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
@@ -4515,15 +4557,10 @@
}
}
},
"mime": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz",
"integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg=="
},
"mime-db": {
"version": "1.34.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.34.0.tgz",
"integrity": "sha1-RS0Oz/XDA0am3B5kseruDTcZ/5o="
"version": "1.42.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
"integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ=="
},
"mime-types": {
"version": "2.1.18",
@@ -4778,14 +4815,22 @@
}
},
"node-notifier": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz",
"integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-6.0.0.tgz",
"integrity": "sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw==",
"requires": {
"growly": "^1.3.0",
"semver": "^5.4.1",
"is-wsl": "^2.1.1",
"semver": "^6.3.0",
"shellwords": "^0.1.1",
"which": "^1.3.0"
"which": "^1.3.1"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
"node-pre-gyp": {
@@ -5225,6 +5270,11 @@
"error-ex": "^1.2.0"
}
},
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -5899,13 +5949,6 @@
"integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
"requires": {
"lodash": "^4.17.11"
},
"dependencies": {
"lodash": {
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw=="
}
}
},
"request-promise-native": {
@@ -6114,6 +6157,31 @@
"integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
"dev": true
},
"slice-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
"integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
"requires": {
"ansi-styles": "^3.2.0",
"astral-regex": "^1.0.0",
"is-fullwidth-code-point": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
}
}
},
"smalltalk": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/smalltalk/-/smalltalk-2.5.1.tgz",
@@ -6901,9 +6969,9 @@
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
@@ -7005,6 +7073,14 @@
"signal-exit": "^3.0.2"
}
},
"ws": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"requires": {
"async-limiter": "~1.0.0"
}
},
"xdg-basedir": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.0.169",
"version": "1.0.170",
"description": "Joplin for Desktop",
"main": "main.js",
"scripts": {
@@ -91,7 +91,7 @@
"compare-versions": "^3.2.1",
"diacritics": "^1.3.0",
"diff-match-patch": "^1.0.4",
"electron-context-menu": "^0.9.1",
"electron-context-menu": "^0.15.0",
"electron-is-dev": "^0.3.0",
"electron-window-state": "^4.1.1",
"es6-promise-pool": "^2.5.0",
@@ -104,8 +104,8 @@
"html-entities": "^1.2.1",
"html-minifier": "^4.0.0",
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.17",
"joplin-turndown-plugin-gfm": "^1.0.9",
"joplin-turndown": "^4.0.18",
"joplin-turndown-plugin-gfm": "^1.0.11",
"jssha": "^2.3.1",
"katex": "^0.10.0",
"levenshtein": "^1.0.5",
@@ -125,12 +125,11 @@
"markdown-it-sup": "^1.0.0",
"markdown-it-toc-done-right": "^4.0.2",
"md5": "^2.2.1",
"mime": "^2.3.1",
"moment": "^2.22.2",
"multiparty": "^4.2.1",
"mustache": "^3.0.1",
"node-fetch": "^1.7.3",
"node-notifier": "^5.2.1",
"node-notifier": "^6.0.0",
"promise": "^8.0.1",
"query-string": "^5.1.1",
"react": "^16.4.0",

View File

@@ -60,7 +60,7 @@ class Dialog extends React.PureComponent {
this.styles_[this.props.theme] = {
dialogBox: Object.assign({}, theme.dialogBox, { minWidth: '50%', maxWidth: '50%' }),
input: Object.assign({}, theme.inputStyle, { flex: 1 }),
row: {overflow: 'hidden', height:itemHeight, display: 'flex', justifyContent: 'center', flexDirection: 'column', paddingLeft: 10, paddingRight: 10},
row: {overflow: 'hidden', height: itemHeight, display: 'flex', justifyContent: 'center', flexDirection: 'column', paddingLeft: 10, paddingRight: 10},
help: Object.assign({}, theme.textStyle, { marginBottom: 10 }),
inputHelpWrapper: {display: 'flex', flexDirection: 'row', alignItems: 'center'},
};

View File

@@ -149,3 +149,30 @@ a {
outline: 0 none;
}
.modal-message {
display: flex;
justify-content: center;
align-items: center;
color: grey;
font-size: 1.2em;
margin: 40px 20px;
}
.modal-message #loading-animation {
margin-right: 20px;
width: 20px;
height: 20px;
border: 5px solid lightgrey;
border-top: 4px solid white;
border-radius: 50%;
transition-property: transform;
animation-name: rotate;
animation-duration: 1.2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
@keyframes rotate {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}

View File

@@ -96,7 +96,7 @@ const lightStyle = {
warningBackgroundColor: '#FFD08D',
htmlColor:'#222222',
htmlColor: '#222222',
htmlBackgroundColor: 'white',
htmlDividerColor: 'rgb(230,230,230)',
htmlLinkColor: 'rgb(80,130,190)',
@@ -223,6 +223,43 @@ const solarizedDarkStyle = {
codeThemeCss: 'atom-one-dark-reasonable.css',
};
const draculaStyle = {
backgroundColor: '#282a36',
backgroundColorTransparent: 'rgba(40, 42, 54, 0.9)',
oddBackgroundColor: '#282a36',
color: '#f8f8f2', // For regular text
colorError: '#ff5555',
colorWarn: '#ffb86c',
colorFaded: '#6272a4', // For less important text;
colorBright: '#50fa7b', // For important text;
dividerColor: '#bd93f9',
selectedColor: '#44475a',
urlColor: '#8be9fd',
backgroundColor2: '#21222C',
depthColor: 'rgb(200, 200, 200, OPACITY)',
color2: '#bd93f9',
selectedColor2: '#44475a',
colorError2: '#ff5555',
raisedBackgroundColor: '#44475a',
raisedColor: '#bd93f9',
warningBackgroundColor: '#ffb86c',
htmlColor: '#f8f8f2',
htmlBackgroundColor: '#282a36',
htmlDividerColor: '#f8f8f2',
htmlLinkColor: '#8be9fd',
htmlTableBackgroundColor: '#6272a4',
htmlCodeBackgroundColor: '#44475a',
htmlCodeBorderColor: '#f8f8f2',
htmlCodeColor: '#50fa7b',
editorTheme: 'dracula',
codeThemeCss: 'atom-one-dark-reasonable.css',
};
function addExtraStyles(style) {
style.tagStyle = {
fontSize: style.fontSize,
@@ -349,7 +386,7 @@ function themeStyle(theme) {
// For WebView - must correspond to the properties above
htmlFontSize: `${Math.round(15 * zoomRatio)}px`,
htmlLineHeight: '1.6em', //Math.round(20 * zoomRatio) + 'px'
htmlLineHeight: '1.6em', // Math.round(20 * zoomRatio) + 'px'
htmlCodeFontSize: '.9em',
};
@@ -368,6 +405,8 @@ function themeStyle(theme) {
output = Object.assign({}, output, solarizedLightStyle);
} else if (theme == Setting.THEME_SOLARIZED_DARK) {
output = Object.assign({}, output, solarizedDarkStyle);
} else if (theme == Setting.THEME_DRACULA) {
output = Object.assign({}, output, draculaStyle);
}
// Note: All the theme specific things should go in addExtraStyles

View File

@@ -1,14 +1,5 @@
#!/bin/bash
set -e
# Title
echo " _ _ _ "
echo " | | ___ _ __ | (_)_ __ "
echo " _ | |/ _ \| '_ \| | | '_ \ "
echo "| |_| | (_) | |_) | | | | | |"
echo " \___/ \___/| .__/|_|_|_| |_|"
echo " |_|"
echo ""
echo "Linux Installer and Updater"
#-----------------------------------------------------
# Variables
@@ -16,8 +7,20 @@ echo "Linux Installer and Updater"
COLOR_RED=`tput setaf 1`
COLOR_GREEN=`tput setaf 2`
COLOR_RESET=`tput sgr0`
SILENT=false
# Check and warn if running as root.
print() {
if [[ "$SILENT" == false ]] ; then
echo $1
fi
}
#-----------------------------------------------------
# ARGUMENTS
#-----------------------------------------------------
# --allow-root
## Check and warn if running as root.
if [[ $EUID = 0 ]] ; then
if [[ $* != *--allow-root* ]] ; then
echo "${COLOR_RED}It is not recommended (nor necessary) to run this script as root. To do so anyway, please use '--allow-root'${COLOR_RESET}"
@@ -25,53 +28,73 @@ if [[ $EUID = 0 ]] ; then
fi
fi
# --silent
## Mutes messages by console
if [[ $* == *--silent* ]] ; then
SILENT=true
fi
#-----------------------------------------------------
# START
#-----------------------------------------------------
# Title
print " _ _ _ "
print " | | ___ _ __ | (_)_ __ "
print " _ | |/ _ \| '_ \| | | '_ \ "
print "| |_| | (_) | |_) | | | | | |"
print " \___/ \___/| .__/|_|_|_| |_|"
print " |_|"
print ""
print "Linux Installer and Updater"
#-----------------------------------------------------
# Download Joplin
#-----------------------------------------------------
# Get the latest version to download
version=$(wget -qO - "https://api.github.com/repos/laurent22/joplin/releases/latest" | grep -Po '"tag_name": "v\K.*?(?=")')
RELEASE_VERSION=$(wget -qO - "https://api.github.com/repos/laurent22/joplin/releases/latest" | grep -Po '"tag_name": "v\K.*?(?=")')
# Check if it's in the latest version
if [[ ! -e ~/.joplin/VERSION ]] || [[ $(< ~/.joplin/VERSION) != "$version" ]]; then
if [[ ! -e ~/.joplin/VERSION ]] || [[ $(< ~/.joplin/VERSION) != "$RELEASE_VERSION" ]]; then
echo 'Downloading Joplin...'
print 'Downloading Joplin...'
# Delete previous version (in future versions joplin.desktop shouldn't exist)
rm -f ~/.joplin/*.AppImage ~/.local/share/applications/joplin.desktop ~/.joplin/VERSION
# Creates the folder where the binary will be stored
mkdir -p ~/.joplin/
# Download the latest version
wget -nv --show-progress -O ~/.joplin/Joplin.AppImage https://github.com/laurent22/joplin/releases/download/v$version/Joplin-$version-x86_64.AppImage
wget -nv --show-progress -O ~/.joplin/Joplin.AppImage https://github.com/laurent22/joplin/releases/download/v$RELEASE_VERSION/Joplin-$RELEASE_VERSION-x86_64.AppImage
# Gives execution privileges
chmod +x ~/.joplin/Joplin.AppImage
echo "${COLOR_GREEN}OK${COLOR_RESET}"
print "${COLOR_GREEN}OK${COLOR_RESET}"
#-----------------------------------------------------
# Icon
#-----------------------------------------------------
# Download icon
echo 'Downloading icon...'
print 'Downloading icon...'
mkdir -p ~/.local/share/icons/hicolor/512x512/apps
wget -nv -O ~/.local/share/icons/hicolor/512x512/apps/joplin.png https://joplinapp.org/images/Icon512.png
echo "${COLOR_GREEN}OK${COLOR_RESET}"
# Detect desktop environment
print "${COLOR_GREEN}OK${COLOR_RESET}"
# Detect desktop environment
if [ "$XDG_CURRENT_DESKTOP" = "" ]
then
desktop=$(echo "$XDG_DATA_DIRS" | sed 's/.*\(xfce\|kde\|gnome\).*/\1/')
DESKTOP=$(echo "$XDG_DATA_DIRS" | sed 's/.*\(xfce\|kde\|gnome\).*/\1/')
else
desktop=$XDG_CURRENT_DESKTOP
DESKTOP=$XDG_CURRENT_DESKTOP
fi
desktop=${desktop,,} # convert to lower case
DESKTOP=${DESKTOP,,} # convert to lower case
# Create icon for Gnome
echo 'Create Desktop icon.'
if [[ $desktop =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*x-cinnamon.*|.*deepin.* ]]
if [[ $DESKTOP =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*x-cinnamon.*|.*deepin.* ]]
then
: "${TMPDIR:=/tmp}"
# This command extracts to squashfs-root by default and can't be changed...
@@ -84,22 +107,23 @@ if [[ ! -e ~/.joplin/VERSION ]] || [[ $(< ~/.joplin/VERSION) != "$version" ]]; t
# On some systems this directory doesn't exist by default
mkdir -p ~/.local/share/applications
echo -e "[Desktop Entry]\nEncoding=UTF-8\nName=Joplin\nComment=Joplin for Desktop\nExec=/home/$USER/.joplin/Joplin.AppImage\nIcon=joplin\nStartupWMClass=Joplin\nType=Application\nCategories=Application;\n$APPIMAGE_VERSION" >> ~/.local/share/applications/appimagekit-joplin.desktop
echo "${COLOR_GREEN}OK${COLOR_RESET}"
echo -e "[Desktop Entry]\nEncoding=UTF-8\nName=Joplin\nComment=Joplin for Desktop\nExec=/home/$USER/.joplin/Joplin.AppImage\nIcon=joplin\nStartupWMClass=Joplin\nType=Application\nCategories=Office;\n$APPIMAGE_VERSION" >> ~/.local/share/applications/appimagekit-joplin.desktop
print "${COLOR_GREEN}OK${COLOR_RESET}"
else
echo "${COLOR_RED}NOT DONE${COLOR_RESET}"
print "${COLOR_RED}NOT DONE${COLOR_RESET}"
fi
#-----------------------------------------------------
# Finish
#-----------------------------------------------------
# Informs the user that it has been installed and cleans variables
echo "${COLOR_GREEN}Joplin version${COLOR_RESET}" $version "${COLOR_GREEN}installed.${COLOR_RESET}"
print "${COLOR_GREEN}Joplin version${COLOR_RESET}" $RELEASE_VERSION "${COLOR_GREEN}installed.${COLOR_RESET}"
# Add version
echo $version > ~/.joplin/VERSION
echo $RELEASE_VERSION > ~/.joplin/VERSION
else
echo "${COLOR_GREEN}You already have the latest version${COLOR_RESET}" $version "${COLOR_GREEN}installed.${COLOR_RESET}"
print "${COLOR_GREEN}You already have the latest version${COLOR_RESET}" $version "${COLOR_GREEN}installed.${COLOR_RESET}"
fi
echo 'Bye!'
unset version
# Goodbye
print 'Bye!'

108
README.md
View File

@@ -2,6 +2,18 @@
[![Donate](https://joplinapp.org/images/badges/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=E8JMYD2LQ8MMA&lc=GB&item_name=Joplin+Development&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) [![Become a patron](https://joplinapp.org/images/badges/Patreon-Badge.svg)](https://www.patreon.com/joplin)
* * *
[Hacktoberfest 🎃](https://hacktoberfest.digitalocean.com/) is back this year again for our great pleasure ^^
To participate go to [https://hacktoberfest.digitalocean.com/](https://hacktoberfest.digitalocean.com/), log in (with you GitHub account) and you are ready to get in. Next, go dive into the Joplin issues list labelled "[Hacktoberfest](https://github.com/laurent22/joplin/labels/hacktoberfest)"
Start hacking, submit the PR from the 1st of October, not before.
We hope you will enjoy that event this year again like the previous one 🎃🎉
*PS: the 4 Pull Request don’t have to be done **only** on Joplin project, those can be done on any FOSS projects. Even PR for issue not tagged as 'hacktoberfest'*
* * *
Joplin is a free, open source note taking and to-do application, which can handle a large number of notes organised into notebooks. The notes are searchable, can be copied, tagged and modified either from the applications directly or from your own text editor. The notes are in [Markdown format](#markdown).
Notes exported from Evernote via .enex files [can be imported](#importing) into Joplin, including the formatted content (which is converted to Markdown), resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.). Plain Markdown files can also be imported.
@@ -20,15 +32,15 @@ Three types of applications are available: for the **desktop** (Windows, macOS a
Operating System | Download | Alternative
-----------------|--------|-------------------
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.168/Joplin-Setup-1.0.168.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a> | Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.0.168/JoplinPortable.exe'>Portable version</a><br><br>The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.168/Joplin-1.0.168.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a> | You can also use Homebrew: `brew cask install joplin`
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.168/Joplin-1.0.168-x86_64.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a> | An Arch Linux package [is also available](#terminal-application).<br><br>If it works with your distribution (it has been tested on Ubuntu, Fedora, Gnome and Mint), the recommended way is to use this script as it will handle the desktop icon too:<br><br> `wget -O - https://raw.githubusercontent.com/laurent22/joplin/master/Joplin_install_and_update.sh \| bash`
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.169/Joplin-Setup-1.0.169.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a> | Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.0.169/JoplinPortable.exe'>Portable version</a><br><br>The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.169/Joplin-1.0.169.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a> | You can also use Homebrew: `brew cask install joplin`
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.169/Joplin-1.0.169-x86_64.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a> | An Arch Linux package [is also available](#terminal-application).<br><br>If it works with your distribution (it has been tested on Ubuntu, Fedora, Gnome and Mint), the recommended way is to use this script as it will handle the desktop icon too:<br><br> `wget -O - https://raw.githubusercontent.com/laurent22/joplin/master/Joplin_install_and_update.sh \| bash`
## Mobile applications
Operating System | Download | Alt. Download
-----------------|----------|----------------
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://joplinapp.org/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.307/joplin-v1.0.307.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.307/joplin-v1.0.307-32bit.apk)
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://joplinapp.org/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.308/joplin-v1.0.308.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.308/joplin-v1.0.308-32bit.apk)
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://joplinapp.org/images/BadgeIOS.png'/></a> | -
## Terminal application
@@ -37,7 +49,7 @@ Operating system | Method
-----------------|----------------
macOS | `brew install joplin`
Linux or Windows (via [WSL](https://msdn.microsoft.com/en-us/commandline/wsl/faq?f=255&MSPPError=-2147217396)) | **Important:** First, [install Node 8+](https://nodejs.org/en/download/package-manager/).<br/><br/>`NPM_CONFIG_PREFIX=~/.joplin-bin npm install -g joplin`<br/>`sudo ln -s ~/.joplin-bin/bin/joplin /usr/bin/joplin`<br><br>By default, the application binary will be installed under `~/.joplin-bin`. You may change this directory if needed. Alternatively, if your npm permissions are setup as described [here](https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-2-change-npms-default-directory-to-another-directory) (Option 2) then simply running `npm -g install joplin` would work.
Arch Linux | An Arch Linux package is available [here](https://aur.archlinux.org/packages/joplin/). To install it, use an AUR wrapper such as yay: `yay -S joplin`. Both the CLI tool (type `joplin`) and desktop app (type `joplin-desktop`) are packaged. For support, please go to the [GitHub repo](https://github.com/masterkorp/joplin-pkgbuild).
Arch Linux | An Arch Linux package is available [here](https://aur.archlinux.org/packages/joplin/). To install it, use an AUR wrapper such as yay: `yay -S joplin`. Both the CLI tool (type `joplin`) and desktop app (type `joplin-desktop`) are packaged. You can also install a compiled version with the [chaotic-aur](https://wiki.archlinux.org/index.php/Unofficial_user_repositories#chaotic-aur) repository. For support, please go to the [GitHub repo](https://github.com/masterkorp/joplin-pkgbuild).
To start it, type `joplin`.
@@ -60,6 +72,7 @@ The Web Clipper is a browser extension that allows you to save web pages and scr
- Support
- [Joplin Forum](https://discourse.joplinapp.org)
- [Markdown Guide](https://github.com/laurent22/joplin/blob/master/readme/markdown.md)
- [How to enable end-to-end encryption](https://github.com/laurent22/joplin/blob/master/readme/e2ee.md)
- [End-to-end encryption spec](https://github.com/laurent22/joplin/blob/master/readme/spec.md)
- [How to enable debug mode](https://github.com/laurent22/joplin/blob/master/readme/debugging.md)
@@ -109,7 +122,7 @@ To import Evernote data, first export your Evernote notebooks to ENEX files as d
In the **desktop application**, open File > Import > ENEX and select your file. The notes will be imported into a new separate notebook. If needed they can then be moved to a different notebook, or the notebook can be renamed, etc.
In the **terminal application**, in [command-line mode](https://joplinapp.org/terminal/#command-line-mode), type `import /path/to/file.enex`. This will import the notes into a new notebook named after the filename.
In the **terminal application**, in [command-line mode](https://github.com/laurent22/joplin/blob/master/readme/terminal.md#command-line-mode), type `import /path/to/file.enex`. This will import the notes into a new notebook named after the filename.
## Importing from Markdown files
@@ -117,7 +130,7 @@ Joplin can import notes from plain Markdown file. You can either import a comple
In the **desktop application**, open File > Import > MD and select your Markdown file or directory.
In the **terminal application**, in [command-line mode](https://joplinapp.org/terminal/#command-line-mode), type `import --format md /path/to/file.md` or `import --format md /path/to/directory/`.
In the **terminal application**, in [command-line mode](https://github.com/laurent22/joplin/blob/master/readme/terminal.md#command-line-mode), type `import --format md /path/to/file.md` or `import --format md /path/to/directory/`.
## Importing from other applications
@@ -192,9 +205,9 @@ In the **terminal application**, to initiate the synchronisation process, type `
# Encryption
Joplin supports end-to-end encryption (E2EE) on all the applications. E2EE is a system where only the owner of the notes, notebooks, tags or resources can read them. It prevents potential eavesdroppers - including telecom providers, internet providers, and even the developers of Joplin from being able to access the data. Please see the [End-To-End Encryption Tutorial](https://joplinapp.org/e2ee/) for more information about this feature and how to enable it.
Joplin supports end-to-end encryption (E2EE) on all the applications. E2EE is a system where only the owner of the notes, notebooks, tags or resources can read them. It prevents potential eavesdroppers - including telecom providers, internet providers, and even the developers of Joplin from being able to access the data. Please see the [End-To-End Encryption Tutorial](https://github.com/laurent22/joplin/blob/master/readme/e2ee.md) for more information about this feature and how to enable it.
For a more technical description, mostly relevant for development or to review the method being used, please see the [Encryption specification](https://joplinapp.org/spec/).
For a more technical description, mostly relevant for development or to review the method being used, please see the [Encryption specification](https://github.com/laurent22/joplin/blob/master/readme/spec.md).
# Note history
@@ -249,76 +262,13 @@ Sub-notebooks allow organising multiple notebooks into a tree of notebooks. For
# Markdown
Joplin uses and renders [Github-flavoured Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) with a few variations and additions. In particular:
Joplin uses and renders a Github-flavoured Markdown with a few variations and additions. In particular it adds math formula support, interactive checkboxes and support for note links. Joplin also supports Markdown plugins which allow enabling and disabling various advanced Markdown features. Have a look at the [Markdown Guide](https://github.com/laurent22/joplin/blob/master/readme/markdown.md) for more information.
## Links to other notes
You can create a link to a note by specifying its ID in the URL. For example:
[Link to my note](:/0b0d62d15e60409dac34f354b6e9e839)
Since getting the ID of a note is not straightforward, each app provides a way to create such link. In the **desktop app**, right click on a note an select "Copy Markdown link". In the **mobile app**, open a note and, in the top right menu, select "Copy Markdown link". You can then paste this link anywhere in another note.
## Plugins
Joplin supports a number of plugins that can be toggled on top the standard markdown features you would expect. These toggle-able plugins are listed below. Note: not all of the plugins are enabled by default, if the enable field is 'no' below, then enter Tools->General Options to enable the plugin. Plugins can be disabled in the same manner.
| Plugin | Syntax | Description | Enabled |
|--------|--------|-------------|---------|
| [Katex](https://katex.org) | `$$math expr$$` or `$math$` | [See Below](https://github.com/laurent22/joplin#math-notation) | yes |
| [Mark](https://github.com/markdown-it/markdown-it-mark) | `==marked==` | Transforms into `<mark>marked</mark>` (highlighted) | yes |
| [Footnote](https://github.com/markdown-it/markdown-it-footnote) | `Simples inline footnote ^[I'm inline!]` | See [plugin page](https://github.com/markdown-it/markdown-it-footnote) for full description | yes |
| [TOC](https://github.com/nagaozen/markdown-it-toc-done-right) | Any of `${toc}, [[toc]], [toc], [[_toc_]]` | Adds a table of contents to the location of the toc page. Based on headings and sub-headings | no |
| [Sub](https://github.com/markdown-it/markdown-it-sub) | `X~1~` | Transforms into X<sub>1</sub> | no |
| [Sup](https://github.com/markdown-it/markdown-it-sup) | `X^2^` | Transforms into X<sup>2</sup> | no |
| [Deflist](https://github.com/markdown-it/markdown-it-deflist) | See [pandoc](http://johnmacfarlane.net/pandoc/README.html#definition-lists) page for syntax | Adds the html `<dl>` tag accessible through markdown | no |
| [Abbr](https://github.com/markdown-it/markdown-it-abbr) | *[HTML]: Hyper Text Markup Language | Allows definition of abbreviations that can be hovered over later for a full expansion | no |
| [Emoji](https://github.com/markdown-it/markdown-it-emoji) | `:smile:` :smile: | See [this list](https://gist.github.com/rxaviers/7360908) for more emoji | no |
| [Insert](https://github.com/markdown-it/markdown-it-ins) | `++inserted++` | Transforms into `<ins>inserted</ins>` (<ins>inserted</ins>) | no |
| [Multitable](https://github.com/RedBug312/markdown-it-multimd-table) | See [MultiMarkdown](https://fletcher.github.io/MultiMarkdown-6/syntax/tables.html) page | Adds more power and customization to markdown tables | no |
| [Fountain](https://fountain.io) | <code>\`\`\`fountain</code><br/>Your screenplay...<br/><code>\`\`\`</code> | Adds support for the Fountain markup language, a plain text markup language for screenwriting | no |
## Math notation
Math expressions can be added using the [KaTeX notation](https://khan.github.io/KaTeX/). To add an inline equation, wrap the expression in `$EXPRESSION$`, eg. `$\sqrt{3x-1}+(1+x)^2$`. To create an expression block, wrap it as follow:
$$
EXPRESSION
$$
For example:
$$
f(x) = \int_{-\infty}^\infty
\hat f(\xi)\,e^{2 \pi i \xi x}
\,d\xi
$$
Here is an example with the Markdown and rendered result side by side:
<img src="https://joplinapp.org/images/Katex.png" height="400px">
## Checkboxes
Checkboxes can be added like so:
- [ ] Milk
- [ ] Rice
- [ ] Eggs
The checkboxes can then be ticked in the mobile and desktop applications.
## HTML support
It is generally recommended to enter the notes as Markdown as it makes the notes easier to edit. However for cases where certain features aren't supported (such as strikethrough or to highlight text), you can also use HTML code directly. For example this would be a valid note:
This is <s>strikethrough text</s> mixed with regular **Markdown**.
## Custom CSS
# 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. Joplin ***must*** be restarted for the new css to be applied, please ensure that Joplin is not closing to the tray, but is actually exiting. 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.
## Note templates
# Note templates
In the **desktop app**, templates can be used to create new notes or to insert into existing ones by creating a `templates` folder in Joplin's config folder and placing Markdown template files into it. For example creating the file `hours.md` in the `templates` directory with the contents:
@@ -361,7 +311,7 @@ In the desktop application, press Ctrl+G or Cmd+G and type the title of a note t
Donations to Joplin support the development of the project. Developing quality applications mostly takes time, but there are also some expenses, such as digital certificates to sign the applications, app store fees, hosting, etc. Most of all, your donation will make it possible to keep up the current development standard.
Please see the [donation page](https://joplinapp.org/donate/) for information on how to support the development of Joplin.
Please see the [donation page](https://github.com/laurent22/joplin/blob/master/readme/donate.md) for information on how to support the development of Joplin.
# Community
@@ -430,9 +380,9 @@ Current translations:
Thanks to our GitHub sponsors!
| | |
| :---: | :---: |
| <img width="50" src="https://avatars1.githubusercontent.com/u/6979755?v=4"/></br>[devonzuegel](https://github.com/devonzuegel) | <img width="50" src="https://avatars1.githubusercontent.com/u/794584?v=4"/></br>[corvus-ch](https://github.com/corvus-ch) |
| | | |
| :---: | :---: | :---: |
| <img width="50" src="https://avatars1.githubusercontent.com/u/6979755?v=4"/></br>[devonzuegel](https://github.com/devonzuegel) | <img width="50" src="https://avatars1.githubusercontent.com/u/794584?v=4"/></br>[corvus-ch](https://github.com/corvus-ch) | <img width="50" src="https://avatars2.githubusercontent.com/u/5559891?v=4"/></br>[stellaktran](https://github.com/stellaktran)
# Contributors

View File

@@ -94,8 +94,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097543
versionName "1.0.307"
versionCode 2097544
versionName "1.0.308"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}

View File

@@ -20,18 +20,18 @@ ArrayUtils.binarySearch = function(items, value) {
middle = Math.floor((stopIndex + startIndex) / 2);
while (items[middle] != value && startIndex < stopIndex) {
//adjust search area
// adjust search area
if (value < items[middle]) {
stopIndex = middle - 1;
} else if (value > items[middle]) {
startIndex = middle + 1;
}
//recalculate middle
// recalculate middle
middle = Math.floor((stopIndex + startIndex) / 2);
}
//make sure it's the right value
// make sure it's the right value
return items[middle] != value ? -1 : middle;
};

View File

@@ -15,6 +15,7 @@ const { reg } = require('lib/registry.js');
const { time } = require('lib/time-utils.js');
const BaseSyncTarget = require('lib/BaseSyncTarget.js');
const { shim } = require('lib/shim.js');
const { uuid } = require('lib/uuid.js');
const { _, setLocale } = require('lib/locale.js');
const reduxSharedMiddleware = require('lib/components/shared/reduxSharedMiddleware');
const os = require('os');
@@ -598,6 +599,8 @@ class BaseApplication {
await Setting.load();
if (!Setting.value('clientId')) Setting.setValue('clientId', uuid.create());
if (Setting.value('firstStart')) {
const locale = shim.detectAndSetLocale(Setting);
reg.logger().info(`First start: detected locale as ${locale}`);

View File

@@ -150,8 +150,8 @@ class BaseModel {
});
}
static load(id) {
return this.loadByField('id', id);
static load(id, options = null) {
return this.loadByField('id', id, options);
}
static shortId(id) {
@@ -250,7 +250,8 @@ class BaseModel {
static loadByField(fieldName, fieldValue, options = null) {
if (!options) options = {};
if (!('caseInsensitive' in options)) options.caseInsensitive = false;
let sql = `SELECT * FROM \`${this.tableName()}\` WHERE \`${fieldName}\` = ?`;
if (!options.fields) options.fields = '*';
let sql = `SELECT ${this.db().escapeFields(options.fields)} FROM \`${this.tableName()}\` WHERE \`${fieldName}\` = ?`;
if (options.caseInsensitive) sql += ' COLLATE NOCASE';
return this.modelSelectOne(sql, [fieldValue]);
}

View File

@@ -63,7 +63,7 @@ class WebDavApi {
try {
// Note: Non-ASCII passwords will throw an error about Latin1 characters - https://github.com/laurent22/joplin/issues/246
// Tried various things like the below, but it didn't work on React Native:
//return base64.encode(utf8.encode(this.options_.username() + ':' + this.options_.password()));
// return base64.encode(utf8.encode(this.options_.username() + ':' + this.options_.password()));
return base64.encode(`${this.options_.username()}:${this.options_.password()}`);
} catch (error) {
error.message = `Cannot encode username/password: ${error.message}`;

View File

@@ -11,16 +11,30 @@ class CameraView extends Component {
this.state = {
snapping: false,
camera: RNCamera.Constants.Type.back,
};
this.back_onPress = this.back_onPress.bind(this);
this.photo_onPress = this.photo_onPress.bind(this);
this.reverse_onPress = this.reverse_onPress.bind(this);
}
back_onPress() {
if (this.props.onCancel) this.props.onCancel();
}
reverse_onPress() {
if (this.state.camera == RNCamera.Constants.Type.back) {
this.setState({
camera: RNCamera.Constants.Type.front,
});
} else if (this.state.camera == RNCamera.Constants.Type.front) {
this.setState({
camera: RNCamera.Constants.Type.back,
});
}
}
async photo_onPress() {
if (!this.camera || !this.props.onPhoto) return;
@@ -47,7 +61,7 @@ class CameraView extends Component {
ref={ref => {
this.camera = ref;
}}
type={RNCamera.Constants.Type.back}
type={this.state.camera}
captureAudio={false}
androidCameraPermissionOptions={{
title: _('Permission to use camera'),
@@ -70,18 +84,31 @@ class CameraView extends Component {
</View>
</TouchableOpacity>
</View>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'flex-end', flexDirection: 'row' }}>
<TouchableOpacity onPress={this.photo_onPress}>
<View style={{ marginBottom: 20, borderRadius: 90, width: 90, height: 90, backgroundColor: '#ffffffaa', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Icon
name={photoIcon}
style={{
fontSize: 60,
color: 'black',
}}
/>
</View>
</TouchableOpacity>
<View style={{ flex: 1, alignItems: 'flex-end', flexDirection: 'row', width: '100%' }}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity onPress={this.reverse_onPress} style={{width: '35%', marginLeft: 20}}>
<View style={{borderRadius: 32, width: 60, height: 60, backgroundColor: '#ffffffaa', justifyContent: 'center', alignItems: 'center', alignSelf: 'baseline' }}>
<Icon
name="md-reverse-camera"
style={{
fontSize: 40,
color: 'black',
}}
/>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this.photo_onPress} style={{width: '65%'}}>
<View style={{ marginBottom: 20, borderRadius: 90, width: 90, height: 90, backgroundColor: '#ffffffaa', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Icon
name={photoIcon}
style={{
fontSize: 60,
color: 'black',
}}
/>
</View>
</TouchableOpacity>
</View>
</View>
</View>
</RNCamera>

View File

@@ -67,7 +67,7 @@ class ItemList extends React.Component {
render() {
const style = this.props.style ? this.props.style : {};
//if (!this.props.itemHeight) throw new Error('itemHeight is required');
// if (!this.props.itemHeight) throw new Error('itemHeight is required');
let itemComps = [];

View File

@@ -7,7 +7,7 @@ const styles = {
checkboxIcon: {
fontSize: 20,
height: 22,
//marginRight: 10,
// marginRight: 10,
},
};
@@ -57,7 +57,7 @@ class Checkbox extends Component {
if (style && style.display === 'none') return <View />;
//if (style.display) thStyle.display = style.display;
// if (style.display) thStyle.display = style.display;
return (
<TouchableHighlight onPress={() => this.onPress()} style={thStyle}>

View File

@@ -96,7 +96,7 @@ class NoteBodyViewer extends Component {
},
paddingBottom: '3.8em', // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text)
highlightedKeywords: this.props.highlightedKeywords,
resources: this.props.noteResources, //await shared.attachedResources(bodyToRender),
resources: this.props.noteResources, // await shared.attachedResources(bodyToRender),
codeTheme: theme.codeThemeCss,
postMessageSyntax: 'window.ReactNativeWebView.postMessage',
};

View File

@@ -30,7 +30,7 @@ class NoteItemComponent extends Component {
let styles = {
listItem: {
flexDirection: 'row',
//height: 40,
// height: 40,
borderBottomWidth: 1,
borderBottomColor: theme.dividerColor,
alignItems: 'flex-start',
@@ -38,7 +38,7 @@ class NoteItemComponent extends Component {
paddingRight: theme.marginRight,
paddingTop: theme.itemMarginTop,
paddingBottom: theme.itemMarginBottom,
//backgroundColor: theme.backgroundColor,
// backgroundColor: theme.backgroundColor,
},
listItemText: {
flex: 1,

View File

@@ -61,7 +61,7 @@ class NoteListComponent extends Component {
}
filterNotes(notes) {
const todoFilter = 'all'; //Setting.value('todoFilter');
const todoFilter = 'all'; // Setting.value('todoFilter');
if (todoFilter == 'all') return notes;
const now = time.unixMs();

View File

@@ -163,6 +163,16 @@ class ScreenHeaderComponent extends React.PureComponent {
NavService.go('Search');
}
async duplicateButton_press() {
const noteIds = this.props.selectedNoteIds;
//Duplicate all selected notes. ensureUniqueTitle is set to true to use the
//original note's name as a root for the new unique identifier.
await Note.duplicateMultipleNotes(noteIds, {ensureUniqueTitle: true});
this.props.dispatch({ type: 'NOTE_SELECTION_END' });
}
async deleteButton_press() {
// Dialog needs to be displayed as a child of the parent component, otherwise
// it won't be visible within the header component.
@@ -245,6 +255,16 @@ class ScreenHeaderComponent extends React.PureComponent {
);
}
function duplicateButton(styles, onPress) {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.iconButton}>
<Icon name="md-copy" style={styles.topIcon} />
</View>
</TouchableOpacity>
);
}
function sortButton(styles, onPress) {
return (
<TouchableOpacity onPress={onPress}>
@@ -282,6 +302,12 @@ class ScreenHeaderComponent extends React.PureComponent {
<Text style={this.styles().contextMenuItemText}>{_('Delete')}</Text>
</MenuOption>
);
menuOptionComponents.push(
<MenuOption value={() => this.duplicateButton_press()} key={'menuOption_duplicate'} style={this.styles().contextMenuItem}>
<Text style={this.styles().contextMenuItemText}>{_('Duplicate')}</Text>
</MenuOption>
);
}
const createTitleComponent = () => {
@@ -383,6 +409,7 @@ class ScreenHeaderComponent extends React.PureComponent {
const backButtonComp = !showBackButton ? null : backButton(this.styles(), () => this.backButton_press(), backButtonDisabled);
const searchButtonComp = !showSearchButton ? null : searchButton(this.styles(), () => this.searchButton_press());
const deleteButtonComp = this.props.noteSelectionEnabled ? deleteButton(this.styles(), () => this.deleteButton_press()) : null;
const duplicateButtonComp = this.props.noteSelectionEnabled ? duplicateButton(this.styles(), () => this.duplicateButton_press()) : null;
const sortButtonComp = !this.props.noteSelectionEnabled && this.props.sortButton_press ? sortButton(this.styles(), () => this.props.sortButton_press()) : null;
const windowHeight = Dimensions.get('window').height - 50;
@@ -419,6 +446,7 @@ class ScreenHeaderComponent extends React.PureComponent {
{titleComp}
{searchButtonComp}
{deleteButtonComp}
{duplicateButtonComp}
{sortButtonComp}
{menuComp}
</View>

View File

@@ -194,7 +194,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
styles.switchSettingControl = Object.assign({}, styles.settingControl);
delete styles.switchSettingControl.color;
//styles.switchSettingControl.width = '20%';
// styles.switchSettingControl.width = '20%';
styles.switchSettingControl.flex = 0;
this.styles_[themeId] = StyleSheet.create(styles);
@@ -366,7 +366,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
</View>
);
} else {
//throw new Error('Unsupported setting type: ' + md.type);
// throw new Error('Unsupported setting type: ' + md.type);
}
return output;

View File

@@ -23,6 +23,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
this.state = {
passwordPromptShow: false,
passwordPromptAnswer: '',
passwordPromptConfirmAnswer: '',
};
shared.constructor(this);
@@ -82,6 +83,12 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
fontSize: theme.fontSize,
color: theme.color,
},
normalTextInput: {
margin: 10,
color: theme.color,
borderWidth: 1,
borderColor: theme.dividerColor,
},
container: {
flex: 1,
padding: theme.margin,
@@ -131,6 +138,9 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
try {
const password = this.state.passwordPromptAnswer;
if (!password) throw new Error(_('Password cannot be empty'));
const password2 = this.state.passwordPromptConfirmAnswer;
if (!password2) throw new Error(_('Confirm password cannot be empty'));
if (password !== password2) throw new Error(_('Passwords do not match!'));
await EncryptionService.instance().generateMasterKeyAndEnableEncryption(password);
this.setState({ passwordPromptShow: false });
} catch (error) {
@@ -140,16 +150,30 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
return (
<View style={{ flex: 1, borderColor: theme.dividerColor, borderWidth: 1, padding: 10, marginTop: 10, marginBottom: 10 }}>
<Text style={{ fontSize: theme.fontSize, color: theme.color }}>{_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.')}</Text>
<Text style={{ fontSize: theme.fontSize, color: theme.color, marginBottom: 10 }}>{_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.')}</Text>
<Text style={this.styles().normalText}>{_('Password:')}</Text>
<TextInput
placeholder={_('Password')}
selectionColor={theme.textSelectionColor}
style={{ margin: 10, color: theme.color, borderWidth: 1, borderColor: theme.dividerColor }}
style={this.styles().normalTextInput}
secureTextEntry={true}
value={this.state.passwordPromptAnswer}
onChangeText={text => {
this.setState({ passwordPromptAnswer: text });
}}
></TextInput>
<Text style={this.styles().normalText}>{_('Confirm password:')}</Text>
<TextInput
placeholder={_('Confirm password')}
selectionColor={theme.textSelectionColor}
style={this.styles().normalTextInput}
secureTextEntry={true}
value={this.state.passwordPromptConfirmAnswer}
onChangeText={text => {
this.setState({ passwordPromptConfirmAnswer: text });
}}
></TextInput>
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1, marginRight: 10 }}>
<Button
@@ -203,6 +227,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
this.setState({
passwordPromptShow: true,
passwordPromptAnswer: '',
passwordPromptConfirmAnswer: '',
});
return;
}

View File

@@ -164,14 +164,16 @@ class NoteScreenComponent extends BaseScreenComponent {
}
};
this.refreshResource = async resource => {
if (!this.state.note || !this.state.note.body) return;
const resourceIds = await Note.linkedResourceIds(this.state.note.body);
if (resourceIds.indexOf(resource.id) >= 0 && this.refs.noteBodyViewer) {
this.refreshResource = async (resource, noteBody = null) => {
if (noteBody === null && this.state.note && this.state.note.body) noteBody = this.state.note.body;
if (noteBody === null) return;
const resourceIds = await Note.linkedResourceIds(noteBody);
if (resourceIds.indexOf(resource.id) >= 0) {
shared.clearResourceCache();
const attachedResources = await shared.attachedResources(this.state.note.body);
const attachedResources = await shared.attachedResources(noteBody);
this.setState({ noteResources: attachedResources }, () => {
this.refs.noteBodyViewer.rebuildMd();
if (this.refs.noteBodyViewer) this.refs.noteBodyViewer.rebuildMd();
});
}
};
@@ -410,7 +412,7 @@ class NoteScreenComponent extends BaseScreenComponent {
const format = mimeType == 'image/png' ? 'PNG' : 'JPEG';
reg.logger().info(`Resizing image ${localFilePath}`);
const resizedImage = await ImageResizer.createResizedImage(localFilePath, dimensions.width, dimensions.height, format, 85); //, 0, targetPath);
const resizedImage = await ImageResizer.createResizedImage(localFilePath, dimensions.width, dimensions.height, format, 85); // , 0, targetPath);
const resizedImagePath = resizedImage.uri;
reg.logger().info('Resized image ', resizedImagePath);
@@ -512,7 +514,7 @@ class NoteScreenComponent extends BaseScreenComponent {
newNote.body += `\n${resourceTag}`;
this.setState({ note: newNote });
this.refreshResource(resource);
this.refreshResource(resource, newNote.body);
this.scheduleSave();
}

View File

@@ -78,7 +78,7 @@ class SelectDateTimeDialog extends React.PureComponent {
width={0.9}
height={350}
>
<View style={{flex:1, margin: 20, alignItems:'center'}}>
<View style={{flex: 1, margin: 20, alignItems: 'center'}}>
<DatePicker
date={this.state.date}
mode="datetime"
@@ -87,7 +87,7 @@ class SelectDateTimeDialog extends React.PureComponent {
confirmBtnText={_('Confirm')}
cancelBtnText={_('Cancel')}
onDateChange={(date) => { this.setState({ date: this.stringToDate(date) }); }}
style={{width:300}}
style={{width: 300}}
customStyles={{
btnConfirm: {
paddingVertical: 0,

View File

@@ -35,11 +35,13 @@ class SideMenuContentNoteComponent extends Component {
fontSize: 22,
color: theme.color,
},
sideButtonText: {
color: theme.color,
},
};
styles.sideButton = Object.assign({}, styles.button, { flex: 0 });
styles.sideButtonDisabled = Object.assign({}, styles.sideButton, { opacity: 0.6 });
styles.sideButtonText = Object.assign({}, styles.buttonText);
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];

View File

@@ -76,7 +76,7 @@ class SideMenuContentComponent extends Component {
styles.folderButtonSelected = Object.assign({}, styles.folderButton);
styles.folderButtonSelected.backgroundColor = theme.selectedColor;
styles.folderIcon = Object.assign({}, theme.icon);
styles.folderIcon.color = theme.colorFaded; //'#0072d5';
styles.folderIcon.color = theme.colorFaded; // '#0072d5';
styles.folderIcon.paddingTop = 3;
styles.sideButton = Object.assign({}, styles.button, { flex: 0 });

View File

@@ -6,7 +6,7 @@ class DatabaseDriverReactNative {
}
open(options) {
//SQLite.DEBUG(true);
// SQLite.DEBUG(true);
return new Promise((resolve, reject) => {
SQLite.openDatabase(
{ name: options.name },

View File

@@ -97,10 +97,10 @@ class FileApiDriverLocal {
try {
if (options.target === 'file') {
//output = await fs.copy(path, options.path, { overwrite: true });
// output = await fs.copy(path, options.path, { overwrite: true });
output = await this.fsDriver().copy(path, options.path);
} else {
//output = await fs.readFile(path, options.encoding);
// output = await fs.readFile(path, options.encoding);
output = await this.fsDriver().readFile(path, options.encoding);
}
} catch (error) {

View File

@@ -131,7 +131,7 @@ class FileApi {
this.logger().debug(`list ${this.baseDir()}`);
const result = await tryAndRepeat(() => this.driver_.list(this.baseDir(), options), this.requestRepeatCount());
const result = await tryAndRepeat(() => this.driver_.list(this.fullPath_(path), options), this.requestRepeatCount());
if (!options.includeHidden) {
let temp = [];
@@ -148,7 +148,7 @@ class FileApi {
setTimestamp(path, timestampMs) {
this.logger().debug(`setTimestamp ${this.fullPath_(path)}`);
return tryAndRepeat(() => this.driver_.setTimestamp(this.fullPath_(path), timestampMs), this.requestRepeatCount());
//return this.driver_.setTimestamp(this.fullPath_(path), timestampMs);
// return this.driver_.setTimestamp(this.fullPath_(path), timestampMs);
}
mkdir(path) {

View File

@@ -173,7 +173,7 @@ class FsDriverNode extends FsDriverBase {
}
async readFileChunk(handle, length, encoding = 'base64') {
//let buffer = new Buffer(length);
// let buffer = new Buffer(length);
let buffer = Buffer.alloc(length);
const result = await fs.read(handle, buffer, 0, length, null);
if (!result.bytesRead) return null;

View File

@@ -392,14 +392,20 @@ function isSpanStyleBold(attributes) {
if (style.includes('font-weight: bold;')) {
return true;
} else if (style.search(/font-family:.*,Bold.*;/) != -1) {
//console.debug('font-family regex matched');
// console.debug('font-family regex matched');
return true;
} else {
//console.debug('Found unsupported style(s) in span tag: %s', style);
// console.debug('Found unsupported style(s) in span tag: %s', style);
return false;
}
}
function isSpanStyleItalic(attributes) {
let style = attributes.style;
style = style.replace(/\s+/g, '');
return (style.toLowerCase().includes('font-style:italic;'));
}
function enexXmlToMdArray(stream, resources) {
let remainingResources = resources.slice();
@@ -694,11 +700,16 @@ function enexXmlToMdArray(stream, resources) {
}
} else if (n == 'span') {
if (isSpanWithStyle(nodeAttributes)) {
// console.debug('Found style(s) in span tag: %s', nodeAttributes.style);
state.spanAttributes.push(nodeAttributes);
if (isSpanStyleBold(nodeAttributes)) {
//console.debug('Applying style found in span tag: bold')
// console.debug('Applying style found in span tag: bold')
section.lines.push('**');
}
if (isSpanStyleItalic(nodeAttributes)) {
// console.debug('Applying style found in span tag: italic')
section.lines.push('*');
}
}
} else if (['font', 'sup', 'cite', 'abbr', 'small', 'tt', 'sub', 'colgroup', 'col', 'ins', 'caption', 'var', 'map', 'area'].indexOf(n) >= 0) {
// Inline tags that can be ignored in Markdown
@@ -884,9 +895,13 @@ function enexXmlToMdArray(stream, resources) {
let attributes = state.spanAttributes.pop();
if (isSpanWithStyle(attributes)) {
if (isSpanStyleBold(attributes)) {
//console.debug('Applying style found in span tag (closing): bold')
// console.debug('Applying style found in span tag (closing): bold')
section.lines.push('**');
}
if (isSpanStyleItalic(attributes)) {
// console.debug('Applying style found in span tag (closing): italic')
section.lines.push('*');
}
}
} else if (isIgnoredEndTag(n)) {
// Skip

View File

@@ -10,7 +10,7 @@ const { time } = require('lib/time-utils.js');
const Levenshtein = require('levenshtein');
const md5 = require('md5');
//const Promise = require('promise');
// const Promise = require('promise');
const fs = require('fs-extra');
function dateToTimestamp(s, zeroIfInvalid = false) {

View File

@@ -768,6 +768,9 @@ const mimeTypes = [
{ t: 'x-conference/x-cooltalk', e: ['ice'] },
];
// Note: if the list above is ever updated, make sure Markdown doesn't appear twice
mimeTypes.push({ t: 'text/markdown', e: ['md', 'markdown'] });
const mime = {
fromFileExtension(ext) {
ext = ext.toLowerCase();
@@ -780,6 +783,13 @@ const mime = {
return null;
},
fromFilename(name) {
if (!name) return null;
const splitted = name.trim().split('.');
if (splitted.length <= 1) return null;
return mime.fromFileExtension(splitted[splitted.length - 1]);
},
toFileExtension(mimeType) {
mimeType = mimeType.toLowerCase();
for (let i = 0; i < mimeTypes.length; i++) {

View File

@@ -238,11 +238,7 @@ class BaseItem extends BaseModel {
static serialize_format(propName, propValue) {
if (['created_time', 'updated_time', 'sync_time', 'user_updated_time', 'user_created_time'].indexOf(propName) >= 0) {
if (!propValue) return '';
propValue =
`${moment
.unix(propValue / 1000)
.utc()
.format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`;
propValue = `${moment.unix(propValue / 1000).utc().format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`;
} else if (['title_diff', 'body_diff'].indexOf(propName) >= 0) {
if (!propValue) return '';
propValue = JSON.stringify(propValue);

View File

@@ -481,6 +481,25 @@ class Note extends BaseItem {
return note;
}
static async duplicateMultipleNotes(noteIds, options = null){
/*
if options.uniqueTitle is true, a unique title for the duplicated file will be assigned.
*/
const ensureUniqueTitle = options && options.ensureUniqueTitle;
for(const noteId of noteIds){
const noteOptions = {};
//If ensureUniqueTitle is truthy, set the original note's name as root for the unique title.
if(ensureUniqueTitle){
const originalNote = await Note.load(noteId);
noteOptions.uniqueTitle = originalNote.title;
}
await Note.duplicate(noteId, noteOptions);
}
}
static async duplicate(noteId, options = null) {
const changes = options && options.changes;
const uniqueTitle = options && options.uniqueTitle;

View File

@@ -31,6 +31,12 @@ class Setting extends BaseModel {
// public for the mobile and desktop apps because they are handled separately in menus.
this.metadata_ = {
'clientId': {
value: '',
type: Setting.TYPE_STRING,
public: false,
},
'sync.target': {
value: SyncTargetRegistry.nameToId('dropbox'),
type: Setting.TYPE_INT,
@@ -219,6 +225,7 @@ class Setting extends BaseModel {
output[Setting.THEME_LIGHT] = _('Light');
output[Setting.THEME_DARK] = _('Dark');
if (platform !== 'mobile') {
output[Setting.THEME_DRACULA] = _('Dracula');
output[Setting.THEME_SOLARIZED_LIGHT] = _('Solarised Light');
output[Setting.THEME_SOLARIZED_DARK] = _('Solarised Dark');
}
@@ -400,6 +407,23 @@ class Setting extends BaseModel {
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, 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.') },
'export.pdfPageSize': { value: 'A4', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['desktop'], label: () => _('Page size for PDF export'), options: () => {
return {
'A4': _('A4'),
'Letter': _('Letter'),
'A3': _('A3'),
'A5': _('A5'),
'Tabloid': _('Tabloid'),
'Legal': _('Legal'),
};
}},
'export.pdfPageOrientation': { value: 'portrait', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['desktop'], label: () => _('Page orientation for PDF export'), options: () => {
return {
'portrait': _('Portrait'),
'landscape': _('Landscape'),
};
}},
'net.customCertificates': {
value: '',
@@ -884,6 +908,7 @@ Setting.THEME_LIGHT = 1;
Setting.THEME_DARK = 2;
Setting.THEME_SOLARIZED_LIGHT = 3;
Setting.THEME_SOLARIZED_DARK = 4;
Setting.THEME_DRACULA = 5;
Setting.FONT_DEFAULT = 0;
Setting.FONT_MENLO = 1;
@@ -915,6 +940,7 @@ Setting.constants_ = {
templateDir: '',
tempDir: '',
openDevTools: false,
syncVersion: 1,
};
Setting.autoSaveEnabled = true;

View File

@@ -186,7 +186,7 @@ class OneDriveApi {
let errorResponseText = await response.text();
let errorResponse = null;
try {
errorResponse = JSON.parse(errorResponseText); //await response.json();
errorResponse = JSON.parse(errorResponseText); // await response.json();
} catch (error) {
error.message = `OneDriveApi::exec: Cannot parse JSON error: ${errorResponseText} ${error.message}`;
throw error;
@@ -249,12 +249,12 @@ class OneDriveApi {
let response = await this.exec(method, path, query, data);
let errorResponseText = await response.text();
try {
let output = JSON.parse(errorResponseText); //await response.json();
let output = JSON.parse(errorResponseText); // await response.json();
return output;
} catch (error) {
error.message = `OneDriveApi::execJson: Cannot parse JSON: ${errorResponseText} ${error.message}`;
throw error;
//throw new Error('Cannot parse JSON: ' + text);
// throw new Error('Cannot parse JSON: ' + text);
}
}

View File

@@ -1,4 +1,4 @@
/*eslint no-useless-escape: 0*/
/* eslint no-useless-escape: 0*/
// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>

View File

@@ -1,4 +1,4 @@
/*eslint no-useless-escape: 0*/
/* eslint no-useless-escape: 0*/
const { _ } = require('lib/locale');

View File

@@ -459,7 +459,7 @@ const reducer = (state = defaultState, action) => {
}
}
//newNotes = Note.sortNotes(newNotes, state.notesOrder, newState.settings.uncompletedTodosOnTop);
// newNotes = Note.sortNotes(newNotes, state.notesOrder, newState.settings.uncompletedTodosOnTop);
newNotes = Note.sortNotes(newNotes, stateUtils.notesOrder(state.settings), newState.settings.uncompletedTodosOnTop);
newState = Object.assign({}, state);
newState.notes = newNotes;

View File

@@ -10,7 +10,7 @@ reg.syncTargets_ = {};
reg.logger = () => {
if (!reg.logger_) {
//console.warn('Calling logger before it is initialized');
// console.warn('Calling logger before it is initialized');
return new Logger();
}

View File

@@ -1,5 +1,6 @@
const htmlUtils = require('lib/htmlUtils');
const utils = require('./utils');
const noteStyle = require('./noteStyle');
class HtmlToHtml {
constructor(options) {
@@ -26,8 +27,11 @@ class HtmlToHtml {
}
});
const cssStrings = noteStyle(theme, options);
const styleHtml = `<style>${cssStrings.join('\n')}</style>`;
return {
html: html,
html: styleHtml + html,
cssFiles: [],
};
}

View File

@@ -119,7 +119,7 @@ function installRule(markdownIt, mdOptions, ruleOptions, context) {
return self.renderToken(tokens, idx, options);
};
markdownIt.renderer.rules.fence = function (tokens, idx, options, env, self) {
markdownIt.renderer.rules.fence = function(tokens, idx, options, env, self) {
const token = tokens[idx];
if (token.info !== 'fountain') return defaultRender(tokens, idx, options, env, self);
addContextAssets(context);

View File

@@ -7,6 +7,9 @@ const Setting = require('lib/models/Setting');
var katex = require('katex');
const katexCss = require('lib/csstojs/katex.css.js');
const md5 = require('md5');
const mhchemModule = require('./katex_mhchem.js');
katex = mhchemModule(katex);
// const style = `
// /*

File diff suppressed because it is too large Load Diff

View File

@@ -9,17 +9,23 @@ function installRule(markdownIt, mdOptions, ruleOptions) {
let href = utils.getAttr(token.attrs, 'href');
const resourceHrefInfo = urlUtils.parseResourceUrl(href);
const isResourceUrl = !!resourceHrefInfo;
const title = isResourceUrl ? utils.getAttr(token.attrs, 'title') : href;
let title = utils.getAttr(token.attrs, 'title', isResourceUrl ? '' : href);
let resourceIdAttr = '';
let icon = '';
let hrefAttr = '#';
let mime = '';
if (isResourceUrl) {
const resourceId = resourceHrefInfo.itemId;
const result = ruleOptions.resources[resourceId];
const resourceStatus = utils.resourceStatus(result);
if (result && result.item) {
title = utils.getAttr(token.attrs, 'title', result.item.title);
mime = result.item.mime;
}
if (result && resourceStatus !== 'ready') {
const icon = utils.resourceStatusFile(resourceStatus);
return `<a class="not-loaded-resource resource-status-${resourceStatus}" data-resource-id="${resourceId}">` + `<img src="data:image/svg+xml;utf8,${htmlentities(icon)}"/>`;
@@ -37,7 +43,7 @@ function installRule(markdownIt, mdOptions, ruleOptions) {
let js = `${ruleOptions.postMessageSyntax}(${JSON.stringify(href)}); return false;`;
if (hrefAttr.indexOf('#') === 0 && href.indexOf('#') === 0) js = ''; // If it's an internal anchor, don't add any JS since the webview is going to handle navigating to the right place
return `<a data-from-md ${resourceIdAttr} title='${htmlentities(title)}' href='${hrefAttr}' onclick='${js}'>${icon}`;
return `<a data-from-md ${resourceIdAttr} title='${htmlentities(title)}' href='${hrefAttr}' onclick='${js}' type='${htmlentities(mime)}'>${icon}`;
};
}

View File

@@ -4,6 +4,8 @@ const Alarm = require('lib/models/Alarm.js');
class AlarmService {
static setDriver(v) {
this.driver_ = v;
if (this.driver_.setService) this.driver_.setService(this);
}
static driver() {

View File

@@ -1,4 +1,5 @@
const notifier = require('node-notifier');
const { bridge } = require('electron').remote.require('./bridge');
class AlarmServiceDriverNode {
constructor(options) {
@@ -6,6 +7,15 @@ class AlarmServiceDriverNode {
// https://github.com/mikaelbr/node-notifier/issues/144#issuecomment-319324058
this.appName_ = options.appName;
this.notifications_ = {};
this.service_ = null;
}
setService(s) {
this.service_ = s;
}
logger() {
return this.service_.logger();
}
hasPersistentNotifications() {
@@ -31,15 +41,46 @@ class AlarmServiceDriverNode {
throw new Error(`Trying to create a notification from an invalid object: ${JSON.stringify(notification)}`);
}
const timeoutId = setTimeout(() => {
const o = {
appName: this.appName_,
title: notification.title,
};
if ('body' in notification) o.message = notification.body;
notifier.notify(o);
this.clearNotification(notification.id);
}, interval);
this.logger().info(`AlarmServiceDriverNode::scheduleNotification: Notification ${notification.id} with interval: ${interval}ms`);
if (this.notifications_[notification.id]) clearTimeout(this.notifications_[notification.id].timeoutId);
let timeoutId = null;
// Note: setTimeout will break for values larger than Number.MAX_VALUE - in which case the timer
// will fire immediately. So instead, if the interval is greater than a set max, reschedule after
// that max interval.
// https://stackoverflow.com/questions/3468607/why-does-settimeout-break-for-large-millisecond-delay-values/3468699
const maxInterval = 60 * 60 * 1000;
if (interval >= maxInterval) {
this.logger().info(`AlarmServiceDriverNode::scheduleNotification: Notification interval is greater than ${maxInterval}ms - will reschedule in ${maxInterval}ms`);
timeoutId = setTimeout(() => {
if (!this.notifications_[notification.id]) {
this.logger().info(`AlarmServiceDriverNode::scheduleNotification: Notification ${notification.id} has been deleted - not rescheduling it`);
return;
}
this.scheduleNotification(this.notifications_[notification.id]);
}, maxInterval);
} else {
timeoutId = setTimeout(() => {
const o = {
appID: this.appName_,
title: notification.title,
icon: `${bridge().electronApp().buildDir()}/icons/512x512.png`,
};
if ('body' in notification) o.message = notification.body;
this.logger().info('AlarmServiceDriverNode::scheduleNotification: Triggering notification:', o);
notifier.notify(o, (error, response) => {
this.logger().info('AlarmServiceDriverNode::scheduleNotification: node-notifier response:', error, response);
});
this.clearNotification(notification.id);
}, interval);
}
this.notifications_[notification.id] = Object.assign({}, notification);
this.notifications_[notification.id].timeoutId = timeoutId;

View File

@@ -273,7 +273,7 @@ class EncryptionService {
ks: 128, // Key size - "128 bits should be secure enough"
ts: 64, // ???
mode: 'ocb2', // The cipher mode is a standard for how to use AES and other algorithms to encrypt and authenticate your message. OCB2 mode is slightly faster and has more features, but CCM mode has wider support because it is not patented.
//"adata":"", // Associated Data - not needed?
// "adata":"", // Associated Data - not needed?
cipher: 'aes',
});
} catch (error) {

View File

@@ -8,6 +8,7 @@ const { fileExtension, basename } = require('lib/path-utils');
const spawn = require('child_process').spawn;
const chokidar = require('chokidar');
const { bridge } = require('electron').remote.require('./bridge');
const { time } = require('lib/time-utils.js');
class ExternalEditWatcher {
constructor() {
@@ -51,7 +52,11 @@ class ExternalEditWatcher {
if (!this.watcher_) {
this.watcher_ = this.chokidar_.watch(fileToWatch);
this.watcher_.on('all', async (event, path) => {
this.logger().debug(`ExternalEditWatcher: Event: ${event}: ${path}`);
// For now, to investigate the lost content issue when using an external editor,
// make all the debug statement to info() so that it goes to the log file.
// Those that were previous debug() statements are marked as "was_debug"
/* was_debug */ this.logger().info(`ExternalEditWatcher: Event: ${event}: ${path}`);
if (event === 'unlink') {
// File are unwatched in the stopWatching functions below. When we receive an unlink event
@@ -67,12 +72,37 @@ class ExternalEditWatcher {
const note = await Note.load(id);
if (!note) {
this.logger().warn(`Watched note has been deleted: ${id}`);
this.logger().warn(`ExternalEditWatcher: Watched note has been deleted: ${id}`);
this.stopWatching(id);
return;
}
const noteContent = await shim.fsDriver().readFile(path, 'utf-8');
let noteContent = await shim.fsDriver().readFile(path, 'utf-8');
// In some very rare cases, the "change" event is going to be emitted but the file will be empty.
// This is likely to be the editor that first clears the file, then writes the content to it, so if
// the file content is read very quickly after the change event, we'll get empty content.
// Usually, re-reading the content again will fix the issue and give back the file content.
// To replicate on Windows: associate Typora as external editor, and leave Ctrl+S pressed -
// it will keep on saving very fast and the bug should happen at some point.
// Below we re-read the file multiple times until we get the content, but in my tests it always
// work in the first try anyway. The loop is just for extra safety.
// https://github.com/laurent22/joplin/issues/1854
if (!noteContent) {
this.logger().warn(`ExternalEditWatcher: Watched note is empty - this is likely to be a bug and re-reading the note should fix it. Trying again... ${id}`);
for (let i = 0; i < 10; i++) {
noteContent = await shim.fsDriver().readFile(path, 'utf-8');
if (noteContent) {
this.logger().info(`ExternalEditWatcher: Note is now readable: ${id}`);
break;
}
await time.msleep(100);
}
if (!noteContent) this.logger().warn(`ExternalEditWatcher: Could not re-read note - user might have purposely deleted note content: ${id}`);
}
const updatedNote = await Note.unserializeForEdit(noteContent);
updatedNote.id = id;
updatedNote.parent_id = note.parent_id;
@@ -197,7 +227,7 @@ class ExternalEditWatcher {
const iid = setInterval(() => {
if (subProcess && subProcess.pid) {
this.logger().debug(`Started editor with PID ${subProcess.pid}`);
/* was_debug */ this.logger().info(`Started editor with PID ${subProcess.pid}`);
clearInterval(iid);
resolve();
}
@@ -273,7 +303,7 @@ class ExternalEditWatcher {
return;
}
this.logger().debug(`ExternalEditWatcher: Update note file: ${note.id}`);
/* was_debug */ this.logger().info(`ExternalEditWatcher: Update note file: ${note.id}`);
// When the note file is updated programmatically, we skip the next change event to
// avoid update loops. We only want to listen to file changes made by the user.

View File

@@ -13,7 +13,8 @@ const { toTitleCase } = require('lib/string-utils');
class InteropService {
constructor() {
this.modules_ = null; }
this.modules_ = null;
}
modules() {
if (this.modules_) return this.modules_;

View File

@@ -1,5 +1,7 @@
/* eslint @typescript-eslint/no-unused-vars: 0, no-unused-vars: ["error", { "argsIgnorePattern": ".*" }], */
const Setting = require('lib/models/Setting');
class InteropService_Exporter_Base {
async init(destDir) {}
async processItem(ItemClass, item) {}
@@ -24,7 +26,7 @@ class InteropService_Exporter_Base {
async temporaryDirectory_(createIt) {
const md5 = require('md5');
const tempDir = `${require('os').tmpdir()}/${md5(Math.random() + Date.now())}`;
const tempDir = `${Setting.value('tempDir')}/${md5(Math.random() + Date.now())}`;
if (createIt) await require('fs-extra').mkdirp(tempDir);
return tempDir;
}

View File

@@ -1,3 +1,5 @@
const Setting = require('lib/models/Setting');
class InteropService_Importer_Base {
setMetadata(md) {
this.metadata_ = md;
@@ -16,7 +18,7 @@ class InteropService_Importer_Base {
async temporaryDirectory_(createIt) {
const md5 = require('md5');
const tempDir = `${require('os').tmpdir()}/${md5(Math.random() + Date.now())}`;
const tempDir = `${Setting.value('tempDir')}/${md5(Math.random() + Date.now())}`;
if (createIt) await require('fs-extra').mkdirp(tempDir);
return tempDir;
}

View File

@@ -19,8 +19,7 @@ class ResourceService extends BaseService {
let foundNoteWithEncryption = false;
while (true) {
const changes = await ItemChange.modelSelectAll(
`
const changes = await ItemChange.modelSelectAll(`
SELECT id, item_id, type
FROM item_changes
WHERE item_type = ?
@@ -28,7 +27,7 @@ class ResourceService extends BaseService {
ORDER BY id ASC
LIMIT 10
`,
[BaseModel.TYPE_NOTE, Setting.value('resourceService.lastProcessedChangeId')]
[BaseModel.TYPE_NOTE, Setting.value('resourceService.lastProcessedChangeId')]
);
if (!changes.length) break;
@@ -54,16 +53,16 @@ class ResourceService extends BaseService {
if (change.type === ItemChange.TYPE_CREATE || change.type === ItemChange.TYPE_UPDATE) {
const note = noteById(change.item_id);
if (note.encryption_applied) {
// If we hit an encrypted note, abort processing for now.
// Note will eventually get decrypted and processing can resume then.
// This is a limitation of the change tracking system - we cannot skip a change
// and keep processing the rest since we only keep track of "lastProcessedChangeId".
foundNoteWithEncryption = true;
break;
}
if (note) {
if (note.encryption_applied) {
// If we hit an encrypted note, abort processing for now.
// Note will eventually get decrypted and processing can resume then.
// This is a limitation of the change tracking system - we cannot skip a change
// and keep processing the rest since we only keep track of "lastProcessedChangeId".
foundNoteWithEncryption = true;
break;
}
await this.setAssociatedResources_(note);
} else {
this.logger().warn(`ResourceService::indexNoteResources: A change was recorded for a note that has been deleted: ${change.item_id}`);

View File

@@ -354,12 +354,28 @@ class Api {
return options;
}
defaultLoadOptions_(request) {
const options = {};
const fields = this.fields_(request, []);
if (fields.length) options.fields = fields;
return options;
}
async action_notes(request, id = null, link = null) {
this.checkToken_(request);
if (request.method === 'GET') {
if (link && link === 'tags') {
return Tag.tagsByNoteId(id);
} else if (link && link === 'resources') {
const note = await Note.load(id);
const resourceIds = await Note.linkedResourceIds(note.body);
const output = [];
const loadOptions = this.defaultLoadOptions_(request);
for (let resourceId of resourceIds) {
output.push(await Resource.load(resourceId, loadOptions));
}
return output;
} else if (link) {
throw new ErrorNotFound();
}
@@ -552,7 +568,7 @@ class Api {
return output;
}
async downloadImage_(url /*, allowFileProtocolImages */) {
async downloadImage_(url /* , allowFileProtocolImages */) {
const tempDir = Setting.value('tempDir');
const isDataUrl = url && url.toLowerCase().indexOf('data:') === 0;

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