You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-24 20:19:10 +02:00
Compare commits
201 Commits
android-v1
...
android-v1
Author | SHA1 | Date | |
---|---|---|---|
|
2bb5acdfb1 | ||
|
dda0d8ca08 | ||
|
f007735936 | ||
|
f5f117cb72 | ||
|
fc6da04081 | ||
|
12ff654986 | ||
|
e852ad846f | ||
|
28e00fdf2e | ||
|
3bd0656eab | ||
|
e9af71dd76 | ||
|
73b33e8e32 | ||
|
c2c7efee91 | ||
|
0836fca822 | ||
|
566df5039c | ||
|
559655bf33 | ||
|
0eab23fbcf | ||
|
f334f4f487 | ||
|
00057da17d | ||
|
0a05464013 | ||
|
9ebb574059 | ||
|
d29c3c2466 | ||
|
a71f1c19ec | ||
|
485921d879 | ||
|
15de7572c0 | ||
|
09f41dd50e | ||
|
7b8ee467a0 | ||
|
99a496d684 | ||
|
f43ee123d8 | ||
|
f42fb1b871 | ||
|
cf2442c5b2 | ||
|
e0e4735b03 | ||
|
8bd58c9608 | ||
|
215a725ded | ||
|
12c0a05af0 | ||
|
a7fa119041 | ||
|
7fb52b8b0e | ||
|
3e86ae4a82 | ||
|
947d81d96d | ||
|
6ca640d2ed | ||
|
6aca233b21 | ||
|
2200be697e | ||
|
25ab3c323b | ||
|
5bf30a9586 | ||
|
b6779a8074 | ||
|
59599d318c | ||
|
538600fd6c | ||
|
63264ba471 | ||
|
95e7f3df7d | ||
|
366fd2a333 | ||
|
5be99a4a16 | ||
|
d86f6a1fbd | ||
|
7d68208cb4 | ||
|
e9de9d9128 | ||
|
1af16d9f0b | ||
|
8e11eababa | ||
|
4ec9faadd5 | ||
|
5cf462c885 | ||
|
f7ef0a2b1e | ||
|
870f55a6c5 | ||
|
7f7e38b434 | ||
|
460a07b1a3 | ||
|
48c9b86d2b | ||
|
7202066c1f | ||
|
5226f0019b | ||
|
26ac745419 | ||
|
b3f2bbee5b | ||
|
56c6cfc785 | ||
|
1db4932573 | ||
|
a2873ebbc5 | ||
|
f652011d59 | ||
|
27c572b2f5 | ||
|
7a4c97618d | ||
|
3ac4fbeee5 | ||
|
9e05fa553c | ||
|
d4f0d2423d | ||
|
abdd7e3256 | ||
|
f3ea476f27 | ||
|
aa22af443c | ||
|
ce3bd2a47d | ||
|
a9b26246e6 | ||
|
cc1e941dd9 | ||
|
9610b7e6bd | ||
|
ad85a12535 | ||
|
b825346829 | ||
|
bd4cbaf93d | ||
|
9af2a19bdf | ||
|
d3fa906a9a | ||
|
22679641ee | ||
|
0ca7457000 | ||
|
c84e49c71c | ||
|
07ab0e986d | ||
|
17957f5da4 | ||
|
a7b5d43e69 | ||
|
38eda3f151 | ||
|
056285deda | ||
|
bdedf69439 | ||
|
c9451d8675 | ||
|
c38834b04c | ||
|
851eee1500 | ||
|
40e24102ce | ||
|
7614a795e9 | ||
|
1273a1dc5f | ||
|
10909fe4fc | ||
|
9b3d3026bf | ||
|
96076c84f4 | ||
|
2c553db45a | ||
|
7d7005596f | ||
|
998dd52adc | ||
|
2a1c6d6475 | ||
|
1ba0644142 | ||
|
88ac57d7f3 | ||
|
314686bede | ||
|
af8845f209 | ||
|
c95d7f9d37 | ||
|
2510c659e6 | ||
|
b7523e1b21 | ||
|
e4e9e801a2 | ||
|
524ec12d8a | ||
|
1108e8c28a | ||
|
0f1156ab9c | ||
|
2a08cc332a | ||
|
5d2baa872e | ||
|
4b377589aa | ||
|
cf78204c85 | ||
|
c513cdd4eb | ||
|
5f410e80e6 | ||
|
2aa7eaa192 | ||
|
b24d060281 | ||
|
a014b9347e | ||
|
582ab4ac13 | ||
|
c9adccad4a | ||
|
f41ba67e15 | ||
|
1f70a76c7e | ||
|
5fe3732a38 | ||
|
445533cfcc | ||
|
a8e29249d6 | ||
|
e4a3cbd2ff | ||
|
96b7ce9d50 | ||
|
2bbc1e7ecd | ||
|
83619b279d | ||
|
8b5a99d494 | ||
|
67d4123608 | ||
|
a424e3c899 | ||
|
08d4b5a714 | ||
|
68aefd5e4c | ||
|
57d750bc9a | ||
|
fbe966903b | ||
|
652748f969 | ||
|
e108fdb1d8 | ||
|
a8296e2e37 | ||
|
0998fc0ad7 | ||
|
d5f3e860b9 | ||
|
4e624f7db5 | ||
|
5b697b7e16 | ||
|
30e0d69a74 | ||
|
652816fd26 | ||
|
3a33e5f416 | ||
|
277dac5512 | ||
|
81d97d9f9d | ||
|
a4873cd40d | ||
|
20cb2daf43 | ||
|
e5b5250a91 | ||
|
db7d617e2b | ||
|
a627884876 | ||
|
ed30d09e07 | ||
|
179e3f9aee | ||
|
a67aedba35 | ||
|
199c411a7d | ||
|
5cd7bb5bdb | ||
|
30b8f5e2aa | ||
|
44f2842820 | ||
|
569355a318 | ||
|
8464e16d5d | ||
|
874c1e3e82 | ||
|
2530ecfc86 | ||
|
6b49f1dfcc | ||
|
b1af25ea18 | ||
|
3086007a9c | ||
|
bdfb6b97f5 | ||
|
c01219e6be | ||
|
743c11c279 | ||
|
11646d1c21 | ||
|
797f4a9669 | ||
|
815775ad8f | ||
|
085109288f | ||
|
c6cf0f3ba5 | ||
|
f9bdce7e24 | ||
|
f8cf4db5db | ||
|
14e6ae373f | ||
|
39bffd2790 | ||
|
f3cb903901 | ||
|
abad1883bc | ||
|
bb8770a967 | ||
|
c903947704 | ||
|
82e96840e9 | ||
|
e190d90832 | ||
|
0ae8d454ad | ||
|
77c7f966cf | ||
|
619fa1d607 | ||
|
157736ff7e | ||
|
0b57d906f8 |
@@ -69,14 +69,24 @@ ElectronClient/commands/focusElement.js
|
||||
ElectronClient/commands/startExternalEditing.js
|
||||
ElectronClient/commands/stopExternalEditing.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/Header/commands/focusSearch.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/newNotebook.js
|
||||
ElectronClient/gui/MainScreen/commands/newTodo.js
|
||||
ElectronClient/gui/MainScreen/commands/print.js
|
||||
ElectronClient/gui/MainScreen/commands/renameFolder.js
|
||||
@@ -88,9 +98,11 @@ 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/MultiNoteActions.js
|
||||
ElectronClient/gui/NoteContentPropertiesDialog.js
|
||||
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
|
||||
@@ -98,12 +110,6 @@ 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/AceEditor/AceEditor.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/styles/index.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/Toolbar.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/utils/index.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/utils/types.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/utils/useListIdent.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Editor.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/styles/index.js
|
||||
@@ -113,9 +119,11 @@ 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
|
||||
@@ -125,19 +133,42 @@ 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/useNoteToolbarButtons.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/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
|
||||
ReactNativeClient/lib/AsyncActionQueue.js
|
||||
ReactNativeClient/lib/checkPermissions.js
|
||||
ReactNativeClient/lib/commands/historyBackward.js
|
||||
@@ -147,13 +178,15 @@ ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
||||
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
|
||||
ReactNativeClient/lib/hooks/usePrevious.js
|
||||
ReactNativeClient/lib/hooks/usePropsDebugger.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/media.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
|
||||
ReactNativeClient/lib/JoplinServerApi.js
|
||||
ReactNativeClient/lib/ntpDate.js
|
||||
ReactNativeClient/lib/services/CommandService.js
|
||||
ReactNativeClient/lib/services/debug/populateDatabase.js
|
||||
ReactNativeClient/lib/services/keychain/KeychainService.js
|
||||
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.dummy.js
|
||||
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.mobile.js
|
||||
@@ -176,6 +209,16 @@ ReactNativeClient/lib/services/synchronizer/utils/types.js
|
||||
ReactNativeClient/lib/services/UndoRedoService.js
|
||||
ReactNativeClient/lib/ShareExtension.js
|
||||
ReactNativeClient/lib/shareHandler.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/versionInfo.js
|
||||
ReactNativeClient/PluginAssetsLoader.js
|
||||
ReactNativeClient/setUpQuickActions.js
|
||||
|
63
.gitignore
vendored
63
.gitignore
vendored
@@ -50,6 +50,8 @@ joplin-webclipper-source.zip
|
||||
Tools/commit_hook.txt
|
||||
.vscode/*
|
||||
*.map
|
||||
ReactNativeClient/lib/sql-extensions/spellfix.so
|
||||
ReactNativeClient/lib/sql-extensions/spellfix.dylib
|
||||
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
CliClient/app/LinkSelector.js
|
||||
@@ -60,14 +62,24 @@ ElectronClient/commands/focusElement.js
|
||||
ElectronClient/commands/startExternalEditing.js
|
||||
ElectronClient/commands/stopExternalEditing.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/Header/commands/focusSearch.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/newNotebook.js
|
||||
ElectronClient/gui/MainScreen/commands/newTodo.js
|
||||
ElectronClient/gui/MainScreen/commands/print.js
|
||||
ElectronClient/gui/MainScreen/commands/renameFolder.js
|
||||
@@ -79,9 +91,11 @@ 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/MultiNoteActions.js
|
||||
ElectronClient/gui/NoteContentPropertiesDialog.js
|
||||
ElectronClient/gui/NoteEditor/commands/editorCommandDeclarations.js
|
||||
@@ -89,12 +103,6 @@ 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/AceEditor/AceEditor.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/styles/index.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/Toolbar.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/utils/index.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/utils/types.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/AceEditor/utils/useListIdent.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Editor.js
|
||||
ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/styles/index.js
|
||||
@@ -104,9 +112,11 @@ 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
|
||||
@@ -116,19 +126,42 @@ 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/useNoteToolbarButtons.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/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
|
||||
ReactNativeClient/lib/AsyncActionQueue.js
|
||||
ReactNativeClient/lib/checkPermissions.js
|
||||
ReactNativeClient/lib/commands/historyBackward.js
|
||||
@@ -138,13 +171,15 @@ ReactNativeClient/lib/components/screens/UpgradeSyncTargetScreen.js
|
||||
ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
|
||||
ReactNativeClient/lib/hooks/usePrevious.js
|
||||
ReactNativeClient/lib/hooks/usePropsDebugger.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/media.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
|
||||
ReactNativeClient/lib/JoplinServerApi.js
|
||||
ReactNativeClient/lib/ntpDate.js
|
||||
ReactNativeClient/lib/services/CommandService.js
|
||||
ReactNativeClient/lib/services/debug/populateDatabase.js
|
||||
ReactNativeClient/lib/services/keychain/KeychainService.js
|
||||
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.dummy.js
|
||||
ReactNativeClient/lib/services/keychain/KeychainServiceDriver.mobile.js
|
||||
@@ -167,6 +202,16 @@ ReactNativeClient/lib/services/synchronizer/utils/types.js
|
||||
ReactNativeClient/lib/services/UndoRedoService.js
|
||||
ReactNativeClient/lib/ShareExtension.js
|
||||
ReactNativeClient/lib/shareHandler.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/versionInfo.js
|
||||
ReactNativeClient/PluginAssetsLoader.js
|
||||
ReactNativeClient/setUpQuickActions.js
|
||||
|
7
BUILD.md
7
BUILD.md
@@ -11,6 +11,7 @@ Note that all the applications share the same library, which, for historical rea
|
||||
- macOS, Linux: Install rsync - https://nodejs.org/en/
|
||||
- macOS: Install Cocoapods - `brew install cocoapods`
|
||||
- Windows: Install Windows Build Tools - `npm install -g windows-build-tools`
|
||||
- Linux: Install dependencies - `sudo apt install libnss3 libsecret-1-dev`
|
||||
|
||||
## Building
|
||||
|
||||
@@ -25,6 +26,8 @@ Then you can test the various applications:
|
||||
cd ElectronClient
|
||||
npm start
|
||||
|
||||
You can also run it under WSL 2. To do so, [follow these instructions](https://www.beekeeperstudio.io/blog/building-electron-windows-ubuntu-wsl2) to setup your environment.
|
||||
|
||||
## Testing the Terminal application
|
||||
|
||||
cd CliClient
|
||||
@@ -87,6 +90,10 @@ It still requires you to quit the application each time you want it to rebuild,
|
||||
2. Switch to the Electron app and <kbd>cmd</kbd>+<kbd>Q</kbd> to quit it.
|
||||
3. `watchman` immediately restarts the app for you (whereas usually you'd have to switch back to the terminal, type `"npm start"`, and hit enter).
|
||||
|
||||
# Updating Markdown renderer packages
|
||||
|
||||
The Markdown renderer is located under ReactNativeClient/lib/joplin-renderer. Whenever updating one of its dependencies, such as Mermaid or Katex, please run `npm run buildAssets` to make sure all assets such as fonts or CSS files are deployed correctly.
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
Please read for the [Build Troubleshooting Document](https://github.com/laurent22/joplin/blob/master/readme/build_troubleshooting.md) for various tips on how to get the build working.
|
@@ -36,6 +36,7 @@ If you want to start contributing to the project's code, please follow these gui
|
||||
- Before adding a new feature, ask about it in the [Github Issue Tracker](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue) or the [Joplin Forum](https://discourse.joplinapp.org/), or check if existing discussions exist to make sure the new functionality is desired.
|
||||
- **Changes that will consist in more than 50 lines of code should be discussed the [Joplin Forum](https://discourse.joplinapp.org/)**, so that you don't spend too much time implementing something that might not be accepted.
|
||||
- All the applications share the same backend (database, synchronisation, settings, models, business logic, etc.) so if you change something in the backend in one app, makes sure it still work in the other apps. Usually it does, but keep this in mind.
|
||||
- Pull requests that make many changes using an automated tool, like for spell fixing, styling, etc. will not be accepted. An exception would be if the changes have been discussed in the forum and someone has agreed to review **and test** the pull request.
|
||||
|
||||
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/master/BUILD.md) for more details.
|
||||
|
||||
|
@@ -2,6 +2,9 @@ const gulp = require('gulp');
|
||||
const fs = require('fs-extra');
|
||||
const utils = require('../Tools/gulp/utils');
|
||||
const tasks = {
|
||||
compileExtensions: {
|
||||
fn: require('../Tools/gulp/tasks/compileExtensions.js'),
|
||||
},
|
||||
copyLib: require('../Tools/gulp/tasks/copyLib'),
|
||||
tsc: require('../Tools/gulp/tasks/tsc'),
|
||||
updateIgnoredTypeScriptBuild: require('../Tools/gulp/tasks/updateIgnoredTypeScriptBuild'),
|
||||
@@ -53,10 +56,12 @@ utils.registerGulpTasks(gulp, tasks);
|
||||
|
||||
gulp.task('build', gulp.series([
|
||||
'prepareBuild',
|
||||
'compileExtensions',
|
||||
'copyLib',
|
||||
]));
|
||||
|
||||
gulp.task('buildTests', gulp.series([
|
||||
'prepareTestBuild',
|
||||
'compileExtensions',
|
||||
'copyLib',
|
||||
]));
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -38,42 +38,42 @@ locales['tr_TR'] = require('./tr_TR.json');
|
||||
locales['vi'] = require('./vi.json');
|
||||
locales['zh_CN'] = require('./zh_CN.json');
|
||||
locales['zh_TW'] = require('./zh_TW.json');
|
||||
stats['ar'] = {"percentDone":82};
|
||||
stats['eu'] = {"percentDone":35};
|
||||
stats['bs_BA'] = {"percentDone":85};
|
||||
stats['bg_BG'] = {"percentDone":68};
|
||||
stats['ca'] = {"percentDone":54};
|
||||
stats['ar'] = {"percentDone":80};
|
||||
stats['eu'] = {"percentDone":34};
|
||||
stats['bs_BA'] = {"percentDone":83};
|
||||
stats['bg_BG'] = {"percentDone":66};
|
||||
stats['ca'] = {"percentDone":53};
|
||||
stats['hr_HR'] = {"percentDone":28};
|
||||
stats['cs_CZ'] = {"percentDone":84};
|
||||
stats['da_DK'] = {"percentDone":76};
|
||||
stats['de_DE'] = {"percentDone":99};
|
||||
stats['et_EE'] = {"percentDone":68};
|
||||
stats['cs_CZ'] = {"percentDone":82};
|
||||
stats['da_DK'] = {"percentDone":74};
|
||||
stats['de_DE'] = {"percentDone":95};
|
||||
stats['et_EE'] = {"percentDone":66};
|
||||
stats['en_GB'] = {"percentDone":100};
|
||||
stats['en_US'] = {"percentDone":100};
|
||||
stats['es_ES'] = {"percentDone":91};
|
||||
stats['eo'] = {"percentDone":39};
|
||||
stats['fr_FR'] = {"percentDone":97};
|
||||
stats['gl_ES'] = {"percentDone":44};
|
||||
stats['id_ID'] = {"percentDone":95};
|
||||
stats['it_IT'] = {"percentDone":93};
|
||||
stats['nl_NL'] = {"percentDone":99};
|
||||
stats['nl_BE'] = {"percentDone":35};
|
||||
stats['nb_NO'] = {"percentDone":91};
|
||||
stats['fa'] = {"percentDone":34};
|
||||
stats['pl_PL'] = {"percentDone":87};
|
||||
stats['pt_PT'] = {"percentDone":91};
|
||||
stats['pt_BR'] = {"percentDone":98};
|
||||
stats['ro'] = {"percentDone":35};
|
||||
stats['sl_SI'] = {"percentDone":44};
|
||||
stats['sv'] = {"percentDone":73};
|
||||
stats['th_TH'] = {"percentDone":54};
|
||||
stats['vi'] = {"percentDone":88};
|
||||
stats['tr_TR'] = {"percentDone":99};
|
||||
stats['el_GR'] = {"percentDone":93};
|
||||
stats['ru_RU'] = {"percentDone":90};
|
||||
stats['sr_RS'] = {"percentDone":74};
|
||||
stats['zh_CN'] = {"percentDone":99};
|
||||
stats['zh_TW'] = {"percentDone":98};
|
||||
stats['ja_JP'] = {"percentDone":99};
|
||||
stats['ko'] = {"percentDone":89};
|
||||
stats['es_ES'] = {"percentDone":95};
|
||||
stats['eo'] = {"percentDone":38};
|
||||
stats['fr_FR'] = {"percentDone":94};
|
||||
stats['gl_ES'] = {"percentDone":43};
|
||||
stats['id_ID'] = {"percentDone":93};
|
||||
stats['it_IT'] = {"percentDone":91};
|
||||
stats['nl_NL'] = {"percentDone":96};
|
||||
stats['nl_BE'] = {"percentDone":34};
|
||||
stats['nb_NO'] = {"percentDone":88};
|
||||
stats['fa'] = {"percentDone":80};
|
||||
stats['pl_PL'] = {"percentDone":96};
|
||||
stats['pt_PT'] = {"percentDone":89};
|
||||
stats['pt_BR'] = {"percentDone":96};
|
||||
stats['ro'] = {"percentDone":78};
|
||||
stats['sl_SI'] = {"percentDone":42};
|
||||
stats['sv'] = {"percentDone":71};
|
||||
stats['th_TH'] = {"percentDone":52};
|
||||
stats['vi'] = {"percentDone":85};
|
||||
stats['tr_TR'] = {"percentDone":96};
|
||||
stats['el_GR'] = {"percentDone":96};
|
||||
stats['ru_RU'] = {"percentDone":95};
|
||||
stats['sr_RS'] = {"percentDone":72};
|
||||
stats['zh_CN'] = {"percentDone":96};
|
||||
stats['zh_TW'] = {"percentDone":95};
|
||||
stats['ja_JP'] = {"percentDone":96};
|
||||
stats['ko'] = {"percentDone":86};
|
||||
module.exports = { locales: locales, stats: stats };
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
20
CliClient/package-lock.json
generated
20
CliClient/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "joplin",
|
||||
"version": "1.0.166",
|
||||
"version": "1.2.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -5880,6 +5880,11 @@
|
||||
"is-fullwidth-code-point": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
@@ -6742,11 +6747,6 @@
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
|
||||
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
|
||||
},
|
||||
"unorm": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
|
||||
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA=="
|
||||
},
|
||||
"unpack-string": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz",
|
||||
@@ -6849,14 +6849,6 @@
|
||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
|
||||
},
|
||||
"uslug": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz",
|
||||
"integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=",
|
||||
"requires": {
|
||||
"unorm": ">= 1.0.0"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
|
@@ -28,7 +28,7 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "1.0.166",
|
||||
"version": "1.2.3",
|
||||
"bin": {
|
||||
"joplin": "./main.js"
|
||||
},
|
||||
@@ -109,7 +109,7 @@
|
||||
"terminal-kit": "^1.30.0",
|
||||
"tkwidgets": "^0.5.26",
|
||||
"url-parse": "^1.4.7",
|
||||
"uslug": "^1.0.4",
|
||||
"slug": "^3.3.4",
|
||||
"uuid": "^3.0.1",
|
||||
"valid-url": "^1.0.9",
|
||||
"word-wrap": "^1.2.3",
|
||||
|
@@ -4,7 +4,12 @@ require('app-module-path').addPath(__dirname);
|
||||
const filterParser = require('lib/services/searchengine/filterParser.js').default;
|
||||
// import filterParser from 'lib/services/searchengine/filterParser.js';
|
||||
|
||||
const makeTerm = (name, value, negated) => { return { name, value, negated }; };
|
||||
const makeTerm = (name, value, negated, quoted = false, wildcard = false) => {
|
||||
if (name === 'text') { return { name, value, negated, quoted, wildcard }; }
|
||||
if (name === 'title' | name === 'body') { return { name, value, negated, wildcard }; }
|
||||
return { name, value, negated };
|
||||
};
|
||||
|
||||
describe('filterParser should be correct filter for keyword', () => {
|
||||
it('title', () => {
|
||||
const searchString = 'title: something';
|
||||
@@ -65,7 +70,7 @@ describe('filterParser should be correct filter for keyword', () => {
|
||||
|
||||
it('phrase text search', () => {
|
||||
const searchString = '"scott joplin"';
|
||||
expect(filterParser(searchString)).toContain(makeTerm('text', '"scott joplin"', false));
|
||||
expect(filterParser(searchString)).toContain(makeTerm('text', '"scott joplin"', false, true));
|
||||
});
|
||||
|
||||
it('multi word body', () => {
|
||||
@@ -105,6 +110,9 @@ describe('filterParser should be correct filter for keyword', () => {
|
||||
|
||||
searchString = 'tag:bl*sphemy';
|
||||
expect(filterParser(searchString)).toContain(makeTerm('tag', 'bl%sphemy', false));
|
||||
|
||||
searchString = 'tag:"space travel"';
|
||||
expect(filterParser(searchString)).toContain(makeTerm('tag', 'space travel', false));
|
||||
});
|
||||
|
||||
it('wildcard notebooks', () => {
|
||||
|
@@ -24,7 +24,7 @@ describe('pathUtils', function() {
|
||||
['no space at the end ', 'no space at the end'],
|
||||
['nor dots...', 'nor dots'],
|
||||
[' no space before either', 'no space before either'],
|
||||
['thatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylong', 'thatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylong'],
|
||||
['thatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylong', 'thatsreallylongthatsreallylongthatsreallylongthats'],
|
||||
];
|
||||
|
||||
for (let i = 0; i < testCases.length; i++) {
|
||||
|
@@ -3,7 +3,7 @@
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||
const { asyncTest, fileContentEqual, expectNotThrow, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||
const InteropService = require('lib/services/InteropService.js');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const Note = require('lib/models/Note.js');
|
||||
@@ -442,4 +442,26 @@ describe('services_InteropService', function() {
|
||||
expect(await shim.fsDriver().exists(`${exportDir()}/testexportfolder/textexportnote2.md`)).toBe(true);
|
||||
}));
|
||||
|
||||
it('should not try to export folders with a non-existing parent', asyncTest(async () => {
|
||||
// Handles and edge case where user has a folder but this folder with a parent
|
||||
// that doesn't exist. Can happen for example in this case:
|
||||
//
|
||||
// - folder1/folder2
|
||||
// - Client 1 sync folder2, but not folder1
|
||||
// - Client 2 sync and get folder2 only
|
||||
// - Client 2 export data
|
||||
// => Crash if we don't handle this case
|
||||
|
||||
await Folder.save({ title: 'orphan', parent_id: '0c5bbd8a1b5a48189484a412a7e534cc' });
|
||||
|
||||
const service = new InteropService();
|
||||
|
||||
const result = await service.export({
|
||||
path: exportDir(),
|
||||
format: 'md',
|
||||
});
|
||||
|
||||
expect(result.warnings.length).toBe(0);
|
||||
}));
|
||||
|
||||
});
|
||||
|
@@ -115,6 +115,7 @@ describe('services_KeymapService', () => {
|
||||
{ command: 'focusElementNoteTitle', accelerator: 'Option+Shift+Cmd+T' },
|
||||
{ command: 'focusElementNoteBody', accelerator: 'Ctrl+Option+Shift+Cmd+B' },
|
||||
];
|
||||
|
||||
testCases_Darwin.forEach(({ command, accelerator }) => {
|
||||
keymapService.setAccelerator(command, accelerator);
|
||||
expect(keymapService.getAccelerator(command)).toEqual(accelerator);
|
||||
@@ -131,6 +132,7 @@ describe('services_KeymapService', () => {
|
||||
{ command: 'focusElementNoteTitle', accelerator: 'Ctrl+Alt+Shift+T' },
|
||||
{ command: 'focusElementNoteBody', accelerator: 'Ctrl+Alt+Shift+B' },
|
||||
];
|
||||
|
||||
testCases_Linux.forEach(({ command, accelerator }) => {
|
||||
keymapService.setAccelerator(command, accelerator);
|
||||
expect(keymapService.getAccelerator(command)).toEqual(accelerator);
|
||||
@@ -138,10 +140,10 @@ describe('services_KeymapService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('resetAccelerator', () => {
|
||||
describe('getDefaultAccelerator', () => {
|
||||
beforeEach(() => keymapService.initialize());
|
||||
|
||||
it('should reset the Accelerator', () => {
|
||||
it('should return the default accelerator', () => {
|
||||
const testCases = [
|
||||
{ command: 'newNote', accelerator: 'Ctrl+Alt+Shift+N' },
|
||||
{ command: 'synchronize', accelerator: null /* Disabled */ },
|
||||
@@ -154,28 +156,24 @@ describe('services_KeymapService', () => {
|
||||
];
|
||||
|
||||
testCases.forEach(({ command, accelerator }) => {
|
||||
// Remember the default Accelerator value
|
||||
const prevAccelerator = keymapService.getAccelerator(command);
|
||||
// Remember the real default Accelerator value
|
||||
const defaultAccelerator = keymapService.getAccelerator(command);
|
||||
|
||||
// Update the Accelerator,
|
||||
// Update the Accelerator and then retrieve the default accelerator
|
||||
keymapService.setAccelerator(command, accelerator);
|
||||
expect(keymapService.getAccelerator(command)).toEqual(accelerator);
|
||||
|
||||
// and then reset it..
|
||||
keymapService.resetAccelerator(command);
|
||||
expect(keymapService.getAccelerator(command)).toEqual(prevAccelerator);
|
||||
expect(keymapService.getDefaultAccelerator(command)).toEqual(defaultAccelerator);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setKeymap', () => {
|
||||
describe('overrideKeymap', () => {
|
||||
beforeEach(() => keymapService.initialize());
|
||||
|
||||
it('should update the keymap', () => {
|
||||
keymapService.initialize('darwin');
|
||||
const customKeymap_Darwin = [
|
||||
const customKeymapItems_Darwin = [
|
||||
{ command: 'newNote', accelerator: 'Option+Shift+Cmd+N' },
|
||||
{ command: 'synchronize', accelerator: 'F11' },
|
||||
{ command: 'synchronize', accelerator: 'Ctrl+F11' },
|
||||
{ command: 'textBold', accelerator: 'Shift+F5' },
|
||||
{ command: 'showLocalSearch', accelerator: 'Ctrl+Option+S' },
|
||||
{ command: 'gotoAnything', accelerator: 'Ctrl+Shift+G' },
|
||||
@@ -187,16 +185,16 @@ describe('services_KeymapService', () => {
|
||||
{ command: 'focusElementNoteList', accelerator: 'Shift+Cmd+S' /* Default of focusElementSideBar */ },
|
||||
];
|
||||
|
||||
expect(() => keymapService.setKeymap(customKeymap_Darwin)).not.toThrow();
|
||||
customKeymap_Darwin.forEach(({ command, accelerator }) => {
|
||||
expect(() => keymapService.overrideKeymap(customKeymapItems_Darwin)).not.toThrow();
|
||||
customKeymapItems_Darwin.forEach(({ command, accelerator }) => {
|
||||
// Also check if keymap is updated or not
|
||||
expect(keymapService.getAccelerator(command)).toEqual(accelerator);
|
||||
});
|
||||
|
||||
keymapService.initialize('win32');
|
||||
const customKeymap_Win32 = [
|
||||
const customKeymapItems_Win32 = [
|
||||
{ command: 'newNote', accelerator: 'Ctrl+Alt+Shift+N' },
|
||||
{ command: 'synchronize', accelerator: 'F11' },
|
||||
{ command: 'synchronize', accelerator: 'Ctrl+F11' },
|
||||
{ command: 'textBold', accelerator: 'Shift+F5' },
|
||||
{ command: 'showLocalSearch', accelerator: 'Ctrl+Alt+S' },
|
||||
{ command: 'gotoAnything', accelerator: 'Ctrl+Shift+G' },
|
||||
@@ -208,8 +206,8 @@ describe('services_KeymapService', () => {
|
||||
{ command: 'focusElementNoteList', accelerator: 'Ctrl+Shift+S' /* Default of focusElementSideBar */ },
|
||||
];
|
||||
|
||||
expect(() => keymapService.setKeymap(customKeymap_Win32)).not.toThrow();
|
||||
customKeymap_Win32.forEach(({ command, accelerator }) => {
|
||||
expect(() => keymapService.overrideKeymap(customKeymapItems_Win32)).not.toThrow();
|
||||
customKeymapItems_Win32.forEach(({ command, accelerator }) => {
|
||||
// Also check if keymap is updated or not
|
||||
expect(keymapService.getAccelerator(command)).toEqual(accelerator);
|
||||
});
|
||||
@@ -240,30 +238,30 @@ describe('services_KeymapService', () => {
|
||||
];
|
||||
|
||||
for (let i = 0; i < customKeymaps.length; i++) {
|
||||
const customKeymap = customKeymaps[i];
|
||||
expect(() => keymapService.setKeymap(customKeymap)).toThrow();
|
||||
const customKeymapItems = customKeymaps[i];
|
||||
expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw when the provided Accelerators are invalid', () => {
|
||||
// Only one test case is provided since KeymapService.validateAccelerator() is already tested
|
||||
const customKeymap = [
|
||||
const customKeymapItems = [
|
||||
{ command: 'gotoAnything', accelerator: 'Ctrl+Shift+G' },
|
||||
{ command: 'print', accelerator: 'Alt+P' },
|
||||
{ command: 'focusElementNoteTitle', accelerator: 'Ctrl+Alt+Shift+J+O+P+L+I+N' },
|
||||
];
|
||||
|
||||
expect(() => keymapService.setKeymap(customKeymap)).toThrow();
|
||||
expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
|
||||
});
|
||||
|
||||
it('should throw when the provided commands are invalid', () => {
|
||||
const customKeymap = [
|
||||
const customKeymapItems = [
|
||||
{ command: 'totallyInvalidCommand', accelerator: 'Ctrl+Shift+G' },
|
||||
{ command: 'print', accelerator: 'Alt+P' },
|
||||
{ command: 'focusElementNoteTitle', accelerator: 'Ctrl+Alt+Shift+J' },
|
||||
];
|
||||
|
||||
expect(() => keymapService.setKeymap(customKeymap)).toThrow();
|
||||
expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
|
||||
});
|
||||
|
||||
it('should throw when duplicate accelerators are provided', () => {
|
||||
@@ -281,14 +279,8 @@ describe('services_KeymapService', () => {
|
||||
];
|
||||
|
||||
for (let i = 0; i < customKeymaps_Darwin.length; i++) {
|
||||
const customKeymap = customKeymaps_Darwin[i];
|
||||
const defaultAccelerators = customKeymap.map(({ command }) => keymapService.getAccelerator(command));
|
||||
|
||||
expect(() => keymapService.setKeymap(customKeymap)).toThrow();
|
||||
// All items should be reset to default values
|
||||
for (let j = 0; j < customKeymap.length; j++) {
|
||||
expect(keymapService.getAccelerator(customKeymap[j].command)).toEqual(defaultAccelerators[j]);
|
||||
}
|
||||
const customKeymapItems = customKeymaps_Darwin[i];
|
||||
expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
|
||||
}
|
||||
|
||||
const customKeymaps_Linux = [
|
||||
@@ -305,14 +297,8 @@ describe('services_KeymapService', () => {
|
||||
];
|
||||
|
||||
for (let i = 0; i < customKeymaps_Linux.length; i++) {
|
||||
const customKeymap = customKeymaps_Linux[i];
|
||||
const defaultAccelerators = customKeymap.map(({ command }) => keymapService.getAccelerator(command));
|
||||
|
||||
expect(() => keymapService.setKeymap(customKeymap)).toThrow();
|
||||
|
||||
for (let j = 0; j < customKeymap.length; j++) {
|
||||
expect(keymapService.getAccelerator(customKeymap[j].command)).toEqual(defaultAccelerators[j]);
|
||||
}
|
||||
const customKeymapItems = customKeymaps_Linux[i];
|
||||
expect(() => keymapService.overrideKeymap(customKeymapItems)).toThrow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@@ -16,6 +16,39 @@ process.on('unhandledRejection', (reason, p) => {
|
||||
|
||||
let engine = null;
|
||||
|
||||
|
||||
const IDF = (N, n) => Math.max(Math.log((N - n + 0.5) / (n + 0.5)), 0);
|
||||
|
||||
const frequency = (word, string) => {
|
||||
const re = new RegExp(`\\b(${word})\\b`, 'g');
|
||||
return (string.match(re) || []).length;
|
||||
};
|
||||
|
||||
const calculateScore = (searchString, notes) => {
|
||||
const K1 = 1.2;
|
||||
const B = 0.75;
|
||||
|
||||
const freqTitle = notes.map(note => frequency(searchString, note.title));
|
||||
const notesWithWord = freqTitle.filter(count => count !== 0).length;
|
||||
const numTokens = notes.map(note => note.title.split(' ').length);
|
||||
const avgTokens = Math.round(numTokens.reduce((a, b) => a + b, 0) / notes.length);
|
||||
|
||||
let titleBM25 = new Array(notes.length).fill(-1);
|
||||
if (avgTokens != 0) {
|
||||
for (let i = 0; i < notes.length; i++) {
|
||||
titleBM25[i] = IDF(notes.length, notesWithWord) * ((freqTitle[i] * (K1 + 1)) / (freqTitle[i] + K1 * (1 - B + B * (numTokens[i] / avgTokens))));
|
||||
}
|
||||
}
|
||||
|
||||
const scores = [];
|
||||
for (let i = 0; i < notes.length; i++) {
|
||||
if (freqTitle[i]) scores.push(titleBM25[i]);
|
||||
}
|
||||
|
||||
scores.sort().reverse();
|
||||
return scores;
|
||||
};
|
||||
|
||||
describe('services_SearchEngine', function() {
|
||||
|
||||
beforeEach(async (done) => {
|
||||
@@ -79,17 +112,92 @@ describe('services_SearchEngine', function() {
|
||||
}));
|
||||
|
||||
|
||||
it('should order search results by relevance (1)', asyncTest(async () => {
|
||||
it('should order search results by relevance BM25', asyncTest(async () => {
|
||||
// BM25 is based on term frequency - inverse document frequency
|
||||
// The tf–idf value increases proportionally to the number of times a word appears in the document
|
||||
// and is offset by the number of documents in the corpus that contain the word, which helps to adjust
|
||||
// for the fact that some words appear more frequently in general.
|
||||
|
||||
// BM25 returns weight zero for search term which occurs in more than half the notes.
|
||||
// So terms that are abundant in all notes to have zero relevance w.r.t BM25.
|
||||
|
||||
const n1 = await Note.save({ title: 'abcd efgh' }); // 3
|
||||
const n2 = await Note.save({ title: 'abcd aaaaa abcd abcd' }); // 1
|
||||
const n2 = await Note.save({ title: 'abcd efgh abcd abcd' }); // 1
|
||||
const n3 = await Note.save({ title: 'abcd aaaaa bbbb eeee abcd' }); // 2
|
||||
const n4 = await Note.save({ title: 'xyz xyz' });
|
||||
const n5 = await Note.save({ title: 'xyz xyz xyz xyz' });
|
||||
const n6 = await Note.save({ title: 'xyz xyz xyz xyz xyz xyz' });
|
||||
const n7 = await Note.save({ title: 'xyz xyz xyz xyz xyz xyz' });
|
||||
const n8 = await Note.save({ title: 'xyz xyz xyz xyz xyz xyz xyz xyz' });
|
||||
|
||||
await engine.syncTables();
|
||||
const rows = await engine.search('abcd');
|
||||
let rows = await engine.search('abcd');
|
||||
|
||||
expect(rows[0].id).toBe(n2.id);
|
||||
expect(rows[1].id).toBe(n3.id);
|
||||
expect(rows[2].id).toBe(n1.id);
|
||||
|
||||
rows = await engine.search('abcd efgh');
|
||||
expect(rows[0].id).toBe(n1.id); // shorter note; also 'efgh' is more rare than 'abcd'.
|
||||
expect(rows[1].id).toBe(n2.id);
|
||||
}));
|
||||
|
||||
it('should correctly weigh notes using BM25', asyncTest(async () => {
|
||||
|
||||
const noteData = [
|
||||
{
|
||||
title: 'abc test2 test2',
|
||||
},
|
||||
{
|
||||
title: 'foo foo',
|
||||
},
|
||||
{
|
||||
title: 'dead beef',
|
||||
},
|
||||
{
|
||||
title: 'test2 bar',
|
||||
},
|
||||
{
|
||||
title: 'blah blah abc',
|
||||
},
|
||||
];
|
||||
|
||||
const n0 = await Note.save(noteData[0]);
|
||||
const n1 = await Note.save(noteData[1]);
|
||||
const n2 = await Note.save(noteData[2]);
|
||||
const n3 = await Note.save(noteData[3]);
|
||||
const n4 = await Note.save(noteData[4]);
|
||||
|
||||
await engine.syncTables();
|
||||
|
||||
let searchString = 'abc';
|
||||
let scores = calculateScore(searchString, noteData);
|
||||
let rows = await engine.search(searchString);
|
||||
|
||||
expect(rows[0].weight).toEqual(scores[0]);
|
||||
expect(rows[1].weight).toEqual(scores[1]);
|
||||
|
||||
// console.log(rows);
|
||||
// console.log(scores);
|
||||
|
||||
searchString = 'test2';
|
||||
scores = calculateScore(searchString, noteData);
|
||||
rows = await engine.search(searchString);
|
||||
|
||||
// console.log(rows);
|
||||
// console.log(scores);
|
||||
|
||||
expect(rows[0].weight).toEqual(scores[0]);
|
||||
expect(rows[1].weight).toEqual(scores[1]);
|
||||
|
||||
searchString = 'foo';
|
||||
scores = calculateScore(searchString, noteData);
|
||||
rows = await engine.search(searchString);
|
||||
|
||||
// console.log(rows);
|
||||
// console.log(scores);
|
||||
|
||||
expect(rows[0].weight).toEqual(scores[0]);
|
||||
}));
|
||||
|
||||
it('should tell where the results are found', asyncTest(async () => {
|
||||
@@ -118,28 +226,6 @@ describe('services_SearchEngine', function() {
|
||||
}
|
||||
}));
|
||||
|
||||
it('should order search results by relevance (2)', asyncTest(async () => {
|
||||
// 1
|
||||
const n1 = await Note.save({ title: 'abcd efgh', body: 'XX abcd XX efgh' });
|
||||
// 4
|
||||
const n2 = await Note.save({ title: 'abcd aaaaa bbbb eeee efgh' });
|
||||
// 3
|
||||
const n3 = await Note.save({ title: 'abcd aaaaa efgh' });
|
||||
// 2
|
||||
const n4 = await Note.save({ title: 'blablablabla blabla bla abcd X efgh' });
|
||||
// 5
|
||||
const n5 = await Note.save({ title: 'occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh' });
|
||||
|
||||
await engine.syncTables();
|
||||
const rows = await engine.search('abcd efgh');
|
||||
|
||||
expect(rows[0].id).toBe(n1.id);
|
||||
expect(rows[1].id).toBe(n4.id);
|
||||
expect(rows[2].id).toBe(n3.id);
|
||||
expect(rows[3].id).toBe(n2.id);
|
||||
expect(rows[4].id).toBe(n5.id);
|
||||
}));
|
||||
|
||||
it('should order search results by relevance (last updated first)', asyncTest(async () => {
|
||||
let rows;
|
||||
|
||||
@@ -340,7 +426,7 @@ describe('services_SearchEngine', function() {
|
||||
const t = testCases[i];
|
||||
const input = t[0];
|
||||
const expected = t[1];
|
||||
const actual = engine.parseQuery(input);
|
||||
const actual = await engine.parseQuery(input);
|
||||
|
||||
const _Values = actual.terms._ ? actual.terms._.map(v => v.value) : undefined;
|
||||
const titleValues = actual.terms.title ? actual.terms.title.map(v => v.value) : undefined;
|
||||
|
@@ -268,7 +268,7 @@ describe('services_SearchFilter', function() {
|
||||
|
||||
await Tag.setNoteTagsByTitles(n1.id, ['tag1', 'tag2']);
|
||||
await Tag.setNoteTagsByTitles(n2.id, ['tag2', 'tag3']);
|
||||
await Tag.setNoteTagsByTitles(n3.id, ['tag3', 'tag4']);
|
||||
await Tag.setNoteTagsByTitles(n3.id, ['tag3', 'tag4', 'space travel']);
|
||||
|
||||
await engine.syncTables();
|
||||
|
||||
@@ -304,6 +304,10 @@ describe('services_SearchFilter', function() {
|
||||
expect(rows.length).toBe(2);
|
||||
expect(ids(rows)).toContain(n1.id);
|
||||
expect(ids(rows)).toContain(n3.id);
|
||||
|
||||
rows = await engine.search('tag:"space travel"');
|
||||
expect(rows.length).toBe(1);
|
||||
expect(ids(rows)).toContain(n3.id);
|
||||
}));
|
||||
|
||||
it('should support filtering by notebook', asyncTest(async () => {
|
||||
|
163
CliClient/tests/services_SearchFuzzy.js
Normal file
163
CliClient/tests/services_SearchFuzzy.js
Normal file
@@ -0,0 +1,163 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* eslint prefer-const: 0*/
|
||||
|
||||
// require('app-module-path').addPath(__dirname);
|
||||
|
||||
// const { time } = require('lib/time-utils.js');
|
||||
// const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, asyncTest, db, synchronizer, fileApi, sleep, createNTestNotes, switchClient, createNTestFolders } = require('test-utils.js');
|
||||
// const SearchEngine = require('lib/services/searchengine/SearchEngine');
|
||||
// const Note = require('lib/models/Note');
|
||||
// const Folder = require('lib/models/Folder');
|
||||
// const Tag = require('lib/models/Tag');
|
||||
// const ItemChange = require('lib/models/ItemChange');
|
||||
// const Setting = require('lib/models/Setting');
|
||||
// const Resource = require('lib/models/Resource.js');
|
||||
// const { shim } = require('lib/shim');
|
||||
// const ResourceService = require('lib/services/ResourceService.js');
|
||||
|
||||
|
||||
// process.on('unhandledRejection', (reason, p) => {
|
||||
// console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
// });
|
||||
|
||||
// let engine = null;
|
||||
|
||||
// const ids = (array) => array.map(a => a.id);
|
||||
|
||||
// describe('services_SearchFuzzy', function() {
|
||||
// beforeEach(async (done) => {
|
||||
// await setupDatabaseAndSynchronizer(1);
|
||||
// await switchClient(1);
|
||||
|
||||
// engine = new SearchEngine();
|
||||
// engine.setDb(db());
|
||||
|
||||
// Setting.setValue('db.fuzzySearchEnabled', 1);
|
||||
// done();
|
||||
// });
|
||||
|
||||
|
||||
// it('should return note almost matching title', asyncTest(async () => {
|
||||
// let rows;
|
||||
// const n1 = await Note.save({ title: 'If It Ain\'t Baroque, Don\'t Fix It' });
|
||||
// const n2 = await Note.save({ title: 'Important note' });
|
||||
|
||||
// await engine.syncTables();
|
||||
// rows = await engine.search('Broke', { fuzzy: false });
|
||||
// expect(rows.length).toBe(0);
|
||||
|
||||
// rows = await engine.search('Broke', { fuzzy: true });
|
||||
// expect(rows.length).toBe(1);
|
||||
// expect(rows[0].id).toBe(n1.id);
|
||||
|
||||
|
||||
// rows = await engine.search('title:Broke', { fuzzy: true });
|
||||
// expect(rows.length).toBe(1);
|
||||
// expect(rows[0].id).toBe(n1.id);
|
||||
|
||||
// rows = await engine.search('title:"Broke"', { fuzzy: true });
|
||||
// expect(rows.length).toBe(1);
|
||||
// expect(rows[0].id).toBe(n1.id);
|
||||
|
||||
// rows = await engine.search('Imprtant', { fuzzy: true });
|
||||
// expect(rows.length).toBe(1);
|
||||
// expect(rows[0].id).toBe(n2.id);
|
||||
// }));
|
||||
|
||||
|
||||
// it('should order results by min fuzziness', asyncTest(async () => {
|
||||
// let rows;
|
||||
// const n1 = await Note.save({ title: 'I demand you take me to him' });
|
||||
// const n2 = await Note.save({ title: 'He demanded an answer' });
|
||||
// const n3 = await Note.save({ title: 'Don\'t you make demands of me' });
|
||||
// const n4 = await Note.save({ title: 'No drama for me' });
|
||||
// const n5 = await Note.save({ title: 'Just minding my own business' });
|
||||
|
||||
// await engine.syncTables();
|
||||
// rows = await engine.search('demand', { fuzzy: false });
|
||||
// expect(rows.length).toBe(1);
|
||||
// expect(rows[0].id).toBe(n1.id);
|
||||
|
||||
|
||||
// rows = await engine.search('demand', { fuzzy: true });
|
||||
// expect(rows.length).toBe(3);
|
||||
// expect(rows[0].id).toBe(n1.id);
|
||||
// expect(rows[1].id).toBe(n3.id);
|
||||
// expect(rows[2].id).toBe(n2.id);
|
||||
// }));
|
||||
|
||||
// it('should consider any:1', asyncTest(async () => {
|
||||
// let rows;
|
||||
// const n1 = await Note.save({ title: 'cat' });
|
||||
// const n2 = await Note.save({ title: 'cats' });
|
||||
// const n3 = await Note.save({ title: 'cot' });
|
||||
|
||||
// const n4 = await Note.save({ title: 'defenestrate' });
|
||||
// const n5 = await Note.save({ title: 'defenstrate' });
|
||||
// const n6 = await Note.save({ title: 'defenestrated' });
|
||||
|
||||
// const n7 = await Note.save({ title: 'he defenestrated the cat' });
|
||||
|
||||
// await engine.syncTables();
|
||||
|
||||
// rows = await engine.search('defenestrated cat', { fuzzy: true });
|
||||
// expect(rows.length).toBe(1);
|
||||
|
||||
// rows = await engine.search('any:1 defenestrated cat', { fuzzy: true });
|
||||
// expect(rows.length).toBe(7);
|
||||
// }));
|
||||
|
||||
// it('should leave phrase searches alone', asyncTest(async () => {
|
||||
// let rows;
|
||||
// const n1 = await Note.save({ title: 'abc def' });
|
||||
// const n2 = await Note.save({ title: 'def ghi' });
|
||||
// const n3 = await Note.save({ title: 'ghi jkl' });
|
||||
// const n4 = await Note.save({ title: 'def abc' });
|
||||
// const n5 = await Note.save({ title: 'mno pqr ghi jkl' });
|
||||
|
||||
// await engine.syncTables();
|
||||
|
||||
// rows = await engine.search('abc def', { fuzzy: true });
|
||||
// expect(rows.length).toBe(2);
|
||||
// expect(rows.map(r=>r.id)).toContain(n1.id);
|
||||
// expect(rows.map(r=>r.id)).toContain(n4.id);
|
||||
|
||||
// rows = await engine.search('"abc def"', { fuzzy: true });
|
||||
// expect(rows.length).toBe(1);
|
||||
// expect(rows.map(r=>r.id)).toContain(n1.id);
|
||||
|
||||
// rows = await engine.search('"ghi jkl"', { fuzzy: true });
|
||||
// expect(rows.length).toBe(2);
|
||||
// expect(rows.map(r=>r.id)).toContain(n3.id);
|
||||
// expect(rows.map(r=>r.id)).toContain(n5.id);
|
||||
|
||||
// rows = await engine.search('"ghi jkl" mno', { fuzzy: true });
|
||||
// expect(rows.length).toBe(1);
|
||||
// expect(rows.map(r=>r.id)).toContain(n5.id);
|
||||
|
||||
// rows = await engine.search('any:1 "ghi jkl" mno', { fuzzy: true });
|
||||
// expect(rows.length).toBe(2);
|
||||
// expect(rows.map(r=>r.id)).toContain(n3.id);
|
||||
// expect(rows.map(r=>r.id)).toContain(n5.id);
|
||||
// }));
|
||||
|
||||
// it('should leave wild card searches alone', asyncTest(async () => {
|
||||
// let rows;
|
||||
// const n1 = await Note.save({ title: 'abc def' });
|
||||
// const n2 = await Note.save({ title: 'abcc ghi' });
|
||||
// const n3 = await Note.save({ title: 'abccc ghi' });
|
||||
// const n4 = await Note.save({ title: 'abcccc ghi' });
|
||||
// const n5 = await Note.save({ title: 'wxy zzz' });
|
||||
|
||||
// await engine.syncTables();
|
||||
|
||||
// rows = await engine.search('abc*', { fuzzy: true });
|
||||
|
||||
// expect(rows.length).toBe(4);
|
||||
// expect(rows.map(r=>r.id)).toContain(n1.id);
|
||||
// expect(rows.map(r=>r.id)).toContain(n2.id);
|
||||
// expect(rows.map(r=>r.id)).toContain(n3.id);
|
||||
// expect(rows.map(r=>r.id)).toContain(n4.id);
|
||||
// }));
|
||||
|
||||
// });
|
@@ -1,5 +1,6 @@
|
||||
import LockHandler from 'lib/services/synchronizer/LockHandler';
|
||||
import MigrationHandler from 'lib/services/synchronizer/MigrationHandler';
|
||||
import { Dirnames } from 'lib/services/synchronizer/utils/types';
|
||||
|
||||
// To create a sync target snapshot for the current syncVersion:
|
||||
// - In test-utils, set syncTargetName_ to "filesystem"
|
||||
@@ -70,6 +71,14 @@ describe('synchronizer_MigrationHandler', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should init a new sync target', asyncTest(async () => {
|
||||
// Check that basic folders "locks" and "temp" are created for new sync targets.
|
||||
await migrationHandler().upgrade(1);
|
||||
const result = await fileApi().list();
|
||||
expect(result.items.filter((i:any) => i.path === Dirnames.Locks).length).toBe(1);
|
||||
expect(result.items.filter((i:any) => i.path === Dirnames.Temp).length).toBe(1);
|
||||
}), specTimeout);
|
||||
|
||||
it('should not allow syncing if the sync target is out-dated', asyncTest(async () => {
|
||||
await synchronizer().start();
|
||||
await fileApi().put('info.json', `{"version":${Setting.value('syncVersion') - 1}}`);
|
||||
|
@@ -50,6 +50,7 @@ const KeychainServiceDriver = require('lib/services/keychain/KeychainServiceDriv
|
||||
const KeychainServiceDriverDummy = require('lib/services/keychain/KeychainServiceDriver.dummy').default;
|
||||
const md5 = require('md5');
|
||||
const S3 = require('aws-sdk/clients/s3');
|
||||
const { Dirnames } = require('lib/services/synchronizer/utils/types');
|
||||
|
||||
const databases_ = [];
|
||||
let synchronizers_ = [];
|
||||
@@ -438,6 +439,7 @@ async function initFileApi() {
|
||||
|
||||
fileApi.setLogger(logger);
|
||||
fileApi.setSyncTargetId(syncTargetId_);
|
||||
fileApi.setTempDirName(Dirnames.Temp);
|
||||
fileApi.requestRepeatCount_ = isNetworkSyncTarget_ ? 1 : 0;
|
||||
|
||||
fileApis_[syncTargetId_] = fileApi;
|
||||
|
@@ -26,10 +26,11 @@ describe('timeUtils', function() {
|
||||
startDate = new Date('3 Aug 2020 07:30:20');
|
||||
expect(time.goBackInTime(startDate, 1, 'day')).toBe(endDate.getTime().toString());
|
||||
|
||||
// Note: this test randomly fails - https://github.com/laurent22/joplin/issues/3722
|
||||
|
||||
startDate = new Date('11 Aug 2020');
|
||||
endDate = new Date('9 Aug 2020'); // week start;
|
||||
expect(time.goBackInTime(startDate, 0, 'week')).toBe(endDate.getTime().toString());
|
||||
// startDate = new Date('11 Aug 2020');
|
||||
// endDate = new Date('9 Aug 2020'); // week start;
|
||||
// expect(time.goBackInTime(startDate, 0, 'week')).toBe(endDate.getTime().toString());
|
||||
|
||||
startDate = new Date('02 Feb 2020');
|
||||
endDate = new Date('01 Jan 2020');
|
||||
@@ -50,9 +51,9 @@ describe('timeUtils', function() {
|
||||
expect(time.goForwardInTime(startDate, 1, 'day')).toBe(endDate.getTime().toString());
|
||||
|
||||
|
||||
startDate = new Date('9 Aug 2020');
|
||||
endDate = new Date('9 Aug 2020'); // week start;
|
||||
expect(time.goForwardInTime(startDate, 0, 'week')).toBe(endDate.getTime().toString());
|
||||
// startDate = new Date('9 Aug 2020');
|
||||
// endDate = new Date('9 Aug 2020'); // week start;
|
||||
// expect(time.goForwardInTime(startDate, 0, 'week')).toBe(endDate.getTime().toString());
|
||||
|
||||
startDate = new Date('02 Jan 2020');
|
||||
endDate = new Date('01 Feb 2020');
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Joplin Web Clipper [DEV]",
|
||||
"version": "1.0.25",
|
||||
"version": "1.2.0",
|
||||
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
|
||||
"homepage_url": "https://joplinapp.org",
|
||||
"content_security_policy": "script-src 'self'; object-src 'self'",
|
||||
|
@@ -8,9 +8,10 @@ const { ipcMain } = require('electron');
|
||||
|
||||
class ElectronAppWrapper {
|
||||
|
||||
constructor(electronApp, env, profilePath) {
|
||||
constructor(electronApp, env, profilePath, isDebugMode) {
|
||||
this.electronApp_ = electronApp;
|
||||
this.env_ = env;
|
||||
this.isDebugMode_ = isDebugMode;
|
||||
this.profilePath_ = profilePath;
|
||||
this.win_ = null;
|
||||
this.willQuitApp_ = false;
|
||||
@@ -41,7 +42,7 @@ class ElectronAppWrapper {
|
||||
|
||||
createWindow() {
|
||||
// Set to true to view errors if the application does not start
|
||||
const debugEarlyBugs = this.env_ === 'dev';
|
||||
const debugEarlyBugs = this.env_ === 'dev' || this.isDebugMode_;
|
||||
|
||||
const windowStateKeeper = require('electron-window-state');
|
||||
|
||||
@@ -104,7 +105,17 @@ class ElectronAppWrapper {
|
||||
// Waiting for one of the ready events might work but they might not be triggered if there's an error, so
|
||||
// the easiest is to use a timeout. Keep in mind that if you get a white window on Windows it might be due
|
||||
// to this line though.
|
||||
if (debugEarlyBugs) setTimeout(() => this.win_.webContents.openDevTools(), 3000);
|
||||
if (debugEarlyBugs) {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
this.win_.webContents.openDevTools();
|
||||
} catch (error) {
|
||||
// This will throw an exception "Object has been destroyed" if the app is closed
|
||||
// in less that the timeout interval. It can be ignored.
|
||||
console.warn('Error opening dev tools', error);
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
this.win_.on('close', (event) => {
|
||||
// If it's on macOS, the app is completely closed only if the user chooses to close the app (willQuitApp_ will be true)
|
||||
|
@@ -30,20 +30,21 @@ const PluginManager = require('lib/services/PluginManager');
|
||||
const RevisionService = require('lib/services/RevisionService');
|
||||
const MigrationService = require('lib/services/MigrationService');
|
||||
const CommandService = require('lib/services/CommandService').default;
|
||||
const KeymapService = require('lib/services/KeymapService.js').default;
|
||||
const KeymapService = require('lib/services/KeymapService').default;
|
||||
const TemplateUtils = require('lib/TemplateUtils');
|
||||
const CssUtils = require('lib/CssUtils');
|
||||
const resourceEditWatcherReducer = require('lib/services/ResourceEditWatcher/reducer').default;
|
||||
// const populateDatabase = require('lib/services/debug/populateDatabase').default;
|
||||
const versionInfo = require('lib/versionInfo').default;
|
||||
|
||||
const commands = [
|
||||
require('./gui/Header/commands/focusSearch'),
|
||||
require('./gui/NoteListControls/commands/focusSearch'),
|
||||
require('./gui/MainScreen/commands/editAlarm'),
|
||||
require('./gui/MainScreen/commands/exportPdf'),
|
||||
require('./gui/MainScreen/commands/hideModalMessage'),
|
||||
require('./gui/MainScreen/commands/moveToFolder'),
|
||||
require('./gui/MainScreen/commands/newNote'),
|
||||
require('./gui/MainScreen/commands/newNotebook'),
|
||||
require('./gui/MainScreen/commands/newFolder'),
|
||||
require('./gui/MainScreen/commands/newTodo'),
|
||||
require('./gui/MainScreen/commands/print'),
|
||||
require('./gui/MainScreen/commands/renameFolder'),
|
||||
@@ -58,6 +59,7 @@ const commands = [
|
||||
require('./gui/MainScreen/commands/toggleNoteList'),
|
||||
require('./gui/MainScreen/commands/toggleSidebar'),
|
||||
require('./gui/MainScreen/commands/toggleVisiblePanes'),
|
||||
require('./gui/MainScreen/commands/toggleEditors'),
|
||||
require('./gui/NoteEditor/commands/focusElementNoteBody'),
|
||||
require('./gui/NoteEditor/commands/focusElementNoteTitle'),
|
||||
require('./gui/NoteEditor/commands/showLocalSearch'),
|
||||
@@ -98,6 +100,8 @@ const appDefaultState = Object.assign({}, defaultState, {
|
||||
watchedNoteFiles: [],
|
||||
lastEditorScrollPercents: {},
|
||||
devToolsVisible: false,
|
||||
visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
||||
focusedField: null,
|
||||
});
|
||||
|
||||
class Application extends BaseApplication {
|
||||
@@ -110,6 +114,8 @@ class Application extends BaseApplication {
|
||||
|
||||
this.commandService_commandsEnabledStateChange = this.commandService_commandsEnabledStateChange.bind(this);
|
||||
CommandService.instance().on('commandsEnabledStateChange', this.commandService_commandsEnabledStateChange);
|
||||
|
||||
KeymapService.instance().on('keymapChange', this.refreshMenu.bind(this));
|
||||
}
|
||||
|
||||
commandService_commandsEnabledStateChange() {
|
||||
@@ -277,6 +283,31 @@ class Application extends BaseApplication {
|
||||
newState.devToolsVisible = action.value;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_ADD':
|
||||
newState = Object.assign({}, state);
|
||||
newState.visibleDialogs[state.name] = true;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_REMOVE':
|
||||
newState = Object.assign({}, state);
|
||||
delete newState.visibleDialogs[state.name];
|
||||
break;
|
||||
|
||||
case 'FOCUS_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.focusedField = action.field;
|
||||
break;
|
||||
|
||||
case 'FOCUS_CLEAR':
|
||||
|
||||
// A field can only clear its own state
|
||||
if (action.field === state.focusedField) {
|
||||
newState = Object.assign({}, state);
|
||||
newState.focusedField = null;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
error.message = `In reducer: ${error.message} Action: ${JSON.stringify(action)}`;
|
||||
@@ -284,10 +315,11 @@ class Application extends BaseApplication {
|
||||
}
|
||||
|
||||
newState = resourceEditWatcherReducer(newState, action);
|
||||
newState = super.reducer(newState, action);
|
||||
|
||||
CommandService.instance().scheduleMapStateToProps(newState);
|
||||
|
||||
return super.reducer(newState, action);
|
||||
return newState;
|
||||
}
|
||||
|
||||
toggleDevTools(visible) {
|
||||
@@ -373,7 +405,7 @@ class Application extends BaseApplication {
|
||||
await this.updateMenu(screen);
|
||||
}
|
||||
|
||||
async updateMenu(screen) {
|
||||
async updateMenu(screen, updateStates = true) {
|
||||
if (this.lastMenuScreen_ === screen) return;
|
||||
|
||||
const cmdService = CommandService.instance();
|
||||
@@ -517,7 +549,7 @@ class Application extends BaseApplication {
|
||||
|
||||
const newNoteItem = cmdService.commandToMenuItem('newNote');
|
||||
const newTodoItem = cmdService.commandToMenuItem('newTodo');
|
||||
const newNotebookItem = cmdService.commandToMenuItem('newNotebook');
|
||||
const newFolderItem = cmdService.commandToMenuItem('newFolder');
|
||||
const printItem = cmdService.commandToMenuItem('print');
|
||||
|
||||
toolsItemsFirst.push(syncStatusItem, {
|
||||
@@ -569,7 +601,7 @@ class Application extends BaseApplication {
|
||||
const toolsItemsWindowsLinux = toolsItemsFirst.concat([{
|
||||
label: _('Options'),
|
||||
visible: !shim.isMac(),
|
||||
accelerator: shim.isMac() ? null : keymapService.getAccelerator('config'),
|
||||
accelerator: !shim.isMac() && keymapService.getAccelerator('config'),
|
||||
click: () => {
|
||||
this.dispatch({
|
||||
type: 'NAV_GO',
|
||||
@@ -631,7 +663,7 @@ class Application extends BaseApplication {
|
||||
}, {
|
||||
label: _('Preferences...'),
|
||||
visible: shim.isMac() ? true : false,
|
||||
accelerator: shim.isMac() ? keymapService.getAccelerator('config') : null,
|
||||
accelerator: shim.isMac() && keymapService.getAccelerator('config'),
|
||||
click: () => {
|
||||
this.dispatch({
|
||||
type: 'NAV_GO',
|
||||
@@ -648,7 +680,7 @@ class Application extends BaseApplication {
|
||||
},
|
||||
shim.isMac() ? noItem : newNoteItem,
|
||||
shim.isMac() ? noItem : newTodoItem,
|
||||
shim.isMac() ? noItem : newNotebookItem, {
|
||||
shim.isMac() ? noItem : newFolderItem, {
|
||||
type: 'separator',
|
||||
visible: shim.isMac() ? false : true,
|
||||
}, {
|
||||
@@ -663,7 +695,7 @@ class Application extends BaseApplication {
|
||||
visible: shim.isMac() ? false : true,
|
||||
submenu: importItems,
|
||||
}, {
|
||||
label: _('Export'),
|
||||
label: _('Export all'),
|
||||
visible: shim.isMac() ? false : true,
|
||||
submenu: exportItems,
|
||||
}, {
|
||||
@@ -680,7 +712,7 @@ class Application extends BaseApplication {
|
||||
}, {
|
||||
label: _('Hide %s', 'Joplin'),
|
||||
platforms: ['darwin'],
|
||||
accelerator: shim.isMac() ? keymapService.getAccelerator('hideApp') : null,
|
||||
accelerator: shim.isMac() && keymapService.getAccelerator('hideApp'),
|
||||
click: () => { bridge().electronApp().hide(); },
|
||||
}, {
|
||||
type: 'separator',
|
||||
@@ -697,10 +729,10 @@ class Application extends BaseApplication {
|
||||
submenu: [
|
||||
newNoteItem,
|
||||
newTodoItem,
|
||||
newNotebookItem, {
|
||||
newFolderItem, {
|
||||
label: _('Close Window'),
|
||||
platforms: ['darwin'],
|
||||
accelerator: shim.isMac() ? keymapService.getAccelerator('closeWindow') : null,
|
||||
accelerator: shim.isMac() && keymapService.getAccelerator('closeWindow'),
|
||||
selector: 'performClose:',
|
||||
}, {
|
||||
type: 'separator',
|
||||
@@ -736,7 +768,6 @@ class Application extends BaseApplication {
|
||||
const separator = () => {
|
||||
return {
|
||||
type: 'separator',
|
||||
screens: ['Main'],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -984,6 +1015,8 @@ class Application extends BaseApplication {
|
||||
Menu.setApplicationMenu(menu);
|
||||
|
||||
this.lastMenuScreen_ = screen;
|
||||
|
||||
if (updateStates) await this.updateMenuItemStates();
|
||||
}
|
||||
|
||||
async updateMenuItemStates(state = null) {
|
||||
@@ -1040,11 +1073,9 @@ class Application extends BaseApplication {
|
||||
// https://github.com/laurent22/joplin/issues/155
|
||||
|
||||
const css = `.CodeMirror * { font-family: ${fontFamilies.join(', ')} !important; }`;
|
||||
const ace_css = `.ace_editor * { font-family: ${fontFamilies.join(', ')} !important; }`;
|
||||
const styleTag = document.createElement('style');
|
||||
styleTag.type = 'text/css';
|
||||
styleTag.appendChild(document.createTextNode(css));
|
||||
styleTag.appendChild(document.createTextNode(ace_css));
|
||||
document.head.appendChild(styleTag);
|
||||
}
|
||||
|
||||
@@ -1074,10 +1105,16 @@ class Application extends BaseApplication {
|
||||
|
||||
argv = await super.start(argv);
|
||||
|
||||
await this.applySettingsSideEffects();
|
||||
|
||||
if (Setting.value('sync.upgradeState') === Setting.SYNC_UPGRADE_STATE_MUST_DO) {
|
||||
reg.logger().info('app.start: doing upgradeSyncTarget action');
|
||||
bridge().window().show();
|
||||
return { action: 'upgradeSyncTarget' };
|
||||
}
|
||||
|
||||
reg.logger().info('app.start: doing regular boot');
|
||||
|
||||
const dir = Setting.value('profileDir');
|
||||
|
||||
// Loads app-wide styles. (Markdown preview-specific styles loaded in app.js)
|
||||
@@ -1087,9 +1124,9 @@ class Application extends BaseApplication {
|
||||
const keymapService = KeymapService.instance();
|
||||
|
||||
try {
|
||||
await KeymapService.instance().loadKeymap(`${dir}/keymap-desktop.json`);
|
||||
await keymapService.loadCustomKeymap(`${dir}/keymap-desktop.json`);
|
||||
} catch (err) {
|
||||
bridge().showErrorMessageBox(err.message);
|
||||
reg.logger().error(err.message);
|
||||
}
|
||||
|
||||
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
||||
@@ -1122,7 +1159,7 @@ class Application extends BaseApplication {
|
||||
CommandService.instance().registerDeclaration(declaration);
|
||||
}
|
||||
|
||||
this.updateMenu('Main');
|
||||
this.updateMenu('Main', false);
|
||||
|
||||
// Since the settings need to be loaded before the store is created, it will never
|
||||
// receive the SETTING_UPDATE_ALL even, which mean state.settings will not be
|
||||
@@ -1206,7 +1243,7 @@ class Application extends BaseApplication {
|
||||
if (Setting.value('env') === 'dev') {
|
||||
AlarmService.updateAllNotifications();
|
||||
} else {
|
||||
reg.scheduleSync().then(() => {
|
||||
reg.scheduleSync(1000).then(() => {
|
||||
// Wait for the first sync before updating the notifications, since synchronisation
|
||||
// might change the notifications.
|
||||
AlarmService.updateAllNotifications();
|
||||
@@ -1237,11 +1274,18 @@ class Application extends BaseApplication {
|
||||
this.updateMenuItemStates();
|
||||
|
||||
// Make it available to the console window - useful to call revisionService.collectRevisions()
|
||||
window.revisionService = RevisionService.instance();
|
||||
window.migrationService = MigrationService.instance();
|
||||
window.decryptionWorker = DecryptionWorker.instance();
|
||||
window.joplin = () => {
|
||||
return {
|
||||
revisionService: RevisionService.instance(),
|
||||
migrationService: MigrationService.instance(),
|
||||
decryptionWorker: DecryptionWorker.instance(),
|
||||
bridge: bridge(),
|
||||
};
|
||||
};
|
||||
|
||||
bridge().addEventListener('nativeThemeUpdated', this.bridge_nativeThemeUpdated);
|
||||
|
||||
// await populateDatabase(reg.db());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
const { _, setLocale } = require('lib/locale.js');
|
||||
const { shim } = require('lib/shim');
|
||||
const { dirname, toSystemSlashes } = require('lib/path-utils.js');
|
||||
const { BrowserWindow, nativeTheme } = require('electron');
|
||||
|
||||
@@ -187,7 +188,18 @@ class Bridge {
|
||||
// to notify services and component that the app is about to close
|
||||
// but for the current use-case it's not really needed.
|
||||
const { app } = require('electron');
|
||||
app.relaunch();
|
||||
|
||||
if (shim.isPortable()) {
|
||||
const options = {
|
||||
execPath: process.env.PORTABLE_EXECUTABLE_FILE,
|
||||
};
|
||||
app.relaunch(options);
|
||||
} else if (shim.isLinux()) {
|
||||
this.showInfoMessageBox(_('The app is now going to close. Please relaunch it to complete the process.'));
|
||||
} else {
|
||||
app.relaunch();
|
||||
}
|
||||
|
||||
app.exit();
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,7 @@ interface Props {
|
||||
export const declaration:CommandDeclaration = {
|
||||
name: 'startExternalEditing',
|
||||
label: () => _('Edit in external editor'),
|
||||
iconName: 'fa-share-square',
|
||||
iconName: 'icon-share',
|
||||
};
|
||||
|
||||
export const runtime = ():CommandRuntime => {
|
||||
@@ -27,10 +27,14 @@ export const runtime = ():CommandRuntime => {
|
||||
// await comp.saveNoteAndWait(comp.formNote);
|
||||
},
|
||||
isEnabled: (props:any) => {
|
||||
if (props.routeName !== 'Main') return false;
|
||||
return !!props.noteId;
|
||||
},
|
||||
mapStateToProps: (state:any) => {
|
||||
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
|
||||
return {
|
||||
noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
|
||||
routeName: state.route.routeName,
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@@ -18,10 +18,11 @@ export const runtime = ():CommandRuntime => {
|
||||
ExternalEditWatcher.instance().stopWatching(props.noteId);
|
||||
},
|
||||
isEnabled: (props:any) => {
|
||||
if (props.routeName !== 'Main') return false;
|
||||
return !!props.noteId;
|
||||
},
|
||||
mapStateToProps: (state:any) => {
|
||||
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null };
|
||||
return { noteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null, routeName: state.route.routeName };
|
||||
},
|
||||
};
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user