You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-29 23:48:19 +02:00
Compare commits
59 Commits
cli-v1.5.1
...
ios_releas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3854ec350 | ||
|
|
c2c737541d | ||
|
|
5b295d5f6f | ||
|
|
0be8cdf760 | ||
|
|
545940f545 | ||
|
|
d58f39823a | ||
|
|
f9fb1b8a81 | ||
|
|
56ded0062a | ||
|
|
83b29d7c51 | ||
|
|
1ec0746263 | ||
|
|
568d11bddf | ||
|
|
97b25ac99d | ||
|
|
7f1d3d8a5d | ||
|
|
fde201fbe9 | ||
|
|
694a1b4ede | ||
|
|
20d126b39d | ||
|
|
8ca9c3092a | ||
|
|
d2771029a3 | ||
|
|
4128c53fcf | ||
|
|
a14410b28c | ||
|
|
d1f8520e6e | ||
|
|
d76746b8e4 | ||
|
|
89d173b460 | ||
|
|
81aba8b8b0 | ||
|
|
f48697572d | ||
|
|
e61e8b7b94 | ||
|
|
1deab7e8d1 | ||
|
|
86b28b5ecf | ||
|
|
938e723434 | ||
|
|
ee2ec28cd4 | ||
|
|
9dc505e85b | ||
|
|
3df31584af | ||
|
|
a7e3b381cb | ||
|
|
70381a233b | ||
|
|
2966fe0df2 | ||
|
|
143f0b4bc5 | ||
|
|
24ec3b8897 | ||
|
|
01aa4f9d5e | ||
|
|
520efdcb39 | ||
|
|
34a99f738c | ||
|
|
0e0de1207f | ||
|
|
2fda067034 | ||
|
|
29177330b0 | ||
|
|
66a5490b54 | ||
|
|
469cd19ec1 | ||
|
|
41684a64ef | ||
|
|
2cd7839552 | ||
|
|
c3d4617612 | ||
|
|
158fafc4a0 | ||
|
|
0f59731c06 | ||
|
|
d0f1a67d96 | ||
|
|
2a1434f987 | ||
|
|
1ee177880d | ||
|
|
f6d899eb29 | ||
|
|
a97f25fd61 | ||
|
|
325a5ab08f | ||
|
|
c158878b66 | ||
|
|
0f0f9c1161 | ||
|
|
79612163b2 |
9
.dockerignore
Normal file
9
.dockerignore
Normal file
@@ -0,0 +1,9 @@
|
||||
**/node_modules
|
||||
Assets/
|
||||
.git/
|
||||
_releases/
|
||||
packages/app-desktop
|
||||
packages/app-cli
|
||||
packages/app-mobile
|
||||
packages/app-clipper
|
||||
packages/generator-joplin
|
||||
9
.env-sample
Normal file
9
.env-sample
Normal file
@@ -0,0 +1,9 @@
|
||||
# Example of local config, for development:
|
||||
#
|
||||
# JOPLIN_BASE_URL=http://localhost:22300
|
||||
# JOPLIN_PORT=22300
|
||||
|
||||
# Example of config for production:
|
||||
#
|
||||
# JOPLIN_BASE_URL=https://example.com/joplin
|
||||
# JOPLIN_PORT=22300
|
||||
250
.eslintignore
250
.eslintignore
@@ -6,6 +6,7 @@ _releases/
|
||||
**/node_modules/
|
||||
Assets/
|
||||
docs/
|
||||
packages/server/dist/
|
||||
highlight.pack.js
|
||||
Modules/TinyMCE/IconPack/postinstall.js
|
||||
Modules/TinyMCE/JoplinLists/
|
||||
@@ -802,6 +803,9 @@ packages/app-mobile/components/screens/Note.js.map
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.d.ts
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
|
||||
packages/app-mobile/root.d.ts
|
||||
packages/app-mobile/root.js
|
||||
packages/app-mobile/root.js.map
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.d.ts
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.js
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.js.map
|
||||
@@ -889,12 +893,18 @@ packages/lib/InMemoryCache.js.map
|
||||
packages/lib/JoplinServerApi.d.ts
|
||||
packages/lib/JoplinServerApi.js
|
||||
packages/lib/JoplinServerApi.js.map
|
||||
packages/lib/JoplinServerApi2.d.ts
|
||||
packages/lib/JoplinServerApi2.js
|
||||
packages/lib/JoplinServerApi2.js.map
|
||||
packages/lib/Logger.d.ts
|
||||
packages/lib/Logger.js
|
||||
packages/lib/Logger.js.map
|
||||
packages/lib/PoorManIntervals.d.ts
|
||||
packages/lib/PoorManIntervals.js
|
||||
packages/lib/PoorManIntervals.js.map
|
||||
packages/lib/SyncTargetJoplinServer.d.ts
|
||||
packages/lib/SyncTargetJoplinServer.js
|
||||
packages/lib/SyncTargetJoplinServer.js.map
|
||||
packages/lib/Synchronizer.d.ts
|
||||
packages/lib/Synchronizer.js
|
||||
packages/lib/Synchronizer.js.map
|
||||
@@ -916,12 +926,18 @@ packages/lib/errorUtils.js.map
|
||||
packages/lib/eventManager.d.ts
|
||||
packages/lib/eventManager.js
|
||||
packages/lib/eventManager.js.map
|
||||
packages/lib/file-api-driver-joplinServer.d.ts
|
||||
packages/lib/file-api-driver-joplinServer.js
|
||||
packages/lib/file-api-driver-joplinServer.js.map
|
||||
packages/lib/fs-driver-base.d.ts
|
||||
packages/lib/fs-driver-base.js
|
||||
packages/lib/fs-driver-base.js.map
|
||||
packages/lib/fs-driver-node.d.ts
|
||||
packages/lib/fs-driver-node.js
|
||||
packages/lib/fs-driver-node.js.map
|
||||
packages/lib/import-enex-md-gen.d.ts
|
||||
packages/lib/import-enex-md-gen.js
|
||||
packages/lib/import-enex-md-gen.js.map
|
||||
packages/lib/locale.d.ts
|
||||
packages/lib/locale.js
|
||||
packages/lib/locale.js.map
|
||||
@@ -1387,4 +1403,238 @@ packages/renderer/pathUtils.js.map
|
||||
packages/renderer/utils.d.ts
|
||||
packages/renderer/utils.js
|
||||
packages/renderer/utils.js.map
|
||||
packages/server/src/app.d.ts
|
||||
packages/server/src/app.js
|
||||
packages/server/src/app.js.map
|
||||
packages/server/src/config-base.d.ts
|
||||
packages/server/src/config-base.js
|
||||
packages/server/src/config-base.js.map
|
||||
packages/server/src/config-buildTypes.d.ts
|
||||
packages/server/src/config-buildTypes.js
|
||||
packages/server/src/config-buildTypes.js.map
|
||||
packages/server/src/config-dev.d.ts
|
||||
packages/server/src/config-dev.js
|
||||
packages/server/src/config-dev.js.map
|
||||
packages/server/src/config-prod.d.ts
|
||||
packages/server/src/config-prod.js
|
||||
packages/server/src/config-prod.js.map
|
||||
packages/server/src/config-tests.d.ts
|
||||
packages/server/src/config-tests.js
|
||||
packages/server/src/config-tests.js.map
|
||||
packages/server/src/config.d.ts
|
||||
packages/server/src/config.js
|
||||
packages/server/src/config.js.map
|
||||
packages/server/src/controllers/BaseController.d.ts
|
||||
packages/server/src/controllers/BaseController.js
|
||||
packages/server/src/controllers/BaseController.js.map
|
||||
packages/server/src/controllers/api/FileController.d.ts
|
||||
packages/server/src/controllers/api/FileController.js
|
||||
packages/server/src/controllers/api/FileController.js.map
|
||||
packages/server/src/controllers/api/FileController.test.d.ts
|
||||
packages/server/src/controllers/api/FileController.test.js
|
||||
packages/server/src/controllers/api/FileController.test.js.map
|
||||
packages/server/src/controllers/api/OAuthController.d.ts
|
||||
packages/server/src/controllers/api/OAuthController.js
|
||||
packages/server/src/controllers/api/OAuthController.js.map
|
||||
packages/server/src/controllers/api/SessionController.d.ts
|
||||
packages/server/src/controllers/api/SessionController.js
|
||||
packages/server/src/controllers/api/SessionController.js.map
|
||||
packages/server/src/controllers/api/SessionController.test.d.ts
|
||||
packages/server/src/controllers/api/SessionController.test.js
|
||||
packages/server/src/controllers/api/SessionController.test.js.map
|
||||
packages/server/src/controllers/api/UserController.d.ts
|
||||
packages/server/src/controllers/api/UserController.js
|
||||
packages/server/src/controllers/api/UserController.js.map
|
||||
packages/server/src/controllers/api/UserController.test.d.ts
|
||||
packages/server/src/controllers/api/UserController.test.js
|
||||
packages/server/src/controllers/api/UserController.test.js.map
|
||||
packages/server/src/controllers/factory.d.ts
|
||||
packages/server/src/controllers/factory.js
|
||||
packages/server/src/controllers/factory.js.map
|
||||
packages/server/src/controllers/index/FileController.d.ts
|
||||
packages/server/src/controllers/index/FileController.js
|
||||
packages/server/src/controllers/index/FileController.js.map
|
||||
packages/server/src/controllers/index/HomeController.d.ts
|
||||
packages/server/src/controllers/index/HomeController.js
|
||||
packages/server/src/controllers/index/HomeController.js.map
|
||||
packages/server/src/controllers/index/LoginController.d.ts
|
||||
packages/server/src/controllers/index/LoginController.js
|
||||
packages/server/src/controllers/index/LoginController.js.map
|
||||
packages/server/src/controllers/index/NotificationController.d.ts
|
||||
packages/server/src/controllers/index/NotificationController.js
|
||||
packages/server/src/controllers/index/NotificationController.js.map
|
||||
packages/server/src/controllers/index/ProfileController.d.ts
|
||||
packages/server/src/controllers/index/ProfileController.js
|
||||
packages/server/src/controllers/index/ProfileController.js.map
|
||||
packages/server/src/controllers/index/UserController.d.ts
|
||||
packages/server/src/controllers/index/UserController.js
|
||||
packages/server/src/controllers/index/UserController.js.map
|
||||
packages/server/src/db.d.ts
|
||||
packages/server/src/db.js
|
||||
packages/server/src/db.js.map
|
||||
packages/server/src/middleware/notificationHandler.d.ts
|
||||
packages/server/src/middleware/notificationHandler.js
|
||||
packages/server/src/middleware/notificationHandler.js.map
|
||||
packages/server/src/middleware/ownerHandler.d.ts
|
||||
packages/server/src/middleware/ownerHandler.js
|
||||
packages/server/src/middleware/ownerHandler.js.map
|
||||
packages/server/src/middleware/routeHandler.d.ts
|
||||
packages/server/src/middleware/routeHandler.js
|
||||
packages/server/src/middleware/routeHandler.js.map
|
||||
packages/server/src/migrations/20190913171451_create.d.ts
|
||||
packages/server/src/migrations/20190913171451_create.js
|
||||
packages/server/src/migrations/20190913171451_create.js.map
|
||||
packages/server/src/migrations/20203012152842_notifications.d.ts
|
||||
packages/server/src/migrations/20203012152842_notifications.js
|
||||
packages/server/src/migrations/20203012152842_notifications.js.map
|
||||
packages/server/src/models/ApiClientModel.d.ts
|
||||
packages/server/src/models/ApiClientModel.js
|
||||
packages/server/src/models/ApiClientModel.js.map
|
||||
packages/server/src/models/BaseModel.d.ts
|
||||
packages/server/src/models/BaseModel.js
|
||||
packages/server/src/models/BaseModel.js.map
|
||||
packages/server/src/models/ChangeModel.d.ts
|
||||
packages/server/src/models/ChangeModel.js
|
||||
packages/server/src/models/ChangeModel.js.map
|
||||
packages/server/src/models/ChangeModel.test.d.ts
|
||||
packages/server/src/models/ChangeModel.test.js
|
||||
packages/server/src/models/ChangeModel.test.js.map
|
||||
packages/server/src/models/FileModel.d.ts
|
||||
packages/server/src/models/FileModel.js
|
||||
packages/server/src/models/FileModel.js.map
|
||||
packages/server/src/models/FileModel.test.d.ts
|
||||
packages/server/src/models/FileModel.test.js
|
||||
packages/server/src/models/FileModel.test.js.map
|
||||
packages/server/src/models/NotificationModel.d.ts
|
||||
packages/server/src/models/NotificationModel.js
|
||||
packages/server/src/models/NotificationModel.js.map
|
||||
packages/server/src/models/NotificationModel.test.d.ts
|
||||
packages/server/src/models/NotificationModel.test.js
|
||||
packages/server/src/models/NotificationModel.test.js.map
|
||||
packages/server/src/models/PermissionModel.d.ts
|
||||
packages/server/src/models/PermissionModel.js
|
||||
packages/server/src/models/PermissionModel.js.map
|
||||
packages/server/src/models/SessionModel.d.ts
|
||||
packages/server/src/models/SessionModel.js
|
||||
packages/server/src/models/SessionModel.js.map
|
||||
packages/server/src/models/UserModel.d.ts
|
||||
packages/server/src/models/UserModel.js
|
||||
packages/server/src/models/UserModel.js.map
|
||||
packages/server/src/models/factory.d.ts
|
||||
packages/server/src/models/factory.js
|
||||
packages/server/src/models/factory.js.map
|
||||
packages/server/src/models/utils/pagination.d.ts
|
||||
packages/server/src/models/utils/pagination.js
|
||||
packages/server/src/models/utils/pagination.js.map
|
||||
packages/server/src/models/utils/pagination.test.d.ts
|
||||
packages/server/src/models/utils/pagination.test.js
|
||||
packages/server/src/models/utils/pagination.test.js.map
|
||||
packages/server/src/routes/api/files.d.ts
|
||||
packages/server/src/routes/api/files.js
|
||||
packages/server/src/routes/api/files.js.map
|
||||
packages/server/src/routes/api/index.d.ts
|
||||
packages/server/src/routes/api/index.js
|
||||
packages/server/src/routes/api/index.js.map
|
||||
packages/server/src/routes/api/ping.d.ts
|
||||
packages/server/src/routes/api/ping.js
|
||||
packages/server/src/routes/api/ping.js.map
|
||||
packages/server/src/routes/api/sessions.d.ts
|
||||
packages/server/src/routes/api/sessions.js
|
||||
packages/server/src/routes/api/sessions.js.map
|
||||
packages/server/src/routes/default.d.ts
|
||||
packages/server/src/routes/default.js
|
||||
packages/server/src/routes/default.js.map
|
||||
packages/server/src/routes/index/files.d.ts
|
||||
packages/server/src/routes/index/files.js
|
||||
packages/server/src/routes/index/files.js.map
|
||||
packages/server/src/routes/index/home.d.ts
|
||||
packages/server/src/routes/index/home.js
|
||||
packages/server/src/routes/index/home.js.map
|
||||
packages/server/src/routes/index/login.d.ts
|
||||
packages/server/src/routes/index/login.js
|
||||
packages/server/src/routes/index/login.js.map
|
||||
packages/server/src/routes/index/logout.d.ts
|
||||
packages/server/src/routes/index/logout.js
|
||||
packages/server/src/routes/index/logout.js.map
|
||||
packages/server/src/routes/index/notifications.d.ts
|
||||
packages/server/src/routes/index/notifications.js
|
||||
packages/server/src/routes/index/notifications.js.map
|
||||
packages/server/src/routes/index/profile.d.ts
|
||||
packages/server/src/routes/index/profile.js
|
||||
packages/server/src/routes/index/profile.js.map
|
||||
packages/server/src/routes/index/user.d.ts
|
||||
packages/server/src/routes/index/user.js
|
||||
packages/server/src/routes/index/user.js.map
|
||||
packages/server/src/routes/index/users.d.ts
|
||||
packages/server/src/routes/index/users.js
|
||||
packages/server/src/routes/index/users.js.map
|
||||
packages/server/src/routes/oauth2/authorize.d.ts
|
||||
packages/server/src/routes/oauth2/authorize.js
|
||||
packages/server/src/routes/oauth2/authorize.js.map
|
||||
packages/server/src/routes/routes.d.ts
|
||||
packages/server/src/routes/routes.js
|
||||
packages/server/src/routes/routes.js.map
|
||||
packages/server/src/services/MustacheService.d.ts
|
||||
packages/server/src/services/MustacheService.js
|
||||
packages/server/src/services/MustacheService.js.map
|
||||
packages/server/src/tools/db-migrate.d.ts
|
||||
packages/server/src/tools/db-migrate.js
|
||||
packages/server/src/tools/db-migrate.js.map
|
||||
packages/server/src/tools/dbTools.d.ts
|
||||
packages/server/src/tools/dbTools.js
|
||||
packages/server/src/tools/dbTools.js.map
|
||||
packages/server/src/tools/generate-types.d.ts
|
||||
packages/server/src/tools/generate-types.js
|
||||
packages/server/src/tools/generate-types.js.map
|
||||
packages/server/src/utils/TransactionHandler.d.ts
|
||||
packages/server/src/utils/TransactionHandler.js
|
||||
packages/server/src/utils/TransactionHandler.js.map
|
||||
packages/server/src/utils/auth.d.ts
|
||||
packages/server/src/utils/auth.js
|
||||
packages/server/src/utils/auth.js.map
|
||||
packages/server/src/utils/base64.d.ts
|
||||
packages/server/src/utils/base64.js
|
||||
packages/server/src/utils/base64.js.map
|
||||
packages/server/src/utils/cache.d.ts
|
||||
packages/server/src/utils/cache.js
|
||||
packages/server/src/utils/cache.js.map
|
||||
packages/server/src/utils/defaultView.d.ts
|
||||
packages/server/src/utils/defaultView.js
|
||||
packages/server/src/utils/defaultView.js.map
|
||||
packages/server/src/utils/errors.d.ts
|
||||
packages/server/src/utils/errors.js
|
||||
packages/server/src/utils/errors.js.map
|
||||
packages/server/src/utils/htmlUtils.d.ts
|
||||
packages/server/src/utils/htmlUtils.js
|
||||
packages/server/src/utils/htmlUtils.js.map
|
||||
packages/server/src/utils/koaIf.d.ts
|
||||
packages/server/src/utils/koaIf.js
|
||||
packages/server/src/utils/koaIf.js.map
|
||||
packages/server/src/utils/requestUtils.d.ts
|
||||
packages/server/src/utils/requestUtils.js
|
||||
packages/server/src/utils/requestUtils.js.map
|
||||
packages/server/src/utils/routeUtils.d.ts
|
||||
packages/server/src/utils/routeUtils.js
|
||||
packages/server/src/utils/routeUtils.js.map
|
||||
packages/server/src/utils/routeUtils.test.d.ts
|
||||
packages/server/src/utils/routeUtils.test.js
|
||||
packages/server/src/utils/routeUtils.test.js.map
|
||||
packages/server/src/utils/testUtils.d.ts
|
||||
packages/server/src/utils/testUtils.js
|
||||
packages/server/src/utils/testUtils.js.map
|
||||
packages/server/src/utils/testing/testRouters.d.ts
|
||||
packages/server/src/utils/testing/testRouters.js
|
||||
packages/server/src/utils/testing/testRouters.js.map
|
||||
packages/server/src/utils/time.d.ts
|
||||
packages/server/src/utils/time.js
|
||||
packages/server/src/utils/time.js.map
|
||||
packages/server/src/utils/types.d.ts
|
||||
packages/server/src/utils/types.js
|
||||
packages/server/src/utils/types.js.map
|
||||
packages/server/src/utils/urlUtils.d.ts
|
||||
packages/server/src/utils/urlUtils.js
|
||||
packages/server/src/utils/urlUtils.js.map
|
||||
packages/server/src/utils/uuidgen.d.ts
|
||||
packages/server/src/utils/uuidgen.js
|
||||
packages/server/src/utils/uuidgen.js.map
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
|
||||
11
.eslintrc.js
11
.eslintrc.js
@@ -1,4 +1,5 @@
|
||||
module.exports = {
|
||||
'root': true,
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es6': true,
|
||||
@@ -34,6 +35,9 @@ module.exports = {
|
||||
'chrome': 'readonly',
|
||||
'browser': 'readonly',
|
||||
|
||||
// Server admin UI global variables
|
||||
'onDocumentReady': 'readonly',
|
||||
|
||||
'tinymce': 'readonly',
|
||||
},
|
||||
'parserOptions': {
|
||||
@@ -61,7 +65,12 @@ module.exports = {
|
||||
'no-var': ['error'],
|
||||
'no-new-func': ['error'],
|
||||
'import/prefer-default-export': ['error'],
|
||||
'import/first': ['error'],
|
||||
|
||||
// This rule should not be enabled since it matters in what order
|
||||
// imports are done, in particular in relation to the shim.setReact
|
||||
// call, which should be done first, but this rule might move it down.
|
||||
// 'import/first': ['error'],
|
||||
|
||||
'no-array-constructor': ['error'],
|
||||
'radix': ['error'],
|
||||
|
||||
|
||||
250
.gitignore
vendored
250
.gitignore
vendored
@@ -48,6 +48,7 @@ TODO.md
|
||||
packages/tools/commit_hook.txt
|
||||
packages/tools/github_oauth_token.txt
|
||||
lerna-debug.log
|
||||
.env
|
||||
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
packages/app-cli/app/LinkSelector.d.ts
|
||||
@@ -791,6 +792,9 @@ packages/app-mobile/components/screens/Note.js.map
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.d.ts
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
|
||||
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
|
||||
packages/app-mobile/root.d.ts
|
||||
packages/app-mobile/root.js
|
||||
packages/app-mobile/root.js.map
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.d.ts
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.js
|
||||
packages/app-mobile/services/AlarmServiceDriver.android.js.map
|
||||
@@ -878,12 +882,18 @@ packages/lib/InMemoryCache.js.map
|
||||
packages/lib/JoplinServerApi.d.ts
|
||||
packages/lib/JoplinServerApi.js
|
||||
packages/lib/JoplinServerApi.js.map
|
||||
packages/lib/JoplinServerApi2.d.ts
|
||||
packages/lib/JoplinServerApi2.js
|
||||
packages/lib/JoplinServerApi2.js.map
|
||||
packages/lib/Logger.d.ts
|
||||
packages/lib/Logger.js
|
||||
packages/lib/Logger.js.map
|
||||
packages/lib/PoorManIntervals.d.ts
|
||||
packages/lib/PoorManIntervals.js
|
||||
packages/lib/PoorManIntervals.js.map
|
||||
packages/lib/SyncTargetJoplinServer.d.ts
|
||||
packages/lib/SyncTargetJoplinServer.js
|
||||
packages/lib/SyncTargetJoplinServer.js.map
|
||||
packages/lib/Synchronizer.d.ts
|
||||
packages/lib/Synchronizer.js
|
||||
packages/lib/Synchronizer.js.map
|
||||
@@ -905,12 +915,18 @@ packages/lib/errorUtils.js.map
|
||||
packages/lib/eventManager.d.ts
|
||||
packages/lib/eventManager.js
|
||||
packages/lib/eventManager.js.map
|
||||
packages/lib/file-api-driver-joplinServer.d.ts
|
||||
packages/lib/file-api-driver-joplinServer.js
|
||||
packages/lib/file-api-driver-joplinServer.js.map
|
||||
packages/lib/fs-driver-base.d.ts
|
||||
packages/lib/fs-driver-base.js
|
||||
packages/lib/fs-driver-base.js.map
|
||||
packages/lib/fs-driver-node.d.ts
|
||||
packages/lib/fs-driver-node.js
|
||||
packages/lib/fs-driver-node.js.map
|
||||
packages/lib/import-enex-md-gen.d.ts
|
||||
packages/lib/import-enex-md-gen.js
|
||||
packages/lib/import-enex-md-gen.js.map
|
||||
packages/lib/locale.d.ts
|
||||
packages/lib/locale.js
|
||||
packages/lib/locale.js.map
|
||||
@@ -1376,4 +1392,238 @@ packages/renderer/pathUtils.js.map
|
||||
packages/renderer/utils.d.ts
|
||||
packages/renderer/utils.js
|
||||
packages/renderer/utils.js.map
|
||||
packages/server/src/app.d.ts
|
||||
packages/server/src/app.js
|
||||
packages/server/src/app.js.map
|
||||
packages/server/src/config-base.d.ts
|
||||
packages/server/src/config-base.js
|
||||
packages/server/src/config-base.js.map
|
||||
packages/server/src/config-buildTypes.d.ts
|
||||
packages/server/src/config-buildTypes.js
|
||||
packages/server/src/config-buildTypes.js.map
|
||||
packages/server/src/config-dev.d.ts
|
||||
packages/server/src/config-dev.js
|
||||
packages/server/src/config-dev.js.map
|
||||
packages/server/src/config-prod.d.ts
|
||||
packages/server/src/config-prod.js
|
||||
packages/server/src/config-prod.js.map
|
||||
packages/server/src/config-tests.d.ts
|
||||
packages/server/src/config-tests.js
|
||||
packages/server/src/config-tests.js.map
|
||||
packages/server/src/config.d.ts
|
||||
packages/server/src/config.js
|
||||
packages/server/src/config.js.map
|
||||
packages/server/src/controllers/BaseController.d.ts
|
||||
packages/server/src/controllers/BaseController.js
|
||||
packages/server/src/controllers/BaseController.js.map
|
||||
packages/server/src/controllers/api/FileController.d.ts
|
||||
packages/server/src/controllers/api/FileController.js
|
||||
packages/server/src/controllers/api/FileController.js.map
|
||||
packages/server/src/controllers/api/FileController.test.d.ts
|
||||
packages/server/src/controllers/api/FileController.test.js
|
||||
packages/server/src/controllers/api/FileController.test.js.map
|
||||
packages/server/src/controllers/api/OAuthController.d.ts
|
||||
packages/server/src/controllers/api/OAuthController.js
|
||||
packages/server/src/controllers/api/OAuthController.js.map
|
||||
packages/server/src/controllers/api/SessionController.d.ts
|
||||
packages/server/src/controllers/api/SessionController.js
|
||||
packages/server/src/controllers/api/SessionController.js.map
|
||||
packages/server/src/controllers/api/SessionController.test.d.ts
|
||||
packages/server/src/controllers/api/SessionController.test.js
|
||||
packages/server/src/controllers/api/SessionController.test.js.map
|
||||
packages/server/src/controllers/api/UserController.d.ts
|
||||
packages/server/src/controllers/api/UserController.js
|
||||
packages/server/src/controllers/api/UserController.js.map
|
||||
packages/server/src/controllers/api/UserController.test.d.ts
|
||||
packages/server/src/controllers/api/UserController.test.js
|
||||
packages/server/src/controllers/api/UserController.test.js.map
|
||||
packages/server/src/controllers/factory.d.ts
|
||||
packages/server/src/controllers/factory.js
|
||||
packages/server/src/controllers/factory.js.map
|
||||
packages/server/src/controllers/index/FileController.d.ts
|
||||
packages/server/src/controllers/index/FileController.js
|
||||
packages/server/src/controllers/index/FileController.js.map
|
||||
packages/server/src/controllers/index/HomeController.d.ts
|
||||
packages/server/src/controllers/index/HomeController.js
|
||||
packages/server/src/controllers/index/HomeController.js.map
|
||||
packages/server/src/controllers/index/LoginController.d.ts
|
||||
packages/server/src/controllers/index/LoginController.js
|
||||
packages/server/src/controllers/index/LoginController.js.map
|
||||
packages/server/src/controllers/index/NotificationController.d.ts
|
||||
packages/server/src/controllers/index/NotificationController.js
|
||||
packages/server/src/controllers/index/NotificationController.js.map
|
||||
packages/server/src/controllers/index/ProfileController.d.ts
|
||||
packages/server/src/controllers/index/ProfileController.js
|
||||
packages/server/src/controllers/index/ProfileController.js.map
|
||||
packages/server/src/controllers/index/UserController.d.ts
|
||||
packages/server/src/controllers/index/UserController.js
|
||||
packages/server/src/controllers/index/UserController.js.map
|
||||
packages/server/src/db.d.ts
|
||||
packages/server/src/db.js
|
||||
packages/server/src/db.js.map
|
||||
packages/server/src/middleware/notificationHandler.d.ts
|
||||
packages/server/src/middleware/notificationHandler.js
|
||||
packages/server/src/middleware/notificationHandler.js.map
|
||||
packages/server/src/middleware/ownerHandler.d.ts
|
||||
packages/server/src/middleware/ownerHandler.js
|
||||
packages/server/src/middleware/ownerHandler.js.map
|
||||
packages/server/src/middleware/routeHandler.d.ts
|
||||
packages/server/src/middleware/routeHandler.js
|
||||
packages/server/src/middleware/routeHandler.js.map
|
||||
packages/server/src/migrations/20190913171451_create.d.ts
|
||||
packages/server/src/migrations/20190913171451_create.js
|
||||
packages/server/src/migrations/20190913171451_create.js.map
|
||||
packages/server/src/migrations/20203012152842_notifications.d.ts
|
||||
packages/server/src/migrations/20203012152842_notifications.js
|
||||
packages/server/src/migrations/20203012152842_notifications.js.map
|
||||
packages/server/src/models/ApiClientModel.d.ts
|
||||
packages/server/src/models/ApiClientModel.js
|
||||
packages/server/src/models/ApiClientModel.js.map
|
||||
packages/server/src/models/BaseModel.d.ts
|
||||
packages/server/src/models/BaseModel.js
|
||||
packages/server/src/models/BaseModel.js.map
|
||||
packages/server/src/models/ChangeModel.d.ts
|
||||
packages/server/src/models/ChangeModel.js
|
||||
packages/server/src/models/ChangeModel.js.map
|
||||
packages/server/src/models/ChangeModel.test.d.ts
|
||||
packages/server/src/models/ChangeModel.test.js
|
||||
packages/server/src/models/ChangeModel.test.js.map
|
||||
packages/server/src/models/FileModel.d.ts
|
||||
packages/server/src/models/FileModel.js
|
||||
packages/server/src/models/FileModel.js.map
|
||||
packages/server/src/models/FileModel.test.d.ts
|
||||
packages/server/src/models/FileModel.test.js
|
||||
packages/server/src/models/FileModel.test.js.map
|
||||
packages/server/src/models/NotificationModel.d.ts
|
||||
packages/server/src/models/NotificationModel.js
|
||||
packages/server/src/models/NotificationModel.js.map
|
||||
packages/server/src/models/NotificationModel.test.d.ts
|
||||
packages/server/src/models/NotificationModel.test.js
|
||||
packages/server/src/models/NotificationModel.test.js.map
|
||||
packages/server/src/models/PermissionModel.d.ts
|
||||
packages/server/src/models/PermissionModel.js
|
||||
packages/server/src/models/PermissionModel.js.map
|
||||
packages/server/src/models/SessionModel.d.ts
|
||||
packages/server/src/models/SessionModel.js
|
||||
packages/server/src/models/SessionModel.js.map
|
||||
packages/server/src/models/UserModel.d.ts
|
||||
packages/server/src/models/UserModel.js
|
||||
packages/server/src/models/UserModel.js.map
|
||||
packages/server/src/models/factory.d.ts
|
||||
packages/server/src/models/factory.js
|
||||
packages/server/src/models/factory.js.map
|
||||
packages/server/src/models/utils/pagination.d.ts
|
||||
packages/server/src/models/utils/pagination.js
|
||||
packages/server/src/models/utils/pagination.js.map
|
||||
packages/server/src/models/utils/pagination.test.d.ts
|
||||
packages/server/src/models/utils/pagination.test.js
|
||||
packages/server/src/models/utils/pagination.test.js.map
|
||||
packages/server/src/routes/api/files.d.ts
|
||||
packages/server/src/routes/api/files.js
|
||||
packages/server/src/routes/api/files.js.map
|
||||
packages/server/src/routes/api/index.d.ts
|
||||
packages/server/src/routes/api/index.js
|
||||
packages/server/src/routes/api/index.js.map
|
||||
packages/server/src/routes/api/ping.d.ts
|
||||
packages/server/src/routes/api/ping.js
|
||||
packages/server/src/routes/api/ping.js.map
|
||||
packages/server/src/routes/api/sessions.d.ts
|
||||
packages/server/src/routes/api/sessions.js
|
||||
packages/server/src/routes/api/sessions.js.map
|
||||
packages/server/src/routes/default.d.ts
|
||||
packages/server/src/routes/default.js
|
||||
packages/server/src/routes/default.js.map
|
||||
packages/server/src/routes/index/files.d.ts
|
||||
packages/server/src/routes/index/files.js
|
||||
packages/server/src/routes/index/files.js.map
|
||||
packages/server/src/routes/index/home.d.ts
|
||||
packages/server/src/routes/index/home.js
|
||||
packages/server/src/routes/index/home.js.map
|
||||
packages/server/src/routes/index/login.d.ts
|
||||
packages/server/src/routes/index/login.js
|
||||
packages/server/src/routes/index/login.js.map
|
||||
packages/server/src/routes/index/logout.d.ts
|
||||
packages/server/src/routes/index/logout.js
|
||||
packages/server/src/routes/index/logout.js.map
|
||||
packages/server/src/routes/index/notifications.d.ts
|
||||
packages/server/src/routes/index/notifications.js
|
||||
packages/server/src/routes/index/notifications.js.map
|
||||
packages/server/src/routes/index/profile.d.ts
|
||||
packages/server/src/routes/index/profile.js
|
||||
packages/server/src/routes/index/profile.js.map
|
||||
packages/server/src/routes/index/user.d.ts
|
||||
packages/server/src/routes/index/user.js
|
||||
packages/server/src/routes/index/user.js.map
|
||||
packages/server/src/routes/index/users.d.ts
|
||||
packages/server/src/routes/index/users.js
|
||||
packages/server/src/routes/index/users.js.map
|
||||
packages/server/src/routes/oauth2/authorize.d.ts
|
||||
packages/server/src/routes/oauth2/authorize.js
|
||||
packages/server/src/routes/oauth2/authorize.js.map
|
||||
packages/server/src/routes/routes.d.ts
|
||||
packages/server/src/routes/routes.js
|
||||
packages/server/src/routes/routes.js.map
|
||||
packages/server/src/services/MustacheService.d.ts
|
||||
packages/server/src/services/MustacheService.js
|
||||
packages/server/src/services/MustacheService.js.map
|
||||
packages/server/src/tools/db-migrate.d.ts
|
||||
packages/server/src/tools/db-migrate.js
|
||||
packages/server/src/tools/db-migrate.js.map
|
||||
packages/server/src/tools/dbTools.d.ts
|
||||
packages/server/src/tools/dbTools.js
|
||||
packages/server/src/tools/dbTools.js.map
|
||||
packages/server/src/tools/generate-types.d.ts
|
||||
packages/server/src/tools/generate-types.js
|
||||
packages/server/src/tools/generate-types.js.map
|
||||
packages/server/src/utils/TransactionHandler.d.ts
|
||||
packages/server/src/utils/TransactionHandler.js
|
||||
packages/server/src/utils/TransactionHandler.js.map
|
||||
packages/server/src/utils/auth.d.ts
|
||||
packages/server/src/utils/auth.js
|
||||
packages/server/src/utils/auth.js.map
|
||||
packages/server/src/utils/base64.d.ts
|
||||
packages/server/src/utils/base64.js
|
||||
packages/server/src/utils/base64.js.map
|
||||
packages/server/src/utils/cache.d.ts
|
||||
packages/server/src/utils/cache.js
|
||||
packages/server/src/utils/cache.js.map
|
||||
packages/server/src/utils/defaultView.d.ts
|
||||
packages/server/src/utils/defaultView.js
|
||||
packages/server/src/utils/defaultView.js.map
|
||||
packages/server/src/utils/errors.d.ts
|
||||
packages/server/src/utils/errors.js
|
||||
packages/server/src/utils/errors.js.map
|
||||
packages/server/src/utils/htmlUtils.d.ts
|
||||
packages/server/src/utils/htmlUtils.js
|
||||
packages/server/src/utils/htmlUtils.js.map
|
||||
packages/server/src/utils/koaIf.d.ts
|
||||
packages/server/src/utils/koaIf.js
|
||||
packages/server/src/utils/koaIf.js.map
|
||||
packages/server/src/utils/requestUtils.d.ts
|
||||
packages/server/src/utils/requestUtils.js
|
||||
packages/server/src/utils/requestUtils.js.map
|
||||
packages/server/src/utils/routeUtils.d.ts
|
||||
packages/server/src/utils/routeUtils.js
|
||||
packages/server/src/utils/routeUtils.js.map
|
||||
packages/server/src/utils/routeUtils.test.d.ts
|
||||
packages/server/src/utils/routeUtils.test.js
|
||||
packages/server/src/utils/routeUtils.test.js.map
|
||||
packages/server/src/utils/testUtils.d.ts
|
||||
packages/server/src/utils/testUtils.js
|
||||
packages/server/src/utils/testUtils.js.map
|
||||
packages/server/src/utils/testing/testRouters.d.ts
|
||||
packages/server/src/utils/testing/testRouters.js
|
||||
packages/server/src/utils/testing/testRouters.js.map
|
||||
packages/server/src/utils/time.d.ts
|
||||
packages/server/src/utils/time.js
|
||||
packages/server/src/utils/time.js.map
|
||||
packages/server/src/utils/types.d.ts
|
||||
packages/server/src/utils/types.js
|
||||
packages/server/src/utils/types.js.map
|
||||
packages/server/src/utils/urlUtils.d.ts
|
||||
packages/server/src/utils/urlUtils.js
|
||||
packages/server/src/utils/urlUtils.js.map
|
||||
packages/server/src/utils/uuidgen.d.ts
|
||||
packages/server/src/utils/uuidgen.js
|
||||
packages/server/src/utils/uuidgen.js.map
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
|
||||
Binary file not shown.
3
Dockerfile.db
Normal file
3
Dockerfile.db
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM postgres:13.1
|
||||
|
||||
EXPOSE 5432
|
||||
71
Dockerfile.server
Normal file
71
Dockerfile.server
Normal file
@@ -0,0 +1,71 @@
|
||||
# https://versatile.nl/blog/deploying-lerna-web-apps-with-docker
|
||||
|
||||
FROM node:12
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get --yes install vim
|
||||
|
||||
ARG user=joplin
|
||||
|
||||
RUN useradd --create-home --shell /bin/bash $user
|
||||
USER $user
|
||||
|
||||
ENV NODE_ENV development
|
||||
|
||||
WORKDIR /home/$user
|
||||
|
||||
RUN mkdir /home/$user/logs
|
||||
|
||||
# To take advantage of the Docker cache, we first copy all the package.json
|
||||
# and package-lock.json files, as they rarely change? and then bootstrap
|
||||
# all the packages.
|
||||
#
|
||||
# Note that bootstrapping the packages will run all the postinstall
|
||||
# scripts, which means that for packages that have such scripts, we need to
|
||||
# copy all the files.
|
||||
#
|
||||
# We can't run boostrap with "--ignore-scripts" because that would
|
||||
# prevent certain sub-packages, such as sqlite3, from being built
|
||||
|
||||
COPY --chown=$user:$user package*.json ./
|
||||
|
||||
# Install the root scripts but don't run postinstall (which would bootstrap
|
||||
# and build TypeScript files, but we don't have the TypeScript files at
|
||||
# this point)
|
||||
|
||||
RUN npm install --ignore-scripts
|
||||
|
||||
COPY --chown=$user:$user packages/fork-sax/package*.json ./packages/fork-sax/
|
||||
COPY --chown=$user:$user packages/lib/package*.json ./packages/lib/
|
||||
COPY --chown=$user:$user packages/renderer/package*.json ./packages/renderer/
|
||||
COPY --chown=$user:$user packages/tools/package*.json ./packages/tools/
|
||||
COPY --chown=$user:$user packages/server/package*.json ./packages/server/
|
||||
COPY --chown=$user:$user lerna.json .
|
||||
COPY --chown=$user:$user tsconfig.json .
|
||||
|
||||
# The following have postinstall scripts so we need to copy all the files.
|
||||
# Since they should rarely change this is not an issue
|
||||
|
||||
COPY --chown=$user:$user packages/turndown ./packages/turndown
|
||||
COPY --chown=$user:$user packages/turndown-plugin-gfm ./packages/turndown-plugin-gfm
|
||||
COPY --chown=$user:$user packages/fork-htmlparser2 ./packages/fork-htmlparser2
|
||||
|
||||
RUN ls -la /home/$user
|
||||
|
||||
# Then bootstrap only, without compiling the TypeScript files
|
||||
|
||||
RUN npm run bootstrap
|
||||
|
||||
COPY --chown=$user:$user packages/fork-sax ./packages/fork-sax
|
||||
COPY --chown=$user:$user packages/lib ./packages/lib
|
||||
COPY --chown=$user:$user packages/renderer ./packages/renderer
|
||||
COPY --chown=$user:$user packages/tools ./packages/tools
|
||||
COPY --chown=$user:$user packages/server ./packages/server
|
||||
|
||||
# Finally build everything, in particular the TypeScript files.
|
||||
|
||||
RUN npm run build
|
||||
|
||||
EXPOSE ${JOPLIN_PORT}
|
||||
|
||||
CMD [ "npm", "--prefix", "packages/server", "start" ]
|
||||
80
README.md
80
README.md
@@ -20,9 +20,9 @@ Three types of applications are available: for the **desktop** (Windows, macOS a
|
||||
|
||||
Operating System | Download | Alternative
|
||||
---|---|---
|
||||
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/Joplin-Setup-1.4.19.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a> | Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/JoplinPortable.exe'>Portable version</a><br><br>The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
|
||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/Joplin-1.4.19.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a> | -
|
||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/Joplin-1.4.19.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a> | The recommended way is to use the following installation script as it will handle the desktop icon too:<br><br> `wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh \| bash`
|
||||
Windows (32 and 64-bit) | <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-Setup-1.5.11.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a> | Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/JoplinPortable.exe'>Portable version</a><br><br>The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
|
||||
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a> | -
|
||||
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a> | The recommended way is to use the following installation script as it will handle the desktop icon too:<br><br> `wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh \| bash`
|
||||
|
||||
## Mobile applications
|
||||
|
||||
@@ -109,6 +109,8 @@ The Web Clipper is a browser extension that allows you to save web pages and scr
|
||||
- [Sync Lock spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/sync_lock.md)
|
||||
- [Plugin Architecture spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/plugins.md)
|
||||
- [Search Sorting spec](https://github.com/laurent22/joplin/blob/dev/readme/spec/search_sorting.md)
|
||||
- [Server: File URL Format](https://github.com/laurent22/joplin/blob/dev/readme/spec/server_file_url_format.md)
|
||||
- [Server: Delta Sync](https://github.com/laurent22/joplin/blob/dev/readme/spec/server_delta_sync.md)
|
||||
|
||||
- Google Summer of Code 2020
|
||||
|
||||
@@ -436,45 +438,45 @@ Current translations:
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
| Language | Po File | Last translator | Percent done
|
||||
---|---|---|---|---
|
||||
 | Arabic | [ar](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ar.po) | [أحمد باشا إبراهيم](mailto:fi_ahmed_bacha@esi.dz) | 77%
|
||||
 | Basque | [eu](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eu.po) | juan.abasolo@ehu.eus | 33%
|
||||
 | Bosnian (Bosna i Hercegovina) | [bs_BA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bs_BA.po) | [Derviš T.](mailto:dervis.t@pm.me) | 79%
|
||||
 | Bulgarian (България) | [bg_BG](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bg_BG.po) | | 64%
|
||||
 | Catalan | [ca](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ca.po) | jmontane, 2019 | 92%
|
||||
 | Arabic | [ar](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ar.po) | [أحمد باشا إبراهيم](mailto:fi_ahmed_bacha@esi.dz) | 75%
|
||||
 | Basque | [eu](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eu.po) | juan.abasolo@ehu.eus | 32%
|
||||
 | Bosnian (Bosna i Hercegovina) | [bs_BA](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bs_BA.po) | [Derviš T.](mailto:dervis.t@pm.me) | 77%
|
||||
 | Bulgarian (България) | [bg_BG](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/bg_BG.po) | | 62%
|
||||
 | Catalan | [ca](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ca.po) | jmontane, 2019 | 89%
|
||||
 | Croatian (Hrvatska) | [hr_HR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/hr_HR.po) | [Hrvoje Mandić](mailto:trbuhom@net.hr) | 26%
|
||||
 | Czech (Česká republika) | [cs_CZ](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/cs_CZ.po) | [Lukas Helebrandt](mailto:lukas@aiya.cz) | 96%
|
||||
 | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | Mustafa Al-Dailemi (dailemi@hotmail.com)Language-Team: | 79%
|
||||
 | Deutsch (Deutschland) | [de_DE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/de_DE.po) | [Ettore Atalan](mailto:atalanttore@users.noreply.github.com) | 96%
|
||||
 | Eesti Keel (Eesti) | [et_EE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/et_EE.po) | | 63%
|
||||
 | Czech (Česká republika) | [cs_CZ](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/cs_CZ.po) | [Lukas Helebrandt](mailto:lukas@aiya.cz) | 93%
|
||||
 | Dansk (Danmark) | [da_DK](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/da_DK.po) | Mustafa Al-Dailemi (dailemi@hotmail.com)Language-Team: | 77%
|
||||
 | Deutsch (Deutschland) | [de_DE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/de_DE.po) | [Ettore Atalan](mailto:atalanttore@users.noreply.github.com) | 95%
|
||||
 | Eesti Keel (Eesti) | [et_EE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/et_EE.po) | | 61%
|
||||
 | English (United Kingdom) | [en_GB](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/en_GB.po) | | 100%
|
||||
 | English (United States of America) | [en_US](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/en_US.po) | | 100%
|
||||
 | Español (España) | [es_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/es_ES.po) | [Mario Campo](mailto:mario.campo@gmail.com) | 96%
|
||||
 | Esperanto | [eo](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eo.po) | Marton Paulo | 36%
|
||||
 | Finnish (Suomi) | [fi_FI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fi_FI.po) | | 97%
|
||||
 | Français (France) | [fr_FR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fr_FR.po) | Laurent Cozic | 96%
|
||||
 | Galician (España) | [gl_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/gl_ES.po) | [Marcos Lans](mailto:marcoslansgarza@gmail.com) | 42%
|
||||
 | Indonesian (Indonesia) | [id_ID](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/id_ID.po) | [Fathy AR](mailto:16875937+fathyar@users.noreply.github.com) | 88%
|
||||
 | Italiano (Italia) | [it_IT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/it_IT.po) | [Alessandro Bernardello](mailto:mailfilledwithspam@gmail.com) | 97%
|
||||
 | Nederlands (België, Belgique, Belgien) | [nl_BE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_BE.po) | | 33%
|
||||
 | Nederlands (Nederland) | [nl_NL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_NL.po) | [MetBril](mailto:metbril@users.noreply.github.com) | 96%
|
||||
 | Norwegian (Norge, Noreg) | [nb_NO](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nb_NO.po) | [Mats Estensen](mailto:code@mxe.no) | 85%
|
||||
 | Persian | [fa](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fa.po) | [Kourosh Firoozbakht](mailto:kourox@protonmail.com) | 79%
|
||||
 | Polski (Polska) | [pl_PL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pl_PL.po) | | 95%
|
||||
 | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_BR.po) | [Renato Nunes Bastos](mailto:rnbastos@gmail.com) | 93%
|
||||
 | Português (Portugal) | [pt_PT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_PT.po) | [João Duarte](mailto:jduar@protonmail.com) | 95%
|
||||
 | Română | [ro](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ro.po) | [Cristi Duluta](mailto:cristi.duluta@gmail.com) | 74%
|
||||
 | Slovenian (Slovenija) | [sl_SI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sl_SI.po) | | 41%
|
||||
 | Svenska | [sv](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sv.po) | [Jonatan Nyberg](mailto:jonatan@autistici.org) | 68%
|
||||
 | Thai (ประเทศไทย) | [th_TH](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/th_TH.po) | | 50%
|
||||
 | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 82%
|
||||
 | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 94%
|
||||
 | Ελληνικά (Ελλάδα) | [el_GR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/el_GR.po) | [Harris Arvanitis](mailto:xaris@tuta.io) | 92%
|
||||
 | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Sergey Segeda](mailto:thesermanarm@gmail.com) | 92%
|
||||
 | српски језик (Србија) | [sr_RS](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sr_RS.po) | | 69%
|
||||
 | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_CN.po) | [WhiredPlanck](mailto:fungdaat31@outlook.com) | 97%
|
||||
 | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Yaoze Ye](mailto:yaozeye@yahoo.co.jp) | 91%
|
||||
 | 日本語 (日本) | [ja_JP](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ja_JP.po) | [genneko](mailto:genneko217@gmail.com) | 97%
|
||||
 | 한국어 | [ko](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ko.po) | [Ji-Hyeon Gim](mailto:potatogim@potatogim.net) | 97%
|
||||
 | Español (España) | [es_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/es_ES.po) | [Mario Campo](mailto:mario.campo@gmail.com) | 99%
|
||||
 | Esperanto | [eo](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/eo.po) | Marton Paulo | 35%
|
||||
 | Finnish (Suomi) | [fi_FI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fi_FI.po) | | 94%
|
||||
 | Français (France) | [fr_FR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fr_FR.po) | Laurent Cozic | 99%
|
||||
 | Galician (España) | [gl_ES](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/gl_ES.po) | [Marcos Lans](mailto:marcoslansgarza@gmail.com) | 40%
|
||||
 | Indonesian (Indonesia) | [id_ID](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/id_ID.po) | [Fathy AR](mailto:16875937+fathyar@users.noreply.github.com) | 85%
|
||||
 | Italiano (Italia) | [it_IT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/it_IT.po) | [Alessandro Bernardello](mailto:mailfilledwithspam@gmail.com) | 96%
|
||||
 | Nederlands (België, Belgique, Belgien) | [nl_BE](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_BE.po) | | 32%
|
||||
 | Nederlands (Nederland) | [nl_NL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nl_NL.po) | [MetBril](mailto:metbril@users.noreply.github.com) | 93%
|
||||
 | Norwegian (Norge, Noreg) | [nb_NO](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/nb_NO.po) | [Mats Estensen](mailto:code@mxe.no) | 82%
|
||||
 | Persian | [fa](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/fa.po) | [Kourosh Firoozbakht](mailto:kourox@protonmail.com) | 77%
|
||||
 | Polski (Polska) | [pl_PL](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pl_PL.po) | | 92%
|
||||
 | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_BR.po) | [Renato Nunes Bastos](mailto:rnbastos@gmail.com) | 91%
|
||||
 | Português (Portugal) | [pt_PT](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/pt_PT.po) | [João Duarte](mailto:jduar@protonmail.com) | 92%
|
||||
 | Română | [ro](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ro.po) | [Cristi Duluta](mailto:cristi.duluta@gmail.com) | 72%
|
||||
 | Slovenian (Slovenija) | [sl_SI](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sl_SI.po) | | 40%
|
||||
 | Svenska | [sv](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sv.po) | [Jonatan Nyberg](mailto:jonatan@autistici.org) | 66%
|
||||
 | Thai (ประเทศไทย) | [th_TH](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/th_TH.po) | | 49%
|
||||
 | Tiếng Việt | [vi](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/vi.po) | | 79%
|
||||
 | Türkçe (Türkiye) | [tr_TR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/tr_TR.po) | [Arda Kılıçdağı](mailto:arda@kilicdagi.com) | 99%
|
||||
 | Ελληνικά (Ελλάδα) | [el_GR](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/el_GR.po) | [Harris Arvanitis](mailto:xaris@tuta.io) | 89%
|
||||
 | Русский (Россия) | [ru_RU](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ru_RU.po) | [Sergey Segeda](mailto:thesermanarm@gmail.com) | 96%
|
||||
 | српски језик (Србија) | [sr_RS](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/sr_RS.po) | | 67%
|
||||
 | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_CN.po) | [WhiredPlanck](mailto:fungdaat31@outlook.com) | 99%
|
||||
 | 中文 (繁體) | [zh_TW](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/zh_TW.po) | [Yaoze Ye](mailto:yaozeye@yahoo.co.jp) | 95%
|
||||
 | 日本語 (日本) | [ja_JP](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ja_JP.po) | [genneko](mailto:genneko217@gmail.com) | 96%
|
||||
 | 한국어 | [ko](https://github.com/laurent22/joplin/blob/dev/packages/tools/locales/ko.po) | [Ji-Hyeon Gim](mailto:potatogim@potatogim.net) | 96%
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
|
||||
# Contributors
|
||||
|
||||
28
docker-compose.server-dev.yml
Normal file
28
docker-compose.server-dev.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
# For development, the easiest might be to only start the Postgres container and
|
||||
# run the app directly with `npm start`. Or use sqlite3.
|
||||
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
# app:
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: Dockerfile.server-dev
|
||||
# ports:
|
||||
# - "22300:22300"
|
||||
# # volumes:
|
||||
# # - ./packages/server/:/var/www/joplin/packages/server/
|
||||
# # - /var/www/joplin/packages/server/node_modules/
|
||||
db:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.db
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
# TODO: Considering the database is only exposed to the
|
||||
# application, and not to the outside world, is there a need to
|
||||
# pick a secure password?
|
||||
- POSTGRES_PASSWORD=joplin
|
||||
- POSTGRES_USER=joplin
|
||||
- POSTGRES_DB=joplin
|
||||
40
docker-compose.server.yml
Normal file
40
docker-compose.server.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
- JOPLIN_BASE_URL=${JOPLIN_BASE_URL}
|
||||
- JOPLIN_PORT=${JOPLIN_PORT}
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.server
|
||||
ports:
|
||||
- "${JOPLIN_PORT}:${JOPLIN_PORT}"
|
||||
# volumes:
|
||||
# # Mount the server directory so that it's possible to edit file
|
||||
# # while the container is running. However don't mount the
|
||||
# # node_modules directory which will be specific to the Docker
|
||||
# # image (eg native modules will be built for Ubuntu, while the
|
||||
# # container might be running in Windows)
|
||||
# # https://stackoverflow.com/a/37898591/561309
|
||||
# - ./packages/server:/home/joplin/packages/server
|
||||
# - /home/joplin/packages/server/node_modules/
|
||||
db:
|
||||
restart: unless-stopped
|
||||
# By default, the Postgres image saves the data to a Docker volume,
|
||||
# so it persists whenever the server is restarted using
|
||||
# `docker-compose up`. Note that it would however be deleted when
|
||||
# running `docker-compose down`.
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.db
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
# TODO: Considering the database is only exposed to the
|
||||
# application, and not to the outside world, is there a need to
|
||||
# pick a secure password?
|
||||
- POSTGRES_PASSWORD=joplin
|
||||
- POSTGRES_USER=joplin
|
||||
- POSTGRES_DB=joplin
|
||||
File diff suppressed because one or more lines are too long
@@ -150,13 +150,21 @@
|
||||
</aside>
|
||||
<div class="tsd-comment tsd-typography">
|
||||
<div class="lead">
|
||||
<p>Registers a new content script. Unlike regular plugin code, which runs in a separate process, content scripts run within the main process code
|
||||
and thus allow improved performances and more customisations in specific cases. It can be used for example to load a Markdown or editor plugin.</p>
|
||||
<p>Registers a new content script. Unlike regular plugin code, which
|
||||
runs in a separate process, content scripts run within the main
|
||||
process code and thus allow improved performances and more
|
||||
customisations in specific cases. It can be used for example to load
|
||||
a Markdown or editor plugin.</p>
|
||||
</div>
|
||||
<p>Note that registering a content script in itself will do nothing - it will only be loaded in specific cases by the relevant app modules
|
||||
(eg. the Markdown renderer or the code editor). So it is not a way to inject and run arbitrary code in the app, which for safety and performance reasons is not supported.</p>
|
||||
<p><a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script">View the renderer demo plugin</a>
|
||||
<a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">View the editor demo plugin</a></p>
|
||||
<p>Note that registering a content script in itself will do nothing -
|
||||
it will only be loaded in specific cases by the relevant app modules
|
||||
(eg. the Markdown renderer or the code editor). So it is not a way
|
||||
to inject and run arbitrary code in the app, which for safety and
|
||||
performance reasons is not supported.</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script">View the renderer demo plugin</a></li>
|
||||
<li><a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">View the editor demo plugin</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<h4 class="tsd-parameters-title">Parameters</h4>
|
||||
<ul class="tsd-parameters">
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
<p>Gets a global setting value, including app-specific settings and those set by other plugins.</p>
|
||||
</div>
|
||||
<p>The list of available settings is not documented yet, but can be found by looking at the source code:</p>
|
||||
<p><a href="https://github.com/laurent22/joplin/blob/3539a452a359162c461d2849829d2d42973eab50/packages/app-mobile/lib/models/Setting.ts#L142">https://github.com/laurent22/joplin/blob/3539a452a359162c461d2849829d2d42973eab50/packages/app-mobile/lib/models/Setting.ts#L142</a></p>
|
||||
<p><a href="https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142">https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142</a></p>
|
||||
</div>
|
||||
<h4 class="tsd-parameters-title">Parameters</h4>
|
||||
<ul class="tsd-parameters">
|
||||
|
||||
@@ -88,7 +88,8 @@
|
||||
</aside>
|
||||
<div class="tsd-comment tsd-typography">
|
||||
<div class="lead">
|
||||
<p>Registers a new CodeMirror plugin, which should follow the template below.</p>
|
||||
<p>Registers a new CodeMirror plugin, which should follow the template
|
||||
below.</p>
|
||||
</div>
|
||||
<pre><code class="language-javascript"><span class="hljs-built_in">module</span>.exports = {
|
||||
<span class="hljs-attr">default</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{
|
||||
@@ -98,8 +99,8 @@
|
||||
},
|
||||
<span class="hljs-attr">codeMirrorResources</span>: [],
|
||||
<span class="hljs-attr">codeMirrorOptions</span>: {
|
||||
<span class="hljs-comment">// ...</span>
|
||||
},
|
||||
<span class="hljs-comment">// ...</span>
|
||||
},
|
||||
<span class="hljs-attr">assets</span>: {
|
||||
<span class="hljs-comment">// ...</span>
|
||||
},
|
||||
@@ -107,19 +108,42 @@
|
||||
}
|
||||
}</code></pre>
|
||||
<ul>
|
||||
<li><p>The <code>context</code> argument is currently unused but could be used later on to provide access to your own plugin so that the content script and plugin can communicate.</p>
|
||||
<li><p>The <code>context</code> argument is currently unused but could be used later
|
||||
on to provide access to your own plugin so that the content script
|
||||
and plugin can communicate.</p>
|
||||
</li>
|
||||
<li><p>The <code>plugin</code> key is your CodeMirror plugin. This is where you can register new commands with CodeMirror or interact with the CodeMirror instance as needed.</p>
|
||||
<li><p>The <code>plugin</code> key is your CodeMirror plugin. This is where you can
|
||||
register new commands with CodeMirror or interact with the
|
||||
CodeMirror instance as needed.</p>
|
||||
</li>
|
||||
<li><p>The <code>codeMirrorResources</code> key is an array of CodeMirror resources that will be loaded and attached to the CodeMirror module. These are made up of addons, keymaps, and modes. For example, for a plugin that want's to enable clojure highlighting in code blocks. <code>codeMirrorResources</code> would be set to <code>['mode/clojure/clojure']</code>.</p>
|
||||
<li><p>The <code>codeMirrorResources</code> key is an array of CodeMirror resources
|
||||
that will be loaded and attached to the CodeMirror module. These
|
||||
are made up of addons, keymaps, and modes. For example, for a
|
||||
plugin that want's to enable clojure highlighting in code blocks.
|
||||
<code>codeMirrorResources</code> would be set to <code>['mode/clojure/clojure']</code>.</p>
|
||||
</li>
|
||||
<li><p>The <code>codeMirrorOptions</code> key contains all the <a href="https://codemirror.net/doc/manual.html#config">CodeMirror</a> options that will be set or changed by this plugin. New options can alse be declared via <a href="https://codemirror.net/doc/manual.html#defineOption"><code>CodeMirror.defineOption</code></a>, and then have their value set here. For example, a plugin that enables line numbers would set <code>codeMirrorOptions</code> to <code>{'lineNumbers': true}</code>.</p>
|
||||
<li><p>The <code>codeMirrorOptions</code> key contains all the
|
||||
<a href="https://codemirror.net/doc/manual.html#config">CodeMirror</a>
|
||||
options that will be set or changed by this plugin. New options
|
||||
can alse be declared via
|
||||
<a href="https://codemirror.net/doc/manual.html#defineOption"><code>CodeMirror.defineOption</code></a>,
|
||||
and then have their value set here. For example, a plugin that
|
||||
enables line numbers would set <code>codeMirrorOptions</code> to
|
||||
<code>{'lineNumbers': true}</code>.</p>
|
||||
</li>
|
||||
<li><p>Using the <strong>optional</strong> <code>assets</code> key you may specify <strong>only</strong> CSS assets that should be loaded in the rendered HTML document. Check for example the Joplin <a href="https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/lib/joplin-renderer/MdToHtml/rules/mermaid.ts">Mermaid plugin</a> to see how the data should be structured.</p>
|
||||
<li><p>Using the <strong>optional</strong> <code>assets</code> key you may specify <strong>only</strong> CSS
|
||||
assets that should be loaded in the rendered HTML document. Check
|
||||
for example the Joplin [Mermaid
|
||||
plugin](<a href="https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts">https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts</a>)
|
||||
to see how the data should be structured.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>One of the <code>plugin</code>, <code>codeMirrorResources</code>, or <code>codeMirrorOptions</code> keys must be provided for the plugin to be valid. Having multiple or all provided is also okay.</p>
|
||||
<p>See the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">demo plugin</a> for an example of all these keys being used in one plugin.</p>
|
||||
<p>One of the <code>plugin</code>, <code>codeMirrorResources</code>, or <code>codeMirrorOptions</code>
|
||||
keys must be provided for the plugin to be valid. Having multiple or
|
||||
all provided is also okay.</p>
|
||||
<p>See the <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script">demo
|
||||
plugin</a>
|
||||
for an example of all these keys being used in one plugin.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
@@ -130,7 +154,8 @@
|
||||
</aside>
|
||||
<div class="tsd-comment tsd-typography">
|
||||
<div class="lead">
|
||||
<p>Registers a new Markdown-It plugin, which should follow the template below.</p>
|
||||
<p>Registers a new Markdown-It plugin, which should follow the template
|
||||
below.</p>
|
||||
</div>
|
||||
<pre><code class="language-javascript"><span class="hljs-built_in">module</span>.exports = {
|
||||
<span class="hljs-attr">default</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{
|
||||
@@ -144,15 +169,50 @@
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p>See <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script">the
|
||||
demo</a>
|
||||
for a simple Markdown-it plugin example.</p>
|
||||
<a href="#exported-members" id="exported-members" style="color: inherit; text-decoration: none;">
|
||||
<h2>Exported members</h2>
|
||||
</a>
|
||||
<ul>
|
||||
<li><p>The <code>context</code> argument is currently unused but could be used later on to provide access to your own plugin so that the content script and plugin can communicate.</p>
|
||||
<li><p>The <code>context</code> argument is currently unused but could be used later
|
||||
on to provide access to your own plugin so that the content script
|
||||
and plugin can communicate.</p>
|
||||
</li>
|
||||
<li><p>The <strong>required</strong> <code>plugin</code> key is the actual Markdown-It plugin - check the <a href="https://github.com/markdown-it/markdown-it">official doc</a> for more information. The <code>options</code> parameter is of type <a href="https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/lib/joplin-renderer/MdToHtml.ts">RuleOptions</a>, which contains a number of options, mostly useful for Joplin's internal code.</p>
|
||||
<li><p>The <strong>required</strong> <code>plugin</code> key is the actual Markdown-It plugin -
|
||||
check the [official
|
||||
doc](<a href="https://github.com/markdown-it/markdown-it">https://github.com/markdown-it/markdown-it</a>) for more
|
||||
information. The <code>options</code> parameter is of type
|
||||
<a href="https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts">RuleOptions</a>,
|
||||
which contains a number of options, mostly useful for Joplin's
|
||||
internal code.</p>
|
||||
</li>
|
||||
<li><p>Using the <strong>optional</strong> <code>assets</code> key you may specify assets such as JS or CSS that should be loaded in the rendered HTML document. Check for example the Joplin <a href="https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/lib/joplin-renderer/MdToHtml/rules/mermaid.ts">Mermaid plugin</a> to see how the data should be structured.</p>
|
||||
<li><p>Using the <strong>optional</strong> <code>assets</code> key you may specify assets such as
|
||||
JS or CSS that should be loaded in the rendered HTML document.
|
||||
Check for example the Joplin [Mermaid
|
||||
plugin](<a href="https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts">https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts</a>)
|
||||
to see how the data should be structured.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>To include a regular Markdown-It plugin, that doesn't make use of any Joplin-specific features, you would simply create a file such as this:</p>
|
||||
<a href="#passing-messages-from-the-content-script-to-your-plugin" id="passing-messages-from-the-content-script-to-your-plugin" style="color: inherit; text-decoration: none;">
|
||||
<h2>Passing messages from the content script to your plugin</h2>
|
||||
</a>
|
||||
<p>The application provides the following function to allow executing
|
||||
commands from the rendered HTML code:</p>
|
||||
<p><code>webviewApi.executeCommand(commandName, ...args)</code></p>
|
||||
<p>So you can use this mechanism to pass messages from the note viewer
|
||||
to your own plugin. To do so you would define a command, using
|
||||
<code>joplin.commands.register</code>, then you would call this command using
|
||||
the <code>webviewApi</code> object. See again <a href="https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script">the
|
||||
demo</a>
|
||||
to see how this can be done.</p>
|
||||
<a href="#registering-an-existing-markdown-it-plugin" id="registering-an-existing-markdown-it-plugin" style="color: inherit; text-decoration: none;">
|
||||
<h2>Registering an existing Markdown-it plugin</h2>
|
||||
</a>
|
||||
<p>To include a regular Markdown-It plugin, that doesn't make use of
|
||||
any Joplin-specific features, you would simply create a file such as
|
||||
this:</p>
|
||||
<pre><code class="language-javascript"><span class="hljs-built_in">module</span>.exports = {
|
||||
<span class="hljs-attr">default</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{
|
||||
<span class="hljs-keyword">return</span> {
|
||||
|
||||
@@ -75,9 +75,11 @@
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#edit" class="tsd-kind-icon">Edit</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#editorcontextmenu" class="tsd-kind-icon">Editor<wbr>Context<wbr>Menu</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#file" class="tsd-kind-icon">File</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#foldercontextmenu" class="tsd-kind-icon">Folder<wbr>Context<wbr>Menu</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#help" class="tsd-kind-icon">Help</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#note" class="tsd-kind-icon">Note</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#notelistcontextmenu" class="tsd-kind-icon">Note<wbr>List<wbr>Context<wbr>Menu</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#tagcontextmenu" class="tsd-kind-icon">Tag<wbr>Context<wbr>Menu</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#tools" class="tsd-kind-icon">Tools</a></li>
|
||||
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="menuitemlocation.html#view" class="tsd-kind-icon">View</a></li>
|
||||
</ul>
|
||||
@@ -122,6 +124,22 @@
|
||||
<aside class="tsd-sources">
|
||||
</aside>
|
||||
</section>
|
||||
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a name="foldercontextmenu" class="tsd-anchor"></a>
|
||||
<h3>Folder<wbr>Context<wbr>Menu</h3>
|
||||
<div class="tsd-signature tsd-kind-icon">Folder<wbr>Context<wbr>Menu<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = "folderContextMenu"</span></div>
|
||||
<aside class="tsd-sources">
|
||||
</aside>
|
||||
<div class="tsd-comment tsd-typography">
|
||||
<div class="lead">
|
||||
<p>When a command is called from a folder context menu, the
|
||||
command will receive the following arguments:</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li><code>folderId:string</code>: ID of the folder that was right-clicked on</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a name="help" class="tsd-anchor"></a>
|
||||
<h3>Help</h3>
|
||||
@@ -142,6 +160,31 @@
|
||||
<div class="tsd-signature tsd-kind-icon">Note<wbr>List<wbr>Context<wbr>Menu<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = "noteListContextMenu"</span></div>
|
||||
<aside class="tsd-sources">
|
||||
</aside>
|
||||
<div class="tsd-comment tsd-typography">
|
||||
<div class="lead">
|
||||
<p>When a command is called from the note list context menu, the
|
||||
command will receive the following arguments:</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li><code>noteIds:string[]</code>: IDs of the notes that were right-clicked on.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a name="tagcontextmenu" class="tsd-anchor"></a>
|
||||
<h3>Tag<wbr>Context<wbr>Menu</h3>
|
||||
<div class="tsd-signature tsd-kind-icon">Tag<wbr>Context<wbr>Menu<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = "tagContextMenu"</span></div>
|
||||
<aside class="tsd-sources">
|
||||
</aside>
|
||||
<div class="tsd-comment tsd-typography">
|
||||
<div class="lead">
|
||||
<p>When a command is called from a tag context menu, the
|
||||
command will receive the following arguments:</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li><code>tagId:string</code>: ID of the tag that was right-clicked on</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a name="tools" class="tsd-anchor"></a>
|
||||
@@ -188,6 +231,9 @@
|
||||
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a href="menuitemlocation.html#file" class="tsd-kind-icon">File</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a href="menuitemlocation.html#foldercontextmenu" class="tsd-kind-icon">Folder<wbr>Context<wbr>Menu</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a href="menuitemlocation.html#help" class="tsd-kind-icon">Help</a>
|
||||
</li>
|
||||
@@ -197,6 +243,9 @@
|
||||
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a href="menuitemlocation.html#notelistcontextmenu" class="tsd-kind-icon">Note<wbr>List<wbr>Context<wbr>Menu</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a href="menuitemlocation.html#tagcontextmenu" class="tsd-kind-icon">Tag<wbr>Context<wbr>Menu</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
|
||||
<a href="menuitemlocation.html#tools" class="tsd-kind-icon">Tools</a>
|
||||
</li>
|
||||
|
||||
@@ -133,6 +133,12 @@
|
||||
<li class="tsd-kind-variable"><a href="globals.html#logger" class="tsd-kind-icon">logger</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="tsd-index-section ">
|
||||
<h3>Functions</h3>
|
||||
<ul class="tsd-index-list">
|
||||
<li class="tsd-kind-function"><a href="globals.html#iscontextmenuitemlocation" class="tsd-kind-icon">is<wbr>Context<wbr>Menu<wbr>Item<wbr>Location</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
@@ -187,9 +193,11 @@
|
||||
<div class="lead">
|
||||
<p>An array of at least one element and at most three elements.</p>
|
||||
</div>
|
||||
<p>[0]: Resource name (eg. "notes", "folders", "tags", etc.)
|
||||
[1]: (Optional) Resource ID.
|
||||
[2]: (Optional) Resource link.</p>
|
||||
<ul>
|
||||
<li><strong>[0]</strong>: Resource name (eg. "notes", "folders", "tags", etc.)</li>
|
||||
<li><strong>[1]</strong>: (Optional) Resource ID.</li>
|
||||
<li><strong>[2]</strong>: (Optional) Resource link.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section class="tsd-panel tsd-member tsd-kind-type-alias">
|
||||
@@ -242,6 +250,33 @@
|
||||
</aside>
|
||||
</section>
|
||||
</section>
|
||||
<section class="tsd-panel-group tsd-member-group ">
|
||||
<h2>Functions</h2>
|
||||
<section class="tsd-panel tsd-member tsd-kind-function">
|
||||
<a name="iscontextmenuitemlocation" class="tsd-anchor"></a>
|
||||
<h3>is<wbr>Context<wbr>Menu<wbr>Item<wbr>Location</h3>
|
||||
<ul class="tsd-signatures tsd-kind-function">
|
||||
<li class="tsd-signature tsd-kind-icon">is<wbr>Context<wbr>Menu<wbr>Item<wbr>Location<span class="tsd-signature-symbol">(</span>location<span class="tsd-signature-symbol">: </span><a href="enums/menuitemlocation.html" class="tsd-signature-type">MenuItemLocation</a><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">boolean</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-descriptions">
|
||||
<li class="tsd-description">
|
||||
<aside class="tsd-sources">
|
||||
</aside>
|
||||
<h4 class="tsd-parameters-title">Parameters</h4>
|
||||
<ul class="tsd-parameters">
|
||||
<li>
|
||||
<h5>location: <a href="enums/menuitemlocation.html" class="tsd-signature-type">MenuItemLocation</a></h5>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- JOPLINCHANGE
|
||||
<h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">boolean</span></h4>
|
||||
|
||||
|
||||
-->
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
|
||||
<!--
|
||||
@@ -381,6 +416,9 @@
|
||||
<li class=" tsd-kind-type-alias">
|
||||
<a href="globals.html#viewhandle" class="tsd-kind-icon">ViewHandle</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-function">
|
||||
<a href="globals.html#iscontextmenuitemlocation" class="tsd-kind-icon">isContextMenuItemLocation</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -206,6 +206,9 @@
|
||||
<li class=" tsd-kind-type-alias">
|
||||
<a href="globals.html#viewhandle" class="tsd-kind-icon">ViewHandle</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-function">
|
||||
<a href="globals.html#iscontextmenuitemlocation" class="tsd-kind-icon">isContextMenuItemLocation</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
<td>"oneNoteSelected && !inConflictFolder"</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Currently the supported context variables aren't documented, but you can <a href="https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/lib/services/commands/stateToWhenClauseContext.ts">find the list here</a>.</p>
|
||||
<p>Currently the supported context variables aren't documented, but you can <a href="https://github.com/laurent22/joplin/blob/dev/packages/lib/services/commands/stateToWhenClauseContext.ts">find the list here</a>.</p>
|
||||
<p>Note: Commands are enabled by default unless you use this property.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -400,6 +400,46 @@ https://github.com/laurent22/joplin/blob/dev/readme/changelog.md
|
||||
|
||||
<div class="main">
|
||||
<h1>Joplin changelog<a name="joplin-changelog" href="#joplin-changelog" class="heading-anchor">🔗</a></h1>
|
||||
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.5.11">v1.5.11</a> - 2020-12-27T19:54:07Z<a name="v1-5-11-https-github-com-laurent22-joplin-releases-tag-v1-5-11-2020-12-27t19-54-07z" href="#v1-5-11-https-github-com-laurent22-joplin-releases-tag-v1-5-11-2020-12-27t19-54-07z" class="heading-anchor">🔗</a></h2>
|
||||
<ul>
|
||||
<li>New: Add support for media players (video, audio and PDF)</li>
|
||||
<li>New: Add table captions when importing ENEX files</li>
|
||||
<li>New: Added doc about Rich Text editor and added way to dismiss warning banner</li>
|
||||
<li>New: MacOS: Notarize application</li>
|
||||
<li>New: Plugins: Add support for content script asset files, for Markdown-it plugins</li>
|
||||
<li>New: Plugins: Add support for context menu items on notebooks and tags</li>
|
||||
<li>New: Plugins: Add support for workspace.onSyncStart event</li>
|
||||
<li>New: Plugins: Added a way to execute commands from Markdown-it content scripts</li>
|
||||
<li>Fixed: Fix End key behavior with Codemirror spellcheck (<a href="https://github.com/laurent22/joplin/issues/4215">#4215</a> by Caleb John)</li>
|
||||
<li>Fixed: Fixed basic search when executing a query in Chinese (<a href="https://github.com/laurent22/joplin/issues/4034">#4034</a> by Naveen M V)</li>
|
||||
<li>Fixed: Fixed context menu when the UI is zoomed in or out (<a href="https://github.com/laurent22/joplin/issues/4201">#4201</a>)</li>
|
||||
<li>Fixed: Fixed importing certain code blocks from ENEX</li>
|
||||
<li>Fixed: Fixed importing ENEX files that contain empty resources</li>
|
||||
<li>Fixed: Fixed importing ENEX files that contain resources with invalid mime type</li>
|
||||
<li>Fixed: Fixed issue when searching for text that contains diacritic (<a href="https://github.com/laurent22/joplin/issues/4152">#4152</a>) (<a href="https://github.com/laurent22/joplin/issues/4025">#4025</a> by Roman Musin)</li>
|
||||
<li>Fixed: Fixed issue with attachment paths being invalid when user has spaces in home directory path.</li>
|
||||
<li>Fixed: Fixed issue with note not being saved when a column is added or remove from Rich Text editor</li>
|
||||
<li>Fixed: Fixed issues when importing hidden tables within hidden sections in Enex files</li>
|
||||
<li>Fixed: Fixed numbered list bug in markdown editor (<a href="https://github.com/laurent22/joplin/issues/4116">#4116</a>) (<a href="https://github.com/laurent22/joplin/issues/3917">#3917</a> by <a href="https://github.com/MichBoi">@MichBoi</a>)</li>
|
||||
<li>Fixed: Fixed potential crash when watching note files or resources</li>
|
||||
<li>Fixed: Fixed title input field width on small windows</li>
|
||||
<li>Fixed: Focus editor after pressing toolbar buttons (<a href="https://github.com/laurent22/joplin/issues/4037">#4037</a>) (<a href="https://github.com/laurent22/joplin/issues/4036">#4036</a> by <a href="https://github.com/CalebJohn">@CalebJohn</a>)</li>
|
||||
<li>Fixed: Plugins: Fixed disabling plugin files that start with "_"</li>
|
||||
<li>Fixed: Prevent double paste when using Shift+Ctrl+V (<a href="https://github.com/laurent22/joplin/issues/4243">#4243</a>)</li>
|
||||
<li>Fixed: Prevents crash when invalid spell checker language is selected, and provide fallback for invalid language codes (<a href="https://github.com/laurent22/joplin/issues/4146">#4146</a>)</li>
|
||||
<li>Fixed: Register Markdown editor commands with the Keyboard Shortcut editor (<a href="https://github.com/laurent22/joplin/issues/4136">#4136</a>) (<a href="https://github.com/laurent22/joplin/issues/4130">#4130</a> by Caleb John)</li>
|
||||
<li>Improved: Display Katex parsing errors</li>
|
||||
<li>Improved: Improved warning banner colors</li>
|
||||
<li>Improved: Plugins: Commands would not show up in keymap editor when no shortcut was associated with them</li>
|
||||
<li>Improved: Plugins: Improved note change event handling.</li>
|
||||
<li>Improved: Removed warning for Markdown editor spell checking</li>
|
||||
<li>Improved: Restrict auto-detection of links, and added option to toggle linkify (<a href="https://github.com/laurent22/joplin/issues/4205">#4205</a>)</li>
|
||||
<li>Improved: Rich Text: Do not converts to markdown links URLs that would be linkified</li>
|
||||
<li>Improved: Translation: Update zh_CN (<a href="https://github.com/laurent22/joplin/issues/4195">#4195</a> by Zhang YANG)</li>
|
||||
<li>Improved: Update macOS icon for macOS Big Sur</li>
|
||||
<li>Improved: Update Mermaid: 8.8.1 -> 8.8.4 (<a href="https://github.com/laurent22/joplin/issues/4193">#4193</a> by Helmut K. C. Tessarek)</li>
|
||||
<li>Improved: Use plugins whenever printing or exporting notes</li>
|
||||
</ul>
|
||||
<h2><a href="https://github.com/laurent22/joplin/releases/tag/v1.4.19">v1.4.19</a> - 2020-12-01T11:11:16Z<a name="v1-4-19-https-github-com-laurent22-joplin-releases-tag-v1-4-19-2020-12-01t11-11-16z" href="#v1-4-19-https-github-com-laurent22-joplin-releases-tag-v1-4-19-2020-12-01t11-11-16z" class="heading-anchor">🔗</a></h2>
|
||||
<ul>
|
||||
<li>Improved: Disable soft-break by default in Markdown rendering</li>
|
||||
|
||||
@@ -400,6 +400,22 @@ https://github.com/laurent22/joplin/blob/dev/readme/changelog_cli.md
|
||||
|
||||
<div class="main">
|
||||
<h1>Joplin terminal app changelog<a name="joplin-terminal-app-changelog" href="#joplin-terminal-app-changelog" class="heading-anchor">🔗</a></h1>
|
||||
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.5.1">cli-v1.5.1</a> - 2020-12-26T00:46:31Z<a name="cli-v1-5-1-https-github-com-laurent22-joplin-releases-tag-cli-v1-5-1-2020-12-26t00-46-31z" href="#cli-v1-5-1-https-github-com-laurent22-joplin-releases-tag-cli-v1-5-1-2020-12-26t00-46-31z" class="heading-anchor">🔗</a></h2>
|
||||
<ul>
|
||||
<li>New: Add table captions when importing ENEX files</li>
|
||||
<li>Improved: Allow exporting conflict notes (#4095)</li>
|
||||
<li>Improved: Allow lowercase filters when doing search</li>
|
||||
<li>Improved: Improved error handling when importing ENEX files</li>
|
||||
<li>Improved: Partially reverts #3975 (link rendering)</li>
|
||||
<li>Fixed: Fix sorting by title in a case insensitive way</li>
|
||||
<li>Fixed: Fixed basic search when executing a query in Chinese (#4034 by Naveen M V)</li>
|
||||
<li>Fixed: Fixed importing ENEX files that contain empty resources</li>
|
||||
<li>Fixed: Fixed importing ENEX files that contain resources with invalid mime type</li>
|
||||
<li>Fixed: Fixed importing certain ENEX files that contain invalid dates</li>
|
||||
<li>Fixed: Fixed importing certain code blocks from ENEX</li>
|
||||
<li>Fixed: Fixed issue when searching for text that contains diacritic (#4152) (#4025 by Roman Musin)</li>
|
||||
<li>Fixed: Fixed issues when importing hidden tables within hidden sections in Enex files</li>
|
||||
</ul>
|
||||
<h2><a href="https://github.com/laurent22/joplin/releases/tag/cli-v1.4.9">cli-v1.4.9</a> - 2020-11-26T15:00:37Z<a name="cli-v1-4-9-https-github-com-laurent22-joplin-releases-tag-cli-v1-4-9-2020-11-26t15-00-37z" href="#cli-v1-4-9-https-github-com-laurent22-joplin-releases-tag-cli-v1-4-9-2020-11-26t15-00-37z" class="heading-anchor">🔗</a></h2>
|
||||
<ul>
|
||||
<li>Improved: Allow exporting conflict notes (#4095)</li>
|
||||
|
||||
@@ -411,6 +411,9 @@ https://github.com/laurent22/joplin/blob/dev/readme/faq.md
|
||||
</ul>
|
||||
<p>Now try to install again and it should work.</p>
|
||||
<p>More info there: <a href="https://github.com/electron-userland/electron-builder/issues/4057">https://github.com/electron-userland/electron-builder/issues/4057</a></p>
|
||||
<h2>How can I pass arguments to the Linux installation script?<a name="how-can-i-pass-arguments-to-the-linux-installation-script" href="#how-can-i-pass-arguments-to-the-linux-installation-script" class="heading-anchor">🔗</a></h2>
|
||||
<p>You can pass <a href="https://github.com/laurent22/joplin/blob/dev/Joplin_install_and_update.sh#L37">arguments</a> to the installation script by using this command.</p>
|
||||
<p><code>wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh \| bash -s -- --argument1 --argument2</code></p>
|
||||
<h2>How can I edit my note in an external text editor?<a name="how-can-i-edit-my-note-in-an-external-text-editor" href="#how-can-i-edit-my-note-in-an-external-text-editor" class="heading-anchor">🔗</a></h2>
|
||||
<p>The editor command (may include arguments) defines which editor will be used to open a note. If none is provided it will try to auto-detect the default editor. If this does nothing or you want to change it for Joplin, you need to configure it in the Preferences -> Text editor command.</p>
|
||||
<p>Some example configurations are: (comments after #)</p>
|
||||
|
||||
@@ -420,17 +420,17 @@ https://github.com/laurent22/joplin/blob/dev/README.md
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Windows (32 and 64-bit)</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/Joplin-Setup-1.4.19.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a></td>
|
||||
<td>Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/JoplinPortable.exe'>Portable version</a><br><br>The <a href="https://en.wikipedia.org/wiki/Portable_application">portable application</a> allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-Setup-1.5.11.exe'><img alt='Get it on Windows' width="134px" src='https://joplinapp.org/images/BadgeWindows.png'/></a></td>
|
||||
<td>Or get the <a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/JoplinPortable.exe'>Portable version</a><br><br>The <a href="https://en.wikipedia.org/wiki/Portable_application">portable application</a> allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>macOS</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/Joplin-1.4.19.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a></td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.dmg'><img alt='Get it on macOS' width="134px" src='https://joplinapp.org/images/BadgeMacOS.png'/></a></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux</td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.4.19/Joplin-1.4.19.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a></td>
|
||||
<td><a href='https://github.com/laurent22/joplin/releases/download/v1.5.11/Joplin-1.5.11.AppImage'><img alt='Get it on Linux' width="134px" src='https://joplinapp.org/images/BadgeLinux.png'/></a></td>
|
||||
<td>The recommended way is to use the following installation script as it will handle the desktop icon too:<br><br> <code>wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh | bash</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -400,6 +400,10 @@ https://github.com/laurent22/joplin/blob/dev/readme/nextcloud_app.md
|
||||
|
||||
<div class="main">
|
||||
<h1>Joplin Web API for Nextcloud<a name="joplin-web-api-for-nextcloud" href="#joplin-web-api-for-nextcloud" class="heading-anchor">🔗</a></h1>
|
||||
<hr>
|
||||
<p><strong>IMPORTANT: THIS APPLICATION IS DEPRECATED AND WILL NO LONGER BE SUPPORTED FROM JOPLIN 1.6.x</strong></p>
|
||||
<p>It is deprecated in favour of <a href="https://discourse.joplinapp.org/t/joplin-web-api-for-nextcloud/4491/72?u=laurent">Joplin Server</a>, so if you are relying on it please do not upgrade to Joplin 1.6.x till you are ready to migrate to Joplin Server or some other alternative.</p>
|
||||
<hr>
|
||||
<p><strong>This is a beta feature, not yet completed. More info coming soon!</strong></p>
|
||||
<p>The app can be downloaded from there: <a href="https://apps.nextcloud.com/apps/joplin">https://apps.nextcloud.com/apps/joplin</a></p>
|
||||
<p>The Joplin Web API for Nextcloud is a helper application that enables certain features that are not possible otherwise. In particular:</p>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -116,6 +116,7 @@
|
||||
"**/_vieux/": true,
|
||||
"**/.DS_Store": true,
|
||||
"**/*.base64": true,
|
||||
"**/*~": true,
|
||||
"**/*.bundle.js": true,
|
||||
"**/*.eot": true,
|
||||
"**/*.icns": true,
|
||||
@@ -309,6 +310,10 @@
|
||||
"packages/renderer/MdToHtml/rules/sanitize_html.js": true,
|
||||
"packages/app-mobile/lib/rnInjectedJs/": true,
|
||||
"packages/app-mobile/lib/sql-extensions/spellfix.so": true,
|
||||
"packages/server/dist/": true,
|
||||
"packages/server/db-*.sqlite": true,
|
||||
"packages/server/test.pid": true,
|
||||
"packages/server/temp": true,
|
||||
"packages/generator-joplin/generators/app/templates/api/": true,
|
||||
"packages/app-mobile/node_modules/": true,
|
||||
"phpunit.xml": true,
|
||||
|
||||
146
package-lock.json
generated
146
package-lock.json
generated
@@ -289,6 +289,75 @@
|
||||
"dedent": "^0.7.0",
|
||||
"npmlog": "^4.1.2",
|
||||
"yargs": "^14.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "14.2.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
|
||||
"integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^5.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
"find-up": "^3.0.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^3.0.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^15.0.1"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
|
||||
"integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@lerna/collect-uncommitted": {
|
||||
@@ -2183,6 +2252,14 @@
|
||||
"ssri": "^6.0.1",
|
||||
"unique-filename": "^1.1.1",
|
||||
"y18n": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"cache-base": {
|
||||
@@ -10578,80 +10655,11 @@
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "14.2.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
|
||||
"integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^5.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
"find-up": "^3.0.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^3.0.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^15.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
|
||||
"integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,16 @@
|
||||
"buildTranslationsNoTsc": "node packages/tools/build-translation.js",
|
||||
"buildWebsite": "npm run buildApiDoc && node ./packages/tools/build-website.js && npm run buildPluginDoc",
|
||||
"clean": "lerna clean -y && lerna run clean",
|
||||
"circularDependencyCheck": "npx madge --warning --circular --extensions js ./",
|
||||
"generateDatabaseTypes": "node packages/tools/generate-database-types",
|
||||
"linkChecker": "linkchecker https://joplinapp.org",
|
||||
"linter-ci": "./node_modules/.bin/eslint --resolve-plugins-relative-to . --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter-precommit": "./node_modules/.bin/eslint --resolve-plugins-relative-to . --fix --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"linter": "./node_modules/.bin/eslint --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
|
||||
"postinstall": "lerna bootstrap --no-ci && npm run tsc",
|
||||
"bootstrap": "lerna bootstrap --no-ci",
|
||||
"bootstrapIgnoreScripts": "lerna bootstrap --ignore-scripts --no-ci",
|
||||
"postinstall": "npm run bootstrap --no-ci && npm run build",
|
||||
"build": "lerna run build && npm run tsc",
|
||||
"publishAll": "git pull && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
|
||||
"releaseAndroid": "node packages/tools/release-android.js",
|
||||
"releaseCli": "node packages/tools/release-cli.js",
|
||||
@@ -39,7 +43,8 @@
|
||||
"updateIgnored": "gulp updateIgnoredTypeScriptBuild",
|
||||
"updatePluginTypes": "./packages/generator-joplin/updateTypes.sh",
|
||||
"watch": "lerna run watch --stream --parallel",
|
||||
"i": "lerna add --no-bootstrap --scope"
|
||||
"i": "lerna add --no-bootstrap --scope",
|
||||
"server-start-dev": "docker-compose --file docker-compose.server-dev.yml up"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const gulp = require('gulp');
|
||||
const fs = require('fs-extra');
|
||||
const utils = require('@joplin/tools/gulp/utils');
|
||||
const { setPackagePrivateField } = require('@joplin/tools/tool-utils');
|
||||
const tasks = {
|
||||
// compileExtensions: {
|
||||
// fn: require('../Tools/gulp/tasks/compileExtensions.js'),
|
||||
@@ -10,12 +11,12 @@ const tasks = {
|
||||
// updateIgnoredTypeScriptBuild: require('../Tools/gulp/tasks/updateIgnoredTypeScriptBuild'),
|
||||
};
|
||||
|
||||
async function makePackagePublic(filePath) {
|
||||
const text = await fs.readFile(filePath, 'utf8');
|
||||
const obj = JSON.parse(text);
|
||||
delete obj.private;
|
||||
await fs.writeFile(filePath, JSON.stringify(obj), 'utf8');
|
||||
}
|
||||
// async function makePackagePublic(filePath) {
|
||||
// const text = await fs.readFile(filePath, 'utf8');
|
||||
// const obj = JSON.parse(text);
|
||||
// delete obj.private;
|
||||
// await fs.writeFile(filePath, JSON.stringify(obj), 'utf8');
|
||||
// }
|
||||
|
||||
tasks.prepareBuild = {
|
||||
fn: async () => {
|
||||
@@ -25,7 +26,8 @@ tasks.prepareBuild = {
|
||||
});
|
||||
|
||||
await utils.copyFile(`${__dirname}/package.json`, `${buildDir}/package.json`);
|
||||
await makePackagePublic(`${buildDir}/package.json`);
|
||||
// await makePackagePublic(`${buildDir}/package.json`);
|
||||
await setPackagePrivateField(`${buildDir}/package.json`, false);
|
||||
|
||||
await utils.copyFile(`${__dirname}/package-lock.json`, `${buildDir}/package-lock.json`);
|
||||
await utils.copyFile(`${__dirname}/gulpfile.js`, `${buildDir}/gulpfile.js`);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "1.5.1",
|
||||
"version": "1.6.0",
|
||||
"bin": {
|
||||
"joplin": "./main.js"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { allNotesFolders, remoteNotesAndFolders, localNotesFoldersSameAsRemote } from './test-utils-synchronizer';
|
||||
|
||||
const { syncTargetName, synchronizerStart, setupDatabaseAndSynchronizer, synchronizer, sleep, switchClient, syncTargetId, fileApi } = require('./test-utils.js');
|
||||
const { syncTargetName, afterAllCleanUp, synchronizerStart, setupDatabaseAndSynchronizer, synchronizer, sleep, switchClient, syncTargetId, fileApi } = require('./test-utils.js');
|
||||
const Folder = require('@joplin/lib/models/Folder.js');
|
||||
const Note = require('@joplin/lib/models/Note.js');
|
||||
const BaseItem = require('@joplin/lib/models/BaseItem.js');
|
||||
@@ -16,6 +16,10 @@ describe('Synchronizer.basics', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await afterAllCleanUp();
|
||||
});
|
||||
|
||||
it('should create remote items', (async () => {
|
||||
const folder = await Folder.save({ title: 'folder1' });
|
||||
await Note.save({ title: 'un', parent_id: folder.id });
|
||||
@@ -123,10 +127,6 @@ describe('Synchronizer.basics', function() {
|
||||
}));
|
||||
|
||||
it('should delete local notes', (async () => {
|
||||
// For these tests we pass the context around for each user. This is to make sure that the "deletedItemsProcessed"
|
||||
// property of the basicDelta() function is cleared properly at the end of a sync operation. If it is not cleared
|
||||
// it means items will no longer be deleted locally via sync.
|
||||
|
||||
const folder1 = await Folder.save({ title: 'folder1' });
|
||||
const note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||
const note2 = await Note.save({ title: 'deux', parent_id: folder1.id });
|
||||
|
||||
1
packages/app-cli/tests/enex_to_md/svg.html
Normal file
1
packages/app-cli/tests/enex_to_md/svg.html
Normal file
@@ -0,0 +1 @@
|
||||
<img src="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='16px' height='16px' viewBox='0 0 24 24' data-evernote-id='0' class='js-evernote-checked'%3e%3cg transform='translate(0%2c 0)' data-evernote-id='18' class='js-evernote-checked'%3e%3cpolygon fill='none' stroke='%23343434' stroke-width='2' stroke-linecap='square' stroke-miterlimit='10' points='12%2c2.6 15%2c9 21.4%2c9 16.7%2c13.9 18.6%2c21.4 12%2c17.6 5.4%2c21.4 7.3%2c13.9 2.6%2c9 9%2c9 ' stroke-linejoin='miter' data-evernote-id='19' class='js-evernote-checked'%3e%3c/polygon%3e%3c/g%3e%3c/svg%3e"/>
|
||||
1
packages/app-cli/tests/enex_to_md/svg.md
Normal file
1
packages/app-cli/tests/enex_to_md/svg.md
Normal file
@@ -0,0 +1 @@
|
||||

|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
dist/*
|
||||
node_modules/
|
||||
*.jpl
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import joplin from 'api';
|
||||
import { ToolbarButtonLocation } from 'api/types';
|
||||
|
||||
const uslug = require('uslug');
|
||||
|
||||
@@ -91,6 +92,18 @@ joplin.plugins.register({
|
||||
updateTocView();
|
||||
});
|
||||
|
||||
await joplin.commands.register({
|
||||
name: 'toggleToc',
|
||||
label: 'Toggle TOC',
|
||||
iconName: 'fas fa-drum',
|
||||
execute: async () => {
|
||||
const isVisible = await (panels as any).visible(view);
|
||||
(panels as any).show(view, !isVisible);
|
||||
},
|
||||
});
|
||||
|
||||
await joplin.views.toolbarButtons.create('toggleToc', 'toggleToc', ToolbarButtonLocation.NoteToolbar);
|
||||
|
||||
updateTocView();
|
||||
},
|
||||
});
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export enum MenuItemLocation {
|
||||
Note = 'note',
|
||||
Tools = 'tools',
|
||||
Help = 'help',
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Do not use - same as NoteListContextMenu
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ export enum MenuItemLocation {
|
||||
* - `noteIds:string[]`: IDs of the notes that were right-clicked on.
|
||||
*/
|
||||
NoteListContextMenu = 'noteListContextMenu',
|
||||
|
||||
|
||||
EditorContextMenu = 'editorContextMenu',
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ export enum MenuItemLocation {
|
||||
TagContextMenu = 'tagContextMenu',
|
||||
}
|
||||
|
||||
export function isContextMenuItemLocation(location:MenuItemLocation):boolean {
|
||||
export function isContextMenuItemLocation(location: MenuItemLocation): boolean {
|
||||
return [
|
||||
MenuItemLocation.Context,
|
||||
MenuItemLocation.NoteListContextMenu,
|
||||
|
||||
@@ -15,6 +15,7 @@ import KeychainServiceDriver from '@joplin/lib/services/keychain/KeychainService
|
||||
import KeychainServiceDriverDummy from '@joplin/lib/services/keychain/KeychainServiceDriver.dummy';
|
||||
import PluginRunner from '../app/services/plugins/PluginRunner';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import FileApiDriverJoplinServer from '@joplin/lib/file-api-driver-joplinServer';
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const { JoplinDatabase } = require('@joplin/lib/joplin-database.js');
|
||||
@@ -43,12 +44,14 @@ const SyncTargetOneDrive = require('@joplin/lib/SyncTargetOneDrive.js');
|
||||
const SyncTargetNextcloud = require('@joplin/lib/SyncTargetNextcloud.js');
|
||||
const SyncTargetDropbox = require('@joplin/lib/SyncTargetDropbox.js');
|
||||
const SyncTargetAmazonS3 = require('@joplin/lib/SyncTargetAmazonS3.js');
|
||||
const SyncTargetJoplinServer = require('@joplin/lib/SyncTargetJoplinServer').default;
|
||||
const EncryptionService = require('@joplin/lib/services/EncryptionService.js');
|
||||
const DecryptionWorker = require('@joplin/lib/services/DecryptionWorker.js');
|
||||
const RevisionService = require('@joplin/lib/services/RevisionService.js');
|
||||
const ResourceFetcher = require('@joplin/lib/services/ResourceFetcher.js');
|
||||
const WebDavApi = require('@joplin/lib/WebDavApi');
|
||||
const DropboxApi = require('@joplin/lib/DropboxApi');
|
||||
const JoplinServerApi = require('@joplin/lib/JoplinServerApi2').default;
|
||||
const { OneDriveApi } = require('@joplin/lib/onedrive-api');
|
||||
const { loadKeychainServiceAndSettings } = require('@joplin/lib/services/SettingUtils');
|
||||
const md5 = require('md5');
|
||||
@@ -116,6 +119,7 @@ SyncTargetRegistry.addClass(SyncTargetOneDrive);
|
||||
SyncTargetRegistry.addClass(SyncTargetNextcloud);
|
||||
SyncTargetRegistry.addClass(SyncTargetDropbox);
|
||||
SyncTargetRegistry.addClass(SyncTargetAmazonS3);
|
||||
SyncTargetRegistry.addClass(SyncTargetJoplinServer);
|
||||
|
||||
let syncTargetName_ = '';
|
||||
let syncTargetId_: number = null;
|
||||
@@ -132,7 +136,7 @@ function setSyncTargetName(name: string) {
|
||||
syncTargetName_ = name;
|
||||
syncTargetId_ = SyncTargetRegistry.nameToId(syncTargetName_);
|
||||
sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 100;// 400;
|
||||
isNetworkSyncTarget_ = ['nextcloud', 'dropbox', 'onedrive', 'amazon_s3'].includes(syncTargetName_);
|
||||
isNetworkSyncTarget_ = ['nextcloud', 'dropbox', 'onedrive', 'amazon_s3', 'joplinServer'].includes(syncTargetName_);
|
||||
synchronizers_ = [];
|
||||
return previousName;
|
||||
}
|
||||
@@ -142,6 +146,7 @@ setSyncTargetName('memory');
|
||||
// setSyncTargetName('dropbox');
|
||||
// setSyncTargetName('onedrive');
|
||||
// setSyncTargetName('amazon_s3');
|
||||
// setSyncTargetName('joplinServer');
|
||||
|
||||
// console.info(`Testing with sync target: ${syncTargetName_}`);
|
||||
|
||||
@@ -214,6 +219,16 @@ async function afterEachCleanUp() {
|
||||
KeymapService.destroyInstance();
|
||||
}
|
||||
|
||||
async function afterAllCleanUp() {
|
||||
if (fileApi()) {
|
||||
try {
|
||||
await fileApi().clearRoot();
|
||||
} catch (error) {
|
||||
console.warn('Could not clear sync target root:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function switchClient(id: number, options: any = null) {
|
||||
options = Object.assign({}, { keychainEnabled: false }, options);
|
||||
|
||||
@@ -346,7 +361,7 @@ async function setupDatabaseAndSynchronizer(id: number, options: any = null) {
|
||||
if (!synchronizers_[id]) {
|
||||
const SyncTargetClass = SyncTargetRegistry.classById(syncTargetId_);
|
||||
const syncTarget = new SyncTargetClass(db(id));
|
||||
await initFileApi();
|
||||
await initFileApi(suiteName_);
|
||||
syncTarget.setFileApi(fileApi());
|
||||
syncTarget.setLogger(logger);
|
||||
synchronizers_[id] = await syncTarget.synchronizer();
|
||||
@@ -361,6 +376,7 @@ async function setupDatabaseAndSynchronizer(id: number, options: any = null) {
|
||||
resourceFetchers_[id] = new ResourceFetcher(() => { return synchronizers_[id].api(); });
|
||||
kvStores_[id] = new KvStore();
|
||||
|
||||
await fileApi().initialize();
|
||||
await fileApi().clearRoot();
|
||||
}
|
||||
|
||||
@@ -440,7 +456,7 @@ async function loadEncryptionMasterKey(id: number = null, useExisting = false) {
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
async function initFileApi() {
|
||||
async function initFileApi(suiteName: string) {
|
||||
if (fileApis_[syncTargetId_]) return;
|
||||
|
||||
let fileApi = null;
|
||||
@@ -482,7 +498,6 @@ async function initFileApi() {
|
||||
|
||||
if (!process.argv.includes('--runInBand')) {
|
||||
throw new Error('OneDrive tests must be run sequentially, with the --runInBand arg. eg `npm test -- --runInBand`');
|
||||
|
||||
}
|
||||
|
||||
const { parameters, setEnvOverride } = require('@joplin/lib/parameters.js');
|
||||
@@ -506,6 +521,16 @@ async function initFileApi() {
|
||||
if (!amazonS3Creds || !amazonS3Creds.accessKeyId) throw new Error(`AWS auth JSON missing in ${amazonS3CredsPath} format should be: { "accessKeyId": "", "secretAccessKey": "", "bucket": "mybucket"}`);
|
||||
const api = new S3({ accessKeyId: amazonS3Creds.accessKeyId, secretAccessKey: amazonS3Creds.secretAccessKey, s3UseArnRegion: true });
|
||||
fileApi = new FileApi('', new FileApiDriverAmazonS3(api, amazonS3Creds.bucket));
|
||||
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('joplinServer')) {
|
||||
// Note that to test the API in parallel mode, you need to use Postgres
|
||||
// as database, as the SQLite database is not reliable when being
|
||||
// read/write from multiple processes at the same time.
|
||||
const api = new JoplinServerApi({
|
||||
baseUrl: () => 'http://localhost:22300',
|
||||
username: () => 'admin@localhost',
|
||||
password: () => 'admin',
|
||||
});
|
||||
fileApi = new FileApi(`root:/Apps/Joplin-${suiteName}`, new FileApiDriverJoplinServer(api));
|
||||
}
|
||||
|
||||
fileApi.setLogger(logger);
|
||||
@@ -743,18 +768,18 @@ class TestApp extends BaseApplication {
|
||||
private middlewareCalls_: any[];
|
||||
private logger_: LoggerWrapper;
|
||||
|
||||
constructor(hasGui = true) {
|
||||
public constructor(hasGui = true) {
|
||||
super();
|
||||
this.hasGui_ = hasGui;
|
||||
this.middlewareCalls_ = [];
|
||||
this.logger_ = super.logger();
|
||||
}
|
||||
|
||||
hasGui() {
|
||||
public hasGui() {
|
||||
return this.hasGui_;
|
||||
}
|
||||
|
||||
async start(argv: any[]) {
|
||||
public async start(argv: any[]) {
|
||||
this.logger_.info('Test app starting...');
|
||||
|
||||
if (!argv.includes('--profile')) {
|
||||
@@ -775,7 +800,7 @@ class TestApp extends BaseApplication {
|
||||
this.logger_.info('Test app started...');
|
||||
}
|
||||
|
||||
async generalMiddleware(store: any, next: any, action: any) {
|
||||
public async generalMiddleware(store: any, next: any, action: any) {
|
||||
this.middlewareCalls_.push(true);
|
||||
try {
|
||||
await super.generalMiddleware(store, next, action);
|
||||
@@ -784,7 +809,7 @@ class TestApp extends BaseApplication {
|
||||
}
|
||||
}
|
||||
|
||||
async wait() {
|
||||
public async wait() {
|
||||
return new Promise((resolve) => {
|
||||
const iid = shim.setInterval(() => {
|
||||
if (!this.middlewareCalls_.length) {
|
||||
@@ -795,11 +820,11 @@ class TestApp extends BaseApplication {
|
||||
});
|
||||
}
|
||||
|
||||
async profileDir() {
|
||||
public async profileDir() {
|
||||
return Setting.value('profileDir');
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
public async destroy() {
|
||||
this.logger_.info('Test app stopping...');
|
||||
await this.wait();
|
||||
await ItemChange.waitForAllSaved();
|
||||
@@ -809,4 +834,4 @@ class TestApp extends BaseApplication {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { exportDir, newPluginService, newPluginScript, synchronizerStart, afterEachCleanUp, syncTargetName, setSyncTargetName, syncDir, createTempDir, isNetworkSyncTarget, kvStore, expectThrow, logger, expectNotThrow, resourceService, resourceFetcher, tempFilePath, allSyncTargetItemsEncrypted, msleep, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, checkThrow, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, currentClientId, id, ids, sortedIds, at, createNTestNotes, createNTestFolders, createNTestTags, TestApp };
|
||||
module.exports = { afterAllCleanUp, exportDir, newPluginService, newPluginScript, synchronizerStart, afterEachCleanUp, syncTargetName, setSyncTargetName, syncDir, createTempDir, isNetworkSyncTarget, kvStore, expectThrow, logger, expectNotThrow, resourceService, resourceFetcher, tempFilePath, allSyncTargetItemsEncrypted, msleep, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, checkThrow, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, currentClientId, id, ids, sortedIds, at, createNTestNotes, createNTestFolders, createNTestTags, TestApp };
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Joplin Web Clipper [DEV]",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.1",
|
||||
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
|
||||
"homepage_url": "https://joplinapp.org",
|
||||
"content_security_policy": "script-src 'self'; object-src 'self'",
|
||||
|
||||
@@ -22,6 +22,9 @@ import { LayoutItem } from './gui/ResizableLayout/utils/types';
|
||||
import stateToWhenClauseContext from './services/commands/stateToWhenClauseContext';
|
||||
import ResourceService from '@joplin/lib/services/ResourceService';
|
||||
import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher';
|
||||
import produce from 'immer';
|
||||
import iterateItems from './gui/ResizableLayout/utils/iterateItems';
|
||||
import validateLayout from './gui/ResizableLayout/utils/validateLayout';
|
||||
|
||||
const { FoldersScreenUtils } = require('@joplin/lib/folders-screen-utils.js');
|
||||
const MasterKey = require('@joplin/lib/models/MasterKey');
|
||||
@@ -247,6 +250,29 @@ class Application extends BaseApplication {
|
||||
};
|
||||
break;
|
||||
|
||||
case 'MAIN_LAYOUT_SET_ITEM_PROP':
|
||||
|
||||
{
|
||||
let newLayout = produce(state.mainLayout, (draftLayout: LayoutItem) => {
|
||||
iterateItems(draftLayout, (_itemIndex: number, item: LayoutItem, _parent: LayoutItem) => {
|
||||
if (item.key === action.itemKey) {
|
||||
(item as any)[action.propName] = action.propValue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
|
||||
|
||||
newState = {
|
||||
...state,
|
||||
mainLayout: newLayout,
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'NOTE_FILE_WATCHER_ADD':
|
||||
|
||||
if (newState.watchedNoteFiles.indexOf(action.id) < 0) {
|
||||
|
||||
@@ -214,7 +214,7 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
let output = null;
|
||||
|
||||
try {
|
||||
output = loadLayout(userLayout, defaultLayout, rootLayoutSize);
|
||||
output = loadLayout(Object.keys(userLayout).length ? userLayout : null, defaultLayout, rootLayoutSize);
|
||||
|
||||
if (!findItemByKey(output, 'sideBar') || !findItemByKey(output, 'noteList') || !findItemByKey(output, 'editor')) {
|
||||
throw new Error('"sideBar", "noteList" and "editor" must be present in the layout');
|
||||
|
||||
@@ -19,7 +19,7 @@ const taboverride = require('taboverride');
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const BaseItem = require('@joplin/lib/models/BaseItem');
|
||||
const { themeStyle } = require('@joplin/lib/theme');
|
||||
// const { clipboard } = require('electron');
|
||||
const { clipboard } = require('electron');
|
||||
const supportedLocales = require('./supportedLocales');
|
||||
|
||||
function markupRenderOptions(override: any = null) {
|
||||
@@ -1015,19 +1015,22 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(_event: any) {
|
||||
// It seems "paste as text" is now handled automatically by
|
||||
// either Chrome, Electron and/or TinyMCE so the code below
|
||||
// should not longer be necessary. Also fixes
|
||||
function onKeyDown(event: any) {
|
||||
// It seems "paste as text" is handled automatically by
|
||||
// on Windows so the code below so we need to run the below
|
||||
// code only on macOS (and maybe Linux). If we were to run
|
||||
// this on Windows we would have this double-paste issue:
|
||||
// https://github.com/laurent22/joplin/issues/4243
|
||||
|
||||
// Handle "paste as text". Note that when pressing CtrlOrCmd+Shift+V it's going
|
||||
// to trigger the "keydown" event but not the "paste" event, so it's ok to process
|
||||
// it here and we don't need to do anything special in onPaste
|
||||
// if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.code === 'KeyV') {
|
||||
// const pastedText = clipboard.readText();
|
||||
// if (pastedText) editor.insertContent(pastedText);
|
||||
// }
|
||||
if (!shim.isWindows()) {
|
||||
if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.code === 'KeyV') {
|
||||
const pastedText = clipboard.readText();
|
||||
if (pastedText) editor.insertContent(pastedText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
editor.on('keyup', onKeyUp);
|
||||
|
||||
@@ -16,8 +16,4 @@ export default function findItemByKey(layout: LayoutItem, key: string): LayoutIt
|
||||
}
|
||||
|
||||
return recurseFind(layout);
|
||||
|
||||
// const output = recurseFind(layout);
|
||||
// if (!output) throw new Error(`Could not find item "${key}"`);
|
||||
// return output;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { LayoutItem } from './types';
|
||||
|
||||
type ItemItemCallback = (itemIndex: number, item: LayoutItem, parent: LayoutItem)=> boolean;
|
||||
|
||||
// Callback should return `true` if iteration should continue, or `false` if it
|
||||
// should stop
|
||||
export default function iterateItems(layout: LayoutItem, callback: ItemItemCallback) {
|
||||
const result = callback(0, layout, null);
|
||||
if (result === false) return;
|
||||
|
||||
2
packages/app-desktop/package-lock.json
generated
2
packages/app-desktop/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "1.5.10",
|
||||
"version": "1.6.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "1.5.10",
|
||||
"version": "1.6.1",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
# It could be used to develop plugins too.
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/register_command"
|
||||
PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/toc"
|
||||
npm i --prefix="$PLUGIN_PATH" && npm start -- --dev-plugins "$PLUGIN_PATH"
|
||||
@@ -138,8 +138,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097613
|
||||
versionName "1.5.0"
|
||||
versionCode 2097618
|
||||
versionName "1.6.4"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// So there's basically still a one way flux: React => SQLite => Redux => React
|
||||
|
||||
import { LogBox, AppRegistry } from 'react-native';
|
||||
const { Root } = require('./root.js');
|
||||
const Root = require('./root').default;
|
||||
|
||||
// Seems JavaScript developers love adding warnings everywhere, even when these warnings can't be fixed
|
||||
// or don't really matter. Because we want important warnings to actually be fixed, we disable
|
||||
|
||||
@@ -338,13 +338,13 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 57;
|
||||
CURRENT_PROJECT_VERSION = 59;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 10.5.0;
|
||||
MARKETING_VERSION = 10.6.1;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -365,12 +365,12 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 57;
|
||||
CURRENT_PROJECT_VERSION = 59;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 10.5.0;
|
||||
MARKETING_VERSION = 10.6.1;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
|
||||
@@ -1,24 +1,43 @@
|
||||
import setUpQuickActions from './setUpQuickActions';
|
||||
import PluginAssetsLoader from './PluginAssetsLoader';
|
||||
|
||||
const React = require('react');
|
||||
const { AppState, Keyboard, NativeModules, BackHandler, Animated, View, StatusBar } = require('react-native');
|
||||
const shim = require('@joplin/lib/shim').default;
|
||||
import shim from '@joplin/lib/shim';
|
||||
shim.setReact(React);
|
||||
|
||||
import setUpQuickActions from './setUpQuickActions';
|
||||
import PluginAssetsLoader from './PluginAssetsLoader';
|
||||
import AlarmService from '@joplin/lib/services/AlarmService';
|
||||
import Alarm from '@joplin/lib/models/Alarm';
|
||||
import time from '@joplin/lib/time';
|
||||
import Logger, { TargetType } from '@joplin/lib/Logger';
|
||||
import BaseModel from '@joplin/lib/BaseModel';
|
||||
import BaseService from '@joplin/lib/services/BaseService';
|
||||
import ResourceService from '@joplin/lib/services/ResourceService';
|
||||
import KvStore from '@joplin/lib/services/KvStore';
|
||||
import NoteScreen from './components/screens/Note';
|
||||
import UpgradeSyncTargetScreen from './components/screens/UpgradeSyncTargetScreen';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import PoorManIntervals from '@joplin/lib/PoorManIntervals';
|
||||
import reducer from '@joplin/lib/reducer';
|
||||
import ShareExtension from './utils/ShareExtension';
|
||||
import handleShared from './utils/shareHandler';
|
||||
import uuid from '@joplin/lib/uuid';
|
||||
import { loadKeychainServiceAndSettings } from '@joplin/lib/services/SettingUtils';
|
||||
import KeychainServiceDriverMobile from '@joplin/lib/services/keychain/KeychainServiceDriver.mobile';
|
||||
import { setLocale, closestSupportedLocale, defaultLocale } from '@joplin/lib/locale';
|
||||
import SyncTargetJoplinServer from '@joplin/lib/SyncTargetJoplinServer';
|
||||
|
||||
const { AppState, Keyboard, NativeModules, BackHandler, Animated, View, StatusBar } = require('react-native');
|
||||
|
||||
const DropdownAlert = require('react-native-dropdownalert').default;
|
||||
const AlarmServiceDriver = require('./services/AlarmServiceDriver').default;
|
||||
const SafeAreaView = require('./components/SafeAreaView');
|
||||
const { connect, Provider } = require('react-redux');
|
||||
const { BackButtonService } = require('./services/back-button.js');
|
||||
const NavService = require('@joplin/lib/services/NavService.js');
|
||||
const AlarmService = require('@joplin/lib/services/AlarmService.js').default;
|
||||
const AlarmServiceDriver = require('./services/AlarmServiceDriver').default;
|
||||
const Alarm = require('@joplin/lib/models/Alarm').default;
|
||||
const { createStore, applyMiddleware } = require('redux');
|
||||
const reduxSharedMiddleware = require('@joplin/lib/components/shared/reduxSharedMiddleware');
|
||||
const { shimInit } = require('./utils/shim-init-react.js');
|
||||
const time = require('@joplin/lib/time').default;
|
||||
const { AppNav } = require('./components/app-nav.js');
|
||||
const Logger = require('@joplin/lib/Logger').default;
|
||||
const Note = require('@joplin/lib/models/Note.js');
|
||||
const Folder = require('@joplin/lib/models/Folder.js');
|
||||
const BaseSyncTarget = require('@joplin/lib/BaseSyncTarget.js');
|
||||
@@ -29,16 +48,11 @@ const NoteTag = require('@joplin/lib/models/NoteTag.js');
|
||||
const BaseItem = require('@joplin/lib/models/BaseItem.js');
|
||||
const MasterKey = require('@joplin/lib/models/MasterKey.js');
|
||||
const Revision = require('@joplin/lib/models/Revision.js');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const BaseService = require('@joplin/lib/services/BaseService').default;
|
||||
const ResourceService = require('@joplin/lib/services/ResourceService').default;
|
||||
const RevisionService = require('@joplin/lib/services/RevisionService');
|
||||
const KvStore = require('@joplin/lib/services/KvStore').default;
|
||||
const { JoplinDatabase } = require('@joplin/lib/joplin-database.js');
|
||||
const { Database } = require('@joplin/lib/database.js');
|
||||
const { NotesScreen } = require('./components/screens/notes.js');
|
||||
const { TagsScreen } = require('./components/screens/tags.js');
|
||||
const NoteScreen = require('./components/screens/Note').default;
|
||||
const { ConfigScreen } = require('./components/screens/config.js');
|
||||
const { FolderScreen } = require('./components/screens/folder.js');
|
||||
const { LogScreen } = require('./components/screens/log.js');
|
||||
@@ -47,31 +61,18 @@ const { SearchScreen } = require('./components/screens/search.js');
|
||||
const { OneDriveLoginScreen } = require('./components/screens/onedrive-login.js');
|
||||
const { EncryptionConfigScreen } = require('./components/screens/encryption-config.js');
|
||||
const { DropboxLoginScreen } = require('./components/screens/dropbox-login.js');
|
||||
const UpgradeSyncTargetScreen = require('./components/screens/UpgradeSyncTargetScreen').default;
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const { MenuContext } = require('react-native-popup-menu');
|
||||
const { SideMenu } = require('./components/side-menu.js');
|
||||
const { SideMenuContent } = require('./components/side-menu-content.js');
|
||||
const { SideMenuContentNote } = require('./components/side-menu-content-note.js');
|
||||
const { DatabaseDriverReactNative } = require('./utils/database-driver-react-native');
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const { setLocale, closestSupportedLocale, defaultLocale } = require('@joplin/lib/locale');
|
||||
const RNFetchBlob = require('rn-fetch-blob').default;
|
||||
const PoorManIntervals = require('@joplin/lib/PoorManIntervals').default;
|
||||
const reducer = require('@joplin/lib/reducer').default;
|
||||
const { defaultState } = require('@joplin/lib/reducer');
|
||||
const { FileApiDriverLocal } = require('@joplin/lib/file-api-driver-local.js');
|
||||
const DropdownAlert = require('react-native-dropdownalert').default;
|
||||
const ShareExtension = require('./utils/ShareExtension.js').default;
|
||||
const handleShared = require('./utils/shareHandler').default;
|
||||
const ResourceFetcher = require('@joplin/lib/services/ResourceFetcher');
|
||||
const SearchEngine = require('@joplin/lib/services/searchengine/SearchEngine');
|
||||
const WelcomeUtils = require('@joplin/lib/WelcomeUtils');
|
||||
const { themeStyle } = require('./components/global-style.js');
|
||||
const uuid = require('@joplin/lib/uuid').default;
|
||||
|
||||
const { loadKeychainServiceAndSettings } = require('@joplin/lib/services/SettingUtils');
|
||||
const KeychainServiceDriverMobile = require('@joplin/lib/services/keychain/KeychainServiceDriver.mobile').default;
|
||||
|
||||
const SyncTargetRegistry = require('@joplin/lib/SyncTargetRegistry.js');
|
||||
const SyncTargetOneDrive = require('@joplin/lib/SyncTargetOneDrive.js');
|
||||
@@ -87,15 +88,16 @@ SyncTargetRegistry.addClass(SyncTargetWebDAV);
|
||||
SyncTargetRegistry.addClass(SyncTargetDropbox);
|
||||
SyncTargetRegistry.addClass(SyncTargetFilesystem);
|
||||
SyncTargetRegistry.addClass(SyncTargetAmazonS3);
|
||||
SyncTargetRegistry.addClass(SyncTargetJoplinServer);
|
||||
|
||||
const FsDriverRN = require('./utils/fs-driver-rn.js').FsDriverRN;
|
||||
const DecryptionWorker = require('@joplin/lib/services/DecryptionWorker');
|
||||
const EncryptionService = require('@joplin/lib/services/EncryptionService');
|
||||
const MigrationService = require('@joplin/lib/services/MigrationService');
|
||||
|
||||
let storeDispatch = function() {};
|
||||
let storeDispatch = function(_action: any) {};
|
||||
|
||||
const logReducerAction = function(action) {
|
||||
const logReducerAction = function(action: any) {
|
||||
if (['SIDE_MENU_OPEN_PERCENT', 'SYNC_REPORT_UPDATE'].indexOf(action.type) >= 0) return;
|
||||
|
||||
const msg = [action.type];
|
||||
@@ -104,7 +106,7 @@ const logReducerAction = function(action) {
|
||||
// reg.logger().debug('Reducer action', msg.join(', '));
|
||||
};
|
||||
|
||||
const generalMiddleware = store => next => async (action) => {
|
||||
const generalMiddleware = (store: any) => (next: any) => async (action: any) => {
|
||||
logReducerAction(action);
|
||||
PoorManIntervals.update(); // This function needs to be called regularly so put it here
|
||||
|
||||
@@ -167,9 +169,9 @@ const generalMiddleware = store => next => async (action) => {
|
||||
return result;
|
||||
};
|
||||
|
||||
const navHistory = [];
|
||||
const navHistory: any[] = [];
|
||||
|
||||
function historyCanGoBackTo(route) {
|
||||
function historyCanGoBackTo(route: any) {
|
||||
if (route.routeName === 'Note') return false;
|
||||
if (route.routeName === 'Folder') return false;
|
||||
|
||||
@@ -194,13 +196,14 @@ const appDefaultState = Object.assign({}, defaultState, {
|
||||
noteSideMenuOptions: null,
|
||||
});
|
||||
|
||||
const appReducer = (state = appDefaultState, action) => {
|
||||
const appReducer = (state = appDefaultState, action: any) => {
|
||||
let newState = state;
|
||||
let historyGoingBack = false;
|
||||
|
||||
try {
|
||||
switch (action.type) {
|
||||
|
||||
// @ts-ignore
|
||||
case 'NAV_BACK':
|
||||
|
||||
{
|
||||
@@ -224,7 +227,7 @@ const appReducer = (state = appDefaultState, action) => {
|
||||
{
|
||||
const currentRoute = state.route;
|
||||
|
||||
if (!historyGoingBack && historyCanGoBackTo(currentRoute, action)) {
|
||||
if (!historyGoingBack && historyCanGoBackTo(currentRoute)) {
|
||||
// If the route *name* is the same (even if the other parameters are different), we
|
||||
// overwrite the last route in the history with the current one. If the route name
|
||||
// is different, we push a new history entry.
|
||||
@@ -368,7 +371,7 @@ const appReducer = (state = appDefaultState, action) => {
|
||||
const store = createStore(appReducer, applyMiddleware(generalMiddleware));
|
||||
storeDispatch = store.dispatch;
|
||||
|
||||
function resourceFetcher_downloadComplete(event) {
|
||||
function resourceFetcher_downloadComplete(event: any) {
|
||||
if (event.encrypted) {
|
||||
DecryptionWorker.instance().scheduleStart();
|
||||
}
|
||||
@@ -378,9 +381,10 @@ function decryptionWorker_resourceMetadataButNotBlobDecrypted() {
|
||||
ResourceFetcher.instance().scheduleAutoAddResources();
|
||||
}
|
||||
|
||||
async function initialize(dispatch) {
|
||||
async function initialize(dispatch: Function) {
|
||||
shimInit();
|
||||
|
||||
// @ts-ignore
|
||||
Setting.setConstant('env', __DEV__ ? 'dev' : 'prod');
|
||||
Setting.setConstant('appId', 'net.cozic.joplin-mobile');
|
||||
Setting.setConstant('appType', 'mobile');
|
||||
@@ -391,18 +395,18 @@ async function initialize(dispatch) {
|
||||
await logDatabase.exec(Logger.databaseCreateTableSql());
|
||||
|
||||
const mainLogger = new Logger();
|
||||
mainLogger.addTarget('database', { database: logDatabase, source: 'm' });
|
||||
mainLogger.addTarget(TargetType.Database, { database: logDatabase, source: 'm' });
|
||||
mainLogger.setLevel(Logger.LEVEL_INFO);
|
||||
|
||||
if (Setting.value('env') == 'dev') {
|
||||
mainLogger.addTarget('console');
|
||||
mainLogger.addTarget(TargetType.Console);
|
||||
mainLogger.setLevel(Logger.LEVEL_DEBUG);
|
||||
}
|
||||
|
||||
Logger.initializeGlobalLogger(mainLogger);
|
||||
|
||||
reg.setLogger(mainLogger);
|
||||
reg.setShowErrorMessageBoxHandler((message) => { alert(message); });
|
||||
reg.setShowErrorMessageBoxHandler((message: string) => { alert(message); });
|
||||
|
||||
BaseService.logger_ = mainLogger;
|
||||
// require('@joplin/lib/ntpDate').setLogger(reg.logger());
|
||||
@@ -411,9 +415,9 @@ async function initialize(dispatch) {
|
||||
reg.logger().info(`Starting application ${Setting.value('appId')} (${Setting.value('env')})`);
|
||||
|
||||
const dbLogger = new Logger();
|
||||
dbLogger.addTarget('database', { database: logDatabase, source: 'm' });
|
||||
dbLogger.addTarget(TargetType.Database, { database: logDatabase, source: 'm' });
|
||||
if (Setting.value('env') == 'dev') {
|
||||
dbLogger.addTarget('console');
|
||||
dbLogger.addTarget(TargetType.Console);
|
||||
dbLogger.setLevel(Logger.LEVEL_INFO); // Set to LEVEL_DEBUG for full SQL queries
|
||||
} else {
|
||||
dbLogger.setLevel(Logger.LEVEL_INFO);
|
||||
@@ -452,7 +456,7 @@ async function initialize(dispatch) {
|
||||
if (Setting.value('env') == 'prod') {
|
||||
await db.open({ name: 'joplin.sqlite' });
|
||||
} else {
|
||||
await db.open({ name: 'joplin-76.sqlite' });
|
||||
await db.open({ name: 'joplin-100.sqlite' });
|
||||
|
||||
// await db.clearForTesting();
|
||||
}
|
||||
@@ -562,7 +566,7 @@ async function initialize(dispatch) {
|
||||
reg.setupRecurrentSync();
|
||||
|
||||
PoorManIntervals.setTimeout(() => {
|
||||
AlarmService.garbageCollect();
|
||||
void AlarmService.garbageCollect();
|
||||
}, 1000 * 60 * 60);
|
||||
|
||||
ResourceService.runInBackground();
|
||||
@@ -584,7 +588,7 @@ async function initialize(dispatch) {
|
||||
reg.scheduleSync(1000).then(() => {
|
||||
// Wait for the first sync before updating the notifications, since synchronisation
|
||||
// might change the notifications.
|
||||
AlarmService.updateAllNotifications();
|
||||
void AlarmService.updateAllNotifications();
|
||||
|
||||
DecryptionWorker.instance().scheduleStart();
|
||||
});
|
||||
@@ -654,7 +658,7 @@ class AppComponent extends React.Component {
|
||||
|
||||
BackButtonService.initialize(this.backButtonHandler_);
|
||||
|
||||
AlarmService.setInAppNotificationHandler(async (alarmId) => {
|
||||
AlarmService.setInAppNotificationHandler(async (alarmId: string) => {
|
||||
const alarm = await Alarm.load(alarmId);
|
||||
const notification = await Alarm.makeNotification(alarm);
|
||||
this.dropdownAlert_.alertWithType('info', notification.title, notification.body ? notification.body : '');
|
||||
@@ -666,7 +670,7 @@ class AppComponent extends React.Component {
|
||||
if (sharedData) {
|
||||
reg.logger().info('Received shared data');
|
||||
if (this.props.selectedFolderId) {
|
||||
handleShared(sharedData, this.props.selectedFolderId, this.props.dispatch);
|
||||
await handleShared(sharedData, this.props.selectedFolderId, this.props.dispatch);
|
||||
} else {
|
||||
reg.logger.info('Cannot handle share - default folder id is not set');
|
||||
}
|
||||
@@ -677,7 +681,7 @@ class AppComponent extends React.Component {
|
||||
AppState.removeEventListener('change', this.onAppStateChange_);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps: any) {
|
||||
if (this.props.showSideMenu !== prevProps.showSideMenu) {
|
||||
Animated.timing(this.state.sideMenuContentOpacity, {
|
||||
toValue: this.props.showSideMenu ? 0.5 : 0,
|
||||
@@ -707,14 +711,14 @@ class AppComponent extends React.Component {
|
||||
return false;
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps) {
|
||||
UNSAFE_componentWillReceiveProps(newProps: any) {
|
||||
if (newProps.syncStarted != this.lastSyncStarted_) {
|
||||
if (!newProps.syncStarted) FoldersScreenUtils.refreshFolders();
|
||||
this.lastSyncStarted_ = newProps.syncStarted;
|
||||
}
|
||||
}
|
||||
|
||||
sideMenu_change(isOpen) {
|
||||
sideMenu_change(isOpen: boolean) {
|
||||
// Make sure showSideMenu property of state is updated
|
||||
// when the menu is open/closed.
|
||||
this.props.dispatch({
|
||||
@@ -759,8 +763,8 @@ class AppComponent extends React.Component {
|
||||
menu={sideMenuContent}
|
||||
edgeHitWidth={5}
|
||||
menuPosition={menuPosition}
|
||||
onChange={(isOpen) => this.sideMenu_change(isOpen)}
|
||||
onSliding={(percent) => {
|
||||
onChange={(isOpen: boolean) => this.sideMenu_change(isOpen)}
|
||||
onSliding={(percent: number) => {
|
||||
this.props.dispatch({
|
||||
type: 'SIDE_MENU_OPEN_PERCENT',
|
||||
value: percent,
|
||||
@@ -773,7 +777,7 @@ class AppComponent extends React.Component {
|
||||
<View style={{ flex: 1, backgroundColor: theme.backgroundColor }}>
|
||||
<AppNav screens={appNavInit} />
|
||||
</View>
|
||||
<DropdownAlert ref={ref => this.dropdownAlert_ = ref} tapToCloseEnabled={true} />
|
||||
<DropdownAlert ref={(ref: any) => this.dropdownAlert_ = ref} tapToCloseEnabled={true} />
|
||||
<Animated.View pointerEvents='none' style={{ position: 'absolute', backgroundColor: 'black', opacity: this.state.sideMenuContentOpacity, width: '100%', height: '120%' }}/>
|
||||
</SafeAreaView>
|
||||
</MenuContext>
|
||||
@@ -783,7 +787,7 @@ class AppComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const mapStateToProps = (state: any) => {
|
||||
return {
|
||||
historyCanGoBack: state.historyCanGoBack,
|
||||
showSideMenu: state.showSideMenu,
|
||||
@@ -799,7 +803,7 @@ const mapStateToProps = (state) => {
|
||||
|
||||
const App = connect(mapStateToProps)(AppComponent);
|
||||
|
||||
class Root extends React.Component {
|
||||
export default class Root extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
@@ -808,5 +812,3 @@ class Root extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Root };
|
||||
@@ -24,9 +24,9 @@ export default async (sharedData: SharedData, folderId: string, dispatch: Functi
|
||||
// below will do nothing (because routeName wouldn't change)
|
||||
// Then we wait a bit for the state to be set correctly, and
|
||||
// finally we go to the new note.
|
||||
await dispatch({ type: 'NAV_BACK' });
|
||||
dispatch({ type: 'NAV_BACK' });
|
||||
|
||||
await dispatch({ type: 'SIDE_MENU_CLOSE' });
|
||||
dispatch({ type: 'SIDE_MENU_CLOSE' });
|
||||
|
||||
const newNote = await Note.save({
|
||||
parent_id: folderId,
|
||||
|
||||
@@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
|
||||
* Called when a message is sent from the webview (using postMessage).
|
||||
*/
|
||||
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
|
||||
/**
|
||||
* Shows the panel
|
||||
*/
|
||||
show(handle: ViewHandle, show?: boolean): Promise<void>;
|
||||
/**
|
||||
* Hides the panel
|
||||
*/
|
||||
hide(handle: ViewHandle): Promise<void>;
|
||||
/**
|
||||
* Tells whether the panel is visible or not
|
||||
*/
|
||||
visible(handle: ViewHandle): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"id": "<%= pluginId %>",
|
||||
"app_min_version": "1.5",
|
||||
"app_min_version": "1.6",
|
||||
"version": "1.0.0",
|
||||
"name": "<%= pluginName %>",
|
||||
"description": "<%= pluginDescription %>",
|
||||
|
||||
2
packages/generator-joplin/package-lock.json
generated
2
packages/generator-joplin/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "generator-joplin",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
{
|
||||
"name": "generator-joplin",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.0",
|
||||
"description": "Scaffolds out a new Joplin plugin",
|
||||
"homepage": "https://joplinapp.org",
|
||||
"private": true,
|
||||
"author": {
|
||||
"name": "Laurent Cozic",
|
||||
"url": "https://joplinapp.org"
|
||||
@@ -25,5 +24,6 @@
|
||||
"yosay": "^2.0.1"
|
||||
},
|
||||
"repository": "https://github.com/laurent22/generator-joplin",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import reducer from './reducer';
|
||||
import KeychainServiceDriver from './services/keychain/KeychainServiceDriver.node';
|
||||
import { _, setLocale } from './locale';
|
||||
import KvStore from './services/KvStore';
|
||||
import SyncTargetJoplinServer from './SyncTargetJoplinServer';
|
||||
|
||||
const { createStore, applyMiddleware } = require('redux');
|
||||
const { defaultState, stateUtils } = require('./reducer');
|
||||
@@ -681,6 +682,7 @@ export default class BaseApplication {
|
||||
SyncTargetRegistry.addClass(SyncTargetWebDAV);
|
||||
SyncTargetRegistry.addClass(SyncTargetDropbox);
|
||||
SyncTargetRegistry.addClass(SyncTargetAmazonS3);
|
||||
SyncTargetRegistry.addClass(SyncTargetJoplinServer);
|
||||
|
||||
try {
|
||||
await shim.fsDriver().remove(tempDir);
|
||||
|
||||
@@ -66,7 +66,7 @@ class BaseModel {
|
||||
public static TYPE_SMART_FILTER = ModelType.SmartFilter;
|
||||
public static TYPE_COMMAND = ModelType.Command;
|
||||
|
||||
protected static dispatch: Function = function() {};
|
||||
public static dispatch: Function = function() {};
|
||||
private static saveMutexes_: any = {};
|
||||
|
||||
private static db_: any;
|
||||
|
||||
174
packages/lib/JoplinServerApi2.ts
Normal file
174
packages/lib/JoplinServerApi2.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import shim from './shim';
|
||||
const { rtrimSlashes } = require('./path-utils.js');
|
||||
const JoplinError = require('./JoplinError');
|
||||
const { stringify } = require('query-string');
|
||||
|
||||
interface Options {
|
||||
baseUrl(): string;
|
||||
username(): string;
|
||||
password(): string;
|
||||
}
|
||||
|
||||
enum ExecOptionsResponseFormat {
|
||||
Json = 'json',
|
||||
Text = 'text',
|
||||
}
|
||||
|
||||
enum ExecOptionsTarget {
|
||||
String = 'string',
|
||||
File = 'file',
|
||||
}
|
||||
|
||||
interface ExecOptions {
|
||||
responseFormat?: ExecOptionsResponseFormat;
|
||||
target?: ExecOptionsTarget;
|
||||
path?: string;
|
||||
source?: string;
|
||||
}
|
||||
|
||||
export default class JoplinServerApi {
|
||||
|
||||
private options_: Options;
|
||||
private session_: any;
|
||||
|
||||
public constructor(options: Options) {
|
||||
this.options_ = options;
|
||||
}
|
||||
|
||||
private baseUrl() {
|
||||
return rtrimSlashes(this.options_.baseUrl());
|
||||
}
|
||||
|
||||
private async session() {
|
||||
// TODO: handle invalid session
|
||||
if (this.session_) return this.session_;
|
||||
|
||||
this.session_ = await this.exec('POST', 'api/sessions', null, {
|
||||
email: this.options_.username(),
|
||||
password: this.options_.password(),
|
||||
});
|
||||
|
||||
return this.session_;
|
||||
}
|
||||
|
||||
private async sessionId() {
|
||||
const session = await this.session();
|
||||
return session ? session.id : '';
|
||||
}
|
||||
|
||||
// private requestToCurl_(url: string, options: any) {
|
||||
// const output = [];
|
||||
// output.push('curl');
|
||||
// output.push('-v');
|
||||
// if (options.method) output.push(`-X ${options.method}`);
|
||||
// if (options.headers) {
|
||||
// for (const n in options.headers) {
|
||||
// if (!options.headers.hasOwnProperty(n)) continue;
|
||||
// output.push(`${'-H ' + '"'}${n}: ${options.headers[n]}"`);
|
||||
// }
|
||||
// }
|
||||
// if (options.body) output.push(`${'--data ' + '\''}${JSON.stringify(options.body)}'`);
|
||||
// output.push(url);
|
||||
|
||||
// return output.join(' ');
|
||||
// }
|
||||
|
||||
public async exec(method: string, path: string = '', query: Record<string, any> = null, body: any = null, headers: any = null, options: ExecOptions = null) {
|
||||
if (headers === null) headers = {};
|
||||
if (options === null) options = {};
|
||||
if (!options.responseFormat) options.responseFormat = ExecOptionsResponseFormat.Json;
|
||||
if (!options.target) options.target = ExecOptionsTarget.String;
|
||||
|
||||
let sessionId = '';
|
||||
if (path !== 'api/sessions' && !sessionId) {
|
||||
sessionId = await this.sessionId();
|
||||
}
|
||||
|
||||
if (sessionId) headers['X-API-AUTH'] = sessionId;
|
||||
|
||||
const fetchOptions: any = {};
|
||||
fetchOptions.headers = headers;
|
||||
fetchOptions.method = method;
|
||||
if (options.path) fetchOptions.path = options.path;
|
||||
|
||||
if (body) {
|
||||
if (typeof body === 'object') {
|
||||
fetchOptions.body = JSON.stringify(body);
|
||||
fetchOptions.headers['Content-Type'] = 'application/json';
|
||||
} else {
|
||||
fetchOptions.body = body;
|
||||
}
|
||||
|
||||
fetchOptions.headers['Content-Length'] = `${shim.stringByteLength(fetchOptions.body)}`;
|
||||
}
|
||||
|
||||
let url = `${this.baseUrl()}/${path}`;
|
||||
|
||||
if (query) {
|
||||
url += url.indexOf('?') < 0 ? '?' : '&';
|
||||
url += stringify(query);
|
||||
}
|
||||
|
||||
let response: any = null;
|
||||
|
||||
// console.info('Joplin API Call', `${method} ${url}`, headers, options);
|
||||
// console.info(this.requestToCurl_(url, fetchOptions));
|
||||
|
||||
if (options.source == 'file' && (method == 'POST' || method == 'PUT')) {
|
||||
if (fetchOptions.path) {
|
||||
const fileStat = await shim.fsDriver().stat(fetchOptions.path);
|
||||
if (fileStat) fetchOptions.headers['Content-Length'] = `${fileStat.size}`;
|
||||
}
|
||||
response = await shim.uploadBlob(url, fetchOptions);
|
||||
} else if (options.target == 'string') {
|
||||
if (typeof body === 'string') fetchOptions.headers['Content-Length'] = `${shim.stringByteLength(body)}`;
|
||||
response = await shim.fetch(url, fetchOptions);
|
||||
} else {
|
||||
// file
|
||||
response = await shim.fetchBlob(url, fetchOptions);
|
||||
}
|
||||
|
||||
const responseText = await response.text();
|
||||
|
||||
// console.info('Joplin API Response', responseText);
|
||||
|
||||
// Creates an error object with as much data as possible as it will appear in the log, which will make debugging easier
|
||||
const newError = (message: string, code: number = 0) => {
|
||||
// Gives a shorter response for error messages. Useful for cases where a full HTML page is accidentally loaded instead of
|
||||
// JSON. That way the error message will still show there's a problem but without filling up the log or screen.
|
||||
const shortResponseText = (`${responseText}`).substr(0, 1024);
|
||||
return new JoplinError(`${method} ${path}: ${message} (${code}): ${shortResponseText}`, code);
|
||||
};
|
||||
|
||||
let responseJson_: any = null;
|
||||
const loadResponseJson = async () => {
|
||||
if (!responseText) return null;
|
||||
if (responseJson_) return responseJson_;
|
||||
responseJson_ = JSON.parse(responseText);
|
||||
if (!responseJson_) throw newError('Cannot parse JSON response', response.status);
|
||||
return responseJson_;
|
||||
};
|
||||
|
||||
if (!response.ok) {
|
||||
if (options.target === 'file') throw newError('fetchBlob error', response.status);
|
||||
|
||||
let json = null;
|
||||
try {
|
||||
json = await loadResponseJson();
|
||||
} catch (error) {
|
||||
// Just send back the plain text in newErro()
|
||||
}
|
||||
|
||||
if (json && json.message) {
|
||||
throw newError(`${json.message}`, response.status);
|
||||
}
|
||||
|
||||
throw newError('Unknown error', response.status);
|
||||
}
|
||||
|
||||
if (options.responseFormat === 'text') return responseText;
|
||||
|
||||
const output = await loadResponseJson();
|
||||
return output;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
const moment = require('moment');
|
||||
const time = require('./time').default;
|
||||
const { FsDriverDummy } = require('./fs-driver-dummy.js');
|
||||
const { sprintf } = require('sprintf-js');
|
||||
|
||||
export enum TargetType {
|
||||
Database = 'database',
|
||||
@@ -24,6 +25,12 @@ interface Target {
|
||||
prefix?: string;
|
||||
path?: string;
|
||||
source?: string;
|
||||
|
||||
// Default message format
|
||||
format?: string;
|
||||
|
||||
// If specified, will use this as format if it's an info message
|
||||
formatInfo?: string;
|
||||
}
|
||||
|
||||
export interface LoggerWrapper {
|
||||
@@ -173,9 +180,25 @@ class Logger {
|
||||
if (level == LogLevel.Warn) fn = 'warn';
|
||||
if (level == LogLevel.Info) fn = 'info';
|
||||
const consoleObj = target.console ? target.console : console;
|
||||
const prefixItems = [moment().format('HH:mm:ss')];
|
||||
if (targetPrefix) prefixItems.push(targetPrefix);
|
||||
const items = [`${prefixItems.join(': ')}:`].concat(...object);
|
||||
let items: any[] = [];
|
||||
|
||||
if (target.format) {
|
||||
const format = level === LogLevel.Info && target.formatInfo ? target.formatInfo : target.format;
|
||||
|
||||
const s = sprintf(format, {
|
||||
date_time: moment().format('YYYY-MM-DD HH:mm:ss'),
|
||||
level: Logger.levelIdToString(level),
|
||||
prefix: targetPrefix || '',
|
||||
message: '',
|
||||
});
|
||||
|
||||
items = [s.trim()].concat(...object);
|
||||
} else {
|
||||
const prefixItems = [moment().format('HH:mm:ss')];
|
||||
if (targetPrefix) prefixItems.push(targetPrefix);
|
||||
items = [`${prefixItems.join(': ')}:`].concat(...object);
|
||||
}
|
||||
|
||||
consoleObj[fn](...items);
|
||||
} else if (target.type == 'file') {
|
||||
const timestamp = moment().format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
91
packages/lib/SyncTargetJoplinServer.ts
Normal file
91
packages/lib/SyncTargetJoplinServer.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import FileApiDriverJoplinServer from './file-api-driver-joplinServer';
|
||||
import Setting from './models/Setting';
|
||||
import Synchronizer from './Synchronizer';
|
||||
import { _ } from './locale.js';
|
||||
import JoplinServerApi from './JoplinServerApi2';
|
||||
|
||||
const BaseSyncTarget = require('./BaseSyncTarget.js');
|
||||
const { FileApi } = require('./file-api.js');
|
||||
|
||||
interface FileApiOptions {
|
||||
path(): string;
|
||||
username(): string;
|
||||
password(): string;
|
||||
directory(): string;
|
||||
}
|
||||
|
||||
export default class SyncTargetJoplinServer extends BaseSyncTarget {
|
||||
|
||||
static id() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
static supportsConfigCheck() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static targetName() {
|
||||
return 'joplinServer';
|
||||
}
|
||||
|
||||
static label() {
|
||||
return _('Joplin Server');
|
||||
}
|
||||
|
||||
async isAuthenticated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static async newFileApi_(options: FileApiOptions) {
|
||||
const apiOptions = {
|
||||
baseUrl: () => options.path(),
|
||||
username: () => options.username(),
|
||||
password: () => options.password(),
|
||||
};
|
||||
|
||||
const api = new JoplinServerApi(apiOptions);
|
||||
const driver = new FileApiDriverJoplinServer(api);
|
||||
const fileApi = new FileApi(() => `root:/${options.directory()}`, driver);
|
||||
fileApi.setSyncTargetId(this.id());
|
||||
await fileApi.initialize();
|
||||
return fileApi;
|
||||
}
|
||||
|
||||
static async checkConfig(options: FileApiOptions) {
|
||||
const fileApi = await SyncTargetJoplinServer.newFileApi_(options);
|
||||
fileApi.requestRepeatCount_ = 0;
|
||||
|
||||
const output = {
|
||||
ok: false,
|
||||
errorMessage: '',
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await fileApi.stat('');
|
||||
if (!result) throw new Error(`Sync directory not found: "${options.directory()}" on server "${options.path()}"`);
|
||||
output.ok = true;
|
||||
} catch (error) {
|
||||
output.errorMessage = error.message;
|
||||
if (error.code) output.errorMessage += ` (Code ${error.code})`;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
async initFileApi() {
|
||||
const fileApi = await SyncTargetJoplinServer.newFileApi_({
|
||||
path: () => Setting.value('sync.9.path'),
|
||||
username: () => Setting.value('sync.9.username'),
|
||||
password: () => Setting.value('sync.9.password'),
|
||||
directory: () => Setting.value('sync.9.directory'),
|
||||
});
|
||||
|
||||
fileApi.setLogger(this.logger());
|
||||
|
||||
return fileApi;
|
||||
}
|
||||
|
||||
async initSynchronizer() {
|
||||
return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType'));
|
||||
}
|
||||
}
|
||||
@@ -336,6 +336,7 @@ export default class Synchronizer {
|
||||
let syncLock = null;
|
||||
|
||||
try {
|
||||
await this.api().initialize();
|
||||
this.api().setTempDirName(Dirnames.Temp);
|
||||
|
||||
try {
|
||||
|
||||
196
packages/lib/file-api-driver-joplinServer.ts
Normal file
196
packages/lib/file-api-driver-joplinServer.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
import JoplinServerApi from './JoplinServerApi2';
|
||||
const { dirname, basename } = require('./path-utils');
|
||||
|
||||
function removeTrailingColon(path: string) {
|
||||
if (!path || !path.length) return '';
|
||||
if (path[path.length - 1] === ':') return path.substr(0, path.length - 1);
|
||||
return path;
|
||||
}
|
||||
|
||||
// All input paths should be in the format: "SPECIAL_DIR:/path/to/file"
|
||||
// The trailing colon must not be included as it's automatically added
|
||||
// when doing the API call.
|
||||
// Only supported special dir at the moment is "root"
|
||||
|
||||
export default class FileApiDriverJoplinServer {
|
||||
|
||||
private api_: JoplinServerApi;
|
||||
|
||||
public constructor(api: JoplinServerApi) {
|
||||
this.api_ = api;
|
||||
}
|
||||
|
||||
public async initialize(basePath: string) {
|
||||
const pieces = removeTrailingColon(basePath).split('/');
|
||||
if (!pieces.length) return;
|
||||
|
||||
let parent = pieces.splice(0, 1)[0];
|
||||
|
||||
for (const p of pieces) {
|
||||
// Syncing with the root, which is ok, and in that
|
||||
// case there's no sub-dir to create.
|
||||
if (!p && pieces.length === 1) return;
|
||||
|
||||
const subPath = `${parent}/${p}`;
|
||||
await this.mkdir(subPath);
|
||||
parent = subPath;
|
||||
}
|
||||
}
|
||||
|
||||
public api() {
|
||||
return this.api_;
|
||||
}
|
||||
|
||||
public requestRepeatCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
private metadataToStat_(md: any, path: string, isDeleted: boolean = false) {
|
||||
const output = {
|
||||
path: path,
|
||||
updated_time: md.updated_time,
|
||||
isDir: !!md.is_directory,
|
||||
isDeleted: isDeleted,
|
||||
};
|
||||
|
||||
// TODO - HANDLE DELETED
|
||||
// if (md['.tag'] === 'deleted') output.isDeleted = true;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private metadataToStats_(mds: any[]) {
|
||||
const output = [];
|
||||
for (let i = 0; i < mds.length; i++) {
|
||||
output.push(this.metadataToStat_(mds[i], mds[i].name));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private apiFilePath_(p: string) {
|
||||
if (p !== 'root') p += ':';
|
||||
return `api/files/${p}`;
|
||||
}
|
||||
|
||||
public async stat(path: string) {
|
||||
try {
|
||||
const response = await this.api().exec('GET', this.apiFilePath_(path));
|
||||
return this.metadataToStat_(response, path);
|
||||
} catch (error) {
|
||||
if (error.code === 404) return null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async delta(path: string, options: any) {
|
||||
const context = options ? options.context : null;
|
||||
let cursor = context ? context.cursor : null;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const query = cursor ? { cursor } : {};
|
||||
const response = await this.api().exec('GET', `${this.apiFilePath_(path)}/delta`, query);
|
||||
const stats = response.items.map((item: any) => {
|
||||
return this.metadataToStat_(item.item, item.item.name, item.type === 3);
|
||||
});
|
||||
|
||||
const output = {
|
||||
items: stats,
|
||||
hasMore: response.has_more,
|
||||
context: { cursor: response.cursor },
|
||||
};
|
||||
|
||||
return output;
|
||||
} catch (error) {
|
||||
// If there's an error related to an invalid cursor, clear the cursor and retry.
|
||||
if (cursor && error.code === 'resyncRequired') {
|
||||
cursor = null;
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async list(path: string, options: any = null) {
|
||||
options = {
|
||||
context: null,
|
||||
...options,
|
||||
};
|
||||
|
||||
const query = options.context?.cursor ? { cursor: options.context.cursor } : null;
|
||||
|
||||
const results = await this.api().exec('GET', `${this.apiFilePath_(path)}/children`, query);
|
||||
|
||||
const newContext: any = {};
|
||||
if (results.cursor) newContext.cursor = results.cursor;
|
||||
|
||||
return {
|
||||
items: this.metadataToStats_(results.items),
|
||||
hasMore: results.has_more,
|
||||
context: newContext,
|
||||
} as any;
|
||||
}
|
||||
|
||||
public async get(path: string, options: any) {
|
||||
if (!options) options = {};
|
||||
if (!options.responseFormat) options.responseFormat = 'text';
|
||||
try {
|
||||
const response = await this.api().exec('GET', `${this.apiFilePath_(path)}/content`, null, null, null, options);
|
||||
return response;
|
||||
} catch (error) {
|
||||
if (error.code !== 404) throw error;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private parentPath_(path: string) {
|
||||
let output = dirname(path);
|
||||
|
||||
// This is the root or a special folder
|
||||
if (output.split('/').length === 1) {
|
||||
output = output.substr(0, output.length - 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private basename_(path: string) {
|
||||
return basename(path);
|
||||
}
|
||||
|
||||
public async mkdir(path: string) {
|
||||
const parentPath = this.parentPath_(path);
|
||||
const filename = this.basename_(path);
|
||||
|
||||
try {
|
||||
const response = await this.api().exec('POST', `${this.apiFilePath_(parentPath)}/children`, null, {
|
||||
name: filename,
|
||||
is_directory: 1,
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
// 409 is OK - directory already exists
|
||||
if (error.code !== 409) throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async put(path: string, content: any, options: any = null) {
|
||||
return this.api().exec('PUT', `${this.apiFilePath_(path)}/content`, null, content, {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
}, options);
|
||||
}
|
||||
|
||||
public async delete(path: string) {
|
||||
return this.api().exec('DELETE', this.apiFilePath_(path));
|
||||
}
|
||||
|
||||
public format() {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
|
||||
public async clearRoot(path: string) {
|
||||
await this.delete(path);
|
||||
await this.mkdir(path);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ const time = require('./time').default;
|
||||
const { sprintf } = require('sprintf-js');
|
||||
const Mutex = require('async-mutex').Mutex;
|
||||
|
||||
const logger = Logger.create('FileApi');
|
||||
|
||||
function requestCanBeRepeated(error) {
|
||||
const errorCode = typeof error === 'object' && error.code ? error.code : null;
|
||||
|
||||
@@ -61,8 +63,14 @@ class FileApi {
|
||||
this.remoteDateOffset_ = 0;
|
||||
this.remoteDateNextCheckTime_ = 0;
|
||||
this.remoteDateMutex_ = new Mutex();
|
||||
this.initialized_ = false;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
if (this.initialized_) return;
|
||||
this.initialized_ = true;
|
||||
if (this.driver_.initialize) return this.driver_.initialize(this.fullPath_(''));
|
||||
}
|
||||
|
||||
async fetchRemoteDateOffset_() {
|
||||
const tempFile = `${this.tempDirName()}/timeCheck${Math.round(Math.random() * 1000000)}.txt`;
|
||||
@@ -108,7 +116,7 @@ class FileApi {
|
||||
this.remoteDateNextCheckTime_ = Date.now() + 10 * 60 * 1000;
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger().warn('Could not retrieve remote date - defaulting to device date:', error);
|
||||
logger.warn('Could not retrieve remote date - defaulting to device date:', error);
|
||||
this.remoteDateOffset_ = 0;
|
||||
this.remoteDateNextCheckTime_ = Date.now() + 60 * 1000;
|
||||
} finally {
|
||||
@@ -137,7 +145,7 @@ class FileApi {
|
||||
}
|
||||
|
||||
baseDir() {
|
||||
return this.baseDir_;
|
||||
return typeof this.baseDir_ === 'function' ? this.baseDir_() : this.baseDir_;
|
||||
}
|
||||
|
||||
tempDirName() {
|
||||
@@ -191,7 +199,7 @@ class FileApi {
|
||||
if (!('includeDirs' in options)) options.includeDirs = true;
|
||||
if (!('syncItemsOnly' in options)) options.syncItemsOnly = false;
|
||||
|
||||
this.logger().debug(`list ${this.baseDir()}`);
|
||||
logger.debug(`list ${this.baseDir()}`);
|
||||
|
||||
const result = await tryAndRepeat(() => this.driver_.list(this.fullPath_(path), options), this.requestRepeatCount());
|
||||
|
||||
@@ -216,18 +224,18 @@ class FileApi {
|
||||
|
||||
// Deprectated
|
||||
setTimestamp(path, timestampMs) {
|
||||
this.logger().debug(`setTimestamp ${this.fullPath_(path)}`);
|
||||
logger.debug(`setTimestamp ${this.fullPath_(path)}`);
|
||||
return tryAndRepeat(() => this.driver_.setTimestamp(this.fullPath_(path), timestampMs), this.requestRepeatCount());
|
||||
// return this.driver_.setTimestamp(this.fullPath_(path), timestampMs);
|
||||
}
|
||||
|
||||
mkdir(path) {
|
||||
this.logger().debug(`mkdir ${this.fullPath_(path)}`);
|
||||
logger.debug(`mkdir ${this.fullPath_(path)}`);
|
||||
return tryAndRepeat(() => this.driver_.mkdir(this.fullPath_(path)), this.requestRepeatCount());
|
||||
}
|
||||
|
||||
async stat(path) {
|
||||
this.logger().debug(`stat ${this.fullPath_(path)}`);
|
||||
logger.debug(`stat ${this.fullPath_(path)}`);
|
||||
|
||||
const output = await tryAndRepeat(() => this.driver_.stat(this.fullPath_(path)), this.requestRepeatCount());
|
||||
|
||||
@@ -246,12 +254,12 @@ class FileApi {
|
||||
get(path, options = null) {
|
||||
if (!options) options = {};
|
||||
if (!options.encoding) options.encoding = 'utf8';
|
||||
this.logger().debug(`get ${this.fullPath_(path)}`);
|
||||
logger.debug(`get ${this.fullPath_(path)}`);
|
||||
return tryAndRepeat(() => this.driver_.get(this.fullPath_(path), options), this.requestRepeatCount());
|
||||
}
|
||||
|
||||
async put(path, content, options = null) {
|
||||
this.logger().debug(`put ${this.fullPath_(path)}`, options);
|
||||
logger.debug(`put ${this.fullPath_(path)}`, options);
|
||||
|
||||
if (options && options.source === 'file') {
|
||||
if (!(await this.fsDriver().exists(options.path))) throw new JoplinError(`File not found: ${options.path}`, 'fileNotFound');
|
||||
@@ -261,13 +269,13 @@ class FileApi {
|
||||
}
|
||||
|
||||
delete(path) {
|
||||
this.logger().debug(`delete ${this.fullPath_(path)}`);
|
||||
logger.debug(`delete ${this.fullPath_(path)}`);
|
||||
return tryAndRepeat(() => this.driver_.delete(this.fullPath_(path)), this.requestRepeatCount());
|
||||
}
|
||||
|
||||
// Deprectated
|
||||
move(oldPath, newPath) {
|
||||
this.logger().debug(`move ${this.fullPath_(oldPath)} => ${this.fullPath_(newPath)}`);
|
||||
logger.debug(`move ${this.fullPath_(oldPath)} => ${this.fullPath_(newPath)}`);
|
||||
return tryAndRepeat(() => this.driver_.move(this.fullPath_(oldPath), this.fullPath_(newPath)), this.requestRepeatCount());
|
||||
}
|
||||
|
||||
@@ -281,7 +289,7 @@ class FileApi {
|
||||
}
|
||||
|
||||
delta(path, options = null) {
|
||||
this.logger().debug(`delta ${this.fullPath_(path)}`);
|
||||
logger.debug(`delta ${this.fullPath_(path)}`);
|
||||
return tryAndRepeat(() => this.driver_.delta(this.fullPath_(path), options), this.requestRepeatCount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import markdownUtils from './markdownUtils';
|
||||
import { ResourceEntity } from './services/database/types';
|
||||
const stringPadding = require('string-padding');
|
||||
const stringToStream = require('string-to-stream');
|
||||
const resourceUtils = require('./resourceUtils.js');
|
||||
@@ -8,7 +10,51 @@ const NEWLINE = '[[NEWLINE]]';
|
||||
const NEWLINE_MERGED = '[[MERGED]]';
|
||||
const SPACE = '[[SPACE]]';
|
||||
|
||||
function processMdArrayNewLines(md) {
|
||||
enum SectionType {
|
||||
Text = 'text',
|
||||
Tr = 'tr',
|
||||
Td = 'td',
|
||||
Table = 'table',
|
||||
Caption = 'caption',
|
||||
Hidden = 'hidden',
|
||||
Code = 'code',
|
||||
}
|
||||
|
||||
interface Section {
|
||||
type: SectionType;
|
||||
parent: Section;
|
||||
lines: any[];
|
||||
isHeader?: boolean;
|
||||
}
|
||||
|
||||
interface ParserStateTag {
|
||||
name: string;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
interface ParserStateList {
|
||||
tag: string;
|
||||
counter: number;
|
||||
startedText: boolean;
|
||||
}
|
||||
|
||||
interface ParserState {
|
||||
inCode: boolean[];
|
||||
inPre: boolean;
|
||||
inQuote: boolean;
|
||||
lists: ParserStateList[];
|
||||
anchorAttributes: any[];
|
||||
spanAttributes: string[];
|
||||
tags: ParserStateTag[];
|
||||
currentCode?: string;
|
||||
}
|
||||
|
||||
interface EnexXmlToMdArrayResult {
|
||||
content: Section;
|
||||
resources: ResourceEntity[];
|
||||
}
|
||||
|
||||
function processMdArrayNewLines(md: string[]): string {
|
||||
while (md.length && md[0] == BLOCK_OPEN) {
|
||||
md.shift();
|
||||
}
|
||||
@@ -102,7 +148,7 @@ function processMdArrayNewLines(md) {
|
||||
if (!output.trim().length) return '';
|
||||
|
||||
// To simplify the result, we only allow up to one empty line between blocks of text
|
||||
const mergeMultipleNewLines = function(lines) {
|
||||
const mergeMultipleNewLines = function(lines: string[]) {
|
||||
const output = [];
|
||||
let newlineCount = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
@@ -159,23 +205,23 @@ function processMdArrayNewLines(md) {
|
||||
// differently than if there's a newlines between them. So the function below parses the almost final MD and add new lines depending
|
||||
// on various rules.
|
||||
|
||||
const isHeading = function(line) {
|
||||
const isHeading = function(line: string) {
|
||||
return !!line.match(/^#+\s/);
|
||||
};
|
||||
|
||||
const isListItem = function(line) {
|
||||
const isListItem = function(line: string) {
|
||||
return line && line.trim().indexOf('- ') === 0;
|
||||
};
|
||||
|
||||
const isCodeLine = function(line) {
|
||||
const isCodeLine = function(line: string) {
|
||||
return line && line.indexOf('\t') === 0;
|
||||
};
|
||||
|
||||
const isTableLine = function(line) {
|
||||
const isTableLine = function(line: string) {
|
||||
return line.indexOf('| ') === 0;
|
||||
};
|
||||
|
||||
const isPlainParagraph = function(line) {
|
||||
const isPlainParagraph = function(line: string) {
|
||||
// Note: if a line is no longer than 80 characters, we don't consider it's a paragraph, which
|
||||
// means no newlines will be added before or after. This is to handle text that has been
|
||||
// written with "hard" new lines.
|
||||
@@ -189,7 +235,7 @@ const isPlainParagraph = function(line) {
|
||||
return true;
|
||||
};
|
||||
|
||||
function formatMdLayout(lines) {
|
||||
function formatMdLayout(lines: string[]) {
|
||||
let previous = '';
|
||||
const newLines = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
@@ -235,13 +281,13 @@ function formatMdLayout(lines) {
|
||||
return newLines;
|
||||
}
|
||||
|
||||
function isWhiteSpace(c) {
|
||||
function isWhiteSpace(c: string): boolean {
|
||||
return c == '\n' || c == '\r' || c == '\v' || c == '\f' || c == '\t' || c == ' ';
|
||||
}
|
||||
|
||||
// Like QString::simpified(), except that it preserves non-breaking spaces (which
|
||||
// Evernote uses for identation, etc.)
|
||||
function simplifyString(s) {
|
||||
function simplifyString(s: string): string {
|
||||
let output = '';
|
||||
let previousWhite = false;
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
@@ -261,7 +307,7 @@ function simplifyString(s) {
|
||||
return output;
|
||||
}
|
||||
|
||||
function collapseWhiteSpaceAndAppend(lines, state, text) {
|
||||
function collapseWhiteSpaceAndAppend(lines: string[], state: any, text: string) {
|
||||
if (state.inCode.length) {
|
||||
lines.push(text);
|
||||
} else {
|
||||
@@ -296,7 +342,7 @@ function collapseWhiteSpaceAndAppend(lines, state, text) {
|
||||
return lines;
|
||||
}
|
||||
|
||||
function tagAttributeToMdText(attr) {
|
||||
function tagAttributeToMdText(attr: string): string {
|
||||
// HTML attributes may contain newlines so remove them.
|
||||
// https://github.com/laurent22/joplin/issues/1583
|
||||
if (!attr) return '';
|
||||
@@ -305,7 +351,7 @@ function tagAttributeToMdText(attr) {
|
||||
return attr;
|
||||
}
|
||||
|
||||
function addResourceTag(lines, resource, alt = '') {
|
||||
function addResourceTag(lines: string[], resource: ResourceEntity, alt: string = ''): string[] {
|
||||
// Note: refactor to use Resource.markdownTag
|
||||
|
||||
if (!alt) alt = resource.title;
|
||||
@@ -326,50 +372,50 @@ function addResourceTag(lines, resource, alt = '') {
|
||||
return lines;
|
||||
}
|
||||
|
||||
function isBlockTag(n) {
|
||||
function isBlockTag(n: string) {
|
||||
return ['div', 'p', 'dl', 'dd', 'dt', 'center', 'address'].indexOf(n) >= 0;
|
||||
}
|
||||
|
||||
function isStrongTag(n) {
|
||||
function isStrongTag(n: string) {
|
||||
return n == 'strong' || n == 'b' || n == 'big';
|
||||
}
|
||||
|
||||
function isStrikeTag(n) {
|
||||
function isStrikeTag(n: string) {
|
||||
return n == 'strike' || n == 's' || n == 'del';
|
||||
}
|
||||
|
||||
function isEmTag(n) {
|
||||
function isEmTag(n: string) {
|
||||
return n == 'em' || n == 'i' || n == 'u';
|
||||
}
|
||||
|
||||
function isAnchor(n) {
|
||||
function isAnchor(n: string) {
|
||||
return n == 'a';
|
||||
}
|
||||
|
||||
function isIgnoredEndTag(n) {
|
||||
function isIgnoredEndTag(n: string) {
|
||||
return ['en-note', 'en-todo', 'body', 'html', 'font', 'br', 'hr', 'tbody', 'sup', 'img', 'abbr', 'cite', 'thead', 'small', 'tt', 'sub', 'colgroup', 'col', 'ins', 'caption', 'var', 'map', 'area'].indexOf(n) >= 0;
|
||||
}
|
||||
|
||||
function isListTag(n) {
|
||||
function isListTag(n: string) {
|
||||
return n == 'ol' || n == 'ul';
|
||||
}
|
||||
|
||||
// Elements that don't require any special treatment beside adding a newline character
|
||||
function isNewLineOnlyEndTag(n) {
|
||||
function isNewLineOnlyEndTag(n: string) {
|
||||
return ['div', 'p', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dl', 'dd', 'dt', 'center', 'address'].indexOf(n) >= 0;
|
||||
}
|
||||
|
||||
function isInlineCodeTag(n) {
|
||||
function isInlineCodeTag(n: string) {
|
||||
return ['samp', 'kbd'].indexOf(n) >= 0;
|
||||
}
|
||||
|
||||
function isNewLineBlock(s) {
|
||||
function isNewLineBlock(s: string) {
|
||||
return s == BLOCK_OPEN || s == BLOCK_CLOSE;
|
||||
}
|
||||
|
||||
function attributeToLowerCase(node) {
|
||||
function attributeToLowerCase(node: any) {
|
||||
if (!node.attributes) return {};
|
||||
const output = {};
|
||||
const output: any = {};
|
||||
for (const n in node.attributes) {
|
||||
if (!node.attributes.hasOwnProperty(n)) continue;
|
||||
output[n.toLowerCase()] = node.attributes[n];
|
||||
@@ -377,13 +423,13 @@ function attributeToLowerCase(node) {
|
||||
return output;
|
||||
}
|
||||
|
||||
function isInvisibleBlock(attributes) {
|
||||
function isInvisibleBlock(attributes: any) {
|
||||
const style = attributes.style;
|
||||
if (!style) return false;
|
||||
return !!style.match(/display:[\s\S]*none/);
|
||||
}
|
||||
|
||||
function isSpanWithStyle(attributes) {
|
||||
function isSpanWithStyle(attributes: any) {
|
||||
if (attributes != undefined) {
|
||||
if ('style' in attributes) {
|
||||
return true;
|
||||
@@ -391,9 +437,10 @@ function isSpanWithStyle(attributes) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isSpanStyleBold(attributes) {
|
||||
function isSpanStyleBold(attributes: any) {
|
||||
const style = attributes.style;
|
||||
if (!style) return false;
|
||||
|
||||
@@ -406,13 +453,13 @@ function isSpanStyleBold(attributes) {
|
||||
}
|
||||
}
|
||||
|
||||
function isSpanStyleItalic(attributes) {
|
||||
function isSpanStyleItalic(attributes: any) {
|
||||
let style = attributes.style;
|
||||
style = style.replace(/\s+/g, '');
|
||||
return (style.toLowerCase().includes('font-style:italic;'));
|
||||
}
|
||||
|
||||
function displaySaxWarning(context, message) {
|
||||
function displaySaxWarning(context: any, message: string) {
|
||||
const line = [];
|
||||
const parser = context ? context._parser : null;
|
||||
if (parser) {
|
||||
@@ -422,31 +469,29 @@ function displaySaxWarning(context, message) {
|
||||
console.warn(line.join(': '));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
||||
function removeSectionParent(section) {
|
||||
if (typeof section === 'string') return section;
|
||||
// function removeSectionParent(section:Section | string) {
|
||||
// if (typeof section === 'string') return section;
|
||||
|
||||
section = { ...section };
|
||||
delete section.parent;
|
||||
// section = { ...section };
|
||||
// delete section.parent;
|
||||
|
||||
section.lines = section.lines.slice();
|
||||
// section.lines = section.lines.slice();
|
||||
|
||||
for (let i = 0; i < section.lines.length; i++) {
|
||||
section.lines[i] = removeSectionParent(section.lines[i]);
|
||||
}
|
||||
// for (let i = 0; i < section.lines.length; i++) {
|
||||
// section.lines[i] = removeSectionParent(section.lines[i]);
|
||||
// }
|
||||
|
||||
return section;
|
||||
}
|
||||
// return section;
|
||||
// }
|
||||
|
||||
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
||||
function printSection(section) {
|
||||
console.info(JSON.stringify(removeSectionParent(section), null, 4));
|
||||
}
|
||||
// function printSection(section:Section) {
|
||||
// console.info(JSON.stringify(removeSectionParent(section), null, 4));
|
||||
// }
|
||||
|
||||
function enexXmlToMdArray(stream, resources) {
|
||||
function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<EnexXmlToMdArrayResult> {
|
||||
const remainingResources = resources.slice();
|
||||
|
||||
const removeRemainingResource = id => {
|
||||
const removeRemainingResource = (id: string) => {
|
||||
for (let i = 0; i < remainingResources.length; i++) {
|
||||
const r = remainingResources[i];
|
||||
if (r.id === id) {
|
||||
@@ -456,7 +501,7 @@ function enexXmlToMdArray(stream, resources) {
|
||||
};
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const state = {
|
||||
const state: ParserState = {
|
||||
inCode: [],
|
||||
inPre: false,
|
||||
inQuote: false,
|
||||
@@ -470,17 +515,17 @@ function enexXmlToMdArray(stream, resources) {
|
||||
const strict = false;
|
||||
const saxStream = require('@joplin/fork-sax').createStream(strict, options);
|
||||
|
||||
let section = {
|
||||
type: 'text',
|
||||
let section: Section = {
|
||||
type: SectionType.Text,
|
||||
lines: [],
|
||||
parent: null,
|
||||
};
|
||||
|
||||
saxStream.on('error', function(e) {
|
||||
saxStream.on('error', function(e: any) {
|
||||
console.warn(e);
|
||||
});
|
||||
|
||||
const unwrapInnerText = text => {
|
||||
const unwrapInnerText = (text: string) => {
|
||||
const lines = text.split('\n');
|
||||
|
||||
let output = '';
|
||||
@@ -504,14 +549,14 @@ function enexXmlToMdArray(stream, resources) {
|
||||
return output;
|
||||
};
|
||||
|
||||
saxStream.on('text', function(text) {
|
||||
saxStream.on('text', function(text: string) {
|
||||
if (['table', 'tr', 'tbody'].indexOf(section.type) >= 0) return;
|
||||
|
||||
text = !state.inPre ? unwrapInnerText(text) : text;
|
||||
section.lines = collapseWhiteSpaceAndAppend(section.lines, state, text);
|
||||
});
|
||||
|
||||
saxStream.on('opentag', function(node) {
|
||||
saxStream.on('opentag', function(node: any) {
|
||||
const nodeAttributes = attributeToLowerCase(node);
|
||||
const n = node.name.toLowerCase();
|
||||
const isVisible = !isInvisibleBlock(nodeAttributes);
|
||||
@@ -542,8 +587,8 @@ function enexXmlToMdArray(stream, resources) {
|
||||
if (n == 'en-note') {
|
||||
// Start of note
|
||||
} else if (n == 'table') {
|
||||
const newSection = {
|
||||
type: 'table',
|
||||
const newSection: Section = {
|
||||
type: SectionType.Table,
|
||||
lines: [],
|
||||
parent: section,
|
||||
};
|
||||
@@ -568,8 +613,8 @@ function enexXmlToMdArray(stream, resources) {
|
||||
// return;
|
||||
}
|
||||
|
||||
const newSection = {
|
||||
type: 'tr',
|
||||
const newSection: Section = {
|
||||
type: SectionType.Tr,
|
||||
lines: [],
|
||||
parent: section,
|
||||
isHeader: false,
|
||||
@@ -585,8 +630,8 @@ function enexXmlToMdArray(stream, resources) {
|
||||
|
||||
if (n == 'th') section.isHeader = true;
|
||||
|
||||
const newSection = {
|
||||
type: 'td',
|
||||
const newSection: Section = {
|
||||
type: SectionType.Td,
|
||||
lines: [],
|
||||
parent: section,
|
||||
};
|
||||
@@ -599,8 +644,8 @@ function enexXmlToMdArray(stream, resources) {
|
||||
// return;
|
||||
}
|
||||
|
||||
const newSection = {
|
||||
type: 'caption',
|
||||
const newSection: Section = {
|
||||
type: SectionType.Caption,
|
||||
lines: [],
|
||||
parent: section,
|
||||
};
|
||||
@@ -608,8 +653,8 @@ function enexXmlToMdArray(stream, resources) {
|
||||
section.lines.push(newSection);
|
||||
section = newSection;
|
||||
} else if (isInvisibleBlock(nodeAttributes)) {
|
||||
const newSection = {
|
||||
type: 'hidden',
|
||||
const newSection: Section = {
|
||||
type: SectionType.Hidden,
|
||||
lines: [],
|
||||
parent: section,
|
||||
};
|
||||
@@ -624,7 +669,7 @@ function enexXmlToMdArray(stream, resources) {
|
||||
section.lines.push(BLOCK_OPEN);
|
||||
if (!state.lists.length) {
|
||||
displaySaxWarning(this, 'Found <li> tag without being inside a list');
|
||||
// return;
|
||||
return;
|
||||
}
|
||||
|
||||
const container = state.lists[state.lists.length - 1];
|
||||
@@ -650,7 +695,7 @@ function enexXmlToMdArray(stream, resources) {
|
||||
// Many (most?) img tags don't have no source associated, especially when they were imported from HTML
|
||||
let s = '`;
|
||||
s += `](${markdownUtils.escapeLinkUrl(nodeAttributes.src)})`;
|
||||
section.lines.push(s);
|
||||
}
|
||||
} else if (isAnchor(n)) {
|
||||
@@ -694,8 +739,8 @@ function enexXmlToMdArray(stream, resources) {
|
||||
state.inCode.push(true);
|
||||
state.currentCode = '';
|
||||
|
||||
const newSection = {
|
||||
type: 'code',
|
||||
const newSection: Section = {
|
||||
type: SectionType.Code,
|
||||
lines: [],
|
||||
parent: section,
|
||||
};
|
||||
@@ -802,7 +847,7 @@ function enexXmlToMdArray(stream, resources) {
|
||||
}
|
||||
});
|
||||
|
||||
saxStream.on('closetag', function(n) {
|
||||
saxStream.on('closetag', function(n: string) {
|
||||
n = n ? n.toLowerCase() : n;
|
||||
|
||||
const poppedTag = state.tags.pop();
|
||||
@@ -940,7 +985,7 @@ function enexXmlToMdArray(stream, resources) {
|
||||
// [ Sign in ](https://example.com)
|
||||
// to:
|
||||
// [Sign in](https://example.com)
|
||||
const trimTextStartAndEndSpaces = function(lines) {
|
||||
const trimTextStartAndEndSpaces = function(lines: string[]) {
|
||||
let firstBracketIndex = 0;
|
||||
let foundFirstNonWhite = false;
|
||||
for (let i = lines.length - 1; i >= 0; i--) {
|
||||
@@ -999,14 +1044,14 @@ function enexXmlToMdArray(stream, resources) {
|
||||
resolve({
|
||||
content: section,
|
||||
resources: remainingResources,
|
||||
});
|
||||
} as EnexXmlToMdArrayResult);
|
||||
});
|
||||
|
||||
stream.pipe(saxStream);
|
||||
});
|
||||
}
|
||||
|
||||
function tableHasSubTables(table) {
|
||||
function tableHasSubTables(table: Section) {
|
||||
for (let trIndex = 0; trIndex < table.lines.length; trIndex++) {
|
||||
const tr = table.lines[trIndex];
|
||||
if (!tr || !tr.lines) continue;
|
||||
@@ -1029,7 +1074,7 @@ function tableHasSubTables(table) {
|
||||
// via Web Clipper. So to handle this, we render all the outer tables as regular text (as if replacing all the <table>, <tr> and <td>
|
||||
// elements by <div>) and only the inner ones, those that don't contain any other tables, are rendered as actual tables. This is generally
|
||||
// the required behaviour since the outer tables are usually for layout and the inner ones are the content.
|
||||
function drawTable(table) {
|
||||
function drawTable(table: Section) {
|
||||
// | First Header | Second Header |
|
||||
// | ------------- | ------------- |
|
||||
// | Content Cell | Content Cell |
|
||||
@@ -1061,7 +1106,7 @@ function drawTable(table) {
|
||||
if (flatRender) {
|
||||
line.push(BLOCK_OPEN);
|
||||
|
||||
let currentCells = [];
|
||||
let currentCells: any[] = [];
|
||||
|
||||
const renderCurrentCells = () => {
|
||||
if (!currentCells.length) return;
|
||||
@@ -1092,7 +1137,7 @@ function drawTable(table) {
|
||||
|
||||
// A cell in a Markdown table cannot have actual new lines so replace
|
||||
// them with <br>, which are supported by the markdown renderers.
|
||||
let cellText = processMdArrayNewLines(td.lines, true);
|
||||
let cellText = processMdArrayNewLines(td.lines);
|
||||
let lines = cellText.split('\n');
|
||||
lines = postProcessMarkdown(lines);
|
||||
cellText = lines.join('\n').replace(/\n+/g, '<br>');
|
||||
@@ -1142,19 +1187,19 @@ function drawTable(table) {
|
||||
lines.push(BLOCK_CLOSE);
|
||||
|
||||
if (caption) {
|
||||
const captionLines = renderLines(caption.lines);
|
||||
const captionLines: any[] = renderLines(caption.lines);
|
||||
lines = lines.concat(captionLines);
|
||||
}
|
||||
|
||||
return flatRender ? lines : lines.join(`<<<<:D>>>>${NEWLINE}<<<<:D>>>>`).split('<<<<:D>>>>');
|
||||
}
|
||||
|
||||
function postProcessMarkdown(lines) {
|
||||
function postProcessMarkdown(lines: string[]) {
|
||||
// After importing HTML, the resulting Markdown often has empty lines at the beginning and end due to
|
||||
// block start/end or elements that were ignored, etc. If these white spaces were intended it's not really
|
||||
// possible to detect it, so simply trim them all so that the result is more deterministic and can be
|
||||
// easily unit tested.
|
||||
const trimEmptyLines = function(lines) {
|
||||
const trimEmptyLines = function(lines: string[]) {
|
||||
while (lines.length) {
|
||||
if (!lines[0].trim()) {
|
||||
lines.splice(0, 1);
|
||||
@@ -1174,7 +1219,7 @@ function postProcessMarkdown(lines) {
|
||||
return lines;
|
||||
};
|
||||
|
||||
function cleanUpSpaces(lines) {
|
||||
function cleanUpSpaces(lines: string[]) {
|
||||
const output = [];
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
@@ -1203,7 +1248,7 @@ function postProcessMarkdown(lines) {
|
||||
|
||||
// A "line" can be some Markdown text, or it can be a section, like a table,
|
||||
// etc. so this function returns an array of strings.
|
||||
function renderLine(line) {
|
||||
function renderLine(line: any) {
|
||||
if (typeof line === 'object' && line.type === 'table') {
|
||||
// A table
|
||||
const table = line;
|
||||
@@ -1227,8 +1272,8 @@ function renderLine(line) {
|
||||
}
|
||||
}
|
||||
|
||||
function renderLines(lines) {
|
||||
let mdLines = [];
|
||||
function renderLines(lines: any[]) {
|
||||
let mdLines: string[] = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const renderedLines = renderLine(lines[i]);
|
||||
mdLines = mdLines.concat(renderedLines);
|
||||
@@ -1236,9 +1281,9 @@ function renderLines(lines) {
|
||||
return mdLines;
|
||||
}
|
||||
|
||||
async function enexXmlToMd(xmlString, resources, options = {}) {
|
||||
async function enexXmlToMd(xmlString: string, resources: ResourceEntity[]) {
|
||||
const stream = stringToStream(xmlString);
|
||||
const result = await enexXmlToMdArray(stream, resources, options);
|
||||
const result = await enexXmlToMdArray(stream, resources);
|
||||
|
||||
let mdLines = renderLines(result.content.lines);
|
||||
|
||||
@@ -1258,4 +1303,4 @@ async function enexXmlToMd(xmlString, resources, options = {}) {
|
||||
return output.join('\n');
|
||||
}
|
||||
|
||||
module.exports = { enexXmlToMd, processMdArrayNewLines, NEWLINE, addResourceTag };
|
||||
export { enexXmlToMd, processMdArrayNewLines, NEWLINE, addResourceTag };
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user