You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-26 23:38:08 +02:00
Compare commits
95 Commits
v2.12.8
...
mobile_plu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6001e07cbc | ||
|
|
6210d85192 | ||
|
|
2633bcef69 | ||
|
|
772c8abdcf | ||
|
|
ac098759ea | ||
|
|
349dda30b8 | ||
|
|
cbbd9b9a61 | ||
|
|
14ef0d725b | ||
|
|
0c981ae4a7 | ||
|
|
401eee568a | ||
|
|
0b85e16125 | ||
|
|
40b89f61bd | ||
|
|
23c4020eea | ||
|
|
5ba374c03b | ||
|
|
f76ae86204 | ||
|
|
46ccd94514 | ||
|
|
7140675181 | ||
|
|
0368c26ead | ||
|
|
31f8e725dd | ||
|
|
5edbdb2466 | ||
|
|
83cf5eb617 | ||
|
|
5b0c332477 | ||
|
|
21a5feb322 | ||
|
|
16c87c36da | ||
|
|
a0ec928fca | ||
|
|
b9659bb9c1 | ||
|
|
35f375d756 | ||
|
|
04c80fe00e | ||
|
|
06732d8b8a | ||
|
|
8fc1e71fb3 | ||
|
|
aebfa6e96d | ||
|
|
3453abb670 | ||
|
|
637a0eac7f | ||
|
|
abe479d03f | ||
|
|
d1558d84b1 | ||
|
|
36e9e0a33c | ||
|
|
d78ab16021 | ||
|
|
c718706f9c | ||
|
|
f6586239c4 | ||
|
|
287d8fee73 | ||
|
|
5357b2b0dc | ||
|
|
0c4513838a | ||
|
|
d8a54da496 | ||
|
|
672ef1fd7c | ||
|
|
c50181f0a6 | ||
|
|
778f317f9f | ||
|
|
0394694a91 | ||
|
|
fec853735b | ||
|
|
087b206982 | ||
|
|
3bd04aeaf4 | ||
|
|
74e81eb6f3 | ||
|
|
3cb8fd035f | ||
|
|
0a96c3d56b | ||
|
|
2d16151fa8 | ||
|
|
93c5f6c9d3 | ||
|
|
e47985c101 | ||
|
|
1c1d20f82c | ||
|
|
880304c2fb | ||
|
|
bd3d5f213e | ||
|
|
0d6f4c9361 | ||
|
|
c49b53cb4b | ||
|
|
da177d3025 | ||
|
|
6d184fb47c | ||
|
|
3691662da2 | ||
|
|
776b6d8f12 | ||
|
|
82c33c4f0c | ||
|
|
ab77f0e0f4 | ||
|
|
df3c60e43f | ||
|
|
9aafdd2d10 | ||
|
|
1fe01dc0ce | ||
|
|
f0b5ec3e3a | ||
|
|
955f724d36 | ||
|
|
6cf0ed6166 | ||
|
|
1bcaf9d167 | ||
|
|
06b2ba9d75 | ||
|
|
85079ad213 | ||
|
|
b9225d1daa | ||
|
|
c88b6b608a | ||
|
|
56cd782175 | ||
|
|
6ce8865719 | ||
|
|
ac66332a4e | ||
|
|
c70afe3478 | ||
|
|
3c2f193714 | ||
|
|
bb9e970f8f | ||
|
|
9c8fbe831f | ||
|
|
4e1ee87269 | ||
|
|
9a32472522 | ||
|
|
1ecd6883d5 | ||
|
|
f89c6523e4 | ||
|
|
5c7b48fce1 | ||
|
|
1e2e8ed099 | ||
|
|
4d7399973e | ||
|
|
2f8275be8c | ||
|
|
58e5b83648 | ||
|
|
49e3f01a0a |
185
.eslintignore
185
.eslintignore
@@ -76,14 +76,15 @@ plugin_types/
|
||||
readme/
|
||||
packages/react-native-vosk/lib/
|
||||
packages/lib/countable/Countable.js
|
||||
packages/app-mobile/plugins
|
||||
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
packages/app-cli/app/LinkSelector.js
|
||||
packages/app-cli/app/base-command.js
|
||||
packages/app-cli/app/command-done.test.js
|
||||
packages/app-cli/app/command-e2ee.js
|
||||
packages/app-cli/app/command-mkbook.js
|
||||
packages/app-cli/app/command-mkbook.test.js
|
||||
packages/app-cli/app/command-mkbook.js
|
||||
packages/app-cli/app/command-settingschema.js
|
||||
packages/app-cli/app/command-sync.js
|
||||
packages/app-cli/app/command-testing.js
|
||||
@@ -92,6 +93,7 @@ packages/app-cli/app/services/plugins/PluginRunner.js
|
||||
packages/app-cli/app/setupCommand.js
|
||||
packages/app-cli/app/utils/testUtils.js
|
||||
packages/app-cli/tests/HtmlToMd.js
|
||||
packages/app-cli/tests/MarkupToHtml.js
|
||||
packages/app-cli/tests/MdToHtml.js
|
||||
packages/app-cli/tests/services/keychain/KeychainService.js
|
||||
packages/app-cli/tests/services/plugins/PluginService.js
|
||||
@@ -105,9 +107,9 @@ packages/app-cli/tests/testUtils.js
|
||||
packages/app-cli/tools/populateDatabase.js
|
||||
packages/app-desktop/ElectronAppWrapper.js
|
||||
packages/app-desktop/InteropServiceHelper.js
|
||||
packages/app-desktop/app.js
|
||||
packages/app-desktop/app.reducer.js
|
||||
packages/app-desktop/app.reducer.test.js
|
||||
packages/app-desktop/app.reducer.js
|
||||
packages/app-desktop/app.js
|
||||
packages/app-desktop/bridge.js
|
||||
packages/app-desktop/checkForUpdates.js
|
||||
packages/app-desktop/commands/copyDevCommand.js
|
||||
@@ -135,8 +137,8 @@ packages/app-desktop/gui/ConfigScreen/Sidebar.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.test.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js
|
||||
packages/app-desktop/gui/Dialog.js
|
||||
packages/app-desktop/gui/DialogButtonRow.js
|
||||
packages/app-desktop/gui/DialogButtonRow/useKeyboardHandler.js
|
||||
@@ -154,6 +156,7 @@ packages/app-desktop/gui/HelpButton.js
|
||||
packages/app-desktop/gui/IconButton.js
|
||||
packages/app-desktop/gui/ImportScreen.js
|
||||
packages/app-desktop/gui/ItemList.js
|
||||
packages/app-desktop/gui/JoplinCloudConfigScreen.js
|
||||
packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.js
|
||||
packages/app-desktop/gui/KeymapConfig/ShortcutRecorder.js
|
||||
packages/app-desktop/gui/KeymapConfig/styles/index.js
|
||||
@@ -217,8 +220,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.test.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useExternalPlugins.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useJoplinCommands.js
|
||||
@@ -246,11 +249,12 @@ packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/contextMenu.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/index.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/resourceHandling.test.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/resourceHandling.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useDropHandler.js
|
||||
@@ -288,17 +292,17 @@ packages/app-desktop/gui/ResizableLayout/utils/findItemByKey.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/isTempContainer.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/iterateItems.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/layoutItemProp.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/movements.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/movements.test.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/persist.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/movements.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/persist.test.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/persist.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/removeItem.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/removeKeylessItems.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/setLayoutItemProps.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/style.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/types.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.test.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useWindowResizeEvent.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/validateLayout.js
|
||||
packages/app-desktop/gui/ResourceScreen.js
|
||||
@@ -357,14 +361,14 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
||||
packages/app-desktop/services/restart.js
|
||||
packages/app-desktop/services/share/invitationRespond.js
|
||||
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
|
||||
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.test.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
@@ -379,17 +383,17 @@ packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useOnMessage.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/decoratorExtension.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.bulletedVsChecklist.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.toggleList.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownMathParser.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownMathParser.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownReformatter.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownMathParser.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownReformatter.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownReformatter.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/syntaxHighlightingLanguages.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/createEditor.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
|
||||
@@ -420,9 +424,14 @@ packages/app-mobile/components/app-nav.js
|
||||
packages/app-mobile/components/biometrics/BiometricPopup.js
|
||||
packages/app-mobile/components/biometrics/biometricAuthenticate.js
|
||||
packages/app-mobile/components/biometrics/sensorInfo.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/getResponsiveValue.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreenButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/exportAllFolders.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
|
||||
packages/app-mobile/components/screens/Note.js
|
||||
packages/app-mobile/components/screens/Notes.js
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
|
||||
@@ -435,6 +444,7 @@ packages/app-mobile/root.js
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.js
|
||||
packages/app-mobile/services/AlarmServiceDriver.ios.js
|
||||
packages/app-mobile/services/e2ee/RSA.react-native.js
|
||||
packages/app-mobile/services/plugins/PluginRunner.js
|
||||
packages/app-mobile/services/profiles/index.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.android.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.ios.js
|
||||
@@ -443,27 +453,29 @@ packages/app-mobile/tools/buildInjectedJs.js
|
||||
packages/app-mobile/utils/ShareExtension.js
|
||||
packages/app-mobile/utils/ShareUtils.js
|
||||
packages/app-mobile/utils/TlsUtils.js
|
||||
packages/app-mobile/utils/autodetectTheme.js
|
||||
packages/app-mobile/utils/checkPermissions.js
|
||||
packages/app-mobile/utils/createRootStyle.js
|
||||
packages/app-mobile/utils/debounce.js
|
||||
packages/app-mobile/utils/fs-driver-rn.js
|
||||
packages/app-mobile/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/utils/setupNotifications.js
|
||||
packages/app-mobile/utils/shareHandler.js
|
||||
packages/app-mobile/utils/types.js
|
||||
packages/fork-htmlparser2/src/CollectingHandler.js
|
||||
packages/fork-htmlparser2/src/FeedHandler.js
|
||||
packages/fork-htmlparser2/src/FeedHandler.spec.js
|
||||
packages/fork-htmlparser2/src/FeedHandler.js
|
||||
packages/fork-htmlparser2/src/MultiplexHandler.js
|
||||
packages/fork-htmlparser2/src/Parser.js
|
||||
packages/fork-htmlparser2/src/Parser.spec.js
|
||||
packages/fork-htmlparser2/src/Parser.js
|
||||
packages/fork-htmlparser2/src/Tokenizer.js
|
||||
packages/fork-htmlparser2/src/WritableStream.js
|
||||
packages/fork-htmlparser2/src/WritableStream.spec.js
|
||||
packages/fork-htmlparser2/src/WritableStream.js
|
||||
packages/fork-htmlparser2/src/__fixtures__/test-helper.js
|
||||
packages/fork-htmlparser2/src/__tests__/events.js
|
||||
packages/fork-htmlparser2/src/__tests__/stream.js
|
||||
packages/fork-htmlparser2/src/index.js
|
||||
packages/fork-htmlparser2/src/index.spec.js
|
||||
packages/fork-htmlparser2/src/index.js
|
||||
packages/generator-joplin/generators/app/templates/api/index.js
|
||||
packages/generator-joplin/generators/app/templates/api/types.js
|
||||
packages/generator-joplin/generators/app/templates/api_index.js
|
||||
@@ -476,19 +488,18 @@ packages/lib/BaseModel.js
|
||||
packages/lib/BaseSyncTarget.js
|
||||
packages/lib/ClipperServer.js
|
||||
packages/lib/CssUtils.js
|
||||
packages/lib/EventDispatcher.js
|
||||
packages/lib/EventDispatcher.test.js
|
||||
packages/lib/EventDispatcher.js
|
||||
packages/lib/HtmlToMd.js
|
||||
packages/lib/InMemoryCache.js
|
||||
packages/lib/InMemoryCache.test.js
|
||||
packages/lib/InMemoryCache.js
|
||||
packages/lib/JoplinDatabase.js
|
||||
packages/lib/JoplinError.js
|
||||
packages/lib/JoplinServerApi.js
|
||||
packages/lib/Logger.js
|
||||
packages/lib/ObjectUtils.js
|
||||
packages/lib/PoorManIntervals.js
|
||||
packages/lib/RotatingLogs.js
|
||||
packages/lib/RotatingLogs.test.js
|
||||
packages/lib/RotatingLogs.js
|
||||
packages/lib/SyncTargetJoplinCloud.js
|
||||
packages/lib/SyncTargetJoplinServer.js
|
||||
packages/lib/SyncTargetNone.js
|
||||
@@ -498,8 +509,8 @@ packages/lib/Synchronizer.js
|
||||
packages/lib/TaskQueue.js
|
||||
packages/lib/WelcomeUtils.js
|
||||
packages/lib/array.js
|
||||
packages/lib/callbackUrlUtils.js
|
||||
packages/lib/callbackUrlUtils.test.js
|
||||
packages/lib/callbackUrlUtils.js
|
||||
packages/lib/commands/historyBackward.js
|
||||
packages/lib/commands/historyForward.js
|
||||
packages/lib/commands/index.js
|
||||
@@ -527,41 +538,41 @@ packages/lib/geolocation-node.js
|
||||
packages/lib/hooks/useAsyncEffect.js
|
||||
packages/lib/hooks/useElementSize.js
|
||||
packages/lib/hooks/useEventListener.js
|
||||
packages/lib/htmlUtils.js
|
||||
packages/lib/htmlUtils.test.js
|
||||
packages/lib/htmlUtils.js
|
||||
packages/lib/htmlUtils2.test.js
|
||||
packages/lib/import-enex-md-gen.js
|
||||
packages/lib/import-enex-md-gen.test.js
|
||||
packages/lib/import-enex-md-gen.js
|
||||
packages/lib/import-enex.js
|
||||
packages/lib/locale.js
|
||||
packages/lib/locale.test.js
|
||||
packages/lib/markdownUtils.js
|
||||
packages/lib/locale.js
|
||||
packages/lib/markdownUtils.test.js
|
||||
packages/lib/markdownUtils.js
|
||||
packages/lib/markdownUtils2.test.js
|
||||
packages/lib/markupLanguageUtils.js
|
||||
packages/lib/migrations/42.js
|
||||
packages/lib/models/Alarm.js
|
||||
packages/lib/models/BaseItem.js
|
||||
packages/lib/models/Folder.js
|
||||
packages/lib/models/Folder.sharing.test.js
|
||||
packages/lib/models/Folder.test.js
|
||||
packages/lib/models/ItemChange.js
|
||||
packages/lib/models/Folder.js
|
||||
packages/lib/models/ItemChange.test.js
|
||||
packages/lib/models/MasterKey.js
|
||||
packages/lib/models/ItemChange.js
|
||||
packages/lib/models/MasterKey.test.js
|
||||
packages/lib/models/MasterKey.js
|
||||
packages/lib/models/Migration.js
|
||||
packages/lib/models/Note.js
|
||||
packages/lib/models/Note.test.js
|
||||
packages/lib/models/Note.js
|
||||
packages/lib/models/NoteResource.js
|
||||
packages/lib/models/NoteTag.js
|
||||
packages/lib/models/Resource.js
|
||||
packages/lib/models/Resource.test.js
|
||||
packages/lib/models/Resource.js
|
||||
packages/lib/models/ResourceLocalState.js
|
||||
packages/lib/models/Revision.js
|
||||
packages/lib/models/Revision.test.js
|
||||
packages/lib/models/Revision.js
|
||||
packages/lib/models/Search.js
|
||||
packages/lib/models/Setting.js
|
||||
packages/lib/models/Setting.test.js
|
||||
packages/lib/models/Setting.js
|
||||
packages/lib/models/SmartFilter.js
|
||||
packages/lib/models/Tag.js
|
||||
packages/lib/models/dateTimeFormats.test.js
|
||||
@@ -571,20 +582,20 @@ packages/lib/models/utils/paginatedFeed.js
|
||||
packages/lib/models/utils/paginationToSql.js
|
||||
packages/lib/models/utils/readOnly.js
|
||||
packages/lib/models/utils/types.js
|
||||
packages/lib/models/utils/userData.js
|
||||
packages/lib/models/utils/userData.test.js
|
||||
packages/lib/models/utils/userData.js
|
||||
packages/lib/net-utils.js
|
||||
packages/lib/ntp.js
|
||||
packages/lib/onedrive-api.js
|
||||
packages/lib/path-utils.js
|
||||
packages/lib/reducer.js
|
||||
packages/lib/registry.js
|
||||
packages/lib/registry.test.js
|
||||
packages/lib/registry.js
|
||||
packages/lib/services/AlarmService.js
|
||||
packages/lib/services/AlarmServiceDriverNode.js
|
||||
packages/lib/services/BaseService.js
|
||||
packages/lib/services/CommandService.js
|
||||
packages/lib/services/CommandService.test.js
|
||||
packages/lib/services/CommandService.js
|
||||
packages/lib/services/DecryptionWorker.js
|
||||
packages/lib/services/ExternalEditWatcher.js
|
||||
packages/lib/services/ExternalEditWatcher/utils.js
|
||||
@@ -600,14 +611,14 @@ packages/lib/services/ReportService.js
|
||||
packages/lib/services/ResourceEditWatcher/index.js
|
||||
packages/lib/services/ResourceEditWatcher/reducer.js
|
||||
packages/lib/services/ResourceFetcher.js
|
||||
packages/lib/services/ResourceService.js
|
||||
packages/lib/services/ResourceService.test.js
|
||||
packages/lib/services/RevisionService.js
|
||||
packages/lib/services/ResourceService.js
|
||||
packages/lib/services/RevisionService.test.js
|
||||
packages/lib/services/RevisionService.js
|
||||
packages/lib/services/SettingUtils.js
|
||||
packages/lib/services/UndoRedoService.js
|
||||
packages/lib/services/WhenClause.js
|
||||
packages/lib/services/WhenClause.test.js
|
||||
packages/lib/services/WhenClause.js
|
||||
packages/lib/services/commands/MenuUtils.js
|
||||
packages/lib/services/commands/ToolbarButtonUtils.js
|
||||
packages/lib/services/commands/commandsToMarkdownTable.js
|
||||
@@ -618,40 +629,40 @@ packages/lib/services/commands/stateToWhenClauseContext.js
|
||||
packages/lib/services/contextkey/contextkey.js
|
||||
packages/lib/services/database/types.js
|
||||
packages/lib/services/debug/populateDatabase.js
|
||||
packages/lib/services/e2ee/EncryptionService.js
|
||||
packages/lib/services/e2ee/EncryptionService.test.js
|
||||
packages/lib/services/e2ee/EncryptionService.js
|
||||
packages/lib/services/e2ee/RSA.node.js
|
||||
packages/lib/services/e2ee/ppk.js
|
||||
packages/lib/services/e2ee/ppk.test.js
|
||||
packages/lib/services/e2ee/ppk.js
|
||||
packages/lib/services/e2ee/ppkTestUtils.js
|
||||
packages/lib/services/e2ee/types.js
|
||||
packages/lib/services/e2ee/utils.js
|
||||
packages/lib/services/e2ee/utils.test.js
|
||||
packages/lib/services/interop/InteropService.js
|
||||
packages/lib/services/e2ee/utils.js
|
||||
packages/lib/services/interop/InteropService.test.js
|
||||
packages/lib/services/interop/InteropService.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Base.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Custom.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Html.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Html.test.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Html.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Jex.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md.test.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md_frontmatter.test.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Raw.js
|
||||
packages/lib/services/interop/InteropService_Importer_Base.js
|
||||
packages/lib/services/interop/InteropService_Importer_Custom.js
|
||||
packages/lib/services/interop/InteropService_Importer_EnexToHtml.js
|
||||
packages/lib/services/interop/InteropService_Importer_EnexToMd.js
|
||||
packages/lib/services/interop/InteropService_Importer_Jex.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md.test.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.test.js
|
||||
packages/lib/services/interop/InteropService_Importer_Raw.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Importer_Raw.test.js
|
||||
packages/lib/services/interop/Module.js
|
||||
packages/lib/services/interop/InteropService_Importer_Raw.js
|
||||
packages/lib/services/interop/Module.test.js
|
||||
packages/lib/services/interop/Module.js
|
||||
packages/lib/services/interop/types.js
|
||||
packages/lib/services/joplinServer/personalizedUserContentBaseUrl.js
|
||||
packages/lib/services/keychain/KeychainService.js
|
||||
@@ -698,23 +709,23 @@ packages/lib/services/plugins/utils/makeListener.js
|
||||
packages/lib/services/plugins/utils/manifestFromObject.js
|
||||
packages/lib/services/plugins/utils/mapEventHandlersToIds.js
|
||||
packages/lib/services/plugins/utils/types.js
|
||||
packages/lib/services/plugins/utils/validatePluginId.js
|
||||
packages/lib/services/plugins/utils/validatePluginId.test.js
|
||||
packages/lib/services/plugins/utils/validatePluginVersion.js
|
||||
packages/lib/services/plugins/utils/validatePluginId.js
|
||||
packages/lib/services/plugins/utils/validatePluginVersion.test.js
|
||||
packages/lib/services/profileConfig/index.js
|
||||
packages/lib/services/plugins/utils/validatePluginVersion.js
|
||||
packages/lib/services/profileConfig/index.test.js
|
||||
packages/lib/services/profileConfig/index.js
|
||||
packages/lib/services/profileConfig/initProfile.js
|
||||
packages/lib/services/profileConfig/mergeGlobalAndLocalSettings.js
|
||||
packages/lib/services/profileConfig/splitGlobalAndLocalSettings.js
|
||||
packages/lib/services/profileConfig/types.js
|
||||
packages/lib/services/rest/Api.js
|
||||
packages/lib/services/rest/Api.test.js
|
||||
packages/lib/services/rest/Api.js
|
||||
packages/lib/services/rest/ApiResponse.js
|
||||
packages/lib/services/rest/actionApi.desktop.js
|
||||
packages/lib/services/rest/routes/auth.js
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/events.test.js
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/master_keys.js
|
||||
packages/lib/services/rest/routes/notes.js
|
||||
@@ -732,26 +743,26 @@ packages/lib/services/rest/utils/readonlyProperties.js
|
||||
packages/lib/services/rest/utils/requestFields.js
|
||||
packages/lib/services/rest/utils/requestPaginationOptions.js
|
||||
packages/lib/services/searchengine/SearchEngine.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.test.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.js
|
||||
packages/lib/services/searchengine/SearchFilter.test.js
|
||||
packages/lib/services/searchengine/filterParser.js
|
||||
packages/lib/services/searchengine/filterParser.test.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/searchengine/filterParser.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.test.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/searchengine/queryBuilder.js
|
||||
packages/lib/services/share/ShareService.js
|
||||
packages/lib/services/share/ShareService.test.js
|
||||
packages/lib/services/share/ShareService.js
|
||||
packages/lib/services/share/reducer.js
|
||||
packages/lib/services/spellChecker/SpellCheckerService.js
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
|
||||
packages/lib/services/style/cssToTheme.js
|
||||
packages/lib/services/style/cssToTheme.test.js
|
||||
packages/lib/services/style/cssToTheme.js
|
||||
packages/lib/services/style/loadCssToTheme.js
|
||||
packages/lib/services/style/themeToCss.js
|
||||
packages/lib/services/style/themeToCss.test.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/style/themeToCss.js
|
||||
packages/lib/services/synchronizer/ItemUploader.test.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/synchronizer/LockHandler.js
|
||||
packages/lib/services/synchronizer/MigrationHandler.js
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.js
|
||||
@@ -768,8 +779,8 @@ packages/lib/services/synchronizer/migrations/1.js
|
||||
packages/lib/services/synchronizer/migrations/2.js
|
||||
packages/lib/services/synchronizer/migrations/3.js
|
||||
packages/lib/services/synchronizer/syncDebugLog.js
|
||||
packages/lib/services/synchronizer/syncInfoUtils.js
|
||||
packages/lib/services/synchronizer/syncInfoUtils.test.js
|
||||
packages/lib/services/synchronizer/syncInfoUtils.js
|
||||
packages/lib/services/synchronizer/synchronizer_LockHandler.test.js
|
||||
packages/lib/services/synchronizer/synchronizer_MigrationHandler.test.js
|
||||
packages/lib/services/synchronizer/tools.js
|
||||
@@ -795,11 +806,12 @@ packages/lib/themes/type.js
|
||||
packages/lib/time.js
|
||||
packages/lib/utils/credentialFiles.js
|
||||
packages/lib/utils/joplinCloud.js
|
||||
packages/lib/utils/webDAVUtils.js
|
||||
packages/lib/utils/userFetcher.js
|
||||
packages/lib/utils/webDAVUtils.test.js
|
||||
packages/lib/utils/webDAVUtils.js
|
||||
packages/lib/uuid.js
|
||||
packages/lib/versionInfo.js
|
||||
packages/lib/versionInfo.test.js
|
||||
packages/lib/versionInfo.js
|
||||
packages/pdf-viewer/FullViewer.js
|
||||
packages/pdf-viewer/Page.js
|
||||
packages/pdf-viewer/PdfDocument.js
|
||||
@@ -820,30 +832,31 @@ packages/pdf-viewer/ui/IconButtons.js
|
||||
packages/pdf-viewer/ui/ZoomControls.js
|
||||
packages/plugin-repo-cli/commands/updateRelease.js
|
||||
packages/plugin-repo-cli/index.js
|
||||
packages/plugin-repo-cli/lib/checkIfPluginCanBeAdded.js
|
||||
packages/plugin-repo-cli/lib/checkIfPluginCanBeAdded.test.js
|
||||
packages/plugin-repo-cli/lib/errorsHaveChanged.js
|
||||
packages/plugin-repo-cli/lib/checkIfPluginCanBeAdded.js
|
||||
packages/plugin-repo-cli/lib/errorsHaveChanged.test.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.js
|
||||
packages/plugin-repo-cli/lib/errorsHaveChanged.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js
|
||||
packages/plugin-repo-cli/lib/types.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.js
|
||||
packages/plugin-repo-cli/lib/utils.js
|
||||
packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/types.js
|
||||
packages/plugins/ToggleSidebars/src/index.js
|
||||
packages/react-native-saf-x/src/index.js
|
||||
packages/renderer/HtmlToHtml.test.js
|
||||
packages/renderer/HtmlToHtml.js
|
||||
packages/renderer/InMemoryCache.js
|
||||
packages/renderer/MarkupToHtml.js
|
||||
packages/renderer/MdToHtml.js
|
||||
packages/renderer/MdToHtml/createEventHandlingAttrs.js
|
||||
packages/renderer/MdToHtml/createEventHandlingAttrs.test.js
|
||||
packages/renderer/MdToHtml/linkReplacement.js
|
||||
packages/renderer/MdToHtml/createEventHandlingAttrs.js
|
||||
packages/renderer/MdToHtml/linkReplacement.test.js
|
||||
packages/renderer/MdToHtml/linkReplacement.js
|
||||
packages/renderer/MdToHtml/renderMedia.js
|
||||
packages/renderer/MdToHtml/rules/checkbox.js
|
||||
packages/renderer/MdToHtml/rules/code_inline.js
|
||||
@@ -862,26 +875,26 @@ packages/renderer/MdToHtml/setupLinkify.js
|
||||
packages/renderer/MdToHtml/validateLinks.js
|
||||
packages/renderer/headerAnchor.js
|
||||
packages/renderer/highlight.js
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/htmlUtils.test.js
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/index.js
|
||||
packages/renderer/noteStyle.js
|
||||
packages/renderer/pathUtils.js
|
||||
packages/renderer/utils.js
|
||||
packages/tools/build-release-stats.js
|
||||
packages/tools/build-welcome.js
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/buildServerDocker.test.js
|
||||
packages/tools/bundleDefaultPlugins.js
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/bundleDefaultPlugins.test.js
|
||||
packages/tools/bundleDefaultPlugins.js
|
||||
packages/tools/checkIgnoredFiles.js
|
||||
packages/tools/checkLibPaths.js
|
||||
packages/tools/checkLibPaths.test.js
|
||||
packages/tools/checkLibPaths.js
|
||||
packages/tools/convertThemesToCss.js
|
||||
packages/tools/generate-database-types.js
|
||||
packages/tools/generate-images.js
|
||||
packages/tools/git-changelog.js
|
||||
packages/tools/git-changelog.test.js
|
||||
packages/tools/git-changelog.js
|
||||
packages/tools/licenseChecker.js
|
||||
packages/tools/release-android.js
|
||||
packages/tools/release-cli.js
|
||||
@@ -893,8 +906,8 @@ packages/tools/setupNewRelease.js
|
||||
packages/tools/spellcheck.js
|
||||
packages/tools/tagServerLatest.js
|
||||
packages/tools/tool-utils.js
|
||||
packages/tools/update-readme-download.js
|
||||
packages/tools/update-readme-download.test.js
|
||||
packages/tools/update-readme-download.js
|
||||
packages/tools/update-readme-sponsors.js
|
||||
packages/tools/updateMarkdownDoc.js
|
||||
packages/tools/utils/discourse.js
|
||||
@@ -904,14 +917,14 @@ packages/tools/website/build.js
|
||||
packages/tools/website/buildTranslations.js
|
||||
packages/tools/website/updateDownloadPage.js
|
||||
packages/tools/website/updateNews.js
|
||||
packages/tools/website/utils/applyTranslations.js
|
||||
packages/tools/website/utils/applyTranslations.test.js
|
||||
packages/tools/website/utils/convertLinksToLocale.js
|
||||
packages/tools/website/utils/applyTranslations.js
|
||||
packages/tools/website/utils/convertLinksToLocale.test.js
|
||||
packages/tools/website/utils/convertLinksToLocale.js
|
||||
packages/tools/website/utils/frontMatter.js
|
||||
packages/tools/website/utils/news.js
|
||||
packages/tools/website/utils/openGraph.js
|
||||
packages/tools/website/utils/openGraph.test.js
|
||||
packages/tools/website/utils/openGraph.js
|
||||
packages/tools/website/utils/parser.js
|
||||
packages/tools/website/utils/pressCarousel.js
|
||||
packages/tools/website/utils/processTranslations.js
|
||||
|
||||
2
.github/workflows/github-actions-main.yml
vendored
2
.github/workflows/github-actions-main.yml
vendored
@@ -183,7 +183,7 @@ jobs:
|
||||
docker run -p 22300:22300 joplin/server:0.0.0-beta node dist/app.js --env dev &
|
||||
|
||||
# Wait for server to start
|
||||
sleep 10
|
||||
sleep 30
|
||||
|
||||
# Check if status code is correct
|
||||
# if the actual_status DOES NOT include the expected_status
|
||||
|
||||
184
.gitignore
vendored
184
.gitignore
vendored
@@ -67,8 +67,8 @@ packages/app-cli/app/LinkSelector.js
|
||||
packages/app-cli/app/base-command.js
|
||||
packages/app-cli/app/command-done.test.js
|
||||
packages/app-cli/app/command-e2ee.js
|
||||
packages/app-cli/app/command-mkbook.js
|
||||
packages/app-cli/app/command-mkbook.test.js
|
||||
packages/app-cli/app/command-mkbook.js
|
||||
packages/app-cli/app/command-settingschema.js
|
||||
packages/app-cli/app/command-sync.js
|
||||
packages/app-cli/app/command-testing.js
|
||||
@@ -77,6 +77,7 @@ packages/app-cli/app/services/plugins/PluginRunner.js
|
||||
packages/app-cli/app/setupCommand.js
|
||||
packages/app-cli/app/utils/testUtils.js
|
||||
packages/app-cli/tests/HtmlToMd.js
|
||||
packages/app-cli/tests/MarkupToHtml.js
|
||||
packages/app-cli/tests/MdToHtml.js
|
||||
packages/app-cli/tests/services/keychain/KeychainService.js
|
||||
packages/app-cli/tests/services/plugins/PluginService.js
|
||||
@@ -90,9 +91,9 @@ packages/app-cli/tests/testUtils.js
|
||||
packages/app-cli/tools/populateDatabase.js
|
||||
packages/app-desktop/ElectronAppWrapper.js
|
||||
packages/app-desktop/InteropServiceHelper.js
|
||||
packages/app-desktop/app.js
|
||||
packages/app-desktop/app.reducer.js
|
||||
packages/app-desktop/app.reducer.test.js
|
||||
packages/app-desktop/app.reducer.js
|
||||
packages/app-desktop/app.js
|
||||
packages/app-desktop/bridge.js
|
||||
packages/app-desktop/checkForUpdates.js
|
||||
packages/app-desktop/commands/copyDevCommand.js
|
||||
@@ -120,8 +121,8 @@ packages/app-desktop/gui/ConfigScreen/Sidebar.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.test.js
|
||||
packages/app-desktop/gui/ConfigScreen/controls/plugins/useOnInstallHandler.js
|
||||
packages/app-desktop/gui/Dialog.js
|
||||
packages/app-desktop/gui/DialogButtonRow.js
|
||||
packages/app-desktop/gui/DialogButtonRow/useKeyboardHandler.js
|
||||
@@ -139,6 +140,7 @@ packages/app-desktop/gui/HelpButton.js
|
||||
packages/app-desktop/gui/IconButton.js
|
||||
packages/app-desktop/gui/ImportScreen.js
|
||||
packages/app-desktop/gui/ItemList.js
|
||||
packages/app-desktop/gui/JoplinCloudConfigScreen.js
|
||||
packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.js
|
||||
packages/app-desktop/gui/KeymapConfig/ShortcutRecorder.js
|
||||
packages/app-desktop/gui/KeymapConfig/styles/index.js
|
||||
@@ -202,8 +204,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.test.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useCursorUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useExternalPlugins.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useJoplinCommands.js
|
||||
@@ -231,11 +233,12 @@ packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||
packages/app-desktop/gui/NoteEditor/commands/showRevisions.js
|
||||
packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.js
|
||||
packages/app-desktop/gui/NoteEditor/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/contextMenu.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/contextMenuUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/index.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/resourceHandling.test.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/resourceHandling.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/types.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useDropHandler.js
|
||||
@@ -273,17 +276,17 @@ packages/app-desktop/gui/ResizableLayout/utils/findItemByKey.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/isTempContainer.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/iterateItems.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/layoutItemProp.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/movements.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/movements.test.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/persist.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/movements.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/persist.test.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/persist.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/removeItem.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/removeKeylessItems.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/setLayoutItemProps.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/style.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/types.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.test.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/useWindowResizeEvent.js
|
||||
packages/app-desktop/gui/ResizableLayout/utils/validateLayout.js
|
||||
packages/app-desktop/gui/ResourceScreen.js
|
||||
@@ -342,14 +345,14 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
||||
packages/app-desktop/services/restart.js
|
||||
packages/app-desktop/services/share/invitationRespond.js
|
||||
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
|
||||
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.test.js
|
||||
packages/app-desktop/utils/checkForUpdatesUtils.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
@@ -364,17 +367,17 @@ packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useOnMessage.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/CodeMirror.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/decoratorExtension.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.bulletedVsChecklist.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.toggleList.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownMathParser.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownCommands.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownMathParser.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownReformatter.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownMathParser.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownReformatter.test.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/markdownReformatter.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/syntaxHighlightingLanguages.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/createEditor.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
|
||||
@@ -405,9 +408,14 @@ packages/app-mobile/components/app-nav.js
|
||||
packages/app-mobile/components/biometrics/BiometricPopup.js
|
||||
packages/app-mobile/components/biometrics/biometricAuthenticate.js
|
||||
packages/app-mobile/components/biometrics/sensorInfo.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/getResponsiveValue.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen.js
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/ConfigScreenButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/exportAllFolders.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
|
||||
packages/app-mobile/components/screens/Note.js
|
||||
packages/app-mobile/components/screens/Notes.js
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
|
||||
@@ -420,6 +428,7 @@ packages/app-mobile/root.js
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.js
|
||||
packages/app-mobile/services/AlarmServiceDriver.ios.js
|
||||
packages/app-mobile/services/e2ee/RSA.react-native.js
|
||||
packages/app-mobile/services/plugins/PluginRunner.js
|
||||
packages/app-mobile/services/profiles/index.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.android.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.ios.js
|
||||
@@ -428,27 +437,29 @@ packages/app-mobile/tools/buildInjectedJs.js
|
||||
packages/app-mobile/utils/ShareExtension.js
|
||||
packages/app-mobile/utils/ShareUtils.js
|
||||
packages/app-mobile/utils/TlsUtils.js
|
||||
packages/app-mobile/utils/autodetectTheme.js
|
||||
packages/app-mobile/utils/checkPermissions.js
|
||||
packages/app-mobile/utils/createRootStyle.js
|
||||
packages/app-mobile/utils/debounce.js
|
||||
packages/app-mobile/utils/fs-driver-rn.js
|
||||
packages/app-mobile/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/utils/setupNotifications.js
|
||||
packages/app-mobile/utils/shareHandler.js
|
||||
packages/app-mobile/utils/types.js
|
||||
packages/fork-htmlparser2/src/CollectingHandler.js
|
||||
packages/fork-htmlparser2/src/FeedHandler.js
|
||||
packages/fork-htmlparser2/src/FeedHandler.spec.js
|
||||
packages/fork-htmlparser2/src/FeedHandler.js
|
||||
packages/fork-htmlparser2/src/MultiplexHandler.js
|
||||
packages/fork-htmlparser2/src/Parser.js
|
||||
packages/fork-htmlparser2/src/Parser.spec.js
|
||||
packages/fork-htmlparser2/src/Parser.js
|
||||
packages/fork-htmlparser2/src/Tokenizer.js
|
||||
packages/fork-htmlparser2/src/WritableStream.js
|
||||
packages/fork-htmlparser2/src/WritableStream.spec.js
|
||||
packages/fork-htmlparser2/src/WritableStream.js
|
||||
packages/fork-htmlparser2/src/__fixtures__/test-helper.js
|
||||
packages/fork-htmlparser2/src/__tests__/events.js
|
||||
packages/fork-htmlparser2/src/__tests__/stream.js
|
||||
packages/fork-htmlparser2/src/index.js
|
||||
packages/fork-htmlparser2/src/index.spec.js
|
||||
packages/fork-htmlparser2/src/index.js
|
||||
packages/generator-joplin/generators/app/templates/api/index.js
|
||||
packages/generator-joplin/generators/app/templates/api/types.js
|
||||
packages/generator-joplin/generators/app/templates/api_index.js
|
||||
@@ -461,19 +472,18 @@ packages/lib/BaseModel.js
|
||||
packages/lib/BaseSyncTarget.js
|
||||
packages/lib/ClipperServer.js
|
||||
packages/lib/CssUtils.js
|
||||
packages/lib/EventDispatcher.js
|
||||
packages/lib/EventDispatcher.test.js
|
||||
packages/lib/EventDispatcher.js
|
||||
packages/lib/HtmlToMd.js
|
||||
packages/lib/InMemoryCache.js
|
||||
packages/lib/InMemoryCache.test.js
|
||||
packages/lib/InMemoryCache.js
|
||||
packages/lib/JoplinDatabase.js
|
||||
packages/lib/JoplinError.js
|
||||
packages/lib/JoplinServerApi.js
|
||||
packages/lib/Logger.js
|
||||
packages/lib/ObjectUtils.js
|
||||
packages/lib/PoorManIntervals.js
|
||||
packages/lib/RotatingLogs.js
|
||||
packages/lib/RotatingLogs.test.js
|
||||
packages/lib/RotatingLogs.js
|
||||
packages/lib/SyncTargetJoplinCloud.js
|
||||
packages/lib/SyncTargetJoplinServer.js
|
||||
packages/lib/SyncTargetNone.js
|
||||
@@ -483,8 +493,8 @@ packages/lib/Synchronizer.js
|
||||
packages/lib/TaskQueue.js
|
||||
packages/lib/WelcomeUtils.js
|
||||
packages/lib/array.js
|
||||
packages/lib/callbackUrlUtils.js
|
||||
packages/lib/callbackUrlUtils.test.js
|
||||
packages/lib/callbackUrlUtils.js
|
||||
packages/lib/commands/historyBackward.js
|
||||
packages/lib/commands/historyForward.js
|
||||
packages/lib/commands/index.js
|
||||
@@ -512,41 +522,41 @@ packages/lib/geolocation-node.js
|
||||
packages/lib/hooks/useAsyncEffect.js
|
||||
packages/lib/hooks/useElementSize.js
|
||||
packages/lib/hooks/useEventListener.js
|
||||
packages/lib/htmlUtils.js
|
||||
packages/lib/htmlUtils.test.js
|
||||
packages/lib/htmlUtils.js
|
||||
packages/lib/htmlUtils2.test.js
|
||||
packages/lib/import-enex-md-gen.js
|
||||
packages/lib/import-enex-md-gen.test.js
|
||||
packages/lib/import-enex-md-gen.js
|
||||
packages/lib/import-enex.js
|
||||
packages/lib/locale.js
|
||||
packages/lib/locale.test.js
|
||||
packages/lib/markdownUtils.js
|
||||
packages/lib/locale.js
|
||||
packages/lib/markdownUtils.test.js
|
||||
packages/lib/markdownUtils.js
|
||||
packages/lib/markdownUtils2.test.js
|
||||
packages/lib/markupLanguageUtils.js
|
||||
packages/lib/migrations/42.js
|
||||
packages/lib/models/Alarm.js
|
||||
packages/lib/models/BaseItem.js
|
||||
packages/lib/models/Folder.js
|
||||
packages/lib/models/Folder.sharing.test.js
|
||||
packages/lib/models/Folder.test.js
|
||||
packages/lib/models/ItemChange.js
|
||||
packages/lib/models/Folder.js
|
||||
packages/lib/models/ItemChange.test.js
|
||||
packages/lib/models/MasterKey.js
|
||||
packages/lib/models/ItemChange.js
|
||||
packages/lib/models/MasterKey.test.js
|
||||
packages/lib/models/MasterKey.js
|
||||
packages/lib/models/Migration.js
|
||||
packages/lib/models/Note.js
|
||||
packages/lib/models/Note.test.js
|
||||
packages/lib/models/Note.js
|
||||
packages/lib/models/NoteResource.js
|
||||
packages/lib/models/NoteTag.js
|
||||
packages/lib/models/Resource.js
|
||||
packages/lib/models/Resource.test.js
|
||||
packages/lib/models/Resource.js
|
||||
packages/lib/models/ResourceLocalState.js
|
||||
packages/lib/models/Revision.js
|
||||
packages/lib/models/Revision.test.js
|
||||
packages/lib/models/Revision.js
|
||||
packages/lib/models/Search.js
|
||||
packages/lib/models/Setting.js
|
||||
packages/lib/models/Setting.test.js
|
||||
packages/lib/models/Setting.js
|
||||
packages/lib/models/SmartFilter.js
|
||||
packages/lib/models/Tag.js
|
||||
packages/lib/models/dateTimeFormats.test.js
|
||||
@@ -556,20 +566,20 @@ packages/lib/models/utils/paginatedFeed.js
|
||||
packages/lib/models/utils/paginationToSql.js
|
||||
packages/lib/models/utils/readOnly.js
|
||||
packages/lib/models/utils/types.js
|
||||
packages/lib/models/utils/userData.js
|
||||
packages/lib/models/utils/userData.test.js
|
||||
packages/lib/models/utils/userData.js
|
||||
packages/lib/net-utils.js
|
||||
packages/lib/ntp.js
|
||||
packages/lib/onedrive-api.js
|
||||
packages/lib/path-utils.js
|
||||
packages/lib/reducer.js
|
||||
packages/lib/registry.js
|
||||
packages/lib/registry.test.js
|
||||
packages/lib/registry.js
|
||||
packages/lib/services/AlarmService.js
|
||||
packages/lib/services/AlarmServiceDriverNode.js
|
||||
packages/lib/services/BaseService.js
|
||||
packages/lib/services/CommandService.js
|
||||
packages/lib/services/CommandService.test.js
|
||||
packages/lib/services/CommandService.js
|
||||
packages/lib/services/DecryptionWorker.js
|
||||
packages/lib/services/ExternalEditWatcher.js
|
||||
packages/lib/services/ExternalEditWatcher/utils.js
|
||||
@@ -585,14 +595,14 @@ packages/lib/services/ReportService.js
|
||||
packages/lib/services/ResourceEditWatcher/index.js
|
||||
packages/lib/services/ResourceEditWatcher/reducer.js
|
||||
packages/lib/services/ResourceFetcher.js
|
||||
packages/lib/services/ResourceService.js
|
||||
packages/lib/services/ResourceService.test.js
|
||||
packages/lib/services/RevisionService.js
|
||||
packages/lib/services/ResourceService.js
|
||||
packages/lib/services/RevisionService.test.js
|
||||
packages/lib/services/RevisionService.js
|
||||
packages/lib/services/SettingUtils.js
|
||||
packages/lib/services/UndoRedoService.js
|
||||
packages/lib/services/WhenClause.js
|
||||
packages/lib/services/WhenClause.test.js
|
||||
packages/lib/services/WhenClause.js
|
||||
packages/lib/services/commands/MenuUtils.js
|
||||
packages/lib/services/commands/ToolbarButtonUtils.js
|
||||
packages/lib/services/commands/commandsToMarkdownTable.js
|
||||
@@ -603,40 +613,40 @@ packages/lib/services/commands/stateToWhenClauseContext.js
|
||||
packages/lib/services/contextkey/contextkey.js
|
||||
packages/lib/services/database/types.js
|
||||
packages/lib/services/debug/populateDatabase.js
|
||||
packages/lib/services/e2ee/EncryptionService.js
|
||||
packages/lib/services/e2ee/EncryptionService.test.js
|
||||
packages/lib/services/e2ee/EncryptionService.js
|
||||
packages/lib/services/e2ee/RSA.node.js
|
||||
packages/lib/services/e2ee/ppk.js
|
||||
packages/lib/services/e2ee/ppk.test.js
|
||||
packages/lib/services/e2ee/ppk.js
|
||||
packages/lib/services/e2ee/ppkTestUtils.js
|
||||
packages/lib/services/e2ee/types.js
|
||||
packages/lib/services/e2ee/utils.js
|
||||
packages/lib/services/e2ee/utils.test.js
|
||||
packages/lib/services/interop/InteropService.js
|
||||
packages/lib/services/e2ee/utils.js
|
||||
packages/lib/services/interop/InteropService.test.js
|
||||
packages/lib/services/interop/InteropService.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Base.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Custom.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Html.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Html.test.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Html.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Jex.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md.test.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md_frontmatter.test.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Exporter_Raw.js
|
||||
packages/lib/services/interop/InteropService_Importer_Base.js
|
||||
packages/lib/services/interop/InteropService_Importer_Custom.js
|
||||
packages/lib/services/interop/InteropService_Importer_EnexToHtml.js
|
||||
packages/lib/services/interop/InteropService_Importer_EnexToMd.js
|
||||
packages/lib/services/interop/InteropService_Importer_Jex.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md.test.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.test.js
|
||||
packages/lib/services/interop/InteropService_Importer_Raw.js
|
||||
packages/lib/services/interop/InteropService_Importer_Md_frontmatter.js
|
||||
packages/lib/services/interop/InteropService_Importer_Raw.test.js
|
||||
packages/lib/services/interop/Module.js
|
||||
packages/lib/services/interop/InteropService_Importer_Raw.js
|
||||
packages/lib/services/interop/Module.test.js
|
||||
packages/lib/services/interop/Module.js
|
||||
packages/lib/services/interop/types.js
|
||||
packages/lib/services/joplinServer/personalizedUserContentBaseUrl.js
|
||||
packages/lib/services/keychain/KeychainService.js
|
||||
@@ -683,23 +693,23 @@ packages/lib/services/plugins/utils/makeListener.js
|
||||
packages/lib/services/plugins/utils/manifestFromObject.js
|
||||
packages/lib/services/plugins/utils/mapEventHandlersToIds.js
|
||||
packages/lib/services/plugins/utils/types.js
|
||||
packages/lib/services/plugins/utils/validatePluginId.js
|
||||
packages/lib/services/plugins/utils/validatePluginId.test.js
|
||||
packages/lib/services/plugins/utils/validatePluginVersion.js
|
||||
packages/lib/services/plugins/utils/validatePluginId.js
|
||||
packages/lib/services/plugins/utils/validatePluginVersion.test.js
|
||||
packages/lib/services/profileConfig/index.js
|
||||
packages/lib/services/plugins/utils/validatePluginVersion.js
|
||||
packages/lib/services/profileConfig/index.test.js
|
||||
packages/lib/services/profileConfig/index.js
|
||||
packages/lib/services/profileConfig/initProfile.js
|
||||
packages/lib/services/profileConfig/mergeGlobalAndLocalSettings.js
|
||||
packages/lib/services/profileConfig/splitGlobalAndLocalSettings.js
|
||||
packages/lib/services/profileConfig/types.js
|
||||
packages/lib/services/rest/Api.js
|
||||
packages/lib/services/rest/Api.test.js
|
||||
packages/lib/services/rest/Api.js
|
||||
packages/lib/services/rest/ApiResponse.js
|
||||
packages/lib/services/rest/actionApi.desktop.js
|
||||
packages/lib/services/rest/routes/auth.js
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/events.test.js
|
||||
packages/lib/services/rest/routes/events.js
|
||||
packages/lib/services/rest/routes/folders.js
|
||||
packages/lib/services/rest/routes/master_keys.js
|
||||
packages/lib/services/rest/routes/notes.js
|
||||
@@ -717,26 +727,26 @@ packages/lib/services/rest/utils/readonlyProperties.js
|
||||
packages/lib/services/rest/utils/requestFields.js
|
||||
packages/lib/services/rest/utils/requestPaginationOptions.js
|
||||
packages/lib/services/searchengine/SearchEngine.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.test.js
|
||||
packages/lib/services/searchengine/SearchEngineUtils.js
|
||||
packages/lib/services/searchengine/SearchFilter.test.js
|
||||
packages/lib/services/searchengine/filterParser.js
|
||||
packages/lib/services/searchengine/filterParser.test.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/searchengine/filterParser.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.test.js
|
||||
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
|
||||
packages/lib/services/searchengine/queryBuilder.js
|
||||
packages/lib/services/share/ShareService.js
|
||||
packages/lib/services/share/ShareService.test.js
|
||||
packages/lib/services/share/ShareService.js
|
||||
packages/lib/services/share/reducer.js
|
||||
packages/lib/services/spellChecker/SpellCheckerService.js
|
||||
packages/lib/services/spellChecker/SpellCheckerServiceDriverBase.js
|
||||
packages/lib/services/style/cssToTheme.js
|
||||
packages/lib/services/style/cssToTheme.test.js
|
||||
packages/lib/services/style/cssToTheme.js
|
||||
packages/lib/services/style/loadCssToTheme.js
|
||||
packages/lib/services/style/themeToCss.js
|
||||
packages/lib/services/style/themeToCss.test.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/style/themeToCss.js
|
||||
packages/lib/services/synchronizer/ItemUploader.test.js
|
||||
packages/lib/services/synchronizer/ItemUploader.js
|
||||
packages/lib/services/synchronizer/LockHandler.js
|
||||
packages/lib/services/synchronizer/MigrationHandler.js
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.js
|
||||
@@ -753,8 +763,8 @@ packages/lib/services/synchronizer/migrations/1.js
|
||||
packages/lib/services/synchronizer/migrations/2.js
|
||||
packages/lib/services/synchronizer/migrations/3.js
|
||||
packages/lib/services/synchronizer/syncDebugLog.js
|
||||
packages/lib/services/synchronizer/syncInfoUtils.js
|
||||
packages/lib/services/synchronizer/syncInfoUtils.test.js
|
||||
packages/lib/services/synchronizer/syncInfoUtils.js
|
||||
packages/lib/services/synchronizer/synchronizer_LockHandler.test.js
|
||||
packages/lib/services/synchronizer/synchronizer_MigrationHandler.test.js
|
||||
packages/lib/services/synchronizer/tools.js
|
||||
@@ -780,11 +790,12 @@ packages/lib/themes/type.js
|
||||
packages/lib/time.js
|
||||
packages/lib/utils/credentialFiles.js
|
||||
packages/lib/utils/joplinCloud.js
|
||||
packages/lib/utils/webDAVUtils.js
|
||||
packages/lib/utils/userFetcher.js
|
||||
packages/lib/utils/webDAVUtils.test.js
|
||||
packages/lib/utils/webDAVUtils.js
|
||||
packages/lib/uuid.js
|
||||
packages/lib/versionInfo.js
|
||||
packages/lib/versionInfo.test.js
|
||||
packages/lib/versionInfo.js
|
||||
packages/pdf-viewer/FullViewer.js
|
||||
packages/pdf-viewer/Page.js
|
||||
packages/pdf-viewer/PdfDocument.js
|
||||
@@ -805,30 +816,31 @@ packages/pdf-viewer/ui/IconButtons.js
|
||||
packages/pdf-viewer/ui/ZoomControls.js
|
||||
packages/plugin-repo-cli/commands/updateRelease.js
|
||||
packages/plugin-repo-cli/index.js
|
||||
packages/plugin-repo-cli/lib/checkIfPluginCanBeAdded.js
|
||||
packages/plugin-repo-cli/lib/checkIfPluginCanBeAdded.test.js
|
||||
packages/plugin-repo-cli/lib/errorsHaveChanged.js
|
||||
packages/plugin-repo-cli/lib/checkIfPluginCanBeAdded.js
|
||||
packages/plugin-repo-cli/lib/errorsHaveChanged.test.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.js
|
||||
packages/plugin-repo-cli/lib/errorsHaveChanged.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.test.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js
|
||||
packages/plugin-repo-cli/lib/gitCompareUrl.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.test.js
|
||||
packages/plugin-repo-cli/lib/overrideUtils.js
|
||||
packages/plugin-repo-cli/lib/types.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.test.js
|
||||
packages/plugin-repo-cli/lib/updateReadme.js
|
||||
packages/plugin-repo-cli/lib/utils.js
|
||||
packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/types.js
|
||||
packages/plugins/ToggleSidebars/src/index.js
|
||||
packages/react-native-saf-x/src/index.js
|
||||
packages/renderer/HtmlToHtml.test.js
|
||||
packages/renderer/HtmlToHtml.js
|
||||
packages/renderer/InMemoryCache.js
|
||||
packages/renderer/MarkupToHtml.js
|
||||
packages/renderer/MdToHtml.js
|
||||
packages/renderer/MdToHtml/createEventHandlingAttrs.js
|
||||
packages/renderer/MdToHtml/createEventHandlingAttrs.test.js
|
||||
packages/renderer/MdToHtml/linkReplacement.js
|
||||
packages/renderer/MdToHtml/createEventHandlingAttrs.js
|
||||
packages/renderer/MdToHtml/linkReplacement.test.js
|
||||
packages/renderer/MdToHtml/linkReplacement.js
|
||||
packages/renderer/MdToHtml/renderMedia.js
|
||||
packages/renderer/MdToHtml/rules/checkbox.js
|
||||
packages/renderer/MdToHtml/rules/code_inline.js
|
||||
@@ -847,26 +859,26 @@ packages/renderer/MdToHtml/setupLinkify.js
|
||||
packages/renderer/MdToHtml/validateLinks.js
|
||||
packages/renderer/headerAnchor.js
|
||||
packages/renderer/highlight.js
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/htmlUtils.test.js
|
||||
packages/renderer/htmlUtils.js
|
||||
packages/renderer/index.js
|
||||
packages/renderer/noteStyle.js
|
||||
packages/renderer/pathUtils.js
|
||||
packages/renderer/utils.js
|
||||
packages/tools/build-release-stats.js
|
||||
packages/tools/build-welcome.js
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/buildServerDocker.test.js
|
||||
packages/tools/bundleDefaultPlugins.js
|
||||
packages/tools/buildServerDocker.js
|
||||
packages/tools/bundleDefaultPlugins.test.js
|
||||
packages/tools/bundleDefaultPlugins.js
|
||||
packages/tools/checkIgnoredFiles.js
|
||||
packages/tools/checkLibPaths.js
|
||||
packages/tools/checkLibPaths.test.js
|
||||
packages/tools/checkLibPaths.js
|
||||
packages/tools/convertThemesToCss.js
|
||||
packages/tools/generate-database-types.js
|
||||
packages/tools/generate-images.js
|
||||
packages/tools/git-changelog.js
|
||||
packages/tools/git-changelog.test.js
|
||||
packages/tools/git-changelog.js
|
||||
packages/tools/licenseChecker.js
|
||||
packages/tools/release-android.js
|
||||
packages/tools/release-cli.js
|
||||
@@ -878,8 +890,8 @@ packages/tools/setupNewRelease.js
|
||||
packages/tools/spellcheck.js
|
||||
packages/tools/tagServerLatest.js
|
||||
packages/tools/tool-utils.js
|
||||
packages/tools/update-readme-download.js
|
||||
packages/tools/update-readme-download.test.js
|
||||
packages/tools/update-readme-download.js
|
||||
packages/tools/update-readme-sponsors.js
|
||||
packages/tools/updateMarkdownDoc.js
|
||||
packages/tools/utils/discourse.js
|
||||
@@ -889,14 +901,14 @@ packages/tools/website/build.js
|
||||
packages/tools/website/buildTranslations.js
|
||||
packages/tools/website/updateDownloadPage.js
|
||||
packages/tools/website/updateNews.js
|
||||
packages/tools/website/utils/applyTranslations.js
|
||||
packages/tools/website/utils/applyTranslations.test.js
|
||||
packages/tools/website/utils/convertLinksToLocale.js
|
||||
packages/tools/website/utils/applyTranslations.js
|
||||
packages/tools/website/utils/convertLinksToLocale.test.js
|
||||
packages/tools/website/utils/convertLinksToLocale.js
|
||||
packages/tools/website/utils/frontMatter.js
|
||||
packages/tools/website/utils/news.js
|
||||
packages/tools/website/utils/openGraph.js
|
||||
packages/tools/website/utils/openGraph.test.js
|
||||
packages/tools/website/utils/openGraph.js
|
||||
packages/tools/website/utils/parser.js
|
||||
packages/tools/website/utils/pressCarousel.js
|
||||
packages/tools/website/utils/processTranslations.js
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
|
||||
index 0f52b73c61625db2a3081c0950b6bdd2b06e3d40..b0fc3de4be0b3a26b638683613c63c783c2739bb 100644
|
||||
--- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
|
||||
+++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
|
||||
@@ -38,7 +38,7 @@ import com.facebook.react.uimanager.common.ViewUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
-import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
+import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -151,7 +151,10 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
}
|
||||
|
||||
private class ConcurrentOperationQueue {
|
||||
- private final Queue<UIThreadOperation> mQueue = new ConcurrentLinkedQueue<>();
|
||||
+ // Patch: Use LinkedBlockingQueue instead of ConcurrentLinkedQueue.
|
||||
+ // In some versions of Android, ConcurrentLinkedQueue is known to drop
|
||||
+ // items, causing crashing. See https://github.com/laurent22/joplin/issues/8425
|
||||
+ private final Queue<UIThreadOperation> mQueue = new LinkedBlockingQueue<>();
|
||||
@Nullable private UIThreadOperation mPeekedOperation = null;
|
||||
|
||||
@AnyThread
|
||||
@@ -0,0 +1,27 @@
|
||||
diff --git a/android/src/main/java/com/swmansion/reanimated/NodesManager.java b/android/src/main/java/com/swmansion/reanimated/NodesManager.java
|
||||
index e974f8eb827a35be4d7e5fa9b096af9387c595dd..bc9e5ff566c9484274e8eacefc88327a5ff30def 100644
|
||||
--- a/android/src/main/java/com/swmansion/reanimated/NodesManager.java
|
||||
+++ b/android/src/main/java/com/swmansion/reanimated/NodesManager.java
|
||||
@@ -34,7 +34,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
-import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
+import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -80,7 +80,12 @@ public class NodesManager implements EventDispatcherListener {
|
||||
private ReactApplicationContext mReactApplicationContext;
|
||||
private RCTEventEmitter mCustomEventHandler;
|
||||
private List<OnAnimationFrame> mFrameCallbacks = new ArrayList<>();
|
||||
- private ConcurrentLinkedQueue<CopiedEvent> mEventQueue = new ConcurrentLinkedQueue<>();
|
||||
+
|
||||
+ // Patch: On some versions of Android, ConcurrentLinkedQueue is known to
|
||||
+ // drop items. LinkedBlockingQueue is a potentially-slower alternative that
|
||||
+ // should not drop items.
|
||||
+ // See https://github.com/laurent22/joplin/issues/8425
|
||||
+ private LinkedBlockingQueue<CopiedEvent> mEventQueue = new LinkedBlockingQueue<>();
|
||||
public double currentFrameTimeMs;
|
||||
public Set<String> uiProps = Collections.emptySet();
|
||||
public Set<String> nativeProps = Collections.emptySet();
|
||||
@@ -24,3 +24,9 @@ logFilters:
|
||||
# eg "string.prototype.matchall@npm:4.0.8 can't be found in the cache and will be fetched from the remote registry"
|
||||
- code: YN0013
|
||||
level: discard
|
||||
|
||||
# To avoid the error "The remote archive doesn't match the expected checksum".
|
||||
# Yarn offers no way to understand what the issue is when it happens, or what
|
||||
# needs to be done so it's just security theater that we have no choice but to
|
||||
# disable.
|
||||
checksumBehavior: update
|
||||
|
||||
@@ -789,7 +789,7 @@ footer .bottom-links-row p {
|
||||
}
|
||||
|
||||
#menu-mobile .social-links .social-link-mastodon,
|
||||
#menu-mobile .social-links .social-link-reddit,
|
||||
#menu-mobile .social-links .social-link-lemmy,
|
||||
#menu-mobile .social-links .social-link-linkedin,
|
||||
#menu-mobile .social-links .social-link-patreon {
|
||||
display: none;
|
||||
|
||||
BIN
Assets/WebsiteAssets/images/email_to_note/desktop.png
Normal file
BIN
Assets/WebsiteAssets/images/email_to_note/desktop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
BIN
Assets/WebsiteAssets/images/email_to_note/mobile.png
Normal file
BIN
Assets/WebsiteAssets/images/email_to_note/mobile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
Assets/WebsiteAssets/images/email_to_note/website.png
Normal file
BIN
Assets/WebsiteAssets/images/email_to_note/website.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 83 KiB |
BIN
Assets/WebsiteAssets/images/sponsors/CitricSheep.png
Normal file
BIN
Assets/WebsiteAssets/images/sponsors/CitricSheep.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -5,7 +5,7 @@
|
||||
<a class="social-link-patreon" href="https://www.patreon.com/joplin" title="Joplin Patreon"><i class="fab fa-patreon"></i></a>
|
||||
<a class="social-link-discord" href="https://discord.gg/VSj7AFHvpq" title="Joplin Discord chat"><i class="fab fa-discord"></i></a>
|
||||
<a class="social-link-linkedin" href="https://www.linkedin.com/company/joplin" title="Joplin LinkedIn Feed"><i class="fab fa-linkedin"></i></a>
|
||||
<a class="social-link-reddit" href="https://www.reddit.com/r/joplinapp/" title="Joplin Subreddit"><i class="fab fa-reddit"></i></a>
|
||||
<a class="social-link-lemmy" href="https://sopuli.xyz/c/joplinapp" title="Joplin Lemmy Community"><i class="fas fa-otter"></i></a>
|
||||
<a class="social-link-github" href="https://github.com/laurent22/joplin/" title="Joplin GitHub repository"><i class="fab fa-github"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
15
README.md
15
README.md
@@ -66,7 +66,7 @@ A community maintained list of these distributions can be found here: [Unofficia
|
||||
# Sponsors
|
||||
|
||||
<!-- SPONSORS-ORG -->
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></a> <a href="https://tranio.com/spain/"><img title="Property for sale in Spain" width="256" src="https://joplinapp.org/images/sponsors/TranioOverseasProperty.jpg"/></a>
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></a> <a href="https://tranio.com/spain/"><img title="Property for sale in Spain" width="256" src="https://joplinapp.org/images/sponsors/TranioOverseasProperty.jpg"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a>
|
||||
<!-- SPONSORS-ORG -->
|
||||
|
||||
* * *
|
||||
@@ -75,11 +75,11 @@ A community maintained list of these distributions can be found here: [Unofficia
|
||||
| | | | |
|
||||
| :---: | :---: | :---: | :---: |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/215668?s=96&v=4"/></br>[avanderberg](https://github.com/avanderberg) | <img width="50" src="https://avatars2.githubusercontent.com/u/67130?s=96&v=4"/></br>[chr15m](https://github.com/chr15m) | <img width="50" src="https://avatars2.githubusercontent.com/u/2793530?s=96&v=4"/></br>[CyberXZT](https://github.com/CyberXZT) | <img width="50" src="https://avatars2.githubusercontent.com/u/1307332?s=96&v=4"/></br>[dbrandonjohnson](https://github.com/dbrandonjohnson) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/56287?s=96&v=4"/></br>[fats](https://github.com/fats) | <img width="50" src="https://avatars2.githubusercontent.com/u/49439044?s=96&v=4"/></br>[fourstepper](https://github.com/fourstepper) | <img width="50" src="https://avatars2.githubusercontent.com/u/64712218?s=96&v=4"/></br>[Hegghammer](https://github.com/Hegghammer) | <img width="50" src="https://avatars2.githubusercontent.com/u/3266447?s=96&v=4"/></br>[iamwillbar](https://github.com/iamwillbar) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/1310474?s=96&v=4"/></br>[jknowles](https://github.com/jknowles) | <img width="50" src="https://avatars2.githubusercontent.com/u/11947658?s=96&v=4"/></br>[KentBrockman](https://github.com/KentBrockman) | <img width="50" src="https://avatars2.githubusercontent.com/u/5588131?s=96&v=4"/></br>[kianenigma](https://github.com/kianenigma) | <img width="50" src="https://avatars2.githubusercontent.com/u/24908652?s=96&v=4"/></br>[konishi-t](https://github.com/konishi-t) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) | <img width="50" src="https://avatars2.githubusercontent.com/u/126279083?s=96&v=4"/></br>[matmoly](https://github.com/matmoly) | <img width="50" src="https://avatars2.githubusercontent.com/u/1788010?s=96&v=4"/></br>[maxtruxa](https://github.com/maxtruxa) | <img width="50" src="https://avatars2.githubusercontent.com/u/29300939?s=96&v=4"/></br>[mcejp](https://github.com/mcejp) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/31054972?s=96&v=4"/></br>[saarantras](https://github.com/saarantras) | <img width="50" src="https://avatars2.githubusercontent.com/u/327998?s=96&v=4"/></br>[sif](https://github.com/sif) | <img width="50" src="https://avatars2.githubusercontent.com/u/765564?s=96&v=4"/></br>[taskcruncher](https://github.com/taskcruncher) | <img width="50" src="https://avatars2.githubusercontent.com/u/333944?s=96&v=4"/></br>[tateisu](https://github.com/tateisu) |
|
||||
| | | | |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/14873877?s=96&v=4"/></br>[dchecks](https://github.com/dchecks) | <img width="50" src="https://avatars2.githubusercontent.com/u/56287?s=96&v=4"/></br>[fats](https://github.com/fats) | <img width="50" src="https://avatars2.githubusercontent.com/u/49439044?s=96&v=4"/></br>[fourstepper](https://github.com/fourstepper) | <img width="50" src="https://avatars2.githubusercontent.com/u/64712218?s=96&v=4"/></br>[Hegghammer](https://github.com/Hegghammer) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/3266447?s=96&v=4"/></br>[iamwillbar](https://github.com/iamwillbar) | <img width="50" src="https://avatars2.githubusercontent.com/u/1310474?s=96&v=4"/></br>[jknowles](https://github.com/jknowles) | <img width="50" src="https://avatars2.githubusercontent.com/u/11947658?s=96&v=4"/></br>[KentBrockman](https://github.com/KentBrockman) | <img width="50" src="https://avatars2.githubusercontent.com/u/5588131?s=96&v=4"/></br>[kianenigma](https://github.com/kianenigma) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/24908652?s=96&v=4"/></br>[konishi-t](https://github.com/konishi-t) | <img width="50" src="https://avatars2.githubusercontent.com/u/42319182?s=96&v=4"/></br>[marcdw1289](https://github.com/marcdw1289) | <img width="50" src="https://avatars2.githubusercontent.com/u/126279083?s=96&v=4"/></br>[matmoly](https://github.com/matmoly) | <img width="50" src="https://avatars2.githubusercontent.com/u/1788010?s=96&v=4"/></br>[maxtruxa](https://github.com/maxtruxa) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/29300939?s=96&v=4"/></br>[mcejp](https://github.com/mcejp) | <img width="50" src="https://avatars2.githubusercontent.com/u/31054972?s=96&v=4"/></br>[saarantras](https://github.com/saarantras) | <img width="50" src="https://avatars2.githubusercontent.com/u/327998?s=96&v=4"/></br>[sif](https://github.com/sif) | <img width="50" src="https://avatars2.githubusercontent.com/u/765564?s=96&v=4"/></br>[taskcruncher](https://github.com/taskcruncher) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/333944?s=96&v=4"/></br>[tateisu](https://github.com/tateisu) | | | |
|
||||
<!-- SPONSORS-GITHUB -->
|
||||
|
||||
<!-- TOC -->
|
||||
@@ -107,6 +107,7 @@ A community maintained list of these distributions can be found here: [Unofficia
|
||||
|
||||
- [Sharing a notebook](https://github.com/laurent22/joplin/blob/dev/readme/share_notebook.md)
|
||||
- [Publishing a note](https://github.com/laurent22/joplin/blob/dev/readme/publish_note.md)
|
||||
- [Email to Note](https://github.com/laurent22/joplin/blob/dev/readme/email_to_note.md)
|
||||
|
||||
- Joplin API - Get Started
|
||||
|
||||
@@ -511,7 +512,7 @@ Name | Description
|
||||
[Patreon page](https://www.patreon.com/joplin) |The latest news are often posted there
|
||||
[Discord server](https://discord.gg/VSj7AFHvpq) | Our chat server
|
||||
[LinkedIn](https://www.linkedin.com/company/joplin) | Our LinkedIn page
|
||||
[Sub-reddit](https://www.reddit.com/r/joplinapp/) | Also a good place to get help
|
||||
[Lemmy Community](https://sopuli.xyz/c/joplinapp) | Also a good place to get help
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
"gulp": "4.0.2",
|
||||
"husky": "3.1.0",
|
||||
"lerna": "3.22.1",
|
||||
"lint-staged": "13.2.2",
|
||||
"lint-staged": "13.2.3",
|
||||
"madge": "6.1.0",
|
||||
"npm-package-json-lint": "6.4.0",
|
||||
"typescript": "5.0.2"
|
||||
@@ -90,7 +90,7 @@
|
||||
"@types/fs-extra": "11.0.1",
|
||||
"eslint-plugin-github": "4.8.0",
|
||||
"http-server": "14.1.1",
|
||||
"node-gyp": "9.3.1",
|
||||
"node-gyp": "9.4.0",
|
||||
"nodemon": "2.0.22"
|
||||
},
|
||||
"packageManager": "yarn@3.5.0",
|
||||
@@ -99,6 +99,8 @@
|
||||
"react-native-vosk@0.1.12": "patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch",
|
||||
"eslint@8.39.0": "patch:eslint@npm%3A8.39.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
|
||||
"eslint@^8.13.0": "patch:eslint@npm%3A8.39.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
|
||||
"app-builder-lib@24.4.0": "patch:app-builder-lib@npm%3A24.4.0#./.yarn/patches/app-builder-lib-npm-24.4.0-05322ff057.patch"
|
||||
"app-builder-lib@24.4.0": "patch:app-builder-lib@npm%3A24.4.0#./.yarn/patches/app-builder-lib-npm-24.4.0-05322ff057.patch",
|
||||
"react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch",
|
||||
"react-native-reanimated@3.3.0": "patch:react-native-reanimated@npm%3A3.3.0#./.yarn/patches/react-native-animation-fix/react-native-reanimated-npm-3.3.0-fb4272741c.patch"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const { findAvailablePort } = require('@joplin/lib/net-utils');
|
||||
|
||||
const http = require('http');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const Folder = require('@joplin/lib/models/Folder').default;
|
||||
const BaseItem = require('@joplin/lib/models/BaseItem').default;
|
||||
const Tag = require('@joplin/lib/models/Tag').default;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const { dirname } = require('@joplin/lib/path-utils');
|
||||
const { DatabaseDriverNode } = require('@joplin/lib/database-driver-node.js');
|
||||
const JoplinDatabase = require('@joplin/lib/JoplinDatabase').default;
|
||||
|
||||
@@ -2,7 +2,7 @@ const yargParser = require('yargs-parser');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const time = require('@joplin/lib/time').default;
|
||||
const stringPadding = require('string-padding');
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
|
||||
const cliUtils = {};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const BaseCommand = require('./base-command').default;
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
|
||||
class Command extends BaseCommand {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const time = require('@joplin/lib/time').default;
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const Resource = require('@joplin/lib/models/Resource').default;
|
||||
const { dirname } = require('@joplin/lib/path-utils');
|
||||
const FsDriverNode = require('@joplin/lib/fs-driver-node').default;
|
||||
|
||||
@@ -20,7 +20,7 @@ const NoteTag = require('@joplin/lib/models/NoteTag').default;
|
||||
const MasterKey = require('@joplin/lib/models/MasterKey').default;
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const Revision = require('@joplin/lib/models/Revision').default;
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const FsDriverNode = require('@joplin/lib/fs-driver-node').default;
|
||||
const sharp = require('sharp');
|
||||
const { shimInit } = require('@joplin/lib/shim-init-node.js');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
const MarkupToHtml = require('@joplin/renderer/MarkupToHtml').default;
|
||||
import MarkupToHtml, { MarkupLanguage, RenderResult } from '@joplin/renderer/MarkupToHtml';
|
||||
|
||||
describe('MarkupToHtml', () => {
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('MarkupToHtml', () => {
|
||||
const input = t[0];
|
||||
const expected = t[1];
|
||||
const actual = service.stripMarkup(Number(markup), input);
|
||||
expect(actual).toBe(expected, `Markup: ${markup}`);
|
||||
expect(actual).toBe(expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,4 +40,18 @@ describe('MarkupToHtml', () => {
|
||||
expect(service.stripMarkup(1, 'one line\n two line', { collapseWhiteSpaces: true })).toBe('one line two line');
|
||||
}));
|
||||
|
||||
|
||||
test('should escape HTML in safe mode', async () => {
|
||||
const service = new MarkupToHtml({ isSafeMode: true });
|
||||
|
||||
const testString = '</pre>.<b>Test</b>';
|
||||
const expectedOutput: RenderResult = {
|
||||
html: '<pre></pre>.<b>Test</b></pre>',
|
||||
cssStrings: [],
|
||||
pluginAssets: [],
|
||||
};
|
||||
|
||||
expect(await service.render(MarkupLanguage.Html, testString, {}, {})).toMatchObject(expectedOutput);
|
||||
expect(await service.render(MarkupLanguage.Markdown, testString, {}, {})).toMatchObject(expectedOutput);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
<p><b> A test... </b>Test</p>
|
||||
@@ -0,0 +1 @@
|
||||
**A test...** Test
|
||||
10
packages/app-cli/tests/html_to_md/linebreaks.html
Normal file
10
packages/app-cli/tests/html_to_md/linebreaks.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<h1>Linebreaks</h1>
|
||||
<div><br>-style linebreaks should be replaced with two spaces followed by a
|
||||
newline.<br/>This allows the generated mark<br/>down to render to equivalent HTML
|
||||
even if the <code>markdown.plugin.softbreaks</code> setting is enabled.</div>
|
||||
<pre class="some-code" style="font-family:monospace;"><br>s shouldn't<br/>lead<br/>to trailing spaces in
|
||||
code
|
||||
however.
|
||||
</pre>
|
||||
<p>Because it isn't</p>
|
||||
<div>necessary.<br/><br/><br/><br/>...</div>
|
||||
21
packages/app-cli/tests/html_to_md/linebreaks.md
Normal file
21
packages/app-cli/tests/html_to_md/linebreaks.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Linebreaks
|
||||
|
||||
<br>-style linebreaks should be replaced with two spaces followed by a newline.
|
||||
This allows the generated mark
|
||||
down to render to equivalent HTML even if the `markdown.plugin.softbreaks` setting is enabled.
|
||||
|
||||
```
|
||||
<br>s shouldn't
|
||||
lead
|
||||
to trailing spaces in
|
||||
code
|
||||
however.
|
||||
```
|
||||
|
||||
Because it isn't
|
||||
|
||||
necessary.
|
||||
|
||||
|
||||
|
||||
...
|
||||
@@ -0,0 +1,3 @@
|
||||
<p>Paragraphs with a single nonbreaking space should be preserved:</p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
@@ -0,0 +1,5 @@
|
||||
Paragraphs with a single nonbreaking space should be preserved:
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
Some pictures:  
|
||||
Some pictures: 
|
||||
@@ -5,5 +5,6 @@
|
||||
| [Source](https://github.com/nim-lang/nim) | The github project |
|
||||
| [nimble](https://github.com/nim-lang/nimble) | The nim package manager |
|
||||
| [choosenim](https://github.com/dom96/choosenim) | Toolchain installer |
|
||||
| | |
|
||||
| **Community** | |
|
||||
| [Forums](https://forum.nim-lang.org) | An async discussion board |
|
||||
@@ -1,4 +1,4 @@
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { PluginMessage } from './services/plugins/PluginRunner';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import { isCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { defaultState, State } from '@joplin/lib/reducer';
|
||||
import iterateItems from './gui/ResizableLayout/utils/iterateItems';
|
||||
import { LayoutItem } from './gui/ResizableLayout/utils/types';
|
||||
import validateLayout from './gui/ResizableLayout/utils/validateLayout';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
|
||||
const logger = Logger.create('app.reducer');
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import PlatformImplementation from './services/plugins/PlatformImplementation';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import AlarmService from '@joplin/lib/services/AlarmService';
|
||||
import AlarmServiceDriverNode from '@joplin/lib/services/AlarmServiceDriverNode';
|
||||
import Logger, { TargetType } from '@joplin/lib/Logger';
|
||||
import Logger, { TargetType } from '@joplin/utils/Logger';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import actionApi from '@joplin/lib/services/rest/actionApi.desktop';
|
||||
import BaseApplication from '@joplin/lib/BaseApplication';
|
||||
@@ -66,7 +66,7 @@ import syncDebugLog from '@joplin/lib/services/synchronizer/syncDebugLog';
|
||||
import eventManager from '@joplin/lib/eventManager';
|
||||
import path = require('path');
|
||||
import { checkPreInstalledDefaultPlugins, installDefaultPlugins, setSettingsForDefaultPlugins } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils';
|
||||
// import { runIntegrationTests } from '@joplin/lib/services/e2ee/ppkTestUtils';
|
||||
import userFetcher, { initializeUserFetcher } from '@joplin/lib/utils/userFetcher';
|
||||
|
||||
const pluginClasses = [
|
||||
require('./plugins/GotoAnything').default,
|
||||
@@ -262,6 +262,8 @@ class Application extends BaseApplication {
|
||||
if (this.initPluginServiceDone_) return;
|
||||
this.initPluginServiceDone_ = true;
|
||||
|
||||
PlatformImplementation.instance().initialize((action: any) => this.dispatch(action));
|
||||
|
||||
const service = PluginService.instance();
|
||||
|
||||
const pluginRunner = new PluginRunner();
|
||||
@@ -487,6 +489,9 @@ class Application extends BaseApplication {
|
||||
shim.setInterval(() => { runAutoUpdateCheck(); }, 12 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
initializeUserFetcher();
|
||||
shim.setInterval(() => { void userFetcher(); }, 1000 * 60 * 60);
|
||||
|
||||
this.updateTray();
|
||||
|
||||
shim.setTimeout(() => {
|
||||
|
||||
@@ -96,11 +96,7 @@ export class Bridge {
|
||||
electronApp: this.electronApp(),
|
||||
|
||||
shouldShowMenu: (_event: any, params: any) => {
|
||||
// params.inputFieldType === 'none' when right-clicking the text
|
||||
// editor. This is a bit of a hack to detect it because in this
|
||||
// case we don't want to use the built-in context menu but a
|
||||
// custom one.
|
||||
return params.isEditable && params.inputFieldType !== 'none';
|
||||
return params.isEditable;
|
||||
},
|
||||
|
||||
// menu: (actions: any, props: any) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import bridge from './services/bridge';
|
||||
import KvStore from '@joplin/lib/services/KvStore';
|
||||
|
||||
@@ -18,6 +18,7 @@ import restart from '../../services/restart';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import { getDefaultPluginsInstallState, updateDefaultPluginsInstallState } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils';
|
||||
import getDefaultPluginsInfo from '@joplin/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo';
|
||||
import JoplinCloudConfigScreen from '../JoplinCloudConfigScreen';
|
||||
const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen');
|
||||
|
||||
const settingKeyToControl: any = {
|
||||
@@ -106,6 +107,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
if (screenName === 'encryption') return <EncryptionConfigScreen/>;
|
||||
if (screenName === 'server') return <ClipperConfigScreen themeId={this.props.themeId}/>;
|
||||
if (screenName === 'keymap') return <KeymapConfigScreen themeId={this.props.themeId}/>;
|
||||
if (screenName === 'joplinCloud') return <JoplinCloudConfigScreen />;
|
||||
|
||||
throw new Error(`Invalid screen name: ${screenName}`);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { PluginItem } from './PluginBox';
|
||||
import RepositoryApi from '@joplin/lib/services/plugins/RepositoryApi';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import useOnInstallHandler, { OnPluginSettingChangeEvent } from './useOnInstallHandler';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import StyledMessage from '../../../style/StyledMessage';
|
||||
import StyledLink from '../../../style/StyledLink';
|
||||
const { space } = require('styled-system');
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
|
||||
import PluginService, { defaultPluginSetting, PluginSettings } from '@joplin/lib/services/plugins/PluginService';
|
||||
import produce from 'immer';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { ItemEvent } from './PluginBox';
|
||||
|
||||
const logger = Logger.create('useOnInstallHandler');
|
||||
|
||||
3
packages/app-desktop/gui/JoplinCloudConfigScreen.scss
Normal file
3
packages/app-desktop/gui/JoplinCloudConfigScreen.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
.inbox-email-value {
|
||||
font-weight: bold;
|
||||
}
|
||||
32
packages/app-desktop/gui/JoplinCloudConfigScreen.tsx
Normal file
32
packages/app-desktop/gui/JoplinCloudConfigScreen.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
const { connect } = require('react-redux');
|
||||
import { AppState } from '../app.reducer';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { clipboard } from 'electron';
|
||||
import Button from './Button/Button';
|
||||
|
||||
type JoplinCloudConfigScreenProps = {
|
||||
inboxEmail: string;
|
||||
};
|
||||
|
||||
const JoplinCloudConfigScreen = (props: JoplinCloudConfigScreenProps) => {
|
||||
const copyToClipboard = () => {
|
||||
clipboard.writeText(props.inboxEmail);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>{_('Email to note')}</h2>
|
||||
<p>{_('Any email sent to this address will be converted into a note and added to your collection. The note will be saved into the Inbox notebook')}</p>
|
||||
<p className='inbox-email-value'>{props.inboxEmail}</p>
|
||||
<Button onClick={copyToClipboard} title={_('Copy to clipboard')} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
inboxEmail: state.settings['sync.10.inboxEmail'],
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(JoplinCloudConfigScreen);
|
||||
@@ -17,10 +17,12 @@ export const runtime = (): CommandRuntime => {
|
||||
const folder = await Folder.load(folderId);
|
||||
if (!folder) throw new Error(`No such folder: ${folderId}`);
|
||||
|
||||
const ok = bridge().showConfirmMessageBox(_('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', substrWithEllipsis(folder.title, 0, 32)), {
|
||||
buttons: [_('Delete'), _('Cancel')],
|
||||
defaultId: 1,
|
||||
});
|
||||
let deleteMessage = _('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', substrWithEllipsis(folder.title, 0, 32));
|
||||
if (folderId === context.state.settings['sync.10.inboxId']) {
|
||||
deleteMessage = _('Delete the Inbox notebook?\n\nIf you delete the inbox notebook, any email that\'s recently been sent to it may be lost.');
|
||||
}
|
||||
|
||||
const ok = bridge().showConfirmMessageBox(deleteMessage);
|
||||
if (!ok) return;
|
||||
|
||||
await Folder.delete(folderId);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
|
||||
const logger = Logger.create('leaveSharedFolder');
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import ErrorBoundary from '../../../ErrorBoundary';
|
||||
import { MarkupToHtmlOptions } from '../../utils/useMarkupToHtml';
|
||||
import eventManager from '@joplin/lib/eventManager';
|
||||
import { EditContextMenuFilterObject } from '@joplin/lib/services/plugins/api/JoplinWorkspace';
|
||||
import type { ContextMenuEvent, ContextMenuParams } from 'electron';
|
||||
|
||||
const menuUtils = new MenuUtils(CommandService.instance());
|
||||
|
||||
@@ -782,20 +783,50 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
// It might be buggy, refer to the below issue
|
||||
// https://github.com/laurent22/joplin/pull/3974#issuecomment-718936703
|
||||
useEffect(() => {
|
||||
function pointerInsideEditor(params: any) {
|
||||
const x = params.x, y = params.y, isEditable = params.isEditable, inputFieldType = params.inputFieldType;
|
||||
const isAncestorOfCodeMirrorEditor = (elem: HTMLElement) => {
|
||||
for (; elem.parentElement; elem = elem.parentElement) {
|
||||
if (elem.classList.contains('codeMirrorEditor')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
let lastInCodeMirrorContextMenuTimestamp = 0;
|
||||
|
||||
// The browser's contextmenu event provides additional information about the
|
||||
// target of the event, not provided by the Electron context-menu event.
|
||||
const onBrowserContextMenu = (event: Event) => {
|
||||
if (isAncestorOfCodeMirrorEditor(event.target as HTMLElement)) {
|
||||
lastInCodeMirrorContextMenuTimestamp = Date.now();
|
||||
}
|
||||
};
|
||||
|
||||
function pointerInsideEditor(params: ContextMenuParams) {
|
||||
const x = params.x, y = params.y, isEditable = params.isEditable;
|
||||
const elements = document.getElementsByClassName('codeMirrorEditor');
|
||||
|
||||
// inputFieldType: The input field type of CodeMirror is "textarea" so the inputFieldType = "none",
|
||||
// and any single-line input above codeMirror has inputFieldType value according to the type of input e.g.(text = plainText, password = password, ...).
|
||||
if (!elements.length || !isEditable || inputFieldType !== 'none') return null;
|
||||
// Note: We can't check inputFieldType here. When spellcheck is enabled,
|
||||
// params.inputFieldType is "none". When spellcheck is disabled,
|
||||
// params.inputFieldType is "plainText". Thus, such a check would be inconsistent.
|
||||
if (!elements.length || !isEditable) return false;
|
||||
|
||||
const maximumMsSinceBrowserEvent = 100;
|
||||
if (Date.now() - lastInCodeMirrorContextMenuTimestamp > maximumMsSinceBrowserEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rect = convertToScreenCoordinates(Setting.value('windowContentZoomFactor'), elements[0].getBoundingClientRect());
|
||||
return rect.x < x && rect.y < y && rect.right > x && rect.bottom > y;
|
||||
}
|
||||
|
||||
async function onContextMenu(_event: any, params: any) {
|
||||
async function onContextMenu(event: ContextMenuEvent, params: ContextMenuParams) {
|
||||
if (!pointerInsideEditor(params)) return;
|
||||
|
||||
// Don't show the default menu.
|
||||
event.preventDefault();
|
||||
|
||||
const menu = new Menu();
|
||||
|
||||
const hasSelectedText = editorRef.current && !!editorRef.current.getSelection() ;
|
||||
@@ -872,10 +903,15 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
menu.popup();
|
||||
}
|
||||
|
||||
bridge().window().webContents.on('context-menu', onContextMenu);
|
||||
// Prepend the event listener so that it gets called before
|
||||
// the listener that shows the default menu.
|
||||
bridge().window().webContents.prependListener('context-menu', onContextMenu);
|
||||
|
||||
window.addEventListener('contextmenu', onBrowserContextMenu);
|
||||
|
||||
return () => {
|
||||
bridge().window().webContents.off('context-menu', onContextMenu);
|
||||
window.removeEventListener('contextmenu', onBrowserContextMenu);
|
||||
};
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [props.plugins]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
|
||||
const logger = Logger.create('useEditorSearch');
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ let dispatchDidUpdateIID_: any = null;
|
||||
let changeId_ = 1;
|
||||
|
||||
const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
const [editor, setEditor] = useState(null);
|
||||
const [editor, setEditor] = useState<Editor|null>(null);
|
||||
const [scriptLoaded, setScriptLoaded] = useState(false);
|
||||
const [editorReady, setEditorReady] = useState(false);
|
||||
const [draggingStarted, setDraggingStarted] = useState(false);
|
||||
@@ -480,6 +480,23 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
/* Override the TinyMCE font styles with more specific CSS selectors.
|
||||
Without this, the built-in FontAwesome styles are not applied because
|
||||
they are overridden by TinyMCE. */
|
||||
.plugin-icon.fa, .plugin-icon.far, .plugin-icon.fas {
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-size: ${theme.toolbarHeight - theme.toolbarPadding}px;
|
||||
}
|
||||
|
||||
.plugin-icon.fa, .plugin-icon.fas {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.plugin-icon.fab, .plugin-icon.far {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
|
||||
.joplin-tinymce .tox-toolbar__group {
|
||||
background-color: ${theme.backgroundColor3};
|
||||
padding-top: ${theme.toolbarPadding}px;
|
||||
@@ -548,15 +565,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
'bold', 'italic', 'joplinHighlight', 'joplinStrikethrough', 'formattingExtras', '|',
|
||||
'link', 'joplinInlineCode', 'joplinCodeBlock', 'joplinAttach', '|',
|
||||
'bullist', 'numlist', 'joplinChecklist', '|',
|
||||
'h1', 'h2', 'h3', 'hr', 'blockquote', 'inserttable', `joplinInsertDateTime${toolbarPluginButtons}`,
|
||||
];
|
||||
|
||||
// Available table toolbar buttons:
|
||||
// https://www.tiny.cloud/docs/advanced/available-toolbar-buttons/#tableplugin
|
||||
const tableToolbar = [
|
||||
'tabledelete',
|
||||
'tableinsertrowafter tablecopyrow tablepasterowafter tabledeleterow',
|
||||
'tableinsertcolafter tablecopycol tablepastecolafter tabledeletecol',
|
||||
'h1', 'h2', 'h3', 'hr', 'blockquote', 'table', `joplinInsertDateTime${toolbarPluginButtons}`,
|
||||
];
|
||||
|
||||
const editors = await (window as any).tinymce.init({
|
||||
@@ -569,7 +578,12 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
icons_url: 'gui/NoteEditor/NoteBody/TinyMCE/icons.js',
|
||||
plugins: 'noneditable link joplinLists hr searchreplace codesample table',
|
||||
noneditable_noneditable_class: 'joplin-editable', // Can be a regex too
|
||||
valid_elements: '*[*]', // We already filter in sanitize_html
|
||||
|
||||
// #p: Pad empty paragraphs with to prevent them from being removed.
|
||||
// *[*]: Allow all elements and attributes -- we already filter in sanitize_html
|
||||
// See https://www.tiny.cloud/docs/configure/content-filtering/#controlcharacters
|
||||
valid_elements: '#p,*[*]',
|
||||
|
||||
menubar: false,
|
||||
relative_urls: false,
|
||||
branding: false,
|
||||
@@ -578,7 +592,6 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
// Handle the first table row as table header.
|
||||
// https://www.tiny.cloud/docs/plugins/table/#table_header_type
|
||||
table_header_type: 'sectionCells',
|
||||
table_toolbar: tableToolbar.join(' | '),
|
||||
table_resize_bars: false,
|
||||
language_url: ['en_US', 'en_GB'].includes(language) ? undefined : `${bridge().vendorDir()}/lib/tinymce/langs/${language}`,
|
||||
toolbar: toolbar.join(' '),
|
||||
@@ -591,6 +604,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
joplinInsert: { inline: 'ins', remove: 'all' },
|
||||
joplinSub: { inline: 'sub', remove: 'all' },
|
||||
joplinSup: { inline: 'sup', remove: 'all' },
|
||||
code: { inline: 'code', remove: 'all', attributes: { spellcheck: false } },
|
||||
},
|
||||
setup: (editor: Editor) => {
|
||||
editor.addCommand('joplinAttach', () => {
|
||||
@@ -631,22 +645,6 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
},
|
||||
});
|
||||
|
||||
editor.ui.registry.addMenuButton('inserttable', {
|
||||
icon: 'table',
|
||||
tooltip: 'Table',
|
||||
fetch: (callback) => {
|
||||
callback([
|
||||
{
|
||||
type: 'fancymenuitem',
|
||||
fancytype: 'inserttable',
|
||||
onAction: (data) => {
|
||||
editor.execCommand('mceInsertTable', false, { rows: data.numRows, columns: data.numColumns, options: { headerRows: 1 } });
|
||||
},
|
||||
},
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
editor.ui.registry.addButton('joplinInsertDateTime', {
|
||||
tooltip: _('Insert time'),
|
||||
icon: 'insert-time',
|
||||
@@ -656,9 +654,16 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
});
|
||||
|
||||
for (const pluginCommandName of pluginCommandNames) {
|
||||
const iconClassName = CommandService.instance().iconName(pluginCommandName);
|
||||
|
||||
// Only allow characters that appear in Font Awesome class names: letters, spaces, and dashes.
|
||||
const safeIconClassName = iconClassName.replace(/[^a-z0-9 -]/g, '');
|
||||
|
||||
editor.ui.registry.addIcon(pluginCommandName, `<i class="plugin-icon ${safeIconClassName}"></i>`);
|
||||
|
||||
editor.ui.registry.addButton(pluginCommandName, {
|
||||
tooltip: CommandService.instance().label(pluginCommandName),
|
||||
icon: CommandService.instance().iconName(pluginCommandName, 'tinymce'),
|
||||
icon: pluginCommandName,
|
||||
onAction: function() {
|
||||
void CommandService.instance().execute(pluginCommandName);
|
||||
},
|
||||
@@ -698,7 +703,17 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
setEditorReady(true);
|
||||
});
|
||||
|
||||
const preprocessContent = () => {
|
||||
// Disable spellcheck for all inline code blocks.
|
||||
const codeElements = editor.dom.doc.querySelectorAll('code.inline-code');
|
||||
for (const code of codeElements) {
|
||||
code.setAttribute('spellcheck', 'false');
|
||||
}
|
||||
};
|
||||
|
||||
editor.on('SetContent', () => {
|
||||
preprocessContent();
|
||||
|
||||
props_onMessage.current({ channel: 'noteRenderComplete' });
|
||||
});
|
||||
},
|
||||
@@ -715,18 +730,10 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
// Set the initial content and load the plugin CSS and JS files
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
const loadDocumentAssets = (editor: any, pluginAssets: any[]) => {
|
||||
// Note: The way files are cached is not correct because it assumes there's only one version
|
||||
// of each file. However, when the theme change, a new CSS file, specific to the theme, is
|
||||
// created. That file should not be loaded on top of the previous one, but as a replacement.
|
||||
// Otherwise it would do this:
|
||||
// - Try to load CSS for theme 1 => OK
|
||||
// - Try to load CSS for theme 2 => OK
|
||||
// - Try to load CSS for theme 1 => Skip because the file is in cache. As a result, theme 2
|
||||
// incorrectly stay.
|
||||
// The fix would be to make allAssets() return a name and a version for each asset. Then the loading
|
||||
// code would check this and either append the CSS or replace.
|
||||
const documentCssElements: Record<string, HTMLLinkElement> = {};
|
||||
const documentScriptElements: Record<string, HTMLScriptElement> = {};
|
||||
|
||||
const loadDocumentAssets = (editor: any, pluginAssets: any[]) => {
|
||||
const theme = themeStyle(props.themeId);
|
||||
|
||||
let docHead_: any = null;
|
||||
@@ -737,49 +744,72 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
return docHead_;
|
||||
}
|
||||
|
||||
const cssFiles = [
|
||||
const allCssFiles = [
|
||||
`${bridge().vendorDir()}/lib/@fortawesome/fontawesome-free/css/all.min.css`,
|
||||
`gui/note-viewer/pluginAssets/highlight.js/${theme.codeThemeCss}`,
|
||||
].concat(
|
||||
pluginAssets
|
||||
.filter((a: any) => a.mime === 'text/css')
|
||||
.map((a: any) => a.path)
|
||||
).filter((path: string) => !loadedCssFiles_.includes(path));
|
||||
);
|
||||
|
||||
const jsFiles = [].concat(
|
||||
const allJsFiles = [].concat(
|
||||
pluginAssets
|
||||
.filter((a: any) => a.mime === 'application/javascript')
|
||||
.map((a: any) => a.path)
|
||||
).filter((path: string) => !loadedJsFiles_.includes(path));
|
||||
);
|
||||
|
||||
for (const cssFile of cssFiles) loadedCssFiles_.push(cssFile);
|
||||
for (const jsFile of jsFiles) loadedJsFiles_.push(jsFile);
|
||||
|
||||
// Remove all previously loaded files that aren't in the assets this time.
|
||||
// Note: This is important to ensure that we properly change themes.
|
||||
// See https://github.com/laurent22/joplin/issues/8520
|
||||
for (const cssFile of loadedCssFiles_) {
|
||||
if (!allCssFiles.includes(cssFile)) {
|
||||
documentCssElements[cssFile]?.remove();
|
||||
delete documentCssElements[cssFile];
|
||||
}
|
||||
}
|
||||
|
||||
for (const jsFile of loadedJsFiles_) {
|
||||
if (!allJsFiles.includes(jsFile)) {
|
||||
documentScriptElements[jsFile]?.remove();
|
||||
delete documentScriptElements[jsFile];
|
||||
}
|
||||
}
|
||||
|
||||
const newCssFiles = allCssFiles.filter((path: string) => !loadedCssFiles_.includes(path));
|
||||
const newJsFiles = allJsFiles.filter((path: string) => !loadedJsFiles_.includes(path));
|
||||
|
||||
loadedCssFiles_ = allCssFiles;
|
||||
loadedJsFiles_ = allJsFiles;
|
||||
|
||||
// console.info('loadDocumentAssets: files to load', cssFiles, jsFiles);
|
||||
|
||||
if (cssFiles.length) {
|
||||
for (const cssFile of cssFiles) {
|
||||
const script = editor.dom.create('link', {
|
||||
if (newCssFiles.length) {
|
||||
for (const cssFile of newCssFiles) {
|
||||
const style = editor.dom.create('link', {
|
||||
rel: 'stylesheet',
|
||||
type: 'text/css',
|
||||
href: cssFile,
|
||||
class: 'jop-tinymce-css',
|
||||
});
|
||||
|
||||
docHead().appendChild(script);
|
||||
documentCssElements[cssFile] = style;
|
||||
docHead().appendChild(style);
|
||||
}
|
||||
}
|
||||
|
||||
if (jsFiles.length) {
|
||||
if (newJsFiles.length) {
|
||||
const editorElementId = editor.dom.uniqueId();
|
||||
|
||||
for (const jsFile of jsFiles) {
|
||||
for (const jsFile of newJsFiles) {
|
||||
const script = editor.dom.create('script', {
|
||||
id: editorElementId,
|
||||
type: 'text/javascript',
|
||||
src: jsFile,
|
||||
});
|
||||
|
||||
documentScriptElements[jsFile] = script;
|
||||
docHead().appendChild(script);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Resource from '@joplin/lib/models/Resource';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
const logger = Logger.create('contextMenuUtils');
|
||||
export enum ContextMenuItemType {
|
||||
None = '',
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { processPastedHtml } from './resourceHandling';
|
||||
|
||||
describe('resourceHandling', () => {
|
||||
it('should sanitize pasted HTML', async () => {
|
||||
const testCases = [
|
||||
['Test: <style onload="evil()"></style>', 'Test: <style></style>'],
|
||||
['<a href="javascript: alert()">test</a>', '<a href="#">test</a>'],
|
||||
['<script >evil()</script>', ''],
|
||||
['<script>evil()</script>', ''],
|
||||
[
|
||||
'<img onload="document.body.innerHTML = evil;" src="data:image/svg+xml;base64,=="/>',
|
||||
'<img src="data:image/svg+xml;base64,=="/>',
|
||||
],
|
||||
];
|
||||
|
||||
for (const [html, expected] of testCases) {
|
||||
expect(await processPastedHtml(html)).toBe(expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -6,7 +6,8 @@ import Resource from '@joplin/lib/models/Resource';
|
||||
const bridge = require('@electron/remote').require('./bridge').default;
|
||||
import ResourceFetcher from '@joplin/lib/services/ResourceFetcher';
|
||||
import htmlUtils from '@joplin/lib/htmlUtils';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import rendererHtmlUtils from '@joplin/renderer/htmlUtils';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
const { fileUriToPath } = require('@joplin/lib/urlUtils');
|
||||
const joplinRendererUtils = require('@joplin/renderer').utils;
|
||||
const { clipboard } = require('electron');
|
||||
@@ -159,6 +160,8 @@ export async function processPastedHtml(html: string) {
|
||||
const createdResource = await shim.createResourceFromPath(imageFilePath);
|
||||
mappedResources[imageSrc] = `file://${encodeURI(Resource.fullPath(createdResource))}`;
|
||||
}
|
||||
} else if (imageSrc.startsWith('data:')) { // Data URIs
|
||||
mappedResources[imageSrc] = imageSrc;
|
||||
} else {
|
||||
const filePath = `${Setting.value('tempDir')}/${md5(Date.now() + Math.random())}`;
|
||||
await shim.fetchBlob(imageSrc, { path: filePath });
|
||||
@@ -173,7 +176,9 @@ export async function processPastedHtml(html: string) {
|
||||
}
|
||||
}
|
||||
|
||||
return htmlUtils.replaceImageUrls(html, (src: string) => {
|
||||
return mappedResources[src];
|
||||
});
|
||||
return rendererHtmlUtils.sanitizeHtml(
|
||||
htmlUtils.replaceImageUrls(html, (src: string) => {
|
||||
return mappedResources[src];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FormNote, defaultFormNote, ResourceInfos } from './types';
|
||||
import { clearResourceCache, attachedResources } from './resourceHandling';
|
||||
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
|
||||
import { handleResourceDownloadMode } from './resourceHandling';
|
||||
import HtmlToHtml from '@joplin/renderer/HtmlToHtml';
|
||||
import { splitHtml } from '@joplin/renderer/HtmlToHtml';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
|
||||
@@ -73,8 +73,7 @@ export default function useFormNote(dependencies: HookDependencies) {
|
||||
let originalCss = '';
|
||||
|
||||
if (n.markup_language === MarkupToHtml.MARKUP_LANGUAGE_HTML) {
|
||||
const htmlToHtml = new HtmlToHtml();
|
||||
const splitted = htmlToHtml.splitHtml(n.body);
|
||||
const splitted = splitHtml(n.body);
|
||||
originalCss = splitted.css;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState, useCallback, MutableRefObject, useEffect } from 'react';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { SearchMarkers } from './useSearchMarkers';
|
||||
const CommandService = require('@joplin/lib/services/CommandService').default;
|
||||
|
||||
|
||||
@@ -246,7 +246,10 @@ const NoteListComponent = (props: Props) => {
|
||||
event.dataTransfer.setDragImage(new Image(), 1, 1);
|
||||
event.dataTransfer.clearData();
|
||||
event.dataTransfer.setData('text/x-jop-note-ids', JSON.stringify(noteIds));
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
// While setting
|
||||
// event.dataTransfer.effectAllowed = 'move';
|
||||
// causes the drag cursor to have a "move", rather than an "add", icon,
|
||||
// this breaks note drag and drop into the markdown editor.
|
||||
return true;
|
||||
}, [props.parentFolderIsReadOnly, props.selectedNoteIds]);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import styled from 'styled-components';
|
||||
import StyledFormLabel from '../style/StyledFormLabel';
|
||||
import StyledInput from '../style/StyledInput';
|
||||
import Button, { ButtonSize } from '../Button/Button';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import StyledMessage from '../style/StyledMessage';
|
||||
import { SharePermissions, ShareUserStatus, StateShare, StateShareUser } from '@joplin/lib/services/share/reducer';
|
||||
import { State } from '@joplin/lib/reducer';
|
||||
@@ -96,6 +96,7 @@ interface Props {
|
||||
onClose(): void;
|
||||
shares: StateShare[];
|
||||
shareUsers: Record<string, StateShareUser[]>;
|
||||
canUseSharePermissions: boolean;
|
||||
}
|
||||
|
||||
interface RecipientDeleteEvent {
|
||||
@@ -111,12 +112,12 @@ enum ShareState {
|
||||
function ShareFolderDialog(props: Props) {
|
||||
const permissionOptions: DropdownOptions = {
|
||||
'can_read': _('Can view'),
|
||||
'can_read_and_write': _('Can edit'),
|
||||
'can_read_and_write': _('Can view and edit'),
|
||||
};
|
||||
|
||||
const [folder, setFolder] = useState<FolderEntity>(null);
|
||||
const [recipientEmail, setRecipientEmail] = useState<string>('');
|
||||
const [recipientPermissions, setRecipientPermissions] = useState<string>('can_read');
|
||||
const [recipientPermissions, setRecipientPermissions] = useState<string>('can_read_and_write');
|
||||
const [latestError, setLatestError] = useState<Error>(null);
|
||||
const [share, setShare] = useState<StateShare>(null);
|
||||
const [shareUsers, setShareUsers] = useState<StateShareUser[]>([]);
|
||||
@@ -148,8 +149,7 @@ function ShareFolderDialog(props: Props) {
|
||||
useEffect(() => {
|
||||
const s = props.shares.find(s => s.folder_id === props.folderId);
|
||||
setShare(s);
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [props.shares]);
|
||||
}, [props.shares, props.folderId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!share) return;
|
||||
@@ -261,12 +261,14 @@ function ShareFolderDialog(props: Props) {
|
||||
function renderAddRecipient() {
|
||||
const disabled = shareState !== ShareState.Idle;
|
||||
|
||||
const dropdown = !props.canUseSharePermissions ? null : <Dropdown className="permission-dropdown" options={permissionOptions} value={recipientPermissions} onChange={recipientPermissions_change}/>;
|
||||
|
||||
return (
|
||||
<StyledAddRecipient>
|
||||
<StyledFormLabel>{_('Add recipient:')}</StyledFormLabel>
|
||||
<StyledRecipientControls>
|
||||
<StyledRecipientInput disabled={disabled} type="email" placeholder="example@domain.com" value={recipientEmail} onChange={recipientEmail_change} />
|
||||
<Dropdown className="permission-dropdown" options={permissionOptions} value={recipientPermissions} onChange={recipientPermissions_change}/>
|
||||
{dropdown}
|
||||
<Button size={ButtonSize.Small} disabled={disabled} title={_('Share')} onClick={shareRecipient_click}></Button>
|
||||
</StyledRecipientControls>
|
||||
</StyledAddRecipient>
|
||||
@@ -304,11 +306,12 @@ function ShareFolderDialog(props: Props) {
|
||||
|
||||
const permission = shareUser.can_write ? 'can_read_and_write' : 'can_read';
|
||||
const enabled = !recipientsBeingUpdated[shareUser.id];
|
||||
const dropdown = !props.canUseSharePermissions ? null : <Dropdown disabled={!enabled} className="permission-dropdown" value={permission} options={permissionOptions} variant={DropdownVariant.NoBorder} onChange={event => recipient_permissionChange(shareUser.id, event.value)}/>;
|
||||
|
||||
return (
|
||||
<StyledRecipient key={shareUser.user.email} index={index}>
|
||||
<StyledRecipientName>{shareUser.user.email}</StyledRecipientName>
|
||||
<Dropdown disabled={!enabled} className="permission-dropdown" value={permission} options={permissionOptions} variant={DropdownVariant.NoBorder} onChange={event => recipient_permissionChange(shareUser.id, event.value)}/>
|
||||
{dropdown}
|
||||
<StyledRecipientStatusIcon title={statusToMessage[shareUser.status]} className={statusToIcon[shareUser.status]}></StyledRecipientStatusIcon>
|
||||
<Button disabled={!enabled} size={ButtonSize.Small} iconName="far fa-times-circle" onClick={() => recipient_delete({ shareUserId: shareUser.id })}/>
|
||||
</StyledRecipient>
|
||||
@@ -404,6 +407,7 @@ const mapStateToProps = (state: State) => {
|
||||
return {
|
||||
shares: state.shareService.shares,
|
||||
shareUsers: state.shareService.shareUsers,
|
||||
canUseSharePermissions: state.settings['sync.target'] === 10 && state.settings['sync.10.canUseSharePermissions'],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import BaseModel from '@joplin/lib/BaseModel';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import Tag from '@joplin/lib/models/Tag';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { FolderEntity, FolderIcon, FolderIconType } from '@joplin/lib/services/database/types';
|
||||
import stateToWhenClauseContext from '../../services/commands/stateToWhenClauseContext';
|
||||
import { store } from '@joplin/lib/reducer';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
|
||||
// Can't upgrade beyond 2.x because it doesn't work with Electron. If trying to
|
||||
// upgrade again, check that adding a link from the CodeMirror editor works/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
|
||||
const logger = Logger.create('loadScript');
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ module.exports = {
|
||||
// setupFiles: [],
|
||||
|
||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||
// setupFilesAfterEnv: [],
|
||||
setupFilesAfterEnv: [`${__dirname}/jest.setup.js`],
|
||||
|
||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||
// slowTestThreshold: 5,
|
||||
|
||||
19
packages/app-desktop/jest.setup.js
Normal file
19
packages/app-desktop/jest.setup.js
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
const { default: Logger, TargetType } = require('@joplin/utils/Logger');
|
||||
|
||||
// TODO: Some libraries required by test-utils.js seem to fail to import with the
|
||||
// jsdom environment.
|
||||
//
|
||||
// Thus, require('@joplin/lib/testing/test-utils.js') fails and some setup must be
|
||||
// copied.
|
||||
|
||||
const logger = new Logger();
|
||||
logger.addTarget(TargetType.Console);
|
||||
logger.setLevel(Logger.LEVEL_WARN);
|
||||
Logger.initializeGlobalLogger(logger);
|
||||
|
||||
|
||||
// @electron/remote requires electron to be running. Mock it.
|
||||
jest.mock('@electron/remote', () => {
|
||||
return { require };
|
||||
});
|
||||
@@ -20,7 +20,7 @@ const NoteTag = require('@joplin/lib/models/NoteTag').default;
|
||||
const MasterKey = require('@joplin/lib/models/MasterKey').default;
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const Revision = require('@joplin/lib/models/Revision').default;
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const FsDriverNode = require('@joplin/lib/fs-driver-node').default;
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
const { shimInit } = require('@joplin/lib/shim-init-node.js');
|
||||
@@ -30,6 +30,13 @@ const { FileApiDriverLocal } = require('@joplin/lib/file-api-driver-local');
|
||||
const React = require('react');
|
||||
const nodeSqlite = require('sqlite3');
|
||||
|
||||
// Security: If we attempt to navigate away from the root HTML page, it's likely because
|
||||
// of an improperly sanitized link. Prevent this by closing the window before we can
|
||||
// navigate away.
|
||||
window.onbeforeunload = () => {
|
||||
window.close();
|
||||
};
|
||||
|
||||
if (bridge().env() === 'dev') {
|
||||
const newConsole = function(oldConsole) {
|
||||
const output = {};
|
||||
|
||||
@@ -4,7 +4,7 @@ const electronApp = require('electron').app;
|
||||
require('@electron/remote/main').initialize();
|
||||
const ElectronAppWrapper = require('./ElectronAppWrapper').default;
|
||||
const { initBridge } = require('./bridge');
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const FsDriverNode = require('@joplin/lib/fs-driver-node').default;
|
||||
const envFromArgs = require('@joplin/lib/envFromArgs');
|
||||
const packageInfo = require('./packageInfo.js');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.12.8",
|
||||
"version": "2.12.10",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
@@ -115,7 +115,7 @@
|
||||
"@types/react": "16.14.41",
|
||||
"@types/react-redux": "7.1.25",
|
||||
"@types/styled-components": "5.1.26",
|
||||
"electron": "25.2.0",
|
||||
"electron": "25.3.1",
|
||||
"electron-builder": "24.4.0",
|
||||
"glob": "10.2.7",
|
||||
"gulp": "4.0.2",
|
||||
@@ -138,6 +138,7 @@
|
||||
"@joeattardi/emoji-button": "4.6.4",
|
||||
"@joplin/lib": "~2.12",
|
||||
"@joplin/renderer": "~2.12",
|
||||
"@joplin/utils": "~2.12",
|
||||
"async-mutex": "0.4.0",
|
||||
"codemirror": "5.65.9",
|
||||
"color": "3.2.1",
|
||||
@@ -161,7 +162,7 @@
|
||||
"react": "18.2.0",
|
||||
"react-datetime": "3.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-redux": "8.0.7",
|
||||
"react-redux": "8.1.1",
|
||||
"react-select": "5.7.3",
|
||||
"react-toggle-button": "2.2.0",
|
||||
"react-tooltip": "4.5.1",
|
||||
|
||||
@@ -18,7 +18,7 @@ const { surroundKeywords, nextWhitespaceIndex, removeDiacritics } = require('@jo
|
||||
import { mergeOverlappingIntervals } from '@joplin/lib/ArrayUtils';
|
||||
import markupLanguageUtils from '../utils/markupLanguageUtils';
|
||||
import focusEditorIfEditorCommand from '@joplin/lib/services/commands/focusEditorIfEditorCommand';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { MarkupToHtml } from '@joplin/renderer';
|
||||
|
||||
const logger = Logger.create('GotoAnything');
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
# ./runForTesting.sh 1 createUsers,createData,reset,sync && ./runForTesting.sh 1a reset,sync && ./runForTesting.sh 1
|
||||
# ./runForTesting.sh 1a
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
# Team accounts:
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
# ./runForTesting.sh 1 createTeams,createData,resetTeam,sync && ./runForTesting.sh 2 resetTeam,sync && ./runForTesting.sh 1
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
@@ -54,13 +60,26 @@ if [ "$USER_NUM" = "1b" ]; then
|
||||
USER_PROFILE_NUM=1b
|
||||
fi
|
||||
|
||||
if [ "$USER_NUM" = "2a" ]; then
|
||||
USER_NUM=2
|
||||
USER_PROFILE_NUM=2a
|
||||
fi
|
||||
|
||||
if [ "$USER_NUM" = "2b" ]; then
|
||||
USER_NUM=2
|
||||
USER_PROFILE_NUM=2b
|
||||
fi
|
||||
|
||||
COMMANDS=($(echo $2 | tr "," "\n"))
|
||||
PROFILE_DIR=~/.config/joplindev-desktop-$USER_PROFILE_NUM
|
||||
SYNC_TARGET=10
|
||||
|
||||
CMD_FILE="$SCRIPT_DIR/runForTestingCommands-$USER_PROFILE_NUM.txt"
|
||||
rm -f "$CMD_FILE"
|
||||
touch "$CMD_FILE"
|
||||
|
||||
echo "Using sync target: $SYNC_TARGET"
|
||||
|
||||
for CMD in "${COMMANDS[@]}"
|
||||
do
|
||||
if [[ $CMD == "createUsers" ]]; then
|
||||
@@ -71,6 +90,10 @@ do
|
||||
|
||||
curl --data '{"action": "createUserDeletions"}' -H 'Content-Type: application/json' http://api.joplincloud.local:22300/api/debug
|
||||
|
||||
elif [[ $CMD == "createTeams" ]]; then
|
||||
|
||||
curl --data '{"action": "createTeams"}' -H 'Content-Type: application/json' http://api.joplincloud.local:22300/api/debug
|
||||
|
||||
elif [[ $CMD == "createData" ]]; then
|
||||
|
||||
echo 'mkbook "shared"' >> "$CMD_FILE"
|
||||
@@ -84,18 +107,26 @@ do
|
||||
USER_EMAIL="user$USER_NUM@example.com"
|
||||
rm -rf "$PROFILE_DIR"
|
||||
|
||||
# rm -rf "$HOME/Temp/SyncTestE2EE copy"
|
||||
# rsync -a "$HOME/Temp/SyncTestE2EE/" "$HOME/Temp/SyncTestE2EE copy/"
|
||||
echo "config keychain.supported 0" >> "$CMD_FILE"
|
||||
echo "config sync.target $SYNC_TARGET" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.username $USER_EMAIL" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.password 111111" >> "$CMD_FILE"
|
||||
|
||||
# echo "config sync.target 2" >> "$CMD_FILE"
|
||||
# echo "config sync.2.path \"$HOME/Temp/SyncTestE2EE copy/\"" >> "$CMD_FILE"
|
||||
if [[ $SYNC_TARGET = 9 ]]; then
|
||||
echo "config sync.$SYNC_TARGET.path http://api.joplincloud.local:22300" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.userContentPath http://joplinusercontent.local:22300" >> "$CMD_FILE"
|
||||
fi
|
||||
|
||||
elif [[ $CMD == "resetTeam" ]]; then
|
||||
|
||||
USER_EMAIL="teamuser1-$USER_NUM@example.com"
|
||||
rm -rf "$PROFILE_DIR"
|
||||
|
||||
echo "config keychain.supported 0" >> "$CMD_FILE"
|
||||
echo "config sync.target 10" >> "$CMD_FILE"
|
||||
# echo "config sync.10.path http://api.joplincloud.local:22300" >> "$CMD_FILE"
|
||||
echo "config sync.10.username $USER_EMAIL" >> "$CMD_FILE"
|
||||
echo "config sync.10.password 111111" >> "$CMD_FILE"
|
||||
|
||||
echo "config sync.target $SYNC_TARGET" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.username $USER_EMAIL" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.password 111111" >> "$CMD_FILE"
|
||||
|
||||
elif [[ $CMD == "e2ee" ]]; then
|
||||
|
||||
echo "e2ee enable --password 111111" >> "$CMD_FILE"
|
||||
@@ -104,11 +135,6 @@ do
|
||||
|
||||
echo "sync --use-lock 0" >> "$CMD_FILE"
|
||||
|
||||
# elif [[ $CMD == "generatePpk" ]]; then
|
||||
|
||||
# echo "e2ee generate-ppk --password 111111" >> "$CMD_FILE"
|
||||
# echo "sync" >> "$CMD_FILE"
|
||||
|
||||
else
|
||||
|
||||
echo "Unknown command: $CMD"
|
||||
|
||||
@@ -42,6 +42,11 @@ const create = (win, options) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// If another listener has called .preventDefault, don't show the default context menu.
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { editFlags } = props;
|
||||
const hasText = props.selectionText.trim().length > 0;
|
||||
const isLink = Boolean(props.linkURL);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import time from '@joplin/lib/time';
|
||||
|
||||
const logger = Logger.create('BackOffHandler');
|
||||
|
||||
@@ -5,6 +5,8 @@ import { VersionInfo } from '@joplin/lib/services/plugins/api/types';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import BasePlatformImplementation, { Joplin } from '@joplin/lib/services/plugins/BasePlatformImplementation';
|
||||
import { Dispatch } from 'redux';
|
||||
import { readFile } from 'fs-extra';
|
||||
const { clipboard, nativeImage } = require('electron');
|
||||
const packageInfo = require('../../packageInfo');
|
||||
|
||||
@@ -20,12 +22,17 @@ export default class PlatformImplementation extends BasePlatformImplementation {
|
||||
private static instance_: PlatformImplementation;
|
||||
private joplin_: Joplin;
|
||||
private components_: Components;
|
||||
private dispatch_: Dispatch|null = null;
|
||||
|
||||
public static instance(): PlatformImplementation {
|
||||
if (!this.instance_) this.instance_ = new PlatformImplementation();
|
||||
return this.instance_;
|
||||
}
|
||||
|
||||
public initialize(dispatch: Dispatch) {
|
||||
this.dispatch_ = dispatch;
|
||||
}
|
||||
|
||||
public get versionInfo(): VersionInfo {
|
||||
return {
|
||||
version: packageInfo.version,
|
||||
@@ -45,6 +52,14 @@ export default class PlatformImplementation extends BasePlatformImplementation {
|
||||
public get window(): WindowImplementation {
|
||||
return {
|
||||
injectCustomStyles: injectCustomStyles,
|
||||
loadNoteCssFile: async (filePath) => {
|
||||
const cssString = await readFile(filePath, 'utf8');
|
||||
|
||||
this.dispatch_({
|
||||
type: 'CUSTOM_CSS_APPEND',
|
||||
css: cssString,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import bridge from '../bridge';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { EventHandlers } from '@joplin/lib/services/plugins/utils/mapEventHandlersToIds';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
// import BackOffHandler from './BackOffHandler';
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import useSubmitHandler from './hooks/useSubmitHandler';
|
||||
import useHtmlLoader from './hooks/useHtmlLoader';
|
||||
import useWebviewToPluginMessages from './hooks/useWebviewToPluginMessages';
|
||||
import useScriptLoader from './hooks/useScriptLoader';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const logger = Logger.create('UserWebview');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import SpellCheckerServiceDriverBase from '@joplin/lib/services/spellChecker/SpellCheckerServiceDriverBase';
|
||||
import bridge from '../bridge';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { languageCodeOnly, localesFromLanguageCode } from '@joplin/lib/locale';
|
||||
|
||||
const logger = Logger.create('SpellCheckerServiceDriverNative');
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@use 'gui/EditFolderDialog/style.scss' as edit-folder-dialog;
|
||||
@use 'gui/EncryptionConfigScreen/style.scss' as encryption-config-screen;
|
||||
@use 'gui/PasswordInput/style.scss' as password-input;
|
||||
@use 'gui/JoplinCloudConfigScreen.scss' as joplin-cloud-config-screen;
|
||||
@use 'gui/Dropdown/style.scss' as dropdown-control;
|
||||
@use 'gui/ShareFolderDialog/style.scss' as share-folder-dialog;
|
||||
@use 'main.scss' as main;
|
||||
@@ -47,7 +47,7 @@ react {
|
||||
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
|
||||
//
|
||||
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||
// hermesFlags = ["-O", "-output-source-map"]
|
||||
hermesFlags = ["-O", "-output-source-map"]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATION" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
|
||||
<!-- Make these features optional to enable Chromebooks -->
|
||||
<!-- https://github.com/laurent22/joplin/issues/37 -->
|
||||
|
||||
@@ -15,7 +15,7 @@ interface FolderPickerProps {
|
||||
folders: FolderEntity[];
|
||||
placeholder?: string;
|
||||
darkText?: boolean;
|
||||
themeId?: string;
|
||||
themeId?: number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { useEffect, useState, useMemo, useRef } from 'react';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
const { themeStyle } = require('../../global-style.js');
|
||||
import markupLanguageUtils from '@joplin/lib/markupLanguageUtils';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import markupLanguageUtils from '../../../utils/markupLanguageUtils';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
const { assetsToHeaders } = require('@joplin/renderer');
|
||||
|
||||
const logger = Logger.create('NoteBodyViewer/useSource');
|
||||
|
||||
@@ -17,6 +17,7 @@ const createEditorSettings = (themeId: number) => {
|
||||
const editorSettings: EditorSettings = {
|
||||
katexEnabled: true,
|
||||
spellcheckEnabled: true,
|
||||
readOnly: false,
|
||||
themeId,
|
||||
themeData,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { EditorSelection } from '@codemirror/state';
|
||||
import { ListType } from '../types';
|
||||
import createEditor from './testUtil/createEditor';
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { EditorSelection } from '@codemirror/state';
|
||||
import {
|
||||
toggleBolded, toggleCode, toggleHeaderLevel, toggleItalicized, toggleMath, updateLink,
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { EditorSelection, EditorState } from '@codemirror/state';
|
||||
import {
|
||||
increaseIndent, toggleList,
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { syntaxTree } from '@codemirror/language';
|
||||
import { SyntaxNode } from '@lezer/common';
|
||||
import { EditorSelection, EditorState } from '@codemirror/state';
|
||||
|
||||
@@ -82,9 +82,11 @@ interface ScreenHeaderProps {
|
||||
historyCanGoBack?: boolean;
|
||||
showMissingMasterKeyMessage?: boolean;
|
||||
hasDisabledSyncItems?: boolean;
|
||||
hasDisabledEncryptionItems?: boolean;
|
||||
shouldUpgradeSyncTarget?: boolean;
|
||||
showShouldUpgradeSyncTargetMessage?: boolean;
|
||||
|
||||
themeId: number;
|
||||
}
|
||||
|
||||
interface ScreenHeaderState {
|
||||
@@ -99,7 +101,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
}
|
||||
|
||||
private styles() {
|
||||
const themeId = Setting.value('theme');
|
||||
const themeId = this.props.themeId;
|
||||
if (this.cachedStyles[themeId]) return this.cachedStyles[themeId];
|
||||
this.cachedStyles = {};
|
||||
|
||||
@@ -296,7 +298,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
}
|
||||
|
||||
public render() {
|
||||
const themeId = Setting.value('theme');
|
||||
const themeId = this.props.themeId;
|
||||
function sideMenuButton(styles: any, onPress: OnPressCallback) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
@@ -563,6 +565,10 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
if (this.props.hasDisabledSyncItems) warningComps.push(this.renderWarningBox('Status', _('Some items cannot be synchronised. Press for more info.')));
|
||||
if (this.props.shouldUpgradeSyncTarget && this.props.showShouldUpgradeSyncTargetMessage !== false) warningComps.push(this.renderWarningBox('UpgradeSyncTarget', _('The sync target needs to be upgraded. Press this banner to proceed.')));
|
||||
|
||||
if (this.props.hasDisabledEncryptionItems) {
|
||||
warningComps.push(this.renderWarningBox('Status', _('Some items cannot be decrypted.')));
|
||||
}
|
||||
|
||||
const showSideMenuButton = !!this.props.showSideMenuButton && !this.props.noteSelectionEnabled;
|
||||
const showSelectAllButton = this.props.noteSelectionEnabled;
|
||||
const showSearchButton = !!this.props.showSearchButton && !this.props.noteSelectionEnabled;
|
||||
@@ -649,6 +655,7 @@ const ScreenHeader = connect((state: State) => {
|
||||
locale: state.settings.locale,
|
||||
folders: state.folders,
|
||||
themeId: state.settings.theme,
|
||||
hasDisabledEncryptionItems: state.hasDisabledEncryptionItems,
|
||||
noteSelectionEnabled: state.noteSelectionEnabled,
|
||||
selectedNoteIds: state.selectedNoteIds,
|
||||
showMissingMasterKeyMessage: showMissingMasterKeyMessage(syncInfo, state.notLoadedMasterKeys),
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { View, Dimensions, Alert, Button } from 'react-native';
|
||||
import { SensorInfo } from './sensorInfo';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import biometricAuthenticate from './biometricAuthenticate';
|
||||
|
||||
const logger = Logger.create('BiometricPopup');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import FingerprintScanner, { Errors } from 'react-native-fingerprint-scanner';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import FingerprintScanner from 'react-native-fingerprint-scanner';
|
||||
const logger = Logger.create('sensorInfo');
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-member-accessibility */
|
||||
import Slider from '@react-native-community/slider';
|
||||
const React = require('react');
|
||||
import { Platform, Linking, View, Switch, StyleSheet, ScrollView, Text, Button, TouchableOpacity, TextInput, Alert, PermissionsAndroid, TouchableNativeFeedback } from 'react-native';
|
||||
import { Platform, Linking, View, Switch, ScrollView, Text, Button, TouchableOpacity, TextInput, Alert, PermissionsAndroid, TouchableNativeFeedback } from 'react-native';
|
||||
import Setting, { AppType } from '@joplin/lib/models/Setting';
|
||||
import NavService from '@joplin/lib/services/NavService';
|
||||
import ReportService from '@joplin/lib/services/ReportService';
|
||||
import SearchEngine from '@joplin/lib/services/searchengine/SearchEngine';
|
||||
import checkPermissions from '../../utils/checkPermissions';
|
||||
import checkPermissions from '../../../utils/checkPermissions';
|
||||
import time from '@joplin/lib/time';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import setIgnoreTlsErrors from '../../utils/TlsUtils';
|
||||
import setIgnoreTlsErrors from '../../../utils/TlsUtils';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import { State } from '@joplin/lib/reducer';
|
||||
const { BackButtonService } = require('../../services/back-button.js');
|
||||
const { BackButtonService } = require('../../../services/back-button.js');
|
||||
const VersionInfo = require('react-native-version-info').default;
|
||||
const { connect } = require('react-redux');
|
||||
import ScreenHeader from '../ScreenHeader';
|
||||
import ScreenHeader from '../../ScreenHeader';
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const { BaseScreenComponent } = require('../base-screen.js');
|
||||
const { Dropdown } = require('../Dropdown.js');
|
||||
const { themeStyle } = require('../global-style.js');
|
||||
const { BaseScreenComponent } = require('../../base-screen.js');
|
||||
const { Dropdown } = require('../../Dropdown');
|
||||
const { themeStyle } = require('../../global-style.js');
|
||||
const shared = require('@joplin/lib/components/shared/config-shared.js');
|
||||
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
|
||||
import { openDocumentTree } from '@joplin/react-native-saf-x';
|
||||
import biometricAuthenticate from '../biometrics/biometricAuthenticate';
|
||||
import biometricAuthenticate from '../../biometrics/biometricAuthenticate';
|
||||
import configScreenStyles from './configScreenStyles';
|
||||
import NoteExportButton from './NoteExportSection/NoteExportButton';
|
||||
import ConfigScreenButton from './ConfigScreenButton';
|
||||
import Clipboard from '@react-native-community/clipboard';
|
||||
|
||||
class ConfigScreenComponent extends BaseScreenComponent {
|
||||
public static navigationOptions(): any {
|
||||
@@ -223,94 +227,11 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
|
||||
public styles() {
|
||||
const themeId = this.props.themeId;
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
if (this.styles_[themeId]) return this.styles_[themeId];
|
||||
this.styles_ = {};
|
||||
|
||||
const styles: any = {
|
||||
body: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-start',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
settingContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
paddingTop: theme.marginTop,
|
||||
paddingBottom: theme.marginBottom,
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
},
|
||||
settingText: {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
flex: 1,
|
||||
paddingRight: 5,
|
||||
},
|
||||
descriptionText: {
|
||||
color: theme.colorFaded,
|
||||
fontSize: theme.fontSizeSmaller,
|
||||
flex: 1,
|
||||
},
|
||||
sliderUnits: {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
marginRight: 10,
|
||||
},
|
||||
settingDescriptionText: {
|
||||
color: theme.colorFaded,
|
||||
fontSize: theme.fontSizeSmaller,
|
||||
flex: 1,
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
paddingBottom: theme.marginBottom,
|
||||
},
|
||||
permissionText: {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
flex: 1,
|
||||
marginTop: 10,
|
||||
},
|
||||
settingControl: {
|
||||
color: theme.color,
|
||||
flex: 1,
|
||||
},
|
||||
textInput: {
|
||||
color: theme.color,
|
||||
},
|
||||
};
|
||||
|
||||
styles.settingContainerNoBottomBorder = { ...styles.settingContainer, borderBottomWidth: 0,
|
||||
paddingBottom: theme.marginBottom / 2 };
|
||||
|
||||
styles.settingControl.borderBottomWidth = 1;
|
||||
styles.settingControl.borderBottomColor = theme.dividerColor;
|
||||
|
||||
styles.switchSettingText = { ...styles.settingText };
|
||||
styles.switchSettingText.width = '80%';
|
||||
|
||||
styles.switchSettingContainer = { ...styles.settingContainer };
|
||||
styles.switchSettingContainer.flexDirection = 'row';
|
||||
styles.switchSettingContainer.justifyContent = 'space-between';
|
||||
|
||||
styles.linkText = { ...styles.settingText };
|
||||
styles.linkText.borderBottomWidth = 1;
|
||||
styles.linkText.borderBottomColor = theme.color;
|
||||
styles.linkText.flex = 0;
|
||||
styles.linkText.fontWeight = 'normal';
|
||||
|
||||
styles.headerWrapperStyle = { ...styles.settingContainer, ...theme.headerWrapperStyle };
|
||||
|
||||
styles.switchSettingControl = { ...styles.settingControl };
|
||||
delete styles.switchSettingControl.color;
|
||||
// styles.switchSettingControl.width = '20%';
|
||||
styles.switchSettingControl.flex = 0;
|
||||
|
||||
this.styles_[themeId] = StyleSheet.create(styles);
|
||||
this.styles_[themeId] = configScreenStyles(themeId);
|
||||
return this.styles_[themeId];
|
||||
}
|
||||
|
||||
@@ -388,28 +309,16 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
);
|
||||
}
|
||||
|
||||
renderButton(key: string, title: string, clickHandler: ()=> void, options: any = null) {
|
||||
if (!options) options = {};
|
||||
|
||||
let descriptionComp = null;
|
||||
if (options.description) {
|
||||
descriptionComp = (
|
||||
<View style={{ flex: 1, marginTop: 10 }}>
|
||||
<Text style={this.styles().descriptionText}>{options.description}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
private renderButton(key: string, title: string, clickHandler: ()=> void, options: any = null) {
|
||||
return (
|
||||
<View key={key} style={this.styles().settingContainer}>
|
||||
<View style={{ flex: 1, flexDirection: 'column' }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Button title={title} onPress={clickHandler} disabled={!!options.disabled} />
|
||||
</View>
|
||||
{options.statusComp}
|
||||
{descriptionComp}
|
||||
</View>
|
||||
</View>
|
||||
<ConfigScreenButton
|
||||
key={key}
|
||||
title={title}
|
||||
clickHandler={clickHandler}
|
||||
description={options?.description}
|
||||
statusComponent={options?.statusComp}
|
||||
styles={this.styles()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -447,6 +356,26 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
settingComps.push(this.renderButton('e2ee_config_button', _('Encryption Config'), this.e2eeConfig_));
|
||||
}
|
||||
|
||||
if (section.name === 'joplinCloud') {
|
||||
const description = _('Any email sent to this address will be converted into a note and added to your collection. The note will be saved into the Inbox notebook');
|
||||
settingComps.push(
|
||||
<View key="joplinCloud">
|
||||
<View style={this.styles().settingContainerNoBottomBorder}>
|
||||
<Text style={this.styles().settingText}>{_('Email to note')}</Text>
|
||||
<Text style={{ fontWeight: 'bold' }}>{this.props.settings['sync.10.inboxEmail']}</Text>
|
||||
</View>
|
||||
{
|
||||
this.renderButton(
|
||||
'sync.10.inboxEmail',
|
||||
_('Copy to clipboard'),
|
||||
() => Clipboard.setString(this.props.settings['sync.10.inboxEmail']),
|
||||
{ description }
|
||||
)
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (!settingComps.length) return null;
|
||||
|
||||
return (
|
||||
@@ -642,12 +571,13 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
settingComps.push(this.renderButton('profiles_buttons', _('Manage profiles'), this.manageProfilesButtonPress_));
|
||||
settingComps.push(this.renderButton('status_button', _('Sync Status'), this.syncStatusButtonPress_));
|
||||
settingComps.push(this.renderButton('log_button', _('Log'), this.logButtonPress_));
|
||||
if (Platform.OS === 'android') {
|
||||
settingComps.push(this.renderButton('export_report_button', this.state.creatingReport ? _('Creating report...') : _('Export Debug Report'), this.exportDebugButtonPress_, { disabled: this.state.creatingReport }));
|
||||
}
|
||||
settingComps.push(this.renderButton('fix_search_engine_index', this.state.fixingSearchIndex ? _('Fixing search index...') : _('Fix search index'), this.fixSearchEngineIndexButtonPress_, { disabled: this.state.fixingSearchIndex, description: _('Use this to rebuild the search index if there is a problem with search. It may take a long time depending on the number of notes.') }));
|
||||
|
||||
settingComps.push(this.renderHeader('export', _('Export')));
|
||||
settingComps.push(<NoteExportButton key={'export_as_jex_button'} styles={this.styles()} />);
|
||||
|
||||
if (shim.mobilePlatform() === 'android') {
|
||||
settingComps.push(this.renderButton('export_report_button', this.state.creatingReport ? _('Creating report...') : _('Export Debug Report'), this.exportDebugButtonPress_, { disabled: this.state.creatingReport }));
|
||||
settingComps.push(this.renderButton('export_data', this.state.profileExportStatus === 'exporting' ? _('Exporting profile...') : _('Export profile'), this.exportProfileButtonPress_, { disabled: this.state.profileExportStatus === 'exporting', description: _('For debugging purpose only: export your profile to an external SD card.') }));
|
||||
|
||||
if (this.state.profileExportStatus === 'prompt') {
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
import * as React from 'react';
|
||||
import { FunctionComponent, ReactNode } from 'react';
|
||||
import { View, Text, Button } from 'react-native';
|
||||
import { ConfigScreenStyles } from './configScreenStyles';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
clickHandler: ()=> void;
|
||||
styles: ConfigScreenStyles;
|
||||
disabled?: boolean;
|
||||
statusComponent?: ReactNode;
|
||||
}
|
||||
|
||||
const ConfigScreenButton: FunctionComponent<Props> = props => {
|
||||
let descriptionComp = null;
|
||||
if (props.description) {
|
||||
descriptionComp = (
|
||||
<View style={{ flex: 1, marginTop: 10 }}>
|
||||
<Text style={props.styles.descriptionText}>{props.description}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={props.styles.settingContainer}>
|
||||
<View style={{ flex: 1, flexDirection: 'column' }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Button title={props.title} onPress={props.clickHandler} disabled={!!props.disabled} />
|
||||
</View>
|
||||
{props.statusComponent}
|
||||
{descriptionComp}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
export default ConfigScreenButton;
|
||||
@@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { act, fireEvent, render, waitFor } from '@testing-library/react-native';
|
||||
import { expect, describe, beforeEach, test, jest } from '@jest/globals';
|
||||
import '@testing-library/jest-native/extend-expect';
|
||||
import { createNTestNotes, setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import configScreenStyles from '../configScreenStyles';
|
||||
import { type ShareOptions } from 'react-native-share';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import NoteExportButton from './NoteExportButton';
|
||||
|
||||
jest.mock('react-native-share', () => {
|
||||
const Share = {
|
||||
open: (_options: ShareOptions) => jest.fn(),
|
||||
};
|
||||
return { default: Share };
|
||||
});
|
||||
|
||||
describe('NoteExportButton', () => {
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
|
||||
const folder1 = await Folder.save({ title: 'folder1' });
|
||||
await createNTestNotes(10, folder1);
|
||||
|
||||
const folder2 = await Folder.save({ title: 'Folder 2 🙂' });
|
||||
await createNTestNotes(10, folder2);
|
||||
});
|
||||
|
||||
test('should show "Exported successfully!" after clicking "Export"', async () => {
|
||||
const styles = configScreenStyles(Setting.THEME_DARK);
|
||||
const view = render(<NoteExportButton
|
||||
styles={styles}
|
||||
/>);
|
||||
|
||||
const exportButton = view.getByText(_('Export all notes as JEX'));
|
||||
await act(() => fireEvent.press(exportButton));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(view.queryByText(_('Exported successfully!'))).not.toBeNull()
|
||||
);
|
||||
|
||||
// With the default folder setup, there should be no warnings
|
||||
expect(view.queryByText(/Warnings/g)).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,114 @@
|
||||
import * as React from 'react';
|
||||
import { Text, Alert, View } from 'react-native';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { ProgressBar } from 'react-native-paper';
|
||||
import { FunctionComponent, useCallback, useState } from 'react';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import { join } from 'path';
|
||||
import Share from 'react-native-share';
|
||||
import exportAllFolders, { makeExportCacheDirectory } from './exportAllFolders';
|
||||
import { ExportProgressState } from '@joplin/lib/services/interop/types';
|
||||
import { ConfigScreenStyles } from '../configScreenStyles';
|
||||
import ConfigScreenButton from '../ConfigScreenButton';
|
||||
|
||||
const logger = Logger.create('NoteExportButton');
|
||||
|
||||
interface Props {
|
||||
styles: ConfigScreenStyles;
|
||||
}
|
||||
|
||||
enum ExportStatus {
|
||||
NotStarted,
|
||||
Exporting,
|
||||
Exported,
|
||||
}
|
||||
|
||||
const NoteExportButton: FunctionComponent<Props> = props => {
|
||||
const [exportStatus, setExportStatus] = useState<ExportStatus>(ExportStatus.NotStarted);
|
||||
const [exportProgress, setExportProgress] = useState<number|undefined>(0);
|
||||
const [warnings, setWarnings] = useState<string>('');
|
||||
|
||||
const startExport = useCallback(async () => {
|
||||
// Don't run multiple exports at the same time.
|
||||
if (exportStatus === ExportStatus.Exporting) {
|
||||
return;
|
||||
}
|
||||
|
||||
setExportStatus(ExportStatus.Exporting);
|
||||
const exportTargetPath = join(await makeExportCacheDirectory(), 'jex-export.jex');
|
||||
logger.info(`Exporting all folders to path ${exportTargetPath}`);
|
||||
|
||||
try {
|
||||
// Initially, undetermined progress
|
||||
setExportProgress(undefined);
|
||||
|
||||
const status = await exportAllFolders(exportTargetPath, (status, progress) => {
|
||||
if (progress !== null) {
|
||||
setExportProgress(progress);
|
||||
} else if (status === ExportProgressState.Closing || status === ExportProgressState.QueuingItems) {
|
||||
// We don't have a numeric progress value and the closing/queuing state may take a while.
|
||||
// Set a special progress value:
|
||||
setExportProgress(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
setExportStatus(ExportStatus.Exported);
|
||||
setWarnings(status.warnings.join('\n'));
|
||||
|
||||
await Share.open({
|
||||
type: 'application/jex',
|
||||
filename: 'export.jex',
|
||||
url: `file://${exportTargetPath}`,
|
||||
failOnCancel: false,
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Unable to export:', e);
|
||||
|
||||
// Display a message to the user (e.g. in the case where the user is out of disk space).
|
||||
Alert.alert(_('Error'), _('Unable to export or share data. Reason: %s', e.toString()));
|
||||
setExportStatus(ExportStatus.NotStarted);
|
||||
} finally {
|
||||
await shim.fsDriver().remove(exportTargetPath);
|
||||
}
|
||||
}, [exportStatus]);
|
||||
|
||||
if (exportStatus === ExportStatus.NotStarted || exportStatus === ExportStatus.Exporting) {
|
||||
const progressComponent = (
|
||||
<ProgressBar
|
||||
visible={exportStatus === ExportStatus.Exporting}
|
||||
indeterminate={exportProgress === undefined}
|
||||
progress={exportProgress}/>
|
||||
);
|
||||
const descriptionText = _('Share a copy of all notes in a file format that can be imported by Joplin on a computer.');
|
||||
|
||||
const startOrCancelExportButton = (
|
||||
<ConfigScreenButton
|
||||
title={exportStatus === ExportStatus.Exporting ? _('Exporting...') : _('Export all notes as JEX')}
|
||||
disabled={exportStatus === ExportStatus.Exporting}
|
||||
description={exportStatus === ExportStatus.NotStarted ? descriptionText : null}
|
||||
statusComponent={progressComponent}
|
||||
clickHandler={startExport}
|
||||
styles={props.styles}
|
||||
/>
|
||||
);
|
||||
|
||||
return startOrCancelExportButton;
|
||||
} else {
|
||||
const warningComponent = (
|
||||
<Text style={props.styles.warningText}>
|
||||
{_('Warnings:\n%s', warnings)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const exportSummary = (
|
||||
<View style={props.styles.settingContainer}>
|
||||
<Text style={props.styles.descriptionText}>{_('Exported successfully!')}</Text>
|
||||
{warnings.length > 0 ? warningComponent : null}
|
||||
</View>
|
||||
);
|
||||
return exportSummary;
|
||||
}
|
||||
};
|
||||
|
||||
export default NoteExportButton;
|
||||
@@ -0,0 +1,29 @@
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import InteropService from '@joplin/lib/services/interop/InteropService';
|
||||
import { ExportOptions, FileSystemItem, OnExportProgressCallback } from '@joplin/lib/services/interop/types';
|
||||
import shim from '@joplin/lib/shim';
|
||||
|
||||
import { CachesDirectoryPath } from 'react-native-fs';
|
||||
export const makeExportCacheDirectory = async () => {
|
||||
const targetDir = `${CachesDirectoryPath}/exports`;
|
||||
await shim.fsDriver().mkdir(targetDir);
|
||||
|
||||
return targetDir;
|
||||
};
|
||||
|
||||
const exportFolders = async (path: string, onProgress: OnExportProgressCallback) => {
|
||||
const folders = await Folder.all();
|
||||
|
||||
const sourceFolderIds = folders.map(folder => folder.id);
|
||||
const exportOptions: ExportOptions = {
|
||||
sourceFolderIds,
|
||||
path,
|
||||
format: 'jex',
|
||||
target: FileSystemItem.File,
|
||||
onProgress,
|
||||
};
|
||||
|
||||
return await InteropService.instance().export(exportOptions);
|
||||
};
|
||||
|
||||
export default exportFolders;
|
||||
@@ -0,0 +1,137 @@
|
||||
import { TextStyle, ViewStyle, StyleSheet } from 'react-native';
|
||||
const { themeStyle } = require('../../global-style.js');
|
||||
|
||||
export interface ConfigScreenStyles {
|
||||
body: ViewStyle;
|
||||
|
||||
settingContainer: ViewStyle;
|
||||
settingContainerNoBottomBorder: ViewStyle;
|
||||
headerWrapperStyle: ViewStyle;
|
||||
|
||||
settingText: TextStyle;
|
||||
linkText: TextStyle;
|
||||
descriptionText: TextStyle;
|
||||
warningText: TextStyle;
|
||||
|
||||
sliderUnits: TextStyle;
|
||||
settingDescriptionText: TextStyle;
|
||||
permissionText: TextStyle;
|
||||
textInput: TextStyle;
|
||||
|
||||
switchSettingText: TextStyle;
|
||||
switchSettingContainer: ViewStyle;
|
||||
switchSettingControl: TextStyle;
|
||||
|
||||
settingControl: TextStyle;
|
||||
}
|
||||
|
||||
const configScreenStyles = (themeId: number): ConfigScreenStyles => {
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
const settingContainerStyle: ViewStyle = {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
paddingTop: theme.marginTop,
|
||||
paddingBottom: theme.marginBottom,
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
};
|
||||
|
||||
const settingTextStyle: TextStyle = {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
flex: 1,
|
||||
paddingRight: 5,
|
||||
};
|
||||
|
||||
const settingControlStyle: TextStyle = {
|
||||
color: theme.color,
|
||||
flex: 1,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
};
|
||||
|
||||
const styles: ConfigScreenStyles = {
|
||||
body: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-start',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
settingContainer: settingContainerStyle,
|
||||
settingContainerNoBottomBorder: {
|
||||
...settingContainerStyle,
|
||||
borderBottomWidth: 0,
|
||||
paddingBottom: theme.marginBottom / 2,
|
||||
},
|
||||
settingText: settingTextStyle,
|
||||
descriptionText: {
|
||||
color: theme.colorFaded,
|
||||
fontSize: theme.fontSizeSmaller,
|
||||
flex: 1,
|
||||
},
|
||||
linkText: {
|
||||
...settingTextStyle,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.color,
|
||||
flex: 0,
|
||||
fontWeight: 'normal',
|
||||
},
|
||||
warningText: {
|
||||
color: theme.color,
|
||||
backgroundColor: theme.warningBackgroundColor,
|
||||
fontSize: theme.fontSizeSmaller,
|
||||
},
|
||||
|
||||
sliderUnits: {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
marginRight: 10,
|
||||
},
|
||||
settingDescriptionText: {
|
||||
color: theme.colorFaded,
|
||||
fontSize: theme.fontSizeSmaller,
|
||||
flex: 1,
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
paddingBottom: theme.marginBottom,
|
||||
},
|
||||
permissionText: {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
flex: 1,
|
||||
marginTop: 10,
|
||||
},
|
||||
settingControl: settingControlStyle,
|
||||
textInput: {
|
||||
color: theme.color,
|
||||
},
|
||||
|
||||
switchSettingText: {
|
||||
...settingTextStyle,
|
||||
width: '80%',
|
||||
},
|
||||
switchSettingContainer: {
|
||||
...settingContainerStyle,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
|
||||
headerWrapperStyle: {
|
||||
...settingContainerStyle,
|
||||
...theme.headerWrapperStyle,
|
||||
},
|
||||
|
||||
switchSettingControl: {
|
||||
...settingControlStyle,
|
||||
color: undefined,
|
||||
flex: 0,
|
||||
},
|
||||
};
|
||||
|
||||
return StyleSheet.create(styles);
|
||||
};
|
||||
|
||||
export default configScreenStyles;
|
||||
@@ -43,7 +43,7 @@ import SelectDateTimeDialog from '../SelectDateTimeDialog';
|
||||
import ShareExtension from '../../utils/ShareExtension.js';
|
||||
import CameraView from '../CameraView';
|
||||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import VoiceTypingDialog from '../voiceTyping/VoiceTypingDialog';
|
||||
import { voskEnabled } from '../../services/voiceTyping/vosk';
|
||||
import { isSupportedLanguage } from '../../services/voiceTyping/vosk.android';
|
||||
|
||||
@@ -6,7 +6,7 @@ const { reg } = require('@joplin/lib/registry.js');
|
||||
const { ScreenHeader } = require('../ScreenHeader');
|
||||
const time = require('@joplin/lib/time').default;
|
||||
const { themeStyle } = require('../global-style.js');
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Logger = require('@joplin/utils/Logger').default;
|
||||
const { BaseScreenComponent } = require('../base-screen.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ interface Props {
|
||||
folders: FolderEntity[];
|
||||
opacity: number;
|
||||
profileConfig: ProfileConfig;
|
||||
inboxJopId: string;
|
||||
}
|
||||
|
||||
const syncIconRotationValue = new Animated.Value(0);
|
||||
@@ -136,6 +137,31 @@ const SideMenuContentComponent = (props: Props) => {
|
||||
|
||||
const folder = folderOrAll as FolderEntity;
|
||||
|
||||
const generateFolderDeletion = () => {
|
||||
const folderDeletion = (message: string) => {
|
||||
Alert.alert('', message, [
|
||||
{
|
||||
text: _('OK'),
|
||||
onPress: () => {
|
||||
void Folder.delete(folder.id);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: _('Cancel'),
|
||||
onPress: () => { },
|
||||
style: 'cancel',
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
if (folder.id === props.inboxJopId) {
|
||||
return folderDeletion(
|
||||
_('Delete the Inbox notebook?\n\nIf you delete the inbox notebook, any email that\'s recently been sent to it may be lost.')
|
||||
);
|
||||
}
|
||||
return folderDeletion(_('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', folder.title));
|
||||
};
|
||||
|
||||
Alert.alert(
|
||||
'',
|
||||
_('Notebook: %s', folder.title),
|
||||
@@ -154,21 +180,7 @@ const SideMenuContentComponent = (props: Props) => {
|
||||
},
|
||||
{
|
||||
text: _('Delete'),
|
||||
onPress: () => {
|
||||
Alert.alert('', _('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', folder.title), [
|
||||
{
|
||||
text: _('OK'),
|
||||
onPress: () => {
|
||||
void Folder.delete(folder.id);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: _('Cancel'),
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
]);
|
||||
},
|
||||
onPress: generateFolderDeletion,
|
||||
style: 'destructive',
|
||||
},
|
||||
{
|
||||
@@ -516,5 +528,6 @@ export default connect((state: AppState) => {
|
||||
isOnMobileData: state.isOnMobileData,
|
||||
syncOnlyOverWifi: state.settings['sync.mobileWifiOnly'],
|
||||
profileConfig: state.profileConfig,
|
||||
inboxJopId: state.settings['sync.10.inboxId'],
|
||||
};
|
||||
})(SideMenuContentComponent);
|
||||
|
||||
@@ -328,7 +328,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=/usr/local/bin/node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||
shellScript = "export NODE_BINARY=/usr/local/bin/node\nexport SOURCEMAP_FILE=\"$(pwd)/../main.jsbundle.map\";\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||
};
|
||||
027E2AA6B101F8CFCA582EC1 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
</array>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Light</string>
|
||||
<string>Automatic</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
|
||||
@@ -355,7 +355,7 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-image-resizer (1.4.5):
|
||||
- React-Core
|
||||
- react-native-netinfo (9.3.10):
|
||||
- react-native-netinfo (9.3.11):
|
||||
- React-Core
|
||||
- react-native-rsa-native (2.0.5):
|
||||
- React
|
||||
@@ -467,7 +467,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNDateTimePicker (7.1.0):
|
||||
- React-Core
|
||||
- RNDeviceInfo (10.6.0):
|
||||
- RNDeviceInfo (10.6.1):
|
||||
- React-Core
|
||||
- RNExitApp (1.1.0):
|
||||
- React
|
||||
@@ -475,9 +475,9 @@ PODS:
|
||||
- React-Core
|
||||
- RNFS (2.20.0):
|
||||
- React-Core
|
||||
- RNGestureHandler (2.10.2):
|
||||
- RNGestureHandler (2.12.0):
|
||||
- React-Core
|
||||
- RNLocalize (3.0.1):
|
||||
- RNLocalize (3.0.2):
|
||||
- React-Core
|
||||
- RNQuickAction (0.3.13):
|
||||
- React
|
||||
@@ -782,9 +782,9 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
boost: 57d2868c099736d80fcd648bf211b4431e51a558
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
FBLazyVector: ddb55c55295ea51ed98aa7e2e08add2f826309d5
|
||||
FBReactNativeSpec: 90fc1a90b4b7a171e0a7c20ea426c1bf6ce4399c
|
||||
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
|
||||
@@ -797,13 +797,13 @@ SPEC CHECKSUMS:
|
||||
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
|
||||
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 5337263514dd6f09803962437687240c5dc39aa4
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
hermes-engine: d27603b55a48402501ad1928c05411dae9cd6b85
|
||||
JoplinCommonShareExtension: a8b60b02704d85a7305627912c0240e94af78db7
|
||||
JoplinRNShareExtension: 485f3e6dad83b7b77f1572eabc249f869ee55c02
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
|
||||
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
|
||||
RCTRequired: 8ef706f91e2b643cd32c26a57700b5f24fab0585
|
||||
RCTTypeSafety: 5fbddd8eb9242b91ac0d901c01da3673f358b1b7
|
||||
React: e5d2d559e89d256a1d6da64d51adaecda9c8ddae
|
||||
@@ -825,7 +825,7 @@ SPEC CHECKSUMS:
|
||||
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
|
||||
react-native-image-picker: 77f552291e993f3fdcdf48cc3c280ef7f11789c8
|
||||
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
|
||||
react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
|
||||
react-native-netinfo: 3a48f51c18dbd9253440621955e11de71bc51b32
|
||||
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
|
||||
react-native-saf-x: 129cd2ddf120a1f6164c724b2846d172666b33de
|
||||
react-native-safe-area-context: 33e71d7408dffe148b08968d97a524009634ccc8
|
||||
@@ -850,12 +850,12 @@ SPEC CHECKSUMS:
|
||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||
RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8
|
||||
RNDateTimePicker: 7ecd54a97fc3749f38c3c89a171f6cbd52f3c142
|
||||
RNDeviceInfo: 475a4c447168d0ad4c807e48ef5e0963a0f4eb1b
|
||||
RNDeviceInfo: ab292735ad4fccc5f2aec0c773f7a7f03c7073ae
|
||||
RNExitApp: c4e052df2568b43bec8a37c7cd61194d4cfee2c3
|
||||
RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592
|
||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||
RNGestureHandler: f75d81410b40aaa99e71ae8f8bb7a88620c95042
|
||||
RNLocalize: 6dd9226886fa61bf0cefc7644e3f9620770b1a31
|
||||
RNGestureHandler: dec4645026e7401a0899f2846d864403478ff6a5
|
||||
RNLocalize: dbea38dcb344bf80ff18a1757b1becf11f70cae4
|
||||
RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93
|
||||
RNReanimated: 9976fbaaeb8a188c36026154c844bf374b3b7eeb
|
||||
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
|
||||
|
||||
@@ -5,15 +5,22 @@ module.exports = {
|
||||
'ts',
|
||||
'tsx',
|
||||
'js',
|
||||
'jsx',
|
||||
],
|
||||
|
||||
'transform': {
|
||||
'\\.(ts|tsx)$': 'ts-jest',
|
||||
},
|
||||
|
||||
testEnvironment: 'jsdom',
|
||||
testMatch: ['**/*.test.(ts|tsx)'],
|
||||
|
||||
testPathIgnorePatterns: ['<rootDir>/node_modules/'],
|
||||
setupFilesAfterEnv: ['./jest.setup.js'],
|
||||
|
||||
// Do transform most packages in node_modules (transformations correct unrecognized
|
||||
// import syntax)
|
||||
transformIgnorePatterns: ['<rootDir>/node_modules/jest'],
|
||||
|
||||
slowTestThreshold: 40,
|
||||
};
|
||||
|
||||
58
packages/app-mobile/jest.setup.js
Normal file
58
packages/app-mobile/jest.setup.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/* eslint-disable jest/require-top-level-describe */
|
||||
|
||||
const { afterEachCleanUp, afterAllCleanUp } = require('@joplin/lib/testing/test-utils.js');
|
||||
const { shimInit } = require('@joplin/lib/shim-init-node.js');
|
||||
const { mkdir, rm } = require('fs-extra');
|
||||
const path = require('path');
|
||||
const { tmpdir } = require('os');
|
||||
const uuid = require('@joplin/lib/uuid').default;
|
||||
const sqlite3 = require('sqlite3');
|
||||
|
||||
import { setImmediate } from 'timers';
|
||||
|
||||
// Required by some libraries (setImmediate is not supported in most browsers,
|
||||
// so is removed by jsdom).
|
||||
window.setImmediate = setImmediate;
|
||||
|
||||
// Prevents the CodeMirror error "getClientRects is undefined".
|
||||
// See https://github.com/jsdom/jsdom/issues/3002#issue-652790925
|
||||
document.createRange = () => {
|
||||
const range = new Range();
|
||||
range.getBoundingClientRect = jest.fn();
|
||||
range.getClientRects = () => {
|
||||
return {
|
||||
length: 0,
|
||||
item: () => null,
|
||||
[Symbol.iterator]: jest.fn(),
|
||||
};
|
||||
};
|
||||
|
||||
return range;
|
||||
};
|
||||
|
||||
|
||||
shimInit({ nodeSqlite: sqlite3 });
|
||||
|
||||
|
||||
// react-native-fs's CachesDirectoryPath export doesn't work in a testing environment.
|
||||
// Use a temporary folder instead.
|
||||
const tempDirectoryPath = path.join(tmpdir(), `appmobile-test-${uuid.createNano()}`);
|
||||
|
||||
jest.doMock('react-native-fs', () => {
|
||||
return {
|
||||
CachesDirectoryPath: tempDirectoryPath,
|
||||
};
|
||||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
await mkdir(tempDirectoryPath);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await afterEachCleanUp();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await afterAllCleanUp();
|
||||
await rm(tempDirectoryPath, { recursive: true });
|
||||
});
|
||||
@@ -13,15 +13,37 @@
|
||||
const path = require('path');
|
||||
|
||||
const localPackages = {
|
||||
'@joplin/fork-htmlparser2': path.resolve(__dirname, '../fork-htmlparser2/'),
|
||||
'@joplin/fork-sax': path.resolve(__dirname, '../fork-sax/'),
|
||||
'@joplin/fork-uslug': path.resolve(__dirname, '../fork-uslug/'),
|
||||
'@joplin/lib': path.resolve(__dirname, '../lib/'),
|
||||
'@joplin/react-native-alarm-notification': path.resolve(__dirname, '../react-native-alarm-notification/'),
|
||||
'@joplin/react-native-saf-x': path.resolve(__dirname, '../react-native-saf-x/'),
|
||||
'@joplin/renderer': path.resolve(__dirname, '../renderer/'),
|
||||
'@joplin/tools': path.resolve(__dirname, '../tools/'),
|
||||
'@joplin/fork-htmlparser2': path.resolve(__dirname, '../fork-htmlparser2/'),
|
||||
'@joplin/fork-uslug': path.resolve(__dirname, '../fork-uslug/'),
|
||||
'@joplin/react-native-saf-x': path.resolve(__dirname, '../react-native-saf-x/'),
|
||||
'@joplin/react-native-alarm-notification': path.resolve(__dirname, '../react-native-alarm-notification/'),
|
||||
'@joplin/turndown-plugin-gfm': path.resolve(__dirname, '../turndown-plugin-gfm/'),
|
||||
'@joplin/turndown': path.resolve(__dirname, '../turndown/'),
|
||||
'@joplin/utils': path.resolve(__dirname, '../utils/'),
|
||||
};
|
||||
|
||||
const remappedPackages = {
|
||||
...localPackages,
|
||||
};
|
||||
|
||||
// Some packages aren't available in react-native and thus must be replaced by browserified
|
||||
// versions. For example, this allows us to `import {resolve} from 'path'` rather than
|
||||
// `const { resolve } = require('path-browserify')` ('path-browerify' doesn't have its own type
|
||||
// definitions).
|
||||
const browserifiedPackages = [
|
||||
'http',
|
||||
'https',
|
||||
'os',
|
||||
'path',
|
||||
];
|
||||
for (const package of browserifiedPackages) {
|
||||
remappedPackages[package] = path.resolve(__dirname, `./node_modules/${package}-browserify/`);
|
||||
}
|
||||
|
||||
const watchedFolders = [];
|
||||
for (const [, v] of Object.entries(localPackages)) {
|
||||
watchedFolders.push(v);
|
||||
@@ -49,7 +71,7 @@ module.exports = {
|
||||
// included in your reusable module as they would be imported when
|
||||
// the module is actually used.
|
||||
//
|
||||
localPackages,
|
||||
remappedPackages,
|
||||
{
|
||||
get: (target, name) => {
|
||||
if (target.hasOwnProperty(name)) {
|
||||
@@ -59,6 +81,30 @@ module.exports = {
|
||||
},
|
||||
}
|
||||
),
|
||||
|
||||
// Documentation at https://facebook.github.io/metro/docs/configuration/
|
||||
resolveRequest: (context, moduleName, platform) => {
|
||||
// console.info('Module: ' + moduleName + ' / ' + context.originModulePath);
|
||||
|
||||
// This can be used to allow importing a module that requires `fs`
|
||||
// somewhere. For example, the `css` package which is used to parse
|
||||
// CSS strings has a `loadFile()` function that we don't need, but
|
||||
// that makes it import the `fs` package.
|
||||
//
|
||||
// So by having this here, we can use those packages as long as we
|
||||
// don't use the specific methods that require `fs`. It's something
|
||||
// to keep in mind if we get weird-related fs errors - it may be
|
||||
// because the package is trying to access the mocked `fs` package.
|
||||
if (moduleName === 'fs') {
|
||||
return {
|
||||
filePath: path.resolve(__dirname, 'mock-fs.js'),
|
||||
type: 'sourceFile',
|
||||
};
|
||||
}
|
||||
|
||||
// Default resolver
|
||||
return context.resolveRequest(context, moduleName, platform);
|
||||
},
|
||||
},
|
||||
projectRoot: path.resolve(__dirname),
|
||||
watchFolders: watchedFolders,
|
||||
|
||||
13
packages/app-mobile/mock-fs.js
Normal file
13
packages/app-mobile/mock-fs.js
Normal file
@@ -0,0 +1,13 @@
|
||||
function traceMethodCalls(obj) {
|
||||
const handler = {
|
||||
get(_target, propKey, _receiver) {
|
||||
if (propKey === '$$typeof') return 'object';
|
||||
throw new Error(`Trying to access member of mocked fs package: \`fs.${propKey}\``);
|
||||
},
|
||||
};
|
||||
return new Proxy(obj, handler);
|
||||
}
|
||||
|
||||
const mockFs = {};
|
||||
|
||||
module.exports = traceMethodCalls(mockFs);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user