You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2026-02-10 08:14:27 +02:00
Compare commits
161 Commits
android-v2
...
vosk_dynam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dc8731755 | ||
|
|
e28ff0d60e | ||
|
|
3c0331eb6e | ||
|
|
cca4115f31 | ||
|
|
1eeb5ab471 | ||
|
|
c77a0b4709 | ||
|
|
1b64688042 | ||
|
|
c082505f61 | ||
|
|
f555e528ba | ||
|
|
96ff76fd1d | ||
|
|
9ceb7b9c88 | ||
|
|
6dc8ad2ba6 | ||
|
|
152e354d87 | ||
|
|
dbef391855 | ||
|
|
78f3f1c01a | ||
|
|
e7409145b6 | ||
|
|
bf8e34a0be | ||
|
|
4aaea3fe71 | ||
|
|
e5b4332f17 | ||
|
|
72a0adb434 | ||
|
|
37b745c69e | ||
|
|
3338164f43 | ||
|
|
98440beffa | ||
|
|
0c6f779aab | ||
|
|
fb27ae991c | ||
|
|
a41c9b6819 | ||
|
|
625812f7e6 | ||
|
|
e8cee2907c | ||
|
|
da25d10900 | ||
|
|
9f01258341 | ||
|
|
8608032243 | ||
|
|
bdbb362644 | ||
|
|
30671e7a20 | ||
|
|
8b578c5dde | ||
|
|
3792a5fb94 | ||
|
|
fb28268582 | ||
|
|
be3c15c37c | ||
|
|
b34342f01e | ||
|
|
19992ffcf9 | ||
|
|
6c15940005 | ||
|
|
7f0f745af3 | ||
|
|
1d62003486 | ||
|
|
fd373baeae | ||
|
|
f880e12a26 | ||
|
|
e81332e6b9 | ||
|
|
bda8766564 | ||
|
|
6d7b856d1d | ||
|
|
90a8d704c1 | ||
|
|
8dfcec249f | ||
|
|
659f602a12 | ||
|
|
45877f8b26 | ||
|
|
77505e3c75 | ||
|
|
dde7acc70f | ||
|
|
531402cede | ||
|
|
56ca9d4125 | ||
|
|
60b3921808 | ||
|
|
3a1759aabc | ||
|
|
ac732f4d1d | ||
|
|
7779879c6d | ||
|
|
c6a9837f1f | ||
|
|
6e49440b95 | ||
|
|
12746c5ff9 | ||
|
|
7bd4a999a0 | ||
|
|
e48d55c3e5 | ||
|
|
54efc9f2f5 | ||
|
|
963eeccf7b | ||
|
|
c89edd7b22 | ||
|
|
804d674d37 | ||
|
|
514091eb41 | ||
|
|
cd506bd3f1 | ||
|
|
e2d47d7d0d | ||
|
|
7a9afd4aff | ||
|
|
e647775608 | ||
|
|
577aa519e0 | ||
|
|
03cfef6a8d | ||
|
|
1219a30dff | ||
|
|
801719e3ba | ||
|
|
02098dbd79 | ||
|
|
e149e4b5fd | ||
|
|
b19f1a1023 | ||
|
|
192bfb5555 | ||
|
|
fd578d1c36 | ||
|
|
230e7f6914 | ||
|
|
12bba9da29 | ||
|
|
03424f76ea | ||
|
|
745849023d | ||
|
|
3e3b1764b7 | ||
|
|
902f0c3bf7 | ||
|
|
0f51249a76 | ||
|
|
3621e252d1 | ||
|
|
5669b1f04f | ||
|
|
91c99960ba | ||
|
|
b309504ffb | ||
|
|
22ab4b7473 | ||
|
|
04ea9343b0 | ||
|
|
b93f91078b | ||
|
|
b82e4be5c5 | ||
|
|
77a6e6f617 | ||
|
|
959ae59af0 | ||
|
|
98dd926cb9 | ||
|
|
8197c7aa7a | ||
|
|
1687adf015 | ||
|
|
7542ca907c | ||
|
|
1652b06e8c | ||
|
|
1a835ef094 | ||
|
|
575f55b22c | ||
|
|
d105387ece | ||
|
|
587eceb7c0 | ||
|
|
c90d7756c0 | ||
|
|
9e90d9016d | ||
|
|
ccec93eaa3 | ||
|
|
7bf823e0df | ||
|
|
b533d8d164 | ||
|
|
97477bb751 | ||
|
|
9cf863979b | ||
|
|
9ffe990c0b | ||
|
|
2c57e949b9 | ||
|
|
a7e185eb11 | ||
|
|
091eff9bc2 | ||
|
|
a04be2b28a | ||
|
|
caf66068bf | ||
|
|
8deba24d7d | ||
|
|
84b130e0cb | ||
|
|
e6209f449e | ||
|
|
faa4c5b9fc | ||
|
|
df9bfc7635 | ||
|
|
a46648f1ee | ||
|
|
215434bb4f | ||
|
|
40e0037d50 | ||
|
|
6afd839ae8 | ||
|
|
63595d2469 | ||
|
|
d715e1ba6b | ||
|
|
fb8a0c9ea9 | ||
|
|
ad20eba65e | ||
|
|
ea73e20115 | ||
|
|
1b8e9271a6 | ||
|
|
3a8a7a592d | ||
|
|
9d5c63de4f | ||
|
|
e37c95b9e5 | ||
|
|
201c7d893e | ||
|
|
c12108d1ac | ||
|
|
6ffd1046bd | ||
|
|
d4f49d6a02 | ||
|
|
cff24af099 | ||
|
|
b99ba85acd | ||
|
|
a0b707cbda | ||
|
|
1d7ffe358e | ||
|
|
9160f0e2a2 | ||
|
|
92272533e5 | ||
|
|
648e091523 | ||
|
|
b023f58497 | ||
|
|
c639791d4f | ||
|
|
6d52288e28 | ||
|
|
3e2f4b163b | ||
|
|
e0dbd198d8 | ||
|
|
a76c5c8746 | ||
|
|
20b43ce56e | ||
|
|
8215ce14c6 | ||
|
|
3fead0a8a7 | ||
|
|
c8bf3e8583 | ||
|
|
42dee6c275 |
@@ -75,6 +75,7 @@ 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
|
||||
@@ -363,6 +364,7 @@ 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
|
||||
@@ -425,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.dummy.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.android.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.ios.js
|
||||
packages/app-mobile/setupQuickActions.js
|
||||
packages/app-mobile/tools/buildInjectedJs.js
|
||||
packages/app-mobile/utils/ShareExtension.js
|
||||
|
||||
@@ -141,6 +141,7 @@ 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
|
||||
|
||||
3
.github/workflows/build-android.yml
vendored
3
.github/workflows/build-android.yml
vendored
@@ -17,9 +17,8 @@ jobs:
|
||||
concurrent_skipping: 'same_content_newer'
|
||||
|
||||
BuildAndroidDebug:
|
||||
if: github.repository == 'laurent22/joplin'
|
||||
needs: pre_job
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
if: github.repository == 'laurent22/joplin' && needs.pre_job.outputs.should_skip != 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Linux dependencies
|
||||
|
||||
1
.github/workflows/github-actions-main.yml
vendored
1
.github/workflows/github-actions-main.yml
vendored
@@ -50,6 +50,7 @@ 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')
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -349,6 +349,7 @@ 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
|
||||
@@ -411,8 +412,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.dummy.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.android.js
|
||||
packages/app-mobile/services/voiceTyping/vosk.ios.js
|
||||
packages/app-mobile/setupQuickActions.js
|
||||
packages/app-mobile/tools/buildInjectedJs.js
|
||||
packages/app-mobile/utils/ShareExtension.js
|
||||
|
||||
@@ -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..f3da440bc2863a59db6d2d1691c54d8d4870cb3f 100644
|
||||
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4e3ff404a 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,7 +66,25 @@ index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..f3da440bc2863a59db6d2d1691c54d8d
|
||||
sendEvent("onResult", text)
|
||||
}
|
||||
}
|
||||
@@ -153,6 +165,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
@@ -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
|
||||
cleanRecognizer();
|
||||
}
|
||||
|
||||
@@ -105,6 +123,70 @@ 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
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
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;
|
||||
@@ -42,7 +42,7 @@ export function addJoplinChecklistCommands(editor, ToggleList) {
|
||||
});
|
||||
|
||||
editor.addCommand('InsertJoplinChecklist', function (ui, detail) {
|
||||
detail = Object.assign({}, detail, { listType: 'joplinChecklist' });
|
||||
detail = { ...detail, listType: 'joplinChecklist' };
|
||||
ToggleList.toggleList(editor, 'UL', detail);
|
||||
});
|
||||
}
|
||||
BIN
Assets/WebsiteAssets/images/sponsors/TranioOverseasProperty.jpg
Normal file
BIN
Assets/WebsiteAssets/images/sponsors/TranioOverseasProperty.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
@@ -114,6 +114,20 @@ 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
|
||||
#-----------------------------------------------------
|
||||
|
||||
42
README.md
42
README.md
@@ -22,16 +22,18 @@ 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.18/Joplin-Setup-2.10.18.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.18/Joplin-2.10.18.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.18/Joplin-2.10.18.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://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>
|
||||
|
||||
**On Windows**, you may also use the <a href='https://objects.joplinusercontent.com/v2.10.18/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://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 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
|
||||
@@ -64,7 +66,7 @@ A community maintained list of these distributions can be found here: [Unofficia
|
||||
# Sponsors
|
||||
|
||||
<!-- SPONSORS-ORG -->
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></a>
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></a> <a href="https://tranio.com/spain/"><img title="Property for sale in Spain" width="256" src="https://joplinapp.org/images/sponsors/TranioOverseasProperty.jpg"/></a>
|
||||
<!-- SPONSORS-ORG -->
|
||||
|
||||
* * *
|
||||
@@ -534,24 +536,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) | 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/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/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) | 98%
|
||||
<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/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 | 99%
|
||||
<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/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) | 89%
|
||||
<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/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) | 88%
|
||||
<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/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%
|
||||
@@ -562,15 +564,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) | 89%
|
||||
<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/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 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/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/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) | 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%
|
||||
<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%
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
|
||||
# Contributors
|
||||
|
||||
@@ -107,7 +107,10 @@
|
||||
".eslintignore": true,
|
||||
".gitignore": true,
|
||||
".vscode/*": true,
|
||||
".yarn": true,
|
||||
".yarn/cache": true,
|
||||
".yarn/install-state.gz": true,
|
||||
".yarn/plugins": true,
|
||||
".yarn/releases": true,
|
||||
"*.sublime-workspace": true,
|
||||
"**/_mydocs": true,
|
||||
"**/_mydocs/EnexSamples/*.enex": true,
|
||||
|
||||
21
package.json
21
package.json
@@ -66,37 +66,36 @@
|
||||
"devDependencies": {
|
||||
"@joplin/utils": "~2.11",
|
||||
"@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.48.2",
|
||||
"@typescript-eslint/parser": "5.48.2",
|
||||
"@typescript-eslint/eslint-plugin": "5.59.0",
|
||||
"@typescript-eslint/parser": "5.59.0",
|
||||
"cspell": "5.21.2",
|
||||
"eslint": "8.31.0",
|
||||
"eslint-interactive": "10.3.0",
|
||||
"eslint-plugin-import": "2.27.4",
|
||||
"eslint": "8.39.0",
|
||||
"eslint-interactive": "10.7.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jest": "27.2.1",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-react": "7.32.0",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"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.1",
|
||||
"lint-staged": "13.2.2",
|
||||
"madge": "6.0.0",
|
||||
"npm-package-json-lint": "6.4.0",
|
||||
"typedoc": "0.17.8",
|
||||
"typescript": "4.9.4"
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/fs-extra": "11.0.1",
|
||||
"http-server": "14.1.1",
|
||||
"node-gyp": "9.3.1",
|
||||
"nodemon": "2.0.22"
|
||||
},
|
||||
"packageManager": "yarn@3.3.1",
|
||||
"packageManager": "yarn@3.5.0",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ class AppGui {
|
||||
const output = [];
|
||||
|
||||
for (let i = 0; i < keymap.length; i++) {
|
||||
const item = Object.assign({}, keymap[i]);
|
||||
const item = { ...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 = Object.assign({}, defaultState);
|
||||
const state = { ...defaultState };
|
||||
state.notes = this.widget('noteList').items;
|
||||
|
||||
const newState = reducer(state, action);
|
||||
|
||||
@@ -192,7 +192,7 @@ class Application extends BaseApplication {
|
||||
let output = await this.cache_.getItem('metadata');
|
||||
if (output) {
|
||||
this.commandMetadata_ = output;
|
||||
return Object.assign({}, this.commandMetadata_);
|
||||
return { ...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 Object.assign({}, this.commandMetadata_);
|
||||
return { ...this.commandMetadata_ };
|
||||
}
|
||||
|
||||
hasGui() {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"proper-lockfile": "4.1.2",
|
||||
"read-chunk": "2.1.0",
|
||||
"server-destroy": "1.0.1",
|
||||
"sharp": "0.32.0",
|
||||
"sharp": "0.32.1",
|
||||
"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": "9.0.13",
|
||||
"@types/jest": "29.2.6",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/fs-extra": "11.0.1",
|
||||
"@types/jest": "29.5.1",
|
||||
"@types/node": "18.15.13",
|
||||
"@types/proper-lockfile": "^4.1.2",
|
||||
"gulp": "4.0.2",
|
||||
"jest": "29.4.3",
|
||||
"jest": "29.5.0",
|
||||
"temp": "0.9.4",
|
||||
"typescript": "4.9.4"
|
||||
"typescript": "5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<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>
|
||||
@@ -0,0 +1,5 @@
|
||||
| | | |
|
||||
| :--- | :---: | ---: |
|
||||
| Left | Centered | Right |
|
||||
| Left | Centered | Right |
|
||||
| Left | Centered | Right |
|
||||
@@ -0,0 +1,26 @@
|
||||
<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>
|
||||
@@ -0,0 +1,5 @@
|
||||
| Left-aligned Column | Center-aligned Column | Right-aligned Column |
|
||||
| :--- | :---: | ---: |
|
||||
| Left | Centered | Right |
|
||||
| Left | Centered | Right |
|
||||
| Left | Centered | Right |
|
||||
@@ -0,0 +1,14 @@
|
||||
<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>
|
||||
@@ -0,0 +1,3 @@
|
||||
| abc | defghi |
|
||||
| :---: | ---: |
|
||||
| bar | baz |
|
||||
@@ -0,0 +1,29 @@
|
||||
<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>
|
||||
@@ -0,0 +1,5 @@
|
||||
| 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 |
|
||||
@@ -1 +1 @@
|
||||
<div class="jop-noMdConv"><svg class="jop-noMdConv"><style class="jop-noMdConv"></svg><iframe srcdoc="<script>top.require('child_process').execSync('calc')</script>"></iframe></div>
|
||||
<div class="jop-noMdConv">
|
||||
1
packages/app-cli/tests/md_to_html/sanitize_15.html
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_15.html
Normal file
@@ -0,0 +1 @@
|
||||
<use href="#" class="jop-noMdConv">
|
||||
1
packages/app-cli/tests/md_to_html/sanitize_15.md
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_15.md
Normal file
@@ -0,0 +1 @@
|
||||
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg'><image href='asdf' onerror='top.require(`child_process`).execSync(`calc.exe`)' /></svg>#x" />
|
||||
|
After Width: | Height: | Size: 193 B |
1
packages/app-cli/tests/md_to_html/sanitize_16.html
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_16.html
Normal file
@@ -0,0 +1 @@
|
||||
<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"/>
|
||||
1
packages/app-cli/tests/md_to_html/sanitize_16.md
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_16.md
Normal file
@@ -0,0 +1 @@
|
||||
<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">
|
||||
1
packages/app-cli/tests/md_to_html/sanitize_17.html
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_17.html
Normal file
@@ -0,0 +1 @@
|
||||
<a href="#top" class="jop-noMdConv">⬆️</a>
|
||||
1
packages/app-cli/tests/md_to_html/sanitize_17.md
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_17.md
Normal file
@@ -0,0 +1 @@
|
||||
<a href="#top">⬆️</a>
|
||||
@@ -94,12 +94,12 @@ browser_.runtime.onMessage.addListener(async (command) => {
|
||||
const imageSize = await getImageSize(imageDataUrl);
|
||||
const imagePixelRatio = imageSize.width / command.content.windowInnerWidth;
|
||||
|
||||
const content = Object.assign({}, command.content);
|
||||
const content = { ...command.content };
|
||||
content.image_data_url = imageDataUrl;
|
||||
if ('url' in content) content.source_url = content.url;
|
||||
|
||||
const ratio = browserZoom * imagePixelRatio;
|
||||
const newArea = Object.assign({}, command.content.crop_rect);
|
||||
const newArea = { ...command.content.crop_rect };
|
||||
newArea.x *= ratio;
|
||||
newArea.y *= ratio;
|
||||
newArea.width *= ratio;
|
||||
|
||||
@@ -378,7 +378,7 @@
|
||||
tags: command.tags || '',
|
||||
image_sizes: imageSizes,
|
||||
anchor_names: anchorNames,
|
||||
source_command: Object.assign({}, command),
|
||||
source_command: { ...command },
|
||||
convert_to: convertToMarkup,
|
||||
stylesheets: stylesheets,
|
||||
};
|
||||
@@ -392,7 +392,7 @@
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
console.warn('Sending full page HTML instead');
|
||||
const newCommand = Object.assign({}, command, { name: 'completePageHtml' });
|
||||
const newCommand = { ...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;
|
||||
|
||||
@@ -67,7 +67,7 @@ class AppComponent extends Component {
|
||||
});
|
||||
|
||||
this.confirm_click = async () => {
|
||||
const content = Object.assign({}, this.props.clippedContent);
|
||||
const content = { ...this.props.clippedContent };
|
||||
content.tags = this.state.selectedTags.join(',');
|
||||
content.parent_id = this.props.selectedFolderId;
|
||||
const response = await bridge().sendContentToJoplin(content);
|
||||
|
||||
@@ -410,7 +410,7 @@ class Bridge {
|
||||
|
||||
if (body) fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
|
||||
|
||||
query = Object.assign(query || {}, { token: this.token_ });
|
||||
query = { ...query, token: this.token_ };
|
||||
|
||||
let queryString = '';
|
||||
if (query) {
|
||||
|
||||
@@ -40,34 +40,34 @@ function reducer(state = defaultState, action) {
|
||||
|
||||
if (action.type === 'WARNING_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.warning = action.text;
|
||||
|
||||
} else if (action.type === 'IS_PROBABLY_READERABLE') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.isProbablyReaderable = action.value;
|
||||
|
||||
} else if (action.type === 'CLIPPED_CONTENT_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.clippedContent = action.content;
|
||||
|
||||
} else if (action.type === 'CLIPPED_CONTENT_TITLE_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
const newContent = newState.clippedContent ? Object.assign({}, newState.clippedContent) : {};
|
||||
newState = { ...state };
|
||||
const newContent = newState.clippedContent ? { ...newState.clippedContent } : {};
|
||||
newContent.title = action.text;
|
||||
newState.clippedContent = newContent;
|
||||
|
||||
} else if (action.type === 'CONTENT_UPLOAD') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.contentUploadOperation = action.operation;
|
||||
|
||||
} else if (action.type === 'FOLDERS_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...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 = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.tags = action.tags;
|
||||
|
||||
} else if (action.type === 'SELECTED_FOLDER_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.selectedFolderId = action.id;
|
||||
|
||||
} else if (action.type === 'CLIPPER_SERVER_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
const clipperServer = Object.assign({}, newState.clipperServer);
|
||||
newState = { ...state };
|
||||
const clipperServer = { ...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 = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.env = action.env;
|
||||
|
||||
} else if (action.type === 'AUTH_STATE_SET') {
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.authStatus = action.value;
|
||||
|
||||
}
|
||||
|
||||
@@ -29,13 +29,11 @@ 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 = Object.assign({}, {
|
||||
path: tempFile,
|
||||
const fullExportOptions: ExportOptions = { path: tempFile,
|
||||
format: 'html',
|
||||
target: FileSystemItem.File,
|
||||
sourceNoteIds: [noteId],
|
||||
customCss: '',
|
||||
}, exportOptions);
|
||||
customCss: '', ...exportOptions };
|
||||
|
||||
const service = InteropService.instance();
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ 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;
|
||||
@@ -82,7 +85,7 @@ export default function(state: AppState, action: any) {
|
||||
|
||||
const currentRoute = state.route;
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
const newNavHistory = state.navHistory.slice();
|
||||
|
||||
if (goingBack) {
|
||||
@@ -119,7 +122,7 @@ export default function(state: AppState, action: any) {
|
||||
|
||||
case 'WINDOW_CONTENT_SIZE_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.windowContentSize = action.size;
|
||||
break;
|
||||
|
||||
@@ -147,7 +150,7 @@ export default function(state: AppState, action: any) {
|
||||
return nextLayout === 'both' ? ['editor', 'viewer'] : [nextLayout];
|
||||
};
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
|
||||
const panes = state.noteVisiblePanes.slice();
|
||||
newState.noteVisiblePanes = getNextLayout(panes);
|
||||
@@ -156,7 +159,7 @@ export default function(state: AppState, action: any) {
|
||||
|
||||
case 'NOTE_VISIBLE_PANES_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.noteVisiblePanes = action.panes;
|
||||
break;
|
||||
|
||||
@@ -171,22 +174,31 @@ export default function(state: AppState, action: any) {
|
||||
case 'MAIN_LAYOUT_SET_ITEM_PROP':
|
||||
|
||||
{
|
||||
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 (!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;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
|
||||
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
mainLayout: newLayout,
|
||||
};
|
||||
newState = {
|
||||
...state,
|
||||
mainLayout: newLayout,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -194,7 +206,7 @@ export default function(state: AppState, action: any) {
|
||||
case 'NOTE_FILE_WATCHER_ADD':
|
||||
|
||||
if (newState.watchedNoteFiles.indexOf(action.id) < 0) {
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
const watchedNoteFiles = newState.watchedNoteFiles.slice();
|
||||
watchedNoteFiles.push(action.id);
|
||||
newState.watchedNoteFiles = watchedNoteFiles;
|
||||
@@ -204,7 +216,7 @@ export default function(state: AppState, action: any) {
|
||||
case 'NOTE_FILE_WATCHER_REMOVE':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
const idx = newState.watchedNoteFiles.indexOf(action.id);
|
||||
if (idx >= 0) {
|
||||
const watchedNoteFiles = newState.watchedNoteFiles.slice();
|
||||
@@ -217,7 +229,7 @@ export default function(state: AppState, action: any) {
|
||||
case 'NOTE_FILE_WATCHER_CLEAR':
|
||||
|
||||
if (state.watchedNoteFiles.length) {
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.watchedNoteFiles = [];
|
||||
}
|
||||
break;
|
||||
@@ -225,38 +237,38 @@ export default function(state: AppState, action: any) {
|
||||
case 'EDITOR_SCROLL_PERCENT_SET':
|
||||
|
||||
{
|
||||
newState = Object.assign({}, state);
|
||||
const newPercents = Object.assign({}, newState.lastEditorScrollPercents);
|
||||
newState = { ...state };
|
||||
const newPercents = { ...newState.lastEditorScrollPercents };
|
||||
newPercents[action.noteId] = action.percent;
|
||||
newState.lastEditorScrollPercents = newPercents;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOTE_DEVTOOLS_TOGGLE':
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.devToolsVisible = !newState.devToolsVisible;
|
||||
break;
|
||||
|
||||
case 'NOTE_DEVTOOLS_SET':
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.devToolsVisible = action.value;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_ADD':
|
||||
newState = Object.assign({}, state);
|
||||
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
|
||||
newState = { ...state };
|
||||
newState.visibleDialogs = { ...newState.visibleDialogs };
|
||||
newState.visibleDialogs[action.name] = true;
|
||||
break;
|
||||
|
||||
case 'VISIBLE_DIALOGS_REMOVE':
|
||||
newState = Object.assign({}, state);
|
||||
newState.visibleDialogs = Object.assign({}, newState.visibleDialogs);
|
||||
newState = { ...state };
|
||||
newState.visibleDialogs = { ...newState.visibleDialogs };
|
||||
delete newState.visibleDialogs[action.name];
|
||||
break;
|
||||
|
||||
case 'FOCUS_SET':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.focusedField = action.field;
|
||||
break;
|
||||
|
||||
@@ -264,7 +276,7 @@ export default function(state: AppState, action: any) {
|
||||
|
||||
// A field can only clear its own state
|
||||
if (action.field === state.focusedField) {
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
newState.focusedField = null;
|
||||
}
|
||||
break;
|
||||
@@ -281,7 +293,7 @@ export default function(state: AppState, action: any) {
|
||||
isOpen = action.isOpen !== false;
|
||||
}
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState = { ...state };
|
||||
|
||||
if (isOpen) {
|
||||
const newDialogs = newState.dialogs.slice();
|
||||
|
||||
@@ -80,6 +80,7 @@ const appDefaultState = createAppDefaultState(
|
||||
class Application extends BaseApplication {
|
||||
|
||||
private checkAllPluginStartedIID_: any = null;
|
||||
private initPluginServiceDone_: boolean = false;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
@@ -258,6 +259,9 @@ class Application extends BaseApplication {
|
||||
}
|
||||
|
||||
private async initPluginService() {
|
||||
if (this.initPluginServiceDone_) return;
|
||||
this.initPluginServiceDone_ = true;
|
||||
|
||||
const service = PluginService.instance();
|
||||
|
||||
const pluginRunner = new PluginRunner();
|
||||
|
||||
@@ -201,12 +201,10 @@ export class Bridge {
|
||||
...options,
|
||||
};
|
||||
|
||||
const result = this.showMessageBox_(this.window(), Object.assign({}, {
|
||||
type: 'question',
|
||||
const result = this.showMessageBox_(this.window(), { type: 'question',
|
||||
message: message,
|
||||
cancelId: 1,
|
||||
buttons: options.buttons,
|
||||
}, options));
|
||||
buttons: options.buttons, ...options });
|
||||
|
||||
return result === 0;
|
||||
}
|
||||
@@ -215,21 +213,17 @@ export class Bridge {
|
||||
public showMessageBox(message: string, options: any = null) {
|
||||
if (options === null) options = {};
|
||||
|
||||
const result = this.showMessageBox_(this.window(), Object.assign({}, {
|
||||
type: 'question',
|
||||
const result = this.showMessageBox_(this.window(), { 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(), Object.assign({}, {
|
||||
type: 'info',
|
||||
const result = this.showMessageBox_(this.window(), { type: 'info',
|
||||
message: message,
|
||||
buttons: [_('OK')],
|
||||
}, options));
|
||||
buttons: [_('OK')], ...options });
|
||||
return result === 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ function getMajorMinorTagName(tagName: string) {
|
||||
}
|
||||
|
||||
async function fetchLatestRelease(options: CheckForUpdateOptions) {
|
||||
options = Object.assign({}, { includePreReleases: false }, options);
|
||||
options = { includePreReleases: false, ...options };
|
||||
|
||||
const response = await shim.fetch('https://api.github.com/repos/laurent22/joplin/releases');
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export const runtime = (): CommandRuntime => {
|
||||
};
|
||||
|
||||
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
|
||||
await restart(false);
|
||||
await restart();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -46,13 +46,11 @@ class ClipperConfigScreenComponent extends React.Component {
|
||||
public render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, {
|
||||
overflowY: 'scroll',
|
||||
const containerStyle = { ...theme.containerStyle, overflowY: 'scroll',
|
||||
// padding: theme.configScreenPadding,
|
||||
backgroundColor: theme.backgroundColor3,
|
||||
});
|
||||
backgroundColor: theme.backgroundColor3 };
|
||||
|
||||
const buttonStyle = Object.assign({}, theme.buttonStyle, { marginRight: 10 });
|
||||
const buttonStyle = { ...theme.buttonStyle, marginRight: 10 };
|
||||
|
||||
const stepBoxStyle = {
|
||||
border: '1px solid',
|
||||
@@ -106,18 +104,16 @@ class ClipperConfigScreenComponent extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const apiTokenStyle = Object.assign({}, theme.textStyle, {
|
||||
color: theme.colorFaded,
|
||||
const apiTokenStyle = { ...theme.textStyle, color: theme.colorFaded,
|
||||
wordBreak: 'break-all',
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
});
|
||||
paddingBottom: 10 };
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={containerStyle}>
|
||||
<div>
|
||||
<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, 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}>
|
||||
|
||||
@@ -135,7 +135,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
return (
|
||||
<div style={Object.assign({}, theme.textStyle, { marginBottom: 15 })}>
|
||||
<div style={{ ...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 = Object.assign({}, theme.textStyle, { marginTop: 10 });
|
||||
const statusStyle = { ...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 = Object.assign({}, theme.buttonStyle, { marginBottom: 10 });
|
||||
// const advancedSettingsButtonStyle = { ...theme.buttonStyle, marginBottom: 10 };
|
||||
advancedSettingsButton = (
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<Button
|
||||
@@ -233,23 +233,19 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
|
||||
private labelStyle(themeId: number) {
|
||||
const theme = themeStyle(themeId);
|
||||
return Object.assign({}, theme.textStyle, {
|
||||
display: 'block',
|
||||
return { ...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 Object.assign({}, theme.textStyle, {
|
||||
color: theme.colorFaded,
|
||||
return { ...theme.textStyle, color: theme.colorFaded,
|
||||
fontStyle: 'italic',
|
||||
maxWidth: '70em',
|
||||
marginTop: 5,
|
||||
});
|
||||
marginTop: 5 };
|
||||
}
|
||||
|
||||
private renderLabel(themeId: number, label: string) {
|
||||
@@ -264,14 +260,12 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
private renderHeader(themeId: number, label: string, style: any = null) {
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
const labelStyle = Object.assign({}, theme.textStyle, {
|
||||
display: 'block',
|
||||
const labelStyle = { ...theme.textStyle, display: 'block',
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize * 1.25,
|
||||
fontWeight: 500,
|
||||
marginBottom: theme.mainPadding,
|
||||
...style,
|
||||
});
|
||||
...style };
|
||||
|
||||
return (
|
||||
<div style={labelStyle}>
|
||||
@@ -295,17 +289,13 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
|
||||
const labelStyle = this.labelStyle(this.props.themeId);
|
||||
|
||||
const subLabel = Object.assign({}, labelStyle, {
|
||||
display: 'block',
|
||||
const subLabel = { ...labelStyle, display: 'block',
|
||||
opacity: 0.7,
|
||||
marginBottom: labelStyle.marginBottom,
|
||||
});
|
||||
marginBottom: labelStyle.marginBottom };
|
||||
|
||||
const checkboxLabelStyle = Object.assign({}, labelStyle, {
|
||||
marginLeft: 8,
|
||||
const checkboxLabelStyle = { ...labelStyle, marginLeft: 8,
|
||||
display: 'inline',
|
||||
backgroundColor: 'transparent',
|
||||
});
|
||||
backgroundColor: 'transparent' };
|
||||
|
||||
const controlStyle = {
|
||||
display: 'inline-block',
|
||||
@@ -314,8 +304,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
backgroundColor: theme.backgroundColor,
|
||||
};
|
||||
|
||||
const textInputBaseStyle = Object.assign({}, controlStyle, {
|
||||
fontFamily: theme.fontFamily,
|
||||
const textInputBaseStyle = { ...controlStyle, fontFamily: theme.fontFamily,
|
||||
border: '1px solid',
|
||||
padding: '4px 6px',
|
||||
boxSizing: 'border-box',
|
||||
@@ -324,8 +313,7 @@ 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);
|
||||
@@ -381,14 +369,12 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
);
|
||||
}
|
||||
|
||||
const selectStyle = Object.assign({}, controlStyle, {
|
||||
paddingLeft: 6,
|
||||
const selectStyle = { ...controlStyle, paddingLeft: 6,
|
||||
paddingRight: 6,
|
||||
paddingTop: 4,
|
||||
paddingBottom: 4,
|
||||
borderColor: theme.borderColor4,
|
||||
borderRadius: 3,
|
||||
});
|
||||
borderRadius: 3 };
|
||||
|
||||
return (
|
||||
<div key={key} style={rowStyle}>
|
||||
@@ -443,10 +429,8 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
</div>
|
||||
);
|
||||
} else if (md.type === Setting.TYPE_STRING) {
|
||||
const inputStyle: any = Object.assign({}, textInputBaseStyle, {
|
||||
width: '50%',
|
||||
minWidth: '20em',
|
||||
});
|
||||
const inputStyle: any = { ...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') {
|
||||
@@ -542,7 +526,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginBottom: inputStyle.marginBottom }}>
|
||||
<input
|
||||
type={inputType}
|
||||
style={Object.assign({}, inputStyle, { marginBottom: 0, marginRight: 5 })}
|
||||
style={{ ...inputStyle, marginBottom: 0, marginRight: 5 }}
|
||||
onChange={(event: any) => {
|
||||
onPathChange(event);
|
||||
}}
|
||||
@@ -595,7 +579,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
const label = [md.label()];
|
||||
if (md.unitLabel) label.push(`(${md.unitLabel()})`);
|
||||
|
||||
const inputStyle: any = Object.assign({}, textInputBaseStyle);
|
||||
const inputStyle: any = { ...textInputBaseStyle };
|
||||
|
||||
return (
|
||||
<div key={key} style={rowStyle}>
|
||||
@@ -679,15 +663,13 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
public render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const style = Object.assign({},
|
||||
this.props.style,
|
||||
{
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: theme.backgroundColor3,
|
||||
}
|
||||
);
|
||||
const style = {
|
||||
...this.props.style,
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: theme.backgroundColor3,
|
||||
};
|
||||
|
||||
const settings = this.state.settings;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function DialogButtonRow(props: Props) {
|
||||
|
||||
if (props.cancelButtonShow !== false) {
|
||||
buttonComps.push(
|
||||
<button disabled={props.cancelButtonDisabled} key="cancel" style={Object.assign({}, buttonStyle)} onClick={onCancelButtonClick}>
|
||||
<button disabled={props.cancelButtonDisabled} key="cancel" style={{ ...buttonStyle }} onClick={onCancelButtonClick}>
|
||||
{props.cancelButtonLabel ? props.cancelButtonLabel : _('Cancel')}
|
||||
</button>
|
||||
);
|
||||
|
||||
@@ -29,15 +29,13 @@ class DropboxLoginScreenComponent extends React.Component<any, any> {
|
||||
const style = this.props.style;
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, {
|
||||
padding: theme.configScreenPadding,
|
||||
const containerStyle = { ...theme.containerStyle, padding: theme.configScreenPadding,
|
||||
height: style.height - theme.margin * 2,
|
||||
flex: 1,
|
||||
});
|
||||
flex: 1 };
|
||||
|
||||
const inputStyle = Object.assign({}, theme.inputStyle, { width: 500 });
|
||||
const inputStyle = { ...theme.inputStyle, width: 500 };
|
||||
|
||||
const buttonStyle = Object.assign({}, theme.buttonStyle, { marginRight: 10 });
|
||||
const buttonStyle = { ...theme.buttonStyle, marginRight: 10 };
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
|
||||
@@ -82,7 +82,7 @@ function ExtensionBadge(props: Props) {
|
||||
void bridge().openExternal(props.url);
|
||||
};
|
||||
|
||||
const rootStyle = props.style ? Object.assign({}, style.root, props.style) : style.root;
|
||||
const rootStyle = props.style ? { ...style.root, ...props.style } : style.root;
|
||||
|
||||
return (
|
||||
<a style={rootStyle} onClick={onClick} href="#">
|
||||
|
||||
@@ -23,7 +23,7 @@ class HelpButtonComponent extends React.Component<Props> {
|
||||
|
||||
public render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const style = Object.assign({}, this.props.style, { color: theme.color, textDecoration: 'none' });
|
||||
const style = { ...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;
|
||||
|
||||
@@ -18,21 +18,19 @@ class IconButton extends React.Component<Props> {
|
||||
};
|
||||
const icon = <i style={iconStyle} className={`fas ${this.props.iconName}`}></i>;
|
||||
|
||||
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
|
||||
);
|
||||
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,
|
||||
};
|
||||
|
||||
return (
|
||||
<a
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
|
||||
const logger = Logger.create('ItemList');
|
||||
|
||||
interface Props {
|
||||
style: any;
|
||||
@@ -50,15 +47,6 @@ 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,
|
||||
@@ -81,21 +69,6 @@ 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();
|
||||
@@ -148,10 +121,8 @@ class ItemList extends React.Component<Props, State> {
|
||||
|
||||
public render() {
|
||||
const items = this.props.items;
|
||||
const style = Object.assign({}, this.props.style, {
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'auto',
|
||||
});
|
||||
const style = { ...this.props.style, overflowX: 'hidden',
|
||||
overflowY: 'auto' };
|
||||
|
||||
// if (this.props.disabled) style.opacity = 0.5;
|
||||
|
||||
|
||||
@@ -501,16 +501,14 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
height: height,
|
||||
};
|
||||
|
||||
this.styles_.modalLayer = Object.assign({}, theme.textStyle, {
|
||||
zIndex: 10000,
|
||||
this.styles_.modalLayer = { ...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_;
|
||||
}
|
||||
@@ -803,13 +801,11 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
|
||||
public render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const style = Object.assign(
|
||||
{
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
},
|
||||
this.props.style
|
||||
);
|
||||
const style = {
|
||||
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());
|
||||
|
||||
@@ -824,7 +820,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 = Object.assign({}, styles.modalLayer, { display: this.state.modalLayer.visible ? 'block' : 'none' });
|
||||
const modalLayerStyle = { ...styles.modalLayer, display: this.state.modalLayer.visible ? 'block' : 'none' };
|
||||
|
||||
const notePropertiesDialogOptions = this.state.notePropertiesDialogOptions;
|
||||
const noteContentPropertiesDialogOptions = this.state.noteContentPropertiesDialogOptions;
|
||||
@@ -866,6 +862,7 @@ 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,
|
||||
@@ -873,7 +870,7 @@ const mapStateToProps = (state: AppState) => {
|
||||
hasDisabledSyncItems: state.hasDisabledSyncItems,
|
||||
hasDisabledEncryptionItems: state.hasDisabledEncryptionItems,
|
||||
showMissingMasterKeyMessage: showMissingMasterKeyMessage(syncInfo, state.notLoadedMasterKeys),
|
||||
showNeedUpgradingMasterKeyMessage: !!EncryptionService.instance().masterKeysThatNeedUpgrading(syncInfo.masterKeys).length,
|
||||
showNeedUpgradingMasterKeyMessage: showNeedUpgradingEnabledMasterKeyMessage,
|
||||
showShouldReencryptMessage: state.settings['encryption.shouldReencrypt'] >= Setting.SHOULD_REENCRYPT_YES,
|
||||
shouldUpgradeSyncTarget: state.settings['sync.upgradeState'] === Setting.SYNC_UPGRADE_STATE_SHOULD_DO,
|
||||
pluginsLegacy: state.pluginsLegacy,
|
||||
|
||||
@@ -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(false);
|
||||
await restart();
|
||||
}
|
||||
|
||||
comp.setState({ promptOptions: null });
|
||||
|
||||
@@ -17,11 +17,9 @@ export const runtime = (): CommandRuntime => {
|
||||
|
||||
const defaultValues = Note.previewFieldsWithDefaultValues({ includeTimestamps: false });
|
||||
|
||||
let newNote = Object.assign({}, defaultValues, {
|
||||
parent_id: folderId,
|
||||
let newNote = { ...defaultValues, parent_id: folderId,
|
||||
is_todo: isTodo ? 1 : 0,
|
||||
body: body,
|
||||
});
|
||||
body: body };
|
||||
|
||||
newNote = await Note.save(newNote, { provisional: true });
|
||||
|
||||
|
||||
@@ -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('countable');
|
||||
const Countable = require('@joplin/lib/countable/Countable');
|
||||
import markupLanguageUtils from '../utils/markupLanguageUtils';
|
||||
|
||||
interface NoteContentPropertiesDialogProps {
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function useExternalPlugins(CodeMirror: any, plugins: PluginState
|
||||
}
|
||||
|
||||
if (mod.codeMirrorOptions) {
|
||||
newOptions = Object.assign({}, newOptions, mod.codeMirrorOptions);
|
||||
newOptions = { ...newOptions, ...mod.codeMirrorOptions };
|
||||
}
|
||||
|
||||
if (mod.assets) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { themeStyle } from '@joplin/lib/theme';
|
||||
import { loadScript } from '../../../utils/loadScript';
|
||||
import bridge from '../../../../services/bridge';
|
||||
import { TinyMceEditorEvents } from './utils/types';
|
||||
import type { Editor } from 'tinymce';
|
||||
const { clipboard } = require('electron');
|
||||
const supportedLocales = require('./supportedLocales');
|
||||
|
||||
@@ -557,7 +558,15 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
'bold', 'italic', 'joplinHighlight', 'joplinStrikethrough', 'formattingExtras', '|',
|
||||
'link', 'joplinInlineCode', 'joplinCodeBlock', 'joplinAttach', '|',
|
||||
'bullist', 'numlist', 'joplinChecklist', '|',
|
||||
'h1', 'h2', 'h3', 'hr', 'blockquote', 'table', `joplinInsertDateTime${toolbarPluginButtons}`,
|
||||
'h1', 'h2', 'h3', 'hr', 'blockquote', 'inserttable', `joplinInsertDateTime${toolbarPluginButtons}`,
|
||||
];
|
||||
|
||||
// Available table toolbar buttons:
|
||||
// https://www.tiny.cloud/docs/advanced/available-toolbar-buttons/#tableplugin
|
||||
const tableToolbar = [
|
||||
'tabledelete',
|
||||
'tableinsertrowafter tablecopyrow tablepasterowafter tabledeleterow',
|
||||
'tableinsertcolafter tablecopycol tablepastecolafter tabledeletecol',
|
||||
];
|
||||
|
||||
const editors = await (window as any).tinymce.init({
|
||||
@@ -576,6 +585,10 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
branding: false,
|
||||
statusbar: false,
|
||||
target_list: false,
|
||||
// Handle the first table row as table header.
|
||||
// https://www.tiny.cloud/docs/plugins/table/#table_header_type
|
||||
table_header_type: 'sectionCells',
|
||||
table_toolbar: tableToolbar.join(' | '),
|
||||
table_resize_bars: false,
|
||||
language_url: ['en_US', 'en_GB'].includes(language) ? undefined : `${bridge().vendorDir()}/lib/tinymce/langs/${language}`,
|
||||
toolbar: toolbar.join(' '),
|
||||
@@ -589,7 +602,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
joplinSub: { inline: 'sub', remove: 'all' },
|
||||
joplinSup: { inline: 'sup', remove: 'all' },
|
||||
},
|
||||
setup: (editor: any) => {
|
||||
setup: (editor: Editor) => {
|
||||
editor.ui.registry.addButton('joplinAttach', {
|
||||
tooltip: _('Attach file'),
|
||||
icon: 'paperclip',
|
||||
@@ -614,7 +627,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
onAction: function() {
|
||||
editor.execCommand('mceToggleFormat', false, 'code', { class: 'inline-code' });
|
||||
},
|
||||
onSetup: function(api: any) {
|
||||
onSetup: function(api) {
|
||||
api.setActive(editor.formatter.match('code'));
|
||||
const unbind = editor.formatter.formatChanged('code', api.setActive).unbind;
|
||||
|
||||
@@ -624,6 +637,22 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
},
|
||||
});
|
||||
|
||||
editor.ui.registry.addMenuButton('inserttable', {
|
||||
icon: 'table',
|
||||
tooltip: 'Table',
|
||||
fetch: (callback) => {
|
||||
callback([
|
||||
{
|
||||
type: 'fancymenuitem',
|
||||
fancytype: 'inserttable',
|
||||
onAction: (data) => {
|
||||
editor.execCommand('mceInsertTable', false, { rows: data.numRows, columns: data.numColumns, options: { headerRows: 1 } });
|
||||
},
|
||||
},
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
editor.ui.registry.addButton('joplinInsertDateTime', {
|
||||
tooltip: _('Insert time'),
|
||||
icon: 'insert-time',
|
||||
@@ -647,13 +676,13 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
editor.addShortcut('Meta+Shift+9', '', () => editor.execCommand('InsertJoplinChecklist'));
|
||||
|
||||
// TODO: remove event on unmount?
|
||||
editor.on('DblClick', (event: any) => {
|
||||
editor.on('DblClick', (event) => {
|
||||
const editable = findEditableContainer(event.target);
|
||||
if (editable) openEditDialog(editor, markupToHtml, dispatchDidUpdate, editable);
|
||||
});
|
||||
|
||||
// This is triggered when an external file is dropped on the editor
|
||||
editor.on('drop', (event: any) => {
|
||||
editor.on('drop', (event) => {
|
||||
// Prevent the message "Dropped file type is not
|
||||
// supported" to show up. It was added in a recent
|
||||
// TinyMCE version and doesn't apply since we do support
|
||||
@@ -664,7 +693,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
props_onDrop.current(event);
|
||||
});
|
||||
|
||||
editor.on('ObjectResized', (event: any) => {
|
||||
editor.on('ObjectResized', (event) => {
|
||||
if (event.target.nodeName === 'IMG') {
|
||||
editor.fire(TinyMceEditorEvents.JoplinChange);
|
||||
dispatchDidUpdate(editor);
|
||||
|
||||
@@ -1544,7 +1544,7 @@
|
||||
}
|
||||
});
|
||||
editor.addCommand('InsertJoplinChecklist', function (ui, detail) {
|
||||
detail = Object.assign({}, detail, { listType: 'joplinChecklist' });
|
||||
detail = { ...detail, listType: 'joplinChecklist' };
|
||||
ToggleList.toggleList(editor, 'UL', detail);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -364,13 +364,11 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
}, [props.dispatch, formNote]);
|
||||
|
||||
function renderNoNotes(rootStyle: any) {
|
||||
const emptyDivStyle = Object.assign(
|
||||
{
|
||||
backgroundColor: 'black',
|
||||
opacity: 0.1,
|
||||
},
|
||||
rootStyle
|
||||
);
|
||||
const emptyDivStyle = {
|
||||
backgroundColor: 'black',
|
||||
opacity: 0.1,
|
||||
...rootStyle,
|
||||
};
|
||||
return <div style={emptyDivStyle}></div>;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,14 +59,12 @@ export default function useMarkupToHtml(deps: HookDependencies) {
|
||||
|
||||
delete options.replaceResourceInternalToExternalLinks;
|
||||
|
||||
const result = await markupToHtml.render(markupLanguage, md, theme, Object.assign({}, {
|
||||
codeTheme: theme.codeThemeCss,
|
||||
const result = await markupToHtml.render(markupLanguage, md, theme, { 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
|
||||
|
||||
@@ -62,7 +62,7 @@ export default function useNoteSearchBar({ noteSearchBarRef }: UseNoteSearchBarP
|
||||
|
||||
const noteSearchBarNextPrevious = useCallback((inc: number) => {
|
||||
setLocalSearch((prev: LocalSearch) => {
|
||||
const ls = Object.assign({}, prev);
|
||||
const ls = { ...prev };
|
||||
ls.selectedIndex += inc;
|
||||
ls.timestamp = Date.now();
|
||||
if (ls.selectedIndex < 0) ls.selectedIndex = ls.resultCount - 1;
|
||||
|
||||
@@ -181,7 +181,7 @@ function NoteListControls(props: Props) {
|
||||
useEffect(() => {
|
||||
if (breakpoint === dynamicBreakpoints.Xl) {
|
||||
noteControlsRef.current.style.flexDirection = 'row';
|
||||
searchAndSortRef.current.style.flex = '2 1 auto';
|
||||
searchAndSortRef.current.style.flex = '2 1 50%';
|
||||
props.onContentHeightChange(true);
|
||||
} else {
|
||||
noteControlsRef.current.style.flexDirection = 'column';
|
||||
|
||||
@@ -108,10 +108,10 @@ function NoteListItem(props: NoteListItemProps, ref: any) {
|
||||
);
|
||||
}
|
||||
|
||||
let listItemTitleStyle = Object.assign({}, props.style.listItemTitle);
|
||||
let listItemTitleStyle = { ...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 = Object.assign(listItemTitleStyle, props.style.listItemTitleCompleted);
|
||||
if (item.is_todo && !!item.todo_completed) listItemTitleStyle = { ...listItemTitleStyle, ...props.style.listItemTitleCompleted };
|
||||
|
||||
const displayTitle = Note.displayTitle(item);
|
||||
let titleComp = null;
|
||||
|
||||
@@ -114,7 +114,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
public formNoteToNote(formNote: any) {
|
||||
const note = Object.assign({ id: formNote.id }, this.latLongFromLocation(formNote.location));
|
||||
const note = { 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 = Object.assign({}, this.state.formNote);
|
||||
const newFormNote = { ...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={Object.assign({}, theme.textStyle, theme.controlBoxLabel)}>{this.formatLabel(key)}</label>;
|
||||
const labelComp = <label style={{ ...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 = Object.assign({}, theme.urlStyle, { maxWidth: '180px', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' });
|
||||
const urlStyle = { ...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={Object.assign({}, theme.textStyle, theme.controlBoxValue)}>{displayedValue}</div>;
|
||||
controlComp = <div style={{ ...theme.textStyle, ...theme.controlBoxValue }}>{displayedValue}</div>;
|
||||
}
|
||||
|
||||
if (['id', 'revisionsLink', 'markup_language'].indexOf(key) < 0) {
|
||||
|
||||
@@ -67,8 +67,8 @@ class NoteRevisionViewerComponent extends React.PureComponent<Props, State> {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
},
|
||||
titleInput: Object.assign({}, theme.inputStyle, { flex: 1 }),
|
||||
revisionList: Object.assign({}, theme.dropdownList, { marginLeft: 10, flex: 0.5 }),
|
||||
titleInput: { ...theme.inputStyle, flex: 1 },
|
||||
revisionList: { ...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={Object.assign({}, theme.buttonStyle, { marginRight: 10, height: theme.inputStyle.height })}>
|
||||
<button onClick={this.backButton_click} style={{ ...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={Object.assign({}, theme.buttonStyle, { marginLeft: 10, height: theme.inputStyle.height })}>
|
||||
<button disabled={!this.state.revisions.length || this.state.restoring} onClick={this.importButton_onClick} style={{ ...theme.buttonStyle, marginLeft: 10, height: theme.inputStyle.height }}>
|
||||
{restoreButtonTitle}
|
||||
</button>
|
||||
<HelpButton tip={helpMessage} id="noteRevisionHelpButton" onClick={this.helpButton_onClick} />
|
||||
|
||||
@@ -37,10 +37,8 @@ class NoteSearchBar extends React.Component<Props> {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const style = {
|
||||
root: Object.assign({}, theme.textStyle, {
|
||||
backgroundColor: theme.backgroundColor,
|
||||
color: theme.colorFaded,
|
||||
}),
|
||||
root: { ...theme.textStyle, backgroundColor: theme.backgroundColor,
|
||||
color: theme.colorFaded },
|
||||
};
|
||||
|
||||
return style;
|
||||
@@ -150,12 +148,10 @@ 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 = Object.assign({
|
||||
fontSize: theme.fontSize,
|
||||
const textStyle = { fontSize: theme.fontSize,
|
||||
fontFamily: theme.fontFamily,
|
||||
color: theme.colorFaded,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
});
|
||||
backgroundColor: theme.backgroundColor };
|
||||
|
||||
const matchesFoundString = (query.length > 0) ? (
|
||||
<div style={textStyle}>
|
||||
|
||||
@@ -15,10 +15,8 @@ class NoteStatusBarComponent extends React.Component<Props> {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const style = {
|
||||
root: Object.assign({}, theme.textStyle, {
|
||||
backgroundColor: theme.backgroundColor,
|
||||
color: theme.colorFaded,
|
||||
}),
|
||||
root: { ...theme.textStyle, backgroundColor: theme.backgroundColor,
|
||||
color: theme.colorFaded },
|
||||
};
|
||||
|
||||
return style;
|
||||
|
||||
@@ -173,7 +173,7 @@ export default class NoteTextViewerComponent extends React.Component<Props, any>
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
public render() {
|
||||
const viewerStyle = Object.assign({}, { border: 'none' }, this.props.viewerStyle);
|
||||
const viewerStyle = { border: 'none', ...this.props.viewerStyle };
|
||||
return <iframe className="noteTextViewer" ref={this.webviewRef_} style={viewerStyle} src="gui/note-viewer/index.html"></iframe>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,43 +132,49 @@ export default class PromptDialog extends React.Component<Props, any> {
|
||||
};
|
||||
|
||||
this.styles_.select = {
|
||||
control: (provided: any) =>
|
||||
Object.assign(provided, {
|
||||
control: (provided: any) => {
|
||||
return { ...provided,
|
||||
minWidth: width * 0.2,
|
||||
maxWidth: width * 0.5,
|
||||
fontFamily: theme.fontFamily,
|
||||
}),
|
||||
input: (provided: any) =>
|
||||
Object.assign(provided, {
|
||||
};
|
||||
},
|
||||
input: (provided: any) => {
|
||||
return { ...provided,
|
||||
minWidth: '20px',
|
||||
color: theme.color,
|
||||
}),
|
||||
menu: (provided: any) =>
|
||||
Object.assign(provided, {
|
||||
};
|
||||
},
|
||||
menu: (provided: any) => {
|
||||
return { ...provided,
|
||||
color: theme.color,
|
||||
fontFamily: theme.fontFamily,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
}),
|
||||
option: (provided: any, state: any) =>
|
||||
Object.assign(provided, {
|
||||
};
|
||||
},
|
||||
option: (provided: any, state: any) => {
|
||||
return { ...provided,
|
||||
color: theme.color,
|
||||
fontFamily: theme.fontFamily,
|
||||
paddingLeft: `${10 + (state.data.indentDepth || 0) * 20}px`,
|
||||
}),
|
||||
multiValueLabel: (provided: any) =>
|
||||
Object.assign(provided, {
|
||||
};
|
||||
},
|
||||
multiValueLabel: (provided: any) => {
|
||||
return { ...provided,
|
||||
fontFamily: theme.fontFamily,
|
||||
}),
|
||||
multiValueRemove: (provided: any) =>
|
||||
Object.assign(provided, {
|
||||
};
|
||||
},
|
||||
multiValueRemove: (provided: any) => {
|
||||
return { ...provided,
|
||||
color: theme.color,
|
||||
}),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
this.styles_.selectTheme = (tagTheme: any) =>
|
||||
Object.assign(tagTheme, {
|
||||
this.styles_.selectTheme = (tagTheme: any) => {
|
||||
return { ...tagTheme,
|
||||
borderRadius: 2,
|
||||
colors: Object.assign(tagTheme.colors, {
|
||||
colors: { ...tagTheme.colors,
|
||||
primary: theme.raisedBackgroundColor,
|
||||
primary25: theme.raisedBackgroundColor,
|
||||
neutral0: theme.backgroundColor,
|
||||
@@ -184,12 +190,11 @@ export default class PromptDialog extends React.Component<Props, any> {
|
||||
neutral90: theme.color,
|
||||
danger: theme.backgroundColor,
|
||||
dangerLight: theme.colorError2,
|
||||
}),
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
this.styles_.desc = Object.assign({}, theme.textStyle, {
|
||||
marginTop: 10,
|
||||
});
|
||||
this.styles_.desc = { ...theme.textStyle, marginTop: 10 };
|
||||
|
||||
return this.styles_;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useRef, useCallback, useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import styled, { css } 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,24 +40,15 @@ const { clipboard } = require('electron');
|
||||
|
||||
const logger = Logger.create('Sidebar');
|
||||
|
||||
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,
|
||||
}}
|
||||
}
|
||||
// Workaround sidebar rendering bug on Linux Intel GPU.
|
||||
// https://github.com/laurent22/joplin/issues/7506
|
||||
const StyledSpanFix = styled.span`
|
||||
${shim.isLinux() && css`
|
||||
position: relative;
|
||||
`}
|
||||
`;
|
||||
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
dispatch: Function;
|
||||
@@ -138,7 +129,7 @@ function FolderItem(props: any) {
|
||||
}}
|
||||
onDoubleClick={onFolderToggleClick_}
|
||||
>
|
||||
{showFolderIcon ? renderFolderIcon(folderIcon) : null}<span className="title" style={{ lineHeight: 0 }}>{folderTitle}</span>
|
||||
{showFolderIcon ? renderFolderIcon(folderIcon) : null}<StyledSpanFix className="title" style={{ lineHeight: 0 }}>{folderTitle}</StyledSpanFix>
|
||||
{shareIcon} {noteCountComp}
|
||||
</StyledListItemAnchor>
|
||||
</StyledListItem>
|
||||
@@ -573,7 +564,7 @@ const SidebarComponent = (props: Props) => {
|
||||
tagItem_click(tag);
|
||||
}}
|
||||
>
|
||||
<span className="tag-label">{Tag.displayTitle(tag)}</span>
|
||||
<StyledSpanFix className="tag-label">{Tag.displayTitle(tag)}</StyledSpanFix>
|
||||
{noteCount}
|
||||
</StyledListItemAnchor>
|
||||
</StyledListItem>
|
||||
@@ -725,13 +716,13 @@ const SidebarComponent = (props: Props) => {
|
||||
const folderItems = [renderAllNotesItem(theme, allNotesSelected)].concat(result.items);
|
||||
folderItemsOrder_.current = result.order;
|
||||
items.push(
|
||||
<StyledFoldersHolder
|
||||
<div
|
||||
className={`folders ${props.folderHeaderIsExpanded ? 'expanded' : ''}`}
|
||||
key="folder_items"
|
||||
style={foldersStyle}
|
||||
>
|
||||
{folderItems}
|
||||
</StyledFoldersHolder>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -747,9 +738,9 @@ const SidebarComponent = (props: Props) => {
|
||||
tagItemsOrder_.current = result.order;
|
||||
|
||||
items.push(
|
||||
<TagsHolder className="tags" key="tag_items" style={{ display: props.tagHeaderIsExpanded ? 'block' : 'none' }}>
|
||||
<div className="tags" key="tag_items" style={{ display: props.tagHeaderIsExpanded ? 'block' : 'none' }}>
|
||||
{tagItems}
|
||||
</TagsHolder>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,9 +100,8 @@ export const StyledExpandLink = styled.a`
|
||||
`;
|
||||
|
||||
export const StyledNoteCount = styled.div`
|
||||
color: ${(props: any) => props.theme.color2};
|
||||
color: ${(props: any) => props.theme.colorFaded2};
|
||||
padding-left: 8px;
|
||||
opacity: 0.5;
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
|
||||
@@ -56,15 +56,13 @@ function StatusScreen(props: Props) {
|
||||
flexDirection: 'column',
|
||||
};
|
||||
|
||||
const retryStyle = Object.assign({}, theme.urlStyle, { marginLeft: 5 });
|
||||
const retryAllStyle = Object.assign({}, theme.urlStyle, { marginTop: 5, display: 'inline-block' });
|
||||
const retryStyle = { ...theme.urlStyle, marginLeft: 5 };
|
||||
const retryAllStyle = { ...theme.urlStyle, marginTop: 5, display: 'inline-block' };
|
||||
|
||||
const containerPadding = theme.configScreenPadding;
|
||||
|
||||
const containerStyle = Object.assign({}, theme.containerStyle, {
|
||||
padding: containerPadding,
|
||||
flex: 1,
|
||||
});
|
||||
const containerStyle = { ...theme.containerStyle, padding: containerPadding,
|
||||
flex: 1 };
|
||||
|
||||
function renderSectionTitleHtml(key: string, title: string) {
|
||||
return (
|
||||
|
||||
@@ -7,7 +7,7 @@ import { AppState } from '../app.reducer';
|
||||
class TagItemComponent extends React.Component {
|
||||
public render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const style = Object.assign({}, theme.tagStyle);
|
||||
const style = { ...theme.tagStyle };
|
||||
const { title, id } = this.props;
|
||||
|
||||
return <button style={style} onClick={() => CommandService.instance().execute('openTag', id)}>{title}</button>;
|
||||
|
||||
@@ -16,14 +16,12 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
|
||||
public render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
const style: any = Object.assign({
|
||||
display: 'flex',
|
||||
const style: any = { 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',
|
||||
@@ -45,13 +43,11 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
|
||||
|
||||
if (!key) key = `${o.type}_${i}`;
|
||||
|
||||
const props = Object.assign(
|
||||
{
|
||||
key: key,
|
||||
themeId: this.props.themeId,
|
||||
},
|
||||
o
|
||||
);
|
||||
const props = {
|
||||
key: key,
|
||||
themeId: this.props.themeId,
|
||||
...o,
|
||||
};
|
||||
|
||||
if (o.name === 'toggleEditors') {
|
||||
rightItemComps.push(<ToggleEditorsButton
|
||||
@@ -77,7 +73,7 @@ class ToolbarBaseComponent extends React.Component<Props, any> {
|
||||
<div style={groupStyle}>
|
||||
{centerItemComps}
|
||||
</div>
|
||||
<div style={Object.assign({}, groupStyle, { flex: 1, justifyContent: 'flex-end' })}>
|
||||
<div style={{ ...groupStyle, flex: 1, justifyContent: 'flex-end' }}>
|
||||
{rightItemComps}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ interface Props {
|
||||
class ToolbarSpace extends React.Component<Props> {
|
||||
public render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const style = Object.assign({}, theme.toolbarStyle);
|
||||
const style = { ...theme.toolbarStyle };
|
||||
style.minWidth = style.height / 2;
|
||||
|
||||
return <span style={style}></span>;
|
||||
|
||||
@@ -96,25 +96,23 @@ markJsUtils.markKeyword = (mark, keyword, stringUtils, extraOptions = null) => {
|
||||
|
||||
mark.mark(
|
||||
[value],
|
||||
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;
|
||||
},
|
||||
{
|
||||
|
||||
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,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -41,13 +41,9 @@ const style = createSelector(
|
||||
},
|
||||
};
|
||||
|
||||
output.buttonIconSelected = Object.assign({}, output.buttonIcon, {
|
||||
color: theme.highlightedColor,
|
||||
});
|
||||
output.buttonIconSelected = { ...output.buttonIcon, color: theme.highlightedColor };
|
||||
|
||||
output.buttonLabelSelected = Object.assign({}, output.buttonLabel, {
|
||||
color: theme.color,
|
||||
});
|
||||
output.buttonLabelSelected = { ...output.buttonLabel, color: theme.color };
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.11.2",
|
||||
"version": "2.11.9",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
@@ -27,7 +27,7 @@
|
||||
},
|
||||
"build": {
|
||||
"appId": "net.cozic.joplin-desktop",
|
||||
"compression": "maximum",
|
||||
"compression": "normal",
|
||||
"productName": "Joplin",
|
||||
"npmRebuild": false,
|
||||
"afterSign": "./tools/notarizeMacApp.js",
|
||||
@@ -110,9 +110,9 @@
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "~2.11",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@types/jest": "29.2.6",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/react": "16.14.35",
|
||||
"@types/jest": "29.5.1",
|
||||
"@types/node": "18.15.13",
|
||||
"@types/react": "16.14.41",
|
||||
"@types/react-redux": "7.1.25",
|
||||
"@types/styled-components": "5.1.26",
|
||||
"electron": "19.1.4",
|
||||
@@ -121,12 +121,12 @@
|
||||
"electron-rebuild": "3.2.9",
|
||||
"glob": "8.1.0",
|
||||
"gulp": "4.0.2",
|
||||
"jest": "29.4.3",
|
||||
"jest-environment-jsdom": "29.4.3",
|
||||
"jest": "29.5.0",
|
||||
"jest-environment-jsdom": "29.5.0",
|
||||
"js-sha512": "0.8.0",
|
||||
"nan": "2.17.0",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"typescript": "4.9.4"
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"7zip-bin-linux": "^1.0.1",
|
||||
@@ -148,7 +148,7 @@
|
||||
"electron-window-state": "5.0.3",
|
||||
"formatcoords": "1.1.3",
|
||||
"fs-extra": "11.1.1",
|
||||
"highlight.js": "11.7.0",
|
||||
"highlight.js": "11.8.0",
|
||||
"immer": "7.0.15",
|
||||
"keytar": "7.9.0",
|
||||
"mark.js": "8.11.1",
|
||||
@@ -163,7 +163,7 @@
|
||||
"react-datetime": "3.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-redux": "8.0.5",
|
||||
"react-select": "5.7.2",
|
||||
"react-select": "5.7.3",
|
||||
"react-toggle-button": "2.2.0",
|
||||
"react-tooltip": "4.5.1",
|
||||
"redux": "4.2.1",
|
||||
@@ -171,7 +171,7 @@
|
||||
"roboto-fontface": "0.10.0",
|
||||
"smalltalk": "2.5.1",
|
||||
"sqlite3": "5.1.6",
|
||||
"styled-components": "5.3.9",
|
||||
"styled-components": "5.3.10",
|
||||
"styled-system": "5.1.5",
|
||||
"taboverride": "4.0.3",
|
||||
"tinymce": "5.10.6"
|
||||
|
||||
@@ -133,8 +133,8 @@ class Dialog extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
this.styles_[styleKey] = {
|
||||
dialogBox: Object.assign({}, theme.dialogBox, { minWidth: '50%', maxWidth: '50%' }),
|
||||
input: Object.assign({}, theme.inputStyle, { flex: 1 }),
|
||||
dialogBox: { ...theme.dialogBox, minWidth: '50%', maxWidth: '50%' },
|
||||
input: { ...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: Object.assign({}, theme.textStyle, { marginBottom: 10 }),
|
||||
help: { ...theme.textStyle, marginBottom: 10 },
|
||||
inputHelpWrapper: { display: 'flex', flexDirection: 'row', alignItems: 'center' },
|
||||
};
|
||||
|
||||
@@ -163,19 +163,15 @@ class Dialog extends React.PureComponent<Props, State> {
|
||||
userSelect: 'none',
|
||||
};
|
||||
|
||||
const rowTitleStyle = Object.assign({}, rowTextStyle, {
|
||||
fontSize: rowTextStyle.fontSize * 1.4,
|
||||
const rowTitleStyle = { ...rowTextStyle, fontSize: rowTextStyle.fontSize * 1.4,
|
||||
marginBottom: this.state.resultsInBody ? 6 : 4,
|
||||
color: theme.colorFaded,
|
||||
});
|
||||
color: theme.colorFaded };
|
||||
|
||||
const rowFragmentsStyle = Object.assign({}, rowTextStyle, {
|
||||
fontSize: rowTextStyle.fontSize * 1.2,
|
||||
const rowFragmentsStyle = { ...rowTextStyle, fontSize: rowTextStyle.fontSize * 1.2,
|
||||
marginBottom: this.state.resultsInBody ? 8 : 6,
|
||||
color: theme.colorFaded,
|
||||
});
|
||||
color: theme.colorFaded };
|
||||
|
||||
this.styles_[styleKey].rowSelected = Object.assign({}, this.styles_[styleKey].row, { backgroundColor: theme.selectedColor });
|
||||
this.styles_[styleKey].rowSelected = { ...this.styles_[styleKey].row, backgroundColor: theme.selectedColor };
|
||||
this.styles_[styleKey].rowPath = rowTextStyle;
|
||||
this.styles_[styleKey].rowTitle = rowTitleStyle;
|
||||
this.styles_[styleKey].rowFragments = rowFragmentsStyle;
|
||||
@@ -304,7 +300,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] = Object.assign({}, row, { path: path ? path : '/' });
|
||||
results[i] = { ...row, path: path ? path : '/' };
|
||||
}
|
||||
} else { // Note TITLE or BODY
|
||||
listType = BaseModel.TYPE_NOTE;
|
||||
@@ -317,7 +313,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] = Object.assign({}, row, { path: path });
|
||||
results[i] = { ...row, path: path };
|
||||
}
|
||||
} else {
|
||||
const limit = 20;
|
||||
@@ -365,9 +361,9 @@ class Dialog extends React.PureComponent<Props, State> {
|
||||
|
||||
}
|
||||
|
||||
results[i] = Object.assign({}, row, { path, fragments });
|
||||
results[i] = { ...row, path, fragments };
|
||||
} else {
|
||||
results[i] = Object.assign({}, row, { path: path, fragments: '' });
|
||||
results[i] = { ...row, path: path, fragments: '' };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,10 @@ export default class PluginRunner extends BasePluginRunner {
|
||||
|
||||
if (plugin.devMode) {
|
||||
pluginWindow.webContents.once('dom-ready', () => {
|
||||
pluginWindow.webContents.openDevTools({ mode: 'detach' });
|
||||
// Need to open with a delay, otherwise it doesn't show up
|
||||
setTimeout(() => {
|
||||
pluginWindow.webContents.openDevTools({ mode: 'detach' });
|
||||
}, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
[android]
|
||||
target = Google Inc.:Google APIs:23
|
||||
|
||||
[maven_repositories]
|
||||
central = https://repo1.maven.org/maven2
|
||||
@@ -1,73 +0,0 @@
|
||||
[ignore]
|
||||
; We fork some components by platform
|
||||
.*/*[.]android.js
|
||||
|
||||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore polyfills
|
||||
node_modules/react-native/Libraries/polyfills/.*
|
||||
|
||||
; These should not be required directly
|
||||
; require from fbjs/lib instead: require('fbjs/lib/warning')
|
||||
node_modules/warning/.*
|
||||
|
||||
; Flow doesn't support platforms
|
||||
.*/Libraries/Utilities/LoadingView.js
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/@react-native-community/cli/.*/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/interface.js
|
||||
node_modules/react-native/flow/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
esproposal.optional_chaining=enable
|
||||
esproposal.nullish_coalescing=enable
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.json
|
||||
module.file_ext=.ios.js
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
|
||||
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[lints]
|
||||
sketchy-null-number=warn
|
||||
sketchy-null-mixed=warn
|
||||
sketchy-number=warn
|
||||
untyped-type-import=warn
|
||||
nonstrict-import=warn
|
||||
deprecated-type=warn
|
||||
unsafe-getters-setters=warn
|
||||
unnecessary-invariant=warn
|
||||
signature-verification-failure=warn
|
||||
deprecated-utility=error
|
||||
|
||||
[strict]
|
||||
deprecated-type
|
||||
nonstrict-import
|
||||
sketchy-null
|
||||
unclear-type
|
||||
unsafe-getters-setters
|
||||
untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.122.0
|
||||
11
packages/app-mobile/.gitignore
vendored
11
packages/app-mobile/.gitignore
vendored
@@ -31,6 +31,8 @@ local.properties
|
||||
*.iml
|
||||
*.hprof
|
||||
.cxx/
|
||||
*.keystore
|
||||
!debug.keystore
|
||||
|
||||
# node.js
|
||||
#
|
||||
@@ -38,12 +40,6 @@ node_modules/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
!debug.keystore
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
@@ -63,6 +59,9 @@ buck-out/
|
||||
/ios/Pods/
|
||||
/vendor/bundle/
|
||||
|
||||
# Temporary files created by Metro to check the health of the file watcher
|
||||
.metro-health-check*
|
||||
|
||||
# Custom
|
||||
lib/csstojs/
|
||||
lib/rnInjectedJs/
|
||||
|
||||
1
packages/app-mobile/.node-version
Normal file
1
packages/app-mobile/.node-version
Normal file
@@ -0,0 +1 @@
|
||||
18
|
||||
@@ -1 +0,0 @@
|
||||
2.7.5
|
||||
@@ -1,4 +1,4 @@
|
||||
source 'https://rubygems.org'
|
||||
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
|
||||
ruby '2.7.5'
|
||||
gem 'cocoapods', '~> 1.11', '>= 1.11.2'
|
||||
ruby '>= 2.6.10'
|
||||
gem 'cocoapods', '>= 1.11.3'
|
||||
|
||||
@@ -1,119 +1,77 @@
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: "com.facebook.react"
|
||||
|
||||
import com.android.build.OutputFile
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
/**
|
||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||
* and bundleReleaseJsAndAssets).
|
||||
* These basically call `react-native bundle` with the correct arguments during the Android build
|
||||
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
|
||||
* bundle directly from the development server. Below you can see all the possible configurations
|
||||
* and their defaults. If you decide to add a configuration block, make sure to add it before the
|
||||
* `apply from: "../../node_modules/react-native/react.gradle"` line.
|
||||
*
|
||||
* project.ext.react = [
|
||||
* // the name of the generated asset file containing your JS bundle
|
||||
* bundleAssetName: "index.android.bundle",
|
||||
*
|
||||
* // the entry file for bundle generation. If none specified and
|
||||
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
|
||||
* // default. Can be overridden with ENTRY_FILE environment variable.
|
||||
* entryFile: "index.android.js",
|
||||
*
|
||||
* // https://reactnative.dev/docs/performance#enable-the-ram-format
|
||||
* bundleCommand: "ram-bundle",
|
||||
*
|
||||
* // whether to bundle JS and assets in debug mode
|
||||
* bundleInDebug: false,
|
||||
*
|
||||
* // whether to bundle JS and assets in release mode
|
||||
* bundleInRelease: true,
|
||||
*
|
||||
* // whether to bundle JS and assets in another build variant (if configured).
|
||||
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'bundleIn${productFlavor}${buildType}'
|
||||
* // 'bundleIn${buildType}'
|
||||
* // bundleInFreeDebug: true,
|
||||
* // bundleInPaidRelease: true,
|
||||
* // bundleInBeta: true,
|
||||
*
|
||||
* // whether to disable dev mode in custom build variants (by default only disabled in release)
|
||||
* // for example: to disable dev mode in the staging build type (if configured)
|
||||
* devDisabledInStaging: true,
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'devDisabledIn${productFlavor}${buildType}'
|
||||
* // 'devDisabledIn${buildType}'
|
||||
*
|
||||
* // the root of your project, i.e. where "package.json" lives
|
||||
* root: "../../",
|
||||
*
|
||||
* // where to put the JS bundle asset in debug mode
|
||||
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
|
||||
*
|
||||
* // where to put the JS bundle asset in release mode
|
||||
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in debug mode
|
||||
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in release mode
|
||||
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
|
||||
*
|
||||
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
|
||||
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
|
||||
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
|
||||
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
|
||||
* // for example, you might want to remove it from here.
|
||||
* inputExcludes: ["android/**", "ios/**"],
|
||||
*
|
||||
* // override which node gets called and with what additional arguments
|
||||
* nodeExecutableAndArgs: ["node"],
|
||||
*
|
||||
* // supply additional arguments to the packager
|
||||
* extraPackagerArgs: []
|
||||
* ]
|
||||
/* This is the configuration block to customize your React Native Android app.
|
||||
* By default you don't need to apply any configuration, just uncomment the lines you need.
|
||||
*/
|
||||
|
||||
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:
|
||||
react {
|
||||
/* Folders */
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '..'
|
||||
// root = file("../")
|
||||
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
|
||||
// reactNativeDir = file("../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
|
||||
// codegenDir = file("../node_modules/react-native-codegen")
|
||||
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
|
||||
// cliFile = file("../node_modules/react-native/cli.js")
|
||||
/* Variants */
|
||||
// The list of variants to that are debuggable. For those we're going to
|
||||
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
|
||||
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
|
||||
// debuggableVariants = ["liteDebug", "prodDebug"]
|
||||
/* Bundling */
|
||||
// A list containing the node command and its flags. Default is just 'node'.
|
||||
// nodeExecutableAndArgs = ["node"]
|
||||
//
|
||||
// > java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libhermes.so"
|
||||
// The command to run when bundling. By default is 'bundle'
|
||||
// bundleCommand = "ram-bundle"
|
||||
//
|
||||
// https://github.com/laurent22/joplin/issues/8144#issuecomment-1539629812
|
||||
enableHermes: true, // clean and rebuild if changing
|
||||
]
|
||||
|
||||
apply from: "../../node_modules/react-native/react.gradle"
|
||||
// The path to the CLI configuration file. Default is empty.
|
||||
// bundleConfig = file(../rn-cli.config.js)
|
||||
//
|
||||
// The name of the generated asset file containing your JS bundle
|
||||
// bundleAssetName = "MyApplication.android.bundle"
|
||||
//
|
||||
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
|
||||
// entryFile = file("../js/MyApplication.android.js")
|
||||
//
|
||||
// A list of extra flags to pass to the 'bundle' commands.
|
||||
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
|
||||
// extraPackagerArgs = []
|
||||
/* Hermes Commands */
|
||||
// The hermes compiler command to run. By default it is 'hermesc'
|
||||
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
|
||||
//
|
||||
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||
// hermesFlags = ["-O", "-output-source-map"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to create two separate APKs instead of one:
|
||||
* - An APK that only works on ARM devices
|
||||
* - An APK that only works on x86 devices
|
||||
* The advantage is the size of the APK is reduced by about 4MB.
|
||||
* Upload all the APKs to the Play Store and people will download
|
||||
* the correct one based on the CPU architecture of their device.
|
||||
* Set this to true to create four separate APKs instead of one,
|
||||
* one for each native architecture. This is useful if you don't
|
||||
* use App Bundles (https://developer.android.com/guide/app-bundle/)
|
||||
* and want to have separate APKs to upload to the Play Store.
|
||||
*/
|
||||
def enableSeparateBuildPerCPUArchitecture = false
|
||||
|
||||
/**
|
||||
* Run Proguard to shrink the Java bytecode in release builds.
|
||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||
*/
|
||||
def enableProguardInReleaseBuilds = false
|
||||
|
||||
/**
|
||||
* The preferred build flavor of JavaScriptCore.
|
||||
* The preferred build flavor of JavaScriptCore (JSC)
|
||||
*
|
||||
* For example, to use the international variant, you can use:
|
||||
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
||||
*
|
||||
* The international variant includes ICU i18n library and necessary data
|
||||
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
||||
* give correct results when using with locales other than en-US. Note that
|
||||
* give correct results when using with locales other than en-US. Note that
|
||||
* this variant is about 6MiB larger per architecture than default.
|
||||
*/
|
||||
|
||||
@@ -122,16 +80,9 @@ def enableProguardInReleaseBuilds = false
|
||||
def jscFlavor = 'org.webkit:android-jsc-intl:+'
|
||||
|
||||
/**
|
||||
* Whether to enable the Hermes VM.
|
||||
*
|
||||
* This should be set on project.ext.react and that value will be read here. If it is not set
|
||||
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
|
||||
* and the benefits of using Hermes will therefore be sharply reduced.
|
||||
*/
|
||||
def enableHermes = project.ext.react.get("enableHermes", false);
|
||||
|
||||
/**
|
||||
* Architectures to build native code for.
|
||||
* Private function to get the list of Native Architectures you want to build.
|
||||
* This reads the value from reactNativeArchitectures in your gradle.properties
|
||||
* file and works together with the --active-arch-only flag of react-native run-android.
|
||||
*/
|
||||
def reactNativeArchitectures() {
|
||||
def value = project.getProperties().get("reactNativeArchitectures")
|
||||
@@ -139,6 +90,8 @@ def reactNativeArchitectures() {
|
||||
}
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
compileOptions {
|
||||
@@ -146,18 +99,19 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
// To fix "GC overhead limit exceeded"
|
||||
// https://stackoverflow.com/q/32133013/561309
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
// dexOptions {
|
||||
// // To fix "GC overhead limit exceeded"
|
||||
// // https://stackoverflow.com/q/32133013/561309
|
||||
// javaMaxHeapSize "4g"
|
||||
// }
|
||||
|
||||
namespace "net.cozic.joplin"
|
||||
defaultConfig {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097701
|
||||
versionName "2.11.16"
|
||||
versionCode 2097712
|
||||
versionName "2.11.27"
|
||||
// ndk {
|
||||
// abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
// }
|
||||
@@ -166,67 +120,7 @@ android {
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
|
||||
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
|
||||
multiDexEnabled true
|
||||
|
||||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the CMake build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DPROJECT_BUILD_DIR=$buildDir",
|
||||
"-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
|
||||
"-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
|
||||
"-DNODE_MODULES_DIR=$rootDir/../node_modules",
|
||||
"-DANDROID_STL=c++_shared"
|
||||
}
|
||||
}
|
||||
if (!enableSeparateBuildPerCPUArchitecture) {
|
||||
ndk {
|
||||
abiFilters (*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the NDK build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "$projectDir/src/main/jni/CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
|
||||
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
|
||||
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
|
||||
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
|
||||
into("$buildDir/react-ndk/exported")
|
||||
}
|
||||
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
|
||||
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
|
||||
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
|
||||
into("$buildDir/react-ndk/exported")
|
||||
}
|
||||
afterEvaluate {
|
||||
// If you wish to add a custom TurboModule or component locally,
|
||||
// you should uncomment this line.
|
||||
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
|
||||
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
|
||||
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
|
||||
// Due to a bug inside AGP, we have to explicitly set a dependency
|
||||
// between configureCMakeDebug* tasks and the preBuild tasks.
|
||||
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
|
||||
configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
|
||||
configureCMakeDebug.dependsOn(preDebugBuild)
|
||||
reactNativeArchitectures().each { architecture ->
|
||||
tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
|
||||
dependsOn("preDebugBuild")
|
||||
}
|
||||
tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
|
||||
dependsOn("preReleaseBuild")
|
||||
}
|
||||
}
|
||||
}
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
splits {
|
||||
@@ -288,10 +182,10 @@ android {
|
||||
// > Execution failed for task ':app:lintVitalRelease'
|
||||
//
|
||||
// https://stackoverflow.com/a/62603296/561309
|
||||
lintOptions {
|
||||
disable 'InvalidPackage'
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
// lintOptions {
|
||||
// disable 'InvalidPackage'
|
||||
// checkReleaseBuilds false
|
||||
// }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -301,72 +195,28 @@ dependencies {
|
||||
exclude group: 'com.google.android.gms', module: 'play-services-vision'
|
||||
}
|
||||
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
// 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 "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.fbjni'
|
||||
}
|
||||
// The version of react-native is set by the React Native Gradle Plugin
|
||||
implementation("com.facebook.react:react-android")
|
||||
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
|
||||
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.flipper'
|
||||
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
||||
}
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.flipper'
|
||||
}
|
||||
|
||||
if (enableHermes) {
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation("com.facebook.react:hermes-engine:+") { // From node_modules
|
||||
exclude group:'com.facebook.fbjni'
|
||||
}
|
||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
|
||||
if (hermesEnabled.toBoolean()) {
|
||||
implementation("com.facebook.react:hermes-android")
|
||||
} else {
|
||||
implementation jscFlavor
|
||||
}
|
||||
|
||||
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
|
||||
implementation 'com.android.support:multidex:2.0.1'
|
||||
}
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// If new architecture is enabled, we let you build RN from source
|
||||
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
|
||||
// This will be applied to all the imported transtitive dependency.
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute(module("com.facebook.react:react-native"))
|
||||
.using(project(":ReactAndroid"))
|
||||
.because("On New Architecture we're building React Native from source")
|
||||
substitute(module("com.facebook.react:hermes-engine"))
|
||||
.using(project(":ReactAndroid:hermes-engine"))
|
||||
.because("On New Architecture we're building Hermes from source")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
// puts all compile dependencies into folder libs for BUCK to use
|
||||
task copyDownloadableDepsToLibs(type: Copy) {
|
||||
from configurations.implementation
|
||||
into 'libs'
|
||||
// implementation 'com.android.support:multidex:2.0.1'
|
||||
}
|
||||
|
||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
|
||||
def isNewArchitectureEnabled() {
|
||||
// To opt-in for the New Architecture, you can either:
|
||||
// - Set `newArchEnabled` to true inside the `gradle.properties` file
|
||||
// - Invoke gradle with `-newArchEnabled=true`
|
||||
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
|
||||
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
"""Helper definitions to glob .aar and .jar targets"""
|
||||
|
||||
def create_aar_targets(aarfiles):
|
||||
for aarfile in aarfiles:
|
||||
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
|
||||
lib_deps.append(":" + name)
|
||||
android_prebuilt_aar(
|
||||
name = name,
|
||||
aar = aarfile,
|
||||
)
|
||||
|
||||
def create_jar_targets(jarfiles):
|
||||
for jarfile in jarfiles:
|
||||
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
|
||||
lib_deps.append(":" + name)
|
||||
prebuilt_jar(
|
||||
name = name,
|
||||
binary_jar = jarfile,
|
||||
)
|
||||
@@ -17,7 +17,6 @@ import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
|
||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||
import com.facebook.react.ReactInstanceEventListener;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
@@ -25,13 +24,16 @@ import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.modules.network.NetworkingModule;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Class responsible of loading Flipper inside your React Native application. This is the debug
|
||||
* flavor of it. Here you can add your own plugins and customize the Flipper setup.
|
||||
*/
|
||||
public class ReactNativeFlipper {
|
||||
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
|
||||
if (FlipperUtils.shouldEnableFlipper(context)) {
|
||||
final FlipperClient client = AndroidFlipperClient.getInstance(context);
|
||||
|
||||
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
|
||||
client.addPlugin(new ReactFlipperPlugin());
|
||||
client.addPlugin(new DatabasesFlipperPlugin(context));
|
||||
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
|
||||
client.addPlugin(CrashReporterPlugin.getInstance());
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="net.cozic.joplin"
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
@@ -8,6 +7,7 @@
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATION" />
|
||||
|
||||
<!-- Make these features optional to enable Chromebooks -->
|
||||
<!-- https://github.com/laurent22/joplin/issues/37 -->
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
French small model for Vosk
|
||||
|
||||
WER
|
||||
|
||||
%WER 23.95 [ 37203 / 155330, 5373 ins, 4427 del, 27403 sub ] exp/chain_a/tdnn/decode_test_cv/wer_12_0.0
|
||||
%WER 19.30 [ 2975 / 15412, 683 ins, 672 del, 1620 sub ] exp/chain_a/tdnn/decode_test_mtedx/wer_10_0.0
|
||||
%WER 27.25 [ 20208 / 74145, 2647 ins, 5852 del, 11709 sub ] exp/chain_a/tdnn/decode_test_podcast_reseg/wer_10_0.0
|
||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
--use-energy=false
|
||||
--sample-frequency=16000
|
||||
--num-mel-bins=40
|
||||
--num-ceps=40
|
||||
--low-freq=40
|
||||
--high-freq=-200
|
||||
--allow-upsample=true
|
||||
--allow-downsample=true
|
||||
@@ -1,10 +0,0 @@
|
||||
--min-active=200
|
||||
--max-active=7000
|
||||
--beam=13.0
|
||||
--lattice-beam=4.0
|
||||
--acoustic-scale=1.0
|
||||
--frame-subsampling-factor=3
|
||||
--endpoint.silence-phones=1:2:3:4:5:6:7:8:9:10
|
||||
--endpoint.rule2.min-trailing-silence=0.5
|
||||
--endpoint.rule3.min-trailing-silence=1.0
|
||||
--endpoint.rule4.min-trailing-silence=2.0
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,76 +0,0 @@
|
||||
9365
|
||||
9366
|
||||
9367
|
||||
9368
|
||||
9369
|
||||
9370
|
||||
9371
|
||||
9372
|
||||
9373
|
||||
9374
|
||||
9375
|
||||
9376
|
||||
9377
|
||||
9378
|
||||
9379
|
||||
9380
|
||||
9381
|
||||
9382
|
||||
9383
|
||||
9384
|
||||
9385
|
||||
9386
|
||||
9387
|
||||
9388
|
||||
9389
|
||||
9390
|
||||
9391
|
||||
9392
|
||||
9393
|
||||
9394
|
||||
9395
|
||||
9396
|
||||
9397
|
||||
9398
|
||||
9399
|
||||
9400
|
||||
9401
|
||||
9402
|
||||
9403
|
||||
9404
|
||||
9405
|
||||
9406
|
||||
9407
|
||||
9408
|
||||
9409
|
||||
9410
|
||||
9411
|
||||
9412
|
||||
9413
|
||||
9414
|
||||
9415
|
||||
9416
|
||||
9417
|
||||
9418
|
||||
9419
|
||||
9420
|
||||
9421
|
||||
9422
|
||||
9423
|
||||
9424
|
||||
9425
|
||||
9426
|
||||
9427
|
||||
9428
|
||||
9429
|
||||
9430
|
||||
9431
|
||||
9432
|
||||
9433
|
||||
9434
|
||||
9435
|
||||
9436
|
||||
9437
|
||||
9438
|
||||
9439
|
||||
9440
|
||||
@@ -1,154 +0,0 @@
|
||||
1 nonword
|
||||
2 begin
|
||||
3 end
|
||||
4 internal
|
||||
5 singleton
|
||||
6 nonword
|
||||
7 begin
|
||||
8 end
|
||||
9 internal
|
||||
10 singleton
|
||||
11 begin
|
||||
12 end
|
||||
13 internal
|
||||
14 singleton
|
||||
15 begin
|
||||
16 end
|
||||
17 internal
|
||||
18 singleton
|
||||
19 begin
|
||||
20 end
|
||||
21 internal
|
||||
22 singleton
|
||||
23 begin
|
||||
24 end
|
||||
25 internal
|
||||
26 singleton
|
||||
27 begin
|
||||
28 end
|
||||
29 internal
|
||||
30 singleton
|
||||
31 begin
|
||||
32 end
|
||||
33 internal
|
||||
34 singleton
|
||||
35 begin
|
||||
36 end
|
||||
37 internal
|
||||
38 singleton
|
||||
39 begin
|
||||
40 end
|
||||
41 internal
|
||||
42 singleton
|
||||
43 begin
|
||||
44 end
|
||||
45 internal
|
||||
46 singleton
|
||||
47 begin
|
||||
48 end
|
||||
49 internal
|
||||
50 singleton
|
||||
51 begin
|
||||
52 end
|
||||
53 internal
|
||||
54 singleton
|
||||
55 begin
|
||||
56 end
|
||||
57 internal
|
||||
58 singleton
|
||||
59 begin
|
||||
60 end
|
||||
61 internal
|
||||
62 singleton
|
||||
63 begin
|
||||
64 end
|
||||
65 internal
|
||||
66 singleton
|
||||
67 begin
|
||||
68 end
|
||||
69 internal
|
||||
70 singleton
|
||||
71 begin
|
||||
72 end
|
||||
73 internal
|
||||
74 singleton
|
||||
75 begin
|
||||
76 end
|
||||
77 internal
|
||||
78 singleton
|
||||
79 begin
|
||||
80 end
|
||||
81 internal
|
||||
82 singleton
|
||||
83 begin
|
||||
84 end
|
||||
85 internal
|
||||
86 singleton
|
||||
87 begin
|
||||
88 end
|
||||
89 internal
|
||||
90 singleton
|
||||
91 begin
|
||||
92 end
|
||||
93 internal
|
||||
94 singleton
|
||||
95 begin
|
||||
96 end
|
||||
97 internal
|
||||
98 singleton
|
||||
99 begin
|
||||
100 end
|
||||
101 internal
|
||||
102 singleton
|
||||
103 begin
|
||||
104 end
|
||||
105 internal
|
||||
106 singleton
|
||||
107 begin
|
||||
108 end
|
||||
109 internal
|
||||
110 singleton
|
||||
111 begin
|
||||
112 end
|
||||
113 internal
|
||||
114 singleton
|
||||
115 begin
|
||||
116 end
|
||||
117 internal
|
||||
118 singleton
|
||||
119 begin
|
||||
120 end
|
||||
121 internal
|
||||
122 singleton
|
||||
123 begin
|
||||
124 end
|
||||
125 internal
|
||||
126 singleton
|
||||
127 begin
|
||||
128 end
|
||||
129 internal
|
||||
130 singleton
|
||||
131 begin
|
||||
132 end
|
||||
133 internal
|
||||
134 singleton
|
||||
135 begin
|
||||
136 end
|
||||
137 internal
|
||||
138 singleton
|
||||
139 begin
|
||||
140 end
|
||||
141 internal
|
||||
142 singleton
|
||||
143 begin
|
||||
144 end
|
||||
145 internal
|
||||
146 singleton
|
||||
147 begin
|
||||
148 end
|
||||
149 internal
|
||||
150 singleton
|
||||
151 begin
|
||||
152 end
|
||||
153 internal
|
||||
154 singleton
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user