1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-30 20:39:46 +02:00

Compare commits

..

4 Commits

Author SHA1 Message Date
Laurent Cozic
4f5e52c363 update 2023-05-08 14:59:27 +01:00
Laurent Cozic
4e7087b350 Merge branch 'dev' into webpack_electron 2023-05-08 14:06:29 +01:00
Laurent Cozic
59e7c4933d Merge branch 'dev' into webpack_electron 2023-05-04 21:14:22 +01:00
Laurent Cozic
621f83d3ce init 2023-04-26 22:53:31 +01:00
403 changed files with 26452 additions and 20884 deletions

View File

@@ -75,7 +75,6 @@ packages/pdf-viewer/dist
plugin_types/
readme/
packages/react-native-vosk/lib/
packages/lib/countable/Countable.js
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
packages/app-cli/app/LinkSelector.js
@@ -260,6 +259,7 @@ packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
packages/app-desktop/gui/NoteList/NoteList.js
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js
packages/app-desktop/gui/NoteList/commands/index.js
packages/app-desktop/gui/NoteList/itemAnchorRef.js
packages/app-desktop/gui/NoteList/types.js
packages/app-desktop/gui/NoteListControls/NoteListControls.js
packages/app-desktop/gui/NoteListControls/commands/focusSearch.js
@@ -312,6 +312,7 @@ packages/app-desktop/gui/TagItem.js
packages/app-desktop/gui/TagList.js
packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.js
packages/app-desktop/gui/ToggleEditorsButton/styles/index.js
packages/app-desktop/gui/ToggleEditorsButton/types.js
packages/app-desktop/gui/ToolbarBase.js
packages/app-desktop/gui/ToolbarButton/ToolbarButton.js
packages/app-desktop/gui/ToolbarButton/styles/index.js
@@ -364,7 +365,6 @@ packages/app-mobile/components/CameraView.js
packages/app-mobile/components/CustomButton.js
packages/app-mobile/components/Dropdown.js
packages/app-mobile/components/ExtendedWebView.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnMessage.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
@@ -427,8 +427,8 @@ 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/profiles/index.js
packages/app-mobile/services/voiceTyping/vosk.android.js
packages/app-mobile/services/voiceTyping/vosk.ios.js
packages/app-mobile/services/voiceTyping/vosk.dummy.js
packages/app-mobile/services/voiceTyping/vosk.js
packages/app-mobile/setupQuickActions.js
packages/app-mobile/tools/buildInjectedJs.js
packages/app-mobile/utils/ShareExtension.js
@@ -485,7 +485,6 @@ packages/lib/SyncTargetOneDrive.js
packages/lib/SyncTargetRegistry.js
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
@@ -521,7 +520,6 @@ packages/lib/import-enex-md-gen.js
packages/lib/import-enex-md-gen.test.js
packages/lib/import-enex.js
packages/lib/locale.js
packages/lib/locale.test.js
packages/lib/markdownUtils.js
packages/lib/markdownUtils.test.js
packages/lib/markdownUtils2.test.js
@@ -553,6 +551,7 @@ packages/lib/models/SmartFilter.js
packages/lib/models/Tag.js
packages/lib/models/dateTimeFormats.test.js
packages/lib/models/settings/FileHandler.js
packages/lib/models/settings/types.js
packages/lib/models/utils/itemCanBeEncrypted.js
packages/lib/models/utils/paginatedFeed.js
packages/lib/models/utils/paginationToSql.js
@@ -687,8 +686,6 @@ packages/lib/services/plugins/utils/validatePluginVersion.test.js
packages/lib/services/profileConfig/index.js
packages/lib/services/profileConfig/index.test.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
@@ -815,6 +812,7 @@ 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/react-native-vosk/src/index.js
packages/renderer/HtmlToHtml.js
packages/renderer/InMemoryCache.js
packages/renderer/MarkupToHtml.js
@@ -848,7 +846,6 @@ 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

View File

@@ -141,7 +141,6 @@ module.exports = {
'spaced-comment': ['error', 'always'],
'keyword-spacing': ['error', { 'before': true, 'after': true }],
'no-multi-spaces': ['error'],
'prefer-object-spread': ['error'],
// Regarding the keyword blacklist:
// - err: We generally avoid using too many abbreviations, so it should

View File

@@ -183,32 +183,12 @@ if [[ $GIT_TAG_NAME = v* ]]; then
# cd "$ROOT_DIR/packages/tools"
# node bundleDefaultPlugins.js
cd "$ROOT_DIR/packages/app-desktop"
if [ "$IS_MACOS" == "1" ]; then
# This is to fix this error:
#
# Exit code: ENOENT. spawn /usr/bin/python ENOENT
#
# Ref: https://github.com/electron-userland/electron-builder/issues/6767#issuecomment-1096589528
#
# It can be removed once we upgrade to electron-builder@23, however we
# cannot currently do this due to this error:
# https://github.com/laurent22/joplin/issues/8149
PYTHON_PATH=$(which python) USE_HARD_LINKS=false yarn run dist
else
USE_HARD_LINKS=false yarn run dist
fi
USE_HARD_LINKS=false yarn run dist
elif [[ $IS_LINUX = 1 ]] && [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
echo "Step: Building Docker Image..."
cd "$ROOT_DIR"
yarn run buildServerDocker --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY
else
echo "Step: Building but *not* publishing desktop application..."
if [ "$IS_MACOS" == "1" ]; then
# See above why we need to specify Python
PYTHON_PATH=$(which python) USE_HARD_LINKS=false yarn run dist --publish=never
else
USE_HARD_LINKS=false yarn run dist --publish=never
fi
USE_HARD_LINKS=false yarn run dist --publish=never
fi

View File

@@ -17,8 +17,9 @@ jobs:
concurrent_skipping: 'same_content_newer'
BuildAndroidDebug:
if: github.repository == 'laurent22/joplin'
needs: pre_job
if: github.repository == 'laurent22/joplin' && needs.pre_job.outputs.should_skip != 'true'
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: ubuntu-latest
steps:
- name: Install Linux dependencies

View File

@@ -50,7 +50,6 @@ jobs:
sudo apt-get install -y gettext
sudo apt-get install -y libsecret-1-dev
sudo apt-get install -y translate-toolkit
sudo apt-get install -y rsync
- name: Install Docker Engine
# if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v')

14
.gitignore vendored
View File

@@ -245,6 +245,7 @@ packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
packages/app-desktop/gui/NoteList/NoteList.js
packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js
packages/app-desktop/gui/NoteList/commands/index.js
packages/app-desktop/gui/NoteList/itemAnchorRef.js
packages/app-desktop/gui/NoteList/types.js
packages/app-desktop/gui/NoteListControls/NoteListControls.js
packages/app-desktop/gui/NoteListControls/commands/focusSearch.js
@@ -297,6 +298,7 @@ packages/app-desktop/gui/TagItem.js
packages/app-desktop/gui/TagList.js
packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.js
packages/app-desktop/gui/ToggleEditorsButton/styles/index.js
packages/app-desktop/gui/ToggleEditorsButton/types.js
packages/app-desktop/gui/ToolbarBase.js
packages/app-desktop/gui/ToolbarButton/ToolbarButton.js
packages/app-desktop/gui/ToolbarButton/styles/index.js
@@ -349,7 +351,6 @@ packages/app-mobile/components/CameraView.js
packages/app-mobile/components/CustomButton.js
packages/app-mobile/components/Dropdown.js
packages/app-mobile/components/ExtendedWebView.js
packages/app-mobile/components/FolderPicker.js
packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnMessage.js
packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js
@@ -412,8 +413,8 @@ 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/profiles/index.js
packages/app-mobile/services/voiceTyping/vosk.android.js
packages/app-mobile/services/voiceTyping/vosk.ios.js
packages/app-mobile/services/voiceTyping/vosk.dummy.js
packages/app-mobile/services/voiceTyping/vosk.js
packages/app-mobile/setupQuickActions.js
packages/app-mobile/tools/buildInjectedJs.js
packages/app-mobile/utils/ShareExtension.js
@@ -470,7 +471,6 @@ packages/lib/SyncTargetOneDrive.js
packages/lib/SyncTargetRegistry.js
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
@@ -506,7 +506,6 @@ packages/lib/import-enex-md-gen.js
packages/lib/import-enex-md-gen.test.js
packages/lib/import-enex.js
packages/lib/locale.js
packages/lib/locale.test.js
packages/lib/markdownUtils.js
packages/lib/markdownUtils.test.js
packages/lib/markdownUtils2.test.js
@@ -538,6 +537,7 @@ packages/lib/models/SmartFilter.js
packages/lib/models/Tag.js
packages/lib/models/dateTimeFormats.test.js
packages/lib/models/settings/FileHandler.js
packages/lib/models/settings/types.js
packages/lib/models/utils/itemCanBeEncrypted.js
packages/lib/models/utils/paginatedFeed.js
packages/lib/models/utils/paginationToSql.js
@@ -672,8 +672,6 @@ packages/lib/services/plugins/utils/validatePluginVersion.test.js
packages/lib/services/profileConfig/index.js
packages/lib/services/profileConfig/index.test.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
@@ -800,6 +798,7 @@ 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/react-native-vosk/src/index.js
packages/renderer/HtmlToHtml.js
packages/renderer/InMemoryCache.js
packages/renderer/MarkupToHtml.js
@@ -833,7 +832,6 @@ 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

View File

@@ -15,6 +15,7 @@
"@joplin/tools",
"@joplin/react-native-saf-x",
"@joplin/react-native-alarm-notification",
"@joplin/react-native-vosk",
"@joplin/utils"
]
}

View File

@@ -36,7 +36,7 @@ index 6afcbbf0cc8ca2d69dd78077d61e59a90b2136bb..9f8d72b4ec5b2b3d290975d6a255917c
def kotlin_version = getExtOrDefault('kotlinVersion')
diff --git a/android/src/main/java/com/reactnativevosk/VoskModule.kt b/android/src/main/java/com/reactnativevosk/VoskModule.kt
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4e3ff404a 100644
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..f3da440bc2863a59db6d2d1691c54d8d4870cb3f 100644
--- a/android/src/main/java/com/reactnativevosk/VoskModule.kt
+++ b/android/src/main/java/com/reactnativevosk/VoskModule.kt
@@ -19,13 +19,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
@@ -66,25 +66,7 @@ index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4
sendEvent("onResult", text)
}
}
@@ -93,12 +105,11 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
@ReactMethod
fun loadModel(path: String, promise: Promise) {
cleanModel();
- StorageService.unpack(context, path, "models",
- { model: Model? ->
- this.model = model
- promise.resolve("Model successfully loaded")
- }
- ) { e: IOException ->
+
+ try {
+ this.model = Model(path);
+ promise.resolve("Model successfully loaded")
+ } catch (e: IOException) {
this.model = null
promise.reject(e)
}
@@ -153,6 +164,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
@@ -153,6 +165,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
cleanRecognizer();
}
@@ -123,70 +105,6 @@ index 441e41cc402cca3a60b34978ef4fea976076259c..a173acebb4b314402550442ad471e0f7
unload: () => void;
onResult: (onResult: (e: VoskEvent) => void) => EventSubscription;
onFinalResult: (onFinalResult: (e: VoskEvent) => void) => EventSubscription;
diff --git a/package.json b/package.json
index 707eddb8d68007f93071ac659c5b087c935c5f01..90ebe20f224eeec472c377df1fef9b15f2ff8200 100644
--- a/package.json
+++ b/package.json
@@ -11,12 +11,9 @@
"src",
"lib",
"android",
- "ios",
"cpp",
- "react-native-vosk.podspec",
"!lib/typescript/example",
"!android/build",
- "!ios/build",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__"
diff --git a/react-native-vosk.podspec b/react-native-vosk.podspec
deleted file mode 100644
index e3d41b90c5eef890c7a5108aaf16ac07d34a698b..0000000000000000000000000000000000000000
--- a/react-native-vosk.podspec
+++ /dev/null
@@ -1,41 +0,0 @@
-require "json"
-
-package = JSON.parse(File.read(File.join(__dir__, "package.json")))
-folly_version = '2021.06.28.00-v2'
-folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
-
-Pod::Spec.new do |s|
- s.name = "react-native-vosk"
- s.version = package["version"]
- s.summary = package["description"]
- s.homepage = package["homepage"]
- s.license = package["license"]
- s.authors = package["author"]
-
- s.platforms = { :ios => "10.0" }
- s.source = { :git => "https://github.com/riderodd/react-native-vosk.git", :tag => "#{s.version}" }
-
- s.source_files = "ios/**/*.{h,m,mm,swift}"
- s.resource_bundles = { 'Vosk' => ['ios/Vosk/*'] }
-
- s.dependency "React-Core"
- s.frameworks = "Accelerate"
- s.library = "c++"
- s.vendored_frameworks = "ios/libvosk.xcframework"
- s.requires_arc = true
-
- # Don't install the dependencies when we run `pod install` in the old architecture.
- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
- s.pod_target_xcconfig = {
- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
- }
-
- s.dependency "React-Codegen"
- s.dependency "RCT-Folly", folly_version
- s.dependency "RCTRequired"
- s.dependency "RCTTypeSafety"
- s.dependency "ReactCommon/turbomodule/core"
- end
-end
diff --git a/src/index.tsx b/src/index.tsx
index d9f90c921d89b1b4d85e145443ed3376546a368a..29e4068dbd7500828a73145bd25497a52c9bf638 100644
--- a/src/index.tsx

View File

@@ -0,0 +1,30 @@
diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
index a8abd71833879201e3438b2fa51d712a311c4551..ffe9c2c6dfa5c703ba76b65d94d5dd6784102c19 100644
--- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
+++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
@@ -591,7 +591,7 @@ public class RNFetchBlobReq extends BroadcastReceiver implements Runnable {
// ignored.printStackTrace();
}
- RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody;
+ RNFetchBlobFileResp rnFetchBlobFileResp = new RNFetchBlobFileResp(responseBody);
if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){
callback.invoke("Download interrupted.", null);
diff --git a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
index 2470eef612308c15a89dfea5a1f16937469be29f..965f8becc195965907699182c764ec9e51811450 100644
--- a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
+++ b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java
@@ -35,6 +35,12 @@ public class RNFetchBlobFileResp extends ResponseBody {
FileOutputStream ofStream;
boolean isEndMarkerReceived;
+ // ref: https://github.com/joltup/rn-fetch-blob/issues/490#issuecomment-990899440
+ public RNFetchBlobFileResp(ResponseBody body) {
+ super();
+ this.originalBody = body;
+ }
+
public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseBody body, String path, boolean overwrite) throws IOException {
super();
this.rctContext = ctx;

View File

@@ -42,7 +42,7 @@ export function addJoplinChecklistCommands(editor, ToggleList) {
});
editor.addCommand('InsertJoplinChecklist', function (ui, detail) {
detail = { ...detail, listType: 'joplinChecklist' };
detail = Object.assign({}, detail, { listType: 'joplinChecklist' });
ToggleList.toggleList(editor, 'UL', detail);
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -9,9 +9,7 @@ function getOs() {
function getFilename(path) {
if (!path) return '';
const s = path.split('/');
const urlWithParams = s.pop();
const s2 = urlWithParams.split('?');
return s2[0];
return s.pop();
}
function getMobileOs() {

View File

@@ -114,20 +114,6 @@ elif [[ $ARCHITECTURE =~ .*i386.*|.*i686.* ]] ; then
exit 1
fi
#-----------------------------------------------------
print "Checking dependencies..."
## Check if libfuse2 is present.
if [[ $(command -v ldconfig) ]]; then
LIBFUSE=$(ldconfig -p | grep "libfuse.so.2" || echo '')
else
LIBFUSE=$(find /lib /usr/lib /lib64 /usr/lib64 /usr/local/lib -name "libfuse.so.2" 2>/dev/null | grep "libfuse.so.2" || echo '')
fi
if [[ $LIBFUSE == "" ]] ; then
print "${COLOR_RED}Error: Can't get libfuse2 on system, please install libfuse2${COLOR_RESET}"
print "See https://joplinapp.org/faq/#desktop-application-will-not-launch-on-linux and https://github.com/AppImage/AppImageKit/wiki/FUSE for more information"
exit 1
fi
#-----------------------------------------------------
# Download Joplin
#-----------------------------------------------------
@@ -148,16 +134,10 @@ else
print "The latest version is ${RELEASE_VERSION}, but you have ${CURRENT_VERSION:-no version} installed."
fi
# Check if it's an update or a new install
DOWNLOAD_TYPE="New"
if [[ -f ~/.joplin/Joplin.AppImage ]]; then
DOWNLOAD_TYPE="Update"
fi
#-----------------------------------------------------
print 'Downloading Joplin...'
TEMP_DIR=$(mktemp -d)
wget -O "${TEMP_DIR}/Joplin.AppImage" "https://objects.joplinusercontent.com/v${RELEASE_VERSION}/Joplin-${RELEASE_VERSION}.AppImage?source=LinuxInstallScript&type=$DOWNLOAD_TYPE"
wget -O "${TEMP_DIR}/Joplin.AppImage" "https://github.com/laurent22/joplin/releases/download/v${RELEASE_VERSION}/Joplin-${RELEASE_VERSION}.AppImage"
wget -O "${TEMP_DIR}/joplin.png" https://joplinapp.org/images/Icon512.png
#-----------------------------------------------------

View File

@@ -22,23 +22,21 @@ Three types of applications are available: for **desktop** (Windows, macOS and L
Operating System | Download
---|---
Windows (32 and 64-bit) | <a href='https://objects.joplinusercontent.com/v2.10.19/Joplin-Setup-2.10.19.exe?source=JoplinWebsite&type=New'><img alt='Get it on Windows' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeWindows.png'/></a>
macOS | <a href='https://objects.joplinusercontent.com/v2.10.19/Joplin-2.10.19.dmg?source=JoplinWebsite&type=New'><img alt='Get it on macOS' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeMacOS.png'/></a>
Linux | <a href='https://objects.joplinusercontent.com/v2.10.19/Joplin-2.10.19.AppImage?source=JoplinWebsite&type=New'><img alt='Get it on Linux' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeLinux.png'/></a>
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-Setup-2.9.17.exe'><img alt='Get it on Windows' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeWindows.png'/></a>
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-2.9.17.dmg'><img alt='Get it on macOS' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeMacOS.png'/></a>
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-2.9.17.AppImage'><img alt='Get it on Linux' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeLinux.png'/></a>
**On Windows**, you may also use the <a href='https://objects.joplinusercontent.com/v2.10.19/JoplinPortable.exe?source=JoplinWebsite&type=New'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
**On Windows**, you may also use the <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/JoplinPortable.exe'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
**On Linux**, the recommended way is to use the following installation script as it will handle the desktop icon too:
<pre><code style="word-break: break-all">wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh | bash</code></pre>
The install and update script supports the [following flags](https://github.com/laurent22/joplin/blob/dev/Joplin_install_and_update.sh#L50) (around line 50 at the time of this writing).
## Mobile applications
Operating System | Download | Alt. Download
---|---|---
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://objects.joplinusercontent.com/android-v2.9.8/joplin-v2.9.8.apk?source=JoplinWebsite&type=New) [32-bit](https://objects.joplinusercontent.com/android-v2.9.8/joplin-v2.9.8-32bit.apk?source=JoplinWebsite&type=New)
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeAndroid.png'/></a> | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.9.8/joplin-v2.9.8.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v2.9.8/joplin-v2.9.8-32bit.apk)
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeIOS.png'/></a> | -
## Terminal application
@@ -66,7 +64,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&amp;mtm_kwd=joplinapp&amp;mtm_source=joplinapp-webseite&amp;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&amp;mtm_kwd=joplinapp&amp;mtm_source=joplinapp-webseite&amp;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>
<!-- SPONSORS-ORG -->
* * *
@@ -536,24 +534,24 @@ Current translations:
<img src="https://joplinapp.org/images/flags/es/basque_country.png" width="16px"/> | Basque | [eu](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eu.po) | juan.abasolo@ehu.eus | 22%
<img src="https://joplinapp.org/images/flags/country-4x3/ba.png" width="16px"/> | Bosnian (Bosna i Hercegovina) | [bs_BA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bs_BA.po) | [Derviš T.](mailto:dervis.t@pm.me) | 57%
<img src="https://joplinapp.org/images/flags/country-4x3/bg.png" width="16px"/> | Bulgarian (България) | [bg_BG](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bg_BG.po) | | 45%
<img src="https://joplinapp.org/images/flags/es/catalonia.png" width="16px"/> | Catalan | [ca](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ca.po) | [Xavi Ivars](mailto:xavi.ivars@gmail.com) | 88%
<img src="https://joplinapp.org/images/flags/country-4x3/hr.png" width="16px"/> | Croatian (Hrvatska) | [hr_HR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hr_HR.po) | [Milo Ivir](mailto:mail@milotype.de) | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/cz.png" width="16px"/> | Czech (Česká republika) | [cs_CZ](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/cs_CZ.po) | Fejby | 98%
<img src="https://joplinapp.org/images/flags/country-4x3/dk.png" width="16px"/> | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | ERYpTION | 98%
<img src="https://joplinapp.org/images/flags/country-4x3/de.png" width="16px"/> | Deutsch (Deutschland) | [de_DE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/de_DE.po) | [MrKanister](mailto:pueblos_spatulas@aleeas.com) | 98%
<img src="https://joplinapp.org/images/flags/es/catalonia.png" width="16px"/> | Catalan | [ca](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ca.po) | [Xavi Ivars](mailto:xavi.ivars@gmail.com) | 89%
<img src="https://joplinapp.org/images/flags/country-4x3/hr.png" width="16px"/> | Croatian (Hrvatska) | [hr_HR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hr_HR.po) | [Milo Ivir](mailto:mail@milotype.de) | 89%
<img src="https://joplinapp.org/images/flags/country-4x3/cz.png" width="16px"/> | Czech (Česká republika) | [cs_CZ](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/cs_CZ.po) | Fejby | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/dk.png" width="16px"/> | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | ERYpTION | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/de.png" width="16px"/> | Deutsch (Deutschland) | [de_DE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/de_DE.po) | [MrKanister](mailto:pueblos_spatulas@aleeas.com) | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/ee.png" width="16px"/> | Eesti Keel (Eesti) | [et_EE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/et_EE.po) | | 44%
<img src="https://joplinapp.org/images/flags/country-4x3/gb.png" width="16px"/> | English (United Kingdom) | [en_GB](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/en_GB.po) | | 100%
<img src="https://joplinapp.org/images/flags/country-4x3/us.png" width="16px"/> | English (United States of America) | [en_US](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/en_US.po) | | 100%
<img src="https://joplinapp.org/images/flags/country-4x3/es.png" width="16px"/> | Español (España) | [es_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/es_ES.po) | [Francisco Villaverde](mailto:teko.gr@gmail.com) | 97%
<img src="https://joplinapp.org/images/flags/country-4x3/es.png" width="16px"/> | Español (España) | [es_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/es_ES.po) | [Francisco Villaverde](mailto:teko.gr@gmail.com) | 98%
<img src="https://joplinapp.org/images/flags/esperanto.png" width="16px"/> | Esperanto | [eo](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eo.po) | Marton Paulo | 25%
<img src="https://joplinapp.org/images/flags/country-4x3/fi.png" width="16px"/> | Finnish (Suomi) | [fi_FI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fi_FI.po) | mrkaato0 | 98%
<img src="https://joplinapp.org/images/flags/country-4x3/fi.png" width="16px"/> | Finnish (Suomi) | [fi_FI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fi_FI.po) | mrkaato0 | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/fr.png" width="16px"/> | Français (France) | [fr_FR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fr_FR.po) | Laurent Cozic | 100%
<img src="https://joplinapp.org/images/flags/es/galicia.png" width="16px"/> | Galician (España) | [gl_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/gl_ES.po) | [Marcos Lans](mailto:marcoslansgarza@gmail.com) | 29%
<img src="https://joplinapp.org/images/flags/country-4x3/id.png" width="16px"/> | Indonesian (Indonesia) | [id_ID](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/id_ID.po) | [Wisnu Adi Santoso](mailto:waditos@gmail.com) | 88%
<img src="https://joplinapp.org/images/flags/country-4x3/id.png" width="16px"/> | Indonesian (Indonesia) | [id_ID](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/id_ID.po) | [Wisnu Adi Santoso](mailto:waditos@gmail.com) | 89%
<img src="https://joplinapp.org/images/flags/country-4x3/it.png" width="16px"/> | Italiano (Italia) | [it_IT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/it_IT.po) | [Manuel Tassi](mailto:mannivuwiki@gmail.com) | 80%
<img src="https://joplinapp.org/images/flags/country-4x3/hu.png" width="16px"/> | Magyar (Magyarország) | [hu_HU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hu_HU.po) | [Magyari Balázs](mailto:balmag@gmail.com) | 77%
<img src="https://joplinapp.org/images/flags/country-4x3/be.png" width="16px"/> | Nederlands (België, Belgique, Belgien) | [nl_BE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_BE.po) | | 78%
<img src="https://joplinapp.org/images/flags/country-4x3/nl.png" width="16px"/> | Nederlands (Nederland) | [nl_NL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_NL.po) | [MHolkamp](mailto:mholkamp@users.noreply.github.com) | 87%
<img src="https://joplinapp.org/images/flags/country-4x3/nl.png" width="16px"/> | Nederlands (Nederland) | [nl_NL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_NL.po) | [MHolkamp](mailto:mholkamp@users.noreply.github.com) | 88%
<img src="https://joplinapp.org/images/flags/country-4x3/no.png" width="16px"/> | Norwegian (Norge, Noreg) | [nb_NO](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nb_NO.po) | [Mats Estensen](mailto:code@mxe.no) | 87%
<img src="https://joplinapp.org/images/flags/country-4x3/ir.png" width="16px"/> | Persian | [fa](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fa.po) | [Kourosh Firoozbakht](mailto:kourox@protonmail.com) | 55%
<img src="https://joplinapp.org/images/flags/country-4x3/pl.png" width="16px"/> | Polski (Polska) | [pl_PL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pl_PL.po) | [X3NO](mailto:X3NO@disroot.org) | 90%
@@ -564,15 +562,15 @@ Current translations:
<img src="https://joplinapp.org/images/flags/country-4x3/se.png" width="16px"/> | Svenska | [sv](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sv.po) | [Jonatan Nyberg](mailto:jonatan@autistici.org) | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/th.png" width="16px"/> | Thai (ประเทศไทย) | [th_TH](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/th_TH.po) | | 36%
<img src="https://joplinapp.org/images/flags/country-4x3/vn.png" width="16px"/> | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 77%
<img src="https://joplinapp.org/images/flags/country-4x3/tr.png" width="16px"/> | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/tr.png" width="16px"/> | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 89%
<img src="https://joplinapp.org/images/flags/country-4x3/ua.png" width="16px"/> | Ukrainian (Україна) | [uk_UA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/uk_UA.po) | [Vyacheslav Andreykiv](mailto:vandreykiv@gmail.com) | 72%
<img src="https://joplinapp.org/images/flags/country-4x3/gr.png" width="16px"/> | Ελληνικά (Ελλάδα) | [el_GR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/el_GR.po) | [Harris Arvanitis](mailto:xaris@tuta.io) | 87%
<img src="https://joplinapp.org/images/flags/country-4x3/ru.png" width="16px"/> | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Dmitriy K](mailto:dmitry@atsip.ru) | 99%
<img src="https://joplinapp.org/images/flags/country-4x3/rs.png" width="16px"/> | српски језик (Србија) | [sr_RS](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sr_RS.po) | | 64%
<img src="https://joplinapp.org/images/flags/country-4x3/ru.png" width="16px"/> | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Dmitriy Q](mailto:krotesk@mail.ru) | 98%
<img src="https://joplinapp.org/images/flags/country-4x3/rs.png" width="16px"/> | српски језик (Србија) | [sr_RS](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sr_RS.po) | | 65%
<img src="https://joplinapp.org/images/flags/country-4x3/cn.png" width="16px"/> | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_CN.po) | [wh201906](mailto:wh201906@yandex.com) | 96%
<img src="https://joplinapp.org/images/flags/country-4x3/tw.png" width="16px"/> | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Kevin Hsu](mailto:kevin.hsu.hws@gmail.com) | 88%
<img src="https://joplinapp.org/images/flags/country-4x3/jp.png" width="16px"/> | 日本語 (日本) | [ja_JP](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ja_JP.po) | [genneko](mailto:genneko217@gmail.com) | 88%
<img src="https://joplinapp.org/images/flags/country-4x3/kr.png" width="16px"/> | 한국어 | [ko](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ko.po) | [Ji-Hyeon Gim](mailto:potatogim@potatogim.net) | 88%
<img src="https://joplinapp.org/images/flags/country-4x3/tw.png" width="16px"/> | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Kevin Hsu](mailto:kevin.hsu.hws@gmail.com) | 89%
<img src="https://joplinapp.org/images/flags/country-4x3/jp.png" width="16px"/> | 日本語 (日本) | [ja_JP](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ja_JP.po) | [genneko](mailto:genneko217@gmail.com) | 89%
<img src="https://joplinapp.org/images/flags/country-4x3/kr.png" width="16px"/> | 한국어 | [ko](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ko.po) | [Ji-Hyeon Gim](mailto:potatogim@potatogim.net) | 89%
<!-- LOCALE-TABLE-AUTO-GENERATED -->
# Contributors

View File

@@ -107,10 +107,7 @@
".eslintignore": true,
".gitignore": true,
".vscode/*": true,
".yarn/cache": true,
".yarn/install-state.gz": true,
".yarn/plugins": true,
".yarn/releases": true,
".yarn": true,
"*.sublime-workspace": true,
"**/_mydocs": true,
"**/_mydocs/EnexSamples/*.enex": true,

View File

@@ -66,36 +66,37 @@
"devDependencies": {
"@joplin/utils": "~2.11",
"@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0",
"@typescript-eslint/eslint-plugin": "5.59.0",
"@typescript-eslint/parser": "5.59.0",
"@typescript-eslint/eslint-plugin": "5.48.2",
"@typescript-eslint/parser": "5.48.2",
"cspell": "5.21.2",
"eslint": "8.39.0",
"eslint-interactive": "10.7.0",
"eslint-plugin-import": "2.27.5",
"eslint": "8.31.0",
"eslint-interactive": "10.3.0",
"eslint-plugin-import": "2.27.4",
"eslint-plugin-jest": "27.2.1",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react": "7.32.0",
"execa": "5.1.1",
"fs-extra": "11.1.1",
"glob": "8.1.0",
"gulp": "4.0.2",
"husky": "3.1.0",
"lerna": "3.22.1",
"lint-staged": "13.2.2",
"lint-staged": "13.2.1",
"madge": "6.0.0",
"npm-package-json-lint": "6.4.0",
"typedoc": "0.17.8",
"typescript": "5.0.2"
"typescript": "4.9.4"
},
"dependencies": {
"@types/fs-extra": "11.0.1",
"@types/fs-extra": "9.0.13",
"http-server": "14.1.1",
"node-gyp": "9.3.1",
"nodemon": "2.0.22"
},
"packageManager": "yarn@3.5.0",
"packageManager": "yarn@3.3.1",
"resolutions": {
"react-native-camera@4.2.1": "patch:react-native-camera@npm%3A4.2.1#./.yarn/patches/react-native-camera-npm-4.2.1-24b2600a7e.patch",
"rn-fetch-blob@0.12.0": "patch:rn-fetch-blob@npm%3A0.12.0#./.yarn/patches/rn-fetch-blob-npm-0.12.0-cf02e3c544.patch",
"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"
}
}

View File

@@ -302,7 +302,7 @@ class AppGui {
const output = [];
for (let i = 0; i < keymap.length; i++) {
const item = { ...keymap[i] };
const item = Object.assign({}, keymap[i]);
if (!item.command) throw new Error(`Missing command for keymap item: ${JSON.stringify(item)}`);
@@ -427,7 +427,7 @@ class AppGui {
async handleModelAction(action) {
this.logger().info('Action:', action);
const state = { ...defaultState };
const state = Object.assign({}, defaultState);
state.notes = this.widget('noteList').items;
const newState = reducer(state, action);

View File

@@ -192,7 +192,7 @@ class Application extends BaseApplication {
let output = await this.cache_.getItem('metadata');
if (output) {
this.commandMetadata_ = output;
return { ...this.commandMetadata_ };
return Object.assign({}, this.commandMetadata_);
}
const commands = this.commands();
@@ -207,7 +207,7 @@ class Application extends BaseApplication {
await this.cache_.setItem('metadata', output, 1000 * 60 * 60 * 24);
this.commandMetadata_ = output;
return { ...this.commandMetadata_ };
return Object.assign({}, this.commandMetadata_);
}
hasGui() {

View File

@@ -1,4 +1,5 @@
import Setting, { SettingStorage } from '@joplin/lib/models/Setting';
import { schemaUrl } from '@joplin/lib/models/settings/types';
import { SettingItemType } from '@joplin/lib/services/plugins/api/types';
import shim from '@joplin/lib/shim';
@@ -38,7 +39,7 @@ class Command extends BaseCommand {
public async action(args: any) {
const schema: Record<string, any> = {
title: 'JSON schema for Joplin setting files',
'$id': Setting.schemaUrl,
'$id': schemaUrl,
'$schema': 'https://json-schema.org/draft-07/schema#',
type: 'object',
properties: {},

View File

@@ -57,7 +57,7 @@
"proper-lockfile": "4.1.2",
"read-chunk": "2.1.0",
"server-destroy": "1.0.1",
"sharp": "0.32.1",
"sharp": "0.32.0",
"sprintf-js": "1.1.2",
"sqlite3": "5.1.6",
"string-padding": "1.0.2",
@@ -71,13 +71,13 @@
},
"devDependencies": {
"@joplin/tools": "~2.11",
"@types/fs-extra": "11.0.1",
"@types/jest": "29.5.1",
"@types/node": "18.15.13",
"@types/fs-extra": "9.0.13",
"@types/jest": "29.2.6",
"@types/node": "18.11.18",
"@types/proper-lockfile": "^4.1.2",
"gulp": "4.0.2",
"jest": "29.5.0",
"jest": "29.4.3",
"temp": "0.9.4",
"typescript": "5.0.2"
"typescript": "4.9.4"
}
}

View File

@@ -1,19 +0,0 @@
<table>
<tbody>
<tr>
<td style="text-align:left">Left</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
<tr>
<td style="text-align:left">Left</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
<tr>
<td style="text-align:left">Left</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
</tbody>
</table>

View File

@@ -1,5 +0,0 @@
| | | |
| :--- | :---: | ---: |
| Left | Centered | Right |
| Left | Centered | Right |
| Left | Centered | Right |

View File

@@ -1,26 +0,0 @@
<table>
<thead>
<tr>
<th style="text-align:left">Left-aligned Column</th>
<th style="text-align:center">Center-aligned Column</th>
<th style="text-align:right">Right-aligned Column</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Left</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
<tr>
<td style="text-align:left">Left</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
<tr>
<td style="text-align:left">Left</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
</tbody>
</table>

View File

@@ -1,5 +0,0 @@
| Left-aligned Column | Center-aligned Column | Right-aligned Column |
| :--- | :---: | ---: |
| Left | Centered | Right |
| Left | Centered | Right |
| Left | Centered | Right |

View File

@@ -1,14 +0,0 @@
<table>
<thead>
<tr>
<th align="center">abc</th>
<th align="right">defghi</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">bar</td>
<td align="right">baz</td>
</tr>
</tbody>
</table>

View File

@@ -1,3 +0,0 @@
| abc | defghi |
| :---: | ---: |
| bar | baz |

View File

@@ -1,29 +0,0 @@
<table>
<thead>
<tr>
<th style="text-align:left">Left-aligned Column</th>
<th>This header cell's text is unaligned, but a majority of the text in this column is center-aligned so the
column will be center-aligned</th>
<th style="text-align:right">Right-aligned Column</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Left</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
<tr>
<td style="text-align:right">This is the only right-aligned cell in this column. This is possible if a user
edits a cell's alignment using the cell properties dialog.</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
<tr>
<td style="text-align:center">This is the only center-aligned cell in this column. This is possible if a
user edits a cell's alignment using the cell properties dialog.</td>
<td style="text-align:center">Centered</td>
<td style="text-align:right">Right</td>
</tr>
</tbody>
</table>

View File

@@ -1,5 +0,0 @@
| Left-aligned Column | This header cell's text is unaligned, but a majority of the text in this column is center-aligned so the column will be center-aligned | Right-aligned Column |
| :--- | :---: | ---: |
| Left | Centered | Right |
| This is the only right-aligned cell in this column. This is possible if a user edits a cell's alignment using the cell properties dialog. | Centered | Right |
| This is the only center-aligned cell in this column. This is possible if a user edits a cell's alignment using the cell properties dialog. | Centered | Right |

View File

@@ -1 +0,0 @@
<div class="jop-noMdConv">

View File

@@ -1 +0,0 @@
<div><svg><style></svg><iframe srcdoc="<script>top.require('child_process').execSync('calc')</script>"></iframe></div>

View File

@@ -1 +0,0 @@
<a href="#" class="jop-noMdConv">XSS</a>

View File

@@ -1 +0,0 @@
<a data-from-md="" href="javascript:top.require('child_process').execSync('open -a Calculator')">XSS</a>

View File

@@ -1 +0,0 @@
<use href="#" class="jop-noMdConv">

View File

@@ -1 +0,0 @@
<svg><use href="data:image/svg+xml,&lt;svg id='x' xmlns='http://www.w3.org/2000/svg'&gt;&lt;image href='asdf' onerror='top.require(`child_process`).execSync(`calc.exe`)' /&gt;&lt;/svg&gt;#x" />

Before

Width:  |  Height:  |  Size: 193 B

View File

@@ -1 +0,0 @@
<map name="test" class="jop-noMdConv"><area coords="0,0,1000,1000" href="#" class="jop-noMdConv"/></map><img usemap="#test" src="https://github.com/Ry0taK.png" class="jop-noMdConv"/>

View File

@@ -1 +0,0 @@
<map name="test"><area coords="0,0,1000,1000" href="javascript:top.require(`child_process`).execSync(`calc.exe`)"></map><img usemap="#test" src="https://github.com/Ry0taK.png">

View File

@@ -1 +0,0 @@
<a href="#top" class="jop-noMdConv">⬆️</a>

View File

@@ -1 +0,0 @@
<a href="#top">⬆️</a>

View File

@@ -94,12 +94,12 @@ browser_.runtime.onMessage.addListener(async (command) => {
const imageSize = await getImageSize(imageDataUrl);
const imagePixelRatio = imageSize.width / command.content.windowInnerWidth;
const content = { ...command.content };
const content = Object.assign({}, command.content);
content.image_data_url = imageDataUrl;
if ('url' in content) content.source_url = content.url;
const ratio = browserZoom * imagePixelRatio;
const newArea = { ...command.content.crop_rect };
const newArea = Object.assign({}, command.content.crop_rect);
newArea.x *= ratio;
newArea.y *= ratio;
newArea.width *= ratio;

View File

@@ -378,7 +378,7 @@
tags: command.tags || '',
image_sizes: imageSizes,
anchor_names: anchorNames,
source_command: { ...command },
source_command: Object.assign({}, command),
convert_to: convertToMarkup,
stylesheets: stylesheets,
};
@@ -392,7 +392,7 @@
} catch (error) {
console.warn(error);
console.warn('Sending full page HTML instead');
const newCommand = { ...command, name: 'completePageHtml' };
const newCommand = Object.assign({}, command, { name: 'completePageHtml' });
const response = await prepareCommandResponse(newCommand);
response.warning = 'Could not retrieve simplified version of page - full page has been saved instead.';
return response;

View File

@@ -67,7 +67,7 @@ class AppComponent extends Component {
});
this.confirm_click = async () => {
const content = { ...this.props.clippedContent };
const content = Object.assign({}, this.props.clippedContent);
content.tags = this.state.selectedTags.join(',');
content.parent_id = this.props.selectedFolderId;
const response = await bridge().sendContentToJoplin(content);

View File

@@ -410,7 +410,7 @@ class Bridge {
if (body) fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
query = { ...query, token: this.token_ };
query = Object.assign(query || {}, { token: this.token_ });
let queryString = '';
if (query) {

View File

@@ -40,34 +40,34 @@ function reducer(state = defaultState, action) {
if (action.type === 'WARNING_SET') {
newState = { ...state };
newState = Object.assign({}, state);
newState.warning = action.text;
} else if (action.type === 'IS_PROBABLY_READERABLE') {
newState = { ...state };
newState = Object.assign({}, state);
newState.isProbablyReaderable = action.value;
} else if (action.type === 'CLIPPED_CONTENT_SET') {
newState = { ...state };
newState = Object.assign({}, state);
newState.clippedContent = action.content;
} else if (action.type === 'CLIPPED_CONTENT_TITLE_SET') {
newState = { ...state };
const newContent = newState.clippedContent ? { ...newState.clippedContent } : {};
newState = Object.assign({}, state);
const newContent = newState.clippedContent ? Object.assign({}, newState.clippedContent) : {};
newContent.title = action.text;
newState.clippedContent = newContent;
} else if (action.type === 'CONTENT_UPLOAD') {
newState = { ...state };
newState = Object.assign({}, state);
newState.contentUploadOperation = action.operation;
} else if (action.type === 'FOLDERS_SET') {
newState = { ...state };
newState = Object.assign({}, state);
newState.folders = action.folders;
if (!newState.selectedFolderId && action.folders.length) {
@@ -76,30 +76,30 @@ function reducer(state = defaultState, action) {
} else if (action.type === 'TAGS_SET') {
newState = { ...state };
newState = Object.assign({}, state);
newState.tags = action.tags;
} else if (action.type === 'SELECTED_FOLDER_SET') {
newState = { ...state };
newState = Object.assign({}, state);
newState.selectedFolderId = action.id;
} else if (action.type === 'CLIPPER_SERVER_SET') {
newState = { ...state };
const clipperServer = { ...newState.clipperServer };
newState = Object.assign({}, state);
const clipperServer = Object.assign({}, newState.clipperServer);
if ('foundState' in action) clipperServer.foundState = action.foundState;
if ('port' in action) clipperServer.port = action.port;
newState.clipperServer = clipperServer;
} else if (action.type === 'ENV_SET') {
newState = { ...state };
newState = Object.assign({}, state);
newState.env = action.env;
} else if (action.type === 'AUTH_STATE_SET') {
newState = { ...state };
newState = Object.assign({}, state);
newState.authStatus = action.value;
}

View File

@@ -14,3 +14,5 @@ style.min.css
build/lib/
vendor/*
!vendor/loadEmojiLib.js
main-html.bundle.js
main.js

View File

@@ -29,11 +29,13 @@ export default class InteropServiceHelper {
private static async exportNoteToHtmlFile(noteId: string, exportOptions: ExportNoteOptions) {
const tempFile = `${Setting.value('tempDir')}/${md5(Date.now() + Math.random())}.html`;
const fullExportOptions: ExportOptions = { path: tempFile,
const fullExportOptions: ExportOptions = Object.assign({}, {
path: tempFile,
format: 'html',
target: FileSystemItem.File,
sourceNoteIds: [noteId],
customCss: '', ...exportOptions };
customCss: '',
}, exportOptions);
const service = InteropService.instance();

View File

@@ -4,9 +4,6 @@ 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';
const logger = Logger.create('app.reducer');
export interface AppStateRoute {
type: string;
@@ -85,7 +82,7 @@ export default function(state: AppState, action: any) {
const currentRoute = state.route;
newState = { ...state };
newState = Object.assign({}, state);
const newNavHistory = state.navHistory.slice();
if (goingBack) {
@@ -122,7 +119,7 @@ export default function(state: AppState, action: any) {
case 'WINDOW_CONTENT_SIZE_SET':
newState = { ...state };
newState = Object.assign({}, state);
newState.windowContentSize = action.size;
break;
@@ -150,7 +147,7 @@ export default function(state: AppState, action: any) {
return nextLayout === 'both' ? ['editor', 'viewer'] : [nextLayout];
};
newState = { ...state };
newState = Object.assign({}, state);
const panes = state.noteVisiblePanes.slice();
newState.noteVisiblePanes = getNextLayout(panes);
@@ -159,7 +156,7 @@ export default function(state: AppState, action: any) {
case 'NOTE_VISIBLE_PANES_SET':
newState = { ...state };
newState = Object.assign({}, state);
newState.noteVisiblePanes = action.panes;
break;
@@ -174,31 +171,22 @@ export default function(state: AppState, action: any) {
case 'MAIN_LAYOUT_SET_ITEM_PROP':
{
if (!state.mainLayout) {
logger.warn('MAIN_LAYOUT_SET_ITEM_PROP: Trying to set an item prop on the layout, but layout is empty: ', JSON.stringify(action));
} else {
let newLayout = produce(state.mainLayout, (draftLayout: LayoutItem) => {
iterateItems(draftLayout, (_itemIndex: number, item: LayoutItem, _parent: LayoutItem) => {
if (!item) {
logger.warn('MAIN_LAYOUT_SET_ITEM_PROP: Found an empty item in layout: ', JSON.stringify(state.mainLayout));
} else {
if (item.key === action.itemKey) {
(item as any)[action.propName] = action.propValue;
return false;
}
}
return true;
});
let newLayout = produce(state.mainLayout, (draftLayout: LayoutItem) => {
iterateItems(draftLayout, (_itemIndex: number, item: LayoutItem, _parent: LayoutItem) => {
if (item.key === action.itemKey) {
(item as any)[action.propName] = action.propValue;
return false;
}
return true;
});
});
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
newState = {
...state,
mainLayout: newLayout,
};
}
newState = {
...state,
mainLayout: newLayout,
};
}
break;
@@ -206,7 +194,7 @@ export default function(state: AppState, action: any) {
case 'NOTE_FILE_WATCHER_ADD':
if (newState.watchedNoteFiles.indexOf(action.id) < 0) {
newState = { ...state };
newState = Object.assign({}, state);
const watchedNoteFiles = newState.watchedNoteFiles.slice();
watchedNoteFiles.push(action.id);
newState.watchedNoteFiles = watchedNoteFiles;
@@ -216,7 +204,7 @@ export default function(state: AppState, action: any) {
case 'NOTE_FILE_WATCHER_REMOVE':
{
newState = { ...state };
newState = Object.assign({}, state);
const idx = newState.watchedNoteFiles.indexOf(action.id);
if (idx >= 0) {
const watchedNoteFiles = newState.watchedNoteFiles.slice();
@@ -229,7 +217,7 @@ export default function(state: AppState, action: any) {
case 'NOTE_FILE_WATCHER_CLEAR':
if (state.watchedNoteFiles.length) {
newState = { ...state };
newState = Object.assign({}, state);
newState.watchedNoteFiles = [];
}
break;
@@ -237,38 +225,38 @@ export default function(state: AppState, action: any) {
case 'EDITOR_SCROLL_PERCENT_SET':
{
newState = { ...state };
const newPercents = { ...newState.lastEditorScrollPercents };
newState = Object.assign({}, state);
const newPercents = Object.assign({}, newState.lastEditorScrollPercents);
newPercents[action.noteId] = action.percent;
newState.lastEditorScrollPercents = newPercents;
}
break;
case 'NOTE_DEVTOOLS_TOGGLE':
newState = { ...state };
newState = Object.assign({}, state);
newState.devToolsVisible = !newState.devToolsVisible;
break;
case 'NOTE_DEVTOOLS_SET':
newState = { ...state };
newState = Object.assign({}, state);
newState.devToolsVisible = action.value;
break;
case 'VISIBLE_DIALOGS_ADD':
newState = { ...state };
newState.visibleDialogs = { ...newState.visibleDialogs };
newState = Object.assign({}, state);
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
newState.visibleDialogs[action.name] = true;
break;
case 'VISIBLE_DIALOGS_REMOVE':
newState = { ...state };
newState.visibleDialogs = { ...newState.visibleDialogs };
newState = Object.assign({}, state);
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
delete newState.visibleDialogs[action.name];
break;
case 'FOCUS_SET':
newState = { ...state };
newState = Object.assign({}, state);
newState.focusedField = action.field;
break;
@@ -276,7 +264,7 @@ export default function(state: AppState, action: any) {
// A field can only clear its own state
if (action.field === state.focusedField) {
newState = { ...state };
newState = Object.assign({}, state);
newState.focusedField = null;
}
break;
@@ -293,7 +281,7 @@ export default function(state: AppState, action: any) {
isOpen = action.isOpen !== false;
}
newState = { ...state };
newState = Object.assign({}, state);
if (isOpen) {
const newDialogs = newState.dialogs.slice();

View File

@@ -80,7 +80,6 @@ const appDefaultState = createAppDefaultState(
class Application extends BaseApplication {
private checkAllPluginStartedIID_: any = null;
private initPluginServiceDone_: boolean = false;
public constructor() {
super();
@@ -259,9 +258,6 @@ class Application extends BaseApplication {
}
private async initPluginService() {
if (this.initPluginServiceDone_) return;
this.initPluginServiceDone_ = true;
const service = PluginService.instance();
const pluginRunner = new PluginRunner();

View File

@@ -68,10 +68,6 @@ export class Bridge {
return process.argv;
}
public getLocale = () => {
return this.electronApp().electronApp().getLocale();
};
// Applies to electron-context-menu@3:
//
// For now we have to disable spell checking in non-editor text
@@ -88,35 +84,35 @@ export class Bridge {
// Perhaps the easiest would be to patch electron-context-menu to
// support the renderer process again. Or possibly revert to an old
// version of electron-context-menu.
public setupContextMenu(_spellCheckerMenuItemsHandler: Function) {
require('electron-context-menu')({
allWindows: [this.window()],
// public setupContextMenu(_spellCheckerMenuItemsHandler: Function) {
// require('electron-context-menu')({
// allWindows: [this.window()],
electronApp: this.electronApp(),
// 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';
},
// 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';
// },
// menu: (actions: any, props: any) => {
// const items = spellCheckerMenuItemsHandler(props.misspelledWord, props.dictionarySuggestions);
// const spellCheckerMenuItems = items.map((item: any) => new MenuItem(item)); //SpellCheckerService.instance().contextMenuItems(props.misspelledWord, props.dictionarySuggestions).map((item: any) => new MenuItem(item));
// // menu: (actions: any, props: any) => {
// // const items = spellCheckerMenuItemsHandler(props.misspelledWord, props.dictionarySuggestions);
// // const spellCheckerMenuItems = items.map((item: any) => new MenuItem(item)); //SpellCheckerService.instance().contextMenuItems(props.misspelledWord, props.dictionarySuggestions).map((item: any) => new MenuItem(item));
// const output = [
// actions.cut(),
// actions.copy(),
// actions.paste(),
// ...spellCheckerMenuItems,
// ];
// // const output = [
// // actions.cut(),
// // actions.copy(),
// // actions.paste(),
// // ...spellCheckerMenuItems,
// // ];
// return output;
// },
});
}
// // return output;
// // },
// });
// }
public window() {
return this.electronWrapper_.window();
@@ -201,10 +197,12 @@ export class Bridge {
...options,
};
const result = this.showMessageBox_(this.window(), { type: 'question',
const result = this.showMessageBox_(this.window(), Object.assign({}, {
type: 'question',
message: message,
cancelId: 1,
buttons: options.buttons, ...options });
buttons: options.buttons,
}, options));
return result === 0;
}
@@ -213,17 +211,21 @@ export class Bridge {
public showMessageBox(message: string, options: any = null) {
if (options === null) options = {};
const result = this.showMessageBox_(this.window(), { type: 'question',
const result = this.showMessageBox_(this.window(), Object.assign({}, {
type: 'question',
message: message,
buttons: [_('OK'), _('Cancel')], ...options });
buttons: [_('OK'), _('Cancel')],
}, options));
return result;
}
public showInfoMessageBox(message: string, options: any = {}) {
const result = this.showMessageBox_(this.window(), { type: 'info',
const result = this.showMessageBox_(this.window(), Object.assign({}, {
type: 'info',
message: message,
buttons: [_('OK')], ...options });
buttons: [_('OK')],
}, options));
return result === 0;
}

View File

@@ -34,7 +34,7 @@ function getMajorMinorTagName(tagName: string) {
}
async function fetchLatestRelease(options: CheckForUpdateOptions) {
options = { includePreReleases: false, ...options };
options = Object.assign({}, { includePreReleases: false }, options);
const response = await shim.fetch('https://api.github.com/repos/laurent22/joplin/releases');
@@ -97,8 +97,7 @@ async function fetchLatestRelease(options: CheckForUpdateOptions) {
}
if (found) {
downloadUrl = asset.browser_download_url.replace('github.com/laurent22/joplin/releases/download', 'objects.joplinusercontent.com');
downloadUrl.concat('?source=DesktopApp&type=Update');
downloadUrl = asset.browser_download_url;
break;
}
}

View File

@@ -20,7 +20,7 @@ export const runtime = (): CommandRuntime => {
};
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
await restart();
await restart(false);
},
};
};

View File

@@ -46,11 +46,13 @@ class ClipperConfigScreenComponent extends React.Component {
public render() {
const theme = themeStyle(this.props.themeId);
const containerStyle = { ...theme.containerStyle, overflowY: 'scroll',
const containerStyle = Object.assign({}, theme.containerStyle, {
overflowY: 'scroll',
// padding: theme.configScreenPadding,
backgroundColor: theme.backgroundColor3 };
backgroundColor: theme.backgroundColor3,
});
const buttonStyle = { ...theme.buttonStyle, marginRight: 10 };
const buttonStyle = Object.assign({}, theme.buttonStyle, { marginRight: 10 });
const stepBoxStyle = {
border: '1px solid',
@@ -104,16 +106,18 @@ class ClipperConfigScreenComponent extends React.Component {
);
}
const apiTokenStyle = { ...theme.textStyle, color: theme.colorFaded,
const apiTokenStyle = Object.assign({}, theme.textStyle, {
color: theme.colorFaded,
wordBreak: 'break-all',
paddingTop: 10,
paddingBottom: 10 };
paddingBottom: 10,
});
return (
<div>
<div style={containerStyle}>
<div>
<p style={{ ...theme.textStyle, marginTop: 0 }}>{_('Joplin Web Clipper allows saving web pages and screenshots from your browser to Joplin.')}</p>
<p style={Object.assign({}, theme.textStyle, { marginTop: 0 })}>{_('Joplin Web Clipper allows saving web pages and screenshots from your browser to Joplin.')}</p>
<p style={theme.textStyle}>{_('In order to use the web clipper, you need to do the following:')}</p>
<div style={stepBoxStyle}>

View File

@@ -135,7 +135,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
const theme = themeStyle(this.props.themeId);
return (
<div style={{ ...theme.textStyle, marginBottom: 15 }}>
<div style={Object.assign({}, theme.textStyle, { marginBottom: 15 })}>
{description}
</div>
);
@@ -177,7 +177,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
if (section.name === 'sync') {
const syncTargetMd = SyncTargetRegistry.idToMetadata(settings['sync.target']);
const statusStyle = { ...theme.textStyle, marginTop: 10 };
const statusStyle = Object.assign({}, theme.textStyle, { marginTop: 10 });
if (syncTargetMd.supportsConfigCheck) {
const messages = shared.checkSyncConfigMessages(this);
@@ -207,7 +207,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
if (advancedSettingComps.length) {
const iconName = this.state.showAdvancedSettings ? 'fa fa-angle-down' : 'fa fa-angle-right';
// const advancedSettingsButtonStyle = { ...theme.buttonStyle, marginBottom: 10 };
// const advancedSettingsButtonStyle = Object.assign({}, theme.buttonStyle, { marginBottom: 10 });
advancedSettingsButton = (
<div style={{ marginBottom: 10 }}>
<Button
@@ -233,19 +233,23 @@ class ConfigScreenComponent extends React.Component<any, any> {
private labelStyle(themeId: number) {
const theme = themeStyle(themeId);
return { ...theme.textStyle, display: 'block',
return Object.assign({}, theme.textStyle, {
display: 'block',
color: theme.color,
fontSize: theme.fontSize * 1.083333,
fontWeight: 500,
marginBottom: theme.mainPadding / 2 };
marginBottom: theme.mainPadding / 2,
});
}
private descriptionStyle(themeId: number) {
const theme = themeStyle(themeId);
return { ...theme.textStyle, color: theme.colorFaded,
return Object.assign({}, theme.textStyle, {
color: theme.colorFaded,
fontStyle: 'italic',
maxWidth: '70em',
marginTop: 5 };
marginTop: 5,
});
}
private renderLabel(themeId: number, label: string) {
@@ -260,12 +264,14 @@ class ConfigScreenComponent extends React.Component<any, any> {
private renderHeader(themeId: number, label: string, style: any = null) {
const theme = themeStyle(themeId);
const labelStyle = { ...theme.textStyle, display: 'block',
const labelStyle = Object.assign({}, theme.textStyle, {
display: 'block',
color: theme.color,
fontSize: theme.fontSize * 1.25,
fontWeight: 500,
marginBottom: theme.mainPadding,
...style };
...style,
});
return (
<div style={labelStyle}>
@@ -289,13 +295,17 @@ class ConfigScreenComponent extends React.Component<any, any> {
const labelStyle = this.labelStyle(this.props.themeId);
const subLabel = { ...labelStyle, display: 'block',
const subLabel = Object.assign({}, labelStyle, {
display: 'block',
opacity: 0.7,
marginBottom: labelStyle.marginBottom };
marginBottom: labelStyle.marginBottom,
});
const checkboxLabelStyle = { ...labelStyle, marginLeft: 8,
const checkboxLabelStyle = Object.assign({}, labelStyle, {
marginLeft: 8,
display: 'inline',
backgroundColor: 'transparent' };
backgroundColor: 'transparent',
});
const controlStyle = {
display: 'inline-block',
@@ -304,7 +314,8 @@ class ConfigScreenComponent extends React.Component<any, any> {
backgroundColor: theme.backgroundColor,
};
const textInputBaseStyle = { ...controlStyle, fontFamily: theme.fontFamily,
const textInputBaseStyle = Object.assign({}, controlStyle, {
fontFamily: theme.fontFamily,
border: '1px solid',
padding: '4px 6px',
boxSizing: 'border-box',
@@ -313,7 +324,8 @@ class ConfigScreenComponent extends React.Component<any, any> {
paddingLeft: 6,
paddingRight: 6,
paddingTop: 4,
paddingBottom: 4 };
paddingBottom: 4,
});
const updateSettingValue = (key: string, value: any) => {
const md = Setting.settingMetadata(key);
@@ -369,12 +381,14 @@ class ConfigScreenComponent extends React.Component<any, any> {
);
}
const selectStyle = { ...controlStyle, paddingLeft: 6,
const selectStyle = Object.assign({}, controlStyle, {
paddingLeft: 6,
paddingRight: 6,
paddingTop: 4,
paddingBottom: 4,
borderColor: theme.borderColor4,
borderRadius: 3 };
borderRadius: 3,
});
return (
<div key={key} style={rowStyle}>
@@ -429,8 +443,10 @@ class ConfigScreenComponent extends React.Component<any, any> {
</div>
);
} else if (md.type === Setting.TYPE_STRING) {
const inputStyle: any = { ...textInputBaseStyle, width: '50%',
minWidth: '20em' };
const inputStyle: any = Object.assign({}, textInputBaseStyle, {
width: '50%',
minWidth: '20em',
});
const inputType = md.secure === true ? 'password' : 'text';
if (md.subType === 'file_path_and_args' || md.subType === 'file_path' || md.subType === 'directory_path') {
@@ -526,7 +542,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginBottom: inputStyle.marginBottom }}>
<input
type={inputType}
style={{ ...inputStyle, marginBottom: 0, marginRight: 5 }}
style={Object.assign({}, inputStyle, { marginBottom: 0, marginRight: 5 })}
onChange={(event: any) => {
onPathChange(event);
}}
@@ -579,7 +595,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
const label = [md.label()];
if (md.unitLabel) label.push(`(${md.unitLabel()})`);
const inputStyle: any = { ...textInputBaseStyle };
const inputStyle: any = Object.assign({}, textInputBaseStyle);
return (
<div key={key} style={rowStyle}>
@@ -663,13 +679,15 @@ class ConfigScreenComponent extends React.Component<any, any> {
public render() {
const theme = themeStyle(this.props.themeId);
const style = {
...this.props.style,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.backgroundColor3,
};
const style = Object.assign({},
this.props.style,
{
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.backgroundColor3,
}
);
const settings = this.state.settings;

View File

@@ -74,7 +74,7 @@ export default function DialogButtonRow(props: Props) {
if (props.cancelButtonShow !== false) {
buttonComps.push(
<button disabled={props.cancelButtonDisabled} key="cancel" style={{ ...buttonStyle }} onClick={onCancelButtonClick}>
<button disabled={props.cancelButtonDisabled} key="cancel" style={Object.assign({}, buttonStyle)} onClick={onCancelButtonClick}>
{props.cancelButtonLabel ? props.cancelButtonLabel : _('Cancel')}
</button>
);

View File

@@ -29,13 +29,15 @@ class DropboxLoginScreenComponent extends React.Component<any, any> {
const style = this.props.style;
const theme = themeStyle(this.props.themeId);
const containerStyle = { ...theme.containerStyle, padding: theme.configScreenPadding,
const containerStyle = Object.assign({}, theme.containerStyle, {
padding: theme.configScreenPadding,
height: style.height - theme.margin * 2,
flex: 1 };
flex: 1,
});
const inputStyle = { ...theme.inputStyle, width: 500 };
const inputStyle = Object.assign({}, theme.inputStyle, { width: 500 });
const buttonStyle = { ...theme.buttonStyle, marginRight: 10 };
const buttonStyle = Object.assign({}, theme.buttonStyle, { marginRight: 10 });
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>

View File

@@ -82,7 +82,7 @@ function ExtensionBadge(props: Props) {
void bridge().openExternal(props.url);
};
const rootStyle = props.style ? { ...style.root, ...props.style } : style.root;
const rootStyle = props.style ? Object.assign({}, style.root, props.style) : style.root;
return (
<a style={rootStyle} onClick={onClick} href="#">

View File

@@ -23,7 +23,7 @@ class HelpButtonComponent extends React.Component<Props> {
public render() {
const theme = themeStyle(this.props.themeId);
const style = { ...this.props.style, color: theme.color, textDecoration: 'none' };
const style = Object.assign({}, this.props.style, { color: theme.color, textDecoration: 'none' });
const helpIconStyle = { flex: 0, width: 16, height: 16, marginLeft: 10 };
const extraProps: any = {};
if (this.props.tip) extraProps['data-tip'] = this.props.tip;

View File

@@ -18,19 +18,21 @@ class IconButton extends React.Component<Props> {
};
const icon = <i style={iconStyle} className={`fas ${this.props.iconName}`}></i>;
const rootStyle = {
display: 'flex',
textDecoration: 'none',
padding: 10,
width: theme.buttonMinHeight,
height: theme.buttonMinHeight,
boxSizing: 'border-box',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.backgroundColor,
cursor: 'default',
...style,
};
const rootStyle = Object.assign(
{
display: 'flex',
textDecoration: 'none',
padding: 10,
width: theme.buttonMinHeight,
height: theme.buttonMinHeight,
boxSizing: 'border-box',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.backgroundColor,
cursor: 'default',
},
style
);
return (
<a

View File

@@ -1,4 +1,7 @@
import * as React from 'react';
import Logger from '@joplin/lib/Logger';
const logger = Logger.create('ItemList');
interface Props {
style: any;
@@ -47,6 +50,15 @@ class ItemList extends React.Component<Props, State> {
let bottomItemIndex = topItemIndex + (visibleItemCount - 1);
if (bottomItemIndex >= props.items.length) bottomItemIndex = props.items.length - 1;
// EDGE CASE:
// ref: https://github.com/laurent22/joplin/issues/4124
// when the note list is hidden, visibleItemCount is negative, and scroll top is positive when a note is selected
if (visibleItemCount < 0 && this.scrollTop_ > 0) {
logger.warn('Resetting scrollTop to 0. visibleItemCount is negative, scrollTop is positive.');
// we will reset the scroll top so that there is no blank space at the top of note list
this.scrollTop_ = 0;
}
this.setState({
topItemIndex: topItemIndex,
bottomItemIndex: bottomItemIndex,
@@ -69,6 +81,21 @@ class ItemList extends React.Component<Props, State> {
this.updateStateItemIndexes(newProps);
}
public componentDidUpdate(): void {
// EDGE CASE
// scroll top is not updated when item list visibility is toggled
// if the user was at the bottom of the item list before hiding, blank spaces are added at the bottom of the item list
if (this.offsetScroll() !== this.listRef.current?.scrollTop) {
logger.warn(`scrollTop mismatch. Updating scrollTop with current listRef scrollTop(${this.listRef.current.scrollTop})`);
// update scroll postion once if there is a mismatch in scroll position after showing item list
this.onScroll({
target: {
scrollTop: this.listRef.current.scrollTop,
},
});
}
}
public onScroll(event: any) {
this.scrollTop_ = event.target.scrollTop;
this.updateStateItemIndexes();
@@ -121,8 +148,10 @@ class ItemList extends React.Component<Props, State> {
public render() {
const items = this.props.items;
const style = { ...this.props.style, overflowX: 'hidden',
overflowY: 'auto' };
const style = Object.assign({}, this.props.style, {
overflowX: 'hidden',
overflowY: 'auto',
});
// if (this.props.disabled) style.opacity = 0.5;

View File

@@ -501,14 +501,16 @@ class MainScreenComponent extends React.Component<Props, State> {
height: height,
};
this.styles_.modalLayer = { ...theme.textStyle, zIndex: 10000,
this.styles_.modalLayer = Object.assign({}, theme.textStyle, {
zIndex: 10000,
position: 'absolute',
top: 0,
left: 0,
backgroundColor: theme.backgroundColor,
width: width - 20,
height: height - 20,
padding: 10 };
padding: 10,
});
return this.styles_;
}
@@ -801,11 +803,13 @@ class MainScreenComponent extends React.Component<Props, State> {
public render() {
const theme = themeStyle(this.props.themeId);
const style = {
color: theme.color,
backgroundColor: theme.backgroundColor,
...this.props.style,
};
const style = Object.assign(
{
color: theme.color,
backgroundColor: theme.backgroundColor,
},
this.props.style
);
const promptOptions = this.state.promptOptions;
const styles = this.styles(this.props.themeId, style.width, style.height, this.messageBoxVisible());
@@ -820,7 +824,7 @@ class MainScreenComponent extends React.Component<Props, State> {
const dialogInfo = PluginManager.instance().pluginDialogToShow(this.props.pluginsLegacy);
const pluginDialog = !dialogInfo ? null : <dialogInfo.Dialog {...dialogInfo.props} />;
const modalLayerStyle = { ...styles.modalLayer, display: this.state.modalLayer.visible ? 'block' : 'none' };
const modalLayerStyle = Object.assign({}, styles.modalLayer, { display: this.state.modalLayer.visible ? 'block' : 'none' });
const notePropertiesDialogOptions = this.state.notePropertiesDialogOptions;
const noteContentPropertiesDialogOptions = this.state.noteContentPropertiesDialogOptions;
@@ -862,7 +866,6 @@ class MainScreenComponent extends React.Component<Props, State> {
const mapStateToProps = (state: AppState) => {
const syncInfo = localSyncInfoFromState(state);
const showNeedUpgradingEnabledMasterKeyMessage = !!EncryptionService.instance().masterKeysThatNeedUpgrading(syncInfo.masterKeys.filter((k) => !!k.enabled)).length;
return {
themeId: state.settings.theme,
@@ -870,7 +873,7 @@ const mapStateToProps = (state: AppState) => {
hasDisabledSyncItems: state.hasDisabledSyncItems,
hasDisabledEncryptionItems: state.hasDisabledEncryptionItems,
showMissingMasterKeyMessage: showMissingMasterKeyMessage(syncInfo, state.notLoadedMasterKeys),
showNeedUpgradingMasterKeyMessage: showNeedUpgradingEnabledMasterKeyMessage,
showNeedUpgradingMasterKeyMessage: !!EncryptionService.instance().masterKeysThatNeedUpgrading(syncInfo.masterKeys).length,
showShouldReencryptMessage: state.settings['encryption.shouldReencrypt'] >= Setting.SHOULD_REENCRYPT_YES,
shouldUpgradeSyncTarget: state.settings['sync.upgradeState'] === Setting.SYNC_UPGRADE_STATE_SHOULD_DO,
pluginsLegacy: state.pluginsLegacy,

View File

@@ -22,7 +22,7 @@ export const runtime = (comp: any): CommandRuntime => {
const { newConfig, newProfile } = createNewProfile(context.state.profileConfig, answer);
newConfig.currentProfileId = newProfile.id;
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
await restart();
await restart(false);
}
comp.setState({ promptOptions: null });

View File

@@ -17,9 +17,11 @@ export const runtime = (): CommandRuntime => {
const defaultValues = Note.previewFieldsWithDefaultValues({ includeTimestamps: false });
let newNote = { ...defaultValues, parent_id: folderId,
let newNote = Object.assign({}, defaultValues, {
parent_id: folderId,
is_todo: isTodo ? 1 : 0,
body: body };
body: body,
});
newNote = await Note.save(newNote, { provisional: true });

View File

@@ -3,7 +3,7 @@ import { useState, useEffect } from 'react';
import { _ } from '@joplin/lib/locale';
import DialogButtonRow from './DialogButtonRow';
const { themeStyle } = require('@joplin/lib/theme');
const Countable = require('@joplin/lib/countable/Countable');
const Countable = require('countable');
import markupLanguageUtils from '../utils/markupLanguageUtils';
interface NoteContentPropertiesDialogProps {

View File

@@ -32,52 +32,84 @@ import Setting from '@joplin/lib/models/Setting';
// import eventManager from '@joplin/lib/eventManager';
import { reg } from '@joplin/lib/registry';
// import { reg } from '@joplin/lib/registry';
// Based on http://pypl.github.io/PYPL.html
const topLanguages = [
'python',
'clike',
'javascript',
'jsx',
'php',
'r',
'swift',
'go',
'vb',
'vbscript',
'ruby',
'rust',
'dart',
'lua',
'groovy',
'perl',
'cobol',
'julia',
'haskell',
'pascal',
'css',
require('codemirror/mode/python/python');
require('codemirror/mode/clike/clike');
require('codemirror/mode/javascript/javascript');
require('codemirror/mode/jsx/jsx');
require('codemirror/mode/php/php');
require('codemirror/mode/r/r');
require('codemirror/mode/swift/swift');
require('codemirror/mode/go/go');
require('codemirror/mode/vb/vb');
require('codemirror/mode/vbscript/vbscript');
require('codemirror/mode/ruby/ruby');
require('codemirror/mode/rust/rust');
require('codemirror/mode/dart/dart');
require('codemirror/mode/lua/lua');
require('codemirror/mode/groovy/groovy');
require('codemirror/mode/perl/perl');
require('codemirror/mode/cobol/cobol');
require('codemirror/mode/julia/julia');
require('codemirror/mode/haskell/haskell');
require('codemirror/mode/pascal/pascal');
require('codemirror/mode/css/css');
// Additional languages, not in the PYPL list
'xml', // For HTML too
'markdown',
'yaml',
'shell',
'dockerfile',
'diff',
'erlang',
'sql',
];
// Load Top Modes
for (let i = 0; i < topLanguages.length; i++) {
const mode = topLanguages[i];
// Additional languages, not in the PYPL list
require('codemirror/mode/xml/xml'); // For HTML too
require('codemirror/mode/markdown/markdown');
require('codemirror/mode/yaml/yaml');
require('codemirror/mode/shell/shell');
require('codemirror/mode/dockerfile/dockerfile');
require('codemirror/mode/diff/diff');
require('codemirror/mode/erlang/erlang');
require('codemirror/mode/sql/sql');
if (CodeMirror.modeInfo.find((m: any) => m.mode === mode)) {
require(`codemirror/mode/${mode}/${mode}`);
} else {
reg.logger().error('Cannot find CodeMirror mode: ', mode);
}
}
// // Based on http://pypl.github.io/PYPL.html
// const topLanguages = [
// 'python',
// 'clike',
// 'javascript',
// 'jsx',
// 'php',
// 'r',
// 'swift',
// 'go',
// 'vb',
// 'vbscript',
// 'ruby',
// 'rust',
// 'dart',
// 'lua',
// 'groovy',
// 'perl',
// 'cobol',
// 'julia',
// 'haskell',
// 'pascal',
// 'css',
// // Additional languages, not in the PYPL list
// 'xml', // For HTML too
// 'markdown',
// 'yaml',
// 'shell',
// 'dockerfile',
// 'diff',
// 'erlang',
// 'sql',
// ];
// // Load Top Modes
// for (let i = 0; i < topLanguages.length; i++) {
// const mode = topLanguages[i];
// if (CodeMirror.modeInfo.find((m: any) => m.mode === mode)) {
// require(`codemirror/mode/${mode}/${mode}`);
// } else {
// reg.logger().error('Cannot find CodeMirror mode: ', mode);
// }
// }
export interface EditorProps {
value: string;

View File

@@ -31,7 +31,7 @@ export default function useExternalPlugins(CodeMirror: any, plugins: PluginState
}
if (mod.codeMirrorOptions) {
newOptions = { ...newOptions, ...mod.codeMirrorOptions };
newOptions = Object.assign({}, newOptions, mod.codeMirrorOptions);
}
if (mod.assets) {

View File

@@ -6,7 +6,8 @@ import useScroll from './utils/useScroll';
import styles_ from './styles';
import CommandService from '@joplin/lib/services/CommandService';
import { ToolbarButtonInfo } from '@joplin/lib/services/commands/ToolbarButtonUtils';
import ToggleEditorsButton, { Value as ToggleEditorsButtonValue } from '../../../ToggleEditorsButton/ToggleEditorsButton';
import ToggleEditorsButton from '../../../ToggleEditorsButton/ToggleEditorsButton';
import { Value as ToggleEditorsButtonValue } from '../../../ToggleEditorsButton/types';
import ToolbarButton from '../../../../gui/ToolbarButton/ToolbarButton';
import usePluginServiceRegistration from '../../utils/usePluginServiceRegistration';
import { utils as pluginUtils } from '@joplin/lib/services/plugins/reducer';

View File

@@ -1544,7 +1544,7 @@
}
});
editor.addCommand('InsertJoplinChecklist', function (ui, detail) {
detail = { ...detail, listType: 'joplinChecklist' };
detail = Object.assign({}, detail, { listType: 'joplinChecklist' });
ToggleList.toggleList(editor, 'UL', detail);
});
}

View File

@@ -364,11 +364,13 @@ function NoteEditor(props: NoteEditorProps) {
}, [props.dispatch, formNote]);
function renderNoNotes(rootStyle: any) {
const emptyDivStyle = {
backgroundColor: 'black',
opacity: 0.1,
...rootStyle,
};
const emptyDivStyle = Object.assign(
{
backgroundColor: 'black',
opacity: 0.1,
},
rootStyle
);
return <div style={emptyDivStyle}></div>;
}

View File

@@ -59,12 +59,14 @@ export default function useMarkupToHtml(deps: HookDependencies) {
delete options.replaceResourceInternalToExternalLinks;
const result = await markupToHtml.render(markupLanguage, md, theme, { codeTheme: theme.codeThemeCss,
const result = await markupToHtml.render(markupLanguage, md, theme, Object.assign({}, {
codeTheme: theme.codeThemeCss,
resources: resources,
postMessageSyntax: 'ipcProxySendToHost',
splitted: true,
externalAssetsOnly: true,
codeHighlightCacheKey: 'useMarkupToHtml', ...options });
codeHighlightCacheKey: 'useMarkupToHtml',
}, options));
return result;
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied

View File

@@ -62,7 +62,7 @@ export default function useNoteSearchBar({ noteSearchBarRef }: UseNoteSearchBarP
const noteSearchBarNextPrevious = useCallback((inc: number) => {
setLocalSearch((prev: LocalSearch) => {
const ls = { ...prev };
const ls = Object.assign({}, prev);
ls.selectedIndex += inc;
ls.timestamp = Date.now();
if (ls.selectedIndex < 0) ls.selectedIndex = ls.resultCount - 1;

View File

@@ -19,6 +19,7 @@ import Note from '@joplin/lib/models/Note';
import Folder from '@joplin/lib/models/Folder';
import { Props } from './types';
import usePrevious from '../hooks/usePrevious';
import itemAnchorRef, { itemAnchorRefs_ } from './itemAnchorRef';
const commands = [
require('./commands/focusElementNoteList'),
@@ -31,15 +32,6 @@ const StyledRoot = styled.div`
border-right: 1px solid ${(props: any) => props.theme.dividerColor};
`;
const itemAnchorRefs_: any = {
current: {},
};
export const itemAnchorRef = (itemId: string) => {
if (itemAnchorRefs_.current[itemId] && itemAnchorRefs_.current[itemId].current) return itemAnchorRefs_.current[itemId].current;
return null;
};
const NoteListComponent = (props: Props) => {
const [dragOverTargetNoteIndex, setDragOverTargetNoteIndex] = useState(null);
const [width, setWidth] = useState(0);

View File

@@ -1,7 +1,7 @@
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
import { _ } from '@joplin/lib/locale';
import { stateUtils } from '@joplin/lib/reducer';
import { itemAnchorRef } from '../NoteList';
import itemAnchorRef from '../itemAnchorRef';
export const declaration: CommandDeclaration = {
name: 'focusElementNoteList',

View File

@@ -0,0 +1,8 @@
export const itemAnchorRefs_: any = {
current: {},
};
export default (itemId: string) => {
if (itemAnchorRefs_.current[itemId] && itemAnchorRefs_.current[itemId].current) return itemAnchorRefs_.current[itemId].current;
return null;
};

View File

@@ -181,7 +181,7 @@ function NoteListControls(props: Props) {
useEffect(() => {
if (breakpoint === dynamicBreakpoints.Xl) {
noteControlsRef.current.style.flexDirection = 'row';
searchAndSortRef.current.style.flex = '2 1 50%';
searchAndSortRef.current.style.flex = '2 1 auto';
props.onContentHeightChange(true);
} else {
noteControlsRef.current.style.flexDirection = 'column';

View File

@@ -108,10 +108,10 @@ function NoteListItem(props: NoteListItemProps, ref: any) {
);
}
let listItemTitleStyle = { ...props.style.listItemTitle };
let listItemTitleStyle = Object.assign({}, props.style.listItemTitle);
listItemTitleStyle.paddingLeft = !item.is_todo ? hPadding : 4;
if (item.is_shared) listItemTitleStyle.color = theme.colorWarn3;
if (item.is_todo && !!item.todo_completed) listItemTitleStyle = { ...listItemTitleStyle, ...props.style.listItemTitleCompleted };
if (item.is_todo && !!item.todo_completed) listItemTitleStyle = Object.assign(listItemTitleStyle, props.style.listItemTitleCompleted);
const displayTitle = Note.displayTitle(item);
let titleComp = null;

View File

@@ -114,7 +114,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
}
public formNoteToNote(formNote: any) {
const note = { id: formNote.id, ...this.latLongFromLocation(formNote.location) };
const note = Object.assign({ id: formNote.id }, this.latLongFromLocation(formNote.location));
note.user_created_time = time.formatLocalToMs(formNote.user_created_time);
note.user_updated_time = time.formatLocalToMs(formNote.user_updated_time);
@@ -211,7 +211,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
if (!this.state.editedKey) return;
return new Promise((resolve: Function) => {
const newFormNote = { ...this.state.formNote };
const newFormNote = Object.assign({}, this.state.formNote);
if (this.state.editedKey.indexOf('_time') >= 0) {
const dt = time.anythingToDateTime(this.state.editedValue, new Date());
@@ -248,7 +248,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
public createNoteField(key: string, value: any) {
const styles = this.styles(this.props.themeId);
const theme = themeStyle(this.props.themeId);
const labelComp = <label style={{ ...theme.textStyle, ...theme.controlBoxLabel }}>{this.formatLabel(key)}</label>;
const labelComp = <label style={Object.assign({}, theme.textStyle, theme.controlBoxLabel)}>{this.formatLabel(key)}</label>;
let controlComp = null;
let editComp = null;
let editCompHandler = null;
@@ -317,7 +317,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
const ll = this.latLongFromLocation(value);
url = Note.geoLocationUrlFromLatLong(ll.latitude, ll.longitude);
}
const urlStyle = { ...theme.urlStyle, maxWidth: '180px', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' };
const urlStyle = Object.assign({}, theme.urlStyle, { maxWidth: '180px', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' });
controlComp = (
<a href="#" onClick={() => bridge().openExternal(url)} style={urlStyle}>
{displayedValue}
@@ -330,7 +330,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
</a>
);
} else {
controlComp = <div style={{ ...theme.textStyle, ...theme.controlBoxValue }}>{displayedValue}</div>;
controlComp = <div style={Object.assign({}, theme.textStyle, theme.controlBoxValue)}>{displayedValue}</div>;
}
if (['id', 'revisionsLink', 'markup_language'].indexOf(key) < 0) {

View File

@@ -67,8 +67,8 @@ class NoteRevisionViewerComponent extends React.PureComponent<Props, State> {
flex: 1,
flexDirection: 'column',
},
titleInput: { ...theme.inputStyle, flex: 1 },
revisionList: { ...theme.dropdownList, marginLeft: 10, flex: 0.5 },
titleInput: Object.assign({}, theme.inputStyle, { flex: 1 }),
revisionList: Object.assign({}, theme.dropdownList, { marginLeft: 10, flex: 0.5 }),
};
return style;
@@ -205,14 +205,14 @@ class NoteRevisionViewerComponent extends React.PureComponent<Props, State> {
const titleInput = (
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginBottom: 10, borderWidth: 1, borderBottomStyle: 'solid', borderColor: theme.dividerColor, paddingBottom: 10 }}>
<button onClick={this.backButton_click} style={{ ...theme.buttonStyle, marginRight: 10, height: theme.inputStyle.height }}>
<button onClick={this.backButton_click} style={Object.assign({}, theme.buttonStyle, { marginRight: 10, height: theme.inputStyle.height })}>
<i style={theme.buttonIconStyle} className={'fa fa-chevron-left'}></i>{_('Back')}
</button>
<input readOnly type="text" style={style.titleInput} value={this.state.note ? this.state.note.title : ''} />
<select disabled={!this.state.revisions.length} value={this.state.currentRevId} style={style.revisionList} onChange={this.revisionList_onChange}>
{revisionListItems}
</select>
<button disabled={!this.state.revisions.length || this.state.restoring} onClick={this.importButton_onClick} style={{ ...theme.buttonStyle, marginLeft: 10, height: theme.inputStyle.height }}>
<button disabled={!this.state.revisions.length || this.state.restoring} onClick={this.importButton_onClick} style={Object.assign({}, theme.buttonStyle, { marginLeft: 10, height: theme.inputStyle.height })}>
{restoreButtonTitle}
</button>
<HelpButton tip={helpMessage} id="noteRevisionHelpButton" onClick={this.helpButton_onClick} />

View File

@@ -37,8 +37,10 @@ class NoteSearchBar extends React.Component<Props> {
const theme = themeStyle(this.props.themeId);
const style = {
root: { ...theme.textStyle, backgroundColor: theme.backgroundColor,
color: theme.colorFaded },
root: Object.assign({}, theme.textStyle, {
backgroundColor: theme.backgroundColor,
color: theme.colorFaded,
}),
};
return style;
@@ -148,10 +150,12 @@ class NoteSearchBar extends React.Component<Props> {
const previousButton = this.buttonIconComponent('fa-chevron-up', this.previousButton_click, buttonEnabled);
const nextButton = this.buttonIconComponent('fa-chevron-down', this.nextButton_click, buttonEnabled);
const textStyle = { fontSize: theme.fontSize,
const textStyle = Object.assign({
fontSize: theme.fontSize,
fontFamily: theme.fontFamily,
color: theme.colorFaded,
backgroundColor: theme.backgroundColor };
backgroundColor: theme.backgroundColor,
});
const matchesFoundString = (query.length > 0) ? (
<div style={textStyle}>

View File

@@ -15,8 +15,10 @@ class NoteStatusBarComponent extends React.Component<Props> {
const theme = themeStyle(this.props.themeId);
const style = {
root: { ...theme.textStyle, backgroundColor: theme.backgroundColor,
color: theme.colorFaded },
root: Object.assign({}, theme.textStyle, {
backgroundColor: theme.backgroundColor,
color: theme.colorFaded,
}),
};
return style;

View File

@@ -173,7 +173,7 @@ export default class NoteTextViewerComponent extends React.Component<Props, any>
// ----------------------------------------------------------------
public render() {
const viewerStyle = { border: 'none', ...this.props.viewerStyle };
const viewerStyle = Object.assign({}, { border: 'none' }, this.props.viewerStyle);
return <iframe className="noteTextViewer" ref={this.webviewRef_} style={viewerStyle} src="gui/note-viewer/index.html"></iframe>;
}
}

View File

@@ -26,15 +26,11 @@ export default class PromptDialog extends React.Component<Props, any> {
private focusInput_: boolean;
private styles_: any;
private styleKey_: string;
private menuIsOpened_: boolean = false;
public constructor(props: Props) {
super(props);
this.answerInput_ = React.createRef();
this.select_menuOpen = this.select_menuOpen.bind(this);
this.select_menuClose = this.select_menuClose.bind(this);
}
public UNSAFE_componentWillMount() {
@@ -43,7 +39,6 @@ export default class PromptDialog extends React.Component<Props, any> {
answer: this.props.defaultValue ? this.props.defaultValue : '',
});
this.focusInput_ = true;
this.menuIsOpened_ = false;
}
public UNSAFE_componentWillReceiveProps(newProps: Props) {
@@ -57,14 +52,6 @@ export default class PromptDialog extends React.Component<Props, any> {
}
}
private select_menuOpen() {
this.menuIsOpened_ = true;
}
private select_menuClose() {
this.menuIsOpened_ = false;
}
public componentDidUpdate() {
if (this.focusInput_ && this.answerInput_.current) this.answerInput_.current.focus();
this.focusInput_ = false;
@@ -132,49 +119,43 @@ export default class PromptDialog extends React.Component<Props, any> {
};
this.styles_.select = {
control: (provided: any) => {
return { ...provided,
control: (provided: any) =>
Object.assign(provided, {
minWidth: width * 0.2,
maxWidth: width * 0.5,
fontFamily: theme.fontFamily,
};
},
input: (provided: any) => {
return { ...provided,
}),
input: (provided: any) =>
Object.assign(provided, {
minWidth: '20px',
color: theme.color,
};
},
menu: (provided: any) => {
return { ...provided,
}),
menu: (provided: any) =>
Object.assign(provided, {
color: theme.color,
fontFamily: theme.fontFamily,
backgroundColor: theme.backgroundColor,
};
},
option: (provided: any, state: any) => {
return { ...provided,
}),
option: (provided: any, state: any) =>
Object.assign(provided, {
color: theme.color,
fontFamily: theme.fontFamily,
paddingLeft: `${10 + (state.data.indentDepth || 0) * 20}px`,
};
},
multiValueLabel: (provided: any) => {
return { ...provided,
}),
multiValueLabel: (provided: any) =>
Object.assign(provided, {
fontFamily: theme.fontFamily,
};
},
multiValueRemove: (provided: any) => {
return { ...provided,
}),
multiValueRemove: (provided: any) =>
Object.assign(provided, {
color: theme.color,
};
},
}),
};
this.styles_.selectTheme = (tagTheme: any) => {
return { ...tagTheme,
this.styles_.selectTheme = (tagTheme: any) =>
Object.assign(tagTheme, {
borderRadius: 2,
colors: { ...tagTheme.colors,
colors: Object.assign(tagTheme.colors, {
primary: theme.raisedBackgroundColor,
primary25: theme.raisedBackgroundColor,
neutral0: theme.backgroundColor,
@@ -190,11 +171,12 @@ export default class PromptDialog extends React.Component<Props, any> {
neutral90: theme.color,
danger: theme.backgroundColor,
dangerLight: theme.colorError2,
},
};
};
}),
});
this.styles_.desc = { ...theme.textStyle, marginTop: 10 };
this.styles_.desc = Object.assign({}, theme.textStyle, {
marginTop: 10,
});
return this.styles_;
}
@@ -242,14 +224,16 @@ export default class PromptDialog extends React.Component<Props, any> {
const onKeyDown = (event: any) => {
if (event.key === 'Enter') {
// If the dropdown is open, we don't close the dialog - instead
// the currently item will be selcted. If it is closed however
// we confirm the dialog.
if ((this.props.inputType === 'tags' || this.props.inputType === 'dropdown') && this.menuIsOpened_) {
if (this.props.inputType === 'tags' || this.props.inputType === 'dropdown') {
// Do nothing
} else {
onClose(true);
}
// } else if (this.answerInput_.current && !this.answerInput_.current.state.menuIsOpen) {
// // The menu will be open if the user is selecting a new item
// onClose(true);
// }
} else if (event.key === 'Escape') {
onClose(false);
}
@@ -262,9 +246,9 @@ export default class PromptDialog extends React.Component<Props, any> {
if (this.props.inputType === 'datetime') {
inputComp = <Datetime className="datetime-picker" value={this.state.answer} inputProps={{ style: styles.input }} dateFormat={time.dateFormat()} timeFormat={time.timeFormat()} onChange={(momentObject: any) => onDateTimeChange(momentObject)} />;
} else if (this.props.inputType === 'tags') {
inputComp = <CreatableSelect className="tag-selector" onMenuOpen={this.select_menuOpen} onMenuClose={this.select_menuClose} styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} value={this.state.answer} placeholder="" components={makeAnimated()} isMulti={true} isClearable={false} backspaceRemovesValue={true} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />;
inputComp = <CreatableSelect className="tag-selector" styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} value={this.state.answer} placeholder="" components={makeAnimated()} isMulti={true} isClearable={false} backspaceRemovesValue={true} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />;
} else if (this.props.inputType === 'dropdown') {
inputComp = <Select className="item-selector" onMenuOpen={this.select_menuOpen} onMenuClose={this.select_menuClose} styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} components={makeAnimated()} value={this.props.answer} defaultValue={this.props.defaultValue} isClearable={false} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />;
inputComp = <Select className="item-selector" styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} components={makeAnimated()} value={this.props.answer} defaultValue={this.props.defaultValue} isClearable={false} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />;
} else {
inputComp = <input style={styles.input} ref={this.answerInput_} value={this.state.answer} type="text" onChange={event => onChange(event)} onKeyDown={event => onKeyDown(event)} />;
}

View File

@@ -27,7 +27,7 @@ import StyleSheetContainer from './StyleSheets/StyleSheetContainer';
import ImportScreen from './ImportScreen';
const { ResourceScreen } = require('./ResourceScreen.js');
import Navigator from './Navigator';
import WelcomeUtils from '@joplin/lib/WelcomeUtils';
const WelcomeUtils = require('@joplin/lib/WelcomeUtils');
const { ThemeProvider, StyleSheetManager, createGlobalStyle } = require('styled-components');
const bridge = require('@electron/remote').require('./bridge').default;
@@ -141,7 +141,7 @@ class RootComponent extends React.Component<Props, any> {
});
}
await WelcomeUtils.install(Setting.value('locale'), this.props.dispatch);
await WelcomeUtils.install(this.props.dispatch);
}
private renderModalMessage(props: ModalDialogProps) {

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { useEffect, useRef, useCallback, useMemo } from 'react';
import styled, { css } from 'styled-components';
import styled from 'styled-components';
import shim from '@joplin/lib/shim';
import { StyledRoot, StyledAddButton, StyledShareIcon, StyledHeader, StyledHeaderIcon, StyledAllNotesIcon, StyledHeaderLabel, StyledListItem, StyledListItemAnchor, StyledExpandLink, StyledNoteCount, StyledSyncReportText, StyledSyncReport, StyledSynchronizeButton } from './styles';
import { ButtonLevel } from '../Button/Button';
@@ -40,14 +40,23 @@ const { clipboard } = require('electron');
const logger = Logger.create('Sidebar');
// Workaround sidebar rendering bug on Linux Intel GPU.
// https://github.com/laurent22/joplin/issues/7506
const StyledSpanFix = styled.span`
${shim.isLinux() && css`
position: relative;
`}
const StyledFoldersHolder = styled.div`
// linux bug: https://github.com/laurent22/joplin/issues/7506#issuecomment-1447101057
& a.list-item {
${shim.isLinux() && {
opacity: 1,
}}
}
`;
const TagsHolder = styled.div`
// linux bug: https://github.com/laurent22/joplin/issues/8000
// solution ref: https://github.com/laurent22/joplin/issues/7506#issuecomment-1447101057
& a.list-item {
${shim.isLinux() && {
opacity: 1,
}}
}
`;
interface Props {
themeId: number;
@@ -129,7 +138,7 @@ function FolderItem(props: any) {
}}
onDoubleClick={onFolderToggleClick_}
>
{showFolderIcon ? renderFolderIcon(folderIcon) : null}<StyledSpanFix className="title" style={{ lineHeight: 0 }}>{folderTitle}</StyledSpanFix>
{showFolderIcon ? renderFolderIcon(folderIcon) : null}<span className="title" style={{ lineHeight: 0 }}>{folderTitle}</span>
{shareIcon} {noteCountComp}
</StyledListItemAnchor>
</StyledListItem>
@@ -564,7 +573,7 @@ const SidebarComponent = (props: Props) => {
tagItem_click(tag);
}}
>
<StyledSpanFix className="tag-label">{Tag.displayTitle(tag)}</StyledSpanFix>
<span className="tag-label">{Tag.displayTitle(tag)}</span>
{noteCount}
</StyledListItemAnchor>
</StyledListItem>
@@ -716,13 +725,13 @@ const SidebarComponent = (props: Props) => {
const folderItems = [renderAllNotesItem(theme, allNotesSelected)].concat(result.items);
folderItemsOrder_.current = result.order;
items.push(
<div
<StyledFoldersHolder
className={`folders ${props.folderHeaderIsExpanded ? 'expanded' : ''}`}
key="folder_items"
style={foldersStyle}
>
{folderItems}
</div>
</StyledFoldersHolder>
);
}
@@ -738,9 +747,9 @@ const SidebarComponent = (props: Props) => {
tagItemsOrder_.current = result.order;
items.push(
<div className="tags" key="tag_items" style={{ display: props.tagHeaderIsExpanded ? 'block' : 'none' }}>
<TagsHolder className="tags" key="tag_items" style={{ display: props.tagHeaderIsExpanded ? 'block' : 'none' }}>
{tagItems}
</div>
</TagsHolder>
);
}

View File

@@ -56,13 +56,15 @@ function StatusScreen(props: Props) {
flexDirection: 'column',
};
const retryStyle = { ...theme.urlStyle, marginLeft: 5 };
const retryAllStyle = { ...theme.urlStyle, marginTop: 5, display: 'inline-block' };
const retryStyle = Object.assign({}, theme.urlStyle, { marginLeft: 5 });
const retryAllStyle = Object.assign({}, theme.urlStyle, { marginTop: 5, display: 'inline-block' });
const containerPadding = theme.configScreenPadding;
const containerStyle = { ...theme.containerStyle, padding: containerPadding,
flex: 1 };
const containerStyle = Object.assign({}, theme.containerStyle, {
padding: containerPadding,
flex: 1,
});
function renderSectionTitleHtml(key: string, title: string) {
return (

View File

@@ -37,5 +37,5 @@ export default function(props: Props): any {
};
}, [styleSheetContent]);
return <div style={{ display: 'none' }}></div>;
return null; // <div style={{ display: 'none' }}></div>;
}

View File

@@ -7,7 +7,7 @@ import { AppState } from '../app.reducer';
class TagItemComponent extends React.Component {
public render() {
const theme = themeStyle(this.props.themeId);
const style = { ...theme.tagStyle };
const style = Object.assign({}, theme.tagStyle);
const { title, id } = this.props;
return <button style={style} onClick={() => CommandService.instance().execute('openTag', id)}>{title}</button>;

View File

@@ -1,17 +1,6 @@
import * as React from 'react';
import styles_ from './styles';
import { ToolbarButtonInfo } from '@joplin/lib/services/commands/ToolbarButtonUtils';
export enum Value {
Markdown = 'markdown',
RichText = 'richText',
}
export interface Props {
themeId: number;
value: Value;
toolbarButtonInfo: ToolbarButtonInfo;
}
import { Props } from './types';
export default function ToggleEditorsButton(props: Props) {
const style = styles_(props);

View File

@@ -1,4 +1,4 @@
import { Props, Value } from '../ToggleEditorsButton';
import { Props, Value } from '../types';
const { buildStyle } = require('@joplin/lib/theme');
export default function styles(props: Props) {

View File

@@ -0,0 +1,12 @@
import { ToolbarButtonInfo } from '@joplin/lib/services/commands/ToolbarButtonUtils';
export enum Value {
Markdown = 'markdown',
RichText = 'richText',
}
export interface Props {
themeId: number;
value: Value;
toolbarButtonInfo: ToolbarButtonInfo;
}

View File

@@ -1,6 +1,7 @@
import * as React from 'react';
import ToolbarButton from './ToolbarButton/ToolbarButton';
import ToggleEditorsButton, { Value } from './ToggleEditorsButton/ToggleEditorsButton';
import ToggleEditorsButton from './ToggleEditorsButton/ToggleEditorsButton';
import { Value } from './ToggleEditorsButton/types';
import ToolbarSpace from './ToolbarSpace';
const { connect } = require('react-redux');
const { themeStyle } = require('@joplin/lib/theme');
@@ -16,12 +17,14 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
public render() {
const theme = themeStyle(this.props.themeId);
const style: any = { display: 'flex',
const style: any = Object.assign({
display: 'flex',
flexDirection: 'row',
boxSizing: 'border-box',
backgroundColor: theme.backgroundColor3,
padding: theme.toolbarPadding,
paddingRight: theme.mainPadding, ...this.props.style };
paddingRight: theme.mainPadding,
}, this.props.style);
const groupStyle: any = {
display: 'flex',
@@ -43,11 +46,13 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
if (!key) key = `${o.type}_${i}`;
const props = {
key: key,
themeId: this.props.themeId,
...o,
};
const props = Object.assign(
{
key: key,
themeId: this.props.themeId,
},
o
);
if (o.name === 'toggleEditors') {
rightItemComps.push(<ToggleEditorsButton
@@ -73,7 +78,7 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
<div style={groupStyle}>
{centerItemComps}
</div>
<div style={{ ...groupStyle, flex: 1, justifyContent: 'flex-end' }}>
<div style={Object.assign({}, groupStyle, { flex: 1, justifyContent: 'flex-end' })}>
{rightItemComps}
</div>
</div>

View File

@@ -8,7 +8,7 @@ interface Props {
class ToolbarSpace extends React.Component<Props> {
public render() {
const theme = themeStyle(this.props.themeId);
const style = { ...theme.toolbarStyle };
const style = Object.assign({}, theme.toolbarStyle);
style.minWidth = style.height / 2;
return <span style={style}></span>;

View File

@@ -96,23 +96,25 @@ markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
mark.mark(
[value],
{
accuracy: accuracy,
filter: (node, _term, _totalCounter, _counter) => {
// We exclude SVG because it creates a "<mark>" tag inside
// the document, which is not a valid SVG tag. As a result
// the content within that tag disappears.
//
// mark.js has an "exclude" parameter, but it doesn't work
// so we use "filter" instead.
//
// https://github.com/joplin/plugin-abc-sheet-music
if (isInsideContainer(node, 'SVG')) return false;
return true;
Object.assign(
{},
{
accuracy: accuracy,
filter: (node, _term, _totalCounter, _counter) => {
// We exclude SVG because it creates a "<mark>" tag inside
// the document, which is not a valid SVG tag. As a result
// the content within that tag disappears.
//
// mark.js has an "exclude" parameter, but it doesn't work
// so we use "filter" instead.
//
// https://github.com/joplin/plugin-abc-sheet-music
if (isInsideContainer(node, 'SVG')) return false;
return true;
},
},
...extraOptions,
}
extraOptions
)
);
};

View File

@@ -41,9 +41,13 @@ const style = createSelector(
},
};
output.buttonIconSelected = { ...output.buttonIcon, color: theme.highlightedColor };
output.buttonIconSelected = Object.assign({}, output.buttonIcon, {
color: theme.highlightedColor,
});
output.buttonLabelSelected = { ...output.buttonLabel, color: theme.color };
output.buttonLabelSelected = Object.assign({}, output.buttonLabel, {
color: theme.color,
});
return output;
}

View File

@@ -42,7 +42,7 @@
</head>
<body>
<div id="react-root"></div>
<script src="main-html.js"></script>
<script src="main-html.bundle.js"></script>
<style>
/* Disable dragging of links (which are often buttons) */
a:not([draggable=true]), img:not([draggable=true]) {

View File

@@ -3,12 +3,15 @@
// Disable React message in console "Download the React DevTools for a better development experience"
// https://stackoverflow.com/questions/42196819/disable-hide-download-the-react-devtools#42196820
// eslint-disable-next-line no-undef
__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
supportsFiber: true,
inject: function() {},
onCommitFiberRoot: function() {},
onCommitFiberUnmount: function() {},
};
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined') {
// eslint-disable-next-line no-undef
__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
supportsFiber: true,
inject: function() {},
onCommitFiberRoot: function() {},
onCommitFiberUnmount: function() {},
};
}
const app = require('./app').default;
const Folder = require('@joplin/lib/models/Folder').default;

View File

@@ -1,18 +1,20 @@
{
"name": "@joplin/app-desktop",
"version": "2.11.9",
"version": "2.11.1",
"description": "Joplin for Desktop",
"main": "main.js",
"private": true,
"scripts": {
"dist": "yarn run electronRebuild && npx electron-builder",
"pack-html": "rollup --config rollup-main-html.config.js",
"pack-main": "rollup --config rollup-main.config.js",
"build": "gulp build",
"postinstall": "yarn run build",
"electronBuilder": "gulp electronBuilder",
"electronRebuild": "gulp electronRebuild",
"tsc": "tsc --project tsconfig.json",
"watch": "tsc --watch --preserveWatchOutput --project tsconfig.json",
"start": "gulp build && electron . --env dev --log-level debug --open-dev-tools",
"start": "gulp build && electron . --env dev --log-level debug --no-welcome --open-dev-tools",
"test": "jest",
"test-ci": "yarn test"
},
@@ -27,7 +29,7 @@
},
"build": {
"appId": "net.cozic.joplin-desktop",
"compression": "normal",
"compression": "maximum",
"productName": "Joplin",
"npmRebuild": false,
"afterSign": "./tools/notarizeMacApp.js",
@@ -36,6 +38,9 @@
"build/images/**",
"build/defaultPlugins/**"
],
"files": [
"!node_modules/**/*"
],
"afterAllArtifactBuild": "./generateSha512.js",
"asar": true,
"asarUnpack": "./node_modules/node-notifier/vendor/**",
@@ -109,24 +114,28 @@
"homepage": "https://github.com/laurent22/joplin#readme",
"devDependencies": {
"@joplin/tools": "~2.11",
"@rollup/plugin-commonjs": "24.1.0",
"@rollup/plugin-json": "6.0.0",
"@rollup/plugin-node-resolve": "15.0.2",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.5.1",
"@types/node": "18.15.13",
"@types/react": "16.14.41",
"@types/jest": "29.2.6",
"@types/node": "18.11.18",
"@types/react": "16.14.35",
"@types/react-redux": "7.1.25",
"@types/styled-components": "5.1.26",
"electron": "19.1.4",
"electron-builder": "22.11.7",
"electron-builder": "23.6.0",
"electron-notarize": "1.2.2",
"electron-rebuild": "3.2.9",
"glob": "8.1.0",
"gulp": "4.0.2",
"jest": "29.5.0",
"jest-environment-jsdom": "29.5.0",
"jest": "29.4.3",
"jest-environment-jsdom": "29.4.3",
"js-sha512": "0.8.0",
"nan": "2.17.0",
"react-test-renderer": "18.2.0",
"typescript": "5.0.2"
"rollup": "3.21.0",
"typescript": "4.9.4"
},
"optionalDependencies": {
"7zip-bin-linux": "^1.0.1",
@@ -163,7 +172,7 @@
"react-datetime": "3.2.0",
"react-dom": "18.2.0",
"react-redux": "8.0.5",
"react-select": "5.7.3",
"react-select": "5.7.2",
"react-toggle-button": "2.2.0",
"react-tooltip": "4.5.1",
"redux": "4.2.1",
@@ -171,7 +180,7 @@
"roboto-fontface": "0.10.0",
"smalltalk": "2.5.1",
"sqlite3": "5.1.6",
"styled-components": "5.3.10",
"styled-components": "5.3.9",
"styled-system": "5.1.5",
"taboverride": "4.0.3",
"tinymce": "5.10.6"

View File

@@ -133,8 +133,8 @@ class Dialog extends React.PureComponent<Props, State> {
}
this.styles_[styleKey] = {
dialogBox: { ...theme.dialogBox, minWidth: '50%', maxWidth: '50%' },
input: { ...theme.inputStyle, flex: 1 },
dialogBox: Object.assign({}, theme.dialogBox, { minWidth: '50%', maxWidth: '50%' }),
input: Object.assign({}, theme.inputStyle, { flex: 1 }),
row: {
overflow: 'hidden',
height: itemHeight,
@@ -148,7 +148,7 @@ class Dialog extends React.PureComponent<Props, State> {
borderBottomColor: theme.dividerColor,
boxSizing: 'border-box',
},
help: { ...theme.textStyle, marginBottom: 10 },
help: Object.assign({}, theme.textStyle, { marginBottom: 10 }),
inputHelpWrapper: { display: 'flex', flexDirection: 'row', alignItems: 'center' },
};
@@ -163,15 +163,19 @@ class Dialog extends React.PureComponent<Props, State> {
userSelect: 'none',
};
const rowTitleStyle = { ...rowTextStyle, fontSize: rowTextStyle.fontSize * 1.4,
const rowTitleStyle = Object.assign({}, rowTextStyle, {
fontSize: rowTextStyle.fontSize * 1.4,
marginBottom: this.state.resultsInBody ? 6 : 4,
color: theme.colorFaded };
color: theme.colorFaded,
});
const rowFragmentsStyle = { ...rowTextStyle, fontSize: rowTextStyle.fontSize * 1.2,
const rowFragmentsStyle = Object.assign({}, rowTextStyle, {
fontSize: rowTextStyle.fontSize * 1.2,
marginBottom: this.state.resultsInBody ? 8 : 6,
color: theme.colorFaded };
color: theme.colorFaded,
});
this.styles_[styleKey].rowSelected = { ...this.styles_[styleKey].row, backgroundColor: theme.selectedColor };
this.styles_[styleKey].rowSelected = Object.assign({}, this.styles_[styleKey].row, { backgroundColor: theme.selectedColor });
this.styles_[styleKey].rowPath = rowTextStyle;
this.styles_[styleKey].rowTitle = rowTitleStyle;
this.styles_[styleKey].rowFragments = rowFragmentsStyle;
@@ -300,7 +304,7 @@ class Dialog extends React.PureComponent<Props, State> {
for (let i = 0; i < results.length; i++) {
const row = results[i];
const path = Folder.folderPathString(this.props.folders, row.parent_id);
results[i] = { ...row, path: path ? path : '/' };
results[i] = Object.assign({}, row, { path: path ? path : '/' });
}
} else { // Note TITLE or BODY
listType = BaseModel.TYPE_NOTE;
@@ -313,7 +317,7 @@ class Dialog extends React.PureComponent<Props, State> {
for (let i = 0; i < results.length; i++) {
const row = results[i];
const path = Folder.folderPathString(this.props.folders, row.parent_id);
results[i] = { ...row, path: path };
results[i] = Object.assign({}, row, { path: path });
}
} else {
const limit = 20;
@@ -361,9 +365,9 @@ class Dialog extends React.PureComponent<Props, State> {
}
results[i] = { ...row, path, fragments };
results[i] = Object.assign({}, row, { path, fragments });
} else {
results[i] = { ...row, path: path, fragments: '' };
results[i] = Object.assign({}, row, { path: path, fragments: '' });
}
}

View File

@@ -0,0 +1,24 @@
const commonjs = require('@rollup/plugin-commonjs');
const nodeResolve = require('@rollup/plugin-node-resolve');
const pluginJson = require('@rollup/plugin-json');
module.exports = {
input: 'main-html.js',
output: {
file: 'main-html.bundle.js',
format: 'cjs',
},
plugins: [
nodeResolve(),
pluginJson(),
commonjs({
dynamicRequireTargets: [
'codemirror/mode/python/python',
],
}),
],
external: [
'keytar',
'fsevents',
],
};

View File

@@ -0,0 +1,16 @@
const commonjs = require('@rollup/plugin-commonjs');
const nodeResolve = require('@rollup/plugin-node-resolve');
const pluginJson = require('@rollup/plugin-json');
module.exports = {
input: 'main.source.js',
output: {
file: 'main.js',
format: 'cjs',
},
plugins: [
nodeResolve(),
pluginJson(),
commonjs(),
],
};

View File

@@ -79,13 +79,9 @@ import org.apache.tools.ant.taskdefs.condition.Os
*/
project.ext.react = [
// 2023-05-09: This seems to be optional, but it's not. Without it, the app
// will crash on certain devices with this error:
//
// > java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libhermes.so"
//
// https://github.com/laurent22/joplin/issues/8144#issuecomment-1539629812
enableHermes: true, // clean and rebuild if changing
// 2023/05/07: Leave that to `false` for now because Hermes is rubbish at
// reporting errors, which it makes it impossible to investigate crashes.
enableHermes: false, // clean and rebuild if changing
]
apply from: "../../node_modules/react-native/react.gradle"
@@ -156,8 +152,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097715
versionName "2.11.30"
versionCode 2097695
versionName "2.11.10"
// ndk {
// abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
// }
@@ -304,11 +300,8 @@ dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
// implementation "com.facebook.react:react-native:+" // From node_modules
implementation ("com.facebook.react:react-native") version {
strictly "0.70.6" // pass in your react-native version
}
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {

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