1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-12-26 23:38:08 +02:00

Compare commits

..

78 Commits

Author SHA1 Message Date
Laurent Cozic
8390d75293 Merge branch 'dev' into ui_update 2020-09-14 13:07:50 +01:00
Laurent Cozic
75e62b86a1 Fixed search field hover styling 2020-09-14 12:43:21 +01:00
Laurent Cozic
840d3e9c60 Fixed hiding and showing note list 2020-09-14 12:39:32 +01:00
Laurent Cozic
a2b747c63d Merge branch 'dev' into ui_update 2020-09-14 12:13:07 +01:00
DarinDev1000
374ee3baf5 Desktop: Fixes #3628: Add scroll offset for dragging notes (#3651)
The note draging was not taking into account the scroll distance.
This caused the notes to be dragged to a different location than the mouse.
This scroll offset should fix that issue.
2020-09-13 16:23:49 +01:00
Laurent Cozic
58574a2d0e Disable randomly failing test 2020-09-13 12:15:53 +01:00
Laurent Cozic
96ac6887ce restored fuzzy seach behaviour 2020-09-13 12:07:26 +01:00
Laurent Cozic
d4cc7ba85b Added + button to sidebar 2020-09-13 11:23:59 +01:00
Laurent Cozic
6919be2908 Merge branch 'dev' into ui_update 2020-09-12 00:39:38 +01:00
Laurent Cozic
cc6d7cebfa Apply linter 2020-09-12 00:39:23 +01:00
Laurent Cozic
7ac224df52 Updated all themes 2020-09-11 17:44:07 +01:00
Laurent Cozic
a2861e476b temp file 2020-09-11 17:26:05 +01:00
Laurent Cozic
76f44fe09f Fixing up dark theme 2020-09-11 17:25:26 +01:00
Laurent Cozic
6f1e8fba2c Fixing up dark theme 2020-09-11 16:58:32 +01:00
Laurent Cozic
fa65e29fb0 Fixing up dark theme 2020-09-11 16:57:50 +01:00
Laurent Cozic
277fa0827e Added comments for light theme 2020-09-11 15:44:04 +01:00
Laurent Cozic
0907cf6e88 Updated dropbox screen 2020-09-11 15:25:29 +01:00
Laurent Cozic
85296a8c09 Updated resource screen 2020-09-11 15:13:50 +01:00
Laurent Cozic
b9a88c9c44 Updated sync status screeen 2020-09-11 15:07:58 +01:00
Laurent Cozic
e4ffebbbc4 Moved button bar to own component 2020-09-11 14:46:29 +01:00
Laurent Cozic
427e90fbf7 Fixed config button bar 2020-09-11 14:27:40 +01:00
Laurent Cozic
204be519c1 Fix button style 2020-09-11 12:53:25 +01:00
Laurent Cozic
20bd001878 Applying new style to config screen 2020-09-11 00:43:01 +01:00
Laurent Cozic
f016d6d6e5 Added config sidebar 2020-09-10 23:08:13 +01:00
Laurent Cozic
96960a7407 Converted config screen to TypeScript 2020-09-10 22:10:50 +01:00
Laurent Cozic
7b233084fe Moved config screen 2020-09-10 22:02:23 +01:00
Laurent Cozic
74355d5320 Reset search when parent type changes 2020-09-10 21:40:32 +01:00
Laurent Cozic
fbfd5942ce Restored showing folder when doing search 2020-09-10 12:17:48 +01:00
Laurent Cozic
eaca80d6c8 Revert "Improved displaying search results"
This reverts commit 1cc348d620.
2020-09-10 11:24:27 +01:00
Laurent Cozic
68f5494e3c Search improvements 2020-09-10 11:22:19 +01:00
Laurent Cozic
cf462b7e03 Fixed resizing window 2020-09-09 18:13:47 +01:00
Laurent Cozic
73a7b683d1 Fixed setTags command 2020-09-09 17:52:33 +01:00
Laurent Cozic
1cc348d620 Improved displaying search results 2020-09-09 17:44:15 +01:00
Laurent Cozic
25ab1704c6 Fixed toolbar buttons with label 2020-09-09 16:34:46 +01:00
Laurent Cozic
cb12c54eb7 Build files 2020-09-09 15:29:56 +01:00
Laurent Cozic
3959a441da Fix sidebar min width 2020-09-09 15:27:33 +01:00
Laurent Cozic
ab26949ad4 Merge branch 'dev' into ui_update 2020-09-09 15:03:13 +01:00
Laurent Cozic
af4a93c9d1 Update ignore files 2020-09-06 16:48:50 +01:00
Laurent Cozic
e364ae9133 delete temp files 2020-09-06 16:46:51 +01:00
Laurent Cozic
a66c40e999 Merge branch 'dev' into ui_update 2020-09-06 16:45:53 +01:00
Laurent Cozic
016943f7eb redraw gui while sidebars are being resized 2020-08-21 00:43:19 +01:00
Laurent Cozic
2dee827bb8 Convert main screen to TypeScript 2020-08-20 23:21:27 +01:00
Laurent Cozic
27700028ee sidebar 2020-08-20 22:53:43 +01:00
Laurent Cozic
56ba7663fd Merge branch 'dev' into ui_update 2020-08-20 19:36:06 +01:00
Laurent Cozic
64413405d7 gitignored 2020-08-20 19:35:42 +01:00
Laurent Cozic
f2469c9bf7 sidebar 2020-08-20 19:34:32 +01:00
Laurent Cozic
81140debdd Merge branch 'dev' into ui_update 2020-08-19 18:31:56 +00:00
Laurent Cozic
274861fdeb Fixed build 2020-08-08 10:30:52 +01:00
Laurent Cozic
8b76699949 Merge branch 'dev' into ui_update 2020-08-08 10:21:41 +01:00
Laurent Cozic
1f301cc841 Tools: Do not display linter warnings on CI 2020-08-08 10:20:48 +01:00
Laurent Cozic
8bcf096840 Merge branch 'dev' into ui_update 2020-08-08 10:16:40 +01:00
Laurent Cozic
d2a31f0ef2 Merge branch 'dev' into ui_update 2020-08-08 00:36:26 +01:00
Laurent Cozic
02a8b22163 sidebar 2020-08-07 23:51:01 +01:00
Laurent Cozic
15d55d537e Refactor SideBar component in TypeScript 2020-08-07 20:43:02 +00:00
Laurent Cozic
488ba01f60 Moved All Notes under Notebook section 2020-08-07 20:04:32 +00:00
Laurent Cozic
d7efc4aaca Remove header component 2020-08-07 19:41:51 +00:00
Laurent Cozic
19ed685a36 Styling 2020-08-07 19:21:37 +00:00
Laurent Cozic
184e22937a Make use of ThemeProvider to simplify code 2020-08-07 18:54:53 +00:00
Laurent Cozic
5b81aa1fdb Renamed theme => themeId 2020-08-07 02:01:59 +00:00
Laurent Cozic
7bb3ba9f3e Adding buttons 2020-08-07 01:24:04 +01:00
Laurent Cozic
54ef47120b Searh bar 2020-08-07 00:05:00 +01:00
Laurent Cozic
f83129cf2f Improve resizable layout 2020-08-06 19:17:28 +00:00
Laurent Cozic
9ec5030830 Merge branch 'dev' into ui_update 2020-08-06 15:30:26 +01:00
Laurent Cozic
4758035b45 toolbar 2020-08-04 23:53:55 +01:00
Laurent Cozic
33895bbc4e Merge branch 'dev' into ui_update 2020-08-04 23:02:22 +01:00
Laurent Cozic
3b36cac7f5 Merge branch 'dev' into ui_update 2020-08-04 22:33:20 +01:00
Laurent Cozic
3acb1a2836 note list 2020-08-04 19:02:15 +01:00
Laurent Cozic
9348499b63 note list 2020-08-04 18:56:54 +00:00
Laurent Cozic
9c61cfd39b Toolbar 2020-08-04 18:32:46 +00:00
Laurent Cozic
6445361bd9 Merge branch 'dev' into ui_update 2020-08-04 16:40:06 +01:00
Laurent Cozic
7ad0c0b9bd Added styled-component package 2020-08-04 00:11:45 +00:00
Laurent Cozic
a405a67367 Toolbar 2020-08-03 23:29:50 +01:00
Laurent Cozic
fc6f29636a Toolbars 2020-08-03 22:41:00 +01:00
Laurent Cozic
ac4e885748 Toolbar 2020-08-03 00:41:44 +00:00
Laurent Cozic
c120c6095a Started updating toolbar 2020-08-02 23:44:52 +01:00
Laurent Cozic
af762f7839 Merge branch 'dev' into ui_update 2020-08-02 16:36:26 +01:00
Laurent Cozic
31a44ac319 Save note list and sidebar width 2020-07-30 20:38:41 +01:00
Laurent Cozic
3ff8fa87a8 Refactoring main screen layout to make it easier to add or remove views and make them resizable. 2020-07-29 23:51:44 +00:00
113 changed files with 2099 additions and 2738 deletions

View File

@@ -119,7 +119,6 @@ ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useJoplinMode.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useLineSorting.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
@@ -146,7 +145,6 @@ ElectronClient/gui/NoteList/NoteList.js
ElectronClient/gui/NoteListControls/commands/focusSearch.js
ElectronClient/gui/NoteListControls/NoteListControls.js
ElectronClient/gui/NoteListItem.js
ElectronClient/gui/NoteTextViewer.js
ElectronClient/gui/NoteToolbar/NoteToolbar.js
ElectronClient/gui/OneDriveLoginScreen.js
ElectronClient/gui/ResizableLayout/hooks/useLayoutItemSizes.js
@@ -166,7 +164,6 @@ ElectronClient/gui/style/StyledInput.js
ElectronClient/gui/style/StyledTextInput.js
ElectronClient/gui/ToggleEditorsButton/styles/index.js
ElectronClient/gui/ToggleEditorsButton/ToggleEditorsButton.js
ElectronClient/gui/ToolbarBase.js
ElectronClient/gui/ToolbarButton/styles/index.js
ElectronClient/gui/ToolbarButton/ToolbarButton.js
ReactNativeClient/lib/AsyncActionQueue.js
@@ -178,7 +175,6 @@ ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
ReactNativeClient/lib/hooks/useEffectDebugger.js
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
ReactNativeClient/lib/hooks/usePrevious.js
ReactNativeClient/lib/hooks/usePropsDebugger.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
@@ -186,7 +182,6 @@ ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
ReactNativeClient/lib/JoplinServerApi.js
ReactNativeClient/lib/ntpDate.js
ReactNativeClient/lib/services/CommandService.js
ReactNativeClient/lib/services/debug/populateDatabase.js
ReactNativeClient/lib/services/keychain/KeychainService.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.dummy.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.mobile.js

9
.gitignore vendored
View File

@@ -50,8 +50,8 @@ joplin-webclipper-source.zip
Tools/commit_hook.txt
.vscode/*
*.map
ReactNativeClient/lib/sql-extensions/spellfix.so
ReactNativeClient/lib/sql-extensions/spellfix.dylib
ReactNativeClient/lib/sql-extensions/
!ReactNativeClient/lib/sql-extensions/spellfix.dll
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
CliClient/app/LinkSelector.js
@@ -112,7 +112,6 @@ ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useJoplinMode.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useKeymap.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useLineSorting.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
@@ -139,7 +138,6 @@ ElectronClient/gui/NoteList/NoteList.js
ElectronClient/gui/NoteListControls/commands/focusSearch.js
ElectronClient/gui/NoteListControls/NoteListControls.js
ElectronClient/gui/NoteListItem.js
ElectronClient/gui/NoteTextViewer.js
ElectronClient/gui/NoteToolbar/NoteToolbar.js
ElectronClient/gui/OneDriveLoginScreen.js
ElectronClient/gui/ResizableLayout/hooks/useLayoutItemSizes.js
@@ -159,7 +157,6 @@ ElectronClient/gui/style/StyledInput.js
ElectronClient/gui/style/StyledTextInput.js
ElectronClient/gui/ToggleEditorsButton/styles/index.js
ElectronClient/gui/ToggleEditorsButton/ToggleEditorsButton.js
ElectronClient/gui/ToolbarBase.js
ElectronClient/gui/ToolbarButton/styles/index.js
ElectronClient/gui/ToolbarButton/ToolbarButton.js
ReactNativeClient/lib/AsyncActionQueue.js
@@ -171,7 +168,6 @@ ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
ReactNativeClient/lib/hooks/useEffectDebugger.js
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
ReactNativeClient/lib/hooks/usePrevious.js
ReactNativeClient/lib/hooks/usePropsDebugger.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
@@ -179,7 +175,6 @@ ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
ReactNativeClient/lib/JoplinServerApi.js
ReactNativeClient/lib/ntpDate.js
ReactNativeClient/lib/services/CommandService.js
ReactNativeClient/lib/services/debug/populateDatabase.js
ReactNativeClient/lib/services/keychain/KeychainService.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.dummy.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.mobile.js

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -13,10 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.4.1\n"
"X-Generator: Poedit 2.3.1\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
#: CliClient/app/command-cp.js:13
msgid ""
@@ -106,9 +104,9 @@ msgid "Do not ask for confirmation."
msgstr "Ne pas demander de confirmation."
#: CliClient/app/command-import.js:27
#, javascript-format
#, fuzzy, javascript-format
msgid "Output format: %s"
msgstr "Format de la sortie : %s"
msgstr "Format de la source : %s"
#: CliClient/app/command-import.js:47 ElectronClient/gui/ImportScreen.min.js:69
#, javascript-format
@@ -319,7 +317,7 @@ msgstr ""
#: CliClient/app/command-sync.js:35
msgid "Upgrade the sync target to the latest version."
msgstr "Mettre à jour la cible de synchronisation."
msgstr ""
#: CliClient/app/command-sync.js:81 CliClient/app/command-sync.js:95
#: ElectronClient/gui/OneDriveLoginScreen.min.js:40
@@ -378,6 +376,7 @@ msgid "Synchronisation target: %s (%s)"
msgstr "Cible de la synchronisation : %s (%s)"
#: CliClient/app/command-sync.js:177
#, fuzzy
msgid "Cannot initialise synchroniser."
msgstr "Impossible d'initialiser la synchronisation."
@@ -814,16 +813,14 @@ msgstr "Annuler"
msgid ""
"The app is now going to close. Please relaunch it to complete the process."
msgstr ""
"L'application va maintenance fermer. Veuillez la relancer pour terminer "
"l'opération."
#: ElectronClient/plugins/GotoAnything.min.js:446
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."
msgstr ""
"Entrez le titre d’une note, ou entrez # suivi du nom d’une étiquette, ou @ "
"suivi du nom d’un carnet."
"Entrez le titre d’une note, ou entrez # suivit du nom d’une étiquette, ou @ "
"suivit du nom d’un carnet."
#: ElectronClient/plugins/GotoAnything.min.js:486
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:20
@@ -1024,6 +1021,7 @@ msgid "strong text"
msgstr "texte en gras"
#: ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.js:147
#, fuzzy
msgid "emphasised text"
msgstr "texte en italique"
@@ -1178,14 +1176,13 @@ msgstr "Création de %s..."
#: ElectronClient/gui/NoteEditor/NoteEditor.js:344
msgid "The following attachments are being watched for changes:"
msgstr "Les changements sur les éléments suivants sont monitorés :"
msgstr ""
#: ElectronClient/gui/NoteEditor/NoteEditor.js:347
msgid ""
"The attachments will no longer be watched when you switch to a different "
"note."
msgstr ""
"Les pièces jointes ne seront plus monitorées lorsque vous changerez de note."
#: ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js:25
msgid "Select all"
@@ -1311,11 +1308,12 @@ msgstr "Importer"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:125
msgid "Command"
msgstr "Commande"
msgstr ""
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:126
#, fuzzy
msgid "Keyboard Shortcut"
msgstr "Raccourci"
msgstr "Mode de clavier"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:14
#: ElectronClient/app.js:690
@@ -1338,8 +1336,9 @@ msgid "Website and documentation"
msgstr "Documentation en ligne"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:24
#, fuzzy
msgid "Hide Joplin"
msgstr "Cacher Joplin"
msgstr "A propos de Joplin"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:26
#: ElectronClient/app.js:703
@@ -1347,8 +1346,9 @@ msgid "Close Window"
msgstr "Fermer la fenêtre"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#, fuzzy
msgid "Preferences"
msgstr "Préférences"
msgstr "Préférences"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#: ElectronClient/gui/Root.min.js:92 ElectronClient/app.js:572
@@ -1357,15 +1357,13 @@ msgstr "Options"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid "Press the shortcut"
msgstr "Taper le raccourci"
msgstr ""
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid ""
"Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the "
"shortcut."
msgstr ""
"Tapez le raccourci et appuyez sur ENTREE. Ou, appuyez sur la touche de "
"retour arrière pour supprimer le raccourci."
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
#: ElectronClient/gui/EncryptionConfigScreen.min.js:95
@@ -1379,13 +1377,11 @@ msgid ""
"may take a few minutes to complete and the app needs to be restarted. To "
"proceed please click on the link."
msgstr ""
"La cible de synchronisation doit être mise à jour. L'opération peut prendre "
"plusieurs minutes et l'application devra être re-démarrée. Pour continuer, "
"veuillez cliquer sur le lien."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:306
#, fuzzy
msgid "Restart and upgrade"
msgstr "Redémarrer et mettre à jour"
msgstr "Clefs maîtres qui peuvent être mise à niveau"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:313
msgid "Some items cannot be synchronised."
@@ -1410,10 +1406,12 @@ msgid "Set the password"
msgstr "Définir le mot de passe"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:349
#, fuzzy
msgid "One of your master keys use an obsolete encryption method."
msgstr "L'une des clefs maîtres utilise une méthode de chiffrement obsolète."
msgstr "L'une des clefs maîtres requiert un mot de passe."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:361
#, fuzzy
msgid ""
"The default encryption method has been changed, you should re-encrypt your "
"data."
@@ -1422,6 +1420,7 @@ msgstr ""
"l'appliquer à vos données."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:366
#, fuzzy
msgid "More info"
msgstr "Plus d'information"
@@ -1762,8 +1761,9 @@ msgid "Icon"
msgstr "Icône"
#: ElectronClient/gui/FolderPropertiesDialog.min.js:272
#, fuzzy
msgid "Notebook properties"
msgstr "Propriétés du carnet"
msgstr "Propriétés de la note"
#: ElectronClient/gui/NoteText.min.js:781
#, javascript-format
@@ -1936,7 +1936,7 @@ msgstr "Statistiques"
#: ElectronClient/gui/NoteContentPropertiesDialog.js:111
#, javascript-format
msgid "Read time: %s min"
msgstr "Temps de lecture : %s min"
msgstr ""
#: ElectronClient/gui/NoteContentPropertiesDialog.js:112
#: ElectronClient/gui/ShareNoteDialog.js:175
@@ -2151,8 +2151,9 @@ msgid "Templates"
msgstr "Modèles"
#: ElectronClient/app.js:668
#, fuzzy
msgid "Export all"
msgstr "Tout exporter"
msgstr "Exporter"
#: ElectronClient/app.js:683
#, javascript-format
@@ -2252,7 +2253,7 @@ msgstr "Paramètre inconnu : %s"
#: ReactNativeClient/lib/SyncTargetAmazonS3.js:28
msgid "AWS S3"
msgstr "AWS S3"
msgstr ""
#: ReactNativeClient/lib/SyncTargetDropbox.js:25
msgid "Dropbox"
@@ -2396,15 +2397,15 @@ msgstr "WebDAV : Mot de passe"
#: ReactNativeClient/lib/models/Setting.js:195
msgid "AWS S3 bucket"
msgstr "AWS S3: bucket"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:206
msgid "AWS key"
msgstr "AWS : Clef"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:216
msgid "AWS secret"
msgstr "AWS : Secret"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:230
msgid "Attachment download behaviour"
@@ -2625,6 +2626,7 @@ msgid "Editor font family"
msgstr "Police de l'éditeur"
#: ReactNativeClient/lib/models/Setting.js:553
#, fuzzy
msgid ""
"This should be a *monospace* font or some elements will render incorrectly. "
"If the font is incorrect or empty, it will default to a generic monospace "
@@ -2865,8 +2867,9 @@ msgid "Web Clipper"
msgstr "Web Clipper"
#: ReactNativeClient/lib/models/Setting.js:1259
#, fuzzy
msgid "Keyboard Shortcuts"
msgstr "Raccourcis clavier"
msgstr "Mode de clavier"
#: ReactNativeClient/lib/models/Setting.js:1264
msgid ""
@@ -3022,8 +3025,6 @@ msgstr "Certains objets ne peuvent être synchronisés."
#: ReactNativeClient/lib/components/screen-header.js:453
msgid "The sync target needs to be upgraded. Press this banner to proceed."
msgstr ""
"La cible de synchronisation doit être mise à jour. Veuillez appuyer sur "
"cette bannière pour commencer."
#: ReactNativeClient/lib/components/side-menu-content.js:126
#, javascript-format
@@ -3150,7 +3151,7 @@ msgstr "Rafraîchir"
#: ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js:42
msgid "Sync Target Upgrade"
msgstr "Mise à jour de la cible de synchro"
msgstr ""
#: ReactNativeClient/lib/components/screens/NoteTagsDialog.js:163
msgid "New tags:"
@@ -3552,6 +3553,7 @@ msgid "Forward"
msgstr "Vers l'avant"
#: ReactNativeClient/lib/commands/synchronize.js:17
#, fuzzy
msgid "Synchronize"
msgstr "Synchroniser"
@@ -3791,11 +3793,9 @@ msgid "Directory"
msgstr "Dossier"
#: ReactNativeClient/lib/services/InteropService.js:174
#, javascript-format
#, fuzzy, javascript-format
msgid "Cannot load \"%s\" module for format \"%s\" and output \"%s\""
msgstr ""
"Impossible de charger module \"%s\" pour le format d'entrée \"%s\" et de "
"sortie \"%s\""
msgstr "Impossible de charger module \"%s\" pour le format \"%s\""
#: ReactNativeClient/lib/services/InteropService.js:232
#, javascript-format

View File

@@ -15,8 +15,6 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.4\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
#: CliClient/app/command-cp.js:13
msgid ""
@@ -314,7 +312,7 @@ msgstr "指定のターゲットと同期します。(標準: sync.targetの
#: CliClient/app/command-sync.js:35
msgid "Upgrade the sync target to the latest version."
msgstr "同期先を最新バージョンにアップグレード。"
msgstr ""
#: CliClient/app/command-sync.js:81 CliClient/app/command-sync.js:95
#: ElectronClient/gui/OneDriveLoginScreen.min.js:40
@@ -798,8 +796,6 @@ msgstr "キャンセル"
msgid ""
"The app is now going to close. Please relaunch it to complete the process."
msgstr ""
"まもなくアプリケーションは終了します。もう一度起動して処理を完了させてくださ"
"い。"
#: ElectronClient/plugins/GotoAnything.min.js:446
msgid ""
@@ -1161,13 +1157,13 @@ msgstr "新しい %s を作成中..."
#: ElectronClient/gui/NoteEditor/NoteEditor.js:344
msgid "The following attachments are being watched for changes:"
msgstr "下記の添付ファイルが変更されたかどうかを監視中です。"
msgstr ""
#: ElectronClient/gui/NoteEditor/NoteEditor.js:347
msgid ""
"The attachments will no longer be watched when you switch to a different "
"note."
msgstr "添付ファイルの監視は他のノートに移動すると終了します。"
msgstr ""
#: ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js:25
msgid "Select all"
@@ -1278,7 +1274,7 @@ msgstr "ノートのプロパティ"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:62
msgid "An unexpected error occured while importing the keymap!"
msgstr "キーマップのインポート中に予期しないエラーが発生しました!"
msgstr ""
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:119
#: ElectronClient/gui/MainScreen/MainScreen.min.js:437
@@ -1293,11 +1289,12 @@ msgstr "インポート"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:125
msgid "Command"
msgstr "コマンド"
msgstr ""
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:126
#, fuzzy
msgid "Keyboard Shortcut"
msgstr "ショートカットキー"
msgstr "キーバインド"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:14
#: ElectronClient/app.js:690
@@ -1320,8 +1317,9 @@ msgid "Website and documentation"
msgstr "Webサイトとドキュメント"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:24
#, fuzzy
msgid "Hide Joplin"
msgstr "Joplinを隠す"
msgstr "Joplinについて"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:26
#: ElectronClient/app.js:703
@@ -1329,6 +1327,7 @@ msgid "Close Window"
msgstr "ウィンドウを閉じる"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#, fuzzy
msgid "Preferences"
msgstr "環境設定"
@@ -1339,15 +1338,13 @@ msgstr "オプション"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid "Press the shortcut"
msgstr "ショートカットキーを押してください"
msgstr ""
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid ""
"Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the "
"shortcut."
msgstr ""
"ショートカットキーに続けてENTERを押すことで設定します。ショートカットを削除す"
"るにはBACKSPACEを押してください。"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
#: ElectronClient/gui/EncryptionConfigScreen.min.js:95
@@ -1361,13 +1358,11 @@ msgid ""
"may take a few minutes to complete and the app needs to be restarted. To "
"proceed please click on the link."
msgstr ""
"同期するには同期先をアップグレードする必要があります。アップグレードには数分"
"かかるかもしれません。またアプリケーションの再起動が必要です。アップグレード"
"するにはリンクをクリックしてください。"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:306
#, fuzzy
msgid "Restart and upgrade"
msgstr "再起動してアップグレード"
msgstr "アップグレードが必要なマスターキー"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:313
msgid "Some items cannot be synchronised."
@@ -2119,8 +2114,9 @@ msgid "Templates"
msgstr "テンプレート"
#: ElectronClient/app.js:668
#, fuzzy
msgid "Export all"
msgstr "すべてをエクスポート"
msgstr "エクスポート"
#: ElectronClient/app.js:683
#, javascript-format
@@ -2219,7 +2215,7 @@ msgstr "不明なレベルID: %s"
#: ReactNativeClient/lib/SyncTargetAmazonS3.js:28
msgid "AWS S3"
msgstr "AWS S3"
msgstr ""
#: ReactNativeClient/lib/SyncTargetDropbox.js:25
msgid "Dropbox"
@@ -2364,15 +2360,15 @@ msgstr "WevDAV パスワード"
#: ReactNativeClient/lib/models/Setting.js:195
msgid "AWS S3 bucket"
msgstr "AWS S3 バケット"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:206
msgid "AWS key"
msgstr "AWS アクセスキーID"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:216
msgid "AWS secret"
msgstr "AWS シークレットアクセスキー"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:230
msgid "Attachment download behaviour"
@@ -2827,8 +2823,9 @@ msgid "Web Clipper"
msgstr "Webクリッパー"
#: ReactNativeClient/lib/models/Setting.js:1259
#, fuzzy
msgid "Keyboard Shortcuts"
msgstr "キーボードショートカット"
msgstr "キーバインド"
#: ReactNativeClient/lib/models/Setting.js:1264
msgid ""
@@ -2983,8 +2980,6 @@ msgstr "いくつかの項目は同期されませんでした。詳細はクリ
#: ReactNativeClient/lib/components/screen-header.js:453
msgid "The sync target needs to be upgraded. Press this banner to proceed."
msgstr ""
"同期先をアップグレードする必要があります。アップグレードするにはバナーをク"
"リックしてください。"
#: ReactNativeClient/lib/components/side-menu-content.js:126
#, javascript-format
@@ -3029,8 +3024,8 @@ msgid ""
"Error. Please check that URL, username, password, etc. are correct and that "
"the sync target is accessible. The reported error was:"
msgstr ""
"エラーです。URL、ユーザー名、パスワードなどを修正し、同期先にアクセスできるか"
"を確認してください。次が報告されたエラーです:"
"エラーです。URL、ユーザー名、パスワードなどを修正し、同期するターゲットにアク"
"セスできるかを確認してください。次が報告されたエラーです:"
#: ReactNativeClient/lib/components/shared/dropbox-login-shared.js:39
msgid "The application has been authorised!"
@@ -3107,7 +3102,7 @@ msgstr "更新"
#: ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js:42
msgid "Sync Target Upgrade"
msgstr "同期先のアップグレード"
msgstr ""
#: ReactNativeClient/lib/components/screens/NoteTagsDialog.js:163
msgid "New tags:"
@@ -3156,10 +3151,10 @@ msgid ""
"password as, for security purposes, this will be the *only* way to decrypt "
"the data! To enable encryption, please enter your password below."
msgstr ""
"暗号化を有効にするとは、*すべて*のノートや添付ファイルを再同期し、同期先に暗"
"号化した状態で送ることを意味します。パスワードはなくさないようにしてくださ"
"い。セキュリティ上、このパスワードがデータを復号する*唯一*の方法になるためで"
"す! 暗号化を有効にするには、下にパスワードを入力してください。"
"暗号化を有効にするとは、*すべて*のノートや添付ファイルを再同期し、同期ター"
"ゲットに暗号化した状態で送ることを意味します。パスワードはなくさないようにし"
"てください。セキュリティ上、このパスワードがデータを復号する*唯一*の方法にな"
"るためです! 暗号化を有効にするには、下にパスワードを入力してください。"
#: ReactNativeClient/lib/components/screens/encryption-config.js:177
msgid "Enable"
@@ -3551,35 +3546,32 @@ msgstr "ノートをどのノートブックにインポートするのか指定
#: ReactNativeClient/lib/services/KeymapService.js:124
#, javascript-format
msgid "Error loading the keymap from file: %s"
msgstr "キーマップ読み込みエラー(ファイル: %s)"
msgstr ""
#: ReactNativeClient/lib/services/KeymapService.js:141
#, javascript-format
msgid "Error saving the keymap to file: %s"
msgstr "キーマップ書き出しエラー(ファイル: %s)"
msgstr ""
#: ReactNativeClient/lib/services/KeymapService.js:204
#, javascript-format
msgid "Keymap item %s is missing the required \"command\" property."
msgstr ""
"キーマップアイテム %s は必須の \"command\" プロパティを持っていません。"
#: ReactNativeClient/lib/services/KeymapService.js:207
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid command."
msgstr "キーマップアイテム %s は %s が有効なコマンドでないため無効です。"
msgstr ""
#: ReactNativeClient/lib/services/KeymapService.js:210
#, javascript-format
msgid "Keymap item %s is missing the required \"accelerator\" property."
msgstr ""
"キーマップアイテム %s は必須の \"accelerator\" プロパティを持っていません。"
#: ReactNativeClient/lib/services/KeymapService.js:217
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid accelerator."
msgstr ""
"キーマップアイテム %s は %s が有効なショートカットキーでないため無効です。"
#: ReactNativeClient/lib/services/KeymapService.js:235
#, javascript-format
@@ -3587,13 +3579,11 @@ msgid ""
"Accelerator \"%s\" is used for \"%s\" and \"%s\" commands. This may lead to "
"unexpected behaviour."
msgstr ""
"ショートカットキー \"%s\" は \"%s\" コマンドと \"%s\" コマンドで使われていま"
"す。これにより予想外の動作が起こる可能性があります。"
#: ReactNativeClient/lib/services/KeymapService.js:260
#, javascript-format
msgid "Accelerator \"%s\" is not valid."
msgstr "ショートカットキー \"%s\" は無効です。"
msgstr ""
#: ReactNativeClient/lib/services/report.js:121
msgid "Items that cannot be synchronised"

File diff suppressed because it is too large Load Diff

View File

@@ -14,9 +14,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.4.1\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"X-Generator: Poedit 2.3.1\n"
#: CliClient/app/command-cp.js:13
msgid ""
@@ -321,7 +319,7 @@ msgstr ""
#: CliClient/app/command-sync.js:35
msgid "Upgrade the sync target to the latest version."
msgstr "Senkronizasyon hedefini en son sürüme yükseltin"
msgstr ""
#: CliClient/app/command-sync.js:81 CliClient/app/command-sync.js:95
#: ElectronClient/gui/OneDriveLoginScreen.min.js:40
@@ -815,8 +813,6 @@ msgstr "İptal et"
msgid ""
"The app is now going to close. Please relaunch it to complete the process."
msgstr ""
"Uygulama şimdi kapanacak. İşlemi tamamlamak için lütfen uygulamayı "
"kapandıktan sonar yeniden çalıştırın."
#: ElectronClient/plugins/GotoAnything.min.js:446
msgid ""
@@ -1177,13 +1173,13 @@ msgstr "Yeni %s oluşturuluyor..."
#: ElectronClient/gui/NoteEditor/NoteEditor.js:344
msgid "The following attachments are being watched for changes:"
msgstr "Şu ek dosyaları değişiklikler için izlenmekte:"
msgstr ""
#: ElectronClient/gui/NoteEditor/NoteEditor.js:347
msgid ""
"The attachments will no longer be watched when you switch to a different "
"note."
msgstr "Eğer başka bir not'a geçerseniz ek dosyalar artık izlenmeyecek."
msgstr ""
#: ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js:25
msgid "Select all"
@@ -1294,7 +1290,7 @@ msgstr "Not özellikleri"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:62
msgid "An unexpected error occured while importing the keymap!"
msgstr "Tuş dizimini içe aktarırken bir hata oluştu!"
msgstr ""
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:119
#: ElectronClient/gui/MainScreen/MainScreen.min.js:437
@@ -1309,11 +1305,12 @@ msgstr "İçe aktar"
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:125
msgid "Command"
msgstr "Komut"
msgstr ""
#: ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js:126
#, fuzzy
msgid "Keyboard Shortcut"
msgstr "Klavye Kısayolu"
msgstr "Klavye modu"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:14
#: ElectronClient/app.js:690
@@ -1336,8 +1333,9 @@ msgid "Website and documentation"
msgstr "Web sitesi ve dökümanlar"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:24
#, fuzzy
msgid "Hide Joplin"
msgstr "Joplin'i Gizle"
msgstr "Joplin hakkında"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:26
#: ElectronClient/app.js:703
@@ -1345,8 +1343,9 @@ msgid "Close Window"
msgstr "Pencereyi Kapat"
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#, fuzzy
msgid "Preferences"
msgstr "Tercihler"
msgstr "Tercihler..."
#: ElectronClient/gui/KeymapConfig/utils/getLabel.js:28
#: ElectronClient/gui/Root.min.js:92 ElectronClient/app.js:572
@@ -1355,15 +1354,13 @@ msgstr "Seçenekler"
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid "Press the shortcut"
msgstr "Kısayolu girin"
msgstr ""
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:48
msgid ""
"Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the "
"shortcut."
msgstr ""
"Kısayolu girin ve ardından ENTER tuşuna basın. Veya BACKSPACE tuşuna basarak "
"kısayolu temizleyin."
#: ElectronClient/gui/KeymapConfig/ShortcutRecorder.js:49
#: ElectronClient/gui/EncryptionConfigScreen.min.js:95
@@ -1377,14 +1374,11 @@ msgid ""
"may take a few minutes to complete and the app needs to be restarted. To "
"proceed please click on the link."
msgstr ""
"Senkronizasyon hedefi'nin Joplin senkronizasyona yeniden başlamadan once "
"güncellenmesi gerekir. Bu işlem notlarınızıın yoğunluğuna göre birkaç dakika "
"sürebilir, ve de bu işlem ardından uygulama yeniden başlatılacaktır. Bu "
"işlemi başlatmak için lütfen linke tıklayın."
#: ElectronClient/gui/MainScreen/MainScreen.min.js:306
#, fuzzy
msgid "Restart and upgrade"
msgstr "Yeniden başlat ve güncelle"
msgstr "Ana anahtarların güncellenmesi lazım"
#: ElectronClient/gui/MainScreen/MainScreen.min.js:313
msgid "Some items cannot be synchronised."
@@ -2144,8 +2138,9 @@ msgid "Templates"
msgstr "Şablonlar"
#: ElectronClient/app.js:668
#, fuzzy
msgid "Export all"
msgstr "Tümünü dışa aktar"
msgstr "Dışa aktar"
#: ElectronClient/app.js:683
#, javascript-format
@@ -2246,7 +2241,7 @@ msgstr "Bilinmeyen ID seviyesi: %s"
#: ReactNativeClient/lib/SyncTargetAmazonS3.js:28
msgid "AWS S3"
msgstr "AWS S3"
msgstr ""
#: ReactNativeClient/lib/SyncTargetDropbox.js:25
msgid "Dropbox"
@@ -2389,15 +2384,15 @@ msgstr "WebDAV şifresi"
#: ReactNativeClient/lib/models/Setting.js:195
msgid "AWS S3 bucket"
msgstr "AWS S3 deposu"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:206
msgid "AWS key"
msgstr "AWS anahtarı"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:216
msgid "AWS secret"
msgstr "AWS gizli anahtarı"
msgstr ""
#: ReactNativeClient/lib/models/Setting.js:230
msgid "Attachment download behaviour"
@@ -2855,8 +2850,9 @@ msgid "Web Clipper"
msgstr "Web Alıntılayıcısı"
#: ReactNativeClient/lib/models/Setting.js:1259
#, fuzzy
msgid "Keyboard Shortcuts"
msgstr "Klavye Kısayolları"
msgstr "Klavye modu"
#: ReactNativeClient/lib/models/Setting.js:1264
msgid ""
@@ -3012,8 +3008,6 @@ msgstr "Bazı öğeler senkronize edilemiyor. Detayları için tıklayın."
#: ReactNativeClient/lib/components/screen-header.js:453
msgid "The sync target needs to be upgraded. Press this banner to proceed."
msgstr ""
"Senkronizasyon hedefinin güncellenmesi gerekmekte. Bu banner'a tıklayarak "
"devam edebilirsiniz."
#: ReactNativeClient/lib/components/side-menu-content.js:126
#, javascript-format
@@ -3135,7 +3129,7 @@ msgstr "Yenile"
#: ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js:42
msgid "Sync Target Upgrade"
msgstr "Senkronizasyon Hedefi Güncellemesi"
msgstr ""
#: ReactNativeClient/lib/components/screens/NoteTagsDialog.js:163
msgid "New tags:"
@@ -3584,37 +3578,32 @@ msgstr "Lütfen notların alınacağı not defterini belirtin."
#: ReactNativeClient/lib/services/KeymapService.js:124
#, javascript-format
msgid "Error loading the keymap from file: %s"
msgstr "%s dosyasından tuş haritası yüklenemedi"
msgstr ""
#: ReactNativeClient/lib/services/KeymapService.js:141
#, javascript-format
msgid "Error saving the keymap to file: %s"
msgstr "%s dosyasına tuş haritası kaydedilemedi"
msgstr ""
#: ReactNativeClient/lib/services/KeymapService.js:204
#, javascript-format
msgid "Keymap item %s is missing the required \"command\" property."
msgstr ""
"%s tuş haritası, işlemler için gerekli olan \"command\" özelliğini "
"barındırmıyor."
#: ReactNativeClient/lib/services/KeymapService.js:207
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid command."
msgstr "%s tuş haritası geçersizdir, çünkü %s geçerli bir komut değildir."
msgstr ""
#: ReactNativeClient/lib/services/KeymapService.js:210
#, javascript-format
msgid "Keymap item %s is missing the required \"accelerator\" property."
msgstr ""
"%s tuş haritası, işlemler için gerekli olan \"accelerator\" özelliğini "
"barındırmıyor."
#: ReactNativeClient/lib/services/KeymapService.js:217
#, javascript-format
msgid "Keymap item %s is invalid because %s is not a valid accelerator."
msgstr ""
"%s tuş haritası geçersizdir, çünkü %s geçerli bir accelerator değildir."
#: ReactNativeClient/lib/services/KeymapService.js:235
#, javascript-format
@@ -3622,13 +3611,11 @@ msgid ""
"Accelerator \"%s\" is used for \"%s\" and \"%s\" commands. This may lead to "
"unexpected behaviour."
msgstr ""
"Kısayol \"%s\", \"%s\" ve \"%s\" komutları için kullanılıyor. Bu beklenmeyen "
"sonuçlara sebep verebilir."
#: ReactNativeClient/lib/services/KeymapService.js:260
#, javascript-format
msgid "Accelerator \"%s\" is not valid."
msgstr "Kısayol \"%s\" geçersiz."
msgstr ""
#: ReactNativeClient/lib/services/report.js:121
msgid "Items that cannot be synchronised"
@@ -3962,7 +3949,7 @@ msgstr ""
#~ "Şu anda not defteriniz yok. (+) butonuna tıklayarak bir tane oluşturun."
#~ msgid "Welcome"
#~ msgstr "Hoş Geldiniz"
#~ msgstr "Hoşgeldiniz"
#~ msgid "Separate each tag by a comma."
#~ msgstr "Her etiketi virgülle ayırın."

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "1.2.3",
"version": "1.0.168",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -5880,11 +5880,6 @@
"is-fullwidth-code-point": "^2.0.0"
}
},
"slug": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/slug/-/slug-3.5.0.tgz",
"integrity": "sha512-+pZLDhMtmAc+ZcojQSMlUKDZBYmvhZiZmK8Ffx/D3Q/MIMHPDBAMbWvWN8vJb9xl2MfbDdRWxFzrdOhBiyVpow=="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -6747,6 +6742,11 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
},
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA=="
},
"unpack-string": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz",
@@ -6849,6 +6849,14 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
"uslug": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz",
"integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=",
"requires": {
"unorm": ">= 1.0.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

View File

@@ -28,7 +28,7 @@
],
"owner": "Laurent Cozic"
},
"version": "1.2.3",
"version": "1.0.168",
"bin": {
"joplin": "./main.js"
},
@@ -98,7 +98,6 @@
"sax": "^1.2.4",
"server-destroy": "^1.0.1",
"sharp": "^0.23.2",
"slug": "^3.5.0",
"sprintf-js": "^1.1.1",
"sqlite3": "^4.1.1",
"string-padding": "^1.0.2",
@@ -110,6 +109,7 @@
"terminal-kit": "^1.30.0",
"tkwidgets": "^0.5.26",
"url-parse": "^1.4.7",
"uslug": "^1.0.4",
"uuid": "^3.0.1",
"valid-url": "^1.0.9",
"word-wrap": "^1.2.3",

View File

@@ -1,163 +1,163 @@
/* eslint-disable no-unused-vars */
/* eslint prefer-const: 0*/
// require('app-module-path').addPath(__dirname);
require('app-module-path').addPath(__dirname);
// const { time } = require('lib/time-utils.js');
// const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, asyncTest, db, synchronizer, fileApi, sleep, createNTestNotes, switchClient, createNTestFolders } = require('test-utils.js');
// const SearchEngine = require('lib/services/searchengine/SearchEngine');
// const Note = require('lib/models/Note');
// const Folder = require('lib/models/Folder');
// const Tag = require('lib/models/Tag');
// const ItemChange = require('lib/models/ItemChange');
// const Setting = require('lib/models/Setting');
// const Resource = require('lib/models/Resource.js');
// const { shim } = require('lib/shim');
// const ResourceService = require('lib/services/ResourceService.js');
const { time } = require('lib/time-utils.js');
const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, asyncTest, db, synchronizer, fileApi, sleep, createNTestNotes, switchClient, createNTestFolders } = require('test-utils.js');
const SearchEngine = require('lib/services/searchengine/SearchEngine');
const Note = require('lib/models/Note');
const Folder = require('lib/models/Folder');
const Tag = require('lib/models/Tag');
const ItemChange = require('lib/models/ItemChange');
const Setting = require('lib/models/Setting');
const Resource = require('lib/models/Resource.js');
const { shim } = require('lib/shim');
const ResourceService = require('lib/services/ResourceService.js');
// process.on('unhandledRejection', (reason, p) => {
// console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// });
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
// let engine = null;
let engine = null;
// const ids = (array) => array.map(a => a.id);
const ids = (array) => array.map(a => a.id);
// describe('services_SearchFuzzy', function() {
// beforeEach(async (done) => {
// await setupDatabaseAndSynchronizer(1);
// await switchClient(1);
describe('services_SearchFuzzy', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
// engine = new SearchEngine();
// engine.setDb(db());
engine = new SearchEngine();
engine.setDb(db());
// Setting.setValue('db.fuzzySearchEnabled', 1);
// done();
// });
Setting.setValue('db.fuzzySearchEnabled', 1);
done();
});
// it('should return note almost matching title', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'If It Ain\'t Baroque, Don\'t Fix It' });
// const n2 = await Note.save({ title: 'Important note' });
it('should return note almost matching title', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'If It Ain\'t Baroque, Don\'t Fix It' });
const n2 = await Note.save({ title: 'Important note' });
// await engine.syncTables();
// rows = await engine.search('Broke', { fuzzy: false });
// expect(rows.length).toBe(0);
await engine.syncTables();
rows = await engine.search('Broke', { fuzzy: false });
expect(rows.length).toBe(0);
// rows = await engine.search('Broke', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
rows = await engine.search('Broke', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('title:Broke', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
rows = await engine.search('title:Broke', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('title:"Broke"', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
rows = await engine.search('title:"Broke"', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('Imprtant', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n2.id);
// }));
rows = await engine.search('Imprtant', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n2.id);
}));
// it('should order results by min fuzziness', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'I demand you take me to him' });
// const n2 = await Note.save({ title: 'He demanded an answer' });
// const n3 = await Note.save({ title: 'Don\'t you make demands of me' });
// const n4 = await Note.save({ title: 'No drama for me' });
// const n5 = await Note.save({ title: 'Just minding my own business' });
it('should order results by min fuzziness', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'I demand you take me to him' });
const n2 = await Note.save({ title: 'He demanded an answer' });
const n3 = await Note.save({ title: 'Don\'t you make demands of me' });
const n4 = await Note.save({ title: 'No drama for me' });
const n5 = await Note.save({ title: 'Just minding my own business' });
// await engine.syncTables();
// rows = await engine.search('demand', { fuzzy: false });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
await engine.syncTables();
rows = await engine.search('demand', { fuzzy: false });
expect(rows.length).toBe(1);
expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('demand', { fuzzy: true });
// expect(rows.length).toBe(3);
// expect(rows[0].id).toBe(n1.id);
// expect(rows[1].id).toBe(n3.id);
// expect(rows[2].id).toBe(n2.id);
// }));
rows = await engine.search('demand', { fuzzy: true });
expect(rows.length).toBe(3);
expect(rows[0].id).toBe(n1.id);
expect(rows[1].id).toBe(n3.id);
expect(rows[2].id).toBe(n2.id);
}));
// it('should consider any:1', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'cat' });
// const n2 = await Note.save({ title: 'cats' });
// const n3 = await Note.save({ title: 'cot' });
it('should consider any:1', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'cat' });
const n2 = await Note.save({ title: 'cats' });
const n3 = await Note.save({ title: 'cot' });
// const n4 = await Note.save({ title: 'defenestrate' });
// const n5 = await Note.save({ title: 'defenstrate' });
// const n6 = await Note.save({ title: 'defenestrated' });
const n4 = await Note.save({ title: 'defenestrate' });
const n5 = await Note.save({ title: 'defenstrate' });
const n6 = await Note.save({ title: 'defenestrated' });
// const n7 = await Note.save({ title: 'he defenestrated the cat' });
const n7 = await Note.save({ title: 'he defenestrated the cat' });
// await engine.syncTables();
await engine.syncTables();
// rows = await engine.search('defenestrated cat', { fuzzy: true });
// expect(rows.length).toBe(1);
rows = await engine.search('defenestrated cat', { fuzzy: true });
expect(rows.length).toBe(1);
// rows = await engine.search('any:1 defenestrated cat', { fuzzy: true });
// expect(rows.length).toBe(7);
// }));
rows = await engine.search('any:1 defenestrated cat', { fuzzy: true });
expect(rows.length).toBe(7);
}));
// it('should leave phrase searches alone', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'abc def' });
// const n2 = await Note.save({ title: 'def ghi' });
// const n3 = await Note.save({ title: 'ghi jkl' });
// const n4 = await Note.save({ title: 'def abc' });
// const n5 = await Note.save({ title: 'mno pqr ghi jkl' });
it('should leave phrase searches alone', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'abc def' });
const n2 = await Note.save({ title: 'def ghi' });
const n3 = await Note.save({ title: 'ghi jkl' });
const n4 = await Note.save({ title: 'def abc' });
const n5 = await Note.save({ title: 'mno pqr ghi jkl' });
// await engine.syncTables();
await engine.syncTables();
// rows = await engine.search('abc def', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n1.id);
// expect(rows.map(r=>r.id)).toContain(n4.id);
rows = await engine.search('abc def', { fuzzy: true });
expect(rows.length).toBe(2);
expect(rows.map(r=>r.id)).toContain(n1.id);
expect(rows.map(r=>r.id)).toContain(n4.id);
// rows = await engine.search('"abc def"', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows.map(r=>r.id)).toContain(n1.id);
rows = await engine.search('"abc def"', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows.map(r=>r.id)).toContain(n1.id);
// rows = await engine.search('"ghi jkl"', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n5.id);
rows = await engine.search('"ghi jkl"', { fuzzy: true });
expect(rows.length).toBe(2);
expect(rows.map(r=>r.id)).toContain(n3.id);
expect(rows.map(r=>r.id)).toContain(n5.id);
// rows = await engine.search('"ghi jkl" mno', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows.map(r=>r.id)).toContain(n5.id);
rows = await engine.search('"ghi jkl" mno', { fuzzy: true });
expect(rows.length).toBe(1);
expect(rows.map(r=>r.id)).toContain(n5.id);
// rows = await engine.search('any:1 "ghi jkl" mno', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n5.id);
// }));
rows = await engine.search('any:1 "ghi jkl" mno', { fuzzy: true });
expect(rows.length).toBe(2);
expect(rows.map(r=>r.id)).toContain(n3.id);
expect(rows.map(r=>r.id)).toContain(n5.id);
}));
// it('should leave wild card searches alone', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'abc def' });
// const n2 = await Note.save({ title: 'abcc ghi' });
// const n3 = await Note.save({ title: 'abccc ghi' });
// const n4 = await Note.save({ title: 'abcccc ghi' });
// const n5 = await Note.save({ title: 'wxy zzz' });
it('should leave wild card searches alone', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: 'abc def' });
const n2 = await Note.save({ title: 'abcc ghi' });
const n3 = await Note.save({ title: 'abccc ghi' });
const n4 = await Note.save({ title: 'abcccc ghi' });
const n5 = await Note.save({ title: 'wxy zzz' });
// await engine.syncTables();
await engine.syncTables();
// rows = await engine.search('abc*', { fuzzy: true });
rows = await engine.search('abc*', { fuzzy: true });
// expect(rows.length).toBe(4);
// expect(rows.map(r=>r.id)).toContain(n1.id);
// expect(rows.map(r=>r.id)).toContain(n2.id);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n4.id);
// }));
expect(rows.length).toBe(4);
expect(rows.map(r=>r.id)).toContain(n1.id);
expect(rows.map(r=>r.id)).toContain(n2.id);
expect(rows.map(r=>r.id)).toContain(n3.id);
expect(rows.map(r=>r.id)).toContain(n4.id);
}));
// });
});

View File

@@ -51,9 +51,9 @@ describe('timeUtils', function() {
expect(time.goForwardInTime(startDate, 1, 'day')).toBe(endDate.getTime().toString());
// startDate = new Date('9 Aug 2020');
// endDate = new Date('9 Aug 2020'); // week start;
// expect(time.goForwardInTime(startDate, 0, 'week')).toBe(endDate.getTime().toString());
startDate = new Date('9 Aug 2020');
endDate = new Date('9 Aug 2020'); // week start;
expect(time.goForwardInTime(startDate, 0, 'week')).toBe(endDate.getTime().toString());
startDate = new Date('02 Jan 2020');
endDate = new Date('01 Feb 2020');

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Joplin Web Clipper [DEV]",
"version": "1.2.0",
"version": "1.0.25",
"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

@@ -34,7 +34,6 @@ const KeymapService = require('lib/services/KeymapService').default;
const TemplateUtils = require('lib/TemplateUtils');
const CssUtils = require('lib/CssUtils');
const resourceEditWatcherReducer = require('lib/services/ResourceEditWatcher/reducer').default;
// const populateDatabase = require('lib/services/debug/populateDatabase').default;
const versionInfo = require('lib/versionInfo').default;
const commands = [
@@ -100,8 +99,6 @@ const appDefaultState = Object.assign({}, defaultState, {
watchedNoteFiles: [],
lastEditorScrollPercents: {},
devToolsVisible: false,
visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
focusedField: null,
});
class Application extends BaseApplication {
@@ -283,31 +280,6 @@ class Application extends BaseApplication {
newState.devToolsVisible = action.value;
break;
case 'VISIBLE_DIALOGS_ADD':
newState = Object.assign({}, state);
newState.visibleDialogs[state.name] = true;
break;
case 'VISIBLE_DIALOGS_REMOVE':
newState = Object.assign({}, state);
delete newState.visibleDialogs[state.name];
break;
case 'FOCUS_SET':
newState = Object.assign({}, state);
newState.focusedField = action.field;
break;
case 'FOCUS_CLEAR':
// A field can only clear its own state
if (action.field === state.focusedField) {
newState = Object.assign({}, state);
newState.focusedField = null;
}
break;
}
} catch (error) {
error.message = `In reducer: ${error.message} Action: ${JSON.stringify(action)}`;
@@ -405,7 +377,7 @@ class Application extends BaseApplication {
await this.updateMenu(screen);
}
async updateMenu(screen, updateStates = true) {
async updateMenu(screen) {
if (this.lastMenuScreen_ === screen) return;
const cmdService = CommandService.instance();
@@ -768,6 +740,7 @@ class Application extends BaseApplication {
const separator = () => {
return {
type: 'separator',
screens: ['Main'],
};
};
@@ -1015,8 +988,6 @@ class Application extends BaseApplication {
Menu.setApplicationMenu(menu);
this.lastMenuScreen_ = screen;
if (updateStates) await this.updateMenuItemStates();
}
async updateMenuItemStates(state = null) {
@@ -1126,7 +1097,7 @@ class Application extends BaseApplication {
try {
await keymapService.loadCustomKeymap(`${dir}/keymap-desktop.json`);
} catch (err) {
reg.logger().error(err.message);
bridge().showErrorMessageBox(err.message);
}
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
@@ -1159,7 +1130,7 @@ class Application extends BaseApplication {
CommandService.instance().registerDeclaration(declaration);
}
this.updateMenu('Main', false);
this.updateMenu('Main');
// Since the settings need to be loaded before the store is created, it will never
// receive the SETTING_UPDATE_ALL even, which mean state.settings will not be
@@ -1284,8 +1255,6 @@ class Application extends BaseApplication {
};
bridge().addEventListener('nativeThemeUpdated', this.bridge_nativeThemeUpdated);
// await populateDatabase(reg.db());
}
}

View File

@@ -27,14 +27,10 @@ export const runtime = ():CommandRuntime => {
// await comp.saveNoteAndWait(comp.formNote);
},
isEnabled: (props:any) => {
if (props.routeName !== 'Main') return false;
return !!props.noteId;
},
mapStateToProps: (state:any) => {
return {
noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
routeName: state.route.routeName,
};
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
},
};
};

View File

@@ -18,11 +18,10 @@ export const runtime = ():CommandRuntime => {
ExternalEditWatcher.instance().stopWatching(props.noteId);
},
isEnabled: (props:any) => {
if (props.routeName !== 'Main') return false;
return !!props.noteId;
},
mapStateToProps: (state:any) => {
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null, routeName: state.route.routeName };
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
},
};
};

View File

@@ -526,7 +526,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
const label = [md.label()];
if (md.unitLabel) label.push(`(${md.unitLabel()})`);
const inputStyle:any = Object.assign({}, textInputBaseStyle);
const inputStyle = Object.assign({}, textInputBaseStyle);
return (
<div key={key} style={rowStyle}>

View File

@@ -62,7 +62,7 @@ export const KeymapConfigScreen = ({ themeId }: KeymapConfigScreenProps) => {
const keymapFile = await shim.fsDriver().readFile(actualFilePath, 'utf-8');
overrideKeymapItems(JSON.parse(keymapFile));
} catch (err) {
bridge().showErrorMessageBox(_('Error: %s', err.message));
bridge().showErrorMessageBox(`${_('An unexpected error occured while importing the keymap!')}\n${err.message}`);
}
}
};

View File

@@ -224,7 +224,7 @@ class MainScreenComponent extends React.Component<any, any> {
}) });
}
componentDidUpdate(prevProps:any, prevState:any) {
componentDidUpdate(prevProps:any) {
if (this.props.noteListVisibility !== prevProps.noteListVisibility || this.props.sidebarVisibility !== prevProps.sidebarVisibility) {
this.setState({ layout: produce(this.state.layout, (draftState:any) => {
const noteListColumn = findItemByKey(draftState, 'noteListColumn');
@@ -238,27 +238,6 @@ class MainScreenComponent extends React.Component<any, any> {
if (prevProps.style.width !== this.props.style.width || prevProps.style.height !== this.props.style.height) {
this.updateRootLayoutSize();
}
if (this.state.notePropertiesDialogOptions !== prevState.notePropertiesDialogOptions) {
this.props.dispatch({
type: this.state.notePropertiesDialogOptions && this.state.notePropertiesDialogOptions.visible ? 'VISIBLE_DIALOGS_ADD' : 'VISIBLE_DIALOGS_REMOVE',
name: 'noteProperties',
});
}
if (this.state.noteContentPropertiesDialogOptions !== prevState.noteContentPropertiesDialogOptions) {
this.props.dispatch({
type: this.state.noteContentPropertiesDialogOptions && this.state.noteContentPropertiesDialogOptions.visible ? 'VISIBLE_DIALOGS_ADD' : 'VISIBLE_DIALOGS_REMOVE',
name: 'noteContentProperties',
});
}
if (this.state.shareNoteDialogOptions !== prevState.shareNoteDialogOptions) {
this.props.dispatch({
type: this.state.shareNoteDialogOptions && this.state.shareNoteDialogOptions.visible ? 'VISIBLE_DIALOGS_ADD' : 'VISIBLE_DIALOGS_REMOVE',
name: 'shareNote',
});
}
}
componentDidMount() {
@@ -566,7 +545,7 @@ class MainScreenComponent extends React.Component<any, any> {
const bodyEditor = this.props.settingEditorCodeView ? 'CodeMirror' : 'TinyMCE';
return <NoteEditor key={key} bodyEditor={bodyEditor} />;
} else if (key === 'noteListControls') {
return <NoteListControls key={key} showNewNoteButtons={this.props.focusedField !== 'globalSearch'} />;
return <NoteListControls key={key} />;
}
throw new Error(`Invalid layout component: ${key}`);
@@ -650,7 +629,6 @@ const mapStateToProps = (state:any) => {
customCss: state.customCss,
editorNoteStatuses: state.editorNoteStatuses,
hasNotesBeingSaved: stateUtils.hasNotesBeingSaved(state),
focusedField: state.focusedField,
};
};

View File

@@ -1,5 +1,7 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
const Note = require('lib/models/Note');
const BaseModel = require('lib/BaseModel');
// const { _ } = require('lib/locale');
const { uuid } = require('lib/uuid.js');
export const declaration:CommandDeclaration = {
@@ -29,18 +31,14 @@ export const runtime = (comp:any):CommandRuntime => {
id: comp.searchId_,
});
} else {
// Note: Normally there's no need to do anything when the search query
// is cleared as the reducer should handle all state changes.
// https://github.com/laurent22/joplin/issues/3748
// const note = await Note.load(comp.props.selectedNoteId);
// if (note) {
// comp.props.dispatch({
// type: 'FOLDER_AND_NOTE_SELECT',
// folderId: note.parent_id,
// noteId: note.id,
// });
// }
const note = await Note.load(comp.props.selectedNoteId);
if (note) {
comp.props.dispatch({
type: 'FOLDER_AND_NOTE_SELECT',
folderId: note.parent_id,
noteId: note.id,
});
}
}
},
};

View File

@@ -152,8 +152,6 @@ export default function NoteContentPropertiesDialog(props:NoteContentPropertiesD
textAlign: 'center',
};
const readTimeLabel = _('Read time: %s min', formatReadTime(strippedReadTime));
return (
<div style={theme.dialogModalLayer}>
<div style={theme.dialogBox}>
@@ -166,8 +164,8 @@ export default function NoteContentPropertiesDialog(props:NoteContentPropertiesD
{tableBodyComps}
</tbody>
</table>
<div style={{ ...labelCompStyle, marginTop: 10 }}>
{readTimeLabel}
<div style={labelCompStyle}>
{_('Read time: %s min', formatReadTime(strippedReadTime))}
</div>
<DialogButtonRow themeId={props.themeId} onClick={buttonRow_click} okButtonShow={false} cancelButtonLabel={_('Close')}/>
</div>

View File

@@ -9,7 +9,6 @@ import { useScrollHandler, usePrevious, cursorPositionToTextOffset, useRootSize
import Toolbar from './Toolbar';
import styles_ from './styles';
import { RenderedBody, defaultRenderedBody } from './utils/types';
import NoteTextViewer from '../../../NoteTextViewer';
import Editor from './Editor';
// @ts-ignore
@@ -18,6 +17,7 @@ const { bridge } = require('electron').remote.require('./bridge');
const Note = require('lib/models/Note.js');
const { clipboard } = require('electron');
const Setting = require('lib/models/Setting.js');
const NoteTextViewer = require('../../../NoteTextViewer.min');
const shared = require('lib/components/shared/note-screen-shared.js');
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
@@ -37,7 +37,6 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
const [renderedBody, setRenderedBody] = useState<RenderedBody>(defaultRenderedBody()); // Viewer content
const [webviewReady, setWebviewReady] = useState(false);
const previousContent = usePrevious(props.content);
const previousRenderedBody = usePrevious(renderedBody);
const previousSearchMarkers = usePrevious(props.searchMarkers);
const previousContentKey = usePrevious(props.contentKey);
@@ -360,7 +359,6 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
/* These must be important to prevent the codemirror defaults from taking over*/
.CodeMirror {
font-family: monospace;
font-size: ${theme.editorFontSize}px;
height: 100% !important;
width: 100% !important;
color: inherit !important;
@@ -374,37 +372,37 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
/* be applied to the viewer. */
padding-bottom: 400px !important;
}
.cm-header-1 {
font-size: 1.5em;
}
.cm-header-2 {
font-size: 1.3em;
}
.cm-header-3 {
font-size: 1.1em;
}
.cm-header-4, .cm-header-5, .cm-header-6 {
font-size: 1em;
}
.cm-header-1, .cm-header-2, .cm-header-3, .cm-header-4, .cm-header-5, .cm-header-6 {
line-height: 1.5em;
}
.cm-search-marker {
background: ${theme.searchMarkerBackgroundColor};
color: ${theme.searchMarkerColor} !important;
}
.cm-search-marker-selected {
background: ${theme.selectedColor2};
color: ${theme.color2} !important;
}
.cm-search-marker-scrollbar {
background: ${theme.searchMarkerBackgroundColor};
-moz-box-sizing: border-box;
@@ -418,27 +416,6 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
background-color: inherit !important;
border-bottom: 1px dotted #dc322f;
}
/* The default dark theme colors don't have enough contrast with the background */
.cm-s-nord span.cm-comment {
color: #9aa4b6 !important;
}
.cm-s-dracula span.cm-comment {
color: #a1abc9 !important;
}
.cm-s-monokai span.cm-comment {
color: #908b74 !important;
}
.cm-s-material-darker span.cm-comment {
color: #878787 !important;
}
.cm-s-solarized.cm-s-dark span.cm-comment {
color: #8ba1a7 !important;
}
`));
return () => {
@@ -502,18 +479,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
}, [renderedBody, webviewReady]);
useEffect(() => {
if (!props.searchMarkers) return;
// If there is a currently active search, it's important to re-search the text as the user
// types. However this is slow for performance so we ONLY want it to happen when there is
// a search
// Note that since the CodeMirror component also needs to handle the viewer pane, we need
// to check if the rendered body has changed too (it will be changed with a delay after
// props.content has been updated).
const textChanged = props.searchMarkers.keywords.length > 0 && (props.content !== previousContent || renderedBody !== previousRenderedBody);
if (props.searchMarkers !== previousSearchMarkers || textChanged) {
if (props.searchMarkers !== previousSearchMarkers || renderedBody !== previousRenderedBody) {
webviewRef.current.wrappedInstance.send('setMarkers', props.searchMarkers.keywords, props.searchMarkers.options);
if (editorRef.current) {
@@ -522,7 +488,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
props.setLocalSearchResultCount(matches);
}
}
}, [props.searchMarkers, previousSearchMarkers, props.setLocalSearchResultCount, props.content, previousContent, renderedBody, previousRenderedBody, renderedBody]);
}, [props.searchMarkers, props.setLocalSearchResultCount, renderedBody]);
const cellEditorStyle = useMemo(() => {
const output = { ...styles.cellEditor };
@@ -574,13 +540,14 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
editorRef.current.refresh();
}, [rootSize, styles.editor, props.visiblePanes]);
const editorReadOnly = props.visiblePanes.indexOf('editor') < 0;
function renderEditor() {
return (
<div style={cellEditorStyle}>
<Editor
value={props.content}
searchMarkers={props.searchMarkers}
ref={editorRef}
mode={props.contentMarkupLanguage === Note.MARKUP_LANGUAGE_HTML ? 'xml' : 'joplin-markdown'}
codeMirrorTheme={styles.editor.codeMirrorTheme}
@@ -616,6 +583,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
<Toolbar
themeId={props.themeId}
dispatch={props.dispatch}
disabled={editorReadOnly}
/>
{props.noteToolbar}
</div>

View File

@@ -17,17 +17,18 @@ import useCursorUtils from './utils/useCursorUtils';
import useLineSorting from './utils/useLineSorting';
import useEditorSearch from './utils/useEditorSearch';
import useJoplinMode from './utils/useJoplinMode';
import useKeymap from './utils/useKeymap';
import 'codemirror/keymap/emacs';
import 'codemirror/keymap/vim';
import 'codemirror/keymap/sublime'; // Used for swapLineUp and swapLineDown
import 'codemirror/mode/meta';
const { shim } = require('lib/shim.js');
const { reg } = require('lib/registry.js');
// Based on http://pypl.github.io/PYPL.html
// +XML (HTML) +CSS and Markdown added
const topLanguages = [
'python',
'clike',
@@ -50,16 +51,8 @@ const topLanguages = [
'haskell',
'pascal',
'css',
// Additional languages, not in the PYPL list
'xml', // For HTML too
'xml',
'markdown',
'yaml',
'shell',
'dockerfile',
'diff',
'erlang',
'sql',
];
// Load Top Modes
for (let i = 0; i < topLanguages.length; i++) {
@@ -74,7 +67,6 @@ for (let i = 0; i < topLanguages.length; i++) {
export interface EditorProps {
value: string,
searchMarkers: any,
mode: string,
style: any,
codeMirrorTheme: any,
@@ -99,7 +91,6 @@ function Editor(props: EditorProps, ref: any) {
useLineSorting(CodeMirror);
useEditorSearch(CodeMirror);
useJoplinMode(CodeMirror);
useKeymap(CodeMirror);
useImperativeHandle(ref, () => {
return editor;
@@ -142,6 +133,83 @@ function Editor(props: EditorProps, ref: any) {
}
}, []);
useEffect(() => {
CodeMirror.keyMap.basic = {
'Left': 'goCharLeft',
'Right': 'goCharRight',
'Up': 'goLineUp',
'Down': 'goLineDown',
'End': 'goLineRight',
'Home': 'goLineLeftSmart',
'PageUp': 'goPageUp',
'PageDown': 'goPageDown',
'Delete': 'delCharAfter',
'Backspace': 'delCharBefore',
'Shift-Backspace': 'delCharBefore',
'Tab': 'smartListIndent',
'Shift-Tab': 'smartListUnindent',
'Enter': 'insertListElement',
'Insert': 'toggleOverwrite',
'Esc': 'singleSelection',
};
if (shim.isMac()) {
CodeMirror.keyMap.default = {
// MacOS
'Cmd-A': 'selectAll',
'Cmd-D': 'deleteLine',
'Cmd-Z': 'undo',
'Shift-Cmd-Z': 'redo',
'Cmd-Y': 'redo',
'Cmd-Home': 'goDocStart',
'Cmd-Up': 'goDocStart',
'Cmd-End': 'goDocEnd',
'Cmd-Down': 'goDocEnd',
'Cmd-Left': 'goLineLeft',
'Cmd-Right': 'goLineRight',
'Alt-Left': 'goGroupLeft',
'Alt-Right': 'goGroupRight',
'Alt-Backspace': 'delGroupBefore',
'Alt-Delete': 'delGroupAfter',
'Cmd-[': 'indentLess',
'Cmd-]': 'indentMore',
'Cmd-/': 'toggleComment',
'Cmd-Opt-S': 'sortSelectedLines',
'Opt-Up': 'swapLineUp',
'Opt-Down': 'swapLineDown',
'fallthrough': 'basic',
};
} else {
CodeMirror.keyMap.default = {
// Windows/linux
'Ctrl-A': 'selectAll',
'Ctrl-D': 'deleteLine',
'Ctrl-Z': 'undo',
'Shift-Ctrl-Z': 'redo',
'Ctrl-Y': 'redo',
'Ctrl-Home': 'goDocStart',
'Ctrl-End': 'goDocEnd',
'Ctrl-Up': 'goLineUp',
'Ctrl-Down': 'goLineDown',
'Ctrl-Left': 'goGroupLeft',
'Ctrl-Right': 'goGroupRight',
'Alt-Left': 'goLineStart',
'Alt-Right': 'goLineEnd',
'Ctrl-Backspace': 'delGroupBefore',
'Ctrl-Delete': 'delGroupAfter',
'Ctrl-[': 'indentLess',
'Ctrl-]': 'indentMore',
'Ctrl-/': 'toggleComment',
'Ctrl-Alt-S': 'sortSelectedLines',
'Alt-Up': 'swapLineUp',
'Alt-Down': 'swapLineDown',
'fallthrough': 'basic',
};
}
}, []);
useEffect(() => {
if (!editorParent.current) return () => {};
@@ -170,11 +238,6 @@ function Editor(props: EditorProps, ref: any) {
cm.on('drop', editor_drop);
cm.on('dragover', editor_drag);
// It's possible for searchMarkers to be available before the editor
// In these cases we set the markers asap so the user can see them as
// soon as the editor is ready
if (props.searchMarkers) { cm.setMarkers(props.searchMarkers.keywords, props.searchMarkers.options); }
return () => {
// Clean up codemirror
cm.off('change', editor_change);

View File

@@ -1,11 +1,13 @@
import * as React from 'react';
import CommandService from 'lib/services/CommandService';
import ToolbarBase from '../../../ToolbarBase';
import CommandService from '../../../../lib/services/CommandService';
const ToolbarBase = require('../../../Toolbar.min.js');
const { buildStyle } = require('lib/theme');
interface ToolbarProps {
themeId: number,
dispatch: Function,
disabled: boolean,
}
function styles_(props:ToolbarProps) {
@@ -47,5 +49,5 @@ export default function Toolbar(props:ToolbarProps) {
cmdService.commandToToolbarButton('toggleEditors'),
];
return <ToolbarBase style={styles.root} items={toolbarItems} />;
return <ToolbarBase disabled={props.disabled} style={styles.root} items={toolbarItems} />;
}

View File

@@ -119,8 +119,7 @@ export default function useEditorSearch(CodeMirror: any) {
// We only want to highlight all matches when there is only 1 search term
if (keywords.length !== 1 || keywords[0].value == '') {
clearOverlay(this);
const prev = keywords.length > 1 ? keywords[0].value : '';
setPreviousKeywordValue(prev);
setPreviousKeywordValue('');
return 0;
}

View File

@@ -21,8 +21,7 @@ export default function useJoplinMode(CodeMirror: any) {
const inlineKatexOpenRE = /(?<!\S)\$(?=[^\s$].*?[^\\\s$]\$(?!\S))/;
const inlineKatexCloseRE = /(?<![\\\s$])\$(?!\S)/;
const blockKatexOpenRE = /(?<!\S)\$\$/;
const blockKatexCloseRE = /(?<![\\\s])\$\$/;
const blockKatexRE = /(?<!\\)\$\$/;
// Find token will search for a valid katex start or end token
// If found then it will return the index, otherwise -1
@@ -56,19 +55,19 @@ export default function useJoplinMode(CodeMirror: any) {
let nextTokenPos = stream.string.length;
let closing = false;
const blockPos = findToken(stream, blockKatexRE);
if (state.openCharacter) {
currentMode = stex;
currentState = state.inner;
tokenLabel = 'katex-marker-close';
closing = true;
const blockPos = findToken(stream, blockKatexCloseRE);
const inlinePos = findToken(stream, inlineKatexCloseRE);
if (state.openCharacter === '$$' && blockPos !== -1) nextTokenPos = blockPos;
if (state.openCharacter === '$' && inlinePos !== -1) nextTokenPos = inlinePos;
} else if (!currentState.code) {
const blockPos = findToken(stream, blockKatexOpenRE);
} else {
const inlinePos = findToken(stream, inlineKatexOpenRE);
if (blockPos !== -1) nextTokenPos = blockPos;

View File

@@ -1,107 +0,0 @@
import { useEffect } from 'react';
import CommandService from 'lib/services/CommandService';
const { shim } = require('lib/shim.js');
export default function useKeymap(CodeMirror: any) {
function save() {
CommandService.instance().execute('synchronize');
}
function setupEmacs() {
CodeMirror.keyMap.emacs['Tab'] = 'smartListIndent';
CodeMirror.keyMap.emacs['Enter'] = 'insertListElement';
CodeMirror.keyMap.emacs['Shift-Tab'] = 'smartListUnindent';
}
function setupVim() {
CodeMirror.Vim.defineAction('swapLineDown', CodeMirror.commands.swapLineDown);
CodeMirror.Vim.mapCommand('<A-j>', 'action', 'swapLineDown', {}, { context: 'normal', isEdit: true });
CodeMirror.Vim.defineAction('swapLineUp', CodeMirror.commands.swapLineUp);
CodeMirror.Vim.mapCommand('<A-k>', 'action', 'swapLineUp', {}, { context: 'normal', isEdit: true });
CodeMirror.Vim.defineAction('insertListElement', CodeMirror.commands.vimInsertListElement);
CodeMirror.Vim.mapCommand('o', 'action', 'insertListElement', { after: true }, { context: 'normal', isEdit: true, interlaceInsertRepeat: true });
}
useEffect(() => {
// This enables the special modes (emacs and vim) to initiate sync by the save action
CodeMirror.commands.save = save;
CodeMirror.keyMap.basic = {
'Left': 'goCharLeft',
'Right': 'goCharRight',
'Up': 'goLineUp',
'Down': 'goLineDown',
'End': 'goLineRight',
'Home': 'goLineLeftSmart',
'PageUp': 'goPageUp',
'PageDown': 'goPageDown',
'Delete': 'delCharAfter',
'Backspace': 'delCharBefore',
'Shift-Backspace': 'delCharBefore',
'Tab': 'smartListIndent',
'Shift-Tab': 'smartListUnindent',
'Enter': 'insertListElement',
'Insert': 'toggleOverwrite',
'Esc': 'singleSelection',
};
if (shim.isMac()) {
CodeMirror.keyMap.default = {
// MacOS
'Cmd-A': 'selectAll',
'Cmd-D': 'deleteLine',
'Cmd-Z': 'undo',
'Shift-Cmd-Z': 'redo',
'Cmd-Y': 'redo',
'Cmd-Home': 'goDocStart',
'Cmd-Up': 'goDocStart',
'Cmd-End': 'goDocEnd',
'Cmd-Down': 'goDocEnd',
'Cmd-Left': 'goLineLeft',
'Cmd-Right': 'goLineRight',
'Alt-Left': 'goGroupLeft',
'Alt-Right': 'goGroupRight',
'Alt-Backspace': 'delGroupBefore',
'Alt-Delete': 'delGroupAfter',
'Cmd-[': 'indentLess',
'Cmd-]': 'indentMore',
'Cmd-/': 'toggleComment',
'Cmd-Opt-S': 'sortSelectedLines',
'Opt-Up': 'swapLineUp',
'Opt-Down': 'swapLineDown',
'fallthrough': 'basic',
};
} else {
CodeMirror.keyMap.default = {
// Windows/linux
'Ctrl-A': 'selectAll',
'Ctrl-D': 'deleteLine',
'Ctrl-Z': 'undo',
'Shift-Ctrl-Z': 'redo',
'Ctrl-Y': 'redo',
'Ctrl-Home': 'goDocStart',
'Ctrl-End': 'goDocEnd',
'Ctrl-Up': 'goLineUp',
'Ctrl-Down': 'goLineDown',
'Ctrl-Left': 'goGroupLeft',
'Ctrl-Right': 'goGroupRight',
'Alt-Left': 'goLineStart',
'Alt-Right': 'goLineEnd',
'Ctrl-Backspace': 'delGroupBefore',
'Ctrl-Delete': 'delGroupAfter',
'Ctrl-[': 'indentLess',
'Ctrl-]': 'indentMore',
'Ctrl-/': 'toggleComment',
'Ctrl-Alt-S': 'sortSelectedLines',
'Alt-Up': 'swapLineUp',
'Alt-Down': 'swapLineDown',
'fallthrough': 'basic',
};
}
setupEmacs();
setupVim();
}, []);
}

View File

@@ -126,24 +126,6 @@ export default function useListIdent(CodeMirror: any) {
});
};
// This is a special case of insertList element because it happens when
// vim is in normal mode and input is disabled and the cursor is not
// necessarily at the end of line (but it should pretend it is
CodeMirror.commands.vimInsertListElement = function(cm: any) {
cm.setOption('disableInput', false);
const ranges = cm.listSelections();
if (ranges.length === 0) return;
const { anchor } = ranges[0];
// Need to move the cursor to end of line as this is the vim behavior
const line = cm.getLine(anchor.line);
cm.setCursor({ line: anchor.line, ch: line.length });
cm.execCommand('insertListElement');
cm.setOption('disableInput', true);
};
CodeMirror.commands.insertListElement = function(cm: any) {
if (cm.getOption('disableInput')) return CodeMirror.Pass;

View File

@@ -338,8 +338,12 @@ function NoteEditor(props: NoteEditorProps) {
}
function renderNoteToolbar() {
// const theme = themeStyle(props.themeId);
const toolbarStyle = {
marginBottom: 0,
// paddingTop: theme.mainPadding,
// paddingBottom: theme.mainPadding,
};
return <NoteToolbar
@@ -359,12 +363,16 @@ function NoteEditor(props: NoteEditorProps) {
function renderTagBar() {
const theme = themeStyle(props.themeId);
const noteIds = [formNote.id];
const instructions = <span onClick={() => { CommandService.instance().execute('setTags', { noteIds }); }} style={{ ...theme.clickableTextStyle, whiteSpace: 'nowrap' }}>Click to add tags...</span>;
const tagList = props.selectedNoteTags.length ? <TagList items={props.selectedNoteTags} /> : null;
let control = null;
if (!props.selectedNoteTags.length) {
const noteIds = [formNote.id];
control = <span onClick={() => { CommandService.instance().execute('setTags', { noteIds }); }} style={theme.clickableTextStyle}>Click to add some tags...</span>;
} else {
control = <TagList items={props.selectedNoteTags} />;
}
return (
<div style={{ paddingLeft: 8, display: 'flex', flexDirection: 'row', alignItems: 'center' }}>{tagList}{instructions}</div>
<div style={{ paddingLeft: 8 }}>{control}</div>
);
}

View File

@@ -44,7 +44,6 @@ function editorCommandRuntime(declaration:CommandDeclaration, editorRef:any):Com
}
},
isEnabled: (props:any) => {
if (props.routeName !== 'Main' || props.isDialogVisible) return false;
if (props.markdownEditorViewerOnly) return false;
if (!props.noteId) return false;
const note = BaseModel.byId(props.notes, props.noteId);
@@ -59,8 +58,6 @@ function editorCommandRuntime(declaration:CommandDeclaration, editorRef:any):Com
noteVisiblePanes: state.noteVisiblePanes,
notes: state.notes,
noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
routeName: state.route.routeName,
isDialogVisible: !!Object.keys(state.visibleDialogs).length,
};
},
};

View File

@@ -6,12 +6,9 @@ import CommandService from 'lib/services/CommandService';
import { runtime as focusSearchRuntime } from './commands/focusSearch';
const styled = require('styled-components').default;
interface Props {
showNewNoteButtons: boolean,
}
const StyledRoot = styled.div`
width: 100%;
/*height: 100%;*/
display: flex;
flex-direction: row;
padding: ${(props:any) => props.theme.mainPadding}px;
@@ -22,12 +19,7 @@ const StyledButton = styled(Button)`
margin-left: 8px;
`;
const ButtonContainer = styled.div`
display: flex;
flex-direction: row;
`;
export default function NoteListControls(props:Props) {
export default function NoteListControls() {
const searchBarRef = useRef(null);
useEffect(function() {
@@ -46,31 +38,21 @@ export default function NoteListControls(props:Props) {
CommandService.instance().execute('newNote');
}
function renderNewNoteButtons() {
if (!props.showNewNoteButtons) return null;
return (
<ButtonContainer>
<StyledButton
tooltip={CommandService.instance().title('newTodo')}
iconName="far fa-check-square"
level={ButtonLevel.Primary}
onClick={onNewTodoButtonClick}
/>
<StyledButton
tooltip={CommandService.instance().title('newNote')}
iconName="icon-note"
level={ButtonLevel.Primary}
onClick={onNewNoteButtonClick}
/>
</ButtonContainer>
);
}
return (
<StyledRoot>
<SearchBar inputRef={searchBarRef}/>
{renderNewNoteButtons()}
<StyledButton
tooltip={CommandService.instance().title('newTodo')}
iconName="far fa-check-square"
level={ButtonLevel.Primary}
onClick={onNewTodoButtonClick}
/>
<StyledButton
tooltip={CommandService.instance().title('newNote')}
iconName="icon-note"
level={ButtonLevel.Primary}
onClick={onNewNoteButtonClick}
/>
</StyledRoot>
);
}

View File

@@ -2,7 +2,7 @@ const React = require('react');
const { connect } = require('react-redux');
const { themeStyle } = require('lib/theme');
const { _ } = require('lib/locale.js');
const NoteTextViewer = require('./NoteTextViewer').default;
const NoteTextViewer = require('./NoteTextViewer.min');
const HelpButton = require('./HelpButton.min');
const BaseModel = require('lib/BaseModel');
const Revision = require('lib/models/Revision');

View File

@@ -1,24 +1,15 @@
import * as React from 'react';
const React = require('react');
const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
interface Props {
onDomReady: Function,
onIpcMessage: Function,
viewerStyle: any,
}
class NoteTextViewerComponent extends React.Component {
constructor() {
super();
class NoteTextViewerComponent extends React.Component<Props, any> {
private initialized_:boolean = false;
private domReady_:boolean = false;
private webviewRef_:any;
private webviewListeners_:any = null;
constructor(props:any) {
super(props);
this.initialized_ = false;
this.domReady_ = false;
this.webviewRef_ = React.createRef();
this.webviewListeners_ = null;
this.webview_domReady = this.webview_domReady.bind(this);
this.webview_ipcMessage = this.webview_ipcMessage.bind(this);
@@ -26,20 +17,20 @@ class NoteTextViewerComponent extends React.Component<Props, any> {
this.webview_message = this.webview_message.bind(this);
}
webview_domReady(event:any) {
webview_domReady(event) {
this.domReady_ = true;
if (this.props.onDomReady) this.props.onDomReady(event);
}
webview_ipcMessage(event:any) {
webview_ipcMessage(event) {
if (this.props.onIpcMessage) this.props.onIpcMessage(event);
}
webview_load() {
this.webview_domReady({});
this.webview_domReady();
}
webview_message(event:any) {
webview_message(event) {
if (!event.data || event.data.target !== 'main') return;
const callName = event.data.name;
@@ -87,14 +78,7 @@ class NoteTextViewerComponent extends React.Component<Props, any> {
wv.removeEventListener(n, fn);
}
try {
// It seems this can throw a cross-origin error in a way that is hard to replicate so just wrap
// it in try/catch since it's not critical.
// https://github.com/laurent22/joplin/issues/3835
this.webviewRef_.current.contentWindow.removeEventListener('message', this.webview_message);
} catch (error) {
reg.logger().warn('Error destroying note viewer', error);
}
this.webviewRef_.current.contentWindow.removeEventListener('message', this.webview_message);
this.initialized_ = false;
this.domReady_ = false;
@@ -123,7 +107,7 @@ class NoteTextViewerComponent extends React.Component<Props, any> {
// Wrap WebView functions
// ----------------------------------------------------------------
send(channel:string, arg0:any = null, arg1:any = null) {
send(channel, arg0 = null, arg1 = null) {
const win = this.webviewRef_.current.contentWindow;
if (channel === 'setHtml') {
@@ -143,6 +127,36 @@ class NoteTextViewerComponent extends React.Component<Props, any> {
}
}
printToPDF() { // options, callback) {
// In Electron 4x, printToPDF is broken so need to use this hack:
// https://github.com/electron/electron/issues/16171#issuecomment-451090245
// return this.webviewRef_.current.printToPDF(options, callback);
// return this.webviewRef_.current.getWebContents().printToPDF(options, callback);
}
print() {
// In Electron 4x, print is broken so need to use this hack:
// https://github.com/electron/electron/issues/16219#issuecomment-451454948
// Note that this is not a perfect workaround since it means the options are ignored
// In particular it means that background images and colours won't be printed (printBackground property will be ignored)
// return this.webviewRef_.current.getWebContents().print({});
return this.webviewRef_.current.getWebContents().executeJavaScript('window.print()');
}
openDevTools() {
// return this.webviewRef_.current.openDevTools();
}
closeDevTools() {
// return this.webviewRef_.current.closeDevTools();
}
isDevToolsOpened() {
// return this.webviewRef_.current.isDevToolsOpened();
}
// ----------------------------------------------------------------
// Wrap WebView functions (END)
// ----------------------------------------------------------------
@@ -153,7 +167,7 @@ class NoteTextViewerComponent extends React.Component<Props, any> {
}
}
const mapStateToProps = (state:any) => {
const mapStateToProps = state => {
return {
themeId: state.settings.theme,
};
@@ -166,4 +180,4 @@ const NoteTextViewer = connect(
{ withRef: true }
)(NoteTextViewerComponent);
export default NoteTextViewer;
module.exports = NoteTextViewer;

View File

@@ -1,9 +1,9 @@
import * as React from 'react';
import { useEffect, useState } from 'react';
import CommandService from '../../lib/services/CommandService';
import ToolbarBase from '../ToolbarBase';
const { connect } = require('react-redux');
const { buildStyle } = require('lib/theme');
const Toolbar = require('../Toolbar.min.js');
// const Folder = require('lib/models/Folder');
// const { _ } = require('lib/locale');
// const { substrWithEllipsis } = require('lib/string-utils');
@@ -40,12 +40,21 @@ function styles_(props:NoteToolbarProps) {
function NoteToolbar(props:NoteToolbarProps) {
const styles = styles_(props);
const [toolbarItems, setToolbarItems] = useState([]);
// const selectedNoteFolder = Folder.byId(props.folders, props.note.parent_id);
// const folderId = selectedNoteFolder ? selectedNoteFolder.id : '';
// const folderTitle = selectedNoteFolder && selectedNoteFolder.title ? selectedNoteFolder.title : '';
const cmdService = CommandService.instance();
function updateToolbarItems() {
const output = [];
// if (props.watchedNoteFiles.indexOf(props.note.id) >= 0) {
// output.push(cmdService.commandToToolbarButton('stopExternalEditing'));
// } else {
// output.push(cmdService.commandToToolbarButton('startExternalEditing'));
// }
output.push(cmdService.commandToToolbarButton('editAlarm'));
output.push(cmdService.commandToToolbarButton('toggleVisiblePanes'));
output.push(cmdService.commandToToolbarButton('showNoteProperties'));
@@ -61,7 +70,7 @@ function NoteToolbar(props:NoteToolbarProps) {
};
}, []);
return <ToolbarBase style={styles.root} items={toolbarItems} />;
return <Toolbar style={styles.root} items={toolbarItems} />;
}
const mapStateToProps = (state:any) => {

View File

@@ -24,7 +24,7 @@ const { bridge } = require('electron').remote.require('./bridge');
const GlobalStyle = createGlobalStyle`
div, span, a {
color: ${(props) => props.theme.color};
/*font-size: ${(props) => props.theme.fontSize}px;*/
font-size: ${(props) => props.theme.fontSize}px;
font-family: ${(props) => props.theme.fontFamily};
}
`;

View File

@@ -10,42 +10,15 @@ const { _ } = require('lib/locale.js');
interface Props {
inputRef?: any,
notesParentType: string,
dispatch?: Function,
}
function SearchBar(props:Props) {
const [query, setQuery] = useState('');
const iconName = !query ? CommandService.instance().iconName('search') : 'fa fa-times';
function onChange(event:any) {
const onChange = (event:any) => {
setQuery(event.currentTarget.value);
}
function onFocus() {
props.dispatch({
type: 'FOCUS_SET',
field: 'globalSearch',
});
}
function onBlur() {
// Do it after a delay so that the "Clear" button
// can be clicked on (otherwise the field loses focus
// and is resized before the click event has been processed)
setTimeout(() => {
props.dispatch({
type: 'FOCUS_CLEAR',
field: 'globalSearch',
});
}, 300);
}
function onKeyDown(event:any) {
if (event.key === 'Escape') {
setQuery('');
if (document.activeElement) (document.activeElement as any).blur();
}
}
};
const onSearchButtonClick = useCallback(() => {
setQuery('');
@@ -61,16 +34,7 @@ function SearchBar(props:Props) {
return (
<Root>
<SearchInput
ref={props.inputRef}
value={query}
type="text"
placeholder={_('Search...')}
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
onKeyDown={onKeyDown}
/>
<SearchInput ref={props.inputRef} value={query} type="text" placeholder={_('Search...')} onChange={onChange}/>
<SearchButton onClick={onSearchButtonClick}>
<SearchButtonIcon className={iconName}/>
</SearchButton>

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { StyledRoot, StyledAddButton, StyledHeader, StyledHeaderIcon, StyledAllNotesIcon, StyledHeaderLabel, StyledListItem, StyledListItemAnchor, StyledExpandLink, StyledNoteCount, StyledSyncReportText, StyledSyncReport, StyledSynchronizeButton } from './styles';
import { StyledRoot, StyledAddButton, StyledHeader, StyledHeaderIcon, StyledHeaderLabel, StyledListItem, StyledListItemAnchor, StyledExpandLink, StyledNoteCount, StyledSyncReportText, StyledSyncReport, StyledSynchronizeButton } from './styles';
import { ButtonLevel } from '../Button/Button';
import CommandService from 'lib/services/CommandService';
@@ -45,52 +45,6 @@ const commands = [
require('./commands/focusElementSideBar'),
];
function ExpandIcon(props:any) {
const theme = themeStyle(props.themeId);
const style:any = { width: 16, maxWidth: 16, opacity: 0.5, fontSize: Math.round(theme.toolbarIconSize * 0.8), display: 'flex', justifyContent: 'center' };
if (!props.isVisible) style.visibility = 'hidden';
return <i className={props.isExpanded ? 'fas fa-caret-down' : 'fas fa-caret-right'} style={style}></i>;
}
function ExpandLink(props:any) {
return props.hasChildren ? (
<StyledExpandLink href="#" data-folder-id={props.folderId} onClick={props.onClick}>
<ExpandIcon themeId={props.themeId} isVisible={true} isExpanded={props.isExpanded}/>
</StyledExpandLink>
) : (
<StyledExpandLink><ExpandIcon themeId={props.themeId} isVisible={false} isExpanded={false}/></StyledExpandLink>
);
}
function FolderItem(props:any) {
const { hasChildren, isExpanded, depth, selected, folderId, folderTitle, anchorRef, noteCount, onFolderDragStart_, onFolderDragOver_, onFolderDrop_, itemContextMenu, folderItem_click, onFolderToggleClick_ } = props;
const noteCountComp = noteCount ? <StyledNoteCount>{noteCount}</StyledNoteCount> : null;
return (
<StyledListItem depth={depth} selected={selected} className={`list-item-container list-item-depth-${depth}`} onDragStart={onFolderDragStart_} onDragOver={onFolderDragOver_} onDrop={onFolderDrop_} draggable={true} data-folder-id={folderId}>
<ExpandLink themeId={props.themeId} hasChildren={hasChildren} folderId={folderId} onClick={onFolderToggleClick_} isExpanded={isExpanded}/>
<StyledListItemAnchor
ref={anchorRef}
className="list-item"
isConflictFolder={folderId === Folder.conflictFolderId()}
href="#"
selected={selected}
data-id={folderId}
data-type={BaseModel.TYPE_FOLDER}
onContextMenu={itemContextMenu}
data-folder-id={folderId}
onClick={() => {
folderItem_click(folderId);
}}
onDoubleClick={onFolderToggleClick_}
>
{folderTitle} {noteCountComp}
</StyledListItemAnchor>
</StyledListItem>
);
}
class SideBarComponent extends React.Component<Props, State> {
private folderItemsOrder_:any[] = [];
@@ -114,8 +68,6 @@ class SideBarComponent extends React.Component<Props, State> {
this.onAllNotesClick_ = this.onAllNotesClick_.bind(this);
this.header_contextMenu = this.header_contextMenu.bind(this);
this.onAddFolderButtonClick = this.onAddFolderButtonClick.bind(this);
this.folderItem_click = this.folderItem_click.bind(this);
this.itemContextMenu = this.itemContextMenu.bind(this);
}
onFolderDragStart_(event:any) {
@@ -305,10 +257,10 @@ class SideBarComponent extends React.Component<Props, State> {
menu.popup(bridge().window());
}
folderItem_click(folderId:string) {
folderItem_click(folder:any) {
this.props.dispatch({
type: 'FOLDER_SELECT',
id: folderId ? folderId : null,
id: folder ? folder.id : null,
});
}
@@ -339,7 +291,7 @@ class SideBarComponent extends React.Component<Props, State> {
}
renderNoteCount(count:number) {
return count ? <StyledNoteCount>{count}</StyledNoteCount> : null;
return <StyledNoteCount>{count}</StyledNoteCount>;
}
renderExpandIcon(isExpanded:boolean, isVisible:boolean = true) {
@@ -353,41 +305,57 @@ class SideBarComponent extends React.Component<Props, State> {
return (
<StyledListItem key="allNotesHeader" selected={selected} className={'list-item-container list-item-depth-0'} isSpecialItem={true}>
<StyledExpandLink>{this.renderExpandIcon(false, false)}</StyledExpandLink>
<StyledAllNotesIcon className="icon-notes"/>
<StyledListItemAnchor
className="list-item"
isSpecialItem={true}
href="#"
selected={selected}
onClick={this.onAllNotesClick_}
onClick={() => {
this.onAllNotesClick_();
}}
>
{_('All notes')}
({_('All notes')})
</StyledListItemAnchor>
</StyledListItem>
);
}
renderFolderItem(folder:any, selected:boolean, hasChildren:boolean, depth:number) {
const anchorRef = this.anchorItemRef('folder', folder.id);
const isExpanded = this.props.collapsedFolderIds.indexOf(folder.id) < 0;
const expandIcon = this.renderExpandIcon(isExpanded, hasChildren);
const expandLink = hasChildren ? (
<StyledExpandLink href="#" data-folder-id={folder.id} onClick={this.onFolderToggleClick_}>
{expandIcon}
</StyledExpandLink>
) : (
<StyledExpandLink>{expandIcon}</StyledExpandLink>
);
return <FolderItem
key={folder.id}
folderId={folder.id}
folderTitle={Folder.displayTitle(folder)}
themeId={this.props.themeId}
depth={depth}
selected={selected}
isExpanded={this.props.collapsedFolderIds.indexOf(folder.id) < 0}
hasChildren={hasChildren}
anchorRef={anchorRef}
noteCount={folder.note_count}
onFolderDragStart_={this.onFolderDragStart_}
onFolderDragOver_={this.onFolderDragOver_}
onFolderDrop_={this.onFolderDrop_}
itemContextMenu={this.itemContextMenu}
folderItem_click={this.folderItem_click}
onFolderToggleClick_={this.onFolderToggleClick_}
/>;
const anchorRef = this.anchorItemRef('folder', folder.id);
const noteCount = folder.note_count ? this.renderNoteCount(folder.note_count) : '';
return (
<StyledListItem depth={depth} selected={selected} className={`list-item-container list-item-depth-${depth}`} key={folder.id} onDragStart={this.onFolderDragStart_} onDragOver={this.onFolderDragOver_} onDrop={this.onFolderDrop_} draggable={true} data-folder-id={folder.id}>
{expandLink}
<StyledListItemAnchor
ref={anchorRef}
className="list-item"
isConflictFolder={folder.id === Folder.conflictFolderId()}
href="#"
selected={selected}
data-id={folder.id}
data-type={BaseModel.TYPE_FOLDER}
onContextMenu={(event:any) => this.itemContextMenu(event)}
data-folder-id={folder.id}
onClick={() => {
this.folderItem_click(folder);
}}
onDoubleClick={this.onFolderToggleClick_}
>
{Folder.displayTitle(folder)} {noteCount}
</StyledListItemAnchor>
</StyledListItem>
);
}
renderTag(tag:any, selected:boolean) {
@@ -404,7 +372,7 @@ class SideBarComponent extends React.Component<Props, State> {
selected={selected}
data-id={tag.id}
data-type={BaseModel.TYPE_TAG}
onContextMenu={this.itemContextMenu}
onContextMenu={(event:any) => this.itemContextMenu(event)}
onClick={() => {
this.tagItem_click(tag);
}}

View File

@@ -31,12 +31,6 @@ export const StyledHeaderIcon = styled.i`
margin-right: 8px;
`;
export const StyledAllNotesIcon = styled(StyledHeaderIcon)`
font-size: ${(props:any) => props.theme.toolbarIconSize * 0.8}px;
color: ${(props:any) => props.theme.colorFaded2};
margin-right: 8px;
`;
export const StyledHeaderLabel = styled.span`
flex: 1;
color: ${(props:any) => props.theme.color2};
@@ -49,10 +43,9 @@ export const StyledListItem = styled.div`
height: 25px;
display: flex;
flex-direction: row;
align-items: center;
padding-left: ${(props:any) => props.theme.mainPadding + ('depth' in props ? props.depth : 0) * 16}px;
background: ${(props:any) => props.selected ? props.theme.selectedColor2 : 'none'};
/*text-transform: ${(props:any) => props.isSpecialItem ? 'uppercase' : 'none'};*/
text-transform: ${(props:any) => props.isSpecialItem ? 'uppercase' : 'none'};
transition: 0.1s;
&:hover {
@@ -78,7 +71,6 @@ export const StyledListItemAnchor = styled.a`
flex: 1;
align-items: center;
user-select: none;
height: 100%;
`;
export const StyledExpandLink = styled.a`
@@ -92,7 +84,6 @@ export const StyledExpandLink = styled.a`
width: 16px;
max-width: 16px;
min-width: 16px;
height: 100%;
`;
export const StyledNoteCount = styled.div`

View File

@@ -5,18 +5,11 @@ const ToolbarButton = require('./ToolbarButton/ToolbarButton.js').default;
const ToolbarSpace = require('./ToolbarSpace.min.js');
const ToggleEditorsButton = require('./ToggleEditorsButton/ToggleEditorsButton.js').default;
interface Props {
themeId: number,
style: any,
items: any[],
}
class ToolbarBaseComponent extends React.Component<Props, any> {
class ToolbarComponent extends React.Component {
render() {
const theme = themeStyle(this.props.themeId);
const style:any = Object.assign({
const style = Object.assign({
display: 'flex',
flexDirection: 'row',
boxSizing: 'border-box',
@@ -25,15 +18,15 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
paddingRight: theme.mainPadding,
}, this.props.style);
const groupStyle:any = {
const groupStyle = {
display: 'flex',
flexDirection: 'row',
boxSizing: 'border-box',
};
const leftItemComps:any[] = [];
const centerItemComps:any[] = [];
const rightItemComps:any[] = [];
const leftItemComps = [];
const centerItemComps = [];
const rightItemComps = [];
if (this.props.items) {
for (let i = 0; i < this.props.items.length; i++) {
@@ -52,6 +45,8 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
o
);
if (this.props.disabled) props.disabled = true;
if (o.name === 'toggleEditors') {
rightItemComps.push(<ToggleEditorsButton
key={o.name}
@@ -84,8 +79,10 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
}
}
const mapStateToProps = (state:any) => {
const mapStateToProps = state => {
return { themeId: state.settings.theme };
};
export default connect(mapStateToProps)(ToolbarBaseComponent);
const Toolbar = connect(mapStateToProps)(ToolbarComponent);
module.exports = Toolbar;

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.2.6",
"version": "1.1.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1535,7 +1535,7 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
@@ -1701,7 +1701,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": false,
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
@@ -1817,7 +1817,7 @@
},
"tar": {
"version": "4.4.8",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
"resolved": false,
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"dev": true,
"optional": true,
@@ -1970,44 +1970,6 @@
"source-map": "^0.5.6"
}
},
"babel-eslint": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
"integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==",
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/parser": "^7.7.0",
"@babel/traverse": "^7.7.0",
"@babel/types": "^7.7.0",
"eslint-visitor-keys": "^1.0.0",
"resolve": "^1.12.0"
},
"dependencies": {
"@babel/types": {
"version": "7.11.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz",
"integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
},
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
"requires": {
"path-parse": "^1.0.6"
}
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
}
}
},
"babel-generator": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz",
@@ -3626,9 +3588,9 @@
}
},
"d3": {
"version": "5.16.0",
"resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz",
"integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==",
"version": "5.15.0",
"resolved": "https://registry.npmjs.org/d3/-/d3-5.15.0.tgz",
"integrity": "sha512-C+E80SL2nLLtmykZ6klwYj5rPqB5nlfN5LdWEAVdWPppqTD8taoJi2PxLZjPeYT8FFRR2yucXq+kBlOnnvZeLg==",
"requires": {
"d3-array": "1",
"d3-axis": "1",
@@ -3674,9 +3636,9 @@
"integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
},
"d3-brush": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz",
"integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==",
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.5.tgz",
"integrity": "sha512-rEaJ5gHlgLxXugWjIkolTA0OyMvw8UWU1imYXy1v642XyyswmI1ybKOv05Ft+ewq+TFmdliD3VuK0pRp1VT/5A==",
"requires": {
"d3-dispatch": "1",
"d3-drag": "1",
@@ -3700,9 +3662,9 @@
"integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
},
"d3-color": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz",
"integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg=="
},
"d3-contour": {
"version": "1.3.2",
@@ -3737,14 +3699,14 @@
}
},
"d3-ease": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
"integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.6.tgz",
"integrity": "sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ=="
},
"d3-fetch": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz",
"integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz",
"integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==",
"requires": {
"d3-dsv": "1"
}
@@ -3761,14 +3723,14 @@
}
},
"d3-format": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
"integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.3.tgz",
"integrity": "sha512-mm/nE2Y9HgGyjP+rKIekeITVgBtX97o1nrvHCWX8F/yBYyevUTvu9vb5pUnKwrcSw7o7GuwMOWjS9gFDs4O+uQ=="
},
"d3-geo": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz",
"integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==",
"version": "1.11.9",
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.9.tgz",
"integrity": "sha512-9edcH6J3s/Aa3KJITWqFJbyB/8q3mMlA9Fi7z6yy+FAYMnRaxmC7jBhUnsINxVWD14GmqX3DK8uk7nV6/Ekt4A==",
"requires": {
"d3-array": "1"
}
@@ -3829,9 +3791,9 @@
}
},
"d3-selection": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
"integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.1.tgz",
"integrity": "sha512-BTIbRjv/m5rcVTfBs4AMBLKs4x8XaaLkwm28KWu9S2vKNqXkXt2AH2Qf0sdPZHjFxcWg/YL53zcqAz+3g4/7PA=="
},
"d3-shape": {
"version": "1.3.7",
@@ -3847,9 +3809,9 @@
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
},
"d3-time-format": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.3.tgz",
"integrity": "sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA==",
"requires": {
"d3-time": "1"
}
@@ -4701,14 +4663,6 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
},
"entity-decode": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/entity-decode/-/entity-decode-2.0.2.tgz",
"integrity": "sha512-5CCY/3ci4MC1m2jlumNjWd7VBFt4VfFnmSqSNmVcXq4gxM3Vmarxtt+SvmBnzwLS669MWdVuXboNVj1qN2esVg==",
"requires": {
"he": "^1.1.1"
}
},
"env-paths": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
@@ -4789,6 +4743,11 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"escaper": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/escaper/-/escaper-2.5.3.tgz",
"integrity": "sha512-QGb9sFxBVpbzMggrKTX0ry1oiI4CSDAl9vIL702hzl1jGW8VZs7qfqTRX7WDOjoNDoEVGcEtu1ZOQgReSfT2kQ=="
},
"escodegen": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
@@ -4809,11 +4768,6 @@
}
}
},
"eslint-visitor-keys": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -6122,7 +6076,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": false,
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
@@ -7193,6 +7147,11 @@
"dev": true,
"optional": true
},
"is-regexp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
"integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk="
},
"is-relative": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
@@ -7601,11 +7560,6 @@
"json-buffer": "3.0.0"
}
},
"khroma": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/khroma/-/khroma-1.1.0.tgz",
"integrity": "sha512-aTO+YX22tYOLEQJYFiatAj1lc5QZ+H5sHWFRBWNCiKwc5NWNUJZyeSeiHEPeURJ2a1GEVYcmyMUwGjjLe5ec5A=="
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -8073,22 +8027,31 @@
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
},
"mermaid": {
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.8.0.tgz",
"integrity": "sha512-SbMzt5T6+XMkHRUECHUneq26H8bvjF752YZCKCJ4G8UU7qI2OmmxYdj4ZJnda7JIx3EuNeN4xSLuLCBJ5ByzSQ==",
"version": "8.4.6",
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.4.6.tgz",
"integrity": "sha512-6YQBkXfvhfjKIzRhtqbCics3pJurGrJAYEeqgyRcDZeTHQ/WCB2Bh/4wdAOho1Uffe0jXB+HjmHT5kEUOxudJw==",
"requires": {
"@braintree/sanitize-url": "^3.1.0",
"babel-eslint": "^10.1.0",
"crypto-random-string": "^3.0.1",
"d3": "^5.7.0",
"dagre": "^0.8.4",
"dagre-d3": "^0.6.4",
"entity-decode": "^2.0.2",
"graphlib": "^2.1.7",
"he": "^1.2.0",
"khroma": "^1.1.0",
"lodash": "^4.17.11",
"minify": "^4.1.1",
"moment-mini": "^2.22.1",
"stylis": "^3.5.2"
"scope-css": "^1.2.1"
},
"dependencies": {
"crypto-random-string": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-3.1.0.tgz",
"integrity": "sha512-Tip3yGB+bA7B0W8E4K4mNf2rZhu5r2G5Tb89/utEl5tP1QuLjTF/S9a1b8ifDrR4ORc9Utf6tscpSEtBY3YcPQ==",
"requires": {
"type-fest": "^0.8.1"
}
}
}
},
"micromatch": {
@@ -8249,11 +8212,11 @@
},
"dependencies": {
"debug": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "2.1.2"
"ms": "^2.1.1"
}
},
"ms": {
@@ -8368,9 +8331,9 @@
"integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y="
},
"moment-mini": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.24.0.tgz",
"integrity": "sha512-9ARkWHBs+6YJIvrIp0Ik5tyTTtP9PoV0Ssu2Ocq5y9v8+NOOpWiRshAp8c4rZVWTOe+157on/5G+zj5pwIQFEQ=="
"version": "2.22.1",
"resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.22.1.tgz",
"integrity": "sha512-OUCkHOz7ehtNMYuZjNciXUfwTuz8vmF1MTbAy59ebf+ZBYZO5/tZKuChVWCX+uDo+4idJBpGltNfV8st+HwsGw=="
},
"ms": {
"version": "2.0.0",
@@ -10465,6 +10428,16 @@
"object-assign": "^4.1.1"
}
},
"scope-css": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/scope-css/-/scope-css-1.2.1.tgz",
"integrity": "sha512-UjLRmyEYaDNiOS673xlVkZFlVCtckJR/dKgr434VMm7Lb+AOOqXKdAcY7PpGlJYErjXXJzKN7HWo4uRPiZZG0Q==",
"requires": {
"escaper": "^2.5.3",
"slugify": "^1.3.1",
"strip-css-comments": "^3.0.0"
}
},
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
@@ -10669,10 +10642,10 @@
}
}
},
"slug": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/slug/-/slug-3.5.0.tgz",
"integrity": "sha512-+pZLDhMtmAc+ZcojQSMlUKDZBYmvhZiZmK8Ffx/D3Q/MIMHPDBAMbWvWN8vJb9xl2MfbDdRWxFzrdOhBiyVpow=="
"slugify": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.6.tgz",
"integrity": "sha512-wA9XS475ZmGNlEnYYLPReSfuz/c3VQsEMoU43mi6OnKMCdbnFXd4/Yg7J0lBv8jkPolacMpOrWEaoYxuE1+hoQ=="
},
"smalltalk": {
"version": "2.5.1",
@@ -11036,6 +11009,14 @@
"is-utf8": "^0.2.0"
}
},
"strip-css-comments": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-css-comments/-/strip-css-comments-3.0.0.tgz",
"integrity": "sha1-elYl7/iisibPiUehElTaluE9rok=",
"requires": {
"is-regexp": "^1.0.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -11316,9 +11297,9 @@
"dev": true
},
"terser": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
"integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz",
"integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==",
"requires": {
"commander": "^2.20.0",
"source-map": "~0.6.1",
@@ -11336,9 +11317,9 @@
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map-support": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
@@ -11604,8 +11585,7 @@
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
},
"typedarray": {
"version": "0.0.6",
@@ -11731,6 +11711,11 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
},
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA=="
},
"unset-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
@@ -11922,6 +11907,14 @@
"integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
"dev": true
},
"uslug": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz",
"integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=",
"requires": {
"unorm": ">= 1.0.0"
}
},
"utf8-byte-length": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.2.6",
"version": "1.1.1",
"description": "Joplin for Desktop",
"main": "main.js",
"scripts": {
@@ -169,7 +169,7 @@
"md5": "^2.2.1",
"md5-file": "^4.0.0",
"memory-cache": "^0.2.0",
"mermaid": "^8.8.0",
"mermaid": "^8.4.6",
"moment": "^2.22.2",
"multiparty": "^4.2.1",
"mustache": "^3.0.1",
@@ -193,7 +193,6 @@
"roboto-fontface": "^0.10.0",
"sax": "^1.2.4",
"server-destroy": "^1.0.1",
"slug": "^3.5.0",
"smalltalk": "^2.5.1",
"sprintf-js": "^1.1.1",
"sqlite3": "^4.1.1",
@@ -208,6 +207,7 @@
"tinymce": "^5.2.0",
"uglifycss": "0.0.29",
"url-parse": "^1.4.3",
"uslug": "^1.0.4",
"uuid": "^3.2.1",
"valid-url": "^1.0.9",
"xml2js": "^0.4.19"

View File

@@ -120,21 +120,11 @@ class Dialog extends React.PureComponent {
componentDidMount() {
document.addEventListener('keydown', this.onKeyDown);
this.props.dispatch({
type: 'VISIBLE_DIALOGS_ADD',
name: 'gotoAnything',
});
}
componentWillUnmount() {
if (this.listUpdateIID_) clearTimeout(this.listUpdateIID_);
document.removeEventListener('keydown', this.onKeyDown);
this.props.dispatch({
type: 'VISIBLE_DIALOGS_REMOVE',
name: 'gotoAnything',
});
}
onKeyDown(event) {

View File

@@ -20,15 +20,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.1.4/Joplin-Setup-1.1.4.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.1.4/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.1.4/Joplin-1.1.4.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a> | You can also use Homebrew (unsupported): `brew cask install joplin`
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.1.4/Joplin-1.1.4.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a> | An Arch Linux package (unsupported) [is also available](#terminal-application).<br><br>If it works with your distribution (it has been tested on Ubuntu, Fedora, and Mint; the desktop environments supported are GNOME, KDE, Xfce, MATE, LXQT, LXDE, Unity, Cinnamon, Deepin and Pantheon), 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.241/Joplin-Setup-1.0.241.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.241/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.241/Joplin-1.0.241.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a> | You can also use Homebrew (unsupported): `brew cask install joplin`
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.0.241/Joplin-1.0.241.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a> | An Arch Linux package (unsupported) [is also available](#terminal-application).<br><br>If it works with your distribution (it has been tested on Ubuntu, Fedora, and Mint; the desktop environments supported are GNOME, KDE, Xfce, MATE, LXQT, LXDE, Unity, Cinnamon, Deepin and Pantheon), 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.2.6/joplin-v1.2.6.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.2.6/joplin-v1.2.6-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.1.1/joplin-v1.1.1.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.1.1/joplin-v1.1.1-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

@@ -125,8 +125,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097583
versionName "1.2.6"
versionCode 2097577
versionName "1.1.1"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}

View File

@@ -80,19 +80,8 @@
<!-- END RN-push-notitication -->
<!-- ============================= -->
<!--
2018-12-16: Changed android:launchMode from "singleInstance" to "singleTop" for Firebase notification
Previously singleInstance was necessary to prevent multiple instance of the RN app from running at the same time, but maybe no longer needed.
2020-10-06: Changed back again to "singleInstance" and notifications still seem to work. Changing to singleInstance
to try to fix this bug: https://discourse.joplinapp.org/t/joplin-android-app-looses-nextcloud-sync-settings/10997/6
Users would lose their settings, and it's possibly due to multiple instances of the app running at the same time, perhaps
due to sharing with the app. When checking the log, it would show "saving settings", then the app startup message, and after the app
has started, it would show "setting saved". So basically the app, or one instance of it, has started while settings were being saved
2020-10-08: Changed back again to "singleTop" as it has worked so far. The multiple instance bug was "fixed" in a different way
See ReactNativeClient/root.js for more info about the bug.
-->
<!-- 2018-12-16: Changed android:launchMode from "singleInstance" to "singleTop" for Firebase notification -->
<!-- Previously singleInstance was necessary to prevent multiple instance of the RN app from running at the same time, but maybe no longer needed. -->
<activity
android:name=".MainActivity"
android:label="@string/app_name"

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -337,7 +337,7 @@
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 55;
CURRENT_PROJECT_VERSION = 53;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = A9BXAFS6CT;
HEADER_SEARCH_PATHS = (
@@ -357,7 +357,7 @@
INFOPLIST_FILE = Joplin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
MARKETING_VERSION = 10.2.1;
MARKETING_VERSION = 10.1.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -380,7 +380,7 @@
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 55;
CURRENT_PROJECT_VERSION = 53;
DEVELOPMENT_TEAM = A9BXAFS6CT;
HEADER_SEARCH_PATHS = (
"$(inherited)",
@@ -393,7 +393,7 @@
INFOPLIST_FILE = Joplin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
MARKETING_VERSION = 10.2.1;
MARKETING_VERSION = 10.1.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",

View File

@@ -300,10 +300,12 @@ class BaseApplication {
}
}
this.store().dispatch({
type: 'SET_HIGHLIGHTED',
words: highlightedWords,
});
if (highlightedWords.length) {
this.store().dispatch({
type: 'SET_HIGHLIGHTED',
words: highlightedWords,
});
}
this.store().dispatch({
type: 'NOTE_UPDATE_ALL',
@@ -467,7 +469,7 @@ class BaseApplication {
refreshNotesUseSelectedNoteId = true;
}
if (action.type == 'HISTORY_BACKWARD' || action.type == 'HISTORY_FORWARD' || action.type == 'FOLDER_SELECT' || action.type === 'FOLDER_DELETE' || action.type === 'FOLDER_AND_NOTE_SELECT' || (action.type === 'SEARCH_UPDATE' && newState.notesParentType === 'Folder')) {
if (action.type == 'FOLDER_SELECT' || action.type === 'FOLDER_DELETE' || action.type === 'FOLDER_AND_NOTE_SELECT' || (action.type === 'SEARCH_UPDATE' && newState.notesParentType === 'Folder')) {
Setting.setValue('activeFolderId', newState.selectedFolderId);
this.currentFolder_ = newState.selectedFolderId ? await Folder.load(newState.selectedFolderId) : null;
refreshNotes = true;
@@ -499,11 +501,7 @@ class BaseApplication {
refreshNotesUseSelectedNoteId = true;
}
// Should refresh the notes when:
// - A tag is selected, to show the notes for that tag
// - When a tag is updated so that when searching by tags, the search results are updated
// https://github.com/laurent22/joplin/issues/3754
if (['TAG_SELECT', 'TAG_DELETE', 'TAG_UPDATE_ONE', 'NOTE_TAG_REMOVE'].includes(action.type)) {
if (action.type == 'TAG_SELECT' || action.type === 'TAG_DELETE') {
refreshNotes = true;
}
@@ -740,23 +738,10 @@ class BaseApplication {
setLocale(Setting.value('locale'));
}
// if (Setting.value('db.fuzzySearchEnabled') === -1) {
// const fuzzySearchEnabled = await this.database_.fuzzySearchEnabled();
// Setting.setValue('db.fuzzySearchEnabled', fuzzySearchEnabled ? 1 : 0);
// }
// // Always disable on CLI because building and packaging the extension is not working
// // and is too error-prone - requires gcc on the machine, or we should package the .so
// // and dylib files, but it's not sure it would work everywhere if not built from
// // source on the target machine.
// if (Setting.value('appType') !== 'desktop') {
// Setting.setValue('db.fuzzySearchEnabled', 0);
// }
// For now always disable fuzzy search due to performance issues:
// https://discourse.joplinapp.org/t/1-1-4-keyboard-locks-up-while-typing/11231/11
// https://discourse.joplinapp.org/t/serious-lagging-when-there-are-tens-of-thousands-of-notes/11215/23
Setting.setValue('db.fuzzySearchEnabled', 0);
if (Setting.value('db.fuzzySearchEnabled') === -1) {
const fuzzySearchEnabled = await this.database_.fuzzySearchEnabled();
Setting.setValue('db.fuzzySearchEnabled', fuzzySearchEnabled ? 1 : 0);
}
if (Setting.value('encryption.shouldReencrypt') < 0) {
// We suggest re-encryption if the user has at least one notebook

View File

@@ -4,7 +4,7 @@ const { reg } = require('lib/registry.js');
export const declaration:CommandDeclaration = {
name: 'synchronize',
label: () => _('Synchronise'),
label: () => _('Synchronize'),
iconName: 'fa-sync-alt',
};

View File

@@ -208,10 +208,6 @@ class NoteScreenComponent extends BaseScreenComponent {
}
};
this.useBetaEditor = () => {
return Setting.value('editor.beta') && Platform.OS !== 'android';
};
this.takePhoto_onPress = this.takePhoto_onPress.bind(this);
this.cameraView_onPhoto = this.cameraView_onPhoto.bind(this);
this.cameraView_onCancel = this.cameraView_onCancel.bind(this);
@@ -407,9 +403,7 @@ class NoteScreenComponent extends BaseScreenComponent {
this.saveActionQueue(this.state.note.id).processAllNow();
// It cannot theoretically be undefined, since componentDidMount should always be called before
// componentWillUnmount, but with React Native the impossible often becomes possible.
if (this.undoRedoService_) this.undoRedoService_.off('stackChange', this.undoRedoService_stackChange);
this.undoRedoService_.off('stackChange', this.undoRedoService_stackChange);
}
title_changeText(text) {
@@ -650,7 +644,7 @@ class NoteScreenComponent extends BaseScreenComponent {
const newNote = Object.assign({}, this.state.note);
if (this.state.mode == 'edit' && !this.useBetaEditor() && !!this.selection) {
if (this.state.mode == 'edit' && !Setting.value('editor.beta') && !!this.selection) {
const prefix = newNote.body.substring(0, this.selection.start);
const suffix = newNote.body.substring(this.selection.end);
newNote.body = `${prefix}\n${resourceTag}\n${suffix}`;
@@ -972,7 +966,7 @@ class NoteScreenComponent extends BaseScreenComponent {
}
let bodyComponent = null;
if (this.state.mode == 'view' && !this.useBetaEditor()) {
if (this.state.mode == 'view' && !Setting.value('editor.beta')) {
const onCheckboxChange = newBody => {
this.saveOneProperty('body', newBody);
};
@@ -1027,7 +1021,7 @@ class NoteScreenComponent extends BaseScreenComponent {
this.saveOneProperty('body', newBody);
};
bodyComponent = this.useBetaEditor()
bodyComponent = Setting.value('editor.beta')
// Note: blurOnSubmit is necessary to get multiline to work.
// See https://github.com/facebook/react-native/issues/12717#issuecomment-327001997
? <MarkdownEditor
@@ -1176,7 +1170,7 @@ class NoteScreenComponent extends BaseScreenComponent {
/>
{titleComp}
{bodyComponent}
{!this.useBetaEditor() && actionButtonComp}
{!Setting.value('editor.beta') && actionButtonComp}
<SelectDateTimeDialog shown={this.state.alarmDialogShown} date={dueDate} onAccept={this.onAlarmDialogAccept} onReject={this.onAlarmDialogReject} />

View File

@@ -11,7 +11,6 @@ const { BaseScreenComponent } = require('lib/components/base-screen.js');
const { themeStyle } = require('lib/components/global-style.js');
const DialogBox = require('react-native-dialogbox').default;
const SearchEngineUtils = require('lib/services/searchengine/SearchEngineUtils');
const SearchEngine = require('lib/services/searchengine/SearchEngine');
Icon.loadFont();
@@ -73,6 +72,18 @@ class SearchScreenComponent extends BaseScreenComponent {
this.isMounted_ = false;
}
// UNSAFE_componentWillReceiveProps(newProps) {
// console.info('UNSAFE_componentWillReceiveProps', newProps);
// let newState = {};
// if ('query' in newProps && !this.state.query) newState.query = newProps.query;
// if (Object.getOwnPropertyNames(newState).length) {
// this.setState(newState);
// this.refreshSearch(newState.query);
// }
// }
searchTextInput_submit() {
const query = this.state.query.trim();
if (!query) return;
@@ -123,14 +134,6 @@ class SearchScreenComponent extends BaseScreenComponent {
if (!this.isMounted_) return;
const parsedQuery = await SearchEngine.instance().parseQuery(query);
const highlightedWords = SearchEngine.instance().allParsedQueryTerms(parsedQuery);
this.props.dispatch({
type: 'SET_HIGHLIGHTED',
words: highlightedWords,
});
this.setState({ notes: notes });
}

View File

@@ -37,15 +37,7 @@ class DatabaseDriverNode {
}
loadExtension(path) {
return new Promise((resolve, reject) => {
this.db_.loadExtension(path, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
return this.db_.loadExtension(path);
}
selectAll(sql, params = null) {

View File

@@ -9,8 +9,6 @@ class Database {
this.logger_ = new Logger();
this.logExcludedQueryTypes_ = [];
this.batchTransactionMutex_ = new Mutex();
this.profilingEnabled_ = false;
this.queryId_ = 1;
}
setLogExcludedQueryTypes(v) {
@@ -73,30 +71,10 @@ class Database {
let waitTime = 50;
let totalWaitTime = 0;
const callStartTime = Date.now();
let profilingTimeoutId = null;
while (true) {
try {
this.logQuery(sql, params);
const queryId = this.queryId_++;
if (this.profilingEnabled_) {
console.info(`SQL START ${queryId}`, sql, params);
profilingTimeoutId = setInterval(() => {
console.warn(`SQL ${queryId} has been running for ${Date.now() - callStartTime}: ${sql}`);
}, 3000);
}
const result = await this.driver()[callName](sql, params);
if (this.profilingEnabled_) {
clearInterval(profilingTimeoutId);
profilingTimeoutId = null;
const elapsed = Date.now() - callStartTime;
if (elapsed > 10) console.info(`SQL END ${queryId}`, elapsed, sql, params);
}
return result; // No exception was thrown
} catch (error) {
if (error && (error.code == 'SQLITE_IOERR' || error.code == 'SQLITE_BUSY')) {
@@ -111,8 +89,6 @@ class Database {
} else {
throw this.sqliteErrorToJsError(error, sql, params);
}
} finally {
if (profilingTimeoutId) clearInterval(profilingTimeoutId);
}
}
}
@@ -121,16 +97,14 @@ class Database {
return this.tryCall('selectOne', sql, params);
}
async loadExtension(/* path */) {
return; // Disabled for now as fuzzy search extension is not in use
// let result = null;
// try {
// result = await this.driver().loadExtension(path);
// return result;
// } catch (e) {
// throw new Error(`Could not load extension ${path}`);
// }
async loadExtension(path) {
let result = null;
try {
result = await this.driver().loadExtension(path);
return result;
} catch (e) {
throw new Error(`Could not load extension ${path}`);
}
}
async selectAll(sql, params = null) {

View File

@@ -1,13 +0,0 @@
import useEffectDebugger from './useEffectDebugger';
export default function usePropsDebugger(effectHook:any, props:any) {
const dependencies:any[] = [];
const dependencyNames:string[] = [];
for (const k in props) {
dependencies.push(props[k]);
dependencyNames.push(k);
}
useEffectDebugger(effectHook, dependencies, dependencyNames);
}

View File

@@ -3,6 +3,7 @@ const { Database } = require('lib/database.js');
const { sprintf } = require('sprintf-js');
const Resource = require('lib/models/Resource');
const { shim } = require('lib/shim.js');
const EventEmitter = require('events');
const structureSql = `
CREATE TABLE folders (
@@ -126,6 +127,11 @@ class JoplinDatabase extends Database {
this.version_ = null;
this.tableFieldNames_ = {};
this.extensionToLoad = './build/lib/sql-extensions/spellfix';
this.eventEmitter_ = new EventEmitter();
}
eventEmitter() {
return this.eventEmitter_;
}
initialized() {
@@ -343,8 +349,6 @@ class JoplinDatabase extends Database {
+ `Expected version: ${existingDatabaseVersions[existingDatabaseVersions.length - 1]}`);
}
this.logger().info(`Upgrading database from version ${fromVersion}`);
if (currentVersionIndex == existingDatabaseVersions.length - 1) return fromVersion;
let latestVersion = fromVersion;
@@ -355,6 +359,8 @@ class JoplinDatabase extends Database {
let queries = [];
this.eventEmitter_.emit('startMigration', { version: targetVersion });
if (targetVersion == 1) {
queries = this.wrapQueries(this.sqlStringToLines(structureSql));
}
@@ -850,32 +856,18 @@ class JoplinDatabase extends Database {
queries.push('CREATE VIRTUAL TABLE notes_spellfix USING spellfix1');
}
const updateVersionQuery = { sql: 'UPDATE version SET version = ?', params: [targetVersion] };
queries.push(updateVersionQuery);
queries.push({ sql: 'UPDATE version SET version = ?', params: [targetVersion] });
try {
await this.transactionExecBatch(queries);
} catch (error) {
// In some cases listed below, when the upgrade fail it is acceptable (a fallback will be used)
// and in those cases, even though it fails, we still want to set the version number so that the
// migration is not repeated on next upgrade.
let saveVersionAgain = false;
if (targetVersion === 15 || targetVersion === 18 || targetVersion === 33) {
this.logger().warn('Could not upgrade to database v15 or v18 or v33 - FTS feature will not be used', error);
saveVersionAgain = true;
} else if (targetVersion === 34) {
this.logger().warn('Could not upgrade to database v34 - fuzzy search will not be used', error);
saveVersionAgain = true;
} else {
throw error;
}
if (saveVersionAgain) {
this.logger().info('Migration failed with fallback and will not be repeated - saving version number');
await this.transactionExecBatch([updateVersionQuery]);
}
}
latestVersion = targetVersion;
@@ -918,12 +910,9 @@ class JoplinDatabase extends Database {
this.logger().info('Checking for database schema update...');
try {
// Note that the only extension that can be loaded as of now is spellfix.
// If it fails here, it will fail on the fuzzySearchEnabled() check above
// too, thus disabling spellfix for the app.
await this.loadExtension(this.extensionToLoad);
} catch (error) {
this.logger().error(error);
console.info(error);
}
let versionRow = null;
@@ -934,20 +923,17 @@ class JoplinDatabase extends Database {
if (error.message && error.message.indexOf('no such table: version') >= 0) {
// Ignore
} else {
this.logger().info(error);
console.info(error);
}
}
const version = !versionRow ? 0 : versionRow.version;
const tableFieldsVersion = !versionRow ? 0 : versionRow.table_fields_version;
this.version_ = version;
this.logger().info('Current database version', versionRow);
this.logger().info('Current database version', version);
const newVersion = await this.upgradeDatabase(version);
this.version_ = newVersion;
this.logger().info(`New version: ${newVersion}. Previously recorded version: ${tableFieldsVersion}`);
if (newVersion !== tableFieldsVersion) await this.refreshTableFields(newVersion);
this.tableFields_ = {};

View File

@@ -1,8 +1,6 @@
const htmlUtils = require('./htmlUtils');
const utils = require('./utils');
const noteStyle = require('./noteStyle');
const Setting = require('lib/models/Setting');
const { themeStyle } = require('lib/theme');
const memoryCache = require('memory-cache');
const md5 = require('md5');
@@ -46,10 +44,7 @@ class HtmlToHtml {
return []; // TODO
}
// Note: the "theme" variable is ignored and instead the light theme is
// always used for HTML notes.
// See: https://github.com/laurent22/joplin/issues/3698
async render(markup, _theme, options) {
async render(markup, theme, options) {
options = Object.assign({}, {
splitted: false,
}, options);
@@ -89,8 +84,7 @@ class HtmlToHtml {
};
}
const lightTheme = themeStyle(Setting.THEME_LIGHT);
let cssStrings = noteStyle(lightTheme);
let cssStrings = noteStyle(theme);
if (options.splitted) {
const splitted = this.splitHtml(html);

View File

@@ -21,7 +21,7 @@ const rules = {
const setupLinkify = require('./MdToHtml/setupLinkify');
const hljs = require('highlight.js');
const nodeSlug = require('slug');
const uslug = require('uslug');
const markdownItAnchor = require('markdown-it-anchor');
// The keys must match the corresponding entry in Setting.js
const plugins = {
@@ -34,13 +34,13 @@ const plugins = {
emoji: { module: require('markdown-it-emoji') },
insert: { module: require('markdown-it-ins') },
multitable: { module: require('markdown-it-multimd-table'), options: { multiline: true, rowspan: true, headerless: true } },
toc: { module: require('markdown-it-toc-done-right'), options: { listType: 'ul', slugify: slugify } },
toc: { module: require('markdown-it-toc-done-right'), options: { listType: 'ul', slugify: uslugify } },
expand_tabs: { module: require('markdown-it-expand-tabs'), options: { tabWidth: 4 } },
};
const defaultNoteStyle = require('./defaultNoteStyle');
function slugify(s) {
return nodeSlug(s);
function uslugify(s) {
return uslug(s);
}
class MdToHtml {
@@ -295,7 +295,7 @@ class MdToHtml {
markdownIt.use(ruleInstall(context, { ...ruleOptions }));
}
markdownIt.use(markdownItAnchor, { slugify: slugify });
markdownIt.use(markdownItAnchor, { slugify: uslugify });
for (const key in plugins) {
if (this.pluginEnabled(key)) markdownIt.use(plugins[key].module, plugins[key].options);

File diff suppressed because one or more lines are too long

View File

@@ -286,7 +286,6 @@ module.exports = function(theme) {
opacity: 0.7;
}
.jop-tinymce ul.joplin-checklist .checked,
.md-checkbox .checkbox-label-checked {
opacity: 0.5;
}

View File

@@ -37,7 +37,7 @@
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1",
"memory-cache": "^0.2.0",
"mermaid": "^8.8.0",
"slug": "^3.5.0"
"mermaid": "^8.4.6",
"uslug": "^1.0.4"
}
}

View File

@@ -156,8 +156,6 @@ class BaseItem extends BaseModel {
}
static async loadItemsByIds(ids) {
if (!ids.length) return [];
const classes = this.syncItemClassNames();
let output = [];
for (let i = 0; i < classes.length; i++) {

View File

@@ -595,7 +595,7 @@ class Setting extends BaseModel {
description: () => 'CSS file support is provided for your convenience, but they are advanced settings, and styles you define may break from one version to the next. If you want to use them, please know that it might require regular development work from you to keep them working. The Joplin team cannot make a commitment to keep the application HTML structure stable.',
},
autoUpdateEnabled: { value: false, type: Setting.TYPE_BOOL, section: 'application', public: true, appTypes: ['desktop'], label: () => _('Automatically update the application') },
autoUpdateEnabled: { value: true, type: Setting.TYPE_BOOL, section: 'application', public: true, appTypes: ['desktop'], label: () => _('Automatically update the application') },
'autoUpdate.includePreReleases': { value: false, type: Setting.TYPE_BOOL, section: 'application', public: true, appTypes: ['desktop'], label: () => _('Get pre-releases when checking for updates'), description: () => _('See the pre-release page for more details: %s', 'https://joplinapp.org/prereleases') },
'clipperServer.autoStart': { value: false, type: Setting.TYPE_BOOL, public: false },
'sync.interval': {

View File

@@ -109,7 +109,6 @@ class Tag extends BaseItem {
static async tagsByNoteId(noteId) {
const tagIds = await NoteTag.tagIdsByNoteId(noteId);
if (!tagIds.length) return [];
return this.modelSelectAll(`SELECT * FROM tags WHERE id IN ("${tagIds.join('","')}")`);
}

View File

@@ -40,12 +40,7 @@ function isHidden(path) {
}
function safeFileExtension(e, maxLength = null) {
// In theory the file extension can have any length but in practice Joplin
// expects a fixed length, so we limit it to 20 which should cover most cases.
// Note that it means that a file extension longer than 20 will break
// external editing (since the extension would be truncated).
// https://discourse.joplinapp.org/t/troubles-with-webarchive-files-on-ios/10447
if (maxLength === null) maxLength = 20;
if (maxLength === null) maxLength = 8;
if (!e || !e.replace) return '';
return e.replace(/[^a-zA-Z0-9]/g, '').substr(0, maxLength);
}
@@ -58,7 +53,7 @@ function safeFilename(e, maxLength = null, allowSpaces = false) {
return output.substr(0, maxLength);
}
let friendlySafeFilename_blackListChars = '/<>:\'"\\|?*#';
let friendlySafeFilename_blackListChars = '/<>:\'"\\|?*';
for (let i = 0; i < 32; i++) {
friendlySafeFilename_blackListChars += String.fromCharCode(i);
}

View File

@@ -313,9 +313,7 @@ function updateSelectedNotesFromExistingNotes(state) {
function defaultNotesParentType(state, exclusion) {
let newNotesParentType = null;
if (exclusion !== 'SmartFilter' && state.selectedSmartFilterId) {
newNotesParentType = 'SmartFilter';
} else if (exclusion !== 'Folder' && state.selectedFolderId) {
if (exclusion !== 'Folder' && state.selectedFolderId) {
newNotesParentType = 'Folder';
} else if (exclusion !== 'Tag' && state.selectedTagId) {
newNotesParentType = 'Tag';
@@ -545,7 +543,7 @@ function handleHistory(state, action) {
}
const reducer = (state = defaultState, action) => {
// if (!['SIDE_MENU_OPEN_PERCENT'].includes(action.type)) console.info('Action', action.type, action);
// if (!['SIDE_MENU_OPEN_PERCENT'].includes(action.type)) console.info('Action', action.type);
let newState = state;

View File

@@ -360,10 +360,7 @@ class InteropService {
continue;
}
if (item.encryption_applied || item.encryption_blob_encrypted) {
result.warnings.push(sprintf('This item is currently encrypted: %s "%s" (%s) and was not exported. You may wait for it to be decrypted and try again.', BaseModel.modelTypeToName(itemType), item.title ? item.title : item.id, item.id));
continue;
}
if (item.encryption_applied || item.encryption_blob_encrypted) throw new Error(_('This item is currently encrypted: %s "%s". Please wait for all items to be decrypted and try again.', BaseModel.modelTypeToName(itemType), item.title ? item.title : item.id));
try {
if (itemType == BaseModel.TYPE_RESOURCE) {

View File

@@ -4,7 +4,6 @@ const BaseModel = require('lib/BaseModel');
const Folder = require('lib/models/Folder');
const Note = require('lib/models/Note');
const { shim } = require('lib/shim');
const markdownUtils = require('lib/markdownUtils');
class InteropService_Exporter_Md extends InteropService_Exporter_Base {
async init(destDir) {
@@ -54,7 +53,7 @@ class InteropService_Exporter_Md extends InteropService_Exporter_Base {
const notePaths = this.context() && this.context().notePaths ? this.context().notePaths : {};
const createRelativePath = function(notePath) {
return markdownUtils.escapeLinkUrl(`${relativePathToRoot}${notePath}`.trim());
return encodeURI(`${relativePathToRoot}${notePath}`.trim());
};
return await this.replaceItemIdsByRelativePaths_(noteBody, linkedNoteIds, notePaths, createRelativePath);
}

View File

@@ -136,7 +136,7 @@ export default class KeymapService extends BaseService {
this.overrideKeymap(JSON.parse(customKeymapFile));
} catch (err) {
const message = err.message || '';
throw new Error(_('Error: %s', message));
throw new Error(`${_('Error loading the keymap from file: %s', customKeymapPath)}\n${message}`);
}
}
}
@@ -153,7 +153,7 @@ export default class KeymapService extends BaseService {
eventManager.emit('keymapChange');
} catch (err) {
const message = err.message || '';
throw new Error(_('Error: %s', message));
throw new Error(`${_('Error saving the keymap to file: %s', customKeymapPath)}\n${message}`);
}
}
@@ -227,18 +227,18 @@ export default class KeymapService extends BaseService {
private validateKeymapItem(item: KeymapItem) {
if (!item.hasOwnProperty('command')) {
throw new Error(_('"%s" is missing the required "%s" property.', JSON.stringify(item), 'command'));
throw new Error(_('Keymap item %s is missing the required "command" property.', JSON.stringify(item)));
} else if (!this.keymap.hasOwnProperty(item.command)) {
throw new Error(_('Invalid %s: %s.', 'command', item.command));
throw new Error(_('Keymap item %s is invalid because %s is not a valid command.', JSON.stringify(item), item.command));
}
if (!item.hasOwnProperty('accelerator')) {
throw new Error(_('"%s" is missing the required "%s" property.', JSON.stringify(item), 'accelerator'));
throw new Error(_('Keymap item %s is missing the required "accelerator" property.', JSON.stringify(item)));
} else if (item.accelerator !== null) {
try {
this.validateAccelerator(item.accelerator);
} catch {
throw new Error(_('Invalid %s: %s.', 'accelerator', item.command));
throw new Error(_('Keymap item %s is invalid because %s is not a valid accelerator.', JSON.stringify(item), item.accelerator));
}
}
}

View File

@@ -1,56 +0,0 @@
const Folder = require('lib/models/Folder');
const Note = require('lib/models/Note');
function randomIndex(array:any[]):number {
return Math.round(Math.random() * (array.length - 1));
}
export default async function populateDatabase(db:any) {
await db.clearForTesting();
const folderCount = 2000;
const noteCount = 20000;
const createdFolderIds:string[] = [];
const createdNoteIds:string[] = [];
for (let i = 0; i < folderCount; i++) {
const folder:any = {
title: `folder${i}`,
};
const isRoot = Math.random() <= 0.1 || i === 0;
if (!isRoot) {
const parentIndex = randomIndex(createdFolderIds);
folder.parent_id = createdFolderIds[parentIndex];
}
const savedFolder = await Folder.save(folder);
createdFolderIds.push(savedFolder.id);
console.info(`Folders: ${i} / ${folderCount}`);
}
let noteBatch = [];
for (let i = 0; i < noteCount; i++) {
const note:any = { title: `note${i}`, body: `This is note num. ${i}` };
const parentIndex = randomIndex(createdFolderIds);
note.parent_id = createdFolderIds[parentIndex];
noteBatch.push(Note.save(note, { dispatchUpdateAction: false }).then((savedNote:any) => {
createdNoteIds.push(savedNote.id);
console.info(`Notes: ${i} / ${noteCount}`);
}));
if (noteBatch.length > 1000) {
await Promise.all(noteBatch);
noteBatch = [];
}
}
if (noteBatch.length) {
await Promise.all(noteBatch);
noteBatch = [];
}
}

View File

@@ -460,15 +460,6 @@ class SearchEngine {
const fuzzyTitle = await this.fuzzifier(titleTerms.filter(x => !x.wildcard).map(x => trimQuotes(x.value)));
const fuzzyBody = await this.fuzzifier(bodyTerms.filter(x => !x.wildcard).map(x => trimQuotes(x.value)));
// Floor the fuzzy scores to 0, 1 and 2.
const floorFuzzyScore = (matches) => {
for (let i = 0; i < matches.length; i++) matches[i].score = i;
};
fuzzyText.forEach(floorFuzzyScore);
fuzzyTitle.forEach(floorFuzzyScore);
fuzzyBody.forEach(floorFuzzyScore);
const phraseTextSearch = textTerms.filter(x => x.quoted);
const wildCardSearch = textTerms.concat(titleTerms).concat(bodyTerms).filter(x => x.wildcard);

View File

@@ -8078,9 +8078,9 @@
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
},
"patch-package": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.2.2.tgz",
"integrity": "sha512-YqScVYkVcClUY0v8fF0kWOjDYopzIM8e3bj/RU1DPeEF14+dCGm6UeOYm4jvCyxqIEQ5/eJzmbWfDWnUleFNMg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.2.1.tgz",
"integrity": "sha512-dfCtQor63PPij6DDYtCzBRoO5nNAcMSg7Cmh+DLhR+s3t0OLQBdvFxJksZHBe1J2MjsSWDjTF4+oQKFbdkssIg==",
"dev": true,
"requires": {
"@yarnpkg/lockfile": "^1.1.0",
@@ -9992,11 +9992,6 @@
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
},
"slug": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/slug/-/slug-3.5.0.tgz",
"integrity": "sha512-+pZLDhMtmAc+ZcojQSMlUKDZBYmvhZiZmK8Ffx/D3Q/MIMHPDBAMbWvWN8vJb9xl2MfbDdRWxFzrdOhBiyVpow=="
},
"slugify": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.6.tgz",
@@ -10655,6 +10650,11 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -10742,6 +10742,14 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
"uslug": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz",
"integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=",
"requires": {
"unorm": ">= 1.0.0"
}
},
"utf8": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz",

View File

@@ -83,13 +83,13 @@
"redux": "4.0.0",
"reselect": "^4.0.0",
"rn-fetch-blob": "^0.12.0",
"slug": "^3.5.0",
"stream": "0.0.2",
"string-natural-compare": "^2.0.2",
"string-padding": "^1.0.2",
"timers": "^0.1.1",
"url": "^0.11.0",
"url-parse": "^1.4.7",
"uslug": "^1.0.4",
"uuid": "^3.0.1",
"valid-url": "^1.0.9",
"word-wrap": "^1.2.3",
@@ -104,7 +104,7 @@
"gulp": "^4.0.2",
"jetifier": "^1.6.5",
"metro-react-native-babel-preset": "^0.54.1",
"patch-package": "^6.2.2",
"patch-package": "^6.2.1",
"react-test-renderer": "^16.8.3"
}
}

View File

@@ -2,7 +2,7 @@ import setUpQuickActions from './setUpQuickActions';
import PluginAssetsLoader from './PluginAssetsLoader';
const React = require('react');
const { AppState, Keyboard, NativeModules, BackHandler, Animated, View, StatusBar } = require('react-native');
const { AppState, Keyboard, NativeModules, BackHandler, Animated, View, StatusBar, Text, Image } = require('react-native');
const SafeAreaView = require('lib/components/SafeAreaView');
const { connect, Provider } = require('react-redux');
const { BackButtonService } = require('lib/services/back-button.js');
@@ -376,7 +376,7 @@ function decryptionWorker_resourceMetadataButNotBlobDecrypted() {
ResourceFetcher.instance().scheduleAutoAddResources();
}
async function initialize(dispatch) {
async function initialize(dispatch, messageHandler) {
shimInit();
Setting.setConstant('env', __DEV__ ? 'dev' : 'prod');
@@ -415,8 +415,13 @@ async function initialize(dispatch) {
dbLogger.setLevel(Logger.LEVEL_INFO);
}
const db_startUpgrade = (event) => {
messageHandler(`Upgrading database to v${event.version}...`);
};
const db = new JoplinDatabase(new DatabaseDriverReactNative());
db.setLogger(dbLogger);
db.eventEmitter().on('startMigration', db_startUpgrade);
reg.setDb(db);
reg.dispatch = dispatch;
@@ -453,9 +458,13 @@ async function initialize(dispatch) {
// await db.clearForTesting();
}
db.eventEmitter().removeListener('startMigration', db_startUpgrade);
reg.logger().info('Database is ready.');
reg.logger().info('Loading settings...');
messageHandler('Initialising application...');
await loadKeychainServiceAndSettings(KeychainServiceDriverMobile);
if (!Setting.value('clientId')) Setting.setValue('clientId', uuid.create());
@@ -602,6 +611,7 @@ class AppComponent extends React.Component {
this.state = {
sideMenuContentOpacity: new Animated.Value(0),
initMessage: '',
};
this.lastSyncStarted_ = defaultState.syncStarted;
@@ -615,66 +625,52 @@ class AppComponent extends React.Component {
};
}
// 2020-10-08: It seems the initialisation code is quite fragile in general and should be kept simple.
// For example, adding a loading screen as was done in this commit: https://github.com/laurent22/joplin/commit/569355a3182bc12e50a54249882e3d68a72c2b28.
// had for effect that sharing with the app would create multiple instances of the app, thus breaking
// database access and so on. It's unclear why it happens and how to fix it but reverting that commit
// fixed the issue for now.
//
// Changing app launch mode doesn't help.
//
// It's possible that it's a bug in React Native, or perhaps the framework expects that the whole app can be
// mounted/unmounted or multiple ones can be running at the same time, but the app was not designed in this
// way.
//
// More reports and info about the multiple instance bug:
//
// https://github.com/laurent22/joplin/issues/3800
// https://github.com/laurent22/joplin/issues/3804
// https://github.com/laurent22/joplin/issues/3807
// https://discourse.joplinapp.org/t/webdav-config-encryption-config-randomly-lost-on-android/11364
// https://discourse.joplinapp.org/t/android-keeps-on-resetting-my-sync-and-theme/11443
async componentDidMount() {
if (this.props.appState == 'starting') {
componentDidMount() {
setTimeout(async () => {
// We run initialization code with a small delay to give time
// to the view to render "please wait" messages.
this.props.dispatch({
type: 'APP_STATE_SET',
state: 'initializing',
});
await initialize(this.props.dispatch);
await initialize(this.props.dispatch, (message) => {
this.setState({ initMessage: message });
});
BackButtonService.initialize(this.backButtonHandler_);
AlarmService.setInAppNotificationHandler(async (alarmId) => {
const alarm = await Alarm.load(alarmId);
const notification = await Alarm.makeNotification(alarm);
this.dropdownAlert_.alertWithType('info', notification.title, notification.body ? notification.body : '');
});
AppState.addEventListener('change', this.onAppStateChange_);
const sharedData = await ShareExtension.data();
if (sharedData) {
reg.logger().info('Received shared data');
if (this.props.selectedFolderId) {
handleShared(sharedData, this.props.selectedFolderId, this.props.dispatch);
} else {
reg.logger.info('Cannot handle share - default folder id is not set');
}
}
this.props.dispatch({
type: 'APP_STATE_SET',
state: 'ready',
});
}
BackButtonService.initialize(this.backButtonHandler_);
AlarmService.setInAppNotificationHandler(async (alarmId) => {
const alarm = await Alarm.load(alarmId);
const notification = await Alarm.makeNotification(alarm);
this.dropdownAlert_.alertWithType('info', notification.title, notification.body ? notification.body : '');
});
AppState.addEventListener('change', this.onAppStateChange_);
const sharedData = await ShareExtension.data();
if (sharedData) {
reg.logger().info('Received shared data');
if (this.props.selectedFolderId) {
handleShared(sharedData, this.props.selectedFolderId, this.props.dispatch);
} else {
reg.logger.info('Cannot handle share - default folder id is not set');
}
}
}, 100);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.onAppStateChange_);
}
componentDidUpdate(prevProps) {
async componentDidUpdate(prevProps) {
if (this.props.showSideMenu !== prevProps.showSideMenu) {
Animated.timing(this.state.sideMenuContentOpacity, {
toValue: this.props.showSideMenu ? 0.5 : 0,
@@ -719,8 +715,19 @@ class AppComponent extends React.Component {
});
}
renderStartupScreen() {
return (
<View style={{ alignItems: 'center', justifyContent: 'center', flex: 1 }}>
<View style={{ alignItems: 'center' }}>
<Image style={{ marginBottom: 5 }} source={require('./images/StartUpIcon.png')} />
<Text style={{ color: '#444444' }}>{this.state.initMessage}</Text>
</View>
</View>
);
}
render() {
if (this.props.appState != 'ready') return null;
if (this.props.appState != 'ready') return this.renderStartupScreen();
const theme = themeStyle(this.props.themeId);
let sideMenuContent = null;

View File

@@ -281,6 +281,29 @@ const operations = [
iconWidth: 46,
iconHeight: 46,
},
// ============================================================================
// Mobile startup icon
// ============================================================================
{
source: 7,
dest: 'ReactNativeClient/images/StartUpIcon.png',
width: 64,
height: 64,
},
{
source: 7,
dest: 'ReactNativeClient/images/StartUpIcon@2x.png',
width: 128,
height: 128,
},
{
source: 7,
dest: 'ReactNativeClient/images/StartUpIcon@3x.png',
width: 192,
height: 192,
},
];
async function main() {

View File

@@ -34,11 +34,6 @@ async function gitLog(sinceTag) {
return output;
}
async function gitTags() {
const lines = await execCommand('git tag --sort=committerdate');
return lines.split('\n').map(l => l.trim());
}
function platformFromTag(tagName) {
if (tagName.indexOf('v') === 0) return 'desktop';
if (tagName.indexOf('android') >= 0) return 'android';
@@ -48,15 +43,6 @@ function platformFromTag(tagName) {
throw new Error(`Could not determine platform from tag: ${tagName}`);
}
// function tagPrefixFromPlatform(platform) {
// if (platform === 'desktop') return '';
// if (platform === 'android') return 'android-';
// if (platform === 'ios') return 'ios-';
// if (platform === 'clipper') return 'clipper-';
// if (platform === 'cli') return 'cli-';
// throw new Error(`Could not determine tag prefix from platform: ${platform}`);
// }
function filterLogs(logs, platform) {
const output = [];
const revertedLogs = [];
@@ -211,6 +197,8 @@ function formatCommitMessage(msg, author, options) {
const commitMessage = parseCommitMessage(output, subModule);
console.info(commitMessage);
const messagePieces = [];
messagePieces.push(`${capitalizeFirstLetter(commitMessage.type)}`);
if (commitMessage.subModule) messagePieces.push(`${capitalizeFirstLetter(commitMessage.subModule)}`);
@@ -261,42 +249,25 @@ function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// function decreaseTagVersion(tag) {
// const s = tag.split('.');
// let updated = false;
// for (let tokenIndex = s.length - 1; tokenIndex >= 0; tokenIndex--) {
// const token = s[tokenIndex];
// const s2 = token.split('-');
// let num = Number(s2[0]);
// num--;
// if (num >= 0) {
// updated = true;
// s[tokenIndex] = num;
// break;
// }
// }
// if (!updated) throw new Error(`Cannot decrease tag version: ${tag}`);
// return s.join('.');
// }
function decreaseTagVersion(tag) {
const s = tag.split('.');
const lastToken = s.pop();
const s2 = lastToken.split('-');
let num = Number(s2[0]);
num--;
if (num < 0) throw new Error(`Cannot decrease tag version: ${tag}`);
s.push(`${num}`);
return s.join('.');
}
// This function finds the first relevant tag starting from the given tag.
// The first "relevant tag" is the one that exists, and from which there are changes.
async function findFirstRelevantTag(baseTag, platform, allTags) {
let baseTagIndex = allTags.indexOf(baseTag);
if (baseTagIndex < 0) baseTagIndex = allTags.length;
for (let i = baseTagIndex - 1; i >= 0; i--) {
const tag = allTags[i];
if (platformFromTag(tag) !== platform) continue;
async function findFirstRelevantTag(baseTag) {
let tag = decreaseTagVersion(baseTag);
while (true) {
try {
const logs = await gitLog(tag);
const filteredLogs = filterLogs(logs, platform);
if (filteredLogs.length) return tag;
if (logs.length) return tag;
} catch (error) {
if (error.message.indexOf('unknown revision') >= 0) {
// We skip the error - it means this particular tag has never been created
@@ -304,22 +275,21 @@ async function findFirstRelevantTag(baseTag, platform, allTags) {
throw error;
}
}
}
throw new Error(`Could not find previous tag for: ${baseTag}`);
tag = decreaseTagVersion(tag);
}
}
async function main() {
const argv = require('yargs').argv;
if (!argv._.length) throw new Error('Tag name must be specified. Provide the tag of the new version and git-changelog will walk backward to find the changes to the previous relevant tag.');
const allTags = await gitTags();
const fromTagName = argv._[0];
let toTagName = argv._.length >= 2 ? argv._[1] : '';
const platform = platformFromTag(fromTagName);
if (!toTagName) toTagName = await findFirstRelevantTag(fromTagName, platform, allTags);
if (!toTagName) toTagName = await findFirstRelevantTag(fromTagName);
const logsSinceTags = await gitLog(toTagName);

View File

@@ -45,11 +45,6 @@ async function main() {
} catch (e) {
console.warn(e);
}
await fs.remove(`${dest}/sqlite.tar.gz`);
await fs.remove(`${dest}/amalgamation.tar.gz`);
await fs.remove(`${dest}/sqlite`);
await fs.remove(`${dest}/sqlite-autoconf-3330000`);
}
module.exports = main;

View File

@@ -1,11 +0,0 @@
const utils = require('../utils');
const rootDir = utils.rootDir();
const fs = require('fs-extra');
module.exports = {
src: '',
fn: async function() {
await fs.remove(`${rootDir}/CliClient/tests-build`);
await fs.remove(`${rootDir}/CliClient/build`);
},
};

407
Tools/package-lock.json generated
View File

@@ -4,11 +4,6 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
},
"ajv": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz",
@@ -25,30 +20,6 @@
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
},
"dependencies": {
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}
}
},
"app-module-path": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz",
@@ -157,6 +128,11 @@
"upper-case": "^1.1.1"
}
},
"camelcase": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA=="
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -176,43 +152,13 @@
}
},
"cliui": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz",
"integrity": "sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
},
"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.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"requires": {
"ansi-regex": "^5.0.0"
}
}
"string-width": "^2.1.1",
"strip-ansi": "^4.0.0",
"wrap-ansi": "^2.0.0"
}
},
"code-point-at": {
@@ -274,6 +220,18 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -282,6 +240,11 @@
"assert-plus": "^1.0.0"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"decompress-response": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
@@ -319,11 +282,6 @@
"safer-buffer": "^2.1.0"
}
},
"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=="
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
@@ -345,10 +303,19 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
},
"escalade": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz",
"integrity": "sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig=="
"execa": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"requires": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
}
},
"expand-template": {
"version": "2.0.3",
@@ -375,6 +342,14 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"requires": {
"locate-path": "^3.0.0"
}
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -462,9 +437,17 @@
}
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
},
"get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"requires": {
"pump": "^3.0.0"
}
},
"getpass": {
"version": "0.1.7",
@@ -561,6 +544,11 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
},
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
@@ -586,6 +574,11 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -630,6 +623,14 @@
"verror": "1.10.0"
}
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"requires": {
"invert-kv": "^2.0.0"
}
},
"linkify-it": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz",
@@ -638,11 +639,28 @@
"uc.micro": "^1.0.1"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"lower-case": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
"integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
},
"map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"requires": {
"p-defer": "^1.0.0"
}
},
"markdown-it": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.1.tgz",
@@ -665,6 +683,16 @@
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
},
"mem": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz",
"integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==",
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^1.0.0",
"p-is-promise": "^1.1.0"
}
},
"mime-db": {
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
@@ -678,6 +706,11 @@
"mime-db": "1.43.0"
}
},
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"mimic-response": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
@@ -738,6 +771,11 @@
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"no-case": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
@@ -773,6 +811,14 @@
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
"integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI="
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"requires": {
"path-key": "^2.0.0"
}
},
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
@@ -807,6 +853,52 @@
"wrappy": "1"
}
},
"os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-is-promise": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
"integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4="
},
"p-limit": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz",
"integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==",
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"requires": {
"p-limit": "^2.0.0"
}
},
"p-try": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
"integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ=="
},
"param-case": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
@@ -815,6 +907,16 @@
"no-case": "^2.2.0"
}
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
},
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
},
"pct-encode": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pct-encode/-/pct-encode-1.0.2.tgz",
@@ -945,6 +1047,11 @@
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
},
"require-main-filename": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
@@ -988,6 +1095,19 @@
}
}
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
@@ -1072,6 +1192,11 @@
"ansi-regex": "^3.0.0"
}
},
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -1221,6 +1346,19 @@
"extsprintf": "^1.2.0"
}
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "^2.0.0"
}
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
},
"which-pm-runs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
@@ -1235,41 +1373,43 @@
}
},
"wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"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=="
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
"number-is-nan": "^1.0.0"
}
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^5.0.0"
"ansi-regex": "^2.0.0"
}
}
}
@@ -1280,9 +1420,9 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"y18n": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.1.tgz",
"integrity": "sha512-/jJ831jEs4vGDbYPQp4yGKDYPSCCEQ45uZWJHE1AoYBzqdZi8+LDWas0z4HrmJXmKdpFsTiowSHXdxyFhpmdMg=="
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
},
"yallist": {
"version": "4.0.0",
@@ -1290,53 +1430,32 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yargs": {
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz",
"integrity": "sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA==",
"version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
"integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
"requires": {
"cliui": "^7.0.0",
"escalade": "^3.0.2",
"get-caller-file": "^2.0.5",
"cliui": "^4.0.0",
"decamelize": "^1.2.0",
"find-up": "^3.0.0",
"get-caller-file": "^1.0.1",
"os-locale": "^3.0.0",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.1",
"yargs-parser": "^20.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
},
"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.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"requires": {
"ansi-regex": "^5.0.0"
}
}
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^2.0.0",
"which-module": "^2.0.0",
"y18n": "^3.2.1 || ^4.0.0",
"yargs-parser": "^11.1.1"
}
},
"yargs-parser": {
"version": "20.2.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.0.tgz",
"integrity": "sha512-2agPoRFPoIcFzOIp6656gcvsg2ohtscpw2OINr/q46+Sq41xz2OYLqx5HRHabmFU1OARIPAYH5uteICE7mn/5A=="
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
}

View File

@@ -24,6 +24,6 @@
"sharp": "^0.25.2",
"string-padding": "^1.0.2",
"uri-template": "^1.0.1",
"yargs": "^16.0.3"
"yargs": "^12.0.5"
}
}

View File

@@ -151,9 +151,7 @@ async function createRelease(name, tagName, version) {
async function main() {
const argv = require('yargs').argv;
if (!['release', 'prerelease'].includes(argv.type)) throw new Error('Must specify release type. Either --type=release or --type=prerelease');
const isPreRelease = argv.type === 'prerelease';
const isPreRelease = !!argv.prerelease;
if (isPreRelease) console.info('Creating pre-release');
console.info('Updating version numbers in build.gradle...');

View File

@@ -1,82 +0,0 @@
const fs = require('fs-extra');
const path = require('path');
const rootDir = path.dirname(__dirname);
async function updatePackageVersion(packageFilePath, majorMinorVersion) {
const contentText = await fs.readFile(packageFilePath, 'utf8');
const content = JSON.parse(contentText);
if (content.version.indexOf(majorMinorVersion) === 0) return;
content.version = `${majorMinorVersion}.0`;
await fs.writeFile(packageFilePath, `${JSON.stringify(content, null, 2)}\n`, 'utf8');
}
async function updateGradleVersion(filePath, majorMinorVersion) {
const contentText = await fs.readFile(filePath, 'utf8');
const newContent = contentText.replace(/(versionName\s+")(\d+?\.\d+?)(\.\d+")/, function(match, prefix, version, suffix) {
if (version === majorMinorVersion) return prefix + version + suffix;
return `${prefix + majorMinorVersion}.0"`;
});
if (newContent === contentText) return;
await fs.writeFile(filePath, newContent, 'utf8');
}
async function updateCodeProjVersion(filePath, majorMinorVersion) {
const contentText = await fs.readFile(filePath, 'utf8');
// MARKETING_VERSION = 10.1.0;
const newContent = contentText.replace(/(MARKETING_VERSION = )(\d+\.\d+)(\.\d+;)/g, function(match, prefix, version, suffix) {
if (version === majorMinorVersion) return prefix + version + suffix;
return `${prefix + majorMinorVersion}.0;`;
});
if (newContent === contentText) return;
await fs.writeFile(filePath, newContent, 'utf8');
}
async function updateClipperManifestVersion(manifestPath, majorMinorVersion) {
const manifestText = await fs.readFile(manifestPath, 'utf8');
const manifest = JSON.parse(manifestText);
const versionText = manifest.version;
if (versionText.indexOf(majorMinorVersion) === 0) return;
manifest.version = `${majorMinorVersion}.0`;
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 4));
}
// Need this hack to transform 1.x.x into 10.x.x due to some mistake
// on one of the release and the App Store won't allow decreasing
// the major version number.
function iosVersionHack(majorMinorVersion) {
const p = majorMinorVersion.split('.');
p[0] = `${p[0]}0`;
return p.join('.');
}
async function main() {
const argv = require('yargs').parserConfiguration({
'parse-numbers': false,
}).argv;
if (!argv._ || !argv._.length) throw new Error('Please specify the major.minor version, eg. 1.2');
const majorMinorVersion = argv._[0];
await updatePackageVersion(`${rootDir}/ElectronClient/package.json`, majorMinorVersion);
await updatePackageVersion(`${rootDir}/CliClient/package.json`, majorMinorVersion);
await updateGradleVersion(`${rootDir}/ReactNativeClient/android/app/build.gradle`, majorMinorVersion);
await updateCodeProjVersion(`${rootDir}/ReactNativeClient/ios/Joplin.xcodeproj/project.pbxproj`, iosVersionHack(majorMinorVersion));
await updateClipperManifestVersion(`${rootDir}/Clipper/manifest.json`, majorMinorVersion);
}
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/api.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/changelog.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>
@@ -351,64 +351,6 @@ https://github.com/laurent22/joplin/blob/master/readme/changelog.md
</ul>
</div>
<h1>Joplin changelog<a name="joplin-changelog" href="#joplin-changelog" class="heading-anchor">🔗</a></h1>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.1.4">v1.1.4</a> - 2020-09-21T11:20:09Z<a name="v1-1-4-https-github-com-laurent22-joplin-releases-tag-v1-1-4-2020-09-21t11-20-09z" href="#v1-1-4-https-github-com-laurent22-joplin-releases-tag-v1-1-4-2020-09-21t11-20-09z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add keyboard shortcut editor (<a href="https://github.com/laurent22/joplin/issues/3525">#3525</a> by Anjula Karunarathne)</li>
<li>New: Add log statement to try to fix issue <a href="https://github.com/laurent22/joplin/issues/3536">#3536</a></li>
<li>Improved: Change codemirror default home and end to be visual line based (<a href="https://github.com/laurent22/joplin/issues/3672">#3672</a> by Caleb John)</li>
<li>Improved: Clarifies labels of certain actions, and added shortcut for note list toggle</li>
<li>Improved: Do not prevent export when one item is still encrypted</li>
<li>Improved: Fuzzy search (<a href="https://github.com/laurent22/joplin/issues/3632">#3632</a> by Naveen M V)</li>
<li>Improved: Make codemirror the default code editor (<a href="https://github.com/laurent22/joplin/issues/3703">#3703</a>) (<a href="https://github.com/laurent22/joplin/issues/3560">#3560</a> by Caleb John)</li>
<li>Improved: Rename menu item from &quot;Export&quot; to &quot;Export all&quot; to clarify what it does</li>
<li>Improved: Sync immediately on startup</li>
<li>Security: Disallow EMBED tags to prevent XSS vulnerability (CVE-2020-15930, vulnerability found by Ademar Nowasky Junior)</li>
<li>Security: Upgrade packages to fix vulnerabilities</li>
<li>Fixed: Creating a note after backward redirection places it in a wrong notebook (<a href="https://github.com/laurent22/joplin/issues/3759">#3759</a> by Naveen M V)</li>
<li>Fixed: Fix applying tags to multiple notes (<a href="https://github.com/laurent22/joplin/issues/3710">#3710</a>)</li>
<li>Fixed: Fix bug with quotes when searching (<a href="https://github.com/laurent22/joplin/issues/3735">#3735</a> by Naveen M V)</li>
<li>Fixed: Fix wildcard search (<a href="https://github.com/laurent22/joplin/issues/3713">#3713</a> by Naveen M V)</li>
<li>Fixed: Fixed clock sync logic when creating new sync target</li>
<li>Fixed: Fixed copying link in Rich Text editor (<a href="https://github.com/laurent22/joplin/issues/3697">#3697</a>)</li>
<li>Fixed: Fixed note export when there are folders with non-existing parents. Also fixed long path issue on Windows. (<a href="https://github.com/laurent22/joplin/issues/3689">#3689</a>)</li>
<li>Fixed: Fixed viewer font size, in particular for inline code (<a href="https://github.com/laurent22/joplin/issues/3553">#3553</a>)</li>
<li>Fixed: Increased file extension limit to 20 to prevent issue when using external editors (<a href="https://github.com/laurent22/joplin/issues/3696">#3696</a>)</li>
<li>Fixed: Use joplin list handling in emacs mode (<a href="https://github.com/laurent22/joplin/issues/3758">#3758</a>) (<a href="https://github.com/laurent22/joplin/issues/3749">#3749</a> by Caleb John)</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.1.3">v1.1.3</a> - 2020-09-17T10:30:37Z<a name="v1-1-3-https-github-com-laurent22-joplin-releases-tag-v1-1-3-2020-09-17t10-30-37z" href="#v1-1-3-https-github-com-laurent22-joplin-releases-tag-v1-1-3-2020-09-17t10-30-37z" class="heading-anchor">🔗</a></h2>
<ul>
<li>Improved: Do not prevent export when one item is still encrypted</li>
<li>Fixed: Creating a note after backward redirection places it in a wrong notebook (<a href="https://github.com/laurent22/joplin/issues/3759">#3759</a> by Naveen M V)</li>
<li>Fixed: Increased file extension limit to 20 to prevent issue when using external editors (<a href="https://github.com/laurent22/joplin/issues/3696">#3696</a>)</li>
<li>Fixed: Use joplin list handling in emacs mode (<a href="https://github.com/laurent22/joplin/issues/3758">#3758</a>) (<a href="https://github.com/laurent22/joplin/issues/3749">#3749</a> by Caleb John)</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.1.2">v1.1.2</a> - 2020-09-15T12:58:38Z<a name="v1-1-2-https-github-com-laurent22-joplin-releases-tag-v1-1-2-2020-09-15t12-58-38z" href="#v1-1-2-https-github-com-laurent22-joplin-releases-tag-v1-1-2-2020-09-15t12-58-38z" class="heading-anchor">🔗</a></h2>
<ul>
<li>Improved: Clarifies labels of certain actions, and added shortcut for note list toggle</li>
<li>Security: Upgrade packages to fix vulnerabilities</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.1.1">v1.1.1</a> - 2020-09-11T23:32:47Z<a name="v1-1-1-https-github-com-laurent22-joplin-releases-tag-v1-1-1-2020-09-11t23-32-47z" href="#v1-1-1-https-github-com-laurent22-joplin-releases-tag-v1-1-1-2020-09-11t23-32-47z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add keyboard shortcut editor (<a href="https://github.com/laurent22/joplin/issues/3525">#3525</a> by Anjula Karunarathne)</li>
<li>Improved: Change CodeMirror default home and end to be visual line based (<a href="https://github.com/laurent22/joplin/issues/3672">#3672</a> by Caleb John)</li>
<li>Improved: Added support for fuzzy search (<a href="https://github.com/laurent22/joplin/issues/3632">#3632</a> by Naveen M V)</li>
<li>Improved: Make CodeMirror the default code editor (<a href="https://github.com/laurent22/joplin/issues/3703">#3703</a>) (<a href="https://github.com/laurent22/joplin/issues/3560">#3560</a> by Caleb John)</li>
<li>Improved: Rename menu item from &quot;Export&quot; to &quot;Export all&quot; to clarify what it does</li>
<li>Improved: Sync immediately on startup</li>
<li>Security: Disallow EMBED tags to prevent XSS vulnerability (CVE-2020-15930, vulnerability found by Ademar Nowasky Junior)</li>
<li>Fixed: Fix applying tags to multiple notes (<a href="https://github.com/laurent22/joplin/issues/3710">#3710</a>)</li>
<li>Fixed: Fix bug with quotes when searching (<a href="https://github.com/laurent22/joplin/issues/3735">#3735</a> by Naveen M V)</li>
<li>Fixed: Fix wildcard search (<a href="https://github.com/laurent22/joplin/issues/3713">#3713</a> by Naveen M V)</li>
<li>Fixed: Fixed copying link in Rich Text editor (<a href="https://github.com/laurent22/joplin/issues/3697">#3697</a>)</li>
<li>Fixed: Fixed note export when there are folders with non-existing parents. Also fixed long path issue on Windows. (<a href="https://github.com/laurent22/joplin/issues/3689">#3689</a>)</li>
<li>Fixed: Fixed viewer font size, in particular for inline code (<a href="https://github.com/laurent22/joplin/issues/3553">#3553</a>)</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.245">v1.0.245</a> - 2020-09-09T12:56:10Z<a name="v1-0-245-https-github-com-laurent22-joplin-releases-tag-v1-0-245-2020-09-09t12-56-10z" href="#v1-0-245-https-github-com-laurent22-joplin-releases-tag-v1-0-245-2020-09-09t12-56-10z" class="heading-anchor">🔗</a></h2>
<p>This release is to fix the sync lock issues on devices that have an incorrect clock. Specifically, it should fix this error: &quot;Cannot acquire sync lock: either the lock could be written but not read back. Or it was expired before it was read again&quot;.</p>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.242">v1.0.242</a> - 2020-09-04T22:00:34Z<a name="v1-0-242-https-github-com-laurent22-joplin-releases-tag-v1-0-242-2020-09-04t22-00-34z" href="#v1-0-242-https-github-com-laurent22-joplin-releases-tag-v1-0-242-2020-09-04t22-00-34z" class="heading-anchor">🔗</a></h2>
<ul>
<li>Fixes sync target upgrade issue when custom TLS settings are used</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.0.241">v1.0.241</a> - 2020-09-04T18:06:00Z<a name="v1-0-241-https-github-com-laurent22-joplin-releases-tag-v1-0-241-2020-09-04t18-06-00z" href="#v1-0-241-https-github-com-laurent22-joplin-releases-tag-v1-0-241-2020-09-04t18-06-00z" class="heading-anchor">🔗</a></h2>
<p>This release will ask you to upgrade your sync target and, once it is done, only the latest clients will be able to sync with this sync target. So please make sure you upgrade your other clients too (mobile, cli, etc.).</p>
<p>This version also includes an update to the search engine and as a result starting the app the first might be SLOW, as the search engine indexes all your notes. It might take from a few seconds to several minutes depending on how large your note collection is. This is a one off operation.</p>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/changelog_cli.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>
@@ -351,17 +351,6 @@ https://github.com/laurent22/joplin/blob/master/readme/changelog_cli.md
</ul>
</div>
<h1>Joplin terminal app changelog<a name="joplin-terminal-app-changelog" href="#joplin-terminal-app-changelog" class="heading-anchor">🔗</a></h1>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.1.8">cli-v1.1.8</a> - 2020-09-21T12:02:29Z<a name="cli-v1-1-8-https-github-com-laurent22-joplin-releases-tag-cli-v1-1-8-2020-09-21t12-02-29z" href="#cli-v1-1-8-https-github-com-laurent22-joplin-releases-tag-cli-v1-1-8-2020-09-21t12-02-29z" class="heading-anchor">🔗</a></h2>
<ul>
<li>Improved: Do not prevent export when one item is still encrypted</li>
<li>Improved: Fix keytar library being loaded up in FreeBSD. (#3712) (#3711 by Jose Esteve)</li>
<li>Fixed: Fixed note export when there are folders with non-existing parents. Also fixed long path issue on Windows. (#3689)</li>
<li>Fixed: Increased file extension limit to 20 to prevent issue when using external editors (#3696)</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.0.168">cli-v1.0.168</a> - 2020-09-14T08:47:08Z<a name="cli-v1-0-168-https-github-com-laurent22-joplin-releases-tag-cli-v1-0-168-2020-09-14t08-47-08z" href="#cli-v1-0-168-https-github-com-laurent22-joplin-releases-tag-cli-v1-0-168-2020-09-14t08-47-08z" class="heading-anchor">🔗</a></h2>
<ul>
<li>Improved: Implemented reliable way to sync device and server clocks</li>
</ul>
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.0.167">cli-v1.0.167</a> - 2020-09-04T17:15:49Z<a name="cli-v1-0-167-https-github-com-laurent22-joplin-releases-tag-cli-v1-0-167-2020-09-04t17-15-49z" href="#cli-v1-0-167-https-github-com-laurent22-joplin-releases-tag-cli-v1-0-167-2020-09-04t17-15-49z" class="heading-anchor">🔗</a></h2>
<ul>
<li>New: Add mechanism to lock and upgrade sync targets (#3524)</li>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/clipper.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/conflict.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/debugging.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/desktop.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/donate.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>
@@ -367,6 +367,7 @@ https://github.com/laurent22/joplin/blob/master/readme/donate.md
<li>Consider rating the app on <a href="https://play.google.com/store/apps/details?id=net.cozic.joplin&amp;utm_source=GitHub&amp;utm_campaign=README&amp;pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1">Google Play</a> or <a href="https://itunes.apple.com/us/app/joplin/id1315599797">App Store</a>.</li>
<li><a href="https://joplinapp.org/#localisation">Create or update a translation</a>.</li>
<li>Vote for or review the app on <a href="https://alternativeto.net/software/joplin/">alternativeTo</a> or <a href="https://www.producthunt.com/posts/joplin">Product Hunt</a>.</li>
<li>Help improve <a href="https://en.wikipedia.org/wiki/Draft:Joplin_(software)">the Wikipedia article</a></li>
</ul>
<div class="bottom-links">

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/e2ee.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/faq.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/gsoc2020/ideas.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/gsoc2020/index.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/gsod2020/ideas.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/gsod2020/index.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/README.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>
@@ -371,17 +371,17 @@ https://github.com/laurent22/joplin/blob/master/README.md
<tbody>
<tr>
<td>Windows (32 and 64-bit)</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.1.4/Joplin-Setup-1.1.4.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a></td>
<td>Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.1.4/JoplinPortable.exe'>Portable version</a><br><br>The <a href="https://en.wikipedia.org/wiki/Portable_application">portable application</a> 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 &quot;JoplinProfile&quot; next to the executable file.</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.241/Joplin-Setup-1.0.241.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a></td>
<td>Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.0.241/JoplinPortable.exe'>Portable version</a><br><br>The <a href="https://en.wikipedia.org/wiki/Portable_application">portable application</a> 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 &quot;JoplinProfile&quot; next to the executable file.</td>
</tr>
<tr>
<td>macOS</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.1.4/Joplin-1.1.4.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.241/Joplin-1.0.241.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a></td>
<td>You can also use Homebrew (unsupported): <code>brew cask install joplin</code></td>
</tr>
<tr>
<td>Linux</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.1.4/Joplin-1.1.4.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.0.241/Joplin-1.0.241.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a></td>
<td>An Arch Linux package (unsupported) <a href="#terminal-application">is also available</a>.<br><br>If it works with your distribution (it has been tested on Ubuntu, Fedora, and Mint; the desktop environments supported are GNOME, KDE, Xfce, MATE, LXQT, LXDE, Unity, Cinnamon, Deepin and Pantheon), the recommended way is to use this script as it will handle the desktop icon too:<br><br> <code>wget -O - https://raw.githubusercontent.com/laurent22/joplin/master/Joplin_install_and_update.sh | bash</code></td>
</tr>
</tbody>
@@ -399,7 +399,7 @@ https://github.com/laurent22/joplin/blob/master/README.md
<tr>
<td>Android</td>
<td><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></td>
<td>or download the APK file: <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.1.1/joplin-v1.1.1.apk">64-bit</a> <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.1.1/joplin-v1.1.1-32bit.apk">32-bit</a></td>
<td>or download the APK file: <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.0.340/joplin-v1.0.340.apk">64-bit</a> <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.0.340/joplin-v1.0.340-32bit.apk">32-bit</a></td>
</tr>
<tr>
<td>iOS</td>
@@ -469,11 +469,6 @@ https://github.com/laurent22/joplin/blob/master/README.md
<td style="text-align:center"><img width="50" src="https://avatars2.githubusercontent.com/u/1439535?s=96&v=4"/></br><a href="https://github.com/fbloise">Frank Bloise</a></td>
<td style="text-align:center"><img width="50" src="https://avatars2.githubusercontent.com/u/15859362?s=96&v=4"/></br><a href="https://github.com/thomasbroussard">Thomas Broussard</a></td>
</tr>
<tr>
<td style="text-align:center"><img width="50" src="https://avatars2.githubusercontent.com/u/1307332?s=96&v=4"/></br><a href="https://github.com/dbrandonjohnson">Brandon Johnson</a></td>
<td style="text-align:center"></td>
<td style="text-align:center"></td>
</tr>
</tbody>
</table>
<h1>Features<a name="features" href="#features" class="heading-anchor">🔗</a></h1>
@@ -829,35 +824,35 @@ Eg. <code>:search -- &quot;-tag:tag1&quot;</code>.</p>
<td>Arabic</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ar.po">ar</a></td>
<td>أحمد باشا إبراهيم (<a href="mailto:fi_ahmed_bacha@esi.dz">fi_ahmed_bacha@esi.dz</a>)</td>
<td>80%</td>
<td>82%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/es/basque_country.png" alt=""></td>
<td>Basque</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po">eu</a></td>
<td>juan.abasolo@ehu.eus</td>
<td>34%</td>
<td>35%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/ba.png" alt=""></td>
<td>Bosnian</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/bs_BA.po">bs_BA</a></td>
<td>Derviš T. (<a href="mailto:dervis.t@pm.me">dervis.t@pm.me</a>)</td>
<td>83%</td>
<td>85%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/bg.png" alt=""></td>
<td>Bulgarian</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/bg_BG.po">bg_BG</a></td>
<td></td>
<td>66%</td>
<td>68%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/es/catalonia.png" alt=""></td>
<td>Catalan</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ca.po">ca</a></td>
<td>jmontane, 2019</td>
<td>53%</td>
<td>54%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/hr.png" alt=""></td>
@@ -871,28 +866,28 @@ Eg. <code>:search -- &quot;-tag:tag1&quot;</code>.</p>
<td>Czech</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/cs_CZ.po">cs_CZ</a></td>
<td>Lukas Helebrandt (<a href="mailto:lukas@aiya.cz">lukas@aiya.cz</a>)</td>
<td>82%</td>
<td>84%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/dk.png" alt=""></td>
<td>Dansk</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/da_DK.po">da_DK</a></td>
<td>Morten Juhl-Johansen Zölde-Fejér (mjjzf@syntaktisk.</td>
<td>74%</td>
<td>76%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/de.png" alt=""></td>
<td>Deutsch</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po">de_DE</a></td>
<td>Eike (<a href="mailto:ei-ke@users.noreply.github.com">ei-ke@users.noreply.github.com</a>)</td>
<td>95%</td>
<td>99%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/ee.png" alt=""></td>
<td>Eesti Keel</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/et_EE.po">et_EE</a></td>
<td></td>
<td>66%</td>
<td>68%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/gb.png" alt=""></td>
@@ -913,182 +908,182 @@ Eg. <code>:search -- &quot;-tag:tag1&quot;</code>.</p>
<td>Español</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po">es_ES</a></td>
<td>Fernando Pindado (<a href="mailto:fpindado@gmail.com">fpindado@gmail.com</a>)</td>
<td>95%</td>
<td>91%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/esperanto.png" alt=""></td>
<td>Esperanto</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/eo.po">eo</a></td>
<td>Marton Paulo</td>
<td>38%</td>
<td>39%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/fr.png" alt=""></td>
<td>Français</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po">fr_FR</a></td>
<td>Laurent Cozic</td>
<td>94%</td>
<td>97%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/es/galicia.png" alt=""></td>
<td>Galician</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/gl_ES.po">gl_ES</a></td>
<td>Marcos Lans (<a href="mailto:marcoslansgarza@gmail.com">marcoslansgarza@gmail.com</a>)</td>
<td>43%</td>
<td>44%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/id.png" alt=""></td>
<td>Indonesian</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/id_ID.po">id_ID</a></td>
<td>Fathy AR (<a href="mailto:16875937+fathyar@users.noreply.github.com">16875937+fathyar@users.noreply.github.com</a>)</td>
<td>93%</td>
<td>95%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/it.png" alt=""></td>
<td>Italiano</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po">it_IT</a></td>
<td>StarFang208</td>
<td>91%</td>
<td>93%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/nl.png" alt=""></td>
<td>Nederlands</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_NL.po">nl_NL</a></td>
<td>MetBril (<a href="mailto:metbril@users.noreply.github.com">metbril@users.noreply.github.com</a>)</td>
<td>96%</td>
<td>99%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/be.png" alt=""></td>
<td>Nederlands</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po">nl_BE</a></td>
<td></td>
<td>34%</td>
<td>35%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/no.png" alt=""></td>
<td>Norwegian</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/nb_NO.po">nb_NO</a></td>
<td>Mats Estensen (<a href="mailto:code@mxe.no">code@mxe.no</a>)</td>
<td>88%</td>
<td>91%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/ir.png" alt=""></td>
<td>Persian</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/fa.po">fa</a></td>
<td>Kourosh Firoozbakht (<a href="mailto:kourox@protonmail.com">kourox@protonmail.com</a>)</td>
<td>80%</td>
<td>Mehrad Mahmoudian (<a href="mailto:mehrad@mahmoudian.me">mehrad@mahmoudian.me</a>)</td>
<td>34%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/pl.png" alt=""></td>
<td>Polski</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/pl_PL.po">pl_PL</a></td>
<td></td>
<td>96%</td>
<td>87%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/pt.png" alt=""></td>
<td>Português</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_PT.po">pt_PT</a></td>
<td>Diogo Caveiro</td>
<td>89%</td>
<td>91%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/br.png" alt=""></td>
<td>Português (Brasil)</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po">pt_BR</a></td>
<td>Renato Nunes Bastos (<a href="mailto:rnbastos@gmail.com">rnbastos@gmail.com</a>)</td>
<td>96%</td>
<td>98%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/ro.png" alt=""></td>
<td>Română</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ro.po">ro</a></td>
<td>Cristi Duluta (<a href="mailto:cristi.duluta@gmail.com">cristi.duluta@gmail.com</a>)</td>
<td>78%</td>
<td></td>
<td>35%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/si.png" alt=""></td>
<td>Slovenian</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/sl_SI.po">sl_SI</a></td>
<td></td>
<td>42%</td>
<td>44%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/se.png" alt=""></td>
<td>Svenska</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/sv.po">sv</a></td>
<td>Jonatan Nyberg (<a href="mailto:jonatan@autistici.org">jonatan@autistici.org</a>)</td>
<td>71%</td>
<td>73%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/th.png" alt=""></td>
<td>Thai</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/th_TH.po">th_TH</a></td>
<td></td>
<td>52%</td>
<td>54%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/.png" alt=""></td>
<td>Tiếng Việt</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/vi.po">vi</a></td>
<td></td>
<td>85%</td>
<td>88%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/tr.png" alt=""></td>
<td>Türkçe</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/tr_TR.po">tr_TR</a></td>
<td>Arda Kılıçdağı (<a href="mailto:arda@kilicdagi.com">arda@kilicdagi.com</a>)</td>
<td>96%</td>
<td>99%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/gr.png" alt=""></td>
<td>Ελληνικά</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/el_GR.po">el_GR</a></td>
<td>Harris Arvanitis (<a href="mailto:xaris@tuta.io">xaris@tuta.io</a>)</td>
<td>96%</td>
<td>93%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/ru.png" alt=""></td>
<td>Русский</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po">ru_RU</a></td>
<td>Sergey Segeda (<a href="mailto:thesermanarm@gmail.com">thesermanarm@gmail.com</a>)</td>
<td>95%</td>
<td>90%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/rs.png" alt=""></td>
<td>српски језик</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/sr_RS.po">sr_RS</a></td>
<td></td>
<td>72%</td>
<td>74%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/cn.png" alt=""></td>
<td>中文 (简体)</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po">zh_CN</a></td>
<td>WhiredPlanck (<a href="mailto:fungdaat31@outlook.com">fungdaat31@outlook.com</a>)</td>
<td>96%</td>
<td>yaozeye (<a href="mailto:yaozeye@outlook.com">yaozeye@outlook.com</a>)</td>
<td>99%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/tw.png" alt=""></td>
<td>中文 (繁體)</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_TW.po">zh_TW</a></td>
<td>Yaoze Ye (<a href="mailto:yaozeye@yahoo.co.jp">yaozeye@yahoo.co.jp</a>)</td>
<td>95%</td>
<td>98%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/jp.png" alt=""></td>
<td>日本語</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po">ja_JP</a></td>
<td>genneko (<a href="mailto:genneko217@gmail.com">genneko217@gmail.com</a>)</td>
<td>96%</td>
<td>99%</td>
</tr>
<tr>
<td><img src="https://joplinapp.org/images/flags/country-4x3/kr.png" alt=""></td>
<td>한국어</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ko.po">ko</a></td>
<td></td>
<td>86%</td>
<td>89%</td>
</tr>
</tbody>
</table>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/markdown.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

View File

@@ -327,7 +327,7 @@ https://github.com/laurent22/joplin/blob/master/readme/mobile.md
<li>
<p>Development</p>
<ul>
<li><a href="https://joplinapp.org/spec/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/e2ee/">End-to-end encryption spec</a></li>
<li><a href="https://joplinapp.org/spec/history/">Note History spec</a></li>
<li><a href="https://joplinapp.org/spec/sync_lock/">Sync Lock spec</a></li>
</ul>

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