You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2026-01-20 00:46:28 +02:00
Compare commits
36 Commits
rn_63
...
command_en
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3b708ff64 | ||
|
|
fea85b39a0 | ||
|
|
a53955a03d | ||
|
|
8d61514f64 | ||
|
|
c8f496b733 | ||
|
|
c4414e3bee | ||
|
|
89e7a3a65e | ||
|
|
b3bce34e9a | ||
|
|
d059aeebab | ||
|
|
910a5ad09d | ||
|
|
259dadb650 | ||
|
|
4ce2bf492b | ||
|
|
e635ee967a | ||
|
|
6a43f3be66 | ||
|
|
a4562a0a75 | ||
|
|
410a0f5d14 | ||
|
|
f8f46db910 | ||
|
|
f529adac99 | ||
|
|
3a52b9764b | ||
|
|
7e78d7716b | ||
|
|
0488c5c4cb | ||
|
|
921cc3b6c6 | ||
|
|
2a7aa28d4c | ||
|
|
7b3440ac4c | ||
|
|
958e5a80b7 | ||
|
|
3179117c62 | ||
|
|
d895463167 | ||
|
|
7e0e513051 | ||
|
|
4309c4f8e2 | ||
|
|
20b1c90574 | ||
|
|
7ff6ceb585 | ||
|
|
3dc3f334ec | ||
|
|
3476211f8b | ||
|
|
48e299916f | ||
|
|
35aebc9f52 | ||
|
|
cb3e1cf1e9 |
@@ -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
18
.gitignore
vendored
@@ -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
277
.ignore
Normal 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
|
||||
33
CliClient/package-lock.json
generated
33
CliClient/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
59
CliClient/tests/InMemoryCache.ts
Normal file
59
CliClient/tests/InMemoryCache.ts
Normal 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);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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 }));
|
||||
}));
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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'));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"webpack-cli": "^3.3.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"slug": "^3.3.4"
|
||||
"uslug": "git+https://github.com/laurent22/uslug.git#emoji-support"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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') : '';
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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',
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CommandDeclaration, CommandRuntime } from '../../../lib/services/CommandService';
|
||||
import { CommandDeclaration, CommandRuntime } from 'lib/services/CommandService';
|
||||
|
||||
export const declaration:CommandDeclaration = {
|
||||
name: 'hideModalMessage',
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CommandRuntime, CommandDeclaration } from '../../../lib/services/CommandService';
|
||||
import { CommandRuntime, CommandDeclaration } from 'lib/services/CommandService';
|
||||
|
||||
export const declaration:CommandDeclaration = {
|
||||
name: 'showRevisions',
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
66
ElectronClient/package-lock.json
generated
66
ElectronClient/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
5
ElectronClient/services/commands/types.ts
Normal file
5
ElectronClient/services/commands/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { AppState } from '../../app';
|
||||
|
||||
export interface DesktopCommandContext {
|
||||
state: AppState,
|
||||
}
|
||||
@@ -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
|
||||
|
||||
27
ReactNativeClient/.gitignore
vendored
27
ReactNativeClient/.gitignore
vendored
@@ -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/
|
||||
|
||||
6
ReactNativeClient/.prettierrc.js
Normal file
6
ReactNativeClient/.prettierrc.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
bracketSpacing: false,
|
||||
jsxBracketSameLine: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
};
|
||||
@@ -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 |
@@ -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"
|
||||
|
||||
19
ReactNativeClient/android/app/build_defs.bzl
Normal file
19
ReactNativeClient/android/app/build_defs.bzl
Normal 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,
|
||||
)
|
||||
Binary file not shown.
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 |
@@ -12,4 +12,4 @@ public class MainActivity extends ReactActivity {
|
||||
protected String getMainComponentName() {
|
||||
return "Joplin";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<color name="white">#FFF</color>
|
||||
</resources>
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
35
ReactNativeClient/android/gradlew
vendored
35
ReactNativeClient/android/gradlew
vendored
@@ -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" "$@"
|
||||
|
||||
7
ReactNativeClient/android/gradlew.bat
vendored
7
ReactNativeClient/android/gradlew.bat
vendored
@@ -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"
|
||||
|
||||
|
||||
@@ -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')
|
||||
@@ -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"
|
||||
}
|
||||
3
ReactNativeClient/babel.config.js
Normal file
3
ReactNativeClient/babel.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
};
|
||||
@@ -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'
|
||||
));
|
||||
@@ -1,3 +0,0 @@
|
||||
const { main } = require('./main.js');
|
||||
|
||||
main();
|
||||
@@ -1,3 +0,0 @@
|
||||
const { main } = require('./main.js');
|
||||
|
||||
main();
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user