1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-09-05 20:56:22 +02:00

Compare commits

...

66 Commits

Author SHA1 Message Date
Laurent Cozic
8e12ace3ed Android 2.10.2 2023-01-02 17:49:12 +00:00
Laurent Cozic
7a0af66c63 Desktop release v2.10.3 2022-12-31 00:39:20 +00:00
Laurent Cozic
49e444e73b Desktop: Fixes #7528: Fixed crash when closing PDF 2022-12-31 00:36:16 +00:00
Laurent Cozic
0db0a565b7 Desktop: Fixes #7499: Random crash when searching 2022-12-30 23:54:20 +00:00
Betty Alagwu
5fb01b5c7a Desktop: Fixes #7520: Search field doesn't get focus when pressing Ctrl+F (#7529) 2022-12-30 23:54:04 +00:00
Laurent Cozic
854f1163cd Desktop: Fixes #7493: Press Enter to select a tag 2022-12-30 23:39:45 +00:00
Roman Musin
d55f6aeb2a Linux: Revert "Linux: Fix AppImage icon when installing using Joplin_install_and_update.sh (#7346)" (#7559)
This reverts commit cb563f7e60.
2022-12-30 23:21:29 +00:00
Henry Heino
ea30a6bd38 Mobile: Fixes #6175: Enable autocorrect with spellcheck (#7532) 2022-12-30 23:20:56 +00:00
github-actions[bot]
e09b26b99b @roman-r-m has signed the CLA from Pull Request #7559 2022-12-30 21:35:38 +00:00
Henry Heino
e7386e6fe3 Chore: Mobile: Fix CodeMirror test failures (#7522) 2022-12-30 17:25:31 +00:00
Laurent Cozic
767213cdc1 Mobile: Add support for realtime search 2022-12-30 14:12:07 +00:00
Laurent Cozic
a189b2eff0 lock file 2022-12-30 13:36:19 +00:00
github-actions[bot]
655ea6945d @k33pn3xtlvl has signed the CLA from Pull Request #6722 2022-12-30 13:34:52 +00:00
renovate[bot]
5106ccee91 Update dependency aws-sdk to v2.1285.0 (#7556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-30 06:12:21 +00:00
renovate[bot]
1ee515454a Update aws-sdk-js-v3 monorepo to v3.241.0 (#7555)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-30 03:53:44 +00:00
renovate[bot]
fc46c87ef7 Update dependency @types/yargs to v17.0.18 (#7554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-30 01:02:53 +00:00
Laurent Cozic
422b81ae24 Android 2.10.1 2022-12-29 14:11:12 +00:00
renovate[bot]
17124e86d1 Update dependency aws-sdk to v2.1284.0 (#7549)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-28 22:04:12 +00:00
Laurent Cozic
d2aab6536c Fixed linter error 2022-12-28 16:12:36 +00:00
Laurent Cozic
ed71f68e1d iOS 12.10.1 2022-12-28 15:09:21 +00:00
Gavin Mogan
01d451f72a Server: Add in ability to use Postgres connection string in configuration (#6836) 2022-12-28 14:38:30 +00:00
renovate[bot]
5b3f07f3c5 Update dependency aws-sdk to v2.1283.0 (#7543)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-28 14:31:37 +00:00
renovate[bot]
edf7cab1ef Update dependency joplin-rn-alarm-notification to v1.0.7 (#7545)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-28 11:25:49 +00:00
github-actions[bot]
caaac5c1a2 @adarsh-sgh has signed the CLA from Pull Request #7546 2022-12-28 08:38:37 +00:00
Laurent Cozic
5a28a6bc90 Ignore package 2022-12-27 20:38:28 +00:00
Laurent Cozic
f9f7c86915 Chore: Remove obsolete patch 2022-12-27 19:38:41 +00:00
Laurent Cozic
e2d59ee1fa Mobile: Upgrade to react-native 0.68.5 2022-12-27 19:37:15 +00:00
Laurent Cozic
d81802e7d2 Mobile: Upgrade to react-native 0.67.5 2022-12-27 17:59:16 +00:00
Laurent Cozic
73bb79b558 Tools: Add suport for npm-package-json-lint 2022-12-27 17:39:48 +00:00
github-actions[bot]
c41ebe8d9d @asrient has signed the CLA from Pull Request #6845 2022-12-27 17:34:17 +00:00
Hitarth Thummar
8e2e7eccd9 Desktop: Resolve #6254: <details> elements remain closed when exporting to PDF (#7515) 2022-12-27 16:57:00 +00:00
Wartijn
527a7da2ff Desktop: Fixes #7329: Fixes import of tasklists from enex files (#7344) 2022-12-27 15:17:42 +00:00
github-actions[bot]
40399cf3e1 @ManavSarkar has signed the CLA from Pull Request #7541 2022-12-27 10:48:33 +00:00
renovate[bot]
873808a66a Update typescript-eslint monorepo to v5.47.1 (#7539)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-27 00:23:59 +00:00
renovate[bot]
cf300bc842 Update dependency @types/node to v18.11.18 (#7538)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-26 21:57:47 +00:00
Laurent Cozic
9a06824fde Server v2.10.5 2022-12-26 12:09:27 +00:00
Laurent Cozic
186316bb8b lock file 2022-12-26 11:56:47 +00:00
Laurent Cozic
5c8861cbd1 Server: Fixes #7525: Fixed regression that would prevent styles from being loaded in published notes 2022-12-26 11:56:34 +00:00
github-actions[bot]
c710cfd273 @ken1kob has signed the CLA from Pull Request #6469 2022-12-26 11:02:08 +00:00
Mr-Kanister
3ef41016b5 All: Translation: Update de_DE.po (#7531) 2022-12-24 21:19:15 -05:00
github-actions[bot]
85423fd835 @Mr-Kanister has signed the CLA from Pull Request #7531 2022-12-24 18:40:34 +00:00
Laurent Cozic
d690146f9f Chore: Make it easier to test publishing notes 2022-12-24 12:30:52 +00:00
renovate[bot]
944e0ef304 Update dependency aws-sdk to v2.1282.0 (#7527)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-24 06:36:12 +00:00
github-actions[bot]
409dcea0c6 @betty-alagwu has signed the CLA from Pull Request #7529 2022-12-24 03:09:03 +00:00
renovate[bot]
6c20cdefd4 Update aws-sdk-js-v3 monorepo to v3.238.0 (#7526)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-24 01:47:48 +00:00
renovate[bot]
300f1590ba Update dependency @types/react-dom to v18.0.10 (#7524)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-23 19:18:31 +00:00
github-actions[bot]
f6c2013df8 @Wartijn has signed the CLA from Pull Request #6886 2022-12-23 16:13:36 +00:00
renovate[bot]
e3dc77357c Update dependency aws-sdk to v2.1281.0 (#7514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-22 22:37:33 +00:00
github-actions[bot]
a739636ce6 @halkeye has signed the CLA from Pull Request #6836 2022-12-22 17:52:40 +00:00
Laurent Cozic
7620c2b0b7 Tools: Disable CodeMirror flaky test 2022-12-22 14:30:04 +00:00
Laurent Cozic
60c4045000 Merge branch 'dev' of github.com:laurent22/joplin into dev 2022-12-22 13:19:35 +00:00
Laurent Cozic
39fb40dc37 Merge branch 'release-2.9' into dev 2022-12-22 13:18:10 +00:00
Laurent Cozic
145cb6c41e iOS 12.9.2 2022-12-22 12:42:38 +00:00
Laurent Cozic
de9f9985d1 Merge branch 'release-2.9' into dev 2022-12-22 12:40:57 +00:00
Laurent Cozic
23277aaf85 Mobile: Fixes #7471: Could not attach images to notes anymore 2022-12-22 12:38:11 +00:00
Henry Heino
e9e7a1d0df iOS: Fixes #7469: Note viewer inertial scroll is slower than native inertial scrolling (#7470) 2022-12-22 12:15:20 +00:00
github-actions[bot]
3453240833 @gtlsgamr has signed the CLA from Pull Request #7515 2022-12-22 09:35:15 +00:00
renovate[bot]
1882aac628 Update aws-sdk-js-v3 monorepo to v3.236.0 (#7513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-22 08:59:20 +00:00
renovate[bot]
6868e7086b Update dependency sharp to v0.31.3 (#7512)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-22 06:31:50 +00:00
renovate[bot]
b35eeb6626 Update dependency react-native-image-picker to v4.10.3 (#7508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-22 03:45:32 +00:00
renovate[bot]
98c56818bb Update contributor-assistant/github-action action to v2.2.1 (#7511)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-22 00:20:50 +00:00
github-actions[bot]
722a0df681 @personalizedrefrigerator has signed the CLA from Pull Request #7470 2022-12-21 21:22:46 +00:00
github-actions[bot]
115cf116a2 @wh201906 has signed the CLA from Pull Request #6865 2022-12-21 17:40:11 +00:00
Laurent Cozic
f34e048fad Update cla.md 2022-12-21 17:10:54 +00:00
github-actions[bot]
a754659ab9 @laurent22 has signed the CLA from Pull Request #7510 2022-12-21 16:54:28 +00:00
github-actions[bot]
0517d1e5d6 Creating file for storing CLA Signatures 2022-12-21 16:44:53 +00:00
100 changed files with 3398 additions and 1245 deletions

View File

@@ -933,6 +933,9 @@ packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/createEditor.js.ma
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.d.ts
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js.map
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.d.ts
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js.map
packages/app-mobile/components/NoteEditor/CodeMirror/theme.d.ts
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js.map
@@ -1005,6 +1008,9 @@ packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
packages/app-mobile/components/screens/encryption-config.d.ts
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/encryption-config.js.map
packages/app-mobile/components/screens/search.d.ts
packages/app-mobile/components/screens/search.js
packages/app-mobile/components/screens/search.js.map
packages/app-mobile/components/side-menu-content.d.ts
packages/app-mobile/components/side-menu-content.js
packages/app-mobile/components/side-menu-content.js.map
@@ -1878,6 +1884,9 @@ packages/lib/services/searchengine/filterParser.js.map
packages/lib/services/searchengine/filterParser.test.d.ts
packages/lib/services/searchengine/filterParser.test.js
packages/lib/services/searchengine/filterParser.test.js.map
packages/lib/services/searchengine/gotoAnythingStyleQuery.d.ts
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
packages/lib/services/searchengine/gotoAnythingStyleQuery.js.map
packages/lib/services/searchengine/queryBuilder.d.ts
packages/lib/services/searchengine/queryBuilder.js
packages/lib/services/searchengine/queryBuilder.js.map

View File

@@ -107,6 +107,12 @@ if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
if [ $testResult -ne 0 ]; then
exit $testResult
fi
yarn run packageJsonLint
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
fi
fi
# =============================================================================

View File

@@ -12,7 +12,7 @@ jobs:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Beta Release
uses: contributor-assistant/github-action@v2.2.0
uses: contributor-assistant/github-action@v2.2.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret

9
.gitignore vendored
View File

@@ -921,6 +921,9 @@ packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/createEditor.js.ma
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.d.ts
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/forceFullParse.js.map
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.d.ts
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js
packages/app-mobile/components/NoteEditor/CodeMirror/testUtil/loadLanguages.js.map
packages/app-mobile/components/NoteEditor/CodeMirror/theme.d.ts
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js
packages/app-mobile/components/NoteEditor/CodeMirror/theme.js.map
@@ -993,6 +996,9 @@ packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
packages/app-mobile/components/screens/encryption-config.d.ts
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/encryption-config.js.map
packages/app-mobile/components/screens/search.d.ts
packages/app-mobile/components/screens/search.js
packages/app-mobile/components/screens/search.js.map
packages/app-mobile/components/side-menu-content.d.ts
packages/app-mobile/components/side-menu-content.js
packages/app-mobile/components/side-menu-content.js.map
@@ -1866,6 +1872,9 @@ packages/lib/services/searchengine/filterParser.js.map
packages/lib/services/searchengine/filterParser.test.d.ts
packages/lib/services/searchengine/filterParser.test.js
packages/lib/services/searchengine/filterParser.test.js.map
packages/lib/services/searchengine/gotoAnythingStyleQuery.d.ts
packages/lib/services/searchengine/gotoAnythingStyleQuery.js
packages/lib/services/searchengine/gotoAnythingStyleQuery.js.map
packages/lib/services/searchengine/queryBuilder.d.ts
packages/lib/services/searchengine/queryBuilder.js
packages/lib/services/searchengine/queryBuilder.js.map

View File

@@ -0,0 +1,2 @@
packages/app-clipper/popup/
packages/app-cli/tests/support/plugins/

View File

@@ -0,0 +1,22 @@
{
"rules": {
"prefer-absolute-version-dependencies": ["error",
{
"exceptions": [
"@joplin/lib",
"@joplin/renderer",
"@joplin/pdf-viewer",
"@joplin/fork-htmlparser2",
"@joplin/fork-sax",
"@joplin/fork-uslug",
"@joplin/htmlpack",
"@joplin/turndown",
"@joplin/turndown-plugin-gfm",
"@joplin/tools",
"@joplin/react-native-saf-x"
]
}
]
}
}

View File

@@ -1,33 +0,0 @@
diff --git a/android/build.gradle b/android/build.gradle
index 1ae415331855895ed6c65d72e155ff91d02b4b39..a7548535a7fb08800fb4731c1d8e36efa8afa1ae 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -22,7 +22,7 @@ def safeExtGet(prop, fallback) {
}
apply plugin: 'com.android.library'
-apply plugin: 'maven'
+apply plugin: 'maven-publish'
buildscript {
// The Android Gradle plugin is only required when opening the android folder stand-alone.
@@ -41,7 +41,7 @@ buildscript {
}
apply plugin: 'com.android.library'
-apply plugin: 'maven'
+apply plugin: 'maven-publish'
android {
compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
@@ -140,10 +140,5 @@ afterEvaluate { project ->
task installArchives(type: Upload) {
configuration = configurations.archives
- repositories.mavenDeployer {
- // Deploy to react-native-event-bridge/maven, ready to publish to npm
- repository url: "file://${projectDir}/../android/maven"
- configureReactNativePom pom
- }
}
}

View File

@@ -216,7 +216,7 @@ then
Name=Joplin
Comment=Joplin for Desktop
Exec=${HOME}/.joplin/Joplin.AppImage ${SANDBOXPARAM} %u
Icon=@joplinapp-desktop
Icon=joplin
StartupWMClass=Joplin
Type=Application
Categories=Office;

View File

@@ -13,7 +13,5 @@ module.exports = {
'*.{js,jsx,ts,tsx}': [
'yarn run linter-precommit',
'yarn run checkLibPaths',
// 'yarn run spellcheck',
// 'git add',
],
};

View File

@@ -33,6 +33,7 @@
"linter-precommit": "eslint --resolve-plugins-relative-to . --fix --ext .js --ext .jsx --ext .ts --ext .tsx",
"linter": "eslint --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
"linter-interactive": "eslint-interactive --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
"packageJsonLint": "npmPkgJsonLint --configFile .npmpackagejsonlintrc.json --quiet .",
"postinstall": "gulp build",
"publishAll": "git pull && yarn run buildParallel && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
"releaseAndroid": "PATH=\"/usr/local/opt/openjdk@11/bin:$PATH\" node packages/tools/release-android.js",
@@ -59,13 +60,13 @@
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
"pre-commit": "lint-staged && yarn run packageJsonLint"
}
},
"devDependencies": {
"@seiyab/eslint-plugin-react-hooks": "4.5.1-beta.0",
"@typescript-eslint/eslint-plugin": "5.47.0",
"@typescript-eslint/parser": "5.47.0",
"@typescript-eslint/eslint-plugin": "5.47.1",
"@typescript-eslint/parser": "5.47.1",
"cspell": "5.21.2",
"eslint": "8.30.0",
"eslint-interactive": "10.3.0",
@@ -79,6 +80,7 @@
"lerna": "3.22.1",
"lint-staged": "13.1.0",
"madge": "5.0.1",
"npm-package-json-lint": "6.4.0",
"typedoc": "0.17.8",
"typescript": "4.9.4"
},
@@ -88,8 +90,5 @@
"node-gyp": "9.3.1",
"nodemon": "2.0.20"
},
"packageManager": "yarn@3.3.1",
"resolutions": {
"joplin-rn-alarm-notification@1.0.5": "patch:joplin-rn-alarm-notification@npm:1.0.5#.yarn/patches/joplin-rn-alarm-notification-npm-1.0.5-662e871c03"
}
"packageManager": "yarn@3.3.1"
}

View File

@@ -42,7 +42,7 @@
"dependencies": {
"@joplin/lib": "~2.10",
"@joplin/renderer": "~2.10",
"aws-sdk": "2.1279.0",
"aws-sdk": "2.1285.0",
"chalk": "4.1.2",
"compare-version": "0.1.2",
"fs-extra": "11.1.0",
@@ -55,7 +55,7 @@
"proper-lockfile": "4.1.2",
"read-chunk": "2.1.0",
"server-destroy": "1.0.1",
"sharp": "0.31.2",
"sharp": "0.31.3",
"sprintf-js": "1.1.2",
"sqlite3": "5.1.4",
"string-padding": "1.0.2",
@@ -71,7 +71,7 @@
"@joplin/tools": "~2.10",
"@types/fs-extra": "9.0.13",
"@types/jest": "29.2.4",
"@types/node": "18.11.17",
"@types/node": "18.11.18",
"gulp": "4.0.2",
"jest": "29.3.1",
"temp": "0.9.4",

View File

@@ -0,0 +1,11 @@
<en-note>
<div>
<p>In Evernote a checklist is not the same as a list with checkboxes.</p>
<ul style="--en-todo:true;">
<li style="--en-checked:false;"><div>One</div></li>
<li style="--en-checked:true;"><div>Two</div>
</li><li style="--en-checked:false;"><div>Three</div></li>
</ul>
</div>
</en-note>

View File

@@ -0,0 +1,19 @@
<en-note>
<div>
<p>In Evernote a checklist is not the same as a list with checkboxes.</p>
<ul style="--en-todo:true;">
<li style="--en-checked:false;">
<input type="checkbox" onclick="return false;">
<div>One</div>
</li>
<li style="--en-checked:true;">
<input checked="checked" type="checkbox" onclick="return false;">
<div>Two</div>
</li>
<li style="--en-checked:false;">
<input type="checkbox" onclick="return false;">
<div>Three</div>
</li>
</ul>
</div>
</en-note>

View File

@@ -0,0 +1,7 @@
<ul style="--en-todo:true;">
<li style="--en-checked:false;"><div>One</div></li>
<li style="--en-checked:true;"><div>Two</div>
</li><li style="--en-checked:false;"><div>Three</div></li>
</ul>
<p>More text</p>

View File

@@ -0,0 +1,7 @@
- [ ] One
- [X] Two
- [ ] Three
More text

View File

@@ -78,6 +78,12 @@ export default class InteropServiceHelper {
shim.setTimeout(async () => {
if (target === 'pdf') {
try {
// The below line "opens" all <details> tags
// before printing. This assures that the
// contents of the tag are visible in printed
// pdfs.
// https://github.com/laurent22/joplin/issues/6254.
win.webContents.executeJavaScript('document.querySelectorAll(\'details\').forEach(el=>el.setAttribute(\'open\',\'\'))');
const data = await win.webContents.printToPDF(options);
resolve(data);
} catch (error) {

View File

@@ -1,5 +1,8 @@
import { useEffect, useRef, useState } from 'react';
import shim from '@joplin/lib/shim';
import Logger from '@joplin/lib/Logger';
const logger = Logger.create('useEditorSearch');
export default function useEditorSearch(CodeMirror: any) {
@@ -23,7 +26,16 @@ export default function useEditorSearch(CodeMirror: any) {
function clearOverlay(cm: any) {
if (overlay) cm.removeOverlay(overlay);
if (scrollbarMarks) scrollbarMarks.clear();
if (scrollbarMarks) {
try {
scrollbarMarks.clear();
} catch (error) {
// This can randomly crash the app so just print a warning since
// it's probably not critical.
// https://github.com/laurent22/joplin/issues/7499
logger.error('useEditorSearch: Could not clear scrollbar marks:', error);
}
}
if (overlayTimeout) shim.clearTimeout(overlayTimeout);

View File

@@ -94,7 +94,7 @@ function NoteEditor(props: NoteEditorProps) {
showLocalSearch,
setShowLocalSearch,
searchMarkers: localSearchMarkerOptions,
} = useNoteSearchBar();
} = useNoteSearchBar({ noteSearchBarRef });
// If the note has been modified in another editor, wait for it to be saved
// before loading it in this editor.

View File

@@ -12,8 +12,11 @@ export const runtime = (comp: any): CommandRuntime => {
if (comp.editorRef.current && comp.editorRef.current.supportsCommand('search')) {
comp.editorRef.current.execCommand({ name: 'search' });
} else {
comp.setShowLocalSearch(true);
if (comp.noteSearchBarRef.current) comp.noteSearchBarRef.current.wrappedInstance.focus();
if (comp.noteSearchBarRef.current) {
comp.noteSearchBarRef.current.focus();
} else {
comp.setShowLocalSearch(true);
}
}
},
enabledCondition: 'oneNoteSelected',

View File

@@ -1,4 +1,4 @@
import { useState, useCallback } from 'react';
import { useState, useCallback, MutableRefObject, useEffect } from 'react';
import Logger from '@joplin/lib/Logger';
import { SearchMarkers } from './useSearchMarkers';
const CommandService = require('@joplin/lib/services/CommandService').default;
@@ -25,10 +25,21 @@ function defaultLocalSearch(): LocalSearch {
};
}
export default function useNoteSearchBar() {
export interface UseNoteSearchBarProps {
noteSearchBarRef: MutableRefObject<any>;
}
export default function useNoteSearchBar({ noteSearchBarRef }: UseNoteSearchBarProps) {
const [showLocalSearch, setShowLocalSearch] = useState(false);
const [localSearch, setLocalSearch] = useState<LocalSearch>(defaultLocalSearch());
useEffect(() => {
if (showLocalSearch && noteSearchBarRef.current) {
noteSearchBarRef.current.focus();
}
}, [showLocalSearch, noteSearchBarRef]);
const onChange = useCallback((query: string) => {
// A query that's too long would make CodeMirror throw an exception
// which would crash the app.

View File

@@ -11,6 +11,7 @@ class NoteSearchBar extends React.Component {
this.previousButton_click = this.previousButton_click.bind(this);
this.nextButton_click = this.nextButton_click.bind(this);
this.closeButton_click = this.closeButton_click.bind(this);
this.focus = this.focus.bind(this);
this.backgroundColor = undefined;
}

View File

@@ -64,28 +64,31 @@ export default function PdfViewer(props: Props) {
menu.popup(bridge().window());
}, [props.dispatch]);
useEffect(() => {
const onMessage_ = async (event: any) =>{
if (!event.data || !event.data.name) {
return;
}
const onMessage_ = useCallback(async (event: any) => {
if (!event.data || !event.data.name) {
return;
}
if (event.data.name === 'close') {
onClose();
} else if (event.data.name === 'externalViewer') {
await openExternalViewer();
} else if (event.data.name === 'textSelected') {
await textSelected(event.data.text);
} else {
console.error('Unknown event received', event.data.name);
}
};
if (event.data.name === 'close') {
onClose();
} else if (event.data.name === 'externalViewer') {
await openExternalViewer();
} else if (event.data.name === 'textSelected') {
await textSelected(event.data.text);
} else {
console.error('Unknown event received', event.data.name);
}
}, [openExternalViewer, textSelected, onClose]);
useEffect(() => {
const iframe = iframeRef.current;
iframe.contentWindow.addEventListener('message', onMessage_);
return () => {
iframe.contentWindow.removeEventListener('message', onMessage_);
// iframe.contentWindow is not always defined
// https://github.com/laurent22/joplin/issues/7528
if (iframe.contentWindow) iframe.contentWindow.removeEventListener('message', onMessage_);
};
}, [onClose, openExternalViewer, textSelected]);
}, [onMessage_]);
const theme = themeStyle(props.themeId);

View File

@@ -224,12 +224,16 @@ export default class PromptDialog extends React.Component<Props, any> {
const onKeyDown = (event: any) => {
if (event.key === 'Enter') {
if (this.props.inputType !== 'tags' && this.props.inputType !== 'dropdown') {
onClose(true);
} else if (this.answerInput_.current && !this.answerInput_.current.state.menuIsOpen) {
// The menu will be open if the user is selecting a new item
if (this.props.inputType === 'tags' || this.props.inputType === 'dropdown') {
// Do nothing
} else {
onClose(true);
}
// } else if (this.answerInput_.current && !this.answerInput_.current.state.menuIsOpen) {
// // The menu will be open if the user is selecting a new item
// onClose(true);
// }
} else if (event.key === 'Escape') {
onClose(false);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/app-desktop",
"version": "2.10.2",
"version": "2.10.3",
"description": "Joplin for Desktop",
"main": "main.js",
"private": true,
@@ -95,7 +95,7 @@
"icon": "../../Assets/LinuxIcons",
"category": "Office",
"desktop": {
"Icon": "@joplinapp-desktop",
"Icon": "joplin",
"MimeType": "x-scheme-handler/joplin;"
},
"target": "AppImage"
@@ -109,7 +109,7 @@
"@joplin/tools": "~2.10",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.2.4",
"@types/node": "18.11.17",
"@types/node": "18.11.18",
"@types/react": "16.14.34",
"@types/react-redux": "7.1.24",
"@types/styled-components": "5.1.26",

View File

@@ -8,6 +8,7 @@ const { connect } = require('react-redux');
const { _ } = require('@joplin/lib/locale');
const { themeStyle } = require('@joplin/lib/theme');
import SearchEngine from '@joplin/lib/services/searchengine/SearchEngine';
import gotoAnythingStyleQuery from '@joplin/lib/services/searchengine/gotoAnythingStyleQuery';
import BaseModel from '@joplin/lib/BaseModel';
import Tag from '@joplin/lib/models/Tag';
import Folder from '@joplin/lib/models/Folder';
@@ -242,19 +243,6 @@ class Dialog extends React.PureComponent<Props, State> {
}, 100);
}
makeSearchQuery(query: string) {
const output = [];
const splitted = query.split(' ');
for (let i = 0; i < splitted.length; i++) {
const s = splitted[i].trim();
if (!s) continue;
output.push(`${s}*`);
}
return output.join(' ');
}
async keywords(searchQuery: string) {
const parsedQuery = await SearchEngine.instance().parseQuery(searchQuery);
return SearchEngine.instance().allParsedQueryTerms(parsedQuery);
@@ -321,7 +309,7 @@ class Dialog extends React.PureComponent<Props, State> {
}
} else { // Note TITLE or BODY
listType = BaseModel.TYPE_NOTE;
searchQuery = this.makeSearchQuery(this.state.query);
searchQuery = gotoAnythingStyleQuery(this.state.query);
results = await SearchEngine.instance().search(searchQuery);
resultsInBody = !!results.find((row: any) => row.fields.includes('body'));

View File

@@ -56,8 +56,9 @@ buck-out/
# Bundle artifact
*.jsbundle
# CocoaPods
# Ruby / CocoaPods
/ios/Pods/
/vendor/bundle/
# Custom
lib/csstojs/

View File

@@ -1,100 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
rexml
activesupport (6.1.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
claide (1.1.0)
cocoapods (1.11.3)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.11.3)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.4.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
fourflusher (>= 2.3.0, < 3.0)
gh_inspector (~> 1.0)
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 1.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.11.3)
activesupport (>= 5.0, < 7)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
netrc (~> 0.11)
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.6.3)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
cocoapods-trunk (1.6.0)
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.2.0)
colored2 (3.1.2)
concurrent-ruby (1.1.10)
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
ffi (1.15.5)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
httpclient (2.8.3)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
json (2.6.2)
minitest (5.16.3)
molinillo (0.8.0)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
public_suffix (4.0.7)
rexml (3.2.5)
ruby-macho (2.5.1)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
zeitwerk (2.6.6)
PLATFORMS
ruby
DEPENDENCIES
cocoapods (~> 1.11, >= 1.11.2)
RUBY VERSION
ruby 2.7.6p219
BUNDLED WITH
2.2.27

View File

@@ -1,6 +1,7 @@
apply plugin: "com.android.application"
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
@@ -124,9 +125,12 @@ def jscFlavor = 'org.webkit:android-jsc-intl:+'
def enableHermes = project.ext.react.get("enableHermes", false);
/**
* Architectures to build native code for in debug.
* Architectures to build native code for.
*/
def nativeArchitectures = project.getProperties().get("reactNativeDebugArchitectures")
def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
android {
compileSdkVersion rootProject.ext.compileSdkVersion
@@ -146,24 +150,97 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097676
versionName "2.10.0"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
versionCode 2097678
versionName "2.10.2"
// ndk {
// abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
// }
// https://github.com/react-native-community/react-native-camera/issues/2138
missingDimensionStrategy 'react-native-camera', 'general'
// Needed to fix: The number of method references in a .dex file cannot exceed 64K
multiDexEnabled true
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
ndkBuild {
arguments "APP_PLATFORM=android-21",
"APP_STL=c++_shared",
"NDK_TOOLCHAIN_VERSION=clang",
"GENERATED_SRC_DIR=$buildDir/generated/source",
"PROJECT_BUILD_DIR=$buildDir",
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
cppFlags "-std=c++17"
// Make sure this target name is the same you specify inside the
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
targets "joplin_appmodules"
// Fix for windows limit on number of character in file paths and in command lines
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
arguments "NDK_APP_SHORT_COMMANDS=true"
}
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
}
}
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
ndkBuild {
path "$projectDir/src/main/jni/Android.mk"
}
}
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 configureNdkBuild* tasks and the preBuild tasks.
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
configureNdkBuildRelease.dependsOn(preReleaseBuild)
configureNdkBuildDebug.dependsOn(preDebugBuild)
reactNativeArchitectures().each { architecture ->
tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
dependsOn("preDebugBuild")
}
tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
dependsOn("preReleaseBuild")
}
}
}
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
// include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
include (*reactNativeArchitectures())
}
}
signingConfigs {
@@ -185,11 +262,6 @@ android {
buildTypes {
debug {
signingConfig signingConfigs.debug
if (nativeArchitectures) {
ndk {
abiFilters nativeArchitectures.split(',')
}
}
}
release {
// Caution! In production, you need to generate your own keystore file.
@@ -235,6 +307,7 @@ dependencies {
}
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
@@ -265,6 +338,18 @@ dependencies {
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")
}
}
}
// 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) {
@@ -274,3 +359,11 @@ task copyDownloadableDepsToLibs(type: Copy) {
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"
}

View File

@@ -8,6 +8,6 @@
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
</application>
</manifest>

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
@@ -19,6 +19,7 @@ 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;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
@@ -51,7 +52,7 @@ public class ReactNativeFlipper {
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
new ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);

View File

@@ -70,7 +70,8 @@
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -85,7 +86,8 @@
android:label="@string/app_name"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />

View File

@@ -1,6 +1,8 @@
package net.cozic.joplin;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
public class MainActivity extends ReactActivity {
@@ -12,4 +14,25 @@ public class MainActivity extends ReactActivity {
protected String getMainComponentName() {
return "Joplin";
}
/**
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
* you can specify the rendered you wish to use (Fabric or the older renderer).
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new MainActivityDelegate(this, getMainComponentName());
}
public static class MainActivityDelegate extends ReactActivityDelegate {
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
super(activity, mainComponentName);
}
@Override
protected ReactRootView createRootView() {
ReactRootView reactRootView = new ReactRootView(getContext());
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
return reactRootView;
}
}
}

View File

@@ -12,7 +12,9 @@ import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import net.cozic.joplin.newarchitecture.MainApplicationReactNativeHost;
import net.cozic.joplin.share.SharePackage;
import net.cozic.joplin.ssl.SslPackage;
@@ -55,15 +57,25 @@ public class MainApplication extends Application implements ReactApplication {
}
};
private final ReactNativeHost mNewArchitectureNativeHost =
new MainApplicationReactNativeHost(this);
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
return mNewArchitectureNativeHost;
} else {
return mReactNativeHost;
}
}
@Override
public void onCreate() {
super.onCreate();
// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
// To try to fix the error "Row too big to fit into CursorWindow"
// https://github.com/andpor/react-native-sqlite-storage/issues/364#issuecomment-526423153
// https://github.com/laurent22/joplin/issues/1767#issuecomment-515617991

View File

@@ -0,0 +1,116 @@
package net.cozic.joplin.newarchitecture;
import android.app.Application;
import androidx.annotation.NonNull;
import com.facebook.react.PackageList;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.JSIModulePackage;
import com.facebook.react.bridge.JSIModuleProvider;
import com.facebook.react.bridge.JSIModuleSpec;
import com.facebook.react.bridge.JSIModuleType;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.react.fabric.CoreComponentsRegistry;
import com.facebook.react.fabric.EmptyReactNativeConfig;
import com.facebook.react.fabric.FabricJSIModuleProvider;
import com.facebook.react.uimanager.ViewManagerRegistry;
import net.cozic.joplin.BuildConfig;
import net.cozic.joplin.newarchitecture.components.MainComponentsRegistry;
import net.cozic.joplin.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
* TurboModule delegates and the Fabric Renderer.
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationReactNativeHost extends ReactNativeHost {
public MainApplicationReactNativeHost(Application application) {
super(application);
}
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
// packages.add(new TurboReactPackage() { ... });
// If you have custom Fabric Components, their ViewManagers should also be loaded here
// inside a ReactPackage.
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@NonNull
@Override
protected ReactPackageTurboModuleManagerDelegate.Builder
getReactPackageTurboModuleManagerDelegateBuilder() {
// Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
// for the new architecture and to use TurboModules correctly.
return new MainApplicationTurboModuleManagerDelegate.Builder();
}
@Override
protected JSIModulePackage getJSIModulePackage() {
return new JSIModulePackage() {
@Override
public List<JSIModuleSpec> getJSIModules(
final ReactApplicationContext reactApplicationContext,
final JavaScriptContextHolder jsContext) {
final List<JSIModuleSpec> specs = new ArrayList<>();
// Here we provide a new JSIModuleSpec that will be responsible of providing the
// custom Fabric Components.
specs.add(
new JSIModuleSpec() {
@Override
public JSIModuleType getJSIModuleType() {
return JSIModuleType.UIManager;
}
@Override
public JSIModuleProvider<UIManager> getJSIModuleProvider() {
final ComponentFactory componentFactory = new ComponentFactory();
CoreComponentsRegistry.register(componentFactory);
// Here we register a Components Registry.
// The one that is generated with the template contains no components
// and just provides you the one from React Native core.
MainComponentsRegistry.register(componentFactory);
final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
ViewManagerRegistry viewManagerRegistry =
new ViewManagerRegistry(
reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
return new FabricJSIModuleProvider(
reactApplicationContext,
componentFactory,
new EmptyReactNativeConfig(),
viewManagerRegistry);
}
});
return specs;
}
};
}
}

View File

@@ -0,0 +1,36 @@
package net.cozic.joplin.newarchitecture.components;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.soloader.SoLoader;
/**
* Class responsible to load the custom Fabric Components. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
@DoNotStrip
public class MainComponentsRegistry {
static {
SoLoader.loadLibrary("fabricjni");
}
@DoNotStrip private final HybridData mHybridData;
@DoNotStrip
private native HybridData initHybrid(ComponentFactory componentFactory);
@DoNotStrip
private MainComponentsRegistry(ComponentFactory componentFactory) {
mHybridData = initHybrid(componentFactory);
}
@DoNotStrip
public static MainComponentsRegistry register(ComponentFactory componentFactory) {
return new MainComponentsRegistry(componentFactory);
}
}

View File

@@ -0,0 +1,48 @@
package net.cozic.joplin.newarchitecture.modules;
import com.facebook.jni.HybridData;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.soloader.SoLoader;
import java.util.List;
/**
* Class responsible to load the TurboModules. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationTurboModuleManagerDelegate
extends ReactPackageTurboModuleManagerDelegate {
private static volatile boolean sIsSoLibraryLoaded;
protected MainApplicationTurboModuleManagerDelegate(
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
super(reactApplicationContext, packages);
}
protected native HybridData initHybrid();
native boolean canCreateTurboModule(String moduleName);
public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
protected MainApplicationTurboModuleManagerDelegate build(
ReactApplicationContext context, List<ReactPackage> packages) {
return new MainApplicationTurboModuleManagerDelegate(context, packages);
}
}
@Override
protected synchronized void maybeLoadOtherSoLibraries() {
if (!sIsSoLibraryLoaded) {
// If you change the name of your application .so file in the Android.mk file,
// make sure you update the name here as well.
SoLoader.loadLibrary("joplin_appmodules");
sIsSoLibraryLoaded = true;
}
}
}

View File

@@ -0,0 +1,49 @@
THIS_DIR := $(call my-dir)
include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
# If you wish to add a custom TurboModule or Fabric component in your app you
# will have to include the following autogenerated makefile.
# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
include $(CLEAR_VARS)
LOCAL_PATH := $(THIS_DIR)
# You can customize the name of your application .so file here.
LOCAL_MODULE := joplin_appmodules
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
# If you wish to add a custom TurboModule or Fabric component in your app you
# will have to uncomment those lines to include the generated source
# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)
#
# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
# Here you should add any native library you wish to depend on.
LOCAL_SHARED_LIBRARIES := \
libfabricjni \
libfbjni \
libfolly_futures \
libfolly_json \
libglog \
libjsi \
libreact_codegen_rncore \
libreact_debug \
libreact_nativemodule_core \
libreact_render_componentregistry \
libreact_render_core \
libreact_render_debug \
libreact_render_graphics \
librrc_view \
libruntimeexecutor \
libturbomodulejsijni \
libyoga
LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall
include $(BUILD_SHARED_LIBRARY)

View File

@@ -0,0 +1,24 @@
#include "MainApplicationModuleProvider.h"
#include <rncore.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string moduleName,
const JavaTurboModule::InitParams &params) {
// Here you can provide your own module provider for TurboModules coming from
// either your application or from external libraries. The approach to follow
// is similar to the following (for a library called `samplelibrary`:
//
// auto module = samplelibrary_ModuleProvider(moduleName, params);
// if (module != nullptr) {
// return module;
// }
// return rncore_ModuleProvider(moduleName, params);
return rncore_ModuleProvider(moduleName, params);
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,16 @@
#pragma once
#include <memory>
#include <string>
#include <ReactCommon/JavaTurboModule.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string moduleName,
const JavaTurboModule::InitParams &params);
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,45 @@
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainApplicationModuleProvider.h"
namespace facebook {
namespace react {
jni::local_ref<MainApplicationTurboModuleManagerDelegate::jhybriddata>
MainApplicationTurboModuleManagerDelegate::initHybrid(
jni::alias_ref<jhybridobject>) {
return makeCxxInstance();
}
void MainApplicationTurboModuleManagerDelegate::registerNatives() {
registerHybrid({
makeNativeMethod(
"initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
makeNativeMethod(
"canCreateTurboModule",
MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
});
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string name,
const std::shared_ptr<CallInvoker> jsInvoker) {
// Not implemented yet: provide pure-C++ NativeModules here.
return nullptr;
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string name,
const JavaTurboModule::InitParams &params) {
return MainApplicationModuleProvider(name, params);
}
bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
std::string name) {
return getTurboModule(name, nullptr) != nullptr ||
getTurboModule(name, {.moduleName = name}) != nullptr;
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,38 @@
#include <memory>
#include <string>
#include <ReactCommon/TurboModuleManagerDelegate.h>
#include <fbjni/fbjni.h>
namespace facebook {
namespace react {
class MainApplicationTurboModuleManagerDelegate
: public jni::HybridClass<
MainApplicationTurboModuleManagerDelegate,
TurboModuleManagerDelegate> {
public:
// Adapt it to the package you used for your Java class.
static constexpr auto kJavaDescriptor =
"Lnet/cozic/joplin/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);
static void registerNatives();
std::shared_ptr<TurboModule> getTurboModule(
const std::string name,
const std::shared_ptr<CallInvoker> jsInvoker) override;
std::shared_ptr<TurboModule> getTurboModule(
const std::string name,
const JavaTurboModule::InitParams &params) override;
/**
* Test-only method. Allows user to verify whether a TurboModule can be
* created by instances of this class.
*/
bool canCreateTurboModule(std::string name);
};
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,61 @@
#include "MainComponentsRegistry.h"
#include <CoreComponentsRegistry.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/rncore/ComponentDescriptors.h>
namespace facebook {
namespace react {
MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
MainComponentsRegistry::sharedProviderRegistry() {
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
// Custom Fabric Components go here. You can register custom
// components coming from your App or from 3rd party libraries here.
//
// providerRegistry->add(concreteComponentDescriptorProvider<
// AocViewerComponentDescriptor>());
return providerRegistry;
}
jni::local_ref<MainComponentsRegistry::jhybriddata>
MainComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate) {
auto instance = makeCxxInstance(delegate);
auto buildRegistryFunction =
[](EventDispatcher::Weak const &eventDispatcher,
ContextContainer::Shared const &contextContainer)
-> ComponentDescriptorRegistry::Shared {
auto registry = MainComponentsRegistry::sharedProviderRegistry()
->createComponentDescriptorRegistry(
{eventDispatcher, contextContainer});
auto mutableRegistry =
std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
mutableRegistry->setFallbackComponentDescriptor(
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
ComponentDescriptorParameters{
eventDispatcher, contextContainer, nullptr}));
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void MainComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,32 @@
#pragma once
#include <ComponentFactory.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
namespace facebook {
namespace react {
class MainComponentsRegistry
: public facebook::jni::HybridClass<MainComponentsRegistry> {
public:
// Adapt it to the package you used for your Java class.
constexpr static auto kJavaDescriptor =
"Lnet/cozic/joplin/newarchitecture/components/MainComponentsRegistry;";
static void registerNatives();
MainComponentsRegistry(ComponentFactory *delegate);
private:
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,11 @@
#include <fbjni/fbjni.h>
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainComponentsRegistry.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
facebook::react::MainApplicationTurboModuleManagerDelegate::
registerNatives();
facebook::react::MainComponentsRegistry::registerNatives();
});
}

View File

@@ -2,18 +2,28 @@
buildscript {
ext {
buildToolsVersion = "30.0.2"
buildToolsVersion = "31.0.0"
minSdkVersion = 21
compileSdkVersion = 30
targetSdkVersion = 30
ndkVersion = "21.4.7075529"
compileSdkVersion = 31
targetSdkVersion = 31
if (System.properties['os.arch'] == "aarch64") {
// For M1 Users we need to use the NDK 24 which added support for aarch64
ndkVersion = "24.0.8215888"
} else {
// Otherwise we default to the side-by-side NDK version from AGP.
ndkVersion = "21.4.7075529"
}
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:4.2.2")
classpath("com.android.tools.build:gradle:7.0.4")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:4.1.2")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

View File

@@ -9,9 +9,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# DDefault value: -Xmx1024m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
@@ -26,7 +25,18 @@ android.useAndroidX=true
android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.99.0
FLIPPER_VERSION=0.125.0
# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# Use this property to enable support to the new architecture.
# This will allow you to use TurboModules and the Fabric render in
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false
# To fix this error:
#

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,78 +17,113 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -105,79 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
exec "$JAVACMD" "$@"
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@@ -1,3 +1,8 @@
rootProject.name = 'Joplin'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
includeBuild('../node_modules/react-native-gradle-plugin')
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
include(":ReactAndroid")
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
}

View File

@@ -145,6 +145,16 @@ export default function useSource(noteBody: string, noteMarkupLanguage: number,
font: -apple-system-body;
}
}
/*
iOS seems to increase inertial scrolling friction when the WebView body/root elements
scroll. Scroll the main container instead.
*/
body > #rendered-md {
width: 100vw;
height: 100vh;
overflow: auto;
}
`;
html =

View File

@@ -7,6 +7,7 @@ import { initCodeMirror } from './CodeMirror';
import { themeStyle } from '@joplin/lib/theme';
import Setting from '@joplin/lib/models/Setting';
import { forceParsing } from '@codemirror/language';
import loadLangauges from './testUtil/loadLanguages';
const createEditorSettings = (themeId: number) => {
@@ -27,6 +28,7 @@ describe('CodeMirror', () => {
const initialText = `${headerLineText}\nThis is a test.`;
const editorSettings = createEditorSettings(Setting.THEME_LIGHT);
await loadLangauges();
const editor = initCodeMirror(document.body, initialText, editorSettings);
// Force the generation of the syntax tree now.

View File

@@ -309,6 +309,7 @@ export function initCodeMirror(
EditorView.lineWrapping,
EditorView.contentAttributes.of({
autocapitalize: 'sentence',
autocorrect: settings.spellcheckEnabled ? 'true' : 'false',
spellcheck: settings.spellcheckEnabled ? 'true' : 'false',
}),
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {

View File

@@ -18,24 +18,26 @@ const regionStopDecoration = Decoration.line({
attributes: { class: 'cm-regionLastLine' },
});
const noSpellCheckAttrs = { spellcheck: 'false', autocorrect: 'false' };
const codeBlockDecoration = Decoration.line({
attributes: { class: 'cm-codeBlock', spellcheck: 'false' },
attributes: { class: 'cm-codeBlock', ...noSpellCheckAttrs },
});
const inlineCodeDecoration = Decoration.mark({
attributes: { class: 'cm-inlineCode', spellcheck: 'false' },
attributes: { class: 'cm-inlineCode', ...noSpellCheckAttrs },
});
const mathBlockDecoration = Decoration.line({
attributes: { class: 'cm-mathBlock', spellcheck: 'false' },
attributes: { class: 'cm-mathBlock', ...noSpellCheckAttrs },
});
const inlineMathDecoration = Decoration.mark({
attributes: { class: 'cm-inlineMath', spellcheck: 'false' },
attributes: { class: 'cm-inlineMath', ...noSpellCheckAttrs },
});
const urlDecoration = Decoration.mark({
attributes: { class: 'cm-url', spellcheck: 'false' },
attributes: { class: 'cm-url', ...noSpellCheckAttrs },
});
const blockQuoteDecoration = Decoration.line({

View File

@@ -10,10 +10,11 @@ describe('markdownCommands.bulletedVsChecklist', () => {
const bulletedListPart = '- Test\n- This is a test.\n- 3\n- 4\n- 5';
const checklistPart = '- [ ] This is a checklist\n- [ ] with multiple items.\n- [ ] ☑';
const initialDocText = `${bulletedListPart}\n\n${checklistPart}`;
const expectedTags = ['BulletList', 'Task'];
it('should remove a checklist following a bulleted list without modifying the bulleted list', () => {
const editor = createEditor(
initialDocText, EditorSelection.cursor(bulletedListPart.length + 5)
it('should remove a checklist following a bulleted list without modifying the bulleted list', async () => {
const editor = await createEditor(
initialDocText, EditorSelection.cursor(bulletedListPart.length + 5), expectedTags
);
toggleList(ListType.CheckList)(editor);
@@ -22,9 +23,9 @@ describe('markdownCommands.bulletedVsChecklist', () => {
);
});
it('should remove an unordered list following a checklist without modifying the checklist', () => {
const editor = createEditor(
initialDocText, EditorSelection.cursor(bulletedListPart.length - 5)
it('should remove an unordered list following a checklist without modifying the checklist', async () => {
const editor = await createEditor(
initialDocText, EditorSelection.cursor(bulletedListPart.length - 5), expectedTags
);
toggleList(ListType.UnorderedList)(editor);
@@ -33,9 +34,9 @@ describe('markdownCommands.bulletedVsChecklist', () => {
);
});
it('should replace a selection of unordered and task lists with a correctly-numbered list', () => {
const editor = createEditor(
initialDocText, EditorSelection.range(0, initialDocText.length)
it('should replace a selection of unordered and task lists with a correctly-numbered list', async () => {
const editor = await createEditor(
initialDocText, EditorSelection.range(0, initialDocText.length), expectedTags
);
toggleList(ListType.OrderedList)(editor);

View File

@@ -2,36 +2,18 @@
* @jest-environment jsdom
*/
import { EditorSelection, EditorState, SelectionRange } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { EditorSelection } from '@codemirror/state';
import {
toggleBolded, toggleCode, toggleHeaderLevel, toggleItalicized, toggleMath, updateLink,
} from './markdownCommands';
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
import { markdown } from '@codemirror/lang-markdown';
import { MarkdownMathExtension } from './markdownMathParser';
import { indentUnit } from '@codemirror/language';
// Creates and returns a minimal editor with markdown extensions
const createEditor = (initialText: string, initialSelection: SelectionRange): EditorView => {
return new EditorView({
doc: initialText,
selection: EditorSelection.create([initialSelection]),
extensions: [
markdown({
extensions: [MarkdownMathExtension, GithubFlavoredMarkdownExt],
}),
indentUnit.of('\t'),
EditorState.tabSize.of(4),
],
});
};
import createEditor from './testUtil/createEditor';
import { blockMathTagName } from './markdownMathParser';
describe('markdownCommands', () => {
it('should bold/italicize everything selected', () => {
it('should bold/italicize everything selected', async () => {
const initialDocText = 'Testing...';
const editor = createEditor(
initialDocText, EditorSelection.range(0, initialDocText.length)
const editor = await createEditor(
initialDocText, EditorSelection.range(0, initialDocText.length), []
);
toggleBolded(editor);
@@ -55,10 +37,10 @@ describe('markdownCommands', () => {
expect(editor.state.doc.toString()).toBe('Testing...');
});
it('for a cursor, bolding, then italicizing, should produce a bold-italic region', () => {
it('for a cursor, bolding, then italicizing, should produce a bold-italic region', async () => {
const initialDocText = '';
const editor = createEditor(
initialDocText, EditorSelection.cursor(0)
const editor = await createEditor(
initialDocText, EditorSelection.cursor(0), []
);
toggleBolded(editor);
@@ -73,9 +55,9 @@ describe('markdownCommands', () => {
expect(editor.state.doc.toString()).toBe('***Test*** Test');
});
it('toggling math should both create and navigate out of math regions', () => {
it('toggling math should both create and navigate out of math regions', async () => {
const initialDocText = 'Testing... ';
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
toggleMath(editor);
expect(editor.state.doc.toString()).toBe('Testing... $$');
@@ -89,9 +71,9 @@ describe('markdownCommands', () => {
expect(editor.state.doc.toString()).toBe('Testing... $3 + 3 \\neq 5$...');
});
it('toggling inline code should both create and navigate out of an inline code region', () => {
it('toggling inline code should both create and navigate out of an inline code region', async () => {
const initialDocText = 'Testing...\n\n';
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
toggleCode(editor);
editor.dispatch(editor.state.replaceSelection('f(x) = ...'));
@@ -101,9 +83,9 @@ describe('markdownCommands', () => {
expect(editor.state.doc.toString()).toBe('Testing...\n\n`f(x) = ...` is a function.');
});
it('should set headers to the proper levels (when toggling)', () => {
it('should set headers to the proper levels (when toggling)', async () => {
const initialDocText = 'Testing...\nThis is a test.';
const editor = createEditor(initialDocText, EditorSelection.cursor(3));
const editor = await createEditor(initialDocText, EditorSelection.cursor(3), []);
toggleHeaderLevel(1)(editor);
@@ -127,11 +109,12 @@ describe('markdownCommands', () => {
expect(mainSel.from).toBe('Testing...'.length);
});
it('headers should toggle properly within block quotes', () => {
it('headers should toggle properly within block quotes', async () => {
const initialDocText = 'Testing...\n\n> This is a test.\n> ...a test';
const editor = createEditor(
const editor = await createEditor(
initialDocText,
EditorSelection.cursor('Testing...\n\n> This'.length)
EditorSelection.cursor('Testing...\n\n> This'.length),
['Blockquote']
);
toggleHeaderLevel(1)(editor);
@@ -150,69 +133,48 @@ describe('markdownCommands', () => {
);
});
// We need to disable this test because it randomly fails on CI.
//
// ● markdownCommands › block math should properly toggle within block quotes
//
// expect(received).toEqual(expected) // deep equality
//
// - Expected - 1
// + Received + 3
//
// Testing...
//
// - > This is a test.
// + > $$
// + > This is$$ a test.
// > y = mx + b
// + > $$
// > ...a test
//
// 179 | toggleMath(editor);
// 180 | mainSel = editor.state.selection.main;
// > 181 | expect(editor.state.doc.toString()).toEqual(initialDocText);
// | ^
// 182 | expect(mainSel.from).toBe('Testing...\n\n'.length);
// 183 | expect(mainSel.to).toBe('Testing...\n\n> This is a test.\n> y = mx + b'.length);
// 184 | });
it('block math should be created correctly within block quotes', async () => {
const initialDocText = 'Testing...\n\n> This is a test.\n> y = mx + b\n> ...a test';
const editor = await createEditor(
initialDocText,
EditorSelection.range(
'Testing...\n\n> This'.length,
'Testing...\n\n> This is a test.\n> y = mx + b'.length
),
['Blockquote']
);
toggleMath(editor);
// it('block math should properly toggle within block quotes', () => {
// const initialDocText = 'Testing...\n\n> This is a test.\n> y = mx + b\n> ...a test';
// const editor = createEditor(
// initialDocText,
// EditorSelection.range(
// 'Testing...\n\n> This'.length,
// 'Testing...\n\n> This is a test.\n> y = mx + b'.length
// )
// );
// Toggling math should surround the content in '$$'s
const mainSel = editor.state.selection.main;
expect(editor.state.doc.toString()).toEqual(
'Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$\n> ...a test'
);
expect(mainSel.from).toBe('Testing...\n\n'.length);
expect(mainSel.to).toBe('Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$'.length);
});
// toggleMath(editor);
it('block math should be correctly removed within block quotes', async () => {
const initialDocText = 'Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$\n> ...a test';
// // Toggling math should surround the content in '$$'s
// let mainSel = editor.state.selection.main;
// expect(editor.state.doc.toString()).toEqual(
// 'Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$\n> ...a test'
// );
// expect(mainSel.from).toBe('Testing...\n\n'.length);
// expect(mainSel.to).toBe('Testing...\n\n> $$\n> This is a test.\n> y = mx + b\n> $$'.length);
const editor = await createEditor(
initialDocText,
EditorSelection.cursor('Testing...\n\n> $$\n> This is'.length),
['Blockquote', blockMathTagName]
);
// // Change to a cursor --- test cursor expansion
// editor.dispatch({
// selection: EditorSelection.cursor('Testing...\n\n> $$\n> This is'.length),
// });
// Toggling math should remove the '$$'s
toggleMath(editor);
const mainSel = editor.state.selection.main;
expect(editor.state.doc.toString()).toEqual('Testing...\n\n> This is a test.\n> y = mx + b\n> ...a test');
expect(mainSel.from).toBe('Testing...\n\n'.length);
expect(mainSel.to).toBe('Testing...\n\n> This is a test.\n> y = mx + b'.length);
});
// // Toggling math again should remove the '$$'s
// toggleMath(editor);
// mainSel = editor.state.selection.main;
// expect(editor.state.doc.toString()).toEqual(initialDocText);
// expect(mainSel.from).toBe('Testing...\n\n'.length);
// expect(mainSel.to).toBe('Testing...\n\n> This is a test.\n> y = mx + b'.length);
// });
it('updateLink should replace link titles and isolate URLs if no title is given', () => {
it('updateLink should replace link titles and isolate URLs if no title is given', async () => {
const initialDocText = '[foo](http://example.com/)';
const editor = createEditor(initialDocText, EditorSelection.cursor('[f'.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor('[f'.length), ['Link']);
updateLink('bar', 'https://example.com/')(editor);
expect(editor.state.doc.toString()).toBe(
@@ -225,9 +187,9 @@ describe('markdownCommands', () => {
);
});
it('toggling math twice, starting on a line with content, should a math block', () => {
it('toggling math twice, starting on a line with content, should a math block', async () => {
const initialDocText = 'Testing... ';
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
toggleMath(editor);
toggleMath(editor);
@@ -235,9 +197,9 @@ describe('markdownCommands', () => {
expect(editor.state.doc.toString()).toBe('Testing... \n$$\nf(x) = ...\n$$');
});
it('toggling math twice on an empty line should create an empty math block', () => {
it('toggling math twice on an empty line should create an empty math block', async () => {
const initialDocText = 'Testing...\n\n';
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
toggleMath(editor);
toggleMath(editor);
@@ -245,9 +207,9 @@ describe('markdownCommands', () => {
expect(editor.state.doc.toString()).toBe('Testing...\n\n$$\nf(x) = ...\n$$');
});
it('toggling code twice on an empty line should create an empty code block', () => {
it('toggling code twice on an empty line should create an empty code block', async () => {
const initialDocText = 'Testing...\n\n';
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
// Toggling code twice should create a block code region
toggleCode(editor);
@@ -259,9 +221,9 @@ describe('markdownCommands', () => {
expect(editor.state.doc.toString()).toBe('Testing...\n\nf(x) = ...\n');
});
it('toggling math twice inside a block quote should produce an empty math block', () => {
it('toggling math twice inside a block quote should produce an empty math block', async () => {
const initialDocText = '> Testing...> \n> ';
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), ['Blockquote']);
toggleMath(editor);
toggleMath(editor);
@@ -278,9 +240,9 @@ describe('markdownCommands', () => {
expect(sel.to).toBe(editor.state.doc.length);
});
it('toggling inline code should both create and navigate out of an inline code region', () => {
it('toggling inline code should both create and navigate out of an inline code region', async () => {
const initialDocText = 'Testing...\n\n';
const editor = createEditor(initialDocText, EditorSelection.cursor(initialDocText.length));
const editor = await createEditor(initialDocText, EditorSelection.cursor(initialDocText.length), []);
toggleCode(editor);
editor.dispatch(editor.state.replaceSelection('f(x) = ...'));

View File

@@ -10,25 +10,27 @@ import { ListType } from '../types';
import createEditor from './testUtil/createEditor';
describe('markdownCommands.toggleList', () => {
it('should remove the same type of list', () => {
const initialDocText = '- testing\n- this is a test';
it('should remove the same type of list', async () => {
const initialDocText = '- testing\n- this is a `test`\n';
const editor = createEditor(
const editor = await createEditor(
initialDocText,
EditorSelection.cursor(5)
EditorSelection.cursor(5),
['BulletList', 'InlineCode']
);
toggleList(ListType.UnorderedList)(editor);
expect(editor.state.doc.toString()).toBe(
'testing\nthis is a test'
'testing\nthis is a `test`\n'
);
});
it('should insert a numbered list with correct numbering', () => {
it('should insert a numbered list with correct numbering', async () => {
const initialDocText = 'Testing...\nThis is a test\nof list toggling...';
const editor = createEditor(
const editor = await createEditor(
initialDocText,
EditorSelection.cursor('Testing...\nThis is a'.length)
EditorSelection.cursor('Testing...\nThis is a'.length),
[]
);
toggleList(ListType.OrderedList)(editor);
@@ -47,12 +49,13 @@ describe('markdownCommands.toggleList', () => {
);
});
const numberedListText = '- 1\n- 2\n- 3\n- 4\n- 5\n- 6\n- 7';
const unorderedListText = '- 1\n- 2\n- 3\n- 4\n- 5\n- 6\n- 7';
it('should correctly replace an unordered list with a numbered list', () => {
const editor = createEditor(
numberedListText,
EditorSelection.cursor(numberedListText.length)
it('should correctly replace an unordered list with a numbered list', async () => {
const editor = await createEditor(
unorderedListText,
EditorSelection.cursor(unorderedListText.length),
['BulletList']
);
toggleList(ListType.OrderedList)(editor);
@@ -62,10 +65,11 @@ describe('markdownCommands.toggleList', () => {
});
it('should correctly replace an unordered list with a checklist', () => {
const editor = createEditor(
numberedListText,
EditorSelection.cursor(numberedListText.length)
it('should correctly replace an unordered list with a checklist', async () => {
const editor = await createEditor(
unorderedListText,
EditorSelection.cursor(unorderedListText.length),
['BulletList']
);
toggleList(ListType.CheckList)(editor);
@@ -74,13 +78,14 @@ describe('markdownCommands.toggleList', () => {
);
});
it('should properly toggle a sublist of a bulleted list', () => {
it('should properly toggle a sublist of a bulleted list', async () => {
const preSubListText = '# List test\n * This\n * is\n';
const initialDocText = `${preSubListText}\t* a\n\t* test\n * of list toggling`;
const editor = createEditor(
const editor = await createEditor(
initialDocText,
EditorSelection.cursor(preSubListText.length + '\t* a'.length)
EditorSelection.cursor(preSubListText.length + '\t* a'.length),
['BulletList', 'ATXHeading1']
);
// Indentation should be preserved when changing list types
@@ -94,6 +99,17 @@ describe('markdownCommands.toggleList', () => {
expect(editor.state.selection.main.to).toBe(
`${preSubListText}\t1. a\n\t2. test`.length
);
});
it('should not preserve indentation when removing sublists', async () => {
const preSubListText = '# List test\n * This\n * is\n';
const initialDocText = `${preSubListText}\t1. a\n\t2. test\n * of list toggling`;
const editor = await createEditor(
initialDocText,
EditorSelection.range(preSubListText.length, `${preSubListText}\t1. a\n\t2. test`.length),
['ATXHeading1', 'BulletList', 'OrderedList']
);
// Indentation should not be preserved when removing lists
toggleList(ListType.OrderedList)(editor);
@@ -102,51 +118,47 @@ describe('markdownCommands.toggleList', () => {
'# List test\n * This\n * is\na\ntest\n * of list toggling'
);
// The below test:
// `expect(editor.state.doc.toString()).toBe(expectedChecklistPart)`
// randomly fails on CI, so disabling it for now.
// Put the cursor in the middle of the list
editor.dispatch({ selection: EditorSelection.cursor(preSubListText.length) });
// Sublists should be changed
toggleList(ListType.CheckList)(editor);
const expectedChecklistPart =
'# List test\n - [ ] This\n - [ ] is\n - [ ] a\n - [ ] test\n - [ ] of list toggling';
expect(editor.state.doc.toString()).toBe(
expectedChecklistPart
);
// // Put the cursor in the middle of the list
// editor.dispatch({ selection: EditorSelection.cursor(preSubListText.length) });
editor.dispatch({ selection: EditorSelection.cursor(editor.state.doc.length) });
editor.dispatch(editor.state.replaceSelection('\n\n\n'));
// // Sublists should be changed
// toggleList(ListType.CheckList)(editor);
// const expectedChecklistPart =
// '# List test\n - [ ] This\n - [ ] is\n - [ ] a\n - [ ] test\n - [ ] of list toggling';
// expect(editor.state.doc.toString()).toBe(
// expectedChecklistPart
// );
// toggleList should also create a new list if the cursor is on an empty line.
toggleList(ListType.OrderedList)(editor);
editor.dispatch(editor.state.replaceSelection('Test.\n2. Test2\n3. Test3'));
// editor.dispatch({ selection: EditorSelection.cursor(editor.state.doc.length) });
// editor.dispatch(editor.state.replaceSelection('\n\n\n'));
expect(editor.state.doc.toString()).toBe(
`${expectedChecklistPart}\n\n\n1. Test.\n2. Test2\n3. Test3`
);
// // toggleList should also create a new list if the cursor is on an empty line.
// toggleList(ListType.OrderedList)(editor);
// editor.dispatch(editor.state.replaceSelection('Test.\n2. Test2\n3. Test3'));
toggleList(ListType.CheckList)(editor);
expect(editor.state.doc.toString()).toBe(
`${expectedChecklistPart}\n\n\n- [ ] Test.\n- [ ] Test2\n- [ ] Test3`
);
// expect(editor.state.doc.toString()).toBe(
// `${expectedChecklistPart}\n\n\n1. Test.\n2. Test2\n3. Test3`
// );
// toggleList(ListType.CheckList)(editor);
// expect(editor.state.doc.toString()).toBe(
// `${expectedChecklistPart}\n\n\n- [ ] Test.\n- [ ] Test2\n- [ ] Test3`
// );
// // The entire checklist should have been selected (and thus will now be indented)
// increaseIndent(editor);
// expect(editor.state.doc.toString()).toBe(
// `${expectedChecklistPart}\n\n\n\t- [ ] Test.\n\t- [ ] Test2\n\t- [ ] Test3`
// );
// The entire checklist should have been selected (and thus will now be indented)
increaseIndent(editor);
expect(editor.state.doc.toString()).toBe(
`${expectedChecklistPart}\n\n\n\t- [ ] Test.\n\t- [ ] Test2\n\t- [ ] Test3`
);
});
it('should toggle a numbered list without changing its sublists', () => {
it('should toggle a numbered list without changing its sublists', async () => {
const initialDocText = '1. Foo\n2. Bar\n3. Baz\n\t- Test\n\t- of\n\t- sublists\n4. Foo';
const editor = createEditor(
const editor = await createEditor(
initialDocText,
EditorSelection.cursor(0)
EditorSelection.cursor(0),
['OrderedList', 'BulletList']
);
toggleList(ListType.CheckList)(editor);
@@ -155,12 +167,13 @@ describe('markdownCommands.toggleList', () => {
);
});
it('should toggle a sublist without changing the parent list', () => {
it('should toggle a sublist without changing the parent list', async () => {
const initialDocText = '1. This\n2. is\n3. ';
const editor = createEditor(
const editor = await createEditor(
initialDocText,
EditorSelection.cursor(initialDocText.length)
EditorSelection.cursor(initialDocText.length),
['OrderedList']
);
increaseIndent(editor);
@@ -177,11 +190,12 @@ describe('markdownCommands.toggleList', () => {
);
});
it('should toggle lists properly within block quotes', () => {
it('should toggle lists properly within block quotes', async () => {
const preSubListText = '> # List test\n> * This\n> * is\n';
const initialDocText = `${preSubListText}> \t* a\n> \t* test\n> * of list toggling`;
const editor = createEditor(
initialDocText, EditorSelection.cursor(preSubListText.length + 3)
const editor = await createEditor(
initialDocText, EditorSelection.cursor(preSubListText.length + 3),
['BlockQuote', 'BulletList']
);
toggleList(ListType.OrderedList)(editor);

View File

@@ -1,24 +1,17 @@
import { markdown } from '@codemirror/lang-markdown';
/**
* @jest-environment jsdom
*/
import { syntaxTree } from '@codemirror/language';
import { SyntaxNode } from '@lezer/common';
import { EditorState } from '@codemirror/state';
import { blockMathTagName, inlineMathContentTagName, inlineMathTagName, MarkdownMathExtension } from './markdownMathParser';
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
import forceFullParse from './testUtil/forceFullParse';
import { EditorSelection, EditorState } from '@codemirror/state';
import { blockMathTagName, inlineMathContentTagName, inlineMathTagName } from './markdownMathParser';
import createEditor from './testUtil/createEditor';
// Creates an EditorState with math and markdown extensions
const createEditorState = (initialText: string): EditorState => {
const editorState = EditorState.create({
doc: initialText,
extensions: [
markdown({
extensions: [MarkdownMathExtension, GithubFlavoredMarkdownExt],
}),
],
});
forceFullParse(editorState);
return editorState;
const createEditorState = async (initialText: string, expectedTags: string[]): Promise<EditorState> => {
return (await createEditor(initialText, EditorSelection.cursor(0), expectedTags)).state;
};
// Returns a list of all nodes with the given name in the given editor's syntax tree.
@@ -37,9 +30,10 @@ const findNodesWithName = (editor: EditorState, nodeName: string) => {
};
describe('markdownMathParser', () => {
it('should parse inline math that contains space characters, numbers, and symbols', () => {
it('should parse inline math that contains space characters, numbers, and symbols', async () => {
const documentText = '$3 + 3$';
const editor = createEditorState(documentText);
const editor = await createEditorState(documentText, [inlineMathTagName, 'number']);
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
const inlineMathContentNodes = findNodesWithName(editor, inlineMathContentTagName);
@@ -53,13 +47,13 @@ describe('markdownMathParser', () => {
expect(inlineMathContentNodes.length).toBe(0);
});
it('should parse comment within multi-word inline math', () => {
it('should parse comment within multi-word inline math', async () => {
const beforeMath = '# Testing!\n\nThis is a test of ';
const mathRegion = '$\\TeX % TeX Comment!$';
const afterMath = ' formatting.';
const documentText = `${beforeMath}${mathRegion}${afterMath}`;
const editor = createEditorState(documentText);
const editor = await createEditorState(documentText, [inlineMathTagName, 'comment']);
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
const commentNodes = findNodesWithName(editor, 'comment');
@@ -72,30 +66,30 @@ describe('markdownMathParser', () => {
expect(inlineMathNodes[0].to).toBe(beforeMath.length + mathRegion.length);
});
it('shouldn\'t start inline math if there is no ending $', () => {
const documentText = 'This is a $test\n\nof inline math$...';
const editor = createEditorState(documentText);
it('shouldn\'t start inline math if there is no ending $', async () => {
const documentText = '*This* is a $test\n\nof inline math$...';
const editor = await createEditorState(documentText, ['Emphasis']);
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
// Math should end if there is no matching '$'.
expect(inlineMathNodes.length).toBe(0);
});
it('shouldn\'t start if math would have a space just after the $', () => {
const documentText = 'This is a $ test of inline math$...\n\n$Testing... $...';
const editor = createEditorState(documentText);
it('shouldn\'t start if math would have a space just after the $', async () => {
const documentText = 'This *is* a $ test of inline math$...\n\n$Testing... $...';
const editor = await createEditorState(documentText, ['Emphasis']);
expect(findNodesWithName(editor, inlineMathTagName).length).toBe(0);
});
it('shouldn\'t start inline math if $ is escaped', () => {
const documentText = 'This is a \\$test of inline math$...';
const editor = createEditorState(documentText);
it('shouldn\'t start inline math if $ is escaped', async () => {
const documentText = 'This is a \\$test of inline math$... **Testing...**';
const editor = await createEditorState(documentText, ['StrongEmphasis']);
expect(findNodesWithName(editor, inlineMathTagName).length).toBe(0);
});
it('should correctly parse document containing just block math', () => {
const documentText = '$$\n\t\\{ 1, 1, 2, 3, 5, ... \\}\n$$';
const editor = createEditorState(documentText);
it('should correctly parse document containing just block math', async () => {
const documentText = '$$\n\t\\{ 1, 1, 2, 3, 5, ... \\} % Comment\n$$';
const editor = await createEditorState(documentText, [blockMathTagName, 'comment']);
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
@@ -106,10 +100,10 @@ describe('markdownMathParser', () => {
expect(blockMathNodes[0].to).toBe(documentText.length);
});
it('should correctly parse comment in block math', () => {
it('should correctly parse comment in block math', async () => {
const startingText = '$$ % Testing...\n\t\\text{Test.}\n$$';
const afterMath = '\nTest.';
const editor = createEditorState(startingText + afterMath);
const editor = await createEditorState(startingText + afterMath, ['comment', blockMathTagName]);
const inlineMathNodes = findNodesWithName(editor, inlineMathTagName);
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
const texParserComments = findNodesWithName(editor, 'comment');
@@ -127,10 +121,10 @@ describe('markdownMathParser', () => {
});
});
it('should extend block math without ending tag to end of document', () => {
it('should extend block math without ending tag to end of document', async () => {
const beforeMath = '# Testing...\n\n';
const documentText = `${beforeMath}$$\n\t\\text{Testing...}\n\n\t3 + 3 = 6`;
const editor = createEditorState(documentText);
const documentText = `${beforeMath}$$\n\t\\text{Testing...}\n\n\t3 + 3 = 6 % Comment`;
const editor = await createEditorState(documentText, ['ATXHeading1', blockMathTagName, 'comment']);
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
expect(blockMathNodes.length).toBe(1);
@@ -138,9 +132,9 @@ describe('markdownMathParser', () => {
expect(blockMathNodes[0].to).toBe(documentText.length);
});
it('should parse block math declared on a single line', () => {
it('should parse block math declared on a single line', async () => {
const documentText = '$$ Test. $$';
const editor = createEditorState(documentText);
const editor = await createEditorState(documentText, [blockMathTagName]);
const blockMathNodes = findNodesWithName(editor, blockMathTagName);
expect(blockMathNodes.length).toBe(1);

View File

@@ -1,13 +1,19 @@
import { markdown } from '@codemirror/lang-markdown';
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
import { indentUnit } from '@codemirror/language';
import { indentUnit, syntaxTree } from '@codemirror/language';
import { SelectionRange, EditorSelection, EditorState } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { MarkdownMathExtension } from '../markdownMathParser';
import forceFullParse from './forceFullParse';
import loadLangauges from './loadLanguages';
// Creates and returns a minimal editor with markdown extensions. Waits to return the editor
// until all syntax tree tags in `expectedSyntaxTreeTags` exist.
const createEditor = async (
initialText: string, initialSelection: SelectionRange, expectedSyntaxTreeTags: string[]
): Promise<EditorView> => {
await loadLangauges();
// Creates and returns a minimal editor with markdown extensions
const createEditor = (initialText: string, initialSelection: SelectionRange): EditorView => {
const editor = new EditorView({
doc: initialText,
selection: EditorSelection.create([initialSelection]),
@@ -20,7 +26,39 @@ const createEditor = (initialText: string, initialSelection: SelectionRange): Ed
],
});
forceFullParse(editor.state);
let sawExpectedTagCount = 0;
while (sawExpectedTagCount < expectedSyntaxTreeTags.length) {
forceFullParse(editor.state);
sawExpectedTagCount = 0;
const seenTags = new Set<string>();
syntaxTree(editor.state).iterate({
from: 0,
to: editor.state.doc.length,
enter: (node) => {
for (const expectedTag of expectedSyntaxTreeTags) {
if (node.name === expectedTag) {
seenTags.add(node.name);
sawExpectedTagCount ++;
break;
}
}
},
});
if (sawExpectedTagCount < expectedSyntaxTreeTags.length) {
const missingTags = expectedSyntaxTreeTags.filter(tagName => {
return !seenTags.has(tagName);
});
console.warn(`Didn't find all expected tags. Missing ${missingTags}. Retrying...`);
await new Promise(resolve => {
setTimeout(resolve, 500);
});
}
}
return editor;
};

View File

@@ -0,0 +1,12 @@
import syntaxHighlightingLanguages from '../syntaxHighlightingLanguages';
// Ensure languages we use are loaded. Without this, tests may randomly fail (LanguageDescriptions
// are loaded asyncronously, in the background).
const loadLangauges = async () => {
const allLanguages = syntaxHighlightingLanguages;
for (const lang of allLanguages) {
await lang.load();
}
};
export default loadLangauges;

View File

@@ -1,7 +1,7 @@
const React = require('react');
import { connect } from 'react-redux';
import { PureComponent, Component } from 'react';
import { PureComponent } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Image, ScrollView, Dimensions, ViewStyle } from 'react-native';
const Icon = require('react-native-vector-icons/Ionicons').default;
const { BackButtonService } = require('../services/back-button.js');
@@ -46,7 +46,7 @@ type DispatchCommandType=(event: { type: string })=> void;
interface ScreenHeaderProps {
selectedNoteIds: string[];
noteSelectionEnabled: boolean;
parentComponent: Component;
parentComponent: any;
showUndoButton: boolean;
undoButtonDisabled?: boolean;
showRedoButton: boolean;
@@ -55,8 +55,8 @@ interface ScreenHeaderProps {
folders: FolderEntity[];
folderPickerOptions?: {
enabled: boolean;
selectedFolderId: string;
onValueChange: OnValueChangedListener;
selectedFolderId?: string;
onValueChange?: OnValueChangedListener;
mustSelect?: boolean;
};

View File

@@ -38,8 +38,7 @@ const { dialogs } = require('../../utils/dialogs.js');
const DialogBox = require('react-native-dialogbox').default;
const ImageResizer = require('react-native-image-resizer').default;
const shared = require('@joplin/lib/components/shared/note-screen-shared.js');
const ImagePicker = require('react-native-image-picker').default;
import { ImagePickerResponse } from 'react-native-image-picker';
import { ImagePickerResponse, launchImageLibrary } from 'react-native-image-picker';
import SelectDateTimeDialog from '../SelectDateTimeDialog';
import ShareExtension from '../../utils/ShareExtension.js';
import CameraView from '../CameraView';
@@ -562,14 +561,6 @@ class NoteScreenComponent extends BaseScreenComponent {
});
}
showImagePicker(options: any) {
return new Promise((resolve) => {
ImagePicker.launchImageLibrary(options, (response: any) => {
resolve(response);
});
});
}
async resizeImage(localFilePath: string, targetPath: string, mimeType: string) {
const maxSize = Resource.IMAGE_MAX_DIMENSION;
@@ -720,7 +711,7 @@ class NoteScreenComponent extends BaseScreenComponent {
private async attachPhoto_onPress() {
// the selection Limit should be specfied. I think 200 is enough?
const response: ImagePickerResponse = await this.showImagePicker({ mediaType: 'photo', includeBase64: false, selectionLimit: 200 });
const response: ImagePickerResponse = await launchImageLibrary({ mediaType: 'photo', includeBase64: false, selectionLimit: 200 });
if (response.errorCode) {
reg.logger().warn('Got error from picker', response.errorCode);

View File

@@ -1,23 +1,31 @@
const React = require('react');
const { StyleSheet, View, TextInput, FlatList, TouchableHighlight } = require('react-native');
import { StyleSheet, View, TextInput, FlatList, TouchableHighlight } from 'react-native';
const { connect } = require('react-redux');
const { ScreenHeader } = require('../ScreenHeader');
import ScreenHeader from '../ScreenHeader';
const Icon = require('react-native-vector-icons/Ionicons').default;
const { _ } = require('@joplin/lib/locale');
const Note = require('@joplin/lib/models/Note').default;
import { _ } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note';
import gotoAnythingStyleQuery from '@joplin/lib/services/searchengine/gotoAnythingStyleQuery';
const { NoteItem } = require('../note-item.js');
const { BaseScreenComponent } = require('../base-screen.js');
const { themeStyle } = require('../global-style.js');
const DialogBox = require('react-native-dialogbox').default;
const SearchEngineUtils = require('@joplin/lib/services/searchengine/SearchEngineUtils').default;
const SearchEngine = require('@joplin/lib/services/searchengine/SearchEngine').default;
import SearchEngineUtils from '@joplin/lib/services/searchengine/SearchEngineUtils';
import SearchEngine from '@joplin/lib/services/searchengine/SearchEngine';
import { AppState } from '../../utils/types';
Icon.loadFont();
class SearchScreenComponent extends BaseScreenComponent {
private state: any = null;
private isMounted_ = false;
private styles_: any = {};
private scheduleSearchTimer_: any = null;
static navigationOptions() {
return { header: null };
return { header: null } as any;
}
constructor() {
@@ -26,8 +34,6 @@ class SearchScreenComponent extends BaseScreenComponent {
query: '',
notes: [],
};
this.isMounted_ = false;
this.styles_ = {};
}
styles() {
@@ -36,7 +42,7 @@ class SearchScreenComponent extends BaseScreenComponent {
if (this.styles_[this.props.themeId]) return this.styles_[this.props.themeId];
this.styles_ = {};
const styles = {
const styles: any = {
body: {
flex: 1,
},
@@ -65,7 +71,7 @@ class SearchScreenComponent extends BaseScreenComponent {
componentDidMount() {
this.setState({ query: this.props.query });
this.refreshSearch(this.props.query);
void this.refreshSearch(this.props.query);
this.isMounted_ = true;
}
@@ -73,19 +79,6 @@ class SearchScreenComponent extends BaseScreenComponent {
this.isMounted_ = false;
}
searchTextInput_submit() {
const query = this.state.query.trim();
if (!query) return;
this.props.dispatch({
type: 'SEARCH_QUERY',
query: query,
});
this.setState({ query: query });
this.refreshSearch(query);
}
clearButton_press() {
this.props.dispatch({
type: 'SEARCH_QUERY',
@@ -93,13 +86,13 @@ class SearchScreenComponent extends BaseScreenComponent {
});
this.setState({ query: '' });
this.refreshSearch('');
void this.refreshSearch('');
}
async refreshSearch(query = null) {
async refreshSearch(query: string = null) {
if (!this.props.visible) return;
query = query === null ? this.state.query.trim : query.trim();
query = gotoAnythingStyleQuery(query);
let notes = [];
@@ -134,8 +127,24 @@ class SearchScreenComponent extends BaseScreenComponent {
this.setState({ notes: notes });
}
searchTextInput_changeText(text) {
scheduleSearch() {
if (this.scheduleSearchTimer_) clearTimeout(this.scheduleSearchTimer_);
this.scheduleSearchTimer_ = setTimeout(() => {
this.scheduleSearchTimer_ = null;
void this.refreshSearch(this.state.query);
}, 200);
}
searchTextInput_changeText(text: string) {
this.setState({ query: text });
this.props.dispatch({
type: 'SEARCH_QUERY',
query: text,
});
this.scheduleSearch();
}
render() {
@@ -172,9 +181,6 @@ class SearchScreenComponent extends BaseScreenComponent {
style={this.styles().searchTextInput}
autoFocus={this.props.visible}
underlineColorAndroid="#ffffff00"
onSubmitEditing={() => {
this.searchTextInput_submit();
}}
onChangeText={text => this.searchTextInput_changeText(text)}
value={this.state.query}
selectionColor={theme.textSelectionColor}
@@ -188,7 +194,7 @@ class SearchScreenComponent extends BaseScreenComponent {
<FlatList data={this.state.notes} keyExtractor={(item) => item.id} renderItem={event => <NoteItem note={event.item} />} />
</View>
<DialogBox
ref={dialogbox => {
ref={(dialogbox: any) => {
this.dialogbox = dialogbox;
}}
/>
@@ -197,7 +203,7 @@ class SearchScreenComponent extends BaseScreenComponent {
}
}
const SearchScreen = connect(state => {
const SearchScreen = connect((state: AppState) => {
return {
query: state.searchQuery,
themeId: state.settings.theme,

View File

@@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
46E31F54C547C341F605BB66 /* libPods-Joplin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A5E1CD825FABD6C4E704EA54 /* libPods-Joplin.a */; };
@@ -51,7 +51,7 @@
09056573D4C040FBD5FEB93A /* Pods-Joplin-JoplinTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Joplin-JoplinTests.debug.xcconfig"; path = "Target Support Files/Pods-Joplin-JoplinTests/Pods-Joplin-JoplinTests.debug.xcconfig"; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* Joplin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Joplin.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Joplin/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Joplin/AppDelegate.m; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.mm; path = Joplin/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Joplin/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Joplin/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Joplin/main.m; sourceTree = "<group>"; };
@@ -125,7 +125,7 @@
AE7945E6259C9AEE00051BE2 /* Joplin.entitlements */,
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
@@ -449,7 +449,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
4D122473270878D700DE23E8 /* wtf.swift in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
@@ -492,13 +492,13 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
CURRENT_PROJECT_VERSION = 83;
CURRENT_PROJECT_VERSION = 85;
DEVELOPMENT_TEAM = A9BXAFS6CT;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Joplin/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 12.10.0;
MARKETING_VERSION = 12.10.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -521,12 +521,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
CURRENT_PROJECT_VERSION = 83;
CURRENT_PROJECT_VERSION = 85;
DEVELOPMENT_TEAM = A9BXAFS6CT;
INFOPLIST_FILE = Joplin/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 12.10.0;
MARKETING_VERSION = 12.10.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -667,14 +667,14 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 83;
CURRENT_PROJECT_VERSION = 85;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = A9BXAFS6CT;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ShareExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 12.10.0;
MARKETING_VERSION = 12.10.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
@@ -698,14 +698,14 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 83;
CURRENT_PROJECT_VERSION = 85;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = A9BXAFS6CT;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ShareExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 12.10.0;
MARKETING_VERSION = 12.10.1;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -1,115 +0,0 @@
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
#import "RNQuickActionManager.h"
// #ifdef FB_SONARKIT_ENABLED
// #import <FlipperKit/FlipperClient.h>
// #import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
// #import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
// #import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
// #import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
// #import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
// static void InitializeFlipper(UIApplication *application) {
// FlipperClient *client = [FlipperClient sharedClient];
// SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
// [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
// [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
// [client addPlugin:[FlipperKitReactPlugin new]];
// [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
// [client start];
// }
// #endif
@implementation AppDelegate
// ===================================================
// BEGIN react-native-quick-actions
// ===================================================
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded)) completionHandler {
[RNQuickActionManager onQuickActionPress:shortcutItem completionHandler:completionHandler];
}
// ===================================================
// END react-native-quick-actions
// ===================================================
// ===================================================
// BEGIN react-native-push-notification-ios
// ===================================================
// IOS 10+ Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
completionHandler();
}
// IOS 4-10 Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
}
// ===================================================
// END react-native-push-notification-ios
// ===================================================
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// #ifdef FB_SONARKIT_ENABLED
// InitializeFlipper(application);
// #endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"Joplin"
initialProperties:nil];
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
// BEGIN react-native-push-notification-ios
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
// END react-native-push-notification-ios
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
return [RCTLinkingManager application:app openURL:url options:options];
}
@end

View File

@@ -0,0 +1,156 @@
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTAppSetupUtils.h>
#import <RNCPushNotificationIOS.h>
#import "RNQuickActionManager.h"
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
// ===================================================
// BEGIN react-native-quick-actions
// ===================================================
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded)) completionHandler {
[RNQuickActionManager onQuickActionPress:shortcutItem completionHandler:completionHandler];
}
// ===================================================
// END react-native-quick-actions
// ===================================================
// ===================================================
// BEGIN react-native-push-notification-ios
// ===================================================
// IOS 10+ Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
completionHandler();
}
// IOS 4-10 Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
}
// ===================================================
// END react-native-push-notification-ios
// ===================================================
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"Joplin", nil);
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
// BEGIN react-native-push-notification-ios
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
// END react-native-push-notification-ios
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
@end

View File

@@ -2,7 +2,8 @@
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

View File

@@ -10,14 +10,21 @@ require_relative '../node_modules/@react-native-community/cli-platform-ios/nativ
# 2021-12-17: Changed back to 11.0 because after the fix it works with at least
# 12.x, and probably 11.0 too, which is the version supported by React Native.
platform :ios, '11.0'
install! 'cocoapods', :deterministic_uuids => false
target 'Joplin' do
config = use_native_modules!
# Flags change depending on the env values.
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
# to enable hermes on iOS, change `false` to `true` and then install pods
:hermes_enabled => false
:hermes_enabled => flags[:hermes_enabled],
:fabric_enabled => flags[:fabric_enabled],
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'

View File

@@ -1,14 +1,14 @@
PODS:
- boost (1.76.0)
- DoubleConversion (1.1.6)
- FBLazyVector (0.67.2)
- FBReactNativeSpec (0.67.2):
- FBLazyVector (0.68.5)
- FBReactNativeSpec (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.67.2)
- RCTTypeSafety (= 0.67.2)
- React-Core (= 0.67.2)
- React-jsi (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- RCTRequired (= 0.68.5)
- RCTTypeSafety (= 0.68.5)
- React-Core (= 0.68.5)
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- fmt (6.2.1)
- glog (0.3.5)
- JoplinCommonShareExtension (1.0.0)
@@ -26,194 +26,203 @@ PODS:
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCTRequired (0.67.2)
- RCTTypeSafety (0.67.2):
- FBLazyVector (= 0.67.2)
- RCTRequired (0.68.5)
- RCTTypeSafety (0.68.5):
- FBLazyVector (= 0.68.5)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.67.2)
- React-Core (= 0.67.2)
- React (0.67.2):
- React-Core (= 0.67.2)
- React-Core/DevSupport (= 0.67.2)
- React-Core/RCTWebSocket (= 0.67.2)
- React-RCTActionSheet (= 0.67.2)
- React-RCTAnimation (= 0.67.2)
- React-RCTBlob (= 0.67.2)
- React-RCTImage (= 0.67.2)
- React-RCTLinking (= 0.67.2)
- React-RCTNetwork (= 0.67.2)
- React-RCTSettings (= 0.67.2)
- React-RCTText (= 0.67.2)
- React-RCTVibration (= 0.67.2)
- React-callinvoker (0.67.2)
- React-Core (0.67.2):
- RCTRequired (= 0.68.5)
- React-Core (= 0.68.5)
- React (0.68.5):
- React-Core (= 0.68.5)
- React-Core/DevSupport (= 0.68.5)
- React-Core/RCTWebSocket (= 0.68.5)
- React-RCTActionSheet (= 0.68.5)
- React-RCTAnimation (= 0.68.5)
- React-RCTBlob (= 0.68.5)
- React-RCTImage (= 0.68.5)
- React-RCTLinking (= 0.68.5)
- React-RCTNetwork (= 0.68.5)
- React-RCTSettings (= 0.68.5)
- React-RCTText (= 0.68.5)
- React-RCTVibration (= 0.68.5)
- React-callinvoker (0.68.5)
- React-Codegen (0.68.5):
- FBReactNativeSpec (= 0.68.5)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.68.5)
- RCTTypeSafety (= 0.68.5)
- React-Core (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-Core (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.67.2)
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-Core/Default (= 0.68.5)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/CoreModulesHeaders (0.67.2):
- React-Core/CoreModulesHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/Default (0.67.2):
- React-Core/Default (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/DevSupport (0.67.2):
- React-Core/DevSupport (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.67.2)
- React-Core/RCTWebSocket (= 0.67.2)
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-jsinspector (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-Core/Default (= 0.68.5)
- React-Core/RCTWebSocket (= 0.68.5)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-jsinspector (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTActionSheetHeaders (0.67.2):
- React-Core/RCTActionSheetHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTAnimationHeaders (0.67.2):
- React-Core/RCTAnimationHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTBlobHeaders (0.67.2):
- React-Core/RCTBlobHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTImageHeaders (0.67.2):
- React-Core/RCTImageHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTLinkingHeaders (0.67.2):
- React-Core/RCTLinkingHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTNetworkHeaders (0.67.2):
- React-Core/RCTNetworkHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTSettingsHeaders (0.67.2):
- React-Core/RCTSettingsHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTTextHeaders (0.67.2):
- React-Core/RCTTextHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTVibrationHeaders (0.67.2):
- React-Core/RCTVibrationHeaders (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-Core/RCTWebSocket (0.67.2):
- React-Core/RCTWebSocket (0.68.5):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.67.2)
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsiexecutor (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-Core/Default (= 0.68.5)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsiexecutor (= 0.68.5)
- React-perflogger (= 0.68.5)
- Yoga
- React-CoreModules (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- React-CoreModules (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.67.2)
- React-Core/CoreModulesHeaders (= 0.67.2)
- React-jsi (= 0.67.2)
- React-RCTImage (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-cxxreact (0.67.2):
- RCTTypeSafety (= 0.68.5)
- React-Codegen (= 0.68.5)
- React-Core/CoreModulesHeaders (= 0.68.5)
- React-jsi (= 0.68.5)
- React-RCTImage (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-cxxreact (0.68.5):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.67.2)
- React-jsi (= 0.67.2)
- React-jsinspector (= 0.67.2)
- React-logger (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-runtimeexecutor (= 0.67.2)
- React-jsi (0.67.2):
- React-callinvoker (= 0.68.5)
- React-jsi (= 0.68.5)
- React-jsinspector (= 0.68.5)
- React-logger (= 0.68.5)
- React-perflogger (= 0.68.5)
- React-runtimeexecutor (= 0.68.5)
- React-jsi (0.68.5):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi/Default (= 0.67.2)
- React-jsi/Default (0.67.2):
- React-jsi/Default (= 0.68.5)
- React-jsi/Default (0.68.5):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.67.2):
- React-jsiexecutor (0.68.5):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-jsinspector (0.67.2)
- React-logger (0.67.2):
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-perflogger (= 0.68.5)
- React-jsinspector (0.68.5)
- React-logger (0.68.5):
- glog
- react-native-alarm-notification (1.0.6):
- react-native-alarm-notification (1.0.7):
- React
- react-native-camera (4.2.1):
- React-Core
@@ -229,7 +238,7 @@ PODS:
- React-Core
- react-native-get-random-values (1.8.0):
- React-Core
- react-native-image-picker (4.10.2):
- react-native-image-picker (4.10.3):
- React-Core
- react-native-image-resizer (1.4.5):
- React-Core
@@ -245,71 +254,71 @@ PODS:
- React-Core
- react-native-webview (11.26.0):
- React-Core
- React-perflogger (0.67.2)
- React-RCTActionSheet (0.67.2):
- React-Core/RCTActionSheetHeaders (= 0.67.2)
- React-RCTAnimation (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- React-perflogger (0.68.5)
- React-RCTActionSheet (0.68.5):
- React-Core/RCTActionSheetHeaders (= 0.68.5)
- React-RCTAnimation (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.67.2)
- React-Core/RCTAnimationHeaders (= 0.67.2)
- React-jsi (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-RCTBlob (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- RCTTypeSafety (= 0.68.5)
- React-Codegen (= 0.68.5)
- React-Core/RCTAnimationHeaders (= 0.68.5)
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-RCTBlob (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/RCTBlobHeaders (= 0.67.2)
- React-Core/RCTWebSocket (= 0.67.2)
- React-jsi (= 0.67.2)
- React-RCTNetwork (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-RCTImage (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- React-Codegen (= 0.68.5)
- React-Core/RCTBlobHeaders (= 0.68.5)
- React-Core/RCTWebSocket (= 0.68.5)
- React-jsi (= 0.68.5)
- React-RCTNetwork (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-RCTImage (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.67.2)
- React-Core/RCTImageHeaders (= 0.67.2)
- React-jsi (= 0.67.2)
- React-RCTNetwork (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-RCTLinking (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- React-Core/RCTLinkingHeaders (= 0.67.2)
- React-jsi (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-RCTNetwork (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- RCTTypeSafety (= 0.68.5)
- React-Codegen (= 0.68.5)
- React-Core/RCTImageHeaders (= 0.68.5)
- React-jsi (= 0.68.5)
- React-RCTNetwork (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-RCTLinking (0.68.5):
- React-Codegen (= 0.68.5)
- React-Core/RCTLinkingHeaders (= 0.68.5)
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-RCTNetwork (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.67.2)
- React-Core/RCTNetworkHeaders (= 0.67.2)
- React-jsi (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-RCTSettings (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- RCTTypeSafety (= 0.68.5)
- React-Codegen (= 0.68.5)
- React-Core/RCTNetworkHeaders (= 0.68.5)
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-RCTSettings (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.67.2)
- React-Core/RCTSettingsHeaders (= 0.67.2)
- React-jsi (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-RCTText (0.67.2):
- React-Core/RCTTextHeaders (= 0.67.2)
- React-RCTVibration (0.67.2):
- FBReactNativeSpec (= 0.67.2)
- RCTTypeSafety (= 0.68.5)
- React-Codegen (= 0.68.5)
- React-Core/RCTSettingsHeaders (= 0.68.5)
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-RCTText (0.68.5):
- React-Core/RCTTextHeaders (= 0.68.5)
- React-RCTVibration (0.68.5):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/RCTVibrationHeaders (= 0.67.2)
- React-jsi (= 0.67.2)
- ReactCommon/turbomodule/core (= 0.67.2)
- React-runtimeexecutor (0.67.2):
- React-jsi (= 0.67.2)
- ReactCommon/turbomodule/core (0.67.2):
- React-Codegen (= 0.68.5)
- React-Core/RCTVibrationHeaders (= 0.68.5)
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- React-runtimeexecutor (0.68.5):
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (0.68.5):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.67.2)
- React-Core (= 0.67.2)
- React-cxxreact (= 0.67.2)
- React-jsi (= 0.67.2)
- React-logger (= 0.67.2)
- React-perflogger (= 0.67.2)
- React-callinvoker (= 0.68.5)
- React-Core (= 0.68.5)
- React-cxxreact (= 0.68.5)
- React-jsi (= 0.68.5)
- React-logger (= 0.68.5)
- React-perflogger (= 0.68.5)
- rn-fetch-blob (0.12.0):
- React-Core
- RNCClipboard (1.5.1):
@@ -345,6 +354,7 @@ DEPENDENCIES:
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Codegen (from `build/generated/ios`)
- React-Core (from `../node_modules/react-native/`)
- React-Core/DevSupport (from `../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
@@ -420,6 +430,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/"
React-callinvoker:
:path: "../node_modules/react-native/ReactCommon/callinvoker"
React-Codegen:
:path: build/generated/ios
React-Core:
:path: "../node_modules/react-native/"
React-CoreModules:
@@ -510,30 +522,31 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
FBLazyVector: 244195e30d63d7f564c55da4410b9a24e8fbceaa
FBReactNativeSpec: c94002c1d93da3658f4d5119c6994d19961e3d52
FBLazyVector: 2b47ff52037bd9ae07cc9b051c9975797814b736
FBReactNativeSpec: 0e0d384ef17a33b385f13f0c7f97702c7cd17858
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 85ecdd10ee8d8ec362ef519a6a45ff9aa27b2e85
glog: 476ee3e89abb49e07f822b48323c51c57124b572
JoplinCommonShareExtension: a8b60b02704d85a7305627912c0240e94af78db7
JoplinRNShareExtension: 485f3e6dad83b7b77f1572eabc249f869ee55c02
RCT-Folly: 803a9cfd78114b2ec0f140cfa6fa2a6bafb2d685
RCTRequired: cd47794163052d2b8318c891a7a14fcfaccc75ab
RCTTypeSafety: 393bb40b3e357b224cde53d3fec26813c52428b1
React: dec6476bc27155b250eeadfc11ea779265f53ebf
React-callinvoker: e5047929e80aea942e6fdd96482504ef0189ca63
React-Core: e382655566b2b9a6e3b4f641d777b7bfdbe52358
React-CoreModules: cf262e82fa101c0aee022b6f90d1a5b612038b64
React-cxxreact: 69d53de3b30c7c161ba087ca1ecdffed9ccb1039
React-jsi: ce9a2d804adf75809ce2fe2374ba3fbbf5d59b03
React-jsiexecutor: 52beb652bbc61201bd70cbe4f0b8edb607e8da4f
React-jsinspector: 595f76eba2176ebd8817a1fffd47b84fbdab9383
React-logger: 23de8ea0f44fa00ee77e96060273225607fd4d78
react-native-alarm-notification: 88c751922c791cc628bd7efb09bff18c8f178a5d
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
RCTRequired: 0f06b6068f530932d10e1a01a5352fad4eaacb74
RCTTypeSafety: b0ee81f10ef1b7d977605a2b266823dabd565e65
React: 3becd12bd51ea8a43bdde7e09d0f40fba7820e03
React-callinvoker: 11abfff50e6bf7a55b3a90b4dc2187f71f224593
React-Codegen: f8946ce0768fb8e92e092e30944489c4b2955b2d
React-Core: 203cdb6ee2657b198d97d41031c249161060e6ca
React-CoreModules: 6eb0c06a4a223fde2cb6a8d0f44f58b67e808942
React-cxxreact: afb0c6c07d19adbd850747fedeac20c6832d40b9
React-jsi: 14d37a6db2af2c1a49f6f5c2e4ee667c364ae45c
React-jsiexecutor: 45c0496ca8cef6b02d9fa0274c25cf458fe91a56
React-jsinspector: eb202e43b3879aba9a14f3f65788aec85d4e1ea9
React-logger: 98f663b292a60967ebbc6d803ae96c1381183b6d
react-native-alarm-notification: 4e150e89c1707e057bc5e8c87ab005f1ea4b8d52
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
react-native-document-picker: 958e2bc82e128be69055be261aeac8d872c8d34c
react-native-geolocation: 69f4fd37650b8e7fee91816d395e62dd16f5ab8d
react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a
react-native-image-picker: bf34f3f516d139ed3e24c5f5a381a91819e349ea
react-native-image-picker: 60f4246eb5bb7187fc15638a8c1f13abd3820695
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
@@ -541,18 +554,18 @@ SPEC CHECKSUMS:
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
react-native-version-info: a106f23009ac0db4ee00de39574eb546682579b9
react-native-webview: 994b9f8fbb504d6314dc40d83f94f27c6831b3bf
React-perflogger: 3c9bb7372493e49036f07a82c44c8cf65cbe88db
React-RCTActionSheet: 052606483045a408693aa7e864410b4a052f541a
React-RCTAnimation: 08d4cac13222bb1348c687a0158dfd3b577cdb63
React-RCTBlob: 928ad1df65219c3d9e2ac80983b943a75b5c3629
React-RCTImage: 524d7313b142a39ee0e20fa312b67277917fe076
React-RCTLinking: 44036ea6f13a2e46238be07a67566247fee35244
React-RCTNetwork: 9b6faacf1e0789253e319ca53b1f8d92c2ac5455
React-RCTSettings: ecd8094f831130a49581d5112a8607220e5d12a5
React-RCTText: 14ba976fb48ed283cfdb1a754a5d4276471e0152
React-RCTVibration: 99c7f67fba7a5ade46e98e870c6ff2444484f995
React-runtimeexecutor: 2450b43df7ffe8e805a0b3dcb2abd4282f1f1836
ReactCommon: d98c6c96b567f9b3a15f9fd4cc302c1eda8e3cf2
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
React-RCTAnimation: 732ce66878d4aa151d56a0d142b1105aa12fd313
React-RCTBlob: 9cb9e3e9a41d27be34aaf89b0e0f52c7ca415d57
React-RCTImage: 6bd16627eb9c4bb79903c4cdec7c551266ee1a5b
React-RCTLinking: e9edfc8919c8fa9a3f3c7b34362811f58a2ebba4
React-RCTNetwork: 880eccd21bbe2660a0b63da5ccba75c46eceeaa6
React-RCTSettings: 8c85d8188c97d6c6bd470af6631a6c4555b79bb3
React-RCTText: bbd275ee287730c5acbab1aadc0db39c25c5c64e
React-RCTVibration: 9819a3bf6230e4b2a99877c21268b0b2416157a1
React-runtimeexecutor: b1f1995089b90696dbc2a7ffe0059a80db5c8eb1
ReactCommon: 149e2c0acab9bac61378da0db5b2880a1b5ff59b
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
RNCPushNotificationIOS: 87b8d16d3ede4532745e05b03c42cff33a36cc45
@@ -563,8 +576,8 @@ SPEC CHECKSUMS:
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
RNShare: d93e00e906e6174657f6370b480437e4702bc86e
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
Yoga: 9b6696970c3289e8dea34b3eda93f23e61fb8121
Yoga: c4d61225a466f250c35c1ee78d2d0b3d41fe661c
PODFILE CHECKSUM: 3503e0565874e79261edc56dcddb35b3a49a2984
PODFILE CHECKSUM: 53dddf84c9a411ea75fb783cdc7cf103c4b0e7d8
COCOAPODS: 1.11.3

View File

@@ -32,13 +32,13 @@
"constants-browserify": "1.0.0",
"crypto-browserify": "3.12.0",
"events": "3.3.0",
"joplin-rn-alarm-notification": "1.0.6",
"joplin-rn-alarm-notification": "1.0.7",
"jsc-android": "241213.1.0",
"md5": "2.3.0",
"prop-types": "15.8.1",
"punycode": "2.1.1",
"react": "18.2.0",
"react-native": "0.67.2",
"react-native": "0.68.5",
"react-native-action-button": "2.8.5",
"react-native-camera": "4.2.1",
"react-native-dialogbox": "0.6.10",
@@ -47,7 +47,7 @@
"react-native-file-viewer": "2.1.5",
"react-native-fs": "2.20.0",
"react-native-get-random-values": "1.8.0",
"react-native-image-picker": "4.10.2",
"react-native-image-picker": "4.10.3",
"react-native-image-resizer": "1.4.5",
"react-native-modal-datetime-picker": "14.0.1",
"react-native-popup-menu": "0.16.1",
@@ -81,11 +81,11 @@
"@codemirror/lang-markdown": "6.0.5",
"@codemirror/lang-php": "6.0.1",
"@codemirror/lang-rust": "6.0.1",
"@codemirror/language": "6.3.1",
"@codemirror/language": "6.3.2",
"@codemirror/legacy-modes": "6.3.1",
"@codemirror/search": "6.2.3",
"@codemirror/state": "6.1.4",
"@codemirror/view": "6.6.0",
"@codemirror/view": "6.7.1",
"@joplin/tools": "~2.10",
"@lezer/highlight": "1.1.3",
"@types/fs-extra": "9.0.13",
@@ -100,7 +100,7 @@
"jest-environment-jsdom": "29.3.1",
"jetifier": "2.0.0",
"jsdom": "20.0.0",
"metro-react-native-babel-preset": "0.66.2",
"metro-react-native-babel-preset": "0.67.0",
"nodemon": "2.0.20",
"ts-jest": "29.0.3",
"ts-loader": "9.4.2",

View File

@@ -46,9 +46,9 @@
},
"devDependencies": {
"@types/jest": "29.2.4",
"@types/node": "18.11.17",
"@typescript-eslint/eslint-plugin": "5.47.0",
"@typescript-eslint/parser": "5.47.0",
"@types/node": "18.11.18",
"@typescript-eslint/eslint-plugin": "5.47.1",
"@typescript-eslint/parser": "5.47.1",
"coveralls": "3.1.1",
"eslint": "8.30.0",
"eslint-config-prettier": "8.5.0",

View File

@@ -857,7 +857,7 @@ export default class BaseApplication {
// Setting.setValue('sync.10.path', 'https://api.joplincloud.com');
// Setting.setValue('sync.10.userContentPath', 'https://joplinusercontent.com');
Setting.setValue('sync.10.path', 'http://api.joplincloud.local:22300');
Setting.setValue('sync.10.userContentPath', 'http://joplincloud.local:22300');
Setting.setValue('sync.10.userContentPath', 'http://joplinusercontent.local:22300');
}
// For now always disable fuzzy search due to performance issues:

View File

@@ -1,6 +1,7 @@
const stringToStream = require('string-to-stream');
// const cleanHtml = require('clean-html');
const resourceUtils = require('./resourceUtils.js');
const { cssValue } = require('./import-enex-md-gen');
const htmlUtils = require('./htmlUtils').default;
const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = new Entities().encode;
@@ -80,6 +81,7 @@ function enexXmlToHtml_(stream, resources) {
saxStream.on('opentag', function(node) {
const tagName = node.name.toLowerCase();
const attributesStr = resourceUtils.attributesToStr(node.attributes);
const nodeAttributes = attributeToLowerCase(node);
if (tagName === 'en-media') {
const nodeAttributes = attributeToLowerCase(node);
@@ -121,9 +123,11 @@ function enexXmlToHtml_(stream, resources) {
section.lines = addResourceTag(section.lines, resource, nodeAttributes);
}
} else if (tagName === 'en-todo') {
const nodeAttributes = attributeToLowerCase(node);
const checkedHtml = nodeAttributes.checked && nodeAttributes.checked.toLowerCase() === 'true' ? ' checked="checked" ' : ' ';
section.lines.push(`<input${checkedHtml}type="checkbox" onclick="return false;" />`);
} else if (tagName === 'li' && cssValue(this, nodeAttributes.style, '--en-checked')) {
const checkedHtml = cssValue(this, nodeAttributes.style, '--en-checked') === 'true' ? ' checked="checked" ' : ' ';
section.lines.push(`<${tagName}${attributesStr}> <input${checkedHtml}type="checkbox" onclick="return false;" />`);
} else if (htmlUtils.isSelfClosingTag(tagName)) {
section.lines.push(`<${tagName}${attributesStr}/>`);
} else {

View File

@@ -65,7 +65,11 @@ describe('EnexToHtml', function() {
});
compareOutputToExpected({
testName: 'checklist-list',
testName: 'checkbox-list',
});
compareOutputToExpected({
testName: 'checklist',
});
compareOutputToExpected({

View File

@@ -35,8 +35,14 @@ interface ParserStateTag {
isHighlight: boolean;
}
enum ListTag {
Ul = 'ul',
Ol = 'ol',
CheckboxList = 'checkboxList',
}
interface ParserStateList {
tag: string;
tag: ListTag;
counter: number;
startedText: boolean;
}
@@ -738,7 +744,9 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<Ene
section.lines.push(BLOCK_OPEN);
} else if (isListTag(n)) {
section.lines.push(BLOCK_OPEN);
state.lists.push({ tag: n, counter: 1, startedText: false });
const isCheckboxList = cssValue(this, nodeAttributes.style, '--en-todo') === 'true';
const tag = isCheckboxList ? ListTag.CheckboxList : n as ListTag;
state.lists.push({ tag: tag, counter: 1, startedText: false });
} else if (n === 'li') {
section.lines.push(BLOCK_OPEN);
if (!state.lists.length) {
@@ -750,7 +758,11 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<Ene
container.startedText = false;
const indent = ' '.repeat(state.lists.length - 1);
if (container.tag === 'ul') {
if (container.tag === ListTag.CheckboxList) {
const x = cssValue(this, nodeAttributes.style, '--en-checked') === 'true' ? 'X' : ' ';
section.lines.push(`${indent}- [${x}] `);
} else if (container.tag === ListTag.Ul) {
section.lines.push(`${indent}- `);
} else {
section.lines.push(`${indent + container.counter}. `);
@@ -782,7 +794,7 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<Ene
} else if (isEmTag(n)) {
section.lines.push('*');
} else if (n === 'en-todo') {
const x = nodeAttributes && nodeAttributes.checked && nodeAttributes.checked.toLowerCase() === 'true' ? 'X' : ' ';
const x = nodeAttributes.checked && nodeAttributes.checked.toLowerCase() === 'true' ? 'X' : ' ';
section.lines.push(`- [${x}] `);
} else if (n === 'hr') {
// Needs to be surrounded by new lines so that it's properly rendered as a line when converting to HTML
@@ -1380,4 +1392,4 @@ async function enexXmlToMd(xmlString: string, resources: ResourceEntity[]) {
return output.join('\n');
}
export { enexXmlToMd, processMdArrayNewLines, NEWLINE, addResourceTag };
export { enexXmlToMd, processMdArrayNewLines, NEWLINE, addResourceTag, cssValue };

View File

@@ -19,18 +19,18 @@
"@types/fs-extra": "9.0.13",
"@types/jest": "29.2.4",
"@types/js-yaml": "4.0.5",
"@types/node": "18.11.17",
"@types/node": "18.11.18",
"@types/node-rsa": "1.1.1",
"@types/react": "17.0.52",
"@types/uuid": "^9.0.0",
"clean-html": "1.5.0",
"jest": "29.3.1",
"sharp": "0.31.2",
"sharp": "0.31.3",
"typescript": "4.9.4"
},
"dependencies": {
"@aws-sdk/client-s3": "3.235.0",
"@aws-sdk/s3-request-presigner": "3.235.0",
"@aws-sdk/client-s3": "3.241.0",
"@aws-sdk/s3-request-presigner": "3.241.0",
"@joplin/fork-htmlparser2": "^4.1.41",
"@joplin/fork-sax": "^1.2.45",
"@joplin/fork-uslug": "^1.0.6",

View File

@@ -9,7 +9,8 @@
// If the userContentBaseUrl is an empty string, the baseUrl is returned instead.
export default function(userId: string, baseUrl: string, userContentBaseUrl: string) {
// Special case for development, because it's difficult to get wildcard domains working locally.
if (userContentBaseUrl === 'http://joplincloud.local:22300') return 'http://joplincloud.local:22300';
// if (userContentBaseUrl === 'http://joplincloud.local:22300') return 'http://joplincloud.local:22300';
// if (userContentBaseUrl === 'http://joplincloud.local:22300') return 'http://abcd1234.joplinusercontent.local:22300';
if (userContentBaseUrl && baseUrl !== userContentBaseUrl) {
if (!userId) throw new Error('User ID must be specified');

View File

@@ -3,7 +3,7 @@ import Note from '../../models/Note';
import Setting from '../../models/Setting';
export default class SearchEngineUtils {
static async notesForQuery(query: string, applyUserSettings: boolean, options: any = null, searchEngine: SearchEngine = null) {
public static async notesForQuery(query: string, applyUserSettings: boolean, options: any = null, searchEngine: SearchEngine = null) {
if (!options) options = {};
if (!searchEngine) {

View File

@@ -0,0 +1,14 @@
export default (query: string) => {
if (!query) return '';
const output = [];
const splitted = query.split(' ');
for (let i = 0; i < splitted.length; i++) {
const s = splitted[i].trim();
if (!s) continue;
output.push(`${s}*`);
}
return output.join(' ');
};

View File

@@ -22,7 +22,7 @@
"@types/jest": "29.2.4",
"@types/pdfjs-dist": "2.10.378",
"@types/react": "16.14.34",
"@types/react-dom": "18.0.9",
"@types/react-dom": "18.0.10",
"@types/styled-components": "5.1.25",
"babel-jest": "29.3.1",
"css-loader": "6.7.3",

View File

@@ -29,7 +29,7 @@
"devDependencies": {
"@types/fs-extra": "9.0.13",
"@types/jest": "29.2.4",
"@types/node": "18.11.17",
"@types/node": "18.11.18",
"jest": "29.3.1",
"source-map-loader": "4.0.1",
"typescript": "4.9.4",

View File

@@ -19,7 +19,7 @@
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@types/jest": "29.2.4",
"@types/node": "18.11.17",
"@types/node": "18.11.18",
"jest": "29.3.1",
"typescript": "4.9.4"
},

View File

@@ -34,7 +34,9 @@ You can setup the container to either use an existing PostgreSQL server, or conn
### Using an existing PostgreSQL server
To use an existing PostgresSQL server, set the following environment variables in the .env file:
To use an existing PostgresSQL server, you can variables in the .env file. Either:
#### Individual variables
```conf
DB_CLIENT=pg
@@ -45,6 +47,13 @@ POSTGRES_PORT=5432
POSTGRES_HOST=localhost
```
#### Connection String
```conf
DB_CLIENT=pg
POSTGRES_CONNECTION_STRING=postgresql://username:password@your_joplin_postgres_server:5432/joplin
```
Ensure that the provided database and user exist as Joplin Server will not create them. When running on macOS or Windows through Docker Desktop, a mapping of localhost is made automatically. On Linux, you can add `--net=host --add-host=host.docker.internal:127.0.0.1` to the `docker run` command line to make the mapping happen. Any other `POSTGRES_HOST` than localhost or 127.0.0.1 should work as expected without further action.
### Using docker-compose

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/server",
"version": "2.10.4",
"version": "2.10.5",
"private": true,
"scripts": {
"start-dev": "yarn run build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",
@@ -21,11 +21,11 @@
"watch": "tsc --watch --preserveWatchOutput --project tsconfig.json"
},
"dependencies": {
"@aws-sdk/client-s3": "3.235.0",
"@aws-sdk/client-s3": "3.241.0",
"@fortawesome/fontawesome-free": "5.15.4",
"@joplin/lib": "~2.10",
"@joplin/renderer": "~2.10",
"@koa/cors": "4.0.0",
"@koa/cors": "3.1.0",
"@types/uuid": "9.0.0",
"bcryptjs": "2.4.3",
"bulma": "0.9.4",
@@ -69,7 +69,7 @@
"@types/markdown-it": "12.2.3",
"@types/mustache": "4.2.2",
"@types/nodemailer": "6.4.7",
"@types/yargs": "17.0.17",
"@types/yargs": "17.0.18",
"@types/zxcvbn": "4.4.1",
"gulp": "4.0.2",
"jest": "29.3.1",

View File

@@ -70,7 +70,7 @@ function markPasswords(o: Record<string, any>): Record<string, any> {
const output: Record<string, any> = {};
for (const k of Object.keys(o)) {
if (k.toLowerCase().includes('password') || k.toLowerCase().includes('secret')) {
if (k.toLowerCase().includes('password') || k.toLowerCase().includes('secret') || k.toLowerCase().includes('connectionstring')) {
output[k] = '********';
} else {
output[k] = o[k];
@@ -184,7 +184,7 @@ async function main() {
app.use(cors({
// https://github.com/koajs/cors/issues/52#issuecomment-413887382
origin: (ctx: AppContext) => {
const origin = ctx.request.origin;
const origin = ctx.request.header.origin;
if (acceptOrigin(origin)) {
return origin;

View File

@@ -42,15 +42,25 @@ function databaseConfigFromEnv(runningInDocker: boolean, env: EnvVariables): Dat
};
if (env.DB_CLIENT === 'pg') {
return {
const databaseConfig: DatabaseConfig = {
...baseConfig,
client: DatabaseConfigClient.PostgreSQL,
name: env.POSTGRES_DATABASE,
user: env.POSTGRES_USER,
password: env.POSTGRES_PASSWORD,
port: env.POSTGRES_PORT,
host: databaseHostFromEnv(runningInDocker, env) || 'localhost',
};
if (env.POSTGRES_CONNECTION_STRING) {
return {
...databaseConfig,
connectionString: env.POSTGRES_CONNECTION_STRING,
};
} else {
return {
...databaseConfig,
name: env.POSTGRES_DATABASE,
user: env.POSTGRES_USER,
password: env.POSTGRES_PASSWORD,
port: env.POSTGRES_PORT,
host: databaseHostFromEnv(runningInDocker, env) || 'localhost',
};
}
}
return {

View File

@@ -45,6 +45,7 @@ export interface DbConfigConnection {
database?: string;
filename?: string;
password?: string;
connectionString?: string;
}
export interface QueryContext {
@@ -77,11 +78,15 @@ export function makeKnexConfig(dbConfig: DatabaseConfig): KnexDatabaseConfig {
if (dbConfig.client === 'sqlite3') {
connection.filename = dbConfig.name;
} else {
connection.database = dbConfig.name;
connection.host = dbConfig.host;
connection.port = dbConfig.port;
connection.user = dbConfig.user;
connection.password = dbConfig.password;
if (dbConfig.connectionString) {
connection.connectionString = dbConfig.connectionString;
} else {
connection.database = dbConfig.name;
connection.host = dbConfig.host;
connection.port = dbConfig.port;
connection.user = dbConfig.user;
connection.password = dbConfig.password;
}
}
return {

View File

@@ -55,6 +55,7 @@ const defaultEnvValues: EnvVariables = {
POSTGRES_USER: 'joplin',
POSTGRES_HOST: '',
POSTGRES_PORT: 5432,
POSTGRES_CONNECTION_STRING: '',
// This must be the full path to the database file
SQLITE_DATABASE: '',
@@ -124,6 +125,7 @@ export interface EnvVariables {
POSTGRES_USER: string;
POSTGRES_HOST: string;
POSTGRES_PORT: number;
POSTGRES_CONNECTION_STRING: string;
SQLITE_DATABASE: string;

View File

@@ -65,6 +65,7 @@ export interface DatabaseConfig {
port?: number;
user?: string;
password?: string;
connectionString?: string;
asyncStackTraces?: boolean;
slowQueryLogEnabled?: boolean;
slowQueryLogMinDuration?: number;

View File

@@ -7,6 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Joplin-CLI 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: MrKanister <pueblos_spatulas@aleeas.com>\n"
"Language-Team: \n"
"Language: de_DE\n"
@@ -14,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.2.1\n"
"X-Generator: Poedit 3.2.2\n"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:609
msgid "- Camera: to allow taking a picture and attaching it to a note."
@@ -349,8 +351,8 @@ msgstr ""
#: packages/app-cli/app/command-mv.js:29
msgid ""
"Ambiguous notebook \"%s\". Please use short notebook id instead - press "
"\"ti\" to see the short notebook id"
"Ambiguous notebook \"%s\". Please use short notebook id instead - press \"ti"
"\" to see the short notebook id"
msgstr ""
"Zweideutiges Notizbuch „%s“. Bitte verwende stattdessen die kurze Notizbuch-"
"ID - drücke „ti“, um die kurze Notizbuch-ID zu sehen"
@@ -3856,9 +3858,8 @@ msgid "Stop external editing"
msgstr "Externe Bearbeitung stoppen"
#: packages/lib/utils/joplinCloud.ts:129
#, fuzzy
msgid "Storage space"
msgstr "%d GB Speicherplatz"
msgstr "Speicherplatz"
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:19
msgid "Strikethrough"
@@ -4496,8 +4497,8 @@ msgstr "Um die Konsole zu maximieren/minimieren, drücke „tc“."
#: packages/app-cli/app/command-help.js:79
msgid "To move from one pane to another, press Tab or Shift+Tab."
msgstr ""
"Um von einem Bereich zu einem anderen zu wechseln, drücke Tab oder "
"Umschalt+Tab."
"Um von einem Bereich zu einem anderen zu wechseln, drücke Tab oder Umschalt"
"+Tab."
#: packages/app-cli/app/command-status.js:44
msgid ""

View File

@@ -23,7 +23,7 @@
"@joplin/lib": "~2.10",
"@joplin/renderer": "~2.10",
"@types/node-fetch": "2.6.2",
"@types/yargs": "17.0.17",
"@types/yargs": "17.0.18",
"dayjs": "1.11.7",
"execa": "4.1.0",
"fs-extra": "11.1.0",
@@ -36,7 +36,7 @@
"node-fetch": "2.6.7",
"relative": "3.0.2",
"request": "2.88.2",
"sharp": "0.31.2",
"sharp": "0.31.3",
"source-map-support": "0.5.21",
"uri-template": "2.0.0",
"yargs": "17.6.2"
@@ -47,7 +47,7 @@
"@types/fs-extra": "9.0.13",
"@types/jest": "29.2.4",
"@types/mustache": "4.2.2",
"@types/node": "18.11.17",
"@types/node": "18.11.18",
"gettext-extractor": "3.6.0",
"gulp": "4.0.2",
"html-entities": "1.4.0",

View File

@@ -1,5 +1,22 @@
# Joplin Android app changelog
## [android-v2.10.2](https://github.com/laurent22/joplin/releases/tag/android-v2.10.2) (Pre-release) - 2023-01-02T17:44:15Z
- New: Add support for realtime search (767213c)
- Fixed: Enable autocorrect with spellcheck (#7532) (#6175 by Henry Heino)
## [android-v2.10.1](https://github.com/laurent22/joplin/releases/tag/android-v2.10.1) (Pre-release) - 2022-12-29T13:55:48Z
- Improved: Switch license to AGPL-3.0 (faf0a4e)
- Improved: Tag search case insensitive (#7368 by [@JackGruber](https://github.com/JackGruber))
- Improved: Update Mermaid: 9.1.7 to 9.2.2 (#7330 by Helmut K. C. Tessarek)
- Improved: Upgrade to react-native 0.68.5 (e2d59ee)
- Fixed: Could not attach images to notes anymore (#7471)
- Fixed: Fix CodeMirror syntax highlighting (#7386 by Henry Heino)
- Fixed: Fix attaching multiple files (#7196) (#7195 by Self Not Found)
- Fixed: Update CodeMirror (#7262) (#7253 by Henry Heino)
- Security: Fix XSS when a specially crafted string is passed to the renderer (762b4e8)
## [android-v2.9.8](https://github.com/laurent22/joplin/releases/tag/android-v2.9.8) (Pre-release) - 2022-11-01T15:45:36Z
- Updated translations

View File

@@ -1,5 +1,21 @@
# Joplin iOS app changelog
## [ios-v12.10.1](https://github.com/laurent22/joplin/releases/tag/ios-v12.10.1) - 2022-12-28T15:08:39Z
- Improved: Switch license to AGPL-3.0 (faf0a4e)
- Improved: Tag search case insensitive (#7368 by [@JackGruber](https://github.com/JackGruber))
- Improved: Update Mermaid: 9.1.7 to 9.2.2 (#7330 by Helmut K. C. Tessarek)
- Improved: Upgrade to react-native 0.68.5 (e2d59ee)
- Fixed: Fix CodeMirror syntax highlighting (#7386 by Henry Heino)
- Fixed: Fix attaching multiple files (#7196) (#7195 by Self Not Found)
- Fixed: Note viewer inertial scroll is slower than native inertial scrolling (#7470) (#7469 by Henry Heino)
- Fixed: Update CodeMirror (#7262) (#7253 by Henry Heino)
- Security: Fix XSS when a specially crafted string is passed to the renderer (a2de167)
## [ios-v12.9.2](https://github.com/laurent22/joplin/releases/tag/ios-v12.9.2) - 2022-12-22T12:42:26Z
- Fixed: Could not attach images to notes anymore (#7471)
## [ios-v12.9.1](https://github.com/laurent22/joplin/releases/tag/ios-v12.9.1) - 2022-12-04T18:03:02Z
- New: Add Markdown toolbar (#6753 by Henry Heino)

View File

@@ -1,5 +1,9 @@
# Joplin Server Changelog
## [server-v2.10.5](https://github.com/laurent22/joplin/releases/tag/server-v2.10.5) - 2022-12-26T12:09:13Z
- Fixed: Fixed regression that would prevent styles from being loaded in published notes (#7525)
## [server-v2.10.4](https://github.com/laurent22/joplin/releases/tag/server-v2.10.4) - 2022-12-18T16:02:06Z
- Fixed: Fixed regression introduced by form-parse lib update (#7463)

View File

@@ -9,9 +9,7 @@ to the license terms below. This license is for your protection as a Contributor
as well as the protection of the Company and its users; it does not change your
rights to use your own Contributions for any other purpose.
Please complete and sign this Agreement, and then email a copy to
cla@joplinapp.org only (do not copy any other persons or lists). Read this
document carefully before signing and keep a copy for your records.
Read this document carefully before signing and keep a copy for your records.
You accept and agree to the following terms and conditions for Your present and
future Contributions submitted to the Company. In return, the Company shall not

116
readme/cla_signatures.json Normal file
View File

@@ -0,0 +1,116 @@
{
"signedContributors": [
{
"name": "laurent22",
"id": 1285584,
"comment_id": 1361665980,
"created_at": "2022-12-21T16:54:13Z",
"repoId": 79162682,
"pullRequestNo": 7510
},
{
"name": "wh201906",
"id": 62299611,
"comment_id": 1361737493,
"created_at": "2022-12-21T17:39:56Z",
"repoId": 79162682,
"pullRequestNo": 6865
},
{
"name": "personalizedrefrigerator",
"id": 46334387,
"comment_id": 1362101229,
"created_at": "2022-12-21T21:22:16Z",
"repoId": 79162682,
"pullRequestNo": 7470
},
{
"name": "gtlsgamr",
"id": 47787284,
"comment_id": 1362615340,
"created_at": "2022-12-22T09:34:59Z",
"repoId": 79162682,
"pullRequestNo": 7515
},
{
"name": "halkeye",
"id": 110087,
"comment_id": 1363180252,
"created_at": "2022-12-22T17:52:26Z",
"repoId": 79162682,
"pullRequestNo": 6836
},
{
"name": "Wartijn",
"id": 10060747,
"comment_id": 1364085068,
"created_at": "2022-12-23T16:13:19Z",
"repoId": 79162682,
"pullRequestNo": 6886
},
{
"name": "betty-alagwu",
"id": 94234459,
"comment_id": 1364449008,
"created_at": "2022-12-24T03:08:45Z",
"repoId": 79162682,
"pullRequestNo": 7529
},
{
"name": "Mr-Kanister",
"id": 68117355,
"comment_id": 1364570129,
"created_at": "2022-12-24T18:40:22Z",
"repoId": 79162682,
"pullRequestNo": 7531
},
{
"name": "ken1kob",
"id": 16041683,
"comment_id": 1365087509,
"created_at": "2022-12-26T11:01:50Z",
"repoId": 79162682,
"pullRequestNo": 6469
},
{
"name": "ManavSarkar",
"id": 42129636,
"comment_id": 1365803305,
"created_at": "2022-12-27T10:48:19Z",
"repoId": 79162682,
"pullRequestNo": 7541
},
{
"name": "asrient",
"id": 44570278,
"comment_id": 1366066282,
"created_at": "2022-12-27T17:34:03Z",
"repoId": 79162682,
"pullRequestNo": 6845
},
{
"name": "adarsh-sgh",
"id": 63918341,
"comment_id": 1366468835,
"created_at": "2022-12-28T08:38:24Z",
"repoId": 79162682,
"pullRequestNo": 7546
},
{
"name": "k33pn3xtlvl",
"id": 81777961,
"comment_id": 1367922850,
"created_at": "2022-12-30T13:34:36Z",
"repoId": 79162682,
"pullRequestNo": 6722
},
{
"name": "roman-r-m",
"id": 995612,
"comment_id": 1368097337,
"created_at": "2022-12-30T21:35:22Z",
"repoId": 79162682,
"pullRequestNo": 7559
}
]
}

View File

@@ -84,6 +84,7 @@
"jsc-android",
"react-native",
"@babel/runtime",
"de.undercouch:gradle-download-task",
// Need special processing when upgrading
"katex",

1669
yarn.lock

File diff suppressed because it is too large Load Diff