1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-27 20:29:45 +02:00

Compare commits

...

31 Commits

Author SHA1 Message Date
Laurent Cozic
1e3bd937ed Android release v1.3.10 2020-10-29 11:34:10 +00:00
Laurent Cozic
0f6932f1e8 Clipper release v1.3.1 2020-10-29 11:28:21 +00:00
Laurent Cozic
cab98776db Electron release v1.3.10 2020-10-29 11:20:45 +00:00
Laurent Cozic
fbc1e3ed3b Merge branch 'dev' into release-1.3 2020-10-29 11:18:32 +00:00
Ji-Hyeon Gim
805d16abda All: Translation: Update ko.po (#3995)
It updates fuzzy translations for Korean.

Signed-off-by: Ji-Hyeon Gim <potatogim@potatogim.net>
2020-10-29 11:18:01 +00:00
Eduardo Braga
f133229287 Add some missing translations to pt_BR.po (#3994) 2020-10-29 11:16:18 +00:00
Mario Campo
8f4031572a Update es_ES.po (#3978)
Several corrections in spanish language
2020-10-29 11:15:53 +00:00
Laurent Cozic
d25fa796c0 Api: Added service to access resource external editing 2020-10-29 11:09:18 +00:00
Laurent Cozic
089d6a5c9e All: Fixes #3993: Fix slow Katex rendering when there are many global definitions 2020-10-29 10:44:48 +00:00
Laurent Cozic
3f83355d9f Clipper: Fixes #3984: Images from some website were not being downloaded 2020-10-29 10:16:31 +00:00
Laurent Cozic
40380e3066 Merge branch 'release-1.3' of github.com:laurent22/joplin into release-1.3 2020-10-29 10:15:08 +00:00
Laurent Cozic
a6748bafb3 All: Fixes #3992: Update highlight.js to fix freeze for certain code blocks 2020-10-28 17:31:54 +00:00
Laurent Cozic
b52f6eb77c All: Fixes #3955: Fixed sync issue when importing ENEX files that contain new line characters in the source URL attribute 2020-10-28 17:21:41 +00:00
Laurent Cozic
98c933fdb7 All: Fixed OneDrive authentication 2020-10-28 15:50:34 +00:00
Laurent Cozic
ece7ffadd6 Desktop: Fixes #3986: Handle gzipped CSS files when importing from clipper 2020-10-28 15:47:36 +00:00
Laurent Cozic
591bceb8ef Update mermaid 2020-10-28 12:10:35 +00:00
Laurent Cozic
04cfd07176 macOS: Regression: Restore Edit menu in config screens so that Copy/Cut/Paste shortcuts work 2020-10-28 11:23:57 +00:00
Laurent Cozic
db2282a351 Desktop: Fix syntax of imported resources when importing ENEX as HTML 2020-10-28 11:11:04 +00:00
Laurent Cozic
0ec3d6ca9d Clipper: Upgraded clipper to support API pagination
This version of the clipper will support both new and old Joplin
clients, so as to ease the transition.
2020-10-27 00:38:39 +00:00
Laurent Cozic
442b7ce0d3 litner 2020-10-26 23:19:52 +00:00
Laurent Cozic
6a068a90b2 Desktop: Regression: Keyboard shortcut would not save in some cases 2020-10-25 17:46:41 +00:00
Laurent Cozic
9a6f6c8b39 Desktop: Regression: Restore "New sub-notebook" command 2020-10-25 17:29:52 +00:00
Laurent Cozic
52d5c32950 Plugins: Add the openNote, openFolder and openTag commands 2020-10-25 17:22:59 +00:00
Laurent Cozic
de47cff86d Fixed case 2020-10-24 12:07:48 +01:00
Laurent Cozic
a459174f98 Desktop: Fix: Command Palette click did not work 2020-10-24 11:46:02 +01:00
Laurent Cozic
75d5aa3a77 Tools: Fixed linter errors 2020-10-24 00:14:30 +01:00
Laurent Cozic
c254ca524f CLI v1.3.3 2020-10-23 17:01:13 +01:00
Laurent Cozic
51934b8d8d Cli: Added missing "immer" package 2020-10-23 17:00:20 +01:00
Laurent Cozic
a5dd686bb2 CLI v1.3.2 2020-10-23 16:58:28 +01:00
Laurent Cozic
4cbfd04522 Cli: Trying to fix build 2020-10-23 16:56:34 +01:00
Laurent Cozic
6d5d9323bd CLI v1.3.1 2020-10-23 16:04:34 +01:00
69 changed files with 562 additions and 227 deletions

View File

@@ -105,7 +105,11 @@ ElectronClient/gui/MainScreen/commands/hideModalMessage.js
ElectronClient/gui/MainScreen/commands/moveToFolder.js
ElectronClient/gui/MainScreen/commands/newFolder.js
ElectronClient/gui/MainScreen/commands/newNote.js
ElectronClient/gui/MainScreen/commands/newSubFolder.js
ElectronClient/gui/MainScreen/commands/newTodo.js
ElectronClient/gui/MainScreen/commands/openFolder.js
ElectronClient/gui/MainScreen/commands/openNote.js
ElectronClient/gui/MainScreen/commands/openTag.js
ElectronClient/gui/MainScreen/commands/print.js
ElectronClient/gui/MainScreen/commands/renameFolder.js
ElectronClient/gui/MainScreen/commands/renameTag.js

4
.gitignore vendored
View File

@@ -99,7 +99,11 @@ ElectronClient/gui/MainScreen/commands/hideModalMessage.js
ElectronClient/gui/MainScreen/commands/moveToFolder.js
ElectronClient/gui/MainScreen/commands/newFolder.js
ElectronClient/gui/MainScreen/commands/newNote.js
ElectronClient/gui/MainScreen/commands/newSubFolder.js
ElectronClient/gui/MainScreen/commands/newTodo.js
ElectronClient/gui/MainScreen/commands/openFolder.js
ElectronClient/gui/MainScreen/commands/openNote.js
ElectronClient/gui/MainScreen/commands/openTag.js
ElectronClient/gui/MainScreen/commands/print.js
ElectronClient/gui/MainScreen/commands/renameFolder.js
ElectronClient/gui/MainScreen/commands/renameTag.js

View File

@@ -48,7 +48,11 @@ ElectronClient/gui/MainScreen/commands/hideModalMessage.js
ElectronClient/gui/MainScreen/commands/moveToFolder.js
ElectronClient/gui/MainScreen/commands/newFolder.js
ElectronClient/gui/MainScreen/commands/newNote.js
ElectronClient/gui/MainScreen/commands/newSubFolder.js
ElectronClient/gui/MainScreen/commands/newTodo.js
ElectronClient/gui/MainScreen/commands/openFolder.js
ElectronClient/gui/MainScreen/commands/openNote.js
ElectronClient/gui/MainScreen/commands/openTag.js
ElectronClient/gui/MainScreen/commands/print.js
ElectronClient/gui/MainScreen/commands/renameFolder.js
ElectronClient/gui/MainScreen/commands/renameTag.js

View File

@@ -22,4 +22,5 @@ yarn-error.log
tests/support/dropbox-auth.txt
tests/support/nextcloud-auth.json
tests/support/onedrive-auth.txt
build/
build/
patches/

View File

@@ -17,12 +17,23 @@ tasks.prepareBuild = {
excluded: ['node_modules'],
});
await utils.copyDir(`${__dirname}/locales-build`, `${buildDir}/locales`);
await utils.copyDir(`${__dirname}/../patches`, `${buildDir}/patches`);
await tasks.copyLib.fn();
await utils.copyFile(`${__dirname}/package.json`, `${buildDir}/package.json`);
await utils.copyFile(`${__dirname}/package-lock.json`, `${buildDir}/package-lock.json`);
await utils.copyFile(`${__dirname}/gulpfile.js`, `${buildDir}/gulpfile.js`);
// Import all the patches inside the CliClient directory
// and build file. Needs to be in CliClient dir for when running
// in dev mode, and in build dir for production.
const localPatchDir = `${buildDir}/patches`;
await fs.remove(localPatchDir);
await fs.mkdirp(localPatchDir);
await utils.copyDir(`${__dirname}/../patches/shared`, `${localPatchDir}`, { delete: false });
await utils.copyDir(`${__dirname}/../patches/node`, `${localPatchDir}`, { delete: false });
await fs.remove(`${__dirname}/patches`);
await utils.copyDir(`${localPatchDir}`, `${__dirname}/patches`);
const packageRaw = await fs.readFile(`${buildDir}/package.json`);
const package = JSON.parse(packageRaw.toString());
package.scripts.postinstall = 'patch-package';

View File

@@ -9,12 +9,12 @@
# Germán Martín <gmag11@gmail.com>, 2019.
# Fernando Pindado <fpindado@gmail.com>, 2020.
# Andros Fenollosa <andros@fenollosa.email>, 2020.
#
# Mario Campo <mario.campo@gmail.com>, 2020
msgid ""
msgstr ""
"Project-Id-Version: Joplin-CLI 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: Andros Fenollosa <andros@fenollosa.email>\n"
"Last-Translator: Mario Campo <mario.campo@gmail.com>\n"
"Language-Team: Spanish <lucas.vieites@gmail.com>\n"
"Language: es_ES\n"
"MIME-Version: 1.0\n"
@@ -279,13 +279,13 @@ msgstr "Las notas han sido importadas: %s"
#: ElectronClient/gui/ConfigScreen.min.js:84
#: ElectronClient/gui/ConfigScreen/ConfigScreen.js:99
msgid "This will open a new screen. Save your current changes?"
msgstr "Esto abrirá una nueva pantalla. ¿Quieres salvar los cambios actuales?"
msgstr "Esto abrirá una nueva pantalla. ¿Quieres guardar los cambios actuales?"
#: ElectronClient/gui/ConfigScreen.min.js:172
#: ElectronClient/gui/ConfigScreen/ConfigScreen.js:162
#: ReactNativeClient/lib/components/screens/config.js:307
msgid "Check synchronisation configuration"
msgstr "Comprobar sincronización"
msgstr "Comprobar sincronización de la configuración"
#: ElectronClient/gui/ConfigScreen.min.js:181
#: ElectronClient/gui/ConfigScreen/ConfigScreen.js:167
@@ -1050,7 +1050,7 @@ msgstr "Descifrando elementos: %d/%d"
#: ReactNativeClient/lib/components/side-menu-content.js:330
#, javascript-format
msgid "Fetching resources: %d/%d"
msgstr "Obteniendo refuersos: %d/%d"
msgstr "Obteniendo recursos: %d/%d"
#: ElectronClient/gui/SideBar/commands/focusElementSideBar.js:16
msgid "Sidebar"

View File

@@ -15,6 +15,8 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.4.1\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
#: ElectronClient/services/plugins/UserWebviewDialogButtonBar.js:20
#: ElectronClient/checkForUpdates.js:139
@@ -121,14 +123,14 @@ msgid "Could not export notes: %s"
msgstr "노트를 내보낼 수 없습니다: %s"
#: ElectronClient/plugins/GotoAnything.js:431
#, fuzzy
msgid ""
"Type a note title or part of its content to jump to it. Or type # followed "
"by a tag name, or @ followed by a notebook name. Or type : to search for "
"commands."
msgstr ""
"노트 제목을 적거나 혹은 건너뛰세요. 혹은 #으로 시작하는 태그 이름이나, @로 시"
"작하는 노트북 이름을 적으세요."
"노트 제목이나 내용의 일부를 입력하여 바로 이동하세요. 혹은 #으로 시작하는 태"
"그 이름이나 @로 시작하는 노트북 이름을 입력하거나, :을 입력하여 명령을 검색하"
"세요.\""
#: ElectronClient/plugins/GotoAnything.js:456
#: ElectronClient/plugins/GotoAnything.min.js:499
@@ -138,9 +140,8 @@ msgstr "가고자 하는 곳으로 이동..."
#: ElectronClient/plugins/GotoAnything.js:463
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#, fuzzy
msgid "Command palette"
msgstr "명령"
msgstr "명령 팔레트"
#: ElectronClient/plugins/GotoAnything.min.js:459
msgid ""
@@ -2709,11 +2710,14 @@ msgid ""
"\n"
"You may turn off this option at any time in the Configuration screen."
msgstr ""
"노트에 지리적 위치 정보를 포함하기 위해서는 위치 정보에 접근이 필요하고, 이"
"를 위해선 권한이 요구됩니다.\n"
"\n"
"설정 화면에서 언제든지 이 설정을 끌 수 있습니다."
#: ReactNativeClient/lib/components/screens/Note.js:341
#, fuzzy
msgid "Permission needed"
msgstr "카메라 사용 허가"
msgstr "권한 요구"
#: ReactNativeClient/lib/components/screens/Note.js:501
#: ReactNativeClient/lib/shim-init-node.js:91
@@ -2971,9 +2975,8 @@ msgstr ""
"다:"
#: ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnResourceLongPress.js:28
#, fuzzy
msgid "Open"
msgstr "열기..."
msgstr "열기"
#: ReactNativeClient/lib/components/note-list.js:97
msgid "You currently have no notebooks."
@@ -3182,9 +3185,8 @@ msgid "AWS S3 bucket"
msgstr "AWS S3 버킷"
#: ReactNativeClient/lib/models/Setting.js:226
#, fuzzy
msgid "AWS S3 URL"
msgstr "AWS S3"
msgstr "AWS S3 URL"
#: ReactNativeClient/lib/models/Setting.js:237
msgid "AWS key"

View File

@@ -141,7 +141,7 @@ msgstr "Ir para qualquer coisa..."
#: ElectronClient/plugins/GotoAnything.js:463
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
msgid "Command palette"
msgstr ""
msgstr "Paleta de Comandos"
#: ElectronClient/plugins/GotoAnything.min.js:459
msgid ""
@@ -549,6 +549,8 @@ msgid ""
"The attachments will no longer be watched when you switch to a different "
"note."
msgstr ""
"Os anexos não serão mais observados quando você mudar para uma nota"
"diferente."
#: ElectronClient/gui/NoteEditor/NoteEditor.js:387
#, javascript-format
@@ -665,6 +667,9 @@ msgid ""
"may take a few minutes to complete and the app needs to be restarted. To "
"proceed please click on the link."
msgstr ""
"O alvo da sincroniação precisa ser atualizado antes que o Joplin possa sincronizar. A operação"
"pode levar alguns minutos para completar e o app terá que ser reiniciado. Para"
"proceder, por favor, clique neste link."
#: ElectronClient/gui/MainScreen/MainScreen.js:416
#: ElectronClient/gui/MainScreen/MainScreen.min.js:306
@@ -1411,13 +1416,15 @@ msgstr "Anexos da nota"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
msgid "Press the shortcut"
msgstr ""
msgstr "Digite o atalho"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
msgid ""
"Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the "
"shortcut."
msgstr ""
"Digite o atalho e então aperte ENTER. Ou, pressione BARRA DE ESPAÇO para limpar o"
"atalho"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:63
#: ReactNativeClient/lib/services/KeymapService.js:144
@@ -1427,7 +1434,7 @@ msgstr "Erro"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:126
msgid "Command"
msgstr ""
msgstr "Command"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:127
#, fuzzy
@@ -1487,6 +1494,7 @@ msgstr "Estatísticas"
msgid ""
"The app is now going to close. Please relaunch it to complete the process."
msgstr ""
"O app irá fechar agora. Por favor, reabra-o para completar o processo."
#: ElectronClient/app.js:340
#, javascript-format
@@ -1514,7 +1522,7 @@ msgstr "Encerrar edição externa"
#: ElectronClient/commands/toggleExternalEditing.js:37
msgid "Stop"
msgstr ""
msgstr "Parar"
#: ElectronClient/commands/stopExternalEditing.js:18
msgid "Stop external editing"
@@ -1741,7 +1749,7 @@ msgstr ""
#: CliClient/app/command-sync.js:35
msgid "Upgrade the sync target to the latest version."
msgstr ""
msgstr "Atualizar o alvo de sincronização para a última versão."
#: CliClient/app/command-sync.js:105
#, javascript-format

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "1.3.0",
"version": "1.3.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -23,9 +23,9 @@
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="
},
"abab": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg=="
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
"integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
},
"abbrev": {
"version": "1.1.1",
@@ -33,9 +33,9 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
"integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA=="
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
},
"acorn-globals": {
"version": "4.3.4",
@@ -47,9 +47,9 @@
},
"dependencies": {
"acorn": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA=="
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
}
}
},
@@ -2964,9 +2964,9 @@
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
},
"highlight.js": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.1.tgz",
"integrity": "sha512-b4L09127uVa+9vkMgPpdUQP78ickGbHEQTWeBrQFTJZ4/n2aihWOGS0ZoUqAwjVmfjhq/C76HRzkqwZhK4sBbg=="
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.2.1.tgz",
"integrity": "sha512-A+sckVPIb9zQTUydC9lpRX1qRFO/N0OKEh0NwIr65ckvWA/oMY8v9P3+kGRK3w2ULSh9E8v5MszXafodQ6039g=="
},
"homedir-polyfill": {
"version": "1.0.3",
@@ -3227,6 +3227,11 @@
"file-type": "^4.1.0"
}
},
"immer": {
"version": "7.0.14",
"resolved": "https://registry.npmjs.org/immer/-/immer-7.0.14.tgz",
"integrity": "sha512-BxCs6pJwhgSEUEOZjywW7OA8DXVzfHjkBelSEl0A+nEu0+zS4cFVdNOONvt55N4WOm8Pu4xqSPYxhm1Lv2iBBA=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -3650,9 +3655,9 @@
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
},
"joplin-turndown": {
"version": "4.0.29",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.29.tgz",
"integrity": "sha512-rVGu8u4TpSRETo59/jiVW9iaXnpdxxpBHjb7nyCflkDfWhg1Kska4uagBQGw7cD2yxw7mB2YUIB/fAgtlIzcDQ==",
"version": "4.0.30",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.30.tgz",
"integrity": "sha512-OrGdNTsjI6/cbx/es9Hl0YI3YTql4SopduFcYCnWTZgqT0SJqILnF2JQxSNnbPnkSDIIRdNOG4+iNzlY6bS1nw==",
"requires": {
"css": "^2.2.4",
"html-entities": "^1.2.1",
@@ -5568,13 +5573,6 @@
"integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
"requires": {
"lodash": "^4.17.19"
},
"dependencies": {
"lodash": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
}
}
},
"request-promise-native": {

View File

@@ -6,7 +6,7 @@
"scripts": {
"test": "gulp buildTests -L && node node_modules/jasmine/bin/jasmine.js --fail-fast=true --config=tests/support/jasmine.json",
"test-ci": "gulp buildTests -L && node node_modules/jasmine/bin/jasmine.js --config=tests/support/jasmine.json",
"postinstall": "npm run build && patch-package --patch-dir ../patches/shared && patch-package --patch-dir ../patches/node",
"postinstall": "npm run build && patch-package --patch-dir ./patches",
"build": "gulp build",
"start": "gulp build -L && node 'build/main.js' --stack-trace-enabled --log-level debug --env dev"
},
@@ -28,7 +28,7 @@
],
"owner": "Laurent Cozic"
},
"version": "1.3.0",
"version": "1.3.3",
"bin": {
"joplin": "./main.js"
},
@@ -52,13 +52,14 @@
"font-awesome-filetypes": "^2.1.0",
"form-data": "^2.1.4",
"fs-extra": "^5.0.0",
"highlight.js": "10.1.1",
"highlight.js": "^10.2.1",
"html-entities": "^1.2.1",
"html-minifier": "^3.5.15",
"htmlparser2": "^4.1.0",
"image-data-uri": "^2.0.0",
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.29",
"immer": "^7.0.14",
"joplin-turndown": "^4.0.30",
"joplin-turndown-plugin-gfm": "^1.0.12",
"json-stringify-safe": "^5.0.1",
"jssha": "^2.3.0",

View File

@@ -1,5 +1,5 @@
<en-note>
<div><a href="joplin://21ca2b948f222a38802940ec7e2e5de3" hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:pointer;" alt="attachment-1">attachment-1</a></div>
<div><a href=":/21ca2b948f222a38802940ec7e2e5de3" hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:pointer;" alt="attachment-1">attachment-1</a></div>
<div>
<br>
</div>

View File

@@ -0,0 +1 @@
<a href="https://images.macrumors.com/filters:quality(90)/article.html"/>testing</a>

View File

@@ -0,0 +1 @@
[testing](https://images.macrumors.com/filters:quality%2890%29/article.html)

View File

@@ -0,0 +1 @@
<img src="https://images.macrumors.com/filters:quality(90)/article/test.jpg?high"/>

View File

@@ -0,0 +1 @@
![](https://images.macrumors.com/filters:quality%2890%29/article/test.jpg?high)

View File

@@ -0,0 +1 @@
<img src="https://example.com/test.jpg" title="hello"/>

View File

@@ -0,0 +1 @@
![](https://example.com/test.jpg "hello")

View File

@@ -0,0 +1 @@
<img src="https://example.com/test.jpg" title='hello &amp; "(ouch)"'/>

View File

@@ -0,0 +1 @@
![](https://example.com/test.jpg "hello & &quot;&#40;ouch&#41;&quot;")

View File

@@ -104,4 +104,14 @@ describe('models_BaseItem', function() {
expect(noteAfter).toEqual(noteBefore);
}));
it('should serialize and unserialize properties that contain new lines', asyncTest(async () => {
const note = await Note.save({ title: 'note', source_url: '\nhttps://joplinapp.org/\n' });
const noteBefore = await Note.load(note.id);
const serialized = await Note.serialize(noteBefore);
const noteAfter = await Note.unserialize(serialized);
expect(noteAfter).toEqual(noteBefore);
}));
});

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Joplin Web Clipper [DEV]",
"version": "1.3.0",
"version": "1.3.1",
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
"homepage_url": "https://joplinapp.org",
"content_security_policy": "script-src 'self'; object-src 'self'",

View File

@@ -55,7 +55,7 @@
},
"scripts": {
"start": "node scripts/start.js",
"build": "SKIP_PREFLIGHT_CHECK=true node scripts/build.js",
"build": "node scripts/build.js SKIP_PREFLIGHT_CHECK",
"test": "node scripts/test.js --env=jsdom",
"watch": "cra-build-watch",
"postinstall": "node postinstall.js && npm run build"

View File

@@ -1,5 +1,9 @@
'use strict';
if (process.argv && process.argv.indexOf('SKIP_PREFLIGHT_CHECK') >= 0) {
process.env.SKIP_PREFLIGHT_CHECK = 'true';
}
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';

View File

@@ -148,10 +148,10 @@ class Bridge {
this.dispatch({ type: 'CLIPPER_SERVER_SET', foundState: 'found', port: state.port });
const folders = await this.folderTree();
this.dispatch({ type: 'FOLDERS_SET', folders: folders });
this.dispatch({ type: 'FOLDERS_SET', folders: folders.items ? folders.items : folders });
const tags = await this.clipperApiExec('GET', 'tags');
this.dispatch({ type: 'TAGS_SET', tags: tags });
this.dispatch({ type: 'TAGS_SET', tags: tags.items ? tags.items : tags });
bridge().restoreState();
return;
@@ -245,7 +245,7 @@ class Bridge {
}
async folderTree() {
return this.clipperApiExec('GET', 'folders');
return this.clipperApiExec('GET', 'folders', { as_tree: 1 });
}
async storageSet(keys) {

View File

@@ -46,6 +46,7 @@ const commands = [
require('./gui/MainScreen/commands/moveToFolder'),
require('./gui/MainScreen/commands/newNote'),
require('./gui/MainScreen/commands/newFolder'),
require('./gui/MainScreen/commands/newSubFolder'),
require('./gui/MainScreen/commands/newTodo'),
require('./gui/MainScreen/commands/print'),
require('./gui/MainScreen/commands/renameFolder'),
@@ -61,6 +62,9 @@ const commands = [
require('./gui/MainScreen/commands/toggleSideBar'),
require('./gui/MainScreen/commands/toggleVisiblePanes'),
require('./gui/MainScreen/commands/toggleEditors'),
require('./gui/MainScreen/commands/openNote'),
require('./gui/MainScreen/commands/openFolder'),
require('./gui/MainScreen/commands/openTag'),
require('./gui/NoteEditor/commands/focusElementNoteBody'),
require('./gui/NoteEditor/commands/focusElementNoteTitle'),
require('./gui/NoteEditor/commands/showLocalSearch'),

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { useState } from 'react';
import KeymapService, { KeymapItem } from '../../lib/services/KeymapService';
import KeymapService, { KeymapItem } from 'lib/services/KeymapService';
import { ShortcutRecorder } from './ShortcutRecorder';
import getLabel from './utils/getLabel';
import useKeymap from './utils/useKeymap';
@@ -106,7 +106,7 @@ export const KeymapConfigScreen = ({ themeId }: KeymapConfigScreenProps) => {
const renderError = (error: Error) => {
return (
<div style={styles.warning}>
<div style={{ ...styles.warning, position: 'absolute', top: 0 }}>
<p style={styles.text}>
<span>
{error.message}

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { useState, useEffect, KeyboardEvent } from 'react';
import KeymapService from '../../lib/services/KeymapService';
import KeymapService from 'lib/services/KeymapService';
import styles_ from './styles';
import { _ } from 'lib/locale';
@@ -41,7 +41,7 @@ export const ShortcutRecorder = ({ onSave, onReset, onCancel, onError, initialAc
}
}, [accelerator]);
const handleKeydown = (event: KeyboardEvent<HTMLDivElement>) => {
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
event.preventDefault();
const newAccelerator = keymapService.domToElectronAccelerator(event);
@@ -64,7 +64,7 @@ export const ShortcutRecorder = ({ onSave, onReset, onCancel, onError, initialAc
<input
value={accelerator}
placeholder={_('Press the shortcut')}
onKeyDown={handleKeydown}
onKeyDown={handleKeyDown}
style={styles.recorderInput}
title={_('Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the shortcut.')}
readOnly

View File

@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import KeymapService, { KeymapItem } from '../../../lib/services/KeymapService';
import KeymapService, { KeymapItem } from 'lib/services/KeymapService';
const keymapService = KeymapService.instance();
@@ -70,7 +70,8 @@ const useKeymap = (): [
await keymapService.saveCustomKeymap();
setKeymapError(null);
} catch (err) {
setKeymapError(err);
const error = new Error(`Could not save file: ${err.message}`);
setKeymapError(error);
}
}

View File

@@ -48,6 +48,7 @@ const commands = [
require('./commands/moveToFolder'),
require('./commands/newNote'),
require('./commands/newFolder'),
require('./commands/newSubFolder'),
require('./commands/newTodo'),
require('./commands/print'),
require('./commands/renameFolder'),
@@ -63,6 +64,9 @@ const commands = [
require('./commands/toggleNoteList'),
require('./commands/toggleSideBar'),
require('./commands/toggleVisiblePanes'),
require('./commands/openNote'),
require('./commands/openFolder'),
require('./commands/openTag'),
];
class MainScreenComponent extends React.Component<any, any> {

View File

@@ -0,0 +1,17 @@
import CommandService, { CommandContext, CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
name: 'newSubFolder',
label: () => _('New sub-notebook'),
iconName: 'fa-book',
};
export const runtime = ():CommandRuntime => {
return {
execute: async (context:CommandContext, parentId:string = null) => {
parentId = parentId || context.state.selectedFolderId;
return CommandService.instance().execute('newFolder', parentId);
},
};
};

View File

@@ -0,0 +1,16 @@
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
export const declaration:CommandDeclaration = {
name: 'openFolder',
};
export const runtime = ():CommandRuntime => {
return {
execute: async (context:CommandContext, folderId:string) => {
context.dispatch({
type: 'FOLDER_SELECT',
id: folderId,
});
},
};
};

View File

@@ -0,0 +1,26 @@
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
const Note = require('lib/models/Note');
const Folder = require('lib/models/Folder');
export const declaration:CommandDeclaration = {
name: 'openNote',
};
export const runtime = ():CommandRuntime => {
return {
execute: async (context:CommandContext, noteId:string, hash:string = null) => {
const note = await Note.load(noteId);
if (!note) throw new Error(`No such note: ${noteId}`);
const folder = await Folder.load(note.parent_id);
if (!folder) throw new Error(`Note parent notebook does not exist: ${JSON.stringify(note)}`);
context.dispatch({
type: 'FOLDER_AND_NOTE_SELECT',
folderId: folder.id,
noteId: note.id,
hash,
});
},
};
};

View File

@@ -0,0 +1,16 @@
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
export const declaration:CommandDeclaration = {
name: 'openTag',
};
export const runtime = ():CommandRuntime => {
return {
execute: async (context:CommandContext, tagId:string) => {
context.dispatch({
type: 'TAG_SELECT',
id: tagId,
});
},
};
};

View File

@@ -95,6 +95,7 @@ const commandNames:string[] = [
'newNote',
'newTodo',
'newFolder',
'newSubFolder',
'print',
'synchronize',
'textCopy',
@@ -301,6 +302,7 @@ function useMenu(props:Props) {
const newNoteItem = menuItemDic.newNote;
const newTodoItem = menuItemDic.newTodo;
const newFolderItem = menuItemDic.newFolder;
const newSubFolderItem = menuItemDic.newSubFolder;
const printItem = menuItemDic.print;
toolsItemsFirst.push(syncStatusItem, {
@@ -423,7 +425,9 @@ function useMenu(props:Props) {
},
shim.isMac() ? noItem : newNoteItem,
shim.isMac() ? noItem : newTodoItem,
shim.isMac() ? noItem : newFolderItem, {
shim.isMac() ? noItem : newFolderItem,
shim.isMac() ? noItem : newSubFolderItem,
{
type: 'separator',
visible: shim.isMac() ? false : true,
}, {
@@ -473,7 +477,9 @@ function useMenu(props:Props) {
submenu: [
newNoteItem,
newTodoItem,
newFolderItem, {
newFolderItem,
newSubFolderItem,
{
label: _('Close Window'),
platforms: ['darwin'],
accelerator: shim.isMac() && keymapService.getAccelerator('closeWindow'),
@@ -788,6 +794,15 @@ function useMenu(props:Props) {
label: _('&File'),
submenu: [quitMenuItem],
},
{
label: _('&Edit'),
submenu: [
menuItemDic.textCopy,
menuItemDic.textCut,
menuItemDic.textPaste,
menuItemDic.textSelectAll,
],
},
]));
} else {
setMenu(Menu.buildFromTemplate(template));

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.3.9",
"version": "1.3.10",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -644,9 +644,9 @@
"dev": true
},
"abab": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg=="
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
"integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
},
"abbrev": {
"version": "1.1.1",
@@ -654,9 +654,9 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
"integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA=="
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
},
"acorn-globals": {
"version": "4.3.4",
@@ -668,9 +668,9 @@
},
"dependencies": {
"acorn": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA=="
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
}
}
},
@@ -6770,9 +6770,9 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"highlight.js": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.1.tgz",
"integrity": "sha512-b4L09127uVa+9vkMgPpdUQP78ickGbHEQTWeBrQFTJZ4/n2aihWOGS0ZoUqAwjVmfjhq/C76HRzkqwZhK4sBbg=="
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.2.1.tgz",
"integrity": "sha512-A+sckVPIb9zQTUydC9lpRX1qRFO/N0OKEh0NwIr65ckvWA/oMY8v9P3+kGRK3w2ULSh9E8v5MszXafodQ6039g=="
},
"hoist-non-react-statics": {
"version": "2.5.0",
@@ -7312,9 +7312,9 @@
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
},
"joplin-turndown": {
"version": "4.0.29",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.29.tgz",
"integrity": "sha512-rVGu8u4TpSRETo59/jiVW9iaXnpdxxpBHjb7nyCflkDfWhg1Kska4uagBQGw7cD2yxw7mB2YUIB/fAgtlIzcDQ==",
"version": "4.0.30",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.30.tgz",
"integrity": "sha512-OrGdNTsjI6/cbx/es9Hl0YI3YTql4SopduFcYCnWTZgqT0SJqILnF2JQxSNnbPnkSDIIRdNOG4+iNzlY6bS1nw==",
"requires": {
"css": "^2.2.4",
"html-entities": "^1.2.1",
@@ -7387,9 +7387,9 @@
},
"dependencies": {
"ajv": {
"version": "6.12.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
"integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -7398,9 +7398,9 @@
}
},
"aws4": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA=="
},
"fast-deep-equal": {
"version": "3.1.3",
@@ -7408,11 +7408,11 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"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==",
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"requires": {
"ajv": "^6.5.5",
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
}
},
@@ -10276,13 +10276,6 @@
"integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
"requires": {
"lodash": "^4.17.19"
},
"dependencies": {
"lodash": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
}
}
},
"request-promise-native": {

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.3.9",
"version": "1.3.10",
"description": "Joplin for Desktop",
"main": "main.js",
"scripts": {
@@ -139,13 +139,13 @@
"form-data": "^2.3.2",
"formatcoords": "^1.1.3",
"fs-extra": "^5.0.0",
"highlight.js": "^10.1.1",
"highlight.js": "^10.2.1",
"html-entities": "^1.2.1",
"html-minifier": "^4.0.0",
"htmlparser2": "^4.1.0",
"image-type": "^3.0.0",
"immer": "^7.0.5",
"joplin-turndown": "^4.0.29",
"joplin-turndown": "^4.0.30",
"joplin-turndown-plugin-gfm": "^1.0.12",
"json-stringify-safe": "^5.0.1",
"jssha": "^2.3.1",

View File

@@ -421,7 +421,7 @@ class Dialog extends React.PureComponent<Props, State> {
listItem_onClick(event:any) {
const itemId = event.currentTarget.getAttribute('data-id');
const parentId = event.currentTarget.getAttribute('data-parent-id');
const itemType = event.currentTarget.getAttribute('data-type');
const itemType = Number(event.currentTarget.getAttribute('data-type'));
this.gotoItem({
id: itemId,

View File

@@ -2,4 +2,5 @@ import { AppState } from '../../app';
export interface DesktopCommandContext {
state: AppState,
dispatch: Function,
}

View File

@@ -28,7 +28,7 @@ Linux | <a href='https://github.com/laurent22/joplin/releases/download/
Operating System | Download | Alt. Download
-----------------|----------|----------------
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://joplinapp.org/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.3.9/joplin-v1.3.9.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.3.9/joplin-v1.3.9-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.3.10/joplin-v1.3.10.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.3.10/joplin-v1.3.10-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

View File

@@ -132,8 +132,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097597
versionName "1.3.9"
versionCode 2097598
versionName "1.3.10"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}

View File

@@ -42,6 +42,7 @@ class HtmlUtils {
return selfClosingElements.includes(tagName.toLowerCase());
}
// Returns the **encoded** URLs, so to be useful they should be decoded again before use.
extractImageUrls(html) {
if (!html) return [];

View File

@@ -474,13 +474,13 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
note.latitude = noteAttributes.latitude;
note.longitude = noteAttributes.longitude;
note.altitude = noteAttributes.altitude;
note.author = noteAttributes.author;
note.author = noteAttributes.author ? noteAttributes.author.trim() : '';
note.is_todo = noteAttributes['reminder-order'] !== '0' && !!noteAttributes['reminder-order'];
note.todo_due = dateToTimestamp(noteAttributes['reminder-time'], true);
note.todo_completed = dateToTimestamp(noteAttributes['reminder-done-time'], true);
note.order = dateToTimestamp(noteAttributes['reminder-order'], true);
note.source = noteAttributes.source ? `evernote.${noteAttributes.source}` : 'evernote';
note.source_url = noteAttributes['source-url'] ? noteAttributes['source-url'] : '';
note.source = noteAttributes.source ? `evernote.${noteAttributes.source.trim()}` : 'evernote';
note.source_url = noteAttributes['source-url'] ? noteAttributes['source-url'].trim() : '';
noteAttributes = null;
} else if (n == 'resource') {
@@ -488,9 +488,9 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
id: noteResource.id,
dataFilePath: noteResource.dataFilePath,
dataEncoding: noteResource.dataEncoding,
mime: noteResource.mime,
title: noteResource.filename ? noteResource.filename : '',
filename: noteResource.filename ? noteResource.filename : '',
mime: noteResource.mime ? noteResource.mime.trim() : '',
title: noteResource.filename ? noteResource.filename.trim() : '',
filename: noteResource.filename ? noteResource.filename.trim() : '',
});
noteResource = null;

View File

@@ -1,6 +1,6 @@
// This plugin is used only on mobile, to highlight search results.
import { RuleOptions } from "lib/joplin-renderer/MdToHtml";
import { RuleOptions } from 'lib/joplin-renderer/MdToHtml';
const stringUtils = require('../../stringUtils.js');
const md5 = require('md5');
@@ -67,4 +67,4 @@ function plugin(markdownIt:any, ruleOptions:RuleOptions) {
export default {
plugin,
}
};

View File

@@ -1,4 +1,4 @@
import { RuleOptions } from "lib/joplin-renderer/MdToHtml";
import { RuleOptions } from 'lib/joplin-renderer/MdToHtml';
const htmlUtils = require('../../htmlUtils.js');
const utils = require('../../utils');
@@ -47,4 +47,4 @@ function plugin(markdownIt:any, ruleOptions:RuleOptions) {
markdownIt.renderer.rules.html_inline = handleImageTags(htmlInlineDefaultRender);
}
export default { plugin }
export default { plugin };

View File

@@ -1,4 +1,4 @@
import { RuleOptions } from "lib/joplin-renderer/MdToHtml";
import { RuleOptions } from 'lib/joplin-renderer/MdToHtml';
let katex = require('katex');
const md5 = require('md5');
@@ -8,6 +8,54 @@ const mhchemModule = require('./katex_mhchem.js');
// to serialize them with json-stringify-safe
const stringifySafe = require('json-stringify-safe');
function stringifyKatexOptions(options:any) {
if (!options) return '';
const newOptions = { ...options };
// The Katex macro structure is extremely verbose and slow to cache,
// so we need bespoke code to serialize it.
// macros:
// \hb: {tokens: Array(1), numArgs: 0}
// \d: {tokens: Array(7), numArgs: 1}
// \e:
// tokens: Array(11)
// 0: Token {text: "}", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 1: Token {text: "1", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 2: Token {text: "#", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 3: Token {text: "{", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 4: Token {text: "^", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 5: Token {text: "}", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 6: Token {text: "e", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 7: Token {text: " ", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 8: Token {text: "m", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 9: Token {text: " ", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// 10: Token {text: "{", loc: SourceLocation, noexpand: undefined, treatAsRelax: undefined}
// numArgs: 1
// \dv: {tokens: Array(15), numArgs: 2}
// \ddv: {tokens: Array(19), numArgs: 2}
// \pdv: {tokens: Array(15), numArgs: 2}
// \pddv: {tokens: Array(15), numArgs: 2}
// \abs: {tokens: Array(10), numArgs: 1}
// \inflim: {tokens: Array(10), numArgs: 0}
// \infint: {tokens: Array(2), numArgs: 0}
// \prob: {tokens: Array(12), numArgs: 1}
// \expval: {tokens: Array(14), numArgs: 2}
// \wf: {tokens: Array(6), numArgs: 0}
if (options.macros) {
const toSerialize:any = {};
for (const k of Object.keys(options.macros)) {
const macroText:string[] = options.macros[k].tokens.map((t:any) => t.text);
toSerialize[k] = `${macroText.join('')}_${options.macros[k].numArgs}`;
}
newOptions.macros = toSerialize;
}
return stringifySafe(newOptions);
}
katex = mhchemModule(katex);
function katexStyle() {
@@ -43,14 +91,13 @@ function katexStyle() {
// Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos]
function isValidDelim(state:any, pos:number) {
let prevChar,
nextChar,
max = state.posMax,
can_open = true,
const max = state.posMax;
let can_open = true,
can_close = true;
prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
const nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
// Check non-whitespace conditions for opening and closing, and
// check that closing delimeter isn't followed by a number
@@ -68,7 +115,7 @@ function isValidDelim(state:any, pos:number) {
}
function math_inline(state:any, silent:boolean) {
let start, match, token, res, pos;
let match, token, res, pos;
if (state.src[state.pos] !== '$') {
return false;
@@ -87,7 +134,7 @@ function math_inline(state:any, silent:boolean) {
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
start = state.pos + 1;
const start = state.pos + 1;
match = start;
while ((match = state.src.indexOf('$', match)) !== -1) {
// Found potential $, look for escapes, pos will point to
@@ -148,7 +195,6 @@ function math_block(state:any, start:number, end:number, silent:boolean) {
next,
lastPos,
found = false,
token,
pos = state.bMarks[start] + state.tShift[start],
max = state.eMarks[start];
@@ -200,7 +246,7 @@ function math_block(state:any, start:number, end:number, silent:boolean) {
state.line = next + 1;
token = state.push('math_block', 'math', 0);
const token = state.push('math_block', 'math', 0);
token.block = true;
token.content = (firstLine && firstLine.trim() ? `${firstLine}\n` : '') + state.getLines(start + 1, next, state.tShift[start], true) + (lastLine && lastLine.trim() ? lastLine : '');
token.map = [start, state.line];
@@ -211,13 +257,13 @@ function math_block(state:any, start:number, end:number, silent:boolean) {
const cache_:any = {};
function renderToStringWithCache(latex:string, katexOptions:any) {
const cacheKey = md5(escape(latex) + escape(stringifySafe(katexOptions)));
const cacheKey = md5(escape(latex) + escape(stringifyKatexOptions(katexOptions)));
if (cacheKey in cache_) {
return cache_[cacheKey];
} else {
const beforeMacros = stringifySafe(katexOptions.macros);
const beforeMacros = stringifyKatexOptions(katexOptions.macros);
const output = katex.renderToString(latex, katexOptions);
const afterMacros = stringifySafe(katexOptions.macros);
const afterMacros = stringifyKatexOptions(katexOptions.macros);
// Don't cache the formulas that add macros, otherwise
// they won't be added on second run.
@@ -233,7 +279,7 @@ export default {
// https://github.com/laurent22/joplin/issues/1105
if (!options.context.userData.__katex) options.context.userData.__katex = { macros: {} };
const katexOptions:any = {}
const katexOptions:any = {};
katexOptions.macros = options.context.userData.__katex.macros;
katexOptions.trust = true;

File diff suppressed because one or more lines are too long

View File

@@ -12,7 +12,7 @@ function mermaidReady() {
// <h1 id="mermaid">Mermaid</h1>
//
// And that's going to make the lib set the `mermaid` object to the H1 element.
// So below, we double-check that what we have really is an instance of the library.
// So below, we double-check that what we have really is an instance of the library.
return typeof mermaid !== 'undefined' && mermaid !== null && typeof mermaid === 'object' && !!mermaid.init;
}

View File

@@ -363,4 +363,4 @@ export default function(theme:any) {
`;
return [css];
};
}

View File

@@ -616,9 +616,9 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"highlight.js": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.1.tgz",
"integrity": "sha512-b4L09127uVa+9vkMgPpdUQP78ickGbHEQTWeBrQFTJZ4/n2aihWOGS0ZoUqAwjVmfjhq/C76HRzkqwZhK4sBbg=="
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.2.1.tgz",
"integrity": "sha512-A+sckVPIb9zQTUydC9lpRX1qRFO/N0OKEh0NwIr65ckvWA/oMY8v9P3+kGRK3w2ULSh9E8v5MszXafodQ6039g=="
},
"html-entities": {
"version": "1.2.1",

View File

@@ -18,7 +18,7 @@
"base-64": "^0.1.0",
"font-awesome-filetypes": "^2.1.0",
"fs-extra": "^8.1.0",
"highlight.js": "10.1.1",
"highlight.js": "^10.2.1",
"html-entities": "^1.2.1",
"json-stringify-safe": "^5.0.1",
"katex": "^0.12.0",

View File

@@ -13,7 +13,7 @@ export function basename(path:string) {
export function filename(path:string, includeDir:boolean = false):string {
if (!path) throw new Error('Path is empty');
let output = includeDir ? path : basename(path);
const output = includeDir ? path : basename(path);
if (output.indexOf('.') < 0) return output;
const splitted = output.split('.');

View File

@@ -30,6 +30,13 @@ const markdownUtils = {
return url;
},
unescapeLinkUrl(url:string) {
url = url.replace(/%28/g, '(');
url = url.replace(/%29/g, ')');
url = url.replace(/%20/g, ' ');
return url;
},
prependBaseUrl(md:string, baseUrl:string) {
// eslint-disable-next-line no-useless-escape
return md.replace(/(\]\()([^\s\)]+)(.*?\))/g, (_match:any, before:string, url:string, after:string) => {
@@ -37,6 +44,7 @@ const markdownUtils = {
});
},
// Returns the **encoded** URLs, so to be useful they should be decoded again before use.
extractImageUrls(md:string) {
const markdownIt = new MarkdownIt();
setupLinkify(markdownIt); // Necessary to support file:/// links

View File

@@ -256,9 +256,11 @@ class BaseItem extends BaseModel {
propValue = JSON.stringify(propValue);
} else if (propValue === null || propValue === undefined) {
propValue = '';
} else {
propValue = `${propValue}`;
}
return propValue;
return propValue.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
}
static unserialize_format(type, propName, propValue) {
@@ -279,7 +281,7 @@ class BaseItem extends BaseModel {
propValue = Database.formatValue(ItemClass.fieldType(propName), propValue);
}
return propValue;
return typeof propValue === 'string' ? propValue.replace(/\\n/g, '\n').replace(/\\r/g, '\r') : propValue;
}
static async serialize(item, shownKeys = null) {

View File

@@ -3,6 +3,7 @@ const { stringify } = require('query-string');
const { time } = require('lib/time-utils.js');
const Logger = require('lib/Logger').default;
const { _ } = require('lib/locale');
const urlUtils = require('lib/urlUtils.js');
class OneDriveApi {
// `isPublic` is to tell OneDrive whether the application is a "public" one (Mobile and desktop
@@ -90,16 +91,16 @@ class OneDriveApi {
}
async execTokenRequest(code, redirectUri) {
const body = new shim.FormData();
body.append('client_id', this.clientId());
if (!this.isPublic()) body.append('client_secret', this.clientSecret());
body.append('code', code);
body.append('redirect_uri', redirectUri);
body.append('grant_type', 'authorization_code');
const body = {};
body['client_id'] = this.clientId();
if (!this.isPublic()) body['client_secret'] = this.clientSecret();
body['code'] = code;
body['redirect_uri'] = redirectUri;
body['grant_type'] = 'authorization_code';
const r = await shim.fetch(this.tokenBaseUrl(), {
method: 'POST',
body: body,
body: urlUtils.objectToQueryString(body),
headers: {
['Content-Type']: 'application/x-www-form-urlencoded',
},
@@ -366,19 +367,21 @@ class OneDriveApi {
throw new Error(_('Cannot refresh token: authentication data is missing. Starting the synchronisation again may fix the problem.'));
}
const body = new shim.FormData();
body.append('client_id', this.clientId());
if (!this.isPublic()) body.append('client_secret', this.clientSecret());
body.append('refresh_token', this.auth_.refresh_token);
body.append('redirect_uri', 'http://localhost:1917');
body.append('grant_type', 'refresh_token');
const body = {};
body['client_id'] = this.clientId();
if (!this.isPublic()) body['client_secret'] = this.clientSecret();
body['refresh_token'] = this.auth_.refresh_token;
body['redirect_uri'] = 'http://localhost:1917';
body['grant_type'] = 'refresh_token';
const options = {
const response = await shim.fetch(this.tokenBaseUrl(), {
method: 'POST',
body: body,
};
body: urlUtils.objectToQueryString(body),
headers: {
['Content-Type']: 'application/x-www-form-urlencoded',
},
});
const response = await shim.fetch(this.tokenBaseUrl(), options);
if (!response.ok) {
this.setAuth(null);
const msg = await response.text();

View File

@@ -17,7 +17,7 @@ export function basename(path:string) {
export function filename(path:string, includeDir:boolean = false) {
if (!path) throw new Error('Path is empty');
let output = includeDir ? path : basename(path);
const output = includeDir ? path : basename(path);
if (output.indexOf('.') < 0) return output;
const splitted = output.split('.');

View File

@@ -47,7 +47,7 @@ const attributesToStr = (attributes) =>
const attachmentElement = ({ src, attributes, id }) =>
[
`<a href='joplin://${id}' ${attributesToStr(attributes)}>`,
`<a href=':/${id}' ${attributesToStr(attributes)}>`,
` ${attributes.alt || src}`,
'</a>',
].join('');

View File

@@ -11,6 +11,7 @@ type EnabledCondition = string;
export interface CommandContext {
// The state may also be of type "AppState" (used by the desktop app), which inherits from "State" (used by all apps)
state: State,
dispatch: Function,
}
export interface CommandRuntime {
@@ -203,10 +204,20 @@ export default class CommandService extends BaseService {
delete command.runtime;
}
private createContext():CommandContext {
return {
state: this.store_.getState(),
dispatch: (action:any) => {
this.store_.dispatch(action);
},
};
}
public async execute(commandName:string, ...args:any[]):Promise<any | void> {
const command = this.commandByName(commandName);
this.logger().info('CommandService::execute:', commandName, args);
return command.runtime.execute({ state: this.store_.getState() }, ...args);
if (!command.runtime) throw new Error(`Cannot execute a command without a runtime: ${commandName}`);
return command.runtime.execute(this.createContext(), ...args);
}
public scheduleExecute(commandName:string, args:any) {

View File

@@ -51,7 +51,7 @@ const defaultKeymapItems = {
{ accelerator: 'Ctrl+N', command: 'newNote' },
{ accelerator: 'Ctrl+T', command: 'newTodo' },
{ accelerator: 'Ctrl+S', command: 'synchronize' },
{ accelerator: '', command: 'print' },
{ accelerator: null, command: 'print' },
{ accelerator: 'Ctrl+Q', command: 'quit' },
{ accelerator: 'Ctrl+Alt+I', command: 'insertTemplate' },
{ accelerator: 'Ctrl+C', command: 'textCopy' },

View File

@@ -73,6 +73,20 @@ export default class ResourceEditWatcher {
return this.eventEmitter_.removeListener(eventName, callback);
}
externalApi() {
return {
openAndWatch: async ({ resourceId }:any) => {
return this.openAndWatch(resourceId);
},
stopWatching: async ({ resourceId }:any) => {
return this.stopWatching(resourceId);
},
isWatched: async ({ resourceId }:any) => {
return !!this.watchedItemByResourceId(resourceId);
},
};
}
private watch(fileToWatch:string) {
if (!this.chokidar_) return;

View File

@@ -2,6 +2,7 @@ import Setting from 'lib/models/Setting';
import Logger from 'lib/Logger';
import shim from 'lib/shim';
import uuid from 'lib/uuid';
import markdownUtils from 'lib/markdownUtils';
const { ltrimSlashes } = require('lib/path-utils');
const { Database } = require('lib/database.js');
@@ -631,6 +632,9 @@ export default class Api {
async downloadImage_(url:string /* , allowFileProtocolImages */) {
const tempDir = Setting.value('tempDir');
// The URL we get to download have been extracted from the Markdown document
url = markdownUtils.unescapeLinkUrl(url);
const isDataUrl = url && url.toLowerCase().indexOf('data:') === 0;
const name = isDataUrl ? md5(`${Math.random()}_${Date.now()}`) : filename(url);

View File

@@ -1,7 +1,9 @@
import ResourceEditWatcher from 'lib/services/ResourceEditWatcher/index';
const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
export default {
externalEditWatcher: () => ExternalEditWatcher.instance().externalApi(),
resourceEditWatcher: () => ResourceEditWatcher.instance().externalApi(),
};

View File

@@ -13,6 +13,43 @@ const http = require('http');
const https = require('https');
const toRelative = require('relative');
const timers = require('timers');
const zlib = require('zlib');
function fileExists(filePath) {
try {
return fs.statSync(filePath).isFile();
} catch (err) {
return false;
}
}
const gunzipFile = function(source, destination) {
if (!fileExists(source)) {
throw new Error(`No such file: ${source}`);
}
return new Promise((resolve, reject) => {
// prepare streams
const src = fs.createReadStream(source);
const dest = fs.createWriteStream(destination);
// extract the archive
src.pipe(zlib.createGunzip()).pipe(dest);
// callback on extract completion
dest.on('close', function() {
resolve();
});
src.on('error', () => {
reject();
});
dest.on('error', () => {
reject();
});
});
};
function shimInit() {
shim.fsDriver = () => {
@@ -365,9 +402,25 @@ function shimInit() {
const request = http.request(requestOptions, function(response) {
response.pipe(file);
const isGzipped = response.headers['content-encoding'] === 'gzip';
file.on('finish', function() {
file.close(() => {
resolve(makeResponse(response));
file.close(async () => {
if (isGzipped) {
const gzipFilePath = `${filePath}.gzip`;
await shim.fsDriver().move(filePath, gzipFilePath);
try {
await gunzipFile(gzipFilePath, filePath);
resolve(makeResponse(response));
} catch (error) {
cleanUpOnError(error);
}
shim.fsDriver().remove(gzipFilePath);
} else {
resolve(makeResponse(response));
}
});
});
});

View File

@@ -36,21 +36,31 @@ function shimInit() {
};
shim.fetch = async function(url, options = null) {
// The native fetch() throws an uncatable error that crashes the app if calling it with an
// invalid URL such as '//.resource' or "http://ocloud. de" so detect if the URL is valid beforehand
// and throw a catchable error.
// Bug: https://github.com/facebook/react-native/issues/7436
// The native fetch() throws an uncatchable error that crashes the
// app if calling it with an invalid URL such as '//.resource' or
// "http://ocloud. de" so detect if the URL is valid beforehand and
// throw a catchable error. Bug:
// https://github.com/facebook/react-native/issues/7436
const validatedUrl = urlValidator.isUri(url);
if (!validatedUrl) throw new Error(`Not a valid URL: ${url}`);
return shim.fetchWithRetry(() => {
// If the request has a body and it's not a GET call, and it doesn't have a Content-Type header
// we display a warning, because it could trigger a "Network request failed" error.
// If the request has a body and it's not a GET call, and it
// doesn't have a Content-Type header we display a warning,
// because it could trigger a "Network request failed" error.
// https://github.com/facebook/react-native/issues/30176
if (options?.body && options?.method && options.method !== 'GET' && !options?.headers?.['Content-Type']) {
console.warn('Done a non-GET fetch call without a Content-Type header. It may make the request fail.', url, options);
}
// Among React Native `fetch()` many bugs, one of them is that
// it will truncate strings when they contain binary data.
// Browser fetch() or Node fetch() work fine but as always RN's
// one doesn't. There's no obvious way to fix this so we'll
// have to wait if it's eventually fixed upstream. See here for
// more info:
// https://github.com/laurent22/joplin/issues/3986#issuecomment-718019688
return fetch(validatedUrl, options);
}, options);
};

View File

@@ -91,4 +91,18 @@ urlUtils.extractResourceUrls = function(text) {
return output;
};
urlUtils.objectToQueryString = function(query) {
if (!query) return '';
let queryString = '';
const s = [];
for (const k in query) {
if (!query.hasOwnProperty(k)) continue;
s.push(`${encodeURIComponent(k)}=${encodeURIComponent(query[k])}`);
}
queryString = s.join('&');
return queryString;
};
module.exports = urlUtils;

View File

@@ -4425,9 +4425,9 @@
}
},
"highlight.js": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.1.tgz",
"integrity": "sha512-b4L09127uVa+9vkMgPpdUQP78ickGbHEQTWeBrQFTJZ4/n2aihWOGS0ZoUqAwjVmfjhq/C76HRzkqwZhK4sBbg=="
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.2.1.tgz",
"integrity": "sha512-A+sckVPIb9zQTUydC9lpRX1qRFO/N0OKEh0NwIr65ckvWA/oMY8v9P3+kGRK3w2ULSh9E8v5MszXafodQ6039g=="
},
"hoist-non-react-statics": {
"version": "2.5.5",

View File

@@ -25,7 +25,7 @@
"events": "^1.1.1",
"font-awesome-filetypes": "^2.1.0",
"form-data": "^2.1.4",
"highlight.js": "10.1.1",
"highlight.js": "^10.2.1",
"html-entities": "^1.2.1",
"htmlparser2": "^4.1.0",
"immer": "^7.0.9",

84
package-lock.json generated
View File

@@ -319,14 +319,14 @@
}
},
"abab": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg=="
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
"integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
},
"acorn": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA=="
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
},
"acorn-globals": {
"version": "4.3.4",
@@ -335,6 +335,13 @@
"requires": {
"acorn": "^6.0.1",
"acorn-walk": "^6.0.1"
},
"dependencies": {
"acorn": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
}
}
},
"acorn-jsx": {
@@ -352,6 +359,7 @@
"version": "6.10.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
"integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -757,9 +765,9 @@
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA=="
},
"bach": {
"version": "1.2.0",
@@ -2652,7 +2660,8 @@
"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="
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"dev": true
},
"fast-glob": {
"version": "3.0.4",
@@ -3821,12 +3830,30 @@
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"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==",
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"requires": {
"ajv": "^6.5.5",
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
},
"dependencies": {
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
}
}
},
"has": {
@@ -4404,9 +4431,9 @@
"dev": true
},
"joplin-turndown": {
"version": "4.0.29",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.29.tgz",
"integrity": "sha512-rVGu8u4TpSRETo59/jiVW9iaXnpdxxpBHjb7nyCflkDfWhg1Kska4uagBQGw7cD2yxw7mB2YUIB/fAgtlIzcDQ==",
"version": "4.0.30",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.30.tgz",
"integrity": "sha512-OrGdNTsjI6/cbx/es9Hl0YI3YTql4SopduFcYCnWTZgqT0SJqILnF2JQxSNnbPnkSDIIRdNOG4+iNzlY6bS1nw==",
"requires": {
"css": "^2.2.4",
"html-entities": "^1.2.1",
@@ -4470,13 +4497,6 @@
"whatwg-url": "^7.0.0",
"ws": "^7.0.0",
"xml-name-validator": "^3.0.0"
},
"dependencies": {
"acorn": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
"integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA=="
}
}
},
"json-parse-better-errors": {
@@ -5453,16 +5473,16 @@
"dev": true
},
"optionator": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.4",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"wordwrap": "~1.0.0"
"word-wrap": "~1.2.3"
}
},
"ordered-read-streams": {
@@ -7328,13 +7348,13 @@
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"wrap-ansi": {
"version": "3.0.1",

View File

@@ -52,7 +52,7 @@
"dependencies": {
"follow-redirects": "^1.11.0",
"immer": "^7.0.5",
"joplin-turndown": "^4.0.29",
"joplin-turndown": "^4.0.30",
"joplin-turndown-plugin-gfm": "^1.0.12",
"relative": "^3.0.2"
}

View File

@@ -1,5 +1,21 @@
# Joplin terminal app changelog
## [cli-v1.3.3](https://github.com/laurent22/joplin/releases/tag/cli-v1.3.3) - 2020-10-23T16:00:38Z
- Improved: Added support for a custom S3 URL (#3921) (#3691 by [@aaron](https://github.com/aaron))
- Improved: Allow setting note geolocation attributes via API (#3884)
- Improved: Import &lt;strike&gt;,&lt;s&gt; tags (strikethrough) from Evernote (#3936 by Ian Slinger)
- Improved: Removed OneDrive Dev sync target which was not really useful
- Improved: Sort search results by average of multiple criteria, including &#039;Sort notes by&#039; field setting (#3777 by [@shawnaxsom](https://github.com/shawnaxsom))
- Improved: Sort tags in a case-insensitive way
- Improved: Updated installation script with BSD support (#3930 by Andros Fenollosa)
- Fixed: Crash when trying to change app locale (#3847)
- Fixed: Fix search filters when language is in Korean or with accents (#3947 by Naveen M V)
- Fixed: Fixed freeze when importing ENEX as HTML, and fixed potential error when importing resources (#3958)
- Fixed: Fixed setting issue that would cause a password to be saved in plain text in the database, even when the keychain is working
- Fixed: Importing ENEX as HTML was importing as Markdown (#3923)
- Fixed: Regression: Fix export of pluginAssets when exporting to html/pdf (#3927 by Caleb John)
## [cli-v1.2.3](https://github.com/laurent22/joplin/releases/tag/cli-v1.2.3) - 2020-10-09T11:17:18Z
- Improved: Improved handling of database migration failures