1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-01-20 00:46:28 +02:00

Compare commits

...

36 Commits

Author SHA1 Message Date
Laurent Cozic
f3b708ff64 Exclude from search commands without a label 2020-10-18 21:50:42 +01:00
Laurent Cozic
fea85b39a0 Added command palette 2020-10-18 21:44:28 +01:00
Laurent Cozic
a53955a03d Converted GotoAnything to TypeScript 2020-10-18 19:08:59 +01:00
Laurent Cozic
8d61514f64 Fixed plugins 2020-10-18 18:58:11 +01:00
Laurent Cozic
c8f496b733 Updated plugin command interface 2020-10-18 15:19:27 +01:00
Laurent Cozic
c4414e3bee Updated plugin command interface 2020-10-18 15:17:18 +01:00
Laurent Cozic
89e7a3a65e Add description to commands 2020-10-18 14:53:28 +01:00
Laurent Cozic
b3bce34e9a Clean up menu bar 2020-10-18 14:30:36 +01:00
Laurent Cozic
d059aeebab Added way to validate enabledCondition keys 2020-10-18 14:24:51 +01:00
Laurent Cozic
910a5ad09d Simplified command service code further 2020-10-18 12:41:40 +01:00
Laurent Cozic
259dadb650 More refactoring 2020-10-18 01:55:16 +01:00
Laurent Cozic
4ce2bf492b Refactor to use When Clauses 2020-10-18 00:49:17 +01:00
Laurent Cozic
e635ee967a Renaming togglesidebar 2020-10-17 23:32:02 +01:00
Laurent Cozic
6a43f3be66 Various changes 2020-10-17 22:54:36 +01:00
Laurent Cozic
a4562a0a75 Renamed to when clause 2020-10-17 17:45:45 +01:00
Laurent Cozic
410a0f5d14 Refactor command system to use when clauses instead 2020-10-17 17:40:09 +01:00
Laurent Cozic
f8f46db910 Plugins: Adding support for command boolean expressions 2020-10-17 16:50:07 +01:00
Laurent Cozic
f529adac99 Electron release v1.3.5 2020-10-17 14:05:13 +01:00
Laurent Cozic
3a52b9764b Electron release v1.3.4 2020-10-17 14:03:16 +01:00
Laurent Cozic
7e78d7716b Desktop: Regression: Fixed opening links 2020-10-17 13:56:41 +01:00
Laurent Cozic
0488c5c4cb Android release v1.3.7 2020-10-17 12:07:51 +01:00
Laurent Cozic
921cc3b6c6 Electron release v1.3.3 2020-10-17 11:37:37 +01:00
Laurent Cozic
2a7aa28d4c Desktop, Cli: Fixes #3923 (Regression): Importing ENEX as HTML was importing as Markdown 2020-10-17 11:35:51 +01:00
Laurent Cozic
7b3440ac4c Desktop: Fixes #3915: Editor toolbar was disabled when importing note from MD file 2020-10-17 11:15:43 +01:00
Laurent Cozic
958e5a80b7 Desktop: Fixes #3903: Header links with special characters were no longer working 2020-10-16 22:55:48 +01:00
Laurent Cozic
3179117c62 Mobile: Fixed notebook expand icons 2020-10-16 21:52:27 +01:00
Laurent Cozic
d895463167 All: Removed OneDrive Dev sync target which was not really useful 2020-10-16 21:34:34 +01:00
Laurent Cozic
7e0e513051 Desktop: Regression: Fixed check for update 2020-10-16 21:14:57 +01:00
Laurent Cozic
4309c4f8e2 Desktop: Fixed Toggle Editor button toolip and icon 2020-10-16 18:52:17 +01:00
Laurent Cozic
20b1c90574 Android: Fixed signing config for production 2020-10-16 18:30:58 +01:00
Laurent Cozic
7ff6ceb585 Merge branch 'release-1.3' of https://github.com/laurent22/joplin into release-1.3 2020-10-16 17:45:29 +01:00
Laurent Cozic
3dc3f334ec Tools: Cleaned up ignored files as it was breaking VSCode search 2020-10-16 17:44:50 +01:00
Laurent Cozic
3476211f8b Desktop: Regression: Fixed move to notebook from context menu 2020-10-16 17:44:04 +01:00
Laurent Cozic
48e299916f Desktop: Make sidebar item font weight normal (not bold) 2020-10-16 17:07:43 +01:00
Laurent Cozic
35aebc9f52 Android release v1.3.3 2020-10-16 17:05:22 +01:00
Laurent Cozic
cb3e1cf1e9 Mobile: Upgraded React Native to v0.63
commit 2fb6cee901
Merge: 4e303be85f db509955f6
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 16:24:07 2020 +0100

    Merge branch 'dev' into rn_63

commit 4e303be85f
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 16:14:39 2020 +0100

    Clean up

commit e3a37ec2d6
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 15:57:55 2020 +0100

    Use different script for pre-commit and manual start

commit bd236648fc
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 15:56:45 2020 +0100

    Removed RN eslint config

commit e7feda41c9
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 15:27:08 2020 +0100

    Revert "Disable git hook for now"

    This reverts commit 89263ac742.

commit cfd63fe46f
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 13:02:32 2020 +0100

    Ask permission to use geo-location

commit 66059939a3
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 12:26:20 2020 +0100

    Fixed WebView race condition

commit 1e0d2b7b86
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 11:56:21 2020 +0100

    Fixed webview issues

commit f537d22d7f
Author: Laurent Cozic <laurent@cozic.net>
Date:   Fri Oct 16 11:08:29 2020 +0100

    Improve resource file watching

commit eec32cf70a
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 18:40:13 2020 +0100

    Removed cache package dependency and implemented one more suitable for React Native

commit efa346fea4
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 14:57:21 2020 +0100

    iOS: Added fonts to Info.plist although it was working without it

commit 572b647bc0
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 14:56:49 2020 +0100

    Specify content-type header for OneDrive to prevent network error

commit bcedf6c7f0
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 12:45:01 2020 +0100

    iOS: Disable long press menu since it is already built-in

commit 7359dd61d1
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 12:37:40 2020 +0100

    Removed unused react-native-device-info

commit 2d63ab36d3
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 12:35:54 2020 +0100

    iOS: Fixed taking a picture

commit 8e2875a91c
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 12:11:13 2020 +0100

    iOS: Restored camera roll functionality

commit 75f5edf2ad
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 11:40:13 2020 +0100

    iOS: Fixed build settings

commit b220c98419
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 11:40:03 2020 +0100

    iOS: Got images to work with WebKit

commit c34b43e841
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 10:24:52 2020 +0100

    iOS: Restore more settings

commit 32997611e6
Author: Laurent Cozic <laurent@cozic.net>
Date:   Thu Oct 15 10:15:14 2020 +0100

    iOS: Added back icons and other properties

commit b5811d7f7c
Author: Laurent Cozic <laurent@cozic.net>
Date:   Wed Oct 14 23:53:14 2020 +0100

    Got iOS build to work

commit dc6d7c00e0
Author: Laurent Cozic <laurent@cozic.net>
Date:   Wed Oct 14 18:40:06 2020 +0100

    Imported old settings in gradle build

commit dff59f5603
Author: Laurent Cozic <laurent@cozic.net>
Date:   Wed Oct 14 18:20:00 2020 +0100

    Restored sharing

commit 0bdb449e72
Author: Laurent Cozic <laurent@cozic.net>
Date:   Wed Oct 14 17:25:40 2020 +0100

    Updated NoteBodyViewer

commit 0c0d228815
Author: Laurent Cozic <laurent@cozic.net>
Date:   Wed Oct 14 16:54:42 2020 +0100

    Fixed networking

commit 6ff45ce485
Author: Laurent Cozic <laurent@cozic.net>
Date:   Wed Oct 14 13:11:00 2020 +0100

    Fixed document picker

commit cc889182b6
Author: Laurent Cozic <laurent@cozic.net>
Date:   Wed Oct 14 12:56:27 2020 +0100

    Added back support for alarms

commit 040261abfa
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 22:04:49 2020 +0100

    Fixed Clipboard and remove image-picker package

commit 1077ad8f16
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 21:54:52 2020 +0100

    Fixed Select Alarm dialog and PoorManIntervals class

commit 8296676fd5
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 21:32:52 2020 +0100

    Fixed icons and warnings

commit 3b0e3f6f43
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 17:02:59 2020 +0100

    Got app to build again

commit 89263ac742
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 15:41:17 2020 +0100

    Disable git hook for now

commit d6da162f67
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 15:39:12 2020 +0100

    Restored back all RN packages

commit 7f8ce3732c
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 15:13:12 2020 +0100

    Restored base packages

commit ea59726eb3
Author: Laurent Cozic <laurent@cozic.net>
Date:   Tue Oct 13 15:05:17 2020 +0100

    Started over from scratch
2020-10-16 16:26:19 +01:00
212 changed files with 7471 additions and 7603 deletions

View File

@@ -64,6 +64,7 @@ CliClient/build/
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
CliClient/app/LinkSelector.js
CliClient/app/services/plugins/PluginRunner.js
CliClient/tests/InMemoryCache.js
CliClient/tests/models_Setting.js
CliClient/tests/services_CommandService.js
CliClient/tests/services_InteropService.js
@@ -113,7 +114,7 @@ ElectronClient/gui/MainScreen/commands/showNoteProperties.js
ElectronClient/gui/MainScreen/commands/showShareNoteDialog.js
ElectronClient/gui/MainScreen/commands/toggleEditors.js
ElectronClient/gui/MainScreen/commands/toggleNoteList.js
ElectronClient/gui/MainScreen/commands/toggleSidebar.js
ElectronClient/gui/MainScreen/commands/toggleSideBar.js
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
ElectronClient/gui/MainScreen/MainScreen.js
ElectronClient/gui/MenuBar.js
@@ -186,7 +187,9 @@ ElectronClient/gui/ToolbarButton/styles/index.js
ElectronClient/gui/ToolbarButton/ToolbarButton.js
ElectronClient/gui/utils/NoteListUtils.js
ElectronClient/InteropServiceHelper.js
ElectronClient/plugins/GotoAnything.js
ElectronClient/services/bridge.js
ElectronClient/services/commands/types.js
ElectronClient/services/plugins/hooks/useThemeCss.js
ElectronClient/services/plugins/hooks/useViewIsReady.js
ElectronClient/services/plugins/PlatformImplementation.js
@@ -201,13 +204,21 @@ ReactNativeClient/lib/commands/historyBackward.js
ReactNativeClient/lib/commands/historyForward.js
ReactNativeClient/lib/commands/synchronize.js
ReactNativeClient/lib/components/BackButtonDialogBox.js
ReactNativeClient/lib/components/CameraView.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnMessage.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useSource.js
ReactNativeClient/lib/components/NoteBodyViewer/NoteBodyViewer.js
ReactNativeClient/lib/components/screens/Note.js
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
ReactNativeClient/lib/components/SelectDateTimeDialog.js
ReactNativeClient/lib/errorUtils.js
ReactNativeClient/lib/eventManager.js
ReactNativeClient/lib/hooks/useEffectDebugger.js
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
ReactNativeClient/lib/hooks/usePrevious.js
ReactNativeClient/lib/hooks/usePropsDebugger.js
ReactNativeClient/lib/InMemoryCache.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
@@ -219,15 +230,17 @@ ReactNativeClient/lib/markdownUtils.js
ReactNativeClient/lib/models/Alarm.js
ReactNativeClient/lib/models/Setting.js
ReactNativeClient/lib/ntpDate.js
ReactNativeClient/lib/PoorManIntervals.js
ReactNativeClient/lib/reducer.js
ReactNativeClient/lib/services/AlarmService.js
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
ReactNativeClient/lib/services/AlarmServiceDriver.ios.js
ReactNativeClient/lib/services/AlarmServiceDriverNode.js
ReactNativeClient/lib/services/BaseService.js
ReactNativeClient/lib/services/BooleanExpression.js
ReactNativeClient/lib/services/commands/commandsToMarkdownTable.js
ReactNativeClient/lib/services/commands/MenuUtils.js
ReactNativeClient/lib/services/commands/propsHaveChanged.js
ReactNativeClient/lib/services/commands/stateToWhenClauseContext.js
ReactNativeClient/lib/services/commands/ToolbarButtonUtils.js
ReactNativeClient/lib/services/CommandService.js
ReactNativeClient/lib/services/contextkey/contextkey.js
@@ -299,6 +312,7 @@ ReactNativeClient/lib/services/synchronizer/migrations/1.js
ReactNativeClient/lib/services/synchronizer/migrations/2.js
ReactNativeClient/lib/services/synchronizer/utils/types.js
ReactNativeClient/lib/services/UndoRedoService.js
ReactNativeClient/lib/services/WhenClause.js
ReactNativeClient/lib/ShareExtension.js
ReactNativeClient/lib/shareHandler.js
ReactNativeClient/lib/shim.js

18
.gitignore vendored
View File

@@ -58,6 +58,7 @@ plugin_types/
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
CliClient/app/LinkSelector.js
CliClient/app/services/plugins/PluginRunner.js
CliClient/tests/InMemoryCache.js
CliClient/tests/models_Setting.js
CliClient/tests/services_CommandService.js
CliClient/tests/services_InteropService.js
@@ -107,7 +108,7 @@ ElectronClient/gui/MainScreen/commands/showNoteProperties.js
ElectronClient/gui/MainScreen/commands/showShareNoteDialog.js
ElectronClient/gui/MainScreen/commands/toggleEditors.js
ElectronClient/gui/MainScreen/commands/toggleNoteList.js
ElectronClient/gui/MainScreen/commands/toggleSidebar.js
ElectronClient/gui/MainScreen/commands/toggleSideBar.js
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
ElectronClient/gui/MainScreen/MainScreen.js
ElectronClient/gui/MenuBar.js
@@ -180,7 +181,9 @@ ElectronClient/gui/ToolbarButton/styles/index.js
ElectronClient/gui/ToolbarButton/ToolbarButton.js
ElectronClient/gui/utils/NoteListUtils.js
ElectronClient/InteropServiceHelper.js
ElectronClient/plugins/GotoAnything.js
ElectronClient/services/bridge.js
ElectronClient/services/commands/types.js
ElectronClient/services/plugins/hooks/useThemeCss.js
ElectronClient/services/plugins/hooks/useViewIsReady.js
ElectronClient/services/plugins/PlatformImplementation.js
@@ -195,13 +198,21 @@ ReactNativeClient/lib/commands/historyBackward.js
ReactNativeClient/lib/commands/historyForward.js
ReactNativeClient/lib/commands/synchronize.js
ReactNativeClient/lib/components/BackButtonDialogBox.js
ReactNativeClient/lib/components/CameraView.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnMessage.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useSource.js
ReactNativeClient/lib/components/NoteBodyViewer/NoteBodyViewer.js
ReactNativeClient/lib/components/screens/Note.js
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
ReactNativeClient/lib/components/SelectDateTimeDialog.js
ReactNativeClient/lib/errorUtils.js
ReactNativeClient/lib/eventManager.js
ReactNativeClient/lib/hooks/useEffectDebugger.js
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
ReactNativeClient/lib/hooks/usePrevious.js
ReactNativeClient/lib/hooks/usePropsDebugger.js
ReactNativeClient/lib/InMemoryCache.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
@@ -213,15 +224,17 @@ ReactNativeClient/lib/markdownUtils.js
ReactNativeClient/lib/models/Alarm.js
ReactNativeClient/lib/models/Setting.js
ReactNativeClient/lib/ntpDate.js
ReactNativeClient/lib/PoorManIntervals.js
ReactNativeClient/lib/reducer.js
ReactNativeClient/lib/services/AlarmService.js
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
ReactNativeClient/lib/services/AlarmServiceDriver.ios.js
ReactNativeClient/lib/services/AlarmServiceDriverNode.js
ReactNativeClient/lib/services/BaseService.js
ReactNativeClient/lib/services/BooleanExpression.js
ReactNativeClient/lib/services/commands/commandsToMarkdownTable.js
ReactNativeClient/lib/services/commands/MenuUtils.js
ReactNativeClient/lib/services/commands/propsHaveChanged.js
ReactNativeClient/lib/services/commands/stateToWhenClauseContext.js
ReactNativeClient/lib/services/commands/ToolbarButtonUtils.js
ReactNativeClient/lib/services/CommandService.js
ReactNativeClient/lib/services/contextkey/contextkey.js
@@ -293,6 +306,7 @@ ReactNativeClient/lib/services/synchronizer/migrations/1.js
ReactNativeClient/lib/services/synchronizer/migrations/2.js
ReactNativeClient/lib/services/synchronizer/utils/types.js
ReactNativeClient/lib/services/UndoRedoService.js
ReactNativeClient/lib/services/WhenClause.js
ReactNativeClient/lib/ShareExtension.js
ReactNativeClient/lib/shareHandler.js
ReactNativeClient/lib/shim.js

277
.ignore Normal file
View File

@@ -0,0 +1,277 @@
# This is used by VSCode to ignore patterns during search.
# Before they were in joplin.code-workspace, under the `files.exclude` key
# but it eventually reached the limit with ENAMETOOLONG error.
#
# https://github.com/microsoft/vscode/issues/94718
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
CliClient/app/LinkSelector.js
CliClient/app/services/plugins/PluginRunner.js
CliClient/tests/InMemoryCache.js
CliClient/tests/models_Setting.js
CliClient/tests/services_CommandService.js
CliClient/tests/services_InteropService.js
CliClient/tests/services_PluginService.js
CliClient/tests/services_rest_Api.js
CliClient/tests/services/plugins/api/JoplinSetting.js
CliClient/tests/services/plugins/sandboxProxy.js
CliClient/tests/synchronizer_LockHandler.js
CliClient/tests/synchronizer_MigrationHandler.js
ElectronClient/app.js
ElectronClient/bridge.js
ElectronClient/commands/copyDevCommand.js
ElectronClient/commands/focusElement.js
ElectronClient/commands/startExternalEditing.js
ElectronClient/commands/stopExternalEditing.js
ElectronClient/commands/toggleExternalEditing.js
ElectronClient/ElectronAppWrapper.js
ElectronClient/global.d.js
ElectronClient/gui/Button/Button.js
ElectronClient/gui/ConfigScreen/ButtonBar.js
ElectronClient/gui/ConfigScreen/ConfigScreen.js
ElectronClient/gui/ConfigScreen/SideBar.js
ElectronClient/gui/DropboxLoginScreen.js
ElectronClient/gui/ErrorBoundary.js
ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js
ElectronClient/gui/KeymapConfig/ShortcutRecorder.js
ElectronClient/gui/KeymapConfig/styles/index.js
ElectronClient/gui/KeymapConfig/utils/getLabel.js
ElectronClient/gui/KeymapConfig/utils/useCommandStatus.js
ElectronClient/gui/KeymapConfig/utils/useKeymap.js
ElectronClient/gui/MainScreen/commands/editAlarm.js
ElectronClient/gui/MainScreen/commands/exportPdf.js
ElectronClient/gui/MainScreen/commands/hideModalMessage.js
ElectronClient/gui/MainScreen/commands/moveToFolder.js
ElectronClient/gui/MainScreen/commands/newFolder.js
ElectronClient/gui/MainScreen/commands/newNote.js
ElectronClient/gui/MainScreen/commands/newTodo.js
ElectronClient/gui/MainScreen/commands/print.js
ElectronClient/gui/MainScreen/commands/renameFolder.js
ElectronClient/gui/MainScreen/commands/renameTag.js
ElectronClient/gui/MainScreen/commands/search.js
ElectronClient/gui/MainScreen/commands/selectTemplate.js
ElectronClient/gui/MainScreen/commands/setTags.js
ElectronClient/gui/MainScreen/commands/showModalMessage.js
ElectronClient/gui/MainScreen/commands/showNoteContentProperties.js
ElectronClient/gui/MainScreen/commands/showNoteProperties.js
ElectronClient/gui/MainScreen/commands/showShareNoteDialog.js
ElectronClient/gui/MainScreen/commands/toggleEditors.js
ElectronClient/gui/MainScreen/commands/toggleNoteList.js
ElectronClient/gui/MainScreen/commands/toggleSideBar.js
ElectronClient/gui/MainScreen/commands/toggleVisiblePanes.js
ElectronClient/gui/MainScreen/MainScreen.js
ElectronClient/gui/MenuBar.js
ElectronClient/gui/MultiNoteActions.js
ElectronClient/gui/NoteContentPropertiesDialog.js
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
ElectronClient/gui/NoteEditor/commands/focusElementNoteBody.js
ElectronClient/gui/NoteEditor/commands/focusElementNoteTitle.js
ElectronClient/gui/NoteEditor/commands/showLocalSearch.js
ElectronClient/gui/NoteEditor/commands/showRevisions.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Editor.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/styles/index.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.js
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/index.js
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
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
ElectronClient/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
ElectronClient/gui/NoteEditor/NoteEditor.js
ElectronClient/gui/NoteEditor/styles/index.js
ElectronClient/gui/NoteEditor/utils/contextMenu.js
ElectronClient/gui/NoteEditor/utils/index.js
ElectronClient/gui/NoteEditor/utils/resourceHandling.js
ElectronClient/gui/NoteEditor/utils/types.js
ElectronClient/gui/NoteEditor/utils/useDropHandler.js
ElectronClient/gui/NoteEditor/utils/useFolder.js
ElectronClient/gui/NoteEditor/utils/useFormNote.js
ElectronClient/gui/NoteEditor/utils/useMarkupToHtml.js
ElectronClient/gui/NoteEditor/utils/useMessageHandler.js
ElectronClient/gui/NoteEditor/utils/useNoteSearchBar.js
ElectronClient/gui/NoteEditor/utils/usePluginServiceRegistration.js
ElectronClient/gui/NoteEditor/utils/useSearchMarkers.js
ElectronClient/gui/NoteEditor/utils/useWindowCommandHandler.js
ElectronClient/gui/NoteList/commands/focusElementNoteList.js
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
ElectronClient/gui/ResizableLayout/hooks/useWindowResizeEvent.js
ElectronClient/gui/ResizableLayout/ResizableLayout.js
ElectronClient/gui/ResourceScreen.js
ElectronClient/gui/Root_UpgradeSyncTarget.js
ElectronClient/gui/Root.js
ElectronClient/gui/SearchBar/hooks/useSearch.js
ElectronClient/gui/SearchBar/SearchBar.js
ElectronClient/gui/SearchBar/styles/index.js
ElectronClient/gui/ShareNoteDialog.js
ElectronClient/gui/SideBar/commands/focusElementSideBar.js
ElectronClient/gui/SideBar/SideBar.js
ElectronClient/gui/SideBar/styles/index.js
ElectronClient/gui/StatusScreen/StatusScreen.js
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
ElectronClient/gui/utils/NoteListUtils.js
ElectronClient/InteropServiceHelper.js
ElectronClient/plugins/GotoAnything.js
ElectronClient/services/bridge.js
ElectronClient/services/commands/types.js
ElectronClient/services/plugins/hooks/useThemeCss.js
ElectronClient/services/plugins/hooks/useViewIsReady.js
ElectronClient/services/plugins/PlatformImplementation.js
ElectronClient/services/plugins/PluginRunner.js
ElectronClient/services/plugins/UserWebview.js
ElectronClient/services/plugins/UserWebviewDialog.js
ElectronClient/services/plugins/UserWebviewDialogButtonBar.js
ReactNativeClient/lib/AsyncActionQueue.js
ReactNativeClient/lib/BaseApplication.js
ReactNativeClient/lib/checkPermissions.js
ReactNativeClient/lib/commands/historyBackward.js
ReactNativeClient/lib/commands/historyForward.js
ReactNativeClient/lib/commands/synchronize.js
ReactNativeClient/lib/components/BackButtonDialogBox.js
ReactNativeClient/lib/components/CameraView.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnMessage.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
ReactNativeClient/lib/components/NoteBodyViewer/hooks/useSource.js
ReactNativeClient/lib/components/NoteBodyViewer/NoteBodyViewer.js
ReactNativeClient/lib/components/screens/Note.js
ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
ReactNativeClient/lib/components/SelectDateTimeDialog.js
ReactNativeClient/lib/errorUtils.js
ReactNativeClient/lib/eventManager.js
ReactNativeClient/lib/hooks/useEffectDebugger.js
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
ReactNativeClient/lib/hooks/usePrevious.js
ReactNativeClient/lib/hooks/usePropsDebugger.js
ReactNativeClient/lib/InMemoryCache.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
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
ReactNativeClient/lib/JoplinServerApi.js
ReactNativeClient/lib/locale.js
ReactNativeClient/lib/Logger.js
ReactNativeClient/lib/markdownUtils.js
ReactNativeClient/lib/models/Alarm.js
ReactNativeClient/lib/models/Setting.js
ReactNativeClient/lib/ntpDate.js
ReactNativeClient/lib/PoorManIntervals.js
ReactNativeClient/lib/reducer.js
ReactNativeClient/lib/services/AlarmService.js
ReactNativeClient/lib/services/AlarmServiceDriver.android.js
ReactNativeClient/lib/services/AlarmServiceDriver.ios.js
ReactNativeClient/lib/services/AlarmServiceDriverNode.js
ReactNativeClient/lib/services/BaseService.js
ReactNativeClient/lib/services/commands/commandsToMarkdownTable.js
ReactNativeClient/lib/services/commands/MenuUtils.js
ReactNativeClient/lib/services/commands/propsHaveChanged.js
ReactNativeClient/lib/services/commands/stateToWhenClauseContext.js
ReactNativeClient/lib/services/commands/ToolbarButtonUtils.js
ReactNativeClient/lib/services/CommandService.js
ReactNativeClient/lib/services/contextkey/contextkey.js
ReactNativeClient/lib/services/debug/populateDatabase.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Base.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Custom.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Html.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Jex.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Md.js
ReactNativeClient/lib/services/interop/InteropService_Exporter_Raw.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Base.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Custom.js
ReactNativeClient/lib/services/interop/InteropService_Importer_EnexToHtml.js
ReactNativeClient/lib/services/interop/InteropService_Importer_EnexToMd.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Jex.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Md.js
ReactNativeClient/lib/services/interop/InteropService_Importer_Raw.js
ReactNativeClient/lib/services/interop/InteropService.js
ReactNativeClient/lib/services/interop/types.js
ReactNativeClient/lib/services/keychain/KeychainService.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.dummy.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.mobile.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.node.js
ReactNativeClient/lib/services/keychain/KeychainServiceDriverBase.js
ReactNativeClient/lib/services/KeymapService.js
ReactNativeClient/lib/services/plugins/api/Global.js
ReactNativeClient/lib/services/plugins/api/Joplin.js
ReactNativeClient/lib/services/plugins/api/JoplinCommands.js
ReactNativeClient/lib/services/plugins/api/JoplinData.js
ReactNativeClient/lib/services/plugins/api/JoplinFilters.js
ReactNativeClient/lib/services/plugins/api/JoplinInterop.js
ReactNativeClient/lib/services/plugins/api/JoplinPlugins.js
ReactNativeClient/lib/services/plugins/api/JoplinSettings.js
ReactNativeClient/lib/services/plugins/api/JoplinViews.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsDialogs.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenuItems.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsMenus.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsPanels.js
ReactNativeClient/lib/services/plugins/api/JoplinViewsToolbarButtons.js
ReactNativeClient/lib/services/plugins/api/JoplinWorkspace.js
ReactNativeClient/lib/services/plugins/api/types.js
ReactNativeClient/lib/services/plugins/BasePluginRunner.js
ReactNativeClient/lib/services/plugins/MenuController.js
ReactNativeClient/lib/services/plugins/MenuItemController.js
ReactNativeClient/lib/services/plugins/Plugin.js
ReactNativeClient/lib/services/plugins/PluginService.js
ReactNativeClient/lib/services/plugins/reducer.js
ReactNativeClient/lib/services/plugins/sandboxProxy.js
ReactNativeClient/lib/services/plugins/ToolbarButtonController.js
ReactNativeClient/lib/services/plugins/utils/createViewHandle.js
ReactNativeClient/lib/services/plugins/utils/executeSandboxCall.js
ReactNativeClient/lib/services/plugins/utils/manifestFromObject.js
ReactNativeClient/lib/services/plugins/utils/mapEventHandlersToIds.js
ReactNativeClient/lib/services/plugins/utils/types.js
ReactNativeClient/lib/services/plugins/ViewController.js
ReactNativeClient/lib/services/plugins/WebviewController.js
ReactNativeClient/lib/services/ResourceEditWatcher/index.js
ReactNativeClient/lib/services/ResourceEditWatcher/reducer.js
ReactNativeClient/lib/services/rest/actionApi.desktop.js
ReactNativeClient/lib/services/rest/Api.js
ReactNativeClient/lib/services/rest/errors.js
ReactNativeClient/lib/services/searchengine/filterParser.js
ReactNativeClient/lib/services/searchengine/queryBuilder.js
ReactNativeClient/lib/services/SettingUtils.js
ReactNativeClient/lib/services/synchronizer/gui/useSyncTargetUpgrade.js
ReactNativeClient/lib/services/synchronizer/LockHandler.js
ReactNativeClient/lib/services/synchronizer/MigrationHandler.js
ReactNativeClient/lib/services/synchronizer/migrations/1.js
ReactNativeClient/lib/services/synchronizer/migrations/2.js
ReactNativeClient/lib/services/synchronizer/utils/types.js
ReactNativeClient/lib/services/UndoRedoService.js
ReactNativeClient/lib/services/WhenClause.js
ReactNativeClient/lib/ShareExtension.js
ReactNativeClient/lib/shareHandler.js
ReactNativeClient/lib/shim.js
ReactNativeClient/lib/Synchronizer.js
ReactNativeClient/lib/theme.js
ReactNativeClient/lib/themes/aritimDark.js
ReactNativeClient/lib/themes/dark.js
ReactNativeClient/lib/themes/dracula.js
ReactNativeClient/lib/themes/light.js
ReactNativeClient/lib/themes/nord.js
ReactNativeClient/lib/themes/oledDark.js
ReactNativeClient/lib/themes/solarizedDark.js
ReactNativeClient/lib/themes/solarizedLight.js
ReactNativeClient/lib/themes/type.js
ReactNativeClient/lib/uuid.js
ReactNativeClient/lib/versionInfo.js
ReactNativeClient/PluginAssetsLoader.js
ReactNativeClient/setUpQuickActions.js
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD

View File

@@ -4199,11 +4199,6 @@
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
},
"memory-cache": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
},
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
@@ -5900,11 +5895,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",
@@ -6767,6 +6757,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",
@@ -6869,6 +6864,24 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
"uslug": {
"version": "git+https://github.com/laurent22/uslug.git#ba2834d79beb0435318709958b2f5e817d96674d",
"from": "git+https://github.com/laurent22/uslug.git#emoji-support",
"requires": {
"node-emoji": "^1.10.0",
"unorm": ">= 1.0.0"
},
"dependencies": {
"node-emoji": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
"integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
"requires": {
"lodash.toarray": "^4.4.0"
}
}
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

View File

@@ -6,7 +6,7 @@
"scripts": {
"test": "gulp buildTests -L && node node_modules/jasmine/bin/jasmine.js --fail-fast=true --config=tests/support/jasmine.json",
"test-ci": "gulp buildTests -L && node node_modules/jasmine/bin/jasmine.js --config=tests/support/jasmine.json",
"postinstall": "npm run build && patch-package --patch-dir ../patches",
"postinstall": "npm run build && patch-package --patch-dir ../patches/shared && patch-package --patch-dir ../patches/node",
"build": "gulp build",
"start": "gulp build -L && node 'build/main.js' --stack-trace-enabled --log-level debug --env dev"
},
@@ -80,7 +80,6 @@
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1",
"md5-file": "^4.0.0",
"memory-cache": "^0.2.0",
"mime": "^2.0.3",
"moment": "^2.24.0",
"multiparty": "^4.2.1",
@@ -102,7 +101,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",
@@ -114,6 +112,7 @@
"terminal-kit": "^1.30.0",
"tkwidgets": "^0.5.26",
"url-parse": "^1.4.7",
"uslug": "git+https://github.com/laurent22/uslug.git#emoji-support",
"uuid": "^3.0.1",
"valid-url": "^1.0.9",
"word-wrap": "^1.2.3",

View File

@@ -0,0 +1,59 @@
import InMemoryCache from 'lib/InMemoryCache';
const { time } = require('lib/time-utils.js');
describe('InMemoryCache', function() {
it('should get and set values', () => {
const cache = new InMemoryCache();
expect(cache.value('test')).toBe(undefined);
expect(cache.value('test', 'default')).toBe('default');
cache.setValue('test', 'something');
expect(cache.value('test')).toBe('something');
// Check we get the exact same object back (cache should not copy)
const someObj = { abcd: '123' };
cache.setValue('someObj', someObj);
expect(cache.value('someObj')).toBe(someObj);
});
it('should expire values', async () => {
const cache = new InMemoryCache();
// Check that the value is udefined once the cache has expired
cache.setValue('test', 'something', 500);
expect(cache.value('test')).toBe('something');
await time.msleep(510);
expect(cache.value('test')).toBe(undefined);
// Check that the TTL is reset every time setValue is called
cache.setValue('test', 'something', 300);
await time.msleep(100);
cache.setValue('test', 'something', 300);
await time.msleep(100);
cache.setValue('test', 'something', 300);
await time.msleep(100);
cache.setValue('test', 'something', 300);
await time.msleep(100);
expect(cache.value('test')).toBe('something');
});
it('should delete old records', async () => {
const cache = new InMemoryCache(5);
cache.setValue('1', '1');
cache.setValue('2', '2');
cache.setValue('3', '3');
cache.setValue('4', '4');
cache.setValue('5', '5');
expect(cache.value('1')).toBe('1');
cache.setValue('6', '6');
expect(cache.value('1')).toBe(undefined);
});
});

View File

@@ -2,7 +2,7 @@ import MenuUtils from 'lib/services/commands/MenuUtils';
import ToolbarButtonUtils from 'lib/services/commands/ToolbarButtonUtils';
import CommandService, { CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
const { asyncTest, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('test-utils.js');
interface TestCommand {
declaration: CommandDeclaration,
@@ -11,7 +11,12 @@ interface TestCommand {
function newService():CommandService {
const service = new CommandService();
service.initialize({});
const mockStore = {
getState: () => {
return {};
},
};
service.initialize(mockStore, true);
return service;
}
@@ -24,8 +29,7 @@ function createCommand(name:string, options:any):TestCommand {
execute: options.execute,
};
if (options.mapStateToProps) runtime.mapStateToProps = options.mapStateToProps;
if (options.isEnabled) runtime.isEnabled = options.isEnabled;
if (options.enabledCondition) runtime.enabledCondition = options.enabledCondition;
return { declaration, runtime };
}
@@ -61,7 +65,7 @@ describe('services_CommandService', function() {
},
}));
const toolbarInfos = toolbarButtonUtils.commandsToToolbarButtons({}, ['test1', 'test2']);
const toolbarInfos = toolbarButtonUtils.commandsToToolbarButtons(['test1', 'test2'], {});
await toolbarInfos[0].onClick();
await toolbarInfos[1].onClick();
@@ -77,98 +81,78 @@ describe('services_CommandService', function() {
registerCommand(service, createCommand('test1', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedNoteId: state.selectedNoteId,
selectedFolderId: state.selectedFolderId,
};
},
isEnabled: (props:any) => {
return props.selectedNoteId === 'abc';
},
enabledCondition: 'oneNoteSelected',
}));
registerCommand(service, createCommand('test2', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedNoteId: state.selectedNoteId,
selectedFolderId: state.selectedFolderId,
};
},
isEnabled: (props:any) => {
return props.selectedNoteId === '123';
},
enabledCondition: 'multipleNotesSelected',
}));
const toolbarInfos = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: '123',
selectedFolderId: 'aaa',
}, ['test1', 'test2']);
const toolbarInfos = toolbarButtonUtils.commandsToToolbarButtons(['test1', 'test2'], {
oneNoteSelected: false,
multipleNotesSelected: true,
});
expect(toolbarInfos[0].enabled).toBe(false);
expect(toolbarInfos[1].enabled).toBe(true);
}));
it('should enable commands by default', asyncTest(async () => {
const service = newService();
registerCommand(service, createCommand('test1', {
execute: () => {},
}));
expect(service.isEnabled('test1', {})).toBe(true);
}));
it('should return the same toolbarButtons array if nothing has changed', asyncTest(async () => {
const service = newService();
const toolbarButtonUtils = new ToolbarButtonUtils(service);
registerCommand(service, createCommand('test1', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedNoteId: state.selectedNoteId,
};
},
isEnabled: (props:any) => {
return props.selectedNoteId === 'ok';
},
enabledCondition: 'cond1',
}));
registerCommand(service, createCommand('test2', {
execute: () => {},
mapStateToProps: (state:any) => {
return {
selectedFolderId: state.selectedFolderId,
};
},
isEnabled: (props:any) => {
return props.selectedFolderId === 'ok';
},
enabledCondition: 'cond2',
}));
const toolbarInfos1 = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', 'test2']);
const toolbarInfos1 = toolbarButtonUtils.commandsToToolbarButtons(['test1', 'test2'], {
cond1: true,
cond2: false,
});
const toolbarInfos2 = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', 'test2']);
const toolbarInfos2 = toolbarButtonUtils.commandsToToolbarButtons(['test1', 'test2'], {
cond1: true,
cond2: false,
});
expect(toolbarInfos1).toBe(toolbarInfos2);
expect(toolbarInfos1[0] === toolbarInfos2[0]).toBe(true);
expect(toolbarInfos1[1] === toolbarInfos2[1]).toBe(true);
const toolbarInfos3 = toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'ok',
}, ['test1', 'test2']);
const toolbarInfos3 = toolbarButtonUtils.commandsToToolbarButtons(['test1', 'test2'], {
cond1: true,
cond2: true,
});
expect(toolbarInfos2 === toolbarInfos3).toBe(false);
expect(toolbarInfos2[0] === toolbarInfos3[0]).toBe(true);
expect(toolbarInfos2[1] === toolbarInfos3[1]).toBe(false);
{
expect(toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', '-', 'test2'])).toBe(toolbarButtonUtils.commandsToToolbarButtons({
selectedNoteId: 'ok',
selectedFolderId: 'notok',
}, ['test1', '-', 'test2']));
expect(toolbarButtonUtils.commandsToToolbarButtons(['test1', '-', 'test2'], {
cond1: true,
cond2: false,
})).toBe(toolbarButtonUtils.commandsToToolbarButtons(['test1', '-', 'test2'], {
cond1: true,
cond2: false,
}));
}
}));
@@ -206,50 +190,37 @@ describe('services_CommandService', function() {
const utils = new MenuUtils(service);
registerCommand(service, createCommand('test1', {
mapStateToProps: (state:any) => {
return {
isOk: state.test1 === 'ok',
};
},
execute: () => {},
enabledCondition: 'cond1',
}));
registerCommand(service, createCommand('test2', {
mapStateToProps: (state:any) => {
return {
isOk: state.test2 === 'ok',
};
},
execute: () => {},
enabledCondition: 'cond2',
}));
{
const menuItemProps = utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'notok',
}, ['test1', 'test2']);
const menuItemProps = utils.commandsToMenuItemProps(['test1', 'test2'], {
cond1: true,
cond2: false,
});
expect(menuItemProps.test1.isOk).toBe(true);
expect(menuItemProps.test2.isOk).toBe(false);
expect(menuItemProps.test1.enabled).toBe(true);
expect(menuItemProps.test2.enabled).toBe(false);
}
{
const menuItemProps = utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'ok',
}, ['test1', 'test2']);
const menuItemProps = utils.commandsToMenuItemProps(['test1', 'test2'], {
cond1: true,
cond2: true,
});
expect(menuItemProps.test1.isOk).toBe(true);
expect(menuItemProps.test2.isOk).toBe(true);
expect(menuItemProps.test1.enabled).toBe(true);
expect(menuItemProps.test2.enabled).toBe(true);
}
expect(utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'ok',
}, ['test1', 'test2'])).toBe(utils.commandsToMenuItemProps({
test1: 'ok',
test2: 'ok',
}, ['test1', 'test2']));
expect(utils.commandsToMenuItemProps(['test1', 'test2'], { cond1: true, cond2: true }))
.toBe(utils.commandsToMenuItemProps(['test1', 'test2'], { cond1: true, cond2: true }));
}));
it('should create stateful menu items', asyncTest(async () => {
@@ -259,20 +230,30 @@ describe('services_CommandService', function() {
let propValue = null;
registerCommand(service, createCommand('test1', {
mapStateToProps: (state:any) => {
return {
isOk: state.test1 === 'ok',
};
},
execute: (props:any) => {
propValue = props.isOk;
execute: (_context:any, greeting:string) => {
propValue = greeting;
},
}));
const menuItem = utils.commandToStatefulMenuItem('test1', { isOk: 'hello' });
const menuItem = utils.commandToStatefulMenuItem('test1', 'hello');
menuItem.click();
expect(propValue).toBe('hello');
}));
it('should throw an error for invalid when clause keys in dev mode', asyncTest(async () => {
const service = newService();
registerCommand(service, createCommand('test1', {
execute: () => {},
enabledCondition: 'cond1 && cond2',
}));
await expectThrow(async () => service.isEnabled('test1', {}));
await expectThrow(async () => service.isEnabled('test1', { cond1: true }));
await expectNotThrow(async () => service.isEnabled('test1', { cond1: true, cond2: true }));
await expectNotThrow(async () => service.isEnabled('test1', { cond1: true, cond2: false }));
}));
});

View File

@@ -146,7 +146,7 @@ describe('services_rest_Api', function() {
}));
const noteId = response.id;
{
const note = await Note.load(noteId);
expect(note.latitude).toBe('48.73207100');
@@ -154,7 +154,7 @@ describe('services_rest_Api', function() {
expect(note.altitude).toBe('21.0000');
}
await api.route('PUT', 'notes/' + noteId, null, JSON.stringify({
await api.route('PUT', `notes/${noteId}`, null, JSON.stringify({
latitude: '49',
longitude: '-3',
altitude: '22',

View File

@@ -45,7 +45,7 @@ joplin.plugins.register({
newLines.push(newCells.join(' | '));
}
await joplin.commands.execute('replaceSelection', { value: newLines.join('\n') });
await joplin.commands.execute('replaceSelection', newLines.join('\n'));
},
});

View File

@@ -2420,6 +2420,11 @@
"path-exists": "^3.0.0"
}
},
"lodash.toarray": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE="
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -2741,6 +2746,14 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"node-emoji": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
"integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
"requires": {
"lodash.toarray": "^4.4.0"
}
},
"node-libs-browser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
@@ -3429,11 +3442,6 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
"slug": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/slug/-/slug-3.3.4.tgz",
"integrity": "sha512-VpHbtRCEWmgaZsrZcTsVl/Dhw98lcrOYDO17DNmJCNpppI6s3qJvnNu2Q3D4L84/2bi6vkW40mjNQI9oGQsflg=="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -3981,6 +3989,11 @@
"imurmurhash": "^0.1.4"
}
},
"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",
@@ -4067,6 +4080,14 @@
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
"dev": true
},
"uslug": {
"version": "git+https://github.com/laurent22/uslug.git#ba2834d79beb0435318709958b2f5e817d96674d",
"from": "git+https://github.com/laurent22/uslug.git#emoji-support",
"requires": {
"node-emoji": "^1.10.0",
"unorm": ">= 1.0.0"
}
},
"util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",

View File

@@ -20,6 +20,6 @@
"webpack-cli": "^3.3.11"
},
"dependencies": {
"slug": "^3.3.4"
"uslug": "git+https://github.com/laurent22/uslug.git#emoji-support"
}
}

View File

@@ -1,6 +1,6 @@
import joplin from 'api';
const nodeSlug = require('slug');
const uslug = require('uslug');
// From https://stackoverflow.com/a/6234804/561309
function escapeHtml(unsafe:string) {
@@ -29,7 +29,7 @@ function noteHeaders(noteBody:string) {
let slugs:any = {};
function headerSlug(headerText:string) {
const s = nodeSlug(headerText);
const s = uslug(headerText);
let num = slugs[s] ? slugs[s] : 1;
const output = [s];
if (num > 1) output.push(num);
@@ -49,9 +49,7 @@ joplin.plugins.register({
panels.onMessage(view, (message:any) => {
if (message.name === 'scrollToHash') {
joplin.commands.execute('scrollToHash', {
hash: message.hash,
})
joplin.commands.execute('scrollToHash', message.hash)
}
});

View File

@@ -155,7 +155,7 @@ export default class InteropServiceHelper {
if (Array.isArray(path)) path = path[0];
CommandService.instance().execute('showModalMessage', { message: _('Exporting to "%s" as "%s" format. Please wait...', path, module.format) });
CommandService.instance().execute('showModalMessage', _('Exporting to "%s" as "%s" format. Please wait...', path, module.format));
const exportOptions:ExportOptions = {};
exportOptions.path = path;

View File

@@ -58,7 +58,7 @@ const commands = [
require('./gui/MainScreen/commands/showNoteProperties'),
require('./gui/MainScreen/commands/showShareNoteDialog'),
require('./gui/MainScreen/commands/toggleNoteList'),
require('./gui/MainScreen/commands/toggleSidebar'),
require('./gui/MainScreen/commands/toggleSideBar'),
require('./gui/MainScreen/commands/toggleVisiblePanes'),
require('./gui/MainScreen/commands/toggleEditors'),
require('./gui/NoteEditor/commands/focusElementNoteBody'),
@@ -85,7 +85,7 @@ const globalCommands = [
const editorCommandDeclarations = require('./gui/NoteEditor/commands/editorCommandDeclarations').default;
const pluginClasses = [
require('./plugins/GotoAnything.min'),
require('./plugins/GotoAnything').default,
];
interface AppStateRoute {
@@ -513,7 +513,7 @@ class Application extends BaseApplication {
this.initRedux();
CommandService.instance().initialize(this.store());
CommandService.instance().initialize(this.store(), Setting.value('env') == 'dev');
for (const command of commands) {
CommandService.instance().registerDeclaration(command.declaration);

View File

@@ -6,7 +6,7 @@ export const declaration:CommandDeclaration = {
export const runtime = ():CommandRuntime => {
return {
execute: async ({ target }:any) => {
execute: async (_context:any, target:string) => {
if (target === 'noteBody') return CommandService.instance().execute('focusElementNoteBody');
if (target === 'noteList') return CommandService.instance().execute('focusElementNoteList');
if (target === 'sideBar') return CommandService.instance().execute('focusElementSideBar');

View File

@@ -1,13 +1,10 @@
import { CommandRuntime, CommandDeclaration } from '../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
import { stateUtils } from 'lib/reducer';
const Note = require('lib/models/Note');
const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
const bridge = require('electron').remote.require('./bridge').default;
interface Props {
noteId: string
}
export const declaration:CommandDeclaration = {
name: 'startExternalEditing',
label: () => _('Edit in external editor'),
@@ -16,21 +13,16 @@ export const declaration:CommandDeclaration = {
export const runtime = ():CommandRuntime => {
return {
execute: async (props:Props) => {
execute: async (context:CommandContext, noteId:string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
try {
const note = await Note.load(props.noteId);
const note = await Note.load(noteId);
ExternalEditWatcher.instance().openAndWatch(note);
} catch (error) {
bridge().showErrorMessageBox(_('Error opening note in editor: %s', error.message));
}
},
isEnabled: (props:any) => {
return !!props.noteId;
},
mapStateToProps: (state:any) => {
return {
noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
};
},
enabledCondition: 'oneNoteSelected',
};
};

View File

@@ -1,11 +1,8 @@
import { CommandRuntime, CommandDeclaration } from '../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
import { stateUtils } from 'lib/reducer';
const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
interface Props {
noteId: string
}
export const declaration:CommandDeclaration = {
name: 'stopExternalEditing',
label: () => _('Stop external editing'),
@@ -14,14 +11,10 @@ export const declaration:CommandDeclaration = {
export const runtime = ():CommandRuntime => {
return {
execute: async (props:Props) => {
ExternalEditWatcher.instance().stopWatching(props.noteId);
},
isEnabled: (props:any) => {
return !!props.noteId;
},
mapStateToProps: (state:any) => {
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
execute: async (context:CommandContext, noteId:string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
ExternalEditWatcher.instance().stopWatching(noteId);
},
enabledCondition: 'oneNoteSelected',
};
};

View File

@@ -1,12 +1,7 @@
import { CommandRuntime, CommandDeclaration } from '../lib/services/CommandService';
import CommandService, { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
import { AppState } from '../app';
import CommandService from 'lib/services/CommandService';
interface Props {
noteId: string
noteIsBeingWatched: boolean
}
import { stateUtils } from 'lib/reducer';
import { DesktopCommandContext } from '../services/commands/types';
export const declaration:CommandDeclaration = {
name: 'toggleExternalEditing',
@@ -16,27 +11,21 @@ export const declaration:CommandDeclaration = {
export const runtime = ():CommandRuntime => {
return {
execute: async (props:Props) => {
if (!props.noteId) return;
execute: async (context:DesktopCommandContext, noteId:string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
if (props.noteIsBeingWatched) {
CommandService.instance().execute('stopExternalEditing', { noteId: props.noteId });
if (!noteId) return;
if (context.state.watchedNoteFiles.includes(noteId)) {
CommandService.instance().execute('stopExternalEditing', noteId);
} else {
CommandService.instance().execute('startExternalEditing', { noteId: props.noteId });
CommandService.instance().execute('startExternalEditing', noteId);
}
},
isEnabled: (props:Props) => {
return !!props.noteId;
},
mapStateToProps: (state:AppState):Props => {
const noteId = state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null;
return {
noteId: noteId,
noteIsBeingWatched: noteId ? state.watchedNoteFiles.includes(noteId) : false,
};
},
title: (props:Props) => {
return props.noteIsBeingWatched ? _('Stop') : '';
enabledCondition: 'oneNoteSelected',
mapStateToTitle: (state:any) => {
const noteId = stateUtils.selectedNoteId(state);
return state.watchedNoteFiles.includes(noteId) ? _('Stop') : '';
},
};
};

View File

@@ -26,6 +26,8 @@ const getLabel = (commandName: string) => {
return _('Hide Joplin');
case 'closeWindow':
return _('Close Window');
case 'commandPalette':
return _('Command palette');
case 'config':
return shim.isMac() ? _('Preferences') : _('Options');
default:

View File

@@ -61,7 +61,7 @@ const commands = [
require('./commands/showShareNoteDialog'),
require('./commands/toggleEditors'),
require('./commands/toggleNoteList'),
require('./commands/toggleSidebar'),
require('./commands/toggleSideBar'),
require('./commands/toggleVisiblePanes'),
];
@@ -320,7 +320,7 @@ class MainScreenComponent extends React.Component<any, any> {
window.removeEventListener('resize', this.window_resize);
}
toggleSidebar() {
toggleSideBar() {
this.props.dispatch({
type: 'SIDEBAR_VISIBILITY_TOGGLE',
});

View File

@@ -1,8 +1,8 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import eventManager from 'lib/eventManager';
import { _ } from 'lib/locale';
import { stateUtils } from 'lib/reducer';
const Note = require('lib/models/Note');
const BaseModel = require('lib/BaseModel');
const { time } = require('lib/time-utils');
export const declaration:CommandDeclaration = {
@@ -13,7 +13,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteId }:any) => {
execute: async (context:CommandContext, noteId:string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
const note = await Note.load(noteId);
const defaultDate = new Date(Date.now() + 2 * 3600 * 1000);
@@ -51,25 +53,12 @@ export const runtime = (comp:any):CommandRuntime => {
},
});
},
title: (props:any):string => {
if (!props.noteId) return null;
if (!props.noteTodoDue) return null;
return time.formatMsToLocal(props.noteTodoDue);
},
isEnabled: (props:any):boolean => {
if (!props.noteId) return false;
return !!props.noteIsTodo && !props.noteTodoCompleted;
},
mapStateToProps: (state:any):any => {
const noteId = state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null;
const note = noteId ? BaseModel.byId(state.notes, noteId) : null;
return {
noteId: note ? noteId : null,
noteIsTodo: note ? note.is_todo : false,
noteTodoCompleted: note ? note.todo_completed : false,
noteTodoDue: note ? note.todo_due : null,
};
enabledCondition: 'oneNoteSelected && noteIsTodo && !noteTodoCompleted',
mapStateToTitle: (state:any) => {
const note = stateUtils.selectedNote(state);
return note && note.todo_due ? time.formatMsToLocal(note.todo_due) : null;
},
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import shim from 'lib/shim';
import InteropServiceHelper from '../../../InteropServiceHelper';
import { _ } from 'lib/locale';
@@ -12,8 +12,10 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteIds }:any) => {
execute: async (context:CommandContext, noteIds:string[] = null) => {
try {
noteIds = noteIds || context.state.selectedNoteIds;
if (!noteIds.length) throw new Error('No notes selected for pdf export');
let path = null;
@@ -22,7 +24,6 @@ export const runtime = (comp:any):CommandRuntime => {
filters: [{ name: _('PDF File'), extensions: ['pdf'] }],
defaultPath: await InteropServiceHelper.defaultFilename(noteIds[0], 'pdf'),
});
} else {
path = bridge().showOpenDialog({
properties: ['openDirectory', 'createDirectory'],
@@ -50,13 +51,7 @@ export const runtime = (comp:any):CommandRuntime => {
bridge().showErrorMessageBox(error.message);
}
},
isEnabled: (props:any):boolean => {
return !!props.noteIds.length;
},
mapStateToProps: (state:any):any => {
return {
noteIds: state.selectedNoteIds,
};
},
enabledCondition: 'someNotesSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import { CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
export const declaration:CommandDeclaration = {
name: 'hideModalMessage',

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const Folder = require('lib/models/Folder');
const Note = require('lib/models/Note');
@@ -10,7 +10,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteIds }:any) => {
execute: async (context:CommandContext, noteIds:string[] = null) => {
noteIds = noteIds || context.state.selectedNoteIds;
const folders:any[] = await Folder.sortFolderTree();
const startFolders:any[] = [];
const maxDepth = 15;
@@ -42,13 +44,6 @@ export const runtime = (comp:any):CommandRuntime => {
},
});
},
isEnabled: (props:any):boolean => {
return !!props.noteIds.length;
},
mapStateToProps: (state:any):any => {
return {
noteIds: state.selectedNoteIds,
};
},
enabledCondition: 'someNotesSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import { CommandContext, CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const Folder = require('lib/models/Folder');
const bridge = require('electron').remote.require('./bridge').default;
@@ -11,7 +11,7 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ parentId }:any) => {
execute: async (_context:CommandContext, parentId:string = null) => {
comp.setState({
promptOptions: {
label: _('Notebook title:'),
@@ -39,8 +39,5 @@ export const runtime = (comp:any):CommandRuntime => {
},
});
},
title: () => {
return _('New notebook');
},
};
};

View File

@@ -1,8 +1,7 @@
import { utils, CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { utils, CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const Setting = require('lib/models/Setting').default;
const Note = require('lib/models/Note');
const Folder = require('lib/models/Folder');
const TemplateUtils = require('lib/TemplateUtils');
export const declaration:CommandDeclaration = {
@@ -13,7 +12,7 @@ export const declaration:CommandDeclaration = {
export const runtime = ():CommandRuntime => {
return {
execute: async ({ template, isTodo }:any) => {
execute: async (_context:CommandContext, template:string = null, isTodo:boolean = false) => {
const folderId = Setting.value('activeFolderId');
if (!folderId) return;
@@ -34,12 +33,6 @@ export const runtime = ():CommandRuntime => {
id: newNote.id,
});
},
isEnabled: () => {
const { folders, selectedFolderId } = utils.store.getState();
return !!folders.length && selectedFolderId !== Folder.conflictFolderId();
},
title: () => {
return _('New note');
},
enabledCondition: 'oneFolderSelected && !inConflictFolder',
};
};

View File

@@ -1,4 +1,4 @@
import CommandService, { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import CommandService, { CommandContext, CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
@@ -9,14 +9,9 @@ export const declaration:CommandDeclaration = {
export const runtime = ():CommandRuntime => {
return {
execute: async ({ template }:any) => {
return CommandService.instance().execute('newNote', { template: template, isTodo: true });
},
isEnabled: () => {
return CommandService.instance().isEnabled('newNote', {});
},
title: () => {
return _('New to-do');
execute: async (_context:CommandContext, template:string = null) => {
return CommandService.instance().execute('newNote', template, true);
},
enabledCondition: 'oneFolderSelected && !inConflictFolder',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const bridge = require('electron').remote.require('./bridge').default;
@@ -10,8 +10,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteIds }:any) => {
// TODO: test
execute: async (context:CommandContext, noteIds:string[] = null) => {
noteIds = noteIds || context.state.selectedNoteIds;
try {
if (noteIds.length !== 1) throw new Error(_('Only one note can be printed at a time.'));
await comp.printTo_('printer', { noteId: noteIds[0] });
@@ -19,13 +20,6 @@ export const runtime = (comp:any):CommandRuntime => {
bridge().showErrorMessageBox(error.message);
}
},
isEnabled: (props:any):boolean => {
return !!props.noteIds.length;
},
mapStateToProps: (state:any):any => {
return {
noteIds: state.selectedNoteIds,
};
},
enabledCondition: 'someNotesSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const Folder = require('lib/models/Folder');
const bridge = require('electron').remote.require('./bridge').default;
@@ -10,7 +10,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ folderId }:any) => {
execute: async (context:CommandContext, folderId:string = null) => {
folderId = folderId || context.state.selectedFolderId;
const folder = await Folder.load(folderId);
if (folder) {

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const Tag = require('lib/models/Tag');
const bridge = require('electron').remote.require('./bridge').default;
@@ -10,7 +10,10 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ tagId }:any) => {
execute: async (context:CommandContext, tagId:string = null) => {
tagId = tagId || context.state.selectedTagId;
if (!tagId) return;
const tag = await Tag.load(tagId);
if (tag) {
comp.setState({

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
const BaseModel = require('lib/BaseModel');
const uuid = require('lib/uuid').default;
@@ -9,7 +9,7 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ query }:any) => {
execute: async (_context:CommandContext, query:string) => {
if (!comp.searchId_) comp.searchId_ = uuid.create();
comp.props.dispatch({

View File

@@ -1,4 +1,4 @@
import CommandService, { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import CommandService, { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const TemplateUtils = require('lib/TemplateUtils');
@@ -8,7 +8,7 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteType }:any) => {
execute: async (_context:CommandContext, noteType:string) => {
comp.setState({
promptOptions: {
label: _('Template file:'),
@@ -18,9 +18,9 @@ export const runtime = (comp:any):CommandRuntime => {
onClose: async (answer:any) => {
if (answer) {
if (noteType === 'note' || noteType === 'todo') {
CommandService.instance().execute('newNote', { template: answer.value, isTodo: noteType === 'todo' });
CommandService.instance().execute('newNote', answer.value, noteType === 'todo');
} else {
CommandService.instance().execute('insertText', { value: TemplateUtils.render(answer.value) });
CommandService.instance().execute('insertText', TemplateUtils.render(answer.value));
}
}

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
const Tag = require('lib/models/Tag');
@@ -10,7 +10,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteIds }:any) => {
execute: async (context:CommandContext, noteIds:string[] = null) => {
noteIds = noteIds || context.state.selectedNoteIds;
const tags = await Tag.commonTagsByNoteIds(noteIds);
const startTags = tags
.map((a:any) => {
@@ -64,11 +66,6 @@ export const runtime = (comp:any):CommandRuntime => {
},
});
},
isEnabled: (props:any) => {
return !!props.noteIds.length;
},
mapStateToProps: (state:any) => {
return { noteIds: state.selectedNoteIds };
},
enabledCondition: 'someNotesSelected',
};
};

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import { CommandDeclaration, CommandRuntime, CommandContext } from 'lib/services/CommandService';
export const declaration:CommandDeclaration = {
name: 'showModalMessage',
@@ -7,7 +7,7 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ message }:any) => {
execute: async (_context:CommandContext, message:string) => {
comp.setState({
modalLayer: {
visible: true,

View File

@@ -1,5 +1,6 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
import { stateUtils } from 'lib/reducer';
const Note = require('lib/models/Note');
export const declaration:CommandDeclaration = {
@@ -9,7 +10,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteId }:any) => {
execute: async (context:CommandContext, noteId:string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
const note = await Note.load(noteId);
if (note) {
comp.setState({
@@ -21,11 +24,7 @@ export const runtime = (comp:any):CommandRuntime => {
});
}
},
isEnabled: (props:any) => {
return !!props.noteId;
},
mapStateToProps: (state:any) => {
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
},
enabledCondition: 'oneNoteSelected',
};
};

View File

@@ -1,5 +1,6 @@
import CommandService, { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import CommandService, { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
import { stateUtils } from 'lib/reducer';
export const declaration:CommandDeclaration = {
name: 'showNoteProperties',
@@ -9,7 +10,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteId }:any) => {
execute: async (context:CommandContext, noteId:string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
comp.setState({
notePropertiesDialogOptions: {
noteId: noteId,
@@ -20,11 +23,6 @@ export const runtime = (comp:any):CommandRuntime => {
},
});
},
isEnabled: (props:any) => {
return !!props.noteId;
},
mapStateToProps: (state:any) => {
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
},
enabledCondition: 'oneNoteSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
@@ -8,7 +8,9 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteIds }:any) => {
execute: async (context:CommandContext, noteIds:string[] = null) => {
noteIds = noteIds || context.state.selectedNoteIds;
comp.setState({
shareNoteDialogOptions: {
noteIds: noteIds,

View File

@@ -1,4 +1,4 @@
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import { CommandDeclaration, CommandRuntime, CommandContext } from 'lib/services/CommandService';
import Setting from 'lib/models/Setting';
import { stateUtils } from 'lib/reducer';
import { _ } from 'lib/locale';
@@ -11,22 +11,14 @@ export const declaration:CommandDeclaration = {
export const runtime = ():CommandRuntime => {
return {
execute: async (props:any) => {
execute: async (context:CommandContext) => {
// A bit of a hack, but for now don't allow changing code view
// while a note is being saved as it will cause a problem with
// TinyMCE because it won't have time to send its content before
// being switch to Ace Editor.
if (props.hasNotesBeingSaved) return;
if (stateUtils.hasNotesBeingSaved(context.state)) return;
Setting.toggle('editor.codeView');
},
isEnabled: (props:any):boolean => {
return !props.hasNotesBeingSaved && props.hasOneSelectedNote;
},
mapStateToProps: (state:any):any => {
return {
hasNotesBeingSaved: stateUtils.hasNotesBeingSaved(state),
hasOneSelectedNote: state.selectedNoteIds.length === 1,
};
},
enabledCondition: '!notesAreBeingSaved && oneNoteSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import { CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {

View File

@@ -1,8 +1,8 @@
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import { CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
name: 'toggleSidebar',
name: 'toggleSideBar',
label: () => _('Toggle sidebar'),
iconName: 'fas fa-bars',
};

View File

@@ -1,4 +1,4 @@
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import { CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
@@ -14,14 +14,7 @@ export const runtime = (comp:any):CommandRuntime => {
type: 'NOTE_VISIBLE_PANES_TOGGLE',
});
},
isEnabled: (props:any):boolean => {
return props.settingEditorCodeView && props.selectedNoteIds.length === 1;
},
mapStateToProps: (state:any):any => {
return {
selectedNoteIds: state.selectedNoteIds,
settingEditorCodeView: state.settings['editor.codeView'],
};
},
enabledCondition: 'markdownEditorVisible && oneNoteSelected',
};
};

View File

@@ -13,6 +13,7 @@ import { Module } from 'lib/services/interop/types';
import InteropServiceHelper from '../InteropServiceHelper';
import { _ } from 'lib/locale';
import { MenuItem, MenuItemLocation } from 'lib/services/plugins/api/types';
import stateToWhenClauseContext from 'lib/services/commands/stateToWhenClauseContext';
const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
@@ -108,7 +109,7 @@ const commandNames:string[] = [
'attachFile',
'focusSearch',
'showLocalSearch',
'toggleSidebar',
'toggleSideBar',
'toggleNoteList',
'toggleVisiblePanes',
'toggleExternalEditing',
@@ -157,12 +158,12 @@ function useMenu(props:Props) {
if (Array.isArray(path)) path = path[0];
CommandService.instance().execute('showModalMessage', { message: _('Importing from "%s" as "%s" format. Please wait...', path, module.format) });
CommandService.instance().execute('showModalMessage', _('Importing from "%s" as "%s" format. Please wait...', path, module.format));
const importOptions = {
path,
format: module.format,
modulePath: module.path,
outputFormat: module.outputFormat,
onError: console.warn,
destinationFolderId: !module.isNoteArchive && moduleSource === 'file' ? props.selectedFolderId : null,
};
@@ -251,7 +252,7 @@ function useMenu(props:Props) {
exportItems.push({
label: module.fullLabel(),
click: async () => {
await InteropServiceHelper.export(props.dispatch.bind(this), module);
await InteropServiceHelper.export((action:any) => props.dispatch(action), module);
},
});
}
@@ -299,12 +300,12 @@ function useMenu(props:Props) {
templateItems.push({
label: _('Create note from template'),
click: () => {
CommandService.instance().execute('selectTemplate', { noteType: 'note' });
CommandService.instance().execute('selectTemplate', 'note');
},
}, {
label: _('Create to-do from template'),
click: () => {
CommandService.instance().execute('selectTemplate', { noteType: 'todo' });
CommandService.instance().execute('selectTemplate', 'todo');
},
}, {
label: _('Insert template'),
@@ -322,7 +323,7 @@ function useMenu(props:Props) {
click: async () => {
const templates = await TemplateUtils.loadTemplates(Setting.value('templateDir'));
this.store().dispatch({
props.dispatch({
type: 'TEMPLATE_UPDATE_ALL',
templates: templates,
});
@@ -358,8 +359,8 @@ function useMenu(props:Props) {
}
toolsItems = toolsItems.concat(toolsItemsAll);
function _checkForUpdates(ctx:any) {
bridge().checkForUpdates(false, bridge().window(), ctx.checkForUpdateLoggerPath(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
function _checkForUpdates() {
bridge().checkForUpdates(false, bridge().window(), `${Setting.value('profileDir')}/log-autoupdater.txt`, { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
}
function _showAbout() {
@@ -405,7 +406,7 @@ function useMenu(props:Props) {
}, {
label: _('Check for updates...'),
visible: shim.isMac() ? true : false,
click: () => _checkForUpdates(this),
click: () => _checkForUpdates(),
}, {
type: 'separator',
visible: shim.isMac() ? true : false,
@@ -532,7 +533,7 @@ function useMenu(props:Props) {
view: {
label: _('&View'),
submenu: [
menuItemDic.toggleSidebar,
menuItemDic.toggleSideBar,
menuItemDic.toggleNoteList,
menuItemDic.toggleVisiblePanes,
{
@@ -550,7 +551,6 @@ function useMenu(props:Props) {
id: 'showNoteCounts',
label: Setting.settingMetadata('showNoteCounts').label(),
type: 'checkbox',
// checked: Setting.value('showNoteCounts'),
click: () => {
Setting.setValue('showNoteCounts', !Setting.value('showNoteCounts'));
},
@@ -558,7 +558,6 @@ function useMenu(props:Props) {
id: 'uncompletedTodosOnTop',
label: Setting.settingMetadata('uncompletedTodosOnTop').label(),
type: 'checkbox',
// checked: Setting.value('uncompletedTodosOnTop'),
click: () => {
Setting.setValue('uncompletedTodosOnTop', !Setting.value('uncompletedTodosOnTop'));
},
@@ -566,7 +565,6 @@ function useMenu(props:Props) {
id: 'showCompletedTodos',
label: Setting.settingMetadata('showCompletedTodos').label(),
type: 'checkbox',
// checked: Setting.value('showCompletedTodos'),
click: () => {
Setting.setValue('showCompletedTodos', !Setting.value('showCompletedTodos'));
},
@@ -638,7 +636,7 @@ function useMenu(props:Props) {
}, {
label: _('Check for updates...'),
visible: shim.isMac() ? false : true,
click: () => _checkForUpdates(this),
click: () => _checkForUpdates(),
},
separator(),
{
@@ -786,9 +784,13 @@ function useMenu(props:Props) {
}, [props.routeName, props.pluginMenuItems, props.pluginMenus, keymapLastChangeTime, modulesLastChangeTime]);
useEffect(() => {
const whenClauseContext = CommandService.instance().currentWhenClauseContext();
for (const commandName in props.menuItemProps) {
if (!props.menuItemProps[commandName]) continue;
menuItemSetEnabled(commandName, CommandService.instance().isEnabled(commandName, props.menuItemProps[commandName]));
const p = props.menuItemProps[commandName];
if (!p) continue;
const enabled = 'enabled' in p ? p.enabled : CommandService.instance().isEnabled(commandName, whenClauseContext);
menuItemSetEnabled(commandName, enabled);
}
const layoutButtonSequenceOptions = Setting.enumOptions('layoutButtonSequence');
@@ -858,8 +860,10 @@ function MenuBar(props:Props):JSX.Element {
}
const mapStateToProps = (state:AppState) => {
const whenClauseContext = stateToWhenClauseContext(state);
return {
menuItemProps: menuUtils.commandsToMenuItemProps(state, commandNames.concat(pluginCommandNames(state.pluginService.plugins))),
menuItemProps: menuUtils.commandsToMenuItemProps(commandNames.concat(pluginCommandNames(state.pluginService.plugins)), whenClauseContext),
routeName: state.route.routeName,
selectedFolderId: state.selectedFolderId,
layoutButtonSequence: state.settings.layoutButtonSequence,

View File

@@ -46,8 +46,6 @@ function formatReadTime(readTimeMinutes: number) {
}
export default function NoteContentPropertiesDialog(props:NoteContentPropertiesDialogProps) {
console.info('MMMMMMMMMMMM', props.markupLanguage);
const theme = themeStyle(props.themeId);
const tableBodyComps: JSX.Element[] = [];
// For the source Markdown

View File

@@ -5,6 +5,7 @@ import { utils as pluginUtils } from 'lib/services/plugins/reducer';
import { connect } from 'react-redux';
import { AppState } from '../../../../app';
import ToolbarButtonUtils, { ToolbarButtonInfo } from 'lib/services/commands/ToolbarButtonUtils';
import stateToWhenClauseContext from 'lib/services/commands/stateToWhenClauseContext';
const { buildStyle } = require('lib/theme');
interface ToolbarProps {
@@ -31,6 +32,8 @@ function Toolbar(props:ToolbarProps) {
}
const mapStateToProps = (state: AppState) => {
const whenClauseContext = stateToWhenClauseContext(state);
const commandNames = [
'historyBackward',
'historyForward',
@@ -53,7 +56,7 @@ const mapStateToProps = (state: AppState) => {
].concat(pluginUtils.commandNamesFromViews(state.pluginService.plugins, 'editorToolbar'));
return {
toolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons(state, commandNames),
toolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons(commandNames, whenClauseContext),
};
};

View File

@@ -25,6 +25,7 @@ import eventManager from 'lib/eventManager';
import { AppState } from '../../app';
import ToolbarButtonUtils from 'lib/services/commands/ToolbarButtonUtils';
import { _ } from 'lib/locale';
import stateToWhenClauseContext from 'lib/services/commands/stateToWhenClauseContext';
const { themeStyle } = require('lib/theme');
const { substrWithEllipsis } = require('lib/string-utils');
@@ -247,9 +248,9 @@ function NoteEditor(props: NoteEditorProps) {
event.preventDefault();
if (event.shiftKey) {
CommandService.instance().execute('focusElement', { target: 'noteList' });
CommandService.instance().execute('focusElement', 'noteList');
} else {
CommandService.instance().execute('focusElement', { target: 'noteBody' });
CommandService.instance().execute('focusElement', 'noteBody');
}
}
}, [props.dispatch]);
@@ -364,7 +365,7 @@ 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 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;
return (
@@ -435,7 +436,7 @@ function NoteEditor(props: NoteEditorProps) {
const wysiwygBanner = props.bodyEditor !== 'TinyMCE' ? null : (
<div style={{ ...styles.warningBanner }}>
This is an experimental WYSIWYG editor for evaluation only. Please do not use with important notes as you may lose some data! See the <a style={styles.urlColor} onClick={introductionPostLinkClick} href="#">introduction post</a> for more information. TO SWITCH TO THE MARKDOWN EDITOR PLEASE PRESS "Code View".
This is an experimental Rich Text editor for evaluation only. Please do not use with important notes as you may lose some data! See the <a style={styles.urlColor} onClick={introductionPostLinkClick} href="#">introduction post</a> for more information. To switch to the Markdown Editor please press the "Toggle editors" in the top right-hand corner.
</div>
);
@@ -565,6 +566,7 @@ export {
const mapStateToProps = (state: AppState) => {
const noteId = state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null;
const whenClauseContext = stateToWhenClauseContext(state);
return {
noteId: noteId,
@@ -587,15 +589,15 @@ const mapStateToProps = (state: AppState) => {
watchedResources: state.watchedResources,
highlightedWords: state.highlightedWords,
plugins: state.pluginService.plugins,
toolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons(state, [
toolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons([
'historyBackward',
'historyForward',
'toggleEditors',
'toggleExternalEditing',
]),
setTagsToolbarButtonInfo: toolbarButtonUtils.commandsToToolbarButtons(state, [
], whenClauseContext),
setTagsToolbarButtonInfo: toolbarButtonUtils.commandsToToolbarButtons([
'setTags',
])[0],
], whenClauseContext)[0],
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
@@ -12,13 +12,6 @@ export const runtime = (comp:any):CommandRuntime => {
execute: async () => {
comp.editorRef.current.execCommand({ name: 'focus' });
},
isEnabled: (props:any):boolean => {
return props.hasOneNoteSelected;
},
mapStateToProps: (state:any):any => {
return {
hasOneNoteSelected: state.selectedNoteIds.length === 1,
};
},
enabledCondition: 'oneNoteSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
@@ -13,14 +13,6 @@ export const runtime = (comp:any):CommandRuntime => {
if (!comp.titleInputRef.current) return;
comp.titleInputRef.current.focus();
},
isEnabled: (props:any):boolean => {
return props.hasOneNoteSelected;
},
mapStateToProps: (state:any):any => {
return {
hasOneNoteSelected: state.selectedNoteIds.length === 1,
};
},
enabledCondition: 'oneNoteSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {
@@ -16,11 +16,6 @@ export const runtime = (comp:any):CommandRuntime => {
if (comp.noteSearchBarRef.current) comp.noteSearchBarRef.current.wrappedInstance.focus();
}
},
isEnabled: (props:any) => {
return !!props.noteId;
},
mapStateToProps: (state:any) => {
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
},
enabledCondition: 'oneNoteSelected',
};
};

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
export const declaration:CommandDeclaration = {
name: 'showRevisions',

View File

@@ -1,11 +1,9 @@
import { useEffect } from 'react';
import { FormNote, ScrollOptionTypes } from './types';
import editorCommandDeclarations from '../commands/editorCommandDeclarations';
import CommandService, { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from 'lib/services/CommandService';
const { time } = require('lib/time-utils.js');
const BaseModel = require('lib/BaseModel');
const { reg } = require('lib/registry.js');
const { MarkupToHtml } = require('lib/joplin-renderer');
const commandsWithDependencies = [
require('../commands/showLocalSearch'),
@@ -25,49 +23,30 @@ interface HookDependencies {
function editorCommandRuntime(declaration:CommandDeclaration, editorRef:any):CommandRuntime {
return {
execute: async (props:any) => {
// console.info('Running editor command:', declaration.name, props);
execute: async (_context:CommandContext, ...args:any[]) => {
if (!editorRef.current.execCommand) {
reg.logger().warn('Received command, but editor cannot execute commands', declaration.name);
return;
}
if (declaration.name === 'insertDateTime') {
return editorRef.current.execCommand({
name: 'insertText',
value: time.formatMsToLocal(new Date().getTime()),
});
} else if (declaration.name === 'scrollToHash') {
return editorRef.current.scrollTo({
type: ScrollOptionTypes.Hash,
value: args[0],
});
} else {
if (declaration.name === 'insertDateTime') {
return editorRef.current.execCommand({
name: 'insertText',
value: time.formatMsToLocal(new Date().getTime()),
});
} else if (declaration.name === 'scrollToHash') {
return editorRef.current.scrollTo({
type: ScrollOptionTypes.Hash,
value: props.hash,
});
} else {
return editorRef.current.execCommand({
name: declaration.name,
value: props.value,
});
}
return editorRef.current.execCommand({
name: declaration.name,
value: args[0],
});
}
},
isEnabled: (props:any) => {
if (props.isDialogVisible) return false;
if (props.markdownEditorViewerOnly) return false;
if (!props.hasSelectedNote) return false;
return props.isMarkdownNote;
},
mapStateToProps: (state:any) => {
const noteId = state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null;
const note = noteId ? BaseModel.byId(state.notes, noteId) : null;
const isMarkdownNote = note ? note.markup_language === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN : false;
return {
// True when the Markdown editor is active, and only the viewer pane is visible
// In this case, all editor-related shortcuts are disabled.
markdownEditorViewerOnly: state.settings['editor.codeView'] && state.noteVisiblePanes.length === 1 && state.noteVisiblePanes[0] === 'viewer',
hasSelectedNote: !!note,
isDialogVisible: !!Object.keys(state.visibleDialogs).length,
isMarkdownNote: isMarkdownNote,
};
},
enabledCondition: '!modalDialogVisible && markdownEditorPaneVisible && oneNoteSelected && noteIsMarkdown',
};
}

View File

@@ -24,7 +24,7 @@ const StyledRoot = styled.div`
width: 100%;
height: 100%;
background-color: ${(props:any) => props.theme.backgroundColor3};
border-right: 1px solid ${(props:any) => props.theme.dividerColor},
border-right: 1px solid ${(props:any) => props.theme.dividerColor};
`;
class NoteListComponent extends React.Component {
@@ -386,9 +386,9 @@ class NoteListComponent extends React.Component {
event.preventDefault();
if (event.shiftKey) {
CommandService.instance().execute('focusElement', { target: 'sideBar' });
CommandService.instance().execute('focusElement', 'sideBar');
} else {
CommandService.instance().execute('focusElement', { target: 'noteTitle' });
CommandService.instance().execute('focusElement', 'noteTitle');
}
}

View File

@@ -1,5 +1,6 @@
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
import { CommandRuntime, CommandDeclaration, CommandContext } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
import { stateUtils } from 'lib/reducer';
export const declaration:CommandDeclaration = {
name: 'focusElementNoteList',
@@ -9,19 +10,14 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ noteId }:any) => {
execute: async (context:CommandContext, noteId:string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
if (noteId) {
const ref = comp.itemAnchorRef(noteId);
if (ref) ref.focus();
}
},
isEnabled: (props:any):boolean => {
return !!props.noteId;
},
mapStateToProps: (state:any):any => {
return {
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
};
},
enabledCondition: 'noteListHasNotes',
};
};

View File

@@ -52,13 +52,13 @@ export default function NoteListControls(props:Props) {
return (
<ButtonContainer>
<StyledButton
tooltip={CommandService.instance().title('newTodo', {})}
tooltip={CommandService.instance().label('newTodo')}
iconName="far fa-check-square"
level={ButtonLevel.Primary}
onClick={onNewTodoButtonClick}
/>
<StyledButton
tooltip={CommandService.instance().title('newNote', {})}
tooltip={CommandService.instance().label('newNote')}
iconName="icon-note"
level={ButtonLevel.Primary}
onClick={onNewNoteButtonClick}

View File

@@ -1,4 +1,4 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
export const declaration:CommandDeclaration = {

View File

@@ -3,6 +3,7 @@ import CommandService from 'lib/services/CommandService';
import ToolbarBase from '../ToolbarBase';
import { utils as pluginUtils } from 'lib/services/plugins/reducer';
import ToolbarButtonUtils, { ToolbarButtonInfo } from 'lib/services/commands/ToolbarButtonUtils';
import stateToWhenClauseContext from 'lib/services/commands/stateToWhenClauseContext';
const { connect } = require('react-redux');
const { buildStyle } = require('lib/theme');
@@ -32,12 +33,14 @@ function NoteToolbar(props:NoteToolbarProps) {
const toolbarButtonUtils = new ToolbarButtonUtils(CommandService.instance());
const mapStateToProps = (state:any) => {
const whenClauseContext = stateToWhenClauseContext(state);
return {
toolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons(state, [
toolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons([
'editAlarm',
'toggleVisiblePanes',
'showNoteProperties',
].concat(pluginUtils.commandNamesFromViews(state.pluginService.plugins, 'noteToolbar'))),
].concat(pluginUtils.commandNamesFromViews(state.pluginService.plugins, 'noteToolbar')), whenClauseContext),
};
};

View File

@@ -5,7 +5,7 @@ const debounce = require('debounce');
export default function useSearch(query:string) {
useEffect(() => {
const search = debounce((query:string) => {
CommandService.instance().execute('search', { query });
CommandService.instance().execute('search', query);
}, 500);
search(query);

View File

@@ -230,7 +230,7 @@ class SideBarComponent extends React.Component<Props, State> {
if (itemType === BaseModel.TYPE_FOLDER && !item.encryption_applied) {
menu.append(
new MenuItem(menuUtils.commandToStatefulMenuItem('newFolder', { parentId: itemId }))
new MenuItem(menuUtils.commandToStatefulMenuItem('newFolder', itemId))
);
}
@@ -259,7 +259,7 @@ class SideBarComponent extends React.Component<Props, State> {
);
if (itemType === BaseModel.TYPE_FOLDER && !item.encryption_applied) {
menu.append(new MenuItem(menuUtils.commandToStatefulMenuItem('renameFolder', { folderId: itemId })));
menu.append(new MenuItem(menuUtils.commandToStatefulMenuItem('renameFolder', itemId)));
menu.append(new MenuItem({ type: 'separator' }));
@@ -290,7 +290,7 @@ class SideBarComponent extends React.Component<Props, State> {
if (itemType === BaseModel.TYPE_TAG) {
menu.append(new MenuItem(
menuUtils.commandToStatefulMenuItem('renameTag', { tagId: itemId })
menuUtils.commandToStatefulMenuItem('renameTag', itemId)
));
}
@@ -510,9 +510,9 @@ class SideBarComponent extends React.Component<Props, State> {
event.preventDefault();
if (event.shiftKey) {
CommandService.instance().execute('focusElement', { target: 'noteBody' });
CommandService.instance().execute('focusElement', 'noteBody');
} else {
CommandService.instance().execute('focusElement', { target: 'noteList' });
CommandService.instance().execute('focusElement', 'noteList');
}
}
@@ -559,7 +559,7 @@ class SideBarComponent extends React.Component<Props, State> {
iconAnimation={iconAnimation}
title={label}
onClick={() => {
CommandService.instance().execute('synchronize', { syncStarted: type !== 'sync' });
CommandService.instance().execute('synchronize', type !== 'sync');
}}
/>
);

View File

@@ -1,5 +1,6 @@
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
import { _ } from 'lib/locale';
import { DesktopCommandContext } from 'ElectronClient/services/commands/types';
export const declaration:CommandDeclaration = {
name: 'focusElementSideBar',
@@ -9,8 +10,10 @@ export const declaration:CommandDeclaration = {
export const runtime = (comp:any):CommandRuntime => {
return {
execute: async ({ sidebarVisibility }:any) => {
if (sidebarVisibility) {
execute: async (context:DesktopCommandContext) => {
const sideBarVisible = !!context.state.sidebarVisibility;
if (sideBarVisible) {
const item = comp.selectedItem();
if (item) {
const anchorRef = comp.anchorItemRefs[item.type][item.id];
@@ -21,13 +24,7 @@ export const runtime = (comp:any):CommandRuntime => {
}
}
},
isEnabled: (props:any):boolean => {
return props.sidebarVisibility;
},
mapStateToProps: (state:any):any => {
return {
sidebarVisibility: state.sidebarVisibility,
};
},
enabledCondition: 'sideBarVisible',
};
};

View File

@@ -68,7 +68,7 @@ function listItemTextColor(props:any) {
export const StyledListItemAnchor = styled.a`
font-size: ${(props:any) => Math.round(props.theme.fontSize * 1.0833333)}px;
font-weight: 500;
// font-weight: 500;
text-decoration: none;
color: ${(props:any) => listItemTextColor(props)};
cursor: default;

View File

@@ -17,7 +17,7 @@ export default function ToggleEditorsButton(props:Props) {
const style = styles_(props);
return (
<button style={style.button} disabled={!props.toolbarButtonInfo.enabled} aria-label={props.toolbarButtonInfo.title} title={props.toolbarButtonInfo.title} type="button" className="tox-tbtn" aria-pressed="false" onClick={props.toolbarButtonInfo.onClick}>
<button style={style.button} disabled={!props.toolbarButtonInfo.enabled} aria-label={props.toolbarButtonInfo.tooltip} title={props.toolbarButtonInfo.tooltip} type="button" className="tox-tbtn" aria-pressed="false" onClick={props.toolbarButtonInfo.onClick}>
<div style={style.leftInnerButton}>
<i style={style.leftIcon} className="fab fa-markdown"></i>
</div>

View File

@@ -5,7 +5,7 @@ export default function styles(props:Props) {
return buildStyle(['ToggleEditorsButton', props.value], props.themeId, (theme: any) => {
const iconSize = 15;
const mdIconWidth = iconSize * 1.25;
const buttonHeight = theme.toolbarHeight - 8;
const buttonHeight = theme.toolbarHeight - 7;
const mdIconPadding = Math.round((buttonHeight - iconSize) / 2) + 3;
const innerButton:any = {
@@ -41,14 +41,14 @@ export default function styles(props:Props) {
leftIcon: {
fontSize: iconSize,
position: 'relative',
top: 1,
top: 2,
color: theme.color3,
},
rightIcon: {
fontSize: iconSize - 1,
borderLeft: 'none',
position: 'relative',
top: 1,
top: 2,
color: theme.color3,
},
};

View File

@@ -40,11 +40,11 @@ export default class NoteListUtils {
if (!hasEncrypted) {
menu.append(
new MenuItem(menuUtils.commandToStatefulMenuItem('setTags', { noteIds }))
new MenuItem(menuUtils.commandToStatefulMenuItem('setTags', noteIds))
);
menu.append(
new MenuItem(menuUtils.commandToStatefulMenuItem('moveToFolder'))
new MenuItem(menuUtils.commandToStatefulMenuItem('moveToFolder', noteIds))
);
menu.append(
@@ -63,7 +63,7 @@ export default class NoteListUtils {
if (singleNoteId) {
const cmd = props.watchedNoteFiles.includes(singleNoteId) ? 'stopExternalEditing' : 'startExternalEditing';
menu.append(new MenuItem(menuUtils.commandToStatefulMenuItem(cmd, { noteId: singleNoteId })));
menu.append(new MenuItem(menuUtils.commandToStatefulMenuItem(cmd, singleNoteId)));
}
if (noteIds.length <= 1) {
@@ -132,7 +132,7 @@ export default class NoteListUtils {
menu.append(
new MenuItem(
menuUtils.commandToStatefulMenuItem('showShareNoteDialog', { noteIds: noteIds.slice() })
menuUtils.commandToStatefulMenuItem('showShareNoteDialog', noteIds.slice())
)
);
@@ -157,7 +157,7 @@ export default class NoteListUtils {
exportMenu.append(
new MenuItem(
menuUtils.commandToStatefulMenuItem('exportPdf', { noteIds: noteIds })
menuUtils.commandToStatefulMenuItem('exportPdf', noteIds)
)
);

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "1.3.2",
"version": "1.3.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1535,7 +1535,8 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": "",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
@@ -1700,7 +1701,8 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
}
@@ -1815,7 +1817,8 @@
},
"tar": {
"version": "4.4.8",
"resolved": "",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"dev": true,
"optional": true,
"requires": {
@@ -5946,8 +5949,22 @@
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"optional": true
"optional": true,
"requires": {
"minimist": "^1.2.5"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true,
"optional": true
}
}
},
"ms": {
"version": "2.1.2",
@@ -6117,7 +6134,8 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
}
@@ -7762,6 +7780,11 @@
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
},
"lodash.toarray": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE="
},
"log-symbols": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
@@ -8061,11 +8084,6 @@
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.0.4.tgz",
"integrity": "sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA=="
},
"memory-cache": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
},
"mermaid": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.8.1.tgz",
@@ -8495,6 +8513,14 @@
"semver": "^5.4.1"
}
},
"node-emoji": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
"integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
"requires": {
"lodash.toarray": "^4.4.0"
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
@@ -10673,11 +10699,6 @@
}
}
},
"slug": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/slug/-/slug-3.5.0.tgz",
"integrity": "sha512-+pZLDhMtmAc+ZcojQSMlUKDZBYmvhZiZmK8Ffx/D3Q/MIMHPDBAMbWvWN8vJb9xl2MfbDdRWxFzrdOhBiyVpow=="
},
"smalltalk": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/smalltalk/-/smalltalk-2.5.1.tgz",
@@ -11740,6 +11761,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",
@@ -11931,6 +11957,14 @@
"integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
"dev": true
},
"uslug": {
"version": "git+https://github.com/laurent22/uslug.git#ba2834d79beb0435318709958b2f5e817d96674d",
"from": "git+https://github.com/laurent22/uslug.git#emoji-support",
"requires": {
"node-emoji": "^1.10.0",
"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,11 +1,11 @@
{
"name": "Joplin",
"version": "1.3.2",
"version": "1.3.5",
"description": "Joplin for Desktop",
"main": "main.js",
"scripts": {
"dist": "node_modules/.bin/electron-builder",
"build": "patch-package --patch-dir ../patches && gulp build",
"build": "patch-package --patch-dir ../patches/shared && patch-package --patch-dir ../patches/node && gulp build",
"postinstall": "npm run build && gulp electronRebuild",
"start": "gulp build && electron . --env dev --log-level debug --no-welcome --open-dev-tools"
},
@@ -169,7 +169,6 @@
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1",
"md5-file": "^4.0.0",
"memory-cache": "^0.2.0",
"mermaid": "^8.8.1",
"moment": "^2.22.2",
"multiparty": "^4.2.1",
@@ -196,7 +195,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",
@@ -212,6 +210,7 @@
"tinymce": "^5.2.0",
"uglifycss": "0.0.29",
"url-parse": "^1.4.3",
"uslug": "git+https://github.com/laurent22/uslug.git#emoji-support",
"uuid": "^3.2.1",
"valid-url": "^1.0.9",
"xml2js": "^0.4.19"

View File

@@ -1,8 +1,12 @@
const React = require('react');
import * as React from 'react';
import { AppState } from '../app';
import CommandService, { SearchResult as CommandSearchResult } from 'lib/services/CommandService';
import KeymapService from 'lib/services/KeymapService';
import shim from 'lib/shim';
const { connect } = require('react-redux');
const { _ } = require('lib/locale');
const { themeStyle } = require('lib/theme');
const CommandService = require('lib/services/CommandService').default;
const SearchEngine = require('lib/services/searchengine/SearchEngine');
const BaseModel = require('lib/BaseModel');
const Tag = require('lib/models/Tag');
@@ -12,32 +16,73 @@ const { ItemList } = require('../gui/ItemList.min');
const HelpButton = require('../gui/HelpButton.min');
const { surroundKeywords, nextWhitespaceIndex, removeDiacritics } = require('lib/string-utils.js');
const { mergeOverlappingIntervals } = require('lib/ArrayUtils.js');
const PLUGIN_NAME = 'gotoAnything';
const markupLanguageUtils = require('lib/markupLanguageUtils');
const KeymapService = require('lib/services/KeymapService.js').default;
const shim = require('lib/shim').default;
const PLUGIN_NAME = 'gotoAnything';
interface SearchResult {
id: string,
title: string,
parent_id: string,
fields: string[],
fragments?: string,
path?: string,
type?: number,
}
interface Props {
themeId: number,
dispatch: Function,
folders: any[],
showCompletedTodos: boolean,
userData: any,
}
interface State {
query: string,
results: SearchResult[],
selectedItemId: string,
keywords: string[],
listType: number,
showHelp: boolean,
resultsInBody: boolean,
}
class GotoAnything {
onTrigger() {
public dispatch:Function;
public static Dialog:any;
public static manifest:any;
onTrigger(event:any) {
this.dispatch({
type: 'PLUGINLEGACY_DIALOG_SET',
open: true,
pluginName: PLUGIN_NAME,
userData: event.userData,
});
}
}
class Dialog extends React.PureComponent {
class Dialog extends React.PureComponent<Props, State> {
constructor() {
super();
private fuzzy_:boolean;
private styles_:any;
private inputRef:any;
private itemListRef:any;
private listUpdateIID_:any;
private markupToHtml_:any;
constructor(props:Props) {
super(props);
this.fuzzy_ = false;
const startString = props?.userData?.startString ? props?.userData?.startString : '';
this.state = {
query: '',
query: startString,
results: [],
selectedItemId: null,
keywords: [],
@@ -55,19 +100,25 @@ class Dialog extends React.PureComponent {
this.input_onChange = this.input_onChange.bind(this);
this.input_onKeyDown = this.input_onKeyDown.bind(this);
this.modalLayer_onClick = this.modalLayer_onClick.bind(this);
this.listItemRenderer = this.listItemRenderer.bind(this);
this.renderItem = this.renderItem.bind(this);
this.listItem_onClick = this.listItem_onClick.bind(this);
this.helpButton_onClick = this.helpButton_onClick.bind(this);
if (startString) this.scheduleListUpdate();
}
style() {
const styleKey = [this.props.themeId, this.state.resultsInBody ? '1' : '0'].join('-');
const styleKey = [this.props.themeId, this.state.listType, this.state.resultsInBody ? '1' : '0'].join('-');
if (this.styles_[styleKey]) return this.styles_[styleKey];
const theme = themeStyle(this.props.themeId);
const itemHeight = this.state.resultsInBody ? 84 : 64;
let itemHeight = this.state.resultsInBody ? 84 : 64;
if (this.state.listType === BaseModel.TYPE_COMMAND) {
itemHeight = 40;
}
this.styles_[styleKey] = {
dialogBox: Object.assign({}, theme.dialogBox, { minWidth: '50%', maxWidth: '50%' }),
@@ -138,7 +189,7 @@ class Dialog extends React.PureComponent {
});
}
onKeyDown(event) {
onKeyDown(event:any) {
if (event.keyCode === 27) { // ESCAPE
this.props.dispatch({
pluginName: PLUGIN_NAME,
@@ -148,7 +199,7 @@ class Dialog extends React.PureComponent {
}
}
modalLayer_onClick(event) {
modalLayer_onClick(event:any) {
if (event.currentTarget == event.target) {
this.props.dispatch({
pluginName: PLUGIN_NAME,
@@ -162,7 +213,7 @@ class Dialog extends React.PureComponent {
this.setState({ showHelp: !this.state.showHelp });
}
input_onChange(event) {
input_onChange(event:any) {
this.setState({ query: event.target.value });
this.scheduleListUpdate();
@@ -177,7 +228,7 @@ class Dialog extends React.PureComponent {
}, 100);
}
makeSearchQuery(query) {
makeSearchQuery(query:string) {
const output = [];
const splitted = query.split(' ');
@@ -190,7 +241,7 @@ class Dialog extends React.PureComponent {
return output.join(' ');
}
async keywords(searchQuery) {
async keywords(searchQuery:string) {
const parsedQuery = await SearchEngine.instance().parseQuery(searchQuery, this.fuzzy_);
return SearchEngine.instance().allParsedQueryTerms(parsedQuery);
}
@@ -207,11 +258,28 @@ class Dialog extends React.PureComponent {
if (!this.state.query) {
this.setState({ results: [], keywords: [] });
} else {
let results = [];
let results:SearchResult[] = [];
let listType = null;
let searchQuery = '';
let keywords = null;
if (this.state.query.indexOf('#') === 0) { // TAGS
if (this.state.query.indexOf(':') === 0) { // COMMANDS
const query = this.state.query.substr(1);
listType = BaseModel.TYPE_COMMAND;
keywords = [query];
const commandResults = CommandService.instance().searchCommands(query, true);
results = commandResults.map((result:CommandSearchResult) => {
return {
id: result.commandName,
title: result.title,
parent_id: null,
fields: [],
type: BaseModel.TYPE_COMMAND,
};
});
} else if (this.state.query.indexOf('#') === 0) { // TAGS
listType = BaseModel.TYPE_TAG;
searchQuery = `*${this.state.query.split(' ')[0].substr(1).trim()}*`;
results = await Tag.searchAllWithNotes({ titlePattern: searchQuery });
@@ -230,7 +298,7 @@ class Dialog extends React.PureComponent {
searchQuery = this.makeSearchQuery(this.state.query);
results = await SearchEngine.instance().search(searchQuery, { fuzzy: this.fuzzy_ });
resultsInBody = !!results.find(row => row.fields.includes('body'));
resultsInBody = !!results.find((row:any) => row.fields.includes('body'));
if (!resultsInBody || this.state.query.length <= 1) {
for (let i = 0; i < results.length; i++) {
@@ -241,7 +309,9 @@ class Dialog extends React.PureComponent {
} else {
const limit = 20;
const searchKeywords = await this.keywords(searchQuery);
const notes = await Note.byIds(results.map(result => result.id).slice(0, limit), { fields: ['id', 'body', 'markup_language', 'is_todo', 'todo_completed'] });
const notes = await Note.byIds(results.map((result:any) => result.id).slice(0, limit), { fields: ['id', 'body', 'markup_language', 'is_todo', 'todo_completed'] });
// Can't make any sense of this code so...
// @ts-ignore
const notesById = notes.reduce((obj, { id, body, markup_language }) => ((obj[[id]] = { id, body, markup_language }), obj), {});
for (let i = 0; i < results.length; i++) {
@@ -272,7 +342,7 @@ class Dialog extends React.PureComponent {
// e.g. 'Joplin is a free, open source' and 'open source note taking application'
// will result in 'Joplin is a free, open source note taking application'
const mergedIndices = mergeOverlappingIntervals(indices, 3);
fragments = mergedIndices.map(f => body.slice(f[0], f[1])).join(' ... ');
fragments = mergedIndices.map((f:any) => body.slice(f[0], f[1])).join(' ... ');
// Add trailing ellipsis if the final fragment doesn't end where the note is ending
if (mergedIndices.length && mergedIndices[mergedIndices.length - 1][1] !== body.length) fragments += ' ...';
@@ -285,7 +355,7 @@ class Dialog extends React.PureComponent {
}
if (!this.props.showCompletedTodos) {
results = results.filter((row) => !row.is_todo || !row.todo_completed);
results = results.filter((row:any) => !row.is_todo || !row.todo_completed);
}
}
}
@@ -296,20 +366,25 @@ class Dialog extends React.PureComponent {
this.setState({
listType: listType,
results: results,
keywords: await this.keywords(searchQuery),
keywords: keywords ? keywords : await this.keywords(searchQuery),
selectedItemId: results.length === 0 ? null : results[0].id,
resultsInBody: resultsInBody,
});
}
}
async gotoItem(item) {
async gotoItem(item:any) {
this.props.dispatch({
pluginName: PLUGIN_NAME,
type: 'PLUGINLEGACY_DIALOG_SET',
open: false,
});
if (item.type === BaseModel.TYPE_COMMAND) {
CommandService.instance().execute(item.id);
return;
}
if (this.state.listType === BaseModel.TYPE_NOTE || this.state.listType === BaseModel.TYPE_FOLDER) {
const folderPath = await Folder.folderPath(this.props.folders, item.parent_id);
@@ -329,7 +404,7 @@ class Dialog extends React.PureComponent {
noteId: item.id,
});
CommandService.instance().scheduleExecute('focusElement', { target: 'noteBody' });
CommandService.instance().scheduleExecute('focusElement', 'noteBody');
} else if (this.state.listType === BaseModel.TYPE_TAG) {
this.props.dispatch({
type: 'TAG_SELECT',
@@ -343,17 +418,19 @@ class Dialog extends React.PureComponent {
}
}
listItem_onClick(event) {
listItem_onClick(event:any) {
const itemId = event.currentTarget.getAttribute('data-id');
const parentId = event.currentTarget.getAttribute('data-parent-id');
const itemType = event.currentTarget.getAttribute('data-type');
this.gotoItem({
id: itemId,
parent_id: parentId,
type: itemType,
});
}
listItemRenderer(item) {
renderItem(item:SearchResult) {
const theme = themeStyle(this.props.themeId);
const style = this.style();
const rowStyle = item.id === this.state.selectedItemId ? style.rowSelected : style.row;
@@ -368,7 +445,7 @@ class Dialog extends React.PureComponent {
const fragmentComp = !fragmentsHtml ? null : <div style={style.rowFragments} dangerouslySetInnerHTML={{ __html: (fragmentsHtml) }}></div>;
return (
<div key={item.id} style={rowStyle} onClick={this.listItem_onClick} data-id={item.id} data-parent-id={item.parent_id}>
<div key={item.id} style={rowStyle} onClick={this.listItem_onClick} data-id={item.id} data-parent-id={item.parent_id} data-type={item.type}>
<div style={style.rowTitle} dangerouslySetInnerHTML={{ __html: titleHtml }}></div>
{fragmentComp}
{pathComp}
@@ -376,7 +453,7 @@ class Dialog extends React.PureComponent {
);
}
selectedItemIndex(results, itemId) {
selectedItemIndex(results:any[] = undefined, itemId:string = undefined) {
if (typeof results === 'undefined') results = this.state.results;
if (typeof itemId === 'undefined') itemId = this.state.selectedItemId;
for (let i = 0; i < results.length; i++) {
@@ -392,7 +469,7 @@ class Dialog extends React.PureComponent {
return this.state.results[index];
}
input_onKeyDown(event) {
input_onKeyDown(event:any) {
const keyCode = event.keyCode;
if (this.state.results.length > 0 && (keyCode === 40 || keyCode === 38)) { // DOWN / UP
@@ -428,7 +505,7 @@ class Dialog extends React.PureComponent {
const itemListStyle = {
marginTop: 5,
height: Math.min(style.itemHeight * this.state.results.length, 7 * style.itemHeight),
height: Math.min(style.itemHeight * this.state.results.length, 10 * style.itemHeight),
};
return (
@@ -437,7 +514,7 @@ class Dialog extends React.PureComponent {
itemHeight={style.itemHeight}
items={this.state.results}
style={itemListStyle}
itemRenderer={this.listItemRenderer}
itemRenderer={this.renderItem}
/>
);
}
@@ -445,7 +522,7 @@ class Dialog extends React.PureComponent {
render() {
const theme = themeStyle(this.props.themeId);
const style = this.style();
const helpComp = !this.state.showHelp ? null : <div style={style.help}>{_('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.')}</div>;
const helpComp = !this.state.showHelp ? null : <div style={style.help}>{_('Type a note title or part of its content to jump to it. Or type # followed by a tag name, or @ followed by a notebook name. Or type : to search for commands.')}</div>;
return (
<div onClick={this.modalLayer_onClick} style={theme.dialogModalLayer}>
@@ -463,7 +540,7 @@ class Dialog extends React.PureComponent {
}
const mapStateToProps = (state) => {
const mapStateToProps = (state:AppState) => {
return {
folders: state.folders,
themeId: state.settings.theme,
@@ -485,8 +562,18 @@ GotoAnything.manifest = {
accelerator: () => KeymapService.instance().getAccelerator('gotoAnything'),
screens: ['Main'],
},
{
name: 'main',
parent: 'tools',
label: _('Command palette'),
accelerator: () => KeymapService.instance().getAccelerator('commandPalette'),
screens: ['Main'],
userData: {
startString: ':',
},
},
],
};
module.exports = GotoAnything;
export default GotoAnything;

View File

@@ -0,0 +1,5 @@
import { AppState } from '../../app';
export interface DesktopCommandContext {
state: AppState,
}

View File

@@ -21,7 +21,7 @@ node_modules/warning/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/interface.js
node_modules/react-native/flow/
[options]
@@ -36,9 +36,8 @@ module.file_ext=.ios.js
munge_underscores=true
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation'
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
@@ -57,7 +56,6 @@ untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
@@ -72,4 +70,4 @@ untyped-import
untyped-type-import
[version]
^0.105.0
^0.122.0

View File

@@ -20,7 +20,6 @@ DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace
# Android/IntelliJ
#
@@ -42,29 +41,19 @@ buck-out/
*.keystore
!debug.keystore
# CocoaPods
ios/Pods/
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
# https://docs.fastlane.tools/best-practices/source-control/
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# This is generated:
android/build*
android/app/build*
# Bundle artifact
*.jsbundle
android/.project
android/.settings/
android/app/.classpath
android/app/.project
android/app/.settings/
android/app/src/debug/res/
pluginAssets/
# CocoaPods
/ios/Pods/

View File

@@ -0,0 +1,6 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
};

View File

@@ -13,7 +13,7 @@ import {
Image,
} from 'react-native';
import { renderFormatButtons } from './renderButtons';
import { NoteBodyViewer } from 'lib/components/note-body-viewer.js';
import NoteBodyViewer from 'lib/components/NoteBodyViewer/NoteBodyViewer';
const styles = StyleSheet.create({
buttonContainer: {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -15,9 +15,14 @@ import com.android.build.OutputFile
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
* // https://reactnative.dev/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
@@ -33,6 +38,13 @@ import com.android.build.OutputFile
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
@@ -66,7 +78,6 @@ import com.android.build.OutputFile
*/
project.ext.react = [
entryFile: "index.android.js",
enableHermes: false, // clean and rebuild if changing
]
@@ -99,6 +110,7 @@ def enableProguardInReleaseBuilds = false
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
@@ -111,37 +123,37 @@ def enableHermes = project.ext.react.get("enableHermes", false);
android {
compileSdkVersion rootProject.ext.compileSdkVersion
// To fix this error:
// > java.io.UncheckedIOException: java.io.IOException: Execution of compression failed. java.lang.OutOfMemoryError
// https://stackoverflow.com/q/57284812/561309
dexOptions { javaMaxHeapSize "4g" }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "net.cozic.joplin"
defaultConfig {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097583
versionName "1.3.0"
versionCode 2097595
versionName "1.3.7"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
missingDimensionStrategy 'react-native-camera', 'general'
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
// https://github.com/react-native-community/react-native-camera/issues/2138
missingDimensionStrategy 'react-native-camera', 'general'
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
multiDexEnabled true
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
@@ -156,57 +168,54 @@ android {
}
}
}
buildTypes {
debug {
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://facebook.github.io/react-native/docs/signed-apk-android.
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
implementation "org.webkit:android-jsc:r241213"
compile project(':react-native-push-notification')
// implementation (project(':react-native-camera')) {
// // This is required because com.google.firebase requires v16.0.x of com.google.android.gms
// // while react-native-camera requires v15.x, which results in broken dependencies with
// // this error message:
// //
// // The library com.google.android.gms:play-services-base is being requested by various other libraries at [[15.0.1,15.0.1]], but resolves to 16.0.1
// //
// // For the record: found solution by removing all Firebase stuff here and running "gradlew.bat :app:dependencies"
// // That shows that react-native-camera was the one requiring v15.0.1.
// exclude group: "com.google.android.gms"
// }
implementation project(':react-native-file-viewer')
implementation project(':react-native-securerandom')
implementation project(':react-native-fs')
implementation project(':react-native-image-picker')
implementation project(':react-native-vector-icons')
implementation project(':react-native-fs')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:appcompat-v7:28.0.0"
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
@@ -216,44 +225,16 @@ dependencies {
implementation jscFlavor
}
implementation project(':react-native-sqlite-storage')
implementation project(':rn-fetch-blob')
implementation project(':react-native-document-picker')
implementation project(':react-native-image-resizer')
// implementation project(':react-native-share-extension')
implementation project(':react-native-version-info')
implementation project(':react-native-camera')
implementation "com.facebook.react:react-native:+"
implementation project(':react-native-quick-actions')
// implementation "com.google.android.gms:play-services-base:16.0.1" // For Firebase
// implementation 'me.leolin:ShortcutBadger:1.1.21@aar' // For Firebase - this line if you wish to use badge on Android
// To fix the error below, which happened after adding react-native-camera.
// Doesn't make any sense since rn-camera neither defines v26 nor 27 but
// v25.0.2 in build.gradle, but anyway now it works ¯\_(ツ)_/¯
// --------------------------------------------------------------------------------------
// Fatal error
// { Error: Command failed: ./gradlew assembleRelease -PbuildDir=build --console plain
//
// FAILURE: Build failed with an exception.
//
// * What went wrong:
// Execution failed for task ':app:preReleaseBuild'.
// > Android dependency 'com.android.support:support-v4' has different version for the compile (26.1.0) and runtime (27.1.1) classpath. You should manually set the same version via DependencyResolution
// --------------------------------------------------------------------------------------
// https://github.com/react-native-community/react-native-camera/issues/1532#issuecomment-386434771
compile ("com.android.support:support-v4:26.0.1") {
force = true //<-- force dependency resolution to 26.0.1 in my case
}
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
implementation 'com.android.support:multidex:2.0.1'
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
from configurations.compile
into 'libs'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

View File

@@ -0,0 +1,19 @@
"""Helper definitions to glob .aar and .jar targets"""
def create_aar_targets(aarfiles):
for aarfile in aarfiles:
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
lib_deps.append(":" + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
def create_jar_targets(jarfiles):
for jarfile in jarfiles:
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
lib_deps.append(":" + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)

View File

@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
</manifest>
</manifest>

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package net.cozic.joplin;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}

View File

@@ -1,111 +1,89 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto"
package="net.cozic.joplin"
android:versionCode="2"
android:versionName="0.8.0">
package="net.cozic.joplin">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove"/>
<!-- ============================= -->
<!-- START RN-push-notitication -->
<!-- ============================= -->
<!-- RN-NOTIFICATION -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- ============================= -->
<!-- END RN-push-notitication -->
<!-- ============================= -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- /RN-NOTIFICATION -->
<!-- Make these features optional to enable Chromebooks -->
<!-- Make these features optional to enable Chromebooks -->
<!-- https://github.com/laurent22/joplin/issues/37 -->
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="26" />
<application
android:name=".MainApplication"
android:usesCleartextTraffic="true"
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:networkSecurityConfig="@xml/network_security_config"
android:hardwareAccelerated="true"
android:largeHeap="true"
>
<!-- ============================= -->
<!-- START RN-push-notitication -->
<!-- ============================= -->
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_name" android:value="@string/default_notification_channel_id"/>
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_description" android:value="Allow displaying a notification for Joplin's alarms"/>
<meta-data android:name="com.dieam.reactnativepushnotification.notification_color" android:resource="@android:color/white"/>
android:theme="@style/AppTheme">
<!-- RN-NOTIFICATION -->
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
</intent-filter>
android:name="com.emekalites.react.alarm.notification.AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="ACTION_DISMISS" />
<action android:name="ACTION_SNOOZE" />
</intent-filter>
</receiver>
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
<receiver
android:name="com.emekalites.react.alarm.notification.AlarmDismissReceiver"
android:enabled="true"
android:exported="true" />
<receiver
android:name="com.emekalites.react.alarm.notification.AlarmBootReceiver"
android:directBootAware="true"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>
<!-- /RN-NOTIFICATION -->
<service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerServiceGcm"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<!-- ============================= -->
<!-- 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.
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.
-->
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize"
android:launchMode="singleTop">
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<!-- SHARE EXTENSION -->
<activity
android:noHistory="true"
android:name=".share.ShareActivity"
@@ -124,6 +102,8 @@
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application>
<!-- /SHARE EXTENSION -->
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -12,4 +12,4 @@ public class MainActivity extends ReactActivity {
protected String getMainComponentName() {
return "Joplin";
}
}
}

View File

@@ -3,24 +3,28 @@ package net.cozic.joplin;
import android.app.Application;
import android.content.Context;
import android.database.CursorWindow;
import android.os.Build;
import android.webkit.WebView;
import androidx.multidex.MultiDex;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import net.cozic.joplin.share.SharePackage;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import net.cozic.joplin.share.SharePackage;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
@@ -29,6 +33,7 @@ public class MainApplication extends Application implements ReactApplication {
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
packages.add(new SharePackage());
@@ -41,23 +46,16 @@ public class MainApplication extends Application implements ReactApplication {
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
@Override
public void onCreate() {
super.onCreate();
// Enable debugging with the WebView we use to display notes
// Changes are made as recommended by folks at `react-native-webview`
// https://github.com/react-native-community/react-native-webview/blob/master/docs/Debugging.md
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
// To try to fix the error "Row too big to fit into CursorWindow"
// To try to fix the error "Row too big to fit into CursorWindow"
// https://github.com/andpor/react-native-sqlite-storage/issues/364#issuecomment-526423153
// https://github.com/laurent22/joplin/issues/1767#issuecomment-515617991
try {
@@ -66,25 +64,31 @@ public class MainApplication extends Application implements ReactApplication {
field.set(null, 50 * 1024 * 1024); //the 102400 is the new size added
} catch (Exception e) {
e.printStackTrace();
}
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
}
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates.
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(Context context) {
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
Class<?> aClass = Class.forName("net.cozic.joplin.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
@@ -96,4 +100,4 @@ public class MainApplication extends Application implements ReactApplication {
}
}
}
}
}

View File

@@ -1,3 +0,0 @@
<resources>
<color name="white">#FFF</color>
</resources>

View File

@@ -2,18 +2,17 @@
buildscript {
ext {
buildToolsVersion = "28.0.3"
buildToolsVersion = "29.0.2"
minSdkVersion = 16
compileSdkVersion = 28
targetSdkVersion = 28
compileSdkVersion = 29
targetSdkVersion = 29
}
repositories {
jcenter()
google()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:3.4.2")
classpath("com.android.tools.build:gradle:3.5.3")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -22,10 +21,6 @@ buildscript {
allprojects {
repositories {
mavenLocal()
maven { url "https://jitpack.io" }
maven {
url "https://maven.google.com"
}
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
@@ -34,22 +29,9 @@ allprojects {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
google()
jcenter()
maven { url 'https://jitpack.io' }
maven { url 'https://www.jitpack.io' }
}
}
// TODO: Maybe remove this (forgot why it was needed - probably to make some module work)
subprojects {
afterEvaluate {project ->
if (project.hasProperty("android")) {
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
}
}
}
}

View File

@@ -17,12 +17,12 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# Required for react-native-webview
# https://github.com/react-native-community/react-native-webview/blob/master/docs/Getting-Started.md
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# To fix this error:
# > java.io.UncheckedIOException: java.io.IOException: Execution of compression failed. java.lang.OutOfMemoryError
# https://stackoverflow.com/q/57284812/561309
org.gradle.jvmargs=-Xmx4608m
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.54.0

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -7,7 +7,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -125,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
@@ -154,19 +154,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -175,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View File

@@ -5,14 +5,14 @@
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

View File

@@ -1,17 +1,3 @@
rootProject.name = 'Joplin'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':react-native-fs'
project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android')
include ':app'
//include ':app', ':react-native-share-extension'
//project(':react-native-share-extension').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-share-extension/android')
include ':react-native-push-notification'
project(':react-native-push-notification').projectDir = file('../node_modules/react-native-push-notification/android')
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')

View File

@@ -1,29 +1,4 @@
{
"name": "Joplin",
"displayName": "Joplin",
"expo": {
"name": "Joplin",
"description": "Joplin for Android",
"slug": "Joplin",
"privacy": "public",
"sdkVersion": "18.0.0",
"version": "1.0.0",
"orientation": "portrait",
"primaryColor": "#cccccc",
"icon": "./assets/icons/app-icon.png",
"notification": {
"icon": "./assets/icons/notification-icon.png",
"color": "#000000"
},
"loading": {
"icon": "./assets/icons/loading-icon.png",
"hideExponentText": false
},
"packagerOpts": {
"assetExts": ["ttf"]
},
"ios": {
"supportsTablet": true
}
}
"displayName": "Joplin"
}

View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};

View File

@@ -1,22 +0,0 @@
const gulp = require('gulp');
const utils = require('../Tools/gulp/utils');
const tasks = {
encodeAssets: {
fn: require('./tools/encodeAssets'),
},
buildReactNativeInjectedJs: {
fn: require('./tools/buildReactNativeInjectedJs'),
},
podInstall: {
fn: require('./tools/podInstall'),
},
};
utils.registerGulpTasks(gulp, tasks);
gulp.task('build', gulp.series(
'buildReactNativeInjectedJs',
'encodeAssets',
'podInstall'
));

View File

@@ -1,3 +0,0 @@
const { main } = require('./main.js');
main();

View File

@@ -1,3 +0,0 @@
const { main } = require('./main.js');
main();

View File

@@ -1,3 +1,44 @@
const { main } = require('./main.js');
// Note about the application structure:
// - The user interface and its state is managed by React/Redux.
// - Persistent storage to SQLite and Web API is handled outside of React/Redux using regular JavaScript (no middleware, no thunk, etc.).
// - Communication from React to SQLite is done by calling model methods (note.save, etc.)
// - Communication from SQLite to Redux is done via dispatcher.
main();
// So there's basically still a one way flux: React => SQLite => Redux => React
import { LogBox, AppRegistry } from 'react-native';
const { Root } = require('./root.js');
// Seems JavaScript developers love adding warnings everywhere, even when these warnings can't be fixed
// or don't really matter. Because we want important warnings to actually be fixed, we disable
// all the useless ones, that way we aren't flooded by them when the app starts, and when there's
// one we know it should be fixed (or added here).
LogBox.ignoreLogs([
// Happens for example in react-native-side-menu, but the package is discontinued
// and we should just switch to a different one (or do it without a package).
'Animated: `useNativeDriver` was not specified. This is a required option and must be explicitly set to `true` or `false`',
// What's the point of printing warnings for non-user code. Of all the things that
// are broken and unreliable in React Native, require cycles are just a minor annoyance
// which shouldn't forever print warnings.
// To make it more fun, they don't normalise paths so forward slashes and backward slashes
// need to be handled to support Windows.
'Require cycle: node_modules/react-native-',
'Require cycle: node_modules\\react-native-',
'Require cycle: node_modules/rn-fetch-blob',
'Require cycle: node_modules\\rn-fetch-blob',
'Require cycle: node_modules/aws-sdk',
'Require cycle: node_modules\\aws-sdk',
// It's being updated over time and we don't need to see these warnings all the time
'Warning: componentWillReceiveProps has been renamed',
'Warning: componentWillUpdate has been renamed',
'Warning: componentWillMount has been renamed',
// Triggered by react-native-webview. Happens on slow devices when loading the note viewer.
// Apparently it can be safely ignored:
// https://github.com/react-native-webview/react-native-webview/issues/124
'Did not receive response to shouldStartLoad in time, defaulting to YES',
]);
AppRegistry.registerComponent('Joplin', () => Root);

View File

@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -22,6 +22,19 @@
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
@@ -36,19 +49,5 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSAppTransportSecurity</key>
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
</dict>
</plist>

View File

@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

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